1

I have two locations between which I have to draw a curved line based on a radius. I have drawn an image:

enter image description here

I know how to draw a circle. But how to draw only a part of the circle?

The following are the known parameters:

  • Current Location
  • Next Location
  • Radius of the curve/circle

If someone can tell me how to get the points along the circle between the Current Location and Next Location, I can use polyline to plot the curve. But how to compute the locations?

Abhishek
  • 2,925
  • 4
  • 34
  • 59

2 Answers2

1

You con use this Answer to draw arc.

To find center for arc.

You can use Google Geometry library to find length of chord between 2 markers,its bearing and position of the cente of arc.

From documentation

computeDistanceBetween(from:LatLng, to:LatLng, radius?:number) Returns the distance between two LatLngs as a number in meters. The radius defaults to the Earth's radius in meters(6378137).

computeHeading(from:LatLng, to:LatLng) Returns the heading from one LatLng to another LatLng. Headings are expressed in degrees clockwise from North within the range [-180,180) as a number.

computeOffset(from:LatLng, distance:number, heading:number, radius?:number) Returns the LatLng resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north) as LatLng.

First find distance between 2 markers

var spherical = google.maps.geometry.spherical; 
var point1 = markers[0].getPosition();
var point2 = markers[1].getPosition();
var length = google.maps.geometry.spherical.computeDistanceBetween(point1,point2);

Then find bearing

 var heading = google.maps.geometry.spherical.computeHeading(point1,point2);

triangle

As you now know the 3 sides of triangle (chord length,radius(other 2 sides) you calculate bearing of center of arc using law of cosines.(Note there are 2 solutions as discuused in comments)

    function solveAngle(a, b, c) {  // Returns angle C using law of cosines
    var temp = (b * b + c * c - a * a) / (2 * b * c);
    if (temp >= -1 && temp <= 1)
        return Math.acos(temp);
    else
        throw "No solution";
   }

var baseAngle = solveAngle(radius, radius, c);
var vertexAngle = solveAngle(c,radius,radius);

baseAngle is used to find bearing of center point.

vertexAngle is used number of points when drawing arc.

Knowing bearing and radius you can find center of arc.

var centerPoint = spherical.computeOffset(point1,radius,heading+baseAngle);

Note Distances in meters. change radius in methods to 3,959 for miles.

If the radius changes the center changes. The yellow dot is 2 times the radius of blue dot

arc test

Community
  • 1
  • 1
david strachan
  • 7,174
  • 2
  • 23
  • 33
  • Hi David. I took your snippet as example and tried in my code. But I find that the center point is being computed near point 2. – Abhishek Aug 01 '14 at 04:14
  • How is the heading of a line computed in google maps? – Abhishek Aug 01 '14 at 04:16
  • On what basis is the direction of the center computed? When I try, I always get to the right. – Abhishek Aug 01 '14 at 05:43
  • For my first comment, I got the solution. I didn't know that Math.acos()returns in radians. Can you help me with the other issue. The center of the circle is on the right side. How and why? – Abhishek Aug 01 '14 at 06:21
  • When the radius is changed, i.e. the values of a,b are increased, the center should be a point farther from previous point, but with same heading. But when I increase the radius, the center heading also changes. – Abhishek Aug 01 '14 at 10:09
  • No the heading will change when the radius changes. Try it on paper to see – david strachan Aug 01 '14 at 10:42
  • But if the heading changes then the center will be wrong – Abhishek Aug 01 '14 at 10:58
  • Hi David. Thank you for making necessary changes to your answer. It worked for me. But what I am saying is, when point1 and point2 are kept same, and radius is increased, the heading value changes because of which the center computed is not correct. – Abhishek Aug 01 '14 at 11:23
  • As per your solution, the two centers wont have same heading – Abhishek Aug 01 '14 at 11:39
  • @Abhishek I initially had formula for wrong angle. I have changed it and you can see from the image that the bearing of the 2 center points are different.email me if you have any other issues – david strachan Aug 01 '14 at 23:07
  • Hi David. Can I get your e-mail address? Can't find it on your profile. – Abhishek Aug 04 '14 at 03:50
  • Hi David. Check the solution I posted. This is what I wanted. – Abhishek Aug 05 '14 at 08:55
1

I found a solution for my question.

What I did was

  • Get the distance between the two points (current location and next location)
  • Calculate the value of the sagitta 's' of the curve.
  • Compute the mid-point of the current location and next location.
  • Compute the heading of line current location and next location.
  • From mid-point, with heading = heading computed in above step + 90 (if you want the center to be on right side of the line) or heading = heading computed in above step - 90 (if you want the center to be on left side of the line) and distance = radius - sagitta, compute offset point. enter image description here

The sagitta can be computed using the formula:

enter image description here

where,

l is half of the distance between current location and next location

r is radius of curve

s is the sagitta

The code I used is:

function DrawCurvedLine(startLatitude, startLongitude, endLatitude, endLongitude, roc, lineColor) {
    var distance;
    var latLng1, latLng2;
    var sagitta;
    var midPoint;
    var heading;
    var roc;
    var center;
    var arc = new Array();

    curvePoints = [];
    // Create current and predicted latlng objects
    latLng1 = new google.maps.LatLng(startLatitude, startLongitude);
    latLng2 = new google.maps.LatLng(endLatitude, endLongitude);

    // Compute the distance between current location and predicted location
    distance = google.maps.geometry.spherical.computeDistanceBetween(currentLatLng, predictedLatLng);
    sagitta = computeSagitta(roc, (distance / 2));
    midPoint = getMidPoint(latLng1, latLng2);
    heading = google.maps.geometry.spherical.computeHeading(latLng1, latLng2);
    heading = headingClPl + 90;

    center = google.maps.geometry.spherical.computeOffset(midPoint, (roc - sagitta), headingClPl);

    var Heading1 = google.maps.geometry.spherical.computeHeading(center, latLng1);
    var Heading2 = google.maps.geometry.spherical.computeHeading(center, latLng2);

    var i = 0;
    while ((Heading1 + i) <= Heading2 || (Heading2 + i) <= Heading1) {
        if (radiusOfCurve < 0) {
            arcPts.push(google.maps.geometry.spherical.computeOffset(centerOfCurve, roc, Heading1 - i));
        }
        else {
            arcPts.push(google.maps.geometry.spherical.computeOffset(centerOfCurve, roc, Heading1 + i));
        }
        i++;
    }

    var curvedLine = new google.maps.Polyline({
        path: arcPts,
        icons: [{
            icon: {
            path: google.maps.SymbolPath.FORWARD_OPEN_ARROW,
            scale: 3,
            strokeColor: lineColor,
            strokeOpacity: 1,
            strokeWeight: 1.3,
            fillColor: 'transparent',
            fillOpacity: 0
            },
            offset: '100%'
        }],
        strokeColor: lineColor,
        strokeOpacity: 0.5,
        strokeWeight: 2,
        map: map
    });

    function computeSagitta(radius, length){
        // radius is radius of circle. length is the half length of chord
        return (radius - (Math.sqrt((radius * radius) - (length * length))));
    }
Abhishek
  • 2,925
  • 4
  • 34
  • 59