[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Fix: NSBezierPath, appendBezierPathWithArcWithCenter:
From: |
Nicola Pero |
Subject: |
Re: Fix: NSBezierPath, appendBezierPathWithArcWithCenter: |
Date: |
Thu, 1 Mar 2001 14:32:40 +0100 (CET) |
> Hi Nicola,
>
> > Thanks - I read your patch and it made lot of sense - so I applied it. I
> > did not test it nor did I check on books the formula used to build the
> > bezier path for the last bit of the arc, so I hope you did. :-)
>
> Yes, I have tested it.
> Anyway, I had to realized another little problem in the same method, so since
>
> it isn't committed yet, I will send a new patch covering this remaining issue
>
> too.
Well - I already committed your patch, anyway we enjoy further patches.
:-)
> > Ahm - just a quick note - before committing, I sligthly simplified the
> > formula used for F - not that I changed it (unless I made a typo) - just
> > did some trivial algebraic/trigonometric simplifications. But as I didn't
> > test it, please tell me if I did something wrong.
>
> Can you send me your changes, so I can test it ?
They should be on CVS already - anyway in case you don't have CVS or
whatever, in attach you find the diff against the original sources (not
against your patch).
Index: NSBezierPath.m
===================================================================
RCS file: /gnustep/gnustep/core/gui/Source/NSBezierPath.m,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- NSBezierPath.m 2001/01/21 22:32:35 1.7
+++ NSBezierPath.m 2001/03/01 01:47:32 1.8
@@ -828,103 +828,132 @@
[self lineToPoint: points[i]];
}
-- (void)appendBezierPathWithOvalInRect:(NSRect)aRect
+- (void) appendBezierPathWithOvalInRect: (NSRect)aRect
{
[self appendBezierPath: [isa bezierPathWithOvalInRect: aRect]];
}
-- (void)appendBezierPathWithArcWithCenter:(NSPoint)center
- radius:(float)radius
- startAngle:(float)startAngle
- endAngle:(float)endAngle
- clockwise:(BOOL)clockwise
+/* startAngle and endAngle are in degrees, counterclockwise, from the
+ x axis */
+- (void) appendBezierPathWithArcWithCenter: (NSPoint)center
+ radius: (float)radius
+ startAngle: (float)startAngle
+ endAngle: (float)endAngle
+ clockwise: (BOOL)clockwise
{
- NSBezierPath *path = [isa bezierPath];
- float strtangrd, endangrd, diff;
+ float startAngle_rad, endAngle_rad, diff;
NSPoint p0, p1, p2, p3;
- while(startAngle < 0)
+ while (startAngle < 0)
startAngle = startAngle + 360;
- while(startAngle > 360)
+ while (startAngle > 360)
startAngle = startAngle - 360;
- while(endAngle < 0)
+ while (endAngle < 0)
endAngle = endAngle + 360;
- while(endAngle > 360)
+ while (endAngle > 360)
endAngle = endAngle - 360;
- strtangrd = PI * startAngle / 180;
- endangrd = PI * endAngle / 180;
+ /* Convert the angles to radians */
+ startAngle_rad = PI * startAngle / 180;
+ endAngle_rad = PI * endAngle / 180;
+
+ /* Start point */
+ p0 = NSMakePoint (center.x + radius * cos (startAngle_rad),
+ center.y + radius * sin (startAngle_rad));
+ [self moveToPoint: p0];
- p0 = NSMakePoint(center.x + radius * cos(strtangrd), center.y + radius *
sin(strtangrd));
- [path moveToPoint: p0];
-
if (clockwise)
{
diff = -PI / 2;
- if (strtangrd < endangrd)
- strtangrd += 2 * PI;
+ if (startAngle_rad < endAngle_rad)
+ {
+ startAngle_rad += 2 * PI;
+ }
}
else
{
diff = PI / 2;
- if (strtangrd > endangrd)
- strtangrd -= 2 * PI;
+ if (startAngle_rad > endAngle_rad)
+ {
+ startAngle_rad -= 2 * PI;
+ }
}
-
- while (strtangrd > endangrd)
- {
- if (strtangrd + diff >= endangrd)
- {
- float sin_sta = sin(strtangrd);
- float cos_sta = cos(strtangrd);
- // FIXME: Add a quarter circle, for clockwise the signs are not
correct!
- p1 = NSMakePoint(center.x + radius * (cos_sta - KAPPA * sin_sta),
- center.y + radius * (sin_sta + KAPPA * cos_sta));
- p2 = NSMakePoint(center.x + radius * (KAPPA * cos_sta -sin_sta),
- center.y + radius * (cos_sta + KAPPA * sin_sta));
- p3 = NSMakePoint(center.x + radius * (-sin_sta),
- center.y + radius * cos_sta);
- [path curveToPoint: p3 controlPoint1: p1 controlPoint2: p2];
- strtangrd += diff;
- }
- else
- {
- float diff_ang = (endangrd - strtangrd) / 2;
- float cos_da = cos(diff_ang);
- float sin_da = sin(diff_ang);
- double x, y;
- float sin_sta = sin(strtangrd + diff_ang);
- float cos_sta = cos(strtangrd + diff_ang);
-
- x = (4 - cos_da) / 3;
- y = ((1- cos_da) * (cos_da - 3)) / (3 * sin_da);
- // FIXME: Add just the missing bit, for clockwise the signs are not
correct!
- p1 = NSMakePoint(center.x + radius * (cos_sta * x - sin_sta * y),
- center.y + radius * (sin_sta * y + cos_sta * x));
- p2 = NSMakePoint(center.x + radius * (cos_sta * x + sin_sta * y),
- center.y + radius * (sin_sta * (-y) + cos_sta * x));
- p3 = NSMakePoint(center.x + radius * cos(endangrd),
- center.y + radius * sin(endangrd));
- [path curveToPoint: p3 controlPoint1: p1 controlPoint2: p2];
- break;
- }
+ while ((clockwise) ? (startAngle_rad > endAngle_rad)
+ : (startAngle_rad < endAngle_rad))
+ {
+ /* Add a quarter circle */
+ if ((clockwise) ? (startAngle_rad + diff >= endAngle_rad)
+ : (startAngle_rad + diff <= endAngle_rad))
+ {
+ float sin_start = sin (startAngle_rad);
+ float cos_start = cos (startAngle_rad);
+ float sign = (clockwise) ? -1.0 : 1.0;
+
+ p1 = NSMakePoint (center.x
+ + radius * (cos_start - KAPPA * sin_start * sign),
+ center.y
+ + radius * (sin_start + KAPPA * cos_start * sign));
+ p2 = NSMakePoint (center.x
+ + radius * (-sin_start * sign + KAPPA * cos_start),
+ center.y
+ + radius * (cos_start * sign + KAPPA * sin_start));
+ p3 = NSMakePoint (center.x + radius * (-sin_start * sign),
+ center.y + radius * cos_start * sign);
+
+ [self curveToPoint: p3 controlPoint1: p1 controlPoint2: p2];
+ startAngle_rad += diff;
+ }
+ else
+ {
+ /* Add the missing bit
+ * We require that the arc be less than a semicircle.
+ * The arc may go either clockwise or counterclockwise.
+ * The approximation is a very simple one: a single curve
+ * whose middle two control points are a fraction F of the way
+ * to the intersection of the tangents, where
+ * F = (4/3) / (1 + sqrt (1 + (d / r)^2))
+ * where r is the radius and d is the distance from either tangent
+ * point to the intersection of the tangents. This produces
+ * a curve whose center point, as well as its ends, lies on
+ * the desired arc.
+ */
+ NSPoint ps = [self currentPoint];
+ /* tangent is the tangent of half the angle */
+ float tangent = tan ((endAngle_rad - startAngle_rad) / 2);
+ /* trad is the distance from either tangent point to the
+ intersection of the tangents */
+ float trad = radius * tangent;
+ /* pt is the intersection of the tangents */
+ NSPoint pt = NSMakePoint (ps.x - trad * sin (startAngle_rad),
+ ps.y + trad * cos (startAngle_rad));
+ /* This is F - in this expression we need to compute
+ (trad/radius)^2, which is simply tangent^2 */
+ float f = (4.0 / 3.0) / (1.0 + sqrt (1.0 + (tangent * tangent)));
+
+ p1 = NSMakePoint (ps.x + (pt.x - ps.x) * f, ps.y + (pt.y - ps.y) * f);
+ p3 = NSMakePoint(center.x + radius * cos (endAngle_rad),
+ center.y + radius * sin (endAngle_rad));
+ p2 = NSMakePoint (p3.x + (pt.x - p3.x) * f, p3.y + (pt.y - p3.y) * f);
+ [self curveToPoint: p3 controlPoint1: p1 controlPoint2: p2];
+ break;
+ }
}
}
-- (void)appendBezierPathWithArcWithCenter:(NSPoint)center
- radius:(float)radius
- startAngle:(float)startAngle
- endAngle:(float)endAngle
-{
- [self appendBezierPathWithArcWithCenter: center radius: radius
- startAngle: startAngle endAngle: endAngle clockwise: NO];
+- (void) appendBezierPathWithArcWithCenter: (NSPoint)center
+ radius: (float)radius
+ startAngle: (float)startAngle
+ endAngle: (float)endAngle
+{
+ [self appendBezierPathWithArcWithCenter: center radius: radius
+ startAngle: startAngle endAngle: endAngle clockwise: NO];
}
-- (void)appendBezierPathWithArcFromPoint:(NSPoint)point1
- toPoint:(NSPoint)point2
- radius:(float)radius
+- (void) appendBezierPathWithArcFromPoint: (NSPoint)point1
+ toPoint: (NSPoint)point2
+ radius: (float)radius
{
// TODO
}
@@ -1326,9 +1355,9 @@
INVALIDATE_CACHE();
}
-- (void)curveToPoint:(NSPoint)aPoint
- controlPoint1:(NSPoint)controlPoint1
- controlPoint2:(NSPoint)controlPoint2
+- (void) curveToPoint: (NSPoint)aPoint
+ controlPoint1: (NSPoint)controlPoint1
+ controlPoint2: (NSPoint)controlPoint2
{
PathElement elem;
@@ -1666,3 +1695,4 @@
[path lineToPoint: coeff[3]];
}
}
+