From 5d6e8c0db09ee2c942c49e5dead1f0ea45421024 Mon Sep 17 00:00:00 2001 From: snoyer Date: Sat, 11 Jan 2025 13:39:52 +0400 Subject: [PATCH] fix bezier approximation --- ocpsvg/ocp.py | 7 +++++-- ocpsvg/svg.py | 2 ++ tests/test_svg.py | 42 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/ocpsvg/ocp.py b/ocpsvg/ocp.py index 21087b6..b2b2ef2 100644 --- a/ocpsvg/ocp.py +++ b/ocpsvg/ocp.py @@ -11,6 +11,7 @@ from OCP.BRepFeat import BRepFeat from OCP.BRepLib import BRepLib_FindSurface from OCP.BRepTools import BRepTools +from OCP.Convert import Convert_ParameterisationType from OCP.GC import ( GC_MakeArcOfCircle, GC_MakeArcOfEllipse, @@ -357,7 +358,7 @@ def ellipse_curve( def curve_to_bspline(curve: Geom_Curve) -> Geom_BSplineCurve: - return GeomConvert.CurveToBSplineCurve_s(curve) # type: ignore + return GeomConvert.CurveToBSplineCurve_s(curve, Convert_ParameterisationType.Convert_RationalC1) # type: ignore def curve_to_beziers( @@ -399,8 +400,10 @@ def curve_to_beziers( ) else: + bspline = curve_to_bspline(curve) + bspline.Segment(adaptor.FirstParameter(), adaptor.LastParameter()) yield from bspline_to_beziers( - curve_to_bspline(curve), + bspline, max_degree=max_degree, max_segments=max_segments, tolerance=tolerance, diff --git a/ocpsvg/svg.py b/ocpsvg/svg.py index 52a9457..3a409c3 100755 --- a/ocpsvg/svg.py +++ b/ocpsvg/svg.py @@ -573,6 +573,8 @@ def curve_to_svg_path( beziers = curve_to_beziers( adaptor, tolerance=tolerance, max_degree=3 if use_cubics else 2 ) + if reverse: + beziers = reversed(list(beziers)) for i, bezier in enumerate(beziers): yield from bezier_to_svg_path( bezier, diff --git a/tests/test_svg.py b/tests/test_svg.py index 7d682e9..3ff574a 100755 --- a/tests/test_svg.py +++ b/tests/test_svg.py @@ -9,9 +9,10 @@ import pytest import svgelements +from OCP.GC import GC_MakeArcOfCircle from OCP.Geom import Geom_Circle, Geom_Curve, Geom_Ellipse, Geom_TrimmedCurve from OCP.GeomAbs import GeomAbs_CurveType -from OCP.gp import gp_Pnt, gp_Vec +from OCP.gp import gp_Ax2, gp_Circ, gp_Pnt, gp_Vec from OCP.TopoDS import TopoDS, TopoDS_Edge, TopoDS_Face, TopoDS_Shape, TopoDS_Wire from pytest import approx, raises @@ -33,6 +34,7 @@ SvgPathCommand, _SegmentInPath, # type: ignore private usage bezier_to_svg_path, + curve_to_svg_path, edge_to_svg_path, edges_from_svg_path, face_to_svg_path, @@ -159,6 +161,44 @@ def test_polyline_apprx(curve: Geom_Curve): assert set(seg[0] for seg in path).issubset(set("MLZ")) +def test_trimmed_arc_to_cubics(): + radius = 10 + circ = gp_Circ(gp_Ax2(), radius) + trimmed_arc = GC_MakeArcOfCircle( + circ, gp_Pnt(-radius, 0, 0), gp_Pnt(0, +radius, 0), True + ).Value() + + svg_with_arcs = list(curve_to_svg_path(trimmed_arc, tolerance=1e-6)) + svg_with_cubics_only = list( + curve_to_svg_path( + trimmed_arc, use_arcs=False, use_quadratics=False, tolerance=1e-6 + ) + ) + assert svg_with_arcs[0][-2:] == approx(svg_with_cubics_only[0][-2:]) + assert svg_with_arcs[-1][-2:] == approx(svg_with_cubics_only[-1][-2:]) + + +def test_trimmed_arc_to_cubics_reversed(): + radius = 10 + circ = gp_Circ(gp_Ax2(), radius) + trimmed_arc = GC_MakeArcOfCircle( + circ, gp_Pnt(-radius, 0, 0), gp_Pnt(0, +radius, 0), True + ).Value() + + svg_with_arcs = list(curve_to_svg_path(trimmed_arc, reverse=True, tolerance=1e-6)) + svg_with_cubics_only = list( + curve_to_svg_path( + trimmed_arc, + reverse=True, + use_arcs=False, + use_quadratics=False, + tolerance=1e-6, + ) + ) + assert svg_with_arcs[0][-2:] == approx(svg_with_cubics_only[0][-2:]) + assert svg_with_arcs[-1][-2:] == approx(svg_with_cubics_only[-1][-2:]) + + @pytest.mark.parametrize( "wire, svg_d, opts", [