class SvConstPipeSurface(SvSurface): __description__ = "Pipe" def __init__(self, curve, radius, algorithm = FRENET, resolution=50): self.curve = curve self.radius = radius self.circle = SvCircle(Matrix(), radius) self.algorithm = algorithm self.normal_delta = 0.001 self.u_bounds = self.circle.get_u_bounds() if algorithm in {FRENET, ZERO, TRACK_NORMAL}: self.calculator = DifferentialRotationCalculator(curve, algorithm, resolution) def get_u_min(self): return self.u_bounds[0] def get_u_max(self): return self.u_bounds[1] def get_v_min(self): return self.curve.get_u_bounds()[0] def get_v_max(self): return self.curve.get_u_bounds()[1] def evaluate(self, u, v): return self.evaluate_array(np.array([u]), np.array([v]))[0] def get_matrix(self, tangent): return MathutilsRotationCalculator.get_matrix(tangent, scale=1.0, axis=2, algorithm = self.algorithm, scale_all=False) def get_matrices(self, ts): if self.algorithm in {FRENET, ZERO, TRACK_NORMAL}: return self.calculator.get_matrices(ts) elif self.algorithm in {HOUSEHOLDER, TRACK, DIFF}: tangents = self.curve.tangent_array(ts) matrices = np.vectorize(lambda t : self.get_matrix(t), signature='(3)->(3,3)')(tangents) return matrices else: raise Exception("Unsupported algorithm") def evaluate_array(self, us, vs): profile_vectors = self.circle.evaluate_array(us) u_min, u_max = self.circle.get_u_bounds() v_min, v_max = self.curve.get_u_bounds() profile_vectors = np.transpose(profile_vectors[np.newaxis], axes=(1, 2, 0)) extrusion_start = self.curve.evaluate(v_min) extrusion_points = self.curve.evaluate_array(vs) extrusion_vectors = extrusion_points - extrusion_start matrices = self.get_matrices(vs) profile_vectors = (matrices @ profile_vectors)[:,:,0] result = extrusion_vectors + profile_vectors result = result + extrusion_start return result
def test_arc_1(self): circle = SvCircle(Matrix(), 1.0) t_min = 0.1 t_max = 1.4 pt1 = circle.evaluate(t_max) nurbs = circle._arc_to_nurbs(t_min, t_max) pt2 = nurbs.evaluate(t_max) self.assert_numpy_arrays_equal(pt1, pt2, precision=8)
def test_circle_1(self): circle = SvCircle(Matrix(), 1.0) circle.u_bounds = (0, pi / 6) nurbs = circle.to_nurbs() cpts = nurbs.get_control_points() expected_cpts = np.array([[1.0, 0.0, 0.0], [1.0, 0.26794919, 0.0], [0.8660254, 0.5, 0.0]]) self.assert_numpy_arrays_equal(cpts, expected_cpts, precision=6)
def test_circle_2(self): circle = SvCircle(Matrix(), 1.0) t_max = pi + 0.3 circle.u_bounds = (0, t_max) nurbs = circle.to_nurbs() ts = np.array([0, pi / 2, pi, t_max]) points = nurbs.evaluate_array(ts) expected_points = circle.evaluate_array(ts) self.assert_numpy_arrays_equal(points, expected_points, precision=6)
def __init__(self, curve, radius, algorithm = FRENET, resolution=50): self.curve = curve self.radius = radius self.circle = SvCircle(Matrix(), radius) self.algorithm = algorithm self.normal_delta = 0.001 self.u_bounds = self.circle.get_u_bounds() if algorithm in {FRENET, ZERO, TRACK_NORMAL}: self.calculator = DifferentialRotationCalculator(curve, algorithm, resolution)
def get_circular_arc(self): center = np.array(self.center) normal = np.array(self.normal) p1 = np.array(self.p1) circle = SvCircle(center = center, normal = -normal, vectorx = p1 - center) circle.u_bounds = (0.0, self.angle) #circle.u_bounds = (-self.angle, 0.0) return circle
def test_arc_2(self): pt1 = (-5, 0, 0) pt2 = (-4, 3, 0) pt3 = (-3, 4, 0) eq = circle_by_three_points(pt1, pt2, pt3) matrix = eq.get_matrix() arc = SvCircle(matrix, eq.radius) arc.u_bounds = (0.0, eq.arc_angle) nurbs = arc.to_nurbs() u_min, u_max = nurbs.get_u_bounds() self.assertEquals(u_min, 0, "U_min") self.assertEquals(u_max, eq.arc_angle, "U_max") startpoint = nurbs.evaluate(u_min) self.assert_sverchok_data_equal(startpoint.tolist(), pt1, precision=8) endpoint = nurbs.evaluate(u_max) self.assert_sverchok_data_equal(endpoint.tolist(), pt3, precision=8)
def test_arc_3(self): pt1 = np.array((-4, 2, 0)) pt2 = np.array((0, 2.5, 0)) pt3 = np.array((4, 2, 0)) eq = circle_by_three_points(pt1, pt2, pt3) #matrix = eq.get_matrix() arc = SvCircle(center=np.array(eq.center), vectorx=np.array(pt1 - eq.center), normal=eq.normal) arc.u_bounds = (0.0, eq.arc_angle) nurbs = arc.to_nurbs() u_min, u_max = nurbs.get_u_bounds() self.assertEquals(u_min, 0, "U_min") self.assertEquals(u_max, eq.arc_angle, "U_max") startpoint = nurbs.evaluate(u_min) self.assert_sverchok_data_equal(startpoint.tolist(), pt1, precision=6) endpoint = nurbs.evaluate(u_max) self.assert_sverchok_data_equal(endpoint.tolist(), pt3, precision=6)
def test_arc_derivative_1(self): pt1 = (-5, 0, 0) pt2 = (-4, 3, 0) pt3 = (-3, 4, 0) eq = circle_by_three_points(pt1, pt2, pt3) circle = SvCircle.from_equation(eq) dv = circle.tangent(0) expected = np.array([0, 5, 0]) self.assert_numpy_arrays_equal(dv, expected, precision=8)
def test_arc_values_1(self): pt1 = np.array((-4, 2, 0)) pt2 = np.array((0, 2.5, 0)) pt3 = np.array((4, 2, 0)) eq = circle_by_three_points(pt1, pt2, pt3) circle = SvCircle.from_equation(eq) res1 = circle.evaluate(0) self.assert_numpy_arrays_equal(res1, pt1, precision=6) t_max = eq.arc_angle res2 = circle.evaluate(t_max) self.assert_numpy_arrays_equal(res2, pt3, precision=6)
def nurbs_revolution_surface(curve, origin, axis, v_min=0, v_max=2 * pi, global_origin=True): my_control_points = curve.get_control_points() my_weights = curve.get_weights() control_points = [] weights = [] any_circle = SvCircle(Matrix(), 1) any_circle.u_bounds = (v_min, v_max) any_circle = any_circle.to_nurbs() # all circles with given (v_min, v_max) # actually always have the same knotvector # and the same number of control points n = len(any_circle.get_control_points()) circle_knotvector = any_circle.get_knotvector() circle_weights = any_circle.get_weights() # TODO: vectorize with numpy? Or better let it so for better readability? for my_control_point, my_weight in zip(my_control_points, my_weights): eq = CircleEquation3D.from_axis_point(origin, axis, my_control_point) if abs(eq.radius) < 1e-8: parallel_points = np.empty((n, 3)) parallel_points[:] = np.array(eq.center) #[np.newaxis].T else: circle = SvCircle.from_equation(eq) circle.u_bounds = (v_min, v_max) nurbs_circle = circle.to_nurbs() parallel_points = nurbs_circle.get_control_points() parallel_weights = circle_weights * my_weight control_points.append(parallel_points) weights.append(parallel_weights) control_points = np.array(control_points) if global_origin: control_points = control_points - origin weights = np.array(weights) degree_u = curve.get_degree() degree_v = 2 # circle return SvNurbsSurface.build(curve.get_nurbs_implementation(), degree_u, degree_v, curve.get_knotvector(), circle_knotvector, control_points, weights)
def test_circle_equal_1(self): circle1 = SvCircle(Matrix(), 1.0) x = np.array([1, 0, 0]) origin = np.array([0, 0, 0]) z = np.array([0, 0, 1]) circle2 = SvCircle(center=origin, normal=z, vectorx=x) ts = np.linspace(0, pi / 2, num=50) pts1 = circle1.evaluate_array(ts) pts2 = circle2.evaluate_array(ts) self.assert_numpy_arrays_equal(pts1, pts2, precision=8)
def calc(point_a, point_b, tangent_a, tangent_b, p, planar_tolerance=1e-6): xx = point_b - point_a xx /= np.linalg.norm(xx) tangent_normal = np.cross(tangent_a, tangent_b) volume = np.dot(xx, tangent_normal) if abs(volume) > planar_tolerance: raise Exception( f"Provided tangents are not coplanar, volume={volume}") zz_a = np.cross(tangent_a, xx) zz_b = np.cross(tangent_b, xx) zz = (zz_a + zz_b) zz /= np.linalg.norm(zz) yy = np.cross(zz, xx) c = np.linalg.norm(point_b - point_a) * 0.5 tangent_a /= np.linalg.norm(tangent_a) tangent_b /= np.linalg.norm(tangent_b) to_center_a = np.cross(zz, tangent_a) to_center_b = -np.cross(zz, tangent_b) matrix_inv = np.stack((xx, yy, zz)) matrix = np.linalg.inv(matrix_inv) # TODO: sin(arccos(...)) = ... alpha = acos(np.dot(tangent_a, xx)) beta = acos(np.dot(tangent_b, xx)) if np.dot(tangent_a, yy) > 0: alpha = -alpha if np.dot(tangent_b, yy) > 0: beta = -beta #print("A", alpha, "B", beta) omega = (alpha + beta) * 0.5 r1 = c / (sin(alpha) + sin(omega) / p) r2 = c / (sin(beta) + p * sin(omega)) #print("R1", r1, "R2", r2) theta1 = 2 * arg(cexp(-1j * alpha) + cexp(-1j * omega) / p) theta2 = 2 * arg(cexp(1j * beta) + p * cexp(1j * omega)) #print("T1", theta1, "T2", theta2) vectorx_a = r1 * to_center_a center1 = point_a + vectorx_a center2 = point_b + r2 * to_center_b arc1 = SvCircle( #radius = r1, center=center1, normal=-zz, vectorx=point_a - center1) if theta1 > 0: arc1.u_bounds = (0.0, theta1) else: theta1 = -theta1 arc1.u_bounds = (0.0, theta1) arc1.set_normal(-arc1.normal) junction = arc1.evaluate(theta1) #print("J", junction) arc2 = SvCircle( #radius = r2, center=center2, normal=-zz, vectorx=junction - center2) if theta2 > 0: arc2.u_bounds = (0.0, theta2) else: theta2 = -theta2 arc2.u_bounds = (0.0, theta2) arc2.set_normal(-arc2.normal) curve = SvBiArc(arc1, arc2) curve.p = p curve.junction = junction return curve
def extend_curve(curve, t_before, t_after, mode='LINE', len_mode='T', len_resolution=50): def make_line(point, tangent, t_ext, sign): if sign < 0: before_start = point - t_ext * tangent # / np.linalg.norm(tangent_start) return SvLine.from_two_points(before_start, point) else: after_end = point + t_ext * tangent # / np.linalg.norm(tangent_end) return SvLine.from_two_points(point, after_end) u_min, u_max = curve.get_u_bounds() start, end = curve.evaluate(u_min), curve.evaluate(u_max) start_extent, end_extent = None, None is_nurbs = isinstance(curve, SvNurbsCurve) if mode == 'LINE': tangent_start = curve.tangent(u_min) tangent_end = curve.tangent(u_max) if t_before > 0: start_extent = make_line(start, tangent_start, t_before, -1) start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution) if t_after > 0: end_extent = make_line(end, tangent_end, t_after, +1) end_extent = set_length(curve, end_extent, t_after, +1, len_mode=len_mode, len_resolution=len_resolution) elif mode == 'ARC': tangent_start = curve.tangent(u_min) tangent_end = curve.tangent(u_max) second_start = curve.second_derivative(u_min) second_end = curve.second_derivative(u_max) if t_before > 0: if np.linalg.norm(second_start) > 1e-6: eq1 = circle_by_two_derivatives(start, -tangent_start, second_start) start_extent = SvCircle.from_equation(eq1) start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution) if is_nurbs: start_extent = start_extent.to_nurbs() start_extent = reverse_curve(start_extent) else: start_extent = make_line(start, tangent_start, t_before, -1) start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution) if t_after > 0: if np.linalg.norm(second_end) > 1e-6: eq2 = circle_by_two_derivatives(end, tangent_end, second_end) end_extent = SvCircle.from_equation(eq2) else: end_extent = make_line(end, tangent_end, t_after, +1) end_extent = set_length(curve, end_extent, t_after, +1, len_mode=len_mode, len_resolution=len_resolution) elif mode == 'QUAD': tangent_start = curve.tangent(u_min) tangent_end = curve.tangent(u_max) second_start = curve.second_derivative(u_min) second_end = curve.second_derivative(u_max) if t_before > 0: start_extent = SvTaylorCurve(start, [-tangent_start, second_start]) start_extent = set_length(curve, start_extent, t_before, len_mode=len_mode, len_resolution=len_resolution) if is_nurbs: start_extent = start_extent.to_nurbs() start_extent = reverse_curve(start_extent) if t_after > 0: end_extent = SvTaylorCurve(end, [tangent_end, second_end]) end_extent = set_length(curve, end_extent, t_after, len_mode=len_mode, len_resolution=len_resolution) elif mode == 'CUBIC': tangent_start = curve.tangent(u_min) tangent_end = curve.tangent(u_max) second_start = curve.second_derivative(u_min) second_end = curve.second_derivative(u_max) third_start, third_end = curve.third_derivative_array( np.array([u_min, u_max])) if t_before > 0: start_extent = SvTaylorCurve( start, [-tangent_start, second_start, -third_start]) start_extent = set_length(curve, start_extent, t_before, len_mode=len_mode, len_resolution=len_resolution) if is_nurbs: start_extent = start_extent.to_nurbs() start_extent = reverse_curve(start_extent) if t_after > 0: end_extent = SvTaylorCurve(end, [tangent_end, second_end, third_end]) end_extent = set_length(curve, end_extent, t_after, len_mode=len_mode, len_resolution=len_resolution) else: raise Exception("Unsupported mode") if is_nurbs: if start_extent is not None and not isinstance(start_extent, SvNurbsCurve): start_extent = start_extent.to_nurbs( implementation=curve.get_nurbs_implementation()) if end_extent is not None and not isinstance(end_extent, SvNurbsCurve): end_extent = end_extent.to_nurbs( implementation=curve.get_nurbs_implementation()) return start_extent, end_extent