Closed tankorsmash closed 4 years ago
Here's my attempt incase anyone knows what the issue is, but I'd definitely love to look at someone else's completed version because mine is broken. Attached is what it renders out too (red lines are the delauntor's coords indexes by triangles, and the circles are the circumcenters, but the black in the corner is supposed to be the vornoi edges, or even triangle edges which I'd expect to be overlaid over the red triangles).
using edge_t = size_t;
using v_double_t = std::vector<double>;
using double_pair_t = std::pair<double, double>;
using v_double_pair_t = std::vector<double_pair_t>;
auto triangleOfEdge = [](edge_t e) {
return (edge_t)std::floor(((size_t)e) / (size_t)3.0);
};
//returns 3 edge IDs
auto edgesOfTriangle = [](edge_t t) -> std::vector<edge_t> {
return std::vector<edge_t>{3* t, 3* t + 1, 3 * t + 2};
};
//finds 3 points for a given triangle id
auto pointsOfTriangle = [edgesOfTriangle](const delaunator::Delaunator& delaunator, edge_t tri_id) ->std::vector<size_t> {
auto edges = edgesOfTriangle(tri_id);
std::vector<size_t> points;
auto find_tri_for_edge = [delaunator](edge_t e) -> size_t{ return delaunator.triangles[e]; };
std::transform(edges.begin(), edges.end(), std::back_inserter(points), find_tri_for_edge);
return points;
};
auto edgesAroundPoint = [nextHalfEdge](const delaunator::Delaunator& delaunator, edge_t start) {
std::vector<edge_t> result;
edge_t incoming = start;
do {
result.push_back(incoming);
const edge_t outgoing = nextHalfEdge(incoming);
incoming = delaunator.halfedges[outgoing];
} while (incoming != (edge_t)-1 && incoming != start);
return result;
};
auto triangleCenter = [pointsOfTriangle](v_double_pair_t points, delaunator::Delaunator& delaunator, edge_t tri_id) -> std::pair<double, double>
{
auto tri_points = pointsOfTriangle(delaunator, tri_id);
std::vector<std::pair<double, double>> vertices{};
std::transform(tri_points.begin(), tri_points.end(), std::back_inserter(vertices), [&points](edge_t tri_point) {
return points[tri_point];
});
auto result = delaunator::circumcenter(
vertices[0].first, vertices[0].second,
vertices[1].first, vertices[1].second,
vertices[2].first, vertices[2].second
);
return std::pair<double, double>(result.first, result.second);
};
auto forEachVoronoiEdge = [&](v_double_pair_t points, delaunator::Delaunator& delaunator, std::function<void(edge_t, double_pair_t, double_pair_t)> callback) {
for (auto e = 0; e < delaunator.triangles.size(); e++) {
if (e < delaunator.halfedges[e]) {
auto pt = triangleOfEdge(e);
auto p = triangleCenter(points, delaunator, pt);
auto qt = triangleOfEdge(delaunator.halfedges[e]);
//this seems to be a bug, qt should never be higher than 10k
if (qt > 10000) {
auto qwe = delaunator::INVALID_INDEX;
//__debugbreak();
continue;
}
auto q = triangleCenter(points, delaunator, qt);
callback(e, p, q);
}
}
};
even the simpler Triangle Edges draws incorrectly, with a ton of 'invalid' prints:
auto forEachTriangleEdge = [&](delaunator::Delaunator& delaunator, std::function<void(edge_t, double_pair_t, double_pair_t)> callback) {
for (unsigned e = 0; e < delaunator.triangles.size(); e++) {
auto halfedge = delaunator.halfedges[e];
if (e < halfedge && halfedge != delaunator::INVALID_INDEX) {
try{
auto p = double_pair_t{delaunator.coords.at(delaunator.triangles[e] * 2), delaunator.coords.at(delaunator.triangles[e] * 2 + 1)};
auto q = double_pair_t{delaunator.coords.at(delaunator.triangles[nextHalfEdge(e)] * 2), delaunator.coords.at(delaunator.triangles[nextHalfEdge(e)] * 2 + 1)};
callback(e, p, q);
}
catch (std::out_of_range& ex) { my_print(L"invalid"); }
}
}
It seems like I had an issue with the drawing library (https://github.com/ArashPartow/bitmap), so if I offset the black lines by some cartesian offsets that works. Not sure why. Would still love to see someone else's approach at porting the demo if they've got it.
Figured out the issue with mine, I was missing a * 2
when looking into the coords which makes sense. I'll close this and leave the code for anyone else looking to have a demo port (after some tweaking to my pasted in code, I'm sure)
auto nextHalfEdge = [](edge_t edge) { return (edge % 3 == 2) ? edge - 2 : edge + 1; };
auto triangleOfEdge = [](edge_t e) {
return e / 3;
};
//returns 3 edge IDs
auto edgesOfTriangle = [](edge_t t) -> std::vector<edge_t> {
return std::vector<edge_t>{3* t, 3* t + 1, 3 * t + 2};
};
//finds 3 points for a given triangle id
auto pointsOfTriangle = [edgesOfTriangle](const delaunator::Delaunator& delaunator, edge_t tri_id) ->std::vector<size_t> {
auto edges = edgesOfTriangle(tri_id);
std::vector<size_t> points;
auto find_tri_for_edge = [delaunator](edge_t e) -> size_t{ return delaunator.triangles[e]; };
std::transform(edges.begin(), edges.end(), std::back_inserter(points), find_tri_for_edge);
return points;
};
auto edgesAroundPoint = [nextHalfEdge](const delaunator::Delaunator& delaunator, edge_t start) {
std::vector<edge_t> result;
edge_t incoming = start;
do {
result.push_back(incoming);
const edge_t outgoing = nextHalfEdge(incoming);
incoming = delaunator.halfedges[outgoing];
} while (incoming != (edge_t)-1 && incoming != start);
return result;
};
//circumcenter of triangle
auto triangleCenter = [pointsOfTriangle](v_double_t points, delaunator::Delaunator& delaunator, edge_t tri_id) -> std::pair<double, double>
{
auto tri_points = pointsOfTriangle(delaunator, tri_id);
std::vector<std::pair<double, double>> vertices{};
std::transform(tri_points.begin(), tri_points.end(), std::back_inserter(vertices), [&points, &delaunator](edge_t tri_point) {
return double_pair_t{delaunator.coords.at(tri_point*2), delaunator.coords.at(tri_point*2 + 1)}; //this is the * 2 that was missing
});
auto result = delaunator::circumcenter(
vertices[0].first, vertices[0].second,
vertices[1].first, vertices[1].second,
vertices[2].first, vertices[2].second
);
return std::pair<double, double>(result.first, result.second);
};
auto forEachVoronoiEdge = [&](delaunator::Delaunator& delaunator, std::function<void(edge_t, double_pair_t, double_pair_t)> callback) {
//forEachTriangleEdge
//for (unsigned e = 0; e < delaunator.triangles.size(); e++) {
// auto halfedge = delaunator.halfedges[e];
// if (e < halfedge && halfedge != delaunator::INVALID_INDEX) {
// try{
// auto p = double_pair_t{delaunator.coords.at(delaunator.triangles[e] * 2), delaunator.coords.at(delaunator.triangles[e] * 2 + 1)};
// auto q = double_pair_t{delaunator.coords.at(delaunator.triangles[nextHalfEdge(e)] * 2), delaunator.coords.at(delaunator.triangles[nextHalfEdge(e)] * 2 + 1)};
// callback(e, p, q);
// }
// catch (std::out_of_range& ex) { my_print(L"invalid"); }
// }
//}
////forEachVoronoiEdge
for (unsigned e = 0; e < delaunator.triangles.size(); e++) {
auto halfedge = delaunator.halfedges[e];
if (e > halfedge && halfedge != delaunator::INVALID_INDEX) {
edge_t pt = triangleOfEdge(e);
double_pair_t p = triangleCenter(delaunator.coords, delaunator, pt); //now im passing in the coords from delaunator
edge_t qt = triangleOfEdge(delaunator.halfedges[e]);
double_pair_t q = triangleCenter(delaunator.coords, delaunator, qt);
callback(e, p, q);
}
}
};
The demo here lists a bunch of code that works with the JS version of this lib, but because of what I'm assuming is type differences across the implementations, porting it isn't straight forward. Has anyone been able to render the voronoi edges like the js demo does?