应用UIView变换后查找帧坐标(CGAffineTransform)

Vad*_*Vad 32 iphone objective-c uiview cgaffinetransform ios

我用我的视角旋转 CGAffineTransform

[view setTransform:newTransform];
Run Code Online (Sandbox Code Playgroud)

应用变换后帧值保持不变,但如何找到此帧的"旋转"或变换值?

http://www.informit.com/content/images/art_sadun_affine/elementLinks/sadun_fig02.png

我想要旋转帧边缘的精确坐标,即a,b,c,d点.

Bla*_*nny 46

要记住的一件事是变换会改变坐标系,因此您需要能够在父"视图"和子(变换)视图之间进行转换.此外,变换保留变换对象的中心,但不保留任何其他坐标.所以你需要根据中心来计算事物.你需要几个助手.(我从Erica Sadun的书"Core iOS Developer's Cookbook"中获得了以下大部分方法).

我通常在UIView上添加这些作为类别.

为了将孩子的坐标转换为父母的坐标,您需要以下内容:

// helper to get pre transform frame
-(CGRect)originalFrame {
   CGAffineTransform currentTransform = self.transform;
   self.transform = CGAffineTransformIdentity;
   CGRect originalFrame = self.frame;
   self.transform = currentTransform;

   return originalFrame;
}

// helper to get point offset from center
-(CGPoint)centerOffset:(CGPoint)thePoint {
    return CGPointMake(thePoint.x - self.center.x, thePoint.y - self.center.y);
}
// helper to get point back relative to center
-(CGPoint)pointRelativeToCenter:(CGPoint)thePoint {
  return CGPointMake(thePoint.x + self.center.x, thePoint.y + self.center.y);
}
// helper to get point relative to transformed coords
-(CGPoint)newPointInView:(CGPoint)thePoint {
    // get offset from center
    CGPoint offset = [self centerOffset:thePoint];
    // get transformed point
    CGPoint transformedPoint = CGPointApplyAffineTransform(offset, self.transform);
    // make relative to center
    return [self pointRelativeToCenter:transformedPoint];
}

// now get your corners
-(CGPoint)newTopLeft {
    CGRect frame = [self originalFrame];
    return [self newPointInView:frame.origin];
}
-(CGPoint)newTopRight {
    CGRect frame = [self originalFrame];
    CGPoint point = frame.origin;
    point.x += frame.size.width;
    return [self newPointInView:point];
}
-(CGPoint)newBottomLeft {
    CGRect frame = [self originalFrame];
    CGPoint point = frame.origin;
    point.y += frame.size.height;
    return [self newPointInView:point];
}
-(CGPoint)newBottomRight {
    CGRect frame = [self originalFrame];
    CGPoint point = frame.origin;
    point.x += frame.size.width;
    point.y += frame.size.height;
    return [self newPointInView:point];
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特4

extension UIView {
    /// Helper to get pre transform frame
    var originalFrame: CGRect {
        let currentTransform = transform
        transform = .identity
        let originalFrame = frame
        transform = currentTransform
        return originalFrame
    }

    /// Helper to get point offset from center
    func centerOffset(_ point: CGPoint) -> CGPoint {
        return CGPoint(x: point.x - center.x, y: point.y - center.y)
    }

    /// Helper to get point back relative to center
    func pointRelativeToCenter(_ point: CGPoint) -> CGPoint {
        return CGPoint(x: point.x + center.x, y: point.y + center.y)
    }

    /// Helper to get point relative to transformed coords
    func newPointInView(_ point: CGPoint) -> CGPoint {
        // get offset from center
        let offset = centerOffset(point)
        // get transformed point
        let transformedPoint = offset.applying(transform)
        // make relative to center
        return pointRelativeToCenter(transformedPoint)
    }

    var newTopLeft: CGPoint {
        return newPointInView(originalFrame.origin)
    }

    var newTopRight: CGPoint {
        var point = originalFrame.origin
        point.x += originalFrame.width
        return newPointInView(point)
    }

    var newBottomLeft: CGPoint {
        var point = originalFrame.origin
        point.y += originalFrame.height
        return newPointInView(point)
    }

    var newBottomRight: CGPoint {
        var point = originalFrame.origin
        point.x += originalFrame.width
        point.y += originalFrame.height
        return newPointInView(point)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是否意味着(例如)CGAffineTransformTranslate可平移对象的坐标系,而不是其坐标系中的对象? (2认同)

Lui*_*ien 17

您可以使用基本三角函数找出旋转视图的坐标.以下是如何做到这一点:

在此输入图像描述

  1. 第一步是了解视图的宽度和高度.将它们除以2,得到三角形的相邻和相对边(分别为青色和绿色).在上面的示例中,width = 300,height = 300.所以adjacentSide = 150,oppositeSice = 150.

  2. 找到斜边(红色).为此你使用公式:h^2 = a^2 + b^2.应用此公式后,我们发现斜边= 212.13

  3. 找到theta.这是相邻边(青色)和斜边(红色)之间的角度.为此你使用公式cos(theta) = (h^2 + a^2 - o^2)/2*h*o.应用该公式后,我们发现θ= 0.785(RADIANS).要将其转换为度数,我们应用公式degrees = radians * 180 / PI= 45(度).这是斜边的初始(偏移)角度.这一点非常重要.如果你的观点是旋转的观点是零的,那么它的偏差是45(DEGREES).我们很快就会需要theta.

  4. 现在我们知道了斜边(红色),我们需要rotationAngle.在这个例子中,我用a UIRotationGestureRecognizer来旋转方形视图.这个类有一个"旋转"属性,告诉我们视图旋转了多少.此值在RADIANS中.在上面的例子中,旋转是0.3597 RADIANS.要将其转换为度数,我们使用公式degrees = radians * PI / 180.应用公式后,我们发现旋转角度为20.61度.

  5. 我们终于可以找到偏移宽度(橙色)和高度(紫色).对于宽度,我们使用公式width = cos(rotationAngle - theta) * hypotenuse,对于高度,我们使用公式height = sen(rotationAngle - theta).我们必须从旋转角度(在RADIANS TOO中)减去THETA(在RADIANS!中),因为它是初始偏移量.以这种方式查看:当旋转角度为零时,斜边的角度为45(度).应用公式后,我们发现width = 193.20,height = -87.60

  6. 最后,我们可以将这些值(宽度和高度)添加到正方形的中心,以找到蓝点的坐标.

-例-

// Get the center point
CGPoint squareCenter = self.squareView.center;

// Get the blue point coordinates
CGPoint bluePointCoordinates = CGPointMake(squareCenter.x + width, squareCenter.y + height);
Run Code Online (Sandbox Code Playgroud)

蓝点坐标为(963.20,272.40)

要更好地了解公式,请参阅以下链接:

此外,如果你想玩我创建的测试项目(它是图像中的那个),请随时从以下链接下载它.

UPDATE

这是一个精简方法,它将计算您正在寻找的偏移右上角(蓝色).

/* Params:
/  viewCenter:      The center point (in superView coordinates) of your view
/  width:           The total width of your view
/  height:          The total height of your view
/  angleOfRotation: The rotation angle of your view. Can be either DEGREES or RADIANS
/  degrees:         A boolean flag indicating whether 'angleOfRotation' is degrees
/                   or radians. E.g.: If 'angleOfRotation' is expressed in degrees
/                   this parameter must be 'YES'
*/
-(CGPoint)calculateTopRightCoordinatesFromViewCenter:(CGPoint)viewCenter viewWidth:(CGFloat)viewWidth viewHeight:(CGFloat)viewHeight angleOfRotation:(CGFloat)angleOfRotation degrees:(BOOL)degrees {

    CGFloat adjacent = viewWidth/2.0;
    CGFloat opposite = viewHeight/2.0;
    CGFloat hipotenuse = sqrtf(powf(adjacent, 2.0) + pow(opposite, 2.0));
    CGFloat thetaRad = acosf((powf(hipotenuse, 2.0) + powf(adjacent, 2.0) - pow(opposite, 2.0)) / (2 * hipotenuse * adjacent));

    CGFloat angleRad = 0.0;
    if (degrees) {
        angleRad = angleOfRotation*M_PI/180.0;
    } else {
        angleRad = angleOfRotation;
    }

    CGFloat widthOffset = cosf(angleRad - thetaRad) * hipotenuse;
    CGFloat heightOffset = sinf(angleRad - thetaRad) * hipotenuse;

    CGPoint offsetPoint = CGPointMake(viewCenter.x + widthOffset, viewCenter.y + heightOffset);
    return offsetPoint;
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!


Leo*_*ica 5

你应该使用:

CGPoint CGPointApplyAffineTransform (
   CGPoint point,
   CGAffineTransform t
);
Run Code Online (Sandbox Code Playgroud)

要获得特定点,请使用视图的边界和中心,然后应用视图的变换以在变换后获得新点。这比添加专门用于旋转变换的代码要好,因为它可以支持任何变换以及链接。


Alb*_*haw 5

所有这些答案都是疯狂的,这就是这么简单......

CGPoint topLeft = [rotatedView convertPoint:CGPointMake(0, 0) toView:rotatedView.superview];

CGPoint topRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, 0) toView:rotatedView.superview];

CGPoint bottomLeft = [rotatedView convertPoint:CGPointMake(0, rotatedView.bounds.size.height) toView:rotatedView.superview];

CGPoint bottomRight = [rotatedView convertPoint:CGPointMake(rotatedView.bounds.size.width, rotatedView.bounds.size.height) toView:rotatedView.superview];
Run Code Online (Sandbox Code Playgroud)