#include "GenerateContours.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace MeshGenerator { namespace { struct output_visitor : public boost::planar_face_traversal_visitor { void begin_face() { //std::cout << "New face: "; } void end_face() { //std::cout << std::endl; } }; struct vertex_output_visitor : public boost::planar_face_traversal_visitor { std::function)> _onFace; std::vector _currentFace; vertex_output_visitor(std::function const &)> &&onFace) : _onFace(std::move(onFace)) { } template void next_vertex(Vertex v) { _currentFace.push_back((int)v); } void begin_face() { _currentFace.clear(); } void end_face() { _onFace(_currentFace); _currentFace.clear(); } }; bool get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y) { typedef double coordinate_type; typedef boost::geometry::model::d2::point_xy point; typedef boost::geometry::model::segment Segment; Segment s0(point(p0_x, p0_y), point(p1_x, p1_y)); Segment s1(point(p2_x, p2_y), point(p3_x, p3_y)); std::vector output; boost::geometry::intersection(s0, s1, output); if (output.empty()) { return false; } if (i_x) { *i_x = output[0].x(); } if (i_y) { *i_y = output[0].y(); } return true; } int addPoint(std::vector &points, std::map &pointIndex, Point const &point) { auto currentIndex = pointIndex.find(point); if (currentIndex != pointIndex.end()) { return currentIndex->second; } int index = (int)points.size(); pointIndex.insert(std::make_pair(point, index)); points.push_back(point); return index; } struct TempEdge { int index; Point v0; Point v1; explicit TempEdge(int index_, Point v0_, Point v1_) : index(index_), v0(v0_), v1(v1_) { } }; void enumerateEdges(Path const &path, std::function f) { TempEdge edge(0, Point(0.0f, 0.0f), Point(0.0f, 0.0f)); for (int i = 1; i < path.points.size(); i++) { edge.index = i - 1; edge.v0 = path.points[i - 1]; edge.v1 = path.points[i]; f(edge); } } } std::vector generateStroke(std::vector const &paths, float lineWidth, float miterLimit, LineJoin lineJoin, LineCap lineCap) { namespace bg = boost::geometry; typedef double coordinate_type; typedef boost::geometry::model::d2::point_xy point; typedef boost::geometry::model::polygon polygon; // Declare strategies const double buffer_distance = lineWidth / 2.0f; const int points_per_circle = 20; boost::geometry::strategy::buffer::distance_symmetric distance_strategy(buffer_distance); boost::geometry::strategy::buffer::join_round join_round(points_per_circle); boost::geometry::strategy::buffer::join_miter join_miter(miterLimit); boost::geometry::strategy::buffer::end_round end_round(points_per_circle); boost::geometry::strategy::buffer::end_flat end_flat; boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle); boost::geometry::strategy::buffer::side_straight side_strategy; boost::geometry::model::multi_polygon results; for (const auto &path : paths) { // Declare output boost::geometry::model::multi_polygon result; // Declare/fill a linestring boost::geometry::model::linestring ls; std::vector points; for (auto p : path.points) { points.emplace_back(p.x, p.y); } boost::geometry::assign_points(ls, points); // Create the buffer of a linestring boost::geometry::buffer(ls, result, distance_strategy, side_strategy, join_round, end_round, circle_strategy); for (auto &it : result) { results.push_back(std::move(it)); } } std::vector resultPaths; boost::geometry::model::multi_polygon border; // the unioned polygons boost::geometry::model::multi_polygon tmp_poly; // a temporary variable for (const polygon &p : results) { // add another polygon each iteration bg::union_(border, p, tmp_poly); border = tmp_poly; boost::geometry::clear(tmp_poly); } assert(boost::geometry::is_valid(border)); for (const auto &poly : border) { Path path; for (const auto &p : poly.outer()) { path.points.emplace_back((float)p.x(), (float)p.y()); } resultPaths.push_back(std::move(path)); for (const auto &inner : poly.inners()) { Path path; for (const auto &p : inner) { path.points.emplace_back((float)p.x(), (float)p.y()); } resultPaths.push_back(std::move(path)); } } return resultPaths; } std::unique_ptr makePlanarStraightLineGraph(std::vector const &paths) { std::unique_ptr result = std::make_unique(); std::map pointIndex; namespace bg = boost::geometry; typedef bg::model::d2::point_xy point_type; typedef bg::model::polygon polygon; typedef bg::model::multi_polygon multi_polygon; multi_polygon sourcePoly; for (const auto &path : paths) { polygon poly; std::vector points; for (auto point : path.points) { points.emplace_back(point.x, point.y); } boost::geometry::assign_points(poly, points); sourcePoly.push_back(std::move(poly)); } boost::geometry::validity_failure_type failure; if (boost::geometry::is_valid(sourcePoly, failure)) { for (int iPath = 0; iPath < paths.size(); iPath++) { enumerateEdges(paths[iPath], [&](const TempEdge &pathEdge) { int startingPointIndex = addPoint(result->points, pointIndex, pathEdge.v0); int endPointIndex = addPoint(result->points, pointIndex, pathEdge.v1); if (endPointIndex != startingPointIndex) { result->edges.push_back(PlanarStraightLineGraph::Edge(startingPointIndex, endPointIndex)); } }); } } else { for (int iPath = 0; iPath < paths.size(); iPath++) { enumerateEdges(paths[iPath], [&](const TempEdge &pathEdge) { int startingPointIndex = addPoint(result->points, pointIndex, pathEdge.v0); std::vector intersections; for (int iOtherPath = 0; iOtherPath < paths.size(); iOtherPath++) { enumerateEdges(paths[iOtherPath], [&](const TempEdge &otherPathEdge) { if (iPath == iOtherPath) { if (pathEdge.index == otherPathEdge.index) { return; } if (otherPathEdge.v0.isEqual(pathEdge.v0) || otherPathEdge.v0.isEqual(pathEdge.v1) || otherPathEdge.v1.isEqual(pathEdge.v0) || otherPathEdge.v1.isEqual(pathEdge.v1)) { return; } } Point intersectionPoint(0.0f, 0.0f); if (get_line_intersection(pathEdge.v0.x, pathEdge.v0.y, pathEdge.v1.x, pathEdge.v1.y, otherPathEdge.v0.x, otherPathEdge.v0.y, otherPathEdge.v1.x, otherPathEdge.v1.y, &intersectionPoint.x, &intersectionPoint.y)) { intersections.push_back(intersectionPoint); } }); } std::sort(intersections.begin(), intersections.end(), [&](Point const &lhs, Point const &rhs) { float lhsDistance = pathEdge.v0.distance(lhs); float rhsDistance = pathEdge.v0.distance(rhs); return lhsDistance < rhsDistance; }); for (const auto &intersectionPoint : intersections) { int intersectionPointIndex = addPoint(result->points, pointIndex, intersectionPoint); if (intersectionPointIndex != startingPointIndex) { result->edges.push_back(PlanarStraightLineGraph::Edge(startingPointIndex, intersectionPointIndex)); } startingPointIndex = intersectionPointIndex; } int endPointIndex = addPoint(result->points, pointIndex, pathEdge.v1); if (endPointIndex != startingPointIndex) { result->edges.push_back(PlanarStraightLineGraph::Edge(startingPointIndex, endPointIndex)); } }); } } return result; } std::vector findFaces(PlanarStraightLineGraph const &graph) { using namespace boost; typedef adjacency_list < vecS, vecS, undirectedS, property, property > ParsedGraph; ParsedGraph parsedGraph(graph.points.size()); for (const auto &edge : graph.edges) { add_edge(edge.v0, edge.v1, parsedGraph); } // Initialize the interior edge index property_map::type e_index = get(edge_index, parsedGraph); graph_traits::edges_size_type edge_count = 0; graph_traits::edge_iterator ei, ei_end; std::map> vertexToEdges; std::vector::edge_descriptor> allEdges; for (tie(ei, ei_end) = edges(parsedGraph); ei != ei_end; ++ei) { int edgeIndex = edge_count++; bool sourceFound = false; for (auto index : vertexToEdges[ei->m_source]) { if (index == edgeIndex) { sourceFound = true; break; } } if (!sourceFound) { vertexToEdges[ei->m_source].push_back(edgeIndex); } bool targetFound = false; for (auto index : vertexToEdges[ei->m_target]) { if (index == edgeIndex) { targetFound = true; break; } } if (!targetFound) { vertexToEdges[ei->m_target].push_back(edgeIndex); } allEdges.push_back(*ei); put(e_index, *ei, edgeIndex); } typedef std::vector::edge_descriptor> vec_t; std::vector embedding(num_vertices(parsedGraph)); std::function::edge_descriptor const &)> getVectorAngle = [&](int vertexIndex, graph_traits::edge_descriptor const &edge) { Point vertex = graph.points[vertexIndex]; Point otherVertex(0.0f, 0.0f); if (edge.m_source == vertexIndex) { otherVertex = graph.points[edge.m_target]; } else { otherVertex = graph.points[edge.m_source]; } Point vector(otherVertex.x - vertex.x, otherVertex.y - vertex.y); Point upVector(0.0f, 1.0f); float dot = upVector.x * vector.x + upVector.y * vector.y; float det = upVector.x * vector.y - upVector.y * vector.x; float angle = atan2(det, dot); return angle; }; for (int i = 0; i < graph.points.size(); i++) { std::vector::edge_descriptor> vertexEdgeIndices; for (auto edgeIndex : vertexToEdges[i]) { vertexEdgeIndices.push_back(allEdges[edgeIndex]); } /*for (tie(ei, ei_end) = edges(parsedGraph); ei != ei_end; ++ei) { if (ei->m_source == i || ei->m_target == i) { vertexEdgeIndices.push_back(*ei); } }*/ std::sort(vertexEdgeIndices.begin(), vertexEdgeIndices.end(), [&](graph_traits::edge_descriptor const &lhs, graph_traits::edge_descriptor const &rhs) { auto lhsAngle = getVectorAngle(i, lhs); auto rhsAngle = getVectorAngle(i, rhs); return lhsAngle < rhsAngle; }); for (const auto &it : vertexEdgeIndices) { embedding[i].push_back(it); } } std::vector faces; //std::cout << std::endl << "Vertices on the faces: " << std::endl; vertex_output_visitor v_vis([&](std::vector vertices) { Face face; for (auto index : vertices) { face.vertices.push_back(index); } faces.push_back(std::move(face)); }); planar_face_traversal(parsedGraph, &embedding[0], v_vis); return faces; } bool faceInsideFace(PlanarStraightLineGraph const &graph, Face const &face, Face const &otherFace) { typedef boost::geometry::model::d2::point_xy point_type; typedef boost::geometry::model::polygon polygon_type; polygon_type poly1; std::vector points1; for (auto index : face.vertices) { points1.emplace_back(graph.points[index].x, graph.points[index].y); } boost::geometry::assign_points(poly1, points1); point_type poly2(graph.points[otherFace.vertices[0]].x, graph.points[otherFace.vertices[0]].y); bool result = boost::geometry::within(poly2, poly1); return result; } float triangleArea(Point const &v1, Point const &v2, Point const &v3) { return v1.x * (v2.y - v3.y) + v2.x * (v3.y - v1.y) + v3.x * (v1.y - v2.y); } bool traceRay(std::vector const &paths, Point const &sourcePoint, bool isNonZero) { int intersectionCount = 0; int intersectionValue = 0; for (const auto &path : paths) { enumerateEdges(path, [&](const TempEdge &edge) { if (get_line_intersection(sourcePoint.x, sourcePoint.y, sourcePoint.x + 10000.0f, sourcePoint.y, edge.v0.x, edge.v0.y, edge.v1.x, edge.v1.y, nullptr, nullptr)) { intersectionCount++; int addValue = 0; if (edge.v0.y < edge.v1.y) { addValue = 1; } else { addValue = -1; } intersectionValue += addValue; } }); } if (isNonZero) { return intersectionValue != 0; } else { return intersectionCount % 2 != 0; } } }