0032633: Draw Harness - extend command incmesh to apply default visualization parameters
[occt.git] / src / MeshTest / MeshTest.cxx
1 // Created on: 1993-09-22
2 // Created by: Didier PIFFAULT
3 // Copyright (c) 1993-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 <MeshTest.hxx>
18
19 #include <stdio.h>
20
21 #include <Bnd_Box.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRepAdaptor_Surface.hxx>
24 #include <BRepBndLib.hxx>
25 #include <BRepBuilderAPI_MakeFace.hxx>
26 #include <BRepBuilderAPI_MakePolygon.hxx>
27 #include <BRepBuilderAPI_MakeVertex.hxx>
28 #include <BRepLib.hxx>
29 #include <BRepMesh_IncrementalMesh.hxx>
30 #include <BRepTest.hxx>
31 #include <BRepTools.hxx>
32 #include <CSLib.hxx>
33 #include <DBRep.hxx>
34 #include <Draw_Appli.hxx>
35 #include <Draw_ProgressIndicator.hxx>
36 #include <Draw_Segment2D.hxx>
37 #include <DrawTrSurf.hxx>
38 #include <GeometryTest.hxx>
39 #include <IMeshData_Status.hxx>
40 #include <Message.hxx>
41 #include <Message_ProgressRange.hxx>
42 #include <OSD_OpenFile.hxx>
43 #include <Poly_Connect.hxx>
44 #include <Poly_MergeNodesTool.hxx>
45 #include <Poly_TriangulationParameters.hxx>
46 #include <Prs3d_Drawer.hxx>
47 #include <StdPrs_ToolTriangulatedShape.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopTools_MapIteratorOfMapOfShape.hxx>
50 #include <BRep_CurveRepresentation.hxx>
51 #include <BRep_TEdge.hxx>
52 #include <TopExp.hxx> 
53
54 #include <BRepMesh_Context.hxx>
55 #include <BRepMesh_FaceDiscret.hxx>
56 #include <BRepMesh_MeshAlgoFactory.hxx>
57 #include <BRepMesh_DelabellaMeshAlgoFactory.hxx>
58
59 #include <algorithm>
60
61 //epa Memory leaks test
62 //OAN: for triepoints
63 #ifdef _WIN32
64 Standard_IMPORT Draw_Viewer dout;
65 #endif
66
67 #define MAX2(X, Y)      (  Abs(X) > Abs(Y)? Abs(X) : Abs(Y) )
68 #define MAX3(X, Y, Z)   ( MAX2 ( MAX2(X,Y) , Z) )
69
70 #define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
71 #define TWOTHIRD 0.666666666666666666666666666666666666666666666666666666666666
72
73 #ifdef OCCT_DEBUG_MESH_CHRONO
74 #include <OSD_Chronometer.hxx>
75 Standard_Integer D0Control, D0Internal, D0Unif, D0Edges, NbControls;
76 OSD_Chronometer chTotal, chInternal, chControl, chUnif, chAddPoint;
77 OSD_Chronometer chEdges, chMaillEdges, chEtuInter, chLastControl, chStock;
78 OSD_Chronometer chAdd11, chAdd12, chAdd2, chUpdate, chPointValid;
79 OSD_Chronometer chIsos, chPointsOnIsos;
80 #endif
81
82 //=======================================================================
83 //function : incrementalmesh
84 //purpose  : 
85 //=======================================================================
86 static Standard_Integer incrementalmesh (Draw_Interpretor& theDI,
87                                          Standard_Integer theNbArgs,
88                                          const char** theArgVec)
89 {
90   if (theNbArgs < 3)
91   {
92     theDI << "Syntax error: wrong number of arguments";
93     return 1;
94   }
95
96   TopoDS_ListOfShape aListOfShapes;
97   IMeshTools_Parameters aMeshParams;
98   bool hasDefl = false, hasAngDefl = false, isPrsDefl = false;
99
100   Handle(IMeshTools_Context) aContext = new BRepMesh_Context();
101   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
102   {
103     TCollection_AsciiString aNameCase (theArgVec[anArgIter]);
104     aNameCase.LowerCase();
105     if (aNameCase == "-relative"
106      || aNameCase == "-norelative")
107     {
108       aMeshParams.Relative = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
109     }
110     else if (aNameCase == "-parallel"
111           || aNameCase == "-noparallel")
112     {
113       aMeshParams.InParallel = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
114     }
115     else if (aNameCase == "-int_vert_off")
116     {
117       aMeshParams.InternalVerticesMode = !Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
118     }
119     else if (aNameCase == "-surf_def_off")
120     {
121       aMeshParams.ControlSurfaceDeflection = !Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
122     }
123     else if (aNameCase == "-adjust_min")
124     {
125       aMeshParams.AdjustMinSize = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
126     }
127     else if (aNameCase == "-force_face_def")
128     {
129       aMeshParams.ForceFaceDeflection = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
130     }
131     else if (aNameCase == "-decrease")
132     {
133       aMeshParams.AllowQualityDecrease = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
134     }
135     else if (aNameCase == "-algo"
136           && anArgIter + 1 < theNbArgs)
137     {
138       TCollection_AsciiString anAlgoStr (theArgVec[++anArgIter]);
139       anAlgoStr.LowerCase();
140       if (anAlgoStr == "watson"
141        || anAlgoStr == "0")
142       {
143         aMeshParams.MeshAlgo = IMeshTools_MeshAlgoType_Watson;
144         aContext->SetFaceDiscret (new BRepMesh_FaceDiscret (new BRepMesh_MeshAlgoFactory()));
145       }
146       else if (anAlgoStr == "delabella"
147             || anAlgoStr == "1")
148       {
149         aMeshParams.MeshAlgo = IMeshTools_MeshAlgoType_Delabella;
150         aContext->SetFaceDiscret (new BRepMesh_FaceDiscret (new BRepMesh_DelabellaMeshAlgoFactory()));
151       }
152       else if (anAlgoStr == "-1"
153             || anAlgoStr == "default")
154       {
155         // already handled by BRepMesh_Context constructor
156         //aMeshParams.MeshAlgo = IMeshTools_MeshAlgoType_DEFAULT;
157       }
158       else
159       {
160         theDI << "Syntax error at '" << anAlgoStr << "'";
161         return 1;
162       }
163     }
164     else if ((aNameCase == "-prs"
165            || aNameCase == "-presentation"
166            || aNameCase == "-vis"
167            || aNameCase == "-visualization")
168          && !isPrsDefl)
169     {
170       isPrsDefl = true;
171     }
172     else if ((aNameCase == "-angular"
173            || aNameCase == "-angdefl"
174            || aNameCase == "-angulardeflection"
175            || aNameCase == "-a")
176           && anArgIter + 1 < theNbArgs)
177     {
178       Standard_Real aVal = Draw::Atof (theArgVec[++anArgIter]) * M_PI / 180.;
179       if (aVal <= Precision::Angular())
180       {
181         theDI << "Syntax error: invalid input parameter '" << theArgVec[anArgIter] << "'";
182         return 1;
183       }
184       aMeshParams.Angle = aVal;
185       hasAngDefl = true;
186     }
187     else if (aNameCase == "-ai"
188           && anArgIter + 1 < theNbArgs)
189     {
190       Standard_Real aVal = Draw::Atof (theArgVec[++anArgIter]) * M_PI / 180.;
191       if (aVal <= Precision::Angular())
192       {
193         theDI << "Syntax error: invalid input parameter '" << theArgVec[anArgIter] << "'";
194         return 1;
195       }
196       aMeshParams.AngleInterior = aVal;
197     }
198     else if (aNameCase == "-min"
199           && anArgIter + 1 < theNbArgs)
200     {
201       Standard_Real aVal = Draw::Atof (theArgVec[++anArgIter]);
202       if (aVal <= Precision::Confusion())
203       {
204         theDI << "Syntax error: invalid input parameter '" << theArgVec[anArgIter] << "'";
205         return 1;
206       }
207       aMeshParams.MinSize = aVal;
208     }
209     else if (aNameCase == "-di"
210           && anArgIter + 1 < theNbArgs)
211     {
212       Standard_Real aVal = Draw::Atof (theArgVec[++anArgIter]);
213       if (aVal <= Precision::Confusion())
214       {
215         theDI << "Syntax error: invalid input parameter '" << theArgVec[anArgIter] << "'";
216         return 1;
217       }
218       aMeshParams.DeflectionInterior = aVal;
219     }
220     else if (aNameCase.IsRealValue (true)
221          && !hasDefl)
222     {
223       aMeshParams.Deflection = Max (Draw::Atof (theArgVec[anArgIter]), Precision::Confusion());
224       if (aMeshParams.DeflectionInterior < Precision::Confusion())
225       {
226         aMeshParams.DeflectionInterior = aMeshParams.Deflection;
227       }
228       hasDefl = true;
229     }
230     else
231     {
232       TopoDS_Shape aShape = DBRep::Get (theArgVec[anArgIter]);
233       if (aShape.IsNull())
234       {
235         theDI << "Syntax error: null shapes are not allowed here '" << theArgVec[anArgIter] << "'\n";
236         return 1;
237       }
238       aListOfShapes.Append (aShape);
239     }
240   }
241
242   if (aListOfShapes.IsEmpty())
243   {
244     Message::SendFail ("Syntax error: wrong number of arguments.");
245     return 1;
246   }
247
248   theDI << "Incremental Mesh, multi-threading "
249         << (aMeshParams.InParallel ? "ON" : "OFF") << "\n";
250
251   TopoDS_Shape aShape;
252   if (aListOfShapes.Size() == 1)
253   {
254     aShape = aListOfShapes.First();
255   }
256   else
257   {
258     TopoDS_Compound aCompound;
259     BRep_Builder().MakeCompound (aCompound);
260     for (TopoDS_ListOfShape::Iterator anIterShape (aListOfShapes); anIterShape.More(); anIterShape.Next())
261     {
262       BRep_Builder().Add (aCompound, anIterShape.Value());
263     }
264     aShape = aCompound;
265   }
266
267   if (isPrsDefl)
268   {
269     Handle(Prs3d_Drawer) aDrawer = new Prs3d_Drawer();
270     if (hasDefl)
271     {
272       aDrawer->SetDeviationCoefficient (aMeshParams.Deflection);
273     }
274     aMeshParams.Deflection = StdPrs_ToolTriangulatedShape::GetDeflection (aShape, aDrawer);
275     if (!hasAngDefl)
276     {
277       aMeshParams.Angle = aDrawer->DeviationAngle();
278     }
279   }
280
281   Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator (theDI, 1);
282   BRepMesh_IncrementalMesh aMesher;
283   aMesher.SetShape (aShape);
284   aMesher.ChangeParameters() = aMeshParams;
285   aMesher.Perform (aContext, aProgress->Start());
286
287   theDI << "Meshing statuses: ";
288   const Standard_Integer aStatus = aMesher.GetStatusFlags();
289   if (aStatus == 0)
290   {
291     theDI << "NoError";
292     return 0;
293   }
294
295   for (Standard_Integer i = 0; i < 9; i++)
296   {
297     Standard_Integer aFlag = aStatus & (1 << i);
298     if (aFlag)
299     {
300       switch ((IMeshData_Status) aFlag)
301       {
302         case IMeshData_OpenWire:             theDI << "OpenWire "; break;
303         case IMeshData_SelfIntersectingWire: theDI << "SelfIntersectingWire "; break;
304         case IMeshData_Failure:              theDI << "Failure "; break;
305         case IMeshData_ReMesh:               theDI << "ReMesh "; break;
306         case IMeshData_UnorientedWire:       theDI << "UnorientedWire "; break;
307         case IMeshData_TooFewPoints:         theDI << "TooFewPoints "; break;
308         case IMeshData_Outdated:             theDI << "Outdated "; break;
309         case IMeshData_Reused:               theDI << "Reused "; break;
310         case IMeshData_UserBreak:            theDI << "UserBreak "; break;
311         case IMeshData_NoError: break;
312       }
313     }
314   }
315   return 0;
316 }
317
318 //=======================================================================
319 //function : tessellate
320 //purpose  : 
321 //=======================================================================
322 static Standard_Integer tessellate (Draw_Interpretor& /*di*/, Standard_Integer nbarg, const char** argv)
323 {
324   if (nbarg != 5)
325   {
326     Message::SendFail() << "Builds regular triangulation with specified number of triangles\n"
327                  "    Usage: tessellate result {surface|face} nbu nbv\n"
328                  "    Triangulation is put into the face with natural bounds (result);\n"
329                  "    it will have 2*nbu*nbv triangles and (nbu+1)*(nbv+1) nodes";
330     return 1;
331   }
332
333   const char *aResName = argv[1];
334   const char *aSrcName = argv[2];
335   int aNbU = Draw::Atoi (argv[3]);
336   int aNbV = Draw::Atoi (argv[4]);
337
338   if (aNbU <= 0 || aNbV <= 0)
339   {
340     Message::SendFail() << "Error: Arguments nbu and nbv must be both greater than 0";
341     return 1;
342   }
343
344   Handle(Geom_Surface) aSurf = DrawTrSurf::GetSurface(aSrcName);
345   double aUMin, aUMax, aVMin, aVMax;
346   if (! aSurf.IsNull())
347   {
348     aSurf->Bounds (aUMin, aUMax, aVMin, aVMax);
349   }
350   else
351   {
352     TopoDS_Shape aShape = DBRep::Get(aSrcName);
353     if (aShape.IsNull() || aShape.ShapeType() != TopAbs_FACE)
354     {
355       Message::SendFail() << "Error: " << aSrcName << " is not a face";
356       return 1;
357     }
358     TopoDS_Face aFace = TopoDS::Face (aShape);
359     aSurf = BRep_Tool::Surface (aFace);
360     if (aSurf.IsNull())
361     {
362       Message::SendFail() << "Error: Face " << aSrcName << " has no surface";
363       return 1;
364     }
365
366     BRepTools::UVBounds (aFace, aUMin, aUMax, aVMin, aVMax);
367   }
368   if (Precision::IsInfinite (aUMin) || Precision::IsInfinite (aUMax) || 
369       Precision::IsInfinite (aVMin) || Precision::IsInfinite (aVMax))
370   {
371     Message::SendFail() << "Error: surface has infinite parametric range, aborting";
372     return 1;
373   }
374
375   BRepBuilderAPI_MakeFace aFaceMaker (aSurf, aUMin, aUMax, aVMin, aVMax, Precision::Confusion());
376   if (! aFaceMaker.IsDone())
377   {
378     Message::SendFail() << "Error: cannot build face with natural bounds, aborting";
379     return 1;
380   }
381   TopoDS_Face aFace = aFaceMaker;
382
383   // create triangulation
384   int aNbNodes = (aNbU + 1) * (aNbV + 1);
385   int aNbTriangles = 2 * aNbU * aNbV;
386   Handle(Poly_Triangulation) aTriangulation =
387     new Poly_Triangulation (aNbNodes, aNbTriangles, Standard_False);
388
389   // fill nodes
390   GeomAdaptor_Surface anAdSurf (aSurf);
391   double aDU = (aUMax - aUMin) / aNbU;
392   double aDV = (aVMax - aVMin) / aNbV;
393   for (int iU = 0, iShift = 1; iU <= aNbU; iU++, iShift += aNbV + 1)
394   {
395     double aU = aUMin + iU * aDU;
396     for (int iV = 0; iV <= aNbV; iV++)
397     {
398       double aV = aVMin + iV * aDV;
399       gp_Pnt aP = anAdSurf.Value (aU, aV);
400       aTriangulation->SetNode (iShift + iV, aP);
401     }
402   }
403
404   // fill triangles
405   for (int iU = 0, iShift = 1, iTri = 0; iU < aNbU; iU++, iShift += aNbV + 1)
406   {
407     for (int iV = 0; iV < aNbV; iV++)
408     {
409       int iBase = iShift + iV;
410       Poly_Triangle aTri1 (iBase, iBase + aNbV + 2, iBase + 1);
411       Poly_Triangle aTri2 (iBase, iBase + aNbV + 1, iBase + aNbV + 2);
412       aTriangulation->SetTriangle (++iTri, aTri1);
413       aTriangulation->SetTriangle (++iTri, aTri2);
414     }
415   }
416
417   // put triangulation to face
418   BRep_Builder B;
419   B.UpdateFace (aFace, aTriangulation);
420
421   // fill edge polygons
422   TColStd_Array1OfInteger aUMinIso (1, aNbV + 1), aUMaxIso (1, aNbV + 1);
423   for (int iV = 0; iV <= aNbV; iV++)
424   {
425     aUMinIso.SetValue (1 + iV, 1 + iV);
426     aUMaxIso.SetValue (1 + iV, 1 + iV + aNbU * (1 + aNbV));
427   }
428   TColStd_Array1OfInteger aVMinIso (1, aNbU + 1), aVMaxIso (1, aNbU + 1);
429   for (int iU = 0; iU <= aNbU; iU++)
430   {
431     aVMinIso.SetValue (1 + iU,  1 + iU  * (1 + aNbV));
432     aVMaxIso.SetValue (1 + iU, (1 + iU) * (1 + aNbV));
433   }
434   Handle(Poly_PolygonOnTriangulation) aUMinPoly = new Poly_PolygonOnTriangulation (aUMinIso);
435   Handle(Poly_PolygonOnTriangulation) aUMaxPoly = new Poly_PolygonOnTriangulation (aUMaxIso);
436   Handle(Poly_PolygonOnTriangulation) aVMinPoly = new Poly_PolygonOnTriangulation (aVMinIso);
437   Handle(Poly_PolygonOnTriangulation) aVMaxPoly = new Poly_PolygonOnTriangulation (aVMaxIso);
438   for (TopExp_Explorer exp (aFace, TopAbs_EDGE); exp.More(); exp.Next())
439   {
440     TopoDS_Edge anEdge = TopoDS::Edge (exp.Current());
441     Standard_Real aFirst, aLast;
442     Handle(Geom2d_Curve) aC = BRep_Tool::CurveOnSurface (anEdge, aFace, aFirst, aLast);
443     gp_Pnt2d aPFirst = aC->Value (aFirst);
444     gp_Pnt2d aPLast  = aC->Value (aLast);
445     if (Abs (aPFirst.X() - aPLast.X()) < 0.1 * (aUMax - aUMin)) // U=const
446     {
447       if (BRep_Tool::IsClosed (anEdge, aFace))
448         B.UpdateEdge (anEdge, aUMinPoly, aUMaxPoly, aTriangulation);
449       else
450         B.UpdateEdge (anEdge, (aPFirst.X() < 0.5 * (aUMin + aUMax) ? aUMinPoly : aUMaxPoly), aTriangulation);
451     }
452     else // V=const
453     {
454       if (BRep_Tool::IsClosed (anEdge, aFace))
455         B.UpdateEdge (anEdge, aVMinPoly, aVMaxPoly, aTriangulation);
456       else
457         B.UpdateEdge (anEdge, (aPFirst.Y() < 0.5 * (aVMin + aVMax) ? aVMinPoly : aVMaxPoly), aTriangulation);
458     }
459   }
460
461   DBRep::Set (aResName, aFace);
462   return 0;
463 }
464
465 //=======================================================================
466 //function : MemLeakTest
467 //purpose  : 
468 //=======================================================================
469 static Standard_Integer MemLeakTest(Draw_Interpretor&, Standard_Integer /*nbarg*/, const char** /*argv*/)
470 {
471   for(int i=0;i<10000;i++)
472   {
473     BRepBuilderAPI_MakePolygon w(gp_Pnt(0,0,0),gp_Pnt(0,100,0),gp_Pnt(20,100,0),gp_Pnt(20,0,0));
474     w.Close();     
475     TopoDS_Wire wireShape( w.Wire());
476     BRepBuilderAPI_MakeFace faceBuilder(wireShape);          
477     TopoDS_Face f( faceBuilder.Face());
478     BRepMesh_IncrementalMesh im(f,1);
479     BRepTools::Clean(f);      
480   }
481   return 0;
482 }
483
484 //=======================================================================
485 //function : TrLateLoad
486 //purpose  :
487 //=======================================================================
488 static Standard_Integer TrLateLoad (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
489 {
490   if (theNbArgs < 3)
491   {
492     theDI << "Syntax error: not enough arguments\n";
493     return 1;
494   }
495   TopoDS_Shape aShape = DBRep::Get (theArgVec[1]);
496   if (aShape.IsNull())
497   {
498     theDI << "Syntax error: '" << theArgVec[1] << "' is not a shape\n";
499     return 1;
500   }
501   for (Standard_Integer anArgIter = 2; anArgIter < theNbArgs; ++anArgIter)
502   {
503     TCollection_AsciiString anArgCase(theArgVec[anArgIter]);
504     anArgCase.LowerCase();
505     if (anArgCase == "-load")
506     {
507       if (anArgIter + 1 < theNbArgs)
508       {
509         TCollection_AsciiString aLoadArg(theArgVec[anArgIter + 1]);
510         aLoadArg.LowerCase();
511         if (aLoadArg == "all"
512          || aLoadArg == "*")
513         {
514           // Load all triangulations
515           anArgIter++;
516           if (BRepTools::LoadAllTriangulations (aShape))
517           {
518             theDI << "All triangulations of shape " << theArgVec[1] << " were loaded\n";
519           }
520           continue;
521         }
522         if (aLoadArg.IsIntegerValue())
523         {
524           // Load defined triangulation
525           anArgIter++;
526           Standard_Integer anIndexToLoad = aLoadArg.IntegerValue();
527           if (anIndexToLoad < -1)
528           {
529             Message::SendWarning ("Invalid negative triangulation index to be loaded");
530             continue;
531           }
532           if (BRepTools::LoadTriangulation (aShape, anIndexToLoad))
533           {
534             theDI << "The " << anIndexToLoad << " triangulation of shape " << theArgVec[1] << " was loaded\n";
535           }
536           continue;
537         }
538       }
539       // Load active triangulation
540       if (BRepTools::LoadTriangulation (aShape))
541       {
542         theDI << "The active triangulation of shape " << theArgVec[1] << " was loaded\n";
543       }
544       continue;
545     }
546     else if (anArgCase == "-unload")
547     {
548       if (anArgIter + 1 < theNbArgs)
549       {
550         TCollection_AsciiString anUnloadArg(theArgVec[anArgIter + 1]);
551         anUnloadArg.LowerCase();
552         if (anUnloadArg == "all"
553          || anUnloadArg == "*")
554         {
555           // Unload all triangulations
556           anArgIter++;
557           if (BRepTools::UnloadAllTriangulations (aShape))
558           {
559             theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
560           }
561           continue;
562         }
563         if (anUnloadArg.IsIntegerValue())
564         {
565           // Unload defined triangulation
566           anArgIter++;
567           Standard_Integer anIndexToUnload = anUnloadArg.IntegerValue();
568           if (anIndexToUnload < -1)
569           {
570             Message::SendWarning ("Invalid negative triangulation index to be unloaded");
571             continue;
572           }
573           if (BRepTools::UnloadTriangulation (aShape, anIndexToUnload))
574           {
575             theDI << "The " << anIndexToUnload << " triangulation of shape " << theArgVec[1] << " was unloaded\n";
576           }
577           continue;
578         }
579       }
580       // Unload active triangulation
581       if (BRepTools::UnloadTriangulation (aShape))
582       {
583         theDI << "The active triangulation of shape " << theArgVec[1] << " was unloaded\n";
584       }
585       continue;
586     }
587     else if (anArgIter + 1 < theNbArgs
588           && anArgCase == "-activate"
589           && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
590     {
591       Standard_Integer anIndexToActivate = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
592       if (anIndexToActivate < 0)
593       {
594         Message::SendWarning ("Invalid negative triangulation index to be activated");
595         continue;
596       }
597       if (BRepTools::ActivateTriangulation (aShape, anIndexToActivate, false))
598       {
599         theDI << "The " << anIndexToActivate << " triangulation of shape " << theArgVec[1] << " was activated\n";
600       }
601     }
602     else if (anArgIter + 1 < theNbArgs
603           && (anArgCase == "-activatestrict" || anArgCase == "-activateexact")
604           && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
605     {
606       Standard_Integer anIndexToActivate = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
607       if (anIndexToActivate < 0)
608       {
609         Message::SendWarning ("Invalid negative triangulation index to be activated");
610         continue;
611       }
612       if (BRepTools::ActivateTriangulation (aShape, anIndexToActivate, true))
613       {
614         theDI << "The " << anIndexToActivate << " triangulation of shape " << theArgVec[1] << " was activated\n";
615       }
616     }
617     else if (anArgCase == "-loadsingle")
618     {
619       Standard_Integer anIndexToSingleLoad = -1;
620       if (anArgIter + 1 < theNbArgs
621        && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
622       {
623         anIndexToSingleLoad = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
624       }
625       if (anIndexToSingleLoad < -1)
626       {
627         Message::SendWarning ("Invalid negative triangulation index to be single loaded");
628         continue;
629       }
630       // Unload all triangulations
631       if (BRepTools::UnloadAllTriangulations (aShape))
632       {
633         theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
634       }
635       // Activate required triangulation
636       if (anIndexToSingleLoad > -1
637        && BRepTools::ActivateTriangulation (aShape, anIndexToSingleLoad))
638       {
639         theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was activated\n";
640       }
641       // Load active triangulation
642       if (BRepTools::LoadTriangulation (aShape))
643       {
644         theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was loaded\n";
645       }
646
647       continue;
648     }
649     else if (anArgCase == "-loadsingleexact" ||
650              anArgCase == "-loadsinglestrict")
651     {
652       Standard_Integer anIndexToSingleLoad = -1;
653       if (anArgIter + 1 < theNbArgs
654        && TCollection_AsciiString(theArgVec[anArgIter + 1]).IsIntegerValue())
655       {
656         anIndexToSingleLoad = TCollection_AsciiString(theArgVec[++anArgIter]).IntegerValue();
657       }
658       if (anIndexToSingleLoad <= -1)
659       {
660         Message::SendWarning ("Invalid negative triangulation index to be single loaded");
661         continue;
662       }
663       // Unload all triangulations
664       if (BRepTools::UnloadAllTriangulations (aShape))
665       {
666         theDI << "All triangulations of shape " << theArgVec[1] << " were unloaded\n";
667       }
668       // Load required triangulation
669       if (BRepTools::LoadTriangulation (aShape, anIndexToSingleLoad, true))
670       {
671         theDI << "The " << anIndexToSingleLoad << " triangulation of shape " << theArgVec[1] << " was loaded and activated\n";
672       }
673       continue;
674     }
675     else
676     {
677       theDI << "Syntax error: incorrect arguments";
678       return 1;
679     }
680   }
681   return 0;
682 }
683
684 //=======================================================================
685 //function : trianglesinfo
686 //purpose  : 
687 //=======================================================================
688 static Standard_Integer trianglesinfo (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
689 {
690   if (theNbArgs < 2)
691   {
692     Message::SendFail ("Syntax error: not enough arguments");
693     return 1;
694   }
695   TopoDS_Shape aShape = DBRep::Get (theArgVec[1]);
696   if (aShape.IsNull())
697   {
698     theDI << theArgVec[1] << " is not a shape\n";
699     return 1;
700   }
701
702   struct TriangulationStat
703   {
704     TriangulationStat()
705     : NbFaces (0),
706       NbEmptyFaces (0),
707       NbTriangles(0),
708       NbDeferredFaces (0),
709       NbUnloadedFaces (0),
710       NbUnloadedTriangles (0) {}
711
712     NCollection_IndexedDataMap<Handle(Standard_Type), Standard_Integer> TypeMap;
713     Standard_Integer NbFaces;
714     Standard_Integer NbEmptyFaces;
715     Standard_Integer NbTriangles;
716     Standard_Integer NbDeferredFaces;
717     Standard_Integer NbUnloadedFaces;
718     Standard_Integer NbUnloadedTriangles;
719   };
720
721   Standard_Boolean toPrintLODs = false;
722   if (theNbArgs > 2)
723   {
724     TCollection_AsciiString anArgCase(theArgVec[2]);
725     anArgCase.LowerCase();
726     if (anArgCase == "-lods")
727     {
728       toPrintLODs = true;
729     }
730   }
731
732   TopExp_Explorer anExp;
733   Handle(Poly_Triangulation) aTriangulation;
734   TopLoc_Location aLoc;
735   Standard_Real aMaxDeflection = 0.0, aMeshingDefl = -1.0, aMeshingAngDefl = -1.0, aMeshingMinSize = -1.0;
736   Standard_Integer aNbFaces = 0, aNbEmptyFaces = 0, aNbTriangles = 0, aNbNodes = 0, aNbRepresentations = 0;
737   NCollection_IndexedDataMap<Standard_Integer, TriangulationStat> aLODsStat;
738   NCollection_Vector<Standard_Integer> aNbLODs;
739   for (anExp.Init (aShape, TopAbs_FACE); anExp.More(); anExp.Next())
740   {
741     TopoDS_Face aFace = TopoDS::Face (anExp.Current());
742     aNbFaces++;
743     aTriangulation = BRep_Tool::Triangulation (aFace, aLoc);
744     if (!aTriangulation.IsNull())
745     {
746       aNbTriangles += aTriangulation->NbTriangles();
747       aNbNodes += aTriangulation->NbNodes();
748       aMaxDeflection = Max (aMaxDeflection, aTriangulation->Deflection());
749       if (!aTriangulation->Parameters().IsNull())
750       {
751         aMeshingDefl    = Max (aMeshingDefl,    aTriangulation->Parameters()->Deflection());
752         aMeshingAngDefl = Max (aMeshingAngDefl, aTriangulation->Parameters()->Angle());
753         aMeshingMinSize = Max (aMeshingMinSize, aTriangulation->Parameters()->MinSize());
754       }
755     }
756     else
757     {
758       aNbEmptyFaces++;
759     }
760     if (toPrintLODs)
761     {
762       // Collect LODs information
763       const Poly_ListOfTriangulation& aLODs = BRep_Tool::Triangulations (aFace, aLoc);
764       if (aLODs.Size() != 0)
765       {
766         aNbLODs.Append (aLODs.Size());
767       }
768       Standard_Integer aTriangIndex = 0;
769       for (Poly_ListOfTriangulation::Iterator anIter(aLODs); anIter.More(); anIter.Next(), ++aTriangIndex)
770       {
771         TriangulationStat* aStats = aLODsStat.ChangeSeek (aTriangIndex);
772         if (aStats == NULL)
773         {
774           Standard_Integer aNewIndex = aLODsStat.Add (aTriangIndex, TriangulationStat());
775           aStats = &aLODsStat.ChangeFromIndex (aNewIndex);
776         }
777         aStats->NbFaces++;
778         const Handle(Poly_Triangulation)& aLOD = anIter.Value();
779         if (aLOD.IsNull())
780         {
781           aStats->NbEmptyFaces++;
782           continue;
783         }
784         Standard_Integer* aDynTypeCounter = aStats->TypeMap.ChangeSeek (aLOD->DynamicType());
785         if (aDynTypeCounter == NULL)
786         {
787           Standard_Integer aNewIndex = aStats->TypeMap.Add (aLOD->DynamicType(), 0);
788           aDynTypeCounter = &aStats->TypeMap.ChangeFromIndex (aNewIndex);
789         }
790         (*aDynTypeCounter)++;
791         if (aLOD->HasDeferredData())
792         {
793           aStats->NbDeferredFaces++;
794           if (aLOD->HasGeometry())
795           {
796             aStats->NbTriangles += aLOD->NbTriangles();
797           }
798           else
799           {
800             aStats->NbUnloadedFaces++;
801             aStats->NbTriangles += aLOD->NbDeferredTriangles();
802             aStats->NbUnloadedTriangles += aLOD->NbDeferredTriangles();
803           }
804         }
805         else
806         {
807           if (aLOD->HasGeometry())
808           {
809             aStats->NbTriangles += aLOD->NbTriangles();
810           }
811           else
812           {
813             aStats->NbEmptyFaces++;
814           }
815         }
816       }
817     }
818   }
819   TopTools_IndexedMapOfShape anEdges;
820   TopExp::MapShapes (aShape, TopAbs_EDGE, anEdges);
821   for (int i = 1; i<=anEdges.Extent(); ++i)
822   {
823     const TopoDS_Edge& anEdge = TopoDS::Edge(anEdges(i));
824     Handle(BRep_CurveRepresentation) aCR;
825     BRep_TEdge* aTE = static_cast<BRep_TEdge*>(anEdge.TShape().get());
826     const BRep_ListOfCurveRepresentation& aLCR = aTE->Curves();
827     BRep_ListIteratorOfListOfCurveRepresentation anIterCR(aLCR);
828
829     while (anIterCR.More()) {
830       aCR = anIterCR.Value();
831       if (aCR->IsPolygonOnTriangulation())
832       {
833         aNbRepresentations++;
834       }
835       anIterCR.Next();
836     }
837   }
838
839   theDI <<"\n";
840   theDI << "This shape contains " << aNbFaces << " faces.\n";
841   if (aNbEmptyFaces > 0)
842   {
843     theDI << "                    " << aNbEmptyFaces << " empty faces.\n";
844   }
845   theDI << "                    " << aNbTriangles << " triangles.\n";
846   theDI << "                    " << aNbNodes << " nodes.\n";
847   theDI << "                    " << aNbRepresentations << " polygons on triangulation.\n";
848   theDI << "Maximal deflection " << aMaxDeflection << "\n";
849   if (aMeshingDefl > 0.0)
850   {
851     theDI << "Meshing deflection " << aMeshingDefl << "\n";
852   }
853   if (aMeshingAngDefl > 0.0)
854   {
855     theDI << "Meshing angular deflection " << (aMeshingAngDefl * 180.0 / M_PI) << "\n";
856   }
857   if (aMeshingMinSize > 0.0)
858   {
859     theDI << "Meshing min size " << aMeshingMinSize << "\n";
860   }
861
862   if (aNbLODs.Size() > 0)
863   {
864     // Find all different numbers of triangulation LODs and their average value per face
865     if (aNbLODs.Size() > 1)
866     {
867       std::sort (aNbLODs.begin(), aNbLODs.end());
868     }
869     NCollection_IndexedMap<Standard_Integer> aLODsRange;
870     for (NCollection_Vector<Standard_Integer>::Iterator aNbIter(aNbLODs); aNbIter.More(); aNbIter.Next())
871     {
872       if (!aLODsRange.Contains (aNbIter.Value()))
873       {
874         aLODsRange.Add (aNbIter.Value());
875       }
876     }
877     TCollection_AsciiString aLODsRangeStr;
878     Standard_Integer anIndex = 0;
879     for (NCollection_IndexedMap<Standard_Integer>::Iterator aRangeIter(aLODsRange); aRangeIter.More(); aRangeIter.Next(), anIndex++)
880     {
881       aLODsRangeStr += TCollection_AsciiString(aRangeIter.Value());
882       if (anIndex < aLODsRange.Size() - 1)
883       {
884         aLODsRangeStr += " ";
885       }
886     }
887     theDI << TCollection_AsciiString("Number of triangulation LODs [") + aLODsRangeStr + "]\n";
888     if (aLODsRange.Size() > 1)
889     {
890       // Find average number of triangulation LODs per face
891       Standard_Integer aMedian = aNbLODs.Value (aNbLODs.Lower() + aNbLODs.Size() / 2);
892       if ((aNbLODs.Size() % 2) == 0)
893       {
894         aMedian += aNbLODs.Value (aNbLODs.Lower() + aNbLODs.Size() / 2 - 1);
895         aMedian /= 2;
896       }
897       theDI << TCollection_AsciiString("                             [average per face: ") + aMedian + "]\n";
898     }
899   }
900   if (!aLODsStat.IsEmpty())
901   {
902     TCollection_AsciiString aLODsStatStr;
903     for (NCollection_IndexedDataMap<Standard_Integer, TriangulationStat>::Iterator anIter(aLODsStat);
904          anIter.More(); anIter.Next())
905     {
906       const TriangulationStat& aLodStat = anIter.Value();
907       aLODsStatStr += TCollection_AsciiString("LOD #") + anIter.Key() + ". ";
908       //aLODsStatStr += TCollection_AsciiString("NbFaces: ") + aLodStat.NbFaces;
909       if (aLodStat.NbEmptyFaces > 0 || aLodStat.NbFaces < aNbFaces)
910       {
911         const Standard_Integer aNbEmpty = aLodStat.NbEmptyFaces + (aNbFaces - aLodStat.NbFaces);
912         aLODsStatStr += TCollection_AsciiString("NbEmpty: ") + aNbEmpty + ", ";
913       }
914       aLODsStatStr += TCollection_AsciiString("NbTris: ") + aLodStat.NbTriangles;
915       if (aLodStat.NbDeferredFaces > 0)
916       {
917         aLODsStatStr += TCollection_AsciiString(", NbDeferred: ") + aLodStat.NbDeferredFaces;
918         if (aLodStat.NbUnloadedFaces > 0)
919         {
920           aLODsStatStr += TCollection_AsciiString(", NbUnloaded: ") + aLodStat.NbUnloadedFaces + ", NbUnloadedTris: " + aLodStat.NbUnloadedTriangles;
921         }
922       }
923       aLODsStatStr += ".\n";
924
925       // Add types
926       aLODsStatStr += TCollection_AsciiString("        Types: ");
927       Standard_Integer aCounter = 0;
928       for (NCollection_IndexedDataMap<Handle(Standard_Type), Standard_Integer>::Iterator aTypeIter(aLodStat.TypeMap);
929            aTypeIter.More(); aTypeIter.Next(), aCounter++)
930       {
931         aLODsStatStr += TCollection_AsciiString(aTypeIter.Key()->Name()) + " (" + aTypeIter.Value() + ")";
932         if (aCounter < aLodStat.TypeMap.Size() - 1)
933         {
934           aLODsStatStr += TCollection_AsciiString(", ");
935         }
936       }
937       aLODsStatStr += ".\n";
938     }
939
940     theDI << aLODsStatStr;
941   }
942   theDI << "\n";
943
944 #ifdef OCCT_DEBUG_MESH_CHRONO
945   Standard_Real tot, addp, unif, contr, inter;
946   Standard_Real edges, mailledges, etuinter, lastcontrol, stock;
947   Standard_Real add11, add12, add2, upda, pointvalid;
948   Standard_Real isos, pointsisos;
949   chTotal.Show(tot); chAddPoint.Show(addp); chUnif.Show(unif); 
950   chControl.Show(contr); chInternal.Show(inter);
951   chEdges.Show(edges); chMaillEdges.Show(mailledges);
952   chEtuInter.Show(etuinter); chLastControl.Show(lastcontrol); 
953   chStock.Show(stock);
954   chAdd11.Show(add11); chAdd12.Show(add12); chAdd2.Show(add2); chUpdate.Show(upda);
955   chPointValid.Show(pointvalid); chIsos.Show(isos); chPointsOnIsos.Show(pointsisos);
956
957   if (tot > 0.00001) {
958     theDI <<"temps total de maillage:     "<<tot        <<" seconds\n";
959     theDI <<"dont: \n";
960     theDI <<"discretisation des edges:    "<<edges      <<" seconds---> "<< 100*edges/tot      <<" %\n";
961     theDI <<"maillage des edges:          "<<mailledges <<" seconds---> "<< 100*mailledges/tot <<" %\n";
962     theDI <<"controle et points internes: "<<etuinter   <<" seconds---> "<< 100*etuinter/tot   <<" %\n";
963     theDI <<"derniers controles:          "<<lastcontrol<<" seconds---> "<< 100*lastcontrol/tot<<" %\n";
964     theDI <<"stockage dans la S.D.        "<<stock      <<" seconds---> "<< 100*stock/tot      <<" %\n";
965     theDI << "\n";
966     theDI <<"et plus precisement: \n";
967     theDI <<"Add 11ere partie :           "<<add11     <<" seconds---> "<<100*add11/tot      <<" %\n";
968     theDI <<"Add 12ere partie :           "<<add12     <<" seconds---> "<<100*add12/tot      <<" %\n";
969     theDI <<"Add 2eme partie :            "<<add2      <<" seconds---> "<<100*add2/tot       <<" %\n";
970     theDI <<"Update :                     "<<upda      <<" seconds---> "<<100*upda/tot       <<" %\n";
971     theDI <<"AddPoint :                   "<<addp      <<" seconds---> "<<100*addp/tot       <<" %\n";
972     theDI <<"UniformDeflection            "<<unif      <<" seconds---> "<<100*unif/tot       <<" %\n";
973     theDI <<"Controle :                   "<<contr     <<" seconds---> "<<100*contr/tot      <<" %\n";
974     theDI <<"Points Internes:             "<<inter     <<" seconds---> "<<100*inter/tot      <<" %\n";
975     theDI <<"calcul des isos et du, dv:   "<<isos      <<" seconds---> "<<100*isos/tot       <<" %\n";
976     theDI <<"calcul des points sur isos:  "<<pointsisos<<" seconds---> "<<100*pointsisos/tot <<" %\n";
977     theDI <<"IsPointValid:                "<<pointvalid<<" seconds---> "<<100*pointvalid/tot <<" %\n";
978     theDI << "\n";
979
980
981     theDI <<"nombre d'appels de controle apres points internes          : "<< NbControls << "\n";
982     theDI <<"nombre de points sur restrictions                          : "<< D0Edges    << "\n";
983     theDI <<"nombre de points calcules par UniformDeflection            : "<< D0Unif     << "\n";
984     theDI <<"nombre de points calcules dans InternalVertices            : "<< D0Internal << "\n";
985     theDI <<"nombre de points calcules dans Control                     : "<< D0Control  << "\n";
986     if (nbnodes-D0Edges != 0) { 
987       Standard_Real ratio = (Standard_Real)(D0Internal+D0Control)/ (Standard_Real)(nbnodes-D0Edges);
988       theDI <<"---> Ratio: (D0Internal+D0Control) / (nbNodes-nbOnEdges)   : "<< ratio      << "\n";
989     }
990
991     theDI << "\n";
992
993     chTotal.Reset(); chAddPoint.Reset(); chUnif.Reset(); 
994     chControl.Reset(); chInternal.Reset();
995     chEdges.Reset(); chMaillEdges.Reset();
996     chEtuInter.Reset(); chLastControl.Reset(); 
997     chStock.Reset();
998     chAdd11.Reset(); chAdd12.Reset(); chAdd2.Reset(); chUpdate.Reset();
999     chPointValid.Reset(); chIsos.Reset(); chPointsOnIsos.Reset();
1000
1001   }
1002 #endif
1003   return 0;
1004 }
1005
1006 //=======================================================================
1007 //function : veriftriangles
1008 //purpose  : 
1009 //=======================================================================
1010 static Standard_Integer veriftriangles(Draw_Interpretor& di, Standard_Integer n, const char** a)
1011 {
1012   if (n < 2) return 1;
1013   Standard_Boolean quiet = 1;
1014   if (n == 3) quiet = 0;
1015   TopoDS_Shape Sh = DBRep::Get(a[1]);
1016   if (Sh.IsNull()) return 1;
1017   TopExp_Explorer ex;
1018   Handle(Poly_Triangulation) T;
1019   TopLoc_Location L;
1020   Standard_Integer i, n1, n2, n3;
1021   gp_Pnt2d mitri, v1, v2, v3, mi2d1, mi2d2, mi2d3;
1022   gp_XYZ vecEd1, vecEd2, vecEd3;
1023   //  Standard_Real dipo, dm, dv, d1, d2, d3, defle;
1024   Standard_Real dipo, dv, d1, d2, d3, defle;
1025   Handle(Geom_Surface) S;
1026   Standard_Integer nbface = 0;
1027   gp_Pnt PP;
1028
1029   for (ex.Init(Sh, TopAbs_FACE); ex.More(); ex.Next()) {
1030     TopoDS_Face F = TopoDS::Face(ex.Current());
1031     nbface++;
1032     T = BRep_Tool::Triangulation(F, L);
1033     Standard_Real deflemax = 0, deflemin = 1.e100;
1034     if (!T.IsNull()) {
1035       Standard_Real defstock = T->Deflection();
1036
1037       S = BRep_Tool::Surface(F, L);
1038
1039       for(i = 1; i <= T->NbTriangles(); i++) {
1040         if (F.Orientation() == TopAbs_REVERSED) 
1041           T->Triangle (i).Get (n1,n3,n2);
1042         else 
1043           T->Triangle (i).Get (n1,n2,n3);
1044
1045         const gp_XY& xy1 = T->UVNode (n1).XY();
1046         const gp_XY& xy2 = T->UVNode (n2).XY();
1047         const gp_XY& xy3 = T->UVNode (n3).XY();
1048
1049         mi2d1.SetCoord((xy2.X()+xy3.X())*0.5, 
1050           (xy2.Y()+xy3.Y())*0.5);
1051         mi2d2.SetCoord((xy1.X()+xy3.X())*0.5, 
1052           (xy1.Y()+xy3.Y())*0.5);
1053         mi2d3.SetCoord((xy1.X()+xy2.X())*0.5, 
1054           (xy1.Y()+xy2.Y())*0.5);
1055
1056         gp_XYZ p1 = T->Node (n1).Transformed (L.Transformation()).XYZ();
1057         gp_XYZ p2 = T->Node (n2).Transformed (L.Transformation()).XYZ();
1058         gp_XYZ p3 = T->Node (n3).Transformed (L.Transformation()).XYZ();
1059
1060         vecEd1=p2-p1;
1061         vecEd2=p3-p2;
1062         vecEd3=p1-p3;
1063         d1=vecEd1.SquareModulus();
1064         d2=vecEd2.SquareModulus();
1065         d3=vecEd3.SquareModulus();
1066
1067         if (d1!=0. && d2!=0. && d3!=0.) {
1068           gp_XYZ equa(vecEd1^vecEd2);
1069           dv=equa.Modulus();
1070           if (dv>0.) {
1071             equa.SetCoord(equa.X()/dv, equa.Y()/dv, equa.Z()/dv);
1072             dipo=equa*p1;
1073
1074
1075             mitri.SetCoord(ONETHIRD*(xy1.X()+xy2.X()+xy3.X()),
1076               ONETHIRD*(xy1.Y()+xy2.Y()+xy3.Y()));
1077             v1.SetCoord(ONETHIRD*mi2d1.X()+TWOTHIRD*xy1.X(), 
1078               ONETHIRD*mi2d1.Y()+TWOTHIRD*xy1.Y());
1079             v2.SetCoord(ONETHIRD*mi2d2.X()+TWOTHIRD*xy2.X(), 
1080               ONETHIRD*mi2d2.Y()+TWOTHIRD*xy2.Y());
1081             v3.SetCoord(ONETHIRD*mi2d3.X()+TWOTHIRD*xy3.X(), 
1082               ONETHIRD*mi2d3.Y()+TWOTHIRD*xy3.Y());
1083
1084             S->D0(mi2d1.X(), mi2d1.Y(), PP);
1085             PP = PP.Transformed(L.Transformation());
1086             defle = Abs((equa*PP.XYZ())-dipo);
1087             deflemax = Max(deflemax, defle);
1088             deflemin = Min(deflemin, defle);
1089
1090             S->D0(mi2d2.X(), mi2d2.Y(), PP);
1091             PP = PP.Transformed(L.Transformation());
1092             defle = Abs((equa*PP.XYZ())-dipo);
1093             deflemax = Max(deflemax, defle);
1094             deflemin = Min(deflemin, defle);
1095
1096             S->D0(mi2d3.X(), mi2d3.Y(), PP);
1097             PP = PP.Transformed(L.Transformation());
1098             defle = Abs((equa*PP.XYZ())-dipo);
1099             deflemax = Max(deflemax, defle);
1100             deflemin = Min(deflemin, defle);
1101
1102             S->D0(v1.X(), v1.Y(), PP);
1103             PP = PP.Transformed(L.Transformation());
1104             defle = Abs((equa*PP.XYZ())-dipo);
1105             deflemax = Max(deflemax, defle);
1106             deflemin = Min(deflemin, defle);
1107
1108             S->D0(v2.X(), v2.Y(), PP);
1109             PP = PP.Transformed(L.Transformation());
1110             defle = Abs((equa*PP.XYZ())-dipo);
1111             deflemax = Max(deflemax, defle);
1112             deflemin = Min(deflemin, defle);
1113
1114             S->D0(v3.X(), v3.Y(), PP);
1115             PP = PP.Transformed(L.Transformation());
1116             defle = Abs((equa*PP.XYZ())-dipo);
1117             deflemax = Max(deflemax, defle);
1118             deflemin = Min(deflemin, defle);
1119
1120             S->D0(mitri.X(), mitri.Y(), PP);
1121             PP = PP.Transformed(L.Transformation());
1122             defle = Abs((equa*PP.XYZ())-dipo);
1123             deflemax = Max(deflemax, defle);
1124             deflemin = Min(deflemin, defle);
1125
1126             if (defle > defstock) {
1127               di <<"face "<< nbface <<" deflection = " << defle <<" pour "<<defstock <<" stockee.\n";
1128             }
1129           }
1130         }
1131       }
1132       if (!quiet) {
1133         di <<"face "<< nbface<<", deflemin = "<< deflemin<<", deflemax = "<<deflemax<<"\n";
1134       }
1135
1136     }
1137   }
1138
1139
1140   return 0;
1141 }
1142
1143 //=======================================================================
1144 //function : tri2d
1145 //purpose  : 
1146 //=======================================================================
1147 static Standard_Integer tri2d(Draw_Interpretor&, Standard_Integer n, const char** a)
1148 {
1149
1150   if (n != 2) return 1;
1151   TopoDS_Shape aLocalShape = DBRep::Get(a[1]);
1152   TopoDS_Face F = TopoDS::Face(aLocalShape);
1153   //  TopoDS_Face F = TopoDS::Face(DBRep::Get(a[1]));
1154   if (F.IsNull()) return 1;
1155   Handle(Poly_Triangulation) T;
1156   TopLoc_Location L;
1157
1158   T = BRep_Tool::Triangulation(F, L);
1159   if (!T.IsNull()) {
1160     // Build the connect tool
1161     Poly_Connect pc(T);
1162
1163     Standard_Integer i,j, nFree, nInternal, nbTriangles = T->NbTriangles();
1164     Standard_Integer t[3];
1165
1166     // count the free edges
1167     nFree = 0;
1168     for (i = 1; i <= nbTriangles; i++) {
1169       pc.Triangles(i,t[0],t[1],t[2]);
1170       for (j = 0; j < 3; j++)
1171         if (t[j] == 0) nFree++;
1172     }
1173
1174     // allocate the arrays
1175     TColStd_Array1OfInteger Free(1,2*nFree);
1176     nInternal = (3*nbTriangles - nFree) / 2;
1177     TColStd_Array1OfInteger Internal(0,2*nInternal);
1178
1179     Standard_Integer fr = 1, in = 1;
1180     Standard_Integer nodes[3];
1181     for (i = 1; i <= nbTriangles; i++) {
1182       pc.Triangles(i,t[0],t[1],t[2]);
1183       T->Triangle (i).Get (nodes[0],nodes[1],nodes[2]);
1184       for (j = 0; j < 3; j++) {
1185         Standard_Integer k = (j+1) % 3;
1186         if (t[j] == 0) {
1187           Free(fr)   = nodes[j];
1188           Free(fr+1) = nodes[k];
1189           fr += 2;
1190         }
1191         // internal edge if this triangle has a lower index than the adjacent
1192         else if (i < t[j]) {
1193           Internal(in)   = nodes[j];
1194           Internal(in+1) = nodes[k];
1195           in += 2;
1196         }
1197       }
1198     }
1199
1200     // Display the edges
1201     if (T->HasUVNodes()) {
1202       Handle(Draw_Segment2D) Seg;
1203
1204       // free edges
1205       Standard_Integer nn;
1206       nn = Free.Length() / 2;
1207       for (i = 1; i <= nn; i++) {
1208         Seg = new Draw_Segment2D (T->UVNode (Free[2*i-1]),
1209                                   T->UVNode (Free[2*i]),
1210                                   Draw_rouge);
1211         dout << Seg;
1212       }
1213
1214       // internal edges
1215
1216       nn = nInternal;
1217       for (i = 1; i <= nn; i++) {
1218         Seg = new Draw_Segment2D (T->UVNode (Internal[2*i-1]),
1219                                   T->UVNode (Internal[2*i]),
1220                                   Draw_bleu);
1221         dout << Seg;
1222       }
1223     }
1224     dout.Flush();
1225   }
1226
1227   return 0;
1228 }
1229
1230 //=======================================================================
1231 //function : wavefront
1232 //purpose  : 
1233 //=======================================================================
1234 static Standard_Integer wavefront(Draw_Interpretor&, Standard_Integer nbarg, const char** argv)
1235 {
1236   if (nbarg < 2) return 1;
1237
1238   TopoDS_Shape S = DBRep::Get(argv[1]);
1239   if (S.IsNull()) return 1;
1240
1241   // creation du maillage s'il n'existe pas.
1242
1243   Bnd_Box B;
1244   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
1245   BRepBndLib::Add(S, B);
1246   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
1247   Standard_Real aDeflection = 
1248     MAX3( aXmax-aXmin , aYmax-aYmin , aZmax-aZmin) * 0.004;
1249
1250   BRepMesh_IncrementalMesh aMesh (S, aDeflection);
1251
1252
1253   TopLoc_Location L;
1254   TopExp_Explorer ex;
1255
1256   Standard_Integer i, nbface = 0;
1257   Standard_Boolean OK = Standard_True;
1258   gp_Vec D1U,D1V;
1259   gp_Vec D2U,D2V,D2UV;
1260   gp_Dir Nor;
1261   gp_Pnt P;
1262   Standard_Real U, V;
1263   CSLib_DerivativeStatus aStatus;
1264   CSLib_NormalStatus NStat;
1265   Standard_Real x, y, z;
1266   Standard_Integer n1, n2, n3;
1267   Standard_Integer k1, k2, k3;
1268
1269   TCollection_AsciiString  aFile;
1270
1271   if (nbarg == 3) {
1272     aFile = argv[2];
1273     aFile += ".obj";
1274   }
1275   else  aFile = "wave.obj";
1276   FILE* outfile = OSD_OpenFile(aFile.ToCString(), "w");
1277
1278
1279   fprintf(outfile, "%s  %s\n%s %s\n\n", "# CASCADE   ","MATRA DATAVISION", "#", aFile.ToCString());
1280
1281   Standard_Integer nbNodes, totalnodes = 0, nbpolygons = 0;
1282   for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next()) {
1283     nbface++;
1284     TopoDS_Face F = TopoDS::Face(ex.Current());
1285     Handle(Poly_Triangulation) Tr = BRep_Tool::Triangulation(F, L);
1286
1287     if (!Tr.IsNull()) {
1288       nbNodes = Tr->NbNodes();
1289
1290       // les noeuds.
1291       for (i = 1; i <= nbNodes; i++) {
1292         gp_Pnt Pnt = Tr->Node (i).Transformed (L.Transformation());
1293         x = Pnt.X();
1294         y = Pnt.Y();
1295         z = Pnt.Z();
1296         fprintf(outfile, "%s      %f  %f  %f\n", "v", x, y, z);
1297       }
1298
1299       fprintf(outfile, "\n%s    %d\n\n", "# number of vertex", nbNodes);
1300
1301
1302       // les normales.
1303
1304       if (Tr->HasUVNodes()) {
1305         BRepAdaptor_Surface BS(F, Standard_False);
1306
1307         for (i = 1; i <= nbNodes; i++) {
1308           U = Tr->UVNode (i).X();
1309           V = Tr->UVNode (i).Y();
1310
1311           BS.D1(U,V,P,D1U,D1V);
1312           CSLib::Normal (D1U, D1V, Precision::Angular(), aStatus, Nor);
1313           if (aStatus != CSLib_Done) {
1314             BS.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
1315             CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,Nor);
1316           }
1317           if (F.Orientation() == TopAbs_REVERSED) Nor.Reverse();
1318
1319           fprintf(outfile, "%s      %f  %f  %f\n", "vn", Nor.X(), Nor.Y(), Nor.Z());
1320         }
1321
1322         fprintf(outfile, "\n%s    %d\n\n", "# number of vertex normals", nbNodes);
1323       }
1324
1325       fprintf(outfile, "%s    %d\n", "s", nbface);
1326
1327       // les triangles.
1328       Standard_Integer nbTriangles = Tr->NbTriangles();
1329
1330       for (i = 1; i <= nbTriangles; i++) {
1331         if (F.Orientation()  == TopAbs_REVERSED)
1332           Tr->Triangle (i).Get (n1, n3, n2);
1333         else 
1334           Tr->Triangle (i).Get (n1, n2, n3);
1335         k1 = n1+totalnodes;
1336         k2 = n2+totalnodes;
1337         k3 = n3+totalnodes;
1338         fprintf(outfile, "f %d%s%d %d%s%d %d%s%d\n", k1,"//", k1, k2,"//", k2, k3,"//", k3);
1339       }
1340       nbpolygons += nbTriangles;
1341       totalnodes += nbNodes;
1342
1343       fprintf(outfile, "\n%s    %d\n", "# number of smooth groups", nbface);
1344       fprintf(outfile, "\n%s    %d\n", "# number of polygons", nbpolygons);
1345
1346     }
1347   }
1348
1349   fclose(outfile);
1350
1351   return 0;
1352 }
1353
1354 //=======================================================================
1355 //function : triedgepoints
1356 //purpose  : 
1357 //=======================================================================
1358 static Standard_Integer triedgepoints(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
1359 {
1360   if( nbarg < 2 )
1361     return 1;
1362
1363   for( Standard_Integer i = 1; i < nbarg; i++ )
1364   {
1365     TopoDS_Shape aShape = DBRep::Get(argv[i]);
1366     if ( aShape.IsNull() )
1367       continue;
1368
1369     Handle(Poly_PolygonOnTriangulation) aPoly;
1370     Handle(Poly_Triangulation)          aT;
1371     TopLoc_Location                     aLoc;
1372     TopTools_MapOfShape                 anEdgeMap;
1373     TopTools_MapIteratorOfMapOfShape    it;
1374     
1375     if( aShape.ShapeType() == TopAbs_EDGE )
1376     {
1377       anEdgeMap.Add( aShape );
1378     }
1379     else
1380     {
1381       TopExp_Explorer ex(aShape, TopAbs_EDGE);
1382       for(; ex.More(); ex.Next() )
1383         anEdgeMap.Add( ex.Current() );
1384     }
1385
1386     if ( anEdgeMap.Extent() == 0 )
1387       continue;
1388
1389     char newname[1024];
1390     strcpy(newname,argv[i]);
1391     char* p = newname;
1392     while (*p != '\0') p++;
1393     *p = '_';
1394     p++;
1395
1396     Standard_Integer nbEdge = 1;
1397     for(it.Initialize(anEdgeMap); it.More(); it.Next())
1398     {
1399       BRep_Tool::PolygonOnTriangulation(TopoDS::Edge(it.Key()), aPoly, aT, aLoc);
1400       if ( aT.IsNull() || aPoly.IsNull() )
1401         continue;
1402
1403       const TColStd_Array1OfInteger& Indices = aPoly->Nodes();
1404       const Standard_Integer         nbnodes = Indices.Length();
1405
1406       for( Standard_Integer j = 1; j <= nbnodes; j++ )
1407       {
1408         gp_Pnt P3d = aT->Node (Indices[j]);
1409         if( !aLoc.IsIdentity() )
1410           P3d.Transform(aLoc.Transformation());
1411
1412         if( anEdgeMap.Extent() > 1 )
1413           Sprintf(p,"%d_%d",nbEdge,j);
1414         else
1415           Sprintf(p,"%d",j);
1416               DBRep::Set( newname, BRepBuilderAPI_MakeVertex(P3d) );
1417               di.AppendElement(newname);
1418       }
1419       nbEdge++;
1420     }
1421   }
1422   return 0;
1423 }
1424
1425 //=======================================================================
1426 //function : TrMergeNodes
1427 //purpose  :
1428 //=======================================================================
1429 static Standard_Integer TrMergeNodes (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
1430 {
1431   if (theNbArgs < 2)
1432   {
1433     theDI << "Syntax error: not enough arguments";
1434     return 1;
1435   }
1436
1437   TopoDS_Shape aShape = DBRep::Get (theArgVec[1]);
1438   if (aShape.IsNull())
1439   {
1440     theDI << "Syntax error: '" << theArgVec[1] << "' is not a shape";
1441     return 1;
1442   }
1443
1444   Standard_Real aMergeAngle = M_PI / 4.0, aMergeToler = 0.0;
1445   bool toForce = false;
1446   TCollection_AsciiString aResFace;
1447   for (Standard_Integer anArgIter = 2; anArgIter < theNbArgs; ++anArgIter)
1448   {
1449     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1450     anArgCase.LowerCase();
1451     if (anArgIter + 1 < theNbArgs
1452      && (anArgCase == "-angle"
1453       || anArgCase == "-smoothangle"
1454       || anArgCase == "-mergeangle")
1455      && Draw::ParseReal (theArgVec[anArgIter + 1], aMergeAngle))
1456     {
1457       if (aMergeAngle < 0.0 || aMergeAngle > 90.0)
1458       {
1459         theDI << "Syntax error: angle should be within [0,90] range";
1460         return 1;
1461       }
1462
1463       ++anArgIter;
1464       aMergeAngle = aMergeAngle * M_PI / 180.0;
1465     }
1466     else if (anArgIter + 1 < theNbArgs
1467           && anArgCase == "-tolerance"
1468           && Draw::ParseReal (theArgVec[anArgIter + 1], aMergeToler))
1469     {
1470       if (aMergeToler < 0.0)
1471       {
1472         theDI << "Syntax error: tolerance should be within >=0";
1473         return 1;
1474       }
1475
1476       ++anArgIter;
1477     }
1478     else if (anArgCase == "-force")
1479     {
1480       toForce = Draw::ParseOnOffIterator (theNbArgs, theArgVec, anArgIter);
1481     }
1482     else if (anArgIter + 1 < theNbArgs
1483           && anArgCase == "-oneface")
1484     {
1485       aResFace = theArgVec[++anArgIter];
1486     }
1487     else
1488     {
1489       theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
1490       return 1;
1491     }
1492   }
1493
1494   Standard_Integer aNbNodesOld = 0, aNbTrisOld = 0;
1495   Standard_Integer aNbNodesNew = 0, aNbTrisNew = 0;
1496   if (!aResFace.IsEmpty())
1497   {
1498     TopLoc_Location aFaceLoc;
1499     Poly_MergeNodesTool aMergeTool (aMergeAngle, aMergeToler);
1500     for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
1501     {
1502       const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value());
1503       Handle(Poly_Triangulation) aTris = BRep_Tool::Triangulation (aFace, aFaceLoc);
1504       if (aTris.IsNull()
1505        || aTris->NbNodes() < 3
1506        || aTris->NbTriangles() < 1)
1507       {
1508         continue;
1509       }
1510
1511       aNbNodesOld += aTris->NbNodes();
1512       aNbTrisOld  += aTris->NbTriangles();
1513       aMergeTool.AddTriangulation (aTris, aFaceLoc, aFace.Orientation() == TopAbs_REVERSED);
1514     }
1515     Handle(Poly_Triangulation) aNewTris = aMergeTool.Result();
1516     if (aNewTris.IsNull())
1517     {
1518       theDI << "Error: empty result";
1519       return 0;
1520     }
1521
1522     aNbNodesNew += aNewTris->NbNodes();
1523     aNbTrisNew  += aNewTris->NbTriangles();
1524     TopoDS_Face aFace;
1525     BRep_Builder().MakeFace (aFace, aNewTris);
1526     DBRep::Set (aResFace.ToCString(), aFace);
1527   }
1528   else
1529   {
1530     TopTools_MapOfShape aProcessedFaces;
1531     TopLoc_Location aDummy;
1532     for (TopExp_Explorer aFaceIter (aShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
1533     {
1534       const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value());
1535       if (!aProcessedFaces.Add (aFace.Located (TopLoc_Location())))
1536       {
1537         continue;
1538       }
1539
1540       Handle(Poly_Triangulation) aTris = BRep_Tool::Triangulation (aFace, aDummy);
1541       if (aTris.IsNull()
1542        || aTris->NbNodes() < 3
1543        || aTris->NbTriangles() < 1)
1544       {
1545         continue;
1546       }
1547
1548       aNbNodesOld += aTris->NbNodes();
1549       aNbTrisOld  += aTris->NbTriangles();
1550       Poly_MergeNodesTool aMergeTool (aMergeAngle, aMergeToler, aTris->NbTriangles());
1551       aMergeTool.AddTriangulation (aTris);
1552       if (toForce
1553        || aMergeTool.NbNodes()    != aTris->NbNodes()
1554        || aMergeTool.NbElements() != aTris->NbTriangles())
1555       {
1556         BRep_Builder().UpdateFace (aFace, aMergeTool.Result(), false);
1557       }
1558
1559       aTris = BRep_Tool::Triangulation (aFace, aDummy);
1560       aNbNodesNew += aTris->NbNodes();
1561       aNbTrisNew  += aTris->NbTriangles();
1562     }
1563   }
1564   theDI << "Old, Triangles: " << aNbTrisOld << ", Nodes: " << aNbNodesOld << "\n";
1565   theDI << "New, Triangles: " << aNbTrisNew << ", Nodes: " << aNbNodesNew << "\n";
1566   return 0;
1567 }
1568
1569 //=======================================================================
1570 //function : correctnormals
1571 //purpose  : Corrects normals in shape triangulation nodes (...)
1572 //=======================================================================
1573 static Standard_Integer correctnormals(Draw_Interpretor& theDI,
1574                                        Standard_Integer /*theNArg*/,
1575                                        const char** theArgVal)
1576 {
1577   TopoDS_Shape S = DBRep::Get(theArgVal[1]);
1578
1579   //Use "correctnormals shape"
1580
1581   
1582   if(!BRepLib::EnsureNormalConsistency(S))
1583   {
1584     theDI << "Normals have not been changed!\n";
1585   }
1586   else
1587   {
1588     theDI << "Some corrections in source shape have been made!\n";
1589   }
1590
1591   return 0;
1592 }
1593
1594 //=======================================================================
1595 void  MeshTest::Commands(Draw_Interpretor& theCommands)
1596 //=======================================================================
1597 {
1598   Draw::Commands(theCommands);
1599   BRepTest::AllCommands(theCommands);
1600   GeometryTest::AllCommands(theCommands);
1601   MeshTest::PluginCommands(theCommands);
1602   const char* g;
1603
1604   g = "Mesh Commands";
1605
1606   theCommands.Add("incmesh",
1607     "incmesh Shape LinDefl [-angular Angle]=28.64 [-prs]"
1608     "\n\t\t:   [-relative {0|1}]=0 [-parallel {0|1}]=0 [-min Size]"
1609     "\n\t\t:   [-algo {watson|delabella}]=watson"
1610     "\n\t\t:   [-di Value] [-ai Angle]=57.29"
1611     "\n\t\t:   [-int_vert_off {0|1}]=0 [-surf_def_off {0|1}]=0 [-adjust_min {0|1}]=0"
1612     "\n\t\t:   [-force_face_def {0|1}]=0 [-decrease {0|1}]=0"
1613     "\n\t\t: Builds triangular mesh for the shape."
1614     "\n\t\t:  LinDefl         linear deflection to control mesh quality;"
1615     "\n\t\t:  -angular        angular deflection for edges in deg (~28.64 deg = 0.5 rad by default);"
1616     "\n\t\t:  -prs            apply default meshing parameters for visualization purposes"
1617     "\n\t\t:                  (20 deg angular deflection, 0.001 of bounding box linear deflection);"
1618     "\n\t\t:  -relative       notifies that relative deflection is used (FALSE by default);"
1619     "\n\t\t:  -parallel       enables parallel execution (FALSE by default);"
1620     "\n\t\t:  -algo           changes core triangulation algorithm to one with specified id (watson by default);"
1621     "\n\t\t:  -min            minimum size parameter limiting size of triangle's edges to prevent sinking"
1622     "\n\t\t:                  into amplification in case of distorted curves and surfaces;"
1623     "\n\t\t:  -di             linear deflection used to tessellate the face interior;"
1624     "\n\t\t:  -ai             angular deflection inside of faces in deg (~57.29 deg = 1 rad by default);"
1625     "\n\t\t:  -int_vert_off   disables insertion of internal vertices into mesh (enabled by default);"
1626     "\n\t\t:  -surf_def_off   disables control of deflection of mesh from real surface (enabled by default);"
1627     "\n\t\t:  -adjust_min     enables local adjustment of min size depending on edge size (FALSE by default);"
1628     "\n\t\t:  -force_face_def disables usage of shape tolerances for computing face deflection (FALSE by default);"
1629     "\n\t\t:  -decrease       enforces the meshing of the shape even if current mesh satisfies the new criteria"
1630     "\n\t\t:                  (FALSE by default).",
1631   __FILE__, incrementalmesh, g);
1632   theCommands.Add("tessellate","Builds triangular mesh for the surface, run w/o args for help",__FILE__, tessellate, g);
1633   theCommands.Add("MemLeakTest","MemLeakTest",__FILE__, MemLeakTest, g);
1634
1635   theCommands.Add("tri2d", "tri2d facename",__FILE__, tri2d, g);
1636   theCommands.Add("trinfo",
1637                   "trinfo shapeName [-lods], print triangles information on objects"
1638                   "\n\t\t: -lods Print detailed LOD information",
1639                   __FILE__,trianglesinfo,g);
1640   theCommands.Add("veriftriangles","veriftriangles name, verif triangles",__FILE__,veriftriangles,g);
1641   theCommands.Add("wavefront","wavefront name",__FILE__, wavefront, g);
1642   theCommands.Add("triepoints", "triepoints shape1 [shape2 ...]",__FILE__, triedgepoints, g);
1643   theCommands.Add("trlateload",
1644                   "trlateload shapeName"
1645                   "\n\t\t:   [-load {-1|Index|ALL}=-1] [-unload {-1|Index|ALL}=-1]"
1646                   "\n\t\t:   [-activate Index] [-activateExact Index]"
1647                   "\n\t\t:   [-loadSingle {-1|Index}=-1] [-loadSingleExact {Index}=-1]"
1648                   "\n\t\t: Interaction with deferred triangulations."
1649                   "\n\t\t:   '-load'            - load triangulation (-1 - currently active one, Index - with defined index,"
1650                   "\n\t\t:                      ALL - all available ones)"
1651                   "\n\t\t:   '-unload'          - unload triangulation (-1 - currently active one, Index - with defined index,"
1652                   "\n\t\t:                      ALL - all available ones)"
1653                   "\n\t\t:   '-activate'        - activate triangulation with defined index. If it doesn't exist -"
1654                   "\n\t\t:                      activate the last available triangulation."
1655                   "\n\t\t:   '-activateExact'   - activate exactly triangulation with defined index or do nothing."
1656                   "\n\t\t:   '-loadSingle'      - make loaded and active ONLY specified triangulation (-1 - currently active one,"
1657                   "\n\t\t:                      Index - with defined index or last available if it doesn't exist)."
1658                   "\n\t\t:                      All other triangulations will be unloaded."
1659                   "\n\t\t:   '-loadSingleExact' - make loaded and active ONLY exactly specified triangulation. All other triangulations"
1660                   "\n\t\t:                      will be unloaded. If triangulation with such Index doesn't exist do nothing",
1661                   __FILE__, TrLateLoad, g);
1662   theCommands.Add("trmergenodes",
1663                   "trmergenodes shapeName"
1664                   "\n\t\t:   [-angle Angle] [-tolerance Value] [-oneFace Result]"
1665                   "\n\t\t: Merging nodes within triangulation data."
1666                   "\n\t\t:   -angle     merge angle upper limit in degrees; 45 when unspecified"
1667                   "\n\t\t:   -tolerance linear tolerance to merge nodes; 0.0 when unspecified"
1668                   "\n\t\t:   -oneFace   create a new single Face with specified name for the whole triangulation",
1669                   __FILE__, TrMergeNodes, g);
1670   theCommands.Add("correctnormals", "correctnormals shape",__FILE__, correctnormals, g);
1671 }