9

I am drawing circle in the center of my unshaped polygon maps. The circle is placed in the center for most of the country. But for "Norway" polygon shape, the return center point is wrong. You can see the difference clearly, after zooming/scaling the page.

enter image description here

I used this stackoverflow solution : link

My code below here. SVG:

<svg xmlns="http://www.w3.org/2000/svg" style="overflow: hidden; z-index: 0; float: left; background: transparent; height: 500px; width: 500px; margin-top: 0px; margin-left: 0px;">
 <path class="mapShape" stroke="#FFFFFF" stroke-width="0.25" fill="#ffff00" d="M289.61881571694846,107.44341140465033,293.96308112495205,110.5369251340838,292.1742152937817,111.64028258514635,293.69594267913214,114.17588213225122,291.33275072129567,115.75640079550517,290.21101327644885,116.115304587361,290.79940687634996,113.34302402649551,289.01707237203874,111.73064813415773,286.86058614336986,113.10652807111005,286.17946205663384,116.00897875925767,284.8551099335093,117.71420145300249,283.3639577705983,116.78716653168755,281.5503303156214,116.97787478097227,280.0068557650149,114.91879878457861,279.17443456817995,115.95395481299134,278.3128736053582,116.11389849530838,278.1091105619184,118.63382135713674,275.4914839478672,118.02707970555407,275.1238635503685,120.11785014900434,273.7901091874799,120.10529402219055,272.87321137841224,122.7050543288587,271.48390485080984,126.60600357598904,269.3273468493182,131.3173178164711,269.8332017031975,132.42411528484843,269.3498835156233,133.6909765856373,267.9721324124638,133.63667113556374,267.07023512332535,136.56637255563933,267.1556447822521,140.55669253761528,268.04325927968785,142.03410132622142,267.5838414420485,145.3716436133896,266.42815545209885,147.26315676671453,265.8157897294402,148.82368555076928,264.88410671891126,147.16092140518467,262.1416671663106,150.27022727262624,260.28992834251846,150.88797751378152,258.3692158361812,149.54060413568916,257.8725479035983,146.63056295282385,257.4334417747625,140.05376745248705,258.71236170116373,138.13152704055724,262.3797376189663,135.55992732652805,265.12181830745385,132.29324106111955,267.6643705490366,127.68026976914571,271.0015914827522,120.85619046583638,273.32767689129025,118.04298816880565,277.1444838258035,113.13815447740048,280.19224496586196,111.35745222872376,282.47741986550216,111.5754647031133,284.5924214026924,108.10819671605745,287.12506899475255,108.29698566394183ZM284.83905555555555,72.19815552139636,281.7365555555555,74.85366572152822,279.28612499999997,73.35699077101634,280.24459722222224,71.66044868206447,279.40541666666667,69.508641420061,282.28369444444445,68.1303212868272,282.8351944444444,70.69457195193213ZM275.84976388888896,58.9806663889022,280.42198611111115,64.57567572395904,276.92690277777774,67.37974197318883,276.1551666666667,72.37724133868834,274.9366805555556,73.61091608778322,274.2752777777778,78.81637965917018,272.6015972222222,79.05316716888755,269.61470833333334,75.26524507138704,270.87438888888886,72.97467771855085,268.79249999999996,71.06094914643477,266.0865416666667,65.20265086315597,265.0062916666667,59.363240232610856,268.7927361111111,56.545993503156645,269.5535,59.301357483657114,271.5316944444445,59.193568518861454,272.0590972222222,56.500983977896404,274.0984027777777,56.221878380253195ZM285.84392411084985,53.30414066139549,288.5659801818243,56.17728511117262,286.50645903652526,60.397046089088526,282.4784246850189,61.291565425339506,278.3822061520165,60.0221846103223,278.1350923237096,57.880800099653854,276.14203281216373,57.74271786397911,274.62224329302427,54.037937230381914,278.9111000819593,51.69790103414376,280.92770107932694,53.71698527072119,282.3322952181492,51.194805998985345Z" stroke-linejoin="round" stroke-linecap="square" nodeValue="#E0E0E0"></path>
<circle fill="#FE0000" cx="271.7692623673869" cy="128.99711033923683" fill-opacity="1" r="1"></circle>
</svg>

JavaScript:

var path = "289.61881571694846,107.44341140465033,293.96308112495205,110.5369251340838,292.1742152937817,111.64028258514635,293.69594267913214,114.17588213225122,291.33275072129566,115.75640079550517,290.21101327644885,116.115304587361,290.79940687634996,113.34302402649551,289.01707237203874,111.73064813415773,286.86058614336985,113.10652807111005,286.17946205663383,116.00897875925767,284.8551099335093,117.71420145300249,283.3639577705983,116.78716653168754,281.5503303156214,116.97787478097227,280.0068557650149,114.91879878457861,279.17443456817994,115.95395481299134,278.3128736053582,116.11389849530837,278.1091105619184,118.63382135713674,275.4914839478672,118.02707970555407,275.1238635503685,120.11785014900434,273.7901091874799,120.10529402219055,272.87321137841223,122.7050543288587,271.48390485080983,126.60600357598903,269.3273468493182,131.3173178164711,269.8332017031975,132.42411528484843,269.3498835156233,133.6909765856373,267.9721324124638,133.63667113556374,267.07023512332534,136.56637255563933,267.1556447822521,140.55669253761528,268.04325927968784,142.03410132622142,267.5838414420485,145.3716436133896,266.42815545209885,147.26315676671453,265.8157897294402,148.82368555076928,264.88410671891125,147.16092140518467,262.1416671663106,150.27022727262624,260.28992834251846,150.88797751378152,258.3692158361812,149.54060413568916,257.8725479035983,146.63056295282385,257.4334417747625,140.05376745248705,258.71236170116373,138.13152704055724,262.3797376189663,135.55992732652805,265.12181830745385,132.29324106111954,267.6643705490366,127.68026976914571,271.0015914827522,120.85619046583638,273.32767689129025,118.04298816880565,277.1444838258035,113.13815447740047,280.19224496586196,111.35745222872376,282.47741986550215,111.5754647031133,284.5924214026924,108.10819671605745,287.12506899475255,108.29698566394182"
        var stringData = path.split(",");
        var length = stringData.length;
        var data = [], obj;

        for (var i = 0; i < length; i = i + 2) {
            obj = { x: parseFloat(stringData[i]), y: parseFloat(stringData[i + 1]) };
            data.push(obj);
        }

        var centerPoint = _findMidPointofPoylgon(data);
        alert("cx: " + centerPoint.x + "cy: " + centerPoint.y);

   //Return the centerX and centerY of the unshape polygon
        function _findMidPointofPoylgon (points) {
            var x = 0,
            y = 0,
            i, min = 0,
            j,
            f,
            point1,
            point2;
            var max = points.length;
            var area = function () {
                var area = 0,
                    i,
                    j,
                    point1,
                    point2;

                for (i = 0, j = max - 1; i < max; j = i, i++) {
                    point1 = points[i];
                    point2 = points[j];
                    area += point1.x * point2.y;
                    area -= point1.y * point2.x;
                }
                area /= 2;

                return area;
            };
            for (i = 0, j = max - 1; i < max; j = i, i++) {
                point1 = points[i];
                point2 = points[j];
                f = point1.x * point2.y - point2.x * point1.y;
                x += (point1.x + point2.x) * f;
                y += (point1.y + point2.y) * f;
            }

            f = area() * 6;
            var xSum = x / f, ySum = y / f;

            return { x: xSum, y: ySum };             
        }

I have stored the direction path data in array collection and used to calculate center point.

Fiddle link

Could you please tell me that what wrong with my code

Community
  • 1
  • 1
Bharathi
  • 1,288
  • 2
  • 14
  • 40
  • 3
    You are calculating [the centroid](https://en.wikipedia.org/wiki/Centroid) of the polygon which is not guaranteed to lay inside the surface on concave polygons (as Norway). You may want to implement some kind of [Point On Surface algorithm](http://gis.stackexchange.com/questions/76498/how-is-st-pointonsurface-calculated) – antonio Mar 27 '17 at 10:10
  • 1
    Unfortunately, the algorithm described in that article won't work here because the OP's path consists of two separate subpaths. And a horizontal line through the centre would miss both subpaths :/ It would need to be modified. – Paul LeBeau Mar 27 '17 at 13:52
  • Is there any other algorithm or solution to achieve this..? – Bharathi Mar 28 '17 at 03:43
  • we used to solve such problem in our AI course. I'm sure the answer to your question is not an easy one. The mapbox solution devised by alpadev is a great answer if it's feasible in your current scenario. – Aurangzeb Apr 27 '17 at 23:46
  • Possible duplicate of [What is the fastest way to find the "visual" center of an irregularly shaped polygon?](https://stackoverflow.com/questions/1203135/what-is-the-fastest-way-to-find-the-visual-center-of-an-irregularly-shaped-pol) – StayOnTarget Jul 11 '18 at 19:44

2 Answers2

2

You could implement Polylabel. It's an algorithm made by the guys from Mapbox designed to display a label in the center of a polygon, regardless of its shape

alpadev
  • 470
  • 9
  • 23
  • An introduction about this algorithm can be found here: https://www.mapbox.com/blog/polygon-center/ – alpadev Apr 27 '17 at 07:20
  • Hi, I know this "Polylabel" algorithm already.. But JavaScript they have used third party plugin. In my source, i can't use third party plugin – Bharathi May 02 '17 at 06:26
0

I think the problem with your code is that you are trying to find centroid of the shape which is the center of mass for 2D shapes. Which takes the area inside the polygon finds the center of that area. Which will be use-full if you trying to balance the area on that point because mass distribution around the point will be even.

But you just need to cover the area with a circle, So you just have to find the two points which are the farthest from each other and draw a circle around those points.

So loop through all points find the farthest pair, find the point between these two points (avg(x1,x2), avg(y1,y2)), and draw a circle there with diameter as the distance between these points.

skam
  • 357
  • 5
  • 18