1 // Created on: 2008-04-11
2 // Created by: Peter KURNEV
3 // Copyright (c) 2008-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <Bnd_Box.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepGProp.hxx>
20 #include <BRepMesh_DiscretFactory.hxx>
21 #include <BRepMesh_DiscretRoot.hxx>
22 #include <BRepMesh_Edge.hxx>
23 #include <BRepMesh_FactoryError.hxx>
24 #include <BRepMesh_IncrementalMesh.hxx>
27 #include <Draw_Interpretor.hxx>
28 #include <DrawTrSurf.hxx>
30 #include <GProp_GProps.hxx>
31 #include <MeshTest.hxx>
32 #include <MeshTest_CheckTopology.hxx>
33 #include <NCollection_Map.hxx>
34 #include <Poly_Polygon2D.hxx>
35 #include <Poly_Polygon3D.hxx>
36 #include <Poly_PolygonOnTriangulation.hxx>
37 #include <Poly_Triangulation.hxx>
38 #include <Standard.hxx>
39 #include <TColgp_Array1OfPnt2d.hxx>
40 #include <TCollection_AsciiString.hxx>
41 #include <TColStd_Array1OfInteger.hxx>
42 #include <TColStd_MapIteratorOfMapOfAsciiString.hxx>
43 #include <TColStd_MapOfAsciiString.hxx>
45 #include <TopExp_Explorer.hxx>
47 #include <TopoDS_Face.hxx>
48 #include <TopTools_IndexedMapOfShape.hxx>
49 #include <Geom_BSplineCurve.hxx>
50 #include <Geom2d_BSplineCurve.hxx>
52 static Standard_Integer mpnames (Draw_Interpretor& , Standard_Integer , const char** );
53 static Standard_Integer mpsetdefaultname (Draw_Interpretor& , Standard_Integer , const char** );
54 static Standard_Integer mpgetdefaultname (Draw_Interpretor& , Standard_Integer , const char** );
55 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
56 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer , const char** );
57 static Standard_Integer mperror (Draw_Interpretor& , Standard_Integer , const char** );
58 static Standard_Integer mpincmesh (Draw_Interpretor& , Standard_Integer , const char** );
59 static Standard_Integer mpparallel (Draw_Interpretor& , Standard_Integer , const char** );
60 static Standard_Integer triarea (Draw_Interpretor& , Standard_Integer , const char** );
61 static Standard_Integer tricheck (Draw_Interpretor& , Standard_Integer , const char** );
63 //=======================================================================
64 //function : PluginCommands
66 //=======================================================================
67 void MeshTest::PluginCommands(Draw_Interpretor& theCommands)
69 static Standard_Boolean done = Standard_False;
75 const char* g = "Mesh Commands";
77 theCommands.Add("mpnames" , "use mpnames" , __FILE__, mpnames , g);
78 theCommands.Add("mpsetdefaultname" , "use mpsetdefaultname" , __FILE__, mpsetdefaultname , g);
79 theCommands.Add("mpgetdefaultname" , "use mpgetdefaultname" , __FILE__, mpgetdefaultname , g);
80 theCommands.Add("mpsetfunctionname", "use mpsetfunctionname", __FILE__, mpsetfunctionname , g);
81 theCommands.Add("mpgetfunctionname", "use mpgetfunctionname", __FILE__, mpgetfunctionname , g);
82 theCommands.Add("mperror" , "use mperror" , __FILE__, mperror , g);
83 theCommands.Add("mpincmesh" , "use mpincmesh" , __FILE__, mpincmesh , g);
84 theCommands.Add("mpparallel" , "mpparallel [toTurnOn] : show / set multi-threading flag for incremental mesh",
85 __FILE__, mpparallel, g);
86 theCommands.Add("triarea","shape [eps] (computes triangles and surface area)",__FILE__, triarea, g);
87 theCommands.Add("tricheck", "shape [-small] (checks triangulation of shape);\n"
88 "\"-small\"-option allows finding triangles with small area", __FILE__, tricheck, g);
91 //=======================================================================
94 //=======================================================================
95 static Standard_Integer mpnames (Draw_Interpretor& , Standard_Integer n, const char** )
98 TColStd_MapIteratorOfMapOfAsciiString aIt;
101 printf(" use mpnames\n");
105 const TColStd_MapOfAsciiString& aMN=BRepMesh_DiscretFactory::Get().Names();
108 printf(" *no names found\n");
112 printf(" *available names:\n");
114 for (; aIt.More(); aIt.Next()) {
115 const TCollection_AsciiString& aName=aIt.Key();
116 printf(" %s\n", aName.ToCString());
121 //=======================================================================
122 //function : mpsetdefaultname
124 //=======================================================================
125 static Standard_Integer mpsetdefaultname (Draw_Interpretor& , Standard_Integer n, const char**a )
127 TCollection_AsciiString aName;
130 printf(" use mpsetdefaultname name\n");
136 if (BRepMesh_DiscretFactory::Get().SetDefaultName (aName))
143 //=======================================================================
144 //function : mpgetdefaultname
146 //=======================================================================
147 static Standard_Integer mpgetdefaultname (Draw_Interpretor& , Standard_Integer n, const char** )
150 printf(" use mpgetdefaultname\n");
154 const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().DefaultName();
155 printf(" *default name: %s\n", aName.ToCString());
159 //=======================================================================
160 //function : mpsetfunctionname
162 //=======================================================================
163 static Standard_Integer mpsetfunctionname (Draw_Interpretor& , Standard_Integer n, const char**a )
165 TCollection_AsciiString aName;
168 printf(" use mpsetfunctionname name\n");
174 if (BRepMesh_DiscretFactory::Get().SetFunctionName (aName))
181 //=======================================================================
182 //function : mpgetdefaultname
184 //=======================================================================
185 static Standard_Integer mpgetfunctionname (Draw_Interpretor& , Standard_Integer n, const char** )
188 printf(" use mpgetfunctionname\n");
192 const TCollection_AsciiString& aName=BRepMesh_DiscretFactory::Get().FunctionName();
193 printf(" *function name: %s\n", aName.ToCString());
197 //=======================================================================
200 //=======================================================================
201 static Standard_Integer mperror (Draw_Interpretor& , Standard_Integer n, const char** )
203 BRepMesh_FactoryError aErr;
206 printf(" use mperror\n");
210 aErr=BRepMesh_DiscretFactory::Get().ErrorStatus();
211 printf(" *ErrorStatus: %d\n", (int)aErr);
216 //=======================================================================
217 //function :mpincmesh
219 //=======================================================================
220 static Standard_Integer mpincmesh (Draw_Interpretor& , Standard_Integer n, const char** a)
222 Standard_Real aDeflection, aAngle;
226 printf(" use mpincmesh s deflection [angle]\n");
232 printf(" null shapes is not allowed here\n");
236 aDeflection=Draw::Atof(a[2]);
239 aAngle=Draw::Atof(a[3]);
242 Handle(BRepMesh_DiscretRoot) aMeshAlgo = BRepMesh_DiscretFactory::Get().Discret (aS,
246 BRepMesh_FactoryError aErr = BRepMesh_DiscretFactory::Get().ErrorStatus();
247 if (aErr != BRepMesh_FE_NOERROR)
249 printf(" *Factory::Get().ErrorStatus()=%d\n", (int)aErr);
252 if (aMeshAlgo.IsNull())
254 printf(" *Can not create the algo\n");
258 aMeshAlgo->Perform();
259 if (!aMeshAlgo->IsDone())
261 printf(" *Not done\n");
267 //#######################################################################
268 static Standard_Integer triarea (Draw_Interpretor& di, int n, const char ** a)
273 TopoDS_Shape shape = DBRep::Get(a[1]);
274 if (shape.IsNull()) return 1;
275 Standard_Real anEps = -1.;
277 anEps = Draw::Atof(a[2]);
279 TopTools_IndexedMapOfShape aMapF;
280 TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
282 // detect if a shape has triangulation
283 Standard_Boolean hasPoly = Standard_False;
285 for (i=1; i <= aMapF.Extent(); i++) {
286 const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
287 TopLoc_Location aLoc;
288 Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
289 if (!aPoly.IsNull()) {
290 hasPoly = Standard_True;
295 // compute area by triangles
298 for (i=1; i <= aMapF.Extent(); i++) {
299 const TopoDS_Face& aFace = TopoDS::Face(aMapF(i));
300 TopLoc_Location aLoc;
301 Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc);
302 if (aPoly.IsNull()) {
303 std::cout << "face "<<i<<" has no triangulation"<<std::endl;
306 const Poly_Array1OfTriangle& triangles = aPoly->Triangles();
307 const TColgp_Array1OfPnt& nodes = aPoly->Nodes();
308 for (int j=triangles.Lower(); j <= triangles.Upper(); j++) {
309 const Poly_Triangle& tri = triangles(j);
311 tri.Get (n1, n2, n3);
312 const gp_Pnt& p1 = nodes(n1);
313 const gp_Pnt& p2 = nodes(n2);
314 const gp_Pnt& p3 = nodes(n3);
317 double ar = v1.CrossMagnitude(v2);
324 // compute area by geometry
327 BRepGProp::SurfaceProperties(shape, props);
329 BRepGProp::SurfaceProperties(shape, props, anEps);
330 double aGeomArea = props.Mass();
332 di << aTriArea << " " << aGeomArea << "\n";
336 //#######################################################################
337 Standard_Boolean IsEqual(const BRepMesh_Edge& theFirst, const BRepMesh_Edge& theSecond)
339 return theFirst.IsEqual(theSecond);
342 static Standard_Integer tricheck (Draw_Interpretor& di, int n, const char ** a)
346 TopoDS_Shape shape = DBRep::Get(a[1]);
347 if (shape.IsNull()) return 1;
349 const Standard_Boolean isToFindSmallTriangles = (n >= 3) ? (strcmp(a[2], "-small") == 0) : Standard_False;
351 TopTools_IndexedMapOfShape aMapF;
352 TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
353 const Standard_CString name = ".";
356 MeshTest_CheckTopology aCheck(shape);
359 // dump info on free links inside the triangulation
360 Standard_Integer nbFree = 0;
361 Standard_Integer nbFac = aCheck.NbFacesWithFL(), i, k;
363 for (k=1; k <= nbFac; k++) {
364 Standard_Integer nbEdge = aCheck.NbFreeLinks(k);
365 Standard_Integer iF = aCheck.GetFaceNumWithFL(k);
367 di << "free links of face " << iF << "\n";
369 const TopoDS_Shape& aShape = aMapF.FindKey(iF);
370 const TopoDS_Face& aFace = TopoDS::Face(aShape);
371 TopLoc_Location aLoc;
372 Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
373 const TColgp_Array1OfPnt& aPoints = aT->Nodes();
374 const gp_Trsf& trsf = aLoc.Transformation();
376 TColgp_Array1OfPnt pnts(1,2);
377 TColgp_Array1OfPnt2d pnts2d(1,2);
378 for (i=1; i <= nbEdge; i++) {
379 Standard_Integer n1, n2;
380 aCheck.GetFreeLink(k, i, n1, n2);
381 di << "{" << n1 << " " << n2 << "} ";
382 pnts(1) = aPoints(n1).Transformed(trsf);
383 pnts(2) = aPoints(n2).Transformed(trsf);
384 Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
385 DrawTrSurf::Set (name, poly);
386 DrawTrSurf::Set (name, pnts(1));
387 DrawTrSurf::Set (name, pnts(2));
388 if (aT->HasUVNodes())
390 const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
391 pnts2d(1) = aPoints2d(n1);
392 pnts2d(2) = aPoints2d(n2);
393 Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
394 DrawTrSurf::Set (name, poly2d);
395 DrawTrSurf::Set (name, pnts2d(1));
396 DrawTrSurf::Set (name, pnts2d(2));
403 // dump info on cross face errors
404 Standard_Integer nbErr = aCheck.NbCrossFaceErrors();
406 di << "cross face errors: {face1, node1, face2, node2, distance}\n";
407 for (i=1; i <= nbErr; i++) {
408 Standard_Integer iF1, n1, iF2, n2;
410 aCheck.GetCrossFaceError(i, iF1, n1, iF2, n2, aVal);
411 di << "{" << iF1 << " " << n1 << " " << iF2 << " " << n2 << " " << aVal << "} ";
416 // dump info on edges
417 Standard_Integer nbAsync = aCheck.NbAsyncEdges();
419 di << "async edges:\n";
420 for (i=1; i <= nbAsync; i++) {
421 Standard_Integer ie = aCheck.GetAsyncEdgeNum(i);
427 // dump info on free nodes
428 Standard_Integer nbFreeNodes = aCheck.NbFreeNodes();
429 if (nbFreeNodes > 0) {
430 di << "free nodes (in pairs: face / node): \n";
431 for (i=1; i <= nbFreeNodes; i++) {
432 Standard_Integer iface, inode;
433 aCheck.GetFreeNodeNum(i, iface, inode);
435 const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(iface));
436 TopLoc_Location aLoc;
437 Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
438 const TColgp_Array1OfPnt& aPoints = aT->Nodes();
439 const gp_Trsf& trsf = aLoc.Transformation();
440 DrawTrSurf::Set (name, aPoints(inode).Transformed(trsf));
441 if (aT->HasUVNodes())
443 DrawTrSurf::Set (name, aT->UVNodes()(inode));
446 di << "{" << iface << " " << inode << "} ";
451 const Standard_Integer aNbSmallTriangles = isToFindSmallTriangles? aCheck.NbSmallTriangles() : 0;
452 if (aNbSmallTriangles > 0)
454 di << "triangles with null area (in pairs: face / triangle): \n";
455 for (i = 1; i <= aNbSmallTriangles; i++)
457 Standard_Integer aFaceId = 0, aTriID = 0;
458 aCheck.GetSmallTriangle(i, aFaceId, aTriID);
460 const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(aFaceId));
461 TopLoc_Location aLoc;
462 const gp_Trsf& aTrsf = aLoc.Transformation();
463 const Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
464 const Poly_Triangle &aTri = aT->Triangle(aTriID);
465 Standard_Integer aN1, aN2, aN3;
466 aTri.Get(aN1, aN2, aN3);
467 const TColgp_Array1OfPnt& aPoints = aT->Nodes();
469 TColgp_Array1OfPnt aPoles(1, 4);
470 aPoles(1) = aPoles(4) = aPoints(aN1).Transformed(aTrsf);
471 aPoles(2) = aPoints(aN2).Transformed(aTrsf);
472 aPoles(3) = aPoints(aN3).Transformed(aTrsf);
474 TColStd_Array1OfInteger aMults(1, 4);
475 aMults(1) = aMults(4) = 2;
476 aMults(2) = aMults(3) = 1;
478 TColStd_Array1OfReal aKnots(1, 4);
484 Handle(Geom_BSplineCurve) aBS = new Geom_BSplineCurve(aPoles, aKnots, aMults, 1);
486 DrawTrSurf::Set(name, aBS);
488 if (aT->HasUVNodes())
490 TColgp_Array1OfPnt2d aPoles2d(1, 4);
491 aPoles2d(1) = aPoles2d(4) = aT->UVNodes()(aN1);
492 aPoles2d(2) = aT->UVNodes()(aN2);
493 aPoles2d(3) = aT->UVNodes()(aN3);
495 Handle(Geom2d_BSplineCurve) aBS2d = new Geom2d_BSplineCurve(aPoles2d, aKnots, aMults, 1);
497 DrawTrSurf::Set(name, aBS2d);
500 di << "{" << aFaceId << " " << aTriID << "} ";
506 // output errors summary to DRAW
511 (aNbSmallTriangles > 0))
513 di << "Free_links " << nbFree
514 << " Cross_face_errors " << nbErr
515 << " Async_edges " << nbAsync
516 << " Free_nodes " << nbFreeNodes
517 << " Small triangles " << aNbSmallTriangles << "\n";
520 Standard_Integer aFaceId = 1;
521 TopExp_Explorer aFaceExp(shape, TopAbs_FACE);
522 for ( ; aFaceExp.More(); aFaceExp.Next(), ++aFaceId)
524 const TopoDS_Shape& aShape = aFaceExp.Current();
525 const TopoDS_Face& aFace = TopoDS::Face(aShape);
527 TopLoc_Location aLoc;
528 Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
530 // Iterate boundary edges
531 NCollection_Map<BRepMesh_Edge> aBoundaryEdgeMap;
532 TopExp_Explorer anExp(aShape, TopAbs_EDGE);
533 for ( ; anExp.More(); anExp.Next() )
535 TopLoc_Location anEdgeLoc;
536 const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
537 Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(anEdge, aT, aLoc);
543 const TColStd_Array1OfInteger& anIndices = aPoly->Nodes();
544 Standard_Integer aLower = anIndices.Lower();
545 Standard_Integer anUpper = anIndices.Upper();
547 Standard_Integer aPrevNode = -1;
548 for (Standard_Integer j = aLower; j <= anUpper; ++j)
550 Standard_Integer aNodeIdx = anIndices.Value(j);
553 BRepMesh_Edge aLink(aPrevNode, aNodeIdx, BRepMesh_Frontier);
554 aBoundaryEdgeMap.Add(aLink);
556 aPrevNode = aNodeIdx;
560 if (aBoundaryEdgeMap.Size() == 0)
565 const Poly_Array1OfTriangle& aTris = aT->Triangles();
566 NCollection_Map<BRepMesh_Edge> aFreeEdgeMap;
567 Standard_Integer aTriNum = aTris.Length();
568 for ( Standard_Integer aTriIndx = 1; aTriIndx <= aTriNum; aTriIndx++ )
570 const Poly_Triangle& aTri = aTris(aTriIndx);
571 Standard_Integer aTriNodes[3] = { aTri.Value(1), aTri.Value(2), aTri.Value(3)};
573 for (Standard_Integer j = 1; j <= 3; ++j)
575 Standard_Integer aLastId = aTriNodes[j % 3];
576 Standard_Integer aFirstId = aTriNodes[j - 1];
578 BRepMesh_Edge aLink(aFirstId, aLastId, BRepMesh_Free);
579 if (!aBoundaryEdgeMap.Contains(aLink))
581 if (!aFreeEdgeMap.Add(aLink))
583 aFreeEdgeMap.Remove(aLink);
589 if (aFreeEdgeMap.Size() != 0)
591 di << "Not connected mesh inside face " << aFaceId << "\n";
593 const TColgp_Array1OfPnt& aPoints = aT->Nodes();
594 const gp_Trsf& trsf = aLoc.Transformation();
596 TColgp_Array1OfPnt pnts(1,2);
597 TColgp_Array1OfPnt2d pnts2d(1,2);
598 NCollection_Map<BRepMesh_Edge>::Iterator aMapIt(aFreeEdgeMap);
599 for (; aMapIt.More(); aMapIt.Next())
601 const BRepMesh_Edge& aLink = aMapIt.Key();
602 di << "{" << aLink.FirstNode() << " " << aLink.LastNode() << "} ";
603 pnts(1) = aPoints(aLink.FirstNode()).Transformed(trsf);
604 pnts(2) = aPoints(aLink.LastNode()).Transformed(trsf);
605 Handle(Poly_Polygon3D) poly = new Poly_Polygon3D (pnts);
606 DrawTrSurf::Set (name, poly);
607 DrawTrSurf::Set (name, pnts(1));
608 DrawTrSurf::Set (name, pnts(2));
609 if (aT->HasUVNodes())
611 const TColgp_Array1OfPnt2d& aPoints2d = aT->UVNodes();
612 pnts2d(1) = aPoints2d(aLink.FirstNode());
613 pnts2d(2) = aPoints2d(aLink.LastNode());
614 Handle(Poly_Polygon2D) poly2d = new Poly_Polygon2D (pnts2d);
615 DrawTrSurf::Set (name, poly2d);
616 DrawTrSurf::Set (name, pnts2d(1));
617 DrawTrSurf::Set (name, pnts2d(2));
626 //=======================================================================
627 //function : mpparallel
629 //=======================================================================
630 static int mpparallel (Draw_Interpretor& /*di*/, Standard_Integer argc, const char** argv)
634 Standard_Boolean isParallelOn = Draw::Atoi (argv[1]) == 1;
635 BRepMesh_IncrementalMesh::SetParallelDefault (isParallelOn);
637 std::cout << "Incremental Mesh, multi-threading "
638 << (BRepMesh_IncrementalMesh::IsParallelDefault() ? "ON\n" : "OFF\n");