Merge pull request #694 from CadQuery/splineApprox
Implement makeSplineApprox for edges and faces
This commit is contained in:
83
tests/naca.py
Executable file
83
tests/naca.py
Executable file
@ -0,0 +1,83 @@
|
||||
naca5305 = [
|
||||
[1.000074, 0.000520],
|
||||
[0.998545, 0.000829],
|
||||
[0.993968, 0.001750],
|
||||
[0.986369, 0.003267],
|
||||
[0.975792, 0.005351],
|
||||
[0.962301, 0.007964],
|
||||
[0.945974, 0.011059],
|
||||
[0.926909, 0.014580],
|
||||
[0.905218, 0.018465],
|
||||
[0.881032, 0.022648],
|
||||
[0.854494, 0.027058],
|
||||
[0.825764, 0.031621],
|
||||
[0.795017, 0.036263],
|
||||
[0.762437, 0.040911],
|
||||
[0.728224, 0.045493],
|
||||
[0.692585, 0.049938],
|
||||
[0.655739, 0.054180],
|
||||
[0.617912, 0.058158],
|
||||
[0.579336, 0.061813],
|
||||
[0.540252, 0.065095],
|
||||
[0.500900, 0.067958],
|
||||
[0.461525, 0.070367],
|
||||
[0.422374, 0.072291],
|
||||
[0.383692, 0.073709],
|
||||
[0.345722, 0.074611],
|
||||
[0.308702, 0.074992],
|
||||
[0.272257, 0.074521],
|
||||
[0.237079, 0.072481],
|
||||
[0.203612, 0.069020],
|
||||
[0.172090, 0.064350],
|
||||
[0.142727, 0.058704],
|
||||
[0.115719, 0.052328],
|
||||
[0.091240, 0.045475],
|
||||
[0.069442, 0.038397],
|
||||
[0.050454, 0.031335],
|
||||
[0.034383, 0.024516],
|
||||
[0.021313, 0.018141],
|
||||
[0.011308, 0.012382],
|
||||
[0.004410, 0.007379],
|
||||
[0.000639, 0.003232],
|
||||
[0.000000, 0.000000],
|
||||
[0.002443, -0.002207],
|
||||
[0.007902, -0.003318],
|
||||
[0.016322, -0.003385],
|
||||
[0.027630, -0.002492],
|
||||
[0.041737, -0.000752],
|
||||
[0.058539, 0.001696],
|
||||
[0.077918, 0.004691],
|
||||
[0.099743, 0.008055],
|
||||
[0.123875, 0.011591],
|
||||
[0.150167, 0.015098],
|
||||
[0.178462, 0.018365],
|
||||
[0.208603, 0.021185],
|
||||
[0.240422, 0.023351],
|
||||
[0.273752, 0.024670],
|
||||
[0.308614, 0.024992],
|
||||
[0.345261, 0.024967],
|
||||
[0.382862, 0.024875],
|
||||
[0.421191, 0.024682],
|
||||
[0.460016, 0.024358],
|
||||
[0.499100, 0.023878],
|
||||
[0.538207, 0.023226],
|
||||
[0.577098, 0.022390],
|
||||
[0.615534, 0.021370],
|
||||
[0.653278, 0.020171],
|
||||
[0.690099, 0.018807],
|
||||
[0.725767, 0.017298],
|
||||
[0.760061, 0.015670],
|
||||
[0.792768, 0.013955],
|
||||
[0.823684, 0.012188],
|
||||
[0.852613, 0.010407],
|
||||
[0.879374, 0.008651],
|
||||
[0.903799, 0.006957],
|
||||
[0.925731, 0.005364],
|
||||
[0.945032, 0.003906],
|
||||
[0.961578, 0.002615],
|
||||
[0.975264, 0.001519],
|
||||
[0.986001, 0.000641],
|
||||
[0.993720, 0.000001],
|
||||
[0.998372, -0.000389],
|
||||
[0.999926, -0.000520],
|
||||
]
|
||||
@ -2189,13 +2189,15 @@ class TestCadQuery(BaseTest):
|
||||
self.assertEqual(8, result.solids().item(0).faces().size())
|
||||
|
||||
def testSplitError(self):
|
||||
"""
|
||||
Test split produces the correct error when called with no solid to split.
|
||||
"""
|
||||
# Test split produces the correct error when called with no solid to split.
|
||||
w = Workplane().hLine(1).vLine(1).close()
|
||||
with raises(ValueError):
|
||||
w.split(keepTop=True)
|
||||
|
||||
# Split should raise ValueError when called with no side kept
|
||||
with raises(ValueError):
|
||||
w.split(keepTop=False, keepBottom=False)
|
||||
|
||||
def testBoxDefaults(self):
|
||||
"""
|
||||
Tests creating a single box
|
||||
@ -3291,6 +3293,11 @@ class TestCadQuery(BaseTest):
|
||||
self.assertTrue(res_closed.solids().val().isValid())
|
||||
self.assertEqual(len(res_closed.faces().vals()), 3)
|
||||
|
||||
res_edge = Workplane("XY").parametricCurve(func, makeWire=False)
|
||||
|
||||
self.assertEqual(len(res_edge.ctx.pendingEdges), 1)
|
||||
self.assertEqual(len(res_edge.ctx.pendingWires), 0)
|
||||
|
||||
def testMakeShellSolid(self):
|
||||
|
||||
c0 = math.sqrt(2) / 4
|
||||
@ -4387,3 +4394,125 @@ class TestCadQuery(BaseTest):
|
||||
|
||||
with raises(ValueError):
|
||||
r.chamfer2D(0.25, [vs[0]])
|
||||
|
||||
def testSplineApprox(self):
|
||||
|
||||
from .naca import naca5305
|
||||
from math import pi, cos
|
||||
|
||||
pts = [Vector(e[0], e[1], 0) for e in naca5305]
|
||||
|
||||
# spline
|
||||
|
||||
e1 = Edge.makeSplineApprox(pts, 1e-6, maxDeg=6, smoothing=(1, 1, 1))
|
||||
e2 = Edge.makeSplineApprox(pts, 1e-6, minDeg=2, maxDeg=6)
|
||||
|
||||
self.assertTrue(e1.isValid())
|
||||
self.assertTrue(e2.isValid())
|
||||
self.assertTrue(e1.Length() > e2.Length())
|
||||
|
||||
with raises(ValueError):
|
||||
e4 = Edge.makeSplineApprox(pts, 1e-6, maxDeg=3, smoothing=(1, 1, 1.0))
|
||||
|
||||
pts_closed = pts + [pts[0]]
|
||||
|
||||
e3 = Edge.makeSplineApprox(pts_closed)
|
||||
w = Edge.makeSplineApprox(pts).close()
|
||||
|
||||
self.assertTrue(e3.IsClosed())
|
||||
self.assertTrue(w.IsClosed())
|
||||
|
||||
# Workplane method
|
||||
|
||||
w1 = Workplane().splineApprox(pts)
|
||||
w2 = Workplane().splineApprox(pts, forConstruction=True)
|
||||
w3 = Workplane().splineApprox(pts, makeWire=True)
|
||||
w4 = Workplane().splineApprox(pts, makeWire=True, forConstruction=True)
|
||||
|
||||
self.assertEqual(w1.edges().size(), 1)
|
||||
self.assertEqual(len(w1.ctx.pendingEdges), 1)
|
||||
self.assertEqual(w2.edges().size(), 1)
|
||||
self.assertEqual(len(w2.ctx.pendingEdges), 0)
|
||||
self.assertEqual(w3.wires().size(), 1)
|
||||
self.assertEqual(len(w3.ctx.pendingWires), 1)
|
||||
self.assertEqual(w4.wires().size(), 1)
|
||||
self.assertEqual(len(w4.ctx.pendingWires), 0)
|
||||
|
||||
# spline surface
|
||||
|
||||
N = 40
|
||||
T = 20
|
||||
A = 5
|
||||
|
||||
pts = [
|
||||
[
|
||||
Vector(i, j, A * cos(2 * pi * i / T) * cos(2 * pi * j / T))
|
||||
for i in range(N + 1)
|
||||
]
|
||||
for j in range(N + 1)
|
||||
]
|
||||
|
||||
f1 = Face.makeSplineApprox(pts, smoothing=(1, 1, 1), maxDeg=6)
|
||||
f2 = Face.makeSplineApprox(pts)
|
||||
|
||||
self.assertTrue(f1.isValid())
|
||||
self.assertTrue(f2.isValid())
|
||||
|
||||
with raises(ValueError):
|
||||
f3 = Face.makeSplineApprox(pts, smoothing=(1, 1, 1), maxDeg=3)
|
||||
|
||||
def testParametricSurface(self):
|
||||
|
||||
from math import pi, cos
|
||||
|
||||
r1 = Workplane().parametricSurface(
|
||||
lambda u, v: (u, v, cos(pi * u) * cos(pi * v)), start=-1, stop=1
|
||||
)
|
||||
|
||||
self.assertTrue(r1.faces().val().isValid())
|
||||
|
||||
r2 = Workplane().box(1, 1, 3).split(r1)
|
||||
|
||||
self.assertTrue(r2.solids().val().isValid())
|
||||
self.assertEqual(r2.solids().size(), 2)
|
||||
|
||||
def testEdgeWireClose(self):
|
||||
|
||||
# test with edge
|
||||
e0 = Edge.makeThreePointArc(Vector(0, 0, 0), Vector(1, 1, 0), Vector(0, 2, 0))
|
||||
self.assertFalse(e0.IsClosed())
|
||||
w0 = e0.close()
|
||||
self.assertTrue(w0.IsClosed())
|
||||
|
||||
# test with already closed edge
|
||||
e1 = Edge.makeCircle(1)
|
||||
self.assertTrue(e1.IsClosed())
|
||||
e2 = e1.close()
|
||||
self.assertTrue(e2.IsClosed())
|
||||
self.assertEqual(type(e1), type(e2))
|
||||
|
||||
# test with already closed WIRE
|
||||
w1 = Wire.makeCircle(1, Vector(), Vector(0, 0, 1))
|
||||
self.assertTrue(w1.IsClosed())
|
||||
w2 = w1.close()
|
||||
self.assertTrue(w1 is w2)
|
||||
|
||||
def testSplitShape(self):
|
||||
"""
|
||||
Testing the Shape.split method.
|
||||
"""
|
||||
# split an edge with a vertex
|
||||
e0 = Edge.makeCircle(1, (0, 0, 0), (0, 0, 1))
|
||||
v0 = Vertex.makeVertex(0, 1, 0)
|
||||
list_of_edges = e0.split(v0).Edges()
|
||||
self.assertEqual(len(list_of_edges), 2)
|
||||
self.assertTrue(Vector(0, 1, 0) in [e.endPoint() for e in list_of_edges])
|
||||
|
||||
# split a circle with multiple vertices
|
||||
angles = [2 * math.pi * idx / 10 for idx in range(10)]
|
||||
vecs = [Vector(math.sin(a), math.cos(a), 0) for a in angles]
|
||||
vertices = [Vertex.makeVertex(*v.toTuple()) for v in vecs]
|
||||
edges = e0.split(*vertices).Edges()
|
||||
self.assertEqual(len(edges), len(vertices) + 1)
|
||||
endpoints = [e.endPoint() for e in edges]
|
||||
self.assertTrue(all([v in endpoints for v in vecs]))
|
||||
|
||||
Reference in New Issue
Block a user