2

I am trying to create a polygon around an existing polyline. I thought of drawing polylines parallel to the existing polyline and then joining them to create a polygon. I tried unsuccessfully to do the math to draw the parallel lines. I found this link which I used to create the polylines on either sides.

http://wtp2.appspot.com/ParallelLines.htm

It seemed exactly what I was looking for. I started the conversion from v2 to v3. I tried to keep to minimal code and deleted the rest. I have also removed the listener for change in zoom level which was present in the original code.

It worked perfectly when I used a small fixed polyline. However when I increased the size of the polyline the parallel polylines began to go haywire.

The code that I have is :

    var points = null;
    var map;
    var line1;
    var line2;
    var prj = null;
    var idlelistener;
    var gapPx = 2;
    var weight = 4; 

    function BDCCParallelLines(maps, point, bounds) {   

        map = maps;
        points = point;
        //map.fitBounds(bounds);
        MyOverlay.prototype = new google.maps.OverlayView();
    MyOverlay.prototype.onAdd = function() { }
    MyOverlay.prototype.onRemove = function() { }
    MyOverlay.prototype.draw = function() { }
    function MyOverlay(map) { this.setMap(map); }

    var overlay = new MyOverlay(map);
    // Wait for idle map
    idlelistener = google.maps.event.addListener(map, 'idle', function() {
       // Get projection
       prj = overlay.getProjection();
       recalc();    
    })
    }

    function recalc() {
        google.maps.event.removeListener(idlelistener);
       var zoom = this.map.getZoom();

       //left and right swapped throughout!

       var pts1 = new google.maps.MVCArray();//left side of center 
       var pts2 = new google.maps.MVCArray();//right 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+=2){


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

          var p1 = this.prj.fromLatLngToContainerPixel(this.points.getAt(i-1),zoom) //**fromLatLngToPixel
          var p2 = this.prj.fromLatLngToContainerPixel(this.points.getAt(i),zoom) //**fromLatLngToPixel
          var theta = Math.atan2(p1.x-p2.x,p1.y-p2.y) + (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); //GPoint
          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.prj.fromContainerPixelToLatLng(p1l),zoom); //**fromPixelToLatLng
            pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom); //**fromPixelToLatLng
          }
          else{ // mid points

            if(theta == thetam1){
                // adjacent segments in a straight line 
                pts1.push(this.prj.fromContainerPixelToLatLng(p1l),zoom);
                pts2.push(this.prj.fromContainerPixelToLatLng(p1r),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.prj.fromContainerPixelToLatLng(p2lm1),zoom);
                   pts1.push(this.prj.fromContainerPixelToLatLng(new google.maps.Point(p1.x+(s*dlxi),p1.y+(s*dlyi))),zoom);
                   pts1.push(this.prj.fromContainerPixelToLatLng(p1l));
                }
            else if (di < dl){
                   pts1.push(this.prj.fromContainerPixelToLatLng(pli),zoom);
            }
                else{
                   pts1.push(this.prj.fromContainerPixelToLatLng(p2lm1),zoom);
                   pts1.push(this.prj.fromContainerPixelToLatLng(p1l),zoom);
            }

                dxi = (pri.x-p1.x)*(pri.x-p1.x);
                dyi = (pri.y-p1.y)*(pri.y-p1.y);
                if(dTheta > Math.PI){
                   //intersect point on outside bend
                   pts2.push(this.prj.fromContainerPixelToLatLng(p2rm1),zoom);
                   pts2.push(this.prj.fromContainerPixelToLatLng(new google.maps.Point(p1.x+(s*drxi),p1.y+(s*dryi))),zoom);
                   pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom);
                }
            else if(di<dl)
                   pts2.push(this.prj.fromContainerPixelToLatLng(pri),zoom);
                else{
                   pts2.push(this.prj.fromContainerPixelToLatLng(p2rm1),zoom);
                   pts2.push(this.prj.fromContainerPixelToLatLng(p1r),zoom);
            }
            }
          }

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

       pts1.push(this.prj.fromContainerPixelToLatLng(p2l),zoom);//final point
       pts2.push(this.prj.fromContainerPixelToLatLng(p2r),zoom);

       this.line1 = new google.maps.Polyline({
              map:           map,
              path:          pts1,
              strokeColor:   "#0000FF",
              strokeWeight:  4,
              strokeOpacity: 1.0
        });


       this.line2 = new google.maps.Polyline({
            map:           map,
                      path:          pts2,
                      strokeColor:   "#0000FF",
                      strokeWeight:  4,
                      strokeOpacity: 1.0
        });*/

       createPolygon(pts1,pts2);
    }

    function intersect(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)); // ** CHANGED HERE

    }

    function createPolygon(side1,side2){
        var a = new Array();
        for(var i = 0; i < side1.length;i++){
            a.push(side1.getAt(i))
        }
        for(var i = side1.length-1; i >=0;i--){
            a.push(side2.getAt(i));
        }
        drawPolylinePolygon(a)  
    }

    function drawPolylinePolygon(a){
        a.push(a[0]);
        var color = getColor(false);
          var polygon_options = {
                paths: a,
                strokeColor: color,
                strokeOpacity: 0.7,
                strokeWeight: 2,
                fillColor: color,
                fillOpacity: 0.2
          };
          current_polygon = new google.maps.Polygon(polygon_options);
          current_polygon.setMap(map);
    }

The createPolygon() function is used to merge the two polylines to create a polygon.

This is the html page :

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">

    <head>
    <title></title>


    <script src="http://maps.google.com/maps/api/js?sensor=true&libraries=drawing,geometry" type="text/javascript"></script>
    <script src="BDCCParallelLines.js" type="text/javascript"></script>

    <script type="text/javascript">
        //<![CDATA[

    var map;

    function linesMap(){

            var latlng1 = new google.maps.LatLng(51.42, -0.95);
            var mapOptions = {zoom: 22, center:latlng1, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: false};
            var map = new google.maps.Map(document.getElementById('mapLines'),mapOptions);

            var pts = new Array();
            var latlngbounds = new google.maps.LatLngBounds();
            pts.push (new google.maps.LatLng(51.42, -0.97));
            latlngbounds.extend(new google.maps.LatLng(51.42, -0.97));
            pts.push (new google.maps.LatLng(51.43, -0.96));
            latlngbounds.extend(new google.maps.LatLng(51.43, -0.96));
            pts.push (new google.maps.LatLng(51.425, -0.955));
            latlngbounds.extend(new google.maps.LatLng(51.425, -0.955));
            pts.push (new google.maps.LatLng(51.42, -0.95));//straight at zoom = 13
            latlngbounds.extend(new google.maps.LatLng(51.42, -0.95));
            pts.push (new google.maps.LatLng(51.43, -0.94));
            latlngbounds.extend(new google.maps.LatLng(51.43, -0.94));
            pts.push (new google.maps.LatLng(51.43, -0.9375));//horz & straight
            latlngbounds.extend(new google.maps.LatLng(51.43, -0.9375));
            pts.push (new google.maps.LatLng(51.43, -0.935));
            latlngbounds.extend(new google.maps.LatLng(51.43, -0.935));
            pts.push (new google.maps.LatLng(51.425, -0.935));
            latlngbounds.extend(new google.maps.LatLng(51.425, -0.935));
            pts.push (new google.maps.LatLng(51.42, -0.935));//vert & straight
            latlngbounds.extend(new google.maps.LatLng(51.42, -0.935));


            var poly = new BDCCParallelLines(map,pts,latlngbounds);

            var poly2 = new google.maps.Polyline({
                      map:           map,
                      path:          pts,
                      strokeColor:   "#FF0000",
                      strokeWeight:  2,
                      strokeOpacity: 1.0
                });
    }


        //]]>

    </script>
    </head>

    <body     onload="linesMap();"
    style="font-weight: bold; font-size: large; font-family: Arial; background-color: #cccc99">
                    <div id="mapLines" style="width: 800px; height: 600px">
                    </div>
    </body>
    </html>

After searching I came across this article where Ben seems to have the same problem. The image on the link shows the exact same problem I'm having. Google maps api parallel path lines

I would like to know if there is any way that I can improve on the existing code for the parallel polylines or if there is any other way the end result I am looking for is a polygon around the polyline.

Community
  • 1
  • 1
Joyson
  • 3,025
  • 1
  • 20
  • 34
  • What is the purpose of the polygon? Would something like what [RouteBoxer](http://google-maps-utility-library-v3.googlecode.com/svn/trunk/routeboxer/docs/reference.html) does work? – geocodezip Sep 24 '12 at 13:23
  • @user1694185 Please trim the code samples to only cover the topic in question so it's both easier to read and to find a general answer. – Mikulas Dite Sep 24 '12 at 20:08
  • @geocodezip - I had checked the RouteBoxer but that won't work for me. I'm letting the user draw a polyline on the map and after that I want to create a polygon as I want to check if a user with gps is entering or exiting the polygon. I already have the javascript code for checking entry and exit. – Joyson Sep 25 '12 at 04:31
  • @MikulasDite - Thanks for pointing that out. I'm new here so I thought that putting up the entire code would help others understand the flow and also allow them to test it. – Joyson Sep 25 '12 at 04:31

1 Answers1

-1

You should use a Buffer-function that exists in any spatial-API or database, one example are sharpmap.

Ulrik
  • 546
  • 1
  • 5
  • 21
  • Thanks for the link. I was looking for a function in javascript as I was looking to do the calculations on the client side rather than the server to minimize the load. However I will test NTS and let you know. – Joyson Sep 25 '12 at 04:51
  • Ok, I was reading to fast, [here](http://gis.stackexchange.com/questions/31027/creating-a-polyline-buffer-in-openlayers) is a related question – Ulrik Sep 25 '12 at 11:13