0026338: STL export (especially binary) needs a lot of time if selected export path...
[occt.git] / src / MeshTest / MeshTest_PluginCommands.cxx
1 // Created on: 2008-04-11
2 // Created by: Peter KURNEV
3 // Copyright (c) 2008-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
17 #include <Bnd_Box.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepGProp.hxx>
20 #include <BRepMesh_DiscretFactory.hxx>
21 #include <BRepMesh_DiscretRoot.hxx>
22 #include <BRepMesh_Edge.hxx>
23 #include <BRepMesh_FactoryError.hxx>
24 #include <BRepMesh_IncrementalMesh.hxx>
25 #include <DBRep.hxx>
26 #include <Draw.hxx>
27 #include <Draw_Interpretor.hxx>
28 #include <DrawTrSurf.hxx>
29 #include <gp_Vec.hxx>
30 #include <GProp_GProps.hxx>
31 #include <MeshTest.hxx>
32 #include <MeshTest_CheckTopology.hxx>
33 #include <NCollection_Map.hxx>
34 #include <Poly_Polygon2D.hxx>
35 #include <Poly_Polygon3D.hxx>
36 #include <Poly_PolygonOnTriangulation.hxx>
37 #include <Poly_Triangulation.hxx>
38 #include <Standard.hxx>
39 #include <TColgp_Array1OfPnt2d.hxx>
40 #include <TCollection_AsciiString.hxx>
41 #include <TColStd_Array1OfInteger.hxx>
42 #include <TColStd_MapIteratorOfMapOfAsciiString.hxx>
43 #include <TColStd_MapOfAsciiString.hxx>
44 #include <TopExp.hxx>
45 #include <TopExp_Explorer.hxx>
46 #include <TopoDS.hxx>
47 #include <TopoDS_Face.hxx>
48 #include <TopTools_IndexedMapOfShape.hxx>
49
50 static Standard_Integer mpnames           (Draw_Interpretor& , Standard_Integer , const char** );
51 static Standard_Integer mpsetdefaultname  (Draw_Interpretor& , Standard_Integer , const char** );
52 static Standard_Integer mpgetdefaultname  (Draw_Interpretor& , Standard_Integer , const char** );
53 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
54 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
55 static Standard_Integer mperror           (Draw_Interpretor& , Standard_Integer , const char** );
56 static Standard_Integer mpincmesh         (Draw_Interpretor& , Standard_Integer , const char** );
57 static Standard_Integer mpparallel        (Draw_Interpretor& , Standard_Integer , const char** );
58 static Standard_Integer triarea           (Draw_Interpretor& , Standard_Integer , const char** );
59 static Standard_Integer tricheck          (Draw_Interpretor& , Standard_Integer , const char** );
60
61 //=======================================================================
62 //function : PluginCommands
63 //purpose  : 
64 //=======================================================================
65 void MeshTest::PluginCommands(Draw_Interpretor& theCommands)
66 {
67   static Standard_Boolean done = Standard_False;
68   if (done) {
69     return;
70   }
71   done = Standard_True;
72   //
73   const char* g = "Mesh Commands";
74   // Commands
75   theCommands.Add("mpnames"          , "use mpnames"          , __FILE__, mpnames    , g);
76   theCommands.Add("mpsetdefaultname" , "use mpsetdefaultname" , __FILE__, mpsetdefaultname     , g);
77   theCommands.Add("mpgetdefaultname" , "use mpgetdefaultname" , __FILE__, mpgetdefaultname     , g);
78   theCommands.Add("mpsetfunctionname", "use mpsetfunctionname", __FILE__, mpsetfunctionname     , g);
79   theCommands.Add("mpgetfunctionname", "use mpgetfunctionname", __FILE__, mpgetfunctionname     , g);
80   theCommands.Add("mperror"          , "use mperror"          , __FILE__, mperror     , g);
81   theCommands.Add("mpincmesh"        , "use mpincmesh"        , __FILE__, mpincmesh      , g);
82   theCommands.Add("mpparallel"       , "mpparallel [toTurnOn] : show / set multi-threading flag for incremental mesh",
83     __FILE__, mpparallel, g);
84   theCommands.Add("triarea","shape [eps]  (computes triangles and surface area)",__FILE__, triarea, g);
85   theCommands.Add("tricheck", "shape   (checks triangulation of shape)", __FILE__, tricheck, g);
86 }
87
88 //=======================================================================
89 //function : mpnames
90 //purpose  : 
91 //=======================================================================
92 static Standard_Integer mpnames (Draw_Interpretor& , Standard_Integer n, const char** )
93 {
94   Standard_Integer aNb;
95   TColStd_MapIteratorOfMapOfAsciiString aIt;
96   //
97   if (n!=1) {
98     printf(" use mpnames\n");
99     return 0;
100   }
101   //
102   const TColStd_MapOfAsciiString& aMN=BRepMesh_DiscretFactory::Get().Names();
103   aNb=aMN.Extent();
104   if (!aNb) {
105     printf(" *no names found\n");
106     return 0;
107   }
108   //
109   printf(" *available names:\n");
110   aIt.Initialize(aMN);
111   for (; aIt.More(); aIt.Next()) {
112     const TCollection_AsciiString& aName=aIt.Key();
113     printf("  %s\n", aName.ToCString());
114   }
115   //
116   return 0;
117 }
118 //=======================================================================
119 //function : mpsetdefaultname
120 //purpose  : 
121 //=======================================================================
122 static Standard_Integer mpsetdefaultname (Draw_Interpretor& , Standard_Integer n, const char**a )
123 {
124   TCollection_AsciiString aName;
125   //
126   if (n!=2) {
127     printf(" use mpsetdefaultname name\n");
128     return 0;
129   }
130   //
131   aName=a[1];
132   //
133   if (BRepMesh_DiscretFactory::Get().SetDefaultName (aName))
134     printf(" *ready\n");
135   else
136     printf(" *fault\n");
137   //
138   return 0;
139 }
140 //=======================================================================
141 //function : mpgetdefaultname
142 //purpose  : 
143 //=======================================================================
144 static Standard_Integer mpgetdefaultname (Draw_Interpretor& , Standard_Integer n, const char** )
145 {
146   if (n!=1) {
147     printf(" use mpgetdefaultname\n");
148     return 0;
149   }
150   //
151   const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().DefaultName();
152   printf(" *default name: %s\n", aName.ToCString());
153   //
154   return 0;
155 }
156 //=======================================================================
157 //function : mpsetfunctionname
158 //purpose  : 
159 //=======================================================================
160 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer n, const char**a )
161 {
162   TCollection_AsciiString aName;
163   //
164   if (n!=2) {
165     printf(" use mpsetfunctionname name\n");
166     return 0;
167   }
168   //
169   aName=a[1];
170   //
171   if (BRepMesh_DiscretFactory::Get().SetFunctionName (aName))
172     printf(" *ready\n");
173   else
174     printf(" *fault\n");
175   //
176   return 0;
177 }
178 //=======================================================================
179 //function : mpgetdefaultname
180 //purpose  : 
181 //=======================================================================
182 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer n, const char** )
183 {
184   if (n!=1) {
185     printf(" use mpgetfunctionname\n");
186     return 0;
187   }
188   //
189   const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().FunctionName();
190   printf(" *function name: %s\n", aName.ToCString());
191   //
192   return 0;
193 }
194 //=======================================================================
195 //function : mperror
196 //purpose  : 
197 //=======================================================================
198 static Standard_Integer mperror (Draw_Interpretor& , Standard_Integer n, const char** )
199 {
200   BRepMesh_FactoryError aErr;
201   //
202   if (n!=1) {
203     printf(" use mperror\n");
204     return 0;
205   }
206   //
207   aErr=BRepMesh_DiscretFactory::Get().ErrorStatus();
208   printf(" *ErrorStatus: %d\n", (int)aErr);
209   //
210   return 0;
211 }
212
213 //=======================================================================
214 //function :mpincmesh
215 //purpose  : 
216 //=======================================================================
217 static Standard_Integer mpincmesh (Draw_Interpretor& , Standard_Integer n, const char** a)
218 {
219   Standard_Real aDeflection, aAngle;
220   TopoDS_Shape aS;
221   //
222   if (n<3) {
223     printf(" use mpincmesh s deflection [angle]\n");
224     return 0;
225   }
226   //
227   aS=DBRep::Get(a[1]);
228   if (aS.IsNull()) {
229     printf(" null shapes is not allowed here\n");
230     return 0;
231   }
232   //
233   aDeflection=Draw::Atof(a[2]);
234   aAngle=0.5;
235   if (n>3) {
236     aAngle=Draw::Atof(a[3]);
237   }
238   //
239   Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (aS,
240                                                                                    aDeflection,
241                                                                                    aAngle);
242   //
243   BRepMesh_FactoryError aErr = BRepMesh_DiscretFactory::Get().ErrorStatus();
244   if (aErr != BRepMesh_FE_NOERROR)
245   {
246     printf(" *Factory::Get().ErrorStatus()=%d\n", (int)aErr);
247   }
248   //
249   if (aMeshAlgo.IsNull())
250   {
251     printf(" *Can not create the algo\n");
252     return 0;
253   }
254   //
255   aMeshAlgo->Perform();
256   if (!aMeshAlgo->IsDone())
257   {
258     printf(" *Not done\n");
259   }
260   //
261   return 0;
262 }
263
264 //#######################################################################
265 static Standard_Integer triarea (Draw_Interpretor& di, int n, const char ** a)
266 {
267
268   if (n < 2) return 1;
269
270   TopoDS_Shape shape = DBRep::Get(a[1]);
271   if (shape.IsNull()) return 1;
272   Standard_Real anEps = -1.;
273   if (n > 2)
274     anEps = Draw::Atof(a[2]);
275
276   TopTools_IndexedMapOfShape aMapF;
277   TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
278
279   // detect if a shape has triangulation
280   Standard_Boolean hasPoly = Standard_False;
281   int i;
282   for (i=1; i <= aMapF.Extent(); i++) {
283     const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
284     TopLoc_Location aLoc;
285     Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
286     if (!aPoly.IsNull()) {
287       hasPoly = Standard_True;
288       break;
289     }
290   }
291
292   // compute area by triangles
293   double aTriArea=0;
294   if (hasPoly) {
295     for (i=1; i <= aMapF.Extent(); i++) {
296       const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
297       TopLoc_Location aLoc;
298       Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
299       if (aPoly.IsNull()) {
300         cout << "face "<<i<<" has no triangulation"<<endl;
301         continue;
302       }
303       const Poly_Array1OfTriangle& triangles = aPoly->Triangles();
304       const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
305       for (int j=triangles.Lower(); j <= triangles.Upper(); j++) {
306         const Poly_Triangle& tri = triangles(j);
307         int n1, n2, n3;
308         tri.Get (n1, n2, n3);
309         const gp_Pnt& p1 = nodes(n1);
310         const gp_Pnt& p2 = nodes(n2);
311         const gp_Pnt& p3 = nodes(n3);
312         gp_Vec v1(p1, p2);
313         gp_Vec v2(p1, p3);
314         double ar = v1.CrossMagnitude(v2);
315         aTriArea += ar;
316       }
317     }
318     aTriArea /= 2;
319   }
320
321   // compute area by geometry
322   GProp_GProps props;
323   if (anEps <= 0.)
324     BRepGProp::SurfaceProperties(shape, props);
325   else
326     BRepGProp::SurfaceProperties(shape, props, anEps);
327   double aGeomArea = props.Mass();
328
329   di << aTriArea << " " << aGeomArea << "\n";
330   return 0;
331 }
332
333 //#######################################################################
334 Standard_Boolean IsEqual(const BRepMesh_Edge& theFirst, const BRepMesh_Edge& theSecond) 
335 {
336   return theFirst.IsEqual(theSecond);
337 }
338
339 static Standard_Integer tricheck (Draw_Interpretor& di, int n, const char ** a)
340 {
341   if (n < 2) return 1;
342
343   TopoDS_Shape shape = DBRep::Get(a[1]);
344   if (shape.IsNull()) return 1;
345
346   TopTools_IndexedMapOfShape aMapF;
347   TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
348   Standard_CString name = ".";
349
350   // execute check
351   MeshTest_CheckTopology aCheck(shape);
352   aCheck.Perform(di);
353
354   // dump info on free links inside the triangulation
355   Standard_Integer nbFree = 0;
356   Standard_Integer nbFac = aCheck.NbFacesWithFL(), i, k;
357   if (nbFac > 0) {
358     for (k=1; k <= nbFac; k++) {
359       Standard_Integer nbEdge = aCheck.NbFreeLinks(k);
360       Standard_Integer iF = aCheck.GetFaceNumWithFL(k);
361       nbFree += nbEdge;
362       di << "free links of face " << iF << "\n";
363
364       const TopoDS_Shape& aShape = aMapF.FindKey(iF);
365       const TopoDS_Face& aFace = TopoDS::Face(aShape);
366       TopLoc_Location aLoc;
367       Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
368       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
369       const gp_Trsf& trsf = aLoc.Transformation();
370
371       TColgp_Array1OfPnt pnts(1,2);
372       TColgp_Array1OfPnt2d pnts2d(1,2);
373       for (i=1; i <= nbEdge; i++) {
374         Standard_Integer n1, n2;
375         aCheck.GetFreeLink(k, i, n1, n2);
376         di << "{" << n1 << " " << n2 << "} ";
377         pnts(1) = aPoints(n1).Transformed(trsf);
378         pnts(2) = aPoints(n2).Transformed(trsf);
379         Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
380         DrawTrSurf::Set (name, poly);
381         DrawTrSurf::Set (name, pnts(1));
382         DrawTrSurf::Set (name, pnts(2));
383         if (aT->HasUVNodes())
384         {
385           const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
386           pnts2d(1) = aPoints2d(n1);
387           pnts2d(2) = aPoints2d(n2);
388           Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
389           DrawTrSurf::Set (name, poly2d);
390           DrawTrSurf::Set (name, pnts2d(1));
391           DrawTrSurf::Set (name, pnts2d(2));
392         }
393       }
394       di << "\n";
395     }
396   }
397
398   // dump info on cross face errors
399   Standard_Integer nbErr = aCheck.NbCrossFaceErrors();
400   if (nbErr > 0) {
401     di << "cross face errors: {face1, node1, face2, node2, distance}\n";
402     for (i=1; i <= nbErr; i++) {
403       Standard_Integer iF1, n1, iF2, n2;
404       Standard_Real aVal;
405       aCheck.GetCrossFaceError(i, iF1, n1, iF2, n2, aVal);
406       di << "{" << iF1 << " " << n1 << " " << iF2 << " " << n2 << " " << aVal << "} ";
407     }
408     di << "\n";
409   }
410
411   // dump info on edges
412   Standard_Integer nbAsync = aCheck.NbAsyncEdges();
413   if (nbAsync > 0) {
414     di << "async edges:\n";
415     for (i=1; i <= nbAsync; i++) {
416       Standard_Integer ie = aCheck.GetAsyncEdgeNum(i);
417       di << ie << " ";
418     }
419     di << "\n";
420   }
421
422   // dump info on free nodes
423   Standard_Integer nbFreeNodes = aCheck.NbFreeNodes();
424   if (nbFreeNodes > 0) {
425     di << "free nodes (in pairs: face / node): \n";
426     for (i=1; i <= nbFreeNodes; i++) {
427       Standard_Integer iface, inode;
428       aCheck.GetFreeNodeNum(i, iface, inode);
429
430       const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(iface));
431       TopLoc_Location aLoc;
432       Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
433       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
434       const gp_Trsf& trsf = aLoc.Transformation();
435       DrawTrSurf::Set (name, aPoints(inode).Transformed(trsf));
436       if (aT->HasUVNodes())
437       {
438         DrawTrSurf::Set (name, aT->UVNodes()(inode));
439       }
440
441       di << "{" << iface << " " << inode << "} ";
442     }
443     di << "\n";
444   }
445
446   // output errors summary to DRAW
447   if ( nbFree > 0 || nbErr > 0 || nbAsync > 0 || nbFreeNodes > 0)
448     di << "Free_links " << nbFree
449        << " Cross_face_errors " << nbErr
450        << " Async_edges " << nbAsync 
451        << " Free_nodes " << nbFreeNodes << "\n";
452
453
454   Standard_Integer aFaceId = 1;
455   TopExp_Explorer aFaceExp(shape, TopAbs_FACE);
456   for ( ; aFaceExp.More(); aFaceExp.Next(), ++aFaceId)
457   {
458     const TopoDS_Shape& aShape = aFaceExp.Current();
459     const TopoDS_Face& aFace = TopoDS::Face(aShape);
460
461     TopLoc_Location aLoc;
462     Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
463
464     // Iterate boundary edges
465     NCollection_Map<BRepMesh_Edge> aBoundaryEdgeMap;
466     TopExp_Explorer anExp(aShape, TopAbs_EDGE);
467     for ( ; anExp.More(); anExp.Next() )
468     {
469       TopLoc_Location anEdgeLoc;
470       const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
471       Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(anEdge, aT, aLoc);
472       if (aPoly.IsNull())
473       {
474         continue;
475       }
476
477       const TColStd_Array1OfInteger& anIndices = aPoly->Nodes();
478       Standard_Integer aLower  = anIndices.Lower(); 
479       Standard_Integer anUpper = anIndices.Upper();
480
481       Standard_Integer aPrevNode = -1;
482       for (Standard_Integer j = aLower; j <= anUpper; ++j)
483       {
484         Standard_Integer aNodeIdx = anIndices.Value(j);
485         if (j != aLower)
486         {
487           BRepMesh_Edge aLink(aPrevNode, aNodeIdx, BRepMesh_Frontier);
488           aBoundaryEdgeMap.Add(aLink);
489         }
490         aPrevNode = aNodeIdx;
491       }
492     }
493
494     if (aBoundaryEdgeMap.Size() == 0)
495     {
496       break;
497     }
498
499     const Poly_Array1OfTriangle& aTris = aT->Triangles();
500     NCollection_Map<BRepMesh_Edge> aFreeEdgeMap;
501     Standard_Integer aTriNum = aTris.Length();
502     for ( Standard_Integer aTriIndx = 1; aTriIndx <= aTriNum; aTriIndx++ )
503     {
504       const Poly_Triangle& aTri = aTris(aTriIndx);
505       Standard_Integer aTriNodes[3] = { aTri.Value(1), aTri.Value(2), aTri.Value(3)};
506
507       for (Standard_Integer j = 1; j <= 3; ++j)
508       {
509         Standard_Integer aLastId  = aTriNodes[j % 3];
510         Standard_Integer aFirstId = aTriNodes[j - 1];
511
512         BRepMesh_Edge aLink(aFirstId, aLastId, BRepMesh_Free);
513         if (!aBoundaryEdgeMap.Contains(aLink))
514         {
515           if (!aFreeEdgeMap.Add(aLink))
516           {
517             aFreeEdgeMap.Remove(aLink);
518           }
519         }
520       }
521     }
522
523     if (aFreeEdgeMap.Size() != 0)
524     {
525       di << "Not connected mesh inside face " << aFaceId << "\n";
526
527       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
528       const gp_Trsf& trsf = aLoc.Transformation();
529
530       TColgp_Array1OfPnt pnts(1,2);
531       TColgp_Array1OfPnt2d pnts2d(1,2);
532       NCollection_Map<BRepMesh_Edge>::Iterator aMapIt(aFreeEdgeMap);
533       for (; aMapIt.More(); aMapIt.Next())
534       {
535         const BRepMesh_Edge& aLink = aMapIt.Key();
536         di << "{" << aLink.FirstNode() << " " << aLink.LastNode() << "} ";
537         pnts(1) = aPoints(aLink.FirstNode()).Transformed(trsf);
538         pnts(2) = aPoints(aLink.LastNode()).Transformed(trsf);
539         Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
540         DrawTrSurf::Set (name, poly);
541         DrawTrSurf::Set (name, pnts(1));
542         DrawTrSurf::Set (name, pnts(2));
543         if (aT->HasUVNodes())
544         {
545           const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
546           pnts2d(1) = aPoints2d(aLink.FirstNode());
547           pnts2d(2) = aPoints2d(aLink.LastNode());
548           Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
549           DrawTrSurf::Set (name, poly2d);
550           DrawTrSurf::Set (name, pnts2d(1));
551           DrawTrSurf::Set (name, pnts2d(2));
552         }
553       }
554       di << "\n";
555     }
556   }
557   return 0;
558 }
559
560 //=======================================================================
561 //function : mpparallel
562 //purpose  :
563 //=======================================================================
564 static int mpparallel (Draw_Interpretor& /*di*/, Standard_Integer argc, const char** argv)
565 {
566   if (argc == 2)
567   {
568     Standard_Boolean isParallelOn = Draw::Atoi (argv[1]) == 1;
569     BRepMesh_IncrementalMesh::SetParallelDefault (isParallelOn);
570   }
571   std::cout << "Incremental Mesh, multi-threading "
572             << (BRepMesh_IncrementalMesh::IsParallelDefault() ? "ON\n" : "OFF\n");
573   return 0;
574 }