- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我应该如何将 CoreGraphics CGAffineTransform 解释为人类可读、有意义的格式?
我正在寻找类似的东西:
NSLog(@"naturalSize %@, appliedSize %@, transformationMatrix %@",
NSStringFromCGSize(clipVideoTrack.naturalSize),
NSStringFromCGSize(CGSizeApplyAffineTransform(clipVideoTrack.naturalSize, clipVideoTrack.preferredTransform)),
NSStringFromCGAffineTransform(clipVideoTrack.preferredTransform));
naturalSize {1920, 1080}, appliedSize {-1080, 1920}, transformationMatrix [0, 1, -1, 0, 1080, 0]
上述矩阵变换的最终结果是取这个 Landscape Right Video并转变为这个Portrait Up Video
我很高兴能够将其分解为步骤,以人类可读的形式,以便人们可以查看和理解转换的实际作用。
类似于(不确定我的步骤是否正确):
0. Will use upper left corner for video export of width 1080, height 1920.
1. Will move the video -1080(left) on the x axis
2. Will move the video 1920(down) on the y axis
3. Will rotate 90deg clockwise from bottom right corner
如果能指出执行此操作的代码、实现或解释,我将不胜感激。我试图学习和理解 AVFoundation 上下文中的转换矩阵究竟是如何运作的。
最佳答案
事实证明,在大多数情况下,您可以对仿射变换进行适当的描述,因为它非常受限。对 3D 变换做同样的事情要更难:(
请注意,我仍然无法告诉您串联的不同变换矩阵,只能告诉您最终结果。我也忽略了剪切,因为没有提供用于创建此类转换的函数。
我编写了一个函数,可以很好地理解仿射变换的作用。
你会在很多地方看到我写的if (fabs(foo - bar) < FLT_EPSILON)
而不仅仅是 if (foo == bar)
.这是为了保护自己在比较中的浮点 (im) 精度。
另一个需要指出的值得注意的事情是我计算旋转角度的方式。对于纯旋转,我可以使用 asin(b)
,但如果变换也被缩放,那么结果将是不正确的。相反,我将 b 除以 a 并使用 arctan 来计算角度。
代码中有大量注释,因此您应该能够跟进,主要是通过阅读代码。
NSString *affineTransformDescription(CGAffineTransform transform)
{
// check if it's simply the identity matrix
if (CGAffineTransformIsIdentity(transform)) {
return @"Is the identity transform";
}
// the above does't catch things like a 720° rotation so also check it manually
if (fabs(transform.a - 1.0) < FLT_EPSILON &&
fabs(transform.b - 0.0) < FLT_EPSILON &&
fabs(transform.c - 0.0) < FLT_EPSILON &&
fabs(transform.d - 1.0) < FLT_EPSILON &&
fabs(transform.tx - 0.0) < FLT_EPSILON &&
fabs(transform.ty - 0.0) < FLT_EPSILON) {
return @"Is the identity transform";
}
// The affine transforms is built up like this:
// a b tx
// c d ty
// 0 0 1
// An array to hold all the different descirptions, charasteristics of the transform.
NSMutableArray *descriptions = [NSMutableArray array];
// Checking for a translation
if (fabs(transform.tx) > FLT_EPSILON) { // translation along X
[descriptions addObject:[NSString stringWithFormat:@"Will move %.2f along the X axis",
transform.tx]];
}
if (fabs(transform.ty) > FLT_EPSILON) { // translation along Y
[descriptions addObject:[NSString stringWithFormat:@"Will move %.2f along the Y axis",
transform.ty]];
}
// Checking for a rotation
CGFloat angle = atan2(transform.b, transform.a); // get the angle of the rotation. Note this assumes no shearing!
if (fabs(angle) < FLT_EPSILON || fabs(angle - M_PI) < FLT_EPSILON) {
// there is a change that there is a 180° rotation, in that case, A and D will and be negative.
BOOL bothAreNegative = transform.a < 0.0 && transform.d < 0.0;
if (bothAreNegative) {
angle = M_PI;
} else {
angle = 0.0; // this is not considered a rotation, but a negative scale along one axis.
}
}
// add the rotation description if there was an angle
if (fabs(angle) > FLT_EPSILON) {
[descriptions addObject:[NSString stringWithFormat:@"Will rotate %.1f° degrees",
angle*180.0/M_PI]];
}
// Checking for a scale (and account for the possible rotation as well)
CGFloat scaleX = transform.a/cos(angle);
CGFloat scaleY = transform.d/cos(angle);
if (fabs(scaleX - scaleY) < FLT_EPSILON && fabs(scaleX - 1.0) > FLT_EPSILON) {
// if both are the same then we can format things a little bit nicer
[descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along both X and Y",
scaleX]];
} else {
// otherwise we look at X and Y scale separately
if (fabs(scaleX - 1.0) > FLT_EPSILON) { // scale along X
[descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along the X axis",
scaleX]];
}
if (fabs(scaleY - 1.0) > FLT_EPSILON) { // scale along Y
[descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along the Y axis",
scaleY]];
}
}
// Return something else when there is nothing to say about the transform matrix
if (descriptions.count == 0) {
return @"Can't easilly be described.";
}
// join all the descriptions on their own line
return [descriptions componentsJoinedByString:@",\n"];
}
为了尝试,我测试了多种不同转换的输出。这是我用来测试它的代码:
// identity
CGAffineTransform t = CGAffineTransformIdentity;
NSLog(@"identity: \n%@", affineTransformDescription(t));
// translation
t = CGAffineTransformMakeTranslation(10, 0);
NSLog(@"translate(10, 0): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeTranslation(0, 20);
NSLog(@"translate(0, 20): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeTranslation(2, -3);
NSLog(@"translate(2, -3): \n%@", affineTransformDescription(t));
// scale
t = CGAffineTransformMakeScale(2, 2);
NSLog(@"scale(2, 2): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeScale(-1, 3);
NSLog(@"scale(-1, 3): \n%@", affineTransformDescription(t));
// rotation
t = CGAffineTransformMakeRotation(M_PI/3.0);
NSLog(@"rotate(60 deg): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeRotation(M_PI);
NSLog(@"rotate(180 deg): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeRotation(4.0*M_PI);
NSLog(@"rotate(720 deg): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeRotation(3.0*M_PI);
NSLog(@"rotate(540 deg): \n%@", affineTransformDescription(t));
// concatenated transforms
// rotate & translate
t = CGAffineTransformMakeRotation(M_PI/3.0);
t = CGAffineTransformTranslate(t, 10, 20);
NSLog(@"rotate(60 deg), translate(10, 20): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeTranslation(10, 20);
t = CGAffineTransformRotate(t, M_PI/3.0);
NSLog(@"translate(10, 20), rotate(60 deg): \n%@", affineTransformDescription(t));
// rotate & scale
t = CGAffineTransformMakeRotation(M_PI/3.0);
t = CGAffineTransformScale(t, 2, 2);
NSLog(@"rotate(60 deg), scale(2, 2): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeScale(2, 2);
t = CGAffineTransformRotate(t, M_PI/3.0);
NSLog(@"scale(2, 2), rotate(60 deg): \n%@", affineTransformDescription(t));
// translate & scale
t = CGAffineTransformMakeTranslation(10, 20);
t = CGAffineTransformScale(t, 2, 2);
NSLog(@"translate(10, 20), scale(2, 2): \n%@", affineTransformDescription(t));
t = CGAffineTransformMakeScale(2, 2);
t = CGAffineTransformTranslate(t, 10, 20);
NSLog(@"scale(2, 2), translate(10, 20): \n%@", affineTransformDescription(t));
以及该测试的输出:
identity:
Is the identity transform
translate(10, 0):
Will move 10.00 along the X axis
translate(0, 20):
Will move 20.00 along the Y axis
translate(2, -3):
Will move 2.00 along the X axis,
Will move -3.00 along the Y axis
scale(2, 2):
Will scale by 2.00 along both X and Y
scale(-1, 3):
Will scale by -1.00 along the X axis,
Will scale by 3.00 along the Y axis
rotate(60 deg):
Will rotate 60.0° degrees
rotate(180 deg):
Will rotate 180.0° degrees
rotate(720 deg):
Is the identity transform
rotate(540 deg):
Will rotate 180.0° degrees
rotate(60 deg), translate(10, 20):
Will move -12.32 along the X axis,
Will move 18.66 along the Y axis,
Will rotate 60.0° degrees
translate(10, 20), rotate(60 deg):
Will move 10.00 along the X axis,
Will move 20.00 along the Y axis,
Will rotate 60.0° degrees
rotate(60 deg), scale(2, 2):
Will rotate 60.0° degrees,
Will scale by 2.00 along both X and Y
scale(2, 2), rotate(60 deg):
Will rotate 60.0° degrees,
Will scale by 2.00 along both X and Y
translate(10, 20), scale(2, 2):
Will move 10.00 along the X axis,
Will move 20.00 along the Y axis,
Will scale by 2.00 along both X and Y
scale(2, 2), translate(10, 20):
Will move 20.00 along the X axis,
Will move 40.00 along the Y axis,
Will scale by 2.00 along both X and Y
关于ios - 用户可读格式的 CGAffineTransform 矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23265519/
如何将 CGAffineTransform 转换为 CGTransform3D? 我使用 UIImagePickerController 作为相机 Controller 。我在相机 View 的上部添
使用此命令时,我在标题中收到错误消息: CGPathContainsPoint(Hitbox.CGPath, self.transform, point, false) Hitbox 是一个 UIBe
我正在尝试使用 CGAffineTransformRotate 旋转基于触摸手势添加到父 View 上的自定义 View (VIEWA)。一切正常。现在,我在父 View 上添加了另一个 View (
我正在尝试在 Swift 中创建 CGPath。我正在使用 CGPathCreateWithRect(rect, transformPointer) . 我怎样才能得到 UnsafePointer来自
什么时候使用 CABasicAnimation 和 CAKeyFrameAnimation 和 CGAffineTransform? 最佳答案 CABasicAnimation :为图层属性提供基本的
我有这个功能可以将 UIButtons 旋转 45 度。但是一旦旋转,调用相同的方法不会再旋转,并且按钮在第一次旋转后卡在其旋转位置。有任何想法吗? - (void)rotateImage:(UIBu
在我的代码中,我有一个表格,在我的表格中,我有一个 slider ,我将其转换为垂直的。 metricSlider.transform = CGAffineTransformRotate(metric
在我的实验中,我得出以下结论: YourView.transform = CGAffineTransformMakeRotation( positive value ); 将顺时针旋转 View ,并
我尝试为 UILabel 设置动画: let label: UILabel = UILabel() var transform = CGAffineTransform.identity UIView.
问题: 当使用 CGAffineTransform 时,我失去了 UIView 及其所有 subview 的质量。 代码 我当前正在运行以下代码来缩放和移动我的 UIView。 func an
我有一个 ImageView ,我正在通过 UISliders 缩放和旋转它。这是我这样做的方法: - (IBAction)sizeSlider:(UISlider *)sender { in
我正在开发一个允许用户旋转时钟指针的应用程序。为此,我正在使用 needle 的 imageview 的 transform 属性: CGAffineTransform newTrans = CGAf
我刚刚意识到一些很奇怪的事情。使用 Xcode 5 中的 Storyboard,我创建了一个非常简单的应用程序;只有一个 View 的 View Controller 。在此 View 上有 slid
我正在对 UILabel 应用翻译,这应该导致标签在其开始的相同 x 位置结束,但由于某种原因它似乎卡在左边。 [UIView animateWithDuration:1 delay:0 usingS
我有一个实例方法,我想返回 CGAffineTransform。我目前收到错误 Semantic Issue: Initializing 'CGAffineTransform' (aka 'struc
IU 在 Java 方面经验丰富,但对 Objective C 还是个新手,所以这可能非常愚蠢。尽管如此,我已经苦苦挣扎了一段时间,从以下代码中寻找我得到预期表达式错误的原因。 CGAffineTra
我可能误解了 CGAffineTransform 的工作原理,但它似乎给出了关于框架原点的奇怪结果。 例如: print(attribute.frame) attrib
我在某个角度添加了 UIView。现在在运行时我想将该 View 向上移动(比如 20 像素)。 开始 dragView = [[DragbleView alloc] initWithFrame:C
我正在尝试缩放 AVCaptureVideoPreviewLayer,以便它显示来自相机的“放大”预览;我可以使用 setAffineTransform:CGAffineTransformMakeSc
我正在尝试编写代码,当触发发生时,UIImageView 的实例会创建一个缓慢的“增长”效果,CGAffineTransform 会运行 20 秒。 当触发器在第一次转换完成之前再次发生时,就会出现此
我是一名优秀的程序员,十分优秀!