#include <Geom2d_Circle.hxx>
#include <Geom2dAPI_Interpolate.hxx>
#include <Geom2d_TrimmedCurve.hxx>
+#include <Message.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Wire.hxx>
+#include <ShapeFix_Wire.hxx>
+#include <ShapeFix_Edge.hxx>
#include <DBRep.hxx>
#include <DBRep_DrawableShape.hxx>
return 0;
}
+//=======================================================================
+// strongwire
+//=======================================================================
+static Standard_Integer strongwire(Draw_Interpretor&, Standard_Integer theArgC, const char** theArgV)
+{
+ enum StrongWireMode {
+ StrongWireMode_FixTolerance = 1,
+ StrongWireMode_Approximation = 2,
+ StrongWireMode_KeepCurveType = 3
+ };
+
+ BRep_Builder aB;
+
+ TopoDS_Wire aWire;
+ aB.MakeWire(aWire);
+
+ if (theArgC < 3)
+ return 1;
+
+ // Tolerance
+ double aTolerance = Precision::Confusion();
+
+ // mode
+ StrongWireMode aMode = StrongWireMode_KeepCurveType;
+
+ // add edges
+ for (Standard_Integer anArgIter = 2; anArgIter < theArgC; anArgIter++)
+ {
+ TCollection_AsciiString aParam(theArgV[anArgIter]);
+ if (aParam == "-t")
+ {
+ anArgIter++;
+ if (anArgIter < theArgC)
+ aTolerance = Draw::Atof(theArgV[anArgIter]);
+ }
+ else if (aParam == "-m")
+ {
+ anArgIter++;
+ if (anArgIter < theArgC)
+ {
+ if (aParam == "keepType" || Draw::Atoi(theArgV[anArgIter]) == 1)
+ {
+ aMode = StrongWireMode_KeepCurveType;
+ continue;
+ }
+ else if (aParam == "approx" || Draw::Atoi(theArgV[anArgIter]) == 2)
+ {
+ aMode = StrongWireMode_Approximation;
+ continue;
+ }
+ else if (aParam == "fixTol" || Draw::Atoi(theArgV[anArgIter]) == 3)
+ {
+ aMode = StrongWireMode_FixTolerance;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ TopoDS_Shape aShape = DBRep::Get(theArgV[anArgIter]);
+ if (aShape.IsNull())
+ Standard_NullObject::Raise("Shape for wire construction is null");
+ if (aShape.ShapeType() == TopAbs_EDGE || aShape.ShapeType() == TopAbs_WIRE)
+ {
+ TopExp_Explorer anExp(aShape, TopAbs_EDGE);
+ for (; anExp.More(); anExp.Next())
+ aB.Add(aWire, TopoDS::Edge(anExp.Current()));
+ }
+ else
+ Standard_TypeMismatch::Raise("Shape for wire construction is neither an edge nor a wire");
+ }
+ }
+
+ // fix edges order
+ Handle(ShapeFix_Wire) aFW = new ShapeFix_Wire;
+ aFW->Load(aWire);
+ aFW->FixReorder();
+
+ if (aFW->StatusReorder(ShapeExtend_FAIL1))
+ {
+ Message::SendFail() << "Error: Wire construction failed: several loops detected";
+ return 1;
+ }
+ else if (aFW->StatusReorder(ShapeExtend_FAIL))
+ {
+ Message::SendFail() << "Wire construction failed";
+ return 1;
+ }
+
+ bool isClosed = false;
+ Handle(ShapeAnalysis_Wire) aSaw = aFW->Analyzer();
+ if (aSaw->CheckGap3d(1)) // between last and first edges
+ {
+ Standard_Real aDist = aSaw->MinDistance3d();
+ if (aDist < aTolerance)
+ isClosed = true;
+ }
+ aFW->ClosedWireMode() = isClosed;
+ aFW->FixConnected(aTolerance);
+
+ if (aFW->StatusConnected(ShapeExtend_FAIL))
+ {
+ Message::SendFail() << "Wire construction failed: cannot build connected wire";
+ return 1;
+ }
+
+ if (aMode == StrongWireMode_KeepCurveType)
+ {
+ aFW->FixCurves();
+ if (aFW->StatusCurves(ShapeExtend_FAIL))
+ {
+ Message::SendFail() << "Wire construction failed: cannot rebuild curves through new points";
+ return 1;
+ }
+ }
+ else if (aFW->StatusConnected(ShapeExtend_DONE3))
+ {
+ if (aMode != StrongWireMode_Approximation)
+ aFW->SetPrecision(aTolerance);
+ aFW->FixGapsByRangesMode() = Standard_True;
+ if (aFW->FixGaps3d())
+ {
+ Handle(ShapeExtend_WireData) sbwd = aFW->WireData();
+ Handle(ShapeFix_Edge) aFe = new ShapeFix_Edge;
+ for (Standard_Integer anIdx = 1; anIdx <= sbwd->NbEdges(); anIdx++)
+ {
+ TopoDS_Edge aEdge = TopoDS::Edge(sbwd->Edge(anIdx));
+ aFe->FixVertexTolerance(aEdge);
+ aFe->FixSameParameter(aEdge);
+ }
+ }
+ else if (aFW->StatusGaps3d(ShapeExtend_FAIL))
+ {
+ Message::SendFail() << "Wire construction failed: cannot fix 3d gaps";
+ return 1;
+ }
+ }
+ aWire = aFW->WireAPIMake();
+
+ DBRep::Set(theArgV[1], aWire);
+ return 0;
+}
+
//=======================================================================
// mkedge
//=======================================================================
theCommands.Add("wire", "wire wirename [-unsorted] e1/w1 [e2/w2 ...]", __FILE__, wire, g);
+ theCommands.Add("strongwire",
+ "strongwire wirename e1/w1 [e2/w2 ...] [-t tol] [-m mode(keepType/1 | approx/2 | fixTol/3)]", __FILE__,
+ strongwire, g);
+
theCommands.Add("profile", "profile, no args to get help", __FILE__, profile, g);
theCommands.Add("bsplineprof", "bsplineprof, no args to get help", __FILE__, bsplineprof, g);
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepTools.hxx>
+#include <GC_MakeArcOfCircle.hxx>
+#include <GC_MakeArcOfEllipse.hxx>
+#include <GC_MakeLine.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dConvert.hxx>
-#include <Geom_BSplineCurve.hxx>
#include <Geom_Curve.hxx>
+#include <Geom_Circle.hxx>
+#include <Geom_Ellipse.hxx>
+#include <Geom_BezierCurve.hxx>
+#include <Geom_BSplineCurve.hxx>
#include <Geom_OffsetCurve.hxx>
#include <Geom_Plane.hxx>
#include <Geom_SphericalSurface.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAPI.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <GeomConvert_CompCurveToBSplineCurve.hxx>
+#include <gp_Elips.hxx>
+#include <gp_Pln.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <IntRes2d_SequenceOfIntersectionPoint.hxx>
#include <Message_Msg.hxx>
myStatusReorder = emptyStatus;
myStatusSmall = emptyStatus;
myStatusConnected = emptyStatus;
+ myStatusCurves = emptyStatus;
myStatusEdgeCurves = emptyStatus;
myStatusDegenerated = emptyStatus;
myStatusSelfIntersection = emptyStatus;
//=================================================================================================
+Standard_Boolean ShapeFix_Wire::FixCurves()
+{
+ myStatusCurves = ShapeExtend::EncodeStatus(ShapeExtend_OK);
+ if (!IsLoaded()) return Standard_False;
+
+ for (Standard_Integer anIdx = NbEdges(); anIdx > 0; anIdx--) {
+ FixCurves(anIdx);
+ myStatusCurves |= myLastFixStatus;
+ }
+
+ return StatusCurves(ShapeExtend_DONE);
+}
+
+//=================================================================================================
+
Standard_Boolean ShapeFix_Wire::FixEdgeCurves()
{
myStatusEdgeCurves = ShapeExtend::EncodeStatus(ShapeExtend_OK);
//=================================================================================================
+Standard_Boolean ShapeFix_Wire::FixCurves(const Standard_Integer theIdx)
+{
+ // assume fix curves step should be after fix vertices
+ myLastFixStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);
+ if (!IsLoaded() || NbEdges() <= 0)
+ return Standard_False;
+
+ // action: replacing curves in edges
+ Handle(ShapeExtend_WireData) anSbwd = WireData();
+ Standard_Integer anIdx = (theIdx > 0 ? theIdx : anSbwd->NbEdges());
+ TopoDS_Edge anEdge = anSbwd->Edge(anIdx);
+ Standard_Real aPrec = BRep_Tool::Tolerance(anEdge);
+ ShapeAnalysis_Edge aSae;
+ ShapeAnalysis_Wire aSaw;
+ Handle(Geom_Curve) aCurve3d;
+ Standard_Real aCurBounds[3];
+ Standard_Boolean IsReversed = Standard_False;
+ aSae.Curve3d(anEdge, aCurve3d, aCurBounds[0], aCurBounds[2], IsReversed);
+ aCurBounds[1] = (aCurBounds[0] + aCurBounds[2]) / 2;
+ gp_Pnt anEnds[3];
+ anEnds[0] = BRep_Tool::Pnt(aSae.FirstVertex(anEdge));
+ aCurve3d->D0(aCurBounds[1], anEnds[1]);
+ anEnds[2] = BRep_Tool::Pnt(aSae.LastVertex(anEdge));
+
+ gp_Pnt aGeomEnds[2];
+ aCurve3d->D0(aCurBounds[0], aGeomEnds[0]);
+ aCurve3d->D0(aCurBounds[2], aGeomEnds[1]);
+
+ Standard_Real aGap0 = Min(anEnds[0].Distance(aGeomEnds[0]), anEnds[0].Distance(aGeomEnds[1]));
+ Standard_Real aGap2 = Min(anEnds[2].Distance(aGeomEnds[0]), anEnds[2].Distance(aGeomEnds[1]));
+ if (Max (aGap0, aGap2) < Precision::Confusion()) // nothing to do
+ return true;
+
+ if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Circle))) {
+ Standard_Real anOldR = Handle(Geom_Circle)::DownCast(aCurve3d)->Circ().Radius();
+ gp_Vec anArcNorm = gp_Vec(anEnds[2], anEnds[0]) / 2;
+ gp_Pnt aCenter(anEnds[0].XYZ() - anArcNorm.XYZ());
+ int aSign = anEnds[1].Distance(aCenter) > anOldR ? 1 : -1; // for arc length > PI
+ Standard_Real aD = anOldR*anOldR - anArcNorm.SquareMagnitude();
+ aD = abs(aD) < Precision::Confusion() ? 0. : aD;
+ Standard_Real anArcR = anOldR + aSign * sqrt(aD);
+ gp_Ax2 aNormal(aCenter, anArcNorm);
+ Handle(Geom_Circle) anArc = new Geom_Circle(aNormal, anArcR);
+ GeomAPI_ProjectPointOnCurve projector(anEnds[1], anArc);
+ anEnds[1] = projector.NearestPoint();
+ GC_MakeArcOfCircle arc(anEnds[0], anEnds[1], anEnds[2]);
+ TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(arc.Value()).Edge();
+ anSbwd->Set(aNewEdge, theIdx);
+ return true;
+ }
+ else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Ellipse))) {
+ /// aaajfa: BEGIN - to provide elliptic edge FORWARD orientation
+ gp_Pnt tmpPnt = anEnds[0];
+ anEnds[0] = anEnds[2];
+ anEnds[2] = tmpPnt;
+ /// aaajfa: END - to provide elliptic edge FORWARD orientation
+
+ Handle(Geom_Ellipse) anOld = Handle(Geom_Ellipse)::DownCast(aCurve3d);
+ Handle(Geom_Plane) aPln = new Geom_Plane(anEnds[0], gp_Vec(anEnds[2], anEnds[0]).Crossed(gp_Vec(anEnds[1], anEnds[0])));
+ GeomAPI_ProjectPointOnSurf aProjector(anOld->Elips().Location(), aPln);
+ gp_Pnt anOrigin = aProjector.NearestPoint();
+ aProjector.Init(anOld->Elips().Location().XYZ() + anOld->Elips().XAxis().Direction().XYZ(), aPln);
+ gp_Ax2 anAx(anOrigin, aPln->Axis().Direction(), aProjector.NearestPoint().XYZ() - anOrigin.XYZ());
+
+ // compute angle
+ Standard_Real aRec = DBL_MAX;
+ Standard_Real anAngle = 0.;
+ Standard_Integer aSplNum = 10;
+ for (Standard_Integer anIdxI = -aSplNum; anIdxI < aSplNum; ++anIdxI)
+ {
+ Handle(Geom_Ellipse) anEll = new Geom_Ellipse(anAx, anOld->MajorRadius(), anOld->MinorRadius());
+ Standard_Real anAnglei = aPrec*anIdxI / anEll->MajorRadius() / aSplNum;
+ anEll->Rotate(anAx.Axis(), anAnglei);
+ GeomAPI_ProjectPointOnCurve aProjector1(anEnds[0], anEll);
+ Standard_Real aDist = 0.;
+ for (Standard_Integer anIdxJ = 0; anIdxJ < 2; ++anIdxJ)
+ {
+ aProjector1.Perform(anEnds[anIdxJ *2]);
+ aDist += std::fmin (aProjector1.Distance(1), aProjector1.Distance(2));
+ }
+ if (aDist < aRec)
+ {
+ aRec = aDist;
+ anAngle = anAnglei;
+ }
+ }
+ gp_Elips aTemp(anAx, anOld->MajorRadius(), anOld->MinorRadius());
+ aTemp.Rotate(anAx.Axis(), anAngle);
+
+ // compute shift
+ gp_Vec aX = aTemp.XAxis().Direction();
+ gp_Vec aY = aTemp.YAxis().Direction();
+ gp_Pnt2d aP1((anEnds[0].XYZ() - anOrigin.XYZ()).Dot(aX.XYZ()), (anEnds[0].XYZ() - anOrigin.XYZ()).Dot(aY.XYZ()));
+ gp_Pnt2d aP2((anEnds[2].XYZ() - anOrigin.XYZ()).Dot(aX.XYZ()), (anEnds[2].XYZ() - anOrigin.XYZ()).Dot(aY.XYZ()));
+
+ // x = ky + p linear equation
+ // where (x, y) shift point,
+ // k, p constant coefficients
+ Standard_Real k = 1, p = 0;
+ Standard_Real R = anOld->MajorRadius();
+ Standard_Real r = anOld->MinorRadius();
+ k = (R / r) * (R / r) *
+ (aP1.Y() - aP2.Y()) / (aP2.X() - aP1.X());
+ p = -(1. / 2) * (R / r) * (R / r) *
+ (aP1.Y()*aP1.Y() - aP2.Y()*aP2.Y()) / (aP2.X() - aP1.X()) + aP1.X() / 2 + aP2.X() / 2;
+ // ax^2 + bx + c = 0 square equation
+ // a, b, c constant coefficients
+ Standard_Real a = 0., b = 0., c = 0.;
+ a = R*R + k*k*r*r;
+ b = 2 * (k*p*r*r - k*aP1.X()*r*r - aP1.Y()*R*R);
+ c = aP1.X()*aP1.X()*r*r +
+ aP1.Y()*aP1.Y()*R*R -
+ r*r*R*R +
+ p*p*r*r - 2 * aP1.X()*p*r*r;
+ Standard_Real y1 = (-b - sqrt(b*b - 4 * a*c)) / 2 / a;
+ Standard_Real y2 = (-b + sqrt(b*b - 4 * a*c)) / 2 / a;
+ Standard_Real x1 = k*y1 + p;
+ Standard_Real x2 = k*y2 + p;
+
+ gp_Pnt anOri = anOld->Location();
+ if (x1*x1 + y1*y1 < x2*x2 + y2*y2)
+ anOri = anOri.XYZ() + aX.XYZ()*x1 + aY.XYZ()*y1;
+ else
+ anOri = anOri.XYZ() + aX.XYZ()*x2 + aY.XYZ()*y2;
+ aTemp.SetLocation(anOri);
+
+ GC_MakeArcOfEllipse anArc(aTemp, anEnds[2], anEnds[0], true);
+ TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(anArc.Value()).Edge();
+ anSbwd->Set(aNewEdge, theIdx);
+ return true;
+ }
+ else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_Line)))
+ {
+ TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(anEnds[0], anEnds[2]).Edge();
+ anSbwd->Set(aNewEdge, theIdx);
+ return true;
+ }
+ else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
+ {
+ Handle(Geom_BSplineCurve) anOld = Handle(Geom_BSplineCurve)::DownCast(aCurve3d);
+
+ if (anOld->Pole(1).Distance(aGeomEnds[0]) > Precision::Confusion() ||
+ anOld->Pole(anOld->NbPoles()).Distance(aGeomEnds[1]) > Precision::Confusion()) {
+ // FAIL1 means we cannot fix Bezier or B-Spline curve
+ // because its ends do not correspond to first and last poles
+ // (i.e. it is a piece of entire curve)
+ myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
+ return false;
+ }
+
+ Handle(Geom_Geometry) aNewG = anOld->Copy();
+ Handle(Geom_BSplineCurve) aNewC = Handle(Geom_BSplineCurve)::DownCast(aNewG);
+ int p = anEnds[0].Distance(aGeomEnds[0]) < anEnds[1].Distance(aGeomEnds[0]) ? 0 : 2;
+ aNewC->SetPole(1, anEnds[p]);
+ aNewC->SetPole(anOld->NbPoles(), anEnds[2-p]);
+ TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(aNewC).Edge();
+ anSbwd->Set(aNewEdge, theIdx);
+ return true;
+ }
+ else if (aCurve3d->IsKind(STANDARD_TYPE(Geom_BezierCurve)))
+ {
+ Handle(Geom_BezierCurve) anOld = Handle(Geom_BezierCurve)::DownCast(aCurve3d);
+
+ if (anOld->Pole(1).Distance(aGeomEnds[0]) > Precision::Confusion() ||
+ anOld->Pole(anOld->NbPoles()).Distance(aGeomEnds[1]) > Precision::Confusion()) {
+ // FAIL1 means we cannot fix Bezier or B-Spline curve
+ // because its ends do not correspond to first and last poles
+ // (i.e. it is a piece of entire curve)
+ myLastFixStatus |= ShapeExtend::EncodeStatus ( ShapeExtend_FAIL1 );
+ return false;
+ }
+
+ Handle(Geom_Geometry) aNewG = anOld->Copy();
+ Handle(Geom_BezierCurve) aNewC = Handle(Geom_BezierCurve)::DownCast(aNewG);
+ int p = anEnds[0].Distance(aGeomEnds[0]) < anEnds[1].Distance(aGeomEnds[0]) ? 0 : 2;
+ aNewC->SetPole(1, anEnds[p]);
+ aNewC->SetPole(anOld->NbPoles(), anEnds[2-p]);
+ TopoDS_Edge aNewEdge = BRepBuilderAPI_MakeEdge(aNewC).Edge();
+ anSbwd->Set(aNewEdge, theIdx);
+ return true;
+ }
+
+ return true;
+}
+
+//=================================================================================================
+
Standard_Boolean ShapeFix_Wire::FixSeam(const Standard_Integer num)
{
myLastFixStatus = ShapeExtend::EncodeStatus(ShapeExtend_OK);