Download src/Mod/Part/App/BSplineCurveBiArcs.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 9.5 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/App/BSplineCurveBiArcs.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Part/App/BSplineCurveBiArcs.cpp
-
curl -L -o BSplineCurveBiArcs.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Part/App/BSplineCurveBiArcs.cpp
9.5 kB
| // SPDX-License-Identifier: BSD-3-Clause | |
| // This file is released under the BSD license | |
| // | |
| // Copyright (c) 2009, Daniel Heeks | |
| // All rights reserved. | |
| // | |
| // Redistribution and use in source and binary forms, with or without modification, | |
| // are permitted provided that the following conditions are met: | |
| // | |
| // * Redistributions of source code must retain the above copyright notice, this | |
| // list of conditions and the following disclaimer. | |
| // * Redistributions in binary form must reproduce the above copyright notice, this | |
| // list of conditions and the following disclaimer in the documentation and/or | |
| // other materials provided with the distribution. | |
| // * Neither the name of Daniel Heeks nor the names of its contributors may be used | |
| // to endorse or promote products derived from this software without specific prior | |
| // written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| // POSSIBILITY OF SUCH DAMAGE. | |
| using Part::BSplineCurveBiArcs; | |
| using Part::GeomBSplineCurve; | |
| using Part::Geometry; | |
| // Algorithm taken from HeeksCAD | |
| namespace Part | |
| { | |
| bool tangentialArc(const gp_Pnt& p0, const gp_Vec& v0, const gp_Pnt& p1, gp_Pnt& c, gp_Dir& axis) | |
| { | |
| if (p0.Distance(p1) > Precision::Intersection() && v0.Magnitude() > Precision::Intersection()) { | |
| gp_Vec v1(p0, p1); | |
| gp_Pnt halfway(p0.XYZ() + v1.XYZ() * 0.5); | |
| gp_Pln pln1(halfway, v1); | |
| gp_Pln pln2(p0, v0); | |
| gp_Lin plane_line; | |
| if (intersect(pln1, pln2, plane_line)) { | |
| gp_Lin l1(halfway, v1); | |
| gp_Pnt p2; | |
| closestPointsOnLines(plane_line, l1, c, p2); | |
| axis = -(plane_line.Direction()); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| class TangentialArc | |
| { | |
| public: | |
| gp_Pnt m_p0; // start point | |
| gp_Vec m_v0; // start direction | |
| gp_Pnt m_p1; // end point | |
| gp_Pnt m_c; // centre point | |
| gp_Dir m_a; // axis | |
| bool m_is_a_line; | |
| TangentialArc(const gp_Pnt& p0, const gp_Vec& v0, const gp_Pnt& p1) | |
| : m_p0(p0) | |
| , m_v0(v0) | |
| , m_p1(p1) | |
| { | |
| // calculate a tangential arc that goes through p0 and p1, with a direction of v0 at p0 | |
| m_is_a_line = !Part::tangentialArc(m_p0, m_v0, m_p1, m_c, m_a); | |
| } | |
| bool isRadiusEqual(const gp_Pnt& p, double tolerance) const | |
| { | |
| if (m_is_a_line) { | |
| return true; | |
| } | |
| double point_radius = gp_Vec(m_c.XYZ() - p.XYZ()).Magnitude(); | |
| double diff = fabs(point_radius - radius()); | |
| return diff <= tolerance; | |
| } | |
| double radius() const | |
| { | |
| double r0 = gp_Vec(m_p0.XYZ() - m_c.XYZ()).Magnitude(); | |
| double r1 = gp_Vec(m_p1.XYZ() - m_c.XYZ()).Magnitude(); | |
| double r = (r0 + r1) / 2; | |
| return r; | |
| } | |
| Geometry* makeArc() const | |
| { | |
| if (m_is_a_line) { | |
| GeomLineSegment* line = new GeomLineSegment(); | |
| line->setPoints( | |
| Base::convertTo<Base::Vector3d>(m_p0), | |
| Base::convertTo<Base::Vector3d>(m_p1) | |
| ); | |
| return line; | |
| } | |
| gp_Circ c(gp_Ax2(m_c, m_a), radius()); | |
| GC_MakeArcOfCircle arc(c, m_p0, m_p1, true); | |
| GeomArcOfCircle* new_object = new GeomArcOfCircle(); | |
| new_object->setHandle(arc.Value()); | |
| return new_object; | |
| } | |
| }; | |
| } // namespace Part | |
| void BSplineCurveBiArcs::createArcs( | |
| double tolerance, | |
| std::list<Geometry*>& new_spans, | |
| const gp_Pnt& p_start, | |
| const gp_Vec& v_start, | |
| double t_start, | |
| double t_end, | |
| gp_Pnt& p_end, | |
| gp_Vec& v_end | |
| ) const | |
| { | |
| this->myCurve->D1(t_end, p_end, v_end); | |
| gp_Pnt p1, p2, p3; | |
| Type can_do_spline_whole | |
| = calculateBiArcPoints(t_start, p_start, v_start, t_end, p_end, v_end, p1, p2, p3); | |
| Geometry* arc_object1 = nullptr; | |
| Geometry* arc_object2 = nullptr; | |
| if (can_do_spline_whole == Type::SingleArc) { | |
| Part::TangentialArc arc1(p_start, v_start, p2); | |
| Part::TangentialArc arc2(p2, gp_Vec(p3.XYZ() - p2.XYZ()), p_end); | |
| gp_Pnt p_middle1, p_middle2; | |
| this->myCurve->D0(t_start + ((t_end - t_start) * 0.25), p_middle1); | |
| this->myCurve->D0(t_start + ((t_end - t_start) * 0.75), p_middle2); | |
| if (!arc1.isRadiusEqual(p_middle1, tolerance) || !arc2.isRadiusEqual(p_middle2, tolerance)) { | |
| can_do_spline_whole = Type::SplitCurve; | |
| } | |
| else { | |
| arc_object1 = arc1.makeArc(); | |
| arc_object2 = arc2.makeArc(); | |
| } | |
| } | |
| if (can_do_spline_whole == Type::SingleArc) { | |
| new_spans.push_back(arc_object1); | |
| new_spans.push_back(arc_object2); | |
| } | |
| else if (can_do_spline_whole == Type::SplitCurve) { | |
| double t_middle = t_start + ((t_end - t_start) * 0.5); | |
| gp_Pnt p_middle; | |
| gp_Vec v_middle; | |
| createArcs(tolerance, new_spans, p_start, v_start, t_start, t_middle, p_middle, v_middle); // recursive | |
| gp_Pnt new_p_end; | |
| gp_Vec new_v_end; | |
| createArcs(tolerance, new_spans, p_middle, v_middle, t_middle, t_end, new_p_end, new_v_end); | |
| } | |
| else { | |
| // calculate_biarc_points failed, just add a line | |
| Part::GeomLineSegment* line = new Part::GeomLineSegment(); | |
| line->setPoints( | |
| Base::convertTo<Base::Vector3d>(p_start), | |
| Base::convertTo<Base::Vector3d>(p_end) | |
| ); | |
| new_spans.push_back(line); | |
| } | |
| } | |
| BSplineCurveBiArcs::Type BSplineCurveBiArcs::calculateBiArcPoints( | |
| double t_start, | |
| const gp_Pnt& p0, | |
| gp_Vec v_start, | |
| double t_end, | |
| const gp_Pnt& p4, | |
| gp_Vec v_end, | |
| gp_Pnt& p1, | |
| gp_Pnt& p2, | |
| gp_Pnt& p3 | |
| ) const | |
| { | |
| if (v_start.Magnitude() < Precision::Intersection()) { | |
| v_start = gp_Vec(p0, p1); | |
| } | |
| if (v_end.Magnitude() < Precision::Intersection()) { | |
| v_end = gp_Vec(p3, p4); | |
| } | |
| v_start.Normalize(); | |
| v_end.Normalize(); | |
| gp_Vec v = p0.XYZ() - p4.XYZ(); | |
| double a = 2 * (v_start * v_end - 1); | |
| double c = v * v; | |
| double b = (v * 2) * (v_start + v_end); | |
| if (fabs(a) < Precision::Intersection()) { | |
| // Check the tangent of a value between t_start and t_end | |
| double t_mid = 0.9 * t_start + 0.1 * t_end; | |
| if (fabs(t_mid) > 0.1) { | |
| gp_Pnt p_mid; | |
| gp_Vec v_mid; | |
| this->myCurve->D1(t_mid, p_mid, v_mid); | |
| v_mid.Normalize(); | |
| double a = 2 * (v_start * v_mid - 1); | |
| if (fabs(a) >= Precision::Intersection()) { | |
| return Type::SplitCurve; | |
| } | |
| } | |
| return Type::SingleLine; | |
| } | |
| double d = b * b - 4 * a * c; | |
| if (d < 0.0) { | |
| return Type::SingleLine; | |
| } | |
| double sd = sqrt(d); | |
| double e1 = (-b - sd) / (2.0 * a); | |
| double e2 = (-b + sd) / (2.0 * a); | |
| if (e1 > 0 && e2 > 0) { | |
| return Type::SingleLine; | |
| } | |
| double e = e1; | |
| if (e2 > e) { | |
| e = e2; | |
| } | |
| if (e < 0) { | |
| return Type::SingleLine; | |
| } | |
| p1 = p0.XYZ() + v_start.XYZ() * e; | |
| p3 = p4.XYZ() - v_end.XYZ() * e; | |
| p2 = p1.XYZ() * 0.5 + p3.XYZ() * 0.5; | |
| return Type::SingleArc; | |
| } | |
| BSplineCurveBiArcs::BSplineCurveBiArcs(const Handle(Geom_Curve) & c) | |
| : myCurve(c) | |
| {} | |
| std::list<Geometry*> BSplineCurveBiArcs::toBiArcs(double tolerance) const | |
| { | |
| gp_Pnt p_start; | |
| gp_Vec v_start; | |
| gp_Pnt p_end; | |
| gp_Vec v_end; | |
| this->myCurve->D0(this->myCurve->FirstParameter(), p_start); | |
| this->myCurve->D0(this->myCurve->LastParameter(), p_end); | |
| std::list<Geometry*> list; | |
| // the spline is closed | |
| if (p_start.Distance(p_end) < Precision::Intersection()) { | |
| this->myCurve->D1(this->myCurve->FirstParameter(), p_start, v_start); | |
| createArcs( | |
| tolerance, | |
| list, | |
| p_start, | |
| v_start, | |
| this->myCurve->FirstParameter(), | |
| this->myCurve->LastParameter() / 2, | |
| p_end, | |
| v_end | |
| ); | |
| this->myCurve->D1(this->myCurve->LastParameter() / 2, p_start, v_start); | |
| createArcs( | |
| tolerance, | |
| list, | |
| p_start, | |
| v_start, | |
| this->myCurve->LastParameter() / 2, | |
| this->myCurve->LastParameter(), | |
| p_end, | |
| v_end | |
| ); | |
| } | |
| else { | |
| this->myCurve->D1(this->myCurve->FirstParameter(), p_start, v_start); | |
| createArcs( | |
| tolerance, | |
| list, | |
| p_start, | |
| v_start, | |
| this->myCurve->FirstParameter(), | |
| this->myCurve->LastParameter(), | |
| p_end, | |
| v_end | |
| ); | |
| } | |
| return list; | |
| } | |