1 /* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
\r
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
\r
7 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
\r
9 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
\r
11 3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
\r
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
15 #include "hacdICHull.h"
\r
19 const long ICHull::sc_dummyIndex = std::numeric_limits<long>::max();
\r
20 ICHull::ICHull(void)
\r
26 bool ICHull::AddPoints(const Vec3<Real> * points, size_t nPoints)
\r
32 CircularListElement<TMMVertex> * vertex = NULL;
\r
33 for (size_t i = 0; i < nPoints; i++)
\r
35 vertex = m_mesh.AddVertex();
\r
36 vertex->GetData().m_pos.X() = points[i].X();
\r
37 vertex->GetData().m_pos.Y() = points[i].Y();
\r
38 vertex->GetData().m_pos.Z() = points[i].Z();
\r
39 vertex->GetData().m_name = static_cast<long>(i);
\r
43 bool ICHull::AddPoints(std::vector< Vec3<Real> > points)
\r
45 CircularListElement<TMMVertex> * vertex = NULL;
\r
46 for (size_t i = 0; i < points.size(); i++)
\r
48 vertex = m_mesh.AddVertex();
\r
49 vertex->GetData().m_pos.X() = points[i].X();
\r
50 vertex->GetData().m_pos.Y() = points[i].Y();
\r
51 vertex->GetData().m_pos.Z() = points[i].Z();
\r
56 bool ICHull::AddPoint(const Vec3<Real> & point, long id)
\r
58 if (AddPoints(&point, 1))
\r
60 m_mesh.m_vertices.GetData().m_name = id;
\r
66 ICHullError ICHull::Process()
\r
68 unsigned long addedPoints = 0;
\r
69 if (m_mesh.GetNVertices() < 3)
\r
71 return ICHullErrorNotEnoughPoints;
\r
73 if (m_mesh.GetNVertices() == 3)
\r
76 CircularListElement<TMMTriangle> * t1 = m_mesh.AddTriangle();
\r
77 CircularListElement<TMMTriangle> * t2 = m_mesh.AddTriangle();
\r
78 CircularListElement<TMMVertex> * v0 = m_mesh.m_vertices.GetHead();
\r
79 CircularListElement<TMMVertex> * v1 = v0->GetNext();
\r
80 CircularListElement<TMMVertex> * v2 = v1->GetNext();
\r
81 // Compute the normal to the plane
\r
82 Vec3<Real> p0 = v0->GetData().m_pos;
\r
83 Vec3<Real> p1 = v1->GetData().m_pos;
\r
84 Vec3<Real> p2 = v2->GetData().m_pos;
\r
85 m_normal = (p1-p0) ^ (p2-p0);
\r
86 m_normal.Normalize();
\r
87 t1->GetData().m_vertices[0] = v0;
\r
88 t1->GetData().m_vertices[1] = v1;
\r
89 t1->GetData().m_vertices[2] = v2;
\r
90 t2->GetData().m_vertices[0] = v1;
\r
91 t2->GetData().m_vertices[1] = v2;
\r
92 t2->GetData().m_vertices[2] = v2;
\r
93 return ICHullErrorOK;
\r
97 m_mesh.m_edges.Clear();
\r
98 m_mesh.m_triangles.Clear();
\r
101 if (m_mesh.GetNTriangles() == 0) // we have to create the first polyhedron
\r
103 ICHullError res = DoubleTriangle();
\r
104 if (res != ICHullErrorOK)
\r
113 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
114 // go to the first added and not processed vertex
\r
115 while (!(vertices.GetHead()->GetPrev()->GetData().m_tag))
\r
119 while (!vertices.GetData().m_tag) // not processed
\r
121 vertices.GetData().m_tag = true;
\r
122 if (ProcessPoint())
\r
125 CleanUp(addedPoints);
\r
127 if (!GetMesh().CheckConsistancy())
\r
129 return ICHullErrorInconsistent;
\r
135 std::vector< CircularListElement<TMMTriangle> * > trianglesToDuplicate;
\r
136 size_t nT = m_mesh.GetNTriangles();
\r
137 for(size_t f = 0; f < nT; f++)
\r
139 TMMTriangle & currentTriangle = m_mesh.m_triangles.GetHead()->GetData();
\r
140 if( currentTriangle.m_vertices[0]->GetData().m_name == sc_dummyIndex ||
\r
141 currentTriangle.m_vertices[1]->GetData().m_name == sc_dummyIndex ||
\r
142 currentTriangle.m_vertices[2]->GetData().m_name == sc_dummyIndex )
\r
144 m_trianglesToDelete.push_back(m_mesh.m_triangles.GetHead());
\r
145 for(int k = 0; k < 3; k++)
\r
147 for(int h = 0; h < 2; h++)
\r
149 if (currentTriangle.m_edges[k]->GetData().m_triangles[h] == m_mesh.m_triangles.GetHead())
\r
151 currentTriangle.m_edges[k]->GetData().m_triangles[h] = 0;
\r
159 trianglesToDuplicate.push_back(m_mesh.m_triangles.GetHead());
\r
161 m_mesh.m_triangles.Next();
\r
163 size_t nE = m_mesh.GetNEdges();
\r
164 for(size_t e = 0; e < nE; e++)
\r
166 TMMEdge & currentEdge = m_mesh.m_edges.GetHead()->GetData();
\r
167 if( currentEdge.m_triangles[0] == 0 && currentEdge.m_triangles[1] == 0)
\r
169 m_edgesToDelete.push_back(m_mesh.m_edges.GetHead());
\r
171 m_mesh.m_edges.Next();
\r
173 m_mesh.m_vertices.Delete(m_dummyVertex);
\r
175 size_t nV = m_mesh.GetNVertices();
\r
176 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
177 for(size_t v = 0; v < nV; ++v)
\r
179 vertices.GetData().m_tag = false;
\r
184 CircularListElement<TMMTriangle> * newTriangle;
\r
185 for(size_t t = 0; t < trianglesToDuplicate.size(); t++)
\r
187 newTriangle = m_mesh.AddTriangle();
\r
188 newTriangle->GetData().m_vertices[0] = trianglesToDuplicate[t]->GetData().m_vertices[1];
\r
189 newTriangle->GetData().m_vertices[1] = trianglesToDuplicate[t]->GetData().m_vertices[0];
\r
190 newTriangle->GetData().m_vertices[2] = trianglesToDuplicate[t]->GetData().m_vertices[2];
\r
193 return ICHullErrorOK;
\r
195 ICHullError ICHull::Process(unsigned long nPointsCH)
\r
197 unsigned long addedPoints = 0;
\r
198 if (nPointsCH < 3 || m_mesh.GetNVertices() < 3)
\r
200 return ICHullErrorNotEnoughPoints;
\r
202 if (m_mesh.GetNVertices() == 3)
\r
205 CircularListElement<TMMTriangle> * t1 = m_mesh.AddTriangle();
\r
206 CircularListElement<TMMTriangle> * t2 = m_mesh.AddTriangle();
\r
207 CircularListElement<TMMVertex> * v0 = m_mesh.m_vertices.GetHead();
\r
208 CircularListElement<TMMVertex> * v1 = v0->GetNext();
\r
209 CircularListElement<TMMVertex> * v2 = v1->GetNext();
\r
210 // Compute the normal to the plane
\r
211 Vec3<Real> p0 = v0->GetData().m_pos;
\r
212 Vec3<Real> p1 = v1->GetData().m_pos;
\r
213 Vec3<Real> p2 = v2->GetData().m_pos;
\r
214 m_normal = (p1-p0) ^ (p2-p0);
\r
215 m_normal.Normalize();
\r
216 t1->GetData().m_vertices[0] = v0;
\r
217 t1->GetData().m_vertices[1] = v1;
\r
218 t1->GetData().m_vertices[2] = v2;
\r
219 t2->GetData().m_vertices[0] = v1;
\r
220 t2->GetData().m_vertices[1] = v0;
\r
221 t2->GetData().m_vertices[2] = v2;
\r
222 return ICHullErrorOK;
\r
227 m_mesh.m_triangles.Clear();
\r
228 m_mesh.m_edges.Clear();
\r
232 if (m_mesh.GetNTriangles() == 0) // we have to create the first polyhedron
\r
234 ICHullError res = DoubleTriangle();
\r
235 if (res != ICHullErrorOK)
\r
244 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
245 while (!vertices.GetData().m_tag && addedPoints < nPointsCH) // not processed
\r
247 if (!FindMaxVolumePoint())
\r
251 vertices.GetData().m_tag = true;
\r
252 if (ProcessPoint())
\r
255 CleanUp(addedPoints);
\r
256 if (!GetMesh().CheckConsistancy())
\r
258 return ICHullErrorInconsistent;
\r
263 // delete remaining points
\r
264 while (!vertices.GetData().m_tag)
\r
270 std::vector< CircularListElement<TMMTriangle> * > trianglesToDuplicate;
\r
271 size_t nT = m_mesh.GetNTriangles();
\r
272 for(size_t f = 0; f < nT; f++)
\r
274 TMMTriangle & currentTriangle = m_mesh.m_triangles.GetHead()->GetData();
\r
275 if( currentTriangle.m_vertices[0]->GetData().m_name == sc_dummyIndex ||
\r
276 currentTriangle.m_vertices[1]->GetData().m_name == sc_dummyIndex ||
\r
277 currentTriangle.m_vertices[2]->GetData().m_name == sc_dummyIndex )
\r
279 m_trianglesToDelete.push_back(m_mesh.m_triangles.GetHead());
\r
280 for(int k = 0; k < 3; k++)
\r
282 for(int h = 0; h < 2; h++)
\r
284 if (currentTriangle.m_edges[k]->GetData().m_triangles[h] == m_mesh.m_triangles.GetHead())
\r
286 currentTriangle.m_edges[k]->GetData().m_triangles[h] = 0;
\r
294 trianglesToDuplicate.push_back(m_mesh.m_triangles.GetHead());
\r
296 m_mesh.m_triangles.Next();
\r
298 size_t nE = m_mesh.GetNEdges();
\r
299 for(size_t e = 0; e < nE; e++)
\r
301 TMMEdge & currentEdge = m_mesh.m_edges.GetHead()->GetData();
\r
302 if( currentEdge.m_triangles[0] == 0 && currentEdge.m_triangles[1] == 0)
\r
304 m_edgesToDelete.push_back(m_mesh.m_edges.GetHead());
\r
306 m_mesh.m_edges.Next();
\r
308 m_mesh.m_vertices.Delete(m_dummyVertex);
\r
310 size_t nV = m_mesh.GetNVertices();
\r
311 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
312 for(size_t v = 0; v < nV; ++v)
\r
314 vertices.GetData().m_tag = false;
\r
319 CircularListElement<TMMTriangle> * newTriangle;
\r
320 for(size_t t = 0; t < trianglesToDuplicate.size(); t++)
\r
322 newTriangle = m_mesh.AddTriangle();
\r
323 newTriangle->GetData().m_vertices[0] = trianglesToDuplicate[t]->GetData().m_vertices[1];
\r
324 newTriangle->GetData().m_vertices[1] = trianglesToDuplicate[t]->GetData().m_vertices[0];
\r
325 newTriangle->GetData().m_vertices[2] = trianglesToDuplicate[t]->GetData().m_vertices[2];
\r
328 return ICHullErrorOK;
\r
330 bool ICHull::FindMaxVolumePoint()
\r
332 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
333 CircularListElement<TMMVertex> * vMaxVolume = 0;
\r
334 CircularListElement<TMMVertex> * vHeadPrev = vertices.GetHead()->GetPrev();
\r
336 double maxVolume = 0.0;
\r
337 double volume = 0.0;
\r
339 while (!vertices.GetData().m_tag) // not processed
\r
341 if (ComputePointVolume(volume, false))
\r
343 if ( maxVolume < volume)
\r
345 maxVolume = volume;
\r
346 vMaxVolume = vertices.GetHead();
\r
351 CircularListElement<TMMVertex> * vHead = vHeadPrev->GetNext();
\r
352 vertices.GetHead() = vHead;
\r
359 if (vMaxVolume != vHead)
\r
361 Vec3<Real> pos = vHead->GetData().m_pos;
\r
362 long id = vHead->GetData().m_name;
\r
363 vHead->GetData().m_pos = vMaxVolume->GetData().m_pos;
\r
364 vHead->GetData().m_name = vMaxVolume->GetData().m_name;
\r
365 vMaxVolume->GetData().m_pos = pos;
\r
366 vHead->GetData().m_name = id;
\r
372 ICHullError ICHull::DoubleTriangle()
\r
374 // find three non colinear points
\r
376 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
377 CircularListElement<TMMVertex> * v0 = vertices.GetHead();
\r
378 while( Colinear(v0->GetData().m_pos,
\r
379 v0->GetNext()->GetData().m_pos,
\r
380 v0->GetNext()->GetNext()->GetData().m_pos))
\r
382 if ( (v0 = v0->GetNext()) == vertices.GetHead())
\r
384 return ICHullErrorCoplanarPoints;
\r
387 CircularListElement<TMMVertex> * v1 = v0->GetNext();
\r
388 CircularListElement<TMMVertex> * v2 = v1->GetNext();
\r
389 // mark points as processed
\r
390 v0->GetData().m_tag = v1->GetData().m_tag = v2->GetData().m_tag = true;
\r
392 // create two triangles
\r
393 CircularListElement<TMMTriangle> * f0 = MakeFace(v0, v1, v2, 0);
\r
394 MakeFace(v2, v1, v0, f0);
\r
396 // find a fourth non-coplanar point to form tetrahedron
\r
397 CircularListElement<TMMVertex> * v3 = v2->GetNext();
\r
398 vertices.GetHead() = v3;
\r
400 double vol = Volume(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos);
\r
401 while (vol == 0.0 && !v3->GetNext()->GetData().m_tag)
\r
403 v3 = v3->GetNext();
\r
404 vol = Volume(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos);
\r
408 // compute the barycenter
\r
409 Vec3<Real> bary(0.0,0.0,0.0);
\r
410 CircularListElement<TMMVertex> * vBary = v0;
\r
413 bary += vBary->GetData().m_pos;
\r
415 while ( (vBary = vBary->GetNext()) != v0);
\r
416 bary /= static_cast<Real>(vertices.GetSize());
\r
418 // Compute the normal to the plane
\r
419 Vec3<Real> p0 = v0->GetData().m_pos;
\r
420 Vec3<Real> p1 = v1->GetData().m_pos;
\r
421 Vec3<Real> p2 = v2->GetData().m_pos;
\r
422 m_normal = (p1-p0) ^ (p2-p0);
\r
423 m_normal.Normalize();
\r
424 // add dummy vertex placed at (bary + normal)
\r
425 vertices.GetHead() = v2;
\r
426 Vec3<Real> newPt = bary + m_normal;
\r
427 AddPoint(newPt, sc_dummyIndex);
\r
428 m_dummyVertex = vertices.GetHead();
\r
430 v3 = v2->GetNext();
\r
431 vol = Volume(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos);
\r
432 return ICHullErrorOK;
\r
434 else if (v3 != vertices.GetHead())
\r
437 temp.m_name = v3->GetData().m_name;
\r
438 temp.m_pos = v3->GetData().m_pos;
\r
439 v3->GetData().m_name = vertices.GetHead()->GetData().m_name;
\r
440 v3->GetData().m_pos = vertices.GetHead()->GetData().m_pos;
\r
441 vertices.GetHead()->GetData().m_name = temp.m_name;
\r
442 vertices.GetHead()->GetData().m_pos = temp.m_pos;
\r
444 return ICHullErrorOK;
\r
446 CircularListElement<TMMTriangle> * ICHull::MakeFace(CircularListElement<TMMVertex> * v0,
\r
447 CircularListElement<TMMVertex> * v1,
\r
448 CircularListElement<TMMVertex> * v2,
\r
449 CircularListElement<TMMTriangle> * fold)
\r
451 CircularListElement<TMMEdge> * e0;
\r
452 CircularListElement<TMMEdge> * e1;
\r
453 CircularListElement<TMMEdge> * e2;
\r
455 if (!fold) // if first face to be created
\r
457 e0 = m_mesh.AddEdge(); // create the three edges
\r
458 e1 = m_mesh.AddEdge();
\r
459 e2 = m_mesh.AddEdge();
\r
461 else // otherwise re-use existing edges (in reverse order)
\r
463 e0 = fold->GetData().m_edges[2];
\r
464 e1 = fold->GetData().m_edges[1];
\r
465 e2 = fold->GetData().m_edges[0];
\r
468 e0->GetData().m_vertices[0] = v0; e0->GetData().m_vertices[1] = v1;
\r
469 e1->GetData().m_vertices[0] = v1; e1->GetData().m_vertices[1] = v2;
\r
470 e2->GetData().m_vertices[0] = v2; e2->GetData().m_vertices[1] = v0;
\r
471 // create the new face
\r
472 CircularListElement<TMMTriangle> * f = m_mesh.AddTriangle();
\r
473 f->GetData().m_edges[0] = e0; f->GetData().m_edges[1] = e1; f->GetData().m_edges[2] = e2;
\r
474 f->GetData().m_vertices[0] = v0; f->GetData().m_vertices[1] = v1; f->GetData().m_vertices[2] = v2;
\r
475 // link edges to face f
\r
476 e0->GetData().m_triangles[index] = e1->GetData().m_triangles[index] = e2->GetData().m_triangles[index] = f;
\r
479 CircularListElement<TMMTriangle> * ICHull::MakeConeFace(CircularListElement<TMMEdge> * e, CircularListElement<TMMVertex> * p)
\r
481 // create two new edges if they don't already exist
\r
482 CircularListElement<TMMEdge> * newEdges[2];
\r
483 for(int i = 0; i < 2; ++i)
\r
485 if ( !( newEdges[i] = e->GetData().m_vertices[i]->GetData().m_duplicate ) )
\r
486 { // if the edge doesn't exits add it and mark the vertex as duplicated
\r
487 newEdges[i] = m_mesh.AddEdge();
\r
488 newEdges[i]->GetData().m_vertices[0] = e->GetData().m_vertices[i];
\r
489 newEdges[i]->GetData().m_vertices[1] = p;
\r
490 e->GetData().m_vertices[i]->GetData().m_duplicate = newEdges[i];
\r
493 // make the new face
\r
494 CircularListElement<TMMTriangle> * newFace = m_mesh.AddTriangle();
\r
495 newFace->GetData().m_edges[0] = e;
\r
496 newFace->GetData().m_edges[1] = newEdges[0];
\r
497 newFace->GetData().m_edges[2] = newEdges[1];
\r
498 MakeCCW(newFace, e, p);
\r
499 for(int i=0; i < 2; ++i)
\r
501 for(int j=0; j < 2; ++j)
\r
503 if ( ! newEdges[i]->GetData().m_triangles[j] )
\r
505 newEdges[i]->GetData().m_triangles[j] = newFace;
\r
512 bool ICHull::ComputePointVolume(double &totalVolume, bool markVisibleFaces)
\r
514 // mark visible faces
\r
515 CircularListElement<TMMTriangle> * fHead = m_mesh.GetTriangles().GetHead();
\r
516 CircularListElement<TMMTriangle> * f = fHead;
\r
517 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
518 CircularListElement<TMMVertex> * vertex0 = vertices.GetHead();
\r
519 bool visible = false;
\r
520 Vec3<double> pos0 = Vec3<double>(vertex0->GetData().m_pos.X(),
\r
521 vertex0->GetData().m_pos.Y(),
\r
522 vertex0->GetData().m_pos.Z());
\r
525 Vec3<double> ver0, ver1, ver2;
\r
528 ver0.X() = f->GetData().m_vertices[0]->GetData().m_pos.X();
\r
529 ver0.Y() = f->GetData().m_vertices[0]->GetData().m_pos.Y();
\r
530 ver0.Z() = f->GetData().m_vertices[0]->GetData().m_pos.Z();
\r
531 ver1.X() = f->GetData().m_vertices[1]->GetData().m_pos.X();
\r
532 ver1.Y() = f->GetData().m_vertices[1]->GetData().m_pos.Y();
\r
533 ver1.Z() = f->GetData().m_vertices[1]->GetData().m_pos.Z();
\r
534 ver2.X() = f->GetData().m_vertices[2]->GetData().m_pos.X();
\r
535 ver2.Y() = f->GetData().m_vertices[2]->GetData().m_pos.Y();
\r
536 ver2.Z() = f->GetData().m_vertices[2]->GetData().m_pos.Z();
\r
537 vol = Volume(ver0, ver1, ver2, pos0);
\r
541 totalVolume += vol;
\r
542 if (markVisibleFaces)
\r
544 f->GetData().m_visible = true;
\r
545 m_trianglesToDelete.push_back(f);
\r
551 while (f != fHead);
\r
553 if (m_trianglesToDelete.size() == m_mesh.m_triangles.GetSize())
\r
555 for(size_t i = 0; i < m_trianglesToDelete.size(); i++)
\r
557 m_trianglesToDelete[i]->GetData().m_visible = false;
\r
561 // if no faces visible from p then p is inside the hull
\r
562 if (!visible && markVisibleFaces)
\r
565 m_trianglesToDelete.clear();
\r
570 bool ICHull::ProcessPoint()
\r
572 double totalVolume = 0.0;
\r
573 if (!ComputePointVolume(totalVolume, true))
\r
577 // Mark edges in interior of visible region for deletion.
\r
578 // Create a new face based on each border edge
\r
579 CircularListElement<TMMVertex> * v0 = m_mesh.GetVertices().GetHead();
\r
580 CircularListElement<TMMEdge> * eHead = m_mesh.GetEdges().GetHead();
\r
581 CircularListElement<TMMEdge> * e = eHead;
\r
582 CircularListElement<TMMEdge> * tmp = 0;
\r
584 m_edgesToDelete.clear();
\r
585 m_edgesToUpdate.clear();
\r
588 tmp = e->GetNext();
\r
590 for(int k = 0; k < 2; k++)
\r
592 if ( e->GetData().m_triangles[k]->GetData().m_visible )
\r
597 if ( nvisible == 2)
\r
599 m_edgesToDelete.push_back(e);
\r
601 else if ( nvisible == 1)
\r
603 e->GetData().m_newFace = MakeConeFace(e, v0);
\r
604 m_edgesToUpdate.push_back(e);
\r
608 while (e != eHead);
\r
611 bool ICHull::MakeCCW(CircularListElement<TMMTriangle> * f,
\r
612 CircularListElement<TMMEdge> * e,
\r
613 CircularListElement<TMMVertex> * v)
\r
615 // the visible face adjacent to e
\r
616 CircularListElement<TMMTriangle> * fv;
\r
617 if (e->GetData().m_triangles[0]->GetData().m_visible)
\r
619 fv = e->GetData().m_triangles[0];
\r
623 fv = e->GetData().m_triangles[1];
\r
626 // set vertex[0] and vertex[1] to have the same orientation as the corresponding vertices of fv.
\r
627 long i; // index of e->m_vertices[0] in fv
\r
628 CircularListElement<TMMVertex> * v0 = e->GetData().m_vertices[0];
\r
629 CircularListElement<TMMVertex> * v1 = e->GetData().m_vertices[1];
\r
630 for(i = 0; fv->GetData().m_vertices[i] != v0; i++);
\r
632 if ( fv->GetData().m_vertices[(i+1) % 3] != e->GetData().m_vertices[1] )
\r
634 f->GetData().m_vertices[0] = v1;
\r
635 f->GetData().m_vertices[1] = v0;
\r
639 f->GetData().m_vertices[0] = v0;
\r
640 f->GetData().m_vertices[1] = v1;
\r
642 CircularListElement<TMMEdge> * tmp = f->GetData().m_edges[0];
\r
643 f->GetData().m_edges[0] = f->GetData().m_edges[1];
\r
644 f->GetData().m_edges[1] = tmp;
\r
646 f->GetData().m_vertices[2] = v;
\r
649 bool ICHull::CleanUp(unsigned long & addedPoints)
\r
651 bool r0 = CleanEdges();
\r
652 bool r1 = CleanTriangles();
\r
653 bool r2 = CleanVertices(addedPoints);
\r
654 return r0 && r1 && r2;
\r
656 bool ICHull::CleanEdges()
\r
658 // integrate the new faces into the data structure
\r
659 CircularListElement<TMMEdge> * e;
\r
660 const std::vector<CircularListElement<TMMEdge> *>::iterator itEndUpdate = m_edgesToUpdate.end();
\r
661 for(std::vector<CircularListElement<TMMEdge> *>::iterator it = m_edgesToUpdate.begin(); it != itEndUpdate; ++it)
\r
664 if ( e->GetData().m_newFace )
\r
666 if ( e->GetData().m_triangles[0]->GetData().m_visible)
\r
668 e->GetData().m_triangles[0] = e->GetData().m_newFace;
\r
672 e->GetData().m_triangles[1] = e->GetData().m_newFace;
\r
674 e->GetData().m_newFace = 0;
\r
677 // delete edges maked for deletion
\r
678 CircularList<TMMEdge> & edges = m_mesh.GetEdges();
\r
679 const std::vector<CircularListElement<TMMEdge> *>::iterator itEndDelete = m_edgesToDelete.end();
\r
680 for(std::vector<CircularListElement<TMMEdge> *>::iterator it = m_edgesToDelete.begin(); it != itEndDelete; ++it)
\r
682 edges.Delete(*it);
\r
684 m_edgesToDelete.clear();
\r
685 m_edgesToUpdate.clear();
\r
688 bool ICHull::CleanTriangles()
\r
690 CircularList<TMMTriangle> & triangles = m_mesh.GetTriangles();
\r
691 const std::vector<CircularListElement<TMMTriangle> *>::iterator itEndDelete = m_trianglesToDelete.end();
\r
692 for(std::vector<CircularListElement<TMMTriangle> *>::iterator it = m_trianglesToDelete.begin(); it != itEndDelete; ++it)
\r
702 std::set<long>::const_iterator itPEnd((*it)->GetData().m_incidentPoints.end());
\r
703 std::set<long>::const_iterator itP((*it)->GetData().m_incidentPoints.begin());
\r
704 std::map<long, DPoint>::iterator itPoint;
\r
705 for(; itP != itPEnd; ++itP)
\r
707 itPoint = m_distPoints->find(*itP);
\r
708 if (itPoint != m_distPoints->end())
\r
710 itPoint->second.m_computed = false;
\r
715 triangles.Delete(*it);
\r
717 m_trianglesToDelete.clear();
\r
720 bool ICHull::CleanVertices(unsigned long & addedPoints)
\r
722 // mark all vertices incident to some undeleted edge as on the hull
\r
723 CircularList<TMMEdge> & edges = m_mesh.GetEdges();
\r
724 CircularListElement<TMMEdge> * e = edges.GetHead();
\r
725 size_t nE = edges.GetSize();
\r
726 for(size_t i = 0; i < nE; i++)
\r
728 e->GetData().m_vertices[0]->GetData().m_onHull = true;
\r
729 e->GetData().m_vertices[1]->GetData().m_onHull = true;
\r
732 // delete all the vertices that have been processed but are not on the hull
\r
733 CircularList<TMMVertex> & vertices = m_mesh.GetVertices();
\r
734 CircularListElement<TMMVertex> * vHead = vertices.GetHead();
\r
735 CircularListElement<TMMVertex> * v = vHead;
\r
739 if (v->GetData().m_tag && !v->GetData().m_onHull)
\r
741 CircularListElement<TMMVertex> * tmp = v->GetPrev();
\r
742 vertices.Delete(v);
\r
748 v->GetData().m_duplicate = 0;
\r
749 v->GetData().m_onHull = false;
\r
753 while (v->GetData().m_tag && v != vHead);
\r
756 void ICHull::Clear()
\r
759 m_edgesToDelete = std::vector<CircularListElement<TMMEdge> *>();
\r
760 m_edgesToUpdate = std::vector<CircularListElement<TMMEdge> *>();
\r
761 m_trianglesToDelete= std::vector<CircularListElement<TMMTriangle> *>();
\r
764 const ICHull & ICHull::operator=(ICHull & rhs)
\r
768 m_mesh.Copy(rhs.m_mesh);
\r
769 m_edgesToDelete = rhs.m_edgesToDelete;
\r
770 m_edgesToUpdate = rhs.m_edgesToUpdate;
\r
771 m_trianglesToDelete = rhs.m_trianglesToDelete;
\r
772 m_isFlat = rhs.m_isFlat;
\r
776 double ICHull::ComputeVolume()
\r
778 size_t nV = m_mesh.m_vertices.GetSize();
\r
779 if (nV == 0 || m_isFlat)
\r
783 Vec3<double> bary(0.0, 0.0, 0.0);
\r
784 for(size_t v = 0; v < nV; v++)
\r
786 bary.X() += m_mesh.m_vertices.GetHead()->GetData().m_pos.X();
\r
787 bary.Y() += m_mesh.m_vertices.GetHead()->GetData().m_pos.Y();
\r
788 bary.Z() += m_mesh.m_vertices.GetHead()->GetData().m_pos.Z();
\r
789 m_mesh.m_vertices.Next();
\r
791 bary /= static_cast<double>(nV);
\r
793 size_t nT = m_mesh.m_triangles.GetSize();
\r
794 Vec3<double> ver0, ver1, ver2;
\r
795 double totalVolume = 0.0;
\r
796 for(size_t t = 0; t < nT; t++)
\r
798 ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X();
\r
799 ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y();
\r
800 ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z();
\r
801 ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X();
\r
802 ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y();
\r
803 ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z();
\r
804 ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X();
\r
805 ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y();
\r
806 ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z();
\r
807 totalVolume += Volume(ver0, ver1, ver2, bary);
\r
808 m_mesh.m_triangles.Next();
\r
810 return totalVolume;
\r
812 bool ICHull::IsInside(const Vec3<Real> & pt0)
\r
814 const Vec3<double> pt(pt0.X(), pt0.Y(), pt0.Z());
\r
817 size_t nT = m_mesh.m_triangles.GetSize();
\r
818 Vec3<double> ver0, ver1, ver2, a, b, c;
\r
820 for(size_t t = 0; t < nT; t++)
\r
822 ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X();
\r
823 ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y();
\r
824 ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z();
\r
825 ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X();
\r
826 ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y();
\r
827 ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z();
\r
828 ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X();
\r
829 ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y();
\r
830 ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z();
\r
836 if ( u >= 0.0 && u <= 1.0 && v >= 0.0 && u+v <= 1.0)
\r
840 m_mesh.m_triangles.Next();
\r
846 size_t nT = m_mesh.m_triangles.GetSize();
\r
847 Vec3<double> ver0, ver1, ver2;
\r
848 for(size_t t = 0; t < nT; t++)
\r
850 ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X();
\r
851 ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y();
\r
852 ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z();
\r
853 ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X();
\r
854 ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y();
\r
855 ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z();
\r
856 ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X();
\r
857 ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y();
\r
858 ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z();
\r
859 if (Volume(ver0, ver1, ver2, pt) < 0.0)
\r
863 m_mesh.m_triangles.Next();
\r
868 double ICHull::ComputeDistance(long name, const Vec3<Real> & pt, const Vec3<Real> & normal, bool & insideHull, bool updateIncidentPoints)
\r
870 Vec3<double> ptNormal(static_cast<double>(normal.X()),
\r
871 static_cast<double>(normal.Y()),
\r
872 static_cast<double>(normal.Z()));
\r
873 Vec3<double> p0( static_cast<double>(pt.X()),
\r
874 static_cast<double>(pt.Y()),
\r
875 static_cast<double>(pt.Z()));
\r
879 double distance = 0.0;
\r
880 Vec3<double> chNormal(static_cast<double>(m_normal.X()),
\r
881 static_cast<double>(m_normal.Y()),
\r
882 static_cast<double>(m_normal.Z()));
\r
883 ptNormal -= (ptNormal * chNormal) * chNormal;
\r
884 if (ptNormal.GetNorm() > 0.0)
\r
886 ptNormal.Normalize();
\r
889 Vec3<double> pa, pb, d0, d1, d2, d3;
\r
890 Vec3<double> p1 = p0 + ptNormal;
\r
891 Vec3<double> p2, p3;
\r
892 double mua, mub, s;
\r
893 const double EPS = 0.00000000001;
\r
894 size_t nE = m_mesh.GetNEdges();
\r
895 for(size_t e = 0; e < nE; e++)
\r
897 TMMEdge & currentEdge = m_mesh.m_edges.GetHead()->GetData();
\r
898 nameVE1 = currentEdge.m_vertices[0]->GetData().m_name;
\r
899 nameVE2 = currentEdge.m_vertices[1]->GetData().m_name;
\r
900 if (currentEdge.m_triangles[0] == 0 || currentEdge.m_triangles[1] == 0)
\r
902 if ( nameVE1==name || nameVE2==name )
\r
907 if (debug) std::cout << "V" << name
\r
908 << " E " << nameVE1 << " " << nameVE2 << std::endl;
\r
911 p2.X() = currentEdge.m_vertices[0]->GetData().m_pos.X();
\r
912 p2.Y() = currentEdge.m_vertices[0]->GetData().m_pos.Y();
\r
913 p2.Z() = currentEdge.m_vertices[0]->GetData().m_pos.Z();
\r
914 p3.X() = currentEdge.m_vertices[1]->GetData().m_pos.X();
\r
915 p3.Y() = currentEdge.m_vertices[1]->GetData().m_pos.Y();
\r
916 p3.Z() = currentEdge.m_vertices[1]->GetData().m_pos.Z();
\r
918 if (d0.GetNorm() > 0.0)
\r
920 if (IntersectLineLine(p0, p1, p2, p3, pa, pb, mua, mub))
\r
925 mua = d1.GetNorm()/d0.GetNorm();
\r
928 if (d2.GetNorm() < EPS && mua <= 1.0 && mub>=0.0 && s>0.0)
\r
930 distance = std::max<double>(distance, d3.GetNorm());
\r
935 m_mesh.m_edges.Next();
\r
942 Vec3<double> ptNormal(static_cast<double>(normal.X()),
\r
943 static_cast<double>(normal.Y()),
\r
944 static_cast<double>(normal.Z()));
\r
946 Vec3<double> impact;
\r
949 double distance = 0.0;
\r
950 size_t nT = m_mesh.GetNTriangles();
\r
951 insideHull = false;
\r
952 CircularListElement<TMMTriangle> * face = 0;
\r
953 Vec3<double> ver0, ver1, ver2;
\r
954 for(size_t f = 0; f < nT; f++)
\r
956 TMMTriangle & currentTriangle = m_mesh.m_triangles.GetHead()->GetData();
\r
958 if (debug) std::cout << "T " << currentTriangle.m_vertices[0]->GetData().m_name << " "
\r
959 << currentTriangle.m_vertices[1]->GetData().m_name << " "
\r
960 << currentTriangle.m_vertices[2]->GetData().m_name << std::endl;
\r
962 if (currentTriangle.m_vertices[0]->GetData().m_name == name ||
\r
963 currentTriangle.m_vertices[1]->GetData().m_name == name ||
\r
964 currentTriangle.m_vertices[2]->GetData().m_name == name)
\r
971 ver0.X() = currentTriangle.m_vertices[0]->GetData().m_pos.X();
\r
972 ver0.Y() = currentTriangle.m_vertices[0]->GetData().m_pos.Y();
\r
973 ver0.Z() = currentTriangle.m_vertices[0]->GetData().m_pos.Z();
\r
974 ver1.X() = currentTriangle.m_vertices[1]->GetData().m_pos.X();
\r
975 ver1.Y() = currentTriangle.m_vertices[1]->GetData().m_pos.Y();
\r
976 ver1.Z() = currentTriangle.m_vertices[1]->GetData().m_pos.Z();
\r
977 ver2.X() = currentTriangle.m_vertices[2]->GetData().m_pos.X();
\r
978 ver2.Y() = currentTriangle.m_vertices[2]->GetData().m_pos.Y();
\r
979 ver2.Z() = currentTriangle.m_vertices[2]->GetData().m_pos.Z();
\r
980 nhit = IntersectRayTriangle(p0, ptNormal, ver0, ver1, ver2, dist);
\r
983 if (nhit == 1 && distance <= dist)
\r
987 face = m_mesh.m_triangles.GetHead();
\r
989 std::cout << name << " -> T " << currentTriangle.m_vertices[0]->GetData().m_name << " "
\r
990 << currentTriangle.m_vertices[1]->GetData().m_name << " "
\r
991 << currentTriangle.m_vertices[2]->GetData().m_name << " Dist "
\r
992 << dist << " P " << currentTriangle.m_normal * normal << std::endl;
\r
999 m_mesh.m_triangles.Next();
\r
1001 if (updateIncidentPoints && face && m_distPoints)
\r
1003 (*m_distPoints)[name].m_dist = static_cast<Real>(distance);
\r
1004 face->GetData().m_incidentPoints.insert(name);
\r