def apply_constraint(self, p, state): if state & const.ConstraintMask: if self.selection in self.selAspect: ref_x, ref_y = self.reference aspect = self.aspect if aspect is None: # width is 0 p = Point(self.drag_start.x, p.y) else: w = p.x - ref_x h = p.y - ref_y if w == 0: w = 0.00001 a = h / w if a > 0: sign = 1 else: sign = -1 if abs(a) > aspect: h = sign * w * aspect else: w = sign * h / aspect p = Point(ref_x + w, ref_y + h) elif self.selection == -1: pi4 = math.pi / 4 off = p - self.drag_start d = Polar(pi4 * round(math.atan2(off.y, off.x) / pi4)) p = self.drag_start + (off * d) * d return p
def hvcurveto(self): dx1, dx2, dy2, dy3 = self.pop_all() d1 = self.cur + Point(dx1, 0) d2 = d1 + Point(dx2, dy2) d3 = d2 + Point(0, dy3) self.cur = d3 self.path.append(tuple(d1) + tuple(d2) + tuple(d3))
def vhcurveto(self): dy1, dx2, dy2, dx3 = self.pop_all() d1 = self.cur + Point(0, dy1) d2 = d1 + Point(dx2, dy2) d3 = d2 + Point(dx3, 0) self.cur = d3 self.path.append(tuple(d1) + tuple(d2) + tuple(d3))
def Snap(self, point): # Determine the point Q on self's outline closest to P and # return a tuple (abs(Q - P), Q) try: p = self.trafo.inverse()(point) except SingularMatrix: return (1e100, point) best_d = 1e100 best_p = None y = p[1] for x in self.cols: t = Point(x, y) dist = (t - p).polar()[0] if dist < best_d: best_d = dist best_p = t x = p[0] for y in self.rows: t = Point(x, y) dist = (t - p).polar()[0] if dist < best_d: best_d = dist best_p = t return (best_d, self.trafo(best_p))
def ButtonDown(self, p, button, state): self.DragStart(p) if self.horizontal: result = Point(0, p.y - self.point.y) else: result = Point(p.x - self.point.x, 0) return result
def getStdConnLine(fromobj, toobj, cplist=()): global tarrw1, tarrw2, tarrw3 #~ snAdct['ptfl_1'], # from (startpoint - moveto) #~ snBdct['box'], # to (endpoint) #~ # here optional arguments for 'in-between' points; #~ # (ordered) tuple of dict, where key is command: #~ # like in tikz:: '|' means along y , '-' means along x #~ # (last {'-':-10}, is not needed - endpoint specifies it #~ ({'-':10}, {'|':-20}, {'-':-30}, {'|':-40}) # for now, we expect that fromobj is always going to be a # 'pointer' tf line; and to obj is going to be a box connlineCol = SolidPattern(CreateRGBColor(0.3, 0.3, 0.3)) # retrieve start point - endpoint of fromobj ptf line # get 2nd node (=segment 1) - in there, Point() is third in list ([2]) tmpep_start = fromobj.paths[0].Segment(1)[2] # NOTE though: 'skpoint' object has only read-only attributes !! (cannot assign to .x) # retrieve end point - the center left (west) point of the box of to obj: #~ tmpep_end = toobj.bounding_rect.center() #~ tmpep_end.x = toobj.bounding_rect.left # there seems to be a 10 units padding for bounding_rect; (see below) # compensate it tobr = toobj.bounding_rect.grown(-10) tmpep_end = Point(tobr.left, tobr.center().y) # start drawing the line tpath = CreatePath() tpath.AppendLine(tmpep_start) # moveto # are there any 'in-between' connection points ? prevPoint = tmpep_start nextPoint = tmpep_start for ibcp in cplist: axiscommand = ibcp.keys()[0] moveval = ibcp[axiscommand] if axiscommand == '-': # along x #~ nextPoint.x = prevPoint.x + moveval nextPoint = Point(prevPoint.x + moveval, prevPoint.y) elif axiscommand == '|': # along y #~ nextPoint.y = prevPoint.y + moveval nextPoint = Point(prevPoint.x, prevPoint.y + moveval) tpath.AppendLine(nextPoint) # moveto prevPoint = nextPoint tpath.AppendLine(tmpep_end) # lineto tline = PolyBezier((tpath, )) #~ tline.AddStyle(tbase_style) # of Graphics.properties (also in compound, document) - seems to add a 'layer' if dynamic; else seems to 'replace' ?! tline.SetProperties(line_width=2.0, line_pattern=connlineCol, line_arrow2=tarrw2) tline.update_rects() return tline
def __init__(self, rect, center=None): SelRectBase.__init__(self) self.start = Point(rect.left, rect.bottom) self.end = Point(rect.right, rect.top) if center is None: self.center = rect.center() else: self.center = center
def RECT(self, size): ll = self.trafo(self.Pnt()) ur = self.trafo(self.Pnt()) lr = Point(ur.x, ll.y) ul = Point(ll.x, ur.y) T = transform_base(ll, lr, ul) self.setfillstyle() apply(self.rectangle, T.coeff())
def Normalize(self): sx, sy = self.start ex, ey = self.end if sx > ex: sx, ex = ex, sx if sy > ey: sy, ey = ey, sy self.start = Point(sx, sy) self.end = Point(ex, ey)
def rect_to_ltrb(self, rct, zero=Point(0, 0)): trf = rct.trafo P1 = self.trafo(trf(zero)) P2 = self.trafo(trf(Point(1, 1))) left = rndtoint(min(P1.x, P2.x)) bottom = rndtoint(max(P1.y, P2.y)) right = rndtoint(max(P1.x, P2.x)) top = rndtoint(min(P1.y, P2.y)) return left, top, right, bottom
def TextCaretData(self, text, pos, size): from math import tan, pi size = size / 1000.0 x = self.metric.string_width(text, pos) * size lly = self.metric.lly * size ury = self.metric.ury * size t = tan(self.metric.italic_angle * pi / 180.0); up = ury - lly return Point(x - t * lly, lly), Point(-t * up, up)
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 SetPoint(self, point): undo = (self.SetPoint, self.point) if type(point) != PointType: if type(point) == type(()): point = apply(Point, point) else: if self.horizontal: point = Point(self.point.x, point) else: point = Point(point, self.point.y) self.point = point return undo
def Rectangle(self, rct): trf = rct.trafo if rct.radius1 != 0 or rct.radius2 != 0: self.PolyBezier(rct.Paths(), rct.Properties()) elif (trf.m12 == 0 and trf.m21 == 0) or (trf.m11 == 0 and trf.m22 == 0): self.FillStyle(rct.Properties()) P1 = trf(Point(0, 0)) P2 = trf(Point(1, 1)) self.putlongseq(0x4160 , map(rndtoint , tuple(self.trafo(P1)) \ + tuple(self.trafo(P2)))) else: self.PolyBezier(rct.Paths(), rct.Properties())
def __init__(self, rect, anchor=None): SelRectBase.__init__(self) if type(rect) == RectType: self.start = Point(rect.left, rect.bottom) self.end = Point(rect.right, rect.top) self.Normalize() self.anchor = anchor else: # assume type Point and interactive creation self.start = rect self.end = rect self.anchor = None self.selection = 5
def ButtonDown(self, p, button, state): self.drag_state = state self.trafo = Identity self.trafo_desc = (0, 0) SelectAndDrag.DragStart(self, p) sel = self.selection if sel == self.selCenter: self.drag_cur = self.drag_start = self.center return p - self.center ds_x = ds_y = 0 if sel in self.selLeft: ds_x = self.start.x if sel in self.selTop: ds_y = self.start.y if sel in self.selRight: ds_x = self.end.x if sel in self.selBottom: ds_y = self.end.y self.drag_cur = self.drag_start = ds = Point(ds_x, ds_y) if sel in self.selTurn: vec = ds - self.center self.start_angle = math.atan2(vec.y, vec.x) else: if sel == 2: self.reference = self.end.y elif sel == 4: self.reference = self.start.x elif sel == 6: self.reference = self.start.y elif sel == 8: self.reference = self.end.x return p - ds
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 Transform(self, trafo, rects=None): dir = trafo.DTransform(self.direction).normalized() if rects: r1, r2 = rects left, bottom, right, top = r1 cx, cy = self.center cx = cx * right + (1 - cx) * left cy = cy * top + (1 - cy) * bottom cx, cy = trafo(cx, cy) left, bottom, right, top = r2 len = right - left if len: cx = (cx - left) / len else: cx = 0 len = top - bottom if len: cy = (cy - bottom) / len else: cy = 0 center = Point(cx, cy) else: center = self.center return self.__set_center_and_dir(center, dir)
def __init__(self, gradient=None, center=Point(0.5, 0.5), direction=Point(1, 0), duplicate=None): GradientPattern.__init__(self, gradient, duplicate=duplicate) self.center = center self.direction = direction if duplicate is not None: if duplicate.__class__ == self.__class__: self.center = duplicate.center self.direction = duplicate.direction elif duplicate.__class__ == LinearGradient: self.direction = duplicate.direction elif duplicate.__class__ == RadialGradient: self.center = duplicate.center
def Transform(self, trafo, rects=None): dx, dy = self.direction dx, dy = trafo.DTransform(dy, -dx) dir = Point(dy, -dx).normalized() if dir * trafo.DTransform(self.direction) < 0: dir = -dir return self.SetDirection(dir)
def recompute(self): h1, h2, n, p1, p2 = self.h1, self.h2, self.n, self.p1, self.p2 xvect = (p2 - p1).normalized() yvect = Point(xvect.y, -xvect.x) new = Sketch.CreatePath() newpaths = [new] new.AppendLine(p1) new.AppendLine(p2) new.Transform(self.trafo) for i in range(0, n + 1): new = Sketch.CreatePath() newpaths.append(new) p = p1 + (p2 - p1) / float(n) * i new.AppendLine(p - yvect * h1) new.AppendLine(p + yvect * h2) new.Transform(self.trafo) if self.objects: self.objects[0].SetPaths(newpaths) else: lines = Sketch.PolyBezier(tuple(newpaths)) self.set_objects([lines])
def sk2ps(filename, infilename, **psargs): global doc psfilename = infilename + ".ps" # convert the SK file FILENAME into a PostScript file PSFILENAME. # Any keyword arguments are passed to the PostScript device class. # we will not load doc - we will draw on doc directly here... #~ doc = load.load_drawing(filename) bbox = doc.BoundingRect(visible=psargs.get('visible', 0), printable=psargs.get('printable', 1)) psargs['bounding_box'] = tuple(bbox) psargs['document'] = doc ps = apply(PostScriptDevice, (psfilename, ), psargs) doc.Draw(ps) ps.Close() # do pdf export, too pdffilename = infilename + ".pdf" pdffile = None if pdffile is None: pdffile = open(pdffilename, 'w') #~ module.save(document, file, filename, options) #~ save(document, file, filename, options = {}): # note: pdfgensaver: self.pdf.setPageSize(document.PageSize()) #~ print doc.PageSize() # (595.27559055118104, 841.88976377952747) # document.py: PageSize returns self.page_layout.Width(), - SetLayout for that # load_SetLayout - direct without undo ; see drawinput.py # pagelayout.PageLayout -> import color, selinfo, pagelayout # default bbox sort of crops, so grow it # # pagelayout.orientation: Portrait = 0, Landscape = 1 #~ pdfbbox = bbox.grown(20) # 20 seems OK here? #~ # actually width = bbox.right (without -bbox.left) seems to have same effect as pdfbbox #~ pdfw = pdfbbox.right-pdfbbox.left #~ pdfh = pdfbbox.top-pdfbbox.bottom # note - orientation seems to want to be 0 (Portrait) - EVEN if the format is actually landscape (w>h)!! pdfo = 0 # (portrait, w<h) #~ if pdfw > pdfh: #~ pdfo = 1 # must set layout like this - else pdf will have incorrect size # - also, the output pdf seems offset somewhat towards top-right # - also, anything going in the -y part of the page will be truncated - so make sure # *manually* that all objects are placed in positive x/y parts of the page! doc.SelectAll() doc.GroupSelected() mg = doc.CurrentObject() # master group # center mg according to its bounding rect: # NVM, just set lower left corner manually pad = 0 # since we move the group, which already seems to contain padding, this should remain 0 #~ mgbr = mg.bounding_rect #~ mgw = mgbr.right-mgbr.left #~ mgh = mgbr.top-mgbr.bottom mg.SetLowerLeftCorner(Point(pad, pad)) #move mg.update_rects() mgbr = mg.bounding_rect doc.load_SetLayout( pagelayout.PageLayout(width=mgbr.right + pad, height=mgbr.top + pad, orientation=pdfo)) pdfgensaver.save(doc, pdffile, pdffilename) pdffile.close()
def bugmark(self, P): P = P - Point(1, 1) style = basestyle.Duplicate() style.fill_pattern = SolidPattern(StandardColors.black) style.line_pattern = SolidPattern(StandardColors.black) self.prop_stack.AddStyle(style) self.rectangle(2, 0, 0, 2, P.x, P.y)
def GetHandles(self): handles = [] for x in self.cols: for y in self.rows: p = Point(x, y) handles.append(handle.MakeNodeHandle(self.trafo(p))) return handles
def getQuickLine(tstart, tend): # expected tuple at input pstart = Point(tstart[0], tstart[1]) pend = Point(tend[0], tend[1]) tpath = CreatePath() # Note - apparently, the first appended point is "moveTo"; # .. the ubsequent ones being "LineTo" tpath.AppendLine(pstart) # moveto tpath.AppendLine(pend) # lineto tline = PolyBezier((tpath,)) tline.AddStyle(tbase_style) # of Graphics.properties (also in compound, document) - seems to add a 'layer' if dynamic; else seems to 'replace' ?! tline.SetProperties(line_pattern = SolidPattern(CreateRGBColor(0.7, 0.7, 0.9))) return tline
def __init__(self, path, closed = 0): self.path = CreatePath() self.head = Point(0,0) if type(path) in (ListType, TupleType): oldseg = None for segment in path: if len(segment) == 2: if oldseg and oldseg[-2:] == segment: self.head = Point(segment) apply(self.path.AppendLine, segment) else: apply(self.path.AppendBezier, segment) oldseg = segment else: self.path = path if closed: self.path.load_close()
def rmoveto(self): dx, dy = self.pop_all() self.cur = self.cur + Point(dx, dy) if self.in_flex: self.flex.append(self.cur) else: self.new_path() self.path.append(tuple(self.cur))
def __init__(self, file, filename, match): GenericLoader.__init__(self, file, filename, match) self.file = file self.curstyle = Style() self.verbosity = 0 self.gdiobjects = [] self.dcstack = [] self.curpoint = Point(0, 0)
def compute_endpoints(self): cur = self.drag_cur start = self.start end = self.end sel = self.selection if sel in self.selTop: start = Point(start.x, cur.y) if sel in self.selBottom: end = Point(end.x, cur.y) if sel in self.selLeft: start = Point(cur.x, start.y) if sel in self.selRight: end = Point(cur.x, end.y) if sel == -1: start = start + self.off end = end + self.off return start, end
def reset(self): self.stack = [] self.ps_stack = [] self.paths = () self.path = [] self.closed = 0 self.in_flex = 0 self.flex = [] self.cur = Point(0, 0)