From cdae5049ed54753ef818c11ade5d76cad501c7a2 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 20 Feb 2021 16:37:02 +0100 Subject: [PATCH] Import: [skip ci] fixes #0003988: the function Import.readDXF doesn't import Bsplines --- src/Mod/Import/App/ImpExpDxf.cpp | 115 ++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/src/Mod/Import/App/ImpExpDxf.cpp b/src/Mod/Import/App/ImpExpDxf.cpp index 0771c7ef1a..9bfc63ec9b 100644 --- a/src/Mod/Import/App/ImpExpDxf.cpp +++ b/src/Mod/Import/App/ImpExpDxf.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -157,9 +158,119 @@ void ImpExpDxfRead::OnReadCircle(const double* s, const double* c, bool dir, boo } -void ImpExpDxfRead::OnReadSpline(struct SplineData& /*sd*/) +Handle(Geom_BSplineCurve) getSplineFromPolesAndKnots(struct SplineData& sd) { - // not yet implemented + std::size_t numPoles = sd.control_points; + if (sd.controlx.size() > numPoles || sd.controly.size() > numPoles || + sd.controlz.size() > numPoles || sd.weight.size() > numPoles) { + return nullptr; + } + + // handle the poles + TColgp_Array1OfPnt occpoles(1, sd.control_points); + int index = 1; + for (auto x : sd.controlx) { + occpoles(index++).SetX(x); + } + + index = 1; + for (auto y : sd.controly) { + occpoles(index++).SetY(y); + } + + index = 1; + for (auto z : sd.controlz) { + occpoles(index++).SetZ(z); + } + + // handle knots and mults + std::set unique; + unique.insert(sd.knot.begin(), sd.knot.end()); + + int numKnots = int(unique.size()); + TColStd_Array1OfInteger occmults(1, numKnots); + TColStd_Array1OfReal occknots(1, numKnots); + index = 1; + for (auto k : unique) { + size_t m = std::count(sd.knot.begin(), sd.knot.end(), k); + occknots(index) = k; + occmults(index) = m; + index++; + } + + // handle weights + TColStd_Array1OfReal occweights(1, sd.control_points); + if (sd.weight.size() == std::size_t(sd.control_points)) { + index = 1; + for (auto w : sd.weight) { + occweights(index++) = w; + } + } + else { + // non-rational + for (int i=occweights.Lower(); i<=occweights.Upper(); i++) { + occweights(i) = 1.0; + } + } + + Standard_Boolean periodic = sd.flag == 2; + Handle(Geom_BSplineCurve) geom = new Geom_BSplineCurve(occpoles, occweights, occknots, occmults, sd.degree, periodic); + return geom; +} + +Handle(Geom_BSplineCurve) getInterpolationSpline(struct SplineData& sd) +{ + std::size_t numPoints = sd.fit_points; + if (sd.fitx.size() > numPoints || sd.fity.size() > numPoints || sd.fitz.size() > numPoints) { + return nullptr; + } + + // handle the poles + Handle(TColgp_HArray1OfPnt) fitpoints = new TColgp_HArray1OfPnt(1, sd.fit_points); + int index = 1; + for (auto x : sd.fitx) { + fitpoints->ChangeValue(index++).SetX(x); + } + + index = 1; + for (auto y : sd.fity) { + fitpoints->ChangeValue(index++).SetY(y); + } + + index = 1; + for (auto z : sd.fitz) { + fitpoints->ChangeValue(index++).SetZ(z); + } + + Standard_Boolean periodic = sd.flag == 2; + GeomAPI_Interpolate interp(fitpoints, periodic, Precision::Confusion()); + interp.Perform(); + return interp.Curve(); +} + +void ImpExpDxfRead::OnReadSpline(struct SplineData& sd) +{ + // https://documentation.help/AutoCAD-DXF/WS1a9193826455f5ff18cb41610ec0a2e719-79e1.htm + // Flags: + // 1: Closed, 2: Periodic, 4: Rational, 8: Planar, 16: Linear + + try { + Handle(Geom_BSplineCurve) geom; + if (sd.fit_points > 0) + geom = getInterpolationSpline(sd); + else + geom = getSplineFromPolesAndKnots(sd); + + if (geom.IsNull()) + throw Standard_Failure(); + + BRepBuilderAPI_MakeEdge makeEdge(geom); + TopoDS_Edge edge = makeEdge.Edge(); + AddObject(new Part::TopoShape(edge)); + } + catch (const Standard_Failure&) { + Base::Console().Warning("ImpExpDxf - failed to create bspline\n"); + } }