Skip to content

Commit 658b04c

Browse files
authored
Merge pull request #22 from Fil/fil/no-hull
multipolygon tricontour
2 parents 79d015c + 0e489ca commit 658b04c

4 files changed

Lines changed: 278 additions & 28 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ These methods are used in d3-geo-voronoi’s [geoContour](https://github.com/Fil
9797

9898
<a href="#triangulate" name="triangulate">#</a> _tricontour_.<b>triangulate</b>([_triangulate_])
9999

100-
Sets the *triangulate* function. Defaults to d3.Delaunay.from. See [Reusing a tricontour triangulation](https://observablehq.com/@fil/reusing-a-tricontour-triangulation) and [UK tricontour](https://observablehq.com/@fil/tricontours-with-a-personalized-triangulation) for detailed examples.
100+
Sets the *triangulate* function. Defaults to d3.Delaunay.from. For detailed examples, see [Reusing a tricontour triangulation](https://observablehq.com/@fil/reusing-a-tricontour-triangulation), [UK tricontour](https://observablehq.com/@fil/tricontours-with-a-personalized-triangulation), and [Multipolygon tricontour](https://observablehq.com/@fil/multipolygon-tricontour).
101101

102102
[<img src="https://raw.githubusercontent.com/Fil/d3-tricontour/main/img/tricontour-triangulation.jpg" alt="UK tricontour" width="320">](https://observablehq.com/@fil/tricontours-with-a-personalized-triangulation)
103103

src/tricontour.js

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,15 @@ export default function() {
111111
// sanity check
112112
for (const d of values) if (!isFinite(d)) throw ["Invalid value", d];
113113

114-
const { halfedges, hull, inedges, triangles } = triangulation,
114+
const { halfedges, inedges, triangles } = triangulation,
115115
n = values.length;
116116

117+
const Hull = new Map();
118+
halfedges.forEach((i, j) => {
119+
if (i === -1)
120+
Hull.set(triangles[j], triangles[j + (j % 3 === 2 ? -2 : 1)]);
121+
});
122+
117123
function edgealpha(i) {
118124
return alpha(triangles[i], triangles[next(i)]);
119125
}
@@ -140,7 +146,7 @@ export default function() {
140146

141147
// is our tour done?
142148
if (
143-
(path.length && (ti === path[0].ti && tj === path[0].tj)) ||
149+
(path.length && ti === path[0].ti && tj === path[0].tj) ||
144150
path.length > 2 * n
145151
)
146152
break;
@@ -163,25 +169,16 @@ export default function() {
163169

164170
// or follow the hull
165171
else {
166-
let h = (hull.indexOf(triangles[i]) + 1) % hull.length;
167-
168-
while (values[hull[h]] < v0) {
169-
// debugger;
170-
h = (h + 1) % hull.length;
171-
}
172-
173-
while (values[hull[h]] >= v0) {
174-
path.push({ ti: hull[h], tj: hull[h], a: 0 });
175-
h = (h + 1) % hull.length;
172+
let h = triangles[i];
173+
while (values[h] < v0) h = Hull.get(h);
174+
while (values[h] >= v0) {
175+
path.push({ ti: h, tj: h, a: 0 });
176+
h = Hull.get(h);
176177
}
177178

178179
// take that entry
179-
j = inedges[hull[h]];
180-
path.push({
181-
ti: hull[h],
182-
tj: triangles[j],
183-
a: alpha(hull[h], triangles[j])
184-
});
180+
j = inedges[h];
181+
path.push({ ti: h, tj: triangles[j], a: alpha(h, triangles[j]) });
185182

186183
if (edgealpha((i = next(j))) > 0) continue;
187184
if (edgealpha((i = prev(j))) > 0) continue;
@@ -194,15 +191,23 @@ export default function() {
194191
}
195192
}
196193

197-
// special case all values on the hull are >=v0, add the hull
198-
if (hull.every(d => values[d] >= v0)) {
199-
rings.unshift(
200-
Array.from(hull)
201-
.concat([hull[0]])
202-
.map(i => pointInterpolate(i, i, 0))
203-
);
204-
}
194+
// special case all values on the hull are >=v0, add the hull (or hulls if
195+
// there are multiple pieces or holes). Note: vacates the Hull Map.
196+
do {
197+
const ring = [];
198+
let i = Hull.keys().next().value;
199+
do {
200+
const j = Hull.get(i);
201+
ring.push(i);
202+
Hull.delete(i);
203+
i = j;
204+
} while (Hull.has(i));
205+
if (ring.every((i) => values[i] >= v0)) {
206+
ring.push(ring[0]);
207+
rings.push(ring.map((i) => pointInterpolate(i, i, 0)));
208+
}
209+
} while (Hull.size);
205210

206211
return ringsort(rings); // return [rings] if we don't need to sort
207212
}
208-
}
213+
}

0 commit comments

Comments
 (0)