def test_length(self): crv = Curve() self.assertAlmostEqual(crv.length(), 1.0) crv = Curve(BSplineBasis(2, [-1,-1,1,2,3,3]), [[0,0,0], [1,0,0], [1,0,3],[1,10,3]]) self.assertAlmostEqual(crv.length(), 14.0)
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
def test_length(self): crv = Curve() self.assertAlmostEqual(crv.length(), 1.0) crv = Curve(BSplineBasis(2, [-1, -1, 1, 2, 3, 3]), [[0, 0, 0], [1, 0, 0], [1, 0, 3], [1, 10, 3]]) self.assertAlmostEqual(crv.length(), 14.0)
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