3

私はパッケージ化された休暇のための一種の旅程マッパーに取り組んでおり、これまでに行ったことに本当に満足しています。カスタムレンダラーで実装された方向APIを持っているので、運転方向を取得し、パスに沿って配置されたGoogleのひどいものではない方向矢印で完成した独自のポリラインをプロットできます。私は正確には数学の専門家ではなく、別のパスに平行なパスを作成する方法を見つけようとしています。たとえば、旅程は都市 1 から都市 2 に行き、その後都市 1 に戻ります。

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

Bill Chadwick から API2 のこのコードを見つけました

リンクはこちら: http://wtp2.appspot.com/ParallelLines.htm

更新: どういうわけか、この古い v2 スクリプトを変換して v3 で動作させることができましたが、いくつかの問題が発生しています...

元のポイント数の 2 倍以上で、パスをたどっていますが、実際にはランダムにそれらを投入しています。スクリーンショットはこちら:

Google マップのスクリーンショット

変換したクラスは次のとおりです。

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、autocad、illustratorがあります...グーグルマップ自体、経路のオフセットであるため、帰りの旅行と元の旅行を区別できます。

特にGoogleマップ用でなくても、JSでこれと同様のことをしたことがある人がいれば、ぜひ見てみたいです。私が調査しているリンク:

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

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

4

2 に答える 2

4

一般にパスをオフセットすることは、かなりトリッキーなビジネスです。この論文 (科学論文の警告) は、「専門的な」オフセット アルゴリズムの手順について適切に説明しています。

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

于 2011-11-16T00:05:44.170 に答える
0

デモのように凝ったものは必要ないようです。私が収集したものから、同じポリラインが必要なだけで、一部のピクセルを右に、おそらく一部を上にシフトして、重複しないようにします。

投稿したコードには、latLngToPoint 関数と pointToLatLng 関数があります。Google から取得した方向は LatLng だと思います。そのため、それらをポイントに変換し、x プロパティと y プロパティを増やして、LatLng に変換し直して、Polyline を描画できます。

これにより、元の行に正確に従う行が得られるはずです。ただし、デモのように派手には見えません。ラインを滑らかにするためにポイントを追加することはないので。

于 2011-11-21T17:36:43.943 に答える