def insert_node_at(path, at): index = int(at) t = at - index newpath = CreatePath() copy_path(newpath, path, 0, index) type, control, node, cont = path.Segment(index + 1) if type == Line: newpath.AppendLine((1 - t) * path.Node(index) + t * node) newpath.select_segment(-1) newpath.AppendLine(node) else: if newpath.Continuity(-1) == ContSymmetrical: newpath.SetContinuity(-1, ContSmooth) p1, p2 = control p1, p2, q, p3, p4 = subdivide(newpath.Node(-1), p1, p2, node, t) newpath.AppendBezier(p1, p2, q, ContSmooth) newpath.select_segment(-1) if cont == ContSymmetrical: cont = ContSmooth newpath.AppendBezier(p3, p4, node, cont) copy_path(newpath, path, index + 2) if path.closed: newpath.ClosePath() newpath.SetContinuity(-1, path.Continuity(-1)) return newpath
def read_polyline(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 15: raise SketchLoadError('Invalid PolyLine specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, join, cap, \ radius, forward_arrow, backward_arrow, npoints = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, join, cap, line_style, style) if forward_arrow: readline() # XXX: implement this if backward_arrow:readline() # XXX: implement this if sub_type == 5: readline() # imported picture path = CreatePath() ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for polyline') if len(pts) > ncoords: del pts[ncoords:] map(path.AppendLine, coords_to_points(pts, self.trafo)) if sub_type in (2, 3, 4): path.load_close(1) self.bezier(paths = path) self.set_depth(depth)
def load_3dface(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, '70': 0, # Invisible edge flags } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() if param['70'] != 0: print 'FIXMY. 3dface Invisible edge flags', param['70'] self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,)
def bezier(self): if self.path.len > 1: if self.path.Node(0) == self.path.Node(-1): self.path.load_close(1) self.prop_stack.AddStyle(self.curstyle.Duplicate()) GenericLoader.bezier(self, paths=(self.path, )) self.path = CreatePath()
def load_solid(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, } param.update(self.general_param) param = self.read_param(param) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,)
def split_path_at(path, at): index = int(at) t = at - index if path.closed: path1 = path2 = CreatePath() result = [path1] else: path1 = CreatePath() path2 = CreatePath() result = [path1, path2] copy_path(path1, path, 0, 0, copy_selection = 0) type, control, node, cont = path.Segment(index + 1) if type == Line: q = (1 - t) * path.Node(index) + t * node path2.AppendLine(q) path2.AppendLine(node) path2.select_segment(0) function = path1.AppendLine args = (q,) else: p1, p2 = control p1, p2, q, p3, p4 = subdivide(path.Node(index), p1, p2, node, t) path2.AppendLine(q) path2.AppendBezier(p3, p4, node, cont) path2.select_segment(0) function = path1.AppendBezier args = (p1, p2, q, ContSymmetrical) copy_path(path2, path, index + 2, copy_selection = 0) copy_path(path1, path, 1, index, copy_selection = 0) apply(function, args) return result
def bezier(self): if self.guess_continuity: self.path.guess_continuity() if self.path.len > 0: if self.compound_path is not None: self.compound_path.append(self.path) else: GenericLoader.bezier(self, paths=(self.path, )) self.path = CreatePath()
def tidy(path): # remove redundant node at the end of the path if path.len > 1: type, control, node, cont = path.Segment(path.len - 1) if type == Line and equal(node, path.Node(path.len - 2)): new_path = CreatePath() for i in range(path.len - 1): type, control, node, cont = path.Segment(i) new_path.AppendSegment(type, control, node, cont) path = new_path return path
def DISJTLINE(self, size): path = () for i in range(size / (4 * reff.vdc.size)): subpath = CreatePath() P = self.Pnt() subpath.AppendLine(self.trafo(P)) P = self.Pnt() subpath.AppendLine(self.trafo(P)) path = path + (subpath,) self.setlinestyle() self.bezier(path)
def LineTo(self): y, x = self.get_struct('<hh') p = self.trafo(x, y) self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.prop_stack.SetProperty(fill_pattern = EmptyPattern) path = CreatePath() path.AppendLine(self.curpoint) path.AppendLine(p) self.bezier((path,)) self.curpoint = p self._print('->', self.curpoint)
def line(self, attrs): if self.in_defs: return x1, y1 = attrs.get('x1', '0'), attrs.get('y1', '0') x2, y2 = attrs.get('x2', '0'), attrs.get('y2', '0') path = CreatePath() path.AppendLine(self.point(x1, y1)) path.AppendLine(self.point(x2, y2)) self.parse_attrs(attrs) self.set_loader_style() self.loader.bezier(paths = (path,))
def initialize(self): self.draw = 0 self.scale = .283464566929 self.cur_x = 0.0 self.cur_y = 0.0 self.palette = Palette(self.basename) self.path = CreatePath() self.cur_style = Style() self.cur_style.line_width = 0.6 self.cur_style.line_join = const.JoinRound self.cur_style.line_cap = const.CapRound self.cur_style.line_pattern = self.palette.next_color(1)
def initialize(self): self.curstyle = Style() self.curstyle.line_join = JoinRound self.curstyle.line_cap = CapRound self.cur_x = 0.0 self.cur_y = 0.0 self.draw = 0 self.absolute = 1 self.path = CreatePath() self.curpen = None self.penwidth = {} self.select_pen()
def __init__(self, path, closed=0): self.path = CreatePath() if type(path) in (ListType, TupleType): for segment in path: if len(segment) == 2: apply(self.path.AppendLine, segment) else: apply(self.path.AppendBezier, segment) else: self.path = path if closed: self.path.load_close()
def polyline(self, attrs): if self.in_defs: return points = as_latin1(attrs['points']) points = string.translate(points, commatospace) points = split(points) path = CreatePath() point = self.point for i in range(0, len(points), 2): path.AppendLine(point(points[i], points[i + 1])) self.parse_attrs(attrs) self.set_loader_style() self.loader.bezier(paths = (path,))
def read_polyline(self, line): readline = self.readline tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 15: raise SketchLoadError('Invalid PolyLine specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, join, cap, \ radius, forward_arrow, backward_arrow, npoints = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, join, cap, line_style, style) if forward_arrow: readline() # XXX: implement this if backward_arrow: readline() # XXX: implement this if sub_type == 5: readline() # imported picture ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for polyline') if len(pts) > ncoords: del pts[ncoords:] trafo = self.trafo if sub_type in (1, 3, 5): path = CreatePath() map(path.AppendLine, coords_to_points(pts, trafo)) if sub_type == 3: path.load_close(1) self.bezier(paths=path) self.set_depth(depth) elif sub_type in (2, 4): wx, wy = trafo(pts[2], pts[3]) - trafo(pts[0], pts[1]) hx, hy = trafo(pts[4], pts[5]) - trafo(pts[2], pts[3]) x, y = trafo(pts[0], pts[1]) if sub_type == 4 and radius > 0: radius1 = (radius * 72.0 / 80.0) / max(abs(wx), abs(wy)) radius2 = (radius * 72.0 / 80.0) / max(abs(hx), abs(hy)) else: radius1 = radius2 = 0 self.rectangle(wx, wy, hx, hy, x, y, radius1=radius1, radius2=radius2) self.set_depth(depth)
def load_seqend(self, line = None, path_flag = None): if line is None: line = self.vertex_path if path_flag is None: path_flag = self.path_flag if path_flag > 1: print 'FIXMY. Curves and smooth surface type', path_flag close_path = path_flag & 1 == 1 path = CreatePath() if len(line): for i in line: x, y, bulge = i #print x, y, bulge path.AppendLine(self.trafo(x, y)) if close_path: if path.Node(0) != path.Node(-1): path.AppendLine(path.Node(0)) path.ClosePath() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path,)
class Arrow: def __init__(self, path, closed = 0): self.path = CreatePath() if type(path) in (ListType, TupleType): for segment in path: if len(segment) == 2: apply(self.path.AppendLine, segment) else: apply(self.path.AppendBezier, segment) else: self.path = path if closed: self.path.load_close() def BoundingRect(self, pos, dir, width): angle = atan2(dir.y, dir.x) if width < 1.0: width = 1.0 s = width * sin(angle) c = width * cos(angle) trafo = Trafo(c, s, -s, c, pos.x, pos.y) return self.path.accurate_rect(trafo) def Draw(self, device, rect = None): if self.path.closed: device.FillBezierPath(self.path, rect) else: device.DrawBezierPath(self.path, rect) def Paths(self): return (self.path,) def IsFilled(self): return self.path.closed def SaveRepr(self): path = map(lambda t: t[:-1], self.path.get_save()) return (path, self.path.closed) def __hash__(self): return hash(id(self.path)) def __cmp__(self, other): if __debug__: pdebug(None, 'Arrow.__cmp__, %s', other) if isinstance(other, self.__class__): return cmp(self.path, other.path) return cmp(id(self), id(other))
def makePageFrame(self): doc = self.doc layout = doc.Layout() hor_p = layout.Width() ver_p = layout.Height() path = CreatePath() path.AppendLine(Point(0, 0)) path.AppendLine(Point(hor_p, 0)) path.AppendLine(Point(hor_p, ver_p)) path.AppendLine(Point(0, ver_p)) path.AppendLine(Point(0, 0)) path.AppendLine(path.Node(0)) path.ClosePath() bezier = PolyBezier((path, )) doc.Insert(bezier)
class Arrow: def __init__(self, path, closed=0): self.path = CreatePath() if type(path) in (ListType, TupleType): for segment in path: if len(segment) == 2: apply(self.path.AppendLine, segment) else: apply(self.path.AppendBezier, segment) else: self.path = path if closed: self.path.load_close() def BoundingRect(self, pos, dir, width): angle = atan2(dir.y, dir.x) if width < 1.0: width = 1.0 s = width * sin(angle) c = width * cos(angle) trafo = Trafo(c, s, -s, c, pos.x, pos.y) return self.path.accurate_rect(trafo) def Draw(self, device, rect=None): if self.path.closed: device.FillBezierPath(self.path, rect) else: device.DrawBezierPath(self.path, rect) def Paths(self): return (self.path, ) def IsFilled(self): return self.path.closed def SaveRepr(self): path = map(lambda t: t[:-1], self.path.get_save()) return (path, self.path.closed) def __hash__(self): return hash(id(self.path)) def __cmp__(self, other): if __debug__: pdebug(None, 'Arrow.__cmp__, %s', other) if isinstance(other, self.__class__): return cmp(self.path, other.path) return cmp(id(self), id(other))
def load_line(self): param={ '10': None, # X coordinat '20': None, # y coordinat #'30': None, # Z coordinat '11': None, # X coordinat endpoint '21': None, # y coordinat endpoint #'31': None, # z coordinat endpoint } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,)
def Polyline(self): points = self.read_points(self.get_int16()) if points: path = CreatePath() map(path.AppendLine, points) self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.prop_stack.SetProperty(fill_pattern = EmptyPattern) self.bezier((path,))
def __init__(self, file, filename, match, treat_toplevel_groups_as_layers=1, flatten_groups=1): GenericLoader.__init__(self, file, filename, match) self.line_color = StandardColors.black self.fill_color = StandardColors.black self.line_width = 0.0 self.line_join = const.JoinMiter self.line_cap = const.CapButt self.line_dashes = () self.cur_x = self.cur_y = 0.0 self.treat_toplevel_groups_as_layers = treat_toplevel_groups_as_layers self.flatten_groups = flatten_groups self.guess_continuity = 1 self.path = CreatePath() self.compound_path = None # If compound_path is None, we're # outside of a compound path, # otherwise it's a possibly empty list # of paths self.compound_render = '' self.stack = [] self.gradients = {} self.in_gradient_instance = 0 self.gradient_geo = None # set to a true value after Bg, and set # to false by make_gradient_pattern self.gradient_rect = None self.in_palette = 0 self.in_text = 0 self.ignore_fill = 0 self.text_type = 0 # 0: point text, 1: area text, 2 = path text self.text_render = 0 # filled self.text_font = None self.text_size = 12 # Test alignment. Possible values: 0: left, 1: center, 2:right, # 3: justified, 4: justified including last line self.text_align = 0 self.text_string = [] self.standard_encoding = encoding.adobe_standard self.font_map = {} self.guides = [] self.format_version = 0.0
def convert_outline(outline): paths = [] trafo = Scale(0.001) for closed, sub in outline: if closed: sub.append(sub[0]) path = CreatePath() paths.append(path) for item in sub: if len(item) == 2: apply(path.AppendLine, item) else: apply(path.AppendBezier, item) if closed: path.load_close() for path in paths: path.Transform(trafo) return tuple(paths)
def bezier(self): if self.guess_continuity: self.path.guess_continuity() if self.path.len > 0: if self.compound_path is not None: self.compound_path.append(self.path) else: GenericLoader.bezier(self, paths = (self.path,)) self.path = CreatePath()
def Polygon(self): points = self.read_points(self.get_int16()) if points: path = CreatePath() map(path.AppendLine, points) if path.Node(-1) != path.Node(0): #print 'correct polygon' path.AppendLine(path.Node(0)) path.load_close() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier((path,))
def read_polyline(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 15: raise SketchLoadError('Invalid PolyLine specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, join, cap, \ radius, forward_arrow, backward_arrow, npoints = args self.fill(fill_color, area_fill) self.line(pen_color, thickness, join, cap, line_style, style) if forward_arrow: readline() # XXX: implement this if backward_arrow:readline() # XXX: implement this if sub_type == 5: readline() # imported picture ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for polyline') if len(pts) > ncoords: del pts[ncoords:] trafo = self.trafo if sub_type in (1, 3, 5): path = CreatePath() map(path.AppendLine, coords_to_points(pts, trafo)) if sub_type == 3: path.load_close(1) self.bezier(paths = path) self.set_depth(depth) elif sub_type in (2, 4): wx, wy = trafo(pts[2], pts[3]) - trafo(pts[0], pts[1]) hx, hy = trafo(pts[4], pts[5]) - trafo(pts[2], pts[3]) x, y = trafo(pts[0], pts[1]) if sub_type == 4 and radius > 0: radius1 = (radius * 72.0/80.0) / max(abs(wx),abs(wy)) radius2 = (radius * 72.0/80.0) / max(abs(hx),abs(hy)) else: radius1 = radius2 = 0 self.rectangle(wx, wy, hx, hy, x, y, radius1 = radius1, radius2 = radius2) self.set_depth(depth)
def __init__(self, path, closed = 0): self.path = CreatePath() if type(path) in (ListType, TupleType): for segment in path: if len(segment) == 2: apply(self.path.AppendLine, segment) else: apply(self.path.AppendBezier, segment) else: self.path = path if closed: self.path.load_close()
def create_spiral_path(rotation, radius): r = unit.convert(radius) rate = r / (rotation * 2 * pi) def tangent(phi, a=0.55197 * rate): return a * Point(cos(phi) - phi * sin(phi), sin(phi) + phi * cos(phi)) pi2 = pi / 2.0 angle = 0 tang = tangent(0) path = CreatePath() p = Point(0, 0) path.AppendLine(p) for i in range(rotation * 4): p1 = p + tang angle = pi2 * (i + 1) p = Polar(rate * angle, angle) tang = tangent(angle) p2 = p - tang path.AppendBezier(p1, p2, p, ContSymmetrical) return path
def create_star_path(corners, outer_radius, inner_radius): outer_radius = unit.convert(outer_radius) inner_radius = unit.convert(inner_radius) path = CreatePath() angle = math.pi * 2 / corners for i in range(corners): path.AppendLine(Polar(outer_radius, angle * i)) path.AppendLine(Polar(inner_radius, angle * i + angle / 2)) path.AppendLine(path.Node(0)) path.ClosePath() return path
def PolyPolygon(self): nr_of_polygons = self.get_int16() nr_of_points = [] for i in range(nr_of_polygons): nr_of_points.append(self.get_int16()) path = () for i in nr_of_points: points = self.read_points(i) if points: subpath = CreatePath() map(subpath.AppendLine, points) if subpath.Node(-1) != subpath.Node(0): subpath.AppendLine(subpath.Node(0)) subpath.load_close() path = path + (subpath,) if path: self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path)
def __init__(self, file, filename, match, treat_toplevel_groups_as_layers = 1, flatten_groups = 1): GenericLoader.__init__(self, file, filename, match) self.line_color = StandardColors.black self.fill_color = StandardColors.black self.line_width = 0.0 self.line_join = const.JoinMiter self.line_cap = const.CapButt self.line_dashes = () self.cur_x = self.cur_y = 0.0 self.treat_toplevel_groups_as_layers = treat_toplevel_groups_as_layers self.flatten_groups = flatten_groups self.guess_continuity = 1 self.path = CreatePath() self.compound_path = None # If compound_path is None, we're # outside of a compound path, # otherwise it's a possibly empty list # of paths self.compound_render = '' self.stack = [] self.gradients = {} self.in_gradient_instance = 0 self.gradient_geo = None # set to a true value after Bg, and set # to false by make_gradient_pattern self.gradient_rect = None self.in_palette = 0 self.in_text = 0 self.ignore_fill = 0 self.text_type = 0 # 0: point text, 1: area text, 2 = path text self.text_render = 0 # filled self.text_font = None self.text_size = 12 # Test alignment. Possible values: 0: left, 1: center, 2:right, # 3: justified, 4: justified including last line self.text_align = 0 self.text_string = [] self.standard_encoding = encoding.adobe_standard self.font_map = {} self.guides = [] self.format_version = 0.0
def bezier_load(self, line): bezier = self.object while 1: try: bezier.paths[-1].append_from_string(line) line = bezier.paths[-1].append_from_file(self.file) except: warn(INTERNAL, _("Error reading line %s"), ` line `) line = self.file.readline() if line[:2] == 'bC': bezier.paths[-1].load_close() line = self.file.readline() if line[:2] == 'bn': bezier.paths = bezier.paths + (CreatePath(), ) line = self.file.readline() else: break if line[:2] not in ('bs', 'bc'): break return line
def convert_paths(self, paths_list): paths = () for path in paths_list: p = CreatePath() p.AppendLine(Point(*path[0])) points = path[1] for point in points: if len(point) == 2: p.AppendLine(Point(*point)) else: point0 = Point(*point[0]) point1 = Point(*point[1]) point2 = Point(*point[2]) p.AppendBezier(point0, point1, point2, point[3]) if path[2]: p.AppendLine(Point(*path[0])) p.ClosePath() paths = paths + (p,) return paths
def create_star_path(corners, step, radius): # create a star-like polygon. center = Point(300, 400) radius = 100 angle = step * 2 * pi / corners # create an empty path and append the line segments path = CreatePath() for i in range(corners): p = Polar(radius, angle * i + pi / 2) path.AppendLine(p) # close the path. path.AppendLine(path.Node(0)) path.ClosePath() return path
def POLYGONSET(self, size): path = () subpath = CreatePath() for i in range(size / (2 * reff.vdc.size + 2)): P = self.Pnt() F = self.Enum() subpath.AppendLine(self.trafo(P)) if F in (2, 3): if subpath.Node(-1) != subpath.Node(0): subpath.AppendLine(subpath.Node(0)) subpath.load_close() path = path + (subpath,) subpath = CreatePath() if subpath.len != 0: if subpath.Node(-1) != subpath.Node(0): subpath.AppendLine(subpath.Node(0)) subpath.load_close() path = path + (subpath,) self.setfillstyle() self.bezier(path)
def read_spline(self, line): readline = self.readline; tokenize = skread.tokenize_line args = tokenize(line) if len(args) != 13: raise SketchLoadError('Invalid Spline specification') sub_type, line_style, thickness, pen_color, fill_color, depth, \ pen_style, area_fill, style, cap, \ forward_arrow, backward_arrow, npoints = args closed = sub_type & 1 if forward_arrow: readline() if backward_arrow:readline() # in 3.2 all splines are stored as x-splines... if self.format_version == 3.2: if sub_type in (0, 2): sub_type = 4 else: sub_type = 5 self.fill(fill_color, area_fill) self.line(pen_color, thickness, 0, cap, line_style, style) ncoords = npoints * 2 pts = self.read_tokens(ncoords) if not pts: raise SketchLoadError('Missing points for spline') if len(pts) > ncoords: del pts[ncoords:] pts = coords_to_points(pts, self.trafo) path = CreatePath() if sub_type in (2, 3): # interpolated spline, read 2 control points for each node ncontrols = 4 * npoints controls = self.read_tokens(ncontrols) if not controls: raise SketchLoadError('Missing control points for spline') if len(controls) > ncontrols: del controls[ncontrols:] controls = coords_to_points(controls[2:-2], self.trafo) path.AppendLine(pts[0]) ncontrols = 2 * (npoints - 1) controls = [controls] * (npoints - 1) map(path.AppendBezier, map(getitem, controls, range(0, ncontrols, 2)), map(getitem, controls, range(1, ncontrols, 2)), pts[1:]) elif sub_type in (0, 1): # approximated spline f13 = 1.0 / 3.0; f23 = 2.0 / 3.0 curve = path.AppendBezier straight = path.AppendLine last = pts[0] cur = pts[1] start = node = (last + cur) / 2 if closed: straight(node) else: straight(last) straight(node) last = cur for cur in pts[2:]: c1 = f13 * node + f23 * last node = (last + cur) / 2 c2 = f13 * node + f23 * last curve(c1, c2, node) last = cur if closed: curve(f13 * node + f23 * last, f13 * start + f23 * last, start) else: straight(last) elif sub_type in (4, 5): # An X-spline. Treat it like a polyline for now. # read and discard the control info self.read_tokens(npoints) self.add_message(_("X-Spline treated as PolyLine")) map(path.AppendLine, pts) if closed: path.AppendLine(path.Node(0)) if closed: path.load_close(1) self.bezier(paths = path) self.set_depth(depth)
class AILoader(GenericLoader): format_name = format_name functions = {"C": 'curveto', "c": 'curveto_smooth', "V": 'curveto_v', "v": 'curveto_v_smooth', "Y": 'curveto_y', "y": 'curveto_y_smooth', "m": 'moveto', "l": 'lineto', "L": 'lineto', "w": 'set_line_width', "j": 'set_line_join', "J": 'set_line_cap', "d": 'set_line_dash', "G": 'set_line_gray', "K": 'set_line_cmyk', "XA": 'set_line_rgb', "X": 'set_line_cmyk_custom', "XX": 'set_line_generic_custom', "P": 'set_line_pattern', "g": 'set_fill_gray', "k": 'set_fill_cmyk', "cmyk": 'set_fill_cmyk', "Xa": 'set_fill_rgb', "rgb": 'set_fill_rgb', "x": 'set_fill_cmyk_custom', "Xx": 'set_fill_generic_custom', "p": 'set_fill_pattern', "F": 'fill', "f": 'fill_close', "S": 'stroke', "s": 'stroke_close', "B": 'fill_stroke', "b": 'fill_stroke_close', "closepath": 'fill_stroke_close', "N": 'invisible', # an invisible open path "n": 'invisible_close', # a invisible closed path "u": 'begin_group', "U": 'end_group', "*u": 'begin_compound_path', "newpath": 'begin_compound_path', "*U": 'end_compound_path', "gsave": 'end_compound_path', "*": 'guide', "[": 'mark', "]": 'make_array', "@": 'ignore_operator', "&": 'ignore_operator', "Bd": 'begin_gradient', "Bs": 'gradient_stop', "BS": 'dummy_gradient_stop', "Br": 'gradient_ramps', "BD": 'end_gradient', "Bb": 'begin_gradient_instance', "Bg": 'gradient_geometry', "BB": 'end_gradient_instance', "Lb": 'begin_ai_layer', "Ln": 'name_layer', "LB": 'end_ai_layer', "Pb": 'begin_palette', "PB": 'end_palette', "TE": 'set_standard_encoding', "TZ": 'reencode_font', "To": 'begin_text', "TO": 'end_text', "Tr": 'set_text_render', "Tf": 'set_text_font', "Ta": 'set_text_align', "Tp": 'begin_text_path', "TP": 'end_text_path', "Tx": 'render_text', "TX": 'render_text_inv', "XI": 'raster_image', } def __init__(self, file, filename, match, treat_toplevel_groups_as_layers = 1, flatten_groups = 1): GenericLoader.__init__(self, file, filename, match) self.line_color = StandardColors.black self.fill_color = StandardColors.black self.line_width = 0.0 self.line_join = const.JoinMiter self.line_cap = const.CapButt self.line_dashes = () self.cur_x = self.cur_y = 0.0 self.treat_toplevel_groups_as_layers = treat_toplevel_groups_as_layers self.flatten_groups = flatten_groups self.guess_continuity = 1 self.path = CreatePath() self.compound_path = None # If compound_path is None, we're # outside of a compound path, # otherwise it's a possibly empty list # of paths self.compound_render = '' self.stack = [] self.gradients = {} self.in_gradient_instance = 0 self.gradient_geo = None # set to a true value after Bg, and set # to false by make_gradient_pattern self.gradient_rect = None self.in_palette = 0 self.in_text = 0 self.ignore_fill = 0 self.text_type = 0 # 0: point text, 1: area text, 2 = path text self.text_render = 0 # filled self.text_font = None self.text_size = 12 # Test alignment. Possible values: 0: left, 1: center, 2:right, # 3: justified, 4: justified including last line self.text_align = 0 self.text_string = [] self.standard_encoding = encoding.adobe_standard self.font_map = {} self.guides = [] self.format_version = 0.0 def __del__(self): pass def warn(self, level, *args, **kw): message = apply(warn, (level,) + args, kw) self.add_message(message) def get_compiled(self): funclist = {} for char, name in self.functions.items(): method = getattr(self, name) argc = method.im_func.func_code.co_argcount - 1 funclist[char] = (method, argc) return funclist def pop(self): value = self.stack[-1] del self.stack[-1] return value def pop_multi(self, num): value = self.stack[-num:] del self.stack[-num:] return value def pop_to_mark(self): s = self.stack[:] s.reverse() try: idx = s.index(None) if idx: array = self.stack[-idx:] del self.stack[-idx - 1:] else: array = [] del self.stack[-1] return array except: raise RuntimeError, 'No mark on stack' def ignore_operator(self): pass def mark(self): self.stack.append(None) def make_array(self): array = self.pop_to_mark() self.stack.append(array) def convert_color(self, color_spec): c = apply(CreateRGBColor, color_spec) return c def set_line_join(self, join): self.line_join = _ai_join[join] def set_line_cap(self, cap): self.line_cap = _ai_cap[cap] def set_line_width(self, w): self.line_width = w def set_line_dash(self, array, phase): self.line_dashes = tuple(array) def set_line_gray(self, k): self.line_color = CreateRGBColor(k, k, k) def set_line_cmyk(self, c, m, y, k): self.line_color = CreateCMYKColor(c, m, y, k) def set_line_rgb(self, r, g, b): self.line_color = CreateRGBColor(r, g, b) def set_line_cmyk_custom(self, c, m, y, k, name, tint): self.line_color = cmyk_custom_color(c, m, y, k, tint) def set_line_generic_custom(self, name, tint, type): if type == 0: # cmyk c, m, y, k = self.pop_multi(4) self.line_color = cmyk_custom_color(c, m, y, k, tint) else: # rgb r, g, b = self.pop_multi(3) self.line_color = rgb_custom_color(r, g, b, tint) def set_line_pattern(self, name, px, py, sx, sy, angle, rf, r, k, ka, matrix): if not self.in_palette: self.add_message(_("Vector patterns not supported. Using black")) self.line_color = StandardColors.black def set_fill_gray(self, k): self.fill_color = CreateRGBColor(k, k, k) def set_fill_cmyk(self, c, m, y, k): self.fill_color = CreateCMYKColor(c, m, y, k) def set_fill_rgb(self, r, g, b): self.fill_color = CreateRGBColor(r, g, b) def set_fill_cmyk_custom(self, c, m, y, k, name, tint): self.fill_color = cmyk_custom_color(c, m, y, k, tint) def set_fill_generic_custom(self, name, tint, type): if type == 0: # cmyk c, m, y, k = self.pop_multi(4) self.fill_color = cmyk_custom_color(c, m, y, k, tint) else: # rgb r, g, b = self.pop_multi(3) self.fill_color = rgb_custom_color(r, g, b, tint) def set_fill_pattern(self, name, px, py, sx, sy, angle, rf, r, k, ka, matrix): if not self.in_palette: self.add_message(_("Vector patterns not supported. Using black")) self.fill_color = StandardColors.black def ls(self): style = self.style style.line_pattern = SolidPattern(self.line_color) style.line_width = self.line_width style.line_join = self.line_join style.line_cap = self.line_cap style.line_dashes = self.line_dashes def lsnone(self): self.style.line_pattern = EmptyPattern def fs(self): if self.gradient_geo: pattern = self.make_gradient_pattern() else: pattern = SolidPattern(self.fill_color) self.style.fill_pattern = pattern def fsnone(self): self.style.fill_pattern = EmptyPattern def stroke(self): if self.compound_path is not None: self.compound_render = 'stroke' else: self.ls() self.fsnone() self.bezier() def stroke_close(self): self.bezier_close() self.stroke() def fill(self): if self.ignore_fill: return if self.compound_path is not None: self.compound_render = 'fill' else: self.lsnone() self.fs() self.bezier() def fill_close(self): self.bezier_close() self.fill() def fill_stroke(self): if self.compound_path is not None: self.compound_render = 'fill_stroke' else: self.ls() self.fs() self.bezier() def fill_stroke_close(self): self.bezier_close() self.fill_stroke() def invisible(self): if self.compound_path is not None: self.compound_render = 'invisible' else: self.lsnone() self.fsnone() self.bezier() def invisible_close(self): self.bezier_close() self.invisible() # Gradient functions def begin_gradient(self, name, type, ncolors): self.gradient_info = name, type, ncolors def gradient_stop(self, color_style, mid_point, ramp_point): if color_style == 0: # gray scale k = self.pop() color = CreateRGBColor(k, k, k) elif color_style == 1: # CMYK color = apply(CreateCMYKColor, tuple(self.pop_multi(4))) elif color_style == 2: # RGB Color args = tuple(self.pop_multi(7)) # The cmyk and rgb values usually differ slightly because AI # does some color correction. Which values should we choose # here? color = apply(CreateRGBColor, args[-3:]) color = apply(CreateCMYKColor, args[:4]) elif color_style == 3: # CMYK Custom Color args = self.pop_multi(6) color = apply(CreateCMYKColor, tuple(args[:4])) else: self.add_message(_("Gradient ColorStyle %d not yet supported." "substituted black") % color_style) if color_style == 4: n = 10 else: self.add_message(_("Unknown ColorStyle %d") % color_style) self.pop_multi(n) color = StandardColors.black # XXX #color = apply(CreateRGBColor, color) self.stack.append((ramp_point / 100.0, color)) def dummy_gradient_stop(self, color_style, mid_point, ramp_point): # same as gradient_stop but ignore all arguments. Illustrator 8 # seems to introduce this one for printing (i.e. Illustrator 8 # files with printing info contain the gradient stops *twice* in # exactly the same format but once with the Bs operator and once # with BS. I guess this has something to do with support for # PostScript Level 3 and backwards compatibility with older # Illustrator versions. if color_style == 0: # gray scale k = self.pop() elif color_style == 1: # CMYK self.pop_multi(4) elif color_style == 2: # RGB Color self.pop_multi(7) elif color_style == 3: # CMYK Custom Color self.pop_multi(6) elif color_style == 4: self.pop_multi(10) else: self.add_message(_("Unknown ColorStyle %d") % color_style) def gradient_ramps(self, ramp_type): # defines the ramp colors with a bunch of strings for printing. # Here we just pop all the strings off the stack num = (1, 4, 5, 6, 7, 8, 9)[ramp_type] self.pop_multi(num) def end_gradient(self): self.make_array() array = self.pop() if len(array) < 2: self.add_message(_("less than two color stops in gradient")) else: # sometimes the ramp_point values are increasing, sometimes # decreasing... what's going on here? The docs say they are # increasing. if array[0][0] > array[-1][0]: array.reverse() name, type, ncolors = self.gradient_info self.gradients[name] = (type, array) del self.stack[:] #self.pop_to_mark() def begin_gradient_instance(self): self.in_gradient_instance = 1 self.ignore_fill = 1 def gradient_geometry(self, flag, name, xorig, yorig, angle, length, a, b, c, d, tx, ty): trafo = Trafo(a, b, c, d, tx, ty) trafo = artboard_trafo_inv(trafo(artboard_trafo)) start = Point(xorig, yorig) end = start + Polar(length, (pi * angle) / 180.0) self.gradient_geo = (name, trafo, start, end) def make_gradient_pattern(self): name, trafo, start, end = self.gradient_geo self.gradient_geo = None type, array = self.gradients[name] array = array[:] if type == 0: # linear (axial) gradient origdir = end - start start = trafo(start) end = trafo(end) dir = end - start try: # adjust endpoint to accomodate trafo v = trafo.DTransform(origdir.y, -origdir.x).normalized() v = Point(v.y, -v.x) # rotate 90 degrees end = start + (v * dir) * v dir = end - start except ZeroDivisionError: pass trafo2 = Trafo(dir.x, dir.y, dir.y, -dir.x, start.x, start.y) trafo2 = trafo2.inverse() left, bottom, right, top = trafo2(self.current_bounding_rect()) if right > left: factor = 1 / (right - left) offset = -left * factor else: factor = 1 offset = 0 array = fix_gradient(array, factor, offset) pattern = LinearGradient(MultiGradient(array), (start - end).normalized()) elif type == 1: # radial gradient start = trafo(start) end = trafo(end) left, bottom, right, top = self.current_bounding_rect() if left == right or top == bottom: # an empty coord_rect???? center = Point(0, 0) else: center = Point((start.x - left) / (right - left), (start.y - bottom) / (top - bottom)) radius = max(hypot(left - start.x, top - start.y), hypot(right - start.x, top - start.y), hypot(right - start.x, bottom - start.y), hypot(left - start.x, bottom - start.y)) if radius: factor = -abs(start - end) / radius array = fix_gradient(array, factor, 1) pattern = RadialGradient(MultiGradient(array), center) else: self.add_message(_("Unknown gradient type %d"), type) pattern = EmptyPattern return pattern def current_bounding_rect(self): if self.gradient_rect is not None: rect = self.gradient_rect else: rect = self.path.accurate_rect() if not self.style.line_pattern.is_Empty: rect = fix_bounding_rect(rect, self.style) return rect def end_gradient_instance(self, flag): self.ignore_fill = 0 if flag == 2: self.fill_stroke_close() elif flag == 1: self.fill_stroke() else: self.fill() self.in_gradient_instance = 0 # Path construction def moveto(self, x, y): self.cur_x = x self.cur_y = y self.path.AppendLine(x, y) def lineto(self, x, y): self.cur_x = x self.cur_y = y self.path.AppendLine(x, y) def curveto(self, x1, y1, x2, y2, x3, y3): self.path.AppendBezier(x1, y1, x2, y2, x3, y3) self.cur_x = x3 self.cur_y = y3 def curveto_smooth(self, x1, y1, x2, y2, x3, y3): self.path.AppendBezier(x1, y1, x2, y2, x3, y3, ContSmooth) self.cur_x = x3 self.cur_y = y3 def curveto_v(self, x2, y2, x3, y3): # current point and first control point are identical self.path.AppendBezier(self.cur_x, self.cur_y, x2, y2, x3, y3) self.cur_x = x3 self.cur_y = y3 def curveto_v_smooth(self, x2, y2, x3, y3): # current point and first control point are identical self.path.AppendBezier(self.cur_x, self.cur_y, x2, y2, x3, y3, ContSmooth) self.cur_x = x3 self.cur_y = y3 def curveto_y(self, x1, y1, x3, y3): # endpoint and last controlpoint are identical self.path.AppendBezier(x1, y1, x3, y3, x3, y3) self.cur_x = x3 self.cur_y = y3 def curveto_y_smooth(self, x1, y1, x3, y3): # endpoint and last controlpoint are identical self.path.AppendBezier(x1, y1, x3, y3, x3, y3, ContSmooth) self.cur_x = x3 self.cur_y = y3 def bezier_close(self): if self.path.len > 1: self.path.AppendLine(self.path.Node(0)) self.path.load_close(1) def bezier(self): if self.guess_continuity: self.path.guess_continuity() if self.path.len > 0: if self.compound_path is not None: self.compound_path.append(self.path) else: GenericLoader.bezier(self, paths = (self.path,)) self.path = CreatePath() # compound paths def begin_compound_path(self): self.compound_path = [] def end_compound_path(self): paths = tuple(self.compound_path) self.compound_path = None if paths: # XXX ugly if self.gradient_geo: rect = paths[0].accurate_rect() for path in paths[1:]: rect = UnionRects(rect, path.accurate_rect()) self.gradient_rect = rect else: self.gradient_rect = None getattr(self, self.compound_render)() GenericLoader.bezier(self, paths = paths) # Groups def begin_group(self): if self.compound_path is None: # a normal group if self.treat_toplevel_groups_as_layers: if self.composite_class == Document: self.begin_layer() return GenericLoader.begin_group(self) else: # a `compound group'. Ignored since Sketch doesn't have this. pass def end_group(self): if self.compound_path is None: # a normal group if self.composite_class == Layer: self.end_composite() else: try: GenericLoader.end_group(self) if self.flatten_groups: if self.object.NumObjects() == 1: obj = self.object.GetObjects()[0] del self.composite_items[-1] self.append_object(obj) except EmptyCompositeError: pass else: # a `compound group'. Ignored since Sketch doesn't have this. pass # Layers def begin_layer(self): self.layer(_("Layer %d") % (len(self.composite_items) + 1)) def begin_ai_layer(self): if self.format_version >= 4.0: visible, preview, enabled, printing, dimmed, unused, has_mlm,\ color, red, green, blue, unused, unused = self.pop_multi(13) else: visible, preview, enabled, printing, dimmed, has_mlm, \ color, red, green, blue = self.pop_multi(10) color = CreateRGBColor(red / 255.0, green / 255.0, blue / 255.0) self.layer_kw_args = {'printable': printing, 'visible': visible, 'locked': not enabled, 'outline_color': color} def end_ai_layer(self): self.end_layer() def name_layer(self, name): apply(self.layer, (name,), self.layer_kw_args) # Guides def guide(self, op): #print 'guide', op method = getattr(self, self.functions[op]) method() guide = self.pop_last() self.guides.append(guide) # Palette def begin_palette(self): self.in_palette = 1 def end_palette(self): self.in_palette = 0 # Text def set_standard_encoding(self): encoding = list(self.standard_encoding) pos = 0 defs = self.pop_to_mark() for item in defs: if type(item) == IntType: pos = item elif type(item) == StringType: encoding[pos] = item pos = pos + 1 else: self.add_message('unknown item %s in encoding' % `item`) self.standard_encoding = tuple(encoding) def define_font(self, psname, newname, encoding = None): if encoding is None: encoding = self.standard_encoding[:] self.font_map[newname] = FontInfo(psname, newname, encoding) def reencode_font(self): args = self.pop_to_mark() if type(args[-1]) == ListType: self.add_message(_("Multiple Master fonts not supported. " "Using Times Roman")) newname = args[-6] self.define_font('Times Roman', newname) else: newname, psname, direction, script, usedefault = args[-5:] if len(args) > 5: self.add_message(_("Additional encoding ignored")) self.define_font(psname, newname) def begin_text(self, text_type): self.in_text = 1 self.text_type = text_type self.text_string = [] if text_type == 1: self.add_message(_("Area text not supported")) if text_type == 2: GenericLoader.begin_group(self) def end_text(self): # we don't support area text (text_type 1) at all. Return # immediately in that case. if self.text_type == 1: return # first, turn the text accumulated in the list text_string into # a single string and unify line endings to newline characters. text = string.join(self.text_string, '') text = string.replace(text, '\r\n', '\n') text = string.replace(text, '\r', '\n') # remove a trailing newline. Many Illustrator files contain a # trailing newline as 'overflow' text, there's probably a better # way to deal with this... if text[-1:] == "\n": text = text[:-1] # Re-encode to Latin1 text = self.text_font.Reencode(text) if not string.strip(text): if self.text_type == 2: self.end_composite() del self.composite_items[-1] if len(self.composite_items) > 0: self.object = self.composite_items[-1] return # first create a simple text object self.fs() self.style.font = GetFont(self.text_font.psname) self.style.font_size = self.text_size self.simple_text(text, self.text_trafo, halign = _ai_text_align[self.text_align]) # if we're actually supposed to create a path-text object, turn # the text object just created into a path-text object if self.text_type == 2: GenericLoader.end_group(self) group = self.pop_last() objects = group.GetObjects() if len(objects) == 2: path, text = objects self.append_object(PathText(text, path, start_pos = self.text_start_pos)) #self.composite_items[-1] = self.object # we've finished the text object self.in_text = 0 def set_text_render(self, render): self.text_render = render def set_text_align(self, align): self.text_align = align def set_text_font(self): # In Illustrator < 7, the operator has two arguments, new # fontname and size. In Illustrator >= 7, there are two # additional arguments, ascent and descent. args = self.pop_multi(2) if type(args[0]) != StringType: newname, size = self.pop_multi(2) else: newname, size = args if self.font_map.has_key(newname): self.text_font = self.font_map[newname] elif newname[0] == '_': # special case for ai files generated by ps2ai. They don't # use the TZ operator to reencode the fonts and define the _ # names. self.define_font(newname[1:], newname) self.text_font = self.font_map[newname] else: self.add_message(_("No font %s.") % newname) self.text_size = size def begin_text_path(self, a, b, c, d, tx, ty, start_pos): self.text_trafo = Trafo(a, b, c, d, tx, ty) self.text_start_pos = start_pos def end_text_path(self): pass def render_text(self, text): if self.text_type != 2: # in a path text only the invisible render operators count self.text_string.append(text) def render_text_inv(self, text): self.text_string.append(text) # Raster Image def raster_image(self, trafo, llx, lly, urx, ury, width, height, bits, mode, alpha, reserved, encoding, mask): if bits != 8 or mode not in (1, 3): self.add_message(_("Only images with 1 or 3 components " "and 8 bits/component supported")) self.skip_to_dsc("AI5_EndRaster") return decode = streamfilter.SubFileDecode(self.tokenizer.source, '%AI5_EndRaster') if encoding == 0: decode = streamfilter.HexDecode(decode) data_length = mode * width * height data = decode.read(data_length) #f = open("/tmp/dump.ppm", "w") #if mode == 1: # f.write("P5\n%d %d\n255\n" % (width, height)) #else: # f.write("P6\n%d %d\n255\n" % (width, height)) #f.write(data) #f.close() if mode == 1: mode = 'L' elif mode == 3: mode = 'RGB' elif mode == 4: mode == 'CMYK' image = Image.fromstring(mode, (width, height), data, 'raw', mode) self.image(image, apply(Trafo, tuple(trafo))) # def append_object(self, object): if self.composite_class == Document \ and object.__class__ != Layer: self.begin_layer() self.composite_items.append(object) self.object = object # # def skip_to_dsc(self, *endcomments): next_dsc = self.tokenizer.next_dsc; split = string.split while 1: value = next_dsc() if not value: return if ':' in value: keyword, value = split(value, ':', 1) else: keyword = value if keyword in endcomments: return def read_prolog(self): next = self.tokenizer.next DSC = DSC_COMMENT; split = string.split while 1: token, value = next() if token == DSC: if ':' in value: keyword, value = split(value, ':', 1) else: keyword = value if keyword in ('EndProlog', 'BeginSetup'): return keyword if keyword[:14] == "AI5_FileFormat": self.format_version = string.atof(keyword[14:]) elif keyword == 'BeginProcSet': # some ai files exported by corel draw don't have an # EndProcSet comment after a BeginProcSet... self.skip_to_dsc('EndProcSet', 'EndProlog') elif keyword == 'BeginResource': self.skip_to_dsc('EndResource', 'EndProlog') #elif keyword == 'Creator': ## try to determine whether the file really is an ## illustrator file as opposed to some other EPS ## file. It seems that Illustrator itself only ## accepts EPS files as illustrator files if they ## contain "Adobe Illustrator" in their Create ## DSC-comment #if string.find(value, "Adobe Illustrator") == -1: #self.add_message("This is probably not an" #" Illustrator file." #" Try embedding it as EPS") if token == END: return def Load(self): funclist = self.get_compiled() # binding frequently used functions to local variables speeds up # the process considerably... a = apply; t = tuple DSC = DSC_COMMENT; MAX = MAX_DATA_TOKEN; split = string.split stack = self.stack; push = self.stack.append unknown_operator = (None, None) decoder = streamfilter.StringDecode(self.match.string, self.file) self.tokenizer = PSTokenizer(decoder) self.tokenizer.ai_pseudo_comments = 1 self.tokenizer.ai_dsc = 1 next = self.tokenizer.next self.document() value = self.read_prolog() while 1: token, value = next() if token <= MAX: push(value) elif token == DSC: if ':' in value: keyword, value = split(value, ':', 1) else: keyword = value if keyword in ('PageTrailer', 'Trailer'): break elif keyword == 'AI5_BeginPalette': self.skip_to_dsc('AI5_EndPalette', 'EndSetup') elif keyword == "AI8_BeginBrushPattern": self.skip_to_dsc('AI8_EndBrushPattern', 'EndSetup') elif token == END: break elif token == OPERATOR: method, argc = funclist.get(value, unknown_operator) #if method is not None: # name = method.__name__ #else: # name = `method` if method is None: del stack[:] else: try: if argc: args = t(stack[-argc:]) del stack[-argc:] a(method, args) else: method() except: warn_tb(INTERNAL, 'AILoader: error') self.end_all() self.object.load_Completed() for obj in self.guides: self.object.guide_layer.Insert(obj, None) return self.object
def insert_segments(path): newpath = CreatePath() newpath.AppendLine(path.Node(0), path.Continuity(0)) newpath.select_segment(0, path.SegmentSelected(0)) for i in range(1, path.len): type, p12, p, cont = path.Segment(i) if path.SegmentSelected(i) and path.SegmentSelected(i - 1): if type == Line: node = 0.5 * path.Node(i - 1) + 0.5 * path.Node(i) newpath.AppendLine(node) newpath.select_segment(-1) newpath.AppendLine(path.Node(i)) newpath.select_segment(-1) else: if newpath.Continuity(-1) == ContSymmetrical: newpath.SetContinuity(-1, ContSmooth) p1, p2 = p12 p1, p2, node, p3, p4 = subdivide(path.Node(i - 1), p1, p2, p) newpath.AppendBezier(p1, p2, node, ContSymmetrical) newpath.select_segment(-1) if cont == ContSymmetrical: cont = ContSmooth newpath.AppendBezier(p3, p4, p, cont) newpath.select_segment(-1) else: newpath.AppendSegment(type, p12, p, cont) newpath.select_segment(-1, path.SegmentSelected(i)) if path.closed: newpath.ClosePath() newpath.SetContinuity(-1, path.Continuity(-1)) return newpath
class PolyBezierCreator(Creator): creation_text = _("Create Curve") def __init__(self, start): self.path = CreatePath() Creator.__init__(self, start) def apply_constraints(self, p, state): if self.path.len > 0: node = self.path.Node(-1) elif self.dragging: node = self.drag_start else: return p if state & ConstraintMask: radius, angle = (p - node).polar() pi12 = pi / 12 angle = pi12 * floor(angle / pi12 + 0.5) p = node + Polar(radius, angle) return p def ButtonDown(self, p, button, state): p = self.apply_constraints(p, state) if self.path.len == 0: self.path.AppendLine(p) else: self.path.AppendBezier(self.drag_cur, p, p) return self.DragStart(p) def MouseMove(self, p, state): if not (state & Button1Mask): return self.DragMove(self.apply_constraints(p, state)) def ButtonUp(self, p, button, state): if not (state & Button1Mask): return p = self.apply_constraints(p, state) self.DragStop(p) if self.path.len > 1: type, (p1, p2), p, cont = self.path.Segment(-1) p2 = adjust_control_point(p2, p, self.drag_cur, ContSymmetrical) self.path.SetBezier(-1, p1, p2, p, ContSymmetrical) def EndCreation(self): return self.path.len > 1 def AppendInteractive(self, p): return self def ContinueCreation(self): return self.AppendInteractive def DrawDragged(self, device, partially): if not partially: self.path.draw_not_last(device.Bezier, device.Line) device.DrawHandleLine(self.path.Node(-1), self.drag_cur) device.DrawSmallRectHandle(self.drag_cur) if self.path.len > 1: type, (p1, p2), p, cont = self.path.Segment(-1) p2 = adjust_control_point(p2, p, self.drag_cur, ContSymmetrical) device.Bezier(self.path.Node(-2), p1, p2, p) device.DrawHandleLine(p, p2) device.DrawSmallRectHandle(p2) def CreatedObject(self): return PolyBezier(paths = (self.path,), properties = DefaultGraphicsProperties())
def __init__(self, start): self.path = CreatePath() Creator.__init__(self, start)
class DXFLoader(GenericLoader): functions={ "POP_TRAFO": 'pop_trafo', "TABLE": 'load_TABLE', "BLOCK": 'load_BLOCK', "LINE": 'load_line', "LWPOLYLINE": 'load_lwpolyline', "POLYLINE": 'load_polyline', "SEQEND": 'load_seqend', "VERTEX": 'load_vertex', "CIRCLE": 'load_circle', "ARC": 'load_arc', "ELLIPSE": 'load_ellips', "POINT": 'load_point', "SOLID": 'load_solid', "INSERT": 'load_insert', "TEXT": 'load_text', #"MTEXT": 'load_text', "3DFACE": 'load_3dface', "SPLINE": 'load_spline', "VIEWPORT": 'load_bypass', } def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.DWGCODEPAGE = 'latin1' self.unit_to_pt = 2.83464566929 self.dynamic_style_dict = {} self.style_dict = {} self.ltype_dict = {'CONTINUOUS': { '2': 'CONTINUOUS', # Linetype name '3': 'Solid line', # Descriptive text for linetype '49': [], # Dash, dot or space length #(one entry per element) } } self.layer_dict = {'0': { '2': '0', # Layer name '6': 'CONTINUOUS', #Linetype name '62': 0, # Color number '370': None, #Line weight } } self.block_dict = {} self.stack = [] self.stack_trafo = [] self.default_layer = '0' self.default_style = 'STANDARD' self.default_block = None self.default_line_width = 30 self.EXTMIN = (1e+20, 1e+20) self.EXTMAX = (-1e+20, -1e+20) self.PEXTMIN = (1e+20, 1e+20) self.PEXTMAX = (-1e+20, -1e+20) self.general_param = { '8': self.default_layer, # Layer name '6': 'BYLAYER', # Linetype name '62': 256, # Color number '48': 1.0, # Linetype scale #'60': 0, # Object visibility. If 1 Invisible } self.curstyle = Style() self.update_trafo() def update_trafo(self, scale = 1): EXT_hight = self.EXTMAX[0] - self.EXTMIN[0] EXT_width = self.EXTMAX[1] - self.EXTMIN[1] PEXT_hight = self.PEXTMAX[0] - self.PEXTMIN[0] PEXT_width = self.PEXTMAX[1] - self.PEXTMIN[1] if EXT_hight > 0: scale = 840 / max(EXT_hight, EXT_width) self.unit_to_pt = scale x = self.EXTMIN[0] * scale y = self.EXTMIN[1] * scale elif PEXT_hight > 0: scale = 840 / max(PEXT_hight, PEXT_width) self.unit_to_pt = scale x = self.PEXTMIN[0] * scale y = self.PEXTMIN[1] * scale else: x = 0 y = 0 self.trafo = Trafo(scale, 0, 0, scale, -x, -y) def push_trafo(self, trafo = None): # save trafo in stack_trafo if trafo is None: trafo = self.trafo self.stack_trafo.append(trafo) def pop_trafo(self): self.trafo = self.stack_trafo.pop() def get_pattern(self, color_index): # 0 = Color BYBLOCK if color_index == 0: block_name = self.default_block if block_name is None: layer_name = '0' else: layer_name = self.block_dict[block_name]['8'] color_index = self.layer_dict[layer_name]['62'] # 256 = Color BYLAYER if color_index == 256 or color_index is None: layer_name = self.default_layer color_index = self.layer_dict[layer_name]['62'] ## FIXMY 257 = Color BYENTITY if color_index < 0: pattern = EmptyPattern else: pattern = SolidPattern(colors[color_index]) return pattern def get_line_width(self, layer_name = None): if layer_name is None: layer_name = self.default_layer layer = self.layer_dict[layer_name] if '370' in layer: width = layer['370'] if width == -3 or width is None: width = self.default_line_width width = width * 72.0 / 2.54 /1000 # th 100 mm to pt if width <= 0.0: # XXX width = 0.1 return width def get_line_type(self, linetype_name = None, scale = 1.0, width = 1.0, layer_name = None): #if linetype_name == 'BYBLOCK': #block_name = self.default_block #layer_name = self.block_dict[block_name]['8'] if layer_name is None: layer_name = self.default_layer if linetype_name is None or linetype_name == 'BYLAYER' or linetype_name == 'BYBLOCK': linetype_name = self.layer_dict[layer_name]['6'] linetype = self.ltype_dict[upper(linetype_name)]['49'] lscale = scale * self.unit_to_pt / width dashes = map(lambda i : abs(linetype[i]) * lscale, xrange(len(linetype))) return tuple(dashes) def get_line_style(self, **kw): if kw['8'] in self.layer_dict: self.default_layer = layer_name = kw['8'] else: layer_name = self.default_layer linetype_name = upper(kw['6']) scale = kw['48'] color_index = kw['62'] style = Style() style.line_width = self.get_line_width() style.line_join = const.JoinRound style.line_cap = const.CapRound style.line_dashes = self.get_line_type(linetype_name = linetype_name, scale = scale, width = style.line_width) style.line_pattern = self.get_pattern(color_index) return style ################ # HEADER Section # def load_HEADER(self): return_code = False header_dict = {} variable = None params = {} line1, line2 = self.read_record() while line1 or line2: if variable and (line1 == '9' or line1 == '0'): header_dict[variable] = params else: params[line1] = line2 if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '9': params = {} variable = line2 line1, line2 = self.read_record() return return_code, header_dict def process_header(self, header): if '$DWGCODEPAGE' in header: self.DWGCODEPAGE = 'cp'+ upper(header['$DWGCODEPAGE']['3']).replace('ANSI_', '').replace('DOS','') if '$INSUNITS' in header: INSUNITS = convert('70', header['$INSUNITS']['70']) if INSUNITS in unit: self.unit_to_pt = unit[INSUNITS] if '$EXTMIN' in header: param10 = convert('10', header['$EXTMIN']['10']) param20 = convert('20', header['$EXTMIN']['20']) self.EXTMIN = (param10, param20) if '$EXTMAX' in header: param10 = convert('10', header['$EXTMAX']['10']) param20 = convert('20', header['$EXTMAX']['20']) self.EXTMAX = (param10, param20) if '$PEXTMIN' in header: param10 = convert('10', header['$PEXTMIN']['10']) param20 = convert('20', header['$PEXTMIN']['20']) self.PEXTMIN = (param10, param20) if '$PEXTMAX' in header: param10 = convert('10', header['$PEXTMAX']['10']) param20 = convert('20', header['$PEXTMAX']['20']) self.PEXTMAX = (param10, param20) self.update_trafo() if '$CLAYER' in header: self.default_layer = convert('8', header['$CLAYER']['8'], self.DWGCODEPAGE) ################ # TABLES Section # def load_TABLE(self): param={ '2': '', # Table name '70': 0 # Maximum number of entries in table } param = self.read_param(param) table_name = param['2'] table_number = param['70'] print '****', table_name, table_number line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDTAB': break if table_name == 'LTYPE': self.load_LTYPE() elif table_name == 'LAYER': self.load_LAYER() elif table_name == 'STYLE': self.load_STYLE() line1, line2 = self.read_record() def load_LTYPE(self): param={ '2': '', # Linetype name '3': '', # Descriptive text for linetype #'73': 0, # The number of linetype elements #'40': 0, # Total pattern length '49': [], # Dash, dot or space length (one entry per element) } param = self.read_param(param, [0]) name = upper(param['2']) if name: self.ltype_dict[name] = param dashes = [] for i in xrange(len(param['49'])): dashes.append(abs(param['49'][i]) * self.unit_to_pt) name3 = param['3'] #print name3, dashes if name3 and dashes: style = Style() style.line_dashes = tuple(dashes) style = style.AsDynamicStyle() style.SetName(name + name3) self.dynamic_style_dict[name] = style def load_LAYER(self): param={ '2': None, # Layer name '6': None, #Linetype name '62': 0, # Color number '370': None, #Line weight } param = self.read_param(param, [0]) layer_name = param['2'] if layer_name: self.layer_dict[layer_name]=param self.layer(name = layer_name) def load_STYLE(self): param={ '2': None, # Style name '70': 0, # Flag '40': 0.0, # Fixed text height; 0 if not fixed '41': 0.0, # Width factor '42': 0.0, # Last height used '50': 0.0, # Oblique angle '71': 0, # Text generation flags '3': None, # Primary font file name '4': None, # Bigfont file name '1000': None, } param = self.read_param(param, [0]) style_name = upper(param['2']) self.style_dict[style_name] = param ################ # BLOCKS Section # def load_BLOCK(self): param={ '2': '', # Block name '10': 0.0, # X Base point '20': 0.0, # Y Base point #'30': 0.0, # Z Base point '8': self.default_layer, # Layer name 'data': [], # block data } param = self.read_param(param) block_name = param['2'] print '****', block_name line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'ENDBLK': param = self.read_param(param) break param['data'].append(line1) param['data'].append(line2) line1, line2 = self.read_record() param['data'].reverse() self.block_dict[block_name] = param # print self.block_dict[block_name] ################ # ENTITIES Section # def load_line(self): param={ '10': None, # X coordinat '20': None, # y coordinat #'30': None, # Z coordinat '11': None, # X coordinat endpoint '21': None, # y coordinat endpoint #'31': None, # z coordinat endpoint } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_lwpolyline(self): param={ '90': 0, # Number of vertices '70': 0, # bit codes for Polyline entity '40': None, # Starting width '43': 0, '370': None, #Line weight } param.update(self.general_param) param = self.read_param(param,[10,20,42]) if param['40'] is not None: line_width = param['40'] * self.unit_to_pt else: line_width = param['43'] * self.unit_to_pt if param['370'] is not None: line_width = param['370'] * self.unit_to_pt * 72.0 / 2.54 /1000 self.curstyle = self.get_line_style(**param) # if Group 70 Flag bit value set 1 This is a closed Polyline path_flag = param['70'] vertex_path = [] for i in xrange(param['90']): vertex={ '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } # 10 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 20 line1, line2 = self.read_record() vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) # 42 line1, line2 = self.read_record() if line1 == '42': vertex[line1] = convert(line1, line2, self.DWGCODEPAGE) else: self.push_record(line1, line2) vertex_path.append((vertex['10'], vertex['20'], vertex['42'])) self.load_seqend(vertex_path, path_flag) def load_polyline(self): param={ '70': 0, # bit codes for Polyline entity '40': 0.01, #XXX FIXMY } param.update(self.general_param) param = self.read_param(param) self.vertex_path = [] self.curstyle.line_width=param['40'] * 72 # XXX self.unit_to_pt self.curstyle.line_pattern = self.get_pattern(param['62']) # if Group 70 Flag bit value set 1 This is a closed Polyline self.path_flag = param['70'] def load_vertex(self): param={#'62': 7, # color #'6': 'CONTINUOUS', # style '10': None, # X coordinat '20': None, # Y coordinat '42': 0.0 # Bulge } param = self.read_param(param) self.vertex_path.append((param['10'], param['20'], param['42'])) def load_seqend(self, line = None, path_flag = None): if line is None: line = self.vertex_path if path_flag is None: path_flag = self.path_flag if path_flag > 1: print 'FIXMY. Curves and smooth surface type', path_flag close_path = path_flag & 1 == 1 path = CreatePath() if len(line): for i in line: x, y, bulge = i #print x, y, bulge path.AppendLine(self.trafo(x, y)) if close_path: if path.Node(0) != path.Node(-1): path.AppendLine(path.Node(0)) path.ClosePath() self.prop_stack.AddStyle(self.curstyle.Duplicate()) self.bezier(path,) def load_circle(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0 # radius } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = param['40'] t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_arc(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center '40': 0.0, # radius '50': 0.0, # Start angle '51': 0.0 # End angle } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = ry = param['40'] start_angle = param['50'] * degrees end_angle = param['51'] * degrees trafo = self.trafo(Trafo(rx, 0, 0, ry, cx, cy)) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_ellips(self): param={ '10': 0.0, # X coordinat center '20': 0.0, # Y coordinat center #'30': 0.0, # Z coordinat center '11': 0.0, # Endpoint of major axis, relative to the center '21': 0.0, #'31': 0.0, '40': 0.0, # Ratio of minor axis to major axis '41': 0.0, # Start parameter (this value is 0.0 for a full ellipse) '42': 0.0, # End parameter (this value is 2pi for a full ellipse) } param.update(self.general_param) param = self.read_param(param) cx = param['10'] cy = param['20'] rx = sqrt(param['21']**2 + param['11']**2) ry = rx * param['40'] start_angle = param['41'] end_angle = param['42'] angle=atan2(param['21'], param['11']) center = self.trafo(cx, cy) radius = self.trafo.DTransform(rx, ry) trafo = Trafo(radius.x, 0, 0, radius.y) trafo = Rotation(angle)(trafo) trafo = Translation(center)(trafo) rx, w1, w2, ry, cx, cy = trafo.coeff() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, (rx, w1, w2, ry, cx, cy, start_angle, end_angle, ArcArc)) def load_point(self): param={ '10': None, # X coordinat center '20': None, # Y coordinat center #'30': None, # Z coordinat center } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] r = 0.3 t = self.trafo(Trafo(r,0,0,r,x,y)) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.prop_stack.AddStyle(style.Duplicate()) apply(self.ellipse, t.coeff()) def load_solid(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, } param.update(self.general_param) param = self.read_param(param) style = self.curstyle.Duplicate() style.line_pattern = EmptyPattern style.fill_pattern = self.get_pattern(param['62']) self.path = CreatePath() self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_insert(self): param={ '2': None, # Block name '10': 0.0, # X coordinat '20': 0.0, # Y coordinat #'30': 0.0, # Z coordinat '41': 1.0, # X scale factor '42': 1.0, # Y scale factor #'43': 1.0, # Z scale factor '50': 0.0, # Rotation angle '66': 0, # Attributes-follow flag } param = self.read_param(param) block_name = self.default_block = param['2'] if block_name: self.stack += ['POP_TRAFO', '0'] + self.block_dict[block_name]['data'] self.push_trafo() x = param['10'] y = param['20'] block_x = self.block_dict[block_name]['10'] block_y = self.block_dict[block_name]['20'] scale_x = param['41'] * self.trafo.m11 scale_y = param['42'] * self.trafo.m22 angle = param['50'] * degrees translate = self.trafo(x, y) trafo = Trafo(1, 0, 0, 1, -block_x, -block_y) trafo = Scale(scale_x,scale_y)(trafo) trafo = Rotation(angle)(trafo) trafo = Translation(translate)(trafo) self.trafo = trafo if param['66'] != 0: line1, line2 = self.read_record() while line1 or line2: if line1 == '0' and line2 == 'SEQEND': break else: if line1 == '0': self.run(line2) line1, line2 = self.read_record() def load_text(self): param={ '10': 0.0, '20': 0.0, '40': None, # Text height '1': '', # Default value '50': 0, # Text rotation '41': 1, # Relative X scale factor—width # '8': self.default_layer, # Layer name '7': self.default_style, # Style name '72': 0, #Horizontal text justification type } param.update(self.general_param) param = self.read_param(param) x = param['10'] y = param['20'] scale_x = param['41'] scale_y = 1 angle = param['50'] * pi / 180 font_size = param['40'] * self.trafo.m11 halign = [ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, \ ALIGN_LEFT, ALIGN_LEFT, ALIGN_LEFT][param['72']] text = unicode_decoder(param['1'], self.DWGCODEPAGE) #style = self.style_dict[param['7']] # print style style_text = self.curstyle.Duplicate() style_text.line_pattern = EmptyPattern style_text.fill_pattern = self.get_pattern(param['62']) style_name = upper(param['7']) style = self.style_dict[style_name] font_name = style['1000'] if font_name == 'Arial': # XXX font_name = 'ArialMT' style_text.font = GetFont(font_name) # print style_text.font style_text.font_size = font_size trafo_text = Translation(self.trafo(x, y))(Rotation(angle))(Scale(scale_x, scale_y)) self.prop_stack.AddStyle(style_text.Duplicate()) self.simple_text(strip(text), trafo_text, halign = halign) def load_3dface(self): param={ '10': None, '20': None, #'30': None, '11': None, '21': None, #'31': None, '12': None, '22': None, #'32': None, '13': None, '23': None, #'33': None, '70': 0, # Invisible edge flags } param.update(self.general_param) param = self.read_param(param) self.path = CreatePath() if param['70'] != 0: print 'FIXMY. 3dface Invisible edge flags', param['70'] self.path.AppendLine(self.trafo(param['10'], param['20'])) self.path.AppendLine(self.trafo(param['11'], param['21'])) self.path.AppendLine(self.trafo(param['12'], param['22'])) self.path.AppendLine(self.trafo(param['13'], param['23'])) self.path.ClosePath() style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(self.path,) def load_spline(self): param={ '70': 0, # Spline flag '71': 0, # Degree of the spline curve '72': 0, # Number of knots '73': 0, # Number of control points '74': 0, # Number of fit points '40': [], # Knot value '10': [], # Control points X '20': [], # Control points Y #'30': [], # Control points Z } param.update(self.general_param) param = self.read_param(param) closed = param['70'] & 1 path = CreatePath() f13 = 1.0 / 3.0 f23 = 2.0 / 3.0 curve = path.AppendBezier straight = path.AppendLine pts = map(lambda x, y: self.trafo(x, y), param['10'],param['20']) print 'SPLINE', param['70'], len(pts) #for i in range(0, len(pts)-1): #self.ellipse(.2, 0, 0, .2, pts[i][0],pts[i][1]) if param['70'] <= 1: straight(pts[0]) for i in range(1, len(pts) / 4): node = pts[i * 4] c1 = pts[i * 4 - 3] c2 = pts[i * 4 - 2] print c1, c2, node curve(c1, c2, node) #straight(node) if closed: curve(pts[-3], pts[-2], pts[0]) else: curve(pts[-4], pts[-4], pts[-1]) if param['70'] & 4 == 4: last = pts[0] cur = pts[1] start = node = (last + cur) / 2 if closed: straight(node) else: straight(last) straight(node) last = cur for cur in pts[2:]: c1 = f13 * node + f23 * last node = (last + cur) / 2 c2 = f13 * node + f23 * last curve(c1, c2, node) last = cur if closed: curve(f13 * node + f23 * last, f13 * start + f23 * last, start) else: straight(last) if param['70'] & 8 == 8: node = pts[0] c1 = pts[1] c2 = pts[2] # first node straight(node) if len(pts) > 4: c2 = (pts[2] + pts[1]) / 2 c3 = pts[3] * f13 + pts[2] * f23 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 for i in range(3, len(pts) - 3): c2 = pts[i - 1] * f13 + pts[i] * f23 c3 = pts[i] * f23 + pts[i + 1] * f13 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 c2 = pts[-4] * f13 + pts[-3] * f23 c3 = (pts[-3] + pts[-2]) / 2 node = (c3 + c2) / 2 curve(c1, c2, node) c1 = c3 # last node curve(c1, pts[-2], pts[-1]) style = self.get_line_style(**param) self.prop_stack.AddStyle(style.Duplicate()) self.bezier(path,) def load_bypass(self): pass ########################################################################### def get_compiled(self): funclist={} for char, name in self.functions.items(): method = getattr(self, name) argc = method.im_func.func_code.co_argcount - 1 funclist[char] = (method, argc) return funclist def push_record(self, line1, line2): # save data in stack self.stack.append(line2) self.stack.append(line1) def read_record(self): # if the stack is empty read two lines from a file if self.stack: line1 = self.stack.pop() line2 = self.stack.pop() else: line1 = self.file.readline().strip() line2 = self.file.readline().strip() return line1, line2 def read_param(self, param, stop=None): # read data and fill in the dictionary if stop is None: stop = [0, 9] line1, line2 = self.read_record() while line1 or line2: if int(line1) in stop: self.push_record(line1, line2) return param else: if line1 in param: value = convert(line1, line2, self.DWGCODEPAGE) if type(param[line1]) == list: param[line1].append(value) else: param[line1] = value line1,line2 = self.read_record() return False def find_record(self, code1, code2): # read data until to not overlap line1 == code1 and line2 == code2 # return True # else return False line1, line2 = self.read_record() while line1 or line2: if line1 == code1 and line2 == code2: return True line1, line2 = self.read_record() return False def load_section(self): return_code = False file = self.file parsed = self.parsed parsed_interval = self.parsed_interval line1, line2 = self.read_record() while line1 or line2: interval_count = file.tell() / parsed_interval if interval_count > parsed: parsed += 10 # 10% progress app.updateInfo(inf2 = '%u' % parsed + _('% of file is parsed...'), inf3 = parsed) if line1 == '0' and line2 == 'ENDSEC': return_code = True break elif line1 == '0': self.run(line2) line1, line2 = self.read_record() self.parsed = parsed return return_code def load_sections(self): return_code = False param={ '2': '', # name section } param = self.read_param(param) name=param['2'] print '**',name if name == 'HEADER': return_code, header_dict = self.load_HEADER() self.process_header(header_dict) elif name == 'CLASSES': return_code = self.find_record('0','ENDSEC') elif name == 'OBJECTS': return_code = self.find_record('0','ENDSEC') elif name == 'THUMBNAILIMAGE': return_code = self.find_record('0','ENDSEC') else: return_code = self.load_section() return return_code def interpret(self): file = self.file if type(file) == StringType: file = open(file, 'r') file.seek(0) readline = file.readline fileinfo = os.stat(self.filename) totalsize = fileinfo[6] self.parsed = 0 self.parsed_interval = totalsize / 99 + 1 line1, line2 = self.read_record() while line1 or line2: if line1 == '0': if line2 == 'EOF': break elif not self.load_sections(): warn_tb(INTERNAL, _('DXFLoader: error. Non find end of sections')) line1, line2 = self.read_record() def run(self,keyword, *args): if keyword is None: return return_code = False unknown_operator = (None, None) funclist = self.funclist if keyword is not None: method, argc = funclist.get(keyword, unknown_operator) if method is not None: try: ##print '******', keyword if len(args): i = 0 while i<len(args): return_code = apply(method, args[i:argc+i]) i+=argc else: return_code = method() except: warn_tb(INTERNAL, 'DXFLoader: error') else: self.add_message(_('Not interpreted %s') % keyword) return return_code def Load(self): import time start_time = time.clock() #print ' ************ "DXF_objects" **************' self.funclist = self.get_compiled() self.document() self.layer(name = _("DXF_objects")) self.interpret() self.end_all() for style in self.dynamic_style_dict.values(): self.object.load_AddStyle(style) self.object.load_Completed() print 'times',time.clock() - start_time return self.object
def parse_path(self, str): paths = self.paths path = self.path trafo = self.trafo str = strip(string.translate(as_latin1(str), commatospace)) last_quad = None last_cmd = cmd = None f13 = 1.0 / 3.0; f23 = 2.0 / 3.0 #print '*', str while 1: match = rx_command.match(str) #print match if match: last_cmd = cmd cmd = str[0] str = str[match.end():] #print '*', str points = match.group(1) #print '**', points if points: # use tokenize_line to parse the arguments so that # we deal with signed numbers following another # number without intervening whitespace other # characters properls. # FIXME: tokenize_line works but is not the best way # to do it because it accepts input that wouldn't be # valid here. points = filter(operator.isNumberType, skread.tokenize_line(points)) #print cmd, points if cmd in 'mM': path = CreatePath() paths.append(path) if cmd == 'M' or len(paths) == 1: path.AppendLine(trafo(points[0], points[1])) else: p = trafo.DTransform(points[0], points[1]) path.AppendLine(paths[-2].Node(-1) + p) if len(points) > 2: if cmd == 'm': for i in range(2, len(points), 2): p = trafo.DTransform(points[i], points[i + 1]) path.AppendLine(path.Node(-1) + p) else: for i in range(2, len(points), 2): path.AppendLine(trafo(points[i], points[i+1])) elif cmd == 'l': for i in range(0, len(points), 2): p = trafo.DTransform(points[i], points[i + 1]) path.AppendLine(path.Node(-1) + p) elif cmd == 'L': for i in range(0, len(points), 2): path.AppendLine(trafo(points[i], points[i+1])) elif cmd =='H': for num in points: path.AppendLine(Point(num, path.Node(-1).y)) elif cmd =='h': for num in points: x, y = path.Node(-1) dx, dy = trafo.DTransform(num, 0) path.AppendLine(Point(x + dx, y + dy)) elif cmd =='V': for num in points: path.AppendLine(Point(path.Node(-1).x, num)) elif cmd =='v': for num in points: x, y = path.Node(-1) dx, dy = trafo.DTransform(0, num) path.AppendLine(Point(x + dx, y + dy)) elif cmd == 'C': if len(points) % 6 != 0: self.loader.add_message("number of parameters of 'C'"\ "must be multiple of 6") else: for i in range(0, len(points), 6): p1 = trafo(points[i], points[i + 1]) p2 = trafo(points[i + 2], points[i + 3]) p3 = trafo(points[i + 4], points[i + 5]) path.AppendBezier(p1, p2, p3) elif cmd == 'c': if len(points) % 6 != 0: self.loader.add_message("number of parameters of 'c'"\ "must be multiple of 6") else: for i in range(0, len(points), 6): p = path.Node(-1) p1 = p + trafo.DTransform(points[i], points[i + 1]) p2 = p + trafo.DTransform(points[i+2], points[i+3]) p3 = p + trafo.DTransform(points[i+4], points[i+5]) path.AppendBezier(p1, p2, p3) elif cmd == 'S': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'S'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): type, controls, p, cont = path.Segment(-1) if type == Bezier: q = controls[1] else: q = p p1 = 2 * p - q p2 = trafo(points[i], points[i + 1]) p3 = trafo(points[i + 2], points[i + 3]) path.AppendBezier(p1, p2, p3) elif cmd == 's': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 's'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): type, controls, p, cont = path.Segment(-1) if type == Bezier: q = controls[1] else: q = p p1 = 2 * p - q p2 = p + trafo.DTransform(points[i], points[i + 1]) p3 = p + trafo.DTransform(points[i+2], points[i+3]) path.AppendBezier(p1, p2, p3) elif cmd == 'Q': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'Q'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): q = trafo(points[i], points[i + 1]) p3 = trafo(points[i + 2], points[i + 3]) p1 = f13 * path.Node(-1) + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 'q': if len(points) % 4 != 0: self.loader.add_message("number of parameters of 'q'"\ "must be multiple of 4") else: for i in range(0, len(points), 4): p = path.Node(-1) q = p + trafo.DTransform(points[i], points[i + 1]) p3 = p + trafo.DTransform(points[i+2], points[i+3]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 'T': if len(points) % 2 != 0: self.loader.add_message("number of parameters of 'T'"\ "must be multiple of 4") else: if last_cmd not in 'QqTt' or last_quad is None: last_quad = path.Node(-1) for i in range(0, len(points), 2): p = path.Node(-1) q = 2 * p - last_quad p3 = trafo(points[i], points[i + 1]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd == 't': if len(points) % 2 != 0: self.loader.add_message("number of parameters of 't'"\ "must be multiple of 4") else: if last_cmd not in 'QqTt' or last_quad is None: last_quad = path.Node(-1) for i in range(0, len(points), 2): p = path.Node(-1) q = 2 * p - last_quad p3 = p + trafo.DTransform(points[i], points[i + 1]) p1 = f13 * p + f23 * q p2 = f13 * p3 + f23 * q path.AppendBezier(p1, p2, p3) last_quad = q elif cmd in 'zZ': if round(path.Node(0).x, 3) != round(path.Node(-1).x, 3) or \ round(path.Node(0).y, 3) != round(path.Node(-1).y, 3): path.AppendLine(path.Node(0)) path.ClosePath() else: break self.path = path
class PLTLoader(GenericLoader): functions = { "IN": 'initialize', "SP": 'select_pen', "PD": 'pen_down', "PU": 'pen_up', "PA": 'plot_absolute', "PR": 'plot_relative', "PW": 'pen_sizes', #"PT": 'pen_metric', #"PL": 'pen_plu', "LT": 'linetype', "AA": 'arc_absolute', "AR": 'arc_relative', "CI": 'circle_plot', } def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.initialize() def get_position(self, x, y, absolute=None): if absolute is None: absolute = self.absolute if x == '' is not None: x = self.cur_x else: x = float(x) / plu if absolute == 0: x += self.cur_x if y == '' is not None: y = self.cur_y else: y = float(y) / plu if absolute == 0: y += self.cur_y return x, y def bezier(self): if self.path.len > 1: if self.path.Node(0) == self.path.Node(-1): self.path.load_close(1) self.prop_stack.AddStyle(self.curstyle.Duplicate()) GenericLoader.bezier(self, paths=(self.path, )) self.path = CreatePath() def arc_absolute(self, x, y, qc, qd=5): x, y = self.get_position(x, y, 1) self.arc(x, y, qc, qd) def arc_relative(self, x, y, qc, qd=5): x, y = self.get_position(x, y, 0) self.arc(x, y, qc, qd) def arc(self, x, y, qc, qd=5): qc = float(qc) * degrees x2 = self.cur_x - x y2 = self.cur_y - y r = hypot(x2, y2) if qc < 0: end_angle = atan2(y2, x2) angle = start_angle = end_angle + qc else: start_angle = atan2(y2, x2) angle = end_angle = start_angle + qc self.cur_x = (x + r * cos(angle)) self.cur_y = (y + r * sin(angle)) if self.draw == 1: self.pen_up() self.pen_down() self.prop_stack.AddStyle(self.curstyle.Duplicate()) apply(self.ellipse, (r, 0, 0, r, x, y, start_angle, end_angle, ArcArc)) def circle_plot(self, r, qd=5): x, y = self.cur_x, self.cur_y r = float(r) / plu #self.bezier() self.prop_stack.AddStyle(self.curstyle.Duplicate()) apply(self.ellipse, (r, 0, 0, r, x, y)) def move(self, x, y): if self.draw == 1: self.path.AppendLine(x, y) else: self.bezier() self.path.AppendLine(x, y) self.cur_x = x self.cur_y = y def pen_down(self, x='', y=''): self.draw = 1 if x != '' is not None: x, y = self.get_position(x, y) self.move(x, y) def pen_up(self, x='', y=''): self.draw = 0 x, y = self.get_position(x, y) self.move(x, y) def plot_absolute(self, x='', y=''): self.absolute = 1 if x != '' is not None: x, y = self.get_position(x, y) self.move(x, y) def plot_relative(self, x='', y=''): self.absolute = 0 if x != '' is not None: x, y = self.get_position(x, y) self.move(x, y) def initialize(self): self.curstyle = Style() self.curstyle.line_join = JoinRound self.curstyle.line_cap = CapRound self.cur_x = 0.0 self.cur_y = 0.0 self.draw = 0 self.absolute = 1 self.path = CreatePath() self.curpen = None self.penwidth = {} self.select_pen() def select_pen(self, pen='1'): if not pen in colors: pen = '1' if not pen in self.penwidth: width = def_width_pen else: width = self.penwidth[pen] if not self.curpen == pen: if self.draw == 1: self.pen_up() self.pen_down() patern = SolidPattern(colors[pen]) self.curstyle.line_pattern = patern self.curstyle.line_width = width self.curpen = pen def linetype(self, n='0', p='10', q=''): n = abs(int(n)) #p = float(p) p = 20 dash = [ [], [0, p], [p * 0.5, p * 0.5], [p * 0.7, p * 0.3], [p * 0.8, p * 0.1, p * 0.1, 0], [p * 0.7, p * 0.1, p * 0.1, p * 0.1], [p * 0.5, p * 0.1, p * 0.1, p * 0.1, p * 0.2, 0], [p * 0.7, p * 0.1, 0, p * 0.1, 0, p * 0.1], [p * 0.5, p * 0.1, 0, p * 0.1, p * 0.1, p * 0.1, p * 0.1, 0], [p, p], [p, p], [p, p], ] self.curstyle.line_dashes = dash[n] def pen_sizes(self, width, pen=None): if pen is None: pen = self.curpen self.penwidth[pen] = float(width) * 72 / 25.4 self.curpen = None self.select_pen(pen) def get_compiled(self): funclist = {} for char, name in self.functions.items(): method = getattr(self, name) argc = method.im_func.func_code.co_argcount - 1 funclist[char] = (method, argc) return funclist def interpret(self): import shlex def is_number(a): try: i = float(a) except ValueError: return 0 return 1 file = self.file if type(file) == StringType: file = open(file, 'r') file.seek(0) readline = file.readline fileinfo = os.stat(self.filename) totalsize = fileinfo[6] lexer = shlex.shlex(file) lexer.debug = 0 lexer.wordchars = lexer.wordchars + ".-+" lexer.whitespace = lexer.whitespace + ';,' keyword = None args = [] parsed = 0 parsed_interval = totalsize / 99 + 1 while 1: interval_count = file.tell() / parsed_interval if interval_count > parsed: parsed += 10 # 10% progress app.updateInfo(inf2='%u' % parsed + _('% of file is parsed...'), inf3=parsed) token = lexer.get_token() if not token: # run last command self.run(keyword, args) # pun up self.run('PU', []) # END INTERPRETATION app.updateInfo(inf2=_('Parsing is finished'), inf3=100) break if keyword and is_number(token): args.append(token) else: self.run(keyword, args) keyword = token[0:2] args = [] if token[2:]: lexer.push_token(token[2:]) def run(self, keyword, args): if keyword is None: return unknown_operator = (None, None) funclist = self.funclist if keyword is not None: method, argc = funclist.get(keyword, unknown_operator) if method is not None: #print method.__name__, args try: if len(args): i = 0 while i < len(args): apply(method, args[i:argc + i]) i += argc else: method() except: warn_tb(INTERNAL, 'PLTLoader: error') def Load(self): self.funclist = self.get_compiled() self.document() self.layer(name=_("PLT_objects")) self.interpret() self.end_all() self.object.load_Completed() return self.object