[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Fix: NSBezierPath, appendBezierPathWithArcWithCenter (2)
From: 
Nicola Pero 
Subject: 
Re: Fix: NSBezierPath, appendBezierPathWithArcWithCenter (2) 
Date: 
Wed, 7 Mar 2001 04:59:19 +0100 (CET) 
Hi Georg,
> > startAngle = 0
> > endAngle = 450
> > clockwise
> >
> > it wouldn't work... <it would draw a full circumference rather than simply
> > from 90 to 0>
>
> Thats exactly what it does, and I think its the correct behavior.
Ok  so we don't agree on what the API is supposed to do. :)
To add to the confusion, the macosx doc for NSBezier path says that the
`clockwise' argument determines whether angles are measured clockwise or
counterclockwise, while postscript operators and common sense push us to
interpret that argument as whether the arc is to be drawn clockwise or
counterclockwise (which is a pretty different concept).
I think it's probably a bug in the doc and I'd really tend to read the API
in the postscript way, but I can't test the behaviour on macosx. Do you
agree at least on this point  interpreting it in the postscript way ?
Can anyone test it ? <we are talking about
[NSBezierPath
appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:clockwise:]>
If we agree that we had to interpret the arguments to NSBezierPath in the
same way as the arguments to the postscript operators `arc' and `arcn',
then we can use the reference doc for those to determine how it should
work.
So  I looked at the postscript reference for the `arc' and `arcn'
operators.
Other doc is vague, but the postscript reference prescribes exactly the
algorithm to use for the angles in arc 
`If angle_2 [end angle] is less than angle_1 [start angle], it is
increased by multiples of 360 until it becomes greater than or equal to
angle_1. No other adjustments are made to the two angles. In particular,
the angle subtended by the arc is not reduced modulo 360; if the
difference angle_1  angle_2 exceeds 360, the resulting path will trace
portions of the circle more than once.'
I won't bother you with the explanation of why I don't like this
prescription at all (but eg :), try drawing an arc between angles 0 and
{a little number} (such as 0.1) using arc  the result will be either a
full circle or nothing depending on how little the number is  on my
system 0.001 generates a full circle, while 0.0001 generates nothing 
it is the hardware which determines whether your arc command draws a full
circle or nothing...)
Anyway  the prescription works perfectly fine for angles between 0 and
360  it's the standard documented postscript prescription so I agree with
using it.
Here is a patch implementing this prescription 
Index: NSBezierPath.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/gui/Source/NSBezierPath.m,v
retrieving revision 1.8
diff u r1.8 NSBezierPath.m
 NSBezierPath.m 2001/03/01 01:47:32 1.8
+++ NSBezierPath.m 2001/03/07 01:22:37
@@ 833,7 +833,7 @@
[self appendBezierPath: [isa bezierPathWithOvalInRect: aRect]];
}
/* startAngle and endAngle are in degrees, counterclockwise, from the
+/* startAngle and endAngle are in degrees, counterclockwise, from the
x axis */
 (void) appendBezierPathWithArcWithCenter: (NSPoint)center
radius: (float)radius
@@ 844,16 +844,37 @@
float startAngle_rad, endAngle_rad, diff;
NSPoint p0, p1, p2, p3;
 while (startAngle < 0)
 startAngle = startAngle + 360;
 while (startAngle > 360)
 startAngle = startAngle  360;

 while (endAngle < 0)
 endAngle = endAngle + 360;
 while (endAngle > 360)
 endAngle = endAngle  360;
+ /* We use the Postscript prescription for managing the angles and
+ drawing the arc. See the documentation for `arc' and `arcn' in
+ the Postscript Reference. */
+ if (clockwise)
+ {
+ /* This modification of the angles is the postscript
+ prescription. */
+ while (startAngle < endAngle)
+ endAngle = 360;
+
+ /* This is used when we draw a clockwise quarter of
+ circumference. By adding diff at the starting angle of the
+ quarter, we get the ending angle. diff is negative because
+ we draw clockwise. */
+ diff =  PI / 2;
+ }
+ else
+ {
+ /* This modification of the angles is the postscript
+ prescription. */
+ while (endAngle < startAngle)
+ endAngle += 360;
+
+ /* This is used when we draw a counterclockwise quarter of
+ circumference. By adding diff at the starting angle of the
+ quarter, we get the ending angle. diff is positive because
+ we draw counterclockwise. */
+ diff = PI / 2;
+ }
+
/* Convert the angles to radians */
startAngle_rad = PI * startAngle / 180;
endAngle_rad = PI * endAngle / 180;
@@ 862,23 +883,6 @@
p0 = NSMakePoint (center.x + radius * cos (startAngle_rad),
center.y + radius * sin (startAngle_rad));
[self moveToPoint: p0];

 if (clockwise)
 {
 diff = PI / 2;
 if (startAngle_rad < endAngle_rad)
 {
 startAngle_rad += 2 * PI;
 }
 }
 else
 {
 diff = PI / 2;
 if (startAngle_rad > endAngle_rad)
 {
 startAngle_rad = 2 * PI;
 }
 }
while ((clockwise) ? (startAngle_rad > endAngle_rad)
: (startAngle_rad < endAngle_rad))
Yes  it is your patch :)  except for my verbose comments and for the
fact that  since we are following the postscript doc, we must not modify
startAngle at the beginning  so I removed the code which did it.
Does this patch look right to you ?
Basically you convinced me to use the postscript way of doing it, and your
patch  with a little fix  implements it (I hadn't realized that was what
you wanted to do!), so I agree with using it rather than what I sent to
you (which implemented my own tentative guess of what the API could mean).
If it's Ok, we can apply to CVS.
> If the current point is not the start point of the arc, PostScript draws a
> line from the current position to the start of the arc.
> To get this behavior in GNUstep, appendBezierPathWithArcWithCenter just has
> to
> perform a lineto instead of a moveto to the start position of the arc (if a
> current point is defined).
Yes  that's what the backend should do in response to arc commands; but I
think the macosx doc for NSBezierPath says that we should not draw the
line in NSBezierPath. I need to look at it  but if the backend is using
NSBezierPath to draw the arc, then what we need to do is adding the line
in the backend before it draws the arc using NSBezierPath.