Несколько кругов-> Один Полигон?

Используя Google Maps API v3, я смог создать несколько google.maps.Circle объекты на моей карте. Однако я теперь должен "соединить" их так или иначе. У меня есть следующая карта с несколькими кругами:

Map with multiple circles

Я теперь должен заставить это выглядеть примерно так:

Correct map
(источник: pcwp.com)

Я посмотрел на всем протяжении Интернета для решений, но напрасно. Какие-либо идеи?

7
задан Glorfindel 22 July 2019 в 11:14
поделиться

2 ответа

Если это всегда последовательность кругов вдоль линии, вы можете обработать пара соседних кругов за раз, найдите две прямые, которые касаются их обоих, и соедините их пересечениями, чтобы образовать один непрерывный путь. Добавьте несколько интерполированных контрольных точек Безье для плавности.

Это может сломаться, если ваша цепочка кругов не такая аккуратная, как в первом посте (много перекрытий, круги внутри кругов и т. Д.), Но это только начало.

4
ответ дан 6 December 2019 в 21:11
поделиться

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

Начнем с воссоздания вашей карты:

<!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 - Рис. 1 http://img186.imageshack.us/img186/1197/mp1h.png

Я предполагаю, что вы уже достигли этой точки, и поэтому приведенный выше пример не требует пояснений. По сути, мы только что определили 6 точек вместе с 6 радиусами, и мы визуализировали круги на карте вместе с зеленым путем.

Прежде чем мы продолжим, нам нужно определить несколько методов, чтобы иметь возможность вычислять расстояние и пеленг от одной точки до другой. Нам также понадобится метод, который будет возвращать точку назначения при задании пеленга и пройденного расстояния от исходной точки.К счастью, есть очень хорошая реализация этих методов на JavaScript, написанная Крисом Венессом в Вычислить расстояние, азимут и многое другое между точками широты / долготы . Следующие методы были адаптированы для работы с 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)));
}

Затем нам нужно будет добавить еще один цикл, который отображает промежуточные круги внутри цикла for , который мы ранее использовался для рендеринга исходных кругов. Вот как это может быть реализовано:

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

Вот что мы получили бы:

Google Maps Cyclones - Figure 2

И вот как это будет выглядеть без черной обводки вокруг исходных кругов:

Циклоны Google Maps - Рисунок 3 http: // img181.imageshack.us/img181/2908/mp3t.png

Как вы могли заметить, основная задача будет заключаться в том, чтобы визуализировать круги с постоянной непрозрачностью, даже если они перекрывают друг друга. Есть несколько способов добиться этого, но это может стать темой другого вопроса.

В любом случае полная реализация этого примера приведена ниже:

<!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
ответ дан 6 December 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: