def unify_curves(curves): curves = [curve.reparametrize(0.0, 1.0) for curve in curves] dst_knots = defaultdict(int) for curve in curves: m = sv_knotvector.to_multiplicity(curve.get_knotvector()) for u, count in m: u = round(u, 6) dst_knots[u] = max(dst_knots[u], count) result = [] # for i, curve1 in enumerate(curves): # for j, curve2 in enumerate(curves): # if i != j: # curve1 = curve1.to_knotvector(curve2) # result.append(curve1) for curve in curves: diffs = [] kv = np.round(curve.get_knotvector(), 6) ms = dict(sv_knotvector.to_multiplicity(kv)) for dst_u, dst_multiplicity in dst_knots.items(): src_multiplicity = ms.get(dst_u, 0) diff = dst_multiplicity - src_multiplicity diffs.append((dst_u, diff)) #print(f"Src {ms}, dst {dst_knots} => diff {diffs}") for u, diff in diffs: if diff > 0: curve = curve.insert_knot(u, diff) result.append(curve) return result
def build(cls, implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights=None, normalize_knots=False): control_points = np.asarray(control_points) m, n, _ = control_points.shape if weights is None: weights = np.ones((m, n)) weights = np.asarray(weights) if normalize_knots: knotvector_u = sv_knotvector.normalize(knotvector_u) knotvector_v = sv_knotvector.normalize(knotvector_v) pts = [[Base.Vector(*t) for t in row] for row in control_points] ms_u = sv_knotvector.to_multiplicity(knotvector_u) knots_u = [p[0] for p in ms_u] mults_u = [p[1] for p in ms_u] ms_v = sv_knotvector.to_multiplicity(knotvector_v) knots_v = [p[0] for p in ms_v] mults_v = [p[1] for p in ms_v] surface = Part.BSplineSurface() surface.buildFromPolesMultsKnots(pts, mults_u, mults_v, knots_u, knots_v, False, False, degree_u, degree_v, weights.tolist()) return SvFreeCadNurbsSurface(surface)
def concatenate(self, curve2, tolerance=1e-6): curve1 = self curve2 = SvNurbsCurve.to_nurbs(curve2) if curve2 is None: raise UnsupportedCurveTypeException("second curve is not NURBS") c1_end = curve1.get_u_bounds()[1] c2_start = curve2.get_u_bounds()[0] pt1 = curve1.evaluate(c1_end) pt2 = curve2.evaluate(c2_start) dpt = np.linalg.norm(pt1 - pt2) if dpt > tolerance: raise UnsupportedCurveTypeException( f"Curve end points do not match: C1({c1_end}) = {pt1} != C2({c2_start}) = {pt2}, distance={dpt}" ) cp1 = curve1.get_control_points()[-1] cp2 = curve2.get_control_points()[0] if np.linalg.norm(cp1 - cp2) > tolerance: raise UnsupportedCurveTypeException( "End control points do not match") w1 = curve1.get_weights()[-1] w2 = curve1.get_weights()[0] if w1 != w2: raise UnsupportedCurveTypeException( "Weights at endpoints do not match") p1, p2 = curve1.get_degree(), curve2.get_degree() if p1 > p2: curve2 = curve2.elevate_degree(delta=p1 - p2) elif p2 > p1: curve1 = curve1.elevate_degree(delta=p2 - p1) p = curve1.get_degree() kv1 = curve1.get_knotvector() kv2 = curve2.get_knotvector() kv1_end_multiplicity = sv_knotvector.to_multiplicity(kv1)[-1][1] kv2_start_multiplicity = sv_knotvector.to_multiplicity(kv2)[0][1] if kv1_end_multiplicity != p + 1: raise UnsupportedCurveTypeException( f"End knot multiplicity of the first curve ({kv1_end_multiplicity}) is not equal to degree+1 ({p+1})" ) if kv2_start_multiplicity != p + 1: raise UnsupportedCurveTypeException( f"Start knot multiplicity of the second curve ({kv2_start_multiplicity}) is not equal to degree+1 ({p+1})" ) knotvector = sv_knotvector.concatenate(kv1, kv2, join_multiplicity=p) #print(f"Concat KV: {kv1} + {kv2} => {knotvector}") weights = np.concatenate( (curve1.get_weights(), curve2.get_weights()[1:])) control_points = np.concatenate( (curve1.get_control_points(), curve2.get_control_points()[1:])) return SvNurbsCurve.build(self.get_nurbs_implementation(), p, knotvector, control_points, weights)
def build_2d(cls, degree, knotvector, control_points, weights=None): n = len(control_points) if weights is None: weights = np.ones((n,)) pts = [Base.Vector2d(t[0], t[1]) for t in control_points] ms = sv_knotvector.to_multiplicity(knotvector) knots = [p[0] for p in ms] mults = [p[1] for p in ms] curve = Geom2d.BSplineCurve2d() curve.buildFromPolesMultsKnots(pts, mults, knots, False, degree, weights) return SvFreeCadNurbsCurve(curve, ndim=2)
def remove_knot(self, u, count=1, tolerance=1e-4): curve = SvFreeCadNurbsCurve(self.curve.copy(), self.ndim) # copy ms = sv_knotvector.to_multiplicity(self.get_knotvector()) idx = None M = None for i, (u1, m) in enumerate(ms): if u1 == u: idx = i M = m - count break if idx is not None: curve.curve.removeKnot(idx + 1, M, tolerance) return curve
def remove_knot(self, direction, parameter, count=1, if_possible=False, tolerance=1e-6): surface = SvFreeCadNurbsSurface(self.surface.copy()) if direction == 'U': ms = sv_knotvector.to_multiplicity(self.get_knotvector_u()) else: ms = sv_knotvector.to_multiplicity(self.get_knotvector_v()) idx = None M = None for i, (u1, m) in enumerate(ms): if u1 == parameter: idx = i M = m - count break if idx is not None: if direction == 'U': surface.surface.removeUKnot(idx + 1, M, tolerance) else: surface.surface.removeVKnot(idx + 1, M, tolerance) return surface
def build(cls, implementation, degree, knotvector, control_points, weights=None, normalize_knots=False): n = len(control_points) if weights is None: weights = np.ones((n,)) if normalize_knots: knotvector = sv_knotvector.normalize(knotvector) pts = [Base.Vector(t[0], t[1], t[2]) for t in control_points] ms = sv_knotvector.to_multiplicity(knotvector) knots = [p[0] for p in ms] mults = [p[1] for p in ms] curve = Part.BSplineCurve() curve.buildFromPolesMultsKnots(pts, mults, knots, False, degree, weights) return SvFreeCadNurbsCurve(curve)
def remove_knot(self, u, count=1, tolerance=1e-4, if_possible=False): curve = SvFreeCadNurbsCurve(self.curve.copy(), self.ndim) # copy ms = sv_knotvector.to_multiplicity(self.get_knotvector()) idx = None M = None for i, (u1, m) in enumerate(ms): if u1 == u: idx = i if count == 'ALL': M = 0 elif count == 'ALL_BUT_ONE': M = 1 else: M = m - count break if idx is not None: curve.curve.removeKnot(idx + 1, M, tolerance) return curve
def test_to_multiplicity_4(self): kv = np.array([0, 0, 0, 0.3, 0.7, 1, 1, 1, 1.5, 1.7], dtype=np.float64) result = sv_knotvector.to_multiplicity(kv) expected = [(0, 3), (0.3, 1), (0.7, 1), (1, 3), (1.5, 1), (1.7, 1)] self.assert_sverchok_data_equal(result, expected)
def unify_curves(curves, method='UNIFY', accuracy=6): tolerance = 10**(-accuracy) curves = [curve.reparametrize(0.0, 1.0) for curve in curves] if method == 'UNIFY': dst_knots = KnotvectorDict(accuracy) for i, curve in enumerate(curves): m = sv_knotvector.to_multiplicity(curve.get_knotvector(), tolerance**2) #print(f"Curve #{i}: degree={curve.get_degree()}, cpts={len(curve.get_control_points())}, {m}") for u, count in m: dst_knots.update(i, u, count) result = [] # for i, curve1 in enumerate(curves): # for j, curve2 in enumerate(curves): # if i != j: # curve1 = curve1.to_knotvector(curve2) # result.append(curve1) for idx, curve in enumerate(curves): diffs = [] #kv = np.round(curve.get_knotvector(), accuracy) #curve = curve.copy(knotvector = kv) #print('next curve', curve.get_knotvector()) ms = dict( sv_knotvector.to_multiplicity(curve.get_knotvector(), tolerance**2)) for dst_u, dst_multiplicity in dst_knots.items(): src_multiplicity = ms.get(dst_u, 0) diff = dst_multiplicity - src_multiplicity #print(f"C#{idx}: U = {dst_u}, was = {src_multiplicity}, need = {dst_multiplicity}, diff = {diff}") diffs.append((dst_u, diff)) #print(f"Src {ms}, dst {dst_knots} => diff {diffs}") for u, diff in diffs: if diff > 0: curve = curve.insert_knot(u, diff) # if u in dst_knots.skip_insertions[idx]: # pass # print(f"C: skip insertion T = {u}") # else: # #kv = curve.get_knotvector() # print(f"C: Insert T = {u} x {diff}") # curve = curve.insert_knot(u, diff) result.append(curve) return result elif method == 'AVERAGE': kvs = [len(curve.get_control_points()) for curve in curves] max_kv, min_kv = max(kvs), min(kvs) if max_kv != min_kv: raise Exception( f"Knotvector averaging is not applicable: Curves have different number of control points: {kvs}" ) knotvectors = np.array([curve.get_knotvector() for curve in curves]) knotvector_u = knotvectors.mean(axis=0) result = [curve.copy(knotvector=knotvector_u) for curve in curves] return result
def unify_nurbs_surfaces(surfaces): # Unify surface degrees degrees_u = [surface.get_degree_u() for surface in surfaces] degrees_v = [surface.get_degree_v() for surface in surfaces] degree_u = max(degrees_u) degree_v = max(degrees_v) surfaces = [ surface.elevate_degree(SvNurbsSurface.U, target=degree_u) for surface in surfaces ] surfaces = [ surface.elevate_degree(SvNurbsSurface.V, target=degree_v) for surface in surfaces ] # Unify surface knotvectors dst_knots_u = defaultdict(int) dst_knots_v = defaultdict(int) for surface in surfaces: m_u = sv_knotvector.to_multiplicity(surface.get_knotvector_u()) m_v = sv_knotvector.to_multiplicity(surface.get_knotvector_v()) for u, count in m_u: u = round(u, 6) dst_knots_u[u] = max(dst_knots_u[u], count) for v, count in m_v: v = round(v, 6) dst_knots_v[v] = max(dst_knots_v[v], count) result = [] for surface in surfaces: diffs_u = [] kv_u = np.round(surface.get_knotvector_u(), 6) ms_u = dict(sv_knotvector.to_multiplicity(kv_u)) for dst_u, dst_multiplicity in dst_knots_u.items(): src_multiplicity = ms_u.get(dst_u, 0) diff = dst_multiplicity - src_multiplicity diffs_u.append((dst_u, diff)) for u, diff in diffs_u: if diff > 0: surface = surface.insert_knot(SvNurbsSurface.U, u, diff) diffs_v = [] kv_v = np.round(surface.get_knotvector_v(), 6) ms_v = dict(sv_knotvector.to_multiplicity(kv_v)) for dst_v, dst_multiplicity in dst_knots_v.items(): src_multiplicity = ms_v.get(dst_v, 0) diff = dst_multiplicity - src_multiplicity diffs_v.append((dst_v, diff)) for v, diff in diffs_v: if diff > 0: surface = surface.insert_knot(SvNurbsSurface.V, v, diff) result.append(surface) return result
def concatenate(self, curve2, tolerance=1e-6, remove_knots=False): curve1 = self curve2 = SvNurbsCurve.to_nurbs(curve2) if curve2 is None: raise UnsupportedCurveTypeException("second curve is not NURBS") c1_end = curve1.get_u_bounds()[1] c2_start = curve2.get_u_bounds()[0] if sv_knotvector.is_clamped(curve1.get_knotvector(), curve1.get_degree(), check_start=True, check_end=False): pt1 = curve1.get_control_points()[-1] else: pt1 = curve1.evaluate(c1_end) if sv_knotvector.is_clamped(curve2.get_knotvector(), curve2.get_degree(), check_start=False, check_end=True): pt2 = curve2.get_control_points()[0] else: pt2 = curve2.evaluate(c2_start) dpt = np.linalg.norm(pt1 - pt2) if dpt > tolerance: raise UnsupportedCurveTypeException( f"Curve end points do not match: C1({c1_end}) = {pt1} != C2({c2_start}) = {pt2}, distance={dpt}" ) cp1 = curve1.get_control_points()[-1] cp2 = curve2.get_control_points()[0] if np.linalg.norm(cp1 - cp2) > tolerance: raise UnsupportedCurveTypeException( "End control points do not match") w1 = curve1.get_weights()[-1] w2 = curve2.get_weights()[0] if abs(w1 - w2) > tolerance: raise UnsupportedCurveTypeException( f"Weights at endpoints do not match: {w1} != {w2}") p1, p2 = curve1.get_degree(), curve2.get_degree() if p1 > p2: curve2 = curve2.elevate_degree(delta=p1 - p2) elif p2 > p1: curve1 = curve1.elevate_degree(delta=p2 - p1) p = curve1.get_degree() kv1 = curve1.get_knotvector() kv2 = curve2.get_knotvector() kv1_end_multiplicity = sv_knotvector.to_multiplicity(kv1)[-1][1] kv2_start_multiplicity = sv_knotvector.to_multiplicity(kv2)[0][1] if kv1_end_multiplicity != p + 1: raise UnsupportedCurveTypeException( f"End knot multiplicity of the first curve ({kv1_end_multiplicity}) is not equal to degree+1 ({p+1})" ) if kv2_start_multiplicity != p + 1: raise UnsupportedCurveTypeException( f"Start knot multiplicity of the second curve ({kv2_start_multiplicity}) is not equal to degree+1 ({p+1})" ) knotvector = sv_knotvector.concatenate(kv1, kv2, join_multiplicity=p) #print(f"Concat KV: {kv1} + {kv2} => {knotvector}") weights = np.concatenate( (curve1.get_weights(), curve2.get_weights()[1:])) control_points = np.concatenate( (curve1.get_control_points(), curve2.get_control_points()[1:])) result = SvNurbsCurve.build(self.get_nurbs_implementation(), p, knotvector, control_points, weights) if remove_knots is not None: if remove_knots == True: remove_knots = p - 1 join_point = kv1[-1] result = result.remove_knot(join_point, count=remove_knots, if_possible=True) return result