def tr_arc(self, chunk, arc_type=sk2const.ARC_ARC): ye, xe, ys, xs, bottom, right, top, left = get_data('<hhhhhhhh', chunk) left, top = apply_trafo_to_point([left, top], self.get_trafo()) right, bottom = apply_trafo_to_point([right, bottom], self.get_trafo()) xs, ys = apply_trafo_to_point([xs, ys], self.get_trafo()) xe, ye = apply_trafo_to_point([xe, ye], self.get_trafo()) if left != right and top != bottom: t = [(right - left) / 2, 0, 0, (bottom - top) / 2, (right + left) / 2, (top + bottom) / 2] t = libgeom.invert_trafo(t) xs, ys = apply_trafo_to_point([xs, ys], t) xe, ye = apply_trafo_to_point([xe, ye], t) end_angle = libgeom.get_point_angle([xs, ys], [0.0, 0.0]) start_angle = libgeom.get_point_angle([xe, ye], [0.0, 0.0]) else: start_angle = end_angle = 0.0 cfg = self.layer.config sk2_style = self.get_style() if arc_type == sk2const.ARC_ARC: sk2_style[0] = [] rect = [left, top, right - left, bottom - top] ellipse = sk2_model.Circle(cfg, self.layer, rect, start_angle, end_angle, arc_type, sk2_style) self.layer.childs.append(ellipse)
def tr_arc(self, chunk, arc_type=sk2_const.ARC_ARC): ye, xe, ys, xs, bottom, right, top, left = get_data('<hhhhhhhh', chunk) left, top = apply_trafo_to_point([left, top], self.get_trafo()) right, bottom = apply_trafo_to_point([right, bottom], self.get_trafo()) xs, ys = apply_trafo_to_point([xs, ys], self.get_trafo()) xe, ye = apply_trafo_to_point([xe, ye], self.get_trafo()) if left != right and top != bottom: t = [(right - left) / 2, 0, 0, (bottom - top) / 2, (right + left) / 2, (top + bottom) / 2] t = libgeom.invert_trafo(t) xs, ys = apply_trafo_to_point([xs, ys], t) xe, ye = apply_trafo_to_point([xe, ye], t) end_angle = libgeom.get_point_angle([xs, ys], [0.0, 0.0]) start_angle = libgeom.get_point_angle([xe, ye], [0.0, 0.0]) else: start_angle = end_angle = 0.0 cfg = self.layer.config sk2_style = self.get_style() if arc_type == sk2_const.ARC_ARC: sk2_style[0] = [] rect = [left, top, right - left, bottom - top] ellipse = sk2_model.Circle(cfg, self.layer, rect, start_angle, end_angle, arc_type, sk2_style) self.layer.childs.append(ellipse)
def _circular_arc_3_point_close(self, element): p1, chunk = self.read_point(element.params) p2, chunk = self.read_point(chunk) p3, chunk = self.read_point(chunk) flag = self.read_enum(chunk)[0] p1, p2, p3 = libgeom.apply_trafo_to_points([p1, p2, p3], self.get_trafo()) center = libgeom.circle_center_by_3points(p1, p2, p3) if not center: return r = libgeom.distance(center, p1) angle1 = libgeom.get_point_angle(p3, center) angle2 = libgeom.get_point_angle(p1, center) x, y = center rect = [x - r, y - r, 2 * r, 2 * r] flag = { 0: sk2const.ARC_PIE_SLICE, 1: sk2const.ARC_CHORD }.get(flag, sk2const.ARC_CHORD) circle = sk2_model.Circle(self.layer.config, self.layer, rect, angle1=angle1, angle2=angle2, circle_type=flag, style=self.get_style(fill=True)) self.layer.childs.append(circle)
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 translate_arc(self, obj, cfg): cx = obj.center_x cy = obj.center_y r = libgeom.distance((cx, cy), (obj.x1, obj.y1)) end_angle = libgeom.get_point_angle((obj.x1, obj.y1), (cx, cy)) start_angle = libgeom.get_point_angle((obj.x3, obj.y3), (cx, cy)) if not obj.direction: start_angle, end_angle = end_angle, start_angle circle_type = FIG_TO_SK2_ARC.get(obj.sub_type, sk2const.ARC_PIE_SLICE) props = dict(circle_type=circle_type, rect=[cx - r, cy - r, 2.0 * r, 2.0 * r], style=self.get_style(obj), angle1=start_angle, angle2=end_angle) new_obj = sk2_model.Circle(cfg, **props) new_obj.trafo = libgeom.multiply_trafo(new_obj.trafo, self.trafo) return new_obj
def _circular_arc_centre(self, element): center, chunk = self.read_point(element.params) p1, chunk = self.read_point(chunk) p2, chunk = self.read_point(chunk) center, p1, p2 = libgeom.apply_trafo_to_points( [center, p1, p2], self.get_trafo()) r = self.read_vdc(chunk)[0] * self.scale angle1 = libgeom.get_point_angle(p1, center) angle2 = libgeom.get_point_angle(p2, center) x, y = center rect = [x - r, y - r, 2 * r, 2 * r] circle = sk2_model.Circle(self.layer.config, self.layer, rect, angle1=angle1, angle2=angle2, circle_type=sk2const.ARC_ARC, style=self.get_style(stroke=True)) self.layer.childs.append(circle)
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 # end arrow if isinstance(arrs[0], int): end_trafo = [coef, 0.0, 0.0, coef, 0.0, 0.0] p1 = libgeom.apply_trafo_to_point(path[0], self.trafo) p0 = libgeom.apply_trafo_to_point(path[1][0], self.trafo) if libgeom.is_curve_point(p0): p0 = p0[0] angle = libgeom.get_point_angle(p1, p0) end_trafo = tr(end_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): start_trafo = [coef, 0.0, 0.0, coef, 0.0, 0.0] p1 = libgeom.apply_trafo_to_point(path[1][-1], self.trafo) if len(path[1]) == 1: p0 = libgeom.apply_trafo_to_point(path[0], self.trafo) else: if libgeom.is_curve_point(p1): p0 = p1[1] p1 = p1[2] else: p0 = libgeom.bezier_base_point(path[1][-2]) p0 = libgeom.apply_trafo_to_point(p0, self.trafo) angle = libgeom.get_point_angle(p1, p0) start_trafo = tr(start_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 _circular_arc_centre_close(self, element): center, chunk = self.read_point(element.params) p1, chunk = self.read_point(chunk) p2, chunk = self.read_point(chunk) flag = self.read_enum(chunk)[0] center, p1, p2 = libgeom.apply_trafo_to_points( [center, p1, p2], self.get_trafo()) r = self.read_vdc(chunk)[0] * self.scale angle1 = libgeom.get_point_angle(p1, center) angle2 = libgeom.get_point_angle(p2, center) x, y = center rect = [x - r, y - r, 2 * r, 2 * r] flag = {0: sk2const.ARC_PIE_SLICE, 1: sk2const.ARC_CHORD}.get(flag, sk2const.ARC_CHORD) circle = sk2_model.Circle(self.layer.config, self.layer, rect, angle1=angle1, angle2=angle2, circle_type=flag, style=self.get_style(fill=True)) self.layer.childs.append(circle)
def _circular_arc_3_point(self, element): p1, chunk = self.read_point(element.params) p2, chunk = self.read_point(chunk) p3, chunk = self.read_point(chunk) p1, p2, p3 = libgeom.apply_trafo_to_points( [p1, p2, p3], self.get_trafo()) center = libgeom.circle_center_by_3points(p1, p2, p3) if not center: return r = libgeom.distance(center, p1) angle1 = libgeom.get_point_angle(p3, center) angle2 = libgeom.get_point_angle(p1, center) x, y = center rect = [x - r, y - r, 2 * r, 2 * r] circle = sk2_model.Circle(self.layer.config, self.layer, rect, angle1=angle1, angle2=angle2, circle_type=sk2const.ARC_ARC, style=self.get_style(stroke=True)) self.layer.childs.append(circle)
def _calc_bottom_left_rotate_trafo(self, event): is_centering = not event.is_shift() is_constraining = event.is_ctrl() start_point = self.canvas.win_to_doc(self.start) end_point = self.canvas.win_to_doc(self.end) bbox = self.presenter.selection.bbox if is_centering: bbox_center = libgeom.bbox_center(bbox) center_offset = self.selection.center_offset center = libgeom.add_points(bbox_center, center_offset) else: center = libgeom.bbox_points(bbox)[3] a1 = libgeom.get_point_angle(start_point, center) a2 = libgeom.get_point_angle(end_point, center) angle = a2 - a1 if is_constraining: step = math.radians(config.rotation_step) angle = (angle + step / 2.0) // step * step return libgeom.trafo_rotate(angle, center[0], center[1])
def fill_linear_tr_gradient(self, obj, pdfpath, fill_trafo, gradient): if not fill_trafo: fill_trafo = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] stops = gradient[2] sp, ep = gradient[1] dx, dy = sp l = libgeom.distance(sp, ep) angle = libgeom.get_point_angle(ep, sp) m21 = math.sin(angle) m11 = m22 = math.cos(angle) m12 = -m21 trafo = [m11, m21, m12, m22, dx, dy] inv_trafo = libgeom.multiply_trafo(libgeom.invert_trafo(fill_trafo), libgeom.invert_trafo(trafo)) cv_trafo = libgeom.multiply_trafo(trafo, fill_trafo) paths = libgeom.apply_trafo_to_paths(obj.paths, obj.trafo) paths = libgeom.apply_trafo_to_paths(paths, inv_trafo) bbox = libgeom.sum_bbox(libgeom.get_paths_bbox(paths), [0.0, 0.0, l, 0.0]) bbox = libgeom.normalize_bbox(bbox) y = bbox[1] d = libgeom.distance(*libgeom.apply_trafo_to_points([[0.0, 0.0], [0.0, 1.0]], inv_trafo)) height = bbox[3] - bbox[1] self.canvas.saveState() self.canvas.clipPath(pdfpath, 0, 0) self.canvas.transform(*cv_trafo) self.canvas.setFillColor(self.get_grcolor_at_point(stops, 0.0)) self.canvas.rect(bbox[0], y, 0.0 - bbox[0], height, stroke=0, fill=1) x = 0.0 while x < l: point = x / l self.canvas.setFillColor(self.get_grcolor_at_point(stops, point)) if x + d < l: width = d else: width = l - x self.canvas.rect(x, y, width, height, stroke=0, fill=1) x += d self.canvas.setFillColor(self.get_grcolor_at_point(stops, 1.0)) self.canvas.rect(l, y, bbox[2] - l, height, stroke=0, fill=1) self.canvas.restoreState()
def apply_midpoint_change(self, point, index, control=False, final=False): wpoint = self.canvas.point_win_to_doc(point) invtrafo = libgeom.invert_trafo(self.target.trafo) x, y = libgeom.apply_trafo_to_point(wpoint, invtrafo) radius = self.target.get_midpoint_radius() angle = self.target.get_midpoint_angle(index) coef2 = libgeom.get_point_radius([x, y]) / radius if control: props = [self.orig_angle1, self.orig_angle2, self.orig_coef1, coef2] else: angle2 = libgeom.get_point_angle([x, y]) - angle props = [self.orig_angle1, angle2, self.orig_coef1, coef2] if final: props_before = [self.orig_angle1, self.orig_angle2, self.orig_coef1, self.orig_coef2] self.api.set_polygon_properties_final(props, props_before, self.target) else: self.api.set_polygon_properties(props, self.target) self.update_points()
def set_sk2_style(sk1_style, dest_obj=None): sk2_style = [[], [], [], []] line_pattern = sk1_style.line_pattern fill_pattern = sk1_style.fill_pattern if not line_pattern.is_Empty: sk2_line = [ sk2const.STROKE_MIDDLE, sk1_style.line_width, get_sk2_color(line_pattern.color), list(sk1_style.line_dashes), SK2_LINE_CAP[sk1_style.line_cap], SK2_LINE_JOIN[sk1_style.line_join], 10.0, 0, 0, [] ] sk2_style[1] = sk2_line if fill_pattern.is_Solid: sk2_fill = [] if fill_pattern.is_Solid: sk2_fill = [ sk2const.FILL_EVENODD, sk2const.FILL_SOLID, get_sk2_color(fill_pattern.color) ] sk2_style[0] = sk2_fill elif fill_pattern.is_AxialGradient: stops = get_sk2_stops(fill_pattern.gradient.colors) point = [fill_pattern.direction.x, fill_pattern.direction.y] angle = libgeom.get_point_angle(point, [0.0, 0.0]) points = [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]] m21 = math.sin(-angle) m11 = m22 = math.cos(-angle) m12 = -m21 dx = 0.5 - m11 * 0.5 + m21 * 0.5 dy = 0.5 - m21 * 0.5 - m11 * 0.5 trafo = [m11, m21, m12, m22, dx, dy] points = libgeom.apply_trafo_to_points(points, trafo) bbox = libgeom.bbox_for_points(points) w, h = libgeom.bbox_size(bbox) vector = [[bbox[0], 0.5], [bbox[2], 0.5]] invtrafo = libgeom.invert_trafo(trafo) vector = libgeom.apply_trafo_to_points(vector, invtrafo) dest_obj.update() bbox = dest_obj.cache_bbox w, h = libgeom.bbox_size(bbox) trafo = [w, 0.0, 0.0, h, bbox[0], bbox[1]] vector = libgeom.apply_trafo_to_points(vector, trafo) sk2_fill = [ sk2const.FILL_EVENODD, sk2const.FILL_GRADIENT, [sk2const.GRADIENT_LINEAR, vector, stops] ] sk2_style[0] = sk2_fill dest_obj.fill_trafo = [] + sk2const.NORMAL_TRAFO elif fill_pattern.is_RadialGradient or fill_pattern.is_ConicalGradient: stops = get_sk2_stops(fill_pattern.gradient.colors) dest_obj.update() bbox = dest_obj.cache_bbox cg = [fill_pattern.center.x, fill_pattern.center.y] w, h = libgeom.bbox_size(bbox) start_point = [bbox[0] + w * cg[0], bbox[1] + h * cg[1]] points = libgeom.bbox_points(bbox) r = 0 for point in points: dist = libgeom.distance(point, start_point) r = max(r, dist) end_point = [start_point[0] + r, start_point[1]] sk2_fill = [ sk2const.FILL_EVENODD, sk2const.FILL_GRADIENT, [sk2const.GRADIENT_RADIAL, [start_point, end_point], stops] ] sk2_style[0] = sk2_fill dest_obj.fill_trafo = [] + sk2const.NORMAL_TRAFO dest_obj.style = sk2_style
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