From: Michael J G. <mic...@us...> - 2012-05-24 15:21:46
|
Dear André André Wobst venit, vidit, dixit 23.05.2012 21:19: > Dear Michael, > > I'm sorry, could we please rewind the whole discussion. And let us > not talk about code but about the way it should work. Sure, I should have marked the code as "RFD" ;) Let me point out that I think that pyx.deco is one of the gems of PyX, and that I only want to help polish it :) > To me, the current behavior is the correct (and only correct) one. > Let me explain again, why I think so. > > 1. The arrow should be "part" of the path, i.e. the tip and the > constriction point needs to be positioned on the path. Yes and no. The arrow head should be part of the path just like (the outline of) a stroke is part of the path. But the stroke extends transversally, of course, and also longitudinally (depending on linecap). > 2. For pos == 0 the arrow should be at the beginning, either in the > forward direction (reverse == 0) or backwards (reverse == 1). As it > is a common use-case, pos == 0 and reverse == 1 is available as > "barrow". > 3. For pos == 1 the arrow should be at the beginning. Again, it can > be reversed. pos == 1 and reverse == 0 is an "earrow". Yes and no: the begin and end case should be available as barrow and earrow. But one can really argue about what "at the beginning" and "at the end" mean. For the simple triangular arrow heads, one could also expect an end head to be attached to the end of a path (like a round linecap). This is difficult for PyX's path-shaped heads, of course. > 4. Between those limits the pos argument should interpolate > linearly. And yes, this means that for pos == 0.5 neighter the tip > nor the constriction point of the arrow is at 0.5*arclen(). > > Do you agree to this functionality? Not completely ;) For example, for a closed smooth curve it's quite reasonable to expect pos=0 and pos=1 to be equivalent since they are the same point with the same tangent! I think the main issue is that all other existing or conceivable decorations are "local" in the sense that they use a point and maybe the tangent at that point of the path; but arrow heads need to use a a whole segment of the path. This limits the available positions if one does not want to extend the path. Note that it is extended even now: _arrowhead() use a portion of the path of size "size", so the first allowed position should be at "size", not "constrictionlen": ---->%---- from pyx import * c = canvas.canvas() const = 0.5 c.stroke(path.circle(0,0,0.3), [deco.arrow(pos=0, constriction=const), deco.earrow(constriction=const)]) c.writePDFfile() ---->%---- See how the linear interpolation is used for pos=0 (i.e. arclenpos=constrictionlen)? So, following the existing reasoning pos from [0,1] should be mapped to an interval of length arclen-size. But that would require adding another exclusion range at the beginning! So, if we insist on avoiding path extrapolation, pos=0 would need to correspond to arclenpos=size (and analogous for reversed heads, of course). I don't think that's the look that we want even for pos=0! > I do understand, that you might wonder about my solution to split > the path to properly align the arrows. But this is a straight forward > and elegant solution to work around the intrinsic problem, that pos > interpolates on the range arclen-constrictionlen. It needs to be > that way. I'm glad you agree that this interpolation is the problem ;) Seriously: maybe we can, for a moment, _not_ take that range as given and see what could happen then: * Either by changing pos or introducing arclenpos, allow range 0 to arclen (or even more). * Make earrow put an arrow at arclenpos, barrow(reversed=true) at size and so on. * Either export size (like you did with constriction) or better introduce a poscorr (or shift) parameter which allows shifting the position by multiples of size. That way, the positioning would be analogous to other decorators, one could "center" the heads at will, and barrow/earrow results would be unchanged (except for a fix the size vs. constrictionlen problem). >> The difference between us is that you seem to care about begin and >> end arrows mainly, while I care about mid arrows (also). > > Well, to me an arrow is something like a text. It has some extend. Yes, exactly! > If you center it, the text starts before half of the path and ends > after half of the path. > Yes, exactly my thinking! And, just like for tick labels, there's no reason why the decoration should be clipped by the path. I've been meaning for a while now to code a deco.insert() which inserts a canvas as a decoration. deco.text() is just a special version of that. deco.arrow() is in some sense a special blend between a decorator and a deformer; but for a "uniformly shaped path", I would expect it to behave like the other decorators in the sense above: insert something at the path pos, where the insertion is centered/anchored at a natural reference point (which may be changed by options). Cheers Michael |