def calc_pentagon_dimensions(self): bbox = calc_overall_bbox(self.new_pentagon()) self._pent_width, self._pent_height = abs(bbox[1] - bbox[0]), abs(bbox[3] - bbox[2]) self._pent_x, self._pent_y = min(bbox[0], bbox[1]), min(bbox[2], bbox[3])
def calc_pattern_viewbox(self): bbox = calc_overall_bbox(self.cairo_group) vbwidth = self.cairo_group[1][3].end.real + self.pent_height vbheight = self.pent_height * 2 self._pattern_viewbox = min(bbox[0], bbox[1]) + self.cairo_group[1][2].end.real, \ min(bbox[2], bbox[3]), vbwidth * self.repetitions, \ vbheight * self.repetitions
def draw_path_clip(self): path_filename = "{}/path_clip_{}.svg".format( self.output_folder, basename(self.filename).replace(".svg", "")) dwg = Drawing(path_filename) image_bbox = calc_overall_bbox(self.tile_paths) dx = self.pent_x - min(image_bbox[0], image_bbox[1]) dy = self.pent_y - min(image_bbox[2], image_bbox[3]) dwg.add( dwg.path( **{ "d": self.new_pentagon().d(), "fill": "none", 'stroke-width': 4, 'stroke': rgb(0, 0, 0) })) neg_transform = "translate({}, {})".format(-dx, -dy) transform = "translate({}, {})".format(dx, dy) clip_path = dwg.defs.add( dwg.clipPath(id="pent_path", transform=neg_transform)) clip_path.add(dwg.path(d=self.new_pentagon().d())) group = dwg.add( dwg.g(clip_path="url(#pent_path)", transform=transform, id="clippedpath")) for i, path in enumerate(self.tile_paths): group.add( dwg.path(d=path.d(), style=self.tile_attributes[i].get('style'), id=self.tile_attributes[i]['id'])) dwg.add(dwg.use("#clippedpath", transform="transform(100, 100)")) dwg.viewbox(self.pent_x, self.pent_y, self.pent_width, self.pent_height) dwg.save() xml = xml.dom.minidom.parse(path_filename) open(path_filename, "w").write(xml.toprettyxml())
def flatten_scene(pScene): lNode = pScene.GetRootNode() if not lNode: return for i in range(lNode.GetChildCount()): lChildNode = lNode.GetChild(i) if lChildNode.GetNodeAttribute() is None: continue lAttributeType = (lChildNode.GetNodeAttribute().GetAttributeType()) if lAttributeType != FbxNodeAttribute.eMesh: continue lMesh = lChildNode.GetNodeAttribute() projected_points = {} control_points = lMesh.GetControlPoints() start_point = 0 poly_paths = [] for polygon_num in range(lMesh.GetPolygonCount()): corners = [] for corner in range(3): corners.append(lMesh.GetPolygonVertex(polygon_num, corner)) # first, check if any of the control points are already projected flattened = [] for j, corner in enumerate(corners): if corner in projected_points: flattened.append(projected_points[corner]) continue target_corner = corners[j - 1] current_vec = control_points[corner] target_vec = control_points[target_corner] angle = acos( current_vec.DotProduct(target_vec) / (current_vec.Length() * target_vec.Length())) length = current_vec.Distance(target_vec) # find where the last point was. If it doesn't exist, use the start point start_corner = projected_points[target_corner] \ if target_corner in projected_points else start_point flattened_corner = start_corner + length * (cos(angle) + 1j * sin(angle)) projected_points[corner] = flattened_corner start_point = flattened_corner flattened.append(flattened_corner) poly_paths.append( Path(*[ Line(start=flattened[j], end=flattened[j - 1]) for j in range(3) ])) dwg = Drawing("mesh{}.svg".format(i), profile='tiny') for poly_path in poly_paths: dwg.add( dwg.path( **{ 'd': poly_path.d(), 'fill': "none", 'stroke-width': 4, 'stroke': rgb(0, 0, 0) })) bbox = calc_overall_bbox(poly_paths) width, height = abs(bbox[1] - bbox[0]), abs(bbox[3] - bbox[2]) dwg.viewbox(min(bbox[0], bbox[1]), min(bbox[2], bbox[3]), width, height) dwg.save()
def flatten_shape(i, all_paths, merge_paths): dwg = Drawing("merge_output%s.svg" % i, profile='tiny') def draw_line(start, end, offset=0.0): start += offset end += offset dwg.add( dwg.line(start=(start.real, start.imag), end=(end.real, end.imag), stroke_width=4, stroke=rgb(255, 0, 0))) dwg.add( dwg.path( **{ 'd': all_paths[i].d(), 'fill': "none", 'stroke-width': 4, 'stroke': rgb(0, 0, 0) })) dwg.add( dwg.path( **{ 'd': merge_paths[i].d(), 'fill': "none", 'stroke-width': 4, 'stroke': rgb(255, 0, 0) })) bbox = calc_overall_bbox(all_paths[i]) width, height = abs(bbox[1] - bbox[0]), abs(bbox[3] - bbox[2]) margin = 40 lower = min(bbox[2], bbox[3]) + height + margin left = min(bbox[0], bbox[1]) + margin def draw_marker(loc, col=rgb(255, 0, 0), offset=(left, lower)): dwg.add( dwg.circle(center=(loc.real + offset[0], loc.imag + offset[1]), r=4, fill=col)) max_axis = max(width, height) num_lines = 10 points = [merge_paths[i].point(j / num_lines) for j in range(num_lines)] + [merge_paths[i].point(1.0)] angles = [ asin((points[j + 1].imag - points[j].imag) / abs(points[j + 1] - points[j])) for j in range(num_lines) ] ends = [max_axis * (sin(angle) + cos(angle) * 1j) for angle in angles] intersection_clips = [] for j, end in enumerate(ends): end_point = end + points[j] intersections = other_paths[i].intersect( Line(start=points[j], end=end_point)) for intersection in intersections[0]: intersection_point = intersection[1].point(intersection[2]) target = merge_paths[i].length() * ( 1 - j / num_lines) + abs(intersection_point - points[j]) * 1j intersection_clips.append( PathClip(index=other_paths[i].index(intersection[1]), t=intersection[2], target=target)) if j % 10 == 0: draw_line(points[j], intersection_point) draw_marker(intersection_point, rgb(0, 255, 0), (0, 0)) break # make the flexed points by chopping the chunks of the other paths out, then # translating and rotating them such that their end points line up with the diff lines def transform_side(sides, targets, angle_offset=0): def angle(point1, point2): diff = point1 - point2 if diff.real == 0: return 90.0 return atan(diff.imag / diff.real) * 180.0 / pi # change this so that it has two targets transformed_side = Path(*sides) source_angle = angle(transformed_side.end, transformed_side.start) - \ angle(targets[0], targets[1]) transformed_side = transformed_side.rotated(-source_angle + angle_offset) source = transformed_side.end if angle_offset == 0 else transformed_side.start diff = targets[1] - source transformed_side = transformed_side.translated(diff) draw_marker(targets[0], rgb(0, 200, 200)) draw_marker(targets[1], rgb(0, 255, 255)) transformed_diff = abs(transformed_side.start - transformed_side.end) targets_diff = abs(targets[0] - targets[1]) if transformed_diff < targets_diff: transformed_side.insert( 0, Line(start=targets[0], end=transformed_side.start)) elif transformed_diff > targets_diff: # pop elements off until the transformed diff is smaller while transformed_diff > targets_diff: transformed_side.pop(0) transformed_diff = abs(transformed_side.start - transformed_side.end) print("path", transformed_side) print("path is longer", transformed_diff - targets_diff) return transformed_side start_index = 0 curr_t = 0 flexed_path = [] t_resolution = 0.01 if intersection_clips[0].index > intersection_clips[-1].index or \ (intersection_clips[0].index == intersection_clips[-1].index and intersection_clips[0].t > intersection_clips[-1].t): intersection_clips.reverse() # add the end of the shape to the intersection clips intersection_clips.append( PathClip(index=len(other_paths[i]) - 1, t=1.0, target=merge_paths[i].length())) last_target = 0 for clip in intersection_clips: sides = [] print("boundaries", start_index, clip.index, curr_t, clip.t) upper_t = clip.t if start_index == clip.index else 1.0 while start_index <= clip.index and curr_t < upper_t: curr_seg = other_paths[i][start_index] while curr_t < upper_t: max_t = curr_t + t_resolution if curr_t + t_resolution < clip.t else clip.t sides.append( Line(start=curr_seg.point(curr_t), end=curr_seg.point(max_t))) curr_t += t_resolution curr_t = upper_t if start_index != clip.index: curr_t = 0.0 if upper_t == 1.0: start_index += 1 upper_t = clip.t if start_index == clip.index else 1.0 if len(sides) != 0: flexed_path.append( transform_side(sides, [last_target, clip.target])) last_target = clip.target straight_path = [Line(start=0, end=merge_paths[i].length())] for p in flexed_path: p = p.translated(left + lower * 1j) dwg.add( dwg.path(d=p.d(), fill="none", stroke_width=4, stroke=rgb(255, 0, 0))) transformed_path = flexed_path + straight_path transformed_path = Path(*transformed_path).translated(left + lower * 1j) dwg.add( dwg.path(d=transformed_path.d(), fill="none", stroke_width=4, stroke=rgb(0, 0, 0))) bbox = calc_overall_bbox(list(all_paths[i]) + list(transformed_path)) width, height = abs(bbox[1] - bbox[0]), abs(bbox[3] - bbox[2]) dwg.viewbox(min(bbox[0], bbox[1]), min(bbox[2], bbox[3]), width, height) dwg.save() return flexed_path
# for each of the shapes, construct a new shape where the section in the merge paths # is straight merge_paths = [ Path(*list(all_paths[i])[start_one:end_one]) for i in range(0, 2) ] other_paths = [ Path(*list(all_paths[i])[end_one:] + list(all_paths[i])[0:start_one]) for i in range(0, 2) ] flexed_paths = [ flatten_shape(i, all_paths, merge_paths) for i in range(0, 2) ] dwg = Drawing("flexed_sides.svg", profile="tiny") upper_sizes = [0, 0] for i, path_list in enumerate(flexed_paths): bbox = calc_overall_bbox(path_list) if i == 0: upper_sizes = [max(bbox[0], bbox[1]), abs(bbox[3] - bbox[2])] transform = "scale(1, {})".format(-1 if i == 0 else 1) group = dwg.add(dwg.g(transform=transform)) for path in path_list: path = path.translated(-min(bbox[2], bbox[3]) * 1j) group.add( dwg.path( **{ 'd': path.d(), 'fill': "none", 'stroke-width': 4, 'stroke': rgb(0, 0, 0) })) bbox = calc_overall_bbox(flexed_paths[1])
def draw_pattern(self): self.output_filename = "{}/snake_tiling_m_{}_{}.svg".format( self.output_folder, self.dx, self.dy) dwg = Drawing(self.output_filename) # add background panel background_clippath = dwg.rect(insert=(self.pattern_viewbox[0], self.pattern_viewbox[1]), size=('100%', '100%')) background_panel = dwg.rect(insert=(self.pattern_viewbox[0], self.pattern_viewbox[1]), size=('101%', '101%'), fill='#3072a2') clip_path = dwg.defs.add(dwg.clipPath(id="background_panel")) clip_path.add(background_clippath) clipped_drawing = dwg.add( dwg.g(clip_path="url(#background_panel)", id="clippedpath")) clipped_drawing.add(background_panel) current_color = 0 def add_pentagon(group, transform, current_color, draw_pent=True): pent_group = group.add( dwg.g(transform=format_transform(*transform))) if draw_pent: pent_group.add( dwg.path( **{ 'd': self.new_pentagon().d(), 'fill': self.colors[current_color % len(self.colors)], 'stroke-width': 4, 'stroke': rgb(0, 0, 0) })) return pent_group for y in range(self.num_down): transform = "translate({}, {})".format(0, self.rep_spacing * y) dgroup = clipped_drawing.add(dwg.g(transform=transform)) for x in range(self.num_across): # if x is odd, point 1 of pent 1 needs to be attached to point 3 of pent 2 if x % 2 == 1: dx = int( x / 2 ) * self.rep_spacing + self.pent_width * 2 + self.column_offset.real diff = dx + self.column_offset.imag * 1j else: diff = int(x / 2) * self.rep_spacing for i in range(4): snake_bbox = calc_overall_bbox(self.tile_paths) snake_width, snake_height = abs(snake_bbox[0] - snake_bbox[1]), \ abs(snake_bbox[2] - snake_bbox[3]) pent_group = add_pentagon( dgroup, (self.transforms[i][0], self.transforms[i][1] + diff), current_color, draw_pent=False) for i, path in enumerate(self.tile_paths): stransform = 'translate({},{})'.format( snake_width * self.dx, snake_height * self.dy) pent_group.add( dwg.path( **{ 'd': path.d(), 'style': self.tile_attributes[i].get( 'style'), 'id': self.tile_attributes[i]['id'], 'transform': stransform })) current_color += 1 dwg.viewbox(*self.pattern_viewbox) dwg.save()