Skip to content

Instantly share code, notes, and snippets.

@fogleman
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fogleman/5b84fbea15de320f16fe to your computer and use it in GitHub Desktop.
Save fogleman/5b84fbea15de320f16fe to your computer and use it in GitHub Desktop.
NSBezierPath+Ops.mm
//
// 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