Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/106.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 应用UIView变换后查找帧坐标(CGAffineTransform)_Iphone_Ios_Objective C_Uiview_Cgaffinetransform - Fatal编程技术网

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

Iphone 应用UIView变换后查找帧坐标(CGAffineTransform),iphone,ios,objective-c,uiview,cgaffinetransform,Iphone,Ios,Objective C,Uiview,Cgaffinetransform,我使用CGAffineTransform [view setTransform:newTransform]; 应用变换后,帧值保持不变,但如何查找此帧的“旋转”或变换值 (来源:) 我想要旋转帧边的精确坐标,即a、b、c、d点。您可以使用基本三角法找到旋转视图的坐标。以下是您如何做到这一点: 第一步是了解视图的宽度和高度。将它们除以2,得到三角形的相邻边和相对边(分别为青色和绿色)。在上面的示例中,宽度=300,高度=300。所以邻接边=150,对边=150 找到斜边(红色)。为此,您可以

我使用
CGAffineTransform

[view setTransform:newTransform];
应用变换后,帧值保持不变,但如何查找此帧的“旋转”或变换值


(来源:)


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

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

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

  • 找到斜边(红色)。为此,您可以使用以下公式:
    h^2=a^2+b^2
    。应用这个公式后,我们发现斜边=212.13

  • 找到西塔。这是相邻边(青色)和斜边(红色)之间的角度。为此,使用公式
    cos(θ)=(h^2+a^2-o^2)/2*h*o
    。应用此公式后,我们发现θ=0.785(弧度)。要将其转换为度,我们应用公式
    度=弧度*180/PI
    =45(度)。这是斜边的初始(偏移)角度。认识到这一点非常重要。如果视图的旋转为零,则斜边的偏移角为45度。我们很快就需要西塔了

  • 既然我们知道了斜边(红色),我们需要旋转角。在本例中,我使用了
    ui旋转手势识别器
    旋转方形视图。这个类有一个“旋转”属性,它告诉我们视图旋转了多少。该值以弧度为单位。在上面的示例中,旋转为0.3597弧度。要将其转换为度,我们使用公式
    度=弧度*PI/180
    。应用公式后,我们发现旋转角度为20.61度

  • 我们最终可以找到偏移宽度(橙色)和高度(紫色)。对于宽度,我们使用公式
    width=cos(旋转角度-θ)*斜边
    ,对于高度,我们使用公式
    height=sen(旋转角度-θ)
    。我们必须从旋转角度中减去θ(弧度!),因为θ是初始偏移量。这样看:当旋转角度为零时,斜边的角度为45度。应用这些公式后,我们发现宽度=193.20,高度=87.60

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

  • -范例-

    // Get the center point
    CGPoint squareCenter = self.squareView.center;
    
    // Get the blue point coordinates
    CGPoint bluePointCoordinates = CGPointMake(squareCenter.x + width, squareCenter.y + height);
    
    蓝点坐标为(963.20272.40)

    为了更好地理解这些公式,请参见以下链接:

    另外,如果你想玩我创建的测试项目(图片中的那个),请随时从下载

    更新

    下面是一个压缩方法,它将计算您要查找的偏移右上角点(蓝色)

    /* 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;
    }
    
    希望这有帮助

    您应该使用:

    CGPoint CGPointApplyAffineTransform (
       CGPoint point,
       CGAffineTransform t
    );
    

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

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

    我通常在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];
    }
    
    Swift 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)
        }
    }
    
    试试这个代码

    CGPoint localBeforeTransform = CGPointMake( view.bounds.size.width/2.0f, view.bounds.size.height/2.0f ); // lower left corner
    CGPoint localAfterTransform = CGPointApplyAffineTransform(localBeforeTransform, transform);
    CGPoint globalAfterTransform = CGPointMake(localAfterTransform.x + view.center.x, localAfterTransform.y + view.center.y);
    

    为什么这么乱?保持简单?在变换之前,x是q rads/度,就像锚周围的其他点一样

    本打算解释这一切,但这篇文章中的这一章在更短的上下文中解释了这一点:


    我写了这个课程可以帮助我们:

    TransformedViewFrameCalculator.h

    #import <Foundation/Foundation.h>
    
    @interface TransformedViewFrameCalculator : NSObject
    
    @property (nonatomic, strong) UIView *viewToProcess;
    
    - (void)calculateTransformedCornersWithTranslation:(CGPoint)translation
                                                 scale:(CGFloat)scale
                                              rotation:(CGFloat)rotation;
    
    @property (nonatomic, readonly) CGPoint transformedTopLeftCorner;
    @property (nonatomic, readonly) CGPoint transformedTopRightCorner;
    @property (nonatomic, readonly) CGPoint transformedBottomLeftCorner;
    @property (nonatomic, readonly) CGPoint transformedBottomRightCorner;
    
    @end
    
    例如,我使用它以以下方式限制容器视图内贴纸的移动/缩放/旋转:

    @property (nonatomic, strong) TransformedViewFrameCalculator *transformedFrameCalculator;
    


    所有这些答案都是愚蠢的,这太简单了

    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];
    

    我对其进行了总结,但并不十分有效:CGFloat-nexting=rte.frame.size.width/2.0;CGFloat反面=rte.frame.size.height/2.0;CGFloat-hipotenuse=sqrtf(功率(相邻,2.0)+功率(相反,2.0));CGFloat theta=acosf((功率因数(hipotenuse,2.0)+功率因数(相邻,2.0)-功率因数(相反,2.0))/(2*hipotenuse*相邻));θ=θ*180/M_π;CGFloat弧度=atan2f(rte.transform.b,rte.transform.a);CGFloat度=弧度*(180/M_-PI);CGFloat width=cosf(θ度)*hipotenuse;CGFloat高度=sinf(θ度)*HIPONEUTE;rightTopNode.center=CGPointMake(rte.center.x+宽度,rte.center.y+高度);嗨,瓦德。我的解释对了。代码中的错误是(这是因为我忘了解释这一部分),因为用于计算宽度和高度的cosf()和sinf()参数必须以弧度为单位。另外,请看我的最新答案。我添加了一个压缩方法,可以为您计算点的坐标。最后,我不知道你为什么要使用atan2f。您提到对视图使用旋转变换。旋转变换函数以弧度为单位进行旋转。您应该使用相同的角度来执行计算。希望这个帮助在某些时候我不能使用旋转变换,我想计算弧度usin
    @property (nonatomic, strong) TransformedViewFrameCalculator *transformedFrameCalculator;
    
    self.transformedFrameCalculator = [TransformedViewFrameCalculator new];
    self.transformedFrameCalculator.viewToProcess = someView;
    
    - (BOOL)transformedView:(UIView *)view
            withTranslation:(CGPoint)translation
                      scale:(double)scale
                   rotation:(double)rotation
    isFullyInsideValidFrame:(CGRect)validFrame {
    
        [self.transformedFrameCalculator calculateTransformedCornersWithTranslation:translation
                                                                              scale:scale
    
        BOOL topRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopRightCorner);
        BOOL topLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedTopLeftCorner);
        BOOL bottomRightIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomRightCorner);
        BOOL bottomLeftIsInsideValidFrame = CGRectContainsPoint(validFrame, self.transformedFrameCalculator.transformedBottomLeftCorner);
    
        return topRightIsInsideValidFrame && topLeftIsInsideValidFrame && bottomRightIsInsideValidFrame && bottomLeftIsInsideValidFrame;
    }
    
    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];