| 
      
      
      From: Joerg L. <jo...@us...> - 2006-03-16 16:43:19
      
     | 
| Hi Michael,
On 16.03.06, Michael J Gruber wrote:
> I'm kinda getting to like the deco concept... I remembered an old post
> by Andre, showing a method (due to Jörg, I think) for laying out text
> along a curve. I adjusted it to the current API and coded it as a
> decorator dubbed deco.curvedtext(). I'm attaching a simple example (how
> to achieve typical line ups) and the code. The code goes into deco.py
> (current svn). I'm unsure about the following:
> 
> a) Is the patch to dvifile.dvifile.putchar appropriate for going into
> the trunk, or are there side effects (I don't know that module)?
No, in this form it's not appropriate because this means that we adjust
the position after each character, which is rather inefficient.
The correct way would be to either add an option to the texrunner or
to allow switching of the single char mode on and off in a dynamical
way, such that you can request this feature for only parts of the
output.
Because the curved-text thing was really more of quick and dirty a hack,
I didn't follow it further. But it's really neat so maybe we should
integrate it in the core.
> b) Is it appropriate to attach eps examples here?
Depends on the size, I would say.
> c) What's the best format for code suggestions? I'd be happy to send
> diffs, but the patch mentioned above made it somehow inconvenient here
> (the "local" patch I'm applying won't be the final form, of course).
> 
> As for the other text decorators (text as it is or (t)text as suggested
> by me recently or text rotated parallel to the curve [tangential
> labels]): I imagine a universal decorator deco.insert() would be best
> which inserts a given canvas at certain points of the path, with or
> without a user specified alignment, with or without rotation with
> respect to the absolute co system or the local path tangent. Then, all
> text decorators (except for deco.curvedtext) would be simple calls to
> deco.insert(text.text(...)). But one could also easily decorate with
> symbols "moving" along the path and such. Please tell me what you think,
> or else I might start hacking away ;)
I like this idea.
> Cheers,
> Michael
> import os,sys
> sys.path.insert(0, os.environ.get("HOME")+"/lib/python/PyX-svn")
Just a side remark: There is os.path.expanduser which allows you to
just write os.path.expanduser("~/lib/...")
> from pyx import *
>  
> c = canvas.canvas()
> 
> R = 1.3 
> p = path.path(path.arc(0,0, R, 0,270)) + path.line(0,-R, R,-R)
> label = (r"\PyX{} is fun. " * 4)[:-1] # chop off last space 
> 
> c.draw(p, [deco.stroked([color.rgb.blue]), deco.curvedtext(label)])
> c.draw(p, [trafo.translate(2.5*R,0), deco.stroked([color.rgb.blue]), deco.curvedtext(label,textattrs=[text.halign.right],relarclenpos=1)])
> c.draw(p.reversed(), [trafo.translate(0, -2.5*R), deco.stroked([color.rgb.blue]), deco.curvedtext(label,textattrs=[text.halign.right],relarclenpos=1)])
> c.draw(p.reversed(), [trafo.translate(2.5*R, -2.5*R), deco.stroked([color.rgb.blue]), deco.curvedtext(label)])
> 
> 
> c.writeEPSfile(__file__[:-3],fittosize=1, paperformat=document.paperformat.A4)
> import dvifile,type1font
> 
> oldputchar = dvifile.dvifile.putchar
> 
> def newputchar(self, char, advancepos=1):
>   oldputchar(self, char, advancepos)
>   self.flushtext()
> 
> dvifile.dvifile.putchar = newputchar
> 
> class curvedtext(deco, attr.attr):
>     """a text decorator for curved text"""
> 
>     def __init__(self, text, textattrs=[], 
>                        relarclenpos=0, arclenfrombegin=None, arclenfromend=None,
>                        texrunner=None):
>         if arclenfrombegin is not None and arclenfromend is not None:
>             raise ValueError("either set arclenfrombegin or arclenfromend")
>         self.text = text
>         self.textattrs = textattrs
>         self.relarclenpos = relarclenpos
>         self.arclenfrombegin = arclenfrombegin
>         self.arclenfromend = arclenfromend
>         self.texrunner = texrunner
> 
>     def decorate(self, dp, texrunner):
>         if self.texrunner:
>             texrunner = self.texrunner
>         import text as textmodule
> 
>         dp.ensurenormpath()
>         if self.arclenfrombegin is not None:
>             textpos = dp.path.begin() + self.arclenfrombegin
>         elif self.arclenfromend is not None:
>             textpos = dp.path.end() - self.arclenfromend
>         else:
>             # relarcpos is used if neither arcfrombegin nor arcfromend is given
>             textpos = self.relarclenpos * dp.path.arclen()
> 
>         c = canvas.canvas()
>         t = texrunner.text(0, 0, self.text, self.textattrs)
>         for op in t.items: # copy over attr ops (colour...)
>             if not isinstance(op, canvas._canvas): # should not occur before ensuredvicanvas
>                 c.insert(op)
> 
>         t.ensuredvicanvas()
This is what I mean with rather hackish...
>         for op in t.dvicanvas.items:
>             if isinstance(op, type1font.text_pt):
>                 x = textpos + unit.t_pt*(op.x_pt+op.width_pt/2) # Make sure we rotate with respect to the middle of the character.
>                 op.x_pt =  -op.width_pt/2
>                 c.insert(op, [dp.path.trafo(x)])
>             else:
>                 c.insert(op)
My latest version looked like:
    items = t.dvicanvas.items
    xs = [item.bbox().center()[0] for item in items]
    trafos = p.trafo(xs)
    for x, op, atrafo in zip(xs, items, trafos):
        c.insert(op, [atrafo, trafo.translate(-x, 0)])
>         dp.ornaments.insert(c)
        Jörg
 |