Conversation
|
Thanks for the update! Great to see progress :) I noticed the refiner API appears to use a flat array of vertices as the second argument, which may force the user to make a flattened copy of the whole polygon data and is inconsistent with the normal earcut function. Could we change the signature to refine(indices, polygon) instead? |
|
@mrgreywater I was also mulling over this but decided to go with the flat version because we have to flatten the polygon either way, either before or internally in |
|
Maybe we could try the |
|
I'll see if I can come up with a clean overload that accepts both options when I'm back home. I'd really prefer if the interface stayed consistent. |
|
Got Claude to investigate this, here's its response: @mrgreywater Before you sink time into the overload — I benchmarked the nested-indexing approach and it turns out to be a real regression, so I want to save you the exploration. I ran three variants of
Two things stack up: the global→(ring, local) mapping runs on every vertex access inside the hot That said, I fully agree the interface should stay consistent, and I think there's a clean way to get there. Instead of indexing the nested structure in place, a convenience overload can flatten once and delegate to the flat path: template <typename N, typename Polygon>
void refine(std::vector<N>& triangles, const Polygon& polygon) {
using Point = typename Polygon::value_type::value_type;
std::vector<Point> coords;
for (const auto& ring : polygon) coords.insert(coords.end(), ring.begin(), ring.end());
refine(triangles, coords); // flat fast path
}The flatten is a single O(verts) copy — negligible next to refine's work — and it runs at the flat 95 ms, not 254/496. So users with a nested polygon get the consistent Happy to draft that overload if you agree with the direction — didn't want you to keep polishing the in-place version given the numbers. |
|
I think having a convenience overload that does the flat copy is a good solution. If we find a faster solution, we can always improve it later without breaking the code for the users of the library. |
Brings the C++ port up to date with the latest earcut.js and modernizes the whole build/test/dev setup. Net: +1,487 / −11,105 lines across 83 files (most deletions are unvendored deps and hand-transcribed fixtures). Supercedes and closes #131. Closes #117. Closes #124.
Algorithm parity
mapbox::refine()Delaunay post-pass (legalizes interior edges in place, same triangle count/index format).std::sort, added the block-index optimization, plus assorted microoptimizations.Testing & benchmarking
FetchContent, pinned to the matching tag) — deletes ~5k lines of generated fixture code and keeps us in lockstep automatically.Build & CI
-Werror(EARCUT_WARNING_IS_ERROR) across all jobs. Fixed a g++ bitfield-narrowing warning surfaced by it.Docs & dev experience
earcutfixture to match the JS demo.CHANGELOG.md(GitHub Releases is the source of truth).