![]() |
API 0.9.5
|
00001 /* 00002 * CGPath.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00025 kCGPathElementMoveToPoint = 0; 00026 kCGPathElementAddLineToPoint = 1; 00027 kCGPathElementAddQuadCurveToPoint = 2; 00028 kCGPathElementAddCurveToPoint = 3; 00029 kCGPathElementCloseSubpath = 4; 00030 00031 kCGPathElementAddArc = 5; 00032 kCGPathElementAddArcToPoint = 6; 00033 00042 function CGPathCreateMutable() 00043 { 00044 return { count:0, start:NULL, current:NULL, elements:[] }; 00045 } 00046 00051 function CGPathCreateMutableCopy(aPath) 00052 { 00053 var path = CGPathCreateMutable(); 00054 00055 CGPathAddPath(path, aPath); 00056 00057 return path; 00058 } 00059 00064 function CGPathCreateCopy(aPath) 00065 { 00066 return CGPathCreateMutableCopy(aPath); 00067 } 00068 00069 function CGPathRelease(aPath) 00070 { 00071 } 00072 00073 function CGPathRetain(aPath) 00074 { 00075 return aPath; 00076 } 00077 00078 function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle, isClockwise) 00079 { 00080 if (aTransform && !_CGAffineTransformIsIdentity(aTransform)) 00081 { 00082 var center = _CGPointMake(x, y), 00083 end = _CGPointMake(COS(anEndAngle), SIN(anEndAngle)), 00084 start = _CGPointMake(COS(aStartAngle), SIN(aStartAngle)); 00085 00086 end = _CGPointApplyAffineTransform(end, aTransform); 00087 start = _CGPointApplyAffineTransform(start, aTransform); 00088 center = _CGPointApplyAffineTransform(center, aTransform); 00089 00090 x = center.x; 00091 y = center.y; 00092 00093 var oldEndAngle = anEndAngle, 00094 oldStartAngle = aStartAngle; 00095 00096 anEndAngle = ATAN2(end.y - aTransform.ty, end.x - aTransform.tx); 00097 aStartAngle = ATAN2(start.y - aTransform.ty, start.x - aTransform.tx); 00098 00099 // Angles that equal "modulo" 2 pi return as equal after transforming them, 00100 // so we have to make sure to make them different again if they were different 00101 // to start out with. It's the difference between no circle and a full circle. 00102 if (anEndAngle == aStartAngle && oldEndAngle != oldStartAngle) 00103 if (oldStartAngle > oldEndAngle) 00104 anEndAngle = anEndAngle - PI2; 00105 else 00106 aStartAngle = aStartAngle - PI2; 00107 00108 aRadius = _CGSizeMake(aRadius, 0); 00109 aRadius = _CGSizeApplyAffineTransform(aRadius, aTransform); 00110 aRadius = SQRT(aRadius.width * aRadius.width + aRadius.height * aRadius.height); 00111 } 00112 00113 aPath.current = _CGPointMake(x + aRadius * COS(anEndAngle), y + aRadius * SIN(anEndAngle)); 00114 aPath.elements[aPath.count++] = { type:kCGPathElementAddArc, x:x, y:y, radius:aRadius, startAngle:aStartAngle, endAngle:anEndAngle }; 00115 } 00116 00117 function CGPathAddArcToPoint(aPath, aTransform, x1, y1, x2, y2, aRadius) 00118 { 00119 } 00120 00121 function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y) 00122 { 00123 var cp1 = _CGPointMake(cp1x, cp1y), 00124 cp2 = _CGPointMake(cp2x, cp2y), 00125 end = _CGPointMake(x, y); 00126 00127 if (aTransform) 00128 { 00129 cp1 = _CGPointApplyAffineTransform(cp1, aTransform); 00130 cp2 = _CGPointApplyAffineTransform(cp2, aTransform); 00131 end = _CGPointApplyAffineTransform(end, aTransform); 00132 } 00133 00134 aPath.current = end; 00135 aPath.elements[aPath.count++] = { type:kCGPathElementAddCurveToPoint, cp1x:cp1.x, cp1y:cp1.y, cp2x:cp2.x, cp2y:cp2.y, x:end.x, y:end.y }; 00136 } 00137 00138 function CGPathAddLines(aPath, aTransform, points, count) 00139 { 00140 var i = 1; 00141 00142 if (count === NULL) 00143 var count = points.length; 00144 00145 if (!aPath || count < 2) 00146 return; 00147 00148 CGPathMoveToPoint(aPath, aTransform, points[0].x, points[0].y); 00149 00150 for (; i < count; ++i) 00151 CGPathAddLineToPoint(aPath, aTransform, points[i].x, points[i].y); 00152 } 00153 00154 function CGPathAddLineToPoint(aPath, aTransform, x, y) 00155 { 00156 var point = _CGPointMake(x, y); 00157 00158 if (aTransform != NULL) 00159 point = _CGPointApplyAffineTransform(point, aTransform); 00160 00161 aPath.elements[aPath.count++] = { type: kCGPathElementAddLineToPoint, x:point.x, y:point.y }; 00162 aPath.current = point; 00163 } 00164 00165 function CGPathAddPath(aPath, aTransform, anotherPath) 00166 { 00167 for (var i = 0, count = anotherPath.count; i < count; ++i) 00168 { 00169 var element = anotherPath.elements[i]; 00170 00171 switch (element.type) 00172 { 00173 case kCGPathElementAddLineToPoint: CGPathAddLineToPoint(aPath, aTransform, element.x, element.y); 00174 break; 00175 00176 case kCGPathElementAddCurveToPoint: CGPathAddCurveToPoint(aPath, aTransform, 00177 element.cp1x, element.cp1y, 00178 element.cp2x, element.cp2y, 00179 element.x, element.y); 00180 break; 00181 00182 case kCGPathElementAddArc: CGPathAddArc(aPath, aTransform, element.x, element.y, 00183 element.radius, element.startAngle, 00184 element.endAngle, element.isClockwise); 00185 break; 00186 00187 case kCGPathElementAddQuadCurveToPoint: CGPathAddQuadCurveToPoint(aPath, aTransform, 00188 element.cpx, element.cpy, 00189 element.x, element.y); 00190 break; 00191 00192 case kCGPathElementMoveToPoint: CGPathMoveToPoint(aPath, aTransform, element.x, element.y); 00193 break; 00194 00195 case kCGPathElementCloseSubpath: CGPathCloseSubpath(aPath); 00196 break; 00197 } 00198 } 00199 } 00200 00201 function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y) 00202 { 00203 var cp = _CGPointMake(cpx, cpy), 00204 end = _CGPointMake(x, y); 00205 00206 if (aTransform) 00207 { 00208 cp = _CGPointApplyAffineTransform(cp, aTransform); 00209 end = _CGPointApplyAffineTransform(end, aTransform); 00210 } 00211 00212 aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y } 00213 aPath.current = end; 00214 } 00215 00216 function CGPathAddRect(aPath, aTransform, aRect) 00217 { 00218 CGPathAddRects(aPath, aTransform, [aRect], 1); 00219 } 00220 00221 function CGPathAddRects(aPath, aTransform, rects, count) 00222 { 00223 var i = 0; 00224 00225 if (count === NULL) 00226 var count = rects.length; 00227 00228 for (; i < count; ++i) 00229 { 00230 var rect = rects[i]; 00231 00232 CGPathMoveToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMinY(rect)); 00233 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMinY(rect)); 00234 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMaxY(rect)); 00235 CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMaxY(rect)); 00236 00237 CGPathCloseSubpath(aPath); 00238 } 00239 } 00240 00241 function CGPathMoveToPoint(aPath, aTransform, x, y) 00242 { 00243 var point = _CGPointMake(x, y), 00244 count = aPath.count; 00245 00246 if (aTransform != NULL) 00247 point = _CGPointApplyAffineTransform(point, aTransform); 00248 00249 aPath.start = point; 00250 aPath.current = point; 00251 00252 var previous = aPath.elements[count - 1]; 00253 00254 if (count != 0 && previous.type == kCGPathElementMoveToPoint) 00255 { 00256 previous.x = point.x; 00257 previous.y = point.y; 00258 } 00259 else 00260 aPath.elements[aPath.count++] = { type:kCGPathElementMoveToPoint, x:point.x, y:point.y }; 00261 } 00262 00263 var KAPPA = 4.0 * ((SQRT2 - 1.0) / 3.0); 00264 00265 function CGPathWithEllipseInRect(aRect) 00266 { 00267 var path = CGPathCreateMutable(); 00268 00269 if (_CGRectGetWidth(aRect) == _CGRectGetHeight(aRect)) 00270 CGPathAddArc(path, nil, _CGRectGetMidX(aRect), _CGRectGetMidY(aRect), _CGRectGetWidth(aRect) / 2.0, 0.0, 2 * PI, YES); 00271 else 00272 { 00273 var axis = _CGSizeMake(_CGRectGetWidth(aRect) / 2.0, _CGRectGetHeight(aRect) / 2.0), 00274 center = _CGPointMake(_CGRectGetMinX(aRect) + axis.width, _CGRectGetMinY(aRect) + axis.height); 00275 00276 CGPathMoveToPoint(path, nil, center.x, center.y - axis.height); 00277 00278 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); 00279 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); 00280 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); 00281 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); 00282 } 00283 00284 CGPathCloseSubpath(path); 00285 00286 return path; 00287 } 00288 00289 function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius/*not currently supported*/, ne, se, sw, nw) 00290 { 00291 var path = CGPathCreateMutable(), 00292 xMin = _CGRectGetMinX(aRect), 00293 xMax = _CGRectGetMaxX(aRect), 00294 yMin = _CGRectGetMinY(aRect), 00295 yMax = _CGRectGetMaxY(aRect); 00296 00297 CGPathMoveToPoint(path, nil, xMin + xRadius, yMin); 00298 00299 if (ne) 00300 { 00301 CGPathAddLineToPoint(path, nil, xMax - xRadius, yMin); 00302 CGPathAddCurveToPoint(path, nil, xMax - xRadius, yMin, xMax, yMin, xMax, yMin + xRadius); 00303 } 00304 else 00305 CGPathAddLineToPoint(path, nil, xMax, yMin); 00306 00307 if (se) 00308 { 00309 CGPathAddLineToPoint(path, nil, xMax, yMax - xRadius); 00310 CGPathAddCurveToPoint(path, nil, xMax, yMax - xRadius, xMax, yMax, xMax - xRadius, yMax); 00311 } 00312 else 00313 CGPathAddLineToPoint(path, nil, xMax, yMax); 00314 00315 if (sw) 00316 { 00317 CGPathAddLineToPoint(path, nil, xMin + xRadius, yMax); 00318 CGPathAddCurveToPoint(path, nil, xMin + xRadius, yMax, xMin, yMax, xMin, yMax - xRadius); 00319 } 00320 else 00321 CGPathAddLineToPoint(path, nil, xMin, yMax); 00322 00323 if (nw) 00324 { 00325 CGPathAddLineToPoint(path, nil, xMin, yMin + xRadius); 00326 CGPathAddCurveToPoint(path, nil, xMin, yMin + xRadius, xMin, yMin, xMin + xRadius, yMin); 00327 } 00328 else 00329 CGPathAddLineToPoint(path, nil, xMin, yMin); 00330 00331 CGPathCloseSubpath(path); 00332 00333 return path; 00334 } 00335 00336 function CGPathCloseSubpath(aPath) 00337 { 00338 var count = aPath.count; 00339 00340 // Don't bother closing this subpath if there aren't any current elements, or the last element already closed the subpath. 00341 if (count == 0 || aPath.elements[count - 1].type == kCGPathElementCloseSubpath) 00342 return; 00343 00344 aPath.elements[aPath.count++] = { type:kCGPathElementCloseSubpath, points:[aPath.start] }; 00345 } 00346 00347 function CGPathEqualToPath(aPath, anotherPath) 00348 { 00349 if (aPath == anotherPath) 00350 return YES; 00351 00352 if (aPath.count != anotherPath.count || !_CGPointEqualToPoint(aPath.start, anotherPath.start) || !_CGPointEqualToPoint(aPath.current, anotherPath.current)) 00353 return NO; 00354 00355 var i = 0, 00356 count = aPath.count; 00357 00358 for (; i < count; ++i) 00359 { 00360 var element = aPath[i], 00361 anotherElement = anotherPath[i]; 00362 00363 if (element.type != anotherElement.type) 00364 return NO; 00365 00366 if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) && 00367 element.radius != anotherElement.radius) 00368 return NO; 00369 00370 var j = element.points.length; 00371 00372 while (j--) 00373 if (!_CGPointEqualToPoint(element.points[j], anotherElement.points[j])) 00374 return NO; 00375 } 00376 00377 return YES; 00378 } 00379 00380 function CGPathGetCurrentPoint(aPath) 00381 { 00382 return _CGPointCreateCopy(aPath.current); 00383 } 00384 00385 function CGPathIsEmpty(aPath) 00386 { 00387 return !aPath || aPath.count == 0; 00388 } 00389