OCC22357 Hidden face selection
[occt.git] / src / Poly / Poly.cxx
1 // File:        Poly.cxx
2 // Created:     Mon Mar  6 11:02:24 1995
3 // Author:      Laurent PAINNOT
4 //              <lpa@metrox>
5
6 #include <Standard_Stream.hxx>
7 #include <Poly.ixx>
8 #include <gp_Pnt.hxx>
9 #include <gp_Pnt2d.hxx>
10 #include <Poly_Triangle.hxx>
11 #include <TColgp_Array1OfPnt.hxx>
12 #include <TColgp_Array1OfPnt.hxx>
13 #include <TColStd_Array1OfReal.hxx>
14 #include <Poly_Array1OfTriangle.hxx>
15 #include <Poly_ListOfTriangulation.hxx>
16
17 #include <Poly_Polygon3D.hxx>
18 #include <Poly_Polygon2D.hxx>
19 #include <Precision.hxx>
20 #include <TShort_Array1OfShortReal.hxx>
21 #include <TShort_HArray1OfShortReal.hxx>
22
23 //=======================================================================
24 //function : Catenate
25 //purpose  : Join several triangulations to one new triangulation object
26 //=======================================================================
27
28 Handle(Poly_Triangulation) Poly::Catenate (const Poly_ListOfTriangulation& lstTri)
29 {
30   Standard_Integer nNodes(0);
31   Standard_Integer nTrian(0);
32
33   // Sum up the total number of nodes.
34   Poly_ListOfTriangulation::Iterator anIter(lstTri);
35   for (; anIter.More(); anIter.Next()) {
36     const Handle(Poly_Triangulation)& aTri = anIter.Value();
37     if (aTri.IsNull() == Standard_False) {
38       nNodes += aTri->NbNodes();
39       nTrian += aTri->NbTriangles();
40     }
41   }
42
43   Handle(Poly_Triangulation) aResult;
44   if (nNodes > 0) {
45     aResult = new Poly_Triangulation(nNodes, nTrian, Standard_False);
46     Standard_Integer i, iNode[3];
47     nNodes = 0;
48     nTrian = 0;
49     TColgp_Array1OfPnt&    arrNode  = aResult->ChangeNodes();
50     Poly_Array1OfTriangle& arrTrian = aResult->ChangeTriangles();
51     for (anIter.Init(lstTri); anIter.More(); anIter.Next()) {
52       const Handle(Poly_Triangulation)& aTri = anIter.Value();
53       if (aTri.IsNull() == Standard_False) {
54         const TColgp_Array1OfPnt&    srcNode  = aTri->Nodes();
55         const Poly_Array1OfTriangle& srcTrian = aTri->Triangles();
56         const Standard_Integer nbNodes = aTri->NbNodes(); 
57         const Standard_Integer nbTrian = aTri->NbTriangles(); 
58         for (i = 1; i <= nbNodes; i++) {
59           arrNode.SetValue(i + nNodes, srcNode(i));
60         }
61         for (i = 1; i <= nbTrian; i++) {
62           srcTrian(i).Get(iNode[0], iNode[1], iNode[2]);
63           arrTrian.SetValue(i + nTrian, Poly_Triangle(iNode[0] + nNodes,
64                                                       iNode[1] + nNodes,
65                                                       iNode[2] + nNodes));
66         }
67         nNodes += nbNodes;
68         nTrian += nbTrian;
69       }
70     }
71   }
72   return aResult;
73 }
74
75 //=======================================================================
76 //function : Write
77 //purpose  :
78 //=======================================================================
79
80 void Poly::Write(const Handle(Poly_Triangulation)& T,
81                  Standard_OStream& OS,
82                  const Standard_Boolean Compact)
83 {
84   OS << "Poly_Triangulation\n";
85   if (Compact) {
86     OS << T->NbNodes() << " " << T->NbTriangles() << " ";
87     OS << ((T->HasUVNodes()) ? "1" : "0") << "\n";
88   }
89   else {
90     OS << setw(8) << T->NbNodes() << " Nodes\n";
91     OS << setw(8) << T->NbTriangles() << " Triangles\n";
92     OS << ((T->HasUVNodes()) ? "with" : "without") << " UV nodes\n";
93   }
94
95   // write the deflection
96
97   if (!Compact) OS << "Deflection : ";
98   OS << T->Deflection() << "\n";
99
100   // write the 3d nodes
101
102   if (!Compact) OS << "\n3D Nodes :\n";
103
104   Standard_Integer i, nbNodes = T->NbNodes();
105   const TColgp_Array1OfPnt& Nodes = T->Nodes();
106   for (i = 1; i <= nbNodes; i++) {
107     if (!Compact) OS << setw(10) << i << " : ";
108     if (!Compact) OS << setw(17);
109     OS << Nodes(i).X() << " ";
110     if (!Compact) OS << setw(17);
111     OS << Nodes(i).Y() << " ";
112     if (!Compact) OS << setw(17);
113     OS << Nodes(i).Z() << "\n";
114   }
115
116   if (T->HasUVNodes()) {
117     if (!Compact) OS << "\nUV Nodes :\n";
118     const TColgp_Array1OfPnt2d& UVNodes = T->UVNodes();
119     for (i = 1; i <= nbNodes; i++) {
120       if (!Compact) OS << setw(10) << i << " : ";
121     if (!Compact) OS << setw(17);
122       OS << UVNodes(i).X() << " ";
123     if (!Compact) OS << setw(17);
124       OS << UVNodes(i).Y() << "\n";
125     }
126   }
127
128   if (!Compact) OS << "\nTriangles :\n";
129   Standard_Integer nbTriangles = T->NbTriangles();
130   Standard_Integer n1, n2, n3;
131   const Poly_Array1OfTriangle& Triangles = T->Triangles();
132   for (i = 1; i <= nbTriangles; i++) {
133     if (!Compact) OS << setw(10) << i << " : ";
134     Triangles(i).Get(n1, n2, n3);
135     if (!Compact) OS << setw(10);
136     OS << n1 << " ";
137     if (!Compact) OS << setw(10);
138     OS << n2 << " ";
139     if (!Compact) OS << setw(10);
140     OS << n3 << "\n";
141   }
142
143 }
144
145 //=======================================================================
146 //function : Write
147 //purpose  :
148 //=======================================================================
149
150 void Poly::Write(const Handle(Poly_Polygon3D)& P,
151                  Standard_OStream&             OS,
152                  const Standard_Boolean        Compact)
153 {
154   OS << "Poly_Polygon3D\n";
155   if (Compact) {
156     OS << P->NbNodes() << " ";
157     OS << ((P->HasParameters()) ? "1" : "0") << "\n";
158   }
159   else {
160     OS << setw(8) << P->NbNodes() << " Nodes\n";
161     OS << ((P->HasParameters()) ? "with" : "without") << " parameters\n";
162   }
163
164   // write the deflection
165
166   if (!Compact) OS << "Deflection : ";
167   OS << P->Deflection() << "\n";
168
169   // write the nodes
170
171   if (!Compact) OS << "\nNodes :\n";
172
173   Standard_Integer i, nbNodes = P->NbNodes();
174   const TColgp_Array1OfPnt& Nodes = P->Nodes();
175   for (i = 1; i <= nbNodes; i++) {
176     if (!Compact) OS << setw(10) << i << " : ";
177     if (!Compact) OS << setw(17);
178     OS << Nodes(i).X() << " ";
179     if (!Compact) OS << setw(17);
180     OS << Nodes(i).Y() << " ";
181     if (!Compact) OS << setw(17);
182     OS << Nodes(i).Z() << "\n";
183   }
184
185   if (P->HasParameters()) {
186     if (!Compact) OS << "\nParameters :\n";
187     const TColStd_Array1OfReal& Param = P->Parameters();
188     for (i = 1; i <= nbNodes; i++) {
189       OS << Param(i) << " ";
190     }
191     OS <<"\n";
192   }
193
194
195 }
196
197
198 //=======================================================================
199 //function : Write
200 //purpose  :
201 //=======================================================================
202
203 void Poly::Write(const Handle(Poly_Polygon2D)& P,
204                  Standard_OStream&             OS,
205                  const Standard_Boolean        Compact)
206 {
207   OS << "Poly_Polygon2D\n";
208   if (Compact) {
209     OS << P->NbNodes() << " ";
210   }
211   else {
212     OS << setw(8) << P->NbNodes() << " Nodes\n";
213   }
214
215   // write the deflection
216
217   if (!Compact) OS << "Deflection : ";
218   OS << P->Deflection() << "\n";
219
220   // write the nodes
221
222   if (!Compact) OS << "\nNodes :\n";
223
224   Standard_Integer i, nbNodes = P->NbNodes();
225   const TColgp_Array1OfPnt2d& Nodes = P->Nodes();
226   for (i = 1; i <= nbNodes; i++) {
227     if (!Compact) OS << setw(10) << i << " : ";
228     if (!Compact) OS << setw(17);
229     OS << Nodes(i).X() << " ";
230     if (!Compact) OS << setw(17);
231     OS << Nodes(i).Y() << "\n";
232   }
233 }
234
235
236
237 //=======================================================================
238 //function : Dump
239 //purpose  :
240 //=======================================================================
241
242 void Poly::Dump(const Handle(Poly_Triangulation)& T, Standard_OStream& OS)
243 {
244   Poly::Write(T,OS,Standard_False);
245 }
246
247
248 //=======================================================================
249 //function : Dump
250 //purpose  :
251 //=======================================================================
252
253 void Poly::Dump(const Handle(Poly_Polygon3D)& P, Standard_OStream& OS)
254 {
255   Poly::Write(P,OS,Standard_False);
256 }
257
258
259 //=======================================================================
260 //function : Dump
261 //purpose  :
262 //=======================================================================
263
264 void Poly::Dump(const Handle(Poly_Polygon2D)& P, Standard_OStream& OS)
265 {
266   Poly::Write(P,OS,Standard_False);
267 }
268
269
270 //=======================================================================
271 //function : ReadTriangulation
272 //purpose  :
273 //=======================================================================
274
275 Handle(Poly_Triangulation) Poly::ReadTriangulation(Standard_IStream& IS)
276 {
277   // Read a triangulation
278
279   char line[100];
280   IS >> line;
281   if (strcmp(line,"Poly_Triangulation")) {
282     cout << "Not a Triangulation in the file" << endl;
283     return Handle(Poly_Triangulation)();
284   }
285
286   Standard_Integer nbNodes, nbTriangles;
287   Standard_Boolean hasUV;
288   IS >> nbNodes >> nbTriangles >> hasUV;
289
290   Standard_Real d;
291   IS >> d;
292
293   // read the 3d nodes
294   Standard_Real x,y,z;
295   Standard_Integer i;
296   TColgp_Array1OfPnt Nodes(1, nbNodes);
297   TColgp_Array1OfPnt2d UVNodes(1, nbNodes);
298
299   for (i = 1; i <= nbNodes; i++) {
300     IS >> x >> y >> z;
301     Nodes(i).SetCoord(x,y,z);
302   }
303
304   // read the UV points if necessary
305
306   if (hasUV) {
307     for (i = 1; i <= nbNodes; i++) {
308       IS >> x >> y;
309       UVNodes(i).SetCoord(x,y);
310     }
311   }
312
313
314   // read the triangles
315   Standard_Integer n1,n2,n3;
316   Poly_Array1OfTriangle Triangles(1, nbTriangles);
317   for (i = 1; i <= nbTriangles; i++) {
318     IS >> n1 >> n2 >> n3;
319     Triangles(i).Set(n1,n2,n3);
320   }
321
322
323   Handle(Poly_Triangulation) T;
324
325   if (hasUV) T =  new Poly_Triangulation(Nodes,UVNodes,Triangles);
326   else T = new Poly_Triangulation(Nodes,Triangles);
327
328   T->Deflection(d);
329
330   return T;
331 }
332
333
334 //=======================================================================
335 //function : ReadPolygon3D
336 //purpose  :
337 //=======================================================================
338
339 Handle(Poly_Polygon3D) Poly::ReadPolygon3D(Standard_IStream& IS)
340 {
341   // Read a 3d polygon
342
343   char line[100];
344   IS >> line;
345   if (strcmp(line,"Poly_Polygon3D")) {
346     cout << "Not a Polygon3D in the file" << endl;
347     return Handle(Poly_Polygon3D)();
348   }
349
350   Standard_Integer nbNodes;
351   IS >> nbNodes;
352
353   Standard_Boolean hasparameters;
354   IS >> hasparameters;
355
356   Standard_Real d;
357   IS >> d;
358
359   // read the nodes
360   Standard_Real x,y,z;
361   Standard_Integer i;
362   TColgp_Array1OfPnt Nodes(1, nbNodes);
363
364   for (i = 1; i <= nbNodes; i++) {
365     IS >> x >> y >> z;
366     Nodes(i).SetCoord(x,y,z);
367   }
368
369   TColStd_Array1OfReal Param(1,nbNodes);
370   if (hasparameters) {
371     for (i = 1; i <= nbNodes; i++) {
372       IS >> Param(i);
373     }
374   }
375
376   Handle(Poly_Polygon3D) P;
377   if (!hasparameters)
378     P = new Poly_Polygon3D(Nodes);
379   else
380     P = new Poly_Polygon3D(Nodes, Param);
381
382   P->Deflection(d);
383
384   return P;
385 }
386
387 //=======================================================================
388 //function : ReadPolygon3D
389 //purpose  :
390 //=======================================================================
391
392 Handle(Poly_Polygon2D) Poly::ReadPolygon2D(Standard_IStream& IS)
393 {
394   // Read a 2d polygon
395
396   char line[100];
397   IS >> line;
398   if (strcmp(line,"Poly_Polygon2D")) {
399     cout << "Not a Polygon2D in the file" << endl;
400     return Handle(Poly_Polygon2D)();
401   }
402
403   Standard_Integer nbNodes;
404   IS >> nbNodes;
405
406   Standard_Real d;
407   IS >> d;
408
409   // read the nodes
410   Standard_Real x,y;
411   Standard_Integer i;
412   TColgp_Array1OfPnt2d Nodes(1, nbNodes);
413
414   for (i = 1; i <= nbNodes; i++) {
415     IS >> x >> y;
416     Nodes(i).SetCoord(x,y);
417   }
418
419   Handle(Poly_Polygon2D) P =
420     new Poly_Polygon2D(Nodes);
421
422   P->Deflection(d);
423
424   return P;
425 }
426
427 //=======================================================================
428 //function : ComputeNormals
429 //purpose  :
430 //=======================================================================
431
432 void  Poly::ComputeNormals(const Handle(Poly_Triangulation)& Tri)
433 {
434   const TColgp_Array1OfPnt&     arrNodes = Tri->Nodes();
435   const Poly_Array1OfTriangle & arrTri   = Tri->Triangles();
436   Standard_Integer              nbNormVal  = Tri->NbNodes() * 3;
437   const Handle(TShort_HArray1OfShortReal) Normals =
438     new TShort_HArray1OfShortReal(1, nbNormVal);
439   Normals->Init(0.F);
440
441   Standard_ShortReal            * arrNormal = &(Normals->ChangeValue(1));
442
443   Standard_Real                 aCoord[3];
444   Standard_Integer              iNode[3] = {0, 0, 0};
445   Standard_Integer              iN, iTri;
446   const Standard_Real eps2 = Precision::Confusion()*Precision::Confusion();
447
448   for (iTri = 1; iTri <= arrTri.Length(); iTri++) {
449     // Get the nodes of the current triangle
450     arrTri(iTri).Get (iNode[0], iNode[1], iNode[2]);
451       const gp_XYZ aVec[2] = {
452         arrNodes(iNode[1]).XYZ() - arrNodes(iNode[0]).XYZ(),
453         arrNodes(iNode[2]).XYZ() - arrNodes(iNode[0]).XYZ()
454       };
455
456     // Find the normal vector of the current triangle
457     gp_XYZ aNorm = aVec[0] ^ aVec[1];
458     const Standard_Real aMod = aNorm.SquareModulus();
459     if (aMod > eps2) {
460       aNorm /= sqrt(aMod);
461       aNorm.Coord (aCoord[0], aCoord[1], aCoord[2]);
462       iNode[0] = (iNode[0]-1)*3;
463       iNode[1] = (iNode[1]-1)*3;
464       iNode[2] = (iNode[2]-1)*3;
465       arrNormal[iNode[0]+0] += (Standard_ShortReal)aCoord[0];
466       arrNormal[iNode[0]+1] += (Standard_ShortReal)aCoord[1];
467       arrNormal[iNode[0]+2] += (Standard_ShortReal)aCoord[2];
468       arrNormal[iNode[1]+0] += (Standard_ShortReal)aCoord[0];
469       arrNormal[iNode[1]+1] += (Standard_ShortReal)aCoord[1];
470       arrNormal[iNode[1]+2] += (Standard_ShortReal)aCoord[2];
471       arrNormal[iNode[2]+0] += (Standard_ShortReal)aCoord[0];
472       arrNormal[iNode[2]+1] += (Standard_ShortReal)aCoord[1];
473       arrNormal[iNode[2]+2] += (Standard_ShortReal)aCoord[2];
474     }
475   }
476   // Normalize all vectors
477   for (iN = 0; iN < nbNormVal; iN+=3) {
478     Standard_Real aMod (arrNormal[iN+0]*arrNormal[iN+0] +
479                         arrNormal[iN+1]*arrNormal[iN+1] +
480                         arrNormal[iN+2]*arrNormal[iN+2]);
481     if (aMod < eps2) {
482       arrNormal[iN+0] = 0.f;
483       arrNormal[iN+1] = 0.f;
484       arrNormal[iN+2] = 1.f;
485     } else {
486       aMod = sqrt(aMod);
487       arrNormal[iN+0] = Standard_ShortReal(arrNormal[iN+0]/aMod);
488       arrNormal[iN+1] = Standard_ShortReal(arrNormal[iN+1]/aMod);
489       arrNormal[iN+2] = Standard_ShortReal(arrNormal[iN+2]/aMod);
490     }
491   }
492
493   Tri->SetNormals(Normals);
494 }
495
496 //=======================================================================
497 //function : PointOnTriangle
498 //purpose  : 
499 //=======================================================================
500
501 Standard_Real Poly::PointOnTriangle (const gp_XY& theP1, const gp_XY& theP2, const gp_XY& theP3, 
502                                      const gp_XY& theP, gp_XY& theUV)
503 {
504   gp_XY aDP = theP  - theP1;
505   gp_XY aDU = theP2 - theP1;
506   gp_XY aDV = theP3 - theP1;
507   Standard_Real aDet = aDU ^ aDV;
508
509   // case of non-degenerated triangle
510   if ( Abs (aDet) > gp::Resolution() )
511   {
512     Standard_Real aU =  (aDP ^ aDV) / aDet;
513     Standard_Real aV = -(aDP ^ aDU) / aDet;
514
515     // if point is inside triangle, just return parameters
516     if ( aU > -gp::Resolution() &&
517          aV > -gp::Resolution() &&
518          1. - aU - aV > -gp::Resolution() ) 
519     {
520       theUV.SetCoord (aU, aV);
521       return 0.;
522     }
523
524     // else find closest point on triangle sides; note that in general case  
525     // triangle can be very distorted and it is necessary to check 
526     // projection on all sides regardless of values of computed parameters
527
528     // project on side U=0
529     aU = 0.;
530     aV = Min (1., Max (0., (aDP * aDV) / aDV.SquareModulus()));
531     Standard_Real aD = (aV * aDV - aDP).SquareModulus();
532
533     // project on side V=0
534     Standard_Real u = Min (1., Max (0., (aDP * aDU) / aDU.SquareModulus()));
535     Standard_Real d = (u * aDU - aDP).SquareModulus();
536     if ( d < aD )
537     {
538       aU = u;
539       aV = 0.;
540       aD = d;
541     }
542
543     // project on side U+V=1
544     gp_XY aDUV = aDV - aDU;
545     Standard_Real v = Min (1., Max (0., ((aDP - aDU) * aDUV) / aDUV.SquareModulus()));
546     d = (theP2 + v * aDUV - theP).SquareModulus();
547     if ( d < aD )
548     {
549       aU = 1. - v;
550       aV = v;
551       aD = d;
552     }
553
554     theUV.SetCoord (aU, aV);
555     return aD;
556   }
557
558   // degenerated triangle
559   Standard_Real aL2U = aDU.SquareModulus();
560   Standard_Real aL2V = aDV.SquareModulus();
561   if ( aL2U < gp::Resolution() ) // side 1-2 is degenerated
562   {
563     if ( aL2V < gp::Resolution() ) // whole triangle is degenerated to point
564     {
565       theUV.SetCoord (0., 0.);
566       return (theP - theP1).SquareModulus();
567     }
568     else
569     {
570       theUV.SetCoord (0., (aDP * aDV) / aL2V);
571       return (theP - (theP1 + theUV.Y() * aDV)).SquareModulus();
572     }
573   }
574   else if ( aL2V < gp::Resolution() ) // side 1-3 is degenerated
575   {
576     theUV.SetCoord ((aDP * aDU) / aL2U, 0.);
577     return (theP - (theP1 + theUV.X() * aDU)).SquareModulus();
578   }
579   else // sides 1-2 and 1-3 are collinear
580   {
581     // select parameter on one of sides so as to have points closer to picked
582     Standard_Real aU = Min (1., Max (0., (aDP * aDU) / aL2U));
583     Standard_Real aV = Min (1., Max (0., (aDP * aDV) / aL2V));
584     Standard_Real aD1 = (aDP - aU * aDU).SquareModulus();
585     Standard_Real aD2 = (aDP - aV * aDV).SquareModulus();
586     if ( aD1 < aD2 )
587     {
588       theUV.SetCoord ((aDP * aDU) / aL2U, 0.);
589       return aD1;
590     }
591     else
592     {
593       theUV.SetCoord (0., (aDP * aDV) / aL2V);
594       return aD2;
595     }
596   }
597 }
598