def circle(a1=2., a2=0., a3=360., r=None, n=None, c=None, eltype='line2'): """A polygonal approximation of a circle or arc. All points generated by this function lie on a circle with unit radius at the origin in the x-y-plane. - `a1`: the angle enclosed between the start and end points of each line segment (dash angle). - `a2`: the angle enclosed between the start points of two subsequent line segments (module angle). If ``a2==0.0``, `a2` will be taken equal to `a1`. - `a3`: the total angle enclosed between the first point of the first segment and the end point of the last segment (arc angle). All angles are given in degrees and are measured in the direction from x- to y-axis. The first point of the first segment is always on the x-axis. The default values produce a full circle (approximately). If $a3 < 360$, the result is an arc. Large values of `a1` and `a2` result in polygons. Thus `circle(120.)` is an equilateral triangle and `circle(60.)` is regular hexagon. Remark that the default a2 == a1 produces a continuous line, while a2 > a1 results in a dashed line. Three optional arguments can be added to scale and position the circle in 3D space: - `r`: the radius of the circle - `n`: the normal on the plane of the circle - `c`: the center of the circle """ if a2 == 0.0: a2 = a1 ns = round(a3/a2) a1 *= pi/180. if eltype=='line2': F = Formex([[[1., 0., 0.], [cos(a1), sin(a1), 0.]]]).rosette(ns, a2, axis=2, point=[0., 0., 0.]) elif eltype=='line3': F = Formex([[[1., 0., 0.], [cos(a1/2.), sin(a1/2.), 0.], [cos(a1), sin(a1), 0.]]], eltype=eltype).rosette(ns, a2, axis=2, point=[0., 0., 0.]) if r is not None: F = F.scale(r) if n is not None: F = F.swapAxes(0, 2).rotate(rotMatrix(n)) if c is not None: F = F.trl(c) return F
def __init__(self,text,pos,gravity=None,size=18,width=None,font=None,lineskip=1.0,grid=None,texmode=4,**kargs): """Initialize the Text actor.""" # split the string on newlines text = str(text).split('\n') # set pos and offset3d depending on pos type (2D vs 3D rendering) pos = at.checkArray(pos) if pos.shape[-1] == 2: rendertype = 2 pos = [pos[0],pos[1],0.] offset3d = None else: rendertype = 1 offset3d = Coords(pos) pos = [0.,0.,0.] if offset3d.ndim > 1: if offset3d.shape[0] != len(text[0]): raise ValueError("Length of text(%s) and pos(%s) should match!" % (len(text),len(pos))) # Flag vertex offset to shader rendertype = -1 # set the font characteristics if font is None: font = FontTexture.default(size) if isinstance(font,(str,unicode)): font = FontTexture(font,size) if width is None: #print("Font %s / %s" % (font.height,font.width)) aspect = float(font.width) / font.height width = size * aspect self.width = width # set the alignment if gravity is None: gravity = 'E' alignment = ['0','0','0'] if 'W' in gravity: alignment[0] = '+' elif 'E' in gravity: alignment[0] = '-' if 'S' in gravity: alignment[1] = '+' elif 'N' in gravity: alignment[1] = '-' alignment = ''.join(alignment) # record the lengths of the lines, join all characters # together, create texture coordinates for all characters # create a geometry grid for the longest line lt = [ len(t) for t in text ] text = ''.join(text) texcoords = font.texCoords(text) if grid is None: grid = Formex('4:0123').replic(max(lt)) grid = grid.scale([width,size,0.]) # create the actor for the first line l = lt[0] g = grid.select(range(l)).align(alignment,pos) Actor.__init__(self,g,rendertype=rendertype,texture=font,texmode=texmode,texcoords=texcoords[:l],opak=False,ontop=True,offset3d=offset3d,**kargs) for k in lt[1:]: # lower the canvas y-value pos[1] -= font.height * lineskip g = grid.select(range(k)).align(alignment,pos) C = Actor(g,rendertype=rendertype,texture=font,texmode=texmode,texcoords=texcoords[l:l+k],opak=False,ontop=True,offset3d=offset3d,**kargs) self.children.append(C) # do next line l += k