1 /*
2 Copyright (C) 2010-2014 Kristian Duske
3
4 This file is part of TrenchBroom.
5
6 TrenchBroom is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 TrenchBroom is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef TrenchBroom_Polyhedron_Misc_h
21 #define TrenchBroom_Polyhedron_Misc_h
22
23 #include <map>
24
25 template <typename T, typename FP, typename VP>
26 class Polyhedron<T,FP,VP>::VertexDistanceCmp {
27 private:
28 V m_anchor;
29 public:
VertexDistanceCmp(const V & anchor)30 VertexDistanceCmp(const V& anchor) :
31 m_anchor(anchor) {}
32
operator()33 bool operator()(const Vertex* lhs, const Vertex* rhs) const {
34 const T lDist = m_anchor.squaredDistanceTo(lhs->position());
35 const T rDist = m_anchor.squaredDistanceTo(rhs->position());
36 if (lDist < rDist)
37 return true;
38 if (lDist > rDist)
39 return false;
40 return lhs->position().compare(rhs->position()) < 0;
41 }
42 };
43
44
45 template <typename T, typename FP, typename VP>
operator()46 const typename Polyhedron<T,FP,VP>::V& Polyhedron<T,FP,VP>::GetVertexPosition::operator()(const Vertex* vertex) const {
47 return vertex->position();
48 }
49
50 template <typename T, typename FP, typename VP>
operator()51 const typename Polyhedron<T,FP,VP>::V& Polyhedron<T,FP,VP>::GetVertexPosition::operator()(const HalfEdge* halfEdge) const {
52 return halfEdge->origin()->position();
53 }
54
55 template <typename T, typename FP, typename VP>
~Callback()56 Polyhedron<T,FP,VP>::Callback::~Callback() {}
57
58 template <typename T, typename FP, typename VP>
plane(const Face * face)59 Plane<T,3> Polyhedron<T,FP,VP>::Callback::plane(const Face* face) const {
60 const HalfEdgeList& boundary = face->boundary();
61 assert(boundary.size() >= 3);
62
63 const HalfEdge* e1 = boundary.front();
64 const HalfEdge* e2 = e1->next();
65 const HalfEdge* e3 = e2->next();
66
67 const V& p1 = e1->origin()->position();
68 const V& p2 = e2->origin()->position();
69 const V& p3 = e3->origin()->position();
70
71 Plane<T,3> plane;
72 assertResult(setPlanePoints(plane, p2, p1, p3));
73 return plane;
74 }
75
76 template <typename T, typename FP, typename VP>
faceWasCreated(Face * face)77 void Polyhedron<T,FP,VP>::Callback::faceWasCreated(Face* face) {}
78
79 template <typename T, typename FP, typename VP>
faceWillBeDeleted(Face * face)80 void Polyhedron<T,FP,VP>::Callback::faceWillBeDeleted(Face* face) {}
81
82 template <typename T, typename FP, typename VP>
faceDidChange(Face * face)83 void Polyhedron<T,FP,VP>::Callback::faceDidChange(Face* face) {}
84
85 template <typename T, typename FP, typename VP>
faceWasSplit(Face * original,Face * clone)86 void Polyhedron<T,FP,VP>::Callback::faceWasSplit(Face* original, Face* clone) {}
87
88 template <typename T, typename FP, typename VP>
facesWillBeMerged(Face * remaining,Face * toDelete)89 void Polyhedron<T,FP,VP>::Callback::facesWillBeMerged(Face* remaining, Face* toDelete) {}
90
91 template <typename T, typename FP, typename VP>
Polyhedron()92 Polyhedron<T,FP,VP>::Polyhedron() {
93 updateBounds();
94 }
95
96 template <typename T, typename FP, typename VP>
Polyhedron(const V & p1,const V & p2,const V & p3,const V & p4)97 Polyhedron<T,FP,VP>::Polyhedron(const V& p1, const V& p2, const V& p3, const V& p4) {
98 Callback c;
99 addPoints(p1, p2, p3, p4, c);
100 }
101
102 template <typename T, typename FP, typename VP>
Polyhedron(const V & p1,const V & p2,const V & p3,const V & p4,Callback & callback)103 Polyhedron<T,FP,VP>::Polyhedron(const V& p1, const V& p2, const V& p3, const V& p4, Callback& callback) {
104 addPoints(p1, p2, p3, p4, callback);
105 }
106
107 template <typename T, typename FP, typename VP>
Polyhedron(const BBox<T,3> & bounds)108 Polyhedron<T,FP,VP>::Polyhedron(const BBox<T,3>& bounds) {
109 Callback c;
110 setBounds(bounds, c);
111 }
112
113 template <typename T, typename FP, typename VP>
Polyhedron(const BBox<T,3> & bounds,Callback & callback)114 Polyhedron<T,FP,VP>::Polyhedron(const BBox<T,3>& bounds, Callback& callback) {
115 setBounds(bounds, callback);
116 }
117
118 template <typename T, typename FP, typename VP>
Polyhedron(const typename V::List & positions)119 Polyhedron<T,FP,VP>::Polyhedron(const typename V::List& positions) {
120 Callback c;
121 addPoints(positions.begin(), positions.end(), c);
122 }
123
124 template <typename T, typename FP, typename VP>
Polyhedron(const typename V::List & positions,Callback & callback)125 Polyhedron<T,FP,VP>::Polyhedron(const typename V::List& positions, Callback& callback) {
126 addPoints(positions.begin(), positions.end(), callback);
127 }
128
129 template <typename T, typename FP, typename VP>
Polyhedron(const typename V::Set & positions)130 Polyhedron<T,FP,VP>::Polyhedron(const typename V::Set& positions) {
131 Callback c;
132 addPoints(positions.begin(), positions.end(), c);
133 }
134
135 template <typename T, typename FP, typename VP>
Polyhedron(const typename V::Set & positions,Callback & callback)136 Polyhedron<T,FP,VP>::Polyhedron(const typename V::Set& positions, Callback& callback) {
137 addPoints(positions.begin(), positions.end(), callback);
138 }
139
140 template <typename T, typename FP, typename VP>
addPoints(const V & p1,const V & p2,const V & p3,const V & p4,Callback & callback)141 void Polyhedron<T,FP,VP>::addPoints(const V& p1, const V& p2, const V& p3, const V& p4, Callback& callback) {
142 addPoint(p1, callback);
143 addPoint(p2, callback);
144 addPoint(p3, callback);
145 addPoint(p4, callback);
146 }
147
148 template <typename T, typename FP, typename VP>
setBounds(const BBox<T,3> & bounds,Callback & callback)149 void Polyhedron<T,FP,VP>::setBounds(const BBox<T,3>& bounds, Callback& callback) {
150 if (bounds.min == bounds.max) {
151 addPoint(bounds.min);
152 return;
153 }
154
155 // Explicitely create the polyhedron for better performance when building brushes.
156
157 const V p1(bounds.min.x(), bounds.min.y(), bounds.min.z());
158 const V p2(bounds.min.x(), bounds.min.y(), bounds.max.z());
159 const V p3(bounds.min.x(), bounds.max.y(), bounds.min.z());
160 const V p4(bounds.min.x(), bounds.max.y(), bounds.max.z());
161 const V p5(bounds.max.x(), bounds.min.y(), bounds.min.z());
162 const V p6(bounds.max.x(), bounds.min.y(), bounds.max.z());
163 const V p7(bounds.max.x(), bounds.max.y(), bounds.min.z());
164 const V p8(bounds.max.x(), bounds.max.y(), bounds.max.z());
165
166 Vertex* v1 = new Vertex(p1);
167 Vertex* v2 = new Vertex(p2);
168 Vertex* v3 = new Vertex(p3);
169 Vertex* v4 = new Vertex(p4);
170 Vertex* v5 = new Vertex(p5);
171 Vertex* v6 = new Vertex(p6);
172 Vertex* v7 = new Vertex(p7);
173 Vertex* v8 = new Vertex(p8);
174
175 m_vertices.append(v1, 1);
176 m_vertices.append(v2, 1);
177 m_vertices.append(v3, 1);
178 m_vertices.append(v4, 1);
179 m_vertices.append(v5, 1);
180 m_vertices.append(v6, 1);
181 m_vertices.append(v7, 1);
182 m_vertices.append(v8, 1);
183
184 // Front face
185 HalfEdge* f1h1 = new HalfEdge(v1);
186 HalfEdge* f1h2 = new HalfEdge(v5);
187 HalfEdge* f1h3 = new HalfEdge(v6);
188 HalfEdge* f1h4 = new HalfEdge(v2);
189 HalfEdgeList f1b;
190 f1b.append(f1h1, 1);
191 f1b.append(f1h2, 1);
192 f1b.append(f1h3, 1);
193 f1b.append(f1h4, 1);
194 m_faces.append(new Face(f1b), 1);
195
196 // Left face
197 HalfEdge* f2h1 = new HalfEdge(v1);
198 HalfEdge* f2h2 = new HalfEdge(v2);
199 HalfEdge* f2h3 = new HalfEdge(v4);
200 HalfEdge* f2h4 = new HalfEdge(v3);
201 HalfEdgeList f2b;
202 f2b.append(f2h1, 1);
203 f2b.append(f2h2, 1);
204 f2b.append(f2h3, 1);
205 f2b.append(f2h4, 1);
206 m_faces.append(new Face(f2b), 1);
207
208 // Bottom face
209 HalfEdge* f3h1 = new HalfEdge(v1);
210 HalfEdge* f3h2 = new HalfEdge(v3);
211 HalfEdge* f3h3 = new HalfEdge(v7);
212 HalfEdge* f3h4 = new HalfEdge(v5);
213 HalfEdgeList f3b;
214 f3b.append(f3h1, 1);
215 f3b.append(f3h2, 1);
216 f3b.append(f3h3, 1);
217 f3b.append(f3h4, 1);
218 m_faces.append(new Face(f3b), 1);
219
220 // Top face
221 HalfEdge* f4h1 = new HalfEdge(v2);
222 HalfEdge* f4h2 = new HalfEdge(v6);
223 HalfEdge* f4h3 = new HalfEdge(v8);
224 HalfEdge* f4h4 = new HalfEdge(v4);
225 HalfEdgeList f4b;
226 f4b.append(f4h1, 1);
227 f4b.append(f4h2, 1);
228 f4b.append(f4h3, 1);
229 f4b.append(f4h4, 1);
230 m_faces.append(new Face(f4b), 1);
231
232 // Back face
233 HalfEdge* f5h1 = new HalfEdge(v3);
234 HalfEdge* f5h2 = new HalfEdge(v4);
235 HalfEdge* f5h3 = new HalfEdge(v8);
236 HalfEdge* f5h4 = new HalfEdge(v7);
237 HalfEdgeList f5b;
238 f5b.append(f5h1, 1);
239 f5b.append(f5h2, 1);
240 f5b.append(f5h3, 1);
241 f5b.append(f5h4, 1);
242 m_faces.append(new Face(f5b), 1);
243
244 // Right face
245 HalfEdge* f6h1 = new HalfEdge(v5);
246 HalfEdge* f6h2 = new HalfEdge(v7);
247 HalfEdge* f6h3 = new HalfEdge(v8);
248 HalfEdge* f6h4 = new HalfEdge(v6);
249 HalfEdgeList f6b;
250 f6b.append(f6h1, 1);
251 f6b.append(f6h2, 1);
252 f6b.append(f6h3, 1);
253 f6b.append(f6h4, 1);
254 m_faces.append(new Face(f6b), 1);
255
256 m_edges.append(new Edge(f1h4, f2h1), 1); // v1, v2
257 m_edges.append(new Edge(f2h4, f3h1), 1); // v1, v3
258 m_edges.append(new Edge(f1h1, f3h4), 1); // v1, v5
259 m_edges.append(new Edge(f2h2, f4h4), 1); // v2, v4
260 m_edges.append(new Edge(f4h1, f1h3), 1); // v2, v6
261 m_edges.append(new Edge(f2h3, f5h1), 1); // v3, v4
262 m_edges.append(new Edge(f3h2, f5h4), 1); // v3, v7
263 m_edges.append(new Edge(f4h3, f5h2), 1); // v4, v8
264 m_edges.append(new Edge(f1h2, f6h4), 1); // v5, v6
265 m_edges.append(new Edge(f6h1, f3h3), 1); // v5, v7
266 m_edges.append(new Edge(f6h3, f4h2), 1); // v6, v8
267 m_edges.append(new Edge(f6h2, f5h3), 1); // v7, v8
268 }
269
270 template <typename T, typename FP, typename VP>
271 class Polyhedron<T,FP,VP>::Copy {
272 private:
273 typedef std::map<const Vertex*, Vertex*> VertexMap;
274 typedef typename VertexMap::value_type VertexMapEntry;
275
276 typedef std::map<const HalfEdge*, HalfEdge*> HalfEdgeMap;
277 typedef typename HalfEdgeMap::value_type HalfEdgeMapEntry;
278
279 VertexMap m_vertexMap;
280 HalfEdgeMap m_halfEdgeMap;
281
282 VertexList m_vertices;
283 EdgeList m_edges;
284 FaceList m_faces;
285 Polyhedron& m_destination;
286 public:
Copy(const FaceList & originalFaces,const EdgeList & originalEdges,Polyhedron & destination)287 Copy(const FaceList& originalFaces, const EdgeList& originalEdges, Polyhedron& destination) :
288 m_destination(destination) {
289 copyFaces(originalFaces);
290 copyEdges(originalEdges);
291 swapContents();
292 }
293 private:
copyFaces(const FaceList & originalFaces)294 void copyFaces(const FaceList& originalFaces) {
295 typename FaceList::const_iterator fIt, fEnd;
296 for (fIt = originalFaces.begin(), fEnd = originalFaces.end(); fIt != fEnd; ++fIt) {
297 const Face* originalFace = *fIt;
298 copyFace(originalFace);
299 }
300 }
301
copyFace(const Face * originalFace)302 void copyFace(const Face* originalFace) {
303 HalfEdgeList myBoundary;
304
305 typename HalfEdgeList::const_iterator hIt, hEnd;
306 for (hIt = originalFace->m_boundary.begin(), hEnd = originalFace->m_boundary.end(); hIt != hEnd; ++hIt) {
307 const HalfEdge* originalHalfEdge = *hIt;
308 myBoundary.append(copyHalfEdge(originalHalfEdge), 1);
309 }
310
311 Face* copy = new Face(myBoundary);
312 m_faces.append(copy, 1);
313 }
314
copyHalfEdge(const HalfEdge * original)315 HalfEdge* copyHalfEdge(const HalfEdge* original) {
316 const Vertex* originalOrigin = original->origin();
317
318 Vertex* myOrigin = findOrCopyVertex(originalOrigin);
319 HalfEdge* copy = new HalfEdge(myOrigin);
320 m_halfEdgeMap.insert(std::make_pair(original, copy));
321 return copy;
322 }
323
findOrCopyVertex(const Vertex * original)324 Vertex* findOrCopyVertex(const Vertex* original) {
325 typedef std::pair<bool, typename VertexMap::iterator> InsertPos;
326
327 InsertPos insertPos = MapUtils::findInsertPos(m_vertexMap, original);
328 if (!insertPos.first) {
329 Vertex* copy = new Vertex(original->position());
330 m_vertices.append(copy, 1);
331 m_vertexMap.insert(insertPos.second, std::make_pair(original, copy));
332 return copy;
333 }
334 return insertPos.second->second;
335 }
336
copyEdges(const EdgeList & originalEdges)337 void copyEdges(const EdgeList& originalEdges) {
338 typename EdgeList::const_iterator eIt, eEnd;
339 for (eIt = originalEdges.begin(), eEnd = originalEdges.end(); eIt != eEnd; ++eIt) {
340 const Edge* originalEdge = *eIt;
341 Edge* copy = copyEdge(originalEdge);
342 m_edges.append(copy, 1);
343 }
344 }
345
copyEdge(const Edge * original)346 Edge* copyEdge(const Edge* original) const {
347 HalfEdge* myFirst = findHalfEdge(original->firstEdge());
348 if (!original->fullySpecified())
349 return new Edge(myFirst);
350
351 HalfEdge* mySecond = findHalfEdge(original->secondEdge());
352 return new Edge(myFirst, mySecond);
353 }
354
findHalfEdge(const HalfEdge * original)355 HalfEdge* findHalfEdge(const HalfEdge* original) const {
356 HalfEdge* result = MapUtils::find(m_halfEdgeMap, original, static_cast<HalfEdge*>(NULL));
357 assert(result != NULL);
358 return result;
359 }
360
swapContents()361 void swapContents() {
362 using std::swap;
363 swap(m_vertices, m_destination.m_vertices);
364 swap(m_edges, m_destination.m_edges);
365 swap(m_faces, m_destination.m_faces);
366 m_destination.updateBounds();
367 }
368 };
369
370 template <typename T, typename FP, typename VP>
Polyhedron(const Polyhedron<T,FP,VP> & other)371 Polyhedron<T,FP,VP>::Polyhedron(const Polyhedron<T,FP,VP>& other) {
372 Copy copy(other.faces(), other.edges(), *this);
373 }
374
375 template <typename T, typename FP, typename VP>
~Polyhedron()376 Polyhedron<T,FP,VP>::~Polyhedron() {
377 clear();
378 }
379
380 template <typename T, typename FP, typename VP>
381 Polyhedron<T,FP,VP>& Polyhedron<T,FP,VP>::operator=(Polyhedron<T,FP,VP> other) {
382 swap(*this, other);
383 return *this;
384 }
385
386 template <typename T, typename FP, typename VP>
vertexCount()387 size_t Polyhedron<T,FP,VP>::vertexCount() const {
388 return m_vertices.size();
389 }
390
391 template <typename T, typename FP, typename VP>
vertices()392 const typename Polyhedron<T,FP,VP>::VertexList& Polyhedron<T,FP,VP>::vertices() const {
393 return m_vertices;
394 }
395
396 template <typename T, typename FP, typename VP>
hasVertex(const V & position,const T epsilon)397 bool Polyhedron<T,FP,VP>::hasVertex(const V& position, const T epsilon) const {
398 return findVertexByPosition(position, NULL, epsilon) != NULL;
399 }
400
401 template <typename T, typename FP, typename VP>
hasVertices(const typename V::List & positions,const T epsilon)402 bool Polyhedron<T,FP,VP>::hasVertices(const typename V::List& positions, const T epsilon) const {
403 if (positions.size() != vertexCount())
404 return false;
405 typename V::List::const_iterator it, end;
406 for (it = positions.begin(), end = positions.end(); it != end; ++it) {
407 if (!hasVertex(*it, epsilon))
408 return false;
409 }
410 return true;
411 }
412
413 template <typename T, typename FP, typename VP>
printVertices()414 void Polyhedron<T,FP,VP>::printVertices() const {
415 const Vertex* firstVertex = m_vertices.front();
416 const Vertex* currentVertex = firstVertex;
417 do {
418 std::cout << currentVertex->position().asString() << std::endl;
419 currentVertex = currentVertex->next();
420 } while (currentVertex != firstVertex);
421 }
422
423
424 template <typename T, typename FP, typename VP>
edgeCount()425 size_t Polyhedron<T,FP,VP>::edgeCount() const {
426 return m_edges.size();
427 }
428
429 template <typename T, typename FP, typename VP>
edges()430 const typename Polyhedron<T,FP,VP>::EdgeList& Polyhedron<T,FP,VP>::edges() const {
431 return m_edges;
432 }
433
434 template <typename T, typename FP, typename VP>
hasEdge(const V & pos1,const V & pos2,const T epsilon)435 bool Polyhedron<T,FP,VP>::hasEdge(const V& pos1, const V& pos2, const T epsilon) const {
436 return findEdgeByPositions(pos1, pos2, epsilon) != NULL;
437 }
438
439 template <typename T, typename FP, typename VP>
faceCount()440 size_t Polyhedron<T,FP,VP>::faceCount() const {
441 return m_faces.size();
442 }
443
444 template <typename T, typename FP, typename VP>
faces()445 const typename Polyhedron<T,FP,VP>::FaceList& Polyhedron<T,FP,VP>::faces() const {
446 return m_faces;
447 }
448
449 template <typename T, typename FP, typename VP>
hasFace(const typename V::List & positions,const T epsilon)450 bool Polyhedron<T,FP,VP>::hasFace(const typename V::List& positions, const T epsilon) const {
451 return findFaceByPositions(positions, epsilon) != NULL;
452 }
453
454 template <typename T, typename FP, typename VP>
bounds()455 const BBox<T,3>& Polyhedron<T,FP,VP>::bounds() const {
456 return m_bounds;
457 }
458
459 template <typename T, typename FP, typename VP>
empty()460 bool Polyhedron<T,FP,VP>::empty() const {
461 return vertexCount() == 0;
462 }
463
464 template <typename T, typename FP, typename VP>
point()465 bool Polyhedron<T,FP,VP>::point() const {
466 return vertexCount() == 1;
467 }
468
469 template <typename T, typename FP, typename VP>
edge()470 bool Polyhedron<T,FP,VP>::edge() const {
471 return vertexCount() == 2;
472 }
473
474 template <typename T, typename FP, typename VP>
polygon()475 bool Polyhedron<T,FP,VP>::polygon() const {
476 return faceCount() == 1;
477 }
478
479 template <typename T, typename FP, typename VP>
polyhedron()480 bool Polyhedron<T,FP,VP>::polyhedron() const {
481 return faceCount() > 3;
482 }
483
484 template <typename T, typename FP, typename VP>
closed()485 bool Polyhedron<T,FP,VP>::closed() const {
486 return vertexCount() + faceCount() == edgeCount() + 2;
487 }
488
489 template <typename T, typename FP, typename VP>
clear()490 void Polyhedron<T,FP,VP>::clear() {
491 m_faces.clear();
492 m_edges.clear();
493 m_vertices.clear();
494 }
495
496 template <typename T, typename FP, typename VP>
FaceHit(Face * i_face,const T i_distance)497 Polyhedron<T,FP,VP>::FaceHit::FaceHit(Face* i_face, const T i_distance) : face(i_face), distance(i_distance) {}
498
499 template <typename T, typename FP, typename VP>
FaceHit()500 Polyhedron<T,FP,VP>::FaceHit::FaceHit() : face(NULL), distance(Math::nan<T>()) {}
501
502 template <typename T, typename FP, typename VP>
isMatch()503 bool Polyhedron<T,FP,VP>::FaceHit::isMatch() const { return face != NULL; }
504
505 template <typename T, typename FP, typename VP>
pickFace(const Ray<T,3> & ray)506 typename Polyhedron<T,FP,VP>::FaceHit Polyhedron<T,FP,VP>::pickFace(const Ray<T,3>& ray) const {
507 const Math::Side side = polygon() ? Math::Side_Both : Math::Side_Front;
508 Face* firstFace = m_faces.front();
509 Face* currentFace = firstFace;
510 do {
511 const T distance = currentFace->intersectWithRay(ray, side);
512 if (!Math::isnan(distance))
513 return FaceHit(currentFace, distance);
514 currentFace = currentFace->next();
515 } while (currentFace != firstFace);
516 return FaceHit();
517 }
518
519 template <typename T, typename FP, typename VP>
findVertexByPosition(const V & position,const Vertex * except,const T epsilon)520 typename Polyhedron<T,FP,VP>::Vertex* Polyhedron<T,FP,VP>::findVertexByPosition(const V& position, const Vertex* except, const T epsilon) const {
521 Vertex* firstVertex = m_vertices.front();
522 Vertex* currentVertex = firstVertex;
523 do {
524 if (currentVertex != except && position.equals(currentVertex->position(), epsilon))
525 return currentVertex;
526 currentVertex = currentVertex->next();
527 } while (currentVertex != firstVertex);
528 return NULL;
529 }
530
531 template <typename T, typename FP, typename VP>
findClosestVertex(const V & position)532 typename Polyhedron<T,FP,VP>::Vertex* Polyhedron<T,FP,VP>::findClosestVertex(const V& position) const {
533 T closestDistance = std::numeric_limits<T>::max();
534 Vertex* closestVertex = NULL;
535
536 Vertex* firstVertex = m_vertices.front();
537 Vertex* currentVertex = firstVertex;
538 do {
539 const T distance = position.squaredDistanceTo(currentVertex->position());
540 if (distance < closestDistance) {
541 closestDistance = distance;
542 closestVertex = currentVertex;
543 }
544 currentVertex = currentVertex->next();
545 } while (currentVertex != firstVertex);
546 return closestVertex;
547 }
548
549 template <typename T, typename FP, typename VP>
findClosestVertices(const V & position)550 typename Polyhedron<T,FP,VP>::ClosestVertexSet Polyhedron<T,FP,VP>::findClosestVertices(const V& position) const {
551 ClosestVertexSet result = ClosestVertexSet(VertexDistanceCmp(position));
552 Vertex* firstVertex = m_vertices.front();
553 Vertex* currentVertex = firstVertex;
554 do {
555 result.insert(currentVertex);
556 currentVertex = currentVertex->next();
557 } while (currentVertex != firstVertex);
558 return result;
559 }
560
561 template <typename T, typename FP, typename VP>
findEdgeByPositions(const V & pos1,const V & pos2,const T epsilon)562 typename Polyhedron<T,FP,VP>::Edge* Polyhedron<T,FP,VP>::findEdgeByPositions(const V& pos1, const V& pos2, const T epsilon) const {
563 Edge* firstEdge = m_edges.front();
564 Edge* currentEdge = firstEdge;
565 do {
566 currentEdge = currentEdge->next();
567 if (currentEdge->hasPositions(pos1, pos2, epsilon))
568 return currentEdge;
569 } while (currentEdge != firstEdge);
570 return NULL;
571 }
572
573 template <typename T, typename FP, typename VP>
findFaceByPositions(const typename V::List & positions,const T epsilon)574 typename Polyhedron<T,FP,VP>::Face* Polyhedron<T,FP,VP>::findFaceByPositions(const typename V::List& positions, const T epsilon) const {
575 Face* firstFace = m_faces.front();
576 Face* currentFace = firstFace;
577 do {
578 if (currentFace->hasVertexPositions(positions, epsilon))
579 return currentFace;
580 currentFace = currentFace->next();
581 } while (currentFace != firstFace);
582 return NULL;
583 }
584
585 template <typename T, typename FP, typename VP> template <typename O>
getVertexPositions(O output)586 void Polyhedron<T,FP,VP>::getVertexPositions(O output) const {
587 Vertex* firstVertex = m_vertices.front();
588 Vertex* currentVertex = firstVertex;
589 do {
590 output = currentVertex->position();
591 currentVertex = currentVertex->next();
592 } while (currentVertex != firstVertex);
593 }
594
595 template <typename T, typename FP, typename VP>
hasVertex(const Vertex * vertex)596 bool Polyhedron<T,FP,VP>::hasVertex(const Vertex* vertex) const {
597 const Vertex* firstVertex = m_vertices.front();
598 const Vertex* currentVertex = firstVertex;
599 do {
600 if (currentVertex == vertex)
601 return true;
602 currentVertex = currentVertex->next();
603 } while (currentVertex != firstVertex);
604 return false;
605 }
606
607 template <typename T, typename FP, typename VP>
hasEdge(const Edge * edge)608 bool Polyhedron<T,FP,VP>::hasEdge(const Edge* edge) const {
609 const Edge* firstEdge = m_edges.front();
610 const Edge* currentEdge = firstEdge;
611 do {
612 if (currentEdge == edge)
613 return true;
614 currentEdge = currentEdge->next();
615 } while (currentEdge != firstEdge);
616 return false;
617 }
618
619 template <typename T, typename FP, typename VP>
hasFace(const Face * face)620 bool Polyhedron<T,FP,VP>::hasFace(const Face* face) const {
621 const Face* firstFace = m_faces.front();
622 const Face* currentFace = firstFace;
623 do {
624 if (currentFace == face)
625 return true;
626 currentFace = currentFace->next();
627 } while (currentFace != firstFace);
628 return false;
629 }
630
631 template <typename T, typename FP, typename VP>
checkInvariant()632 bool Polyhedron<T,FP,VP>::checkInvariant() const {
633 /*
634 if (!checkConvex())
635 return false;
636 */
637 if (!checkFaceBoundaries())
638 return false;
639 if (polyhedron() && !checkClosed())
640 return false;
641 if (polyhedron() && !checkNoDegenerateFaces())
642 return false;
643 if (polyhedron() && !checkVertexLeavingEdges())
644 return false;
645 if (polyhedron() && !checkEdges())
646 return false;
647 /* This check leads to false positive with almost coplanar faces.
648 if (polyhedron() && !checkNoCoplanarFaces())
649 return false;
650 */
651 return true;
652 }
653
654 template <typename T, typename FP, typename VP>
checkFaceBoundaries()655 bool Polyhedron<T,FP,VP>::checkFaceBoundaries() const {
656 if (m_faces.empty())
657 return true;
658 Face* first = m_faces.front();
659 Face* current = first;
660 do {
661 if (!current->checkBoundary())
662 return false;
663 current = current->next();
664 } while (current != first);
665 return true;
666 }
667
668 template <typename T, typename FP, typename VP>
checkConvex()669 bool Polyhedron<T,FP,VP>::checkConvex() const {
670 typename FaceList::const_iterator fIt, fEnd;
671 for (fIt = m_faces.begin(), fEnd = m_faces.end(); fIt != fEnd; ++fIt) {
672 const Face* face = *fIt;
673 typename VertexList::const_iterator vIt, vEnd;
674 for (vIt = m_vertices.begin(), vEnd = m_vertices.end(); vIt != vEnd; ++vIt) {
675 const Vertex* vertex = *vIt;
676 if (face->pointStatus(vertex->position()) == Math::PointStatus::PSAbove)
677 return false;
678 }
679 }
680 return true;
681 }
682
683 template <typename T, typename FP, typename VP>
checkClosed()684 bool Polyhedron<T,FP,VP>::checkClosed() const {
685 typename EdgeList::const_iterator eIt, eEnd;
686 for (eIt = m_edges.begin(), eEnd = m_edges.end(); eIt != eEnd; ++eIt) {
687 const Edge* edge = *eIt;
688 if (!edge->fullySpecified())
689 return false;
690
691 const Face* firstFace = edge->firstFace();
692 const Face* secondFace = edge->secondFace();
693
694 if (!m_faces.contains(firstFace))
695 return false;
696 if (!m_faces.contains(secondFace))
697 return false;
698 }
699 return true;
700 }
701
702 template <typename T, typename FP, typename VP>
checkNoCoplanarFaces()703 bool Polyhedron<T,FP,VP>::checkNoCoplanarFaces() const {
704 typename EdgeList::const_iterator eIt, eEnd;
705 for (eIt = m_edges.begin(), eEnd = m_edges.end(); eIt != eEnd; ++eIt) {
706 const Edge* edge = *eIt;
707 const Face* firstFace = edge->firstFace();
708 const Face* secondFace = edge->secondFace();
709
710 if (firstFace == secondFace)
711 return false;
712 if (firstFace->coplanar(secondFace))
713 return false;
714 }
715 return true;
716 }
717
718 template <typename T, typename FP, typename VP>
checkNoDegenerateFaces()719 bool Polyhedron<T,FP,VP>::checkNoDegenerateFaces() const {
720 typename FaceList::const_iterator fIt, fEnd;
721 for (fIt = m_faces.begin(), fEnd = m_faces.end(); fIt != fEnd; ++fIt) {
722 const Face* face = *fIt;
723 if (face->vertexCount() < 3)
724 return false;
725
726 const HalfEdgeList& boundary = face->boundary();
727 typename HalfEdgeList::const_iterator hIt, hEnd;
728 for (hIt = boundary.begin(), hEnd = boundary.end(); hIt != hEnd; ++hIt) {
729 const HalfEdge* halfEdge = *hIt;
730 const Edge* edge = halfEdge->edge();
731
732 if (edge == NULL || !edge->fullySpecified())
733 return false;
734 }
735 }
736 return true;
737 }
738
739 template <typename T, typename FP, typename VP>
checkVertexLeavingEdges()740 bool Polyhedron<T,FP,VP>::checkVertexLeavingEdges() const {
741 const Vertex* firstVertex = m_vertices.front();
742 const Vertex* currentVertex = firstVertex;
743 do {
744 const HalfEdge* leaving = currentVertex->leaving();
745 if (leaving == NULL)
746 return false;
747 if (leaving->origin() != currentVertex)
748 return false;
749 const Edge* edge = leaving->edge();
750 if (edge == NULL)
751 return false;
752 if (!edge->fullySpecified())
753 return false;
754 if (!hasEdge(edge))
755 return false;
756 currentVertex = currentVertex->next();
757 } while (currentVertex != firstVertex);
758 return true;
759 }
760
761 template <typename T, typename FP, typename VP>
checkEdges()762 bool Polyhedron<T,FP,VP>::checkEdges() const {
763 if (m_edges.empty())
764 return true;
765
766 Edge* firstEdge = m_edges.front();
767 Edge* currentEdge = firstEdge;
768 do {
769 if (!currentEdge->fullySpecified())
770 return false;
771 Face* firstFace = currentEdge->firstFace();
772 if (firstFace == NULL)
773 return false;
774 if (!m_faces.contains(firstFace))
775 return false;
776
777 Face* secondFace = currentEdge->secondFace();
778 if (secondFace == NULL)
779 return false;
780 if (!m_faces.contains(secondFace))
781 return false;
782
783 currentEdge = currentEdge->next();
784 } while (currentEdge != firstEdge);
785 return true;
786 }
787
788 template <typename T, typename FP, typename VP>
checkEdgeLengths(const T minLength)789 bool Polyhedron<T,FP,VP>::checkEdgeLengths(const T minLength) const {
790 if (m_edges.empty())
791 return true;
792
793 const T minLength2 = minLength * minLength;
794
795 const Edge* firstEdge = m_edges.front();
796 const Edge* currentEdge = firstEdge;
797 do {
798 const T length2 = currentEdge->vector().squaredLength();
799 if (length2 < minLength2)
800 return false;
801 currentEdge = currentEdge->next();
802 } while (currentEdge != firstEdge);
803 return true;
804 }
805
806 template <typename T, typename FP, typename VP>
correctVertexPositions(const size_t decimals,const T epsilon)807 void Polyhedron<T,FP,VP>::correctVertexPositions(const size_t decimals, const T epsilon) {
808 Vertex* firstVertex = m_vertices.front();
809 Vertex* currentVertex = firstVertex;
810 do {
811 currentVertex->correctPosition(decimals, epsilon);
812 currentVertex = currentVertex->next();
813 } while (currentVertex != firstVertex);
814 }
815
816 template <typename T, typename FP, typename VP>
healEdges(const T minLength)817 bool Polyhedron<T,FP,VP>::healEdges(const T minLength) {
818 Callback callback;
819 return healEdges(callback, minLength);
820 }
821
822 template <typename T, typename FP, typename VP>
healEdges(Callback & callback,const T minLength)823 bool Polyhedron<T,FP,VP>::healEdges(Callback& callback, const T minLength) {
824 const T minLength2 = minLength * minLength;
825
826 /*
827 We have to iterate over all edges while the list of edges is being modified, so we cannot use the usual
828 do / while iteration. Instead, we count the number of edges we have examined - but since one or more edges
829 can be removed in every iteration, we have to correct that number for the decrease in the total number of
830 edges of the brush - this is where sizeDelta comes in. If no edges has been removed, it comes out as -1.
831 If one edge has been removed, it comes out as 0, if two edges have been removed, it comes out as +1, and so on.
832
833 Since sizeDelta is subtracted from the number of examined edges, it corrects exactly for the change in the number
834 of edges of the brush.
835 */
836
837 long examined = 0;
838 Edge* currentEdge = m_edges.front();
839 while (examined < static_cast<long>(m_edges.size()) && polyhedron()) {
840 const size_t oldSize = m_edges.size();
841
842 const T length2 = currentEdge->vector().squaredLength();
843 if (length2 < minLength2)
844 currentEdge = removeEdge(currentEdge, callback);
845 else
846 currentEdge = currentEdge->next();
847
848 const long sizeDelta = static_cast<long>(oldSize - m_edges.size()) - 1;
849 examined -= sizeDelta;
850 }
851
852 assert(!polyhedron() || checkEdgeLengths(minLength));
853
854 return polyhedron();
855 }
856
857 template <typename T, typename FP, typename VP>
removeEdge(Edge * edge,Callback & callback)858 typename Polyhedron<T,FP,VP>::Edge* Polyhedron<T,FP,VP>::removeEdge(Edge* edge, Callback& callback) {
859 // First, transfer all edges from the second to the first vertex of the given edge.
860 // This results in the edge being a loop and the second vertex to be orphaned.
861 Vertex* firstVertex = edge->firstVertex();
862 Vertex* secondVertex = edge->secondVertex();
863 while (secondVertex->leaving() != NULL) {
864 HalfEdge* leaving = secondVertex->leaving();
865 HalfEdge* newLeaving = leaving->previous()->twin();
866 leaving->setOrigin(firstVertex);
867 if (newLeaving->origin() == secondVertex)
868 secondVertex->setLeaving(newLeaving);
869 else
870 secondVertex->setLeaving(NULL);
871 }
872
873 // Remove the edge's first edge from its first face and delete the face if it degenerates
874 {
875 Face* firstFace = edge->firstFace();
876 HalfEdge* firstEdge = edge->firstEdge();
877 HalfEdge* nextEdge = firstEdge->next();
878
879 firstVertex->setLeaving(firstEdge->previous()->twin());
880 firstFace->removeFromBoundary(firstEdge);
881 nextEdge->setOrigin(firstVertex);
882 delete firstEdge;
883
884 if (firstFace->vertexCount() == 2)
885 removeDegenerateFace(firstFace, callback);
886 }
887
888 // Remove the edges's second edge from its second face and delete the face if it degenerates
889 {
890 Face* secondFace = edge->secondFace();
891 HalfEdge* secondEdge = edge->secondEdge();
892
893 secondFace->removeFromBoundary(secondEdge);
894 delete secondEdge;
895
896 if (secondFace->vertexCount() == 2)
897 removeDegenerateFace(secondFace, callback);
898 }
899
900 m_vertices.remove(secondVertex);
901 delete secondVertex;
902
903 Edge* result = edge->next();
904 m_edges.remove(edge);
905 delete edge;
906
907 // Merge faces that may have become coplanar
908 {
909 HalfEdge* firstEdge = firstVertex->leaving();
910 HalfEdge* currentEdge = firstEdge;
911 do {
912 HalfEdge* nextEdge = currentEdge->nextIncident();
913 Face* currentFace = firstEdge->face();
914 Face* neighbour = firstEdge->twin()->face();
915 if (currentFace->coplanar(neighbour))
916 mergeNeighbours(currentEdge, callback);
917 currentEdge = nextEdge;
918 } while (currentEdge != firstEdge);
919 }
920
921 return result;
922 }
923
924 template <typename T, typename FP, typename VP>
removeDegenerateFace(Face * face,Callback & callback)925 void Polyhedron<T,FP,VP>::removeDegenerateFace(Face* face, Callback& callback) {
926 assert(face->vertexCount() == 2);
927
928 HalfEdge* halfEdge1 = face->boundary().front();
929 HalfEdge* halfEdge2 = halfEdge1->next();
930 assert(halfEdge2->next() == halfEdge1);
931 assert(halfEdge1->previous() == halfEdge2);
932
933 Vertex* vertex1 = halfEdge1->origin();
934 Vertex* vertex2 = halfEdge2->origin();
935
936 vertex1->setLeaving(halfEdge2->twin());
937 vertex2->setLeaving(halfEdge1->twin());
938
939 Edge* edge1 = halfEdge1->edge();
940 Edge* edge2 = halfEdge2->edge();
941
942 edge1->makeSecondEdge(halfEdge1);
943 edge2->makeFirstEdge(halfEdge2);
944
945 HalfEdge* halfEdge3 = edge2->secondEdge();
946 halfEdge3->setEdge(NULL);
947 edge1->unsetSecondEdge();
948 edge1->setSecondEdge(halfEdge3);
949
950 m_edges.remove(edge2);
951 delete edge2;
952
953 callback.faceWillBeDeleted(face);
954 m_faces.remove(face);
955 delete face;
956 }
957
958 template <typename T, typename FP, typename VP>
updateBounds()959 void Polyhedron<T,FP,VP>::updateBounds() {
960 if (m_vertices.size() == 0) {
961 m_bounds.min = m_bounds.max = Vec<T,3>::NaN;
962 } else {
963 Vertex* first = m_vertices.front();
964 Vertex* current = first;
965 m_bounds.min = m_bounds.max = current->position();
966
967 current = current->next();
968 while (current != first) {
969 m_bounds.mergeWith(current->position());
970 current = current->next();
971 }
972 }
973 }
974
975 #endif
976