A few laps & # 8594; One landfill?

Using the Google Maps API v3, I was able to create several google.maps.Circle objects on the map. However, now I need to somehow connect them. I have the following map with several circles:

Map with multiple circles

Now I need it to look something like this:

Correct map
(source: pcwp.com )

I searched for solutions all over the Internet, but to no avail. Any ideas?

+7
javascript geometry google-maps google-maps-api-3 circle bezier
source share
2 answers

You might want to solve this problem by adding extra circles at x intervals with increasing radii between each waypoint. This would be very easy to implement and would work for any direction of the cyclone. Obviously, Matti proposed a solution to create a polygon, connecting all the tangents would be more accurate, but you can consider this as a possible alternative. The main disadvantage is that it may take some effort to make it look beautiful, and it will obviously use more resources on the client side than if you were displaying one polygon.

Let's start by re-creating your map:

 <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Cyclones</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> </head> <body> <div id="map" style="width: 600px; height: 400px"></div> <script type="text/javascript"> var i; var mapOptions = { mapTypeId: google.maps.MapTypeId.TERRAIN, center: new google.maps.LatLng(28.50, -81.50), zoom: 5 }; var map = new google.maps.Map(document.getElementById("map"), mapOptions); var pathPoints = [ new google.maps.LatLng(25.48, -71.26), new google.maps.LatLng(25.38, -73.70), new google.maps.LatLng(25.28, -77.00), new google.maps.LatLng(25.24, -80.11), new google.maps.LatLng(25.94, -82.71), new google.maps.LatLng(27.70, -87.14) ]; pathPoints[0].radius = 80; pathPoints[1].radius = 100; pathPoints[2].radius = 200; pathPoints[3].radius = 300; pathPoints[4].radius = 350; pathPoints[5].radius = 550; new google.maps.Polyline({ path: pathPoints, strokeColor: '#00FF00', strokeOpacity: 1.0, strokeWeight: 3, map: map }); for (i = 0; i < pathPoints.length; i++) { new google.maps.Circle({ center: pathPoints[i], radius: pathPoints[i].radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeOpacity: 0.5, strokeWeight: 1, map: map }); } </script> </body> </html> 

Google Maps Cyclones - Figure 1 http://img186.imageshack.us/img186/1197/mp1h.png

I assume that you have already reached this point, and therefore the above example is self-explanatory. In fact, we just identified 6 points along with 6 radii, and we drew circles on the map along with the green track.

Before continuing, we need to define several methods so that we can calculate the distance and direction from one point to another. We will also need a method that will return the destination if there is a bearing and the distance traveled from the starting point. Fortunately, Chris Veness offers a very good JavaScript implementation for these methods in the section Calculating the distance, bearing, and other points between latitude and longitude . The following methods have been adapted to work with Google google.maps.LatLng :

 Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) ); var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); } google.maps.LatLng.prototype.bearingTo = function(point) { var lat1 = this.lat().toRad(), lat2 = point.lat().toRad(); var dLon = (point.lng()-this.lng()).toRad(); var y = Math.sin(dLon) * Math.cos(lat2); var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); var brng = Math.atan2(y, x); return ((brng.toDeg()+360) % 360); } google.maps.LatLng.prototype.distanceTo = function(point) { var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = point.lat().toRad(), lon2 = point.lng().toRad(); var dLat = lat2 - lat1; var dLon = lon2 - lon1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); } 

Then we would need to add another loop that renders the intermediate circles inside the for loop that we used earlier to render the original circles. Here's how to do it:

 var distanceStep = 50; // Render an intermediate circle every 50km. for (i = 0; i < pathPoints.length; i++) { new google.maps.Circle({ center: pathPoints[i], radius: pathPoints[i].radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeOpacity: 0.5, strokeWeight: 1, map: map }); if (i < (pathPoints.length - 1)) { distanceToNextPoint = pathPoints[i].distanceTo(pathPoints[i + 1]); bearingToNextPoint = pathPoints[i].bearingTo(pathPoints[i + 1]); radius = pathPoints[i].radius; radiusIncrement = (pathPoints[i + 1].radius - radius) / (distanceToNextPoint / distanceStep); for (j = distanceStep; j < distanceToNextPoint; j += distanceStep, radius += radiusIncrement) { new google.maps.Circle({ center: pathPoints[i].destinationPoint(bearingToNextPoint, j), radius: radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeWeight: 0, map: map }); } } } 

Here is what we would get:

Google Maps Cyclones - Figure 2

And this is how it would have looked without black strokes around the original circles:

Google Maps Cyclones - Figure 3 http://img181.imageshack.us/img181/2908/mp3t.png

As you can see, the main task will be to make the circles opaque, even if they overlap. There are several options for achieving this, but this may be the subject of another question.

In any case, the following implementation is the full implementation for this example:

 <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Cyclones</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> </head> <body> <div id="map" style="width: 600px; height: 400px"></div> <script type="text/javascript"> Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) ); var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); } google.maps.LatLng.prototype.bearingTo = function(point) { var lat1 = this.lat().toRad(), lat2 = point.lat().toRad(); var dLon = (point.lng()-this.lng()).toRad(); var y = Math.sin(dLon) * Math.cos(lat2); var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); var brng = Math.atan2(y, x); return ((brng.toDeg()+360) % 360); } google.maps.LatLng.prototype.distanceTo = function(point) { var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = point.lat().toRad(), lon2 = point.lng().toRad(); var dLat = lat2 - lat1; var dLon = lon2 - lon1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2); return 6371 * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); } var i; var j; var distanceToNextPoint; var bearingToNextPoint; var radius; var radiusIncrement; var distanceStep = 50; // Render an intermediate circle every 50km. var mapOptions = { mapTypeId: google.maps.MapTypeId.TERRAIN, center: new google.maps.LatLng(28.50, -81.50), zoom: 5 }; var map = new google.maps.Map(document.getElementById("map"), mapOptions); var pathPoints = [ new google.maps.LatLng(25.48, -71.26), new google.maps.LatLng(25.38, -73.70), new google.maps.LatLng(25.28, -77.00), new google.maps.LatLng(25.24, -80.11), new google.maps.LatLng(25.94, -82.71), new google.maps.LatLng(27.70, -87.14) ]; pathPoints[0].radius = 80; pathPoints[1].radius = 100; pathPoints[2].radius = 200; pathPoints[3].radius = 300; pathPoints[4].radius = 350; pathPoints[5].radius = 550; new google.maps.Polyline({ path: pathPoints, strokeColor: '#00FF00', strokeOpacity: 1.0, strokeWeight: 3, map: map }); for (i = 0; i < pathPoints.length; i++) { new google.maps.Circle({ center: pathPoints[i], radius: pathPoints[i].radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeOpacity: 0.5, strokeWeight: 0, map: map }); if (i < (pathPoints.length - 1)) { distanceToNextPoint = pathPoints[i].distanceTo(pathPoints[i + 1]); bearingToNextPoint = pathPoints[i].bearingTo(pathPoints[i + 1]); radius = pathPoints[i].radius; radiusIncrement = (pathPoints[i + 1].radius - radius) / (distanceToNextPoint / distanceStep); for (j = distanceStep; j < distanceToNextPoint; j += distanceStep, radius += radiusIncrement) { new google.maps.Circle({ center: pathPoints[i].destinationPoint(bearingToNextPoint, j), radius: radius * 1000, fillColor: '#FF0000', fillOpacity: 0.2, strokeWeight: 0, map: map }); } } } </script> </body> </html> 
+8
source share

If it is always a line of circles along a line, you can process a pair of adjacent circles at a time, find two lines that touch each other, and connect them at their intersections to make one continuous path. Add the smoothness of the interpolated bezier control points.

This may break if your circle line is not as neat as the first in your first post (lots of overlap, circles inside circles, etc.), but this is the beginning.

+4
source share

All Articles