TexGen
DomainPlanes.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2006 Martin Sherburn
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#include "PrecompiledHeaders.h"
21#include "DomainPlanes.h"
22#include "Yarn.h"
23using namespace TexGen;
24
25/*
26extern "C"
27{
28#include "../Triangle/triangle.h"
29}
30*/
31CDomainPlanes::CDomainPlanes(const vector<PLANE> &Planes)
32: m_Planes(Planes)
33{
34 BuildMesh();
35}
36
38{
39}
40
42{
43 m_Planes.push_back(PLANE(XYZ(1, 0, 0), Min.x));
44 m_Planes.push_back(PLANE(XYZ(-1, 0, 0), -Max.x));
45 m_Planes.push_back(PLANE(XYZ(0, 1, 0), Min.y));
46 m_Planes.push_back(PLANE(XYZ(0, -1, 0), -Max.y));
47 m_Planes.push_back(PLANE(XYZ(0, 0, 1), Min.z));
48 m_Planes.push_back(PLANE(XYZ(0, 0, -1), -Max.z));
49 BuildMesh();
50}
51
53{
54}
55
56CDomainPlanes::CDomainPlanes(TiXmlElement &Element)
57: CDomain(Element)
58{
59 PLANE Plane;
60 FOR_EACH_TIXMLELEMENT(pPlane, Element, "Plane")
61 {
62 Plane.Normal = valueify<XYZ>(pPlane->Attribute("Normal"));
63 pPlane->Attribute("d", &Plane.d);
64 m_Planes.push_back(Plane);
65 }
66// if (m_Mesh.m_Nodes.empty())
67 if(m_Mesh.GetNumNodes()==0)
68 {
69 BuildMesh();
70 }
71}
72
73void CDomainPlanes::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
74{
75 CDomain::PopulateTiXmlElement(Element, OutputType);
76 vector<PLANE>::const_iterator itPlane;
77 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
78 {
79 TiXmlElement Plane("Plane");
80 Plane.SetAttribute("Normal", stringify(itPlane->Normal));
81 Plane.SetAttribute("d", stringify(itPlane->d));
82 Element.InsertEndChild(Plane);
83 }
84}
85
87{
88 m_Planes.push_back(Plane);
89 BuildMesh();
90}
91
92void CDomainPlanes::Grow(double dDistance)
93{
94 vector<PLANE>::iterator itPlane;
95 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
96 {
97 itPlane->d -= dDistance;
98 }
99 BuildMesh();
100}
101
103{
104 vector<PLANE>::iterator itPlane;
105 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
106 {
107 itPlane->Normal = Rotation * itPlane->Normal;
108 }
109 BuildMesh();
110}
111
113{
114 vector<PLANE>::iterator itPlane;
115 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
116 {
117 itPlane->d += DotProduct(Vector, itPlane->Normal);
118 }
119 BuildMesh();
120}
121
123{
124 vector<PLANE>::iterator itPlane;
125 XYZ P;
126 // See http://www.unknownroad.com/rtfm/graphics/rt_normals.html for details
127 // On why we create the NormalTransformation matrix like this
128 CMatrix NormalTransformation;
129 Transformation.GetInverse(NormalTransformation);
130 NormalTransformation = NormalTransformation.GetTranspose();
131 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
132 {
133 P = itPlane->Normal * itPlane->d;
134 P = Transformation * P;
135 itPlane->Normal = NormalTransformation * itPlane->Normal;
136 Normalise(itPlane->Normal);
137 itPlane->d = DotProduct(itPlane->Normal, P);
138 }
139 BuildMesh();
140}
141
142
143
145{
146 if (m_Planes.size() != 6)
147 return false;
148 int i;
149 bool bLimitsSet[6] = {false,false,false,false,false,false};
150 for (i=0; i<6; ++i)
151 {
152 if (m_Planes[i].Normal == XYZ(1, 0, 0))
153 {
154 Min.x = m_Planes[i].d;
155 bLimitsSet[0] = true;
156 }
157 if (m_Planes[i].Normal == XYZ(0, 1, 0))
158 {
159 Min.y = m_Planes[i].d;
160 bLimitsSet[1] = true;
161 }
162 if (m_Planes[i].Normal == XYZ(0, 0, 1))
163 {
164 Min.z = m_Planes[i].d;
165 bLimitsSet[2] = true;
166 }
167 if (m_Planes[i].Normal == XYZ(-1, 0, 0))
168 {
169 Max.x = -m_Planes[i].d;
170 bLimitsSet[3] = true;
171 }
172 if (m_Planes[i].Normal == XYZ(0, -1, 0))
173 {
174 Max.y = -m_Planes[i].d;
175 bLimitsSet[4] = true;
176 }
177 if (m_Planes[i].Normal == XYZ(0, 0, -1))
178 {
179 Max.z = -m_Planes[i].d;
180 bLimitsSet[5] = true;
181 }
182 }
183 for (i=0; i<6; ++i)
184 {
185 if (bLimitsSet[i] == false)
186 return false;
187 }
188 return true;
189}
190
191void CDomainPlanes::ClipMeshToDomain(CMesh &Mesh, bool bFillGaps) const
192{
193 const double TOL = 1e-9;
194
195 TGLOGINDENT("Clipping mesh to domain");
196
197 vector<XYZ> NewTriangles;
198 vector<bool> NewTrianglesFlipped;
199 vector<XYZ>::iterator itXYZ;
200 vector<XYZ> NewQuads;
201
202 vector<PLANE>::const_iterator itPlane;
203 list<int>::iterator itStart;
204 list<int>::iterator itInt;
205 const XYZ *p1, *p2, *p3, *p4;
206 double d1, d2, d3, d4; // d represents the distance of the point to the plane (i.e. +ve inside, -ve outside, 0 on top)
207 double dTemp;
208 const XYZ *pTemp;
209 double u;
210 int i;
211 int iLastNodeIndex;
212 bool bFlipped;
213
214 // Deal with surface elements
215 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
216 {
217 list<int> &QuadIndices = Mesh.GetIndices(CMesh::QUAD);
218 for (itInt = QuadIndices.begin(); itInt != QuadIndices.end(); )
219 {
220 itStart = itInt;
221
222 p1 = &Mesh.GetNode(*(itInt++));
223 p2 = &Mesh.GetNode(*(itInt++));
224 p3 = &Mesh.GetNode(*(itInt++));
225 p4 = &Mesh.GetNode(*(itInt++));
226
227 d1 = DotProduct(itPlane->Normal, *p1) - itPlane->d;
228 d2 = DotProduct(itPlane->Normal, *p2) - itPlane->d;
229 d3 = DotProduct(itPlane->Normal, *p3) - itPlane->d;
230 d4 = DotProduct(itPlane->Normal, *p4) - itPlane->d;
231
232 if (d1 <= TOL && d2 <= TOL && d3 <= TOL && d4 <= TOL) // The quad lies completely on or outside the plane
233 {
234 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
235 }
236 else if (d1 >= -TOL && d2 >= -TOL && d3 >= -TOL && d4 >= -TOL) // The quad lies completely inside the plane
237 {
238 // Do nothing
239 }
240 else if ( d1 < TOL && d2 < TOL && d3 > TOL && d4 > TOL ) // Points 1 & 2 outside plane
241 {
242 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
243 u = d4 / (d4-d1);
244 NewQuads.push_back(*p4 + (*p1-*p4) * u);
245 u = d3 / (d3-d2);
246 NewQuads.push_back(*p3 + (*p2-*p3) * u);
247 NewQuads.push_back(*p3);
248 NewQuads.push_back(*p4);
249 }
250 else if ( d2 < TOL && d3 < TOL && d4 > TOL && d1 > TOL ) // Points 2 & 3 outside plane
251 {
252 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
253 NewQuads.push_back(*p1);
254 u = d1 / (d1-d2);
255 NewQuads.push_back(*p1 + (*p2-*p1) * u);
256 u = d4 / (d4-d3);
257 NewQuads.push_back(*p4 + (*p3-*p4) * u);
258 NewQuads.push_back(*p4);
259 }
260 else if ( d3 < TOL && d4 < TOL && d1 > TOL && d2 > TOL ) // Points 3 & 4 outside plane
261 {
262 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
263 NewQuads.push_back(*p1);
264 NewQuads.push_back(*p2);
265 u = d2 / (d2-d3);
266 NewQuads.push_back(*p2 + (*p3-*p2) * u);
267 u = d1 / (d1-d4);
268 NewQuads.push_back(*p1 + (*p4-*p1) * u);
269 }
270 else if ( d4 < TOL && d1 < TOL && d2 > TOL && d3 > TOL ) // Points 4 & 1 outside plane
271 {
272 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
273 u = d2 / (d2-d1);
274 NewQuads.push_back(*p2 + (*p1-*p2) * u);
275 NewQuads.push_back(*p2);
276 NewQuads.push_back(*p3);
277 u = d3 / (d3-d4);
278 NewQuads.push_back(*p3 + (*p4-*p3) * u);
279
280 }
281 else // Convert the quad to a triangle for trimming if 1 or 3 points inside plane
282 {
283 itInt = Mesh.ConvertQuadtoTriangles(itStart);
284 }
285 }
286
287 // Add the new quads to the mesh, and clear the new quad list
288 iLastNodeIndex = int(Mesh.GetNumNodes());
289 for (i = 0; i < int(NewQuads.size()/4); ++i)
290 {
291
292 QuadIndices.push_back(4*i+iLastNodeIndex);
293 QuadIndices.push_back(4*i+1+iLastNodeIndex);
294 QuadIndices.push_back(4*i+2+iLastNodeIndex);
295 QuadIndices.push_back(4*i+3+iLastNodeIndex);
296 }
297 for (itXYZ = NewQuads.begin(); itXYZ != NewQuads.end(); ++itXYZ)
298 {
299 Mesh.AddNode(*itXYZ);
300 }
301 NewQuads.clear();
302
303 list<int> &TriIndices = Mesh.GetIndices(CMesh::TRI);
304 for (itInt = TriIndices.begin(); itInt != TriIndices.end(); )
305 {
306 itStart = itInt;
307
308 p1 = &Mesh.GetNode(*(itInt++));
309 p2 = &Mesh.GetNode(*(itInt++));
310 p3 = &Mesh.GetNode(*(itInt++));
311
312 d1 = DotProduct(itPlane->Normal, *p1) - itPlane->d;
313 d2 = DotProduct(itPlane->Normal, *p2) - itPlane->d;
314 d3 = DotProduct(itPlane->Normal, *p3) - itPlane->d;
315
316 if (d1 <= TOL && d2 <= TOL && d3 <= TOL) // The triangle lies completely outside or on the plane
317 {
318 itInt = TriIndices.erase(itStart, itInt); // Delete the triangle
319 }
320 else if (d1 >= -TOL && d2 >= -TOL && d3 >= -TOL) // The triangle lies completely inside the plane
321 {
322 // Do nothing
323 }
324 else
325 {
326 itInt = TriIndices.erase(itStart, itInt); // Delete the triangle, will need to be seperated into smaller ones
327 // Order points such that d1 >= d2 >= d3
328 bFlipped = false; // Keep track of whether the triangle is flipped or not
329 if (d2 > d1)
330 {
331 dTemp = d2; d2 = d1; d1 = dTemp;
332 pTemp = p2; p2 = p1; p1 = pTemp;
333 bFlipped = !bFlipped;
334 }
335 if (d3 > d2)
336 {
337 dTemp = d3; d3 = d2; d2 = dTemp;
338 pTemp = p3; p3 = p2; p2 = pTemp;
339 bFlipped = !bFlipped;
340 if (d2 > d1)
341 {
342 dTemp = d2; d2 = d1; d1 = dTemp;
343 pTemp = p2; p2 = p1; p1 = pTemp;
344 bFlipped = !bFlipped;
345 }
346 }
347
348 if (d2 <= TOL) // One point of the triangle lies inside the plane, the other two are outside or on the plane
349 {
350 NewTriangles.push_back(*p1);
351 u = d1 / (d1-d2);
352 NewTriangles.push_back(*p1 + (*p2-*p1) * u);
353 u = d1 / (d1-d3);
354 NewTriangles.push_back(*p1 + (*p3-*p1) * u);
355 NewTrianglesFlipped.push_back(bFlipped);
356 }
357 else if (d3 <= TOL) // Two points of the triangle lie inside the plane, the other is outside or on the plane
358 {
359 NewTriangles.push_back(*p1);
360 NewTriangles.push_back(*p2);
361 u = d2 / (d2-d3);
362 NewTriangles.push_back(*p2 + (*p3-*p2) * u);
363 NewTrianglesFlipped.push_back(bFlipped);
364
365 NewTriangles.push_back(*p2 + (*p3-*p2) * u);
366 u = d1 / (d1-d3);
367 NewTriangles.push_back(*p1 + (*p3-*p1) * u);
368 NewTriangles.push_back(*p1);
369 NewTrianglesFlipped.push_back(bFlipped);
370 }
371 }
372 }
373
374 // Add the new triangles to the mesh, and clear the new triangles list
375 iLastNodeIndex = int(Mesh.GetNumNodes());
376 for (i = 0; i < int(NewTriangles.size()/3); ++i)
377 {
378 // The order of the vertices determines the direction of the normal,
379 // the normal should always point outwards from the yarn. Thus if the
380 // normal was flipped we must make sure the indices are swapped so
381 // the normal is flipped back to its original state.
382 if (!NewTrianglesFlipped[i])
383 {
384 TriIndices.push_back(3*i+iLastNodeIndex);
385 TriIndices.push_back(3*i+1+iLastNodeIndex);
386 TriIndices.push_back(3*i+2+iLastNodeIndex);
387 }
388 else
389 {
390 TriIndices.push_back(3*i+iLastNodeIndex);
391 TriIndices.push_back(3*i+2+iLastNodeIndex);
392 TriIndices.push_back(3*i+1+iLastNodeIndex);
393 }
394 }
395 for (itXYZ = NewTriangles.begin(); itXYZ != NewTriangles.end(); ++itXYZ)
396 {
397 Mesh.AddNode(*itXYZ);
398 }
399 NewTriangles.clear();
400 NewTrianglesFlipped.clear();
401
402 vector<int> ClosedLoop;
403 if (bFillGaps)
404 FillGaps(Mesh, *itPlane, ClosedLoop);
405 }
406
407 // Deal with volume elements
408 int iNumNodes;
409 double d;
410 vector<CMesh::ELEMENT_TYPE> VolumeElements;
411 vector<CMesh::ELEMENT_TYPE>::iterator itElementType;
412 VolumeElements.push_back(CMesh::TET);
413 VolumeElements.push_back(CMesh::PYRAMID);
414 VolumeElements.push_back(CMesh::WEDGE);
415 VolumeElements.push_back(CMesh::HEX);
416 VolumeElements.push_back(CMesh::QUADRATIC_TET);
417 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
418 {
419 for (itElementType = VolumeElements.begin(); itElementType != VolumeElements.end(); ++itElementType)
420 {
421 list<int> &Indices = Mesh.GetIndices(*itElementType);
422 for (itInt = Indices.begin(); itInt != Indices.end(); )
423 {
424 iNumNodes = CMesh::GetNumNodes(*itElementType);
425 itStart = itInt;
426
427 XYZ Center;
428 for (i=0; i<iNumNodes; ++i)
429 {
430 Center += Mesh.GetNode(*(itInt++));
431 }
432 Center /= iNumNodes;
433
434 d = DotProduct(itPlane->Normal, Center) - itPlane->d;
435 if (d < 0)
436 itInt = Indices.erase(itStart, itInt); // Delete the volume element
437 }
438 }
439 }
440
441 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
442 {
443 list<int> &Indices = Mesh.GetIndices(CMesh::POLYGON);
444 list<int>::iterator itIndices;
445 int StartIndex, NewStartIndex;
446 bool bResetStart = true;
447 list<int>::iterator itStartIndex;
448 bool bDelete = true;
449
450 for ( itIndices = Indices.begin(); itIndices != Indices.end(); )
451 {
452 bDelete = true;
453 StartIndex = NewStartIndex = (*(itIndices));
454 itStartIndex = itIndices;
455 vector<int> PolygonIndex;
456 XYZ p;
457 bResetStart = true;
458 int i = 0, iPoints = 0;
459 do {
460 p = Mesh.GetNode(*(itIndices));
461 d = DotProduct(itPlane->Normal, p) - itPlane->d;
462 if ( d < TOL )
463 {
464 //if ( *itIndices == NewStartIndex )
465 //bResetStart = false; // Keeping 1st so don't need to reset
466 //bDelete = false;
467 ++iPoints;
468 }
469 ++i;
470 ++itIndices;
471 } while ( (*itIndices) != StartIndex );
472 ++itIndices;
473 //if ( bDelete )
474 if ( iPoints == i ) // All points outside plane
475 {
476 itIndices = Indices.erase( itStartIndex, itIndices );
477 }
478 /*if ( NewStartIndex != StartIndex ) // Must have deleted start so reset to new start value
479 *(itIndices) = NewStartIndex;
480 if ( NewStartIndex == StartIndex && bResetStart ) // Deleted whole loop so need to delete repeated start index
481 itIndices = Indices.erase(itIndices);
482 else
483 itIndices++;*/
484 }
485 }
486
488}
489
490bool CDomainPlanes::ClipMeshToDomain(CMesh &Mesh, vector<CMesh> &DomainMeshes, bool bFillGaps) const
491{
492 const double TOL = 1e-9;
493
494 TGLOGINDENT("Clipping mesh to domain");
495
496 vector<XYZ> NewTriangles;
497 vector<bool> NewTrianglesFlipped;
498 vector<XYZ>::iterator itXYZ;
499 vector<XYZ> NewQuads;
500
501 vector<PLANE>::const_iterator itPlane;
502 list<int>::iterator itStart;
503 list<int>::iterator itInt;
504 const XYZ *p1, *p2, *p3, *p4;
505 double d1, d2, d3, d4; // d represents the distance of the point to the plane (i.e. +ve inside, -ve outside, 0 on top)
506 double dTemp;
507 const XYZ *pTemp;
508 double u;
509 int i;
510 int iLastNodeIndex;
511 bool bFlipped;
512 vector<CMesh>::iterator itDomainMeshes;
513 bool bSaveDomainMeshes = false;
514 if ( DomainMeshes.size() != 0 )
515 bSaveDomainMeshes = true;
516 /*if( DomainMeshes.size() != 0 && DomainMeshes.size() == m_Planes.size() ) // If these aren't equal then assumption that DomainMeshes match plains isn't sound
517 {
518 itDomainMeshes = DomainMeshes.begin();
519 bSaveDomainMeshes = true;
520 }*/
521 // Deal with surface elements
522 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
523 {
524 list<int> &QuadIndices = Mesh.GetIndices(CMesh::QUAD);
525 for (itInt = QuadIndices.begin(); itInt != QuadIndices.end(); )
526 {
527 itStart = itInt;
528
529 p1 = &Mesh.GetNode(*(itInt++));
530 p2 = &Mesh.GetNode(*(itInt++));
531 p3 = &Mesh.GetNode(*(itInt++));
532 p4 = &Mesh.GetNode(*(itInt++));
533
534 d1 = DotProduct(itPlane->Normal, *p1) - itPlane->d;
535 d2 = DotProduct(itPlane->Normal, *p2) - itPlane->d;
536 d3 = DotProduct(itPlane->Normal, *p3) - itPlane->d;
537 d4 = DotProduct(itPlane->Normal, *p4) - itPlane->d;
538
539 if (d1 <= TOL && d2 <= TOL && d3 <= TOL && d4 <= TOL) // The quad lies completely on or outside the plane
540 {
541 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
542 }
543 else if (d1 >= -TOL && d2 >= -TOL && d3 >= -TOL && d4 >= -TOL) // The quad lies completely inside the plane
544 {
545 // Do nothing
546 }
547 else if ( d1 < TOL && d2 < TOL && d3 > TOL && d4 > TOL ) // Points 1 & 2 outside plane
548 {
549 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
550 u = d4 / (d4-d1);
551 NewQuads.push_back(*p4 + (*p1-*p4) * u);
552 u = d3 / (d3-d2);
553 NewQuads.push_back(*p3 + (*p2-*p3) * u);
554 NewQuads.push_back(*p3);
555 NewQuads.push_back(*p4);
556 }
557 else if ( d2 < TOL && d3 < TOL && d4 > TOL && d1 > TOL ) // Points 2 & 3 outside plane
558 {
559 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
560 NewQuads.push_back(*p1);
561 u = d1 / (d1-d2);
562 NewQuads.push_back(*p1 + (*p2-*p1) * u);
563 u = d4 / (d4-d3);
564 NewQuads.push_back(*p4 + (*p3-*p4) * u);
565 NewQuads.push_back(*p4);
566 }
567 else if ( d3 < TOL && d4 < TOL && d1 > TOL && d2 > TOL ) // Points 3 & 4 outside plane
568 {
569 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
570 NewQuads.push_back(*p1);
571 NewQuads.push_back(*p2);
572 u = d2 / (d2-d3);
573 NewQuads.push_back(*p2 + (*p3-*p2) * u);
574 u = d1 / (d1-d4);
575 NewQuads.push_back(*p1 + (*p4-*p1) * u);
576 }
577 else if ( d4 < TOL && d1 < TOL && d2 > TOL && d3 > TOL ) // Points 4 & 1 outside plane
578 {
579 itInt = QuadIndices.erase(itStart, itInt); // Delete the quad
580 u = d2 / (d2-d1);
581 NewQuads.push_back(*p2 + (*p1-*p2) * u);
582 NewQuads.push_back(*p2);
583 NewQuads.push_back(*p3);
584 u = d3 / (d3-d4);
585 NewQuads.push_back(*p3 + (*p4-*p3) * u);
586
587 }
588 else // Convert the quad to a triangle for trimming if 1 or 3 points inside plane
589 {
590 itInt = Mesh.ConvertQuadtoTriangles(itStart);
591 }
592 }
593
594 // Add the new quads to the mesh, and clear the new quad list
595 iLastNodeIndex = int(Mesh.GetNumNodes());
596 for (i = 0; i < int(NewQuads.size()/4); ++i)
597 {
598
599 QuadIndices.push_back(4*i+iLastNodeIndex);
600 QuadIndices.push_back(4*i+1+iLastNodeIndex);
601 QuadIndices.push_back(4*i+2+iLastNodeIndex);
602 QuadIndices.push_back(4*i+3+iLastNodeIndex);
603 }
604 for (itXYZ = NewQuads.begin(); itXYZ != NewQuads.end(); ++itXYZ)
605 {
606 Mesh.AddNode(*itXYZ);
607 }
608 NewQuads.clear();
609
610 list<int> &TriIndices = Mesh.GetIndices(CMesh::TRI);
611 for (itInt = TriIndices.begin(); itInt != TriIndices.end(); )
612 {
613 itStart = itInt;
614
615 p1 = &Mesh.GetNode(*(itInt++));
616 p2 = &Mesh.GetNode(*(itInt++));
617 p3 = &Mesh.GetNode(*(itInt++));
618
619 d1 = DotProduct(itPlane->Normal, *p1) - itPlane->d;
620 d2 = DotProduct(itPlane->Normal, *p2) - itPlane->d;
621 d3 = DotProduct(itPlane->Normal, *p3) - itPlane->d;
622
623 if (d1 <= TOL && d2 <= TOL && d3 <= TOL) // The triangle lies completely outside or on the plane
624 {
625 itInt = TriIndices.erase(itStart, itInt); // Delete the triangle
626 }
627 else if (d1 >= -TOL && d2 >= -TOL && d3 >= -TOL) // The triangle lies completely inside the plane
628 {
629 // Do nothing
630 }
631 else
632 {
633 itInt = TriIndices.erase(itStart, itInt); // Delete the triangle, will need to be seperated into smaller ones
634 // Order points such that d1 >= d2 >= d3
635 bFlipped = false; // Keep track of whether the triangle is flipped or not
636 if (d2 > d1)
637 {
638 dTemp = d2; d2 = d1; d1 = dTemp;
639 pTemp = p2; p2 = p1; p1 = pTemp;
640 bFlipped = !bFlipped;
641 }
642 if (d3 > d2)
643 {
644 dTemp = d3; d3 = d2; d2 = dTemp;
645 pTemp = p3; p3 = p2; p2 = pTemp;
646 bFlipped = !bFlipped;
647 if (d2 > d1)
648 {
649 dTemp = d2; d2 = d1; d1 = dTemp;
650 pTemp = p2; p2 = p1; p1 = pTemp;
651 bFlipped = !bFlipped;
652 }
653 }
654
655 if (d2 <= TOL) // One point of the triangle lies inside the plane, the other two are outside or on the plane
656 {
657 NewTriangles.push_back(*p1);
658 u = d1 / (d1-d2);
659 NewTriangles.push_back(*p1 + (*p2-*p1) * u);
660 u = d1 / (d1-d3);
661 NewTriangles.push_back(*p1 + (*p3-*p1) * u);
662 NewTrianglesFlipped.push_back(bFlipped);
663 }
664 else if (d3 <= TOL) // Two points of the triangle lie inside the plane, the other is outside or on the plane
665 {
666 NewTriangles.push_back(*p1);
667 NewTriangles.push_back(*p2);
668 u = d2 / (d2-d3);
669 NewTriangles.push_back(*p2 + (*p3-*p2) * u);
670 NewTrianglesFlipped.push_back(bFlipped);
671
672 NewTriangles.push_back(*p2 + (*p3-*p2) * u);
673 u = d1 / (d1-d3);
674 NewTriangles.push_back(*p1 + (*p3-*p1) * u);
675 NewTriangles.push_back(*p1);
676 NewTrianglesFlipped.push_back(bFlipped);
677 }
678 }
679 }
680
681 // Add the new triangles to the mesh, and clear the new triangles list
682 iLastNodeIndex = int(Mesh.GetNumNodes());
683 for (i = 0; i < int(NewTriangles.size()/3); ++i)
684 {
685 // The order of the vertices determines the direction of the normal,
686 // the normal should always point outwards from the yarn. Thus if the
687 // normal was flipped we must make sure the indices are swapped so
688 // the normal is flipped back to its original state.
689 if (!NewTrianglesFlipped[i])
690 {
691 TriIndices.push_back(3*i+iLastNodeIndex);
692 TriIndices.push_back(3*i+1+iLastNodeIndex);
693 TriIndices.push_back(3*i+2+iLastNodeIndex);
694 }
695 else
696 {
697 TriIndices.push_back(3*i+iLastNodeIndex);
698 TriIndices.push_back(3*i+2+iLastNodeIndex);
699 TriIndices.push_back(3*i+1+iLastNodeIndex);
700 }
701 }
702 for (itXYZ = NewTriangles.begin(); itXYZ != NewTriangles.end(); ++itXYZ)
703 {
704 Mesh.AddNode(*itXYZ);
705 }
706 NewTriangles.clear();
707 NewTrianglesFlipped.clear();
708
709 vector<int> ClosedLoop;
710 if (bFillGaps)
711 {
712 if ( !FillGaps(Mesh, *itPlane, ClosedLoop, false) )
713 return false;
714 }
715 if ( bSaveDomainMeshes )
716 {
717 if ( ClosedLoop.size() > 0 )
718 {
719 for( itDomainMeshes = DomainMeshes.begin(); itDomainMeshes != DomainMeshes.end(); itDomainMeshes++ )
720 {
721 XYZ Points[3];
722 XYZ Normal;
723 double dPlane;
724 for( int i = 0; i < 3; i++ )
725 {
726 Points[i] = (*itDomainMeshes).GetNode(i);
727 }
728 Normal = CrossProduct( (Points[0]-Points[1]), Points[2]-Points[1] );
729 dPlane = DotProduct(Points[2], Normal);
730 if ( fabs( DotProduct( Mesh.GetNode(ClosedLoop[0]), Normal )- dPlane) < 0.000001 )
731 {
732 int iIndex = (*itDomainMeshes).GetNumNodes();
733 int iPolyStart = iIndex;
734 vector<int>::iterator itClosedLoop;
735 vector<int> Indices;
736 int iStartInd = ClosedLoop[0];
737 for ( itClosedLoop = ClosedLoop.begin(); itClosedLoop != ClosedLoop.end(); itClosedLoop++ )
738 {
739 if ( *itClosedLoop == iStartInd && iIndex > iPolyStart ) // Back to start of loop
740 {
741 Indices.push_back( iPolyStart );
742 }
743 else
744 {
745 Indices.push_back(iIndex++);
746 (*itDomainMeshes).AddNode( Mesh.GetNode(*itClosedLoop) );
747 }
748 }
749 if ( ClosedLoop[ClosedLoop.size()-1] != iStartInd ) // Close loop if not already closed
750 Indices.push_back(iPolyStart);
751 (*itDomainMeshes).AddElement(CMesh::POLYGON, Indices );
752 break;
753 }
754 }
755 }
756 //itDomainMeshes++;
757 }
758 }
759
760 // Deal with volume elements
761 int iNumNodes;
762 double d;
763 vector<CMesh::ELEMENT_TYPE> VolumeElements;
764 vector<CMesh::ELEMENT_TYPE>::iterator itElementType;
765 VolumeElements.push_back(CMesh::TET);
766 VolumeElements.push_back(CMesh::PYRAMID);
767 VolumeElements.push_back(CMesh::WEDGE);
768 VolumeElements.push_back(CMesh::HEX);
769 VolumeElements.push_back(CMesh::QUADRATIC_TET);
770 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
771 {
772 for (itElementType = VolumeElements.begin(); itElementType != VolumeElements.end(); ++itElementType)
773 {
774 list<int> &Indices = Mesh.GetIndices(*itElementType);
775 for (itInt = Indices.begin(); itInt != Indices.end(); )
776 {
777 iNumNodes = CMesh::GetNumNodes(*itElementType);
778 itStart = itInt;
779
780 XYZ Center;
781 for (i=0; i<iNumNodes; ++i)
782 {
783 Center += Mesh.GetNode(*(itInt++));
784 }
785 Center /= iNumNodes;
786
787 d = DotProduct(itPlane->Normal, Center) - itPlane->d;
788 if (d < 0)
789 itInt = Indices.erase(itStart, itInt); // Delete the volume element
790 }
791 }
792 }
793
794 // Deal with polygon elements
795/* for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
796 {
797 list<int> &Indices = Mesh.GetIndices(CMesh::POLYGON);
798 list<int>::iterator itIndices;
799 int StartIndex, NewStartIndex;
800 bool bResetStart = true;
801 list<int>::iterator itStartIndex;
802
803 for ( itIndices = Indices.begin(); itIndices != Indices.end(); )
804 {
805 StartIndex = NewStartIndex = (*itIndices);
806 itStartIndex = itIndices;
807 vector<int> PolygonIndex;
808 XYZ p;
809 bResetStart = true;
810 do {
811 p = Mesh.GetNode(*itIndices);
812 d = DotProduct(itPlane->Normal, p) - itPlane->d;
813 if ( d < TOL )
814 {
815 //if ( *itIndices == NewStartIndex )
816 // bResetStart = true;
817 itIndices = Indices.erase(itIndices);
818 if ( bResetStart )
819 NewStartIndex = *itIndices;
820 }
821 else
822 {
823 //if ( *itIndices == NewStartIndex )
824 bResetStart = false; // Keeping 1st so don't need to reset
825 ++itIndices;
826 }
827 } while ( (*itIndices) != StartIndex );
828
829 if ( NewStartIndex != StartIndex ) // Must have deleted start so reset to new start value
830 *(itIndices) = NewStartIndex;
831 if ( NewStartIndex == StartIndex && bResetStart ) // Deleted whole loop so need to delete repeated start index
832 itIndices = Indices.erase(itIndices);
833 else
834 itIndices++;
835 }
836 }*/
837
838 // Deal with polygon elements
839 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
840 {
841 list<int> &Indices = Mesh.GetIndices(CMesh::POLYGON);
842 list<int>::iterator itIndices;
843 int StartIndex, NewStartIndex;
844 bool bResetStart = true;
845 list<int>::iterator itStartIndex;
846 bool bDelete = true;
847
848 for ( itIndices = Indices.begin(); itIndices != Indices.end(); )
849 {
850 bDelete = true;
851 StartIndex = NewStartIndex = (*(itIndices));
852 itStartIndex = itIndices;
853 vector<int> PolygonIndex;
854 XYZ p;
855 bResetStart = true;
856 int i = 0, iPoints = 0;
857 do {
858 p = Mesh.GetNode(*(itIndices));
859 d = DotProduct(itPlane->Normal, p) - itPlane->d;
860 if ( d < TOL )
861 {
862 //if ( *itIndices == NewStartIndex )
863 //bResetStart = false; // Keeping 1st so don't need to reset
864 //bDelete = false;
865 ++iPoints;
866 }
867 ++i;
868 ++itIndices;
869 } while ( (*itIndices) != StartIndex );
870 ++itIndices;
871 //if ( bDelete )
872 if ( iPoints == i ) // All points outside plane
873 {
874 itIndices = Indices.erase( itStartIndex, itIndices );
875 }
876 /*if ( NewStartIndex != StartIndex ) // Must have deleted start so reset to new start value
877 *(itIndices) = NewStartIndex;
878 if ( NewStartIndex == StartIndex && bResetStart ) // Deleted whole loop so need to delete repeated start index
879 itIndices = Indices.erase(itIndices);
880 else
881 itIndices++;*/
882 }
883 }
884
886 return true;
887}
888
889
891{
892 {
893 // http://paulbourke.net/geometry/pointlineplane/
894 m_PlaneIntersections.clear();
895 m_PlaneIntersections.resize(m_Planes.size());
896 vector<PLANE>::const_iterator itPlane1;
897 vector<PLANE>::const_iterator itPlane2;
898 double dDeterminant;
899 double N1dotN2, c1, c2;
900 int i;
901 for (itPlane1 = m_Planes.begin(), i=0; itPlane1 != m_Planes.end(); ++itPlane1, ++i)
902 {
903 for (itPlane2 = m_Planes.begin(); itPlane2 != m_Planes.end(); ++itPlane2)
904 {
905 if (itPlane1 == itPlane2)
906 continue;
907 N1dotN2 = DotProduct(itPlane1->Normal, itPlane2->Normal);
908 dDeterminant = GetLengthSquared(itPlane1->Normal)*GetLengthSquared(itPlane2->Normal) - N1dotN2 * N1dotN2;
909 if (abs(dDeterminant) < 1e-6)
910 continue;
911
912 c1 = (itPlane1->d*GetLengthSquared(itPlane2->Normal) - itPlane2->d*N1dotN2) / dDeterminant;
913 c2 = (itPlane2->d*GetLengthSquared(itPlane1->Normal) - itPlane1->d*N1dotN2) / dDeterminant;
914
915 // Points to the left of the line are considered inside when looking along the second vector
916 m_PlaneIntersections[i].push_back(make_pair(c1 * itPlane1->Normal + c2 * itPlane2->Normal, CrossProduct(itPlane1->Normal, itPlane2->Normal)));
917 }
918 }
919 }
920 {
921 m_Mesh.Clear();
922 double dDenom, u;
923 vector<PLANE>::const_iterator itPlane;
924 int i, j;
925 for (i=0; i<(int)m_PlaneIntersections.size(); ++i)
926 {
927 for (j=0; j<(int)m_PlaneIntersections[i].size(); ++j)
928 {
929 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
930 {
931 dDenom = DotProduct(itPlane->Normal, m_PlaneIntersections[i][j].second);
932 if (abs(dDenom) < 1e-6)
933 continue;
934 u = (itPlane->d-DotProduct(itPlane->Normal, m_PlaneIntersections[i][j].first)) / dDenom;
935 m_Mesh.AddNode(m_PlaneIntersections[i][j].first + u * m_PlaneIntersections[i][j].second);
936 }
937 }
938 }
939 vector<XYZ>::iterator itPoint;
940
941 for (itPoint = m_Mesh.GetNodes().begin(); itPoint != m_Mesh.GetNodes().end(); )
942 {
943 for (itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane)
944 {
945 double u;
946 u = DotProduct(*itPoint, itPlane->Normal) - itPlane->d;
947 if (u < -1e-6)
948 {
949 itPoint = m_Mesh.DeleteNode(itPoint);
950 break;
951 }
952 }
953 if (itPlane == m_Planes.end())
954 ++itPoint;
955 }
957 }
958}
959
960bool CDomainPlanes::FillGaps(CMesh &Mesh, const PLANE &Plane, vector<int> &Polygon, bool bMeshGaps )
961{
962 const double TOL = 1e-9;
963
964 int i1, i2, i3, i4;
965 const XYZ *p1, *p2, *p3, *p4;
966 double d1, d2, d3, d4; // d represents the distance of the point to the plane (i.e. +ve inside, -ve outside, 0 on top)
967
968 vector<pair<int, int> > Segments;
969
970 // Merge the nodes together and remove degenerate triangles
971 Mesh.MergeNodes();
973
974 // Build a list of segments which lie on the plane
975 list<int>::iterator itInt;
976 // Check each quad to see if any of the edges lie on the plane
977 list<int> &QuadIndices = Mesh.GetIndices(CMesh::QUAD);
978 for (itInt = QuadIndices.begin(); itInt != QuadIndices.end(); )
979 {
980 i1 = *(itInt++);
981 i2 = *(itInt++);
982 i3 = *(itInt++);
983 i4 = *(itInt++);
984
985 p1 = &Mesh.GetNode(i1);
986 p2 = &Mesh.GetNode(i2);
987 p3 = &Mesh.GetNode(i3);
988 p4 = &Mesh.GetNode(i4);
989
990 d1 = DotProduct(Plane.Normal, *p1) - Plane.d;
991 d2 = DotProduct(Plane.Normal, *p2) - Plane.d;
992 d3 = DotProduct(Plane.Normal, *p3) - Plane.d;
993 d4 = DotProduct(Plane.Normal, *p4) - Plane.d;
994
995 d1 = abs(d1);
996 d2 = abs(d2);
997 d3 = abs(d3);
998 d4 = abs(d4);
999
1000 // Add the segments which lie on the plane
1001 // The order of the segment indices is important, it tells us
1002 // which side is inside and which side is outside
1003 // Here the segments are added clockwise when viewed along the plane normal
1004 if (d1 <= TOL && d2 <= TOL)
1005 {
1006 Segments.push_back(pair<int, int>(i1, i2));
1007 }
1008 if (d2 <= TOL && d3 <= TOL)
1009 {
1010 Segments.push_back(pair<int, int>(i2, i3));
1011 }
1012 if (d3 <= TOL && d4 <= TOL)
1013 {
1014 Segments.push_back(pair<int, int>(i3, i4));
1015 }
1016 if (d4 <= TOL && d1 <= TOL)
1017 {
1018 Segments.push_back(pair<int, int>(i4, i1));
1019 }
1020 }
1021 // Check each triangle to find edges that lie on the plane
1022 list<int> &TriIndices = Mesh.GetIndices(CMesh::TRI);
1023 for (itInt = TriIndices.begin(); itInt != TriIndices.end(); )
1024 {
1025 i1 = *(itInt++);
1026 i2 = *(itInt++);
1027 i3 = *(itInt++);
1028
1029 p1 = &Mesh.GetNode(i1);
1030 p2 = &Mesh.GetNode(i2);
1031 p3 = &Mesh.GetNode(i3);
1032
1033 d1 = DotProduct(Plane.Normal, *p1) - Plane.d;
1034 d2 = DotProduct(Plane.Normal, *p2) - Plane.d;
1035 d3 = DotProduct(Plane.Normal, *p3) - Plane.d;
1036
1037 d1 = abs(d1);
1038 d2 = abs(d2);
1039 d3 = abs(d3);
1040
1041 // Add the segments which lie on the plane
1042 // The order of the segment indices is important, it tells us
1043 // which side is inside and which side is outside
1044 // Here the segments are added clockwise when viewed along the plane normal
1045 if (d1 <= TOL && d2 <= TOL)
1046 {
1047 Segments.push_back(pair<int, int>(i1, i2));
1048 }
1049 if (d2 <= TOL && d3 <= TOL)
1050 {
1051 Segments.push_back(pair<int, int>(i2, i3));
1052 }
1053 if (d3 <= TOL && d1 <= TOL)
1054 {
1055 Segments.push_back(pair<int, int>(i3, i1));
1056 }
1057 }
1058
1059 vector<pair<int, int> >::iterator itSegment;
1060
1061 // Find closed loops
1062 int iIndex, iFirstIndex;
1063 bool bFound;
1064
1065#ifdef _DEBUG
1066 // This code will help to find out where the source of the problem comes from.
1067 // It basically checks how many times each node has been referenced by the segments.
1068 // Each node should be referenced twice, otherwise there will be a problem.
1069
1070 map<int, int> Indices;
1071 map<int, int>::iterator itIndex;
1072
1073 for (itSegment = Segments.begin(); itSegment != Segments.end(); ++itSegment)
1074 {
1075 Indices[itSegment->first]++;
1076 Indices[itSegment->second]++;
1077 }
1078#endif
1079
1080 while(Segments.size())
1081 {
1082 vector<int> ClosedLoop;
1083 // Start at a random index and go round counterclockwise until a full circle is done
1084 // Indices are added to the ClosedLoop list with each index specified only once.
1085 // As segments are followed they are removed from the segments list.
1086 iFirstIndex = iIndex = Segments.begin()->first;
1087 do
1088 {
1089 bFound = false;
1090 for (itSegment = Segments.begin(); itSegment != Segments.end(); ++itSegment)
1091 {
1092 // Follow segments counter-clockwise only
1093 if (itSegment->second == iIndex)
1094 {
1095 // Adjust the index to go follow the segment
1096 iIndex = itSegment->first;
1097 // Delete the segment, it is no longer needed
1098 itSegment = Segments.erase(itSegment);
1099 // Found the segment, now stop searching
1100 bFound = true;
1101 break;
1102 }
1103 // This part is commented because we only want to go counter-clockwise
1104/* else if (itSegment->first == iIndex)
1105 {
1106 iIndex = itSegment->second;
1107 itSegment = Segments.erase(itSegment);
1108 bFound = true;
1109 break;
1110 }*/
1111 }
1112 if (bFound)
1113 {
1114 // Add the index to the loop
1115 ClosedLoop.push_back(iIndex);
1116 // If the index is the same as the first index then a full circle
1117 // has been made, its time to exit the loop
1118 if (iFirstIndex == iIndex)
1119 break;
1120 }
1121 } while(bFound);
1122
1123 // If a dead end was reached the bFound will be false. This means that the segments
1124 // do not form a fully closed loop. This can occur if nodes are not merged together
1125 // correctly (two nodes may occupy the same position where each one is only referenced
1126 // once which will cause a break in the loop).
1127 if (!bFound)
1128 {
1129 // Report the error
1130 TGERROR("Unable to fill gaps satisfactorily");
1131
1132#ifdef _DEBUG
1133 // Print out the total number of nodes
1134 TGLOG("Number of nodes: " << Indices.size());
1135
1136 // Print out the number of nodes referenced more than once
1137// for (itIndex = Indices.begin(); itIndex != Indices.end(); ++itIndex)
1138// {
1139// if (itIndex->second > 1)
1140// cout << "Node " << itIndex->first << " referenced " << itIndex->second << " times. (" << Mesh.m_Nodes[itIndex->first] << ")" << endl;
1141// }
1142 // Print out the number of nodes referenced only once
1143 for (itIndex = Indices.begin(); itIndex != Indices.end(); ++itIndex)
1144 {
1145 if (itIndex->second != 2)
1146 TGLOG("Node " << itIndex->first << " referenced " << itIndex->second << " times. (" << Mesh.GetNode(itIndex->first) << ")");
1147 }
1148
1149 //assert(false);
1150#endif
1151 return false;
1152 }
1153
1154 // Check for two points next to each other which are the same
1155 // Happens on issue #2 - would be better to find cause
1156 vector<int>::iterator itCurrent = ClosedLoop.begin();
1157 vector<int>::iterator itNext = itCurrent+1;
1158 while(itNext != ClosedLoop.end() )
1159 {
1160 if (*itCurrent == *itNext )
1161 {
1162 itNext = ClosedLoop.erase(itNext);
1163 }
1164 else
1165 {
1166 ++itCurrent;
1167 ++itNext;
1168 }
1169 }
1170
1171 // Check for spike in loop where points two apart are the same
1172 // Would be better to find the root cause of this happening
1173
1174 vector<int>::iterator itPrev = ClosedLoop.begin();
1175 itCurrent = itPrev+1;
1176 itNext = itCurrent+1;
1177
1178 while( itNext != ClosedLoop.end() )
1179 {
1180 if ( *itPrev == *itNext )
1181 {
1182 ClosedLoop.erase(itCurrent, itNext+1);
1183 if ( itPrev != ClosedLoop.begin() )
1184 {
1185 itCurrent = itPrev;
1186 --itPrev;
1187 itNext = itCurrent+1;
1188 }
1189 }
1190 else
1191 {
1192 // Go to the next set of 3 points
1193 ++itPrev;
1194 ++itCurrent;
1195 ++itNext;
1196 if (itPrev == ClosedLoop.end())
1197 itPrev = ClosedLoop.begin();
1198 }
1199 }
1200
1201 Polygon.insert( Polygon.begin(), ClosedLoop.begin(), ClosedLoop.end() );
1202 // Mesh the closed loop
1203 if ( bMeshGaps ) // If just saving closed loop don't want to fill in end
1204 Mesh.MeshClosedLoop(Plane.Normal, ClosedLoop);
1205 };
1206
1207 return true;
1208
1209}
1210
1211bool CDomainPlanes::PointInDomain(const XYZ &Point) const
1212{
1213 const double TOL = 1e-9;
1214 vector<PLANE>::const_iterator itPlane;
1215
1216 for ( itPlane = m_Planes.begin(); itPlane != m_Planes.end(); ++itPlane )
1217 {
1218 double d = DotProduct(itPlane->Normal, Point) - itPlane->d;
1219 if ( d < TOL )
1220 return false;
1221 }
1222 return true;
1223}
1224
1225int CDomainPlanes::GetPlane( XYZ &Normal, PLANE &Plane )
1226{
1227 vector<PLANE>::iterator itPlane;
1228 int i;
1229
1230 for ( itPlane = m_Planes.begin(),i = 0; itPlane != m_Planes.end(); ++itPlane, ++i )
1231 {
1232 if ( itPlane->Normal == Normal )
1233 {
1234 Plane = *itPlane;
1235 return i;
1236 }
1237 }
1238 return -1;
1239}
1240
1241void CDomainPlanes::SetPlane( int index, PLANE &Plane )
1242{
1243 if ( index >= m_Planes.size() )
1244 return;
1245 m_Planes[index] = Plane;
1246 BuildMesh();
1247}
1248
1249
1250
1251
1252
#define TOL
#define TGLOGINDENT(MESSAGE)
Combines the TGLOG macro and TGLOGAUTOINDENT macro in one.
Definition: Logger.h:68
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define TGLOG(MESSAGE)
Definition: Logger.h:36
#define FOR_EACH_TIXMLELEMENT(CHILDELEMENT, PARENTELEMENT, ELEMENTNAME)
Macro to enable looping over tinyxml easier.
Definition: Misc.h:45
Abstract base class representing the domain in which a textile cell may lie.
Definition: Domain.h:34
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType=OUTPUT_STANDARD) const
Used for saving data to XML.
Definition: Domain.cpp:43
CMesh m_Mesh
A mesh representing the domain as a surface mesh.
Definition: Domain.h:112
void BuildMesh()
Populate m_PlaneIntersections and m_Mesh, note this only works for closed domains.
vector< vector< pair< XYZ, XYZ > > > m_PlaneIntersections
A list of lines for each plane representing the intersections between other planes.
Definition: DomainPlanes.h:89
void Deform(CLinearTransformation Transformation)
Deform the domain by given linear transformation.
void SetPlane(int index, PLANE &Plane)
Set plane at given index.
static bool FillGaps(CMesh &Mesh, const PLANE &Plane, vector< int > &Polygon, bool bMeshGaps=true)
void ClipMeshToDomain(CMesh &Mesh, bool bFillGaps=true) const
Clip the surface elements to the domain.
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType=OUTPUT_STANDARD) const
Used for saving data to XML.
void Translate(XYZ Vector)
Translate the domain by given vector.
void Grow(double dDistance)
Move all the planes by given distance along their normal.
int GetPlane(XYZ &Normal, PLANE &Plane)
Get plane with given normal. Returns both the plane and its index.
bool PointInDomain(const XYZ &Point) const
Check if a point lies within the domain.
bool GetBoxLimits(XYZ &Min, XYZ &Max)
If the limits describe a box return the minimum and maximum otherwise return false.
void Rotate(WXYZ Rotation)
Rotate the domain by given rotation quaternion.
void AddPlane(const PLANE &Plane)
vector< PLANE > m_Planes
List of planes that define the limits of the cell.
Definition: DomainPlanes.h:86
Represents a linear transformation as a 3x3 matrix.
Class to represent a matrix and perform various operations on it.
Definition: Matrix.h:33
double GetInverse(CMatrix &Inverse) const
Definition: Matrix.h:544
CMatrix GetTranspose()
Definition: Matrix.h:220
Defines the nodes and elements of a surface or volume mesh.
Definition: Mesh.h:58
int GetNumNodes() const
Return the number of nodes.
Definition: Mesh.cpp:2646
int MergeNodes(const double Tolerance=1e-8)
If any nodes share the same coordinates merge the nodes together and adjust indices accordingly.
Definition: Mesh.cpp:382
void RemoveDegenerateTriangles()
Remove triangles which have two equal corner indices.
Definition: Mesh.cpp:214
const vector< XYZ > & GetNodes() const
Get a const reference to the nodes.
Definition: Mesh.cpp:2656
const int AddNode(XYZ Node)
Append a node to the list of nodes, the integer returns the index of the node
Definition: Mesh.cpp:2624
const XYZ & GetNode(int iIndex) const
Get the node with given ID.
Definition: Mesh.cpp:2636
int RemoveUnreferencedNodes()
Remove nodes that are not referenced by any elements.
Definition: Mesh.cpp:687
list< int >::iterator ConvertQuadtoTriangles(list< int >::iterator itQuad)
Convert a specific quad element to two triangles.
Definition: Mesh.cpp:1044
void MeshConvexHull()
Create a triangular convex hull of the nodes contained within the mesh.
Definition: Mesh.cpp:1758
static int GetNumNodes(ELEMENT_TYPE Type)
Get the number of nodes a particular element type contains.
Definition: Mesh.h:81
const list< int > & GetIndices(ELEMENT_TYPE ElemType) const
Get the element indices of a given element type.
Definition: Mesh.cpp:2671
@ PYRAMID
Definition: Mesh.h:70
@ QUADRATIC_TET
Definition: Mesh.h:75
@ POLYGON
Definition: Mesh.h:76
void MeshClosedLoop(const XYZ &Normal, const vector< int > &ClosedLoopVector, bool bQuality=false)
Definition: Mesh.cpp:1200
void Clear()
Empty mesh nodes and indices.
Definition: Mesh.cpp:1448
vector< XYZ >::iterator DeleteNode(vector< XYZ >::iterator it)
Delete a node given iterator.
Definition: Mesh.cpp:2641
Namespace containing a series of customised math operations not found in the standard c++ library.
double GetLengthSquared(const XYZ &Point1, const XYZ &Point2)
Get the length squared between two points.
Definition: mymath.h:548
OUTPUT_TYPE
Definition: Misc.h:105
double Max(XYZ &Vector)
Get maximum element of vector and return it.
Definition: mymath.h:642
std::string stringify(const T &x, int iPrecision=12, bool bScientific=true)
Function to convert a value (e.g. int, double, etc...) to a string.
Definition: Misc.h:50
XYZ Min(const XYZ &P1, const XYZ &P2)
Given two points, return a new point who's coordinates are the smaller of the two.
Definition: mymath.h:1142
WXYZ & Normalise(WXYZ &Quaternion)
Normalise the quaternion and return it.
Definition: mymath.h:609
double DotProduct(const XYZ &left, const XYZ &right)
Get the dot product of two vectors.
Definition: mymath.h:512
XYZ CrossProduct(const XYZ &left, const XYZ &right)
Get the cross product of two vectors.
Definition: mymath.h:524
Struct for representing a Plane.
Definition: Plane.h:25
XYZ Normal
Definition: Plane.h:30
double d
Definition: Plane.h:31
Struct for representing a quaternion.
Definition: mymath.h:38
Struct for representing points in 3D space.
Definition: mymath.h:56
double z
Definition: mymath.h:57
double x
Definition: mymath.h:57
double y
Definition: mymath.h:57