def setUpClass(cls):
        """Initialize test cases for Quadratic Bezier class."""
        cls.name = 'quadractic_bezier'

        # Initialize nominal cases for Quadratic Bezier class
        cls.paths = [
            parse_path("m  25, 47 q 17,  -7  6,  20"),
            parse_path("m  48, 68 q 14  -57 26,   0"),
            parse_path("m  85, 59 q 14,  57 26,   0"),
            parse_path("m 128, 64 q 14,  17 25, -18"),
            parse_path("m 128, 64 q 14,  17 25, -18"),
            parse_path("m  81, 29 q 14, -17 25,  18"),
        ]

        # Initialize edge cases for Quadratic Bezier class
        cls.edge_paths = [
            parse_path("m 80, 20 q 10,10 -10, 20"),
            # parse_path("m 80, 20 q  0, 0   0,  0"),  # Single point
            # parse_path("m 80, 20 q 10, 0  20,  0"),  # Straight line
            parse_path("m 80, 20 q 10,10   0, 20"),
        ]
        # ym_list for specific yms
        cls.ym_list = [None, 50, 80, None, None, None, None, None]

        # visual control all correct
        cls.results.update({
            "quadractic_bezier_1": [2, 1, 1, [[(34.25259515570934 + 46.99999999999999j)], [], [(34.425982139631 + 57j)]]],
            "quadractic_bezier_2": [2, 2, 2, [[(74 + 68j)], [(48 + 68j)], [(69.2064901963537 + 50j), (53.42508875101472 + 49.99999999999999j)]]],
            "quadractic_bezier_3": [2, 2, 2, [[(111 + 59j)], [(85 + 59j)], [(105.03728034118508 + 80j), (91.69956176407807 + 80j)]]],
            "quadractic_bezier_4": [2, 1, 1, [[(145.0251479289941 + 64j)], [], [(149.7705100077186 + 55j)]]],
            "quadractic_bezier_5": [2, 1, 1, [[(145.0251479289941 + 64j)], [], [(149.7705100077186 + 55j)]]],
            "quadractic_bezier_6": [2, 1, 1, [[(98.02514792899407 + 29j)], [], [(102.77051000771863 + 38j)]]],
            "quadractic_bezier_7": [1, 1, 1, [[], [], [(82.5 + 30j)]]],
            "quadractic_bezier_8": [1, 1, 1, [[], [], [(85 + 30j)]]],
        })
    def setUpClass(cls):
        """Initialize test cases for Arc class."""
        # configure_pathPoint_class()
        cls.name = 'arc'

        # Initialize  cases for Arc class
        for flag in ['0 0', '0 1', '1 0', '1 1']:
            cls.paths.extend([
                parse_path(f"M  50, 200 a 100, 50   0 {flag} 250,50"),
                parse_path(f"M 400, 100 a 100, 50  30 {flag} 250,50"),
                parse_path(f"M 400, 300 a 100, 50  45 {flag} 22,244"),
                parse_path(f"M 750, 200 a 100, 50 135 {flag} 22,244"),
                parse_path(f"M 750, 300 a 100, 50 220 {flag} 22,244"),
                parse_path(f"M 950, 100 a 100, 50 310 {flag} 22,244"),
            ])

        # Initialize edge cases for Arc class
        cls.edge_paths.extend([
            parse_path("M 400  200 a100 50, 0,  0, 0, 0 250"),
            parse_path("M 50 200 a100 50, 0,  0, 1, 0 250"),
            parse_path("M 400 200 a100 50, 90, 0, 0, 0 250"),
        ])
        # visual control of results show that most results are wrong if the arc has a rotation
        cls.results.update({
            "i1_arc_0_0_0": [1, 2, 1, [[], [(49.99999999999997 + 249.99999999999997j)], [(40.3708798216374 + 225j)]]],
            "i2_arc_30_0_0": [1, 2, 1, [[], [(437.1153753760908 + 149.9999999999999j)], []]],
            "i3_arc_45_0_0": [2, 1, 1, [[], [(275.59999999999997 + 300j)], [(295.26495776991305 + 421.999999999)]]],
            "i4_arc_135_0_0": [1, 2, 1, [[], [(603.5999999999999 + 443.9999999999994j)], [(632.0992629966765 + 321.9999999999999j)]]],
            "i5_arc_220_0_0": [2, 1, 1, [[(611.0555150486008 + 300j)], [], [(631.783782028338 + 421.9999999999999j)]]],
            "i6_arc_310_0_0": [1, 2, 1, [[], [(819.4282706707221 + 344.0000000000003j)], [(844.2419419089059 + 222.00000000000006j)]]],
            "i7_arc_0_0_1": [2, 1, 1, [[(300 + 200j)], [], [(309.6291201783626 + 225j)]]],
            "i8_arc_30_0_1": [2, 1, 1, [[(612.8846246239091 + 99.99999999999994j)], [], [(635.2102190245106 + 124.99999999999997j)]]],


            "i9_arc_45_0_1": [1, 2, 1, [[], [(546.3999999999999 + 544.0000000000002j)], [(526.735042230087 + 421.99999999999994j)]]],
            "i10_arc_135_0_1": [2, 1, 1, [[(918.4000000000001 + 200.00000000000034j)], [], [(889.9007370033237 + 321.99999999999994j), ]]],
            "i11_arc_220_0_1": [1, 2, 1, [[], [(910.9444849513991 + 544.0000000000001j)], [(890.2162179716619 + 421.99999999999994j), (631.783782028338 + 421.9999999999999j)]]],
            "i12_arc_310_0_1": [2, 1, 1, [[(1102.5717293292782 + 100.00000000000063j)], [(819.4282706707221 + 344.0000000000003j)], [(1077.758058091094 + 222.00000000000006j)]]],
            "i13_arc_0_1_0": [1, 2, 1, [[], [(49.99999999999997 + 249.99999999999997j)], [(40.3708798216374 + 225j)]]],
            "i14_arc_30_1_0": [1, 2, 1, [[], [(437.11537351971816 + 150.00000000000006j)], [(414.789780047303 + 124.99999999999993j)]]],
            "i15_arc_45_1_0": [2, 1, 1, [[(275.59999999999997 + 300j)], [], [(295.26495776991305 + 421.9999999999999j)]]],
            "i16_arc_135_1_0": [1, 2, 1, [[], [(603.5999999999999 + 443.9999999999994j)], [(632.0992629966765 + 321.9999999999999j)]]],
            "i17_arc_220_1_0": [2, 1, 1, [[(611.0555150486008 + 300j)], [], [(631.783782028338 + 421.9999999999999j)]]],
            "i18_arc_310_1_0": [1, 2, 1, [[], [(819.4282706707221 + 344.0000000000003j)], [(844.2419419089059 + 222.00000000000006j)]]],
            "i19_arc_0_1_1": [2, 1, 1, [[(300 + 200j)], [], [(309.6291201783626 + 225j)]]],
            "i20_arc_30_1_1": [2, 1, 1, [[(612.8846264802819 + 99.99999999999996j)], [], [(635.2102199526969 + 124.99999999999991j)]]],
            "i21_arc_45_1_1": [1, 2, 1, [[], [(546.3999999999999 + 544.0000000000002j)], [(526.735042230087 + 421.99999999999994j)]]],
            "i22_arc_135_1_1": [2, 1, 1, [[(918.4000000000001 + 200.00000000000034j)], [], [(889.9007370033237 + 321.99999999999994j)]]],
            "i23_arc_220_1_1": [1, 2, 1, [[], [(910.9444849513991 + 544.0000000000001j)], [(890.2162179716619 + 421.99999999999994j)]]],
            "i24_arc_310_1_1": [2, 1, 1, [[(1102.5717293292782 + 100.00000000000063j)], [], [(1077.758058091094 + 222.00000000000006j)]]],
            "i25_arc_0_0_0": [1, 1, 1, [[], [], [(150 + 325j)]]],
            "i26_arc_0_0_1": [1, 1, 1, [[], [], [(300 + 325j)]]],
            "i27_arc_90_0_0": [1, 1, 1, [[], [], [(337.5 + 325j)]]],
        })
Esempio n. 3
0
def extractStrokes(path):
    bezpath = parse_path(path)
    n = 100
    ptpath = [bezpath.point(t) for t in np.linspace(0, 1, n)]
    return [((ptpath[i % n].real, ptpath[i % n].imag),
             (ptpath[(i + 1) % n].real, ptpath[(i + 1) % n].imag))
            for i in range(n)]
Esempio n. 4
0
File: panel.py Progetto: wlaub/vcv
    def __init__(self, node, layer):
        """
        self.kind from the path label describes the type of control
        self._id from the path id is the enum name excluding _PARAM/INPUT/etc
        self.widget from the path title is the widget class name
        self.config is a python variable in the path description (dict)
        self.pos is [x,y] location of the center of the control
        """
        self.kind = self.enum_kind_map[self.kind_map[layer.lower()]]

        self._id = node.get('id').upper()
        d = node.get('d')

        self.enum_base = None
        self.enum_idx = None
        self.enum_count = None

        self.path = parse_path(d)

        bbox = self.path.bbox()
        self.pos = [(bbox[i * 2] + bbox[i * 2 + 1]) / 2 for i in range(2)]

        self.widget = None
        self.config = {}
        for subnode in node.getchildren():
            if Control.is_title(subnode):
                self.widget = subnode.text
            elif Control.is_desc(subnode):
                try:
                    self.config = ast.literal_eval(subnode.text)
                except:
                    print(f'Failed to load for {self._id} from {subnode.text}')
                    raise
    def setUpClass(cls):
        """Initialize test cases for Cubic Bezier class."""
        cls.name = 'cubic_bezier'

        # Initialize nominal cases for Cubic Bezier class
        cls.paths = [
            parse_path("m  10, 110 c  46,-16  21,  22  5,  24"),
            parse_path("m  70, 134 c  15,  7  51, -18 29, -32"),
            parse_path("m 139, 100 c  26,-15  18,  33  8,  44"),
            parse_path("m  35, 151 c  15, -7  51,  18 29,  32"),
            parse_path("m 133, 154 c -46,-16 -21,  22 -5,  24"),
        ]

        # Initialize edge cases for Cubic Bezier class
        cls.edge_paths = [
            parse_path("m 139, 100 c 26, 5 18, 33  8, 44"),
            parse_path("m  35, 151 c 15, 0 51, 18 29, 32"),
            # parse_path("m  80,  20 c 10, 0 20,  0 30,  0"), this is a line
        ]
        # visual control cubic_bezier_1 and cubic_bezier_5 and cubic_bezier_7 are missing one cutpoint at the end
        cls.results.update({
            "cubic_bezier_1": [2, 1, 1, [[(36.003610559732806 + 110j)], [], [(32.078141538112355 + 122.00000000000001j)]]],
            "cubic_bezier_2": [2, 1, 1, [[(83.69506360982835 + 134j)], [], [(104.62766766084235 + 118j)]]],
            "cubic_bezier_3": [2, 1, 1, [[(153.52855800284362 + 100j)], [], [(155.59972699011112 + 121.99999999999997j)]]],
            "cubic_bezier_4": [2, 1, 1, [[(48.69506360982835 + 151j)], [], [(69.62766766084235 + 167j)]]],
            "cubic_bezier_5": [2, 1, 1, [[(106.9963894402672 + 154j)], [], [(110.92185846188764 + 166j)]]],
            "cubic_bezier_6": [1, 1, 1, [[], [], [(156.4095736229877 + 122j)]]],
            "cubic_bezier_7": [1, 1, 1, [[], [], [(68.65030968920104 + 167j)]]],
        })
    def setUpClass(cls):
        """Initialize test cases for Quadratic Bezier class."""
        cls.name = 'quadractic_bezier'

        # Initialize nominal cases for Quadratic Bezier class
        cls.paths = [
            parse_path("m  25, 47 q 17,  -7  6,  20"),
            parse_path("m  48, 68 q 14  -17 26,   0"),
            parse_path("m  85, 59 q 14,  17 26,   0"),
            parse_path("m 128, 64 q 14,  17 25, -18"),
            parse_path("m 128, 64 q 14,  17 25, -18"),
            parse_path("m  81, 29 q 14, -17 25,  18"),
        ]

        # Initialize edge cases for Quadratic Bezier class
        cls.edge_paths = [
            parse_path("m 80, 20 q 10,10 -10, 20"),
            parse_path("m 80, 20 q  0, 0   0,  0"),  # Single point
            parse_path("m 80, 20 q 10, 0  20,  0"),  # Straight line
            parse_path("m 80, 20 q 10,10   0, 20"),
        ]
def process_paths(path_groups):
    """
    Extracts pose and region annotations represented as paths

    :param path_groups: a list of groups each containing a text element and a path
    :return: a tuple of poses and regions
    """
    if len(path_groups) == 0:
        return [], []

    regions = []
    poses = []
    for group in path_groups:
        if len(list(group)) != 2:
            # May want to print a warning here
            continue

        # We assume that the text was created in inkscape so the string will be in a tspan
        path, text = group.find(
            ".//{}".format(path_el)), get_text_from_group(group)
        if text is None:
            warn("No text label found for path group: {}".format(group))
            continue
        name = text

        transform = get_transform(group)

        # Single line segment path => pose
        try:
            pose = extract_line_from_path(path, transform)
            poses.append(tuple([name] + list(pose)))
            continue
        except RuntimeError:
            pass

        # SVG paths are specified in a rich language of segment commands:
        # https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
        # We'll use a new dependency to extract what we can
        path_geom = parse_path(path.attrib["d"])
        # If they're all lines, let's assume it's closed and use it as a region
        if all(map(is_line, path_geom)):
            # Real part => x, imag part => y
            lines = map(
                lambda l: ((l.start.real, l.start.imag),
                           (l.end.real, l.end.imag)), path_geom)
            # Each line segment starts where the previous ended, so we can drop the end points
            points = map(lambda l: l[0], lines)
            points = map(lambda p: (float_s3(p[0]), float_s3(p[1])), points)
            points = map(lambda p: apply_transform(p, transform), points)
            regions.append((name, points))
        else:
            warn("Encountered path that couldn't be parsed {}".format(name))
    return poses, regions
    def setUpClass(cls):
        """Initialize test cases for Arc class."""
        #        configure_pathPoint_class()
        cls.name = 'arc'

        # Initialize nominal cases for Arc class
        for flag in ['0 0', '0 1', '1 0', '1 1']:
            cls.paths.extend([
                parse_path(f"M  50, 200 a 100, 50   0 {flag} 250,50"),
                parse_path(f"M 400, 100 a 100, 50  30 {flag} 250,50"),
                parse_path(f"M 400, 300 a 100, 50  45 {flag} 22,244"),
                parse_path(f"M 750, 200 a 100, 50 135 {flag} 22,244"),
                parse_path(f"M 750, 300 a 100, 50 220 {flag} 22,244"),
                parse_path(f"M 950, 100 a 100, 50 310 {flag} 22,244"),
            ])

        # Initialize edge cases for Arc class
        cls.edge_paths.extend([
            parse_path("M 50 200 a100 50, 0,  0, 0, 0 250"),
            parse_path("M 50 200 a100 50, 0,  0, 1, 0 250"),
            parse_path("M 50 200 a100 50, 90, 0, 0, 0 250"),
        ])
    def setUpClass(cls):
        """Initialize test cases for Cubic Bezier class."""
        cls.name = 'cubic_bezier'

        # Initialize nominal cases for Cubic Bezier class
        cls.paths = [
            parse_path("m  10, 110 c  46,-16  21,  22  5,  24"),
            parse_path("m  70, 134 c  15,  7  51, -18 29, -32"),
            parse_path("m 139, 100 c  26,-15  18,  33  8,  44"),
            parse_path("m  35, 151 c  15, -7  51,  18 29,  32"),
            parse_path("m 133, 154 c -46,-16 -21,  22 -5,  24"),
        ]

        # Initialize edge cases for Cubic Bezier class
        cls.edge_paths = [
            parse_path("m 139, 100 c 26, 5 18, 33  8, 44"),
            parse_path("m  35, 151 c 15, 0 51, 18 29, 32"),
            parse_path("m  80,  20 c 10, 0 20,  0 30,  0"),
        ]
Esempio n. 10
0
def recursively_parse_paths(group):
    paths = OrderedDict()
    attributes = OrderedDict()
    for node in group.childNodes:
        if getattr(node, 'nodeName', None) == 'g':
            child_paths, child_attrs = recursively_parse_paths(node)
            paths.update(child_paths)
            attributes.update(child_attrs)
        elif getattr(node, 'nodeName', None) == 'path':
            node_attrs = attributes_to_dict(node.attributes)
            if 'transform' in node_attrs.keys():
                raise NotImplementedError('Transform found on node. Cannot handle transforms yet')
            if 'inkscape:label' not in node_attrs.keys():
                raise ValueError('All path nodes should have ids on the inkscape:label attribute')
            path_id = node_attrs['inkscape:label']
            attributes[path_id] = node_attrs
            paths[path_id] = parse_path(node_attrs.get('d'))
    return paths, attributes
def extract_line_from_path(path, transform=None):
    """
    Treat a path as a line-segment and extract end points. Throws
    if the path isn't a line.

    :param path:
    :param transform: the transform to apply to the coordinates
    :return: tuple of line-segment start and end coordinates
    """
    path_geom = parse_path(path.attrib["d"])

    if len(path_geom) == 1 and is_line(path_geom[0]):
        line = path_geom[0]
        # We assume line starts at origin and points towards the second point
        start_coord = (float_s3(line.start.real), float_s3(line.start.imag))
        end_coord = (float_s3(line.end.real), float_s3(line.end.imag))
        return apply_transform(start_coord, transform), apply_transform(
            end_coord, transform)
    else:
        raise RuntimeError()
Esempio n. 12
0
def svg2pathsdom(doc, convert_lines_to_paths, convert_polylines_to_paths,
                 convert_polygons_to_paths, return_svg_attributes):
    """
    Converts an SVG file into a list of Path objects and a list of
    dictionaries containing their attributes.  This currently supports
    SVG Path, Line, Polyline, and Polygon elements.
    :param doc: the svg dom document
    :param convert_lines_to_paths: Set to False to disclude SVG-Line objects
    (converted to Paths)
    :param convert_polylines_to_paths: Set to False to disclude SVG-Polyline
    objects (converted to Paths)
    :param convert_polygons_to_paths: Set to False to disclude SVG-Polygon
    objects (converted to Paths)
    :param return_svg_attributes: Set to True and a dictionary of
    svg-attributes will be extracted and returned
    :return: list of Path objects, list of path attribute dictionaries, and
    (optionally) a dictionary of svg-attributes

    """
    def dom2dict(element):
        """Converts DOM elements to dictionaries of attributes."""
        keys = list(element.attributes.keys())
        values = [val.value for val in list(element.attributes.values())]
        return dict(list(zip(keys, values)))

    # Use minidom to extract path strings from input SVG
    paths = [dom2dict(el) for el in doc.getElementsByTagName('path')]
    d_strings = [el['d'] for el in paths]
    attribute_dictionary_list = paths
    # if pathless_svg:
    #     for el in doc.getElementsByTagName('path'):
    #         el.parentNode.removeChild(el)

    # Use minidom to extract polyline strings from input SVG, convert to
    # path strings, add to list
    if convert_polylines_to_paths:
        plins = [dom2dict(el) for el in doc.getElementsByTagName('polyline')]
        d_strings += [polyline2pathd(pl['points']) for pl in plins]
        attribute_dictionary_list += plins

    # Use minidom to extract polygon strings from input SVG, convert to
    # path strings, add to list
    if convert_polygons_to_paths:
        pgons = [dom2dict(el) for el in doc.getElementsByTagName('polygon')]
        d_strings += [polyline2pathd(pg['points']) + 'z' for pg in pgons]
        attribute_dictionary_list += pgons

    if convert_lines_to_paths:
        lines = [dom2dict(el) for el in doc.getElementsByTagName('line')]
        d_strings += [
            ('M' + l['x1'] + ' ' + l['y1'] + 'L' + l['x2'] + ' ' + l['y2'])
            for l in lines
        ]
        attribute_dictionary_list += lines

    # if pathless_svg:
    #     with open(pathless_svg, "wb") as f:
    #         doc.writexml(f)

    if return_svg_attributes:
        svg_attributes = dom2dict(doc.getElementsByTagName('svg')[0])
        doc.unlink()
        path_list = [parse_path(d) for d in d_strings]
        return path_list, attribute_dictionary_list, svg_attributes
    else:
        doc.unlink()
        path_list = [parse_path(d) for d in d_strings]
        return path_list, attribute_dictionary_list