void find_next_edge(Segment s, std::vector<Segment>& segments, std::set<int>& unusedIndexes, std::vector<Polygon_2>& rings) { if (unusedIndexes.empty() || prev_size == unusedIndexes.size()) { return; } prev_size = unusedIndexes.size(); Point start = s.source(); Point end = s.target(); rings.back().push_back(end); std::vector<int> nextIndexes; for (unsigned int i = 0; i < segments.size(); i++) { if (unusedIndexes.find(i) != unusedIndexes.end()) { Point source = segments.at(i).source(); if (source == end) { nextIndexes.push_back(i); } } } if (nextIndexes.size() == 1) { int i = nextIndexes.at(0); unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } else if (nextIndexes.size() > 1) { std::vector< std::pair<double, int> > nextAngles; for (unsigned int i = 0; i < nextIndexes.size(); i++) { int j = nextIndexes.at(i); Point target = segments.at(j).target(); double angle = get_angle(start, end, target); nextAngles.push_back(std::pair<double, int>(angle, j)); } std::sort(nextAngles.begin(), nextAngles.end()); int i = nextAngles.begin()->second; unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } if (!unusedIndexes.empty()) { for (unsigned int i = 0; i < segments.size(); i++) { if (unusedIndexes.find(i) != unusedIndexes.end()) { Polygon_2 ring; ring.push_back(segments.at(i).source()); rings.push_back(ring); unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } } } }
int alpha_shape(vertex_t *vertices, size_t count, double alpha, vertex_t **res, size_t *res_count, char **err_msg) { try { std::list<Point> points; { std::vector<Point> pv; for (std::size_t j = 0; j < count; ++j) { Point p(vertices[j].x, vertices[j].y); pv.push_back(p); } std::sort(pv.begin(), pv.end(), [](const Point &e1, const Point &e2)->bool { return e2.y() < e1.y(); }); std::stable_sort(pv.begin(), pv.end(), [](const Point &e1, const Point &e2)->bool { return e2.x() < e1.x(); }); pv.erase(std::unique(pv.begin(), pv.end()), pv.end()); if (pv.size() != count && pv.size() < 3) { *err_msg = strdup("After eliminating duplicated points, less than 3 points remain!!. Alpha shape calculation needs at least 3 vertices."); return -1; } points.insert(points.begin(), pv.begin(), pv.end()); } Alpha_shape_2 A(points.begin(), points.end(), coord_type(10000), Alpha_shape_2::REGULARIZED); std::vector<Segment> segments; // std::vector<Segment> result; // Alpha_shape_2::Alpha_shape_vertices_iterator vit; // Alpha_shape_2::Vertex_handle vertex; // Alpha_shape_2::Alpha_shape_edges_iterator eit; // Alpha_shape_2::Edge edge; // Alpha_shape_2::Face_iterator fit; // Alpha_shape_2::Face_handle face; if (alpha <= 0.0) { alpha = *A.find_optimal_alpha(1); } A.set_alpha(alpha); alpha_edges( A, std::back_inserter(segments)); // Segment s = segments.at(0); // find_next_edge(s, segments, result); if (segments.empty()) { *res = NULL; *res_count = 0; } else { std::set<int> unusedIndexes; for (unsigned int i = 0; i < segments.size(); i++) { unusedIndexes.insert(i); } std::vector<Polygon_2> rings; Polygon_2 ring; ring.push_back(segments.at(0).source()); rings.push_back(ring); unusedIndexes.erase(0); find_next_edge(segments.at(0), segments, unusedIndexes, rings); size_t result_count = 0; for (unsigned int i = 0; i < rings.size(); i++) { Polygon_2 ring = rings.at(i); result_count += ring.size(); } result_count += rings.size() - 1; *res = (vertex_t *) malloc(sizeof(vertex_t) * result_count); *res_count = result_count; int idx = 0; for (unsigned int i = 0; i < rings.size(); i++) { if (i > 0) { (*res)[idx].x = DBL_MAX; (*res)[idx].y = DBL_MAX; idx++; } Polygon_2 ring = rings.at(i); for(unsigned int j = 0; j < ring.size(); j++) { Point point = ring.vertex(j); (*res)[idx].x = point.x(); (*res)[idx].y = point.y(); idx++; } } } *err_msg = NULL; return EXIT_SUCCESS; } catch ( ... ) { *err_msg = strdup("Caught unknown expection!"); } return -1; }