Гугл карты api параллельные пути - PullRequest
3 голосов
/ 15 ноября 2011

Я работаю над своего рода картографическим маршрутом для упакованных каникул, и я действительно доволен тем, что я сделал до сих пор;У меня есть API-интерфейсы, реализованные с помощью специального средства визуализации, так что я могу взять направления движения и построить собственную ломаную линию со стрелками направления, которые не являются ужасными стрелками Google, расположенными вдоль пути.Я не совсем математик, и я пытаюсь понять, как я могу сделать путь, параллельный другому пути.Например, маршрут идет из города 1 в город 2, а затем обратно в город 1.

Я хочу сместить поездку обратно к полилинии города 1, чтобы она отражала путь, но проходила параллельно ей,В идеале я хотел бы, чтобы при создании пути я проверял наличие пересекающихся точек в других путях и, если они были найдены, смещал путь только в этих точках.Это было бы лучшей реализацией, потому что вы могли бы, например, параллелить путь только там, где он пересекает другой, например, когда он встречает другой путь только в течение короткого времени.

Я нашел этот код для API2 из счетаchadwick

Ссылка здесь: http://wtp2.appspot.com/ParallelLines.htm

Обновление: каким-то образом удалось преобразовать этот старый скрипт v2, чтобы он работал в v3, но у меня возникли некоторые проблемы ...

Это больше, чем удвоение исходного количества точек и следование по пути, но на самом деле их случайное добавление.Снимок экрана здесь:

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));

}

Это работает до некоторой степени ... Это работает так же, как иоригинальная реализация.Весь путь пересчитывается на основе масштабирования, и я вроде взломал функцию пропуска очень коротких путей (странных углов) при более высоком уровне масштабирования, чем он ближе, тем больше масштаб.

IЯ бы предпочел просто иметь фиксированное смещение расстояния, которое не пересчитывается, так как оно довольно интенсивное ... Есть много программ, которые выполняют этот подвиг, rhino3d, autocad, illustrator ... Я чувствую, что это было бы здорово для направления движения в Googleкарты, смещение пути, чтобы вы могли различить обратную поездку и исходную поездку.

Если бы кто-нибудь сделал что-то подобное в JS, даже если это не для карт Google, я бы очень хотел увидетьЭто.Ссылки, которые я расследую:

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

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

Ответы [ 2 ]

4 голосов
/ 16 ноября 2011

Смещение траекторий в целом довольно сложное дело.Эта статья (научная статья) дает хорошее описание шагов, предпринятых для «профессиональных» алгоритмов смещения.

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

0 голосов
/ 21 ноября 2011

Вы, кажется, не хотите ничего такого фантастического, как в демоверсии. Исходя из того, что я понял, вам нужна та же ломаная линия, смещенная только на несколько пикселей вправо и, возможно, на вершину, чтобы она не перекрывалась.

Код, который вы опубликовали, имеет функцию latLngToPoint и функцию pointToLatLng. Я думаю, что направления, которые вы получаете от Google - это LatLng, поэтому вы можете преобразовать их в Точки, увеличить свойство x и y, а затем преобразовать его обратно в LatLng и нарисовать вашу Полилинию.

Это должно дать вам линию, которая точно следует исходной линии. Но это будет выглядеть не так красиво, как в демоверсии. Так как он не будет добавлять какие-либо точки к гладкой линии.

...