def test_edge_curves(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # mixes rational and non-rational curves with different parametrization spaces c1 = CurveFactory.circle_segment(pi / 2) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) c3 = CurveFactory.circle_segment(pi / 2) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]) surf = SurfaceFactory.edge_curves(c1, c2, c3, c4) # srf spits out parametric space (0,1)^2, so we sync these up to input curves c3.reverse() c4.reverse() c1.reparam() c2.reparam() c3.reparam() c4.reparam() for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 0)[0], c1(u)[0]) # x-coord, bottom crv self.assertAlmostEqual(surf(u, 0)[1], c1(u)[1]) # y-coord, bottom crv for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 1)[0], c3(u)[0]) # x-coord, top crv self.assertAlmostEqual(surf(u, 1)[1], c3(u)[1]) # y-coord, top crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(0, v)[0], c4(v)[0]) # x-coord, left crv self.assertAlmostEqual(surf(0, v)[1], c4(v)[1]) # y-coord, left crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(1, v)[0], c2(v)[0]) # x-coord, right crv self.assertAlmostEqual(surf(1, v)[1], c2(v)[1]) # y-coord, right crv
def test_edge_curves(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # mixes rational and non-rational curves with different parametrization spaces c1 = cf.circle_segment(pi / 2) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) c3 = cf.circle_segment(pi / 2) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]) surf = sf.edge_curves(c1, c2, c3, c4) # srf spits out parametric space (0,1)^2, so we sync these up to input curves c3.reverse() c4.reverse() c1.reparam() c2.reparam() c3.reparam() c4.reparam() for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 0)[0], c1(u)[0]) # x-coord, bottom crv self.assertAlmostEqual(surf(u, 0)[1], c1(u)[1]) # y-coord, bottom crv for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 1)[0], c3(u)[0]) # x-coord, top crv self.assertAlmostEqual(surf(u, 1)[1], c3(u)[1]) # y-coord, top crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(0, v)[0], c4(v)[0]) # x-coord, left crv self.assertAlmostEqual(surf(0, v)[1], c4(v)[1]) # y-coord, left crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(1, v)[0], c2(v)[0]) # x-coord, right crv self.assertAlmostEqual(surf(1, v)[1], c2(v)[1]) # y-coord, right crv # add a case where opposing sites have mis-matching rationality crvs = Surface().edges() # returned in order umin, umax, vmin, vmax crvs[0].force_rational() crvs[1].reverse() crvs[2].reverse() # input curves should be clockwise oriented closed loop srf = sf.edge_curves(crvs[0], crvs[3], crvs[1], crvs[2]) crvs[1].reverse() u = np.linspace(0, 1, 7) self.assertTrue(np.allclose(srf(u, 0).reshape((7, 2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u, 1).reshape((7, 2)), crvs[1](u))) # test self-organizing curve ordering when they are not sequential srf = sf.edge_curves(crvs[0], crvs[2].reverse(), crvs[3], crvs[1]) u = np.linspace(0, 1, 7) self.assertTrue(np.allclose(srf(u, 0).reshape((7, 2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u, 1).reshape((7, 2)), crvs[1](u))) # test error handling with self.assertRaises(ValueError): srf = sf.edge_curves(crvs + (Curve(), )) # 5 input curves
def test_edge_curves_elasticity(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # rebuild to avoid rational representations c1 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) c3 = CurveFactory.circle_segment(pi / 2).rebuild(3,11) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]).rebuild(3,10) c4 = c4.rebuild(4,11) surf = SurfaceFactory.edge_curves([c1, c2, c3, c4], type='elasticity') # check right dimensions of output self.assertEqual(surf.shape[0], 11) # 11 controlpoints in the circle segment self.assertEqual(surf.shape[1], 13) # 11 controlpoints in c4, +2 for C0-knot in c1 self.assertEqual(surf.order(0), 3) self.assertEqual(surf.order(1), 4) # check that c1 edge conforms to surface edge u = np.linspace(0,1,7) c1.reparam() pts_surf = surf(u,0.0) pts_c1 = c1(u) for (xs,xc) in zip(pts_surf[:,0,:], pts_c1): self.assertTrue(np.allclose(xs, xc)) # check that c2 edge conforms to surface edge v = np.linspace(0,1,7) c2.reparam() pts_surf = surf(1.0,v) pts_c2 = c2(v) for (xs,xc) in zip(pts_surf[:,0,:], pts_c2): self.assertTrue(np.allclose(xs, xc))
def test_edge_curves(self): # create an arrow-like 2D geometry with the pointy end at (-1,1) towards up and left # mixes rational and non-rational curves with different parametrization spaces c1 = CurveFactory.circle_segment(pi / 2) c2 = Curve(BSplineBasis(2, [0, 0, 1, 2, 2]), [[0, 1], [-1, 1], [-1, 0]]) c3 = CurveFactory.circle_segment(pi / 2) c3.rotate(pi) c4 = Curve(BSplineBasis(2), [[0, -1], [1, 0]]) surf = SurfaceFactory.edge_curves(c1, c2, c3, c4) # srf spits out parametric space (0,1)^2, so we sync these up to input curves c3.reverse() c4.reverse() c1.reparam() c2.reparam() c3.reparam() c4.reparam() for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 0)[0], c1(u)[0]) # x-coord, bottom crv self.assertAlmostEqual(surf(u, 0)[1], c1(u)[1]) # y-coord, bottom crv for u in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(u, 1)[0], c3(u)[0]) # x-coord, top crv self.assertAlmostEqual(surf(u, 1)[1], c3(u)[1]) # y-coord, top crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(0, v)[0], c4(v)[0]) # x-coord, left crv self.assertAlmostEqual(surf(0, v)[1], c4(v)[1]) # y-coord, left crv for v in np.linspace(0, 1, 7): self.assertAlmostEqual(surf(1, v)[0], c2(v)[0]) # x-coord, right crv self.assertAlmostEqual(surf(1, v)[1], c2(v)[1]) # y-coord, right crv # add a case where opposing sites have mis-matching rationality crvs = Surface().edges() # returned in order umin, umax, vmin, vmax crvs[0].force_rational() crvs[1].reverse() crvs[2].reverse() # input curves should be clockwise oriented closed loop srf = SurfaceFactory.edge_curves(crvs[0], crvs[3], crvs[1], crvs[2]) crvs[1].reverse() u = np.linspace(0,1,7) self.assertTrue(np.allclose(srf(u,0).reshape((7,2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u,1).reshape((7,2)), crvs[1](u))) # test self-organizing curve ordering when they are not sequential srf = SurfaceFactory.edge_curves(crvs[0], crvs[2].reverse(), crvs[3], crvs[1]) u = np.linspace(0,1,7) self.assertTrue(np.allclose(srf(u,0).reshape((7,2)), crvs[0](u))) self.assertTrue(np.allclose(srf(u,1).reshape((7,2)), crvs[1](u))) # test error handling with self.assertRaises(ValueError): srf = SurfaceFactory.edge_curves(crvs + (Curve(),)) # 5 input curves
def test_circle_segment(self): # basic circle segment c = cf.circle_segment(pi * 0.9) 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, 2), 1.0) # check radius=1 # radius 7 circle segment c = cf.circle_segment(pi * 1.87, 7) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=7 t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(norm(pt, 2), 7.0) # check radius=7 # negative theta c = cf.circle_segment(-pi / 2) self.assertEqual(c.rational, True) self.assertTrue(np.allclose(c(0), [1, 0])) self.assertTrue(np.allclose(c(-pi / 4), [1 / sqrt(2), -1 / sqrt(2)])) self.assertTrue(np.allclose(c(-pi / 2), [0, -1])) # boundary case with one knot span circle segment c = cf.circle_segment(2 * pi / 3) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 2) self.assertFalse(c.periodic(0)) # 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, 2), 1.0) # check radius=1 # boundary case with full circle c = cf.circle_segment(2 * pi) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 5) self.assertTrue(c.periodic(0)) # 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, 2), 1.0) # check radius=1 # test errors and exceptions with self.assertRaises(ValueError): c = cf.circle_segment(3 * pi) # outside domain with self.assertRaises(ValueError): c = cf.circle_segment(-3 * pi) # outside domain with self.assertRaises(ValueError): c = cf.circle_segment(pi, -2) # negative radius
def test_circle_segment(self): # basic circle segment c = CurveFactory.circle_segment(pi * 0.9) 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, 2), 1.0) # check radius=1 # radius 7 circle segment c = CurveFactory.circle_segment(pi * 1.87, 7) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) # test evaluation at 25 points for radius=7 t = np.linspace(c.start(0), c.end(0), 25) x = c.evaluate(t) for pt in np.array(x): self.assertAlmostEqual(norm(pt, 2), 7.0) # check radius=7 # negative theta c = CurveFactory.circle_segment(-pi/2) self.assertEqual(c.rational, True) self.assertTrue(np.allclose(c(0), [1,0])) self.assertTrue(np.allclose(c(-pi/4), [1/sqrt(2),-1/sqrt(2)])) self.assertTrue(np.allclose(c(-pi/2), [0,-1])) # boundary case with one knot span circle segment c = CurveFactory.circle_segment(2 * pi / 3) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 2) self.assertFalse(c.periodic(0)) # 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, 2), 1.0) # check radius=1 # boundary case with full circle c = CurveFactory.circle_segment(2 * pi) self.assertEqual(c.dimension, 2) self.assertEqual(c.rational, True) self.assertEqual(len(c.knots(0)), 5) self.assertTrue(c.periodic(0)) # 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, 2), 1.0) # check radius=1 # test errors and exceptions with self.assertRaises(ValueError): c = CurveFactory.circle_segment(3 * pi) # outside domain with self.assertRaises(ValueError): c = CurveFactory.circle_segment(-3 * pi) # outside domain with self.assertRaises(ValueError): c = CurveFactory.circle_segment(pi, -2) # negative radius
def thingy(radius, elements, out): right = cf.circle_segment(np.pi / 2) right.rotate(-np.pi / 4).translate((radius - 1, 0, 0)) left = right.clone().rotate(np.pi) right.reverse() thingy = sf.edge_curves(left, right) thingy.raise_order(0, 1) thingy.refine(*[e - 1 for e in elements]) with G2(out + '.g2') as f: f.write([thingy])
def sphere(r=1, center=(0,0,0)): """sphere([r=1]) Create a spherical shell. :param float r: Radius :param point-like center: Local origin of the sphere :return: The spherical shell :rtype: Surface """ circle = CurveFactory.circle_segment(pi, r) circle.rotate(-pi / 2) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane return revolve(circle) + center
def sphere(r=1, center=(0, 0, 0), zaxis=(0, 0, 1), xaxis=(1, 0, 0)): """ Create a spherical shell. :param float r: Radius :param array-like center: Local origin of the sphere :param array-like zaxis: direction of the north/south pole of the parametrization :param array-like xaxis: direction of the longitudal sem :return: The spherical shell :rtype: Surface """ circle = CurveFactory.circle_segment(pi, r) circle.rotate(-pi / 2) circle.rotate(pi / 2, (1, 0, 0)) # flip up into xz-plane result = revolve(circle) result.rotate(rotate_local_x_axis(xaxis, zaxis)) return flip_and_move_plane_geometry(result, center, zaxis)
def revolve(curve, theta=2 * pi, axis=[0,0,1]): """revolve(curve, [theta=2pi], [axis=[0,0,1]]) Revolve a surface by sweeping a curve in a rotational fashion around the *z* axis. :param Curve curve: Curve to revolve :param float theta: Angle to revolve, in radians :param vector-like axis: Axis of rotation :return: The revolved surface :rtype: Surface """ curve = curve.clone() # clone input curve, throw away input reference curve.set_dimension(3) # add z-components (if not already present) curve.force_rational() # add weight (if not already present) # align axis with the z-axis normal_theta = atan2(axis[1], axis[0]) normal_phi = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2]) curve.rotate(-normal_theta, [0,0,1]) curve.rotate(-normal_phi, [0,1,0]) circle_seg = CurveFactory.circle_segment(theta) n = len(curve) # number of control points of the curve m = len(circle_seg) # number of control points of the sweep cp = np.zeros((m * n, 4)) # loop around the circle and set control points by the traditional 9-point # circle curve with weights 1/sqrt(2), only here C0-periodic, so 8 points dt = 0 t = 0 for i in range(m): x,y,w = circle_seg[i] dt = atan2(y,x) - t t += dt curve.rotate(dt) cp[i * n:(i + 1) * n, :] = curve[:] cp[i * n:(i + 1) * n, 2] *= w cp[i * n:(i + 1) * n, 3] *= w result = Surface(curve.bases[0], circle_seg.bases[0], cp, True) # rotate it back again result.rotate(normal_phi, [0,1,0]) result.rotate(normal_theta, [0,0,1]) return result
def revolve(curve, theta=2 * pi, axis=(0, 0, 1)): """ Revolve a surface by sweeping a curve in a rotational fashion around the *z* axis. :param Curve curve: Curve to revolve :param float theta: Angle to revolve, in radians :param array-like axis: Axis of rotation :return: The revolved surface :rtype: Surface """ curve = curve.clone() # clone input curve, throw away input reference curve.set_dimension(3) # add z-components (if not already present) curve.force_rational() # add weight (if not already present) # align axis with the z-axis normal_theta = atan2(axis[1], axis[0]) normal_phi = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2]) curve.rotate(-normal_theta, [0, 0, 1]) curve.rotate(-normal_phi, [0, 1, 0]) circle_seg = CurveFactory.circle_segment(theta) n = len(curve) # number of control points of the curve m = len(circle_seg) # number of control points of the sweep cp = np.zeros((m * n, 4)) # loop around the circle and set control points by the traditional 9-point # circle curve with weights 1/sqrt(2), only here C0-periodic, so 8 points dt = 0 t = 0 for i in range(m): x, y, w = circle_seg[i] dt = atan2(y, x) - t t += dt curve.rotate(dt) cp[i * n:(i + 1) * n, :] = curve[:] cp[i * n:(i + 1) * n, 2] *= w cp[i * n:(i + 1) * n, 3] *= w result = Surface(curve.bases[0], circle_seg.bases[0], cp, True) # rotate it back again result.rotate(normal_phi, [0, 1, 0]) result.rotate(normal_theta, [0, 0, 1]) return result
def revolve(surf, theta=2 * pi, axis=(0, 0, 1)): """ Revolve a volume by sweeping a surface in a rotational fashion around an axis. :param Surface surf: Surface to revolve :param float theta: Angle to revolve, in radians :param array-like axis: Axis of rotation :return: The revolved surface :rtype: Volume """ surf = surf.clone() # clone input surface, throw away old reference surf.set_dimension(3) # add z-components (if not already present) surf.force_rational() # add weight (if not already present) # align axis with the z-axis normal_theta = atan2(axis[1], axis[0]) normal_phi = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2]) surf.rotate(-normal_theta, [0, 0, 1]) surf.rotate(-normal_phi, [0, 1, 0]) path = CurveFactory.circle_segment(theta=theta) n = len(surf) # number of control points of the surface m = len(path) # number of control points of the sweep cp = np.zeros((m * n, 4)) dt = np.sign(theta) * (path.knots(0)[1] - path.knots(0)[0]) / 2.0 for i in range(m): weight = path[i, -1] cp[i * n:(i + 1) * n, :] = np.reshape( surf.controlpoints.transpose(1, 0, 2), (n, 4)) cp[i * n:(i + 1) * n, 2] *= weight cp[i * n:(i + 1) * n, 3] *= weight surf.rotate(dt) result = Volume(surf.bases[0], surf.bases[1], path.bases[0], cp, True) # rotate it back again result.rotate(normal_phi, [0, 1, 0]) result.rotate(normal_theta, [0, 0, 1]) return result
def revolve(surf, theta=2 * pi, axis=(0,0,1)): """ Revolve a volume by sweeping a surface in a rotational fashion around an axis. :param Surface surf: Surface to revolve :param float theta: Angle to revolve, in radians :param array-like axis: Axis of rotation :return: The revolved surface :rtype: Volume """ surf = surf.clone() # clone input surface, throw away old reference surf.set_dimension(3) # add z-components (if not already present) surf.force_rational() # add weight (if not already present) # align axis with the z-axis normal_theta = atan2(axis[1], axis[0]) normal_phi = atan2(sqrt(axis[0]**2 + axis[1]**2), axis[2]) surf.rotate(-normal_theta, [0,0,1]) surf.rotate(-normal_phi, [0,1,0]) path = CurveFactory.circle_segment(theta=theta) n = len(surf) # number of control points of the surface m = len(path) # number of control points of the sweep cp = np.zeros((m * n, 4)) dt = np.sign(theta)*(path.knots(0)[1] - path.knots(0)[0]) / 2.0 for i in range(m): weight = path[i,-1] cp[i * n:(i + 1) * n, :] = np.reshape(surf.controlpoints.transpose(1, 0, 2), (n, 4)) cp[i * n:(i + 1) * n, 2] *= weight cp[i * n:(i + 1) * n, 3] *= weight surf.rotate(dt) result = Volume(surf.bases[0], surf.bases[1], path.bases[0], cp, True) # rotate it back again result.rotate(normal_phi, [0,1,0]) result.rotate(normal_theta, [0,0,1]) return result
def curves_from_path(self, path): # see https://www.w3schools.com/graphics/svg_path.asp for documentation # and also https://www.w3.org/TR/SVG/paths.html # figure out the largest polynomial order of this path if re.search('[cCsS]', path): order = 4 elif re.search('[qQtTaA]', path): order = 3 else: order = 2 last_curve = None result = [] # each 'piece' is an operator (M,C,Q,L etc) and accomponying list of argument points for piece in re.findall('[a-zA-Z][^a-zA-Z]*', path): # if not single-letter command (i.e. 'z') if len(piece) > 1: # points is a (string-)list of (x,y)-coordinates for the given operator points = re.findall('-?\d+\.?\d*', piece[1:]) if piece[0].lower() != 'a' and piece[0].lower( ) != 'v' and piece[0].lower() != 'h': # convert string-list to a list of numpy arrays (of size 2) np_pts = np.reshape( np.array(points).astype('float'), (int(len(points) / 2), 2)) if piece[0] == 'm' or piece[0] == 'M': # I really hope it always start with a move command (think it does) startpoint = np_pts[0] if len(np_pts) > 1: if piece[0] == 'M': knot = [0] + list(range( len(np_pts))) + [len(np_pts) - 1] curve_piece = Curve(BSplineBasis(2, knot), np_pts) elif piece[0] == 'm': knot = [0] + list(range( len(np_pts))) + [len(np_pts) - 1] controlpoints = [startpoint] for cp in np_pts[1:]: controlpoints.append(cp + controlpoints[-1]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) else: continue elif piece[0] == 'c': # cubic spline, relatively positioned controlpoints = [startpoint] knot = list(range(int(len(np_pts) / 3) + 1)) * 3 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[int( (len(controlpoints) - 1) / 3) * 3] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'C': # cubic spline, absolute position controlpoints = [startpoint] knot = list(range(int(len(np_pts) / 3) + 1)) * 3 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 's': # smooth cubic spline, relative position controlpoints = [startpoint] knot = list(range(int(len(np_pts) / 2) + 1)) * 3 knot += [knot[0], knot[-1]] knot.sort() x0 = np.array(last_curve[-1]) xn1 = np.array(last_curve[-2]) controlpoints.append(2 * x0 - xn1) startpoint = controlpoints[-1] for i, cp in enumerate(np_pts): if i % 2 == 0 and i > 0: startpoint = controlpoints[-1] controlpoints.append(2 * controlpoints[-1] - controlpoints[-2]) controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'S': # smooth cubic spline, absolute position controlpoints = [startpoint] knot = list(range(int(len(np_pts) / 2) + 1)) * 3 knot += [knot[0], knot[-1]] knot.sort() x0 = np.array(last_curve[-1]) xn1 = np.array(last_curve[-2]) controlpoints.append(2 * x0 - xn1) for i, cp in enumerate(np_pts): if i % 2 == 0 and i > 0: controlpoints.append(2 * controlpoints[-1] - controlpoints[-2]) controlpoints.append(cp) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'q': # quadratic spline, relatively positioned controlpoints = [startpoint] knot = list(range(int(len(np_pts) / 2) + 1)) * 2 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[int( (len(controlpoints) - 1) / 2) * 2] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(3, knot), controlpoints) elif piece[0] == 'Q': # quadratic spline, absolute position controlpoints = [startpoint] knot = list(range(len(np_pts) / 2 + 1)) * 2 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(3, knot), controlpoints) elif piece[0] == 'l': # linear spline, relatively positioned controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'L': # linear spline, absolute position controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'h': # horizontal piece, relatively positioned np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(np.array([cp, 0]) + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'H': # horizontal piece, absolute position np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append([cp, startpoint[1]]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'v': # vertical piece, relatively positioned np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(np.array([0, cp]) + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'V': # vertical piece, absolute position np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts) + 1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append([startpoint[0], cp]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'A' or piece[0] == 'a': np_pts = np.reshape( np.array(points).astype('float'), (int(len(points)))) rx = float(points[0]) ry = float(points[1]) x_axis_rotation = float(points[2]) large_arc_flag = (points[3] != '0') sweep_flag = (points[4] != '0') xend = np.array([float(points[5]), float(points[6])]) if piece[0] == 'a': xend += startpoint R = np.array( [[np.cos(x_axis_rotation), np.sin(x_axis_rotation)], [-np.sin(x_axis_rotation), np.cos(x_axis_rotation)]]) xp = np.linalg.solve(R, (startpoint - xend) / 2) if sweep_flag == large_arc_flag: cprime = -(np.sqrt( abs(rx**2 * ry**2 - rx**2 * xp[1]**2 - ry**2 * xp[0]**2) / (rx**2 * xp[1]**2 + ry**2 * xp[0]**2)) * np.array([rx * xp[1] / ry, -ry * xp[0] / rx])) else: cprime = +(np.sqrt( abs(rx**2 * ry**2 - rx**2 * xp[1]**2 - ry**2 * xp[0]**2) / (rx**2 * xp[1]**2 + ry**2 * xp[0]**2)) * np.array([rx * xp[1] / ry, -ry * xp[0] / rx])) center = np.linalg.solve(R.T, cprime) + (startpoint + xend) / 2 def arccos(vec1, vec2): return (np.sign(vec1[0] * vec2[1] - vec1[1] * vec2[0]) * np.arccos( vec1.dot(vec2) / np.linalg.norm(vec1) / np.linalg.norm(vec2))) tmp1 = np.divide(xp - cprime, [rx, ry]) tmp2 = np.divide(-xp - cprime, [rx, ry]) theta1 = arccos(np.array([1, 0]), tmp1) delta_t = arccos(tmp1, tmp2) % (2 * np.pi) if not sweep_flag and delta_t > 0: delta_t -= 2 * np.pi elif sweep_flag and delta_t < 0: delta_t += 2 * np.pi curve_piece = (curve_factory.circle_segment(delta_t) * [rx, ry]).rotate(theta1) + center # curve_piece = curve_factory.circle_segment(delta_t) elif piece[0] == 'z' or piece[0] == 'Z': # periodic curve # curve_piece = Curve(BSplineBasis(2), [startpoint, last_curve[0]]) # curve_piece.reparam([0, curve_piece.length()]) # last_curve.append(curve_piece).make_periodic(0) last_curve.make_periodic(0) result.append(last_curve) last_curve = None continue else: raise RuntimeError('Unknown path parameter:' + piece) if (curve_piece.length() > state.controlpoint_absolute_tolerance): curve_piece.reparam([0, curve_piece.length()]) if last_curve is None: last_curve = curve_piece else: last_curve.append(curve_piece) startpoint = last_curve[-1, : 2] # disregard rational weight (if any) if last_curve is not None: result.append(last_curve) return result
# 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 splipy.surface_factory as surfaces import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from math import pi, cos, sin # create the three sides of the triangle, each consisting of a circle segment c1 = curves.circle_segment(pi/3) c2 = c1.clone().rotate(2*pi/3) + [1,0] c3 = c1.clone().rotate(4*pi/3) + [cos(pi/3), sin(pi/3)] # merge the three circles into one, and center it at the origin c = c1.append(c2).append(c3) c -= c.center() # plot the reuleaux triangle t = np.linspace(c.start(0), c.end(0), 151) # 151 parametric evaluation points x = c(t) # evaluate (x,y)-coordinates plt.plot(x[:,0], x[:,1]) plt.axis('equal') plt.show() # split the triangle in two, and align this with the y-axis
import splipy.curve_factory as CurveFactory import splipy.surface_factory as SurfaceFactory from splipy.io import G2 from math import sqrt, sin, pi beta = 0.1 R = 2540 l = 508 w = 2*R*sin(beta) y0 = -sqrt(R*R-0.25*w*w) arch = CurveFactory.circle_segment(2*beta,R,[0,0,1]) arch.rotate(pi/2-beta) arch.translate([0,y0,0]) shell = SurfaceFactory.extrude(arch,[0,0,l]) print(shell) with G2('shallow_arch.g2') as output: output.write(shell)
# 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 splipy.surface_factory as surfaces import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from math import pi, cos, sin # create the three sides of the triangle, each consisting of a circle segment c1 = curves.circle_segment(pi / 3) c2 = c1.clone().rotate(2 * pi / 3) + [1, 0] c3 = c1.clone().rotate(4 * pi / 3) + [cos(pi / 3), sin(pi / 3)] # merge the three circles into one, and center it at the origin c = c1.append(c2).append(c3) c -= c.center() # plot the reuleaux triangle t = np.linspace(c.start(0), c.end(0), 151) # 151 parametric evaluation points x = c(t) # evaluate (x,y)-coordinates plt.plot(x[:, 0], x[:, 1]) plt.axis('equal') plt.show() # split the triangle in two, and align this with the y-axis
def curves_from_path(self, path): # see https://www.w3schools.com/graphics/svg_path.asp for documentation # and also https://www.w3.org/TR/SVG/paths.html # figure out the largest polynomial order of this path if re.search('[cCsS]', path): order = 4 elif re.search('[qQtTaA]', path): order = 3 else: order = 2 last_curve = None result = [] # each 'piece' is an operator (M,C,Q,L etc) and accomponying list of argument points for piece in re.findall('[a-zA-Z][^a-zA-Z]*', path): # if not single-letter command (i.e. 'z') if len(piece)>1: # points is a (string-)list of (x,y)-coordinates for the given operator points = re.findall('-?\d+\.?\d*', piece[1:]) if piece[0].lower() != 'a' and piece[0].lower() != 'v' and piece[0].lower() != 'h': # convert string-list to a list of numpy arrays (of size 2) np_pts = np.reshape(np.array(points).astype('float'), (int(len(points)/2),2)) if piece[0] == 'm' or piece[0] == 'M': # I really hope it always start with a move command (think it does) startpoint = np_pts[0] if len(np_pts) > 1: if piece[0] == 'M': knot = [0] + list(range(len(np_pts))) + [len(np_pts)-1] curve_piece = Curve(BSplineBasis(2, knot), np_pts) elif piece[0] == 'm': knot = [0] + list(range(len(np_pts))) + [len(np_pts)-1] controlpoints = [startpoint] for cp in np_pts[1:]: controlpoints.append(cp + controlpoints[-1]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) else: continue elif piece[0] == 'c': # cubic spline, relatively positioned controlpoints = [startpoint] knot = list(range(int(len(np_pts)/3)+1)) * 3 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[int((len(controlpoints)-1)/3)*3] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'C': # cubic spline, absolute position controlpoints = [startpoint] knot = list(range(int(len(np_pts)/3)+1)) * 3 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 's': # smooth cubic spline, relative position controlpoints = [startpoint] knot = list(range(int(len(np_pts)/2)+1)) * 3 knot += [knot[0], knot[-1]] knot.sort() x0 = np.array(last_curve[-1]) xn1 = np.array(last_curve[-2]) controlpoints.append(2*x0 -xn1) startpoint = controlpoints[-1] for i, cp in enumerate(np_pts): if i % 2 == 0 and i>0: startpoint = controlpoints[-1] controlpoints.append(2*controlpoints[-1] - controlpoints[-2]) controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'S': # smooth cubic spline, absolute position controlpoints = [startpoint] knot = list(range(int(len(np_pts)/2)+1)) * 3 knot += [knot[0], knot[-1]] knot.sort() x0 = np.array(last_curve[-1]) xn1 = np.array(last_curve[-2]) controlpoints.append(2*x0 -xn1) for i,cp in enumerate(np_pts): if i % 2 == 0 and i>0: controlpoints.append(2*controlpoints[-1] - controlpoints[-2]) controlpoints.append(cp) curve_piece = Curve(BSplineBasis(4, knot), controlpoints) elif piece[0] == 'q': # quadratic spline, relatively positioned controlpoints = [startpoint] knot = list(range(int(len(np_pts)/2)+1)) * 2 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[int((len(controlpoints)-1)/2)*2] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(3, knot), controlpoints) elif piece[0] == 'Q': # quadratic spline, absolute position controlpoints = [startpoint] knot = list(range(len(np_pts)/2+1)) * 2 knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(3, knot), controlpoints) elif piece[0] == 'l': # linear spline, relatively positioned controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(cp + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'L': # linear spline, absolute position controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append(cp) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'h': # horizontal piece, relatively positioned np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(np.array([cp, 0]) + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'H': # horizontal piece, absolute position np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append([cp, startpoint[1]]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'v': # vertical piece, relatively positioned np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: startpoint = controlpoints[-1] controlpoints.append(np.array([0, cp]) + startpoint) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'V': # vertical piece, absolute position np_pts = np.array(points).astype('float') controlpoints = [startpoint] knot = list(range(len(np_pts)+1)) knot += [knot[0], knot[-1]] knot.sort() for cp in np_pts: controlpoints.append([startpoint[0], cp]) curve_piece = Curve(BSplineBasis(2, knot), controlpoints) elif piece[0] == 'A' or piece[0] == 'a': np_pts = np.reshape(np.array(points).astype('float'), (int(len(points)))) rx = float(points[0]) ry = float(points[1]) x_axis_rotation = float(points[2]) large_arc_flag = (points[3] != '0') sweep_flag = (points[4] != '0') xend = np.array([float(points[5]), float(points[6]) ]) if piece[0] == 'a': xend += startpoint R = np.array([[ np.cos(x_axis_rotation), np.sin(x_axis_rotation)], [-np.sin(x_axis_rotation), np.cos(x_axis_rotation)]]) xp = np.linalg.solve(R, (startpoint - xend)/2) if sweep_flag == large_arc_flag: cprime = -(np.sqrt(abs(rx**2*ry**2 - rx**2*xp[1]**2 - ry**2*xp[0]**2) / (rx**2*xp[1]**2 + ry**2*xp[0]**2)) * np.array([rx*xp[1]/ry, -ry*xp[0]/rx])) else: cprime = +(np.sqrt(abs(rx**2*ry**2 - rx**2*xp[1]**2 - ry**2*xp[0]**2) / (rx**2*xp[1]**2 + ry**2*xp[0]**2)) * np.array([rx*xp[1]/ry, -ry*xp[0]/rx])) center = np.linalg.solve(R.T, cprime) + (startpoint+xend)/2 def arccos(vec1, vec2): return (np.sign(vec1[0]*vec2[1] - vec1[1]*vec2[0]) * np.arccos(vec1.dot(vec2)/np.linalg.norm(vec1)/np.linalg.norm(vec2))) tmp1 = np.divide( xp - cprime, [rx,ry]) tmp2 = np.divide(-xp - cprime, [rx,ry]) theta1 = arccos(np.array([1,0]), tmp1) delta_t= arccos(tmp1, tmp2) % (2*np.pi) if not sweep_flag and delta_t > 0: delta_t -= 2*np.pi elif sweep_flag and delta_t < 0: delta_t += 2*np.pi curve_piece = (curve_factory.circle_segment(delta_t)*[rx,ry]).rotate(theta1) + center # curve_piece = curve_factory.circle_segment(delta_t) elif piece[0] == 'z' or piece[0] == 'Z': # periodic curve # curve_piece = Curve(BSplineBasis(2), [startpoint, last_curve[0]]) # curve_piece.reparam([0, curve_piece.length()]) # last_curve.append(curve_piece).make_periodic(0) last_curve.make_periodic(0) result.append(last_curve) last_curve = None continue else: raise RuntimeError('Unknown path parameter:' + piece) if(curve_piece.length()>state.controlpoint_absolute_tolerance): curve_piece.reparam([0, curve_piece.length()]) if last_curve is None: last_curve = curve_piece else: last_curve.append(curve_piece) startpoint = last_curve[-1,:2] # disregard rational weight (if any) if last_curve is not None: result.append(last_curve) return result