0028838: Configuration - undefine macros coming from X11 headers in place of collision
[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
18 #include <AppCont_ContMatrices.hxx>
19 #include <Bnd_Box.hxx>
20 #include <BRep_Builder.hxx>
21 #include <BRep_Tool.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepBndLib.hxx>
24 #include <BRepBuilderAPI_MakeFace.hxx>
25 #include <BRepBuilderAPI_MakePolygon.hxx>
26 #include <BRepBuilderAPI_MakeVertex.hxx>
27 #include <BRepLib.hxx>
28 #include <BRepMesh_DataStructureOfDelaun.hxx>
29 #include <BRepMesh_Delaun.hxx>
30 #include <BRepMesh_Edge.hxx>
31 #include <BRepMesh_FastDiscret.hxx>
32 #include <BRepMesh_IncrementalMesh.hxx>
33 #include <BRepMesh_Triangle.hxx>
34 #include <BRepMesh_Vertex.hxx>
35 #include <BRepTest.hxx>
36 #include <BRepTools.hxx>
37 #include <CSLib.hxx>
38 #include <CSLib_DerivativeStatus.hxx>
39 #include <DBRep.hxx>
40 #include <Draw.hxx>
41 #include <Draw_Appli.hxx>
42 #include <Draw_Interpretor.hxx>
43 #include <Draw_Marker3D.hxx>
44 #include <Draw_MarkerShape.hxx>
45 #include <Draw_Segment2D.hxx>
46 #include <DrawTrSurf.hxx>
47 #include <Extrema_LocateExtPC.hxx>
48 #include <GCPnts_UniformAbscissa.hxx>
49 #include <Geom_Curve.hxx>
50 #include <Geom_Plane.hxx>
51 #include <Geom_Surface.hxx>
52 #include <GeomAdaptor_Curve.hxx>
53 #include <GeometryTest.hxx>
54 #include <gp_Pln.hxx>
55 #include <gp_Trsf.hxx>
56 #include <math.hxx>
57 #include <math_Matrix.hxx>
58 #include <math_Vector.hxx>
59 #include <MeshTest.hxx>
60 #include <MeshTest_DrawableMesh.hxx>
61 #include <PLib.hxx>
62 #include <Poly_Connect.hxx>
63 #include <Poly_PolygonOnTriangulation.hxx>
64 #include <Poly_Triangulation.hxx>
65 #include <Precision.hxx>
66 #include <Standard_Stream.hxx>
67 #include <TColgp_Array1OfPnt2d.hxx>
68 #include <TCollection_AsciiString.hxx>
69 #include <TColStd_HArray1OfInteger.hxx>
70 #include <TColStd_ListIteratorOfListOfInteger.hxx>
71 #include <TColStd_MapIteratorOfMapOfInteger.hxx>
72 #include <TopAbs_ShapeEnum.hxx>
73 #include <TopExp_Explorer.hxx>
74 #include <TopLoc_Location.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Compound.hxx>
77 #include <TopoDS_Edge.hxx>
78 #include <TopoDS_Face.hxx>
79 #include <TopoDS_Shape.hxx>
80 #include <TopoDS_Wire.hxx>
81 #include <TopTools_ListIteratorOfListOfShape.hxx>
82 #include <TopTools_MapIteratorOfMapOfShape.hxx>
83
84 #include <stdio.h>
85 //epa Memory leaks test
86 //OAN: for triepoints
87 #ifdef _WIN32
88 Standard_IMPORT Draw_Viewer dout;
89 #endif
90
91 #define MAX2(X, Y)      (  Abs(X) > Abs(Y)? Abs(X) : Abs(Y) )
92 #define MAX3(X, Y, Z)   ( MAX2 ( MAX2(X,Y) , Z) )
93
94
95
96 #define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
97 #define TWOTHIRD 0.666666666666666666666666666666666666666666666666666666666666
98
99 #ifdef OCCT_DEBUG_MESH_CHRONO
100 #include <OSD_Chronometer.hxx>
101 Standard_Integer D0Control, D0Internal, D0Unif, D0Edges, NbControls;
102 OSD_Chronometer chTotal, chInternal, chControl, chUnif, chAddPoint;
103 OSD_Chronometer chEdges, chMaillEdges, chEtuInter, chLastControl, chStock;
104 OSD_Chronometer chAdd11, chAdd12, chAdd2, chUpdate, chPointValid;
105 OSD_Chronometer chIsos, chPointsOnIsos;
106 #endif
107
108 //=======================================================================
109 //function : incrementalmesh
110 //purpose  : 
111 //=======================================================================
112 static Standard_Integer incrementalmesh(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
113 {
114   if (nbarg < 3)
115   {
116     di << "\
117 Builds triangular mesh for the shape\n\
118 usage: incmesh Shape LinearDeflection [options]\n\
119 options:\n\
120         -a val          angular deflection in deg\n\
121                         (default ~28.64 deg = 0.5 rad)\n\n\
122         -min            minimum size parameter limiting size of triangle's\n\
123                         edges to prevent sinking into amplification in case\n\
124                         of distorted curves and surfaces\n\n\
125         -relative       notifies that relative deflection is used\n\
126                         (switched off by default)\n\n\
127         -int_vert_off   disables insertion of internal vertices into mesh\n\
128                         (enabled by default)\n\
129         -surf_def_off   disables control of deflection of mesh from real\n\
130                         surface (enabled by default)\n\
131         -parallel       enables parallel execution (switched off by default)\n\
132         -adaptive       enables adaptive computation of minimal value in parametric space\n";
133     return 0;
134   }
135
136   TopoDS_Shape aShape = DBRep::Get(argv[1]);
137   if (aShape.IsNull())
138   {
139     di << " Null shapes are not allowed here\n";
140     return 0;
141   }
142
143   Standard_Real aLinDeflection     = Max(Draw::Atof(argv[2]), Precision::Confusion());
144   Standard_Real aAngDeflection     = 0.5;
145   Standard_Real aMinSize           = Precision::Confusion();
146   Standard_Boolean isRelative      = Standard_False;
147   Standard_Boolean isInParallel    = Standard_False;
148   Standard_Boolean isIntVertices   = Standard_True;
149   Standard_Boolean isControlSurDef = Standard_True;
150   Standard_Boolean isAdaptiveMin   = Standard_False;
151
152   if (nbarg > 3)
153   {
154     Standard_Integer i = 3;
155     while (i < nbarg)
156     {
157       TCollection_AsciiString aOpt(argv[i++]);
158       aOpt.LowerCase();
159
160       if (aOpt == "")
161         continue;
162       else if (aOpt == "-relative")
163         isRelative = Standard_True;
164       else if (aOpt == "-parallel")
165         isInParallel = Standard_True;
166       else if (aOpt == "-int_vert_off")
167         isIntVertices = Standard_False;
168       else if (aOpt == "-surf_def_off")
169         isControlSurDef = Standard_False;
170       else if (aOpt == "-adaptive")
171         isAdaptiveMin   = Standard_True;
172       else if (i < nbarg)
173       {
174         Standard_Real aVal = Draw::Atof(argv[i++]);
175         if (aOpt == "-a")
176           aAngDeflection = aVal * M_PI / 180.;
177         else if (aOpt == "-min")
178           aMinSize = aVal;
179         else
180           --i;
181       }
182     }
183   }
184
185   di << "Incremental Mesh, multi-threading "
186      << (isInParallel ? "ON" : "OFF") << "\n";
187
188   BRepMesh_FastDiscret::Parameters aMeshParams;
189   aMeshParams.Deflection = aLinDeflection;
190   aMeshParams.Angle = aAngDeflection;
191   aMeshParams.Relative =  isRelative;
192   aMeshParams.InParallel = isInParallel;
193   aMeshParams.MinSize = aMinSize;
194   aMeshParams.InternalVerticesMode = isIntVertices;
195   aMeshParams.ControlSurfaceDeflection = isControlSurDef;
196   aMeshParams.AdaptiveMin = isAdaptiveMin;
197   
198   BRepMesh_IncrementalMesh aMesher (aShape, aMeshParams);
199
200   di << "Meshing statuses: ";
201   Standard_Integer statusFlags = aMesher.GetStatusFlags();
202   if( !statusFlags )
203   {
204     di << "NoError";
205   }
206   else
207   {
208     Standard_Integer i;
209     for( i = 0; i < 4; i++ )
210     {
211       if( (statusFlags >> i) & (Standard_Integer)1 )
212       {
213         switch(i+1)
214         {
215           case 1:
216             di << "OpenWire ";
217             break;
218           case 2:
219             di << "SelfIntersectingWire ";
220             break;
221           case 3:
222             di << "Failure ";
223             break;
224           case 4:
225             di << "ReMesh ";
226             break;
227         }
228       }
229     }
230   }
231
232   return 0;
233 }
234
235 //=======================================================================
236 //function : tessellate
237 //purpose  : 
238 //=======================================================================
239 static Standard_Integer tessellate (Draw_Interpretor& /*di*/, Standard_Integer nbarg, const char** argv)
240 {
241   if (nbarg != 5)
242   {
243     std::cerr << "Builds regular triangulation with specified number of triangles\n"
244                  "    Usage: tessellate result {surface|face} nbu nbv\n"
245                  "    Triangulation is put into the face with natural bounds (result);\n"
246                  "    it will have 2*nbu*nbv triangles and (nbu+1)*(nbv+1) nodes";
247     return 1;
248   }
249
250   const char *aResName = argv[1];
251   const char *aSrcName = argv[2];
252   int aNbU = Draw::Atoi (argv[3]);
253   int aNbV = Draw::Atoi (argv[4]);
254
255   if (aNbU <= 0 || aNbV <= 0)
256   {
257     std::cerr << "Error: Arguments nbu and nbv must be both greater than 0\n";
258     return 1;
259   }
260
261   Handle(Geom_Surface) aSurf = DrawTrSurf::GetSurface(aSrcName);
262   double aUMin, aUMax, aVMin, aVMax;
263   if (! aSurf.IsNull())
264   {
265     aSurf->Bounds (aUMin, aUMax, aVMin, aVMax);
266   }
267   else
268   {
269     TopoDS_Shape aShape = DBRep::Get(aSrcName);
270     if (aShape.IsNull() || aShape.ShapeType() != TopAbs_FACE)
271     {
272       std::cerr << "Error: " << aSrcName << " is not a face\n";
273       return 1;
274     }
275     TopoDS_Face aFace = TopoDS::Face (aShape);
276     aSurf = BRep_Tool::Surface (aFace);
277     if (aSurf.IsNull())
278     {
279       std::cerr << "Error: Face " << aSrcName << " has no surface\n";
280       return 1;
281     }
282
283     BRepTools::UVBounds (aFace, aUMin, aUMax, aVMin, aVMax);
284   }
285   if (Precision::IsInfinite (aUMin) || Precision::IsInfinite (aUMax) || 
286       Precision::IsInfinite (aVMin) || Precision::IsInfinite (aVMax))
287   {
288     std::cerr << "Error: surface has infinite parametric range, aborting\n";
289     return 1;
290   }
291
292   BRepBuilderAPI_MakeFace aFaceMaker (aSurf, aUMin, aUMax, aVMin, aVMax, Precision::Confusion());
293   if (! aFaceMaker.IsDone())
294   {
295     std::cerr << "Error: cannot build face with natural bounds, aborting\n";
296     return 1;
297   }
298   TopoDS_Face aFace = aFaceMaker;
299
300   // create triangulation
301   int aNbNodes = (aNbU + 1) * (aNbV + 1);
302   int aNbTriangles = 2 * aNbU * aNbV;
303   Handle(Poly_Triangulation) aTriangulation =
304     new Poly_Triangulation (aNbNodes, aNbTriangles, Standard_False);
305
306   // fill nodes
307   TColgp_Array1OfPnt &aNodes = aTriangulation->ChangeNodes();
308   GeomAdaptor_Surface anAdSurf (aSurf);
309   double aDU = (aUMax - aUMin) / aNbU;
310   double aDV = (aVMax - aVMin) / aNbV;
311   for (int iU = 0, iShift = 1; iU <= aNbU; iU++, iShift += aNbV + 1)
312   {
313     double aU = aUMin + iU * aDU;
314     for (int iV = 0; iV <= aNbV; iV++)
315     {
316       double aV = aVMin + iV * aDV;
317       gp_Pnt aP = anAdSurf.Value (aU, aV);
318       aNodes.SetValue (iShift + iV, aP);
319     }
320   }
321
322   // fill triangles
323   Poly_Array1OfTriangle &aTriangles = aTriangulation->ChangeTriangles();
324   for (int iU = 0, iShift = 1, iTri = 0; iU < aNbU; iU++, iShift += aNbV + 1)
325   {
326     for (int iV = 0; iV < aNbV; iV++)
327     {
328       int iBase = iShift + iV;
329       Poly_Triangle aTri1 (iBase, iBase + aNbV + 2, iBase + 1);
330       Poly_Triangle aTri2 (iBase, iBase + aNbV + 1, iBase + aNbV + 2);
331       aTriangles.SetValue (++iTri, aTri1);
332       aTriangles.SetValue (++iTri, aTri2);
333     }
334   }
335
336   // put triangulation to face
337   BRep_Builder B;
338   B.UpdateFace (aFace, aTriangulation);
339
340   // fill edge polygons
341   TColStd_Array1OfInteger aUMinIso (1, aNbV + 1), aUMaxIso (1, aNbV + 1);
342   for (int iV = 0; iV <= aNbV; iV++)
343   {
344     aUMinIso.SetValue (1 + iV, 1 + iV);
345     aUMaxIso.SetValue (1 + iV, 1 + iV + aNbU * (1 + aNbV));
346   }
347   TColStd_Array1OfInteger aVMinIso (1, aNbU + 1), aVMaxIso (1, aNbU + 1);
348   for (int iU = 0; iU <= aNbU; iU++)
349   {
350     aVMinIso.SetValue (1 + iU,  1 + iU  * (1 + aNbV));
351     aVMaxIso.SetValue (1 + iU, (1 + iU) * (1 + aNbV));
352   }
353   Handle(Poly_PolygonOnTriangulation) aUMinPoly = new Poly_PolygonOnTriangulation (aUMinIso);
354   Handle(Poly_PolygonOnTriangulation) aUMaxPoly = new Poly_PolygonOnTriangulation (aUMaxIso);
355   Handle(Poly_PolygonOnTriangulation) aVMinPoly = new Poly_PolygonOnTriangulation (aVMinIso);
356   Handle(Poly_PolygonOnTriangulation) aVMaxPoly = new Poly_PolygonOnTriangulation (aVMaxIso);
357   for (TopExp_Explorer exp (aFace, TopAbs_EDGE); exp.More(); exp.Next())
358   {
359     TopoDS_Edge anEdge = TopoDS::Edge (exp.Current());
360     Standard_Real aFirst, aLast;
361     Handle(Geom2d_Curve) aC = BRep_Tool::CurveOnSurface (anEdge, aFace, aFirst, aLast);
362     gp_Pnt2d aPFirst = aC->Value (aFirst);
363     gp_Pnt2d aPLast  = aC->Value (aLast);
364     if (Abs (aPFirst.X() - aPLast.X()) < 0.1 * (aUMax - aUMin)) // U=const
365     {
366       if (BRep_Tool::IsClosed (anEdge, aFace))
367         B.UpdateEdge (anEdge, aUMinPoly, aUMaxPoly, aTriangulation);
368       else
369         B.UpdateEdge (anEdge, (aPFirst.X() < 0.5 * (aUMin + aUMax) ? aUMinPoly : aUMaxPoly), aTriangulation);
370     }
371     else // V=const
372     {
373       if (BRep_Tool::IsClosed (anEdge, aFace))
374         B.UpdateEdge (anEdge, aVMinPoly, aVMaxPoly, aTriangulation);
375       else
376         B.UpdateEdge (anEdge, (aPFirst.Y() < 0.5 * (aVMin + aVMax) ? aVMinPoly : aVMaxPoly), aTriangulation);
377     }
378   }
379
380   DBRep::Set (aResName, aFace);
381   return 0;
382 }
383
384 //=======================================================================
385 //function : MemLeakTest
386 //purpose  : 
387 //=======================================================================
388
389 static Standard_Integer MemLeakTest(Draw_Interpretor&, Standard_Integer /*nbarg*/, const char** /*argv*/)
390 {
391   for(int i=0;i<10000;i++)
392   {
393     BRepBuilderAPI_MakePolygon w(gp_Pnt(0,0,0),gp_Pnt(0,100,0),gp_Pnt(20,100,0),gp_Pnt(20,0,0));
394     w.Close();     
395     TopoDS_Wire wireShape( w.Wire());
396     BRepBuilderAPI_MakeFace faceBuilder(wireShape);          
397     TopoDS_Face f( faceBuilder.Face());
398     BRepMesh_IncrementalMesh im(f,1);
399     BRepTools::Clean(f);      
400   }
401   return 0;
402 }
403
404 //=======================================================================
405 //function : fastdiscret
406 //purpose  : 
407 //=======================================================================
408
409 static Standard_Integer fastdiscret(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
410 {
411   if (nbarg < 3) return 1;
412
413   TopoDS_Shape S = DBRep::Get(argv[1]);
414   if (S.IsNull()) return 1;
415
416   const Standard_Real d = Draw::Atof(argv[2]);
417
418   Bnd_Box B;
419   BRepBndLib::Add(S,B);
420   BRepMesh_FastDiscret::Parameters aParams;
421   aParams.Deflection = d;
422   aParams.Angle = 0.5;
423   BRepMesh_FastDiscret MESH(B,aParams);
424
425   //Standard_Integer NbIterations = MESH.NbIterations();
426   //if (nbarg > 4) NbIterations = Draw::Atoi(argv[4]);
427   //MESH.NbIterations() = NbIterations;
428
429   di<<"Starting FastDiscret with :\n";
430   di<<"  Deflection="<<d<<"\n";
431   di<<"  Angle="<<0.5<<"\n";
432
433   Handle(Poly_Triangulation) T;
434   BRep_Builder aBuilder;
435   TopExp_Explorer ex;
436
437   // Clear existing triangulations
438   for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next())
439     aBuilder.UpdateFace(TopoDS::Face(ex.Current()),T);
440
441   MESH.Perform(S);
442
443   TopoDS_Compound aCompGood, aCompFailed, aCompViolating;
444
445   TopLoc_Location L;
446   Standard_Integer nbtriangles = 0, nbnodes = 0, nbfailed = 0, nbviolating = 0;
447   Standard_Real maxdef = 0.0;
448   for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next())
449   {
450     T = BRep_Tool::Triangulation(TopoDS::Face(ex.Current()),L);
451     if (T.IsNull())
452     {
453       nbfailed++;
454       if (aCompFailed.IsNull())
455         aBuilder.MakeCompound(aCompFailed);
456       aBuilder.Add(aCompFailed,ex.Current());
457     }
458     else
459     {
460       nbtriangles += T->NbTriangles();
461       nbnodes += T->NbNodes();
462       if (T->Deflection() > maxdef) maxdef = T->Deflection();
463       if (T->Deflection() > d)
464       {
465         nbviolating++;
466         if (aCompViolating.IsNull())
467           aBuilder.MakeCompound(aCompViolating);
468         aBuilder.Add(aCompViolating,ex.Current());
469       }
470       else
471       {
472         if (aCompGood.IsNull())
473           aBuilder.MakeCompound(aCompGood);
474         aBuilder.Add(aCompGood,ex.Current());
475       }
476     }
477   }
478
479   if (!aCompGood.IsNull())
480   {
481     char name[256];
482     strcpy(name,argv[1]);
483     strcat(name,"_good");
484     DBRep::Set(name,aCompGood);
485   }
486   if (!aCompFailed.IsNull())
487   {
488     char name[256];
489     strcpy(name,argv[1]);
490     strcat(name,"_failed");
491     DBRep::Set(name,aCompFailed);
492   }
493   if (!aCompViolating.IsNull())
494   {
495     char name[256];
496     strcpy(name,argv[1]);
497     strcat(name,"_violating");
498     DBRep::Set(name,aCompViolating);
499   }
500
501   di<<"FastDiscret completed with :\n";
502   di<<"  MaxDeflection="<<maxdef<<"\n";
503   di<<"  NbNodes="<<nbnodes<<"\n";
504   di<<"  NbTriangles="<<nbtriangles<<"\n";
505   di<<"  NbFailed="<<nbfailed<<"\n";
506   di<<"  NbViolating="<<nbviolating<<"\n";
507
508   return 0;
509 }
510
511
512 //=======================================================================
513 //function : triangule
514 //purpose  : 
515 //=======================================================================
516
517
518 class BRepMesh_Couple
519 {
520 public:
521   BRepMesh_Couple() { myI1 = myI2 = 0; }
522   BRepMesh_Couple(const Standard_Integer I1,
523     const Standard_Integer I2)
524   { myI1 = I1; myI2 = I2; }
525
526   Standard_Integer myI1;
527   Standard_Integer myI2;
528 };
529
530 inline Standard_Boolean IsEqual(const BRepMesh_Couple& one,
531                                 const BRepMesh_Couple& other)
532 {
533   if (one.myI1 == other.myI1 &&
534     one.myI2 == other.myI2) return Standard_True;
535   else return Standard_False;
536 }
537
538 inline Standard_Integer HashCode(const BRepMesh_Couple& one,
539                                  const Standard_Integer Upper)
540 {
541   return ::HashCode((one.myI1+one.myI2), Upper);
542 }
543
544 typedef NCollection_Map<BRepMesh_Couple> BRepMesh_MapOfCouple;
545
546
547 static void AddLink(BRepMesh_MapOfCouple& aMap, 
548                     Standard_Integer v1,
549                     Standard_Integer v2)
550 {
551   Standard_Integer i1 = v1;
552   Standard_Integer i2 = v2;
553   if(i1 > i2) {
554     i1 = v2;
555     i2 = v1;
556   }
557   aMap.Add(BRepMesh_Couple(i1,i2));
558 }
559
560 static void MeshStats(const TopoDS_Shape& theSape,
561                       Standard_Integer& theNbTri,
562                       Standard_Integer& theNbEdges,
563                       Standard_Integer& theNbNodes)
564 {
565   theNbTri = 0;
566   theNbEdges = 0;
567   theNbNodes = 0;
568
569   Handle(Poly_Triangulation) T;
570   TopLoc_Location L;
571
572   for ( TopExp_Explorer ex(theSape, TopAbs_FACE); ex.More(); ex.Next()) {
573     TopoDS_Face F = TopoDS::Face(ex.Current());
574     T = BRep_Tool::Triangulation(F, L);
575     if (!T.IsNull()) {
576       theNbTri += T->NbTriangles();
577       theNbNodes += T->NbNodes();
578
579       BRepMesh_MapOfCouple aMap;
580       //count number of links
581       Poly_Array1OfTriangle& Trian = T->ChangeTriangles();
582       for(Standard_Integer i = 1; i<=Trian.Length();i++) {
583         Standard_Integer v1, v2, v3;
584         Trian(i).Get(v1,v2,v3);
585
586         AddLink(aMap, v1, v2);
587         AddLink(aMap, v2, v3);
588         AddLink(aMap, v3, v1);
589       }
590
591       theNbEdges+=aMap.Extent();
592     }
593   }
594 }
595
596 static Standard_Integer triangule(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
597 {
598   if (nbarg < 4)
599     return 1;
600
601   const char *id1 = argv[2];
602   TopoDS_Shape aShape = DBRep::Get(id1);
603   if (aShape.IsNull())
604     return 1;
605
606   di << argv[1] << " ";
607
608   Standard_Real aDeflection = Draw::Atof(argv[3]);
609   if (aDeflection <= 0.)
610   {
611     di << " Incorrect value of deflection!\n";
612     return 1;
613   }
614
615   Handle(MeshTest_DrawableMesh) aDMesh = 
616     new MeshTest_DrawableMesh(aShape, aDeflection);
617
618   Draw::Set(argv[1], aDMesh);
619
620   Standard_Integer nbn, nbl, nbe;
621   MeshStats(aShape, nbe, nbl, nbn);
622
623   di<<"(Resultat ("<<nbe<<" mailles) ("<<nbl<<" aretes) ("<<nbn<<" sommets))\n";
624
625   // passe de verification du maillage.
626   /*Standard_Integer nbc;
627   for (Standard_Integer iLi=1; iLi<= DM->Mesh()->NbEdges(); iLi++) {
628   const BRepMesh_Edge& ed=DM->Mesh()->Edge(iLi);
629   if (ed.Movability()!=BRepMesh_Deleted) {
630   nbc=struc->ElemConnectedTo(iLi).Extent();
631   if (nbc != 1 && nbc != 2) di <<"ERROR MAILLAGE Edge no "<< iLi<<"\n";
632   }
633   }*/
634
635
636   Bnd_Box aBox;
637
638   TopExp_Explorer aFaceIt(aShape, TopAbs_FACE);
639   for (; aFaceIt.More(); aFaceIt.Next())
640   {
641     const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current());
642
643     TopLoc_Location aLoc = aFace.Location();
644     Handle(Poly_Triangulation) aTriangulation =
645       BRep_Tool::Triangulation(aFace, aLoc);
646
647     if (!aTriangulation.IsNull())
648     {
649       const Standard_Integer    aLength = aTriangulation->NbNodes();
650       const TColgp_Array1OfPnt& aNodes  = aTriangulation->Nodes();
651       for (Standard_Integer i = 1; i <= aLength; ++i)
652         aBox.Add(aNodes(i));
653     }
654   }
655
656   Standard_Real aDelta = 0.;
657   if (!aBox.IsVoid())
658   {
659     Standard_Real x, y, z, X, Y, Z;
660     aBox.Get(x, y, z, X, Y, Z);
661
662     aDelta = Max(X - x, Max(Y - y, Z - z));
663     if (aDelta > 0.0)
664       aDelta = aDeflection / aDelta;
665   }
666
667   di << " Ratio between deflection and total shape size is " << aDelta << "\n";
668
669   return 0;
670 }
671
672 //=======================================================================
673 //function : addshape
674 //purpose  : 
675 //=======================================================================
676
677 Standard_Integer addshape(Draw_Interpretor&, Standard_Integer n, const char** a)
678 {
679   if (n < 3) return 1;
680   Handle(MeshTest_DrawableMesh) D =
681     Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
682   if (D.IsNull()) return 1;
683   TopoDS_Shape S = DBRep::Get(a[2]);
684   if (S.IsNull()) return 1;
685
686   D->Add(S);
687   Draw::Repaint();
688
689   return 0;
690 }
691
692
693 //=======================================================================
694 //function : smooth
695 //purpose  : 
696 //=======================================================================
697
698 /*Standard_Integer smooth(Draw_Interpretor&, Standard_Integer n, const char** a)
699 {
700 if (n < 2) return 1;
701 Handle(MeshTest_DrawableMesh) D =
702 Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
703 if (D.IsNull()) return 1;
704 Handle(BRepMesh_DataStructureOfDelaun) struc=
705 D->Mesh()->Result();
706 BRepMesh_Array1OfVertexOfDelaun toto(1,1);
707 BRepMesh_Delaun trial(struc, 
708 toto,
709 Standard_True);
710 trial.SmoothMesh(0.1);
711 Draw::Repaint();
712 return 0;
713 }
714 */
715
716 //=======================================================================
717 //function : edges
718 //purpose  : 
719 //=======================================================================
720
721 /*static Standard_Integer edges (Draw_Interpretor&, Standard_Integer n, const char** a)
722 {
723 if (n < 3) return 1;
724
725 Handle(MeshTest_DrawableMesh) D =
726 Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
727 if (D.IsNull()) return 1;
728 TopoDS_Shape S = DBRep::Get(a[2]);
729 if (S.IsNull()) return 1;
730
731 TopExp_Explorer ex;
732 TColStd_SequenceOfInteger& eseq = D->Edges();
733 Handle(BRepMesh_FastDiscret) M = D->Mesh();
734 Handle(BRepMesh_DataStructureOfDelaun) DS = M->Result();
735 Standard_Integer e1, e2, e3, iTri;
736 Standard_Boolean o1, o2, o3;
737
738 // the faces
739 for (ex.Init(S,TopAbs_FACE);ex.More();ex.Next()) {
740 const BRepMesh_MapOfInteger& elems = DS->ElemOfDomain();
741 BRepMesh_MapOfInteger::Iterator it;
742 for (it.Initialize(elems); it.More(); it.Next()) {
743 iTri = it.Key();
744 const BRepMesh_Triangle& triang = M->Triangle(iTri);
745 if (triang.Movability()!=BRepMesh_Deleted) {
746 triang.Edges(e1, e2, e3, o1, o2, o3);
747 eseq.Append(e1);
748 eseq.Append(e2);
749 eseq.Append(e3);
750 }
751 }
752 }
753
754 // the edges
755 //for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE);ex.More();ex.Next()) {
756 //}
757
758 Draw::Repaint();
759 return 0;
760 }
761 */
762
763 //=======================================================================
764 //function : vertices
765 //purpose  : 
766 //=======================================================================
767 static Standard_Integer vertices(
768   Draw_Interpretor& /*di*/, 
769   Standard_Integer  /*argc*/, 
770   const char**      /*argv*/)
771 {
772   return 0;
773
774   // TODO: OAN re-implement this command according changes in BRepMesh
775   //if (argc < 3)
776   //  return 1;
777
778   //Handle(MeshTest_DrawableMesh) aDrawableMesh =
779   //  Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(argv[1]));
780   //if (aDrawableMesh.IsNull())
781   //  return 1;
782
783   //TopoDS_Shape aShape = DBRep::Get(argv[2]);
784   //if (aShape.IsNull())
785   //  return 1;
786
787   //TColStd_SequenceOfInteger&   aVertexSeq = aDrawableMesh->Vertices();
788   //Handle(BRepMesh_FastDiscret) aMesh      = aDrawableMesh->Mesh();
789
790   //TopExp_Explorer aFaceIt(aShape, TopAbs_FACE);
791   //for (; aFaceIt.More(); aFaceIt.Next())
792   //{
793   //  const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current());
794
795   //  Handle(BRepMesh_FaceAttribute) aAttribute;
796   //  if (aMesh->GetFaceAttribute(aFace, aAttribute))
797   //  {
798   //    Handle(BRepMesh_DataStructureOfDelaun) aStructure = aAttribute->EditStructure();
799
800   //    // Recuperate from the map of edges.
801   //    const BRepMeshCol::MapOfInteger& aEdgeMap = aStructure->LinksOfDomain();
802
803   //    // Iterator on edges.
804   //    BRepMeshCol::MapOfInteger aVertices;
805   //    BRepMeshCol::MapOfInteger::Iterator aEdgeIt(aEdgeMap);
806   //    for (; aEdgeIt.More(); aEdgeIt.Next())
807   //    {
808   //      const BRepMesh_Edge& aEdge = aStructure->GetLink(aEdgeIt.Key());
809   //      aVertices.Add(aEdge.FirstNode());
810   //      aVertices.Add(aEdge.LastNode());
811   //    }
812
813   //    BRepMeshCol::MapOfInteger::Iterator anIt(vtx);
814   //    for ( ; anIt.More(); anIt.Next() )
815   //      aVertexSeq.Append(anIt.Key());
816   //  }
817   //}
818
819   //Draw::Repaint();
820   //return 0;
821 }
822
823 //=======================================================================
824 //function : medge
825 //purpose  : 
826 //=======================================================================
827
828 static Standard_Integer medge (Draw_Interpretor&, Standard_Integer n, const char** a)
829 {
830   if (n < 3) return 1;
831
832   Handle(MeshTest_DrawableMesh) D =
833     Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
834   if (D.IsNull()) return 1;
835
836   Standard_Integer i,j,e;
837   TColStd_SequenceOfInteger& eseq = D->Edges();
838   for (i = 2; i < n; i++) {
839     e = Draw::Atoi(a[i]);
840     if (e > 0)
841       eseq.Append(e);
842     else if (e < 0) {
843       e = -e;
844       j = 1; 
845       while (j <= eseq.Length()) {
846         if (eseq(j) == e) 
847           eseq.Remove(j);
848         else
849           j++;
850       }
851     }
852     else
853       eseq.Clear();
854   }
855
856   Draw::Repaint();
857   return 0;
858 }
859
860
861 //=======================================================================
862 //function : mvertex
863 //purpose  : 
864 //=======================================================================
865
866 static Standard_Integer mvertex (Draw_Interpretor&, Standard_Integer n, const char** a)
867 {
868   if (n < 3) return 1;
869
870   Handle(MeshTest_DrawableMesh) D =
871     Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
872   if (D.IsNull()) return 1;
873
874   Standard_Integer i,j,v;
875   TColStd_SequenceOfInteger& vseq = D->Vertices();
876   for (i = 2; i < n; i++) {
877     v = Draw::Atoi(a[i]);
878     if (v > 0)
879       vseq.Append(v);
880     else if (v < 0) {
881       v = -v;
882       j = 1;
883       while (j <= vseq.Length()) {
884         if (vseq(j) == v)
885           vseq.Remove(v);
886         else
887           j++;
888       }
889     }
890     else
891       vseq.Clear();
892   }
893   Draw::Repaint();
894   return 0;
895 }
896
897
898 //=======================================================================
899 //function : triangle
900 //purpose  : 
901 //=======================================================================
902
903 static Standard_Integer triangle (Draw_Interpretor&, Standard_Integer n, const char** a)
904 {
905   if (n < 3) return 1;
906
907   Handle(MeshTest_DrawableMesh) D =
908     Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(a[1]));
909   if (D.IsNull()) return 1;
910
911   Standard_Integer i,j,v;
912   TColStd_SequenceOfInteger& tseq = D->Triangles();
913   for (i = 2; i < n; i++) {
914     v = Draw::Atoi(a[i]);
915     if (v > 0)
916       tseq.Append(v);
917     else if (v < 0) {
918       v = -v;
919       j = 1;
920       while (j <= tseq.Length()) {
921         if (tseq(j) == v)
922           tseq.Remove(v);
923         else
924           j++;
925       }
926     }
927     else
928       tseq.Clear();
929   }
930   Draw::Repaint();
931   return 0;
932 }
933
934 //=======================================================================
935 //function : dumpvertex
936 //purpose  : 
937 //=======================================================================
938
939 /*
940 Standard_Integer dumpvertex(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
941 {
942 if (argc < 2) return 1;
943
944 Handle(MeshTest_DrawableMesh) D =
945 Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(argv[1]));
946 if (D.IsNull()) return 1;
947
948 Handle(BRepMesh_DataStructureOfDelaun) struc = D->Mesh()->Result();
949
950 Standard_Integer in=1;
951 if (argc>=3) {
952 in=Draw::Atoi(argv[2]);
953 in=Max(1,in);
954 }
955 Standard_Integer nbn=in;
956 if (argc>=4) {
957 nbn=Draw::Atoi(argv[3]);
958 nbn=Min(nbn,struc->NbNodes());
959 }
960
961 for (; in<=nbn; in++) {
962 BRepMesh_Vertex nod=struc->GetNode(in);
963 di<<"(node "<<in<<" (uv "<<nod.Coord().X()
964 <<" "<<nod.Coord().Y()<<") (3d "
965 <<nod.Location3d()<<") ";
966 printdegree(nod.Movability(), di);
967 di<<" (edgeconex";
968 BRepMesh_ListOfInteger::Iterator tati(struc->LinkNeighboursOf(in));
969 for (; tati.More(); tati.Next()) di<<" "<<tati.Value();
970 di << "))\n";
971 }
972 di <<"\n";
973 return 0;
974 }
975
976 //=======================================================================
977 //function : dumpedge
978 //purpose  : 
979 //=======================================================================
980
981 Standard_Integer dumpedge(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
982 {
983 if (argc < 2) return 1;
984
985 Handle(MeshTest_DrawableMesh) D =
986 Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(argv[1]));
987 if (D.IsNull()) return 1;
988
989 Handle(BRepMesh_DataStructureOfDelaun) struc=D->Mesh()->Result();
990 Standard_Integer il=1;
991 if (argc>=3) {
992 il=Draw::Atoi(argv[2]);
993 il=Max(1, il);
994 }
995 Standard_Integer nbl=il;
996 if (argc>=4) {
997 nbl=Draw::Atoi(argv[3]);
998 nbl=Min(nbl, struc->NbLinks());
999 }
1000
1001 for (; il<=nbl; il++) {
1002 BRepMesh_Edge edg=struc->GetLink(il);
1003 di << "(edge "<<il<<" ("<<edg.FirstNode()<<" "<<edg.LastNode()
1004 <<" ";
1005 printdegree(edg.Movability(), di);
1006 di<<") (triconex";
1007 const BRepMesh_PairOfIndex& pair = struc->ElemConnectedTo(il);
1008 for (Standard_Integer j = 1, jn = pair.Extent(); j <= jn; j++)
1009 di<<" "<<pair.Index(j);
1010 di << "))\n";
1011 }
1012 di <<"\n";
1013 return 0;
1014 }
1015
1016 //=======================================================================
1017 //function : dumptriangle
1018 //purpose  : 
1019 //=======================================================================
1020
1021 Standard_Integer dumptriangle(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1022 {
1023 if (argc < 2) return 1;
1024
1025 Handle(MeshTest_DrawableMesh) D =
1026 Handle(MeshTest_DrawableMesh)::DownCast(Draw::Get(argv[1]));
1027 if (D.IsNull()) return 1;
1028
1029 Handle(BRepMesh_DataStructureOfDelaun) struc=D->Mesh()->Result();
1030 Standard_Integer ie=1;
1031 if (argc>=3) {
1032 ie=Draw::Atoi(argv[2]);
1033 ie=Max(1, ie);
1034 }
1035 Standard_Integer nbe=ie;
1036 if (argc>=4) {
1037 nbe=Draw::Atoi(argv[3]);
1038 nbe=Min(nbe, struc->NbElements());
1039 }
1040
1041 Standard_Integer e1, e2, e3;
1042 Standard_Boolean o1, o2, o3;
1043
1044 for (; ie<=nbe; ie++) {
1045 BRepMesh_Triangle tri=struc->GetElement(ie);
1046 tri.Edges(e1, e2, e3, o1, o2, o3); 
1047 if (o1) e1=-e1;
1048 if (o2) e2=-e2;
1049 if (o3) e3=-e3;
1050 di<<" (maille "<<ie<<" (links "<<e1<<" "
1051 <<e2<<" "<<e3<<")";
1052 printdegree(tri.Movability(), di);
1053 di<<")\n";
1054 }
1055 di << "\n";
1056 return 0;
1057 }
1058 */
1059
1060 //=======================================================================
1061 //function : trianglesinfo
1062 //purpose  : 
1063 //=======================================================================
1064 static Standard_Integer trianglesinfo(Draw_Interpretor& di, Standard_Integer n, const char** a)
1065 {
1066   if (n != 2) return 1;
1067   TopoDS_Shape S = DBRep::Get(a[1]);
1068   if (S.IsNull()) return 1;
1069   TopExp_Explorer ex;
1070   Handle(Poly_Triangulation) T;
1071   TopLoc_Location L;
1072
1073   Standard_Real MaxDeflection = 0.0;
1074   Standard_Integer nbtriangles = 0, nbnodes = 0;
1075   for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next()) {
1076     TopoDS_Face F = TopoDS::Face(ex.Current());
1077     T = BRep_Tool::Triangulation(F, L);
1078     if (!T.IsNull()) {
1079       nbtriangles += T->NbTriangles();
1080       nbnodes += T->NbNodes();
1081       if (T->Deflection() > MaxDeflection)
1082         MaxDeflection = T->Deflection();
1083     }
1084   }
1085
1086   di<<"\n";
1087   di<<"This shape contains " <<nbtriangles<<" triangles.\n";
1088   di<<"                    " <<nbnodes    <<" nodes.\n";
1089   di<<"Maximal deflection " <<MaxDeflection<<"\n";
1090   di<<"\n";
1091 #ifdef OCCT_DEBUG_MESH_CHRONO
1092   Standard_Real tot, addp, unif, contr, inter;
1093   Standard_Real edges, mailledges, etuinter, lastcontrol, stock;
1094   Standard_Real add11, add12, add2, upda, pointvalid;
1095   Standard_Real isos, pointsisos;
1096   chTotal.Show(tot); chAddPoint.Show(addp); chUnif.Show(unif); 
1097   chControl.Show(contr); chInternal.Show(inter);
1098   chEdges.Show(edges); chMaillEdges.Show(mailledges);
1099   chEtuInter.Show(etuinter); chLastControl.Show(lastcontrol); 
1100   chStock.Show(stock);
1101   chAdd11.Show(add11); chAdd12.Show(add12); chAdd2.Show(add2); chUpdate.Show(upda);
1102   chPointValid.Show(pointvalid); chIsos.Show(isos); chPointsOnIsos.Show(pointsisos);
1103
1104   if (tot > 0.00001) {
1105     di <<"temps total de maillage:     "<<tot        <<" seconds\n";
1106     di <<"dont: \n";
1107     di <<"discretisation des edges:    "<<edges      <<" seconds---> "<< 100*edges/tot      <<" %\n";
1108     di <<"maillage des edges:          "<<mailledges <<" seconds---> "<< 100*mailledges/tot <<" %\n";
1109     di <<"controle et points internes: "<<etuinter   <<" seconds---> "<< 100*etuinter/tot   <<" %\n";
1110     di <<"derniers controles:          "<<lastcontrol<<" seconds---> "<< 100*lastcontrol/tot<<" %\n";
1111     di <<"stockage dans la S.D.        "<<stock      <<" seconds---> "<< 100*stock/tot      <<" %\n";
1112     di << "\n";
1113     di <<"et plus precisement: \n";
1114     di <<"Add 11ere partie :           "<<add11     <<" seconds---> "<<100*add11/tot      <<" %\n";
1115     di <<"Add 12ere partie :           "<<add12     <<" seconds---> "<<100*add12/tot      <<" %\n";
1116     di <<"Add 2eme partie :            "<<add2      <<" seconds---> "<<100*add2/tot       <<" %\n";
1117     di <<"Update :                     "<<upda      <<" seconds---> "<<100*upda/tot       <<" %\n";
1118     di <<"AddPoint :                   "<<addp      <<" seconds---> "<<100*addp/tot       <<" %\n";
1119     di <<"UniformDeflection            "<<unif      <<" seconds---> "<<100*unif/tot       <<" %\n";
1120     di <<"Controle :                   "<<contr     <<" seconds---> "<<100*contr/tot      <<" %\n";
1121     di <<"Points Internes:             "<<inter     <<" seconds---> "<<100*inter/tot      <<" %\n";
1122     di <<"calcul des isos et du, dv:   "<<isos      <<" seconds---> "<<100*isos/tot       <<" %\n";
1123     di <<"calcul des points sur isos:  "<<pointsisos<<" seconds---> "<<100*pointsisos/tot <<" %\n";
1124     di <<"IsPointValid:                "<<pointvalid<<" seconds---> "<<100*pointvalid/tot <<" %\n";
1125     di << "\n";
1126
1127
1128     di <<"nombre d'appels de controle apres points internes          : "<< NbControls << "\n";
1129     di <<"nombre de points sur restrictions                          : "<< D0Edges    << "\n";
1130     di <<"nombre de points calcules par UniformDeflection            : "<< D0Unif     << "\n";
1131     di <<"nombre de points calcules dans InternalVertices            : "<< D0Internal << "\n";
1132     di <<"nombre de points calcules dans Control                     : "<< D0Control  << "\n";
1133     if (nbnodes-D0Edges != 0) { 
1134       Standard_Real ratio = (Standard_Real)(D0Internal+D0Control)/ (Standard_Real)(nbnodes-D0Edges);
1135       di <<"---> Ratio: (D0Internal+D0Control) / (nbNodes-nbOnEdges)   : "<< ratio      << "\n";
1136     }
1137
1138     di << "\n";
1139
1140     chTotal.Reset(); chAddPoint.Reset(); chUnif.Reset(); 
1141     chControl.Reset(); chInternal.Reset();
1142     chEdges.Reset(); chMaillEdges.Reset();
1143     chEtuInter.Reset(); chLastControl.Reset(); 
1144     chStock.Reset();
1145     chAdd11.Reset(); chAdd12.Reset(); chAdd2.Reset(); chUpdate.Reset();
1146     chPointValid.Reset(); chIsos.Reset(); chPointsOnIsos.Reset();
1147
1148   }
1149 #endif
1150   return 0;
1151 }
1152
1153 //=======================================================================
1154 //function : veriftriangles
1155 //purpose  : 
1156 //=======================================================================
1157
1158 static Standard_Integer veriftriangles(Draw_Interpretor& di, Standard_Integer n, const char** a)
1159 {
1160   if (n < 2) return 1;
1161   Standard_Boolean quiet = 1;
1162   if (n == 3) quiet = 0;
1163   TopoDS_Shape Sh = DBRep::Get(a[1]);
1164   if (Sh.IsNull()) return 1;
1165   TopExp_Explorer ex;
1166   Handle(Poly_Triangulation) T;
1167   TopLoc_Location L;
1168   Standard_Integer i, n1, n2, n3;
1169   gp_Pnt2d mitri, v1, v2, v3, mi2d1, mi2d2, mi2d3;
1170   gp_XYZ vecEd1, vecEd2, vecEd3;
1171   //  Standard_Real dipo, dm, dv, d1, d2, d3, defle;
1172   Standard_Real dipo, dv, d1, d2, d3, defle;
1173   Handle(Geom_Surface) S;
1174   Standard_Integer nbface = 0;
1175   gp_Pnt PP;
1176
1177   for (ex.Init(Sh, TopAbs_FACE); ex.More(); ex.Next()) {
1178     TopoDS_Face F = TopoDS::Face(ex.Current());
1179     nbface++;
1180     T = BRep_Tool::Triangulation(F, L);
1181     Standard_Real deflemax = 0, deflemin = 1.e100;
1182     if (!T.IsNull()) {
1183       Standard_Real defstock = T->Deflection();
1184       const Poly_Array1OfTriangle& triangles  = T->Triangles();
1185       const TColgp_Array1OfPnt2d&  Nodes2d    = T->UVNodes();
1186       const TColgp_Array1OfPnt&    Nodes      = T->Nodes();
1187
1188       S = BRep_Tool::Surface(F, L);
1189
1190       for(i = 1; i <= triangles.Length(); i++) {
1191         if (F.Orientation() == TopAbs_REVERSED) 
1192           triangles(i).Get(n1,n3,n2);
1193         else 
1194           triangles(i).Get(n1,n2,n3);
1195
1196         const gp_XY& xy1 = Nodes2d(n1).XY();
1197         const gp_XY& xy2 = Nodes2d(n2).XY();
1198         const gp_XY& xy3 = Nodes2d(n3).XY();
1199
1200         mi2d1.SetCoord((xy2.X()+xy3.X())*0.5, 
1201           (xy2.Y()+xy3.Y())*0.5);
1202         mi2d2.SetCoord((xy1.X()+xy3.X())*0.5, 
1203           (xy1.Y()+xy3.Y())*0.5);
1204         mi2d3.SetCoord((xy1.X()+xy2.X())*0.5, 
1205           (xy1.Y()+xy2.Y())*0.5);
1206
1207         gp_XYZ p1 = Nodes(n1).Transformed(L.Transformation()).XYZ();
1208         gp_XYZ p2 = Nodes(n2).Transformed(L.Transformation()).XYZ();
1209         gp_XYZ p3 = Nodes(n3).Transformed(L.Transformation()).XYZ();
1210
1211         vecEd1=p2-p1;
1212         vecEd2=p3-p2;
1213         vecEd3=p1-p3;
1214         d1=vecEd1.SquareModulus();
1215         d2=vecEd2.SquareModulus();
1216         d3=vecEd3.SquareModulus();
1217
1218         if (d1!=0. && d2!=0. && d3!=0.) {
1219           gp_XYZ equa(vecEd1^vecEd2);
1220           dv=equa.Modulus();
1221           if (dv>0.) {
1222             equa.SetCoord(equa.X()/dv, equa.Y()/dv, equa.Z()/dv);
1223             dipo=equa*p1;
1224
1225
1226             mitri.SetCoord(ONETHIRD*(xy1.X()+xy2.X()+xy3.X()),
1227               ONETHIRD*(xy1.Y()+xy2.Y()+xy3.Y()));
1228             v1.SetCoord(ONETHIRD*mi2d1.X()+TWOTHIRD*xy1.X(), 
1229               ONETHIRD*mi2d1.Y()+TWOTHIRD*xy1.Y());
1230             v2.SetCoord(ONETHIRD*mi2d2.X()+TWOTHIRD*xy2.X(), 
1231               ONETHIRD*mi2d2.Y()+TWOTHIRD*xy2.Y());
1232             v3.SetCoord(ONETHIRD*mi2d3.X()+TWOTHIRD*xy3.X(), 
1233               ONETHIRD*mi2d3.Y()+TWOTHIRD*xy3.Y());
1234
1235             S->D0(mi2d1.X(), mi2d1.Y(), PP);
1236             PP = PP.Transformed(L.Transformation());
1237             defle = Abs((equa*PP.XYZ())-dipo);
1238             deflemax = Max(deflemax, defle);
1239             deflemin = Min(deflemin, defle);
1240
1241             S->D0(mi2d2.X(), mi2d2.Y(), PP);
1242             PP = PP.Transformed(L.Transformation());
1243             defle = Abs((equa*PP.XYZ())-dipo);
1244             deflemax = Max(deflemax, defle);
1245             deflemin = Min(deflemin, defle);
1246
1247             S->D0(mi2d3.X(), mi2d3.Y(), PP);
1248             PP = PP.Transformed(L.Transformation());
1249             defle = Abs((equa*PP.XYZ())-dipo);
1250             deflemax = Max(deflemax, defle);
1251             deflemin = Min(deflemin, defle);
1252
1253             S->D0(v1.X(), v1.Y(), PP);
1254             PP = PP.Transformed(L.Transformation());
1255             defle = Abs((equa*PP.XYZ())-dipo);
1256             deflemax = Max(deflemax, defle);
1257             deflemin = Min(deflemin, defle);
1258
1259             S->D0(v2.X(), v2.Y(), PP);
1260             PP = PP.Transformed(L.Transformation());
1261             defle = Abs((equa*PP.XYZ())-dipo);
1262             deflemax = Max(deflemax, defle);
1263             deflemin = Min(deflemin, defle);
1264
1265             S->D0(v3.X(), v3.Y(), PP);
1266             PP = PP.Transformed(L.Transformation());
1267             defle = Abs((equa*PP.XYZ())-dipo);
1268             deflemax = Max(deflemax, defle);
1269             deflemin = Min(deflemin, defle);
1270
1271             S->D0(mitri.X(), mitri.Y(), PP);
1272             PP = PP.Transformed(L.Transformation());
1273             defle = Abs((equa*PP.XYZ())-dipo);
1274             deflemax = Max(deflemax, defle);
1275             deflemin = Min(deflemin, defle);
1276
1277             if (defle > defstock) {
1278               di <<"face "<< nbface <<" deflection = " << defle <<" pour "<<defstock <<" stockee.\n";
1279             }
1280           }
1281         }
1282       }
1283       if (!quiet) {
1284         di <<"face "<< nbface<<", deflemin = "<< deflemin<<", deflemax = "<<deflemax<<"\n";
1285       }
1286
1287     }
1288   }
1289
1290
1291   return 0;
1292 }
1293
1294
1295
1296
1297 //=======================================================================
1298 //function : tri2d
1299 //purpose  : 
1300 //=======================================================================
1301
1302 Standard_Integer tri2d(Draw_Interpretor&, Standard_Integer n, const char** a)
1303 {
1304
1305   if (n != 2) return 1;
1306   TopoDS_Shape aLocalShape = DBRep::Get(a[1]);
1307   TopoDS_Face F = TopoDS::Face(aLocalShape);
1308   //  TopoDS_Face F = TopoDS::Face(DBRep::Get(a[1]));
1309   if (F.IsNull()) return 1;
1310   Handle(Poly_Triangulation) T;
1311   TopLoc_Location L;
1312
1313   T = BRep_Tool::Triangulation(F, L);
1314   if (!T.IsNull()) {
1315     // Build the connect tool
1316     Poly_Connect pc(T);
1317
1318     Standard_Integer i,j, nFree, nInternal, nbTriangles = T->NbTriangles();
1319     Standard_Integer t[3];
1320
1321     // count the free edges
1322     nFree = 0;
1323     for (i = 1; i <= nbTriangles; i++) {
1324       pc.Triangles(i,t[0],t[1],t[2]);
1325       for (j = 0; j < 3; j++)
1326         if (t[j] == 0) nFree++;
1327     }
1328
1329     // allocate the arrays
1330     TColStd_Array1OfInteger Free(1,2*nFree);
1331     nInternal = (3*nbTriangles - nFree) / 2;
1332     TColStd_Array1OfInteger Internal(0,2*nInternal);
1333
1334     Standard_Integer fr = 1, in = 1;
1335     const Poly_Array1OfTriangle& triangles = T->Triangles();
1336     Standard_Integer nodes[3];
1337     for (i = 1; i <= nbTriangles; i++) {
1338       pc.Triangles(i,t[0],t[1],t[2]);
1339       triangles(i).Get(nodes[0],nodes[1],nodes[2]);
1340       for (j = 0; j < 3; j++) {
1341         Standard_Integer k = (j+1) % 3;
1342         if (t[j] == 0) {
1343           Free(fr)   = nodes[j];
1344           Free(fr+1) = nodes[k];
1345           fr += 2;
1346         }
1347         // internal edge if this triangle has a lower index than the adjacent
1348         else if (i < t[j]) {
1349           Internal(in)   = nodes[j];
1350           Internal(in+1) = nodes[k];
1351           in += 2;
1352         }
1353       }
1354     }
1355
1356     // Display the edges
1357     if (T->HasUVNodes()) {
1358       const TColgp_Array1OfPnt2d& Nodes2d = T->UVNodes();
1359
1360       Handle(Draw_Segment2D) Seg;
1361
1362       // free edges
1363       Standard_Integer nn;
1364       nn = Free.Length() / 2;
1365       for (i = 1; i <= nn; i++) {
1366         Seg = new Draw_Segment2D(Nodes2d(Free(2*i-1)),
1367           Nodes2d(Free(2*i)),
1368           Draw_rouge);
1369         dout << Seg;
1370       }
1371
1372       // internal edges
1373
1374       nn = nInternal;
1375       for (i = 1; i <= nn; i++) {
1376         Seg = new Draw_Segment2D(Nodes2d(Internal(2*i-1)),
1377           Nodes2d(Internal(2*i)),
1378           Draw_bleu);
1379         dout << Seg;
1380       }
1381     }
1382     dout.Flush();
1383   }
1384
1385   return 0;
1386 }
1387
1388
1389
1390
1391 //=======================================================================
1392 //function : wavefront
1393 //purpose  : 
1394 //=======================================================================
1395
1396 static Standard_Integer wavefront(Draw_Interpretor&, Standard_Integer nbarg, const char** argv)
1397 {
1398   if (nbarg < 2) return 1;
1399
1400   TopoDS_Shape S = DBRep::Get(argv[1]);
1401   if (S.IsNull()) return 1;
1402
1403   // creation du maillage s'il n'existe pas.
1404
1405   Bnd_Box B;
1406   Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
1407   BRepBndLib::Add(S, B);
1408   B.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
1409   Standard_Real aDeflection = 
1410     MAX3( aXmax-aXmin , aYmax-aYmin , aZmax-aZmin) * 0.004;
1411
1412   BRepMesh_IncrementalMesh aMesh (S, aDeflection);
1413
1414
1415   TopLoc_Location L;
1416   TopExp_Explorer ex;
1417
1418   Standard_Integer i, nbface = 0;
1419   Standard_Boolean OK = Standard_True;
1420   gp_Vec D1U,D1V;
1421   gp_Vec D2U,D2V,D2UV;
1422   gp_Dir Nor;
1423   gp_Pnt P;
1424   Standard_Real U, V;
1425   CSLib_DerivativeStatus aStatus;
1426   CSLib_NormalStatus NStat;
1427   Standard_Real x, y, z;
1428   Standard_Integer n1, n2, n3;
1429   Standard_Integer k1, k2, k3;
1430
1431   char ffile[100];
1432
1433   if (nbarg == 3) {
1434     strcpy(ffile, argv[2]);
1435     strcat(ffile, ".obj");
1436   }
1437   else  strcpy(ffile, "wave.obj");
1438   FILE* outfile = fopen(ffile, "w");
1439
1440
1441   fprintf(outfile, "%s  %s\n%s %s\n\n", "# CASCADE   ","MATRA DATAVISION", "#", ffile);
1442
1443   Standard_Integer nbNodes, totalnodes = 0, nbpolygons = 0;
1444   for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next()) {
1445     nbface++;
1446     TopoDS_Face F = TopoDS::Face(ex.Current());
1447     Handle(Poly_Triangulation) Tr = BRep_Tool::Triangulation(F, L);
1448
1449     if (!Tr.IsNull()) {
1450       nbNodes = Tr->NbNodes();
1451       const TColgp_Array1OfPnt& Nodes = Tr->Nodes();
1452
1453       // les noeuds.
1454       for (i = 1; i <= nbNodes; i++) {
1455         gp_Pnt Pnt = Nodes(i).Transformed(L.Transformation());
1456         x = Pnt.X();
1457         y = Pnt.Y();
1458         z = Pnt.Z();
1459         fprintf(outfile, "%s      %f  %f  %f\n", "v", x, y, z);
1460       }
1461
1462       fprintf(outfile, "\n%s    %d\n\n", "# number of vertex", nbNodes);
1463
1464
1465       // les normales.
1466
1467       if (Tr->HasUVNodes()) {
1468         const TColgp_Array1OfPnt2d& UVNodes = Tr->UVNodes();
1469         BRepAdaptor_Surface BS(F, Standard_False);
1470
1471         for (i = 1; i <= nbNodes; i++) {
1472           U = UVNodes(i).X();
1473           V = UVNodes(i).Y();
1474
1475           BS.D1(U,V,P,D1U,D1V);
1476           CSLib::Normal (D1U, D1V, Precision::Angular(), aStatus, Nor);
1477           if (aStatus != CSLib_Done) {
1478             BS.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
1479             CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,Nor);
1480           }
1481           if (F.Orientation() == TopAbs_REVERSED) Nor.Reverse();
1482
1483           fprintf(outfile, "%s      %f  %f  %f\n", "vn", Nor.X(), Nor.Y(), Nor.Z());
1484         }
1485
1486         fprintf(outfile, "\n%s    %d\n\n", "# number of vertex normals", nbNodes);
1487       }
1488
1489       fprintf(outfile, "%s    %d\n", "s", nbface);
1490
1491       // les triangles.
1492       Standard_Integer nbTriangles = Tr->NbTriangles();
1493       const Poly_Array1OfTriangle& triangles = Tr->Triangles();
1494
1495
1496       for (i = 1; i <= nbTriangles; i++) {
1497         if (F.Orientation()  == TopAbs_REVERSED)
1498           triangles(i).Get(n1, n3, n2);
1499         else 
1500           triangles(i).Get(n1, n2, n3);
1501         k1 = n1+totalnodes;
1502         k2 = n2+totalnodes;
1503         k3 = n3+totalnodes;
1504         fprintf(outfile, "%s %d%s%d %d%s%d %d%s%d\n", "fo", k1,"//", k1, k2,"//", k2, k3,"//", k3);
1505       }
1506       nbpolygons += nbTriangles;
1507       totalnodes += nbNodes;
1508
1509       fprintf(outfile, "\n%s    %d\n", "# number of smooth groups", nbface);
1510       fprintf(outfile, "\n%s    %d\n", "# number of polygons", nbpolygons);
1511
1512     }
1513   }
1514
1515   fclose(outfile);
1516
1517   return 0;
1518 }
1519
1520
1521 //=======================================================================
1522 //function : onetriangulation
1523 //purpose  : 
1524 //=======================================================================
1525
1526 Standard_Integer onetriangulation(Draw_Interpretor&, Standard_Integer /*nbarg*/, const char** /*argv*/)
1527 {
1528
1529   /*
1530
1531   if (nbarg < 2) return 1;
1532
1533   TopoDS_Shape S = DBRep::Get(argv[1]);
1534   if (S.IsNull()) return 1;
1535
1536   Handle(Poly_Triangulation) TFinale;
1537   char name[100];
1538   Standard_Integer nbshell = 0;
1539
1540   TopExp_Explorer ex, exs, ex2;
1541
1542   for (ex.Init(S, TopAbs_SHELL); ex.More(); ex.Next()) {
1543   nbshell++;
1544   TopoDS_Shell Sh = TopoDS::Shell(ex.Current());
1545
1546   for (exs.Init(Sh, TopAbs_Face); exs.More(); exs.Next()) {
1547   TopoDS_Face F = TopoDS::Face(exs.Current());
1548   Handle(Poly_Triangulation) T = BRep_Tool::Triangulation(F, L);
1549
1550   for (ex2.Init(F, TopAbs_EDGE); ex2.More(); ex2.Next()) {
1551   TopoDS_Edge edge = TopoDS::Edge(ex2.Current());
1552   const TColgp_Array1OfPnt& Nodes = T->Nodes();
1553   const Poly_Array1OfTriangle& triangles = T->Triangles();
1554
1555   if (mapedges.IsBound(edge)) {
1556   const TColStd_ListOfTransient& L = edges.Find(edge);
1557   const Handle(Poly_PolygonOnTriangulation)& P = 
1558   *(Handle(Poly_PolygonOnTriangulation)*)&(L.First());
1559   const TColStd_Array1OfInteger& NOD = P->Nodes();
1560
1561   }
1562   }
1563   }
1564
1565   Sprintf(name, "%s_%i", "tr", nbshell);
1566   DrawTrSurf::Set(name, TFinale);
1567
1568   }
1569
1570   */
1571   return 0;
1572 }
1573
1574
1575 #if 0
1576
1577 //=======================================================================
1578 //function : vb
1579 //purpose  : 
1580 //=======================================================================
1581
1582 Standard_Integer vb(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
1583 {
1584   Standard_Integer NbPoints = 1, Deg = 1;
1585
1586   for (Deg = 1; Deg <= 25; Deg++) {
1587     for (NbPoints = 1; NbPoints <= 24; NbPoints++) {
1588
1589       math_Vector GaussP(1, NbPoints), GaussW(1, NbPoints);
1590       math_Vector TheWeights(1, NbPoints), VBParam(1, NbPoints);
1591       math_Matrix VB(1, Deg+1, 1, NbPoints);
1592
1593       math::GaussPoints(NbPoints, GaussP);
1594
1595       Standard_Integer i, j, classe = Deg+1, cl1 = Deg;
1596
1597       // calcul et mise en ordre des parametres et des poids:
1598       for (i = 1; i <= NbPoints; i++) {
1599         if (i <=  (NbPoints+1)/2) {
1600           VBParam(NbPoints-i+1)  = 0.5*(1 + GaussP(i));
1601         }
1602         else {
1603           VBParam(i-(NbPoints+1)/2)  = 0.5*(1 + GaussP(i));
1604         }
1605       }
1606
1607
1608       // Calcul du VB (Valeur des fonctions de Bernstein):
1609       for (i = 1; i <= classe; i++) {
1610         for (j = 1; j <= NbPoints; j++) {
1611           VB(i,j)=PLib::Binomial(cl1,i-1)*Pow((1-VBParam(j)),classe-i)*Pow(VBParam(j),i-1);
1612         }
1613       }
1614
1615
1616       for (i = 1; i <= classe; i++) {
1617         for (j = 1; j <= NbPoints; j++) {
1618           di<< VB(i, j) << ", ";
1619         }
1620       }
1621       di << "\n\n";
1622     }
1623   }
1624   return 0;
1625 }  
1626 //=======================================================================
1627 //function : extrema
1628 //purpose  : 
1629 //=======================================================================
1630
1631 Standard_Integer extrema(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
1632 {
1633
1634
1635   Handle(Geom_Curve) C = DrawTrSurf::GetCurve(argv[1]);
1636
1637   Standard_Real X, Y, Z, U0;
1638   X = Draw::Atof(argv[2]);
1639   Y = Draw::Atof(argv[3]);
1640   Z = Draw::Atof(argv[4]);
1641   U0 = Draw::Atof(argv[5]);
1642
1643   gp_Pnt P(X, Y, Z);
1644   GeomAdaptor_Curve GC(C);
1645   Standard_Real tol = 1.e-09;
1646   Extrema_LocateExtPC ext(P, GC, U0, tol);
1647
1648   if (ext.IsDone()) {
1649     gp_Pnt P1 = ext.Point().Value();
1650     di <<"distance =  "<<ext.Value() << "\n";
1651     di <<"point =     "<<P1.X()<<" "<<P1.Y()<<" "<< P1.Z()<< "\n";
1652     di <<"parametre = "<<ext.Point().Parameter()<<"\n";
1653   }
1654
1655   return 0;
1656 }
1657
1658 #endif
1659
1660
1661 //=======================================================================
1662 //function : triedgepoints
1663 //purpose  : 
1664 //=======================================================================
1665
1666 Standard_Integer triedgepoints(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
1667 {
1668   if( nbarg < 2 )
1669     return 1;
1670
1671   for( Standard_Integer i = 1; i < nbarg; i++ )
1672   {
1673     TopoDS_Shape aShape = DBRep::Get(argv[i]);
1674     if ( aShape.IsNull() )
1675       continue;
1676
1677     Handle(Poly_PolygonOnTriangulation) aPoly;
1678     Handle(Poly_Triangulation)          aT;
1679     TopLoc_Location                     aLoc;
1680     TopTools_MapOfShape                 anEdgeMap;
1681     TopTools_MapIteratorOfMapOfShape    it;
1682     
1683     if( aShape.ShapeType() == TopAbs_EDGE )
1684     {
1685       anEdgeMap.Add( aShape );
1686     }
1687     else
1688     {
1689       TopExp_Explorer ex(aShape, TopAbs_EDGE);
1690       for(; ex.More(); ex.Next() )
1691         anEdgeMap.Add( ex.Current() );
1692     }
1693
1694     if ( anEdgeMap.Extent() == 0 )
1695       continue;
1696
1697     char newname[1024];
1698     strcpy(newname,argv[i]);
1699     char* p = newname;
1700     while (*p != '\0') p++;
1701     *p = '_';
1702     p++;
1703
1704     Standard_Integer nbEdge = 1;
1705     for(it.Initialize(anEdgeMap); it.More(); it.Next())
1706     {
1707       BRep_Tool::PolygonOnTriangulation(TopoDS::Edge(it.Key()), aPoly, aT, aLoc);
1708       if ( aT.IsNull() || aPoly.IsNull() )
1709         continue;
1710       
1711       const TColgp_Array1OfPnt&      Nodes   = aT->Nodes();
1712       const TColStd_Array1OfInteger& Indices = aPoly->Nodes();
1713       const Standard_Integer         nbnodes = Indices.Length();
1714
1715       for( Standard_Integer j = 1; j <= nbnodes; j++ )
1716       {
1717         gp_Pnt P3d = Nodes(Indices(j));
1718         if( !aLoc.IsIdentity() )
1719           P3d.Transform(aLoc.Transformation());
1720
1721         if( anEdgeMap.Extent() > 1 )
1722           Sprintf(p,"%d_%d",nbEdge,j);
1723         else
1724           Sprintf(p,"%d",j);
1725               DBRep::Set( newname, BRepBuilderAPI_MakeVertex(P3d) );
1726               di.AppendElement(newname);
1727       }
1728       nbEdge++;
1729     }
1730   }
1731   return 0;
1732 }
1733
1734 //=======================================================================
1735 //function : correctnormals
1736 //purpose  : Corrects normals in shape triangulation nodes (...)
1737 //=======================================================================
1738 Standard_Integer correctnormals (Draw_Interpretor& theDI, 
1739                             Standard_Integer /*theNArg*/, 
1740                             const char** theArgVal)
1741 {
1742   TopoDS_Shape S = DBRep::Get(theArgVal[1]);
1743
1744   //Use "correctnormals shape"
1745
1746   
1747   if(!BRepLib::EnsureNormalConsistency(S))
1748   {
1749     theDI << "Normals have not been changed!\n";
1750   }
1751   else
1752   {
1753     theDI << "Some corrections in source shape have been made!\n";
1754   }
1755
1756   return 0;
1757 }
1758
1759 //=======================================================================
1760 void  MeshTest::Commands(Draw_Interpretor& theCommands)
1761 //=======================================================================
1762 {
1763   Draw::Commands(theCommands);
1764   BRepTest::AllCommands(theCommands);
1765   GeometryTest::AllCommands(theCommands);
1766   MeshTest::PluginCommands(theCommands);
1767   const char* g;
1768
1769   g = "Mesh Commands";
1770
1771   theCommands.Add("incmesh","Builds triangular mesh for the shape, run w/o args for help",__FILE__, incrementalmesh, g);
1772   theCommands.Add("tessellate","Builds triangular mesh for the surface, run w/o args for help",__FILE__, tessellate, g);
1773   theCommands.Add("MemLeakTest","MemLeakTest",__FILE__, MemLeakTest, g);
1774   theCommands.Add("fastdiscret","fastdiscret shape deflection",__FILE__, fastdiscret, g);
1775   theCommands.Add("mesh","mesh result Shape deflection",__FILE__, triangule, g);
1776   theCommands.Add("addshape","addshape meshname Shape [deflection]",__FILE__, addshape, g);
1777   //theCommands.Add("smooth","smooth meshname",__FILE__, smooth, g);
1778   //theCommands.Add("edges","edges mesh shape, highlight the edges",__FILE__,edges, g);
1779   theCommands.Add("vertices","vertices mesh shape, highlight the vertices",__FILE__,vertices, g);
1780   theCommands.Add("medge","medge mesh [-]index (0 to clear all)",__FILE__,medge, g);
1781   theCommands.Add("mvertex","mvertex mesh [-]index (0 to clear all)",__FILE__,mvertex, g);
1782   theCommands.Add("triangle","triangle mesh [-]index (0 to clear all)",__FILE__,triangle, g);
1783   //theCommands.Add("dumpvertex","dumpvertex mesh [index]",__FILE__,dumpvertex, g);
1784   //theCommands.Add("dumpedge","dumpedge mesh [index]",__FILE__,dumpedge, g);
1785   //theCommands.Add("dumptriangle","dumptriangle mesh [index]",__FILE__,dumptriangle, g);
1786
1787   theCommands.Add("tri2d", "tri2d facename",__FILE__, tri2d, g);
1788   theCommands.Add("trinfo","trinfo name, print triangles information on objects",__FILE__,trianglesinfo,g);
1789   theCommands.Add("veriftriangles","veriftriangles name, verif triangles",__FILE__,veriftriangles,g);
1790   theCommands.Add("wavefront","wavefront name",__FILE__, wavefront, g);
1791   theCommands.Add("onetriangulation","onetriangulation name",__FILE__, onetriangulation, g);
1792   theCommands.Add("triepoints", "triepoints shape1 [shape2 ...]",__FILE__, triedgepoints, g);
1793
1794   theCommands.Add("correctnormals", "correctnormals shape",__FILE__, correctnormals, g);
1795
1796 #if 0
1797   theCommands.Add("extrema","extrema ",__FILE__, extrema, g);
1798   theCommands.Add("vb","vb ",__FILE__, vb, g);
1799 #endif
1800 }