def update_arrows(self): self.cache_arrows = [] if self.is_curve and self.style[1]: stroke = self.style[1] arrs = stroke[9] if not arrs: return for path in self.paths: if path[-1] == sk2const.CURVE_CLOSED: self.cache_arrows.append([]) continue tr = libgeom.multiply_trafo coef = self.cache_line_width end = start = None stroke_trafo = [coef, 0.0, 0.0, coef, 0.0, 0.0] def get_vector(path, trafo): p0 = p1 = path[0] is_cp = libgeom.is_curve_point t = 0.001 for point in path[1]: p0 = point[0] if is_cp(point) else point if not p0 == p1: break elif is_cp(point) and p1 != point[2]: p0 = libgeom.split_bezier_curve(p1, point, t)[0][2] break return [ libgeom.apply_trafo_to_point(p, trafo) for p in (p0, p1) ] # end arrow if isinstance(arrs[0], int): p0, p1 = get_vector(path, self.trafo) angle = libgeom.get_point_angle(p1, p0) end_trafo = tr(stroke_trafo, libgeom.trafo_rotate(angle)) trafo = [1.0, 0.0, 0.0, 1.0, p1[0], p1[1]] end_trafo = tr(end_trafo, trafo) end = arrows.get_arrow_cpath(arrs[0], end_trafo) # start arrow if isinstance(arrs[1], int): p0, p1 = get_vector(libgeom.reverse_path(path), self.trafo) angle = libgeom.get_point_angle(p1, p0) start_trafo = tr(stroke_trafo, libgeom.trafo_rotate(angle)) trafo = [1.0, 0.0, 0.0, 1.0, p1[0], p1[1]] start_trafo = tr(start_trafo, trafo) start = arrows.get_arrow_cpath(arrs[1], start_trafo) self.cache_arrows.append([end, start])
def parse_svg_path_cmds(pathcmds): index = 0 last = None last_index = 0 cmds = [] pathcmds = re.sub(' *', ' ', pathcmds) for item in pathcmds: if item in 'MmZzLlHhVvCcSsQqTtAa': if last: coords = parse_svg_coords(pathcmds[last_index + 1:index]) cmds.append((last, coords)) last = item last_index = index index += 1 coords = parse_svg_coords(pathcmds[last_index + 1:index]) cmds.append([last, coords]) paths = [] path = [] cpoint = [] rel_flag = False last_cmd = 'M' last_quad = None for cmd in cmds: if cmd[0] in 'Mm': if path: paths.append(path) path = deepcopy(PATH_STUB) rel_flag = cmd[0] == 'm' points = [cmd[1][i:i + 2] for i in range(0, len(cmd[1]), 2)] for point in points: if cpoint and rel_flag: point = add_points(base_point(cpoint), point) if not path[0]: path[0] = point else: path[1].append(point) cpoint = point elif cmd[0] in 'Zz': p0 = [] + base_point(cpoint) p1 = [] + path[0] if not libgeom.is_equal_points(p0, p1, 8): path[1].append([] + path[0]) path[2] = sk2const.CURVE_CLOSED cpoint = [] + path[0] elif cmd[0] in 'Cc': rel_flag = cmd[0] == 'c' points = [cmd[1][i:i + 2] for i in range(0, len(cmd[1]), 2)] points = [points[i:i + 3] for i in range(0, len(points), 3)] for point in points: if rel_flag: point = [ add_points(base_point(cpoint), point[0]), add_points(base_point(cpoint), point[1]), add_points(base_point(cpoint), point[2]) ] qpoint = [] + point qpoint.append(sk2const.NODE_CUSP) path[1].append(qpoint) cpoint = point elif cmd[0] in 'Ll': rel_flag = cmd[0] == 'l' points = [cmd[1][i:i + 2] for i in range(0, len(cmd[1]), 2)] for point in points: if rel_flag: point = add_points(base_point(cpoint), point) path[1].append(point) cpoint = point elif cmd[0] in 'Hh': rel_flag = cmd[0] == 'h' for x in cmd[1]: dx, y = base_point(cpoint) if rel_flag: point = [x + dx, y] else: point = [x, y] path[1].append(point) cpoint = point elif cmd[0] in 'Vv': rel_flag = cmd[0] == 'v' for y in cmd[1]: x, dy = base_point(cpoint) if rel_flag: point = [x, y + dy] else: point = [x, y] path[1].append(point) cpoint = point elif cmd[0] in 'Ss': rel_flag = cmd[0] == 's' points = [cmd[1][i:i + 2] for i in range(0, len(cmd[1]), 2)] points = [points[i:i + 2] for i in range(0, len(points), 2)] for point in points: q = cpoint p = cpoint if len(cpoint) > 2: q = cpoint[1] p = cpoint[2] p1 = sub_points(add_points(p, p), q) if rel_flag: p2 = add_points(base_point(cpoint), point[0]) p3 = add_points(base_point(cpoint), point[1]) else: p2, p3 = point point = [p1, p2, p3] qpoint = [] + point qpoint.append(sk2const.NODE_CUSP) path[1].append(qpoint) cpoint = point elif cmd[0] in 'Qq': rel_flag = cmd[0] == 'q' groups = [cmd[1][i:i + 4] for i in range(0, len(cmd[1]), 4)] for vals in groups: p = base_point(cpoint) if rel_flag: q = add_points(p, [vals[0], vals[1]]) p3 = add_points(p, [vals[2], vals[3]]) else: q = [vals[0], vals[1]] p3 = [vals[2], vals[3]] p1 = add_points(mult_point(p, F13), mult_point(q, F23)) p2 = add_points(mult_point(p3, F13), mult_point(q, F23)) point = [p1, p2, p3] qpoint = [] + point qpoint.append(sk2const.NODE_CUSP) path[1].append(qpoint) cpoint = point last_quad = q elif cmd[0] in 'Tt': rel_flag = cmd[0] == 't' groups = [cmd[1][i:i + 2] for i in range(0, len(cmd[1]), 2)] if last_cmd not in 'QqTt' or last_quad is None: last_quad = base_point(cpoint) for vals in groups: p = base_point(cpoint) q = sub_points(mult_point(p, 2.0), last_quad) if rel_flag: p3 = add_points(p, [vals[0], vals[1]]) else: p3 = [vals[0], vals[1]] p1 = add_points(mult_point(p, F13), mult_point(q, F23)) p2 = add_points(mult_point(p3, F13), mult_point(q, F23)) point = [p1, p2, p3] qpoint = [] + point qpoint.append(sk2const.NODE_CUSP) path[1].append(qpoint) cpoint = point last_quad = q elif cmd[0] in 'Aa': rel_flag = cmd[0] == 'a' arcs = [cmd[1][i:i + 7] for i in range(0, len(cmd[1]), 7)] for arc in arcs: cpoint = base_point(cpoint) rev_flag = False rx, ry, xrot, large_arc_flag, sweep_flag, x, y = arc rx = abs(rx) ry = abs(ry) if rel_flag: x += cpoint[0] y += cpoint[1] if cpoint == [x, y]: continue if not rx or not ry: path[1].append([x, y]) continue vector = [[] + cpoint, [x, y]] if sweep_flag: vector = [[x, y], [] + cpoint] rev_flag = True cpoint = [x, y] dir_tr = libgeom.trafo_rotate_grad(-xrot) if rx > ry: tr = [1.0, 0.0, 0.0, rx / ry, 0.0, 0.0] r = rx else: tr = [ry / rx, 0.0, 0.0, 1.0, 0.0, 0.0] r = ry dir_tr = libgeom.multiply_trafo(dir_tr, tr) vector = libgeom.apply_trafo_to_points(vector, dir_tr) l = libgeom.distance(*vector) if l > 2.0 * r: r = l / 2.0 mp = libgeom.midpoint(*vector) tr0 = libgeom.trafo_rotate(math.pi / 2.0, mp[0], mp[1]) pvector = libgeom.apply_trafo_to_points(vector, tr0) k = math.sqrt(r * r - l * l / 4.0) if large_arc_flag: center = libgeom.midpoint(mp, pvector[1], 2.0 * k / l) else: center = libgeom.midpoint(mp, pvector[0], 2.0 * k / l) angle1 = libgeom.get_point_angle(vector[0], center) angle2 = libgeom.get_point_angle(vector[1], center) da = angle2 - angle1 start = angle1 end = angle2 if large_arc_flag: if -math.pi >= da or da <= math.pi: start = angle2 end = angle1 rev_flag = not rev_flag else: if -math.pi <= da or da >= math.pi: start = angle2 end = angle1 rev_flag = not rev_flag pth = libgeom.get_circle_paths(start, end, sk2const.ARC_ARC)[0] if rev_flag: pth = libgeom.reverse_path(pth) points = pth[1] for point in points: if len(point) == 3: point.append(sk2const.NODE_CUSP) tr0 = [1.0, 0.0, 0.0, 1.0, -0.5, -0.5] points = libgeom.apply_trafo_to_points(points, tr0) tr1 = [2.0 * r, 0.0, 0.0, 2.0 * r, 0.0, 0.0] points = libgeom.apply_trafo_to_points(points, tr1) tr2 = [1.0, 0.0, 0.0, 1.0, center[0], center[1]] points = libgeom.apply_trafo_to_points(points, tr2) tr3 = libgeom.invert_trafo(dir_tr) points = libgeom.apply_trafo_to_points(points, tr3) for point in points: path[1].append(point) last_cmd = cmd[0] if path: paths.append(path) return paths