def split_path_at(self, at, cross_id=0): index = int(at) t = at - index if not at or at == float(self.get_len() - 1): new_path = deepcopy(self.path) new_path[-1] = 0 path_obj = PathObject(new_path) path_obj.start_id = path_obj.end_id = cross_id path_obj.obj_id = self.obj_id return[path_obj, ] elif not t: segs = self.get_segments() new_segs1 = segs[:index] start1 = self.get_start_point() new_segs2 = segs[index:] start2 = bezier_base_point(self.get_node(index)) else: segs = self.get_segments() base_point = bezier_base_point(self.get_node(index)) end, start2, seg0 = self.split_seg(base_point, segs[index], t) new_segs1 = segs[:index] + [end, ] start1 = self.get_start_point() new_segs2 = segs[index:] if not seg0 is None: new_segs2[0] = seg0 path_obj1 = PathObject([start1, new_segs1, 0]) path_obj1.start_id = self.start_id path_obj1.end_id = cross_id path_obj1.obj_id = self.obj_id path_obj2 = PathObject([start2, new_segs2, 0]) path_obj2.start_id = cross_id path_obj2.obj_id = self.obj_id path_obj2.end_id = self.end_id return[path_obj1, path_obj2]
def split_path_at(self, at, cross_id=0): index = int(at) t = at - index if not at or at == float(self.get_len() - 1): new_path = deepcopy(self.path) new_path[-1] = 0 path_obj = PathObject(new_path) path_obj.start_id = path_obj.end_id = cross_id path_obj.obj_id = self.obj_id return [path_obj, ] elif not t: segs = self.get_segments() new_segs1 = segs[:index] start1 = self.get_start_point() new_segs2 = segs[index:] start2 = bezier_base_point(self.get_node(index)) else: segs = self.get_segments() base_point = bezier_base_point(self.get_node(index)) end, start2, seg0 = self.split_seg(base_point, segs[index], t) new_segs1 = segs[:index] + [end, ] start1 = self.get_start_point() new_segs2 = segs[index:] if not seg0 is None: new_segs2[0] = seg0 path_obj1 = PathObject([start1, new_segs1, 0]) path_obj1.start_id = self.start_id path_obj1.end_id = cross_id path_obj1.obj_id = self.obj_id path_obj2 = PathObject([start2, new_segs2, 0]) path_obj2.start_id = cross_id path_obj2.obj_id = self.obj_id path_obj2.end_id = self.end_id return [path_obj1, path_obj2]
def _split_arcs_at_point(angle): segments = deepcopy(sk2_const.STUB_ARCS) index = _get_arc_index(angle) if angle in EXTREME_ANGLES: index += 1 if angle in START_ANGLES: index = 0 points = segments[index:] + segments[:index] start = bezier_base_point(points[-1]) return [ [start, points, sk2_const.CURVE_CLOSED], ] else: points = segments[index + 1:] + segments[:index] seg_start = bezier_base_point(points[-1]) seg_end = segments[index] t = 2.0 * (angle - EXTREME_ANGLES[index]) / math.pi new_point, new_end_point = split_bezier_curve(seg_start, seg_end, t) new_point[3] = sk2_const.NODE_SMOOTH new_end_point[3] = sk2_const.NODE_SMOOTH points[-1][3] = sk2_const.NODE_SMOOTH start = bezier_base_point(new_point) return [ [ start, [ new_end_point, ] + points + [ new_point, ], sk2_const.CURVE_CLOSED ], ]
def close_path(self): self.path[-1] = 1 if not self.path[0] == bezier_base_point(self.path[1][-1]): if equal(self.path[0], bezier_base_point(self.path[1][-1])): if is_bezier(self.path[1][-1]): self.path[1][-1][3] = self.get_start_point() else: self.path[1][-1] = self.get_start_point() else: self.path[1].append(self.get_start_point())
def make_path(segments, close=1): """ This function prepares a path given by a list of lists of coordinates for the use with app. """ first_point = segments[0][0] last_point = first_point new_path = [[] + first_point, [], sk2const.CURVE_OPENED] points = new_path[1] for seg in segments: if seg[0] != last_point: points.append(deepcopy(seg[0])) if len(seg) == 2: points.append(deepcopy(seg[1])) last_point = seg[1] while len(seg) >= 4: points.append( deepcopy([seg[1], seg[2], seg[3], sk2const.NODE_CUSP])) last_point = seg[3] seg = seg[3:] if close: new_path[2] = sk2const.CURVE_CLOSED if not new_path[0] == bezier_base_point(points[-1]): points.append(deepcopy(new_path[0])) return new_path
def get_points(self): result = [ self.get_start_point(), ] for item in self.get_segments(): result.append(bezier_base_point(item)) return result
def make_path(segments, close=1): """ This function prepares a path given by a list of lists of coordinates for the use with app. """ first_point = segments[0][0] last_point = first_point new_path = [[] + first_point, [], sk2_const.CURVE_OPENED] points = new_path[1] for seg in segments: if seg[0] != last_point: print "Need to fix up! Should not happen." points.append(deepcopy(seg[0])) if len (seg) == 2: points.append(deepcopy(seg[1])) last_point = seg[1] while len (seg) >= 4: points.append(deepcopy([seg[1], seg[2], seg[3], sk2_const.NODE_CUSP])) last_point = seg[3] seg = seg[3:] if close: new_path[2] = sk2_const.CURVE_CLOSED if not new_path[0] == bezier_base_point(points[-1]): points.append(deepcopy(new_path[0])) return new_path
def get_seg_as_path(self, index): if not index: start = self.get_start_point() else: start = bezier_base_point(self.get_seg(index - 1)) return [start, [ self.get_seg(index), ], sk2_const.CURVE_OPENED]
def get_test_point(self, index=0): if index >= len(self.path[1]): index = len(self.path[1]) - 1 if not index: base_point = self.get_start_point() else: base_point = bezier_base_point(self.get_seg(index - 1)) point = self.get_seg(index) return self.split_seg(base_point, point)[1]
def _split_arcs_at_point(angle): segments = deepcopy(sk2_const.STUB_ARCS) index = _get_arc_index(angle) if angle in EXTREME_ANGLES: if angle in START_ANGLES:index = 0 points = segments[index:] + segments[:index] start = bezier_base_point(points[-1]) return [[start, points, sk2_const.CURVE_CLOSED], ] else: points = segments[index + 1:] + segments[:index] seg_start = bezier_base_point(points[-1]) seg_end = segments[index] t = 2.0 * (angle - EXTREME_ANGLES[index]) / math.pi new_point, new_end_point = split_bezier_curve(seg_start, seg_end, t) new_point[3] = sk2_const.NODE_SMOOTH new_end_point[3] = sk2_const.NODE_SMOOTH points[-1][3] = sk2_const.NODE_SMOOTH start = bezier_base_point(new_point) return [[start, [new_end_point, ] + points + [new_point, ], sk2_const.CURVE_CLOSED], ]
def create_stroke_outline(path, radius, linejoin=sk2const.JOIN_MITER, captype=sk2const.CAP_BUTT, miter_limit=MITER_LIMIT): """ Outlines a single stroke. Returns two lists of lists of bezier segments for both sides of the stroke. """ fw_segments = [] bw_segments = [] last_point = None segs = [path[0], ] + path[1] startpoint = [] + path[0] for i in range(len(segs)): segment = unpack_seg(segs[i], startpoint) startpoint = bezier_base_point(segs[i]) if not segment[0]: if last_point: c1 = sub_points(segment[2], last_point) if not c1 == [0.0]: t1 = mult_point(normalize(c1), radius) fw_segments.append( [add_points(last_point, [t1[1], -t1[0]]), add_points(segment[2], [t1[1], -t1[0]])]) bw_segments.insert(0, [sub_points(segment[2], [t1[1], -t1[0]]), sub_points(last_point, [t1[1], -t1[0]])]) last_point = segment[2] else: segments = build_parallel([last_point, segment[1][0], segment[1][1], segment[2]], radius) fw_segments.append(segments) segments = build_parallel([segment[2], segment[1][1], segment[1][0], last_point], radius) bw_segments.insert(0, segments) last_point = segment[2] # Connect segments if necessary for item in [fw_segments, bw_segments]: join_segs(item, radius, linejoin, miter_limit, path[2] == sk2const.CURVE_CLOSED) # Set caps for unclosed paths if not path[2] == sk2const.CURVE_CLOSED: fw_segments.insert(0, get_cap_segment(bw_segments[-1][-1], fw_segments[0][0], captype)) bw_segments.insert(0, get_cap_segment(fw_segments[-1][-1], bw_segments[0][0], captype)) return fw_segments, bw_segments
def create_stroke_outline (path, radius, linejoin=sk2_const.JOIN_MITER, captype=sk2_const.CAP_BUTT, miter_limit=MITER_LIMIT): """ Outlines a single stroke. Returns two lists of lists of bezier segments for both sides of the stroke. """ fw_segments = [] bw_segments = [] last_point = None segs = [path[0], ] + path[1] startpoint = [] + path[0] for i in range (len(segs)): segment = unpack_seg(segs[i], startpoint) startpoint = bezier_base_point(segs[i]) if not segment[0]: if last_point: c1 = sub_points(segment[2], last_point) if not c1 == [0.0]: t1 = mult_point(normalize(c1), radius) fw_segments.append( [add_points(last_point, [t1[1], -t1[0]]), add_points(segment[2], [t1[1], -t1[0]])]) bw_segments.insert(0, [sub_points(segment[2], [t1[1], -t1[0]]), sub_points(last_point, [t1[1], -t1[0]])]) last_point = segment[2] else: segments = build_parallel([last_point, segment[1][0], segment[1][1], segment[2]], radius) fw_segments.append(segments) segments = build_parallel([segment[2], segment[1][1], segment[1][0], last_point], radius) bw_segments.insert(0, segments) last_point = segment[2] # Connect segments if necessary for item in [fw_segments, bw_segments]: join_segs(item, radius, linejoin, miter_limit, path[2] == sk2_const.CURVE_CLOSED) # Set caps for unclosed paths if not path[2] == sk2_const.CURVE_CLOSED: fw_segments.insert(0, get_cap_segment (bw_segments[-1][-1], fw_segments[0][0], captype)) bw_segments.insert(0, get_cap_segment (fw_segments[-1][-1], bw_segments[0][0], captype)) return fw_segments, bw_segments
def _exclude_segment_from_arcs(angle1, angle2): segments = deepcopy(sk2_const.STUB_ARCS) points = [] start_index = 0 end_index = 0 start_point = None if angle1 in EXTREME_ANGLES: start_index = _get_arc_index(angle1) + 1 if angle1 in START_ANGLES: start_index = 0 start_point = bezier_base_point(segments[start_index - 1]) points = segments[start_index:] + segments[:start_index] else: start_index = _get_arc_index(angle1) seg_start = bezier_base_point(segments[start_index - 1]) seg_end = segments[start_index] t = 2.0 * (angle1 - EXTREME_ANGLES[start_index]) / math.pi new_point, new_end_point = split_bezier_curve(seg_start, seg_end, t) new_end_point[3] = sk2_const.NODE_SMOOTH points = segments[start_index + 1:] + segments[:start_index] points = [ new_end_point, ] + points + [ new_point, ] start_point = bezier_base_point(new_point) if angle2 in EXTREME_ANGLES and angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) + 1 if angle2 in START_ANGLES: end_index = 0 index = points.index(segments[end_index]) points = points[:index] elif angle2 in EXTREME_ANGLES and not angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) + 1 if angle2 in START_ANGLES: end_index = 0 if segments[end_index] in points: index = points.index(segments[end_index]) else: index = -1 points = points[:index] elif not angle2 in EXTREME_ANGLES and angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) seg_start = bezier_base_point(segments[end_index - 1]) seg_end = segments[end_index] t = 2.0 * (angle2 - EXTREME_ANGLES[end_index]) / math.pi new_point = split_bezier_curve(seg_start, seg_end, t)[0] index = points.index(segments[end_index]) points = points[:index] points += [ new_point, ] else: end_index = _get_arc_index(angle2) if not start_index == end_index: seg_start = bezier_base_point(segments[end_index - 1]) seg_end = segments[end_index] t = 2.0 * (angle2 - EXTREME_ANGLES[end_index]) / math.pi new_point = split_bezier_curve(seg_start, seg_end, t)[0] if segments[end_index] in points: index = points.index(segments[end_index]) else: index = -1 points = points[:index] points += [ new_point, ] elif angle2 > angle1: da = angle2 - angle1 t = da / (math.pi / 2.0 - (angle1 - EXTREME_ANGLES[end_index])) seg_start = start_point seg_end = points[0] new_point = split_bezier_curve(seg_start, seg_end, t)[0] points = [ new_point, ] else: da = angle1 - angle2 t = 1.0 - da / (angle1 - EXTREME_ANGLES[end_index]) seg_start = bezier_base_point(points[-2]) seg_end = points[-1] points[-1] = split_bezier_curve(seg_start, seg_end, t)[0] return [ [start_point, points, sk2_const.CURVE_CLOSED], ]
def _exclude_segment_from_arcs(angle1, angle2): segments = deepcopy(sk2_const.STUB_ARCS) points = [] start_index = 0 end_index = 0 start_point = None if angle1 in EXTREME_ANGLES: start_index = _get_arc_index(angle1) + 1 if angle1 in START_ANGLES:start_index = 0 start_point = bezier_base_point(segments[start_index - 1]) points = segments[start_index:] + segments[:start_index] else: start_index = _get_arc_index(angle1) seg_start = bezier_base_point(segments[start_index - 1]) seg_end = segments[start_index] t = 2.0 * (angle1 - EXTREME_ANGLES[start_index]) / math.pi new_point, new_end_point = split_bezier_curve(seg_start, seg_end, t) new_end_point[3] = sk2_const.NODE_SMOOTH points = segments[start_index + 1:] + segments[:start_index] points = [new_end_point, ] + points + [new_point, ] start_point = bezier_base_point(new_point) if angle2 in EXTREME_ANGLES and angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) + 1 if angle2 in START_ANGLES:end_index = 0 index = points.index(segments[end_index]) points = points[:index] elif angle2 in EXTREME_ANGLES and not angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) + 1 if angle2 in START_ANGLES:end_index = 0 if segments[end_index] in points: index = points.index(segments[end_index]) else: index = -1 points = points[:index] elif not angle2 in EXTREME_ANGLES and angle1 in EXTREME_ANGLES: end_index = _get_arc_index(angle2) seg_start = bezier_base_point(segments[end_index - 1]) seg_end = segments[end_index] t = 2.0 * (angle2 - EXTREME_ANGLES[end_index]) / math.pi new_point = split_bezier_curve(seg_start, seg_end, t)[0] index = points.index(segments[end_index]) points = points[:index] points += [new_point, ] else: end_index = _get_arc_index(angle2) if not start_index == end_index: seg_start = bezier_base_point(segments[end_index - 1]) seg_end = segments[end_index] t = 2.0 * (angle2 - EXTREME_ANGLES[end_index]) / math.pi new_point = split_bezier_curve(seg_start, seg_end, t)[0] if segments[end_index] in points: index = points.index(segments[end_index]) else: index = -1 points = points[:index] points += [new_point, ] elif angle2 > angle1: da = angle2 - angle1 t = da / (math.pi / 2.0 - (angle1 - EXTREME_ANGLES[end_index])) seg_start = start_point seg_end = points[0] new_point = split_bezier_curve(seg_start, seg_end, t)[0] points = [new_point, ] else: da = angle1 - angle2 t = 1.0 - da / (angle1 - EXTREME_ANGLES[end_index]) seg_start = bezier_base_point(points[-2]) seg_end = points[-1] points[-1] = split_bezier_curve(seg_start, seg_end, t)[0] return [[start_point, points, sk2_const.CURVE_CLOSED], ]
def get_points(self): result = [self.get_start_point(), ] for item in self.get_segments(): result.append(bezier_base_point(item)) return result
def get_seg_as_path(self, index): if not index: start = self.get_start_point() else: start = bezier_base_point(self.get_seg(index - 1)) return [start, [self.get_seg(index), ], sk2_const.CURVE_OPENED]