Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Right-click on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-10 08:28:24
|
r3151 took into account the direction already but missed the fact that arrows are positioned wrt. the constriction center now. Make it so that a reversed arrow is positioned wrt. the constriction center also. Signed-off-by: Michael J Gruber <michaeljgruber@...> --- pyx/deco.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyx/deco.py b/pyx/deco.py index 8cc6f95..2231899 100644 --- a/pyx/deco.py +++ b/pyx/deco.py @@ -472,7 +472,7 @@ class arrow(deco, attr.attr): constrictionlen = self.size * 1 * math.cos(math.radians(self.angle/2.0)) arrowheadconstrictionlen = None - arclenfrombegin = (1-self.reversed)*constrictionlen + self.pos * (anormpath.arclen() - constrictionlen) + arclenfrombegin = (1-2*self.reversed)*constrictionlen + self.pos * (anormpath.arclen() - constrictionlen) direction = self.reversed and -1 or 1 arrowhead = _arrowhead(anormpath, arclenfrombegin, direction, self.size, self.angle, arrowheadconstrictionlen) -- 1.7.10.1.702.g60a8c8a |
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-10 08:28:25
|
Currently, pos is relative to (arclength - constrictionlen) which makes it very hard to position arrow heads correctly at, say, quarter circles etc. Make it relative to the full arclength to ease positioning of the arrow heads. This requires putting in a safeguard (so that arrow heads do no come out before nor after that path) which may be of independent interest. Signed-off-by: Michael J Gruber <michaeljgruber@...> --- pyx/deco.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyx/deco.py b/pyx/deco.py index 2231899..84ae7f0 100644 --- a/pyx/deco.py +++ b/pyx/deco.py @@ -472,7 +472,8 @@ class arrow(deco, attr.attr): constrictionlen = self.size * 1 * math.cos(math.radians(self.angle/2.0)) arrowheadconstrictionlen = None - arclenfrombegin = (1-2*self.reversed)*constrictionlen + self.pos * (anormpath.arclen() - constrictionlen) + arclenfrombegin = (1-2*self.reversed)*constrictionlen + self.pos * anormpath.arclen() + arclenfrombegin = min(anormpath.arclen(), max(0, arclenfrombegin)) direction = self.reversed and -1 or 1 arrowhead = _arrowhead(anormpath, arclenfrombegin, direction, self.size, self.angle, arrowheadconstrictionlen) -- 1.7.10.1.702.g60a8c8a |
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-11 10:12:12
|
To make it clearer what this is about, here's some before and after comparison: https://github.com/mjg/PyX/wiki/Arrow-Heads Cheers Michael |
From: Joerg Lehmann <joergl@us...> - 2012-05-13 16:01:52
|
Hi Michael, Thanks for the patch. I am not sure, however, whether it really improves the situation. In particular, I do not like the fact that varying the pos argument at the beginning and end of the path does not move the arrow at all. If I understand the intention of the change correctly, it means that the arrow is always positioned at the end of the constriction - as long as this is possible. Why is this desirable? Cheers, Jörg On 11.05.12, Michael J Gruber wrote: > To make it clearer what this is about, here's some before and after > comparison: > > https://github.com/mjg/PyX/wiki/Arrow-Heads > > Cheers > Michael > > ------------------------------------------------------------------------------ > Live Security Virtual Conference > Exclusive live event will cover all the ways today's security and > threat landscape has changed and how IT managers can respond. Discussions > will include endpoint security, mobile security and the latest in malware > threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ > _______________________________________________ > PyX-devel mailing list > PyX-devel@... > https://lists.sourceforge.net/lists/listinfo/pyx-devel > |
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-14 09:05:53
|
Joerg Lehmann venit, vidit, dixit 13.05.2012 17:20: > Hi Michael, > > Thanks for the patch. I am not sure, however, whether it really improves > the situation. In particular, I do not like the fact that varying the > pos argument at the beginning and end of the path does not move the > arrow at all. If I understand the intention of the change correctly, it > means that the arrow is always positioned at the end of the > constriction - as long as this is possible. Why is this desirable? That means I have not made myself clear enough. Let me try again: We do try to position the arrow head based on the "inward tip" (constriction center) since r3151, which can be considered the "middle of the head". I don't propose changing that. PATCH 1/2 only makes sure that the same positioning is applied to reversed heads, i.e. non-reversed and reversed are mirror symmetric with respect to (an axis through) the "middle of the head", i.e. the positioning center. The problem I'm trying to address with PATCH 2/2 is: An arrow head positioned with pos=0.5 ist not positioned at 0.5*arclen, e.g. a semicircle. It is positioned at 0.5*(arclen-constrictionlen). This becomes quite visible when you're trying to position arrow heads at various intermediate positions, but also when you try to line up arrow heads with other decorations (such as text) which are *really* positioned at pos*arclen (or relarclenpos*arclen, there's no consistent naming). In the example which I provided, notice how the position of the ("middle of the") arrow heads does not scale linearly with the radius of the circle, even though the pos argument is always the same. It's the result of this principle: We calculate/restrict "admissible positions" so that 0 and 1 mean begin and end arrow, where an end arrow head has its tip lined up the end of the path, and a begin arrow has its constriction center lined up with the start of the path. That's why (1-0) has to mean (arclen-constrictionlen) which creates the other problems. Basically, I would love (1-0) to mean arclen (patch 2/2), i.e. everything relative to full arclen, then a beginhead would have pos=0, and an endhead would be at pos=1-constrictionlen/arclen. Consequently, a head at pos=1 would have its constriction center ("middle") at the end of the path. This would require additional adjustments to the way we cut the path, though. Which is why I did the min/max thingy. Cheers, Michael |
From: André Wobst <wobsta@us...> - 2012-05-21 21:04:45
Attachments:
smime.p7s
|
Hi, Am 14.05.2012 um 11:05 schrieb Michael J Gruber: > This becomes quite visible when you're trying to position arrow heads at > various intermediate positions, but also when you try to line up arrow > heads with other decorations (such as text) which are *really* > positioned at pos*arclen (or relarclenpos*arclen, there's no consistent > naming). I just wonder about this one. I didn't check myself, but it might be an error of the text decorator. Shouldn't it take into account "<arclen-of-the-path> - <length-of-the-text>" for positioning? Well, it might be, it might not. But the arrow does take into account "<arclen-of-the-path> - <constriction-length>". This is correct IMHO. Best, André -- by _ _ _ Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim / \ \ / ) wobsta@..., http://www.wobsta.de/ / _ \ \/\/ / PyX - High quality PostScript and PDF figures (_/ \_)_/\_/ with Python & TeX: visit http://pyx.sourceforge.net/ |
From: André Wobst <wobsta@us...> - 2012-05-21 21:00:26
Attachments:
smime.p7s
|
Hi Michael, sorry for being late in the discussion. Am 10.05.2012 um 10:28 schrieb Michael J Gruber: > r3151 took into account the direction already but missed the fact that > arrows are positioned wrt. the constriction center now. Make it so that > a reversed arrow is positioned wrt. the constriction center also. To my understanding this is not true. Everything is completely symmetric. For earrows, at pos=0, the "back" of the arrow starts at the starting point of the path and at pos=1 (the default for earrow) the tip is at the end. The same for barrow. At pos=1 the back is at the end of the path and at pos=0 (the default for barrow) the tip is at the beginning. Those limits are correct. In between we're just going linearly. I'm sorry, your circular example is much to complicated for me. Here's my attempt: from pyx import * ···· c = canvas.canvas() c.stroke(path.line(0, 0, 10, 0)) c.stroke(path.line(0, 0, 0, 2)) c.stroke(path.line(0.1, 0, 0.1, 2)) c.stroke(path.line(5, 0, 5, 2)) c.stroke(path.line(9.9, 0, 9.9, 2)) c.stroke(path.line(10, 0, 10, 2)) c.stroke(path.line(0, 0.2, 10, 0.2), [deco.arrow(pos=1)]) # earrow c.stroke(path.line(0, 0.4, 10, 0.4), [deco.arrow(pos=1, reversed=1)]) c.stroke(path.line(0, 0.6, 10, 0.6), [deco.arrow(pos=0.99)]) c.stroke(path.line(0, 0.8, 10, 0.8), [deco.arrow(pos=0.99, reversed=1)]) c.stroke(path.line(0, 1.0, 10, 1.0), [deco.arrow(pos=0.5)]) c.stroke(path.line(0, 1.2, 10, 1.2), [deco.arrow(pos=0.5, reversed=1)]) c.stroke(path.line(0, 1.4, 10, 1.4), [deco.arrow(pos=0.01)]) c.stroke(path.line(0, 1.6, 10, 1.6), [deco.arrow(pos=0.01, reversed=1)]) c.stroke(path.line(0, 1.8, 10, 1.8), [deco.arrow(pos=0)]) c.stroke(path.line(0, 2.0, 10, 2.0), [deco.arrow(pos=0, reversed=1)]) # barrow c.writePDFfile() Now try your patches. It creates a lot of confusion. No way. I think the positioning of the arrows on the circle you're trying to get right should be done using path features. This is trivial: from pyx import * c = canvas.canvas() circ = path.circle(0, 0, 5) p = path.line(0, 0, 5, 5) c.stroke(circ.split(circ.intersect(p)[0][0])[0], [deco.arrow(size=1)]) c.stroke(p) c.writePDFfile() Now, the only problem is if you want to position the "back of the arrow" at the intersection point. I don't know whether it is that useful (technically) but I fully understand that it might be desirable from a visual point of view sometimes. You need to take into account the constriction length of the arrow in question. Unfortunately this was not accessible from the outside. I just checked in a simple patch (changeset 3247). Then it becomes a simple modification of what we had before: from pyx import * c = canvas.canvas() circ = path.circle(0, 0, 5) p = path.line(0, 0, 5, 5) a = deco.arrow(size=1) c.stroke(circ.split(circ.intersect(p)[0][0] + a.constrictionlen)[0], [a]) c.stroke(p) c.writePDFfile() Best, André -- by _ _ _ Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim / \ \ / ) wobsta@..., http://www.wobsta.de/ / _ \ \/\/ / PyX - High quality PostScript and PDF figures (_/ \_)_/\_/ with Python & TeX: visit http://pyx.sourceforge.net/ |
From: Joerg Lehmann <joergl@us...> - 2012-05-22 07:18:17
|
Hi Michael, sorry - too much traveling last week. On 14.05.12, Michael J Gruber wrote: > Joerg Lehmann venit, vidit, dixit 13.05.2012 17:20: > > Hi Michael, > > > > Thanks for the patch. I am not sure, however, whether it really improves > > the situation. In particular, I do not like the fact that varying the > > pos argument at the beginning and end of the path does not move the > > arrow at all. If I understand the intention of the change correctly, it > > means that the arrow is always positioned at the end of the > > constriction - as long as this is possible. Why is this desirable? > > That means I have not made myself clear enough. Let me try again: > > We do try to position the arrow head based on the "inward tip" > (constriction center) since r3151, which can be considered the "middle > of the head". I am not sure if I understand you correctly, but I would say no. > I don't propose changing that. PATCH 1/2 only makes sure > that the same positioning is applied to reversed heads, i.e. > non-reversed and reversed are mirror symmetric with respect to (an axis > through) the "middle of the head", i.e. the positioning center. > The problem I'm trying to address with PATCH 2/2 is: An arrow head > positioned with pos=0.5 ist not positioned at 0.5*arclen, e.g. a > semicircle. It is positioned at 0.5*(arclen-constrictionlen). But this patch changes the positioning of both heads again - so in fact your two patches do change this. > This becomes quite visible when you're trying to position arrow heads at > various intermediate positions, but also when you try to line up arrow > heads with other decorations (such as text) which are *really* > positioned at pos*arclen (or relarclenpos*arclen, there's no consistent > naming). The naming is another issue - we should fix that. > In the example which I provided, notice how the position of the ("middle > of the") arrow heads does not scale linearly with the radius of the > circle, even though the pos argument is always the same. I think, I see what you mean, but still the other solution also has it's drawbacks - in particular the one I pointed out previously, namely that it fixes the arrow position for a finite interval around pos<=1. > It's the result of this principle: > We calculate/restrict "admissible positions" so that 0 and 1 mean begin > and end arrow, where an end arrow head has its tip lined up the end of > the path, and a begin arrow has its constriction center lined up with > the start of the path. That's why (1-0) has to mean > (arclen-constrictionlen) which creates the other problems. Yes. > Basically, I would love (1-0) to mean arclen (patch 2/2), i.e. > everything relative to full arclen, then a beginhead would have pos=0, > and an endhead would be at pos=1-constrictionlen/arclen. Consequently, a > head at pos=1 would have its constriction center ("middle") at the end > of the path. This would require additional adjustments to the way we cut > the path, though. Which is why I did the min/max thingy. We would need to extend the path, which is rather tricky. But doing the min/max thing is not a solution, IMHO. Best, Jörg |
From: André Wobst <wobsta@us...> - 2012-05-22 08:10:49
Attachments:
smime.p7s
|
Hi, Am 22.05.2012 um 09:18 schrieb Joerg Lehmann: >> We do try to position the arrow head based on the "inward tip" >> (constriction center) since r3151, which can be considered the "middle >> of the head". > > I am not sure if I understand you correctly, but I would say no. Jörg is right. We definitely don't do that. pos defines the position of the tip of the arrow. Originally before your patches. We really should stick at this simple rule. >> It's the result of this principle: >> We calculate/restrict "admissible positions" so that 0 and 1 mean begin >> and end arrow, where an end arrow head has its tip lined up the end of >> the path, and a begin arrow has its constriction center lined up with >> the start of the path. That's why (1-0) has to mean >> (arclen-constrictionlen) which creates the other problems. > > Yes. Really, I don't see where this creates any problem. It's simple and it's the right thing to do. >> Basically, I would love (1-0) to mean arclen (patch 2/2), i.e. >> everything relative to full arclen, then a beginhead would have pos=0, >> and an endhead would be at pos=1-constrictionlen/arclen. Consequently, a >> head at pos=1 would have its constriction center ("middle") at the end >> of the path. This would require additional adjustments to the way we cut >> the path, though. Which is why I did the min/max thingy. Sorry, IMHO this whole discussion will not result in anything useful. > We would need to extend the path, which is rather tricky. But doing the > min/max thing is not a solution, IMHO. Don't even think about extending the path. This is an absolute no-go. (I do understand that Michael did try to not do this. But he did so by using some very obscure min/max thing. Absolutely bizarre. No, no, no. Never.) André -- by _ _ _ Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim / \ \ / ) wobsta@..., http://www.wobsta.de/ / _ \ \/\/ / PyX - High quality PostScript and PDF figures (_/ \_)_/\_/ with Python & TeX: visit http://pyx.sourceforge.net/ |
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-23 15:18:39
|
André Wobst venit, vidit, dixit 22.05.2012 10:10: > Hi, > > Am 22.05.2012 um 09:18 schrieb Joerg Lehmann: >>> We do try to position the arrow head based on the "inward tip" >>> (constriction center) since r3151, which can be considered the >>> "middle of the head". >> >> I am not sure if I understand you correctly, but I would say no. > > Jörg is right. We definitely don't do that. pos defines the position > of the tip of the arrow. Originally before your patches. We really > should stick at this simple rule. Well, then please tell me what r3079 was about: diff --git a/pyx/deco.py b/pyx/deco.py index 3206627..9f11211 100644 --- a/pyx/deco.py +++ b/pyx/deco.py @@ -472,7 +472,7 @@ class arrow(deco, attr.attr): constrictionlen = self.size * 1 * math.cos(math.radians(self.angle/2.0)) arrowheadconstrictionlen = None - arclenfrombegin = self.pos * anormpath.arclen() + arclenfrombegin = constrictionlen + self.pos * (anormpath.arclen() - constrictionlen) direction = self.reversed and -1 or 1 arrowhead = _arrowhead(anormpath, arclenfrombegin, direction, self.size, self.angle, arrowheadconstrictionlen) This shifts the head by constrictionlen to the right, and the later r3151 made the direction of the shift depend on "reversed". I mean, I even uploaded those circular images where you can see it clearly. >>> It's the result of this principle: We calculate/restrict >>> "admissible positions" so that 0 and 1 mean begin and end arrow, >>> where an end arrow head has its tip lined up the end of the path, >>> and a begin arrow has its constriction center lined up with the >>> start of the path. That's why (1-0) has to mean >>> (arclen-constrictionlen) which creates the other problems. >> >> Yes. > > Really, I don't see where this creates any problem. It's simple and > it's the right thing to do. Again, please, look at the pictures again: There's currently no way to position an arrow head visually in the middle of a path. And the positions don't scale if you scale the path! >>> Basically, I would love (1-0) to mean arclen (patch 2/2), i.e. >>> everything relative to full arclen, then a beginhead would have >>> pos=0, and an endhead would be at pos=1-constrictionlen/arclen. >>> Consequently, a head at pos=1 would have its constriction center >>> ("middle") at the end of the path. This would require additional >>> adjustments to the way we cut the path, though. Which is why I >>> did the min/max thingy. > > Sorry, IMHO this whole discussion will not result in anything useful. > > >> We would need to extend the path, which is rather tricky. But doing >> the min/max thing is not a solution, IMHO. > > > Don't even think about extending the path. This is an absolute no-go. > (I do understand that Michael did try to not do this. But he did so > by using some very obscure min/max thing. Absolutely bizarre. No, no, > no. Never.) I never suggested extending the path, and I never did it. You see, the bizarre thing is that an arrow at pos=0 is not positioned in the same way as an arrow at pos=1, *if* you agree that pos is supposed to be a position relative to arclen. Calculating pos relative to (arclen-constrictionlen) is what seems completely bizarre to me. Let me repeat: a head at pos=0 is positioned differently (with respect to the start point of the path) comapred to how a head at pos=1 is positioned (with respect to the end of the point). The difference between us is that you seem to care about begin and end arrows mainly, while I care about mid arrows (also). Michael |
From: Michael J Gruber <michaeljgruber@us...> - 2012-05-23 16:05:51
|
André Wobst venit, vidit, dixit 21.05.2012 22:59: > Hi Michael, > > sorry for being late in the discussion. > > Am 10.05.2012 um 10:28 schrieb Michael J Gruber: >> r3151 took into account the direction already but missed the fact that >> arrows are positioned wrt. the constriction center now. Make it so that >> a reversed arrow is positioned wrt. the constriction center also. > > > To my understanding this is not true. Everything is completely symmetric. For earrows, at pos=0, the "back" of the arrow starts at the starting point of the path and at pos=1 (the default for earrow) the tip is at the end. The same for barrow. At pos=1 the back is at the end of the path and at pos=0 (the default for barrow) the tip is at the beginning. Those limits are correct. In between we're just going linearly. > > I'm sorry, your circular example is much to complicated for me. Here's my attempt: > > from pyx import * > ···· > c = canvas.canvas() > c.stroke(path.line(0, 0, 10, 0)) > c.stroke(path.line(0, 0, 0, 2)) > c.stroke(path.line(0.1, 0, 0.1, 2)) > c.stroke(path.line(5, 0, 5, 2)) > c.stroke(path.line(9.9, 0, 9.9, 2)) > c.stroke(path.line(10, 0, 10, 2)) > c.stroke(path.line(0, 0.2, 10, 0.2), [deco.arrow(pos=1)]) # earrow > c.stroke(path.line(0, 0.4, 10, 0.4), [deco.arrow(pos=1, reversed=1)]) > c.stroke(path.line(0, 0.6, 10, 0.6), [deco.arrow(pos=0.99)]) > c.stroke(path.line(0, 0.8, 10, 0.8), [deco.arrow(pos=0.99, reversed=1)]) > c.stroke(path.line(0, 1.0, 10, 1.0), [deco.arrow(pos=0.5)]) > c.stroke(path.line(0, 1.2, 10, 1.2), [deco.arrow(pos=0.5, reversed=1)]) > c.stroke(path.line(0, 1.4, 10, 1.4), [deco.arrow(pos=0.01)]) > c.stroke(path.line(0, 1.6, 10, 1.6), [deco.arrow(pos=0.01, reversed=1)]) > c.stroke(path.line(0, 1.8, 10, 1.8), [deco.arrow(pos=0)]) > c.stroke(path.line(0, 2.0, 10, 2.0), [deco.arrow(pos=0, reversed=1)]) # barrow > c.writePDFfile() I think that's a perfect illustration of the current problems: The pos=1 arrow has its tip on the vertical comparison line, the one at 0.99 also. The one at pos=0.5 has "something" on that line (the line interesects the head between the tip and the constriction center). The one at pos=0 and pos=0.01 have their constriction centers on the respective lines. All positioned differently. Also note how the tips of the back of the arrow protrude beyond the vertical line, but the forward tip does not. Compare that to line drawing for accute angles: There, a stroked path will (due to the angle and linewidth) always protrude beyond the corner of the angle. In that sense, enforcing that an arrow tip does not protrude (as it is now) is artificial. But that's probably not going to change. I'm not saying that my patch solves all this - in fact, what you call "confusion" comes from the attempt to provide some backwards compatibility for pos=0 and 1. >From my point of view, pos should be relative to full arclength, and barrow and earrow should do whatever is needed so that they come out unchanged (say, earrow would have pos= (arclen-constricionlen/arclen)). Simply because that is the most natural, controllable and mathematically sane. But I see I'm facing an uphill battle. And no, splitting a path for every decoration that I put there is not a solution. Just thing of annotating an integration path. Do you really suggesting stroking it piecewise, or over and over again? The beauty of the deco module in PyX is the fact that you have *one* path carrying allow decorations (text labels, arrow heads and what not). For that you have to be able to position them consistently (say, text label at pos for arrow at pos). Michael |
From: André Wobst <wobsta@us...> - 2012-05-23 19:33:16
Attachments:
smime.p7s
|
Hi Michael, there is one interesting point in here which I don't want to die. Am 23.05.2012 um 18:05 schrieb Michael J Gruber: > And no, splitting a path for every decoration that I put there is not a > solution. Just thing of annotating an integration path. Do you really > suggesting stroking it piecewise, or over and over again? The beauty of > the deco module in PyX is the fact that you have *one* path carrying > allow decorations (text labels, arrow heads and what not). For that you > have to be able to position them consistently (say, text label at pos > for arrow at pos). I agree. And I did see it already, but I don't have a proper solution yet. Sure, you want to stoke the path in a single operation. You can add multiple arrows and text. But how do you define their position? For text we have pos but also arclenfrombegin and arclenfromend. But you probably don't want to mess around with arclen either. Furthermore, for text you have halign.left, halign.center and halign.right. Maybe we need something like this for arrows too. Still I think using path.intersect() is a great and very PyX-like way of doing things. Now, how do you enter such a position into the decorators? Splitting the path and using "end of the path" is a solution, but it is not the nicest one I could envision. I don't have a solution so far. Best, André -- by _ _ _ Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim / \ \ / ) wobsta@..., http://www.wobsta.de/ / _ \ \/\/ / PyX - High quality PostScript and PDF figures (_/ \_)_/\_/ with Python & TeX: visit http://pyx.sourceforge.net/ |
From: André Wobst <wobsta@us...> - 2012-05-23 19:20:02
Attachments:
smime.p7s
|
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. 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. 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". 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? 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. The interesting question is whether we can do what you want by adding another parameter or so. However, I don't see an obvious solution to it. Sure, we could add something like arclenfrombegin and arclenfromend like we did for the text decorators. But you don't really want that to position arrows at the circle. You know what? I really think, that my suggestion in splitting the path is the most elegant solution you can ever achieve. Consider the case, where you want to draw the arrow at the "x-axis", i.e. at zero degree. You can do so at the moment by using earrow to get the tip on the line or barrow(reverse=0) to get the constriction point on the line. This is very unsteady and will always be. I'll add some comment below, but don't mind. Best, André Am 23.05.2012 um 17:18 schrieb Michael J Gruber: > André Wobst venit, vidit, dixit 22.05.2012 10:10: >> Hi, >> >> Am 22.05.2012 um 09:18 schrieb Joerg Lehmann: >>>> We do try to position the arrow head based on the "inward tip" >>>> (constriction center) since r3151, which can be considered the >>>> "middle of the head". >>> >>> I am not sure if I understand you correctly, but I would say no. >> >> Jörg is right. We definitely don't do that. pos defines the position >> of the tip of the arrow. Originally before your patches. We really >> should stick at this simple rule. > > Well, then please tell me what r3079 was about: > > > diff --git a/pyx/deco.py b/pyx/deco.py > index 3206627..9f11211 100644 > --- a/pyx/deco.py > +++ b/pyx/deco.py > @@ -472,7 +472,7 @@ class arrow(deco, attr.attr): > constrictionlen = self.size * 1 * > math.cos(math.radians(self.angle/2.0)) > arrowheadconstrictionlen = None > > - arclenfrombegin = self.pos * anormpath.arclen() > + arclenfrombegin = constrictionlen + self.pos * > (anormpath.arclen() - constrictionlen) > direction = self.reversed and -1 or 1 > arrowhead = _arrowhead(anormpath, arclenfrombegin, direction, > self.size, self.angle, arrowheadconstrictionlen) > > > This shifts the head by constrictionlen to the right, and the later > r3151 made the direction of the shift depend on "reversed". The point is that the arrow should always be part of the path, not extending it. > I mean, I even uploaded those circular images where you can see it clearly. > >>>> It's the result of this principle: We calculate/restrict >>>> "admissible positions" so that 0 and 1 mean begin and end arrow, >>>> where an end arrow head has its tip lined up the end of the path, >>>> and a begin arrow has its constriction center lined up with the >>>> start of the path. That's why (1-0) has to mean >>>> (arclen-constrictionlen) which creates the other problems. >>> >>> Yes. >> >> Really, I don't see where this creates any problem. It's simple and >> it's the right thing to do. > > Again, please, look at the pictures again: There's currently no way to > position an arrow head visually in the middle of a path. And the > positions don't scale if you scale the path! What exactly is "in the middle of the path?" if you talk about it "visually"? To my mind it does not mean that the top nor the constriction point is at half of the arclen. It looks a little strange, as you change the size of the circle here. Please fix the size of the circle and change the size of the arrow. This is geometrically identical. But look at the result. Both, the tip and the constriction point will move. Isn't it right that it works that way? I don't see something wrong in it. >>>> Basically, I would love (1-0) to mean arclen (patch 2/2), i.e. >>>> everything relative to full arclen, then a beginhead would have >>>> pos=0, and an endhead would be at pos=1-constrictionlen/arclen. >>>> Consequently, a head at pos=1 would have its constriction center >>>> ("middle") at the end of the path. This would require additional >>>> adjustments to the way we cut the path, though. Which is why I >>>> did the min/max thingy. >> >> Sorry, IMHO this whole discussion will not result in anything useful. >> >> >>> We would need to extend the path, which is rather tricky. But doing >>> the min/max thing is not a solution, IMHO. >> >> >> Don't even think about extending the path. This is an absolute no-go. >> (I do understand that Michael did try to not do this. But he did so >> by using some very obscure min/max thing. Absolutely bizarre. No, no, >> no. Never.) > > I never suggested extending the path, and I never did it. You see, the > bizarre thing is that an arrow at pos=0 is not positioned in the same > way as an arrow at pos=1, *if* you agree that pos is supposed to be a > position relative to arclen. Calculating pos relative to > (arclen-constrictionlen) is what seems completely bizarre to me. And to me it is the other way around. "arclen-constrictionlen" clearly is the which is available for moving the arrow around. > Let me repeat: a head at pos=0 is positioned differently (with respect > to the start point of the path) comapred to how a head at pos=1 is > positioned (with respect to the end of the point). Sure, we position the arrow, not the tip of the arrow. We need to do so, as for pos=0 (and reverse=0) the constriction point is at the beginning of the path. What else should be it? > 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. If you center it, the text starts before half of the path and ends after half of the path. -- by _ _ _ Dr. André Wobst, Amselweg 22, 85716 Unterschleißheim / \ \ / ) wobsta@..., http://www.wobsta.de/ / _ \ \/\/ / PyX - High quality PostScript and PDF figures (_/ \_)_/\_/ with Python & TeX: visit http://pyx.sourceforge.net/ |
From: Michael J Gruber <michaeljgruber@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 |