0026106: BRepMesh - revision of data model
[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 #include <Geom_BSplineCurve.hxx>
50 #include <Geom2d_BSplineCurve.hxx>
51
52 static Standard_Integer mpnames           (Draw_Interpretor& , Standard_Integer , const char** );
53 static Standard_Integer mpsetdefaultname  (Draw_Interpretor& , Standard_Integer , const char** );
54 static Standard_Integer mpgetdefaultname  (Draw_Interpretor& , Standard_Integer , const char** );
55 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
56 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
57 static Standard_Integer mperror           (Draw_Interpretor& , Standard_Integer , const char** );
58 static Standard_Integer mpincmesh         (Draw_Interpretor& , Standard_Integer , const char** );
59 static Standard_Integer mpparallel        (Draw_Interpretor& , Standard_Integer , const char** );
60 static Standard_Integer triarea           (Draw_Interpretor& , Standard_Integer , const char** );
61 static Standard_Integer tricheck          (Draw_Interpretor& , Standard_Integer , const char** );
62
63 //=======================================================================
64 //function : PluginCommands
65 //purpose  : 
66 //=======================================================================
67 void MeshTest::PluginCommands(Draw_Interpretor& theCommands)
68 {
69   static Standard_Boolean done = Standard_False;
70   if (done) {
71     return;
72   }
73   done = Standard_True;
74   //
75   const char* g = "Mesh Commands";
76   // Commands
77   theCommands.Add("mpnames"          , "use mpnames"          , __FILE__, mpnames    , g);
78   theCommands.Add("mpsetdefaultname" , "use mpsetdefaultname" , __FILE__, mpsetdefaultname     , g);
79   theCommands.Add("mpgetdefaultname" , "use mpgetdefaultname" , __FILE__, mpgetdefaultname     , g);
80   theCommands.Add("mpsetfunctionname", "use mpsetfunctionname", __FILE__, mpsetfunctionname     , g);
81   theCommands.Add("mpgetfunctionname", "use mpgetfunctionname", __FILE__, mpgetfunctionname     , g);
82   theCommands.Add("mperror"          , "use mperror"          , __FILE__, mperror     , g);
83   theCommands.Add("mpincmesh"        , "use mpincmesh"        , __FILE__, mpincmesh      , g);
84   theCommands.Add("mpparallel"       , "mpparallel [toTurnOn] : show / set multi-threading flag for incremental mesh",
85     __FILE__, mpparallel, g);
86   theCommands.Add("triarea","shape [eps]  (computes triangles and surface area)",__FILE__, triarea, g);
87   theCommands.Add("tricheck", "shape [-small]  (checks triangulation of shape);\n"
88                   "\"-small\"-option allows finding triangles with small area", __FILE__, tricheck, g);
89 }
90
91 //=======================================================================
92 //function : mpnames
93 //purpose  : 
94 //=======================================================================
95 static Standard_Integer mpnames (Draw_Interpretor& , Standard_Integer n, const char** )
96 {
97   Standard_Integer aNb;
98   TColStd_MapIteratorOfMapOfAsciiString aIt;
99   //
100   if (n!=1) {
101     printf(" use mpnames\n");
102     return 0;
103   }
104   //
105   const TColStd_MapOfAsciiString& aMN=BRepMesh_DiscretFactory::Get().Names();
106   aNb=aMN.Extent();
107   if (!aNb) {
108     printf(" *no names found\n");
109     return 0;
110   }
111   //
112   printf(" *available names:\n");
113   aIt.Initialize(aMN);
114   for (; aIt.More(); aIt.Next()) {
115     const TCollection_AsciiString& aName=aIt.Key();
116     printf("  %s\n", aName.ToCString());
117   }
118   //
119   return 0;
120 }
121 //=======================================================================
122 //function : mpsetdefaultname
123 //purpose  : 
124 //=======================================================================
125 static Standard_Integer mpsetdefaultname (Draw_Interpretor& , Standard_Integer n, const char**a )
126 {
127   TCollection_AsciiString aName;
128   //
129   if (n!=2) {
130     printf(" use mpsetdefaultname name\n");
131     return 0;
132   }
133   //
134   aName=a[1];
135   //
136   if (BRepMesh_DiscretFactory::Get().SetDefaultName (aName))
137     printf(" *ready\n");
138   else
139     printf(" *fault\n");
140   //
141   return 0;
142 }
143 //=======================================================================
144 //function : mpgetdefaultname
145 //purpose  : 
146 //=======================================================================
147 static Standard_Integer mpgetdefaultname (Draw_Interpretor& , Standard_Integer n, const char** )
148 {
149   if (n!=1) {
150     printf(" use mpgetdefaultname\n");
151     return 0;
152   }
153   //
154   const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().DefaultName();
155   printf(" *default name: %s\n", aName.ToCString());
156   //
157   return 0;
158 }
159 //=======================================================================
160 //function : mpsetfunctionname
161 //purpose  : 
162 //=======================================================================
163 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer n, const char**a )
164 {
165   TCollection_AsciiString aName;
166   //
167   if (n!=2) {
168     printf(" use mpsetfunctionname name\n");
169     return 0;
170   }
171   //
172   aName=a[1];
173   //
174   if (BRepMesh_DiscretFactory::Get().SetFunctionName (aName))
175     printf(" *ready\n");
176   else
177     printf(" *fault\n");
178   //
179   return 0;
180 }
181 //=======================================================================
182 //function : mpgetdefaultname
183 //purpose  : 
184 //=======================================================================
185 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer n, const char** )
186 {
187   if (n!=1) {
188     printf(" use mpgetfunctionname\n");
189     return 0;
190   }
191   //
192   const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().FunctionName();
193   printf(" *function name: %s\n", aName.ToCString());
194   //
195   return 0;
196 }
197 //=======================================================================
198 //function : mperror
199 //purpose  : 
200 //=======================================================================
201 static Standard_Integer mperror (Draw_Interpretor& , Standard_Integer n, const char** )
202 {
203   BRepMesh_FactoryError aErr;
204   //
205   if (n!=1) {
206     printf(" use mperror\n");
207     return 0;
208   }
209   //
210   aErr=BRepMesh_DiscretFactory::Get().ErrorStatus();
211   printf(" *ErrorStatus: %d\n", (int)aErr);
212   //
213   return 0;
214 }
215
216 //=======================================================================
217 //function :mpincmesh
218 //purpose  : 
219 //=======================================================================
220 static Standard_Integer mpincmesh (Draw_Interpretor& , Standard_Integer n, const char** a)
221 {
222   Standard_Real aDeflection, aAngle;
223   TopoDS_Shape aS;
224   //
225   if (n<3) {
226     printf(" use mpincmesh s deflection [angle]\n");
227     return 0;
228   }
229   //
230   aS=DBRep::Get(a[1]);
231   if (aS.IsNull()) {
232     printf(" null shapes is not allowed here\n");
233     return 0;
234   }
235   //
236   aDeflection=Draw::Atof(a[2]);
237   aAngle=0.5;
238   if (n>3) {
239     aAngle=Draw::Atof(a[3]);
240   }
241   //
242   Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (aS,
243                                                                                    aDeflection,
244                                                                                    aAngle);
245   //
246   BRepMesh_FactoryError aErr = BRepMesh_DiscretFactory::Get().ErrorStatus();
247   if (aErr != BRepMesh_FE_NOERROR)
248   {
249     printf(" *Factory::Get().ErrorStatus()=%d\n", (int)aErr);
250   }
251   //
252   if (aMeshAlgo.IsNull())
253   {
254     printf(" *Can not create the algo\n");
255     return 0;
256   }
257   //
258   aMeshAlgo->Perform();
259   if (!aMeshAlgo->IsDone())
260   {
261     printf(" *Not done\n");
262   }
263   //
264   return 0;
265 }
266
267 //#######################################################################
268 static Standard_Integer triarea (Draw_Interpretor& di, int n, const char ** a)
269 {
270
271   if (n < 2) return 1;
272
273   TopoDS_Shape shape = DBRep::Get(a[1]);
274   if (shape.IsNull()) return 1;
275   Standard_Real anEps = -1.;
276   if (n > 2)
277     anEps = Draw::Atof(a[2]);
278
279   TopTools_IndexedMapOfShape aMapF;
280   TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
281
282   // detect if a shape has triangulation
283   Standard_Boolean hasPoly = Standard_False;
284   int i;
285   for (i=1; i <= aMapF.Extent(); i++) {
286     const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
287     TopLoc_Location aLoc;
288     Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
289     if (!aPoly.IsNull()) {
290       hasPoly = Standard_True;
291       break;
292     }
293   }
294
295   // compute area by triangles
296   double aTriArea=0;
297   if (hasPoly) {
298     for (i=1; i <= aMapF.Extent(); i++) {
299       const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
300       TopLoc_Location aLoc;
301       Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
302       if (aPoly.IsNull()) {
303         cout << "face "<<i<<" has no triangulation"<<endl;
304         continue;
305       }
306       const Poly_Array1OfTriangle& triangles = aPoly->Triangles();
307       const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
308       for (int j=triangles.Lower(); j <= triangles.Upper(); j++) {
309         const Poly_Triangle& tri = triangles(j);
310         int n1, n2, n3;
311         tri.Get (n1, n2, n3);
312         const gp_Pnt& p1 = nodes(n1);
313         const gp_Pnt& p2 = nodes(n2);
314         const gp_Pnt& p3 = nodes(n3);
315         gp_Vec v1(p1, p2);
316         gp_Vec v2(p1, p3);
317         double ar = v1.CrossMagnitude(v2);
318         aTriArea += ar;
319       }
320     }
321     aTriArea /= 2;
322   }
323
324   // compute area by geometry
325   GProp_GProps props;
326   if (anEps <= 0.)
327     BRepGProp::SurfaceProperties(shape, props);
328   else
329     BRepGProp::SurfaceProperties(shape, props, anEps);
330   double aGeomArea = props.Mass();
331
332   di << aTriArea << " " << aGeomArea << "\n";
333   return 0;
334 }
335
336 //#######################################################################
337 Standard_Boolean IsEqual(const BRepMesh_Edge& theFirst, const BRepMesh_Edge& theSecond) 
338 {
339   return theFirst.IsEqual(theSecond);
340 }
341
342 static Standard_Integer tricheck (Draw_Interpretor& di, int n, const char ** a)
343 {
344   if (n < 2) return 1;
345
346   TopoDS_Shape shape = DBRep::Get(a[1]);
347   if (shape.IsNull()) return 1;
348
349   const Standard_Boolean isToFindSmallTriangles = (n >= 3) ? (strcmp(a[2], "-small") == 0) : Standard_False;
350
351   TopTools_IndexedMapOfShape aMapF;
352   TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
353   const Standard_CString name = ".";
354
355   // execute check
356   MeshTest_CheckTopology aCheck(shape);
357   aCheck.Perform(di);
358
359   // dump info on free links inside the triangulation
360   Standard_Integer nbFree = 0;
361   Standard_Integer nbFac = aCheck.NbFacesWithFL(), i, k;
362   if (nbFac > 0) {
363     for (k=1; k <= nbFac; k++) {
364       Standard_Integer nbEdge = aCheck.NbFreeLinks(k);
365       Standard_Integer iF = aCheck.GetFaceNumWithFL(k);
366       nbFree += nbEdge;
367       di << "free links of face " << iF << "\n";
368
369       const TopoDS_Shape& aShape = aMapF.FindKey(iF);
370       const TopoDS_Face& aFace = TopoDS::Face(aShape);
371       TopLoc_Location aLoc;
372       Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
373       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
374       const gp_Trsf& trsf = aLoc.Transformation();
375
376       TColgp_Array1OfPnt pnts(1,2);
377       TColgp_Array1OfPnt2d pnts2d(1,2);
378       for (i=1; i <= nbEdge; i++) {
379         Standard_Integer n1, n2;
380         aCheck.GetFreeLink(k, i, n1, n2);
381         di << "{" << n1 << " " << n2 << "} ";
382         pnts(1) = aPoints(n1).Transformed(trsf);
383         pnts(2) = aPoints(n2).Transformed(trsf);
384         Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
385         DrawTrSurf::Set (name, poly);
386         DrawTrSurf::Set (name, pnts(1));
387         DrawTrSurf::Set (name, pnts(2));
388         if (aT->HasUVNodes())
389         {
390           const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
391           pnts2d(1) = aPoints2d(n1);
392           pnts2d(2) = aPoints2d(n2);
393           Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
394           DrawTrSurf::Set (name, poly2d);
395           DrawTrSurf::Set (name, pnts2d(1));
396           DrawTrSurf::Set (name, pnts2d(2));
397         }
398       }
399       di << "\n";
400     }
401   }
402
403   // dump info on cross face errors
404   Standard_Integer nbErr = aCheck.NbCrossFaceErrors();
405   if (nbErr > 0) {
406     di << "cross face errors: {face1, node1, face2, node2, distance}\n";
407     for (i=1; i <= nbErr; i++) {
408       Standard_Integer iF1, n1, iF2, n2;
409       Standard_Real aVal;
410       aCheck.GetCrossFaceError(i, iF1, n1, iF2, n2, aVal);
411       di << "{" << iF1 << " " << n1 << " " << iF2 << " " << n2 << " " << aVal << "} ";
412     }
413     di << "\n";
414   }
415
416   // dump info on edges
417   Standard_Integer nbAsync = aCheck.NbAsyncEdges();
418   if (nbAsync > 0) {
419     di << "async edges:\n";
420     for (i=1; i <= nbAsync; i++) {
421       Standard_Integer ie = aCheck.GetAsyncEdgeNum(i);
422       di << ie << " ";
423     }
424     di << "\n";
425   }
426
427   // dump info on free nodes
428   Standard_Integer nbFreeNodes = aCheck.NbFreeNodes();
429   if (nbFreeNodes > 0) {
430     di << "free nodes (in pairs: face / node): \n";
431     for (i=1; i <= nbFreeNodes; i++) {
432       Standard_Integer iface, inode;
433       aCheck.GetFreeNodeNum(i, iface, inode);
434
435       const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(iface));
436       TopLoc_Location aLoc;
437       Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
438       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
439       const gp_Trsf& trsf = aLoc.Transformation();
440       DrawTrSurf::Set (name, aPoints(inode).Transformed(trsf));
441       if (aT->HasUVNodes())
442       {
443         DrawTrSurf::Set (name, aT->UVNodes()(inode));
444       }
445
446       di << "{" << iface << " " << inode << "} ";
447     }
448     di << "\n";
449   }
450
451   const Standard_Integer aNbSmallTriangles = isToFindSmallTriangles? aCheck.NbSmallTriangles() : 0;
452   if (aNbSmallTriangles > 0)
453   {
454     di << "triangles with null area (in pairs: face / triangle): \n";
455     for (i = 1; i <= aNbSmallTriangles; i++)
456     {
457       Standard_Integer aFaceId = 0, aTriID = 0;
458       aCheck.GetSmallTriangle(i, aFaceId, aTriID);
459
460       const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(aFaceId));
461       TopLoc_Location aLoc;
462       const gp_Trsf& aTrsf = aLoc.Transformation();
463       const Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
464       const Poly_Triangle &aTri = aT->Triangle(aTriID);
465       Standard_Integer aN1, aN2, aN3;
466       aTri.Get(aN1, aN2, aN3);
467       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
468
469       TColgp_Array1OfPnt aPoles(1, 4);
470       aPoles(1) = aPoles(4) = aPoints(aN1).Transformed(aTrsf);
471       aPoles(2) = aPoints(aN2).Transformed(aTrsf);
472       aPoles(3) = aPoints(aN3).Transformed(aTrsf);
473
474       TColStd_Array1OfInteger aMults(1, 4);
475       aMults(1) = aMults(4) = 2;
476       aMults(2) = aMults(3) = 1;
477
478       TColStd_Array1OfReal aKnots(1, 4);
479       aKnots(1) = 1.0;
480       aKnots(2) = 2.0;
481       aKnots(3) = 3.0;
482       aKnots(4) = 4.0;
483       
484       Handle(Geom_BSplineCurve) aBS = new Geom_BSplineCurve(aPoles, aKnots, aMults, 1);
485
486       DrawTrSurf::Set(name, aBS);
487
488       if (aT->HasUVNodes())
489       {
490         TColgp_Array1OfPnt2d aPoles2d(1, 4);
491         aPoles2d(1) = aPoles2d(4) = aT->UVNodes()(aN1);
492         aPoles2d(2) = aT->UVNodes()(aN2);
493         aPoles2d(3) = aT->UVNodes()(aN3);
494
495         Handle(Geom2d_BSplineCurve) aBS2d = new Geom2d_BSplineCurve(aPoles2d, aKnots, aMults, 1);
496
497         DrawTrSurf::Set(name, aBS2d);
498       }
499
500       di << "{" << aFaceId << " " << aTriID << "} ";
501     }
502
503     di << "\n";
504   }
505
506   // output errors summary to DRAW
507   if (nbFree > 0 ||
508       nbErr > 0 ||
509       nbAsync > 0 ||
510       nbFreeNodes > 0 ||
511       (aNbSmallTriangles > 0))
512   {
513     di << "Free_links " << nbFree
514       << " Cross_face_errors " << nbErr
515       << " Async_edges " << nbAsync
516       << " Free_nodes " << nbFreeNodes
517       << " Small triangles " << aNbSmallTriangles << "\n";
518   }
519
520   Standard_Integer aFaceId = 1;
521   TopExp_Explorer aFaceExp(shape, TopAbs_FACE);
522   for ( ; aFaceExp.More(); aFaceExp.Next(), ++aFaceId)
523   {
524     const TopoDS_Shape& aShape = aFaceExp.Current();
525     const TopoDS_Face& aFace = TopoDS::Face(aShape);
526
527     TopLoc_Location aLoc;
528     Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
529
530     // Iterate boundary edges
531     NCollection_Map<BRepMesh_Edge> aBoundaryEdgeMap;
532     TopExp_Explorer anExp(aShape, TopAbs_EDGE);
533     for ( ; anExp.More(); anExp.Next() )
534     {
535       TopLoc_Location anEdgeLoc;
536       const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
537       Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(anEdge, aT, aLoc);
538       if (aPoly.IsNull())
539       {
540         continue;
541       }
542
543       const TColStd_Array1OfInteger& anIndices = aPoly->Nodes();
544       Standard_Integer aLower  = anIndices.Lower(); 
545       Standard_Integer anUpper = anIndices.Upper();
546
547       Standard_Integer aPrevNode = -1;
548       for (Standard_Integer j = aLower; j <= anUpper; ++j)
549       {
550         Standard_Integer aNodeIdx = anIndices.Value(j);
551         if (j != aLower)
552         {
553           BRepMesh_Edge aLink(aPrevNode, aNodeIdx, BRepMesh_Frontier);
554           aBoundaryEdgeMap.Add(aLink);
555         }
556         aPrevNode = aNodeIdx;
557       }
558     }
559
560     if (aBoundaryEdgeMap.Size() == 0)
561     {
562       break;
563     }
564
565     const Poly_Array1OfTriangle& aTris = aT->Triangles();
566     NCollection_Map<BRepMesh_Edge> aFreeEdgeMap;
567     Standard_Integer aTriNum = aTris.Length();
568     for ( Standard_Integer aTriIndx = 1; aTriIndx <= aTriNum; aTriIndx++ )
569     {
570       const Poly_Triangle& aTri = aTris(aTriIndx);
571       Standard_Integer aTriNodes[3] = { aTri.Value(1), aTri.Value(2), aTri.Value(3)};
572
573       for (Standard_Integer j = 1; j <= 3; ++j)
574       {
575         Standard_Integer aLastId  = aTriNodes[j % 3];
576         Standard_Integer aFirstId = aTriNodes[j - 1];
577
578         BRepMesh_Edge aLink(aFirstId, aLastId, BRepMesh_Free);
579         if (!aBoundaryEdgeMap.Contains(aLink))
580         {
581           if (!aFreeEdgeMap.Add(aLink))
582           {
583             aFreeEdgeMap.Remove(aLink);
584           }
585         }
586       }
587     }
588
589     if (aFreeEdgeMap.Size() != 0)
590     {
591       di << "Not connected mesh inside face " << aFaceId << "\n";
592
593       const TColgp_Array1OfPnt& aPoints = aT->Nodes();
594       const gp_Trsf& trsf = aLoc.Transformation();
595
596       TColgp_Array1OfPnt pnts(1,2);
597       TColgp_Array1OfPnt2d pnts2d(1,2);
598       NCollection_Map<BRepMesh_Edge>::Iterator aMapIt(aFreeEdgeMap);
599       for (; aMapIt.More(); aMapIt.Next())
600       {
601         const BRepMesh_Edge& aLink = aMapIt.Key();
602         di << "{" << aLink.FirstNode() << " " << aLink.LastNode() << "} ";
603         pnts(1) = aPoints(aLink.FirstNode()).Transformed(trsf);
604         pnts(2) = aPoints(aLink.LastNode()).Transformed(trsf);
605         Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
606         DrawTrSurf::Set (name, poly);
607         DrawTrSurf::Set (name, pnts(1));
608         DrawTrSurf::Set (name, pnts(2));
609         if (aT->HasUVNodes())
610         {
611           const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
612           pnts2d(1) = aPoints2d(aLink.FirstNode());
613           pnts2d(2) = aPoints2d(aLink.LastNode());
614           Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
615           DrawTrSurf::Set (name, poly2d);
616           DrawTrSurf::Set (name, pnts2d(1));
617           DrawTrSurf::Set (name, pnts2d(2));
618         }
619       }
620       di << "\n";
621     }
622   }
623   return 0;
624 }
625
626 //=======================================================================
627 //function : mpparallel
628 //purpose  :
629 //=======================================================================
630 static int mpparallel (Draw_Interpretor& /*di*/, Standard_Integer argc, const char** argv)
631 {
632   if (argc == 2)
633   {
634     Standard_Boolean isParallelOn = Draw::Atoi (argv[1]) == 1;
635     BRepMesh_IncrementalMesh::SetParallelDefault (isParallelOn);
636   }
637   std::cout << "Incremental Mesh, multi-threading "
638             << (BRepMesh_IncrementalMesh::IsParallelDefault() ? "ON\n" : "OFF\n");
639   return 0;
640 }