Spinning Topp Logo BlackTopp Studios
inc
triangulator.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 /*
41  -----------------------------------------------------------------------------
42  This source file is part of ogre-procedural
43 
44  For the latest info, see http://code.google.com/p/ogre-procedural/
45 
46  Copyright (c) 2010-2013 Michael Broutin
47 
48  Permission is hereby granted, free of charge, to any person obtaining a copy
49  of this software and associated documentation files (the "Software"), to deal
50  in the Software without restriction, including without limitation the rights
51  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52  copies of the Software, and to permit persons to whom the Software is
53  furnished to do so, subject to the following conditions:
54 
55  The above copyright notice and this permission notice shall be included in
56  all copies or substantial portions of the Software.
57 
58  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64  THE SOFTWARE.
65  -----------------------------------------------------------------------------
66  */
67 #ifndef _graphicsproceduraltriangulator_cpp
68 #define _graphicsproceduraltriangulator_cpp
69 
70 #include "Graphics/Procedural/triangulator.h"
71 #include "Graphics/Procedural/shape.h"
72 #include "Graphics/Procedural/multishape.h"
73 
74 #include "MathTools/mathtools.h"
75 #include "circle.h"
76 #include "stringtool.h"
77 #include "exception.h"
78 #include "matrix4x4.h"
79 
80 namespace Mezzanine
81 {
82  namespace Graphics
83  {
84  namespace Procedural
85  {
86  ///////////////////////////////////////////////////////////////////////////////
87  // DelaunaySegment Methods
88 
89  ///////////////////////////////////////////////////////////////////////////////
90  // Construction and Destruction
91 
92  DelaunaySegment::DelaunaySegment(const Integer First, const Integer Second) :
93  Index1(First),
94  Index2(Second)
95  { }
96 
98  { }
99 
100  ///////////////////////////////////////////////////////////////////////////////
101  // Utility
102 
104  { return DelaunaySegment(this->Index2,this->Index1); }
105 
107  {
108  if( this->Index1 != Other.Index1 ) {
109  return ( this->Index1 < Other.Index1 );
110  }else{
111  return ( this->Index2 < Other.Index2 );
112  }
113  }
114 
115  ///////////////////////////////////////////////////////////////////////////////
116  // DelaunayTriangle Methods
117 
118  ///////////////////////////////////////////////////////////////////////////////
119  // Construction and Destruction
120 
122  Points(List)
123  { }
124 
126  { }
127 
128  ///////////////////////////////////////////////////////////////////////////////
129  // Utility
130 
131  void DelaunayTriangle::SetVertices(const Integer Index0, const Integer Index1, const Integer Index2)
132  {
133  this->Indexes[0] = Index0;
134  this->Indexes[1] = Index1;
135  this->Indexes[2] = Index2;
136  }
137 
139  {
140  if( ( this->GetPoint(1) - this->GetPoint(0) ).CrossProduct( this->GetPoint(2) - this->GetPoint(0) ) < 0 ) {
141  std::swap( this->Indexes[0], this->Indexes[1] );
142  }
143  }
144 
146  {
147  return (*Points)[ this->Indexes[ Point ] ];
148  }
149 
151  {
152  return ( ( this->GetPoint(0) + this->GetPoint(1) + this->GetPoint(2) ) * 1.f / 3.f );
153  }
154 
155  Integer DelaunayTriangle::FindSegNumber(const Integer Index0, const Integer Index1) const
156  {
157  if( ( Index0 == this->Indexes[0] && Index1 == this->Indexes[1] ) || ( Index0 == this->Indexes[1] && Index1 == this->Indexes[0] ) )
158  return 2;
159  if( ( Index0 == this->Indexes[1] && Index1 == this->Indexes[2] ) || ( Index0 == this->Indexes[2] && Index1 == this->Indexes[1] ) )
160  return 0;
161  if( ( Index0 == this->Indexes[2] && Index1 == this->Indexes[0] ) || ( Index0 == this->Indexes[0] && Index1 == this->Indexes[2] ) )
162  return 1;
163  MEZZ_EXCEPTION(ExceptionBase::INTERNAL_EXCEPTION,"Specified segment was not found. If the algorithm is working properly, you should never see this message.");
164  return -1;
165  }
166 
167  Boole DelaunayTriangle::ContainsSegment(const Integer Index0, const Integer Index1) const
168  {
169  return ( ( Index0 == this->Indexes[0] || Index0 == this->Indexes[1] || Index0 == this->Indexes[2] ) &&
170  ( Index1 == this->Indexes[0] || Index1 == this->Indexes[1] || Index1 == this->Indexes[2] ) );
171  }
172 
174  {
175  // Compute vectors
176  Vector2 v0 = this->GetPoint(2) - this->GetPoint(0);
177  Vector2 v1 = this->GetPoint(1) - this->GetPoint(0);
178  Vector2 v2 = Point - this->GetPoint(0);
179 
180  // Compute dot products
181  Real dot00 = v0.SquaredLength();
182  Real dot01 = v0.DotProduct(v1);
183  Real dot02 = v0.DotProduct(v2);
184  Real dot11 = v1.SquaredLength();
185  Real dot12 = v1.DotProduct(v2);
186 
187  // Compute barycentric coordinates
188  Real invDenom = 1.0 / ( dot00 * dot11 - dot01 * dot01 );
189  Real u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
190  Real v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
191 
192  // Check if point is in triangle
193  return ( u >= 0 ) && ( v >= 0 ) && ( u + v - 1 <= 0 );
194  }
195 
197  {
198  Vector2 v0 = this->GetPoint(0);
199  Vector2 v1 = this->GetPoint(1);
200  Vector2 v2 = this->GetPoint(2);
201  Matrix4x4 Mat( v0.X, v0.Y, v0.SquaredLength(), 1.0,
202  v1.X, v1.Y, v1.SquaredLength(), 1.0,
203  v2.X, v2.Y, v2.SquaredLength(), 1.0,
204  Point.X, Point.Y, Point.SquaredLength(), 1.0 );
205  Real det = Mat.GetDeterminant();
206  if( det >= 0 )
207  return IT_Inside;
208  if( det > -1e-3 )
209  return IT_BorderlineOutside;
210  return IT_Outside;
211  }
212 
214  {
215  if( MathTools::Abs( ( this->GetPoint(1) - this->GetPoint(0) ).CrossProduct( this->GetPoint(2) - this->GetPoint(0) ) ) < 1e-4 )
216  return true;
217  return false;
218  }
219 
221  {
222  return "(" + StringTools::ConvertToString( this->Indexes[0] ) + ","
223  + StringTools::ConvertToString( this->Indexes[1] ) + "," + StringTools::ConvertToString( this->Indexes[2] ) + ") <"
224  "(" + StringTools::ConvertToString( this->GetPoint(0) ) + ","
225  + StringTools::ConvertToString( this->GetPoint(1) ) + "," + StringTools::ConvertToString( this->GetPoint(2) ) + ">";
226  }
227 
229  {
230  return ( this->Indexes[0] == Other.Indexes[0] && this->Indexes[1] == Other.Indexes[1] && this->Indexes[2] == Other.Indexes[2] );
231  }
232 
233  ///////////////////////////////////////////////////////////////////////////////
234  // TouchSuperTriangle Methods
235 
236  ///////////////////////////////////////////////////////////////////////////////
237  // Construction and Destruction
238 
239  TouchSuperTriangle::TouchSuperTriangle(const Integer First, const Integer Second, const Integer Third) :
240  Index0(First),
241  Index1(Second),
242  Index2(Third)
243  { }
244 
246  { }
247 
248  ///////////////////////////////////////////////////////////////////////////////
249  // Triangulator Methods
250 
252  {
253  for( Integer Index = 0 ; Index < 3 ; ++Index )
254  {
255  if( Tri.Indexes[Index] == this->Index0 || Tri.Indexes[Index] == this->Index1 || Tri.Indexes[Index] == this->Index2 )
256  return true;
257  }
258  return false;
259  }
260 
261  ///////////////////////////////////////////////////////////////////////////////
262  // Construction and Destruction
263 
265  { }
266 
268  { }
269 
271  {
272  // Compute super triangle or insert manual super triangle
273  if( !this->ManualSuperTriangle ) {
274  Real MaxTriangleSize = 0.0;
275  for( Point2DIterator PointIt = List.begin() ; PointIt != List.end() ; ++PointIt )
276  {
277  MaxTriangleSize = std::max<Real>( MaxTriangleSize, MathTools::Abs( PointIt->X ) );
278  MaxTriangleSize = std::max<Real>( MaxTriangleSize, MathTools::Abs( PointIt->Y ) );
279  }
280 
281  List.push_back( Vector2( -3 * MaxTriangleSize, -3 * MaxTriangleSize ) );
282  List.push_back( Vector2( 3 * MaxTriangleSize, -3 * MaxTriangleSize ) );
283  List.push_back( Vector2( 0.0, 3 * MaxTriangleSize) );
284 
285  Integer MaxTriangleIndex = List.size() - 3;
286  DelaunayTriangle SuperTriangle( &List );
287  SuperTriangle.Indexes[0] = MaxTriangleIndex;
288  SuperTriangle.Indexes[1] = MaxTriangleIndex + 1;
289  SuperTriangle.Indexes[2] = MaxTriangleIndex + 2;
290  TriBuf.push_back( SuperTriangle );
291  }
292 
293  // Point insertion loop
294  for( UInt16 PointIndex = 0 ; PointIndex < List.size() - 3 ; ++PointIndex )
295  {
296  std::list< std::list<DelaunayTriangle>::iterator > BorderlineTriangles;
297  // Insert 1 point, find all triangles for which the point is in circumcircle
298  Vector2& CurrPoint = List[ PointIndex ];
299  std::set<DelaunaySegment> Segments;
300  for( DelaunayTriangleBuffer::iterator TriIt = TriBuf.begin() ; TriIt != TriBuf.end() ; )
301  {
302  DelaunayTriangle::InsideType IsInside = TriIt->IsPointInsideCircumcircle( CurrPoint );
303  if( IsInside == DelaunayTriangle::IT_Inside ) {
304  if( !TriIt->IsDegenerate() ) {
305  for( Integer TriPointIndex = 0 ; TriPointIndex < 3 ; ++TriPointIndex )
306  {
307  DelaunaySegment DSeg1( TriIt->Indexes[ TriPointIndex ], TriIt->Indexes[ ( TriPointIndex + 1 ) % 3 ] );
308  if( Segments.find(DSeg1) != Segments.end() ) {
309  Segments.erase(DSeg1);
310  }else if( Segments.find( DSeg1.Inverse() ) != Segments.end() ) {
311  Segments.erase( DSeg1.Inverse() );
312  }else{
313  Segments.insert(DSeg1);
314  }
315  }
316  }
317  TriIt = TriBuf.erase(TriIt);
318  }else if( IsInside == DelaunayTriangle::IT_BorderlineOutside ) {
319  BorderlineTriangles.push_back(TriIt);
320  ++TriIt;
321  }else{
322  ++TriIt;
323  }
324  }
325 
326  // Robustification of the standard algorithm : if one triangle's circumcircle was borderline against the new point,
327  // test whether that triangle is intersected by new segments or not (normal situation : it should not)
328  // If intersected, the triangle is considered having the new point in its circumc
329  std::set<DelaunaySegment> CopySegment = Segments;
330  for( std::list< std::list<DelaunayTriangle>::iterator >::iterator BorderItIt = BorderlineTriangles.begin() ; BorderItIt != BorderlineTriangles.end() ; BorderItIt++ )
331  {
332  DelaunayTriangleBuffer::iterator BorderTriIt = (*BorderItIt);
333  Boole TriRemoved = false;
334  for( std::set<DelaunaySegment>::iterator SegIt = CopySegment.begin() ; SegIt != CopySegment.end() && !TriRemoved ; ++SegIt )
335  {
336  Boole IsTriangleIntersected = false;
337  for( Integer SegIndex = 0 ; SegIndex < 2 ; ++SegIndex )
338  {
339  Integer Index1 = ( SegIndex == 0 ) ? SegIt->Index1 : SegIt->Index2;
340  Integer Index2 = PointIndex;
341  for( Integer TriCheckIndex = 0 ; TriCheckIndex < 3 ; ++TriCheckIndex )
342  {
343  //Early out if 2 points are in fact the same
344  if( BorderTriIt->Indexes[ TriCheckIndex ] == Index1 ||
345  BorderTriIt->Indexes[ TriCheckIndex ] == Index2 ||
346  BorderTriIt->Indexes[ ( TriCheckIndex + 1 ) % 3 ] == Index1 ||
347  BorderTriIt->Indexes[ ( TriCheckIndex + 1 ) % 3 ] == Index2 )
348  { continue; }
349  LineSegment2D Seg2( BorderTriIt->GetPoint( TriCheckIndex ), BorderTriIt->GetPoint( ( TriCheckIndex + 1 ) % 3 ) );
350  LineSegment2D Seg1( List[Index1], List[Index2] );
351  LineSegment2D::IntersectionTestResult Result = Seg1.Intersects(Seg2);
352  if( Result.first ) {
353  IsTriangleIntersected = true;
354  break;
355  }
356  }
357  }
358  if( IsTriangleIntersected ) {
359  if( !BorderTriIt->IsDegenerate() ) {
360  for( Integer TriPointIndex = 0 ; TriPointIndex < 3 ; ++TriPointIndex )
361  {
362  DelaunaySegment DSeg1( BorderTriIt->Indexes[ TriPointIndex ], BorderTriIt->Indexes[ ( TriPointIndex + 1 ) % 3 ] );
363  if( Segments.find(DSeg1) != Segments.end() ) {
364  Segments.erase(DSeg1);
365  }else if( Segments.find( DSeg1.Inverse() ) != Segments.end() ) {
366  Segments.erase( DSeg1.Inverse() );
367  }else{
368  Segments.insert(DSeg1);
369  }
370  }
371  }
372  TriBuf.erase(BorderTriIt);
373  TriRemoved = true;
374  }
375  }
376  }
377 
378  // Find all the non-interior edges
379  for( std::set<DelaunaySegment>::iterator EdgeIt = Segments.begin() ; EdgeIt != Segments.end() ; ++EdgeIt )
380  {
381  DelaunayTriangle EdgeTriangle( &List );
382  EdgeTriangle.SetVertices( EdgeIt->Index1, EdgeIt->Index2, PointIndex );
383  EdgeTriangle.MakeDirectIfNeeded();
384  TriBuf.push_back(EdgeTriangle);
385 
386  }
387  }
388 
389  // NB : Don't remove super triangle here, because all outer triangles are already removed in the addconstraints method.
390  // Uncomment that code if delaunay triangulation ever has to be unconstrained...
391  /*TouchSuperTriangle TouchSuperTriangle( MaxTriangleIndex, MaxTriangleIndex + 1, MaxTriangleIndex + 2 );
392  TriBuf.remove_if( TouchSuperTriangle );
393  List.pop_back();
394  List.pop_back();
395  List.pop_back();*/
396  }
397 
398  void Triangulator::_AddConstraints(DelaunayTriangleBuffer& TriBuf, const Point2DContainer& List, const IndexContainer& SegmentListIndices) const
399  {
400  DelaunaySegmentContainer DelSegList;
401 
402  // First, list all the segments that are not already in one of the delaunay triangles
403  for( IndexContainer::const_iterator SegIndexIt = SegmentListIndices.begin() ; SegIndexIt != SegmentListIndices.end() ; ++SegIndexIt )
404  {
405  Integer Index1 = *SegIndexIt;
406  SegIndexIt++;
407  Integer Index2 = *SegIndexIt;
408  Boole IsAlreadyIn = false;
409  for( DelaunayTriangleBuffer::iterator TriIt = TriBuf.begin() ; TriIt != TriBuf.end() ; ++TriIt )
410  {
411  if( TriIt->ContainsSegment(Index1,Index2) ) {
412  IsAlreadyIn = true;
413  break;
414  }
415  }
416  // only do something for segments not already in DT
417  if( !IsAlreadyIn ) {
418  DelSegList.push_back( DelaunaySegment(Index1,Index2) );
419  }
420  }
421 
422  // Re-Triangulate according to the new segments
423  for( DelaunaySegmentContainer::iterator DelSegIt = DelSegList.begin() ; DelSegIt != DelSegList.end() ; DelSegIt++ )
424  {
425  // Remove all triangles intersecting the segment and keep a list of outside edges
426  std::set<DelaunaySegment> Segments;
427  LineSegment2D Seg1( List[DelSegIt->Index1], List[DelSegIt->Index2] );
428  for( DelaunayTriangleBuffer::iterator DelTriIt = TriBuf.begin() ; DelTriIt != TriBuf.end() ; )
429  {
430  Boole IsTriangleIntersected = false;
431  Integer DegenIndex;
432  for( Integer TriPoint = 0 ; TriPoint < 3 ; ++TriPoint )
433  {
434  //Early out if 2 points are in fact the same
435  if( DelTriIt->Indexes[ TriPoint ] == DelSegIt->Index1 ||
436  DelTriIt->Indexes[ TriPoint ] == DelSegIt->Index2 ||
437  DelTriIt->Indexes[ ( TriPoint + 1 ) % 3 ] == DelSegIt->Index1 ||
438  DelTriIt->Indexes[ ( TriPoint + 1 ) % 3 ] == DelSegIt->Index2 )
439  {
440  if( DelTriIt->IsDegenerate() ) {
441  if( DelTriIt->Indexes[ TriPoint ] == DelSegIt->Index1 || DelTriIt->Indexes[ ( TriPoint + 1 ) % 3 ] == DelSegIt->Index1 ) {
442  DegenIndex = DelSegIt->Index1;
443  }else if( DelTriIt->Indexes[ TriPoint ] == DelSegIt->Index2 || DelTriIt->Indexes[ ( TriPoint + 1 ) % 3 ] == DelSegIt->Index2 ) {
444  DegenIndex = DelSegIt->Index2;
445  }
446  IsTriangleIntersected = true;
447  }else{
448  continue;
449  }
450  }
451  LineSegment2D Seg2( DelTriIt->GetPoint( TriPoint ), DelTriIt->GetPoint( ( TriPoint + 1 ) % 3 ) );
453  if( Result.first ) {
454  IsTriangleIntersected = true;
455  break;
456  }
457  }
458  if( IsTriangleIntersected ) {
459  for( Integer TriPoint = 0 ; TriPoint < 3 ; ++TriPoint )
460  {
461  DelaunaySegment DelSeg1( DelTriIt->Indexes[ TriPoint ], DelTriIt->Indexes[ ( TriPoint + 1 ) % 3 ] );
462  if( Segments.find(DelSeg1) != Segments.end() ) {
463  Segments.erase(DelSeg1);
464  }else if( Segments.find( DelSeg1.Inverse() ) != Segments.end() ) {
465  Segments.erase( DelSeg1.Inverse() );
466  }else{
467  Segments.insert(DelSeg1);
468  }
469  }
470  DelTriIt = TriBuf.erase( DelTriIt );
471  }else{
472  DelTriIt++;
473  }
474  }
475 
476  // Divide the list of points (coming from remaining segments) in 2 groups : "above" and "below"
477  IndexContainer PointsAbove;
478  IndexContainer PointsBelow;
479  Integer Point = DelSegIt->Index1;
480  Boole IsAbove = true;
481  while( Segments.size() > 0 )
482  {
483  //find next point
484  for( std::set<DelaunaySegment>::iterator SegSetIt = Segments.begin() ; SegSetIt != Segments.end() ; ++SegSetIt )
485  {
486  if( SegSetIt->Index1 == Point || SegSetIt->Index2 == Point ) {
487  if( SegSetIt->Index1 == Point ) {
488  Point = SegSetIt->Index2;
489  }else{
490  Point = SegSetIt->Index1;
491  }
492  Segments.erase(SegSetIt);
493  if( Point == DelSegIt->Index2 ) {
494  IsAbove = false;
495  }else if( Point != DelSegIt->Index1 ) {
496  if( IsAbove ) {
497  PointsAbove.push_back(Point);
498  }else{
499  PointsBelow.push_back(Point);
500  }
501  }
502  break;
503  }
504  }
505  }
506 
507  // Recursively triangulate both polygons
508  this->_RecursiveTriangulatePolygon(*DelSegIt,PointsAbove,TriBuf,List);
509  this->_RecursiveTriangulatePolygon(DelSegIt->Inverse(),PointsBelow,TriBuf,List);
510  }
511 
512  // Clean up segments outside of multishape
513  if( this->RemoveOutside ) {
515  for( DelaunayTriangleBuffer::iterator TriIt = TriBuf.begin() ; TriIt != TriBuf.end() ; )
516  {
517  Boole IsTriangleOut = !this->MultiShapeToTriangulate->IsPointInside( TriIt->GetMidPoint() );
518 
519  if( IsTriangleOut ) {
520  TriIt = TriBuf.erase(TriIt);
521  }else{
522  ++TriIt;
523  }
524  }
525  }else if( this->ShapeToTriangulate && this->ShapeToTriangulate->IsClosed() ) {
526  for( DelaunayTriangleBuffer::iterator TriIt = TriBuf.begin() ; TriIt != TriBuf.end() ; )
527  {
528  Boole IsTriangleOut = !this->ShapeToTriangulate->IsPointInside( TriIt->GetMidPoint() );
529 
530  if( IsTriangleOut ) {
531  TriIt = TriBuf.erase(TriIt);
532  }else{
533  ++TriIt;
534  }
535  }
536  }
537  }
538  }
539 
540  void Triangulator::_RecursiveTriangulatePolygon(const DelaunaySegment& CuttingSeg, const IndexContainer& InputPoints, DelaunayTriangleBuffer& TriBuf, const Point2DContainer& List) const
541  {
542  if( InputPoints.size() == 0 )
543  return;
544  if( InputPoints.size() ==1 ) {
545  DelaunayTriangle Tri(&List);
546  Tri.SetVertices( CuttingSeg.Index1, CuttingSeg.Index2, *InputPoints.begin() );
547  Tri.MakeDirectIfNeeded();
548  TriBuf.push_back(Tri);
549  return;
550  }
551  // Find a point which, when associated with seg.i1 and seg.i2, builds a Delaunay triangle
552  IndexContainer::const_iterator CurrentPoint = InputPoints.begin();
553  Boole Found = false;
554  while( !Found )
555  {
556  Boole IsDelaunay = true;
557  Circle Cir( List[*CurrentPoint], List[CuttingSeg.Index1], List[CuttingSeg.Index2] );
558  for( IndexContainer::const_iterator it = InputPoints.begin() ; it != InputPoints.end() ; ++it )
559  {
560  if( Cir.IsInside( List[*it] ) && (*it != *CurrentPoint) ) {
561  IsDelaunay = false;
562  CurrentPoint = it;
563  break;
564  }
565  }
566  if( IsDelaunay ) {
567  Found = true;
568  }
569  }
570 
571  // Insert current triangle
572  DelaunayTriangle Tri(&List);
573  Tri.SetVertices(*CurrentPoint, CuttingSeg.Index1, CuttingSeg.Index2);
574  Tri.MakeDirectIfNeeded();
575  TriBuf.push_back(Tri);
576 
577  // Recurse
578  DelaunaySegment NewCut1( CuttingSeg.Index1, *CurrentPoint );
579  DelaunaySegment NewCut2( CuttingSeg.Index2, *CurrentPoint );
580  IndexContainer Set1( InputPoints.begin(), CurrentPoint );
581  IndexContainer Set2( CurrentPoint + 1, InputPoints.end() );
582 
583  if( !Set1.empty() ) {
584  this->_RecursiveTriangulatePolygon(NewCut1,Set1,TriBuf,List);
585  }
586  if( !Set2.empty() ) {
587  this->_RecursiveTriangulatePolygon(NewCut2,Set2,TriBuf,List);
588  }
589  }
590 
591  ///////////////////////////////////////////////////////////////////////////////
592  // Utility
593 
595  {
596  Point2DContainer Points;
597  IndexContainer IndexBuffer;
598  this->Triangulate(IndexBuffer,Points);
599  for( size_t CurrPoint = 0 ; CurrPoint < Points.size() ; ++CurrPoint )
600  {
601  Vector2 VP2 = Points[CurrPoint];
602  Vector3 VP(VP2.X,VP2.Y,0);
603  Vector3 Normal = -Vector3::Unit_Z();
604 
605  this->AddPoint(Buffer,VP,Normal,Vector2(VP2.X,VP2.Y));
606  }
607 
608  for( size_t CurrIndex = 0 ; CurrIndex < IndexBuffer.size() / 3 ; ++CurrIndex )
609  {
610  Buffer.AddIndex( IndexBuffer[ CurrIndex * 3 ] );
611  Buffer.AddIndex( IndexBuffer[ CurrIndex * 3 + 2 ] );
612  Buffer.AddIndex( IndexBuffer[ CurrIndex * 3 + 1 ] );
613  }
614  }
615 
617  {
618  if( this->ShapeToTriangulate == NULL && this->MultiShapeToTriangulate == NULL && this->SegmentListToTriangulate == NULL )
619  MEZZ_EXCEPTION(ExceptionBase::INVALID_STATE_EXCEPTION,"A Shape, MultiShape, or SegmentList to triangulate must be set.");
620 
621  DelaunayTriangleBuffer DelaunayTriBuf;
622  // Do the Delaunay triangulation
623  IndexContainer SegmentListIndices;
624 
625  if( this->ShapeToTriangulate ) {
626  Vertices = this->ShapeToTriangulate->GetPoints();
627  for( Whole SegIndex = 0 ; SegIndex < this->ShapeToTriangulate->GetSegCount() ; ++SegIndex )
628  {
629  SegmentListIndices.push_back( SegIndex );
630  SegmentListIndices.push_back( this->ShapeToTriangulate->GetBoundedIndex( SegIndex + 1 ) );
631  }
632  }else if( this->MultiShapeToTriangulate ) {
633  Vertices = this->MultiShapeToTriangulate->GetPoints();
634  Whole TotalIndex = 0;
635  for( Whole ShapeIndex = 0 ; ShapeIndex < this->MultiShapeToTriangulate->GetNumShapes() ; ++ShapeIndex )
636  {
637  const Shape& CurrShape = this->MultiShapeToTriangulate->GetShape(ShapeIndex);
638  for( Whole SegIndex = 0 ; SegIndex < CurrShape.GetSegCount() ; ++SegIndex )
639  {
640  SegmentListIndices.push_back( TotalIndex + SegIndex );
641  SegmentListIndices.push_back( TotalIndex + CurrShape.GetBoundedIndex( SegIndex + 1 ) );
642  }
643  TotalIndex += CurrShape.GetSegCount();
644  }
645  }else if( this->SegmentListToTriangulate ) {
646  typedef std::map<Vector2,Integer,Vector2LengthCompare> PointIndexMap;
647  PointIndexMap PointMap;
648 
649  for( SegmentContainer::iterator SegIt = this->SegmentListToTriangulate->begin() ; SegIt != this->SegmentListToTriangulate->end() ; SegIt++ )
650  {
651  if( SegIt->PointA.SquaredDistance( SegIt->PointB ) < 1e-6 ) {
652  continue;
653  }
654 
655  PointIndexMap::iterator PointIt = PointMap.find( SegIt->PointA );
656  if( PointIt != PointMap.end() ) {
657  SegmentListIndices.push_back( PointIt->second );
658  }else{
659  PointMap[ SegIt->PointA ] = Vertices.size();
660  SegmentListIndices.push_back( Vertices.size() );
661  Vertices.push_back( SegIt->PointA );
662  }
663 
664  PointIt = PointMap.find( SegIt->PointB );
665  if( PointIt != PointMap.end() ) {
666  SegmentListIndices.push_back( PointIt->second );
667  }else{
668  PointMap[ SegIt->PointB ] = Vertices.size();
669  SegmentListIndices.push_back( Vertices.size() );
670  Vertices.push_back( SegIt->PointB );
671  }
672  }
673 
674  if( this->ManualSuperTriangle ) {
675  DelaunayTriangle SuperTriangle(&Vertices);
676  for( Whole PointIndex = 0 ; PointIndex < 3 ; PointIndex++ )
677  {
678  PointIndexMap::iterator TriPointIt = PointMap.find( (*this->ManualSuperTriangle)[PointIndex] );
679  if( TriPointIt != PointMap.end() ) {
680  //SegmentListIndices.push_back(it->second);
681  SuperTriangle.Indexes[PointIndex] = TriPointIt->second;
682  }else{
683  PointMap[ (*this->ManualSuperTriangle)[PointIndex] ] = Vertices.size();
684  //SegmentListIndices.push_back(Vertices.size());
685  SuperTriangle.Indexes[PointIndex] = Vertices.size();
686  Vertices.push_back( (*this->ManualSuperTriangle)[PointIndex] );
687  }
688  }
689 
690  DelaunayTriBuf.push_back(SuperTriangle);
691  }
692  }
693  this->Delaunay(Vertices,DelaunayTriBuf);
694  // Add contraints
695  this->_AddConstraints(DelaunayTriBuf,Vertices,SegmentListIndices);
696  //Outputs index buffer
697  for( DelaunayTriangleBuffer::iterator TriIt = DelaunayTriBuf.begin() ; TriIt != DelaunayTriBuf.end() ; ++TriIt )
698  {
699  if( !TriIt->IsDegenerate() ) {
700  Indexes.push_back( TriIt->Indexes[0] );
701  Indexes.push_back( TriIt->Indexes[1] );
702  Indexes.push_back( TriIt->Indexes[2] );
703  }
704  }
705 
706  // Remove super triangle
707  if( this->RemoveOutside ) {
708  Vertices.pop_back();
709  Vertices.pop_back();
710  Vertices.pop_back();
711  }
712  }
713 
714  ///////////////////////////////////////////////////////////////////////////////
715  // Configuration
716 
718  {
719  this->ShapeToTriangulate = TriShape;
720  this->MultiShapeToTriangulate = NULL;
721  this->SegmentListToTriangulate = NULL;
722  return *this;
723  }
724 
726  {
727  this->ShapeToTriangulate = NULL;
728  this->MultiShapeToTriangulate = TriMultiShape;
729  this->SegmentListToTriangulate = NULL;
730  return *this;
731  }
732 
734  {
735  this->ShapeToTriangulate = NULL;
736  this->MultiShapeToTriangulate = NULL;
737  this->SegmentListToTriangulate = Segments;
738  return *this;
739  }
740 
742  {
743  this->ManualSuperTriangle = Tri;
744  return *this;
745  }
746 
748  {
749  this->RemoveOutside = Remove;
750  return *this;
751  }
752  }//Procedural
753  }//Graphics
754 }//Mezzanine
755 
756 #endif
Boole ContainsSegment(const Integer Index0, const Integer Index1) const
Checks to see of the segment specified via Indexes is a part of this triangle.
Integer Indexes[3]
An array of indexes forming the triangle.
Definition: triangulator.h:143
Triangulator & SetManualSuperTriangle(Triangle2D *Tri)
Sets manual super triangle.
Point2DContainer::iterator Point2DIterator
Iterator type for a Point2DContainer.
DelaunaySegment Inverse() const
Gets the inverse of this segment.
A triangle formed from 3 points in a Point2DContainer.
Definition: triangulator.h:128
Thrown when an unknown internal error occurred.
Definition: exception.h:116
Triangle2D * ManualSuperTriangle
A pointer to an optional triangle that encompasses all points to be triangulated. ...
Definition: triangulator.h:275
void _AddConstraints(DelaunayTriangleBuffer &TriBuf, const Point2DContainer &List, const IndexContainer &SegmentListIndices) const
Forces specific segments to be present in the resulting triangulation.
DelaunaySegment(const Integer First, const Integer Second)
Class constructor.
bool Boole
Generally acts a single bit, true or false.
Definition: datatypes.h:173
std::list< DelaunayTriangle > DelaunayTriangleBuffer
A container type for the storage of DelaunayTriangles.
Definition: triangulator.h:207
Boole IsPointInside(const Vector2 &Point) const
Tells whether a point is inside a shape or not.
Definition: shape.cpp:486
std::vector< LineSegment2D > SegmentContainer
Convenience typedef for the storage of segments to be processed by this class.
Definition: triangulator.h:256
A geometry math class for expressing a triangle in 2D space.
Definition: triangle.h:53
IntersectionTestResult Intersects(const LineSegment2D &Other) const
Gets whether or not another line segment intersects with this one.
Definition: linesegment.cpp:70
const Shape * ShapeToTriangulate
A pointer to the Shape to be triangulated.
Definition: triangulator.h:263
Boole IsInside(const Vector2 &Point) const
Gets whether or not a point is inside this circle.
Definition: circle.cpp:88
String ConvertToString(const Vector2 &ToConvert)
Converts a Vector2 into a string.
Definition: stringtool.cpp:291
A convenience buffer that stores vertices and indices of a mesh to be generated.
#define MEZZ_EXCEPTION(num, desc)
An easy way to throw exceptions with rich information.
Definition: exception.h:3048
int Integer
A datatype used to represent any integer close to.
Definition: datatypes.h:154
Triangulator & SetShapeToTriangulate(const Shape *TriShape)
Sets shape to triangulate.
A 4x4 matrix math class for the representation of full transforms.
Definition: matrix4x4.h:59
Boole IsDegenerate() const
Checks if this triangle is degenerate.
Real GetDeterminant() const
Gets the Determinant of this Matrix.
Definition: matrix4x4.cpp:114
SegmentContainer * SegmentListToTriangulate
A pointer to a container of segments forming the shape to triangulate.
Definition: triangulator.h:271
Boole IsPointInside(const Vector2 &Point) const
Checks to see if a point is inside this triangle.
This implements the exception hiearchy for Mezzanine.
Integer FindSegNumber(const Integer Index0, const Integer Index1) const
Gets the index of a segment within this triangle. a valid segment index is not found then an INTERNAL...
DelaunayTriangle(const Point2DContainer *List)
Class constructor.
std::pair< Boole, Vector2 > IntersectionTestResult
This is a type used for the return of a intersection test.
Definition: linesegment.h:58
Real DotProduct(const Vector2 &Other) const
This is used to calculate the dotproduct of this and another vector.
Definition: vector2.cpp:248
Boole IsClosed() const
Gets whether or not every Shape in this MultiShape is closed.
Definition: multishape.cpp:285
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
A generic circle class for geometry calculations.
Definition: circle.h:52
std::vector< DelaunaySegment > DelaunaySegmentContainer
Convenience typedef for the storage of delaunay segments to be processed by this class.
Definition: triangulator.h:258
Boole IsPointInside(const Vector2 &Point) const
Gets whether or not a point is inside this MultiShape.
Definition: multishape.cpp:198
std::vector< Integer > IndexContainer
A container of Integers used to represent the indicies of a shape.
std::vector< Vector2 > Point2DContainer
Basic container type for the storage of 2D points.
uint16_t UInt16
An 16-bit unsigned integer.
Definition: datatypes.h:122
Returned when the specified point is inside the circumcircle.
Definition: triangulator.h:136
Real Y
Coordinate on the Y vector.
Definition: vector2.h:69
void Delaunay(Point2DContainer &List, DelaunayTriangleBuffer &TriBuf) const
Performs a Delaunay Triangulation on a provided list of points in 2D space and populates a triangle b...
Returned when the specified point is exceedingly close to being outside the circumcircle.
Definition: triangulator.h:138
Real X
Coordinate on the X vector.
Definition: vector2.h:67
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
A segment of 2 points in a Point2DContainer.
Definition: triangulator.h:90
Point2DContainer GetPoints() const
Gets a copy of raw vector data of this shape.
Definition: shape.cpp:712
Integer Index1
The first index of the segment.
Definition: triangulator.h:97
Whole GetSegCount() const
Gets the number of segments in this shape.
Definition: shape.cpp:472
const Point2DContainer * Points
An array of Vector2's that for all the triangles/segments being operated on.
Definition: triangulator.h:145
Point2DContainer GetPoints() const
Gets a container of all the points in this MultiShape.
Definition: multishape.cpp:187
Real SquaredLength() const
Gets the length of this vector squared.
Definition: vector2.cpp:260
Boole RemoveOutside
Stores whether or not the super triangle should be removed at the end of triangulation.
Definition: triangulator.h:278
A generator class that implements the Delaunay Triangulation algorithm.
Definition: triangulator.h:252
Thrown when the available information should have worked but failed for unknown reasons.
Definition: exception.h:113
Whole GetBoundedIndex(const Integer Index) const
Converts a potentially unsafe Integer index into a safe Whole index.
Definition: shape.cpp:704
void AddPoint(TriangleBuffer &Buffer, const Vector3 &Loc, const Vector3 &Norm, const Vector2 &UV) const
Adds a new point to a triangle buffer, using the format defined for that MeshGenerator.
TouchSuperTriangle(const Integer First, const Integer Second, const Integer Third)
Class constructor.
Triangulator & SetRemoveOutside(const Boole Remove)
Sets if the outside of the shape must be removed.
void Triangulate(IndexContainer &Indexes, Point2DContainer &Vertices) const
Executes the Constrained Delaunay Triangulation algorithm. INVALID_STATE_EXCEPTION will be thrown if ...
String GetDebugDescription() const
Gets a string description of this triangle.
Whole GetNumShapes() const
Gets the number of shapes in this MultiShape.
Definition: multishape.cpp:317
static Vector3 Unit_Z()
Gets a vector representing the Z unit of a Vector3.
Definition: vector3.cpp:137
TriangleBuffer & AddIndex(const Integer Index)
Adds an index to the index buffer.
This is used to represent a point in space, or a vector through space.
Definition: vector3.h:77
Boole IsClosed() const
Gets whether or not this shape is closed.
Definition: shape.cpp:629
InsideType IsPointInsideCircumcircle(const Vector2 &Point) const
Checks to see if a point is inside the Circumcircle generated from this triangle. ...
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
InsideType
An enum used to describe the proximity of a point to the edge of a Circumcircle generated by the Dela...
Definition: triangulator.h:134
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
Triangulator & SetSegmentListToTriangulate(SegmentContainer *Segments)
Sets segment list to triangulate.
Triangulator & SetMultiShapeToTriangulate(const MultiShape *TriMultiShape)
Sets multi shape to triangulate.
Returned when the specified point is outside the circumcircle.
Definition: triangulator.h:137
void _RecursiveTriangulatePolygon(const DelaunaySegment &CuttingSeg, const IndexContainer &InputPoints, DelaunayTriangleBuffer &TriBuf, const Point2DContainer &List) const
Recursively generates a Delaunay triangle from a container of points.
Boole operator()(const DelaunayTriangle &Tri)
Functor operator.
Boole operator<(const DelaunaySegment &Other) const
Less-than compare operator.
A geometry math class for expressing a line connecting 2 points in 2D space.
Definition: linesegment.h:52
A collection of interconnected 2D points used to express an arbitrary 2D shape.
Definition: shape.h:95
Shape & GetShape(const Whole Index)
Gets a shape by index.
Definition: multishape.cpp:311
Vector2 GetMidPoint() const
Gets the central point of this triangle.
Boole operator==(const DelaunayTriangle &Other) const
Equality comparison operator.
virtual void AddToTriangleBuffer(TriangleBuffer &Buffer) const
Adds the vertices and indices as configured in this generator to a triangle buffer.
A grouping of individual 2D shapes used to express more elaborate shapes.
Definition: multishape.h:87
const MultiShape * MultiShapeToTriangulate
A pointer to the MultiShape to be triangulated.
Definition: triangulator.h:267
void MakeDirectIfNeeded()
Will conditionally re-arrange the vertices of this triangle.
std::string String
A datatype used to a series of characters.
Definition: datatypes.h:159
Integer Index2
The second index of the segment.
Definition: triangulator.h:100
void SetVertices(const Integer Index0, const Integer Index1, const Integer Index2)
Sets the points that form this triangle.
Vector2 GetPoint(const Integer Point) const
Gets a point in the Point2DContainer by index.