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