2011-11-15 10 views
3

私は、パッケージ旅行のための旅程マッパーのような作業をしています。私はこれまで行ってきたことに本当に満足しています。私は道案内APIをカスタムレンダラで実装しているので、運転の道順を取ることができ、経路に沿ったGoogleのひどいものではない方向矢印で自分のポリラインをプロットすることができます。私は正確に数学の専門家ではない、私は別のパスに平行してパスを作る方法を理解しようとしている。たとえば、旅程は都市1から都市2に、都市1に戻ります。Googleマップapiパラレルパスライン

都市1のポリラインに戻り、パスを鏡映して平行移動します。理想的には、パスを作成し、他のパスの交差点をチェックし、見つかった場合はそれらのポイントだけのパスをオフセットすることが理想的です。たとえば、短時間だけ別のパスに出会った場合など、別のパスと交差する場所でのみパスをパラレルにすることができるので、これはより優れた実装になります。

私は法案のチャドウィック

リンクからAPI2のため、このコードはここにあるが見つかりました:http://wtp2.appspot.com/ParallelLines.htm

更新:どういうわけか、それはv3の中で働いて得るために、この古いv2のスクリプトを変換するために管理が、私はいくつかを経験しています問題...

元のポイント数を2倍以上にしてパスに従いますが、実際にランダムに投げています。ここにスクリーンショット:私は変換

Google maps screenshot

クラスはここにある:これはポイントに取り組んでいる

function BDCCParallelLines(points, color, weight, opacity, opts, gapPx) { 

    console.log('Pllel COnstructor Initialized'); 
    this.gapPx = gapPx; 
    this.points = points; 
    this.color = color; 
    this.weight = weight; 
    this.opacity = opacity; 
    this.opts = opts; 
    this.line1 = null; 
    this.line2 = null; 
    this.lstnZoom = null; 
} 


BDCCParallelLines.prototype = new google.maps.OverlayView(); 



BDCCParallelLines.prototype.onAdd = function() { 
console.log('Pllel Initialized'); 
this.prj = map.getProjection(); 

var self = this; 
    this.lstnZoom = google.maps.event.addListener(map, "zoom_changed", function() { 
self.recalc(); 
    }); 
    this.recalc();//first draw 
} 


BDCCParallelLines.prototype.onRemove = function() { 

    if(this.line2) 
     this.line2.setMap(null); 
    if(this.line1) 
     this.line1.setMap(null); 
    if(this.lstnZoom != null) 
     google.maps.event.removeListener(this.lstnZoom); 

} 

BDCCParallelLines.prototype.copy = function() { 
    return new BDCCParallelLines(this.points,this.color,this.weight,this.opacity,this.opts,this.gapPx); 
} 

BDCCParallelLines.prototype.draw = function(force) { 
    return; //do nothing 
} 




    /** 
* @param {google.maps.Map} map 
* @param {google.maps.LatLng} latlng 
* @param {int} z 
* @return {google.maps.Point} 
*/ 
BDCCParallelLines.prototype.latLngToPoint = function(latlng, z){ 
var normalizedPoint = map.getProjection().fromLatLngToPoint(latlng); // returns x,y normalized to 0~255 
var scale = Math.pow(2, z); 
var pixelCoordinate = new google.maps.Point(normalizedPoint.x * scale, normalizedPoint.y * scale); 
return pixelCoordinate; 
}; 
/** 
* @param {google.maps.Map} map 
* @param {google.maps.Point} point 
* @param {int} z 
* @return {google.maps.LatLng} 
*/ 
BDCCParallelLines.prototype.pointToLatlng = function(point, z){ 
var scale = Math.pow(2, z); 
var normalizedPoint = new google.maps.Point(point.x/scale, point.y/scale); 
var latlng = map.getProjection().fromPointToLatLng(normalizedPoint); 
return latlng; 
}; 


BDCCParallelLines.prototype.recalc = function() { 

var distallowance; 
console.log('recalc called'); 
    var zoom = map.getZoom(); 
    distallowance = 1.6; 
    if(zoom > 6){ 
     distallowance = 1.3; 
     if(zoom > 9){ 
      distallowance = .7; 
      if(zoom > 13){ 
       distallowance = .2; 
       if(zoom > 15){ 
       distallowance = .0001; 
       } 
       } 

      }  
     } 
     console.log('Zoom Level: ' + zoom); 
     console.log('Allowance = ' + distallowance); 


    var pts1 = new Array();//left side of center 

    //shift the pts array away from the centre-line by half the gap + half the line width 
    var o = (this.gapPx + this.weight)/2; 

    var p2l,p2r; 

    for (var i=1; i<this.points.length; i++){ 

     var p1lm1; 
     var p1rm1; 
     var p2lm1; 
     var p2rm1; 
     var thetam1; 

     var p1 = this.latLngToPoint(this.points[i-1], zoom) 
     var p2 = this.latLngToPoint(this.points[i], zoom) 
     var theta = Math.atan2(p1.x-p2.x,p1.y-p2.y); 
     theta = theta + (Math.PI/2); 


     var dl = Math.sqrt(((p1.x-p2.x)*(p1.x-p2.x))+((p1.y-p2.y)*(p1.y-p2.y))); 

     if(theta > Math.PI) 
      theta -= Math.PI*2; 
     var dx = Math.round(o * Math.sin(theta)); 
     var dy = Math.round(o * Math.cos(theta)); 

     var p1l = new google.maps.Point(p1.x+dx,p1.y+dy); 
     var p1r = new google.maps.Point(p1.x-dx,p1.y-dy); 
     p2l = new google.maps.Point(p2.x+dx,p2.y+dy); 
     p2r = new google.maps.Point(p2.x-dx,p2.y-dy); 

     if(i==1){ //first point 
     pts1.push(this.pointToLatlng(p1l,zoom)); 
     } 
     else{ // mid this.points 

    if(distbetweentwo(this.points[i-1], this.points[i]) > distallowance){ 

     if(theta == thetam1){ 
      // adjacent segments in a straight line 
     pts1.push(this.pointToLatlng(p1l,zoom)); 
     } 
     else{ 
      var pli = this.intersect(p1lm1,p2lm1,p1l,p2l); 
      var pri = this.intersect(p1rm1,p2rm1,p1r,p2r); 

      var dlxi = (pli.x-p1.x); 
      var dlyi = (pli.y-p1.y); 
      var drxi = (pri.x-p1.x); 
      var dryi = (pri.y-p1.y); 
     var di = Math.sqrt((drxi*drxi)+(dryi*dryi)); 
      var s = o/di; 

      var dTheta = theta - thetam1; 
      if(dTheta < (Math.PI*2)) 
       dTheta += Math.PI*2; 
      if(dTheta > (Math.PI*2)) 
       dTheta -= Math.PI*2; 

      if(dTheta < Math.PI){ 
       //intersect point on outside bend 
      pts1.push(this.pointToLatlng(p2lm1,zoom)); 
      pts1.push(this.pointToLatlng(new google.maps.Point(p1.x+(s*dlxi),p1.y+(s*dlyi)),zoom)); 
      pts1.push(this.pointToLatlng(p1l,zoom)); 


      } 
     else if (di < dl){ 

     pts1.push(this.pointToLatlng(pli,zoom)); 

     } 
      else{ 

       pts1.push(this.pointToLatlng(p2lm1,zoom)); 
       pts1.push(this.pointToLatlng(p1l,zoom)); 

     } 



     } 

    } 
    else{ 
    //console.log(distbetweentwo(this.points[i-1], this.points[i])); 
    } 
    } 




     p1lm1 = p1l; 
     p1rm1 = p1r; 
     p2lm1 = p2l; 
     p2rm1 = p2r; 
     thetam1 = theta; 

     //end loop 
    } 

    pts1.push(this.pointToLatlng(p2l,zoom));//final point 

    // console.log(pts1); 

    if(this.line1) 
    this.line1.setMap(null); 
     this.line1 = new google.maps.Polyline({ 
     strokeColor: this.color, 
     strokeOpacity: this.opacity, 
     strokeWeight: this.weight, 
     map: map, 
     path: pts1 }); 


    this.line1.setMap(map); 


} 

BDCCParallelLines.prototype.intersect = function(p0,p1,p2,p3) 
{ 
// this function computes the intersection of the sent lines p0-p1 and p2-p3 
// and returns the intersection point, 

var a1,b1,c1, // constants of linear equations 
    a2,b2,c2, 
    det_inv, // the inverse of the determinant of the coefficient matrix 
    m1,m2; // the slopes of each line 

var x0 = p0.x; 
var y0 = p0.y; 
var x1 = p1.x; 
var y1 = p1.y; 
var x2 = p2.x; 
var y2 = p2.y; 
var x3 = p3.x; 
var y3 = p3.y; 

// compute slopes, note the cludge for infinity, however, this will 
// be close enough 

if ((x1-x0)!=0) 
    m1 = (y1-y0)/(x1-x0); 
else 
    m1 = 1e+10; // close enough to infinity 

if ((x3-x2)!=0) 
    m2 = (y3-y2)/(x3-x2); 
else 
    m2 = 1e+10; // close enough to infinity 

// compute constants 

a1 = m1; 
a2 = m2; 

b1 = -1; 
b2 = -1; 

c1 = (y0-m1*x0); 
c2 = (y2-m2*x2); 

// compute the inverse of the determinate 

det_inv = 1/(a1*b2 - a2*b1); 

// use Kramers rule to compute xi and yi 

var xi=((b1*c2 - b2*c1)*det_inv); 
var yi=((a2*c1 - a1*c2)*det_inv); 

return new google.maps.Point(Math.round(xi),Math.round(yi)); 

} 

...それは元の実装としてうまく機能しています。パス全体がズームベースで再計算されていますが、ズームレベルが高いほど非常に短いパス(奇妙な角度)をスキップする機能をハックしましたが、ズームしたほうがパスに近づきます。

ちょうどそれはかなり集中しているので、再計算されていない固定された距離のオフセットを持っている...この偉業、rhino3d、オートキャド、イラストレーターを達成する多くのプログラムがあります...私はそれがグーグルマップ自身、あなたが帰り旅行と元の旅行を区別することができるようにパスの相殺。

Googleのマップではないにしても、誰かがJSに似たようなことをしてくれたら、私はそれを見たいと思うでしょう。私が調査していますリンク:一般的に

http://processingjs.nihongoresources.com/bezierinfo/

http://www.groupsrv.com/computers/about21532.html

+0

あなたは問題を解決しましたか?ありがとう – SERG

答えて

4

オフセットパスはかなりトリッキーなグレードってこんなモンです。この論文(科学論文のアラート)は、「プロフェッショナル」なオフセットアルゴリズムのためのステップをよく説明しています。

http://cgcad.thss.tsinghua.edu.cn/~yongjh/papers/CiI2007V58N03P0240.pdf

+0

うわー....それは私の頭の上の方法です、私は大学に留まるべきだったと思います!まあ、私は今持っているもので遊んでいきますが、情報に感謝します。 – Ben

0

あなたはデモのように空想のように何かをしたいとは思われません。私が収集したものから、同じポリラインが必要なだけで、いくつかのピクセルが右に移動し、一部が上に移動するだけで重なり合わないようになりました。

投稿したコードには、latLngToPoint関数とpointToLatLng関数があります。Googleからの指示はLatLngなので、それらをポイントに変換し、xプロパティとyプロパティを増やして、LatLngに戻してポリラインを描画することができます。

これは、元の行の次の行を取得するはずです。しかし、それはデモのものと同じように見えません。それ以来、スムースラインに任意のポイントを追加することはありません。

+0

まあ、あなたはその音を本当にシンプルにしました....しかし、私はeaxactly xとyに追加することはできません。私はすでにポイント変換関数を使用しています。つまり、チャドウィックのデモの全体の基礎です。単純にx、yポイントに任意の数値を追加すると、重なり合う線で終わりますが、実際にはそのパスにはまったく追従しません。実際には、各点の対のポリラインを計算し、そのポリラインの(正接?)を計算して、どの方向をオフセットする必要があるかを調べる必要があります。あなたがちょっとだけ相殺しているなら、これは素晴らしいことです。しかし、あなたが\ _ /: – Ben

+0

のようなカーブを持っていると、ある距離離れてオフセットしていると、すべてのロジックが壊れます。あなたは曲線の正確なコピーを作っていないので...距離をずらしてオフセットするときは、それをスケーリングするのと同じようになります。 – Ben

+0

おそらく、クロスオーバのように、線の方向が変わったときを検出することができます。ここに示した例があります:http://img855.imageshack.us/img855/4063/crossover.png – Halcyon