예제 #1
0
 def test_third_derivs_equal(self):
     ts = np.linspace(0.0, 1.0, num=10)
     points = cubic_control_points()
     cubic = SvCubicBezierCurve(*points)
     generic = SvBezierCurve(points)
     cubic_points = cubic.third_derivative_array(ts)
     generic_points = generic.third_derivative_array(ts)
     self.assert_numpy_arrays_equal(cubic_points, generic_points, precision=6)
예제 #2
0
 def test_cubic_equals_generic(self):
     ts = np.linspace(0.0, 1.0, num=10)
     points = cubic_control_points()
     cubic = SvCubicBezierCurve(*points)
     generic = SvBezierCurve(points)
     cubic_points = cubic.evaluate_array(ts)
     generic_points = generic.evaluate_array(ts)
     self.assert_numpy_arrays_equal(cubic_points, generic_points, precision=6)
예제 #3
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        points_s = self.inputs['Points'].sv_get()
        tangents_s = self.inputs['Tangents'].sv_get()

        points_s = ensure_nesting_level(points_s, 3)
        tangents_s = ensure_nesting_level(tangents_s, 3)

        curve_out = []
        controls_out = []
        for points, tangents in zip_long_repeat(points_s, tangents_s):
            new_curves = []
            new_controls = []
            control_points = []
            pairs = list(zip_long_repeat(points, tangents))
            segments = list(zip(pairs, pairs[1:]))
            if self.cyclic:
                segments.append((pairs[-1], pairs[0]))
            for pair1, pair2 in segments:
                point1, tangent1 = pair1
                point2, tangent2 = pair2
                point1, tangent1 = np.array(point1), np.array(tangent1)
                point2, tangent2 = np.array(point2), np.array(tangent2)
                tangent1, tangent2 = tangent1 / 2.0, tangent2 / 2.0
                curve = SvCubicBezierCurve(point1, point1 + tangent1,
                                           point2 - tangent2, point2)
                curve_controls = [
                    curve.p0.tolist(),
                    curve.p1.tolist(),
                    curve.p2.tolist(),
                    curve.p3.tolist()
                ]
                new_curves.append(curve)
                new_controls.append(curve_controls)
            if self.concat:
                new_curves = [SvConcatCurve(new_curves)]
            curve_out.append(new_curves)
            controls_out.append(new_controls)

        self.outputs['Curve'].sv_set(curve_out)
        self.outputs['ControlPoints'].sv_set(controls_out)
예제 #4
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return
        start_s = self.inputs['Start'].sv_get()
        end_s = self.inputs['End'].sv_get()
        knot1_s = self.inputs[CONTROL1_SOCKET].sv_get()
        knot2_s = self.inputs[CONTROL2_SOCKET].sv_get()
        controls_s = self.inputs['ControlPoints'].sv_get(default=[[[[]]]])

        start_s = ensure_nesting_level(start_s, 3)
        end_s = ensure_nesting_level(end_s, 3)
        knot1_s = ensure_nesting_level(knot1_s, 3)
        knot2_s = ensure_nesting_level(knot2_s, 3)
        controls_s = ensure_nesting_level(controls_s, 4)

        curves_out = []
        controls_out = []
        for starts, ends, knot1s, knot2s, controls_i in zip_long_repeat(
                start_s, end_s, knot1_s, knot2_s, controls_s):
            new_curves = []
            new_controls = []
            for start, end, knot1, knot2, controls in zip_long_repeat(
                    starts, ends, knot1s, knot2s, controls_i):
                start, end = np.array(start), np.array(end)
                knot1, knot2 = np.array(knot1), np.array(knot2)
                if self.mode == CUBIC:
                    curve = SvCubicBezierCurve(start, knot1, knot2, end)
                    curve_controls = [
                        start.tolist(),
                        knot1.tolist(),
                        knot2.tolist(),
                        end.tolist()
                    ]
                elif self.mode == CUBIC_TANGENT:
                    curve = SvBezierCurve.from_points_and_tangents(
                        start, knot1, knot2, end)
                    curve_controls = [
                        curve.p0.tolist(),
                        curve.p1.tolist(),
                        curve.p2.tolist(),
                        curve.p3.tolist()
                    ]
                elif self.mode == CUBIC_4PT:
                    curve = SvCubicBezierCurve.from_four_points(
                        start, knot1, knot2, end)
                    curve_controls = [
                        curve.p0.tolist(),
                        curve.p1.tolist(),
                        curve.p2.tolist(),
                        curve.p3.tolist()
                    ]
                elif self.mode == QUADRATIC:
                    curve = SvBezierCurve([start, knot1, end])
                    curve_controls = [p.tolist() for p in curve.points]
                else:  # GENERIC
                    if not controls:
                        raise SvNoDataError(
                            socket=self.inputs['ControlPoints'], node=self)
                    if len(controls) < 2:
                        raise Exception(
                            "At least two control points are required to build a Bezier spline!"
                        )
                    if self.is_cyclic:
                        controls = controls + [controls[0]]
                    curve = SvBezierCurve(controls)
                    curve_controls = controls
                new_curves.append(curve)
                new_controls.extend(curve_controls)
            curves_out.append(new_curves)
            controls_out.append(new_controls)

        self.outputs['Curve'].sv_set(curves_out)
        self.outputs['ControlPoints'].sv_set(controls_out)
예제 #5
0
    def interpret(self, interpreter, variables):
        vec = lambda v: Vector((v[0], v[1], 0))

        interpreter.assert_not_closed()
        interpreter.start_new_segment()

        v0 = interpreter.position
        if interpreter.has_last_vertex:
            v0_index = interpreter.get_last_vertex()
        else:
            v0_index = interpreter.new_vertex(*v0)

        knot1 = None
        for i, segment in enumerate(self.segments):
            # For first segment, knot1 is initial pen position;
            # for the following, knot1 is knot2 of previous segment.
            if knot1 is None:
                knot1 = interpreter.position
            else:
                knot1 = knot2

            if interpreter.prev_bezier_knot is None:
                # If there is no previous command or if the previous command was
                # not an C, c, S or s, assume the first control point is coincident
                # with the current point.
                handle1 = knot1
            else:
                # The first control point is assumed to be the reflection of the
                # second control point on the previous command relative to the
                # current point. 
                prev_knot_x, prev_knot_y = interpreter.prev_bezier_knot
                x0, y0 = knot1
                dx, dy = x0 - prev_knot_x, y0 - prev_knot_y
                handle1 = x0 + dx, y0 + dy

            # I assume that handle2 should be relative to knot1, not to handle1.
            # interpreter.position = handle1
            handle2 = interpreter.calc_vertex(self.is_abs, segment.control2[0], segment.control2[1], variables)
            # interpreter.position = handle2
            knot2 = interpreter.calc_vertex(self.is_abs, segment.knot2[0], segment.knot2[1], variables)
            interpreter.position = knot2

            if self.num_segments is not None:
                r = interpreter.eval_(self.num_segments, variables)
            else:
                r = interpreter.dflt_num_verts

            curve = SvCubicBezierCurve(vec(knot1), vec(handle1), vec(handle2), vec(knot2))
            interpreter.new_curve(curve, self)

            points = interpolate_bezier(vec(knot1), vec(handle1), vec(handle2), vec(knot2), r)

            interpreter.new_knot("S#.{}.h1".format(i), *handle1)
            interpreter.new_knot("S#.{}.h2".format(i), *handle2)
            interpreter.new_knot("S#.{}.k".format(i), *knot2)

            interpreter.prev_bezier_knot = handle2

            for point in points[1:]:
                v1_index = interpreter.new_vertex(point.x, point.y)
                interpreter.new_edge(v0_index, v1_index)
                v0_index = v1_index

        if self.close:
            interpreter.close_segment(v1_index)

        interpreter.has_last_vertex = True
예제 #6
0
    def interpret(self, interpreter, variables):
        vec = lambda v: Vector((v[0], v[1], 0))

        interpreter.assert_not_closed()
        interpreter.start_new_segment()

        v0 = interpreter.position
        if interpreter.has_last_vertex:
            v0_index = interpreter.get_last_vertex()
        else:
            v0_index = interpreter.new_vertex(*v0)

        knot1 = None
        for i, segment in enumerate(self.segments):
            # For first segment, knot1 is initial pen position;
            # for the following, knot1 is knot2 of previous segment.
            if knot1 is None:
                knot1 = interpreter.position
            else:
                knot1 = knot2

            handle1 = interpreter.calc_vertex(self.is_abs, segment.control1[0], segment.control1[1], variables)

            # In Profile mk2, for "c" handle2 was calculated relative to handle1,
            # and knot2 was calculated relative to handle2.
            # But in SVG specification, 
            # >> ...  *At the end of the command*, the new current point becomes
            # >> the final (x,y) coordinate pair used in the polybézier.
            # This is also behaivour of browsers.

            #interpreter.position = handle1
            handle2 = interpreter.calc_vertex(self.is_abs, segment.control2[0], segment.control2[1], variables)
            #interpreter.position = handle2
            knot2 = interpreter.calc_vertex(self.is_abs, segment.knot2[0], segment.knot2[1], variables)
            # Judging by the behaivour of Inkscape and Firefox, by "end of command"
            # SVG spec means "end of segment".
            interpreter.position = knot2

            if self.num_segments is not None:
                r = interpreter.eval_(self.num_segments, variables)
            else:
                r = interpreter.dflt_num_verts

            curve = SvCubicBezierCurve(vec(knot1), vec(handle1), vec(handle2), vec(knot2))
            interpreter.new_curve(curve, self)

            points = interpolate_bezier(vec(knot1), vec(handle1), vec(handle2), vec(knot2), r)

            interpreter.new_knot("C#.{}.h1".format(i), *handle1)
            interpreter.new_knot("C#.{}.h2".format(i), *handle2)
            interpreter.new_knot("C#.{}.k".format(i), *knot2)

            interpreter.prev_bezier_knot = handle2

            for point in points[1:]:
                v1_index = interpreter.new_vertex(point.x, point.y)
                interpreter.new_edge(v0_index, v1_index)
                v0_index = v1_index

        if self.close:
            interpreter.close_segment(v1_index)

        interpreter.has_last_vertex = True
예제 #7
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        output_src = self.output_src or self.concat

        curves_out = []
        controls_out = []
        is_first = True
        for curve1, curve2, factor1, factor2 in self.get_inputs():
            _, t_max_1 = curve1.get_u_bounds()
            t_min_2, _ = curve2.get_u_bounds()

            curve1_end = curve1.evaluate(t_max_1)
            curve2_begin = curve2.evaluate(t_min_2)

            smooth = int(self.smooth_mode)

            if smooth == 0:
                new_curve = SvLine.from_two_points(curve1_end, curve2_begin)
                new_controls = [curve1_end, curve2_begin]
            elif smooth == 1:
                tangent_1_end = curve1.tangent(t_max_1)
                tangent_2_begin = curve2.tangent(t_min_2)

                tangent1 = factor1 * tangent_1_end
                tangent2 = factor2 * tangent_2_begin

                new_curve = SvCubicBezierCurve(
                        curve1_end,
                        curve1_end + tangent1 / 3.0,
                        curve2_begin - tangent2 / 3.0,
                        curve2_begin
                    )
                new_controls = [new_curve.p0.tolist(), new_curve.p1.tolist(),
                                new_curve.p2.tolist(), new_curve.p3.tolist()]
            elif smooth == 2:
                tangent_1_end = curve1.tangent(t_max_1)
                tangent_2_begin = curve2.tangent(t_min_2)
                second_1_end = curve1.second_derivative(t_max_1)
                second_2_begin = curve2.second_derivative(t_min_2)

                new_curve = SvBezierCurve.blend_second_derivatives(
                                curve1_end, tangent_1_end, second_1_end,
                                curve2_begin, tangent_2_begin, second_2_begin)
                new_controls = [p.tolist() for p in new_curve.points]
            elif smooth == 3:
                tangent_1_end = curve1.tangent(t_max_1)
                tangent_2_begin = curve2.tangent(t_min_2)
                second_1_end = curve1.second_derivative(t_max_1)
                second_2_begin = curve2.second_derivative(t_min_2)
                third_1_end = curve1.third_derivative_array(np.array([t_max_1]))[0]
                third_2_begin = curve2.third_derivative_array(np.array([t_min_2]))[0]

                new_curve = SvBezierCurve.blend_third_derivatives(
                                curve1_end, tangent_1_end, second_1_end, third_1_end,
                                curve2_begin, tangent_2_begin, second_2_begin, third_2_begin)
                new_controls = [p.tolist() for p in new_curve.points]
            else:
                raise Exception("Unsupported smooth level")

            if self.mode == 'N' and not self.cyclic and output_src and is_first:
                curves_out.append(curve1)
            curves_out.append(new_curve)
            if self.mode == 'N' and output_src:
                curves_out.append(curve2)
            controls_out.append(new_controls)

            is_first = False

        if self.concat:
            curves_out = [SvConcatCurve(curves_out)]

        self.outputs['Curve'].sv_set(curves_out)
        self.outputs['ControlPoints'].sv_set(controls_out)
예제 #8
0
    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        output_src = self.output_src or self.concat

        curves_out = []
        controls_out = []
        is_first = True

        for params in self.get_inputs():
            new_curves = []
            new_controls = []
            for curve1, curve2, factor1, factor2, parameter in params:
                _, t_max_1 = curve1.get_u_bounds()
                t_min_2, _ = curve2.get_u_bounds()

                curve1_end = curve1.evaluate(t_max_1)
                curve2_begin = curve2.evaluate(t_min_2)

                smooth = self.smooth_mode

                if smooth == '0':
                    new_curve = SvLine.from_two_points(curve1_end,
                                                       curve2_begin)
                    controls = [curve1_end, curve2_begin]
                elif smooth == '1':
                    tangent_1_end = curve1.tangent(t_max_1)
                    tangent_2_begin = curve2.tangent(t_min_2)

                    tangent1 = factor1 * tangent_1_end
                    tangent2 = factor2 * tangent_2_begin

                    new_curve = SvCubicBezierCurve(
                        curve1_end, curve1_end + tangent1 / 3.0,
                        curve2_begin - tangent2 / 3.0, curve2_begin)
                    controls = [
                        new_curve.p0.tolist(),
                        new_curve.p1.tolist(),
                        new_curve.p2.tolist(),
                        new_curve.p3.tolist()
                    ]
                elif smooth == '1b':
                    tangent_1_end = curve1.tangent(t_max_1)
                    tangent_2_begin = curve2.tangent(t_min_2)

                    new_curve = SvBiArc.calc(
                        curve1_end,
                        curve2_begin,
                        tangent_1_end,
                        tangent_2_begin,
                        parameter,
                        planar_tolerance=self.planar_tolerance)

                    controls = [new_curve.junction.tolist()]
                elif smooth == '2':
                    tangent_1_end = curve1.tangent(t_max_1)
                    tangent_2_begin = curve2.tangent(t_min_2)
                    second_1_end = curve1.second_derivative(t_max_1)
                    second_2_begin = curve2.second_derivative(t_min_2)

                    new_curve = SvBezierCurve.blend_second_derivatives(
                        curve1_end, tangent_1_end, second_1_end, curve2_begin,
                        tangent_2_begin, second_2_begin)
                    controls = [p.tolist() for p in new_curve.points]
                elif smooth == '3':
                    tangent_1_end = curve1.tangent(t_max_1)
                    tangent_2_begin = curve2.tangent(t_min_2)
                    second_1_end = curve1.second_derivative(t_max_1)
                    second_2_begin = curve2.second_derivative(t_min_2)
                    third_1_end = curve1.third_derivative_array(
                        np.array([t_max_1]))[0]
                    third_2_begin = curve2.third_derivative_array(
                        np.array([t_min_2]))[0]

                    new_curve = SvBezierCurve.blend_third_derivatives(
                        curve1_end, tangent_1_end, second_1_end, third_1_end,
                        curve2_begin, tangent_2_begin, second_2_begin,
                        third_2_begin)
                    controls = [p.tolist() for p in new_curve.points]
                else:
                    raise Exception("Unsupported smooth level")

                if self.mode == 'N' and not self.cyclic and output_src and is_first:
                    new_curves.append(curve1)
                new_curves.append(new_curve)
                if self.mode == 'N' and output_src:
                    new_curves.append(curve2)
                new_controls.append(controls)

                is_first = False

                if self.concat:
                    new_curves = [concatenate_curves(new_curves)]

            if self.join:
                curves_out.extend(new_curves)
                controls_out.extend(new_controls)
            else:
                curves_out.append(new_curves)
                controls_out.append(new_controls)

        self.outputs['Curve'].sv_set(curves_out)
        self.outputs['ControlPoints'].sv_set(controls_out)