コード例 #1
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def vertical_line(numbers, p_current, relative=False):
    """vertical line from current point"""
    if len(numbers) != 1:
        return None

    if relative:
        p_next = Point(p_current.x, numbers[0] + p_current.y)
    else:
        p_next = Point(p_current.x, numbers[0])

    return Line(p_current, p_next)
コード例 #2
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def horizontal_line(numbers, p_current, relative=False):
    """horizontal line from current point"""
    if len(numbers) != 1:
        return None

    if relative:
        p_next = Point(numbers[0] + p_current.x, p_current.y)
    else:
        p_next = Point(numbers[0], p_current.y)

    return Line(p_current, p_next)
コード例 #3
0
    def __call__(self, pt):
        if not isinstance(pt, Point):
            raise ValueError("Transform.__call__ requires a point")

        b = np.array([pt.x, pt.y, 1])
        c = np.dot(self.mat, b)

        return Point(c[0], c[1])
コード例 #4
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def move_to(numbers, p_current, relative=False):
    """create subpath, move pointer at coordinate of first two numbers"""
    if len(numbers) != 2:
        return None

    p_start = Point(numbers[0], numbers[1])  #first point
    if relative:
        p_start += p_current
    return p_start
コード例 #5
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def straight_line(numbers, p_current, relative=False):
    """straight line from current point"""
    if len(numbers) != 2:
        return None

    p_next = Point(numbers[0], numbers[1])
    if relative:  #relative
        p_next += p_current

    return Line(p_current, p_next)
コード例 #6
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def curve_bezier(numbers, p_current, relative=False):
    """curve bezier with 2 or 3 points, it is the same instruction"""
    if len(numbers) < 2 or len(numbers) > 3:
        return None

    pp = [ Point(numbers[i], numbers[i+1]) \
            for i in range(0, len(numbers), 2) ]
    if relative:
        pp = [p + p_current for p in pp]

    p_list = [p_current]
    p_list.append(pp)

    return Bezier(p_list)
コード例 #7
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def short_bezier(numbers, p_current, p_last=None, relative=False):
    """short bezier with 2 or 3 points, it is the same instruction
    it requires the second to last point (p_last) of the previous bezier curve
    in order to make a symmetrical one
    """
    if len(numbers) < 1 or len(numbers) > 2:
        return None

    p_next = p_current.copy()
    if p_last is not None:  #if last shape was bezier, copy next to last point
        p_next += p_current - p_last

    pp = [ Point(numbers[i], numbers[i+1]) \
            for i in range(0, len(numbers), 2) ]
    if relative:
        pp = [p + p_current for p in pp[2:]]

    p_list = [p_current, p_next]
    p_list.append(pp)

    return Bezier(p_list)
コード例 #8
0
ファイル: path.py プロジェクト: tboschi/svg2dat
def elliptic_arc(numbers, p_current, relative = False):
    """elliptic arc from current point
    if any of the two radii are null, then a straight line is created instead
    """
    if len(numbers) != 7:
        return None

    if any(numbers[:2]) == 0:
        return straight_line(numbers, p_current, relative)
    else:
        p_next = Point(numbers[5], numbers[6])
        if relative:
            p_next += p_curent

                       #start     #end
        return Ellipse(p_current, p_next, 
                       radX = numbers[0],   #radius x
                       radY = numbers[1],   #radius y
                       angle = numbers[2],   #angle
                       large = numbers[3],   #large flag
                       sweep = numbers[4])   #sweep flag
コード例 #9
0
ファイル: shape.py プロジェクト: tboschi/svg2dat
    def __init__(self, start, end, transform = None, **kw):
        """start and end are required
        if transform is passed it is applied
        kw is shape specific
        """

        self.start = start
        self.end   = end
        self.kw    = kw

        if trans is not None:
            transform(trans)


    def transform(self, trans)

        self.start = trans(start)
        self.end   = trans(end)

        if "control" in self.kw:    #for bezier
            self.kw["control"] = [trans(p) for p in self.kw["control"]]
        if "radX" in self.kw:       #for ellipse
            prx = Point(self.kw["radX"], 0)
            self.kw["radX"] = trans(prx).x
        if "radY" in self.kw:       #for ellipse
            pry = Point(0, self.kw["radY"])
            self.kw["radY"] = trans(pry).y

        #build shape. The function is defined in child classes
        build()
コード例 #10
0
ファイル: parser.py プロジェクト: tboschi/svg2dat
def parse_d(d):
    """parse the d attribute of an svg shape
    return a list of shapes separated by a None
    each section of shapes represent a sub shape 
    inside the global shape
    """

    commands = "mzlhvcsqta"
    commands += commands.upper()

    p_current = Point()
    p_start = Point()

    shapes = []
    subshapes = []
    numbers = []

    #loop over lines first
    for line in d.split('\n'):

        #print(line)

        #remove comments or other stuff
        if '#' in line:
            line = line[:line.find('#')]
        if '$' in line:
            line = line[:line.find('$') + 1]
        if '@' in line:
            line = line[:line.find('@') + 1]
        if not line:
            continue

        #loop over character of line
        num = ""
        comm = ""
        for char in line:

            #check first if character is a command
            if char in commands:
                comm = char

            #check if character is a digit and save it
            elif char.isdigit() or char == '+' or char == '-' \
                    or (char == '.' and num[-1] != '.'):
                num += char
            #if char is something else and num is not empty, then save num as float
            elif num:
                numbers.append(float(num))
                num = ""

            #try to execute some commands

            last_path = None
            path_closed = False

            if comm.upper() == 'M':  #move to defines the start
                p_start = move_to(numbers, p_current, comm.islower())
                if p_start is not None:
                    p_current = p_start
                    path_closed = True
                    if comm.isupper():  #default to straight lines
                        comm = 'L'
                    elif comm.islower():
                        comm = 'l'
                    numbers.clear()  #clear numbers
            elif comm.upper() == 'Z':  #cannot return none
                last_path = close_path(p_current, p_current, p_start)
                if last_path is not None:
                    path_closed = True
                    if comm.isupper():  #next, move to a point
                        comm = 'M'
                    elif comm.islower():
                        comm = 'm'
            elif comm.upper() == 'L':
                last_path = straight_line(numbers, p_current, comm.islower())
            elif comm.upper() == 'H':
                last_path = horizontal_line(numbers, p_current, comm.islower())
            elif comm.upper() == 'V':
                last_path = vertical_line(numbers, p_current, comm.islower())
            elif comm.upper() == 'T' or comm.upper() == 'S':
                p_last = None
                if isinstance(self.subshapes[-1], Bezier):
                    p_last = subpath[-1].points[-2]
                last_path = short_bezier(numbers, p_current, p_last,
                                         comm.islower())
            elif comm.upper() == 'Q' or comm.upper() == 'C':
                last_path = curve_bezier(numbers, p_current, comm.islower())
            elif comm.upper() == 'A':
                last_path = elliptic_arc(numbers, p_current, comm.islower())
            elif comm:
                raise ValueError(f"command {comm} is unknown")

            if last_path is not None:
                #print(comm + "-> adding shape " + str(last_path))
                p_current = last_path.get_end(
                )  #current point is end of last shape
                subshapes.append(last_path)
                numbers.clear()  #clear numbers

            if path_closed and subshapes:  #shapes is closed, start a new subpath
                #print(comm + "-> closing shape")
                shapes.append(subshapes)
                shapes.append(None)
                subshapes.clear()

    if subshapes:  #if trailing subshapes, save them
        shapes.append(subshapes)  #subpath finished, append
        shapes.append(None)
        subshapes.clear()  #and clear

    return shapes