Skip to content

Commit 9ab2678

Browse files
authored
Merge pull request #406 from CadQuery/spline-dxf
dxf splines and ellipse import support
2 parents a8707ce + 6d6da05 commit 9ab2678

File tree

5 files changed

+5146
-1
lines changed

5 files changed

+5146
-1
lines changed

cadquery/occ_impl/importers.py

+79-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
1+
from collections import OrderedDict
2+
from math import pi
3+
14
from .. import cq
25
from .geom import Vector
3-
from .shapes import Shape, Edge, Face, sortWiresByBuildOrder
6+
from .shapes import Shape, Edge, Face, sortWiresByBuildOrder, DEG2RAD
47

58
import ezdxf
69

710
from OCP.STEPControl import STEPControl_Reader
811
from OCP.ShapeAnalysis import ShapeAnalysis_FreeBounds
912
from OCP.TopTools import TopTools_HSequenceOfShape
13+
from OCP.gp import gp_Pnt
14+
from OCP.Geom import Geom_BSplineCurve
15+
from OCP.TColgp import TColgp_Array1OfPnt
16+
from OCP.TColStd import TColStd_Array1OfReal, TColStd_Array1OfInteger
17+
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
18+
1019

1120
import OCP.IFSelect
1221

22+
RAD2DEG = 360.0 / (2 * pi)
23+
1324

1425
class ImportTypes:
1526
STEP = "STEP"
@@ -104,12 +115,79 @@ def _dxf_polyline(el):
104115
return (e[0] for e in rv if e)
105116

106117

118+
def _dxf_spline(el):
119+
120+
try:
121+
degree = el.dxf.degree
122+
periodic = el.closed
123+
rational = False
124+
125+
knots_unique = OrderedDict()
126+
for k in el.knots:
127+
if k in knots_unique:
128+
knots_unique[k] += 1
129+
else:
130+
knots_unique[k] = 1
131+
132+
# assmble knots
133+
knots = TColStd_Array1OfReal(1, len(knots_unique))
134+
multiplicities = TColStd_Array1OfInteger(1, len(knots_unique))
135+
for i, (k, m) in enumerate(knots_unique.items()):
136+
knots.SetValue(i + 1, k)
137+
multiplicities.SetValue(i + 1, m)
138+
139+
# assemble wieghts if present:
140+
if el.weights:
141+
rational = True
142+
143+
weights = OCP.TColStd.TColStd_Array1OfReal(1, len(el.weights))
144+
for i, w in enumerate(el.weights):
145+
weights.SetValue(i + 1, w)
146+
147+
# assmeble conotrol points
148+
pts = TColgp_Array1OfPnt(1, len(el.control_points))
149+
for i, p in enumerate(el.control_points):
150+
pts.SetValue(i + 1, gp_Pnt(*p))
151+
152+
if rational:
153+
spline = Geom_BSplineCurve(
154+
pts, weights, knots, multiplicities, degree, periodic
155+
)
156+
else:
157+
spline = Geom_BSplineCurve(pts, knots, multiplicities, degree, periodic)
158+
159+
return (Edge(BRepBuilderAPI_MakeEdge(spline).Edge()),)
160+
161+
except Exception:
162+
return ()
163+
164+
165+
def _dxf_ellipse(el):
166+
167+
try:
168+
169+
return (
170+
Edge.makeEllipse(
171+
el.dxf.major_axis.magnitude,
172+
el.minor_axis.magnitude,
173+
pnt=Vector(el.dxf.center.xyz),
174+
xdir=Vector(el.dxf.major_axis.xyz),
175+
angle1=el.dxf.start_param * RAD2DEG,
176+
angle2=el.dxf.end_param * RAD2DEG,
177+
),
178+
)
179+
except Exception:
180+
return ()
181+
182+
107183
DXF_CONVERTERS = {
108184
"LINE": _dxf_line,
109185
"CIRCLE": _dxf_circle,
110186
"ARC": _dxf_arc,
111187
"POLYLINE": _dxf_polyline,
112188
"LWPOLYLINE": _dxf_polyline,
189+
"SPLINE": _dxf_spline,
190+
"ELLIPSE": _dxf_ellipse,
113191
}
114192

115193

tests/test_importers.py

+21
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ def testImportDXF(self):
109109
obj = importers.importDXF(filename)
110110
self.assertTrue(obj.val().isValid())
111111

112+
# test spline import
113+
114+
filename = os.path.join(testdataDir, "spline.dxf")
115+
obj = importers.importDXF(filename, tol=1)
116+
self.assertTrue(obj.val().isValid())
117+
self.assertEqual(obj.faces().size(), 1)
118+
self.assertEqual(obj.wires().size(), 2)
119+
120+
# test rational spline import
121+
filename = os.path.join(testdataDir, "rational_spline.dxf")
122+
obj = importers.importDXF(filename)
123+
self.assertTrue(obj.val().isValid())
124+
self.assertEqual(obj.faces().size(), 1)
125+
self.assertEqual(obj.edges().size(), 1)
126+
127+
# importing of a complex shape exported from Inkscape
128+
filename = os.path.join(testdataDir, "genshi.dxf")
129+
obj = importers.importDXF(filename)
130+
self.assertTrue(obj.val().isValid())
131+
self.assertEqual(obj.faces().size(), 1)
132+
112133

113134
if __name__ == "__main__":
114135
import unittest

0 commit comments

Comments
 (0)