Created
March 18, 2014 18:49
-
-
Save martinwinter/9626774 to your computer and use it in GitHub Desktop.
A thin object wrapper around CGPath, mainly for the purpose of serializing paths. (Not yet converted to ARC, sorry.)
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
// | |
// MWCGPath.h | |
// | |
// Created by Martin Winter on 14.01.11. | |
// Copyright 2011 Martin Winter. All rights reserved. | |
// | |
// Provides an NSObject wrapper around CGPathRef. | |
// | |
#if TARGET_OS_IPHONE | |
#import <UIKit/UIKit.h> | |
#import <CoreGraphics/CoreGraphics.h> | |
#else | |
#import <Cocoa/Cocoa.h> | |
#import <ApplicationServices/ApplicationServices.h> | |
#endif | |
@interface MWCGPath : NSObject | |
@property (nonatomic, retain) __attribute__((NSObject)) CGPathRef CGPath; | |
- (id)initWithCGPath:(CGPathRef)inCGPath; | |
@end |
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
// | |
// MWCGPath.m | |
// | |
// Created by Martin Winter on 14.01.11. | |
// Copyright 2011 Martin Winter. All rights reserved. | |
// | |
#import "MWCGPath.h" | |
void MWCGPathApplierFunction(void *info, const CGPathElement *element) | |
{ | |
NSMutableArray *array = (NSMutableArray *)info; | |
CGPathElementType type = element->type; | |
CGPoint *points = element->points; | |
// Determine number of points for element type. | |
NSUInteger pointCount = 0; | |
switch (type) | |
{ | |
case kCGPathElementMoveToPoint: | |
pointCount = 1; | |
break; | |
case kCGPathElementAddLineToPoint: | |
pointCount = 1; | |
break; | |
case kCGPathElementAddQuadCurveToPoint: | |
pointCount = 2; | |
break; | |
case kCGPathElementAddCurveToPoint: | |
pointCount = 3; | |
break; | |
case kCGPathElementCloseSubpath: | |
pointCount = 0; | |
break; | |
default: | |
[array replaceObjectAtIndex:0 withObject:[NSNumber numberWithBool:NO]]; // Set status flag ... | |
return; // ... and return. | |
} | |
// Serialize points. | |
NSData *pointsData = [NSData dataWithBytes:points | |
length:(pointCount * sizeof(CGPoint))]; | |
// Package type and points. | |
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: | |
[NSNumber numberWithInt:type], @"type", | |
pointsData, @"points", | |
nil]; | |
// Add dictionary to array. | |
[array addObject:dictionary]; | |
} | |
// Return value is autoreleased. | |
NSData *MWNSDataFromCGPath(CGPathRef path) | |
{ | |
if (path == NULL) return nil; | |
// Create array that will hold path elements. Initialize with status flag. | |
NSMutableArray *array = [NSMutableArray arrayWithObject:[NSNumber numberWithBool:YES]]; | |
// Examine path elements. | |
CGPathApply(path, array, MWCGPathApplierFunction); | |
// Serialize array. | |
return [NSKeyedArchiver archivedDataWithRootObject:array]; | |
} | |
// Caller is responsible for releasing return value. | |
CGPathRef MWCGPathCreateFromNSData(NSData *data) | |
{ | |
if (data == nil) return NULL; | |
// Unserialize array. | |
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data]; | |
// Recreate path. | |
CGMutablePathRef path = CGPathCreateMutable(); | |
for (NSUInteger elementIndex = 0; elementIndex < [array count]; elementIndex++) | |
{ | |
NSDictionary *dictionary = [array objectAtIndex:elementIndex]; | |
CGPathElementType type = [(NSNumber *)[dictionary objectForKey:@"type"] intValue]; | |
CGPoint *points = (CGPoint *)[(NSData *)[dictionary objectForKey:@"points"] bytes]; | |
switch (type) | |
{ | |
case kCGPathElementMoveToPoint: | |
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y); | |
break; | |
case kCGPathElementAddLineToPoint: | |
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y); | |
break; | |
case kCGPathElementAddQuadCurveToPoint: | |
CGPathAddQuadCurveToPoint(path, NULL, points[0].x, points[0].y, points[1].x, points[1].y); | |
break; | |
case kCGPathElementAddCurveToPoint: | |
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); | |
break; | |
case kCGPathElementCloseSubpath: | |
CGPathCloseSubpath(path); | |
break; | |
default: | |
CGPathRelease(path); | |
return NULL; | |
} | |
} | |
return path; | |
} | |
@implementation MWCGPath | |
@synthesize CGPath; | |
- (id)initWithCGPath:(CGPathRef)inCGPath | |
{ | |
self = [super init]; | |
if (self) | |
{ | |
if (inCGPath != NULL) | |
{ | |
CGPath = CGPathCreateCopy(inCGPath); | |
} | |
} | |
return self; | |
} | |
- (id)init | |
{ | |
return [self initWithCGPath:NULL]; | |
} | |
- (void)dealloc | |
{ | |
if (CGPath != NULL) CGPathRelease(CGPath); | |
[super dealloc]; | |
} | |
#pragma mark - NSCoding Protocol. | |
- (id)initWithCoder:(NSCoder *)decoder | |
{ | |
self = [super init]; | |
if (self) | |
{ | |
NSData *CGPathData = [decoder decodeObjectForKey:@"CGPathData"]; | |
CGPath = MWCGPathCreateFromNSData(CGPathData); // Retain count 1. | |
} | |
return self; | |
} | |
- (void)encodeWithCoder:(NSCoder *)encoder | |
{ | |
NSData *CGPathData = MWNSDataFromCGPath(CGPath); | |
[encoder encodeObject:CGPathData forKey:@"CGPathData"]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment