Dear Michael,

your patch still had the problem, that singlecharmode was a global setting to 
the dvi file which is wrong. (You could easily break your code by rendering 
some text without singlecharmode being active and then activating the 
singlecharmode on the *same* texrunner instance.)

Furthermore we properly have to copy all canvas item instance in the correct 
order. (You need that, when you change the color of the text for some 
characters in TeX/LaTeX (i.e. special commands).)

I also added an exclude feature to the decorator, changed some defaults and did 
some quite different examples. It is all submitted now, please see changeset 
3225. 

Anyway, thanks a lot for your effort to finally bring this functionality to 
PyX. I'm pretty sure users will love it ... :-)

Best,


André


Am 09.10.2011 um 17:25 schrieb Michael J Gruber:

> Implement a decorator curvedtext for setting text along a given path.
> curvedtext switches to singlecharmode, but only while it is needed.
> 
> The basic idea has been discussed on the list and goes back to the PyX
> grand masters.
> 
> Signed-off-by: Michael J Gruber <[email protected]>
> ---
> v2 has singlecharmode as a parameter to text() rather than the texrunner.
> The drawback is that ensuredvicanvas() and finishdvi() need that parameter
> also, or else the last few characters come out wrong.
> ---
> examples/text/INDEX             |    1 +
> examples/text/textalongpath.py  |   15 ++++++++++
> examples/text/textalongpath.txt |    5 +++
> pyx/deco.py                     |   56 +++++++++++++++++++++++++++++++++++++++
> pyx/dvi/dvifile.py              |    5 ++-
> pyx/text.py                     |   12 ++++----
> 6 files changed, 86 insertions(+), 8 deletions(-)
> create mode 100644 examples/text/textalongpath.py
> create mode 100644 examples/text/textalongpath.txt
> 
> diff --git a/examples/text/INDEX b/examples/text/INDEX
> index 04692ae..c982f89 100644
> --- a/examples/text/INDEX
> +++ b/examples/text/INDEX
> @@ -5,3 +5,4 @@ marker
> color
> texrunner
> textbox
> +textalongpath
> diff --git a/examples/text/textalongpath.py b/examples/text/textalongpath.py
> new file mode 100644
> index 0000000..f4aad4e
> --- /dev/null
> +++ b/examples/text/textalongpath.py
> @@ -0,0 +1,15 @@
> +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("textalongpath")
> +c.writePDFfile("textalongpath")
> diff --git a/examples/text/textalongpath.txt b/examples/text/textalongpath.txt
> new file mode 100644
> index 0000000..1737993
> --- /dev/null
> +++ b/examples/text/textalongpath.txt
> @@ -0,0 +1,5 @@
> +Text along path
> +
> +! In order to set text along a given path, you can use the `curvedtext()`
> +decorator. The examples show how you can position the text relative to the
> +path.
> diff --git a/pyx/deco.py b/pyx/deco.py
> index 656845f..ceb6712 100644
> --- a/pyx/deco.py
> +++ b/pyx/deco.py
> @@ -564,6 +564,62 @@ class text(deco, attr.attr):
>        t.linealign(self.textdist, math.cos(angle), math.sin(angle))
>        dp.ornaments.insert(t)
> 
> +class curvedtext(deco, attr.attr):
> +    """a text decorator for curved text
> +
> +    - text: is typeset along the path to which this decorator is applied
> +    - relarclenpos: position for the base point of the text (default: 0)
> +    - arlenfrombegin, arclenfromend: alternative ways of specifying the 
> position of the base point;
> +                                     use of relarclenpos, arclenfrombegin 
> and arclenfromend is mutually exclusive
> +    - textattrs, texrunner: standard text arguments (defaults: [] resp None)
> +
> +    """
> +
> +    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, singlecharmode=1)
> +
> +        # copy over attr ops (colour...)
> +        # isinstance(op, canvas._canvas) should not occur before 
> ensuredvicanvas; should we even care to check?
> +        [ c.insert(op) for op in t.items if not isinstance(op, 
> canvas._canvas)]
> +
> +        t.ensuredvicanvas(singlecharmode=1)
> +
> +        items = t.dvicanvas.items
> +        xs = [item.bbox().center()[0] for item in items]
> +        trafos = dp.path.trafo([textpos +x for x in xs])
> +        for x, op, atrafo in zip(xs, items, trafos):
> +            c.insert(op, [trafo.translate(-x, 0), atrafo]) # reversed 
> trafos: fix for change in canvas.py from r2728 to 2730
> +
> +        dp.ornaments.insert(c)
> +
> +
> 
> class shownormpath(deco, attr.attr):
> 
> diff --git a/pyx/dvi/dvifile.py b/pyx/dvi/dvifile.py
> index b1e8123..d65e952 100644
> --- a/pyx/dvi/dvifile.py
> +++ b/pyx/dvi/dvifile.py
> @@ -112,12 +112,13 @@ class _restoretrafo(canvasitem.canvasitem):
> 
> class DVIfile:
> 
> -    def __init__(self, filename, debug=0, debugfile=sys.stdout):
> +    def __init__(self, filename, debug=0, debugfile=sys.stdout, 
> singlecharmode=0):
>        """ opens the dvi file and reads the preamble """
>        self.filename = filename
>        self.debug = debug
>        self.debugfile = debugfile
>        self.debugstack = []
> +        self.singlecharmode = singlecharmode
> 
>        self.fonts = {}
>        self.activefont = None
> @@ -197,7 +198,7 @@ class DVIfile:
>            self.activetext[2].append(char)
>            self.pos[_POS_H] += dx
> 
> -        if not advancepos:
> +        if (not advancepos) or self.singlecharmode:
>            self.flushtext(fontmap)
> 
>    def usefont(self, fontnum, id1234, fontmap):
> diff --git a/pyx/text.py b/pyx/text.py
> index 242a4b9..b55667d 100644
> --- a/pyx/text.py
> +++ b/pyx/text.py
> @@ -700,9 +700,9 @@ class textbox(box.rect, canvas._canvas):
>            raise RuntimeError("multiple call to setdvicanvas")
>        self.dvicanvas = dvicanvas
> 
> -    def ensuredvicanvas(self):
> +    def ensuredvicanvas(self, singlecharmode=0):
>        if self.dvicanvas is None:
> -            self.finishdvi()
> +            self.finishdvi(singlecharmode=singlecharmode)
>            assert self.dvicanvas is not None, "finishdvi is broken"
>        if not self.insertdvicanvas:
>            self.insert(self.dvicanvas, [self.texttrafo])
> @@ -1024,14 +1024,14 @@ class texrunner:
>        else:
>            raise TexResultError("TeX didn't respond as expected within the 
> timeout period (%i seconds)." % self.waitfortex, self)
> 
> -    def finishdvi(self, ignoretail=0):
> +    def finishdvi(self, ignoretail=0, singlecharmode=0):
>        """finish TeX/LaTeX and read the dvifile
>        - this method ensures that all textboxes can access their
>          dvicanvas"""
>        self.execute(None, self.defaulttexmessagesend + self.texmessagesend)
>        dvifilename = "%s.dvi" % self.texfilename
>        if not self.texipc:
> -            self.dvifile = dvifile.DVIfile(dvifilename, debug=self.dvidebug)
> +            self.dvifile = dvifile.DVIfile(dvifilename, debug=self.dvidebug, 
> singlecharmode=singlecharmode)
>            page = 1
>            for box in self.needdvitextboxes:
>                box.setdvicanvas(self.dvifile.readpage([ord("P"), ord("y"), 
> ord("X"), page, 0, 0, 0, 0, 0, 0], fontmap=box.fontmap))
> @@ -1151,7 +1151,7 @@ class texrunner:
> 
>    PyXBoxPattern = 
> re.compile(r"PyXBox:page=(?P<page>\d+),lt=(?P<lt>-?\d*((\d\.?)|(\.?\d))\d*)pt,rt=(?P<rt>-?\d*((\d\.?)|(\.?\d))\d*)pt,ht=(?P<ht>-?\d*((\d\.?)|(\.?\d))\d*)pt,dp=(?P<dp>-?\d*((\d\.?)|(\.?\d))\d*)pt:")
> 
> -    def text(self, x, y, expr, textattrs=[], texmessages=[], fontmap=None):
> +    def text(self, x, y, expr, textattrs=[], texmessages=[], fontmap=None, 
> singlecharmode=0):
>        """create text by passing expr to TeX/LaTeX
>        - returns a textbox containing the result from running expr thru 
> TeX/LaTeX
>        - the box center is set to x, y
> @@ -1190,7 +1190,7 @@ class texrunner:
>            raise e
>        if self.texipc:
>            if first:
> -                self.dvifile = dvifile.DVIfile("%s.dvi" % self.texfilename, 
> debug=self.dvidebug)
> +                self.dvifile = dvifile.DVIfile("%s.dvi" % self.texfilename, 
> debug=self.dvidebug, singlecharmode=singlecharmode)
>        match = self.PyXBoxPattern.search(self.texmessage)
>        if not match or int(match.group("page")) != self.page:
>            raise TexResultError("box extents not found", self)
> -- 
> 1.7.7.338.g0156b
> 

-- 
by  _ _      _    Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim
  / \ \    / )   [email protected], http://www.wobsta.de/
 / _ \ \/\/ /    PyX - High quality PostScript and PDF figures
(_/ \_)_/\_/     with Python & TeX: visit http://pyx.sourceforge.net/

Attachment: smime.p7s
Description: S/MIME cryptographic signature

------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2d-oct
_______________________________________________
PyX-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/pyx-devel

Reply via email to