11 template<> struct mapbox::util::nth<1, glm::vec3> |
11 template<> struct mapbox::util::nth<1, glm::vec3> |
12 { |
12 { |
13 static constexpr float get(const glm::vec3& t) { return t.y; } |
13 static constexpr float get(const glm::vec3& t) { return t.y; } |
14 }; |
14 }; |
15 |
15 |
16 using indextype = std::uint16_t; |
16 namespace triangulate |
17 using indexpair = std::pair<indextype, indextype>; |
|
18 struct boundaryinfo |
|
19 { |
17 { |
20 indextype third; |
18 struct triangleid |
21 std::size_t triangleid; |
19 { |
22 }; |
20 std::size_t id; |
23 using boundarymap_t = std::map<indexpair, boundaryinfo>; |
21 constexpr auto operator<=>(const triangleid&) const = default; |
24 |
22 }; |
25 struct MergedTriangles |
23 //! \brief Index type of vertex |
26 { |
24 using index_t = std::uint16_t; |
27 std::vector<Quadrilateral> quadrilaterals; |
25 //! \brief Pair of vertex indices, forming a triangle boundary |
28 std::set<std::size_t> cutTriangles; |
26 using boundary_t = std::pair<index_t, index_t>; |
29 }; |
27 //! \brief Additional information about a triangle boundary |
|
28 struct triangleinfo |
|
29 { |
|
30 //! \brief What's the third vertex of this triangle |
|
31 index_t third_vertex; |
|
32 //! \brief Id of triangle (starting position of the triangle in the result |
|
33 //! value of mapbox::earcut) |
|
34 triangleid triangleid; |
|
35 }; |
|
36 using triangleinfomap_t = std::map<boundary_t, triangleinfo>; |
|
37 struct MergedTriangles |
|
38 { |
|
39 //! \brief List of merged quadrilaterals |
|
40 std::vector<Quadrilateral> quadrilaterals; |
|
41 //! \brief Ids of cut triangles |
|
42 std::set<triangleid> cutTriangles; |
|
43 }; |
|
44 static MergedTriangles mergeTriangles( |
|
45 const std::vector<std::uint16_t>& indices, |
|
46 std::vector<glm::vec3>::const_iterator polyBegin); |
|
47 } |
30 |
48 |
31 static bool findQuadsToMerge( |
49 static bool findQuadsToMerge( |
32 const boundarymap_t& boundaries, |
50 const triangulate::triangleinfomap_t& boundaries, |
33 auto&& iscut, |
51 auto&& iscut, |
34 auto&& addMergedQuad |
52 auto&& addMergedQuad |
35 ) { |
53 ) { |
36 bool foundQuads = false; |
54 bool foundQuads = false; |
37 // Go through triangle boundaries |
55 // Go through triangle boundaries |
38 for (boundarymap_t::const_iterator it1 = boundaries.begin(); it1 != boundaries.end(); ++it1) { |
56 for ( |
39 const indexpair& pair1 = it1->first; |
57 triangulate::triangleinfomap_t::const_iterator it1 = boundaries.begin(); |
40 const boundaryinfo& boundary1 = it1->second; |
58 it1 != boundaries.end(); |
|
59 ++it1 |
|
60 ) { |
|
61 const triangulate::boundary_t& boundary = it1->first; |
|
62 const triangulate::triangleinfo& earcut_triangle_1 = it1->second; |
41 // .. the ones we haven't already been merged... |
63 // .. the ones we haven't already been merged... |
42 if (not iscut(boundary1.triangleid)) { |
64 if (not iscut(earcut_triangle_1.triangleid)) { |
43 // Look for its inverse boundary to find the touching triangle |
65 // Look for its inverse boundary to find the touching triangle |
44 const indexpair inverse_boundary_key = std::make_pair(pair1.second, pair1.first); |
66 const triangulate::boundary_t inverse_boundary = std::make_pair(boundary.second, boundary.first); |
45 const boundarymap_t::const_iterator it2 = boundaries.find(inverse_boundary_key); |
67 const triangulate::triangleinfomap_t::const_iterator it2 = boundaries.find(inverse_boundary); |
46 // Also if that hasn't been cut |
68 // Also if that hasn't been cut |
47 if (it2 != boundaries.end() and not iscut(it2->second.triangleid)) { |
69 if (it2 != boundaries.end() and not iscut(it2->second.triangleid)) { |
48 // Continue until no more new quads are found |
70 // Continue until no more new quads are found |
49 foundQuads |= addMergedQuad(it1, it2); |
71 foundQuads |= addMergedQuad(it1, it2); |
50 } |
72 } |
51 } |
73 } |
52 } |
74 } |
53 return foundQuads; |
75 return foundQuads; |
54 } |
76 } |
55 |
77 |
56 static MergedTriangles mergeTriangles( |
78 static triangulate::MergedTriangles triangulate::mergeTriangles( |
57 const std::vector<std::uint16_t>& indices, |
79 const std::vector<std::uint16_t>& indices, |
58 std::vector<glm::vec3>::const_iterator polyBegin) |
80 std::vector<glm::vec3>::const_iterator polyBegin) |
59 { |
81 { |
60 MergedTriangles result; |
82 MergedTriangles result; |
61 const auto iscut = [&result](const std::size_t i){ |
83 const auto iscut = [&result](const triangleid i){ |
62 return result.cutTriangles.find(i) != result.cutTriangles.end(); |
84 return result.cutTriangles.find(i) != result.cutTriangles.end(); |
63 }; |
85 }; |
64 const auto addMergedQuad = [&result, polyBegin]( |
86 const auto addMergedQuad = [&result, polyBegin]( |
65 boundarymap_t::const_iterator it1, |
87 triangleinfomap_t::const_iterator it1, |
66 boundarymap_t::const_iterator it2 |
88 triangleinfomap_t::const_iterator it2 |
67 ) { |
89 ) { |
68 const indexpair& common_indices = it1->first; |
90 const boundary_t& shared_boundary = it1->first; |
69 const boundaryinfo& boundary_1 = it1->second; |
91 const triangleinfo& earcut_triangle_1 = it1->second; |
70 const boundaryinfo& boundary_2 = it2->second; |
92 const triangleinfo& earcut_triangle_2 = it2->second; |
71 const Quadrilateral quad{ |
93 const Quadrilateral quad{ |
72 *(polyBegin + common_indices.first), |
94 *(polyBegin + shared_boundary.first), |
73 *(polyBegin + boundary_2.third), |
95 *(polyBegin + earcut_triangle_2.third_vertex), |
74 *(polyBegin + common_indices.second), |
96 *(polyBegin + shared_boundary.second), |
75 *(polyBegin + boundary_1.third), |
97 *(polyBegin + earcut_triangle_1.third_vertex), |
76 }; |
98 }; |
77 if (isConvex(quad)) { |
99 if (isConvex(quad)) { |
78 result.quadrilaterals.push_back(quad); |
100 result.quadrilaterals.push_back(quad); |
79 result.cutTriangles.insert(boundary_1.triangleid); |
101 result.cutTriangles.insert(earcut_triangle_1.triangleid); |
80 result.cutTriangles.insert(boundary_2.triangleid); |
102 result.cutTriangles.insert(earcut_triangle_2.triangleid); |
81 return true; |
103 return true; |
82 } |
104 } |
83 else { |
105 else { |
84 return false; |
106 return false; |
85 } |
107 } |
86 }; |
108 }; |
87 boundarymap_t boundaries; |
109 triangleinfomap_t boundaries; |
88 for (std::size_t i = 0; i < indices.size(); i += 3) { |
110 for (std::size_t i = 0; i < indices.size(); i += 3) { |
89 const auto add = [&](const std::size_t o1, const std::size_t o2, const std::size_t o3){ |
111 const auto add = [&](const std::size_t o1, const std::size_t o2, const std::size_t o3){ |
90 const auto key = std::make_pair(indices[i + o1], indices[i + o2]); |
112 const auto key = std::make_pair(indices[i + o1], indices[i + o2]); |
91 boundaries[key] = {indices[i + o3], i}; |
113 boundaries[key] = triangleinfo{ |
|
114 .third_vertex = indices[i + o3], |
|
115 .triangleid = {i}, |
|
116 }; |
92 }; |
117 }; |
93 add(0, 1, 2); |
118 add(0, 1, 2); |
94 add(1, 2, 0); |
119 add(1, 2, 0); |
95 add(2, 0, 1); |
120 add(2, 0, 1); |
96 } |
121 } |
99 repeat = findQuadsToMerge(boundaries, iscut, addMergedQuad); |
124 repeat = findQuadsToMerge(boundaries, iscut, addMergedQuad); |
100 } |
125 } |
101 return result; |
126 return result; |
102 } |
127 } |
103 |
128 |
|
129 //! \brief Polygonize a polygon into triangles and try merge as many of them |
|
130 //! as possible into quadrilaterals. The polygons must all reside in the same |
|
131 //! plane. |
104 std::vector<PlainPolygonElement> polygonize( |
132 std::vector<PlainPolygonElement> polygonize( |
105 std::vector<glm::vec3>::const_iterator begin, |
133 std::vector<glm::vec3>::const_iterator begin, |
106 std::vector<glm::vec3>::const_iterator end, |
134 std::vector<glm::vec3>::const_iterator end) |
107 const glm::mat4& planeMatrix) |
|
108 { |
135 { |
109 std::vector<PlainPolygonElement> result; |
136 std::vector<PlainPolygonElement> result; |
110 const glm::mat4 inverseGrid = glm::inverse(planeMatrix); |
137 const glm::vec3 xvec = *begin - *(begin + 1); |
111 // mapbox::earcut will always produce a CCW polygon, so if we're drawing |
138 const glm::vec3 yvec = *(begin + 2) - *(begin + 1); |
112 // a CW polygon, we should invert the result afterwards |
139 const glm::vec3 zvec = glm::cross(xvec, yvec); |
113 const float shouldInvert = glm::dot( |
140 const glm::mat3 inverseMatrix = glm::inverse(glm::mat3{xvec, yvec, zvec}); |
114 glm::vec3{inverseGrid[2]}, |
|
115 glm::cross(*begin - *(begin + 1), *(begin + 2) - *(begin + 1))); |
|
116 std::vector<std::vector<glm::vec3>> polygons{1}; |
141 std::vector<std::vector<glm::vec3>> polygons{1}; |
117 std::vector<glm::vec3>& polygon2d = polygons.back(); |
142 std::vector<glm::vec3>& polygon2d = polygons.back(); |
118 polygon2d.reserve(static_cast<std::size_t>(end - begin)); |
143 polygon2d.reserve(static_cast<std::size_t>(end - begin)); |
119 for (std::vector<glm::vec3>::const_iterator it = begin; it != end; ++it) { |
144 for (std::vector<glm::vec3>::const_iterator it = begin; it != end; ++it) { |
120 polygon2d.push_back(inverseGrid * glm::vec4{*it, 1}); |
145 polygon2d.push_back(inverseMatrix * glm::vec4{*it, 1}); |
121 } |
146 } |
122 const std::vector<indextype> indices = mapbox::earcut<std::uint16_t>(polygons); |
147 const std::vector<triangulate::index_t> indices = mapbox::earcut<triangulate::index_t>(polygons); |
123 MergedTriangles mergedTriangles = mergeTriangles(indices, begin); |
148 triangulate::MergedTriangles mergedTriangles = triangulate::mergeTriangles(indices, begin); |
124 for (Quadrilateral& quad : mergedTriangles.quadrilaterals) { |
149 for (Quadrilateral& quad : mergedTriangles.quadrilaterals) { |
125 if (shouldInvert < 0) { |
|
126 invert(quad); |
|
127 } |
|
128 result.push_back(quad); |
150 result.push_back(quad); |
129 } |
151 } |
130 for (std::size_t i = 0; i < indices.size(); i += 3) { |
152 for (std::size_t i = 0; i < indices.size(); i += 3) { |
131 if (mergedTriangles.cutTriangles.find(i) == mergedTriangles.cutTriangles.end()) { |
153 if (not mergedTriangles.cutTriangles.contains({i})) { |
132 Triangle tri = triangle( |
154 Triangle tri = triangle( |
133 *(begin + indices[i]), |
155 *(begin + indices[i]), |
134 *(begin + indices[i + 1]), |
156 *(begin + indices[i + 1]), |
135 *(begin + indices[i + 2])); |
157 *(begin + indices[i + 2])); |
136 if (shouldInvert < 0) { |
|
137 invert(tri); |
|
138 } |
|
139 result.push_back(tri); |
158 result.push_back(tri); |
140 } |
159 } |
141 } |
160 } |
142 return result; |
161 return result; |
143 } |
162 } |