def get_resolution(self): path = libgeom.apply_trafo_to_paths(self.cache_paths, self.trafo)[0] p0 = path[0] p1 = path[1][0] p2, p3 = path[1][-2:] m11 = (libgeom.distance(p0, p1)) / float(self.size[1]) m22 = (libgeom.distance(p2, p3)) / float(self.size[0]) v_dpi = int(round(uc2const.in_to_pt / m11)) h_dpi = int(round(uc2const.in_to_pt / m22)) return (h_dpi, v_dpi)
def fill_radial_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) trafo = [1.0, 0.0, 0.0, 1.0, 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) d = libgeom.distance(*libgeom.apply_trafo_to_points([[0.0, 0.0], [0.0, 1.0]], inv_trafo)) circle_paths = libgeom.get_circle_paths(0.0, 0.0, sk2const.ARC_CHORD) trafo = [2.0, 0.0, 0.0, 2.0, -1.0, -1.0] circle_paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) inner_paths = [] r = 0.0 self.canvas.saveState() self.canvas.clipPath(pdfpath, 0, 0) self.canvas.transform(*cv_trafo) while r < l: point = r / l self.canvas.setFillColor(self.get_grcolor_at_point(stops, point)) if r + d < l: coef = (r + d) else: coef = l trafo = [coef, 0.0, 0.0, coef, 0.0, 0.0] paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) ring = self.make_pdfpath(inner_paths + paths)[0] inner_paths = paths self.canvas.drawPath(ring, stroke=0, fill=1) r += d self.canvas.setFillColor(self.get_grcolor_at_point(stops, 1.0)) r = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) trafo = [2.0 * r, 0.0, 0.0, 2.0 * r, 0.0, 0.0] paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) ring = self.make_pdfpath(inner_paths + paths)[0] self.canvas.drawPath(ring, stroke=0, fill=1) self.canvas.restoreState()
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 ctrl_points(p0, p1, p2, t=1.0): d01 = libgeom.distance(p1, p0) d12 = libgeom.distance(p2, p1) if not d01 or not d12: return p0[:], p1[:] fa = t * d01 / (d01 + d12) fb = t * d12 / (d01 + d12) p1x = p1[0] - fa * (p2[0] - p0[0]) p1y = p1[1] - fa * (p2[1] - p0[1]) p2x = p1[0] + fb * (p2[0] - p0[0]) p2y = p1[1] + fb * (p2[1] - p0[1]) return [p1x, p1y], [p2x, p2y]
def fill_radial_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) trafo = [1.0, 0.0, 0.0, 1.0, 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) d = libgeom.distance(*libgeom.apply_trafo_to_points([[0.0, 0.0], [0.0, 1.0]], inv_trafo)) circle_paths = libgeom.get_circle_paths(0.0, 0.0, sk2_const.ARC_CHORD) trafo = [2.0, 0.0, 0.0, 2.0, -1.0, -1.0] circle_paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) inner_paths = [] r = 0.0 self.canvas.saveState() self.canvas.clipPath(pdfpath, 0, 0) self.canvas.transform(*cv_trafo) while r < l: point = r / l self.canvas.setFillColor(self.get_grcolor_at_point(stops, point)) if r + d < l: coef = (r + d) else: coef = l trafo = [coef, 0.0, 0.0, coef, 0.0, 0.0] paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) ring = self.make_pdfpath(inner_paths + paths)[0] inner_paths = paths self.canvas.drawPath(ring, stroke=0, fill=1) r += d self.canvas.setFillColor(self.get_grcolor_at_point(stops, 1.0)) r = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) trafo = [2.0 * r, 0.0, 0.0, 2.0 * r, 0.0, 0.0] paths = libgeom.apply_trafo_to_paths(circle_paths, trafo) ring = self.make_pdfpath(inner_paths + paths)[0] self.canvas.drawPath(ring, stroke=0, fill=1) self.canvas.restoreState()
def _snap_midpoints(self, point): p0 = None p1 = None if self.res_index == 1: p0 = self.midpoints[1].get_screen_point() p1 = self.midpoints[3].get_screen_point() elif self.res_index == 3: p0 = self.midpoints[3].get_screen_point() p1 = self.midpoints[1].get_screen_point() elif self.res_index == 2: p0 = self.midpoints[2].get_screen_point() p1 = self.midpoints[0].get_screen_point() elif self.res_index == 0: p0 = self.midpoints[0].get_screen_point() p1 = self.midpoints[2].get_screen_point() if p0 is not None: cp = None flag, wp, dp = self.snap.snap_point(p0) if flag and self.snap.active_snap[1] is not None: cp = x_intersect(p0, p1, wp[1]) if not cp and flag and self.snap.active_snap[0] is not None: cp = y_intersect(p0, p1, wp[0]) if cp: closest_point = project_point_to_line(point, p0, p1) d = libgeom.distance(cp, closest_point) if d < config.point_sensitivity_size * 2: point = cp else: self.snap.active_snap = [None, None] return point
def process_stroke(self, ctx, obj, style=None): if style: stroke = style[1] else: stroke = obj.style[1] #FIXME: add stroke style #Line width if not stroke[8]: line_width = stroke[1] if obj and obj.stroke_trafo: obj.stroke_trafo = [] else: if obj and not obj.stroke_trafo: obj.stroke_trafo = [] + sk2_const.NORMAL_TRAFO points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points(points, obj.stroke_trafo) coef = libgeom.distance(*points) line_width = stroke[1] * coef ctx.set_line_width(line_width) #Line color ctx.set_source_rgba(*self.get_color(stroke[2])) #Dashes dash = [] for item in stroke[3]:dash.append(item * line_width) ctx.set_dash(dash) ctx.set_line_cap(CAPS[stroke[4]]) ctx.set_line_join(JOINS[stroke[5]]) ctx.set_miter_limit(stroke[6])
def process_stroke(self, ctx, obj, style=None): if style: stroke = style[1] else: stroke = obj.style[1] # Line width if not stroke[8]: line_width = stroke[1] if obj and obj.stroke_trafo: obj.stroke_trafo = [] else: if obj and not obj.stroke_trafo: obj.stroke_trafo = [] + sk2const.NORMAL_TRAFO points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points(points, obj.stroke_trafo) coef = libgeom.distance(*points) line_width = stroke[1] * coef ctx.set_line_width(line_width) # Line color ctx.set_source_rgba(*self.get_color(stroke[2])) # Dashes dash = [] for item in stroke[3]: dash.append(item * line_width) ctx.set_dash(dash) ctx.set_line_cap(CAPS[stroke[4]]) ctx.set_line_join(JOINS[stroke[5]]) ctx.set_miter_limit(stroke[6])
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 stroke_pdfpath(self, pdfpath, stroke_style, stroke_trafo=[]): width = stroke_style[1] if not stroke_style[8]: width = stroke_style[1] else: if not stroke_trafo: stroke_trafo = [] + sk2_const.NORMAL_TRAFO points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points(points, stroke_trafo) coef = libgeom.distance(*points) width = stroke_style[1] * coef self.canvas.setStrokeColor(self.get_pdfcolor(stroke_style[2])) dash = stroke_style[3] caps = stroke_style[4] joint = stroke_style[5] miter = stroke_style[6] self.canvas.setLineWidth(width) self.canvas.setLineCap(caps - 1) self.canvas.setLineJoin(joint) dashes = [] if dash: dashes = list(dash) w = width if w < 1.0: w = 1.0 for i in range(len(dashes)): dashes[i] = w * dashes[i] self.canvas.setDash(dashes) self.canvas.setMiterLimit(miter) self.canvas.drawPath(pdfpath, 1, 0) self.canvas.setStrokeAlpha(1.0)
def stroke_pdfpath(self, pdfpath, stroke_style, stroke_trafo=[]): width = stroke_style[1] if not stroke_style[8]: width = stroke_style[1] else: if not stroke_trafo: stroke_trafo = [] + sk2const.NORMAL_TRAFO points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points(points, stroke_trafo) coef = libgeom.distance(*points) width = stroke_style[1] * coef self.canvas.setStrokeColor(self.get_pdfcolor(stroke_style[2])) dash = stroke_style[3] caps = stroke_style[4] joint = stroke_style[5] miter = stroke_style[6] self.canvas.setLineWidth(width) self.canvas.setLineCap(caps - 1) self.canvas.setLineJoin(joint) dashes = [] if dash: dashes = list(dash) w = width if w < 1.0: w = 1.0 for i in range(len(dashes)): dashes[i] = w * dashes[i] self.canvas.setDash(dashes) self.canvas.setMiterLimit(miter) self.canvas.drawPath(pdfpath, 1, 0) self.canvas.setStrokeAlpha(1.0)
def _snap_respoints(self, point): p0 = None rnd_index = self.rnd_index rnd_subindex = self.rnd_subindex if self.stop2: for item in self.points: if item.is_pressed(self.end): p0 = item.get_screen_point() rnd_index = item.index rnd_subindex = item.subindex break if p0 is None: for p in self.points: if p.index == rnd_index and p.subindex == rnd_subindex: p0 = p.get_screen_point() break if p0: cp = None index = rnd_index - (1 - rnd_subindex) p1 = self.midpoints[index].get_screen_point() flag, wp, dp = self.snap.snap_point(p0, snap_x=False) self.snap.active_snap = [None, None] if flag: cp = x_intersect(p0, p1, wp[1]) if cp: closest_point = project_point_to_line(point, p0, p1) d = libgeom.distance(cp, closest_point) if d < config.point_sensitivity_size * 2: self.snap.active_snap = [None, dp[1]] point = cp else: flag, wp, dp = self.snap.snap_point(p0, snap_y=False) self.snap.active_snap = [None, None] if flag: cp = y_intersect(p0, p1, wp[0]) if cp: closest_point = project_point_to_line(point, p0, p1) d = libgeom.distance(cp, closest_point) if d < config.point_sensitivity_size * 2: self.snap.active_snap = [dp[0], None] point = cp return point
def apply_moving(self, event, start=False, final=False): point = event.get_point() wpoint = self.canvas.point_win_to_doc(point) invtrafo = libgeom.invert_trafo(self.target.trafo) x, y = libgeom.apply_trafo_to_point(wpoint, invtrafo) x -= 0.5 y -= 0.5 angle = 0.0 if x > 0 and y > 0: angle = math.atan(y / x) elif x == 0 and y > 0: angle = math.pi / 2.0 elif x < 0 < y: angle = math.atan(-x / y) + math.pi / 2.0 elif x < 0 and y == 0: angle = math.pi elif x < 0 and y < 0: angle = math.atan(y / x) + math.pi elif x == 0 and y < 0: angle = 1.5 * math.pi elif x > 0 > y: angle = math.atan(x / -y) + 1.5 * math.pi elif x > 0 and y == 0: angle = 0.0 elif x == 0 and y == 0: return if event.is_ctrl(): fixed_angle = math.pi * config.ellipse_fixed_angle / 180.0 angle //= fixed_angle angle *= fixed_angle else: contra_point = self.start_point if start: contra_point = self.end_point if contra_point.is_pressed(point): angle = contra_point.get_angle() circle_type = self.orig_type if event.is_alt() and not circle_type == sk2const.ARC_ARC: circle_type = sk2const.ARC_CHORD if libgeom.distance([x, y]) < 0.5: circle_type = sk2const.ARC_PIE_SLICE angle1 = self.orig_angle1 angle2 = self.orig_angle2 if start: angle1 = angle else: angle2 = angle if final: self.api.set_circle_properties_final(circle_type, angle1, angle2, self.orig_type, self.orig_angle1, self.orig_angle2, self.target) else: self.api.set_circle_properties(circle_type, angle1, angle2, self.target) self.update_points()
def update_connection(self): after = self.get_point_after() before = self.get_point_before() if self.path.is_closed(): if self.path.points[0] == self: before = self.path.points[-1] if not after and self.is_end(): after = self.path.points[0] if after and after.is_curve(): if self.is_symmetrical(): after.point[0] = libgeom.contra_point(self.point[1], self.point[2]) if self.is_smooth() and self.is_curve(): after.point[0] = libgeom.contra_point(self.point[1], self.point[2], after.point[0]) elif after and not after.is_curve(): if self.is_smooth() and self.is_curve(): lenght = libgeom.distance(self.point[2], after.point) if lenght: self.point[1] = libgeom.contra_point(after.point, self.point[2], self.point[1]) if before and before.is_curve(): if before.is_symmetrical(): before.point[1] = libgeom.contra_point(self.point[0], before.point[2]) if before.is_smooth() and self.is_curve(): before.point[1] = libgeom.contra_point(self.point[0], before.point[2], before.point[1]) elif before and not before.is_curve(): if self.is_opp_smooth(): p = before.get_point_before() if p: p = p.get_base_point() lenght = libgeom.distance(p, before.point) if lenght: self.point[0] = libgeom.contra_point(p, before.point, self.point[0])
def apply_moving(self, event, start=False, final=False): point = event.get_point() wpoint = self.canvas.point_win_to_doc(point) invtrafo = libgeom.invert_trafo(self.target.trafo) x, y = libgeom.apply_trafo_to_point(wpoint, invtrafo) x -= 0.5 y -= 0.5 angle = 0.0 if x > 0 and y > 0: angle = math.atan(y / x) elif x == 0 and y > 0: angle = math.pi / 2.0 elif x < 0 and y > 0: angle = math.atan(-x / y) + math.pi / 2.0 elif x < 0 and y == 0: angle = math.pi elif x < 0 and y < 0: angle = math.atan(y / x) + math.pi elif x == 0 and y < 0: angle = 1.5 * math.pi elif x > 0 and y < 0: angle = math.atan(x / -y) + 1.5 * math.pi elif x > 0 and y == 0: angle = 0.0 elif x == 0 and y == 0: return if event.is_ctrl(): fixed_angle = math.pi * config.ellipse_fixed_angle / 180.0 angle //= fixed_angle angle *= fixed_angle else: contra_point = self.start_point if start:contra_point = self.end_point if contra_point.is_pressed(point): angle = contra_point.get_angle() circle_type = self.orig_type if event.is_alt() and not circle_type == sk2_const.ARC_ARC: circle_type = sk2_const.ARC_CHORD if libgeom.distance([x, y]) < 0.5: circle_type = sk2_const.ARC_PIE_SLICE angle1 = self.orig_angle1 angle2 = self.orig_angle2 if start: angle1 = angle else: angle2 = angle if final: self.api.set_circle_properties_final(circle_type, angle1, angle2, self.orig_type, self.orig_angle1, self.orig_angle2, self.target) else: self.api.set_circle_properties(circle_type, angle1, angle2, self.target) self.update_points()
def update_connection(self): after = self.get_point_after() before = self.get_point_before() if self.path.is_closed(): if self.path.points[0] == self: before = self.path.points[-1] if not after and self.is_end(): after = self.path.points[0] if after and after.is_curve(): if self.is_symmetrical(): after.point[0] = libgeom.contra_point(self.point[1], self.point[2]) if self.is_smooth() and self.is_curve(): after.point[0] = libgeom.contra_point(self.point[1], self.point[2], after.point[0]) elif after and not after.is_curve(): if self.is_smooth() and self.is_curve(): l = libgeom.distance(self.point[2], after.point) if l: self.point[1] = libgeom.contra_point(after.point, self.point[2], self.point[1]) if before and before.is_curve(): if before.is_symmetrical(): before.point[1] = libgeom.contra_point(self.point[0], before.point[2]) if before.is_smooth() and self.is_curve(): before.point[1] = libgeom.contra_point(self.point[0], before.point[2], before.point[1]) elif before and not before.is_curve(): if self.is_opp_smooth(): p = before.get_point_before() if p: p = p.get_base_point() l = libgeom.distance(p, before.point) if l: self.point[0] = libgeom.contra_point(p, before.point, self.point[0])
def update_stroke(self): stroke = self.style[1] if not stroke: return if not stroke[8]: self.cache_line_width = stroke[1] self.stroke_trafo = [] else: if not self.stroke_trafo: self.stroke_trafo = [] + sk2const.NORMAL_TRAFO points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points(points, self.stroke_trafo) coef = libgeom.distance(*points) self.cache_line_width = stroke[1] * coef self.update_arrows()
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_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 _to(self, x, y, cid, max_distance): end_point = (x, y) while True: current_point = (self.x, self.y) distance = libgeom.distance(current_point, end_point) print "##", distance if distance > 0: coef = min(distance, max_distance) / distance if coef != 1.0: x, y = libgeom.midpoint(current_point, end_point, coef) cmd = dst_model.DstStitch() cmd.cid = cid cmd.dx = int(x) - self.x cmd.dy = int(y) - self.y self.dst_mt.childs.append(cmd) self.move(cmd.dx, cmd.dy) if distance < max_distance: break
def fill_gradient(self, pdfpath, fill_trafo, gradient): self.canvas.saveState() self.canvas.clipPath(pdfpath, 0, 0) if fill_trafo: self.canvas.transform(*fill_trafo) grad_type = gradient[0] sp, ep = gradient[1] stops = gradient[2] colors = [] positions = [] for offset, color in stops: positions.append(offset) colors.append(self.get_pdfcolor(color)) if grad_type == sk2const.GRADIENT_RADIAL: radius = libgeom.distance(sp, ep) self.canvas.radialGradient(sp[0], sp[1], radius, colors, positions, True) else: x0, y0 = sp x1, y1 = ep self.canvas.linearGradient(x0, y0, x1, y1, colors, positions, True) self.canvas.restoreState()
def fill_gradient(self, pdfpath, fill_trafo, gradient): self.canvas.saveState() self.canvas.clipPath(pdfpath, 0, 0) if fill_trafo: self.canvas.transform(*fill_trafo) grad_type = gradient[0] sp, ep = gradient[1] stops = gradient[2] colors = [] positions = [] for offset, color in stops: positions.append(offset) colors.append(self.get_pdfcolor(color)) if grad_type == sk2_const.GRADIENT_RADIAL: radius = libgeom.distance(sp, ep) self.canvas.radialGradient(sp[0], sp[1], radius, colors, positions, True) else: x0, y0 = sp x1, y1 = ep self.canvas.linearGradient(x0, y0, x1, y1, colors, positions, True) self.canvas.restoreState()
def process_fill(self, ctx, obj): fill = obj.style[0] fill_rule = fill[0] if fill_rule & sk2_const.FILL_CLOSED_ONLY and not obj.is_closed(): ctx.set_source_rgba(0.0, 0.0, 0.0, 0.0) return if fill_rule & sk2_const.FILL_EVENODD: ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) else: ctx.set_fill_rule(cairo.FILL_RULE_WINDING) if fill[1] == sk2_const.FILL_SOLID: if obj.fill_trafo: obj.fill_trafo = [] color = fill[2] ctx.set_source_rgba(*self.get_color(color)) elif fill[1] == sk2_const.FILL_GRADIENT: if not obj.fill_trafo: obj.fill_trafo = [] + sk2_const.NORMAL_TRAFO gradient = fill[2] points = gradient[1] if not points: obj.fill_trafo = [] + sk2_const.NORMAL_TRAFO points = libgeom.bbox_middle_points(obj.cache_bbox) if gradient[0] == sk2_const.GRADIENT_LINEAR: points = [points[0], points[2]] else: points = [[points[1][0], points[2][1]], points[2]] gradient[1] = points coords = points[0] + points[1] if gradient[0] == sk2_const.GRADIENT_LINEAR: grd = cairo.LinearGradient(*coords) else: x0, y0 = coords[:2] radius = libgeom.distance(*points) grd = cairo.RadialGradient(x0, y0, 0, x0, y0, radius) for stop in gradient[2]: grd.add_color_stop_rgba(stop[0], *self.get_color(stop[1])) matrix = cairo.Matrix(*obj.fill_trafo) matrix.invert() grd.set_matrix(matrix) ctx.set_source(grd) elif fill[1] == sk2_const.FILL_PATTERN: if not obj.fill_trafo: obj.fill_trafo = [] + sk2_const.NORMAL_TRAFO obj.fill_trafo = obj.fill_trafo[:4] + \ [obj.cache_bbox[0], obj.cache_bbox[3]] pattern_fill = fill[2] if not obj.cache_pattern_img: bmpstr = b64decode(pattern_fill[1]) image_obj = model.Pixmap(obj.config) libimg.set_image_data(self.cms, image_obj, bmpstr) libimg.flip_top_to_bottom(image_obj) if pattern_fill[0] == sk2_const.PATTERN_IMG and \ len(pattern_fill) > 2: image_obj.style[3] = deepcopy(pattern_fill[2]) libimg.update_image(self.cms, image_obj) obj.cache_pattern_img = image_obj.cache_cdata image_obj.cache_cdata = None sp = cairo.SurfacePattern(obj.cache_pattern_img) sp.set_extend(cairo.EXTEND_REPEAT) flip_matrix = cairo.Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) if len(pattern_fill) > 3: pattern_matrix = cairo.Matrix(*pattern_fill[3]) pattern_matrix.invert() flip_matrix = flip_matrix * pattern_matrix trafo_matrix = cairo.Matrix(*obj.fill_trafo) trafo_matrix.invert() flip_matrix = flip_matrix * trafo_matrix sp.set_matrix(flip_matrix) ctx.set_source(sp) canvas_matrix = ctx.get_matrix() canvas_trafo = libcairo.get_trafo_from_matrix(canvas_matrix) zoom = canvas_trafo[0] if zoom * abs(obj.fill_trafo[0]) > .98: ctx.get_source().set_filter(cairo.FILTER_NEAREST)
def process_fill(self, ctx, obj): fill = obj.style[0] fill_rule = fill[0] if fill_rule & sk2const.FILL_CLOSED_ONLY and not obj.is_closed(): ctx.set_source_rgba(0.0, 0.0, 0.0, 0.0) return if fill_rule & sk2const.FILL_EVENODD: ctx.set_fill_rule(cairo.FILL_RULE_EVEN_ODD) else: ctx.set_fill_rule(cairo.FILL_RULE_WINDING) if fill[1] == sk2const.FILL_SOLID: if obj.fill_trafo: obj.fill_trafo = [] color = fill[2] ctx.set_source_rgba(*self.get_color(color)) elif fill[1] == sk2const.FILL_GRADIENT: if not obj.fill_trafo: obj.fill_trafo = [] + sk2const.NORMAL_TRAFO gradient = fill[2] points = gradient[1] if not points: obj.fill_trafo = [] + sk2const.NORMAL_TRAFO points = libgeom.bbox_middle_points(obj.cache_bbox) if gradient[0] == sk2const.GRADIENT_LINEAR: points = [points[0], points[2]] else: points = [[points[1][0], points[2][1]], points[2]] gradient[1] = points coords = points[0] + points[1] if gradient[0] == sk2const.GRADIENT_LINEAR: grd = cairo.LinearGradient(*coords) else: x0, y0 = coords[:2] radius = libgeom.distance(*points) grd = cairo.RadialGradient(x0, y0, 0, x0, y0, radius) for stop in gradient[2]: grd.add_color_stop_rgba(stop[0], *self.get_color(stop[1])) matrix = cairo.Matrix(*obj.fill_trafo) matrix.invert() extend = cairo.EXTEND_PAD if len(gradient) > 3: extend = EXTEND[gradient[3]] grd.set_extend(extend) grd.set_matrix(matrix) ctx.set_source(grd) elif fill[1] == sk2const.FILL_PATTERN: if not obj.fill_trafo: obj.fill_trafo = [] + sk2const.NORMAL_TRAFO obj.fill_trafo = obj.fill_trafo[:4] + [ obj.cache_bbox[0], obj.cache_bbox[3] ] pattern_fill = fill[2] sp = cairo.SurfacePattern(self.get_pattern_surface(obj)) sp.set_extend(cairo.EXTEND_REPEAT) flip_matrix = cairo.Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) if len(pattern_fill) > 3: pattern_matrix = cairo.Matrix(*pattern_fill[3]) pattern_matrix.invert() flip_matrix = flip_matrix * pattern_matrix trafo_matrix = cairo.Matrix(*obj.fill_trafo) trafo_matrix.invert() flip_matrix = flip_matrix * trafo_matrix sp.set_matrix(flip_matrix) ctx.set_source(sp) canvas_matrix = ctx.get_matrix() canvas_trafo = libcairo.get_trafo_from_matrix(canvas_matrix) zoom = canvas_trafo[0] if zoom * abs(obj.fill_trafo[0]) > .98: ctx.get_source().set_filter(cairo.FILTER_NEAREST)
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
def make_v1_objects(self, parent_instr, obj): if obj.is_group and obj.childs: kwargs = { 'bbox': (0, 0, 0, 0), 'tail': '\x00\x00', } group_instr = mkinstr(self.cmx_cfg, identifier=cmx_const.BEGIN_GROUP, **kwargs) parent_instr.add(group_instr) for item in obj.childs: self.make_v1_objects(group_instr, item) group_instr.add( mkinstr(self.cmx_cfg, identifier=cmx_const.END_GROUP)) group_instr.data['bbox'] = group_instr.get_bbox() elif obj.is_primitive: curve = obj.to_curve() curve.update() if not curve: return elif curve.is_group: self.make_v1_objects(parent_instr, curve) elif curve.paths: close_flag = False style = curve.style attrs = { 'style_flags': 1 if style[0] else 0, 'fill_type': cmx_const.INSTR_FILL_EMPTY, } attrs['style_flags'] += 2 if style[1] else 0 if style[0] and style[0][1] == sk2const.FILL_SOLID: attrs['fill_type'] = cmx_const.INSTR_FILL_UNIFORM attrs['fill'] = (self._add_color(style[0][2]), 1) close_flag = not style[0][0] & sk2const.FILL_CLOSED_ONLY if style[1]: outline = style[1] if curve.stroke_trafo: points = [[0.0, 0.0], [1.0, 0.0]] points = libgeom.apply_trafo_to_points( points, obj.stroke_trafo) coef = libgeom.distance(*points) outline = deepcopy(outline) outline[1] *= coef attrs['outline'] = self._add_outline(outline) trafo = libgeom.multiply_trafo( curve.trafo, [self.coef, 0.0, 0.0, self.coef, 0.0, 0.0]) paths = libgeom.apply_trafo_to_paths(curve.paths, trafo) attrs['points'] = [] attrs['nodes'] = [] for path in paths: # Force path closing if close_flag and not path[2] == sk2const.CURVE_CLOSED: path = deepcopy(path) path[2] = sk2const.CURVE_CLOSED p = path[1][-1] if len(path[1][-1]) == 2 \ else path[1][-1][-1] if not path[0] == p: path[1].append([] + path[0]) x, y = path[0] attrs['points'].append((int(x), int(y))) node = cmx_const.NODE_MOVE + cmx_const.NODE_USER if path[2] == sk2const.CURVE_CLOSED: node += cmx_const.NODE_CLOSED attrs['nodes'].append(node) for point in path[1]: if len(point) == 2: x, y = point attrs['points'].append((int(x), int(y))) node = cmx_const.NODE_LINE + cmx_const.NODE_USER attrs['nodes'].append(node) else: p0, p1, p2, flag = point for item in (p0, p1, p2): x, y = item attrs['points'].append((int(x), int(y))) node = cmx_const.NODE_ARC attrs['nodes'].append(node) attrs['nodes'].append(node) node = cmx_const.NODE_CURVE + cmx_const.NODE_USER attrs['nodes'].append(node) if path[2] == sk2const.CURVE_CLOSED: attrs['nodes'][-1] += cmx_const.NODE_CLOSED attrs['bbox'] = self._make_bbox(curve.cache_bbox) attrs['tail'] = '' curve_instr = mkinstr(self.cmx_cfg, identifier=cmx_const.POLYCURVE, **attrs) parent_instr.add(curve_instr)