Ejemplo n.º 1
0
def get_paths(file_path):
    doc = Document(file_path)
    paths = doc.paths()
    paths = [
        path for path in paths if path.length() > args.threshold_path_length
    ]
    return paths
Ejemplo n.º 2
0
def svgpathtools_flatten(stage_svg):
    # TODO: perhaps use this instead of inkscapes's deep ungroup?
    from svgpathtools import Document

    doc = Document(str(stage_svg))
    results = doc.flatten_all_paths()
    for result in results:
        # TODO: save result.path to new SVG document
        # and overwrite stage_svg?
        pass
    def _create_from_svg(cls, filepath, height_mm):
        assert isinstance(filepath, pathlib.Path)
        if not filepath.is_file():
            raise IOError(
                "Unable to create Face from image file: {}. File does not exist"
                .format(filepath))

        # Load as a document rather than as paths directly (using svg2paths) because
        # the document respects any transforms
        doc = Document(str(filepath))
        paths = doc.paths()
        continuous_paths = cls._get_continuous_subpaths(paths)
        continuous_paths = cls._remove_zero_length_lines(continuous_paths)

        ymin = min([path.bbox()[2] for path in continuous_paths])
        ymax = max([path.bbox()[3] for path in continuous_paths])
        current_height = ymax - ymin
        assert current_height >= 0
        scaling_factor = height_mm / current_height
        scaled_paths = [
            path.scaled(scaling_factor, -scaling_factor)
            for path in continuous_paths
        ]

        # Line up to the x and y axes
        xmin = min([path.bbox()[0] for path in scaled_paths])
        ymin = min([path.bbox()[2] for path in scaled_paths])
        translated_paths = [
            path.translated(complex(-xmin, -ymin)) for path in scaled_paths
        ]

        normalized_paths = cls._normalize_paths_clockwise(translated_paths)
        path_hierarchies = cls._create_path_hierarchy(normalized_paths)
        # Currently only really support a single main contiguous shape with holes.
        # Although multiple disconnected shapes can be generated, they won't be
        # perfectly represented by the final geometry because some material has to
        # connect them
        assert len(path_hierarchies) == 1

        faceMaker = BRepBuilderAPI_MakeFace(PL_XZ)
        for path_hierarchy in path_hierarchies:
            root_edges = cls._create_edges_from_path(
                path_hierarchy.root_path())
            root_wire = cls._create_wire_from_edges(root_edges)
            faceMaker.Add(root_wire)
            for sub_path in path_hierarchy.child_paths():
                sub_path_edges = cls._create_edges_from_path(sub_path)
                sub_path_wire = cls._create_wire_from_edges(sub_path_edges)
                # reverse the wire so it creates a hole
                sub_path_wire.Reverse()
                faceMaker.Add(sub_path_wire)
        return faceMaker.Shape()
Ejemplo n.º 4
0
Archivo: read.py Proyecto: zoso95/vpype
def read(file, quantization: float) -> LineCollection:
    """
    Extract geometries from a SVG file.

    This command only extracts path elements as well as primitives (rectangles, ellipses,
    lines, polylines, polygons). In particular, text and bitmap images are discarded, as well
    as all formatting.

    All curved primitives (e.g. bezier path, ellipses, etc.) are linearized and approximated
    by polylines. The quantization length controls the maximum length of individual segments
    (1mm by default).
    """

    doc = Document(file)
    results = doc.flatten_all_paths()
    root = doc.tree.getroot()

    # we must interpret correctly the viewBox, width and height attribs in order to scale
    # the file content to proper pixels

    if "viewBox" in root.attrib:
        # A view box is defined so we must correctly scale from user coordinates
        # https://css-tricks.com/scale-svg/
        # TODO: we should honor the `preserveAspectRatio` attribute

        viewbox_min_x, viewbox_min_y, viewbox_width, viewbox_height = [
            float(s) for s in root.attrib["viewBox"].split()
        ]

        w = convert(root.attrib.get("width", viewbox_width))
        h = convert(root.attrib.get("height", viewbox_height))

        scale_x = w / viewbox_width
        scale_y = h / viewbox_height
        offset_x = -viewbox_min_x
        offset_y = -viewbox_min_y
    else:
        scale_x = 1
        scale_y = 1
        offset_x = 0
        offset_y = 0

    lc = LineCollection()
    for result in results:
        for elem in result.path:
            if isinstance(elem, Line):
                coords = np.array([elem.start, elem.end])
            else:
                # This is a curved element that we approximate with small segments
                step = int(math.ceil(elem.length() / quantization))
                coords = np.empty(step + 1, dtype=complex)
                coords[0] = elem.start
                for i in range(step - 1):
                    coords[i + 1] = elem.point((i + 1) / step)
                coords[-1] = elem.end

            # transform
            coords += offset_x + 1j * offset_y
            coords.real *= scale_x
            coords.imag *= scale_y

            lc.append(coords)

    return lc
def arc_length_statistics(path_to_svg):
    '''
    Given:
        path_to_svg: A path to an SVG file.
    
    Normalizes by the svg's long edge as defined by its viewBox.
    
    Ignores <svg> width or height attributes.
    '''
    flatpaths = None
    paths = None
    try:
        doc = Document(path_to_svg)
        flatpaths = doc.flatten_all_paths()
    except:
        paths, _ = svg2paths(path_to_svg)
        flatpaths = paths

    ## Absolute distances
    lengths = []
    for path in flatpaths:
        total_path_length = 0.
        last_pt = None
        # if this is get by flatten_all_paths, then we just need to get the first item
        if paths == None:
            path = path[0]
        for seg in path:
            ## Make sure this segment is connected to the previous one.
            ## If not, start a new one.
            ## I checked and it doesn't look like svgpathtools tells us when a Move
            ## command happens, so we have to figure it out.
            if not (last_pt is None or allclose(last_pt, seg.point(0))):
                lengths.append(total_path_length)
                total_path_length = 0.

            ## Add the current segment to the running tally.
            total_path_length += seg.length()
            last_pt = seg.point(1)

        lengths.append(total_path_length)

    ## Divide by long edge.
    if 'viewBox' in doc.root.attrib:
        import re
        _, _, width, height = [
            float(v)
            for v in re.split('[ ,]+', doc.root.attrib['viewBox'].strip())
        ]
        long_edge = max(width, height)
        print("Normalizing by long edge:", long_edge)
        lengths = [l / long_edge for l in lengths]
    elif "width" in doc.root.attrib and "height" in doc.root.attrib:
        width = doc.root.attrib["width"].strip().strip("px")
        height = doc.root.attrib["height"].strip().strip("px")
        long_edge = max(float(width), float(height))
        print("Normalizing by long edge:", long_edge)
        lengths = [l / long_edge for l in lengths]
    else:
        print(
            "WARNING: No viewBox found in <svg>. Not normalizing by long edge."
        )
    print("Done")
    return lengths