392 lines
18 KiB
Mathematica
392 lines
18 KiB
Mathematica
|
|
//
|
||
|
|
// SVGAVectorLayer.m
|
||
|
|
// SVGAPlayer
|
||
|
|
//
|
||
|
|
// Created by 崔明辉 on 2017/2/20.
|
||
|
|
// Copyright © 2017年 UED Center. All rights reserved.
|
||
|
|
//
|
||
|
|
|
||
|
|
#import "SVGAVectorLayer.h"
|
||
|
|
#import "SVGABezierPath.h"
|
||
|
|
#import "SVGAVideoSpriteFrameEntity.h"
|
||
|
|
#import "Svga.pbobjc.h"
|
||
|
|
|
||
|
|
@interface SVGAVectorLayer ()
|
||
|
|
|
||
|
|
@property (nonatomic, strong) NSArray<SVGAVideoSpriteFrameEntity *> *frames;
|
||
|
|
@property (nonatomic, assign) NSInteger drawedFrame;
|
||
|
|
@property (nonatomic, strong) NSDictionary *keepFrameCache;
|
||
|
|
|
||
|
|
@end
|
||
|
|
|
||
|
|
@implementation SVGAVectorLayer
|
||
|
|
|
||
|
|
- (instancetype)initWithFrames:(NSArray *)frames {
|
||
|
|
self = [super init];
|
||
|
|
if (self) {
|
||
|
|
self.backgroundColor = [UIColor clearColor].CGColor;
|
||
|
|
self.masksToBounds = NO;
|
||
|
|
_frames = frames;
|
||
|
|
_keepFrameCache = [NSMutableDictionary dictionary];
|
||
|
|
[self resetKeepFrameCache];
|
||
|
|
[self stepToFrame:0];
|
||
|
|
}
|
||
|
|
return self;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)resetKeepFrameCache {
|
||
|
|
__block NSInteger lastKeep = 0;
|
||
|
|
__block NSMutableDictionary *keepFrameCache = [NSMutableDictionary dictionary];
|
||
|
|
[self.frames enumerateObjectsUsingBlock:^(SVGAVideoSpriteFrameEntity * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
|
|
if (![self isKeepFrame:obj]) {
|
||
|
|
lastKeep = idx;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
[keepFrameCache setObject:@(lastKeep) forKey:@(idx)];
|
||
|
|
}
|
||
|
|
}];
|
||
|
|
self.keepFrameCache = [keepFrameCache copy];
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)stepToFrame:(NSInteger)frame {
|
||
|
|
if (frame < self.frames.count) {
|
||
|
|
[self drawFrame:frame];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (BOOL)isKeepFrame:(SVGAVideoSpriteFrameEntity *)frameItem {
|
||
|
|
if (frameItem.shapes.count == 0) {
|
||
|
|
return NO;
|
||
|
|
}
|
||
|
|
else if ([frameItem.shapes.firstObject isKindOfClass:[NSDictionary class]]) {
|
||
|
|
return [frameItem.shapes.firstObject[@"type"] isKindOfClass:[NSString class]] &&
|
||
|
|
[frameItem.shapes.firstObject[@"type"] isEqualToString:@"keep"];
|
||
|
|
}
|
||
|
|
else if ([frameItem.shapes.firstObject isKindOfClass:[SVGAProtoShapeEntity class]]) {
|
||
|
|
return [(SVGAProtoShapeEntity *)frameItem.shapes.firstObject type] == SVGAProtoShapeEntity_ShapeType_Keep;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return NO;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (NSInteger)requestKeepFrame:(NSInteger)frame {
|
||
|
|
if ([self.keepFrameCache objectForKey:@(frame)] != nil) {
|
||
|
|
return [[self.keepFrameCache objectForKey:@(frame)] integerValue];
|
||
|
|
}
|
||
|
|
return NSNotFound;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)drawFrame:(NSInteger)frame {
|
||
|
|
if (frame < self.frames.count) {
|
||
|
|
SVGAVideoSpriteFrameEntity *frameItem = self.frames[frame];
|
||
|
|
if ([self isKeepFrame:frameItem]) {
|
||
|
|
if (self.drawedFrame == [self requestKeepFrame:frame]) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
while(self.sublayers.count) [self.sublayers.firstObject removeFromSuperlayer];
|
||
|
|
for (NSDictionary *shape in frameItem.shapes) {
|
||
|
|
if ([shape isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"type"] isKindOfClass:[NSString class]]) {
|
||
|
|
if ([shape[@"type"] isEqualToString:@"shape"]) {
|
||
|
|
[self addSublayer:[self createCurveLayer:shape]];
|
||
|
|
}
|
||
|
|
else if ([shape[@"type"] isEqualToString:@"ellipse"]) {
|
||
|
|
[self addSublayer:[self createEllipseLayer:shape]];
|
||
|
|
}
|
||
|
|
else if ([shape[@"type"] isEqualToString:@"rect"]) {
|
||
|
|
[self addSublayer:[self createRectLayer:shape]];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if ([shape isKindOfClass:[SVGAProtoShapeEntity class]]) {
|
||
|
|
SVGAProtoShapeEntity *shapeItem = (id)shape;
|
||
|
|
if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Shape) {
|
||
|
|
[self addSublayer:[self createCurveLayerWithProto:shapeItem]];
|
||
|
|
}
|
||
|
|
else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Ellipse) {
|
||
|
|
[self addSublayer:[self createEllipseLayerWithProto:shapeItem]];
|
||
|
|
}
|
||
|
|
else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Rect) {
|
||
|
|
[self addSublayer:[self createRectLayerWithProto:shapeItem]];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
self.drawedFrame = frame;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createCurveLayer:(NSDictionary *)shape {
|
||
|
|
SVGABezierPath *bezierPath = [SVGABezierPath new];
|
||
|
|
if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"args"][@"d"] isKindOfClass:[NSString class]]) {
|
||
|
|
[bezierPath setValues:shape[@"args"][@"d"]];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CAShapeLayer *shapeLayer = [bezierPath createLayer];
|
||
|
|
[self resetStyles:shapeLayer shape:shape];
|
||
|
|
[self resetTransform:shapeLayer shape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createCurveLayerWithProto:(SVGAProtoShapeEntity *)shape {
|
||
|
|
SVGABezierPath *bezierPath = [SVGABezierPath new];
|
||
|
|
if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Shape) {
|
||
|
|
if ([shape.shape.d isKindOfClass:[NSString class]] && shape.shape.d.length > 0) {
|
||
|
|
[bezierPath setValues:shape.shape.d];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
CAShapeLayer *shapeLayer = [bezierPath createLayer];
|
||
|
|
[self resetStyles:shapeLayer protoShape:shape];
|
||
|
|
[self resetTransform:shapeLayer protoShape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createEllipseLayer:(NSDictionary *)shape {
|
||
|
|
UIBezierPath *bezierPath;
|
||
|
|
if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"radiusX"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"radiusY"] isKindOfClass:[NSNumber class]]) {
|
||
|
|
CGFloat x = [shape[@"args"][@"x"] floatValue];
|
||
|
|
CGFloat y = [shape[@"args"][@"y"] floatValue];
|
||
|
|
CGFloat rx = [shape[@"args"][@"radiusX"] floatValue];
|
||
|
|
CGFloat ry = [shape[@"args"][@"radiusY"] floatValue];
|
||
|
|
bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x - rx, y - ry, rx * 2, ry * 2)];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (bezierPath != nil) {
|
||
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||
|
|
[shapeLayer setPath:[bezierPath CGPath]];
|
||
|
|
[self resetStyles:shapeLayer shape:shape];
|
||
|
|
[self resetTransform:shapeLayer shape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return [CALayer layer];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createEllipseLayerWithProto:(SVGAProtoShapeEntity *)shape {
|
||
|
|
UIBezierPath *bezierPath;
|
||
|
|
if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Ellipse) {
|
||
|
|
bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(shape.ellipse.x - shape.ellipse.radiusX,
|
||
|
|
shape.ellipse.y - shape.ellipse.radiusY,
|
||
|
|
shape.ellipse.radiusX * 2,
|
||
|
|
shape.ellipse.radiusY * 2)];
|
||
|
|
}
|
||
|
|
if (bezierPath != nil) {
|
||
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||
|
|
[shapeLayer setPath:[bezierPath CGPath]];
|
||
|
|
[self resetStyles:shapeLayer protoShape:shape];
|
||
|
|
[self resetTransform:shapeLayer protoShape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return [CALayer layer];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createRectLayer:(NSDictionary *)shape {
|
||
|
|
UIBezierPath *bezierPath;
|
||
|
|
if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"width"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"height"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"args"][@"cornerRadius"] isKindOfClass:[NSNumber class]]) {
|
||
|
|
CGFloat x = [shape[@"args"][@"x"] floatValue];
|
||
|
|
CGFloat y = [shape[@"args"][@"y"] floatValue];
|
||
|
|
CGFloat width = [shape[@"args"][@"width"] floatValue];
|
||
|
|
CGFloat height = [shape[@"args"][@"height"] floatValue];
|
||
|
|
CGFloat cornerRadius = [shape[@"args"][@"cornerRadius"] floatValue];
|
||
|
|
bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, width, height) cornerRadius:cornerRadius];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (bezierPath != nil) {
|
||
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||
|
|
[shapeLayer setPath:[bezierPath CGPath]];
|
||
|
|
[self resetStyles:shapeLayer shape:shape];
|
||
|
|
[self resetTransform:shapeLayer shape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return [CALayer layer];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (CALayer *)createRectLayerWithProto:(SVGAProtoShapeEntity *)shape {
|
||
|
|
UIBezierPath *bezierPath;
|
||
|
|
if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Rect) {
|
||
|
|
bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(shape.rect.x, shape.rect.y, shape.rect.width, shape.rect.height)
|
||
|
|
cornerRadius:shape.rect.cornerRadius];
|
||
|
|
}
|
||
|
|
if (bezierPath != nil) {
|
||
|
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||
|
|
[shapeLayer setPath:[bezierPath CGPath]];
|
||
|
|
[self resetStyles:shapeLayer protoShape:shape];
|
||
|
|
[self resetTransform:shapeLayer protoShape:shape];
|
||
|
|
return shapeLayer;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return [CALayer layer];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)resetStyles:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
|
||
|
|
shapeLayer.masksToBounds = NO;
|
||
|
|
shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
|
||
|
|
if ([shape[@"styles"] isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"styles"][@"fill"] isKindOfClass:[NSArray class]]) {
|
||
|
|
NSArray *colorArray = shape[@"styles"][@"fill"];
|
||
|
|
if ([colorArray count] == 4 &&
|
||
|
|
[colorArray[0] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[1] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[2] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[3] isKindOfClass:[NSNumber class]]) {
|
||
|
|
shapeLayer.fillColor = [UIColor colorWithRed:[colorArray[0] floatValue]
|
||
|
|
green:[colorArray[1] floatValue]
|
||
|
|
blue:[colorArray[2] floatValue]
|
||
|
|
alpha:[colorArray[3] floatValue]].CGColor;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
shapeLayer.fillColor = [UIColor clearColor].CGColor;
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"stroke"] isKindOfClass:[NSArray class]]) {
|
||
|
|
NSArray *colorArray = shape[@"styles"][@"stroke"];
|
||
|
|
if ([colorArray count] == 4 &&
|
||
|
|
[colorArray[0] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[1] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[2] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[colorArray[3] isKindOfClass:[NSNumber class]]) {
|
||
|
|
shapeLayer.strokeColor = [UIColor colorWithRed:[colorArray[0] floatValue]
|
||
|
|
green:[colorArray[1] floatValue]
|
||
|
|
blue:[colorArray[2] floatValue]
|
||
|
|
alpha:[colorArray[3] floatValue]].CGColor;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"strokeWidth"] isKindOfClass:[NSNumber class]]) {
|
||
|
|
shapeLayer.lineWidth = [shape[@"styles"][@"strokeWidth"] floatValue];
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"lineCap"] isKindOfClass:[NSString class]]) {
|
||
|
|
shapeLayer.lineCap = shape[@"styles"][@"lineCap"];
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"lineJoin"] isKindOfClass:[NSString class]]) {
|
||
|
|
shapeLayer.lineJoin = shape[@"styles"][@"lineJoin"];
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"lineDash"] isKindOfClass:[NSArray class]]) {
|
||
|
|
BOOL accept = YES;
|
||
|
|
for (id obj in shape[@"styles"][@"lineDash"]) {
|
||
|
|
if (![obj isKindOfClass:[NSNumber class]]) {
|
||
|
|
accept = NO;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (accept) {
|
||
|
|
if ([shape[@"styles"][@"lineDash"] count] == 3) {
|
||
|
|
shapeLayer.lineDashPhase = [shape[@"styles"][@"lineDash"][2] floatValue];
|
||
|
|
shapeLayer.lineDashPattern = @[
|
||
|
|
([shape[@"styles"][@"lineDash"][0] floatValue] < 1.0 ? @(1.0) : shape[@"styles"][@"lineDash"][0]),
|
||
|
|
([shape[@"styles"][@"lineDash"][1] floatValue] < 0.1 ? @(0.1) : shape[@"styles"][@"lineDash"][1])
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if ([shape[@"styles"][@"miterLimit"] isKindOfClass:[NSNumber class]]) {
|
||
|
|
shapeLayer.miterLimit = [shape[@"styles"][@"miterLimit"] floatValue];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)resetStyles:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
|
||
|
|
shapeLayer.masksToBounds = NO;
|
||
|
|
shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
|
||
|
|
if (protoShape.hasStyles) {
|
||
|
|
if (protoShape.styles.hasFill) {
|
||
|
|
shapeLayer.fillColor = [UIColor colorWithRed:protoShape.styles.fill.r
|
||
|
|
green:protoShape.styles.fill.g
|
||
|
|
blue:protoShape.styles.fill.b
|
||
|
|
alpha:protoShape.styles.fill.a].CGColor;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
shapeLayer.fillColor = [UIColor clearColor].CGColor;
|
||
|
|
}
|
||
|
|
if (protoShape.styles.hasStroke) {
|
||
|
|
shapeLayer.strokeColor = [UIColor colorWithRed:protoShape.styles.stroke.r
|
||
|
|
green:protoShape.styles.stroke.g
|
||
|
|
blue:protoShape.styles.stroke.b
|
||
|
|
alpha:protoShape.styles.stroke.a].CGColor;
|
||
|
|
}
|
||
|
|
shapeLayer.lineWidth = protoShape.styles.strokeWidth;
|
||
|
|
switch (protoShape.styles.lineCap) {
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapButt:
|
||
|
|
shapeLayer.lineCap = @"butt";
|
||
|
|
break;
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapRound:
|
||
|
|
shapeLayer.lineCap = @"round";
|
||
|
|
break;
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapSquare:
|
||
|
|
shapeLayer.lineCap = @"square";
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
switch (protoShape.styles.lineJoin) {
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinRound:
|
||
|
|
shapeLayer.lineJoin = @"round";
|
||
|
|
break;
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinMiter:
|
||
|
|
shapeLayer.lineJoin = @"miter";
|
||
|
|
break;
|
||
|
|
case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinBevel:
|
||
|
|
shapeLayer.lineJoin = @"bevel";
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
shapeLayer.lineDashPhase = protoShape.styles.lineDashIii;
|
||
|
|
if (protoShape.styles.lineDashI > 0.0 || protoShape.styles.lineDashIi > 0.0) {
|
||
|
|
shapeLayer.lineDashPattern = @[
|
||
|
|
(protoShape.styles.lineDashI < 1.0 ? @(1.0) : @(protoShape.styles.lineDashI)),
|
||
|
|
(protoShape.styles.lineDashIi < 0.1 ? @(0.1) : @(protoShape.styles.lineDashIi))
|
||
|
|
];
|
||
|
|
}
|
||
|
|
shapeLayer.miterLimit = protoShape.styles.miterLimit;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)resetTransform:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
|
||
|
|
if ([shape[@"transform"] isKindOfClass:[NSDictionary class]]) {
|
||
|
|
if ([shape[@"transform"][@"a"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"transform"][@"b"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"transform"][@"c"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"transform"][@"d"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"transform"][@"tx"] isKindOfClass:[NSNumber class]] &&
|
||
|
|
[shape[@"transform"][@"ty"] isKindOfClass:[NSNumber class]]) {
|
||
|
|
shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake([shape[@"transform"][@"a"] floatValue],
|
||
|
|
[shape[@"transform"][@"b"] floatValue],
|
||
|
|
[shape[@"transform"][@"c"] floatValue],
|
||
|
|
[shape[@"transform"][@"d"] floatValue],
|
||
|
|
[shape[@"transform"][@"tx"] floatValue],
|
||
|
|
[shape[@"transform"][@"ty"] floatValue])
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
- (void)resetTransform:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
|
||
|
|
if (protoShape.hasTransform) {
|
||
|
|
shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake((CGFloat)protoShape.transform.a,
|
||
|
|
(CGFloat)protoShape.transform.b,
|
||
|
|
(CGFloat)protoShape.transform.c,
|
||
|
|
(CGFloat)protoShape.transform.d,
|
||
|
|
(CGFloat)protoShape.transform.tx,
|
||
|
|
(CGFloat)protoShape.transform.ty)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@end
|