Example #1
0
    def __convert_to_svgpath(self):
        location_A = (0 + 0j)
        location_B = (self.xB + self.yB * self.thickness_ratio * 1j)
        location_C = (1 + 0j)
        location_D = (self.xD + (self.yB - 1.0) * self.thickness_ratio * 1j)

        control_1 = (0 + self.y1 * location_B.imag * 1j)
        control_2 = (self.x2 * location_B.real + location_B.imag * 1j)
        control_3 = (self.x3 * (1.0 - location_B.real) + location_B.real +
                     location_B.imag * 1j)

        control_6 = (self.x6 * (1.0 - location_D.real) + location_D.real +
                     location_D.imag * 1j)
        control_7 = (self.x2 * location_D.real + location_D.imag * 1j)
        control_8 = (0 + self.y8 * location_D.imag * 1j)

        y4 = location_C.imag + self.y4 * (location_B.imag - location_C.imag)
        x4 = location_C.real - self.x4 * (location_C.real - control_3.real)
        control_4 = (x4 + y4 * 1j)

        x5 = control_4.real - self.x5 * (control_4.real - control_6.real)
        y5 = control_4.imag - self.y5 * (control_4.imag - control_6.imag)
        control_5 = (x5 + y5 * 1j)

        return svg.Path(
            svg.CubicBezier(start=location_A,
                            control1=control_1,
                            control2=control_2,
                            end=location_B),
            svg.CubicBezier(start=location_B,
                            control1=control_3,
                            control2=control_4,
                            end=location_C),
            svg.CubicBezier(start=location_C,
                            control1=control_5,
                            control2=control_6,
                            end=location_D),
            svg.CubicBezier(start=location_D,
                            control1=control_7,
                            control2=control_8,
                            end=location_A))
Example #2
0
    def fromCircleDef(cls, center: float, radius: float) -> 'SvgPath':
        '''
        PyCut Tab import in svg viewer
        '''
        NB_SEGMENTS = 12
        angles = [
            float(k * M_PI) / (NB_SEGMENTS) for k in range(NB_SEGMENTS * 2 + 1)
        ]

        discretized_svg_path : List[complex] = [ complex( \
                    center[0] + radius*math.cos(angle),
                    center[1] + radius*math.sin(angle) ) for angle in angles]

        svg_path = svgpathtools.Path()

        for i in range(len(discretized_svg_path) - 1):
            start = discretized_svg_path[i]
            end = discretized_svg_path[i + 1]

            svg_path.append(svgpathtools.Line(start, end))

        return SvgPath("pycut_tab", {'d': svg_path.d()})
Example #3
0
    def add_fillet_to_path(self, d):
        p = svgpathtools.parse_path(d)
        p = remove_zero_length_segments(
            p)  # for z, a zero length line segment is possibly added

        if len(p) <= 1:
            return d

        new_p = svgpathtools.Path()
        self._prev_t = 0  # used as cache
        self._very_first_t = None  # update first segment if closed
        if isclosedac(p):
            for i in range(len(p)):
                new_p.extend(self._calc_fillet_for_joint(p, i))
            if not isclosedac(new_p):
                del new_p[0]  # remove first segment if closed
        else:
            for i in range(len(p) - 1):
                new_p.extend(self._calc_fillet_for_joint(p, i))
        new_p = round_path(new_p, 6)
        # inkex.errormsg(d_str(new_p, use_closed_attrib=True, rel=True))
        return d_str(new_p, use_closed_attrib=True, rel=True)
Example #4
0
def colorize(args):
    input_file = args.infile
    output_file = args.outfile

    if input_file == "" or output_file == "":
        logging.error("Input or output file names are missing")
        raise ValueError("Input and output files are needed")

    logging.info("input file {} output file {}".format(input_file, output_file))

    paths, attributes, svg_attributes = spt.svg2paths2(input_file)

    # each segment must be a path in order to assign a color

    new_paths = []
    for path in paths:
        for segment in path:
            new_paths.append(spt.Path(segment))

    nb_segments = len(new_paths)
    col = ['r', 'g', 'b', 'k']
    segment_col = ''.join([col[i % len(col)] for i in range(nb_segments)])

    spt.wsvg(new_paths, colors=segment_col, stroke_widths=[2] * nb_segments, filename=output_file)
Example #5
0
File: engine.py Project: ertpoi/smt
 def _bbox(self):
     return SPT.Path(self._path().d()).bbox()
Example #6
0
def convert_and_write_svg(cubic, filename):
    cubic_path = svgpathtools.Path(cubic)
    cubic_ctrl = svgpathtools.Path(
        svgpathtools.Line(cubic.start, cubic.control1),
        svgpathtools.Line(cubic.control1, cubic.control2),
        svgpathtools.Line(cubic.control2, cubic.end))
    cubic_color = (50, 50, 200)
    cubic_ctrl_color = (150, 150, 150)

    r = 4.0

    paths = [cubic_path, cubic_ctrl]
    colors = [cubic_color, cubic_ctrl_color]
    dots = [
        cubic_path[0].start, cubic_path[0].control1, cubic_path[0].control2,
        cubic_path[0].end
    ]
    ncols = ['green', 'green', 'green', 'green']
    nradii = [r, r, r, r]
    stroke_widths = [3.0, 1.5]

    def add_quadratic(q):
        paths.append(q)
        q_ctrl = svgpathtools.Path(svgpathtools.Line(q.start, q.control),
                                   svgpathtools.Line(q.control, q.end))
        paths.append(q_ctrl)
        colors.append((200, 50, 50))  # q_color
        colors.append((150, 150, 150))  # q_ctrl_color
        dots.append(q.start)
        dots.append(q.control)
        dots.append(q.end)
        ncols.append('purple')
        ncols.append('purple')
        ncols.append('purple')
        nradii.append(r)
        nradii.append(r)
        nradii.append(r)
        stroke_widths.append(3.0)
        stroke_widths.append(1.5)

    prec = 1.0
    queue = [cubic]
    num_quadratics = 0
    while len(queue) > 0:
        c = queue[-1]
        queue = queue[:-1]

        # Criteria for conversion
        # http://caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html
        p = c.end - 3 * c.control2 + 3 * c.control1 - c.start
        d = math.sqrt(p.real * p.real + p.imag * p.imag) * math.sqrt(3.0) / 36
        t = math.pow(1.0 / d, 1.0 / 3.0)

        if t < 1.0:
            c0, c1 = split_cubic(c, 0.5)
            queue.append(c0)
            queue.append(c1)
        else:
            quadratic = cubic_to_quadratic(c)
            print(quadratic)
            add_quadratic(quadratic)
            num_quadratics += 1
    print('num_quadratics:', num_quadratics)

    svgpathtools.wsvg(paths,
                      colors=colors,
                      stroke_widths=stroke_widths,
                      nodes=dots,
                      node_colors=ncols,
                      node_radii=nradii,
                      filename=filename)
Example #7
0
def remove_zero_length_segments(p, eps=1e-6):
    "z will add a zero length line segment"
    return svgpathtools.Path(*filter(lambda seg: seg.length() > eps, p))
Example #8
0
    def _calc_fillet_for_joint(self, p, i):
        seg1 = p[(i) % len(p)]
        seg2 = p[(i + 1) % len(p)]

        ori_p = svgpathtools.Path(seg1, seg2)
        new_p = svgpathtools.Path()

        # ignore the node if G1 continuity
        tg1 = seg1.unit_tangent(1.0)
        tg2 = seg2.unit_tangent(0.0)
        cosA = abs(tg1.real * tg2.real + tg1.imag * tg2.imag)
        if abs(cosA - 1.0) < 1e-6:
            new_p.append(seg1.cropped(self._prev_t, 1.0))
            self._prev_t = 0.0
            if self._very_first_t is None:
                self._very_first_t = 1.0
            if not isclosedac(p) and i == len(p) - 2:
                new_p.append(seg2.cropped(
                    0.0, 1.0))  # add last segment if not closed
        else:
            cir = self.circle(seg1.end, self.options.radius)
            #        new_p.extend(cir)

            intersects = ori_p.intersect(cir)
            if len(intersects) != 2:
                inkex.errormsg(
                    "Some fillet or chamfer may not be drawn: %d intersections!"
                    % len(intersects))
                new_p.append(seg1.cropped(self._prev_t, 1.0))
                self._prev_t = 0.0
                if self._very_first_t is None:
                    self._very_first_t = 1.0
                if not isclosedac(p) and i == len(p) - 2:
                    new_p.append(seg2.cropped(
                        0.0, 1.0))  # add last segment if not closed
            else:
                cb = []
                segs = []
                ts = []
                for (T1, seg1, t1), (T2, seg2, t2) in intersects:
                    c1 = seg1.point(t1)
                    tg1 = seg1.unit_tangent(t1) * (self.options.radius * KAPPA)
                    cb.extend([c1, tg1])
                    segs.append(seg1)
                    ts.append(t1)

    #                cir1 = self.circle(c1, self.options.radius * KAPPA)
    #                new_p.extend(cir1)
    #                new_p.append(svgpathtools.Line(c1, c1+tg1))

                assert len(cb) == 4
                new_p.append(segs[0].cropped(self._prev_t, ts[0]))
                if self.options.fillet_type == 'fillet':
                    fillet = svgpathtools.CubicBezier(cb[0], cb[0] + cb[1],
                                                      cb[2] - cb[3], cb[2])
                else:
                    fillet = svgpathtools.Line(cb[0], cb[2])
                new_p.append(fillet)
                self._prev_t = ts[1]
                if self._very_first_t is None:
                    self._very_first_t = ts[0]

                if isclosedac(p) and i == len(p) - 1:
                    new_p.append(segs[1].cropped(
                        ts[1],
                        self._very_first_t))  # update first segment if closed
                elif not isclosedac(p) and i == len(p) - 2:
                    new_p.append(segs[1].cropped(
                        ts[1], 1.0))  # add last segment if not closed


#            # fix for the first segment
#            if p.isclosed():
#                new_p[0] = p[0].cropped(ts[1], self._very_first_t)

#            new_p.append(segs[0].cropped(ts[0], 1.0))
#            new_p.append(segs[1].cropped(0.0, ts[1]))
#            if self.options.fillet_type == 'fillet':
#                fillet = svgpathtools.CubicBezier(cb[0], cb[0]+cb[1], cb[2]-cb[3], cb[2])
#            else:
#                fillet = svgpathtools.Line(cb[0], cb[2])
#            new_p.append(fillet.reversed())

        return new_p
Example #9
0
def offset_paths(path, offset_distance, steps=100, debug=False):
    """Takes an svgpathtools.path.Path object, `path`, and a float
    distance, `offset_distance`, and returns the parallel offset curves
    (in the form of a list of svgpathtools.path.Path objects)."""


    def is_enclosed(path, check_paths):

        """`path` is an svgpathtools.path.Path object, `check_paths`
        is a list of svgpath.path.Path objects.  This function returns
        True if `path` lies inside any of the paths in `check_paths`,
        and returns False if it lies outside all of them."""

        seg = path[0]
        point = seg.point(0.5)

        for i in range(len(check_paths)):
            test_path = check_paths[i]
            if path == test_path:
                continue
            # find outside_point, which lies outside other_path
            (xmin, xmax, ymin, ymax) = test_path.bbox()
            outside_point = complex(xmax+100, ymax+100)
            if svgpathtools.path_encloses_pt(point, outside_point, test_path):
                if debug: print("point is within path", i, file=sys.stderr)
                return True
        return False


    # This only works on closed paths.
    if debug: print("input path:", file=sys.stderr)
    if debug: print(path, file=sys.stderr)
    if debug: print("offset:", offset_distance, file=sys.stderr)
    assert(path.isclosed())


    #
    # First generate a list of Path elements (Lines and Arcs),
    # corresponding to the offset versions of the Path elements in the
    # input path.
    #

    if debug: print("generating offset segments...", file=sys.stderr)

    offset_path_list = []
    for seg in path:
        if type(seg) == svgpathtools.path.Line:
            start = seg.point(0) + (offset_distance * seg.normal(0))
            end = seg.point(1) + (offset_distance * seg.normal(1))
            offset_path_list.append(svgpathtools.Line(start, end))
            if debug: print("    ", offset_path_list[-1], file=sys.stderr)

        elif type(seg) == svgpathtools.path.Arc and (seg.radius.real == seg.radius.imag):
            # Circular arcs remain arcs, elliptical arcs become linear
            # approximations below.
            #
            # Polygons (input paths) are counter-clockwise.
            #
            # Positive offsets are to the inside of the polygon, negative
            # offsets are to the outside.
            #
            # If this arc is counter-clockwise (sweep == False),
            # *subtract* the `offset_distance` from its radius, so
            # insetting makes the arc smaller and outsetting makes
            # it larger.
            #
            # If this arc is clockwise (sweep == True), *add* the
            # `offset_distance` from its radius, so insetting makes the
            # arc larger and outsetting makes it smaller.
            #
            # If the radius of the offset arc is negative, use its
            # absolute value and invert the sweep.

            if seg.sweep == False:
                new_radius = seg.radius.real - offset_distance
            else:
                new_radius = seg.radius.real + offset_distance

            start = seg.point(0) + (offset_distance * seg.normal(0))
            end = seg.point(1) + (offset_distance * seg.normal(1))
            sweep = seg.sweep

            flipped = False
            if new_radius < 0.0:
                if debug: print("    inverting Arc!", file=sys.stderr)
                flipped = True
                new_radius = abs(new_radius)
                sweep = not sweep

            if new_radius > 0.002:
                radius = complex(new_radius, new_radius)
                offset_arc = svgpathtools.path.Arc(
                    start = start,
                    end = end,
                    radius = radius,
                    rotation = seg.rotation,
                    large_arc = seg.large_arc,
                    sweep = sweep
                )
                offset_path_list.append(offset_arc)
            elif new_radius > epsilon:
                # Offset Arc radius is smaller than the minimum that
                # LinuxCNC accepts, replace with a Line.
                if debug: print("    arc too small, replacing with a line", file=sys.stderr)
                if flipped:
                    old_start = start
                    start = end
                    end = old_start
                offset_arc = svgpathtools.path.Line(start = start, end = end)
                offset_path_list.append(offset_arc)
            else:
                # Zero-radius Arc, it disappeared.
                if debug: print("    arc way too small, removing", file=sys.stderr)
                continue
            if debug: print("    ", offset_path_list[-1], file=sys.stderr)

        else:
            # Deal with any segment that's not a line or a circular arc.
            # This includes elliptic arcs and bezier curves.  Use linear
            # approximation.
            #
            # FIXME: Steps should probably be computed dynamically to make
            #     the length of the *offset* line segments manageable.
            points = []
            for k in range(steps+1):
                t = k / float(steps)
                normal = seg.normal(t)
                offset_vector = offset_distance * normal
                points.append(seg.point(t) + offset_vector)
            for k in range(len(points)-1):
                start = points[k]
                end = points[k+1]
                offset_path_list.append(svgpathtools.Line(start, end))
            if debug: print("    (long list of short lines)", file=sys.stderr)


    #
    # Find all the places where one segment intersects the next, and
    # trim to the intersection.
    #

    if debug: print("trimming intersecting segments...", file=sys.stderr)

    for i in range(len(offset_path_list)):
        this_seg = offset_path_list[i]
        if (i+1) < len(offset_path_list):
            next_seg = offset_path_list[i+1]
        else:
            next_seg = offset_path_list[0]

        # FIXME: I'm not sure about this part.
        if debug: print("intersecting", file=sys.stderr)
        if debug: print("    this", this_seg, file=sys.stderr)
        if debug: print("    next", next_seg, file=sys.stderr)
        intersections = this_seg.intersect(next_seg)
        if debug: print("    intersections:", intersections, file=sys.stderr)
        if len(intersections) > 0:
            intersection = intersections[0]
            point = this_seg.point(intersection[0])
            if debug: print("    intersection point:", point, file=sys.stderr)
            if not complex_close_enough(point, this_seg.end):
                this_seg.end = this_seg.point(intersection[0])
                next_seg.start = this_seg.end


    #
    # Find all the places where adjacent segments do not end/start close
    # to each other, and join them with Arcs.
    #

    if debug: print("joining non-connecting segments with arcs...", file=sys.stderr)

    joined_offset_path_list = []
    for i in range(len(offset_path_list)):
        this_seg = offset_path_list[i]
        if (i+1) < len(offset_path_list):
            next_seg = offset_path_list[i+1]
        else:
            next_seg = offset_path_list[0]

        if complex_close_enough(this_seg.end, next_seg.start):
            joined_offset_path_list.append(this_seg)
            continue

        if debug: print("these segments don't touch end to end:", file=sys.stderr)
        if debug: print(this_seg, file=sys.stderr)
        if debug: print(next_seg, file=sys.stderr)
        if debug: print("    error:", this_seg.end-next_seg.start, file=sys.stderr)

        # FIXME: Choose values for `large_arc` and `sweep` correctly here.
        # I think the goal is to make the joining arc tangent to the segments it joins.
        # large_arc should always be False
        # sweep means "clockwise" (but +Y is down)
        if debug: print("determining joining arc:", file=sys.stderr)
        if debug: print("    this_seg ending normal:", this_seg.normal(1), file=sys.stderr)
        if debug: print("    next_seg starting normal:", next_seg.normal(0), file=sys.stderr)

        sweep_arc = svgpathtools.path.Arc(
            start = this_seg.end,
            end = next_seg.start,
            radius = complex(offset_distance, offset_distance),
            rotation = 0,
            large_arc = False,
            sweep = True
        )
        sweep_start_error = this_seg.normal(1) - sweep_arc.normal(0)
        sweep_end_error = next_seg.normal(0) - sweep_arc.normal(1)
        sweep_error = pow(abs(sweep_start_error), 2) + pow(abs(sweep_end_error), 2)
        if debug: print("    sweep arc starting normal:", sweep_arc.normal(0), file=sys.stderr)
        if debug: print("    sweep arc ending normal:", sweep_arc.normal(1), file=sys.stderr)
        if debug: print("    sweep starting error:", sweep_start_error, file=sys.stderr)
        if debug: print("    sweep end error:", sweep_end_error, file=sys.stderr)
        if debug: print("    sweep error:", sweep_error, file=sys.stderr)

        antisweep_arc = svgpathtools.path.Arc(
            start = this_seg.end,
            end = next_seg.start,
            radius = complex(offset_distance, offset_distance),
            rotation = 0,
            large_arc = False,
            sweep = False
        )
        antisweep_start_error = this_seg.normal(1) - antisweep_arc.normal(0)
        antisweep_end_error = next_seg.normal(0) - antisweep_arc.normal(1)
        antisweep_error = pow(abs(antisweep_start_error), 2) + pow(abs(antisweep_end_error), 2)
        if debug: print("    antisweep arc starting normal:", antisweep_arc.normal(0), file=sys.stderr)
        if debug: print("    antisweep arc ending normal:", antisweep_arc.normal(1), file=sys.stderr)
        if debug: print("    antisweep starting error:", antisweep_start_error, file=sys.stderr)
        if debug: print("    antisweep end error:", antisweep_end_error, file=sys.stderr)
        if debug: print("    antisweep error:", antisweep_error, file=sys.stderr)

        joining_arc = None
        if sweep_error < antisweep_error:
            if debug: print("joining arc is sweep", file=sys.stderr)
            joining_arc = sweep_arc
        else:
            if debug: print("joining arc is antisweep", file=sys.stderr)
            joining_arc = antisweep_arc

        if debug: print("joining arc:", file=sys.stderr)
        if debug: print(joining_arc, file=sys.stderr)
        if debug: print("    length:", joining_arc.length(), file=sys.stderr)
        if debug: print("    start-end distance:", joining_arc.start-joining_arc.end, file=sys.stderr)

        # FIXME: this is kind of arbitrary
        joining_seg = joining_arc
        if joining_arc.length() < 1e-4:
            joining_seg = svgpathtools.path.Line(joining_arc.start, joining_arc.end)
            if debug: print("    too short!  replacing with a line:", joining_seg, file=sys.stderr)

        joined_offset_path_list.append(this_seg)
        joined_offset_path_list.append(joining_seg)

    offset_path_list = joined_offset_path_list


    #
    # Find the places where the path intersects itself, split into
    # multiple separate paths in those places.
    #

    if debug: print("splitting path at intersections...", file=sys.stderr)

    offset_paths_list = split_path_at_intersections(offset_path_list)


    #
    # Smooth the path: adjacent segments whose start/end points are
    # "close enough" to each other are adjusted so they actually touch.
    #
    # FIXME: is this still needed?
    #

    if debug: print("smoothing paths...", file=sys.stderr)

    for path_list in offset_paths_list:
        for i in range(len(path_list)):
            this_seg = path_list[i]
            if (i+1) < len(path_list):
                next_seg = path_list[i+1]
            else:
                next_seg = path_list[0]
            if complex_close_enough(this_seg.end, next_seg.start):
                next_seg.start = this_seg.end
            else:
                if debug: print("gap in the path (seg %d and following):" % i, file=sys.stderr)
                if debug: print("    this_seg.end:", this_seg.end, file=sys.stderr)
                if debug: print("    next_seg.start:", next_seg.start, file=sys.stderr)


    #
    # Convert each path list to a Path object and sanity check.
    #

    if debug: print("converting path lists to paths...", file=sys.stderr)

    offset_paths = []
    for path_list in offset_paths_list:
        offset_path = svgpathtools.Path(*path_list)
        if debug: print("offset path:", file=sys.stderr)
        if debug: print(offset_path, file=sys.stderr)
        assert(offset_path.isclosed())
        offset_paths.append(offset_path)


    #
    # The set of paths we got from split_path_at_intersections() has
    # zero or more 'true paths' that we actually want to return, plus
    # zero or more 'false paths' that should be discarded.
    #
    # When offsetting a path to the inside, the false paths will be
    # outside the true path and will wind in the opposite direction of
    # the input path.
    #
    # When offsetting a path to the outside, the false paths will be
    # inside the true paths, and will wind in the same direction as the
    # input path.
    #
    # [citation needed]
    #

    if debug: print("pruning false paths...", file=sys.stderr)

    path_area = approximate_path_area(path)
    if debug: print("input path area:", path_area, file=sys.stderr)

    keepers = []

    if offset_distance > 0:
        # The offset is positive (inwards), discard paths with opposite
        # direction from input path.
        for offset_path in offset_paths:
            if debug: print("checking path:", offset_path, file=sys.stderr)
            offset_path_area = approximate_path_area(offset_path)
            if debug: print("offset path area:", offset_path_area, file=sys.stderr)
            if path_area * offset_path_area < 0.0:
                # Input path and offset path go in the opposite directions,
                # drop offset path.
                if debug: print("wrong direction, dropping", file=sys.stderr)
                continue
            keepers.append(offset_path)

    else:
        # The offset is negative (outwards), discard paths that lie
        # inside any other path and have the same winding direction as
        # the input path.
        for offset_path in offset_paths:
            if debug: print("checking path:", offset_path, file=sys.stderr)
            if is_enclosed(offset_path, offset_paths):
                if debug: print("    enclosed", file=sys.stderr)
                # This path is enclosed, check the winding direction.
                offset_path_area = approximate_path_area(offset_path)
                if debug: print("offset path area:", offset_path_area, file=sys.stderr)
                if path_area * offset_path_area > 0.0:
                    if debug: print("    winding is the same as input, dropping", file=sys.stderr)
                    continue
                else:
                    if debug: print("    winding is opposite input", file=sys.stderr)
            else:
                if debug: print("    not enclosed", file=sys.stderr)
            if debug: print("    keeping", file=sys.stderr)
            keepers.append(offset_path)

    offset_paths = keepers

    return offset_paths
Example #10
0
def extract_lines(filepath, page_dir):
    doc = svgpathtools.Document(filepath)
    content_group = doc.get_group([None, "content"])

    # bounds are in the format (xmin, xmax, ymin, ymax)
    page_bounds = doc.paths_from_group(content_group)[0].bbox()

    line_height = (page_bounds[3] - page_bounds[2]) / 15

    lines = {}
    debug_lines = {}
    debug_nodes = {}
    for line_number in range(1, 16):
        lines[line_number] = svgpathtools.Path()
        debug_lines[line_number] = svgpathtools.Path()
        debug_nodes[line_number] = []

    full_path = svgpathtools.Path()
    for doc_path in doc.paths():
        for sub_path in doc_path:
            full_path.append(sub_path)

    indeterminate_paths = []
    for _path in full_path.d().split("M"):
        if len(_path.strip()) > 0:
            glyph_path = svgpathtools.parse_path(f"M{_path}")
            line_number = detect_line_number(glyph_path.bbox(), page_bounds[2],
                                             line_height)
            if line_number:
                for path_command in glyph_path:
                    lines[line_number].append(path_command)
            else:
                indeterminate_paths.append(glyph_path)

    indeterminate_paths = [
        indeterminate_path_info(p, page_bounds[2], line_height)
        for p in indeterminate_paths
    ]
    indeterminate_num = len(indeterminate_paths)
    print(f"Found {indeterminate_num} indeterminate paths")

    indeterminate_paths.sort(key=lambda x: x[2])

    for i, indeterminate_path in enumerate(indeterminate_paths):
        start_time = time.time()
        determination = detect_indeterminate_line(indeterminate_path, lines)
        if determination[0]:
            if determination[1]:
                debug_nodes[determination[0]].append(determination[1])
            for path_command in indeterminate_path[0]:
                lines[determination[0]].append(path_command)
                debug_lines[determination[0]].append(path_command)
        print(
            f"Completed {i+1}/{indeterminate_num} path determations in {time.time() - start_time:.2} seconds"
        )

    attribs = {"fill": "#000000", "fill-rule": "evenodd"}

    debug_attribs = {
        "stroke": "#FF0000",
        "stroke-width": "0.5",
        "fill-opacity": "0"
    }

    svg_attribs = {
        "xml:space": "preserve",
        "viewBox": "0 0 345 50",
        "width": "",
        "height": ""
    }

    for svg_line in lines.items():
        if len(svg_line[1]) == 0:
            continue

        line_number = svg_line[0]
        y_pos = floor(svg_line[1].bbox()[2])
        svg_attribs["viewBox"] = f"0 {y_pos} 345 50"
        filename = path.join(page_dir, f"{line_number}.svg")

        _paths = [svg_line[1]]
        _attribs = [attribs]
        _nodes = []
        if debug_mode:
            _nodes = debug_nodes[line_number]
            if len(debug_lines[line_number]) > 0:
                _paths.append(debug_lines[line_number])
                _attribs.append(debug_attribs)

        svgpathtools.wsvg(_paths,
                          filename=filename,
                          attributes=_attribs,
                          svg_attributes=svg_attribs,
                          nodes=_nodes)

    if debug_mode:
        filename = path.join(page_dir, "debug.svg")
        debug_paths = [full_path]
        svg_attribs["viewBox"] = "0 0 345 550"
        _attribs = [attribs]
        for line in range(1, 16):
            debug_paths.append(
                debug_overlay_path(page_bounds[2], line_height, line))
            _attribs.append(debug_attribs)

        svgpathtools.wsvg(
            debug_paths,
            filename=filename,
            attributes=_attribs,
            svg_attributes=svg_attribs,
        )
Example #11
0
def circle (r) :
    arcs = []
    arcs.append(svg.Arc(-r + 0j, r + r * 1j, 0, False, False, r + 0j))
    arcs.append(svg.Arc(-r + 0j, r + r * 1j, 0, False, True, r + 0j))
    return svg.Path(*arcs)