Untitled
unknown
c_cpp
22 days ago
7.2 kB
2
Indexable
Never
Delaunator::Delaunator(std::vector<double> const& in_coords) : coords(in_coords), triangles(), halfedges(), hull_prev(), hull_next(), hull_tri(), hull_start(), m_hash(), m_center_x(), m_center_y(), m_hash_size(), m_edge_stack() { std::size_t n = coords.size() >> 1; double max_x = std::numeric_limits<double>::min(); double max_y = std::numeric_limits<double>::min(); double min_x = std::numeric_limits<double>::max(); double min_y = std::numeric_limits<double>::max(); std::vector<std::size_t> ids; ids.reserve(n); for (std::size_t i = 0; i < n; i++) { const double x = coords[2 * i]; const double y = coords[2 * i + 1]; if (x < min_x) min_x = x; if (y < min_y) min_y = y; if (x > max_x) max_x = x; if (y > max_y) max_y = y; ids.push_back(i); } const double cx = (min_x + max_x) / 2; const double cy = (min_y + max_y) / 2; double min_dist = std::numeric_limits<double>::max(); std::size_t i0 = INVALID_INDEX; std::size_t i1 = INVALID_INDEX; std::size_t i2 = INVALID_INDEX; // pick a seed point close to the centroid for (std::size_t i = 0; i < n; i++) { const double d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]); if (d < min_dist) { i0 = i; min_dist = d; } } const double i0x = coords[2 * i0]; const double i0y = coords[2 * i0 + 1]; min_dist = std::numeric_limits<double>::max(); // find the point closest to the seed for (std::size_t i = 0; i < n; i++) { if (i == i0) continue; const double d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]); if (d < min_dist && d > 0.0) { i1 = i; min_dist = d; } } double i1x = coords[2 * i1]; double i1y = coords[2 * i1 + 1]; double min_radius = std::numeric_limits<double>::max(); // find the third point which forms the smallest circumcircle with the first two for (std::size_t i = 0; i < n; i++) { if (i == i0 || i == i1) continue; const double r = circumradius( i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]); if (r < min_radius) { i2 = i; min_radius = r; } } if (!(min_radius < std::numeric_limits<double>::max())) { throw std::runtime_error("not triangulation"); } double i2x = coords[2 * i2]; double i2y = coords[2 * i2 + 1]; if (orient(i0x, i0y, i1x, i1y, i2x, i2y)) { std::swap(i1, i2); std::swap(i1x, i2x); std::swap(i1y, i2y); } std::tie(m_center_x, m_center_y) = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y); // sort the points by distance from the seed triangle circumcenter std::sort(ids.begin(), ids.end(), compare{ coords, m_center_x, m_center_y }); // initialize a hash table for storing edges of the advancing convex hull m_hash_size = static_cast<std::size_t>(std::llround(std::ceil(std::sqrt(n)))); m_hash.resize(m_hash_size); std::fill(m_hash.begin(), m_hash.end(), INVALID_INDEX); // initialize arrays for tracking the edges of the advancing convex hull hull_prev.resize(n); hull_next.resize(n); hull_tri.resize(n); hull_start = i0; size_t hull_size = 3; hull_next[i0] = hull_prev[i2] = i1; hull_next[i1] = hull_prev[i0] = i2; hull_next[i2] = hull_prev[i1] = i0; hull_tri[i0] = 0; hull_tri[i1] = 1; hull_tri[i2] = 2; m_hash[hash_key(i0x, i0y)] = i0; m_hash[hash_key(i1x, i1y)] = i1; m_hash[hash_key(i2x, i2y)] = i2; std::size_t max_triangles = n < 3 ? 1 : 2 * n - 5; triangles.reserve(max_triangles * 3); halfedges.reserve(max_triangles * 3); add_triangle(i0, i1, i2, INVALID_INDEX, INVALID_INDEX, INVALID_INDEX); double xp = std::numeric_limits<double>::quiet_NaN(); double yp = std::numeric_limits<double>::quiet_NaN(); for (std::size_t k = 0; k < n; k++) { const std::size_t i = ids[k]; const double x = coords[2 * i]; const double y = coords[2 * i + 1]; // skip near-duplicate points if (k > 0 && check_pts_equal(x, y, xp, yp)) continue; xp = x; yp = y; // skip seed triangle points if ( check_pts_equal(x, y, i0x, i0y) || check_pts_equal(x, y, i1x, i1y) || check_pts_equal(x, y, i2x, i2y)) continue; // find a visible edge on the convex hull using edge hash std::size_t start = 0; size_t key = hash_key(x, y); for (size_t j = 0; j < m_hash_size; j++) { start = m_hash[fast_mod(key + j, m_hash_size)]; if (start != INVALID_INDEX && start != hull_next[start]) break; } start = hull_prev[start]; size_t e = start; size_t q; while (q = hull_next[e], !orient(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1])) { //TODO: does it works in a same way as in JS e = q; if (e == start) { e = INVALID_INDEX; break; } } if (e == INVALID_INDEX) continue; // likely a near-duplicate point; skip it // add the first triangle from the point std::size_t t = add_triangle( e, i, hull_next[e], INVALID_INDEX, INVALID_INDEX, hull_tri[e]); hull_tri[i] = legalize(t + 2); hull_tri[e] = t; hull_size++; // walk forward through the hull, adding more triangles and flipping recursively std::size_t next = hull_next[e]; while ( q = hull_next[next], orient(x, y, coords[2 * next], coords[2 * next + 1], coords[2 * q], coords[2 * q + 1])) { t = add_triangle(next, i, q, hull_tri[i], INVALID_INDEX, hull_tri[next]); hull_tri[i] = legalize(t + 2); hull_next[next] = next; // mark as removed hull_size--; next = q; } // walk backward from the other side, adding more triangles and flipping if (e == start) { while ( q = hull_prev[e], orient(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1])) { t = add_triangle(q, i, e, INVALID_INDEX, hull_tri[e], hull_tri[q]); legalize(t + 2); hull_tri[q] = t; hull_next[e] = e; // mark as removed hull_size--; e = q; } } // update the hull indices hull_prev[i] = e; hull_start = e; hull_prev[next] = i; hull_next[e] = i; hull_next[i] = next; m_hash[hash_key(x, y)] = i; m_hash[hash_key(coords[2 * e], coords[2 * e + 1])] = e; } }
Leave a Comment