00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "CGGeometry.h"
00024 #include "CGAffineTransform.h"
00025
00026 @import "CGGeometry.j"
00027 @import "CGAffineTransform.j"
00028
00029
00030 kCGPathElementMoveToPoint = 0;
00031 kCGPathElementAddLineToPoint = 1;
00032 kCGPathElementAddQuadCurveToPoint = 2;
00033 kCGPathElementAddCurveToPoint = 3;
00034 kCGPathElementCloseSubpath = 4;
00035
00036 kCGPathElementAddArc = 5;
00037 kCGPathElementAddArcToPoint = 6;
00038
00047 function CGPathCreateMutable()
00048 {
00049 return { count:0, start:NULL, current:NULL, elements:[] };
00050 }
00051
00056 function CGPathCreateMutableCopy(aPath)
00057 {
00058 var path = CGPathCreateMutable();
00059
00060 CGPathAddPath(path, aPath);
00061
00062 return path;
00063 }
00064
00069 function CGPathCreateCopy(aPath)
00070 {
00071 return CGPathCreateMutableCopy(aPath);
00072 }
00073
00074 function CGPathRelease(aPath)
00075 {
00076 }
00077
00078 function CGPathRetain(aPath)
00079 {
00080 return aPath;
00081 }
00082
00083 function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle, isClockwise)
00084 {
00085 if (aTransform && !_CGAffineTransformIsIdentity(aTransform))
00086 {
00087 var center = _CGPointMake(x, y),
00088 end = _CGPointMake(COS(anEndAngle), SIN(anEndAngle)),
00089 start = _CGPointMake(COS(aStartAngle), SIN(aStartAngle));
00090
00091 end = _CGPointApplyAffineTransform(end, aTransform);
00092 start = _CGPointApplyAffineTransform(start, aTransform);
00093 center = _CGPointApplyAffineTransform(center, aTransform);
00094
00095 x = center.x;
00096 y = center.y;
00097
00098 var oldEndAngle = anEndAngle,
00099 oldStartAngle = aStartAngle;
00100
00101 anEndAngle = ATAN2(end.y - aTransform.ty, end.x - aTransform.tx);
00102 aStartAngle = ATAN2(start.y - aTransform.ty, start.x - aTransform.tx);
00103
00104
00105
00106
00107 if (anEndAngle == aStartAngle && oldEndAngle != oldStartAngle)
00108 if (oldStartAngle > oldEndAngle)
00109 anEndAngle = anEndAngle - PI2;
00110 else
00111 aStartAngle = aStartAngle - PI2;
00112
00113 aRadius = _CGSizeMake(aRadius, 0);
00114 aRadius = _CGSizeApplyAffineTransform(aRadius, aTransform);
00115 aRadius = SQRT(aRadius.width * aRadius.width + aRadius.height * aRadius.height);
00116 }
00117
00118 aPath.current = _CGPointMake(x + aRadius * COS(anEndAngle), y + aRadius * SIN(anEndAngle));
00119 aPath.elements[aPath.count++] = { type:kCGPathElementAddArc, x:x, y:y, radius:aRadius, startAngle:aStartAngle, endAngle:anEndAngle };
00120 }
00121
00122 function CGPathAddArcToPoint(aPath, aTransform, x1, y1, x2, y2, aRadius)
00123 {
00124 }
00125
00126 function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
00127 {
00128 var cp1 = _CGPointMake(cp1x, cp1y),
00129 cp2 = _CGPointMake(cp2x, cp2y),
00130 end = _CGPointMake(x, y);
00131
00132 if (aTransform)
00133 {
00134 cp1 = _CGPointApplyAffineTransform(cp1, aTransform);
00135 cp2 = _CGPointApplyAffineTransform(cp2, aTransform);
00136 end = _CGPointApplyAffineTransform(end, aTransform);
00137 }
00138
00139 aPath.current = end;
00140 aPath.elements[aPath.count++] = { type:kCGPathElementAddCurveToPoint, cp1x:cp1.x, cp1y:cp1.y, cp2x:cp2.x, cp2y:cp2.y, x:end.x, y:end.y };
00141 }
00142
00143 function CGPathAddLines(aPath, aTransform, points, count)
00144 {
00145 var i = 1;
00146
00147 if (arguments["count"] == NULL)
00148 var count = points.length;
00149
00150 if (!aPath || count < 2)
00151 return;
00152
00153 CGPathMoveToPoint(aPath, aTransform, points[0].x, points[0].y);
00154
00155 for (; i < count; ++i)
00156 CGPathAddLineToPoint(aPath, aTransform, points[i].x, points[i].y);
00157 }
00158
00159 function CGPathAddLineToPoint(aPath, aTransform, x, y)
00160 {
00161 var point = _CGPointMake(x, y);
00162
00163 if (aTransform != NULL)
00164 point = _CGPointApplyAffineTransform(point, aTransform);
00165
00166 aPath.elements[aPath.count++] = { type: kCGPathElementAddLineToPoint, x:point.x, y:point.y };
00167 aPath.current = point;
00168 }
00169
00170 function CGPathAddPath(aPath, aTransform, anotherPath)
00171 {
00172 for (var i = 0, count = anotherPath.count; i < count; ++i)
00173 {
00174 var element = anotherPath.elements[i];
00175
00176 switch (element.type)
00177 {
00178 case kCGPathElementAddLineToPoint: CGPathAddLineToPoint(aPath, aTransform, element.x, element.y);
00179 break;
00180
00181 case kCGPathElementAddCurveToPoint: CGPathAddCurveToPoint(aPath, aTransform,
00182 element.cp1x, element.cp1y,
00183 element.cp2x, element.cp2y,
00184 element.x, element.y);
00185 break;
00186
00187 case kCGPathElementAddArc: CGPathAddArc(aPath, aTransform, element.x, element.y,
00188 element.radius, element.startAngle,
00189 element.endAngle, element.isClockwise);
00190 break;
00191
00192 case kCGPathElementAddQuadCurveToPoint: CGPathAddQuadCurveToPoint(aPath, aTransform,
00193 element.cpx, element.cpy,
00194 element.x, element.y);
00195 break;
00196
00197 case kCGPathElementMoveToPoint: CGPathMoveToPoint(aPath, aTransform, element.x, element.y);
00198 break;
00199
00200 case kCGPathElementCloseSubpath: CGPathCloseSubpath(aPath);
00201 break;
00202 }
00203 }
00204 }
00205
00206 function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
00207 {
00208 var cp = _CGPointMake(cpx, cpy),
00209 end = _CGPointMake(x, y);
00210
00211 if (aTransform)
00212 {
00213 cp = _CGPointApplyAffineTransform(cp, aTransform);
00214 end = _CGPointApplyAffineTransform(end, aTransform);
00215 }
00216
00217 aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y }
00218 aPath.current = end;
00219 }
00220
00221 function CGPathAddRect(aPath, aTransform, aRect)
00222 {
00223 CGPathAddRects(aPath, aTransform, [aRect], 1);
00224 }
00225
00226 function CGPathAddRects(aPath, aTransform, rects, count)
00227 {
00228 var i = 0;
00229
00230 if (arguments["count"] == NULL)
00231 var count = rects.length;
00232
00233 for (; i < count; ++i)
00234 {
00235 var rect = rects[i];
00236
00237 CGPathMoveToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMinY(rect));
00238 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMinY(rect));
00239 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
00240 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMaxY(rect));
00241
00242 CGPathCloseSubpath(aPath);
00243 }
00244 }
00245
00246 function CGPathMoveToPoint(aPath, aTransform, x, y)
00247 {
00248 var point = _CGPointMake(x, y),
00249 count = aPath.count;
00250
00251 if (aTransform != NULL)
00252 point = _CGPointApplyAffineTransform(point, aTransform);
00253
00254 aPath.start = point;
00255 aPath.current = point;
00256
00257 var previous = aPath.elements[count - 1];
00258
00259 if (count != 0 && previous.type == kCGPathElementMoveToPoint)
00260 {
00261 previous.x = point.x;
00262 previous.y = point.y;
00263 }
00264 else
00265 aPath.elements[aPath.count++] = { type:kCGPathElementMoveToPoint, x:point.x, y:point.y };
00266 }
00267
00268 var KAPPA = 4.0 * ((SQRT2 - 1.0) / 3.0);
00269
00270 function CGPathWithEllipseInRect(aRect)
00271 {
00272 var path = CGPathCreateMutable();
00273
00274 if (_CGRectGetWidth(aRect) == _CGRectGetHeight(aRect))
00275 CGPathAddArc(path, nil, _CGRectGetMidX(aRect), _CGRectGetMidY(aRect), _CGRectGetWidth(aRect) / 2.0, 0.0, 2 * PI, YES);
00276 else
00277 {
00278 var axis = _CGSizeMake(_CGRectGetWidth(aRect) / 2.0, _CGRectGetHeight(aRect) / 2.0),
00279 center = _CGPointMake(_CGRectGetMinX(aRect) + axis.width, _CGRectGetMinY(aRect) + axis.height);
00280
00281 CGPathMoveToPoint(path, nil, center.x, center.y - axis.height);
00282
00283 CGPathAddCurveToPoint(path, nil, center.x + (KAPPA * axis.width), center.y - axis.height, center.x + axis.width, center.y - (KAPPA * axis.height), center.x + axis.width, center.y);
00284 CGPathAddCurveToPoint(path, nil, center.x + axis.width, center.y + (KAPPA * axis.height), center.x + (KAPPA * axis.width), center.y + axis.height, center.x, center.y + axis.height);
00285 CGPathAddCurveToPoint(path, nil, center.x - (KAPPA * axis.width), center.y + axis.height, center.x - axis.width, center.y + (KAPPA * axis.height), center.x - axis.width, center.y);
00286 CGPathAddCurveToPoint(path, nil, center.x - axis.width, center.y - (KAPPA * axis.height), center.x - (KAPPA * axis.width), center.y - axis.height, center.x, center.y - axis.height);
00287 }
00288
00289 CGPathCloseSubpath(path);
00290
00291 return path;
00292 }
00293
00294 function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius, ne, se, sw, nw)
00295 {
00296 var path = CGPathCreateMutable(),
00297 xMin = _CGRectGetMinX(aRect),
00298 xMax = _CGRectGetMaxX(aRect),
00299 yMin = _CGRectGetMinY(aRect),
00300 yMax = _CGRectGetMaxY(aRect);
00301
00302 CGPathMoveToPoint(path, nil, xMin + xRadius, yMin);
00303
00304 if (ne)
00305 {
00306 CGPathAddLineToPoint(path, nil, xMax - xRadius, yMin);
00307 CGPathAddCurveToPoint(path, nil, xMax - xRadius, yMin, xMax, yMin, xMax, yMin + xRadius);
00308 }
00309 else
00310 CGPathAddLineToPoint(path, nil, xMax, yMin);
00311
00312 if (se)
00313 {
00314 CGPathAddLineToPoint(path, nil, xMax, yMax - xRadius);
00315 CGPathAddCurveToPoint(path, nil, xMax, yMax - xRadius, xMax, yMax, xMax - xRadius, yMax);
00316 }
00317 else
00318 CGPathAddLineToPoint(path, nil, xMax, yMax);
00319
00320 if (sw)
00321 {
00322 CGPathAddLineToPoint(path, nil, xMin + xRadius, yMax);
00323 CGPathAddCurveToPoint(path, nil, xMin + xRadius, yMax, xMin, yMax, xMin, yMax - xRadius);
00324 }
00325 else
00326 CGPathAddLineToPoint(path, nil, xMin, yMax);
00327
00328 if (nw)
00329 {
00330 CGPathAddLineToPoint(path, nil, xMin, yMin + xRadius);
00331 CGPathAddCurveToPoint(path, nil, xMin, yMin + xRadius, xMin, yMin, xMin + xRadius, yMin);
00332 } else
00333 CGPathAddLineToPoint(path, nil, xMin, yMin);
00334
00335 CGPathCloseSubpath(path);
00336
00337 return path;
00338 }
00339
00340 function CGPathCloseSubpath(aPath)
00341 {
00342 var count = aPath.count;
00343
00344
00345 if (count == 0 || aPath.elements[count - 1].type == kCGPathElementCloseSubpath)
00346 return;
00347
00348 aPath.elements[aPath.count++] = { type:kCGPathElementCloseSubpath, points:[aPath.start] };
00349 }
00350
00351 function CGPathEqualToPath(aPath, anotherPath)
00352 {
00353 if (aPath == anotherPath)
00354 return YES;
00355
00356 if (aPath.count != anotherPath.count || !_CGPointEqualToPoint(aPath.start, anotherPath.start) || !_CGPointEqualToPoint(aPath.current, anotherPath.current))
00357 return NO;
00358
00359 var i = 0,
00360 count = aPath.count;
00361
00362 for (; i < count; ++i)
00363 {
00364 var element = aPath[i],
00365 anotherElement = anotherPath[i];
00366
00367 if (element.type != anotherElement.type)
00368 return NO;
00369
00370 if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) &&
00371 element.radius != anotherElement.radius)
00372 return NO;
00373
00374 var j = element.points.length;
00375
00376 while (j--)
00377 if (!_CGPointEqualToPoint(element.points[j], anotherElement.points[j]))
00378 return NO;
00379 }
00380
00381 return YES;
00382 }
00383
00384 function CGPathGetCurrentPoint(aPath)
00385 {
00386 return _CGPointCreateCopy(aPath.current);
00387 }
00388
00389 function CGPathIsEmpty(aPath)
00390 {
00391 return !aPath || aPath.count == 0;
00392 }
00393