def test_surface_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1,-1], [1,0], [1,1], [-1,1], [-1,0], [-1,-1]]) crv2 = CurveFactory.circle(2) + (0,0,1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1,-1,2], [1,1,2], [-1,1,2], [-1,-1,2]]) crv4 = CurveFactory.circle(2) + (0,0,3) surf = SurfaceFactory.loft(crv1, crv2, crv3, crv4) crv1.set_dimension(3) # for convenience when evaluating t = np.linspace( 0, 1, 13) u = np.linspace(crv1.start(0), crv1.end(0), 13) pt = crv1(u) pt2 = surf(t,0).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv2.start(0), crv2.end(0), 13) pt = crv2(u) pt2 = surf(t,1).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv3.start(0), crv3.end(0), 13) pt = crv3(u) pt2 = surf(t,2).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv4.start(0), crv4.end(0), 13) pt = crv4(u) pt2 = surf(t,3).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
def test_surface_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1,-1], [1,0], [1,1], [-1,1], [-1,0], [-1,-1]]) crv2 = cf.circle(2) + (0,0,1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1,-1,2], [1,1,2], [-1,1,2], [-1,-1,2]]) crv4 = cf.circle(2) + (0,0,3) surf = sf.loft(crv1, crv2, crv3, crv4) crv1.set_dimension(3) # for convenience when evaluating t = np.linspace( 0, 1, 13) u = np.linspace(crv1.start(0), crv1.end(0), 13) pt = crv1(u) pt2 = surf(t,0).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv2.start(0), crv2.end(0), 13) pt = crv2(u) pt2 = surf(t,1).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv3.start(0), crv3.end(0), 13) pt = crv3(u) pt2 = surf(t,2).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(crv4.start(0), crv4.end(0), 13) pt = crv4(u) pt2 = surf(t,3).reshape(13,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
def test_circle(self): # unit circle of radius 1 c = CurveFactory.circle() self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=1 t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(np.linalg.norm(pt), 1.0) # check radius=1 # test evaluation at key points pt = c.evaluate(0) # evaluate at 0 self.assertAlmostEqual(pt[0], 1.0) self.assertAlmostEqual(pt[1], 0.0) pt = c.evaluate(c.end(0) / 4) # evaluate at pi/2 self.assertAlmostEqual(pt[0], 0.0) self.assertAlmostEqual(pt[1], 1.0) pt = c.evaluate(c.end(0) / 2) # evaluate at pi self.assertAlmostEqual(pt[0], -1.0) self.assertAlmostEqual(pt[1], 0.0) pt = c.evaluate(c.end(0) * 2) # evaluate outside domain (test periodic) self.assertAlmostEqual(pt[0], 1.0) self.assertAlmostEqual(pt[1], 0.0) # circle of radius different from 1 c = CurveFactory.circle(3) # test evaluation at 25 points for radius=3, outside domain t = np.linspace(c.start(0) - 3, c.end(0) + 2, 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(np.linalg.norm(pt, 2), 3.0) # check radius=3 self.assertAlmostEqual(c.length(), 6*pi, places=3) # circle not at origin c = CurveFactory.circle(1, center=(1,0,0), normal=(1,1,1)) # test evaluation at 25 points t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(np.linalg.norm(pt-[1,0,0], 2), 1.0) # check radius=1 self.assertAlmostEqual(pt[0]+pt[1]+pt[2] - 1, 0.0) # in plane x+y+z=1 self.assertAlmostEqual(c.length(), 2*pi, places=3) # test alt circle c = CurveFactory.circle(r=3, type='p4C1') t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertTrue(np.allclose(x[:,0]**2 + x[:,1]**2, 3.0**2)) for k in c.knots(0): self.assertEqual(c.continuity(k), 1) # test errors and exceptions with self.assertRaises(ValueError): c = CurveFactory.circle(-2.5) # negative radius
def disc(r=1, center=(0, 0, 0), normal=(0, 0, 1), type='radial', xaxis=(1, 0, 0)): """ Create a circular disc. The *type* parameter distinguishes between different parametrizations. :param float r: Radius :param array-like center: local origin :param array-like normal: local normal :param string type: The type of parametrization ('radial' or 'square') :param array-like xaxis: direction of sem, i.e. parametric start point v=0 :return: The disc :rtype: Surface """ if type == 'radial': c1 = CurveFactory.circle(r, center=center, normal=normal, xaxis=xaxis) c2 = flip_and_move_plane_geometry(c1 * 0, center, normal) result = edge_curves(c2, c1) result.swap() result.reparam((0, r), (0, 2 * pi)) return result elif type == 'square': w = 1 / sqrt(2) cp = [[-r * w, -r * w, 1], [0, -r, w], [r * w, -r * w, 1], [-r, 0, w], [0, 0, 1], [r, 0, w], [-r * w, r * w, 1], [0, r, w], [r * w, r * w, 1]] basis1 = BSplineBasis(3) basis2 = BSplineBasis(3) result = Surface(basis1, basis2, cp, True) return flip_and_move_plane_geometry(result, center, normal) else: raise ValueError('invalid type argument')
def disc(r=1, center=(0,0,0), normal=(0,0,1), type='radial'): """disc([r=1], [type='radial']) Create a circular disc. The *type* parameter distinguishes between different parametrizations. :param float r: Radius :param string type: The type of parametrization ('radial' or 'square') :return: The disc :rtype: Surface """ if type == 'radial': c1 = CurveFactory.circle(r) c2 = c1*0 result = edge_curves(c2, c1) result.swap() result.reparam((0,r), (0,2*pi)) elif type == 'square': w = 1 / sqrt(2) cp = [[-r * w, -r * w, 1], [0, -r, w], [r * w, -r * w, 1], [-r, 0, w], [0, 0, 1], [r, 0, w], [-r * w, r * w, 1], [0, r, w], [r * w, r * w, 1]] basis1 = BSplineBasis(3) basis2 = BSplineBasis(3) result = Surface(basis1, basis2, cp, True) else: raise ValueError('invalid type argument') return flip_and_move_plane_geometry(result, center, normal)
def test_3d_self_double_connection(self): c1 = curve_factory.circle(r=1, center=(3, 0, 0), normal=(0, 1, 0)) c2 = curve_factory.circle(r=2, center=(3, 0, 0), normal=(0, 1, 0)) ring = surface_factory.edge_curves(c1, c2) vol = volume_factory.revolve(ring) vol = vol.split(vol.knots('u')[0], direction='u') # break periodicity vol = vol.split(vol.knots('w')[0], direction='w') model = SplineModel(3, 3) model.add(vol, raise_on_twins=False) writer = IFEMWriter(model) expected = [ IFEMConnection(1, 1, 1, 2, 0), IFEMConnection(1, 1, 5, 6, 0) ] for connection, want in zip(writer.connections(), expected): self.assertEqual(connection, want)
def test_volume_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1, -1], [1, 0], [1, 1], [-1, 1], [-1, 0], [-1, -1]]) crv2 = CurveFactory.circle(2) + (0, 0, 1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1, -1, 2], [1, 1, 2], [-1, 1, 2], [-1, -1, 2]]) crv4 = CurveFactory.circle(2) + (0, 0, 3) surf = [] for c in [crv1, crv2, crv3, crv4]: c2 = c.clone() c2.project('z') surf.append(SurfaceFactory.edge_curves(c, c2)) vol = VolumeFactory.loft(surf) surf[0].set_dimension(3) # for convenience when evaluating t = np.linspace(0, 1, 9) s = np.linspace(0, 1, 9) u = np.linspace(surf[0].start(0), surf[0].end(0), 9) v = np.linspace(surf[0].start(1), surf[0].end(1), 9) pt = surf[0](u, v) pt2 = vol(s, t, 0).reshape(9, 9, 3) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0) u = np.linspace(surf[1].start(0), surf[1].end(0), 9) u = np.linspace(surf[1].start(1), surf[1].end(1), 9) pt = surf[1](u, v) pt2 = vol(s, t, 1).reshape(9, 9, 3) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0) u = np.linspace(surf[2].start(0), surf[2].end(0), 9) v = np.linspace(surf[2].start(1), surf[2].end(1), 9) pt = surf[2](u, v) pt2 = vol(s, t, 2).reshape(9, 9, 3) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0) u = np.linspace(surf[3].start(0), surf[3].end(0), 9) v = np.linspace(surf[3].start(1), surf[3].end(1), 9) pt = surf[3](u, v) pt2 = vol(s, t, 3).reshape(9, 9, 3) self.assertAlmostEqual(np.linalg.norm(pt - pt2), 0.0)
def test_volume_loft(self): crv1 = Curve(BSplineBasis(3, range(11), 1), [[1,-1], [1,0], [1,1], [-1,1], [-1,0], [-1,-1]]) crv2 = CurveFactory.circle(2) + (0,0,1) crv3 = Curve(BSplineBasis(4, range(11), 2), [[1,-1,2], [1,1,2], [-1,1,2], [-1,-1,2]]) crv4 = CurveFactory.circle(2) + (0,0,3) surf = [] for c in [crv1, crv2, crv3, crv4]: c2 = c.clone() c2.project('z') surf.append(SurfaceFactory.edge_curves(c, c2)) vol = VolumeFactory.loft(surf) surf[0].set_dimension(3) # for convenience when evaluating t = np.linspace( 0, 1, 9) s = np.linspace( 0, 1, 9) u = np.linspace(surf[0].start(0), surf[0].end(0), 9) v = np.linspace(surf[0].start(1), surf[0].end(1), 9) pt = surf[0](u,v) pt2 = vol(s,t,0).reshape(9,9,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(surf[1].start(0), surf[1].end(0), 9) u = np.linspace(surf[1].start(1), surf[1].end(1), 9) pt = surf[1](u,v) pt2 = vol(s,t,1).reshape(9,9,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(surf[2].start(0), surf[2].end(0), 9) v = np.linspace(surf[2].start(1), surf[2].end(1), 9) pt = surf[2](u,v) pt2 = vol(s,t,2).reshape(9,9,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0) u = np.linspace(surf[3].start(0), surf[3].end(0), 9) v = np.linspace(surf[3].start(1), surf[3].end(1), 9) pt = surf[3](u,v) pt2 = vol(s,t,3).reshape(9,9,3) self.assertAlmostEqual(np.linalg.norm(pt-pt2), 0.0)
def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1), xaxis=(1,0,0)): """ Create a cylinder shell with no top or bottom :param float r: Radius :param float h: Height :param array-like center: The center of the bottom circle :param array-like axis: Cylinder axis :param array-like xaxis: direction of sem, i.e. parametric start point u=0 :return: The cylinder shell :rtype: Surface """ return extrude(CurveFactory.circle(r, center, axis, xaxis=xaxis), h*np.array(axis))
def cylinder(r=1, h=1, center=(0,0,0), axis=(0,0,1)): """cylinder([r=1], [h=1], [center=(0,0,0)], [axis=(0,0,1)]) Create a cylinder shell with no top or bottom :param float r: Radius :param float h: Height :param point-like center: The center of the bottom circle :param vector-like axis: Cylinder axis :return: The cylinder shell :rtype: Surface """ return extrude(CurveFactory.circle(r, center, axis), h*axis)
def circle(self): dim = int( self.read_next_non_whitespace().strip()) r = float( next(self.fstream).strip()) center= np.array(next(self.fstream).split(), dtype=float) normal= np.array(next(self.fstream).split(), dtype=float) xaxis = np.array(next(self.fstream).split(), dtype=float) param = np.array(next(self.fstream).split(), dtype=float) reverse = next(self.fstream).strip() != '0' result = CurveFactory.circle(r=r, center=center, normal=normal, xaxis=xaxis) result.reparam(param) if reverse: result.reverse() return result
def torus(minor_r=1, major_r=3, center=(0,0,0)): """torus([minor_r=1], [major_r=3]) Create a torus (doughnut) by revolving a circle of size *minor_r* around the *z* axis with radius *major_r*. :param float minor_r: The thickness of the torus (radius in the *xz* plane) :param float major_r: The size of the torus (radius in the *xy* plane) :param point-like center: Local origin of the torus :return: A periodic torus :rtype: Surface """ circle = CurveFactory.circle(minor_r) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane circle.translate((major_r, 0, 0)) # move into position to spin around z-axis return revolve(circle) + center
def test_curvature(self): # linear curves have zero curvature crv = Curve() self.assertAlmostEqual(crv.curvature(.3), 0.0) # test multiple evaluation points t = np.linspace(0, 1, 10) k = crv.curvature(t) self.assertTrue(np.allclose(k, 0.0)) # test circle crv = cf.circle(r=3) + [1, 1] t = np.linspace(0, 2 * pi, 10) k = crv.curvature(t) self.assertTrue(np.allclose(k, 1.0 / 3.0)) # circles: k = 1/r # test 3D (np.cross has different behaviour in 2D/3D) crv.set_dimension(3) k = crv.curvature(t) self.assertTrue(np.allclose(k, 1.0 / 3.0)) # circles: k = 1/r
def torus(minor_r=1, major_r=3, center=(0,0,0), normal=(0,0,1), xaxis=(1,0,0)): """ Create a torus (doughnut) by revolving a circle of size *minor_r* around the *z* axis with radius *major_r*. :param float minor_r: The thickness of the torus (radius in the *xz* plane) :param float major_r: The size of the torus (radius in the *xy* plane) :param array-like center: Local origin of the torus :param array-like normal: Local origin of the torus :param array-like center: Local origin of the torus :return: A periodic torus :rtype: Surface """ circle = CurveFactory.circle(minor_r) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane circle.translate((major_r, 0, 0)) # move into position to spin around z-axis result = revolve(circle) result.rotate(rotate_local_x_axis(xaxis, normal)) return flip_and_move_plane_geometry(result, center, normal)
def test_tangent_and_normal(self): crv = cf.circle() crv.set_dimension(3) t = np.linspace(crv.start(0), crv.end(0), 13) X = crv(t) T = crv.tangent(t) B = crv.binormal(t) N = crv.normal(t) # check correct size self.assertEqual(len(B.shape), 2) # returns a matrix self.assertEqual(B.shape[0], 13) self.assertEqual(B.shape[1], 3) # check all evaluation points for (x, t, b, n) in zip(X, T, B, N): # for the circle we have x*t=0 and x=-n self.assertAlmostEqual(np.dot(x, t), 0.0) self.assertTrue(np.allclose(x, -n)) # for all curves we have that t,b,n are orthogonal self.assertAlmostEqual(np.dot(t, b), 0.0) self.assertAlmostEqual(np.dot(b, n), 0.0) self.assertAlmostEqual(np.dot(n, t), 0.0) # for planar (2D) curves, we have b=[0,0,1] self.assertTrue(np.allclose(b, [0, 0, 1])) # check that evaluations work for single-valued input t = crv.tangent(.23) b = crv.binormal(.23) n = crv.normal(.23) self.assertEqual(len(t.shape), 1) # is a vector (not matrix) self.assertEqual(len(b.shape), 1) self.assertEqual(len(n.shape), 1) self.assertAlmostEqual(np.linalg.norm(t), 1.0) # should be normalized self.assertAlmostEqual(np.linalg.norm(b), 1.0) self.assertAlmostEqual(np.linalg.norm(n), 1.0)
def thicken(curve, amount): """ Generate a surface by adding thickness to a curve. - For 2D curves this will generate a 2D planar surface with the curve through the center. - For 3D curves this will generate a surface "tube" which is open at both ends (that is, for a straight line it will generate a cylinder shell). The resulting surface is an approximation generated by interpolating at the Greville points. It will use the same discretization as the input curve. It does not check for self-intersecting geometries. :param Curve curve: The generating curve :param amount: The amount of thickness, either constant or variable (if variable, the function must accept parameters named *x*, *y*, *z* and/or *t*) :return: Surrounding surface :rtype: Surface """ # NOTES: There are several pitfalls with this function # * self intersection: # could be handled more gracefully, but is here ignored # * choice of discretization: # the offset curve is computed from the velocity (tangent) which is of # one continuity less than the original curve. In particular C1 # quadratic curves will get very noticeable C0-kinks in them. Currently # this is completely ignored and we keep the high continuity of the # original curve. # * width given by function input # could produce wild behaviour. Original discretization might not # produce a satisfactory result curve = curve.clone() # clone input curve, throw away input reference t = curve.bases[0].greville() if curve.dimension == 2: # linear parametrization across domain n = len(curve) left_points = np.zeros((n, 2)) right_points = np.zeros((n, 2)) linear = BSplineBasis(2) x = curve.evaluate(t) # curve at interpolation points v = curve.derivative(t) # velocity at interpolation points l = np.sqrt(v[:, 0]**2 + v[:, 1]**2) # normalizing factor for velocity for i in range(n): if l[i] < 1e-13: # in case of zero velocity, use neighbour instead if i > 0: v[i, :] = v[i - 1, :] else: v[i, :] = v[i + 1, :] else: v[i, :] /= l[i] if inspect.isfunction(amount): arg_names = inspect.signature(amount).parameters argc = len(arg_names) argv = [0] * argc for i in range(n): # build up the list of arguments (in case not all of (x,y,t) are specified) for j, name in enumerate(arg_names): if name == 'x': argv[j] = x[i, 0] elif name == 'y': argv[j] = x[i, 1] elif name == 'z': argv[j] = 0.0 elif name == 't': argv[j] = t[i] # figure out the distane at this particular point dist = amount(*argv) # store interpolation points right_points[i, 0] = x[i, 0] - v[i, 1] * dist # x at bottom right_points[i, 1] = x[i, 1] + v[i, 0] * dist # y at bottom left_points[i, 0] = x[i, 0] + v[i, 1] * dist # x at top left_points[i, 1] = x[i, 1] - v[i, 0] * dist # y at top else: right_points[:, 0] = x[:, 0] - v[:, 1] * amount # x at bottom right_points[:, 1] = x[:, 1] + v[:, 0] * amount # y at bottom left_points[:, 0] = x[:, 0] + v[:, 1] * amount # x at top left_points[:, 1] = x[:, 1] - v[:, 0] * amount # y at top # perform interpolation on each side right = CurveFactory.interpolate(right_points, curve.bases[0]) left = CurveFactory.interpolate(left_points, curve.bases[0]) return edge_curves(right, left) else: # dimension=3, we will create a surrounding tube return sweep(curve, CurveFactory.circle(r=amount))
path.append('../') from splipy import curve_factory, surface_factory from splipy.io import STL from numpy import pi, cos, sin import numpy as np ### create a parametric 3D-function def trefoil(t): t = np.array(t) return np.array([sin(t) + 2*sin(2*t), cos(t) - 2*cos(2*t), -sin(3*t)]).T ### do an adaptive best cubic spline-fit of this function path = curve_factory.fit(trefoil, 0, 2*pi) ### since we know it is a closed curve, enforce this on the path path = path.make_periodic(0,0) ### create a sweeping curve (either a circle or square) shape = curve_factory.circle(r=0.2) # shape = 16*curve_factory.n_gon(4) ### sweep *shape along *path srf = surface_factory.sweep(path, shape) ### write results to file. Use meshlab (www.meshlab.net) to view stl-files with STL('trefoil.stl') as f: f.write(srf, n=(150,30))
def test_circle(self): # unit circle of radius 1 c = cf.circle() self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=1 t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(norm(pt), 1.0) # check radius=1 # test evaluation at key points pt = c.evaluate(0) # evaluate at 0 self.assertAlmostEqual(pt[0], 1.0) self.assertAlmostEqual(pt[1], 0.0) pt = c.evaluate(c.end(0) / 4) # evaluate at pi/2 self.assertAlmostEqual(pt[0], 0.0) self.assertAlmostEqual(pt[1], 1.0) pt = c.evaluate(c.end(0) / 2) # evaluate at pi self.assertAlmostEqual(pt[0], -1.0) self.assertAlmostEqual(pt[1], 0.0) pt = c.evaluate(c.end(0) * 2) # evaluate outside domain (test periodic) self.assertAlmostEqual(pt[0], 1.0) self.assertAlmostEqual(pt[1], 0.0) # circle of radius different from 1 c = cf.circle(3) # test evaluation at 25 points for radius=3, outside domain t = np.linspace(c.start(0) - 3, c.end(0) + 2, 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(norm(pt, 2), 3.0) # check radius=3 self.assertAlmostEqual(c.length(), 6 * pi, places=3) # circle not at origin c = cf.circle(1, center=(1, 0, 0), normal=(1, 1, 1)) # test evaluation at 25 points t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(norm(pt - [1, 0, 0], 2), 1.0) # check radius=1 self.assertAlmostEqual(pt[0] + pt[1] + pt[2] - 1, 0.0) # in plane x+y+z=1 self.assertAlmostEqual(c.length(), 2 * pi, places=3) # test alt circle c = cf.circle(r=3, type='p4C1') t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertTrue(np.allclose(x[:, 0]**2 + x[:, 1]**2, 3.0**2)) for k in c.knots(0): self.assertEqual(c.continuity(k), 1) # test circle with different xaxis c = cf.circle(xaxis=(1, 1, 0)) t = np.linspace(c.start(0), c.end(0), 5) x = c.evaluate(t) self.assertTrue(np.allclose(x[:, 0]**2 + x[:, 1]**2, 1.0**2)) self.assertTrue(np.allclose(x[0, :], [1 / sqrt(2), 1 / sqrt(2)])) self.assertTrue(np.allclose(x[1, :], [-1 / sqrt(2), 1 / sqrt(2)])) # test using all parameters (in x+y+z=1 plane) c = cf.circle(r=sqrt(2), normal=(1, 1, 1), center=(1, 0, 0), xaxis=(-1, 1, 0)) t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) self.assertTrue( np.allclose((x[:, 0] - 1)**2 + x[:, 1]**2 + x[:, 2]**2, 2.0)) self.assertTrue(np.allclose(c(0), [0, 1, 0])) self.assertTrue(np.allclose(c(pi), [2, -1, 0])) # test errors and exceptions with self.assertRaises(ValueError): c = cf.circle(-2.5) # negative radius
from splipy import curve_factory, surface_factory from splipy.io import STL from numpy import pi, cos, sin import numpy as np ### create a parametric 3D-function def trefoil(t): t = np.array(t) return np.array( [sin(t) + 2 * sin(2 * t), cos(t) - 2 * cos(2 * t), -sin(3 * t)]).T ### do an adaptive best cubic spline-fit of this function path = curve_factory.fit(trefoil, 0, 2 * pi) ### since we know it is a closed curve, enforce this on the path path = path.make_periodic(0, 0) ### create a sweeping curve (either a circle or square) shape = curve_factory.circle(r=0.2) # shape = 16*curve_factory.n_gon(4) ### sweep *shape along *path srf = surface_factory.sweep(path, shape) ### write results to file. Use meshlab (www.meshlab.net) to view stl-files with STL('trefoil.stl') as f: f.write(srf, n=(150, 30))
# parametrization, and the acceleration vector is shown to be discontinuous. # # Author: Kjetil Andre Johannessen # Institute: Norwegian University of Science and Technology (NTNU) # Date: March 2016 # from sys import path path.append('../') from splipy import * import splipy.curve_factory as curves import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation n = 250 # number of evaluation points c = curves.circle() # create the NURBS circle t = np.linspace(c.start(0), c.end(0), n) # parametric evaluation points x = c(t) # physical (x,y)-coordinates, size (n,2) v = c.derivative(t, 1) # velocity at all points a = c.derivative(t, 2) # acceleration at all points # plot the circle and get reference to the acceleration/velocity lines which we # will update during animation fig = plt.figure() plt.plot(x[:,0], x[:,1], 'k-') velocity, = plt.plot([x[0,0], x[0,0]+v[0,0]], [x[0,1], x[0,1]+v[0,1]], 'r-', linewidth=2) acceleration, = plt.plot([x[0,0], x[0,0]+a[0,0]], [x[0,1], x[0,1]+a[0,1]], 'b-', linewidth=3) plt.axis('equal') plt.legend(('NURBS Circle', 'Velocity', 'Acceleration')) # update the velocity/acceleration lines for frame *i* in the animation