1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-04 13:13:25 +03:00

0026106: BRepMesh - revision of data model

Removed tight connections between data structures, auxiliary tools and algorithms in order to create extensible solution, easy for maintenance and improvements;
Code is separated on several functional units responsible for specific operation for the sake of simplification of debugging and readability;
Introduced new data structures enabling possibility to manipulate discrete model of particular entity (edge, wire, face) in order to perform computations locally instead of processing an entire model.

The workflow of updated component can be divided on six parts:
* Creation of model data structure: source TopoDS_Shape passed to algorithm is analyzed and exploded on faces and edges. For each topological entity corresponding reflection is created in data model. Note that underlying algorithms use data model as input and access it via common interface which allows user to create custom data model with necessary dependencies between particular entities;
* Discretize edges 3D & 2D curves: 3D curve as well as associated set of 2D curves of each model edge is discretized in order to create coherent skeleton used as a base in faces meshing process. In case if some edge of source shape already contains polygonal data which suites specified parameters, it is extracted from shape and stored to the model as is. Each edge is processed separately, adjacency is not taken into account;
* Heal discrete model: source TopoDS_Shape can contain problems, such as open-wire or self-intersections, introduced during design, exchange or modification of model. In addition, some problems like self-intersections can be introduced by roughly discretized edges. This stage is responsible for analysis of discrete model in order to detect and repair faced problems or refuse model’s part for further processing in case if problem cannot be solved;
* Preprocess discrete model: defines actions specific for implemented approach to be performed before meshing of faces. By default, iterates over model faces and checks consistency of existing triangulations. Cleans topological faces and its adjacent edges from polygonal data in case of inconsistency or marks face of discrete model as not required for computation;
* Discretize faces: represents core part performing mesh generation for particular face based on 2D discrete data related to processing face. Caches polygonal data associated with face’s edges in data model for further processing and stores generated mesh to TopoDS_Face;
* Postprocess discrete model: defines actions specific for implemented approach to be performed after meshing of faces. By default, stores polygonal data obtained on previous stage to TopoDS_Edge objects of source model.

Component is now spread over IMeshData, IMeshTools, BRepMeshData and BRepMesh units.

<!break>

1. Extend "tricheck" DRAW-command in order to find degenerated triangles.

2. Class BRepMesh_FastDiscret::Parameters has been declared as deprecated.

3. NURBS range splitter: do not split intervals without necessity. Intervals are split only in case if it is impossible to compute normals directly on intervals.

4. Default value of IMeshTools_Parameters::MinSize has been changed. New value is equal to 0.1*Deflection.

5. Correction of test scripts:

1) perf mesh bug27119: requested deflection is increased from 1e-6 to 1e-5 to keep reasonable performance (but still reproducing original issue)
2) bugs mesh bug26692_1, 2: make snapshot of triangulation instead of wireframe (irrelevant)

Correction in upgrade guide.
This commit is contained in:
oan
2017-10-09 13:04:54 +03:00
committed by bugmaster
parent 80da8585f4
commit 7bd071edb1
261 changed files with 19333 additions and 7480 deletions

View File

@@ -28,8 +28,8 @@
#include <BRepMesh_DataStructureOfDelaun.hxx>
#include <BRepMesh_Delaun.hxx>
#include <BRepMesh_Edge.hxx>
#include <BRepMesh_FastDiscret.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <IMeshTools_Parameters.hxx>
#include <BRepMesh_Triangle.hxx>
#include <BRepMesh_Vertex.hxx>
#include <BRepTest.hxx>
@@ -80,6 +80,7 @@
#include <TopoDS_Wire.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <IMeshData_Status.hxx>
#include <stdio.h>
//epa Memory leaks test
@@ -140,14 +141,7 @@ options:\n\
return 0;
}
Standard_Real aLinDeflection = Max(Draw::Atof(argv[2]), Precision::Confusion());
Standard_Real aAngDeflection = 0.5;
Standard_Real aMinSize = Precision::Confusion();
Standard_Boolean isRelative = Standard_False;
Standard_Boolean isInParallel = Standard_False;
Standard_Boolean isIntVertices = Standard_True;
Standard_Boolean isControlSurDef = Standard_True;
Standard_Boolean isAdaptiveMin = Standard_False;
IMeshTools_Parameters aMeshParams;
if (nbarg > 3)
{
@@ -160,22 +154,22 @@ options:\n\
if (aOpt == "")
continue;
else if (aOpt == "-relative")
isRelative = Standard_True;
aMeshParams.Relative = Standard_True;
else if (aOpt == "-parallel")
isInParallel = Standard_True;
aMeshParams.InParallel = Standard_True;
else if (aOpt == "-int_vert_off")
isIntVertices = Standard_False;
aMeshParams.InternalVerticesMode = Standard_False;
else if (aOpt == "-surf_def_off")
isControlSurDef = Standard_False;
else if (aOpt == "-adaptive")
isAdaptiveMin = Standard_True;
aMeshParams.ControlSurfaceDeflection = Standard_False;
else if (i < nbarg)
{
Standard_Real aVal = Draw::Atof(argv[i++]);
if (aOpt == "-a")
aAngDeflection = aVal * M_PI / 180.;
{
aMeshParams.Angle = aVal * M_PI / 180.;
}
else if (aOpt == "-min")
aMinSize = aVal;
aMeshParams.MinSize = aVal;
else
--i;
}
@@ -183,47 +177,53 @@ options:\n\
}
di << "Incremental Mesh, multi-threading "
<< (isInParallel ? "ON" : "OFF") << "\n";
<< (aMeshParams.InParallel ? "ON" : "OFF") << "\n";
BRepMesh_FastDiscret::Parameters aMeshParams;
aMeshParams.Deflection = aLinDeflection;
aMeshParams.Angle = aAngDeflection;
aMeshParams.Relative = isRelative;
aMeshParams.InParallel = isInParallel;
aMeshParams.MinSize = aMinSize;
aMeshParams.InternalVerticesMode = isIntVertices;
aMeshParams.ControlSurfaceDeflection = isControlSurDef;
aMeshParams.AdaptiveMin = isAdaptiveMin;
BRepMesh_IncrementalMesh aMesher (aShape, aMeshParams);
di << "Meshing statuses: ";
Standard_Integer statusFlags = aMesher.GetStatusFlags();
if( !statusFlags )
const Standard_Integer aStatus = aMesher.GetStatusFlags();
if (!aStatus)
{
di << "NoError";
}
else
{
Standard_Integer i;
for( i = 0; i < 4; i++ )
for (i = 0; i < 8; i++)
{
if( (statusFlags >> i) & (Standard_Integer)1 )
Standard_Integer aFlag = aStatus & (1 << i);
if (aFlag)
{
switch(i+1)
switch ((IMeshData_Status) aFlag)
{
case 1:
di << "OpenWire ";
break;
case 2:
di << "SelfIntersectingWire ";
break;
case 3:
di << "Failure ";
break;
case 4:
di << "ReMesh ";
break;
case IMeshData_OpenWire:
di << "OpenWire ";
break;
case IMeshData_SelfIntersectingWire:
di << "SelfIntersectingWire ";
break;
case IMeshData_Failure:
di << "Failure ";
break;
case IMeshData_ReMesh:
di << "ReMesh ";
break;
case IMeshData_UnorientedWire:
di << "UnorientedWire ";
break;
case IMeshData_TooFewPoints:
di << "TooFewPoints ";
break;
case IMeshData_Outdated:
di << "Outdated ";
break;
case IMeshData_Reused:
di << "Reused ";
break;
case IMeshData_NoError:
default:
break;
}
}
}
@@ -401,114 +401,6 @@ static Standard_Integer MemLeakTest(Draw_Interpretor&, Standard_Integer /*nbarg*
return 0;
}
//=======================================================================
//function : fastdiscret
//purpose :
//=======================================================================
static Standard_Integer fastdiscret(Draw_Interpretor& di, Standard_Integer nbarg, const char** argv)
{
if (nbarg < 3) return 1;
TopoDS_Shape S = DBRep::Get(argv[1]);
if (S.IsNull()) return 1;
const Standard_Real d = Draw::Atof(argv[2]);
Bnd_Box B;
BRepBndLib::Add(S,B);
BRepMesh_FastDiscret::Parameters aParams;
aParams.Deflection = d;
aParams.Angle = 0.5;
BRepMesh_FastDiscret MESH(B,aParams);
//Standard_Integer NbIterations = MESH.NbIterations();
//if (nbarg > 4) NbIterations = Draw::Atoi(argv[4]);
//MESH.NbIterations() = NbIterations;
di<<"Starting FastDiscret with :\n";
di<<" Deflection="<<d<<"\n";
di<<" Angle="<<0.5<<"\n";
Handle(Poly_Triangulation) T;
BRep_Builder aBuilder;
TopExp_Explorer ex;
// Clear existing triangulations
for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next())
aBuilder.UpdateFace(TopoDS::Face(ex.Current()),T);
MESH.Perform(S);
TopoDS_Compound aCompGood, aCompFailed, aCompViolating;
TopLoc_Location L;
Standard_Integer nbtriangles = 0, nbnodes = 0, nbfailed = 0, nbviolating = 0;
Standard_Real maxdef = 0.0;
for (ex.Init(S, TopAbs_FACE); ex.More(); ex.Next())
{
T = BRep_Tool::Triangulation(TopoDS::Face(ex.Current()),L);
if (T.IsNull())
{
nbfailed++;
if (aCompFailed.IsNull())
aBuilder.MakeCompound(aCompFailed);
aBuilder.Add(aCompFailed,ex.Current());
}
else
{
nbtriangles += T->NbTriangles();
nbnodes += T->NbNodes();
if (T->Deflection() > maxdef) maxdef = T->Deflection();
if (T->Deflection() > d)
{
nbviolating++;
if (aCompViolating.IsNull())
aBuilder.MakeCompound(aCompViolating);
aBuilder.Add(aCompViolating,ex.Current());
}
else
{
if (aCompGood.IsNull())
aBuilder.MakeCompound(aCompGood);
aBuilder.Add(aCompGood,ex.Current());
}
}
}
if (!aCompGood.IsNull())
{
char name[256];
strcpy(name,argv[1]);
strcat(name,"_good");
DBRep::Set(name,aCompGood);
}
if (!aCompFailed.IsNull())
{
char name[256];
strcpy(name,argv[1]);
strcat(name,"_failed");
DBRep::Set(name,aCompFailed);
}
if (!aCompViolating.IsNull())
{
char name[256];
strcpy(name,argv[1]);
strcat(name,"_violating");
DBRep::Set(name,aCompViolating);
}
di<<"FastDiscret completed with :\n";
di<<" MaxDeflection="<<maxdef<<"\n";
di<<" NbNodes="<<nbnodes<<"\n";
di<<" NbTriangles="<<nbtriangles<<"\n";
di<<" NbFailed="<<nbfailed<<"\n";
di<<" NbViolating="<<nbviolating<<"\n";
return 0;
}
//=======================================================================
//function : triangule
//purpose :
@@ -1771,7 +1663,6 @@ void MeshTest::Commands(Draw_Interpretor& theCommands)
theCommands.Add("incmesh","Builds triangular mesh for the shape, run w/o args for help",__FILE__, incrementalmesh, g);
theCommands.Add("tessellate","Builds triangular mesh for the surface, run w/o args for help",__FILE__, tessellate, g);
theCommands.Add("MemLeakTest","MemLeakTest",__FILE__, MemLeakTest, g);
theCommands.Add("fastdiscret","fastdiscret shape deflection",__FILE__, fastdiscret, g);
theCommands.Add("mesh","mesh result Shape deflection",__FILE__, triangule, g);
theCommands.Add("addshape","addshape meshname Shape [deflection]",__FILE__, addshape, g);
//theCommands.Add("smooth","smooth meshname",__FILE__, smooth, g);

View File

@@ -29,6 +29,29 @@
#include <Poly_Triangulation.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Connect.hxx>
#include <Precision.hxx>
//=======================================================================
//function : ComputeArea
//purpose : Computes area of the triangle given by its three points (either 2D or3D)
//=======================================================================
static Standard_Real ComputeArea(const gp_XYZ& theP1,
const gp_XYZ& theP2,
const gp_XYZ& theP3)
{
return 0.5*(theP3 - theP1).Crossed(theP2 - theP1).Modulus();
}
//=======================================================================
//function : ComputeArea
//purpose : Computes area of the triangle given by its three points (either 2D or3D)
//=======================================================================
static Standard_Real ComputeArea(const gp_XY& theP1,
const gp_XY& theP2,
const gp_XY& theP3)
{
return 0.5*Abs((theP3 - theP1).Crossed(theP2 - theP1));
}
//=======================================================================
//function : Perform
@@ -87,25 +110,27 @@ void MeshTest_CheckTopology::Perform (Draw_Interpretor& di)
}
// check distances between corresponding points
Standard_Real aDefle = Max(aT1->Deflection(), aT2->Deflection());
Standard_Real aSqDefle = Max(aT1->Deflection(), aT2->Deflection());
aSqDefle *= aSqDefle;
const TColgp_Array1OfPnt& aPoints1 = aT1->Nodes();
const TColgp_Array1OfPnt& aPoints2 = aT2->Nodes();
Standard_Integer iF1 = aMapF.FindIndex(aFace1);
Standard_Integer iF2 = aMapF.FindIndex(aFace2);
Standard_Integer i1 = aNodes1.Lower();
Standard_Integer i2 = aNodes2.Lower();
gp_Trsf aTrsf1 = aFace1.Location().Transformation();
gp_Trsf aTrsf2 = aFace2.Location().Transformation();
const gp_Trsf &aTrsf1 = aFace1.Location().Transformation();
const gp_Trsf &aTrsf2 = aFace2.Location().Transformation();
for (; i1 <= aNodes1.Upper(); i1++, i2++) {
gp_Pnt aP1 = aPoints1(aNodes1(i1)).Transformed(aTrsf1);
gp_Pnt aP2 = aPoints2(aNodes2(i2)).Transformed(aTrsf2);
Standard_Real aDist = aP1.Distance(aP2);
if (aDist > aDefle) {
const gp_Pnt aP1 = aPoints1(aNodes1(i1)).Transformed(aTrsf1);
const gp_Pnt aP2 = aPoints2(aNodes2(i2)).Transformed(aTrsf2);
const Standard_Real aSqDist = aP1.SquareDistance(aP2);
if (aSqDist > aSqDefle)
{
myErrors.Append(iF1);
myErrors.Append(i1);
myErrors.Append(iF2);
myErrors.Append(i2);
myErrorsVal.Append(aDist);
myErrorsVal.Append(Sqrt(aSqDist));
}
}
}
@@ -122,6 +147,8 @@ void MeshTest_CheckTopology::Perform (Draw_Interpretor& di)
continue;
}
const gp_Trsf &aTrsf = aLoc.Transformation();
// remember boundary nodes
TColStd_PackedMapOfInteger aMapBndNodes;
TopExp_Explorer ex(aFace, TopAbs_EDGE);
@@ -149,6 +176,29 @@ void MeshTest_CheckTopology::Perform (Draw_Interpretor& di)
aUsedNodes.Add (n[1]);
aUsedNodes.Add (n[2]);
const gp_Pnt aPts[3] = {aT->Node(n[0]).Transformed(aTrsf),
aT->Node(n[1]).Transformed(aTrsf),
aT->Node(n[2]).Transformed(aTrsf)};
Standard_Real anArea = ComputeArea(aPts[0].XYZ(), aPts[1].XYZ(), aPts[2].XYZ());
if (anArea < Precision::SquareConfusion())
{
mySmallTrianglesFaces.Append(iF);
mySmallTrianglesTriangles.Append(i);
}
else if (aT->HasUVNodes())
{
const gp_XY aPUV[3] = {aT->UVNode(n[0]).XY(),
aT->UVNode(n[1]).XY(),
aT->UVNode(n[2]).XY()};
anArea = ComputeArea(aPUV[0], aPUV[1], aPUV[2]);
if (anArea < Precision::SquarePConfusion())
{
mySmallTrianglesFaces.Append(iF);
mySmallTrianglesTriangles.Append(i);
}
}
aConn.Triangles(i, t[0], t[1], t[2]);
for (j = 0; j < 3; j++) {
if (t[j] == 0) {

View File

@@ -101,6 +101,23 @@ public:
theNodeNum = myFreeNodeNums(theIndex);
}
//! Returns number of triangles with null area
Standard_Integer NbSmallTriangles() const
{
return mySmallTrianglesFaces.Length();
}
//! returns the number of face containing the Index-th detected
//! small triangle and number of the problematic triangle in
//! this face.
void GetSmallTriangle(const Standard_Integer theIndex,
Standard_Integer& theFaceNum,
Standard_Integer& theNodeNum) const
{
theFaceNum = mySmallTrianglesFaces(theIndex);
theNodeNum = mySmallTrianglesTriangles(theIndex);
}
private:
TopoDS_Shape myShape;
NCollection_IndexedDataMap<Standard_Integer,Handle(TColStd_HSequenceOfInteger)>
@@ -112,6 +129,9 @@ private:
TColStd_SequenceOfInteger myAsyncEdges;
TColStd_SequenceOfInteger myFreeNodeFaces;
TColStd_SequenceOfInteger myFreeNodeNums;
TColStd_SequenceOfInteger mySmallTrianglesFaces;
TColStd_SequenceOfInteger mySmallTrianglesTriangles;
};
#endif

View File

@@ -13,13 +13,16 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepMesh_FaceAttribute.hxx>
#include <Draw_Segment3D.hxx>
#include <DrawTrSurf_Polygon3D.hxx>
#include <Draw.hxx>
#include <TCollection_AsciiString.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <Poly_Polygon3D.hxx>
#include <BRepMesh_Edge.hxx>
#include <BRepMesh_Vertex.hxx>
#include <BRepMesh_Triangle.hxx>
#include <BRepMesh_DataStructureOfDelaun.hxx>
// This file defines global functions not declared in any public header,
// intended for use from debugger prompt (Command Window in Visual Studio)
@@ -28,15 +31,14 @@
//function : MeshTest_DrawLinks
//purpose : Draw links from mesh data structure of type BRepMesh_FaceAttribute
//=======================================================================
Standard_EXPORT const char* MeshTest_DrawLinks(const char* theNameStr, void* theFaceAttr)
Standard_EXPORT const char* MeshTest_DrawLinks(const char* theNameStr, void* theDataStruct)
{
if (theNameStr == 0 || theFaceAttr == 0)
if (theNameStr == 0 || theDataStruct == 0)
{
return "Error: name or face attribute is null";
}
try {
const Handle(BRepMesh_FaceAttribute)& aFaceAttr = *(Handle(BRepMesh_FaceAttribute)*)theFaceAttr;
const Handle(BRepMesh_DataStructureOfDelaun)& aMeshData = aFaceAttr->ChangeStructure();
const Handle(BRepMesh_DataStructureOfDelaun)& aMeshData = *(Handle(BRepMesh_DataStructureOfDelaun)*)theDataStruct;
if (aMeshData.IsNull())
return "Null mesh data structure";
Standard_Integer nbLinks = aMeshData->NbLinks();
@@ -51,9 +53,9 @@ Standard_EXPORT const char* MeshTest_DrawLinks(const char* theNameStr, void* the
Standard_Integer n2 = aLink.LastNode();
const BRepMesh_Vertex& aV1 = aMeshData->GetNode(n1);
const BRepMesh_Vertex& aV2 = aMeshData->GetNode(n2);
const gp_Pnt& aP1 = aFaceAttr->GetPoint(aV1);
const gp_Pnt& aP2 = aFaceAttr->GetPoint(aV2);
Handle(Draw_Segment3D) aSeg = new Draw_Segment3D(aP1, aP2, Draw_bleu);
Handle(Draw_Segment3D) aSeg = new Draw_Segment3D(gp_Pnt(aV1.Coord().X(), aV1.Coord().Y(), 0),
gp_Pnt(aV2.Coord().X(), aV2.Coord().Y(), 0),
Draw_bleu);
Draw::Set((aName + "_" + i).ToCString(), aSeg);
}
return theNameStr;
@@ -68,16 +70,16 @@ Standard_EXPORT const char* MeshTest_DrawLinks(const char* theNameStr, void* the
//function : MeshTest_DrawTriangles
//purpose : Draw triangles from mesh data structure of type BRepMesh_FaceAttribute
//=======================================================================
Standard_EXPORT const char* MeshTest_DrawTriangles(const char* theNameStr, void* theFaceAttr)
Standard_EXPORT const char* MeshTest_DrawTriangles(const char* theNameStr, void* theDataStruct)
{
if (theNameStr == 0 || theFaceAttr == 0)
if (theNameStr == 0 || theDataStruct == 0)
{
return "Error: name or face attribute is null";
}
try {
const Handle(BRepMesh_FaceAttribute)& aFaceAttr =
*(Handle(BRepMesh_FaceAttribute)*)theFaceAttr;
const Handle(BRepMesh_DataStructureOfDelaun)& aMeshData = aFaceAttr->ChangeStructure();
const Handle(BRepMesh_DataStructureOfDelaun)& aMeshData =
*(Handle(BRepMesh_DataStructureOfDelaun)*)theDataStruct;
if (aMeshData.IsNull())
return "Null mesh data structure";
Standard_Integer nbElem = aMeshData->NbElements();
@@ -93,8 +95,10 @@ Standard_EXPORT const char* MeshTest_DrawTriangles(const char* theNameStr, void*
const BRepMesh_Vertex& aV1 = aMeshData->GetNode(n[0]);
const BRepMesh_Vertex& aV2 = aMeshData->GetNode(n[1]);
const BRepMesh_Vertex& aV3 = aMeshData->GetNode(n[2]);
gp_Pnt aP[4] = { aFaceAttr->GetPoint(aV1), aFaceAttr->GetPoint(aV2),
aFaceAttr->GetPoint(aV3), aFaceAttr->GetPoint(aV1) };
gp_Pnt aP[4] = { gp_Pnt(aV1.Coord().X(), aV1.Coord().Y(), 0),
gp_Pnt(aV2.Coord().X(), aV2.Coord().Y(), 0),
gp_Pnt(aV3.Coord().X(), aV3.Coord().Y(), 0),
gp_Pnt(aV1.Coord().X(), aV1.Coord().Y(), 0) };
TColgp_Array1OfPnt aPnts(aP[0], 1, 4);
Handle(Poly_Polygon3D) aPoly = new Poly_Polygon3D(aPnts);
Handle(DrawTrSurf_Polygon3D) aDPoly = new DrawTrSurf_Polygon3D(aPoly);

View File

@@ -29,7 +29,7 @@
#include <BRepMesh_Triangle.hxx>
#include <BRepMesh_DataStructureOfDelaun.hxx>
#include <TopExp_Explorer.hxx>
#include <BRep_Tool.hxx>
IMPLEMENT_STANDARD_RTTIEXT(MeshTest_DrawableMesh,Draw_Drawable3D)
@@ -86,7 +86,7 @@ void MeshTest_DrawableMesh::Add(const TopoDS_Shape& theShape)
{
myMesher = new BRepMesh_IncrementalMesh;
myMesher->ChangeParameters().Deflection = myDeflection;
myMesher->ChangeParameters().Angle = 0.5;
myMesher->ChangeParameters().Angle = 0.5;
}
myMesher->SetShape(theShape);

View File

@@ -46,6 +46,8 @@
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
static Standard_Integer mpnames (Draw_Interpretor& , Standard_Integer , const char** );
static Standard_Integer mpsetdefaultname (Draw_Interpretor& , Standard_Integer , const char** );
@@ -82,7 +84,8 @@ void MeshTest::PluginCommands(Draw_Interpretor& theCommands)
theCommands.Add("mpparallel" , "mpparallel [toTurnOn] : show / set multi-threading flag for incremental mesh",
__FILE__, mpparallel, g);
theCommands.Add("triarea","shape [eps] (computes triangles and surface area)",__FILE__, triarea, g);
theCommands.Add("tricheck", "shape (checks triangulation of shape)", __FILE__, tricheck, g);
theCommands.Add("tricheck", "shape [-small] (checks triangulation of shape);\n"
"\"-small\"-option allows finding triangles with small area", __FILE__, tricheck, g);
}
//=======================================================================
@@ -343,9 +346,11 @@ static Standard_Integer tricheck (Draw_Interpretor& di, int n, const char ** a)
TopoDS_Shape shape = DBRep::Get(a[1]);
if (shape.IsNull()) return 1;
const Standard_Boolean isToFindSmallTriangles = (n >= 3) ? (strcmp(a[2], "-small") == 0) : Standard_False;
TopTools_IndexedMapOfShape aMapF;
TopExp::MapShapes (shape, TopAbs_FACE, aMapF);
Standard_CString name = ".";
const Standard_CString name = ".";
// execute check
MeshTest_CheckTopology aCheck(shape);
@@ -443,13 +448,74 @@ static Standard_Integer tricheck (Draw_Interpretor& di, int n, const char ** a)
di << "\n";
}
// output errors summary to DRAW
if ( nbFree > 0 || nbErr > 0 || nbAsync > 0 || nbFreeNodes > 0)
di << "Free_links " << nbFree
<< " Cross_face_errors " << nbErr
<< " Async_edges " << nbAsync
<< " Free_nodes " << nbFreeNodes << "\n";
const Standard_Integer aNbSmallTriangles = isToFindSmallTriangles? aCheck.NbSmallTriangles() : 0;
if (aNbSmallTriangles > 0)
{
di << "triangles with null area (in pairs: face / triangle): \n";
for (i = 1; i <= aNbSmallTriangles; i++)
{
Standard_Integer aFaceId = 0, aTriID = 0;
aCheck.GetSmallTriangle(i, aFaceId, aTriID);
const TopoDS_Face& aFace = TopoDS::Face(aMapF.FindKey(aFaceId));
TopLoc_Location aLoc;
const gp_Trsf& aTrsf = aLoc.Transformation();
const Handle(Poly_Triangulation) aT = BRep_Tool::Triangulation(aFace, aLoc);
const Poly_Triangle &aTri = aT->Triangle(aTriID);
Standard_Integer aN1, aN2, aN3;
aTri.Get(aN1, aN2, aN3);
const TColgp_Array1OfPnt& aPoints = aT->Nodes();
TColgp_Array1OfPnt aPoles(1, 4);
aPoles(1) = aPoles(4) = aPoints(aN1).Transformed(aTrsf);
aPoles(2) = aPoints(aN2).Transformed(aTrsf);
aPoles(3) = aPoints(aN3).Transformed(aTrsf);
TColStd_Array1OfInteger aMults(1, 4);
aMults(1) = aMults(4) = 2;
aMults(2) = aMults(3) = 1;
TColStd_Array1OfReal aKnots(1, 4);
aKnots(1) = 1.0;
aKnots(2) = 2.0;
aKnots(3) = 3.0;
aKnots(4) = 4.0;
Handle(Geom_BSplineCurve) aBS = new Geom_BSplineCurve(aPoles, aKnots, aMults, 1);
DrawTrSurf::Set(name, aBS);
if (aT->HasUVNodes())
{
TColgp_Array1OfPnt2d aPoles2d(1, 4);
aPoles2d(1) = aPoles2d(4) = aT->UVNodes()(aN1);
aPoles2d(2) = aT->UVNodes()(aN2);
aPoles2d(3) = aT->UVNodes()(aN3);
Handle(Geom2d_BSplineCurve) aBS2d = new Geom2d_BSplineCurve(aPoles2d, aKnots, aMults, 1);
DrawTrSurf::Set(name, aBS2d);
}
di << "{" << aFaceId << " " << aTriID << "} ";
}
di << "\n";
}
// output errors summary to DRAW
if (nbFree > 0 ||
nbErr > 0 ||
nbAsync > 0 ||
nbFreeNodes > 0 ||
(aNbSmallTriangles > 0))
{
di << "Free_links " << nbFree
<< " Cross_face_errors " << nbErr
<< " Async_edges " << nbAsync
<< " Free_nodes " << nbFreeNodes
<< " Small triangles " << aNbSmallTriangles << "\n";
}
Standard_Integer aFaceId = 1;
TopExp_Explorer aFaceExp(shape, TopAbs_FACE);