def gauge(self): """Get a sequence of SVG use statements representing the gauge.""" g=Group(Key("gauge")); uk=Key("part") spr = [d for d in self._defs if d.key.count("splice")>0][0] sr = [d for d in self._defs if d.key.count("section")>0][0] hr = [d for d in self._defs if d.key.count("hairpin")>0][0] a=Angle(2.0*self.angle,'deg'); m=self._n>>1 if odd(m): cp=m+1>>1; cm=cp-1 u=Use(hr,uk); u.xform=Transform(rotate=-a*cm); g+=u u=Use(spr,uk); u.xform=Transform(rotate=-a*cm+a/2.0); g+=u else: cp=cm=m>>1; u=Use(hr,uk); u.xform=Transform(rotate=-a*cm); g+=u for i in range(-cm+1,0): if odd(i): u=Use(sr,uk); u.xform=Transform(rotate=a*i); g+=u else: u=Use(hr,uk); u.xform=Transform(rotate=a*i); g+=u for i in range(1,cp): if odd(i): u=Use(sr,uk); u.xform=Transform(rotate=a*i); g+=u else: u=Use(hr,uk); u.xform=Transform(rotate=a*i); g+=u hr = [d for d in self._defs if d.key.count("header")>0][0] z=C(0.0,-(self._ir+self._or)/2.0)*C(-self._a/1.618) u=Use(hr,uk); u.xform=Transform(translate=z); g+=u return g
def __init__(self,vertex=C(.5,.5),center=C(0.0,0.0),key=None): """Create a new rectangle at 'center' defined by one 'vertex'.""" super(Rectangle,self).__init__() self._v=C(vertex); self._c=C(center); dvabs=C(map(abs,self._v))-self._c self._ll,self._ur = self._c-dvabs,self._c+dvabs if key is None: self._id=next(Rectangle._key) else: self._id=next(key)
def rarc(self,radius=1.0, end=C(1.0), \ clockwise=True, bigarc=False, orient=0): """The endpoint 'end' is relative; otherwise the same as 'arc'.""" end=C(end); self._pos+=end; rx,ry = C(radius) if ry==0.0: ry=rx cw = 1 if clockwise else 0; b = 1 if bigarc else 0 self._p.append(('a',(rx,ry,orient,b,cw,end.x,end.y))); self._pts.append(self._pos)
def __getitem__(self, i): """Return a static function that evaluates the i-th trivially parameterized complex derivative value of the path as a 'C' object when passed a abcissa value 'x'. 'i in (0,1,2,3,4,5)'.""" if i == 0: return lambda x: C(x, self._dfs[0](x)) if i == 1: return lambda x: C(1.0, self._dfs[1](x)) return lambda x: C(0.0, self._dfs[i](x))
def __init__(self,radius=1.0,center=C(0.0,0.0),key=None): """Create a new circle at 'center' with size 'radius'.""" super(Circle,self).__init__() self._r=radius; self._c=C(center); self.stroke_linejoin='' dvabs=C(abs(radius),abs(radius)) self._ll,self._ur = self._c-dvabs,self._c+dvabs if key is None: self._id=next(Circle._key) else: self._id=next(key)
def span(self): """Return a pair of 'C' values representing the lower left corner and upper right corner of user unit space spanned by all vertices in this 'Path' in their transformed display space.""" xs,ys = zip(*(e for e in self._pts)) xmin,ymin = map(min,zip(*ll)); xmax,ymax = map(max,zip(*ur)) self._ll,self._ur = C(xmin,ymin),C(xmax,ymax) return Element.span # computes transformed bounding box
def span(self): """Return a pair of 'C' values representing the lower left corner and upper right corner of user unit space spanned by all components in this 'Element' in its transformed display space.""" m = self.Matrix() if self._transform is None else self._transform.merge xs,ys = zip(self._ll,self._ur) # bounding box corner coordinates xsys = zip(*map(m,[C(u,v) for u in xs for v in ys])) # transform corners return C(map(min,xsys)),C(map(max,xsys)) # transformed bounding box
def __init__(self,vertex=C(1.0,.5),center=C(0.0,0.0),key=None): """Create a new ellipse tangent to the edges of a rectangle at 'center' with corner 'vertex'.""" super(Ellipse,self).__init__() self._v=C(vertex); self._c=C(center); self.stroke_linejoin='' dvabs=C(map(abs,self._v))-self._c self._ll,self._ur = self._c-dvabs,self._c+dvabs if key is None: self._id=next(Ellipse._key) else: self._id=next(key)
def hairpin(self): """Get an svg.dom.Group representing the inner turn and two legs.""" g,p = Group(Key("hairpin")),Path(Key("arc")); g+=p g.xform=Transform(translate=C(0.0,-self._cr)) p.fill,p.stroke = "none","Chocolate" p.stroke_width,p.stroke_linejoin = self._w,"round" r,a,d = self._r,self._a,C(0.0,self._cr) t,e = r*C(a),C(0.0,pythagoras(None,r,self._tr-r))*C(a)-d # tangent,end p.move(~e); p.line(-~t); p.arc(r,t,False); p.line(-e) return g
def __init__(self, p0, p1, p2): """'pi' are non-collinear positions 'P'. 'p0' corresponds to the complex plane origin. 'p1' is in the direction of the real axis. 'p2' is used to find the orthogonal imaginary axis.""" self._p0, self._dp1, self._dp2 = p0, p1 - p0, p2 - p0 self._u = self._dp1.unit self._v = self._dp2.unit # v as a temporary c = (self._u | self._v) self._v = (self._v - c * self._u).unit # u,v now orthogonal, in plane self._defs=tuple( (p0, p1, p2, C(0.0), C(abs(self._dp1)), \ C(abs(self._dp2)*c,(self._dp2|self._v))) )
def __init__(self,size=5, vertex=C(-2.0,-2.0), \ text="none", font="Arial", key=None): """Create a new text element with lower left corner 'vertex', 'size' pixels tall. Use 'font' when rendering the string passed in 'text'. The default text color is '#404040'.""" super(Text,self).__init__() self._anch="start"; self._s=size; self._v=C(vertex); self._t=text self._fnt=font; self.fill="#404040"; self.stroke_linejoin='' self._domb="auto"; self.xform=Transform() # empty transformation if key is None: self._id=next(Text._key) else: self._id=next(key)
def arc(self,radius=1.0, end=C(1.0), \ clockwise=True, bigarc=False, orient=0): """An arc is defined from the current position to the end position along an elliptical path. There are four such paths. 'big' and 'clockwise' select which is rendered. When 'radius' is a scalar, a circle is indicated; when complex, an ellipse. 'orient' is the relative angle in degrees of the axes of the path defining ellipse.""" end=self._pos=C(end); rx,ry = C(radius) if ry==0.0: ry=rx cw = 1 if clockwise else 0; b = 1 if bigarc else 0 self._p.append(('A',(rx,ry,orient,b,cw,end.x,end.y))); self._pts.append(end)
def span(self): """Return a pair of 'C' values representing the lower left corner and upper right corner of user unit space spanned by all characters in this 'Text' in their transformed display space. This is an estimate assuming an 'em' box size x 2*size (max-width x (ascent+descent)) for all characters.""" ll,ur = self._a-C(0.0,self._s),self._a+C(len(self._t*self._s,self._s)) # correct for Cartesian coordinate mirror and initially position text self._transform.translate(*self._v); self._transform.scale(1.0,-1.0) sp=Element.span; self._transform.pop(); self._transform.pop() return sp
def __call__(self, x, derivative=0): """Return the complex position of the trivial parameterization of the indicated derivative of the function represented by this instance at the parameter 'x', e.g.: derivative return value ---------- ------------ 0 C(x , f(x)) 1 C(1.0, fp(x)) >1 C(0.0,f<d>p(x)), where <d>==derivative""" if derivative == 0: return C(x, self._dfs[0](x)) if derivative == 1: return C(1.0, self._dfs[1](x)) return C(0.0, self._dfs[derivative](x))
def inside_sensor(self): """Get a 'gauge' customized for the inside.""" g,p = Group(Key("inside_sensor")),Path(Key("patch_i")); g+=p sr = [d for d in self._defs if d.key.count("gauge")>0][0] u=Use(sr,Key("sensor_i")); g+=u p.fill,p.stroke = "none","Chocolate" p.stroke_width,p.stroke_linejoin = self._w,"round" p.xform=Transform(translate=C(0.0,-self._cr)) r,a,d = self._r,self._a,C(0.0,self._cr) s=C(0.0,pythagoras(None,r,self._tr-r))*C(a)-d # start e=-r*C(a)-s; e0,e1 = s+e*.1,s+e*.9 p.move(~s); p.line(~e0); p.move(-s); p.line(-e1) return g
def __init__(self,radius=.05,clearance=0.03): """The 'SqPin' object origin is the pin center. The pad is a circle of radius in inches with two flats so that there is 'clearance' inches between adjacent pads on a header. The pin is a .64 mm square (~.025").""" super(SqPin,self).__init__(Key("sqpin")) self._cl,self._r = map(float,[clearance,radius]) p,s = Path(Key("pad")),Rectangle(C(0.32,0.32),key=Key("pin")) self+=p; self+=s p.fill,p.stroke = "Chocolate","none" s.fill,s.stroke = "Gold","none" r,c = self._r*25.4,self._cl*25.4 a=Angle(acos((r-c/2.0)/r),'rad'); v=r*C(a) p.move(-v); p.arc(r,-~v,False); p.line(v); p.arc(r,~v,False); p.line(-v)
def __call__(self, zp): """If 'zp' is a 'C' object, return the equivalent 'P' object. If 'zp' is a 'P' object, return the equivalent 'C' object.""" if isinstance(zp, C): return self._p0 + self._u * zp.x + self._v * zp.y if isinstance(zp, P): delta = zp - self._p0 return C(delta | self._u, delta | self._v) raise ValueError, "{!r} must be a 'C' or 'P' object.".format(zp)
def sqrt(self): """Return the quaternion operator that, when applied twice, is equivalent to this operator applied once. That is, for a unit, return a rotation operator about the same axis by half the angle. Returns 'None' for the zero quaternion or the gimbal lock quaternion: [-1 0 0 0].""" q=self.unit if q is None: return None # zero quaternion d=q.d; z=C(q[0]+1.,abs(d)).unit; d=d.unit # C(cos,sin)+C(1) unitized if z is None: return None # gimbal lock quaternion: [-1 0 0 0] if d is None: return Q(sqrt(abs(self)),q.d) # scalar sqrt return Q(z.x,d*z.y)*sqrt(abs(self))
def splice(self): """Get an svg.dom.Group representing two outer traces and a connecting hairpin.""" g,p = Group(Key("splice")),Path(Key("base")); g+=p g.xform=Transform(translate=C(0.0,-self._cr)) p.fill,p.stroke = "none","Chocolate" p.stroke_width,p.stroke_linejoin = self._w,"round" r,a,tr,d = self._r,self._a,self._tr,C(0.0,self._cr) e = C(0.0,pythagoras(None,r,self._tr-r))*C(a) - d # end t = ( C(0.0,tr) + ~C(a)*r )*C(a) - d # tangent p.move(~e); p.arc(r,~t); p.arc(tr,-t); p.arc(r,-e) return g
def __init__(self,group,pins=3,reference=1): """The 'Header' has 'pins' number of 'svg.dom.group' objects extending from the reference pin along the y-axis, .1" on center. The 'group' object represents the appearance of the pin, and must be defined in an 'svg.dom.Defs' object. Pins are numbered from zero. The reference pin is located at the origin. Subsequent pins are along the positive y-axis and prior ones are along the negative y-axis.""" super(Header,self).__init__(Key("header")) self._p,self._r = map(int,[pins,reference]) if not self._r in range(self._p): raise ValueError, \ "Reference pin {} is not contained in header pins: [0 .. {}]".format( \ self._r,self.p) self._pin=pin=group; uk=Key("pin") for i in range(self._p): u=Use(pin,uk) u.xform=Transform(translate=C(0.0,2.54)*(i-self._r)) self+=u
def rline(self,z=C(1.0)): z=C(z); self._pos+=z self._p.append(('l',z)); self._pts.append(self._pos)
def rmove(self,z=C(0.0)): z=C(z); self._pos+=z; self._start+=z self._p.append(('m',z)); self._pts.append(self._pos)
def line(self,z=C(1.0)): z=self._pos=C(z); self._p.append(('L',z)); self._pts.append(z)
def move(self,z=C(0.0)): z=self._pos=self._start=C(z) self._p.append(('M',z)); self._pts.append(z)
def _xy(self): halfdiag=C(map(abs,self._c-self._v)) return 'x="{0}" y="{1}"'.format(*map(_,self._c-halfdiag))
def vertex(self,v=C(-2.0,-2.0)): self._v=C(v) @property
def center(self,c=C(0.0,0.0)): self._c=C(c) @property
def vertex(self,v=C(.5,.5)): self._v=C(v) def xml(self,svg):
def _dxdy(self): diag=2.0*C(map(abs,self._c-self._v)) return 'width="{0}" height="{1}"'.format(*map(_,diag))
def __init__(self,key=None): """Create a new empty path element.""" super(Path,self).__init__() self._p=[]; self._start=self._pos=C(0.0); self._pts=[] if key is None: self._id=next(Path._key) else: self._id=next(key)