def render(self, text, origin=None, skew=0, line_spacing=1.0, pitch=1.0, align=None): result = ContourModel() if origin is None: origin = Point(0, 0, 0) if align is None: align = TEXT_ALIGN_LEFT base = origin letter_spacing = self.letterspacing * pitch word_spacing = self.wordspacing * pitch line_factor = self.default_linespacing * self.linespacingfactor \ * line_spacing for line in text.splitlines(): current_line = ContourModel() line_height = self.default_height for character in line: if character == " ": base = base.add(Point(word_spacing, 0, 0)) elif character in self.letters.keys(): charset_letter = self.letters[character] new_model = ContourModel() for line in charset_letter.get_positioned_lines(base, skew=skew): new_model.append(line, allow_reverse=True) for polygon in new_model.get_polygons(): # add polygons instead of lines -> more efficient current_line.append(polygon) # update line height line_height = max(line_height, charset_letter.maxy()) # shift the base position base = base.add(Point( charset_letter.maxx() + letter_spacing, 0, 0)) else: # unknown character - add a small whitespace base = base.add(Point(letter_spacing, 0, 0)) # go to the next line base = Point(origin.x, base.y - line_height * line_factor, origin.z) if not current_line.maxx is None: if align == TEXT_ALIGN_CENTER: current_line.shift(-current_line.maxx / 2, 0, 0) elif align == TEXT_ALIGN_RIGHT: current_line.shift(-current_line.maxx, 0, 0) else: # left align if current_line.minx != 0: current_line.shift(-current_line.minx, 0, 0) for polygon in current_line.get_polygons(): result.append(polygon) # the text should be just above the x axis if result.miny: # don't shift, if result.miny is None (e.g.: no content) or zero result.shift(0, -result.miny, 0) return result
def union(self, other): """ This "union" of two polygons only works for polygons without shared edges. TODO: fix the issues of shared edges! """ # don't import earlier to avoid circular imports from pycam.Geometry.Model import ContourModel # check if one of the polygons is completely inside of the other if self.is_polygon_inside(other): return [self] if other.is_polygon_inside(self): return [other] # check if there is any overlap at all if not self.is_overlap(other): # no changes return [self, other] contour = ContourModel(self.plane) def get_outside_lines(poly1, poly2): result = [] for line in poly1.get_lines(): collisions = [] for o_line in poly2.get_lines(): cp, dist = o_line.get_intersection(line) if (cp is not None) and (0 < dist < 1): collisions.append((cp, dist)) # sort the collisions according to the distance collisions.append((line.p1, 0)) collisions.append((line.p2, 1)) collisions.sort(key=lambda collision: collision[1]) for index in range(len(collisions) - 1): p1 = collisions[index][0] p2 = collisions[index + 1][0] if pdist(p1, p2) < epsilon: # ignore zero-length lines continue # Use the middle between p1 and p2 to check the # inner/outer state. p_middle = pdiv(padd(p1, p2), 2) p_inside = (poly2.is_point_inside(p_middle) and not poly2.is_point_on_outline(p_middle)) if not p_inside: result.append(Line(p1, p2)) return result outside_lines = [] outside_lines.extend(get_outside_lines(self, other)) outside_lines.extend(get_outside_lines(other, self)) for line in outside_lines: contour.append(line) # fix potential overlapping at the beginning and end of each polygon result = [] for poly in contour.get_polygons(): if not poly.is_closed: lines = poly.get_lines() line1 = lines[-1] line2 = lines[0] if (line1.dir == line2.dir) \ and (line1.is_point_inside(line2.p1)): # remove the last point and define the polygon as closed poly._points.pop(-1) poly.is_closed = True result.append(poly) return result
def render(self, text, origin=None, skew=0, line_spacing=1.0, pitch=1.0, align=None): result = ContourModel() if origin is None: origin = Point(0, 0, 0) if align is None: align = TEXT_ALIGN_LEFT base = origin letter_spacing = self.letterspacing * pitch word_spacing = self.wordspacing * pitch line_factor = self.default_linespacing * self.linespacingfactor \ * line_spacing for line in text.splitlines(): current_line = ContourModel() line_height = self.default_height for character in line: if character == " ": base = base.add(Point(word_spacing, 0, 0)) elif character in self.letters.keys(): charset_letter = self.letters[character] new_model = ContourModel() for line in charset_letter.get_positioned_lines(base, skew=skew): new_model.append(line, allow_reverse=True) for polygon in new_model.get_polygons(): # add polygons instead of lines -> more efficient current_line.append(polygon) # update line height line_height = max(line_height, charset_letter.maxy()) # shift the base position base = base.add( Point(charset_letter.maxx() + letter_spacing, 0, 0)) else: # unknown character - add a small whitespace base = base.add(Point(letter_spacing, 0, 0)) # go to the next line base = Point(origin.x, base.y - line_height * line_factor, origin.z) if not current_line.maxx is None: if align == TEXT_ALIGN_CENTER: current_line.shift(-current_line.maxx / 2, 0, 0) elif align == TEXT_ALIGN_RIGHT: current_line.shift(-current_line.maxx, 0, 0) else: # left align if current_line.minx != 0: current_line.shift(-current_line.minx, 0, 0) for polygon in current_line.get_polygons(): result.append(polygon) # the text should be just above the x axis if result.miny: # don't shift, if result.miny is None (e.g.: no content) or zero result.shift(0, -result.miny, 0) return result