def process(self): if not any(socket.is_linked for socket in self.outputs): return curve1_s = self.inputs['Curve1'].sv_get() curve2_s = self.inputs['Curve2'].sv_get() curve1_s = ensure_nesting_level(curve1_s, 2, data_types=(SvCurve, )) curve2_s = ensure_nesting_level(curve2_s, 2, data_types=(SvCurve, )) points_out = [] t1_out = [] t2_out = [] for curve1s, curve2s in zip_long_repeat(curve1_s, curve2_s): new_points = [] new_t1 = [] new_t2 = [] for curve1, curve2 in self.match(curve1s, curve2s): curve1 = SvNurbsCurve.to_nurbs(curve1) if curve1 is None: raise Exception("Curve1 is not a NURBS") curve2 = SvNurbsCurve.to_nurbs(curve2) if curve2 is None: raise Exception("Curve2 is not a NURBS") if self.implementation == 'SCIPY': t1s, t2s, ps = self.process_native(curve1, curve2) else: t1s, t2s, ps = self.process_freecad(curve1, curve2) if self.check_intersection: if not ps: raise Exception("Some curves do not intersect!") if self.single: if len(ps) >= 1: ps = ps[0] t1s = t1s[0] t2s = t2s[0] new_points.append(ps) new_t1.append(t1s) new_t2.append(t2s) if self.split: n = len(curve1s) new_points = split_by_count(new_points, n) new_t1 = split_by_count(new_t1, n) new_t1 = transpose_list(new_t1) new_t2 = split_by_count(new_t2, n) points_out.append(new_points) t1_out.append(new_t1) t2_out.append(new_t2) self.outputs['Intersections'].sv_set(points_out) self.outputs['T1'].sv_set(t1_out) self.outputs['T2'].sv_set(t2_out)
def process(self): if not any(socket.is_linked for socket in self.outputs): return curve_s = self.inputs['Curve'].sv_get() field_s = self.inputs['Field'].sv_get() coeff_s = self.inputs['Coefficient'].sv_get() curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve, )) field_s = ensure_nesting_level(field_s, 2, data_types=(SvVectorField, )) coeff_s = ensure_nesting_level(coeff_s, 2) curve_out = [] for curve_i, field_i, coeff_i in zip_long_repeat( curve_s, field_s, coeff_s): new_curves = [] for curve, field, coeff in zip_long_repeat(curve_i, field_i, coeff_i): if self.use_control_points: nurbs = SvNurbsCurve.to_nurbs(curve) if nurbs is not None: control_points = nurbs.get_control_points() else: raise Exception("Curve is not a NURBS!") cpt_xs = control_points[:, 0] cpt_ys = control_points[:, 1] cpt_zs = control_points[:, 2] cpt_dxs, cpt_dys, cpt_dzs = field.evaluate_grid( cpt_xs, cpt_ys, cpt_zs) xs = cpt_xs + coeff * cpt_dxs ys = cpt_ys + coeff * cpt_dys zs = cpt_zs + coeff * cpt_dzs control_points = np.stack((xs, ys, zs)).T knotvector = nurbs.get_knotvector() #old_t_min, old_t_max = curve.get_u_bounds() #knotvector = sv_knotvector.rescale(knotvector, old_t_min, old_t_max) new_curve = SvNurbsCurve.build( nurbs.get_nurbs_implementation(), nurbs.get_degree(), knotvector, control_points, nurbs.get_weights()) new_curve.u_bounds = nurbs.u_bounds else: new_curve = SvDeformedByFieldCurve(curve, field, coeff) new_curves.append(new_curve) if self.join: curve_out.extend(new_curves) else: curve_out.append(new_curves) self.outputs['Curve'].sv_set(curve_out)
def process(self): if not any(socket.is_linked for socket in self.outputs): return u_curves_s = self.inputs['CurvesU'].sv_get() v_curves_s = self.inputs['CurvesV'].sv_get() intersections_s = self.inputs['Intersections'].sv_get() if self.explicit_t_values: t1_s = self.inputs['T1'].sv_get() t2_s = self.inputs['T2'].sv_get() else: t1_s = [[[]]] t2_s = [[[]]] u_curves_s = ensure_nesting_level(u_curves_s, 2, data_types=(SvCurve,)) v_curves_s = ensure_nesting_level(v_curves_s, 2, data_types=(SvCurve,)) t1_s = ensure_nesting_level(t1_s, 3) t2_s = ensure_nesting_level(t2_s, 3) intersections_s = ensure_nesting_level(intersections_s, 4) surface_out = [] for u_curves, v_curves, t1s, t2s, intersections in zip_long_repeat(u_curves_s, v_curves_s, t1_s, t2_s, intersections_s): u_curves = [SvNurbsCurve.to_nurbs(c) for c in u_curves] if any(c is None for c in u_curves): raise Exception("Some of U curves are not NURBS!") v_curves = [SvNurbsCurve.to_nurbs(c) for c in v_curves] if any(c is None for c in v_curves): raise Exception("Some of V curves are not NURBS!") if self.explicit_t_values: if len(t1s) < len(u_curves): t1s = repeat_last_for_length(t1s, len(u_curves)) elif len(t1s) > len(u_curves): raise Exception(f"Number of items in T1 input {len(t1s)} > number of U-curves {len(u_curves)}") if len(t1s[0]) != len(v_curves): raise Exception(f"Length of items in T1 input {len(t1s[0])} != number of V-curves {len(v_curves)}") if len(t2s) < len(v_curves): t2s = repeat_last_for_length(t2s, len(v_curves)) elif len(t2s) > len(v_curves): raise Exception(f"Number of items in T2 input {len(t2s)} > number of V-curves {len(v_curves)}") if len(t2s[0]) != len(u_curves): raise Exception(f"Length of items in T2 input {len(t2s[0])} != number of U-curves {len(u_curves)}") if self.explicit_t_values: kwargs = {'u_knots': np.array(t1s), 'v_knots': np.array(t2s)} else: kwargs = dict() _, _, _, surface = gordon_surface(u_curves, v_curves, intersections, metric=self.metric, knotvector_accuracy = self.knotvector_accuracy, **kwargs) surface_out.append(surface) self.outputs['Surface'].sv_set(surface_out)
def test_curve_3436(self): points = [(0.0, 0.0, 0.0), (0.5, 0.0, 0.5), (1.0, 0.0, 0.0)] ts = np.array([0, 0.5, 1, 1.61803397]) #ts = self.ts degree = 2 knotvector = [0, 0, 0, 1, 1, 1] weights = [1, 1, 1] geomdl_curve = SvNurbsCurve.build('GEOMDL', degree, knotvector, points, weights) native_curve = SvNurbsCurve.build('NATIVE', degree, knotvector, points, weights) p1s = geomdl_curve.evaluate_array(ts) p2s = native_curve.evaluate_array(ts) #print("NATIVE:", p2s) self.assert_numpy_arrays_equal(p1s, p2s, precision=8)
def process(self): if not any(socket.is_linked for socket in self.outputs): return curve_s = self.inputs['Curve'].sv_get() input_level = get_data_nesting_level(curve_s, data_types=(SvCurve,)) flat_output = input_level < 2 curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve,)) tolerance = self.tolerance curves_out = [] for curves in curve_s: new_curves = [] for curve in curves: curve = SvNurbsCurve.to_nurbs(curve) if curve is None: raise Exception("One of curves is not NURBS") curve = remove_excessive_knots(curve, tolerance=tolerance) new_curves.append(curve) if flat_output: curves_out.extend(new_curves) else: curves_out.append(new_curves) self.outputs['Curve'].sv_set(curves_out)
def process(self): if not any(socket.is_linked for socket in self.outputs): return curve_s = self.inputs['Curve'].sv_get() knot_s = self.inputs['Knot'].sv_get() count_s = self.inputs['Count'].sv_get() input_level = get_data_nesting_level(curve_s, data_types=(SvCurve, )) flat_output = input_level < 2 curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve, )) knot_s = ensure_nesting_level(knot_s, 3) count_s = ensure_nesting_level(count_s, 3) curves_out = [] for curves, knots_i, counts_i in zip_long_repeat( curve_s, knot_s, count_s): new_curves = [] for curve, knots, counts in zip_long_repeat( curves, knots_i, counts_i): curve = SvNurbsCurve.to_nurbs(curve) if curve is None: raise Exception("One of curves is not NURBS") for knot, count in zip_long_repeat(knots, counts): curve = curve.insert_knot(knot, count, if_possible=self.if_possible) new_curves.append(curve) if flat_output: curves_out.extend(new_curves) else: curves_out.append(new_curves) self.outputs['Curve'].sv_set(curves_out)
def to_nurbs(self, implementation=SvNurbsCurve.NATIVE): knotvector = sv_knotvector.generate(3, 4) control_points = np.array([self.p0, self.p1, self.p2, self.p3]) return SvNurbsCurve.build(implementation, degree=3, knotvector=knotvector, control_points=control_points)
def deconstruct(self, curve): nurbs = SvNurbsCurve.to_nurbs(curve) if nurbs is None: nurbs = curve try: degree = nurbs.get_degree() except: degree = None if hasattr(nurbs, 'get_knotvector'): knots = nurbs.get_knotvector().tolist() else: knots = [] try: points = nurbs.get_control_points().tolist() except Exception as e: points = [] if hasattr(nurbs, 'get_weights'): weights = nurbs.get_weights().tolist() else: weights = [] return degree, knots, points, weights
def process(self): if not any(socket.is_linked for socket in self.outputs): return vertices_s = self.inputs['ControlPoints'].sv_get() has_weights = self.inputs['Weights'].is_linked weights_s = self.inputs['Weights'].sv_get(default = [[1.0]]) knots_s = self.inputs['Knots'].sv_get(default = [[]]) degree_s = self.inputs['Degree'].sv_get() curves_out = [] knots_out = [] for vertices, weights, knots, degree in zip_long_repeat(vertices_s, weights_s, knots_s, degree_s): if isinstance(degree, (tuple, list)): degree = degree[0] n_source = len(vertices) fullList(weights, n_source) if self.knot_mode == 'AUTO' and self.is_cyclic: vertices = vertices + vertices[:degree] weights = weights + weights[:degree] n_total = len(vertices) # Set degree curve_degree = degree if has_weights and self.surface_mode == 'NURBS': curve_weights = weights else: curve_weights = None # Set knot vector if self.knot_mode == 'AUTO': if self.is_cyclic: self.debug("N: %s, degree: %s", n_total, degree) knots = list(range(n_total + degree + 1)) else: knots = sv_knotvector.generate(curve_degree, n_total) self.debug('Auto knots: %s', knots) curve_knotvector = knots else: self.debug('Manual knots: %s', knots) curve_knotvector = knots new_curve = SvNurbsCurve.build(self.implementation, degree, curve_knotvector, vertices, curve_weights, normalize_knots = self.normalize_knots) curve_knotvector = new_curve.get_knotvector().tolist() if self.knot_mode == 'AUTO' and self.is_cyclic: u_min = curve_knotvector[degree] u_max = curve_knotvector[-degree-1] new_curve.u_bounds = u_min, u_max else: u_min = min(curve_knotvector) u_max = max(curve_knotvector) new_curve.u_bounds = (u_min, u_max) curves_out.append(new_curve) knots_out.append(curve_knotvector) self.outputs['Curve'].sv_set(curves_out) self.outputs['Knots'].sv_set(knots_out)
def to_nurbs(self, curves): result = [] for i,c in enumerate(curves): nurbs = SvNurbsCurve.to_nurbs(c) if nurbs is None: raise Exception(f"Curve #{i} - {c} - can not be converted to NURBS!") result.append(nurbs) return result
def to_nurbs(self, implementation=SvNurbsCurve.NATIVE): knotvector = sv_knotvector.generate(1, 2) u_min, u_max = self.get_u_bounds() p1 = self.evaluate(u_min) p2 = self.evaluate(u_max) control_points = np.array([p1, p2]) return SvNurbsCurve.build(implementation, degree=1, knotvector=knotvector, control_points=control_points)
def test_outside_sphere_3(self): cpts = np.array([[-2, 5, 0], [2, 5, 0]]) degree = 1 knotvector = sv_knotvector.generate(degree, len(cpts)) curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE, degree, knotvector, cpts) result = curve.is_strongly_outside_sphere(np.array([0, 0, 0]), 1) expected_result = True self.assertEquals(result, expected_result)
def to_nurbs(self, implementation=SvNurbsCurve.NATIVE): control_points = self.spline.get_control_points() degree = self.spline.get_degree() n_points = degree + 1 knotvector = sv_knotvector.generate(degree, n_points) t_segments = self.spline.get_t_segments() segments = [SvNurbsCurve.build(implementation, degree, knotvector, points) for points in control_points] segments = [reparametrize_curve(segment, t_min, t_max) for segment, (t_min, t_max) in zip(segments, t_segments)] # pairs = [f"#{i}: {t_min}-{t_max}: {segment.evaluate(t_min)} -- {segment.evaluate(t_max)}" for i, (segment, (t_min, t_max)) in enumerate(zip(segments, t_segments))] # pairs = ", ".join(pairs) # print(f"S: {pairs}") return concatenate_nurbs_curves(segments)
def scipy_nurbs_approximate(points, weights=None, metric='DISTANCE', degree=3, filter_doubles=None, smoothing=None, is_cyclic=False): points = np.asarray(points) if weights is not None and len(points) != len(weights): raise Exception("Number of weights must be equal to number of points") if filter_doubles is not None: good = np.where( np.linalg.norm(np.diff(points, axis=0), axis=1) > filter_doubles) points = np.r_[points[good], points[-1][np.newaxis]] if weights is not None: weights = np.r_[weights[good], weights[-1]] if is_cyclic: if (points[0] != points[-1]).any(): points = np.vstack((points, points[0])) if weights is not None: weights = np.insert(weights, -1, weights[0]) points_orig = points points = points.T kwargs = dict() if weights is not None: kwargs['w'] = np.asarray(weights) if metric is not None: tknots = Spline.create_knots(points.T, metric) if len(tknots) != len(points.T): raise Exception( f"Number of T knots ({len(tknots)}) is not equal to number of points ({len(points.T)})" ) kwargs['u'] = tknots if degree is not None: kwargs['k'] = degree if smoothing is not None: kwargs['s'] = smoothing if is_cyclic: kwargs['per'] = 1 tck, u = interpolate.splprep(points, **kwargs) knotvector = tck[0] control_points = np.stack(tck[1]).T degree = tck[2] curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE, degree, knotvector, control_points) if is_cyclic: curve = curve.cut_segment(0.0, 1.00) #curve.u_bounds = (0.0, 1.0) return curve
def process(self): if not any(socket.is_linked for socket in self.outputs): return curves_s = self.inputs['Curve'].sv_get() point_s = self.inputs['Point'].sv_get() normal_s = self.inputs['Normal'].sv_get() curves_s = ensure_nesting_level(curves_s, 2, data_types=(SvCurve, )) points_out = [] t_out = [] tolerance = 10**(-self.accuracy) for curves, points, normals in zip_long_repeat( curves_s, point_s, normal_s): new_points = [] new_ts = [] for curve, point, normal in zip_long_repeat( curves, points, normals): method = EQUATION if self.use_nurbs: c = SvNurbsCurve.to_nurbs(curve) if c is not None: curve = c method = NURBS plane = PlaneEquation.from_normal_and_point(normal, point) ps = intersect_curve_plane(curve, plane, method=method, init_samples=self.samples, tolerance=tolerance) ts = [p[0] for p in ps] points = [p[1].tolist() for p in ps] if self.join: new_points.extend(points) new_ts.extend(ts) else: new_points.append(points) new_ts.append(ts) points_out.append(new_points) t_out.append(new_ts) self.outputs['Point'].sv_set(points_out) self.outputs['T'].sv_set(t_out)
def _cast_nurbs(self, curve, center, direction, radius, coeff): curve = SvNurbsCurve.to_nurbs(curve) if curve is None: raise Exception("Provided curve is not a NURBS") if self.form == 'PLANE': target = PlaneEquation.from_normal_and_point(direction, center) elif self.form == 'SPHERE': target = SphereEquation(center, radius) elif self.form == 'CYLINDER': target = CylinderEquation.from_point_direction_radius(center, direction, radius) else: raise Exception("Unsupported target form") return cast_nurbs_curve(curve, target, coeff=coeff)
def cut(self, face_surface, sv_curves, point, vector): # face_surface : SvFreeCadNurbsSurface nurbs = [SvNurbsCurve.to_nurbs(curve) for curve in sv_curves] if any(c is None for c in nurbs): raise Exception("One of curves is not a NURBS!") fc_nurbs_curves = [SvFreeCadNurbsCurve.from_any_nurbs(c) for c in nurbs] fc_nurbs = [c.curve for c in fc_nurbs_curves] if self.projection_type in {'PARALLEL', 'PERSPECTIVE', 'ORTHO'}: try: fc_edges = [Part.Edge(c) for c in fc_nurbs] except Exception as e: raise Exception(f"Can't build edges from {fc_nurbs}: {e}") fc_face = Part.Face(face_surface.surface) if self.projection_type == 'PARALLEL': vector = Base.Vector(*vector) projections = [fc_face.makeParallelProjection(edge, vector) for edge in fc_edges] projections = [p.Edges for p in projections] elif self.projection_type == 'PERSPECTIVE': point = Base.Vector(*point) projections = [fc_face.makePerspectiveProjection(edge, point).Edges for edge in fc_edges] elif self.projection_type == 'ORTHO': projections = [fc_face.project(fc_edges).Edges] else: # UV uv_curves = [c.to_2d() for c in fc_nurbs_curves] fc_nurbs_2d = [c.curve for c in uv_curves] projections = [[c.toShape(face_surface.surface) for c in fc_nurbs_2d]] projections = sum(projections, []) if not projections: words = f"along {vector}" if self.projection_type == 'PARALLEL' else f"from {point}" raise Exception(f"Projection {words} of {sv_curves} onto {face_surface} is empty for some reason") try: wire = Part.Wire(projections) except Exception as e: ps = [SvFreeCadNurbsCurve(p.Curve) for p in projections] raise Exception(f"Can't make a valid Wire out of curves {sv_curves} projected onto {face_surface}:\n{e}\nProjections are: {ps}") cut_fc_face = Part.Face(face_surface.surface, wire) cut_face_surface = SvFreeCadNurbsSurface(face_surface.surface, face=cut_fc_face) if self.projection_type != 'UV': uv_curves = [] for edge in cut_fc_face.OuterWire.Edges: trim,m,M = cut_fc_face.curveOnSurface(edge) trim = SvFreeCadCurve(trim, (m,M), ndim=2) uv_curves.append(trim) projections = [SvSolidEdgeCurve(p) for p in projections] return uv_curves, projections, cut_face_surface
def test_bezier_to_taylor_2(self): cpts = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [2, 1, 0]], dtype=np.float64) degree = 3 knotvector = sv_knotvector.generate(degree, len(cpts)) knotvector += 1.0 curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE, degree, knotvector, cpts) taylor = curve.bezier_to_taylor() nurbs = taylor.to_nurbs() self.assert_numpy_arrays_equal(nurbs.get_control_points(), cpts, precision=8)
def process(self): if not any(socket.is_linked for socket in self.outputs): return curve_s = self.inputs['Curve'].sv_get() init_cuts_s = self.inputs['InitCuts'].sv_get() tolerance_s = self.inputs['Tolerance'].sv_get() curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve, )) init_cuts_s = ensure_nesting_level(init_cuts_s, 2) tolerance_s = ensure_nesting_level(tolerance_s, 2) need_verts = self.outputs['Vertices'].is_linked verts_out = [] edges_out = [] ts_out = [] for params in zip_long_repeat(curve_s, init_cuts_s, tolerance_s): new_verts = [] new_edges = [] new_ts = [] for curve, init_cuts, tolerance in zip_long_repeat(*params): curve = SvNurbsCurve.to_nurbs(curve) if curve is None: raise Exception("Curve is not NURBS") ts = curve.calc_linear_segment_knots(splits=init_cuts, tolerance=tolerance) new_ts.append(ts.tolist()) if need_verts: verts = curve.evaluate_array(ts) new_verts.append(verts.tolist()) n = len(ts) edges = [(i, i + 1) for i in range(n - 1)] new_edges.append(edges) if self.join: verts_out.extend(new_verts) edges_out.extend(new_edges) ts_out.extend(new_ts) else: verts_out.append(new_verts) edges_out.append(new_edges) ts_out.append(new_ts) self.outputs['Vertices'].sv_set(verts_out) self.outputs['Edges'].sv_set(edges_out) self.outputs['T'].sv_set(ts_out)
def curve_to_freecad_nurbs(sv_curve): """ Convert SvCurve to FreeCAD's NURBS curve. Raise an exception if it is not possible. input: SvCurve output: SvFreeCadNurbsCurve """ nurbs = SvNurbsCurve.to_nurbs(sv_curve) if nurbs is None: raise TypeError(f"{sv_curve} is not a NURBS curve") fc_curve = SvNurbsMaths.build_curve(SvNurbsMaths.FREECAD, nurbs.get_degree(), nurbs.get_knotvector(), nurbs.get_control_points(), nurbs.get_weights()) return fc_curve
def get_curve(self, spline, matrix): curve_degree = spline.order_u - 1 if self.apply_matrix: vertices = [ tuple(matrix @ Vector(p.co[:3])) for p in spline.points ] else: vertices = [tuple(p.co)[:3] for p in spline.points] weights = [tuple(p.co)[3] for p in spline.points] if spline.use_cyclic_u: vertices = vertices + vertices[:curve_degree + 1] weights = weights + weights[:curve_degree + 1] n_total = len(vertices) curve_ctrlpts = vertices curve_weights = weights if spline.use_cyclic_u: knots = list(range(n_total + curve_degree + 1)) else: knots = sv_knotvector.generate(curve_degree, n_total, clamped=spline.use_endpoint_u) self.debug('Auto knots: %s', knots) curve_knotvector = knots new_curve = SvNurbsCurve.build(self.implementation, curve_degree, curve_knotvector, curve_ctrlpts, curve_weights) if spline.use_cyclic_u: u_min = curve_knotvector[curve_degree] u_max = curve_knotvector[-curve_degree - 2] new_curve = new_curve.cut_segment(u_min, u_max) #new_curve.u_bounds = u_min, u_max else: if spline.use_endpoint_u: u_min = min(curve_knotvector) u_max = max(curve_knotvector) else: u_min = curve_knotvector[curve_degree] u_max = curve_knotvector[-curve_degree - 1] new_curve.u_bounds = (u_min, u_max) return new_curve
def test_bezier_to_taylor_1(self): cpts = np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [2, 1, 0]], dtype=np.float64) degree = 3 knotvector = sv_knotvector.generate(degree, len(cpts)) curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE, degree, knotvector, cpts) taylor = curve.bezier_to_taylor() coeffs = taylor.get_coefficients() self.assert_numpy_arrays_equal(coeffs[0], np.array([0, 0, 0, 1]), precision=8) self.assert_numpy_arrays_equal(coeffs[1], np.array([3, 0, 0, 0]), precision=8) self.assert_numpy_arrays_equal(coeffs[2], np.array([-3, 3, 0, 0]), precision=8) self.assert_numpy_arrays_equal(coeffs[3], np.array([2, -2, 0, 0]), precision=8)
def process(self): if not any(socket.is_linked for socket in self.outputs): return curves_s = self.inputs['Curves'].sv_get() degrees_s = self.inputs['DegreeV'].sv_get() curves_s = ensure_nesting_level(curves_s, 3, data_types=(SvCurve, )) degrees_s = ensure_nesting_level(degrees_s, 2) surface_out = [] curves_out = [] v_curves_out = [] for curves_i, degrees in zip_long_repeat(curves_s, degrees_s): new_surfaces = [] new_curves = [] new_v_curves = [] for curves, degree_v in zip_long_repeat(curves_i, degrees): curves = [SvNurbsCurve.to_nurbs(c) for c in curves] if any(c is None for c in curves): raise Exception("Some of curves are not NURBS!") unified_curves, v_curves, new_surface = simple_loft( curves, degree_v=degree_v, knots_u=self.u_knots_mode, metric=self.metric, implementation=self.nurbs_implementation) new_surfaces.append(new_surface) new_curves.extend(unified_curves) new_v_curves.extend(v_curves) surface_out.append(new_surfaces) curves_out.append(new_curves) v_curves_out.append(new_v_curves) self.outputs['Surface'].sv_set(surface_out) self.outputs['UnifiedCurves'].sv_set(curves_out) self.outputs['VCurves'].sv_set(v_curves_out)
def to_nurbs(self, implementation=SvNurbsCurve.NATIVE): t_min, t_max = self.get_u_bounds() if t_min < 0 or t_max > 2 * pi: raise UnsupportedCurveTypeException( f"Can't transform a circle arc out of 0-2pi bound ({t_min} - {t_max}) to NURBS" ) control_points = np.array([[1, 0, 0], [1, 1, 0], [0, 1, 0], [-1, 1, 0], [-1, 0, 0], [-1, -1, 0], [0, -1, 0], [1, -1, 0], [1, 0, 0]]) control_points = self.radius * control_points control_points = np.apply_along_axis(lambda v: self.matrix @ v, 1, control_points) sqrt22 = sqrt(2.0) / 2.0 weights = np.array([1, sqrt22, 1, sqrt22, 1, sqrt22, 1, sqrt22, 1]) pi2 = pi / 2.0 pi32 = 3 * pi / 2.0 knotvector = np.array( [0, 0, 0, pi2, pi2, pi, pi, pi32, pi32, 2 * pi, 2 * pi, 2 * pi]) degree = 2 curve = SvNurbsCurve.build(implementation, degree, knotvector, control_points, weights) if t_min != 0 or t_max != 2 * pi: curve = curve_segment(curve, t_min, t_max) return curve
def process(self): if not any(socket.is_linked for socket in self.outputs): return path_s = self.inputs['Path'].sv_get() profile_s = self.inputs['Profile'].sv_get() if self.explicit_v: v_s = self.inputs['V'].sv_get() v_s = ensure_nesting_level(v_s, 3) else: v_s = [[[]]] profiles_count_s = self.inputs['VSections'].sv_get() resolution_s = self.inputs['Resolution'].sv_get() normal_s = self.inputs['Normal'].sv_get() path_s = ensure_nesting_level(path_s, 2, data_types=(SvCurve,)) profile_s = ensure_nesting_level(profile_s, 3, data_types=(SvCurve,)) resolution_s = ensure_nesting_level(resolution_s, 2) normal_s = ensure_nesting_level(normal_s, 3) profiles_count_s = ensure_nesting_level(profiles_count_s, 2) surfaces_out = [] curves_out = [] v_curves_out = [] for params in zip_long_repeat(path_s, profile_s, v_s, profiles_count_s, resolution_s, normal_s): new_surfaces = [] new_curves = [] new_v_curves = [] new_profiles = [] for path, profiles, vs, profiles_count, resolution, normal in zip_long_repeat(*params): path = SvNurbsCurve.to_nurbs(path) if path is None: raise Exception("Path is not a NURBS curve!") profiles = [SvNurbsCurve.to_nurbs(profile) for profile in profiles] if any(p is None for p in profiles): raise Exception("Some of profiles are not NURBS curves!") if self.explicit_v: ts = np.array(vs) else: ts = None _, unified_curves, v_curves, surface = nurbs_sweep(path, profiles, ts = ts, min_profiles = profiles_count, algorithm = self.algorithm, knots_u = self.u_knots_mode, metric = self.metric, implementation = self.nurbs_implementation, resolution = resolution, normal = np.array(normal)) new_surfaces.append(surface) new_curves.extend(unified_curves) new_v_curves.extend(v_curves) surfaces_out.append(new_surfaces) curves_out.append(new_curves) v_curves_out.append(new_v_curves) self.outputs['Surface'].sv_set(surfaces_out) if 'AllProfiles' in self.outputs: self.outputs['AllProfiles'].sv_set(curves_out) if 'VCurves' in self.outputs: self.outputs['VCurves'].sv_set(v_curves_out)
def to_nurbs(self, implementation=SvNurbsCurve.NATIVE): knotvector = sv_knotvector.generate(self.degree, len(self.points)) return SvNurbsCurve.build(implementation, degree=self.degree, knotvector=knotvector, control_points=self.points)
def check_nurbs(*curves): return [SvNurbsCurve.to_nurbs(c) for c in curves]
def coons_surface(curve1, curve2, curve3, curve4): curves = [curve1, curve2, curve3, curve4] nurbs_curves = [SvNurbsCurve.to_nurbs(c) for c in curves] if any(c is None for c in nurbs_curves): return SvCoonsSurface(*curves) try: nurbs_curves = [c.reparametrize(0, 1) for c in nurbs_curves] degrees = [c.get_degree() for c in nurbs_curves] implementation = nurbs_curves[0].get_nurbs_implementation() if degrees[0] > degrees[2]: nurbs_curves[2] = nurbs_curves[2].elevate_degree(delta=degrees[0] - degrees[2]) if degrees[2] > degrees[0]: nurbs_curves[0] = nurbs_curves[0].elevate_degree(delta=degrees[2] - degrees[0]) if degrees[1] > degrees[3]: nurbs_curves[3] = nurbs_curves[3].elevate_degree(delta=degrees[1] - degrees[3]) if degrees[3] > degrees[1]: nurbs_curves[1] = nurbs_curves[1].elevate_degree(delta=degrees[3] - degrees[1]) degree_u = nurbs_curves[0].get_degree() degree_v = nurbs_curves[1].get_degree() knotvectors = [c.get_knotvector() for c in nurbs_curves] if not sv_knotvector.equal(knotvectors[0], knotvectors[2]): nurbs_curves[0], nurbs_curves[2] = unify_two_curves( nurbs_curves[0], nurbs_curves[2]) if not sv_knotvector.equal(knotvectors[1], knotvectors[3]): nurbs_curves[1], nurbs_curves[3] = unify_two_curves( nurbs_curves[1], nurbs_curves[3]) nurbs_curves[0] = reverse_curve(nurbs_curves[0]) nurbs_curves[3] = reverse_curve(nurbs_curves[3]) ruled1 = nurbs_curves[0].make_ruled_surface(nurbs_curves[2], 0, 1) ruled2 = nurbs_curves[1].make_ruled_surface(nurbs_curves[3], 0, 1).swap_uv() ruled1 = ruled1.elevate_degree(SvNurbsSurface.V, target=degree_v) ruled2 = ruled2.elevate_degree(SvNurbsSurface.U, target=degree_u) diff_1to2 = sv_knotvector.difference(ruled1.get_knotvector_v(), ruled2.get_knotvector_v()) diff_2to1 = sv_knotvector.difference(ruled2.get_knotvector_u(), ruled1.get_knotvector_u()) for v, count in diff_1to2: #print(f"R1: insert V={v} {count} times") ruled1 = ruled1.insert_knot(SvNurbsSurface.V, v, count) for u, count in diff_2to1: #print(f"R2: insert U={u} {count} times") ruled2 = ruled2.insert_knot(SvNurbsSurface.U, u, count) #print(f"R1: {ruled1.get_control_points().shape}, R2: {ruled2.get_control_points().shape}") linear_kv = sv_knotvector.generate(1, 2) c1_t_min, c1_t_max = nurbs_curves[0].get_u_bounds() c3_t_min, c3_t_max = nurbs_curves[2].get_u_bounds() pt1 = nurbs_curves[0].evaluate(c1_t_min) pt2 = nurbs_curves[0].evaluate(c1_t_max) pt3 = nurbs_curves[2].evaluate(c3_t_min) pt4 = nurbs_curves[2].evaluate(c3_t_max) w1 = nurbs_curves[0].get_weights()[0] w2 = nurbs_curves[0].get_weights()[-1] w3 = nurbs_curves[2].get_weights()[0] w4 = nurbs_curves[2].get_weights()[-1] linear_pts = np.array([[pt1, pt3], [pt2, pt4]]) linear_weights = np.array([[w1, w3], [w2, w4]]) #linear_weights = np.array([[1,1], [1,1]]) bilinear = SvNurbsSurface.build(implementation, 1, 1, linear_kv, linear_kv, linear_pts, linear_weights) bilinear = bilinear.elevate_degree(SvNurbsSurface.U, target=degree_u) bilinear = bilinear.elevate_degree(SvNurbsSurface.V, target=degree_v) knotvector_u = ruled1.get_knotvector_u() knotvector_v = ruled2.get_knotvector_v() for u, count in sv_knotvector.get_internal_knots( knotvector_u, output_multiplicity=True): #print(f"B: insert U={u} {count} times") bilinear = bilinear.insert_knot(SvNurbsSurface.U, u, count) for v, count in sv_knotvector.get_internal_knots( knotvector_v, output_multiplicity=True): #print(f"B: insert V={v} {count} times") bilinear = bilinear.insert_knot(SvNurbsSurface.V, v, count) control_points = ruled1.get_control_points( ) + ruled2.get_control_points() - bilinear.get_control_points() weights = ruled1.get_weights() + ruled2.get_weights( ) - bilinear.get_weights() result = SvNurbsSurface.build(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights) return result except UnsupportedCurveTypeException as e: info("Can't create a native Coons surface from curves %s: %s", curves, e) return SvCoonsSurface(*curves)
def intersect_curve_surface(curve, surface, init_samples=10, raycast_samples=10, tolerance=1e-3, maxiter=50, raycast_method='hybr', support_nurbs=False): """ Intersect a curve with a surface. dependencies: scipy """ u_min, u_max = curve.get_u_bounds() is_nurbs = False c = SvNurbsCurve.to_nurbs(curve) if c is not None: curve = c is_nurbs = True raycaster = SurfaceRaycaster(surface) raycaster.init_bvh(raycast_samples) def do_raycast(point, tangent, sign=1): good_sign = sign raycast = raycaster.raycast([point], [sign * tangent], method=raycast_method, on_init_fail=RETURN_NONE) if raycast is None: good_sign = -sign raycast = raycaster.raycast([point], [-sign * tangent], method=raycast_method, on_init_fail=RETURN_NONE) return good_sign, raycast good_ranges = [] u_range = np.linspace(u_min, u_max, num=init_samples) points = curve.evaluate_array(u_range) tangents = curve.tangent_array(u_range) for u1, u2, p1, p2, tangent1, tangent2 in zip(u_range, u_range[1:], points, points[1:], tangents, tangents[1:]): raycast = raycaster.raycast([p1, p2], [tangent1, -tangent2], precise=False, calc_points=False, on_init_fail=RETURN_NONE) if raycast is None: continue good_ranges.append((u1, u2, raycast.points[0], raycast.points[1])) def to_curve(point, curve, u1, u2, raycast=None): if support_nurbs and is_nurbs and raycast is not None: segment = curve.cut_segment(u1, u2) surface_u, surface_v = raycast.us[0], raycast.vs[0] point_on_surface = raycast.points[0] surface_normal = surface.normal(surface_u, surface_v) plane = PlaneEquation.from_normal_and_point( surface_normal, point_on_surface) r = intersect_curve_plane_nurbs(segment, plane, init_samples=2, tolerance=tolerance, maxiter=maxiter) if not r: return None else: return r[0] else: ortho = ortho_project_curve(point, curve, subdomain=(u1, u2), init_samples=2, on_fail=RETURN_NONE) if ortho is None: return None else: return ortho.nearest_u, ortho.nearest result = [] for u1, u2, init_p1, init_p2 in good_ranges: tangent = curve.tangent(u1) point = curve.evaluate(u1) i = 0 sign = 1 prev_prev_point = None prev_point = init_p1 u_root = None point_found = False raycast = None while True: i += 1 if i > maxiter: raise Exception( "Maximum number of iterations is exceeded; last step {} - {} = {}" .format(prev_prev_point, point, step)) on_curve = to_curve(prev_point, curve, u1, u2, raycast=raycast) if on_curve is None: break u_root, point = on_curve if u_root < u1 or u_root > u2: break step = np.linalg.norm(point - prev_point) if step < tolerance and i > 1: debug("After ortho: Point {}, prev {}, iter {}".format( point, prev_point, i)) point_found = True break prev_point = point tangent = curve.tangent(u_root) sign, raycast = do_raycast(point, tangent, sign) if raycast is None: raise Exception( "Iteration #{}: Can't do a raycast with point {}, direction {} onto surface {}" .format(i, point, tangent, surface)) point = raycast.points[0] step = np.linalg.norm(point - prev_point) prev_prev_point = prev_point prev_point = point if point_found: result.append((u_root, point)) return result
def process(self): if not any(socket.is_linked for socket in self.outputs): return path1_s = self.inputs['Path1'].sv_get() path2_s = self.inputs['Path2'].sv_get() profile_s = self.inputs['Profile'].sv_get() if self.explicit_v: v1_s = self.inputs['V1'].sv_get() v1_s = ensure_nesting_level(v1_s, 3) v2_s = self.inputs['V2'].sv_get() v2_s = ensure_nesting_level(v2_s, 3) else: v1_s = [[[]]] v2_s = [[[]]] profiles_count_s = self.inputs['VSections'].sv_get() degree_v_s = self.inputs['DegreeV'].sv_get() path1_s = ensure_nesting_level(path1_s, 2, data_types=(SvCurve, )) path2_s = ensure_nesting_level(path2_s, 2, data_types=(SvCurve, )) profile_s = ensure_nesting_level(profile_s, 3, data_types=(SvCurve, )) profiles_count_s = ensure_nesting_level(profiles_count_s, 2) degree_v_s = ensure_nesting_level(degree_v_s, 2) surfaces_out = [] curves_out = [] v_curves_out = [] for params in zip_long_repeat(path1_s, path2_s, profile_s, v1_s, v2_s, profiles_count_s, degree_v_s): new_surfaces = [] new_curves = [] new_v_curves = [] new_profiles = [] for path1, path2, profiles, vs1, vs2, profiles_count, degree_v in zip_long_repeat( *params): path1 = SvNurbsCurve.to_nurbs(path1) if path1 is None: raise Exception("Path #1 is not a NURBS curve!") path2 = SvNurbsCurve.to_nurbs(path2) if path2 is None: raise Exception("Path #2 is not a NURBS curve!") profiles = [ SvNurbsCurve.to_nurbs(profile) for profile in profiles ] if any(p is None for p in profiles): raise Exception("Some of profiles are not NURBS curves!") if self.explicit_v: ts1 = np.array(vs1) ts2 = np.array(vs2) else: ts1 = None ts2 = None _, unified_curves, v_curves, surface = nurbs_birail( path1, path2, profiles, ts1=ts1, ts2=ts2, min_profiles=profiles_count, knots_u=self.u_knots_mode, degree_v=degree_v, metric=self.metric, scale_uniform=self.scale_uniform, implementation=self.nurbs_implementation) new_surfaces.append(surface) new_curves.extend(unified_curves) new_v_curves.extend(v_curves) surfaces_out.append(new_surfaces) curves_out.append(new_curves) v_curves_out.append(new_v_curves) self.outputs['Surface'].sv_set(surfaces_out) self.outputs['AllProfiles'].sv_set(curves_out) self.outputs['VCurves'].sv_set(v_curves_out)