mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-07-17 20:17:11 +08:00
Mesh - Fix periodic seam constraints (#1338)
The base mesh algorithm created constraint links for all pcurves of an edge, including duplicate representations at periodic seams. Register nodes and mesh indices for all pcurves so polygon-on-triangulation data remains valid, but add links only for the pcurve of the wire occurrence.
This commit is contained in:
@@ -86,40 +86,59 @@ bool BRepMesh_BaseMeshAlgo::initDataStructure()
|
||||
|
||||
for (int aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt)
|
||||
{
|
||||
const IMeshData::IEdgeHandle aDEdge = aDWire->GetEdge(aEdgeIt);
|
||||
const IMeshData::ICurveHandle& aCurve = aDEdge->GetCurve();
|
||||
const IMeshData::ListOfInteger& aListOfPCurves = aDEdge->GetPCurves(myDFace.get());
|
||||
const IMeshData::IEdgeHandle aDEdge = aDWire->GetEdge(aEdgeIt);
|
||||
const IMeshData::ICurveHandle& aCurve = aDEdge->GetCurve();
|
||||
// A wire defines one topological occurrence of an edge. Registering every
|
||||
// pcurve attached to its face would create duplicate constraints at a periodic seam.
|
||||
const IMeshData::IPCurveHandle& aPCurve =
|
||||
aDEdge->GetPCurve(myDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt));
|
||||
const TopAbs_Orientation aOri = fixSeamEdgeOrientation(aDEdge, aPCurve);
|
||||
|
||||
int aPrevNodeIndex = -1;
|
||||
const int aLastPoint = aPCurve->ParametersNb() - 1;
|
||||
for (int aPointIndex = 0; aPointIndex <= aLastPoint; ++aPointIndex)
|
||||
{
|
||||
const int aNodeIndex = registerNode(aCurve->GetPoint(aPointIndex),
|
||||
aPCurve->GetPoint(aPointIndex),
|
||||
BRepMesh_Frontier,
|
||||
false);
|
||||
|
||||
aPCurve->GetIndex(aPointIndex) = aNodeIndex;
|
||||
|
||||
if (aPrevNodeIndex != -1 && aPrevNodeIndex != aNodeIndex)
|
||||
{
|
||||
const int aLinksNb = myStructure->NbLinks();
|
||||
const int aLinkIndex = addLinkToMesh(aPrevNodeIndex, aNodeIndex, aOri);
|
||||
if (aWireIt != 0 && aLinkIndex <= aLinksNb)
|
||||
{
|
||||
// Prevent holes around wire of zero area.
|
||||
BRepMesh_Edge& aLink = const_cast<BRepMesh_Edge&>(myStructure->GetLink(aLinkIndex));
|
||||
aLink.SetMovability(BRepMesh_Fixed);
|
||||
}
|
||||
}
|
||||
|
||||
aPrevNodeIndex = aNodeIndex;
|
||||
}
|
||||
|
||||
// Every pcurve needs node indices for Poly_PolygonOnTriangulation, but only
|
||||
// the pcurve belonging to this wire occurrence defines a mesh constraint.
|
||||
const IMeshData::ListOfInteger& aListOfPCurves = aDEdge->GetPCurves(myDFace.get());
|
||||
for (IMeshData::ListOfInteger::Iterator aPCurveIt(aListOfPCurves); aPCurveIt.More();
|
||||
aPCurveIt.Next())
|
||||
{
|
||||
const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(aPCurveIt.Value());
|
||||
const TopAbs_Orientation aOri = fixSeamEdgeOrientation(aDEdge, aPCurve);
|
||||
|
||||
int aPrevNodeIndex = -1;
|
||||
const int aLastPoint = aPCurve->ParametersNb() - 1;
|
||||
for (int aPointIndex = 0; aPointIndex <= aLastPoint; ++aPointIndex)
|
||||
const IMeshData::IPCurveHandle& anOtherPCurve = aDEdge->GetPCurve(aPCurveIt.Value());
|
||||
if (anOtherPCurve == aPCurve)
|
||||
{
|
||||
const int aNodeIndex = registerNode(aCurve->GetPoint(aPointIndex),
|
||||
aPCurve->GetPoint(aPointIndex),
|
||||
BRepMesh_Frontier,
|
||||
false);
|
||||
continue;
|
||||
}
|
||||
|
||||
aPCurve->GetIndex(aPointIndex) = aNodeIndex;
|
||||
|
||||
if (aPrevNodeIndex != -1 && aPrevNodeIndex != aNodeIndex)
|
||||
{
|
||||
const int aLinksNb = myStructure->NbLinks();
|
||||
const int aLinkIndex = addLinkToMesh(aPrevNodeIndex, aNodeIndex, aOri);
|
||||
if (aWireIt != 0 && aLinkIndex <= aLinksNb)
|
||||
{
|
||||
// Prevent holes around wire of zero area.
|
||||
BRepMesh_Edge& aLink = const_cast<BRepMesh_Edge&>(myStructure->GetLink(aLinkIndex));
|
||||
aLink.SetMovability(BRepMesh_Fixed);
|
||||
}
|
||||
}
|
||||
|
||||
aPrevNodeIndex = aNodeIndex;
|
||||
const int anOtherLastPoint = anOtherPCurve->ParametersNb() - 1;
|
||||
for (int aPointIndex = 0; aPointIndex <= anOtherLastPoint; ++aPointIndex)
|
||||
{
|
||||
anOtherPCurve->GetIndex(aPointIndex) = registerNode(aCurve->GetPoint(aPointIndex),
|
||||
anOtherPCurve->GetPoint(aPointIndex),
|
||||
BRepMesh_Frontier,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,37 @@
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <BRepPrimAPI_MakeCylinder.hxx>
|
||||
#include <BRepPrimAPI_MakeRevol.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
#include <IMeshTools_Parameters.hxx>
|
||||
#include <Poly_PolygonOnTriangulation.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Ax1.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
|
||||
@@ -71,3 +90,184 @@ TEST(BRepMesh_IncrementalMeshTest, OCC26407_PlanarPolygonMeshStatus)
|
||||
EXPECT_EQ(aMesher.GetStatusFlags(), 0)
|
||||
<< "Meshing of the planar polygon face should succeed (status 0)";
|
||||
}
|
||||
|
||||
TEST(BRepMesh_IncrementalMeshTest, TrimmedCylinder_RespectsUVRangeAndDeflection)
|
||||
{
|
||||
constexpr double THE_RADIUS = 5.0;
|
||||
constexpr double THE_FIRST_U = 0.4;
|
||||
constexpr double THE_LAST_U = 5.7;
|
||||
constexpr double THE_FIRST_V = -2.0;
|
||||
constexpr double THE_LAST_V = 7.0;
|
||||
constexpr double THE_DEFLECTION = 0.05;
|
||||
|
||||
occ::handle<Geom_CylindricalSurface> aCylinder =
|
||||
new Geom_CylindricalSurface(gp_Ax3(gp::Origin(), gp::DZ()), THE_RADIUS);
|
||||
BRepBuilderAPI_MakeFace aFaceBuilder(aCylinder,
|
||||
THE_FIRST_U,
|
||||
THE_LAST_U,
|
||||
THE_FIRST_V,
|
||||
THE_LAST_V,
|
||||
Precision::Confusion());
|
||||
ASSERT_TRUE(aFaceBuilder.IsDone());
|
||||
const TopoDS_Face aFace = aFaceBuilder.Face();
|
||||
|
||||
BRepMesh_IncrementalMesh aMesher(aFace, THE_DEFLECTION);
|
||||
ASSERT_TRUE(aMesher.IsDone());
|
||||
|
||||
TopLoc_Location aLocation;
|
||||
const occ::handle<Poly_Triangulation> aTriangulation = BRep_Tool::Triangulation(aFace, aLocation);
|
||||
ASSERT_FALSE(aTriangulation.IsNull());
|
||||
ASSERT_TRUE(aTriangulation->HasUVNodes());
|
||||
ASSERT_GT(aTriangulation->NbTriangles(), 0);
|
||||
|
||||
for (int aNodeIdx = 1; aNodeIdx <= aTriangulation->NbNodes(); ++aNodeIdx)
|
||||
{
|
||||
const gp_Pnt2d aUV = aTriangulation->UVNode(aNodeIdx);
|
||||
EXPECT_GE(aUV.X(), THE_FIRST_U - Precision::PConfusion());
|
||||
EXPECT_LE(aUV.X(), THE_LAST_U + Precision::PConfusion());
|
||||
EXPECT_GE(aUV.Y(), THE_FIRST_V - Precision::PConfusion());
|
||||
EXPECT_LE(aUV.Y(), THE_LAST_V + Precision::PConfusion());
|
||||
|
||||
const gp_Pnt anExpectedPoint = aCylinder->Value(aUV.X(), aUV.Y());
|
||||
const gp_Pnt anActualPoint = aTriangulation->Node(aNodeIdx).Transformed(aLocation);
|
||||
EXPECT_LE(anActualPoint.Distance(anExpectedPoint), Precision::Confusion());
|
||||
}
|
||||
|
||||
for (int aTriangleIdx = 1; aTriangleIdx <= aTriangulation->NbTriangles(); ++aTriangleIdx)
|
||||
{
|
||||
int aNode1 = 0;
|
||||
int aNode2 = 0;
|
||||
int aNode3 = 0;
|
||||
aTriangulation->Triangle(aTriangleIdx).Get(aNode1, aNode2, aNode3);
|
||||
|
||||
const gp_Pnt2d aUV1 = aTriangulation->UVNode(aNode1);
|
||||
const gp_Pnt2d aUV2 = aTriangulation->UVNode(aNode2);
|
||||
const gp_Pnt2d aUV3 = aTriangulation->UVNode(aNode3);
|
||||
const gp_Pnt anExpectedPoint = aCylinder->Value((aUV1.X() + aUV2.X() + aUV3.X()) / 3.0,
|
||||
(aUV1.Y() + aUV2.Y() + aUV3.Y()) / 3.0);
|
||||
const gp_Pnt aPoint1 = aTriangulation->Node(aNode1).Transformed(aLocation);
|
||||
const gp_Pnt aPoint2 = aTriangulation->Node(aNode2).Transformed(aLocation);
|
||||
const gp_Pnt aPoint3 = aTriangulation->Node(aNode3).Transformed(aLocation);
|
||||
const gp_Pnt anActualPoint((aPoint1.XYZ() + aPoint2.XYZ() + aPoint3.XYZ()) / 3.0);
|
||||
EXPECT_LE(anActualPoint.Distance(anExpectedPoint), THE_DEFLECTION);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BRepMesh_IncrementalMeshTest, BooleanTrimmedTorus_CrossingSeamProducesDenseMesh)
|
||||
{
|
||||
BRepPrimAPI_MakeBox aBoxBuilder(gp_Pnt(-187.0, -20.0, -67.5), gp_Pnt(187.0, 0.0, 67.5));
|
||||
const TopoDS_Shape aBox = aBoxBuilder.Shape();
|
||||
ASSERT_TRUE(aBoxBuilder.IsDone());
|
||||
|
||||
const gp_Circ aCircle(gp_Ax2(gp_Pnt(200.0, -20.0, 0.0), gp_Dir(0.0, -1.0, 0.0)), 17.5);
|
||||
BRepBuilderAPI_MakeEdge anEdgeBuilder(aCircle);
|
||||
const TopoDS_Edge anEdge = anEdgeBuilder.Edge();
|
||||
ASSERT_TRUE(anEdgeBuilder.IsDone());
|
||||
|
||||
BRepBuilderAPI_MakeWire aWireBuilder(anEdge);
|
||||
const TopoDS_Wire aWire = aWireBuilder.Wire();
|
||||
ASSERT_TRUE(aWireBuilder.IsDone());
|
||||
|
||||
BRepBuilderAPI_MakeFace aFaceBuilder(aWire, true);
|
||||
const TopoDS_Face aProfile = aFaceBuilder.Face();
|
||||
ASSERT_TRUE(aFaceBuilder.IsDone());
|
||||
|
||||
const gp_Ax1 anAxis(gp_Pnt(0.0, -20.0, 0.0), gp_Dir(0.0, 0.0, -1.0));
|
||||
BRepPrimAPI_MakeRevol aRingBuilder(aProfile, anAxis, 2.0 * M_PI);
|
||||
const TopoDS_Shape aRing = aRingBuilder.Shape();
|
||||
ASSERT_TRUE(aRingBuilder.IsDone());
|
||||
|
||||
BRepAlgoAPI_Fuse aFuse(aBox, aRing);
|
||||
aFuse.Build();
|
||||
ASSERT_TRUE(aFuse.IsDone());
|
||||
|
||||
const TopoDS_Shape aFused = aFuse.Shape();
|
||||
ASSERT_FALSE(aFused.IsNull());
|
||||
EXPECT_TRUE(BRepCheck_Analyzer(aFused).IsValid());
|
||||
|
||||
IMeshTools_Parameters aParameters;
|
||||
aParameters.Deflection = 0.1;
|
||||
aParameters.Angle = 0.4;
|
||||
BRepMesh_IncrementalMesh aMesher(aFused, aParameters);
|
||||
ASSERT_TRUE(aMesher.IsDone());
|
||||
|
||||
int aTorusFaces = 0;
|
||||
int aTorusNodes = 0;
|
||||
int aTorusTriangles = 0;
|
||||
for (TopExp_Explorer anExplorer(aFused, TopAbs_FACE); anExplorer.More(); anExplorer.Next())
|
||||
{
|
||||
const TopoDS_Face& aFace = TopoDS::Face(anExplorer.Current());
|
||||
BRepAdaptor_Surface aSurface(aFace);
|
||||
if (aSurface.GetType() != GeomAbs_Torus)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
++aTorusFaces;
|
||||
TopLoc_Location aLocation;
|
||||
const occ::handle<Poly_Triangulation> aTriangulation =
|
||||
BRep_Tool::Triangulation(aFace, aLocation);
|
||||
ASSERT_FALSE(aTriangulation.IsNull());
|
||||
aTorusNodes += aTriangulation->NbNodes();
|
||||
aTorusTriangles += aTriangulation->NbTriangles();
|
||||
}
|
||||
|
||||
ASSERT_GT(aTorusFaces, 0);
|
||||
// The regression produced fewer than 450 triangles for the whole fused shape.
|
||||
EXPECT_GT(aTorusNodes, 1000);
|
||||
EXPECT_GT(aTorusTriangles, 1000);
|
||||
}
|
||||
|
||||
TEST(BRepMesh_IncrementalMeshTest, ClosedCylinder_SeamPolygonsReferenceValidMeshNodes)
|
||||
{
|
||||
BRepPrimAPI_MakeCylinder aCylinderBuilder(5.0, 10.0);
|
||||
const TopoDS_Shape aCylinder = aCylinderBuilder.Shape();
|
||||
ASSERT_TRUE(aCylinderBuilder.IsDone());
|
||||
|
||||
BRepMesh_IncrementalMesh aMesher(aCylinder, 0.1);
|
||||
ASSERT_TRUE(aMesher.IsDone());
|
||||
|
||||
int aSeamEdges = 0;
|
||||
for (TopExp_Explorer aFaceExplorer(aCylinder, TopAbs_FACE); aFaceExplorer.More();
|
||||
aFaceExplorer.Next())
|
||||
{
|
||||
const TopoDS_Face& aFace = TopoDS::Face(aFaceExplorer.Current());
|
||||
TopLoc_Location aLocation;
|
||||
const occ::handle<Poly_Triangulation> aTriangulation =
|
||||
BRep_Tool::Triangulation(aFace, aLocation);
|
||||
ASSERT_FALSE(aTriangulation.IsNull());
|
||||
|
||||
for (TopExp_Explorer anEdgeExplorer(aFace, TopAbs_EDGE); anEdgeExplorer.More();
|
||||
anEdgeExplorer.Next())
|
||||
{
|
||||
const TopoDS_Edge& anEdge = TopoDS::Edge(anEdgeExplorer.Current());
|
||||
if (!BRep_Tool::IsClosed(anEdge, aFace))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const occ::handle<Poly_PolygonOnTriangulation>& aForwardPolygon =
|
||||
BRep_Tool::PolygonOnTriangulation(anEdge, aTriangulation, aLocation);
|
||||
const TopoDS_Edge aReversedEdge = TopoDS::Edge(anEdge.Reversed());
|
||||
const occ::handle<Poly_PolygonOnTriangulation>& aReversedPolygon =
|
||||
BRep_Tool::PolygonOnTriangulation(aReversedEdge, aTriangulation, aLocation);
|
||||
ASSERT_FALSE(aForwardPolygon.IsNull());
|
||||
ASSERT_FALSE(aReversedPolygon.IsNull());
|
||||
|
||||
for (int aNodeIndex = 1; aNodeIndex <= aForwardPolygon->NbNodes(); ++aNodeIndex)
|
||||
{
|
||||
EXPECT_GE(aForwardPolygon->Node(aNodeIndex), 1);
|
||||
EXPECT_LE(aForwardPolygon->Node(aNodeIndex), aTriangulation->NbNodes());
|
||||
}
|
||||
for (int aNodeIndex = 1; aNodeIndex <= aReversedPolygon->NbNodes(); ++aNodeIndex)
|
||||
{
|
||||
EXPECT_GE(aReversedPolygon->Node(aNodeIndex), 1);
|
||||
EXPECT_LE(aReversedPolygon->Node(aNodeIndex), aTriangulation->NbNodes());
|
||||
}
|
||||
|
||||
++aSeamEdges;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_GT(aSeamEdges, 0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
puts "TODO OCC30286 Linux: Error : The length of result shape is 3025.32, expected 3025.36"
|
||||
puts "TODO OCC30286 Linux: Error : The length of result shape is 3025.4"
|
||||
|
||||
puts "==========================================="
|
||||
puts "OCC25813: regression in Hidden Line Removal"
|
||||
@@ -6,7 +6,7 @@ puts "==========================================="
|
||||
puts ""
|
||||
|
||||
set viewname ""
|
||||
set length 3025.36
|
||||
set length 3025.49
|
||||
|
||||
restore [locate_data_file bug25813_hlr-bus1-draw-Fusion001.brep] a
|
||||
COMPUTE_HLR $viewname $algotype
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
puts "TODO OCC30286 Linux: Error : The length of result shape is 302.183, expected 302.238"
|
||||
puts "TODO OCC30286 Linux: Error : The length of result shape is 302"
|
||||
|
||||
puts "==========================================="
|
||||
puts "OCC25813: regression in Hidden Line Removal"
|
||||
puts "==========================================="
|
||||
puts ""
|
||||
|
||||
|
||||
|
||||
set viewname ""
|
||||
set length 302.238
|
||||
set length 301.999
|
||||
|
||||
ptorus a 30 10
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ puts "==========================================="
|
||||
puts ""
|
||||
|
||||
set viewname ""
|
||||
set length 1196.25
|
||||
set length 1196.29
|
||||
|
||||
restore [locate_data_file bug25813_hlr-test_normandc1m1-draw-Cut001.brep] a
|
||||
COMPUTE_HLR $viewname $algotype
|
||||
|
||||
Reference in New Issue
Block a user