bff781887d56eefbf4c6484e75ea45c9a32b4b27
[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 #include <MeshTest.ixx>
17 #include <Draw_Interpretor.hxx>
18 #include <TColStd_MapOfAsciiString.hxx>
19 #include <BRepMesh_DiscretFactory.hxx>
20 #include <TCollection_AsciiString.hxx>
21 #include <TColStd_MapIteratorOfMapOfAsciiString.hxx>
22 #include <BRepMesh_FactoryError.hxx>
23 #include <BRepMesh_DiscretRoot.hxx>
24 #include <BRepMesh_IncrementalMesh.hxx>
25 #include <Bnd_Box.hxx>
26 #include <BRepMesh_DiscretRoot.hxx>
27 #include <Draw.hxx>
28 #include <DBRep.hxx>
29 #include <TopTools_IndexedMapOfShape.hxx>
30 #include <TopExp.hxx>
31 #include <Poly_Triangulation.hxx>
32 #include <gp_Vec.hxx>
33 #include <GProp_GProps.hxx>
34 #include <BRepGProp.hxx>
35 #include <DrawTrSurf.hxx>
36 #include <BRep_Tool.hxx>
37 #include <TopoDS.hxx>
38 #include <MeshTest_CheckTopology.hxx>
39 #include <TColgp_Array1OfPnt2d.hxx>
40 #include <Poly_Polygon3D.hxx>
41 #include <Poly_Polygon2D.hxx>
42 #include <Standard.hxx>
43 #include <TopExp_Explorer.hxx>
44 #include <TColStd_Array1OfInteger.hxx>
45 #include <Poly_PolygonOnTriangulation.hxx>
46 #include <TopoDS_Face.hxx>
47 #include <BRepMesh_Edge.hxx>
48 #include <NCollection_Map.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 TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
370       const gp_Trsf& trsf = aLoc.Transformation();
371
372       TColgp_Array1OfPnt pnts(1,2);
373       TColgp_Array1OfPnt2d pnts2d(1,2);
374       for (i=1; i <= nbEdge; i++) {
375         Standard_Integer n1, n2;
376         aCheck.GetFreeLink(k, i, n1, n2);
377         di << "{" << n1 << " " << n2 << "} ";
378         pnts(1) = aPoints(n1).Transformed(trsf);
379         pnts(2) = aPoints(n2).Transformed(trsf);
380         Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
381         DrawTrSurf::Set (name, poly);
382         DrawTrSurf::Set (name, pnts(1));
383         DrawTrSurf::Set (name, pnts(2));
384         pnts2d(1) = aPoints2d(n1);
385         pnts2d(2) = aPoints2d(n2);
386         Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
387         DrawTrSurf::Set (name, poly2d);
388         DrawTrSurf::Set (name, pnts2d(1));
389         DrawTrSurf::Set (name, pnts2d(2));
390       }
391       di << "\n";
392     }
393   }
394
395   // dump info on cross face errors
396   Standard_Integer nbErr = aCheck.NbCrossFaceErrors();
397   if (nbErr > 0) {
398     di << "cross face errors: {face1, node1, face2, node2, distance}" << "\n";
399     for (i=1; i <= nbErr; i++) {
400       Standard_Integer iF1, n1, iF2, n2;
401       Standard_Real aVal;
402       aCheck.GetCrossFaceError(i, iF1, n1, iF2, n2, aVal);
403       di << "{" << iF1 << " " << n1 << " " << iF2 << " " << n2 << " " << aVal << "} ";
404     }
405     di << "\n";
406   }
407
408   // dump info on edges
409   Standard_Integer nbAsync = aCheck.NbAsyncEdges();
410   if (nbAsync > 0) {
411     di << "async edges:" << "\n";
412     for (i=1; i <= nbAsync; i++) {
413       Standard_Integer ie = aCheck.GetAsyncEdgeNum(i);
414       di << ie << " ";
415     }
416     di << "\n";
417   }
418
419   // dump info on free nodes
420   Standard_Integer nbFreeNodes = aCheck.NbFreeNodes();
421   if (nbFreeNodes > 0) {
422     di << "free nodes (in pairs: face / node): " << "\n";
423     for (i=1; i <= nbFreeNodes; i++) {
424       Standard_Integer iface, inode;
425       aCheck.GetFreeNodeNum(i, iface, inode);
426       di << "{" << iface << " " << inode << "} ";
427     }
428     di << "\n";
429   }
430
431   // output errors summary to DRAW
432   if ( nbFree > 0 || nbErr > 0 || nbAsync > 0 || nbFreeNodes > 0)
433     di << "Free_links " << nbFree
434        << " Cross_face_errors " << nbErr
435        << " Async_edges " << nbAsync 
436        << " Free_nodes " << nbFreeNodes << "\n";
437
438
439   Standard_Integer aFaceId = 1;
440   TopExp_Explorer aFaceExp(shape, TopAbs_FACE);
441   for ( ; aFaceExp.More(); aFaceExp.Next(), ++aFaceId)
442   {
443     const TopoDS_Shape& aShape = aFaceExp.Current();
444     const TopoDS_Face& aFace = TopoDS::Face(aShape);
445
446     TopLoc_Location aLoc;
447     Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
448
449     // Iterate boundary edges
450     NCollection_Map<BRepMesh_Edge> aBoundaryEdgeMap;
451     TopExp_Explorer anExp(aShape, TopAbs_EDGE);
452     for ( ; anExp.More(); anExp.Next() )
453     {
454       TopLoc_Location anEdgeLoc;
455       const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
456       Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(anEdge, aT, aLoc);
457       if (aPoly.IsNull())
458       {
459         continue;
460       }
461
462       const TColStd_Array1OfInteger& anIndices = aPoly->Nodes();
463       Standard_Integer aLower  = anIndices.Lower(); 
464       Standard_Integer anUpper = anIndices.Upper();
465
466       Standard_Integer aPrevNode = -1;
467       for (Standard_Integer i = aLower; i <= anUpper; ++i)
468       {
469         Standard_Integer aNodeIdx = anIndices.Value(i);
470         if (i != aLower)
471         {
472           BRepMesh_Edge aLink(aPrevNode, aNodeIdx, BRepMesh_Frontier);
473           aBoundaryEdgeMap.Add(aLink);
474         }
475         aPrevNode = aNodeIdx;
476       }
477     }
478
479     if (aBoundaryEdgeMap.Size() == 0)
480     {
481       break;
482     }
483
484     const Poly_Array1OfTriangle& aTris = aT->Triangles();
485     NCollection_Map<BRepMesh_Edge> aFreeEdgeMap;
486     Standard_Integer aTriNum = aTris.Length();
487     for ( Standard_Integer aTriIndx = 1; aTriIndx <= aTriNum; aTriIndx++ )
488     {
489       const Poly_Triangle& aTri = aTris(aTriIndx);
490       Standard_Integer aTriNodes[3] = { aTri.Value(1), aTri.Value(2), aTri.Value(3)};
491
492       for (Standard_Integer i = 1; i <= 3; ++i)
493       {
494         Standard_Integer aLastId  = aTriNodes[i % 3];
495         Standard_Integer aFirstId = aTriNodes[i - 1];
496
497         BRepMesh_Edge aLink(aFirstId, aLastId, BRepMesh_Free);
498         if (!aBoundaryEdgeMap.Contains(aLink))
499         {
500           if (!aFreeEdgeMap.Add(aLink))
501           {
502             aFreeEdgeMap.Remove(aLink);
503           }
504         }
505       }
506     }
507
508     if (aFreeEdgeMap.Size() != 0)
509     {
510       di << "Not connected mesh inside face " << aFaceId << "\n";
511     }
512   }
513   return 0;
514 }
515
516 //=======================================================================
517 //function : mpparallel
518 //purpose  :
519 //=======================================================================
520 static int mpparallel (Draw_Interpretor& /*di*/, Standard_Integer argc, const char** argv)
521 {
522   if (argc == 2)
523   {
524     Standard_Boolean isParallelOn = Draw::Atoi (argv[1]) == 1;
525     BRepMesh_IncrementalMesh::SetParallelDefault (isParallelOn);
526   }
527   std::cout << "Incremental Mesh, multi-threading "
528             << (BRepMesh_IncrementalMesh::IsParallelDefault() ? "ON\n" : "OFF\n");
529   return 0;
530 }