当孔与多边形的边界重叠时,小叶js填充颜色错误

时间:2018-02-08 18:17:59

标签: javascript maps leaflet

我在传单js地图中定义了一个多边形(在bing地图上) 该多边形有两个孔(黄色多边形)。 SECOND 孔多边形与主多边形的外边界重叠。

enter image description here

问题:

SECOND 多边形延伸到主多边形外边缘的部分获取主多边形的填充颜色。

在这种情况下,主要多边形是红色,并且整个被移除的是黄色

我已在附图中圈出了这个问题。

以下是fiddle where I have recreated the issue

问题

有人可以帮我弄清楚如何从红色多边形中删除第二个黄色形状的部分而没有这种重叠颜色问题吗?

为清楚起见,这里是小提琴的所有代码:

#ifdef __cplusplus

你只需要在html页面上瘦:

并链接到leaflet.js和.css cdn

1 个答案:

答案 0 :(得分:1)

您的外环(即RED多边形定义中的第一个多边形数组)应绑定几何体,包括孔。

在您当前的定义中,第二个孔(即RED多边形定义中第二个多边形的第二个环)比外环延伸得更深(一些坐标的经度低于外环的最低点)。

这种不一致性使得渲染难以正确地表示带孔的多面体,导致孔的一部分被涂上填充颜色。

“简单”的解决方案是手动修改外圈,以便完全包含您的洞:

// Create the map
var map = L.map('map').setView([53.54, -113.9], 10);

// Set up the OSM layer
L.tileLayer(
  'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 18
  }).addTo(map);

//Create polygon YELLOW
var polyYellow = new L.Polygon([
  [
    [
      [53.716006, -113.252565],
      [53.715496, -113.228546],
      [53.717052, -113.215209],
      [53.734927, -113.197527],
      [53.753505, -113.172980],
      [53.768016, -113.168688],
      [53.774205, -113.157874],
      [53.774284, -113.148883],
      [53.715867, -113.149098],
      [53.715934, -113.172036],
      [53.686769, -113.172207],
      [53.686935, -113.196896],
      [53.367132, -113.197204],
      [53.366818, -113.221196],
      [53.337761, -113.220792],
      [53.337882, -113.801601],
      [53.367033, -113.807995],
      [53.367197, -113.836702],
      [53.716273, -113.836434]
    ],
    [
      [53.569268602609704, -113.71411800384523],
      [53.51214299292513, -113.71411800384523],
      [53.51214299292513, -113.68802547454835],
      [53.403391858715274, -113.6907720565796],
      [53.40461992848445, -113.64957332611085],
      [53.3960226956682, -113.64614009857179],
      [53.39684155458476, -113.34332942962648],
      [53.4471711023092, -113.35744857788087],
      [53.4471711023092, -113.24483871459962],
      [53.57212285981298, -113.24445247650148],
      [53.58149977709897, -113.29389095306398],
      [53.58435320870081, -113.36118221282959],
      [53.62102302920731, -113.3447027206421],
      [53.646672964306994, -113.36942195892335],
      [53.64952199454264, -113.57116699218751],
      [53.669866612978275, -113.6345958709717],
      [53.65603334084723, -113.70188713073732],
      [53.57620003591595, -113.68678092956544]
    ]
  ],
  [
    [
      [53.555985, -114.002024],
      [53.555804, -114.038727],
      [53.541397, -114.038512],
      [53.541372, -114.050958],
      [53.512009, -114.050958],
      [53.512111, -114.026410],
      [53.505169, -114.026410],
      [53.505373, -113.971564],
      [53.512034, -113.971650],
      [53.512034, -113.959076],
      [53.520338, -113.959179],
      [53.519726, -113.885364],
      [53.541153, -113.885364],
      [53.541101, -113.845993],
      [53.571438, -113.846851],
      [53.570012, -113.885364],
      [53.571082, -113.916435],
      [53.569349, -113.959007],
      [53.555451, -113.959383]
    ]
  ]
], {
  color: 'yellow',
  opacity: 1,
  fillOpacity: 0.5
});

// CREATE POLYGONE RED
var polyRed = new L.Polygon([
  // First polygon.
  [
    // First ring = outer ring, must bound the surface.
    [
      [53.773877, -114.001813],
      [53.774105, -113.998508],
      [53.774105, -113.917720],
      [53.803400, -113.917398],
      [53.803575, -113.661065],
      [53.812242, -113.660379],
      [53.818221, -113.652482],
      [53.818221, -113.620124],
      [53.803575, -113.620124],
      [53.803499, -113.347294],
      [53.818120, -113.347380],
      [53.818145, -113.345062],
      [53.830178, -113.334934],
      [53.835015, -113.335750],
      [53.842232, -113.324506],
      [53.840485, -113.321759],
      [53.845245, -113.314550],
      [53.845448, -113.309958],
      [53.847321, -113.309271],
      [53.847296, -113.305537],
      [53.845827, -113.306310],
      [53.845827, -113.304164],
      [53.844030, -113.306267],
      [53.842283, -113.310601],
      [53.825365, -113.310601],
      [53.825340, -113.322317],
      [53.803524, -113.322961],
      [53.803244, -113.124330],
      [53.774265, -113.124223],
      [53.715852, -113.124309],
      [53.715846, -113.098581],
      [53.571181, -113.098811],
      [53.366714, -113.098865],
      [53.366702, -113.074291],
      [53.279625, -113.074530],
      [53.279664, -113.098670],
      [53.279606, -113.220582],
      [53.250595, -113.220603],
      [53.250582, -113.488503],
      [53.250531, -113.499918],
      [53.235790, -113.499918],
      [53.235892, -113.561716],
      [53.250531, -113.561716],
      [53.250556, -113.598323],
      [53.257720, -113.598452],
      [53.257771, -113.610425],
      [53.265139, -113.610468],
      [53.265062, -113.927419],
      [53.366600, -113.927333],
      [53.366715, -114.001904],
      // up to here, -114.001904 is the West-most longitude
      [53.505169, -114.001904], // Intersection point, manually built, but you can see a small gap.
      // Reversed order
      [53.505169, -114.026410], // More West than -114.001904
      [53.512111, -114.026410], // More West than -114.001904
      [53.512009, -114.050958], // More West than -114.001904
      [53.541372, -114.050958], // More West than -114.001904
      [53.541397, -114.038512], // More West than -114.001904
      [53.555804, -114.038727], // More West than -114.001904
      [53.555985, -114.002024], // More West than -114.001904
      [53.555985, -114.001813] // Intersection point, manually built
    ]
    // No other ring, therefore it should have no hole, but see 2nd polygon below.
  ],
  // Second polygon, incorrectly rendered by Leaflet as a hole.
  [
    // First ring = outer ring, but incorrectly rendered by Leaflet as 1st hole of 1st polygon.
    [
      [53.716006, -113.252565],
      [53.715496, -113.228546],
      [53.717052, -113.215209],
      [53.734927, -113.197527],
      [53.753505, -113.172980],
      [53.768016, -113.168688],
      [53.774205, -113.157874],
      [53.774284, -113.148883],
      [53.715867, -113.149098],
      [53.715934, -113.172036],
      [53.686769, -113.172207],
      [53.686935, -113.196896],
      [53.367132, -113.197204],
      [53.366818, -113.221196],
      [53.337761, -113.220792],
      [53.337882, -113.801601],
      [53.367033, -113.807995],
      [53.367197, -113.836702],
      [53.716273, -113.836434]
    ],
    // Second ring = hole.
    [
      [53.555985, -114.002024], // More West than -114.001904
      [53.555804, -114.038727], // More West than -114.001904
      [53.541397, -114.038512], // More West than -114.001904
      [53.541372, -114.050958], // More West than -114.001904
      [53.512009, -114.050958], // More West than -114.001904
      [53.512111, -114.026410], // More West than -114.001904
      [53.505169, -114.026410], // More West than -114.001904
      [53.505373, -113.971564],
      [53.512034, -113.971650],
      [53.512034, -113.959076],
      [53.520338, -113.959179],
      [53.519726, -113.885364],
      [53.541153, -113.885364],
      [53.541101, -113.845993],
      [53.571438, -113.846851],
      [53.570012, -113.885364],
      [53.571082, -113.916435],
      [53.569349, -113.959007],
      [53.555451, -113.959383]
    ]
  ]
], {
  color: 'red',
  opacity: 1,
  fillOpacity: 0.3
});

//Add polygons to map
polyRed.addTo(map);
polyYellow.addTo(map);
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>

<div id="map" style="height: 200px"></div>

顺便说一句,这突出了Leaflet的不一致性,它使用多边形定义的第一个多边形作为外环,第二个多边形的所有环作为第一个多边形的孔。而docs example坚持GeoJSON规范。这可能与Leaflet issue #3498有关。

更强大的解决方案是从外圈正确移除孔洞,例如:使用Turf.js difference

var outerRingLatLng = [
  [53.773877, -114.001813],
  [53.774105, -113.998508],
  [53.774105, -113.917720],
  [53.803400, -113.917398],
  [53.803575, -113.661065],
  [53.812242, -113.660379],
  [53.818221, -113.652482],
  [53.818221, -113.620124],
  [53.803575, -113.620124],
  [53.803499, -113.347294],
  [53.818120, -113.347380],
  [53.818145, -113.345062],
  [53.830178, -113.334934],
  [53.835015, -113.335750],
  [53.842232, -113.324506],
  [53.840485, -113.321759],
  [53.845245, -113.314550],
  [53.845448, -113.309958],
  [53.847321, -113.309271],
  [53.847296, -113.305537],
  [53.845827, -113.306310],
  [53.845827, -113.304164],
  [53.844030, -113.306267],
  [53.842283, -113.310601],
  [53.825365, -113.310601],
  [53.825340, -113.322317],
  [53.803524, -113.322961],
  [53.803244, -113.124330],
  [53.774265, -113.124223],
  [53.715852, -113.124309],
  [53.715846, -113.098581],
  [53.571181, -113.098811],
  [53.366714, -113.098865],
  [53.366702, -113.074291],
  [53.279625, -113.074530],
  [53.279664, -113.098670],
  [53.279606, -113.220582],
  [53.250595, -113.220603],
  [53.250582, -113.488503],
  [53.250531, -113.499918],
  [53.235790, -113.499918],
  [53.235892, -113.561716],
  [53.250531, -113.561716],
  [53.250556, -113.598323],
  [53.257720, -113.598452],
  [53.257771, -113.610425],
  [53.265139, -113.610468],
  [53.265062, -113.927419],
  [53.366600, -113.927333],
  [53.366715, -114.001904],
  [53.773877, -114.001813] // Finish by first position for GeoJSON compliancy.
];

var hole1LatLng = [
  [53.716006, -113.252565],
  [53.715496, -113.228546],
  [53.717052, -113.215209],
  [53.734927, -113.197527],
  [53.753505, -113.172980],
  [53.768016, -113.168688],
  [53.774205, -113.157874],
  [53.774284, -113.148883],
  [53.715867, -113.149098],
  [53.715934, -113.172036],
  [53.686769, -113.172207],
  [53.686935, -113.196896],
  [53.367132, -113.197204],
  [53.366818, -113.221196],
  [53.337761, -113.220792],
  [53.337882, -113.801601],
  [53.367033, -113.807995],
  [53.367197, -113.836702],
  [53.716273, -113.836434],
  [53.716006, -113.252565] // Finish by first position for GeoJSON compliancy.
];

var hole2LatLng = [
  [53.555985, -114.002024],
  [53.555804, -114.038727],
  [53.541397, -114.038512],
  [53.541372, -114.050958],
  [53.512009, -114.050958],
  [53.512111, -114.026410],
  [53.505169, -114.026410],
  [53.505373, -113.971564],
  [53.512034, -113.971650],
  [53.512034, -113.959076],
  [53.520338, -113.959179],
  [53.519726, -113.885364],
  [53.541153, -113.885364],
  [53.541101, -113.845993],
  [53.571438, -113.846851],
  [53.570012, -113.885364],
  [53.571082, -113.916435],
  [53.569349, -113.959007],
  [53.555451, -113.959383],
  [53.555985, -114.002024] // Finish by first position for GeoJSON compliancy.
];

var outerRing = turf.polygon([latLngArrayToLngLat(outerRingLatLng)]);
var holes = turf.multiPolygon([
  [latLngArrayToLngLat(hole1LatLng)],
  [latLngArrayToLngLat(hole2LatLng)]
]);
var result = turf.difference(outerRing, holes);
var resultGeoJSON = turf.getGeom(result);

var map = L.map('map');

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

var geojsonLayer = L.geoJSON(resultGeoJSON, {
  style: {
    color: 'red',
    opacity: 1,
    fillOpacity: 0.3
  }
}).addTo(map);
map.fitBounds(geojsonLayer.getBounds());


function latLngArrayToLngLat(latLngArray) {
  return latLngArray.map(latLngToLngLat);
}

function latLngToLngLat(latLng) {
  return [latLng[1], latLng[0]];
}

//Create polygon YELLOW
var polyYellow = new L.Polygon([
  [
    [
      [53.716006, -113.252565],
      [53.715496, -113.228546],
      [53.717052, -113.215209],
      [53.734927, -113.197527],
      [53.753505, -113.172980],
      [53.768016, -113.168688],
      [53.774205, -113.157874],
      [53.774284, -113.148883],
      [53.715867, -113.149098],
      [53.715934, -113.172036],
      [53.686769, -113.172207],
      [53.686935, -113.196896],
      [53.367132, -113.197204],
      [53.366818, -113.221196],
      [53.337761, -113.220792],
      [53.337882, -113.801601],
      [53.367033, -113.807995],
      [53.367197, -113.836702],
      [53.716273, -113.836434]
    ],
    [
      [53.569268602609704, -113.71411800384523],
      [53.51214299292513, -113.71411800384523],
      [53.51214299292513, -113.68802547454835],
      [53.403391858715274, -113.6907720565796],
      [53.40461992848445, -113.64957332611085],
      [53.3960226956682, -113.64614009857179],
      [53.39684155458476, -113.34332942962648],
      [53.4471711023092, -113.35744857788087],
      [53.4471711023092, -113.24483871459962],
      [53.57212285981298, -113.24445247650148],
      [53.58149977709897, -113.29389095306398],
      [53.58435320870081, -113.36118221282959],
      [53.62102302920731, -113.3447027206421],
      [53.646672964306994, -113.36942195892335],
      [53.64952199454264, -113.57116699218751],
      [53.669866612978275, -113.6345958709717],
      [53.65603334084723, -113.70188713073732],
      [53.57620003591595, -113.68678092956544]
    ]
  ],
  [
    [
      [53.555985, -114.002024],
      [53.555804, -114.038727],
      [53.541397, -114.038512],
      [53.541372, -114.050958],
      [53.512009, -114.050958],
      [53.512111, -114.026410],
      [53.505169, -114.026410],
      [53.505373, -113.971564],
      [53.512034, -113.971650],
      [53.512034, -113.959076],
      [53.520338, -113.959179],
      [53.519726, -113.885364],
      [53.541153, -113.885364],
      [53.541101, -113.845993],
      [53.571438, -113.846851],
      [53.570012, -113.885364],
      [53.571082, -113.916435],
      [53.569349, -113.959007],
      [53.555451, -113.959383]
    ]
  ]
], {
  color: 'yellow',
  opacity: 1,
  fillOpacity: 0.5
});

//Add polygons to map
polyYellow.addTo(map);
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>

<script src="https://unpkg.com/@turf/turf@5.1.6/turf.js"></script>

<div id="map" style="height: 200px"></div>

当然,你可以简单地将这次重构的结果保存为RED多边形的新定义,现在只有一个洞。