<p>If you can assume the subpaths are non-intersecting (and non-self-intersecting), and that the fill rule is always the nonzero rule, the easiest way is probably to pick the first point on the first subpath, and do <a href="https://en.wikipedia.org/wiki/Point_in_polygon" rel="nofollow noreferrer">a standard point-in-polygon test</a> with the polygons defined by each other subpath. If the point is not inside any other subpath, then this subpath is the outermost one. If the point is inside one other subpath, that one must be the outermost one. If the point is inside more than one other subpath, take the set of subpaths it is inside and repeat the test.</p>

<p>Obviously doing it this way requires that there is only one outermost subpath. It's entirely possible in SVG to have multiple disjoint subpaths in one path, and you didn't say whether this is possible in your source data. If it is possible, then you'll have to test every subpath to find out which other subpath(s) it is inside. Each time you run the point-in-polygon test, you find the subpath you're considering is either an outermost one, or you'll find out which subpath it is inside. If it's inside another path, you don't need to consider it in any further tests. At the end, you have a list of outermost subpaths, each of which has a list of all the subpaths it encloses. You can turn each outermost subpath into a separate GeoJSON polygon.</p>

CC BY-SA 3.0
2017-06-19T14:01:50.707Z
2017-06-19T14:01:50.707Z
Dan Hulme
<p>The following four SVG paths render the same (using the default <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule" rel="nofollow noreferrer"><code>fill-rule=&quot;nonzero&quot;</code></a>):</p>
<pre><code>&lt;path id=&quot;cwOccwI&quot; d=&quot;M0,0 10,0 10,10zM5,2 8,5 8,2z&quot; transform=&quot;translate( 0,0)&quot;/&gt;
&lt;path id=&quot;ccwOcwI&quot; d=&quot;M0,0 10,10 10,0zM5,2 8,2 8,5z&quot; transform=&quot;translate(15,0)&quot;/&gt;
&lt;path id=&quot;ccwIcwO&quot; d=&quot;M5,2 8,5 8,2zM0,0 10,0 10,10z&quot; transform=&quot;translate(30,0)&quot;/&gt;
&lt;path id=&quot;cwIccwO&quot; d=&quot;M5,2 8,2 8,5zM0,0 10,10 10,0z&quot; transform=&quot;translate(45,0)&quot;/&gt;
</code></pre>
<p><a href="https://i.sstatic.net/4yENe.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/4yENe.png" alt="Four triangles with triangular holes inside" /></a></p>
<p>As hinted at by the IDs, these are combinations of clockwise (<code>cw</code>) and counter-clockwise (<code>ccw</code>) orientations for the outer (<code>O</code>) and inner (<code>I</code>) subpaths, varying the order the subpaths are added.</p>
<p>I'm converting SVG paths to <a href="http://geojson.org/" rel="nofollow noreferrer">GeoJSON</a>. It requires a single 'positive' subpath that is oriented counter-clockwise, and any/all <a href="https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6" rel="nofollow noreferrer">'hole' subpaths to be oriented clockwise</a>.</p>
<p>Given an SVG path with subpaths (which I can assume/guarantee will not overlap), how can I determine which subpath(s) are 'positive' paths, and which are 'holes'? As shown above, I cannot rely on the orientation of the points within the path, and I cannot rely on the ordering of sub-paths.</p>

<vector-graphics>
Determining the 'outer' subpath in a compound SVG path
Phrogz
# Determining the 'outer' subpath in a compound SVG path

(Asked by: username_0 on 2017-06-19)

The following four SVG paths render the same (using the default [`fill-rule="nonzero"`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule)):

```
<path id="cwOccwI" d="M0,0 10,0 10,10zM5,2 8,5 8,2z" transform="translate( 0,0)"/>
<path id="ccwOcwI" d="M0,0 10,10 10,0zM5,2 8,2 8,5z" transform="translate(15,0)"/>
<path id="ccwIcwO" d="M5,2 8,5 8,2zM0,0 10,0 10,10z" transform="translate(30,0)"/>
<path id="cwIccwO" d="M5,2 8,2 8,5zM0,0 10,10 10,0z" transform="translate(45,0)"/>

```

[![Four triangles with triangular holes inside](https://i.sstatic.net/4yENe.png)](https://i.sstatic.net/4yENe.png)

As hinted at by the IDs, these are combinations of clockwise (`cw`) and counter-clockwise (`ccw`) orientations for the outer (`O`) and inner (`I`) subpaths, varying the order the subpaths are added.

I'm converting SVG paths to [GeoJSON](http://geojson.org/). It requires a single 'positive' subpath that is oriented counter-clockwise, and any/all ['hole' subpaths to be oriented clockwise](https://www.rfc-editor.org/rfc/rfc7946#section-3.1.6).

Given an SVG path with subpaths (which I can assume/guarantee will not overlap), how can I determine which subpath(s) are 'positive' paths, and which are 'holes'? As shown above, I cannot rely on the orientation of the points within the path, and I cannot rely on the ordering of sub-paths.

**Tags:** vector-graphics


---

## 1 answers

### Answer by username_1 on 2017-06-19. Score: 2 | Accepted answer

If you can assume the subpaths are non-intersecting (and non-self-intersecting), and that the fill rule is always the nonzero rule, the easiest way is probably to pick the first point on the first subpath, and do [a standard point-in-polygon test](https://en.wikipedia.org/wiki/Point_in_polygon) with the polygons defined by each other subpath. If the point is not inside any other subpath, then this subpath is the outermost one. If the point is inside one other subpath, that one must be the outermost one. If the point is inside more than one other subpath, take the set of subpaths it is inside and repeat the test.

Obviously doing it this way requires that there is only one outermost subpath. It's entirely possible in SVG to have multiple disjoint subpaths in one path, and you didn't say whether this is possible in your source data. If it is possible, then you'll have to test every subpath to find out which other subpath(s) it is inside. Each time you run the point-in-polygon test, you find the subpath you're considering is either an outermost one, or you'll find out which subpath it is inside. If it's inside another path, you don't need to consider it in any further tests. At the end, you have a list of outermost subpaths, each of which has a list of all the subpaths it encloses. You can turn each outermost subpath into a separate GeoJSON polygon.


---

