Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 77 additions & 2 deletions src/ModelingAlgorithms/TKTopAlgo/BRepCheck/BRepCheck_Face.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,58 @@ BRepCheck_Status BRepCheck_Face::ClassifyWires(const bool Update)
BRep_Builder B;
TopExp_Explorer exp1, exp2;
NCollection_List<TopoDS_Shape> theListOfShape;

// Precompute a 2D parametric bounding box for every wire, the same
// pattern IntersectWires() already uses above. IsInside() classifies a
// single representative point of wir2 against wir1's region, so if the
// two wires' boxes don't overlap, that point can't be inside wir1's
// region and the classification test can be skipped. The loop below is
// still a pair over every wire, but each pair now costs an O(1) box
// check instead of a real classification, which is what actually
// matters for a plate with many non-overlapping holes.
Geom2dAdaptor_Curve aBoxCurveAdapt;
double aBoxFirst, aBoxLast;
DataMapOfShapeBox2d aWireBoxMap;
for (exp1.Init(myShape.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp1.More(); exp1.Next())
{
Bnd_Box2d aBoxW;
bool isBoxReliable = true;
for (exp2.Init(exp1.Current(), TopAbs_EDGE); exp2.More(); exp2.Next())
{
const TopoDS_Edge& anEdge = TopoDS::Edge(exp2.Current());
occ::handle<Geom2d_Curve> aPCurve =
BRep_Tool::CurveOnSurface(anEdge, TopoDS::Face(myShape), aBoxFirst, aBoxLast);
if (aPCurve.IsNull())
{
continue;
}
aBoxCurveAdapt.Load(aPCurve);
double aF = aBoxFirst, aL = aBoxLast;
if (aBoxCurveAdapt.FirstParameter() > aF)
{
aF = aBoxCurveAdapt.FirstParameter();
isBoxReliable = false;
}
if (aBoxCurveAdapt.LastParameter() < aL)
{
aL = aBoxCurveAdapt.LastParameter();
isBoxReliable = false;
}
Bnd_Box2d aBoxE;
BndLib_Add2dCurve::Add(aBoxCurveAdapt, aF, aL, 0., aBoxE);
aBoxW.Add(aBoxE);
}
// IsInside() below picks its representative point using the edge's own
// (unclamped) parameter range, not the curve's own definition domain, so
// if any edge's trim range had to be clamped to build this box, the box
// may not actually contain the point IsInside() would evaluate. Skip the
// pre-filter for such a wire rather than risk a wrong answer.
if (isBoxReliable)
{
aWireBoxMap.Bind(exp1.Current(), aBoxW);
}
}

for (exp1.Init(myShape.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp1.More(); exp1.Next())
{

Expand All @@ -368,13 +420,36 @@ BRepCheck_Status BRepCheck_Face::ClassifyWires(const bool Update)
myMapImb.Bind(wir1.Reversed(), theListOfShape);
}

Bnd_Box2d aBox1;
bool hasBox1 =
aWireBoxMap.IsBound(exp1.Current()) && !(aBox1 = aWireBoxMap(exp1.Current())).IsVoid();

for (exp2.Init(myShape.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp2.More(); exp2.Next())
{
const TopoDS_Wire& wir2 = TopoDS::Wire(exp2.Current());
if (!wir2.IsSame(wir1))
{

if (IsInside(wir2, WireBienOriente, FClass2d, newFace))
bool isWire2Inside;
Bnd_Box2d aBox2;
bool hasBox2 = hasBox1 && aWireBoxMap.IsBound(exp2.Current())
&& !(aBox2 = aWireBoxMap(exp2.Current())).IsVoid();
if (hasBox2 && aBox1.IsOut(aBox2))
{
// wir2's point falls outside wir1's box, so it's outside wir1's
// finite bounded region. If WireBienOriente is false, that
// finite region is exactly what IsInside() tests for, so the
// point is out. If WireBienOriente is true, IsInside() tests
// for the infinite complement of that region instead, and a
// point outside the finite region is inside the complement, so
// IsInside() returns false there too. Either way the answer is
// false.
isWire2Inside = false;
}
else
{
isWire2Inside = IsInside(wir2, WireBienOriente, FClass2d, newFace);
}
if (isWire2Inside)
{
myMapImb(wir1).Append(wir2);
}
Expand Down
70 changes: 70 additions & 0 deletions src/ModelingData/TKGeomBase/GeomLib/GeomLib_Tool.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
#include <Extrema_ExtPC2d.hxx>
#include <Extrema_ExtPS.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Ellipse.hxx>
#include <Geom_Hyperbola.hxx>
#include <Geom_Line.hxx>
#include <Geom_Parabola.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <math_PSO.hxx>
Expand All @@ -46,6 +52,70 @@ bool GeomLib_Tool::Parameter(const occ::handle<Geom_Curve>& Curve,
//
U = 0.;
double aTol = MaxDist * MaxDist;

// Analytic curve types already have an O(1) closed-form parameter
// computation in ElCLib, so use that instead of the iterative
// Extrema_ExtPC search below when the curve (or its basis curve, if
// trimmed) is a Line, Circle, Ellipse, Hyperbola or Parabola. The
// closed-form result is only kept if it lands within the curve's own
// range, accounting for periodicity. A trimmed arc whose true closest
// point falls outside the trimmed portion still goes through the
// generic search below.
{
occ::handle<Geom_Curve> aBasisCurve = Curve;
while (aBasisCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve)))
{
aBasisCurve = occ::down_cast<Geom_TrimmedCurve>(aBasisCurve)->BasisCurve();
}

bool hasFastU = true;
double aFastU = 0.0;
if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_Line)))
{
aFastU = ElCLib::Parameter(occ::down_cast<Geom_Line>(aBasisCurve)->Lin(), Point);
}
else if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_Circle)))
{
aFastU = ElCLib::Parameter(occ::down_cast<Geom_Circle>(aBasisCurve)->Circ(), Point);
}
else if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_Ellipse)))
{
aFastU = ElCLib::Parameter(occ::down_cast<Geom_Ellipse>(aBasisCurve)->Elips(), Point);
}
else if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_Hyperbola)))
{
aFastU = ElCLib::Parameter(occ::down_cast<Geom_Hyperbola>(aBasisCurve)->Hypr(), Point);
}
else if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_Parabola)))
{
aFastU = ElCLib::Parameter(occ::down_cast<Geom_Parabola>(aBasisCurve)->Parab(), Point);
}
else
{
hasFastU = false;
}

if (hasFastU)
{
if (Curve->IsPeriodic())
{
aFastU = ElCLib::InPeriod(aFastU,
Curve->FirstParameter(),
Curve->FirstParameter() + Curve->Period());
}
if (aFastU >= Curve->FirstParameter() - PARTOLERANCE
&& aFastU <= Curve->LastParameter() + PARTOLERANCE)
{
const gp_Pnt aFastP = Curve->Value(aFastU);
if (aFastP.SquareDistance(Point) <= aTol)
{
U = aFastU;
return true;
}
return false;
}
}
}
//
GeomAdaptor_Curve aGAC(Curve);
Extrema_ExtPC extrema(Point, aGAC);
Expand Down
Loading