Last active
August 29, 2015 14:10
-
-
Save fogleman/5b84fbea15de320f16fe to your computer and use it in GitHub Desktop.
NSBezierPath+Ops.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSBezierPath+Ops.m | |
// Grids | |
// | |
// Created by Michael Fogleman on 12/2/14. | |
// Copyright (c) 2014 Michael Fogleman. All rights reserved. | |
// | |
#import "NSBezierPath+Ops.h" | |
#import "SkPath.h" | |
#import "SkPathOps.h" | |
static void toSkia(SkPath &dst, NSBezierPath *src) { | |
dst.reset(); | |
NSInteger n = [src elementCount]; | |
for (NSInteger i = 0; i < n; i++) { | |
NSPoint points[3]; | |
switch ([src elementAtIndex:i associatedPoints:points]) { | |
case NSMoveToBezierPathElement: | |
if (i == n - 1) { | |
// sometimes NSBezierPath has an extraneous MoveTo command | |
// at the end, and this doesn't work well with Skia | |
break; | |
} | |
dst.moveTo(points[0].x, points[0].y); | |
break; | |
case NSLineToBezierPathElement: | |
dst.lineTo(points[0].x, points[0].y); | |
break; | |
case NSCurveToBezierPathElement: | |
dst.cubicTo(points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); | |
break; | |
case NSClosePathBezierPathElement: | |
dst.close(); | |
break; | |
} | |
} | |
} | |
static void fromSkia(NSBezierPath *dst, SkPath &src) { | |
[dst setWindingRule:NSEvenOddWindingRule]; | |
SkPath::Iter iter(src, false); | |
BOOL done = NO; | |
while (!done) { | |
SkPoint points[4]; | |
SkPath::Verb verb = iter.next(points); | |
NSPoint p0, p1, p2, p3, pa, pb; | |
switch (verb) { | |
case SkPath::kMove_Verb: | |
p0 = NSMakePoint(points[0].x(), points[0].y()); | |
[dst moveToPoint:p0]; | |
break; | |
case SkPath::kLine_Verb: | |
p1 = NSMakePoint(points[1].x(), points[1].y()); | |
[dst lineToPoint:p1]; | |
break; | |
case SkPath::kCubic_Verb: | |
p1 = NSMakePoint(points[1].x(), points[1].y()); | |
p2 = NSMakePoint(points[2].x(), points[2].y()); | |
p3 = NSMakePoint(points[3].x(), points[3].y()); | |
[dst curveToPoint:p3 controlPoint1:p1 controlPoint2:p2]; | |
break; | |
case SkPath::kClose_Verb: | |
[dst closePath]; | |
break; | |
case SkPath::kDone_Verb: | |
done = YES; | |
break; | |
case SkPath::kQuad_Verb: | |
p0 = NSMakePoint(points[0].x(), points[0].y()); | |
p1 = NSMakePoint(points[1].x(), points[1].y()); | |
p2 = NSMakePoint(points[2].x(), points[2].y()); | |
pa = NSMakePoint(p0.x + 2.0 / 3.0 * (p1.x - p0.x), p0.y + 2.0 / 3.0 * (p1.y - p0.y)); | |
pb = NSMakePoint(p2.x + 2.0 / 3.0 * (p1.x - p2.x), p2.y + 2.0 / 3.0 * (p1.y - p2.y)); | |
[dst curveToPoint:p2 controlPoint1:pa controlPoint2:pb]; | |
break; | |
case SkPath::kConic_Verb: | |
break; | |
} | |
} | |
} | |
@implementation NSBezierPath (Ops) | |
+ (NSBezierPath *)bezierPathWithIntersectionOfPaths:(NSArray *)paths { | |
if (paths.count == 0) { | |
return [NSBezierPath bezierPath]; | |
} | |
if (paths.count == 1) { | |
return [paths objectAtIndex:0]; | |
} | |
SkPath path; | |
toSkia(path, [paths objectAtIndex:0]); | |
for (int i = 1; i < paths.count; i++) { | |
SkPath other; | |
toSkia(other, [paths objectAtIndex:i]); | |
Op(path, other, kIntersect_PathOp, &path); | |
} | |
NSBezierPath *result = [NSBezierPath bezierPath]; | |
fromSkia(result, path); | |
return result; | |
} | |
+ (NSBezierPath *)bezierPathWithUnionOfPaths:(NSArray *)paths { | |
if (paths.count == 0) { | |
return [NSBezierPath bezierPath]; | |
} | |
if (paths.count == 1) { | |
return [paths objectAtIndex:0]; | |
} | |
SkPath path; | |
toSkia(path, [paths objectAtIndex:0]); | |
for (int i = 1; i < paths.count; i++) { | |
SkPath other; | |
toSkia(other, [paths objectAtIndex:i]); | |
Op(path, other, kUnion_PathOp, &path); | |
} | |
NSBezierPath *result = [NSBezierPath bezierPath]; | |
fromSkia(result, path); | |
return result; | |
} | |
- (NSBezierPath *)intersectionWithPath:(NSBezierPath *)path { | |
SkPath a; | |
SkPath b; | |
toSkia(a, self); | |
toSkia(b, path); | |
Op(a, b, kIntersect_PathOp, &a); | |
NSBezierPath *result = [NSBezierPath bezierPath]; | |
fromSkia(result, a); | |
return result; | |
} | |
- (NSBezierPath *)differenceWithPath:(NSBezierPath *)path { | |
SkPath a; | |
SkPath b; | |
toSkia(a, self); | |
toSkia(b, path); | |
Op(a, b, kDifference_PathOp, &a); | |
NSBezierPath *result = [NSBezierPath bezierPath]; | |
fromSkia(result, a); | |
return result; | |
} | |
- (NSBezierPath *)unionWithPath:(NSBezierPath *)path { | |
SkPath a; | |
SkPath b; | |
toSkia(a, self); | |
toSkia(b, path); | |
Op(a, b, kUnion_PathOp, &a); | |
NSBezierPath *result = [NSBezierPath bezierPath]; | |
fromSkia(result, a); | |
return result; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment