Ios CALayer如何将点从和转换到其子层?

Ios CALayer如何将点从和转换到其子层?,ios,core-animation,transformation,Ios,Core Animation,Transformation,假设我们有一个2D空间(为了简化情况),层S和层C,其中C是S的子层。 转换过程必须影响边界、C的位置、C的变换、S的子层变换、C的锚点。我的猜测是下一个: CGAffineTransform transformToChild(CALayer *S, CALayer *C) { CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x; CGFloat tya = - C.bounds.or

假设我们有一个2D空间(为了简化情况),层S和层C,其中C是S的子层。 转换过程必须影响边界、C的位置、C的变换、S的子层变换、C的锚点。我的猜测是下一个:

CGAffineTransform transformToChild(CALayer *S, CALayer *C) {
    CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txb = C.position.x;
    CGFloat tyb = C.position.y;

    CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(S.sublayerTransform);
    CGAffineTransform fromS = CGAffineTransformTranslate(sublayerTransform, txb, tyb);
    fromS = CGAffineTransformConcat(fromS, C.affineTransform);
    fromS = CGAffineTransformTranslate(fromS, txa, tya);

    return fromS;
}
但当子层的变换不一致时(例如,旋转到M_PI_2角度时),这不起作用。 带层的完整代码:

CALayer *l1 = [CALayer new];
l1.frame = CGRectMake(-40, -40, 80, 80);
l1.bounds = CGRectMake(40, 40, 80, 80);
CALayer *l2 = [CALayer new];
l2.frame = CGRectMake(50, 40, 20, 20);
l2.bounds = CGRectMake(40, 40, 20, 20);
CGAffineTransform t2 = CGAffineTransformMakeRotation(M_PI / 2);
l2.affineTransform = t2;
[l1 addSublayer:l2];

CGAffineTransform toL2 = transformToChild(l1, l2);
CGPoint p = CGPointApplyAffineTransform(CGPointMake(70, 50), toL2);
NSLog(@"Custom Point %@", [NSValue valueWithCGPoint:p]);

p = [l1 convertPoint:CGPointMake(70, 50) toLayer:l2];
NSLog(@"CoreAnimation Point %@", [NSValue valueWithCGPoint:p]);
与系统结果的比较:

Custom Point NSPoint: {-50, 80}
CoreAnimation Point NSPoint: {50, 40}

所以,我找到了这种从子层坐标空间到子层坐标空间的点转换方法,它可以正确地与子层的非恒等变换一起工作。这里不涉及超级层的子层变换,但我认为扩展这些函数以支持它并不困难

CGPoint pointToChild(CALayer *C, CGPoint p) {

    CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txb = C.position.x;
    CGFloat tyb = C.position.y;

    p.x -= txb;
    p.y -= tyb;

    p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(C.affineTransform));

    if (C.isGeometryFlipped) {
        CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
        flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
        p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(flip));
    }

    p.x -= txa;
    p.y -= tya;

    return p;
}

CGPoint pointFromChild(CALayer *C, CGPoint p) {

    CGFloat txb = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
    CGFloat tyb = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;

    CGFloat txa = C.position.x;
    CGFloat tya = C.position.y;

    p.x += txb;
    p.y += tyb;

    if (C.isGeometryFlipped) {
        CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
        flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
        p = CGPointApplyAffineTransform(p, flip);   
    }

    p = CGPointApplyAffineTransform(p, C.affineTransform);

    p.x += txa;
    p.y += tya;

    return p;
}

这里有一个旧的邮件列表线程,其中包含一些关于此的详细信息:


这些消息非常旧,例如,它们不包括最近添加的geometryFlipped属性的效果,但这只会在合并矩阵中添加另一个术语。

回答了您的问题吗?谢谢,David。是的,根据那篇文章,我发现我必须精确地对子层的变换执行点变换,而不必对任何变换进行压缩。并将偏移应用于点坐标。我将很快添加一个更具体的解释作为答案。那么,view.layer.sublayerttransform和view.layer.transform呢?/*返回由“t”表示的仿射变换。如果“t”不能*由仿射变换精确表示,则返回值为*未定义。*/CATTransfer M3DGetAffinetTransfer这个问题是关于2D空间的。我认为UIView总是可以很好地处理层的仿射变换特性(如果您没有直接修改层的变换特性)。