1 // Created on: 1995-03-06
2 // Created by: Laurent PAINNOT
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <Poly_Triangulation.hxx>
18
19 #include <gp_Pnt.hxx>
20 #include <OSD_FileSystem.hxx>
21 #include <Poly_Triangle.hxx>
22 #include <Standard_Dump.hxx>
23 #include <Standard_Type.hxx>
24
IMPLEMENT_STANDARD_RTTIEXT(Poly_Triangulation,Standard_Transient)25 IMPLEMENT_STANDARD_RTTIEXT (Poly_Triangulation, Standard_Transient)
26
27 //=======================================================================
28 //function : Poly_Triangulation
29 //purpose :
30 //=======================================================================
31 Poly_Triangulation::Poly_Triangulation()
32 : myCachedMinMax (NULL),
33 myDeflection (0),
34 myPurpose (Poly_MeshPurpose_NONE)
35 {
36 //
37 }
38
39 //=======================================================================
40 //function : Poly_Triangulation
41 //purpose :
42 //=======================================================================
Poly_Triangulation(const Standard_Integer theNbNodes,const Standard_Integer theNbTriangles,const Standard_Boolean theHasUVNodes,const Standard_Boolean theHasNormals)43 Poly_Triangulation::Poly_Triangulation (const Standard_Integer theNbNodes,
44 const Standard_Integer theNbTriangles,
45 const Standard_Boolean theHasUVNodes,
46 const Standard_Boolean theHasNormals)
47 : myCachedMinMax (NULL),
48 myDeflection(0),
49 myNodes (theNbNodes),
50 myTriangles (1, theNbTriangles),
51 myPurpose (Poly_MeshPurpose_NONE)
52 {
53 if (theHasUVNodes)
54 {
55 myUVNodes.Resize (theNbNodes, false);
56 }
57 if (theHasNormals)
58 {
59 myNormals.Resize (0, theNbNodes - 1, false);
60 }
61 }
62
63 //=======================================================================
64 //function : Poly_Triangulation
65 //purpose :
66 //=======================================================================
Poly_Triangulation(const TColgp_Array1OfPnt & theNodes,const Poly_Array1OfTriangle & theTriangles)67 Poly_Triangulation::Poly_Triangulation (const TColgp_Array1OfPnt& theNodes,
68 const Poly_Array1OfTriangle& theTriangles)
69 : myCachedMinMax (NULL),
70 myDeflection (0),
71 myNodes (theNodes.Length()),
72 myTriangles (1, theTriangles.Length()),
73 myPurpose (Poly_MeshPurpose_NONE)
74 {
75 const Poly_ArrayOfNodes aNodeWrapper (theNodes.First(), theNodes.Length());
76 myNodes = aNodeWrapper;
77 myTriangles = theTriangles;
78 }
79
80 //=======================================================================
81 //function : Poly_Triangulation
82 //purpose :
83 //=======================================================================
84
Poly_Triangulation(const TColgp_Array1OfPnt & theNodes,const TColgp_Array1OfPnt2d & theUVNodes,const Poly_Array1OfTriangle & theTriangles)85 Poly_Triangulation::Poly_Triangulation (const TColgp_Array1OfPnt& theNodes,
86 const TColgp_Array1OfPnt2d& theUVNodes,
87 const Poly_Array1OfTriangle& theTriangles)
88 : myCachedMinMax (NULL),
89 myDeflection (0),
90 myNodes (theNodes.Length()),
91 myTriangles (1, theTriangles.Length()),
92 myUVNodes (theNodes.Length()),
93 myPurpose (Poly_MeshPurpose_NONE)
94 {
95 const Poly_ArrayOfNodes aNodeWrapper (theNodes.First(), theNodes.Length());
96 myNodes = aNodeWrapper;
97 myTriangles = theTriangles;
98 const Poly_ArrayOfUVNodes aUVNodeWrapper (theUVNodes.First(), theUVNodes.Length());
99 myUVNodes = aUVNodeWrapper;
100 }
101
102 //=======================================================================
103 //function : ~Poly_Triangulation
104 //purpose :
105 //=======================================================================
~Poly_Triangulation()106 Poly_Triangulation::~Poly_Triangulation()
107 {
108 delete myCachedMinMax;
109 }
110
111 //=======================================================================
112 //function : Copy
113 //purpose :
114 //=======================================================================
115
Handle(Poly_Triangulation)116 Handle(Poly_Triangulation) Poly_Triangulation::Copy() const
117 {
118 return new Poly_Triangulation (this);
119 }
120
121 //=======================================================================
122 //function : Poly_Triangulation
123 //purpose :
124 //=======================================================================
125
Poly_Triangulation(const Handle (Poly_Triangulation)& theTriangulation)126 Poly_Triangulation::Poly_Triangulation (const Handle(Poly_Triangulation)& theTriangulation)
127 : myCachedMinMax (NULL),
128 myDeflection(theTriangulation->myDeflection),
129 myNodes (theTriangulation->myNodes),
130 myTriangles (theTriangulation->myTriangles),
131 myUVNodes (theTriangulation->myUVNodes),
132 myNormals (theTriangulation->myNormals),
133 myPurpose (theTriangulation->myPurpose)
134 {
135 SetCachedMinMax (theTriangulation->CachedMinMax());
136 }
137
138 //=======================================================================
139 //function : Clear
140 //purpose :
141 //=======================================================================
Clear()142 void Poly_Triangulation::Clear()
143 {
144 if (!myNodes.IsEmpty())
145 {
146 Poly_ArrayOfNodes anEmptyNodes;
147 anEmptyNodes.SetDoublePrecision (myNodes.IsDoublePrecision());
148 myNodes.Move (anEmptyNodes);
149 }
150 if (!myTriangles.IsEmpty())
151 {
152 Poly_Array1OfTriangle anEmptyTriangles;
153 myTriangles.Move(anEmptyTriangles);
154 }
155 RemoveUVNodes();
156 RemoveNormals();
157 }
158
159 //=======================================================================
160 //function : RemoveUVNodes
161 //purpose :
162 //=======================================================================
RemoveUVNodes()163 void Poly_Triangulation::RemoveUVNodes()
164 {
165 if (!myUVNodes.IsEmpty())
166 {
167 Poly_ArrayOfUVNodes anEmpty;
168 anEmpty.SetDoublePrecision (myUVNodes.IsDoublePrecision());
169 myUVNodes.Move (anEmpty);
170 }
171 }
172
173 //=======================================================================
174 //function : RemoveNormals
175 //purpose :
176 //=======================================================================
RemoveNormals()177 void Poly_Triangulation::RemoveNormals()
178 {
179 if (!myNormals.IsEmpty())
180 {
181 NCollection_Array1<gp_Vec3f> anEmpty;
182 myNormals.Move (anEmpty);
183 }
184 }
185
186 //=======================================================================
187 //function : MapNodeArray
188 //purpose :
189 //=======================================================================
Handle(TColgp_HArray1OfPnt)190 Handle(TColgp_HArray1OfPnt) Poly_Triangulation::MapNodeArray() const
191 {
192 if (myNodes.IsEmpty())
193 {
194 return Handle(TColgp_HArray1OfPnt)();
195 }
196
197 if (myNodes.IsDoublePrecision())
198 {
199 // wrap array
200 const gp_Pnt* aPntArr = &myNodes.First<gp_Pnt>();
201 Handle(TColgp_HArray1OfPnt) anHArray = new TColgp_HArray1OfPnt();
202 TColgp_Array1OfPnt anArray (*aPntArr, 1, NbNodes());
203 anHArray->Move (anArray);
204 return anHArray;
205 }
206
207 // deep copy
208 Handle(TColgp_HArray1OfPnt) anArray = new TColgp_HArray1OfPnt (1, NbNodes());
209 for (Standard_Integer aNodeIter = 0; aNodeIter < NbNodes(); ++aNodeIter)
210 {
211 const gp_Pnt aPnt = myNodes.Value (aNodeIter);
212 anArray->SetValue (aNodeIter + 1, aPnt);
213 }
214 return anArray;
215 }
216
217 //=======================================================================
218 //function : MapTriangleArray
219 //purpose :
220 //=======================================================================
Handle(Poly_HArray1OfTriangle)221 Handle(Poly_HArray1OfTriangle) Poly_Triangulation::MapTriangleArray() const
222 {
223 if (myTriangles.IsEmpty())
224 {
225 return Handle(Poly_HArray1OfTriangle)();
226 }
227
228 Handle(Poly_HArray1OfTriangle) anHArray = new Poly_HArray1OfTriangle();
229 Poly_Array1OfTriangle anArray (myTriangles.First(), 1, NbTriangles());
230 anHArray->Move (anArray);
231 return anHArray;
232 }
233
234 //=======================================================================
235 //function : MapUVNodeArray
236 //purpose :
237 //=======================================================================
Handle(TColgp_HArray1OfPnt2d)238 Handle(TColgp_HArray1OfPnt2d) Poly_Triangulation::MapUVNodeArray() const
239 {
240 if (myUVNodes.IsEmpty())
241 {
242 return Handle(TColgp_HArray1OfPnt2d)();
243 }
244
245 if (myUVNodes.IsDoublePrecision())
246 {
247 // wrap array
248 const gp_Pnt2d* aPntArr = &myUVNodes.First<gp_Pnt2d>();
249 Handle(TColgp_HArray1OfPnt2d) anHArray = new TColgp_HArray1OfPnt2d();
250 TColgp_Array1OfPnt2d anArray (*aPntArr, 1, NbNodes());
251 anHArray->Move (anArray);
252 return anHArray;
253 }
254
255 // deep copy
256 Handle(TColgp_HArray1OfPnt2d) anArray = new TColgp_HArray1OfPnt2d (1, NbNodes());
257 for (Standard_Integer aNodeIter = 0; aNodeIter < NbNodes(); ++aNodeIter)
258 {
259 const gp_Pnt2d aPnt = myUVNodes.Value (aNodeIter);
260 anArray->SetValue (aNodeIter + 1, aPnt);
261 }
262 return anArray;
263 }
264
265 //=======================================================================
266 //function : MapNormalArray
267 //purpose :
268 //=======================================================================
Handle(TShort_HArray1OfShortReal)269 Handle(TShort_HArray1OfShortReal) Poly_Triangulation::MapNormalArray() const
270 {
271 if (myNormals.IsEmpty())
272 {
273 return Handle(TShort_HArray1OfShortReal)();
274 }
275
276 Handle(TShort_HArray1OfShortReal) anHArray = new TShort_HArray1OfShortReal();
277 TShort_Array1OfShortReal anArray (*myNormals.First().GetData(), 1, 3 * NbNodes());
278 anHArray->Move (anArray);
279 return anHArray;
280 }
281
282 //=======================================================================
283 //function : SetNormals
284 //purpose :
285 //=======================================================================
SetNormals(const Handle (TShort_HArray1OfShortReal)& theNormals)286 void Poly_Triangulation::SetNormals (const Handle(TShort_HArray1OfShortReal)& theNormals)
287 {
288 if (theNormals.IsNull() || theNormals->Length() != 3 * NbNodes())
289 {
290 throw Standard_DomainError("Poly_Triangulation::SetNormals : wrong length");
291 }
292
293 AddNormals();
294 const Standard_Integer anArrayLower = theNormals->Lower();
295 for (Standard_Integer aNodeIter = 1; aNodeIter <= NbNodes(); ++aNodeIter)
296 {
297 Standard_Integer anArrayInd = anArrayLower + (aNodeIter - 1) * 3;
298 gp_Vec3f aNorm (theNormals->Value (anArrayInd + 0),
299 theNormals->Value (anArrayInd + 1),
300 theNormals->Value (anArrayInd + 2));
301 SetNormal (aNodeIter, aNorm);
302 }
303 }
304
305 // =======================================================================
306 // function : SetDoublePrecision
307 // purpose :
308 // =======================================================================
SetDoublePrecision(bool theIsDouble)309 void Poly_Triangulation::SetDoublePrecision (bool theIsDouble)
310 {
311 myNodes .SetDoublePrecision (theIsDouble);
312 myUVNodes.SetDoublePrecision (theIsDouble);
313 }
314
315 // =======================================================================
316 // function : ResizeNodes
317 // purpose :
318 // =======================================================================
ResizeNodes(Standard_Integer theNbNodes,Standard_Boolean theToCopyOld)319 void Poly_Triangulation::ResizeNodes (Standard_Integer theNbNodes,
320 Standard_Boolean theToCopyOld)
321 {
322 myNodes.Resize (theNbNodes, theToCopyOld);
323 if (!myUVNodes.IsEmpty())
324 {
325 myUVNodes.Resize (theNbNodes, theToCopyOld);
326 }
327 if (!myNormals.IsEmpty())
328 {
329 myNormals.Resize (0, theNbNodes - 1, theToCopyOld);
330 }
331 }
332
333 // =======================================================================
334 // function : ResizeTriangles
335 // purpose :
336 // =======================================================================
ResizeTriangles(Standard_Integer theNbTriangles,Standard_Boolean theToCopyOld)337 void Poly_Triangulation::ResizeTriangles (Standard_Integer theNbTriangles,
338 Standard_Boolean theToCopyOld)
339 {
340 myTriangles.Resize (1, theNbTriangles, theToCopyOld);
341 }
342
343 // =======================================================================
344 // function : AddUVNodes
345 // purpose :
346 // =======================================================================
AddUVNodes()347 void Poly_Triangulation::AddUVNodes()
348 {
349 if (myUVNodes.IsEmpty() || myUVNodes.Size() != myNodes.Size())
350 {
351 myUVNodes.Resize (myNodes.Size(), false);
352 }
353 }
354
355 // =======================================================================
356 // function : AddNormals
357 // purpose :
358 // =======================================================================
AddNormals()359 void Poly_Triangulation::AddNormals()
360 {
361 if (myNormals.IsEmpty() || myNormals.Size() != myNodes.Size())
362 {
363 myNormals.Resize (0, myNodes.Size() - 1, false);
364 }
365 }
366
367 // =======================================================================
368 // function : DumpJson
369 // purpose :
370 // =======================================================================
371
DumpJson(Standard_OStream & theOStream,Standard_Integer) const372 void Poly_Triangulation::DumpJson (Standard_OStream& theOStream, Standard_Integer) const
373 {
374 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
375
376 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDeflection)
377
378 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNodes.Size())
379 if (!myUVNodes.IsEmpty())
380 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myUVNodes.Size())
381 if (!myNormals.IsEmpty())
382 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNormals.Size())
383 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTriangles.Size())
384 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPurpose)
385
386 }
387
388 // =======================================================================
389 // function : CachedMinMax
390 // purpose :
391 // =======================================================================
CachedMinMax() const392 const Bnd_Box& Poly_Triangulation::CachedMinMax() const
393 {
394 static const Bnd_Box anEmptyBox;
395 return (myCachedMinMax == NULL) ? anEmptyBox : *myCachedMinMax;
396 }
397
398 // =======================================================================
399 // function : SetCachedMinMax
400 // purpose :
401 // =======================================================================
SetCachedMinMax(const Bnd_Box & theBox)402 void Poly_Triangulation::SetCachedMinMax (const Bnd_Box& theBox)
403 {
404 if (theBox.IsVoid())
405 {
406 unsetCachedMinMax();
407 return;
408 }
409 if (myCachedMinMax == NULL)
410 {
411 myCachedMinMax = new Bnd_Box();
412 }
413 *myCachedMinMax = theBox;
414 }
415
416 // =======================================================================
417 // function : unsetCachedMinMax
418 // purpose :
419 // =======================================================================
unsetCachedMinMax()420 void Poly_Triangulation::unsetCachedMinMax()
421 {
422 if (myCachedMinMax != NULL)
423 {
424 delete myCachedMinMax;
425 myCachedMinMax = NULL;
426 }
427 }
428
429 // =======================================================================
430 // function : MinMax
431 // purpose :
432 // =======================================================================
MinMax(Bnd_Box & theBox,const gp_Trsf & theTrsf,const bool theIsAccurate) const433 Standard_Boolean Poly_Triangulation::MinMax (Bnd_Box& theBox, const gp_Trsf& theTrsf, const bool theIsAccurate) const
434 {
435 Bnd_Box aBox;
436 if (HasCachedMinMax() &&
437 (!HasGeometry() || !theIsAccurate ||
438 theTrsf.Form() == gp_Identity || theTrsf.Form() == gp_Translation ||
439 theTrsf.Form() == gp_PntMirror || theTrsf.Form() == gp_Scale))
440 {
441 aBox = myCachedMinMax->Transformed (theTrsf);
442 }
443 else
444 {
445 aBox = computeBoundingBox (theTrsf);
446 }
447 if (aBox.IsVoid())
448 {
449 return Standard_False;
450 }
451 theBox.Add (aBox);
452 return Standard_True;
453 }
454
455 // =======================================================================
456 // function : computeBoundingBox
457 // purpose :
458 // =======================================================================
computeBoundingBox(const gp_Trsf & theTrsf) const459 Bnd_Box Poly_Triangulation::computeBoundingBox (const gp_Trsf& theTrsf) const
460 {
461 Bnd_Box aBox;
462 if (theTrsf.Form() == gp_Identity)
463 {
464 for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes(); aNodeIdx++)
465 {
466 aBox.Add (myNodes.Value (aNodeIdx));
467 }
468 }
469 else
470 {
471 for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes(); aNodeIdx++)
472 {
473 aBox.Add (myNodes.Value (aNodeIdx).Transformed (theTrsf));
474 }
475 }
476 return aBox;
477 }
478
479 //=======================================================================
480 //function : ComputeNormals
481 //purpose :
482 //=======================================================================
ComputeNormals()483 void Poly_Triangulation::ComputeNormals()
484 {
485 // zero values
486 AddNormals();
487 myNormals.Init (gp_Vec3f (0.0f));
488
489 Standard_Integer anElem[3] = {0, 0, 0};
490 for (Poly_Array1OfTriangle::Iterator aTriIter (myTriangles); aTriIter.More(); aTriIter.Next())
491 {
492 aTriIter.Value().Get (anElem[0], anElem[1], anElem[2]);
493 const gp_Pnt aNode0 = myNodes.Value (anElem[0] - 1);
494 const gp_Pnt aNode1 = myNodes.Value (anElem[1] - 1);
495 const gp_Pnt aNode2 = myNodes.Value (anElem[2] - 1);
496
497 const gp_XYZ aVec01 = aNode1.XYZ() - aNode0.XYZ();
498 const gp_XYZ aVec02 = aNode2.XYZ() - aNode0.XYZ();
499 const gp_XYZ aTriNorm = aVec01 ^ aVec02;
500 const gp_Vec3f aNorm3f = gp_Vec3f (float(aTriNorm.X()), float(aTriNorm.Y()), float(aTriNorm.Z()));
501 for (Standard_Integer aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
502 {
503 myNormals.ChangeValue (anElem[aNodeIter] - 1) += aNorm3f;
504 }
505 }
506
507 // Normalize all vectors
508 for (NCollection_Array1<gp_Vec3f>::Iterator aNodeIter (myNormals); aNodeIter.More(); aNodeIter.Next())
509 {
510 gp_Vec3f& aNorm3f = aNodeIter.ChangeValue();
511 const float aMod = aNorm3f.Modulus();
512 aNorm3f = aMod == 0.0f ? gp_Vec3f (0.0f, 0.0f, 1.0f) : (aNorm3f / aMod);
513 }
514 }
515
516 //=======================================================================
517 //function : LoadDeferredData
518 //purpose :
519 //=======================================================================
LoadDeferredData(const Handle (OSD_FileSystem)& theFileSystem)520 Standard_Boolean Poly_Triangulation::LoadDeferredData (const Handle(OSD_FileSystem)& theFileSystem)
521 {
522 if (!HasDeferredData())
523 {
524 return false;
525 }
526 if (!loadDeferredData (theFileSystem, this))
527 {
528 return false;
529 }
530 SetMeshPurpose (myPurpose | Poly_MeshPurpose_Loaded);
531 return true;
532 }
533
534 //=======================================================================
535 //function : DetachedLoadDeferredData
536 //purpose :
537 //=======================================================================
Handle(Poly_Triangulation)538 Handle(Poly_Triangulation) Poly_Triangulation::DetachedLoadDeferredData (const Handle(OSD_FileSystem)& theFileSystem) const
539 {
540 if (!HasDeferredData())
541 {
542 return Handle(Poly_Triangulation)();
543 }
544 Handle(Poly_Triangulation) aResult = createNewEntity();
545 if (!loadDeferredData (theFileSystem, aResult))
546 {
547 return Handle(Poly_Triangulation)();
548 }
549 aResult->SetMeshPurpose (aResult->MeshPurpose() | Poly_MeshPurpose_Loaded);
550 return aResult;
551 }
552
553 //=======================================================================
554 //function : UnloadDeferredData
555 //purpose :
556 //=======================================================================
UnloadDeferredData()557 Standard_Boolean Poly_Triangulation::UnloadDeferredData()
558 {
559 if (HasDeferredData())
560 {
561 Clear();
562 SetMeshPurpose (myPurpose & ~Poly_MeshPurpose_Loaded);
563 return true;
564 }
565 return false;
566 }
567