3

我正在为打包假期开发一种行程映射器,我对到目前为止所做的工作感到非常满意;我有使用自定义渲染器实现的方向 api,因此我可以获取行车路线,并绘制我自己的折线,并绘制完整的方向箭头,这些箭头不是沿路径间隔的谷歌可怕的箭头。我不完全是数学专家,我正试图弄清楚如何使一条路径与另一条路径平行。例如,行程从城市 1 到城市 2,然后返回城市 1。

我想抵消返回城市 1 的折线的行程,以便它反映路径,但平行于它。理想情况下,我想在创建路径时检查其他路径中的交叉点,如果找到,则仅在这些点处偏移路径。这将是一个更好的实现,因为您可以例如仅在路径恰好与另一条​​路径相交的地方平行路径,例如当它仅在短时间内与另一条路径相遇时。

我从 bill chadwick 那里找到了 API2 的这段代码

链接在这里:http ://wtp2.appspot.com/ParallelLines.htm

更新:不知何故设法转换了这个旧的 v2 脚本以使其在 v3 中工作,但我遇到了一些麻烦......

它比原来的点数增加了一倍多,并遵循路径,但实际上是随机扔掉它们。截图在这里:

谷歌地图截图

我转换的课程在这里:

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......我觉得这对于驾驶方向来说会很棒谷歌地图本身,路径的偏移,因此您可以区分回程和原始行程。

如果有人在 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 并绘制您的折线。

这应该会为您提供一条完全遵循原始行的行。但是,它看起来不像演示中的那样花哨。因为它不会添加任何点来平滑线条。

于 2011-11-21T17:36:43.943 回答