Esempio n. 1
0
    def elevate_degree(self, delta=None, target=None):
        if delta is None and target is None:
            delta = 1
        if delta is not None and target is not None:
            raise Exception(
                "Of delta and target, only one parameter can be specified")
        degree = self.get_degree()
        if delta is None:
            delta = target - degree
            if delta < 0:
                raise Exception(
                    f"Curve already has degree {degree}, which is greater than target {target}"
                )
        if delta == 0:
            return self

        if self.is_bezier():
            control_points = self.get_homogenous_control_points()
            control_points = elevate_bezier_degree(degree, control_points,
                                                   delta)
            control_points, weights = from_homogenous(control_points)
            knotvector = self.get_knotvector()
            knotvector = sv_knotvector.elevate_degree(knotvector, delta)
            return SvNurbsCurve.build(self.get_nurbs_implementation(),
                                      degree + delta, knotvector,
                                      control_points, weights)
        else:
            raise UnsupportedCurveTypeException(
                "Degree elevation is not implemented for non-bezier curves yet"
            )
Esempio n. 2
0
    def make_ruled_surface(self, curve2, vmin, vmax):
        curve = self
        curve2 = SvNurbsCurve.to_nurbs(curve2)
        if curve2 is None:
            raise UnsupportedCurveTypeException("second curve is not NURBS")
        curve, curve2 = unify_curves_degree([curve, curve2])
        if curve.get_degree() != curve2.get_degree():
            raise UnsupportedCurveTypeException(
                f"curves have different degrees: {curve.get_degree()} != {curve2.get_degree()}"
            )

        #print(f"kv1: {curve.get_knotvector().shape}, kv2: {curve2.get_knotvector().shape}")
        kv1, kv2 = curve.get_knotvector(), curve2.get_knotvector()
        if kv1.shape != kv2.shape or (kv1 != kv2).any():
            curve, curve2 = unify_two_curves(curve, curve2)
            #raise UnsupportedCurveTypeException("curves have different knot vectors")

        my_control_points = curve.get_control_points()
        other_control_points = curve2.get_control_points()
        if len(my_control_points) != len(other_control_points):
            raise UnsupportedCurveTypeException(
                "curves have different number of control points")

        if vmin != 0:
            my_control_points = (
                1 - vmin) * my_control_points + vmin * other_control_points
        if vmax != 0:
            other_control_points = (
                1 - vmax) * my_control_points + vmax * other_control_points

        control_points = np.stack((my_control_points, other_control_points))
        control_points = np.transpose(control_points, axes=(1, 0, 2))

        weights = np.stack((curve.get_weights(), curve2.get_weights())).T
        knotvector_v = sv_knotvector.generate(1, 2, clamped=True)

        surface = SvNurbsMaths.build_surface(
            self.get_nurbs_implementation(),
            degree_u=curve.get_degree(),
            degree_v=1,
            knotvector_u=curve.get_knotvector(),
            knotvector_v=knotvector_v,
            control_points=control_points,
            weights=weights)
        return surface
Esempio n. 3
0
 def to_bezier(self):
     points = self.get_control_points()
     if not self.is_bezier():
         n = len(points)
         p = self.get_degree()
         raise UnsupportedCurveTypeException(
             f"Curve with {n} control points and {p}'th degree can not be converted into Bezier curve"
         )
     return SvBezierCurve(points)
Esempio n. 4
0
 def get_actual_radius(self, tolerance=1e-10):
     x = np.array([self.radius, 0, 0])
     y = np.array([0, self.radius, 0])
     m = self.matrix
     vx = m @ x
     vy = m @ y
     rx = np.linalg.norm(vx)
     ry = np.linalg.norm(vy)
     if abs(rx - ry) > tolerance:
         raise UnsupportedCurveTypeException(
             f"This SvCircle instance is not an exact circle: {rx} != {ry}")
     return (rx + ry) / 2.0
Esempio n. 5
0
 def to_bezier_segments(self):
     if self.is_rational():
         raise UnsupportedCurveTypeException(
             "Rational NURBS curve can not be converted into non-rational Bezier curves"
         )
     if self.is_bezier():
         return [self.to_bezier()]
     segments = []
     rest = self
     for u in sv_knotvector.get_internal_knots(self.get_knotvector()):
         segment, rest = rest.split_at(u)
         segments.append(segment.to_bezier())
     segments.append(rest.to_bezier())
     return segments
Esempio n. 6
0
    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)
Esempio n. 7
0
    def to_nurbs(self, implementation=SvNurbsMaths.NATIVE):
        t_min, t_max = self.get_u_bounds()
        epsilon = 1e-6

        if -2 * pi < t_min < 0 and 0 < t_max < 2 * pi:
            arc1 = self.copy()
            arc1.u_bounds = (2 * pi + t_min, 2 * pi)
            arc1 = arc1.to_nurbs()
            arc2 = self.copy()
            arc2.u_bounds = (0, t_max)
            arc2 = arc2.to_nurbs()
            return arc1.concatenate(arc2)

        if t_min < 0 or t_max > 2 * pi + epsilon:
            raise UnsupportedCurveTypeException(
                f"Can't transform a circle arc out of 0-2pi bound ({t_min} - {t_max}) to NURBS"
            )

        #print(f"T {t_min},{t_max}, 2pi {2*pi}")
        if t_max - t_min < pi:
            return self._arc_to_nurbs(t_min, t_max, implementation)
        elif t_max - t_min < 2 * pi + epsilon:
            half = self._half_circle_nurbs(t_min, implementation)
            if abs(t_max - t_min - pi) < epsilon:
                return half
            arc = self._arc_to_nurbs(t_min + pi, t_max, implementation)
            return half.concatenate(arc)

        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)
        control_points = self.center + 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 = SvNurbsMaths.build_curve(implementation, degree, knotvector,
                                         control_points, weights)

        #if t_min != 0 or t_max != 2*pi:
        #print(f"Cut {t_min} - {t_max}")
        #curve = curve_segment(curve, t_min, t_max)
        return curve
Esempio n. 8
0
    def lerp_to(self, curve2, coefficient):
        curve1 = self
        curve2 = SvNurbsCurve.to_nurbs(curve2)
        if curve2 is None:
            raise UnsupportedCurveTypeException("second curve is not NURBS")
        curve1, curve2 = unify_curves_degree([curve1, curve2])
        curve1, curve2 = unify_two_curves(curve1, curve2)

        #c1cp = curve1.get_homogenous_control_points()
        #c2cp = curve2.get_homogenous_control_points()
        c1cp = curve1.get_control_points()
        c2cp = curve2.get_control_points()
        ws1 = curve1.get_weights()
        ws2 = curve2.get_weights()

        points = c1cp * (1 - coefficient) + coefficient * c2cp

        weights = ws1 * (1 - coefficient) + coefficient * ws2

        return SvNurbsCurve.build(curve1.get_nurbs_implementation(),
                                  curve1.get_degree(), curve1.get_knotvector(),
                                  points, weights)
Esempio n. 9
0
 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
Esempio n. 10
0
 def concatenate(self, curve2):
     curve2 = SvNurbsMaths.to_nurbs_curve(curve2)
     if curve2 is None:
         raise UnsupportedCurveTypeException("Second curve is not a NURBS")
     return self.to_nurbs().concatenate(curve2)
Esempio n. 11
0
    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
Esempio n. 12
0
def coons_surface(curve1, curve2, curve3, curve4, use_nurbs=NURBS_IF_POSSIBLE):
    curves = [curve1, curve2, curve3, curve4]
    nurbs_curves = [SvNurbsCurve.to_nurbs(c) for c in curves]
    if use_nurbs == GENERIC:
        return SvCoonsSurface(*curves)
    if any(c is None for c in nurbs_curves):
        if use_nurbs == NURBS_ONLY:
            raise UnsupportedCurveTypeException("Some of curves are not NURBS")
        else:
            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()

        nurbs_curves[0], nurbs_curves[2] = unify_curves(
            [nurbs_curves[0], nurbs_curves[2]])
        nurbs_curves[1], nurbs_curves[3] = unify_curves(
            [nurbs_curves[1], nurbs_curves[3]])

        degree_u = nurbs_curves[0].get_degree()
        degree_v = nurbs_curves[1].get_degree()

        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()

        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)

        ruled1, ruled2, bilinear = unify_nurbs_surfaces(
            [ruled1, ruled2, bilinear])
        knotvector_u = ruled1.get_knotvector_u()
        knotvector_v = ruled1.get_knotvector_v()

        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:
        if use_nurbs == NURBS_ONLY:
            raise
        else:
            info("Can't create a native Coons surface from curves %s: %s",
                 curves, e)
            return SvCoonsSurface(*curves)