Suppose the current scale of my UIView is x. Suppose I apply a scale transformation to my UIView of the amount y ie:
view.transform = CGAffineTransformScale(view.transform, y, y);
. How do I determine what the value of the scale of the UIView after the scale transformation occurs (in terms of x and y?).
The scale transform multiplies the current scale with your scale y.
if the scale was 2.0 for retina, it is y* 2.0 afterwards.
So x*y is the answer. but dont forget x.achsis scale and y achsis can be different.
x, and y for scale is confusing, better use s1 and s2, or sx, sy if you have different scale on y and x achsis, in your code.
Scaling combines by multiplication, translation (movement) by addition, rotation is a matrix multiplication. All three can be combined into an AffineTransformation (a matrix with 1 more row than the dimensions of the space), these are combined by matrix multiplication. 2D AffineTransformations are 3x2 or 3x3 matrices, the extra column just makes them easier to work with.
Edit:
Using clearer names: if he current scale was currxs, currys and the scale applied was xs,ys the new scale would be currxs*xs, currys*ys. Note that applying a scale will also scale any translation component that is contained in the AffineTransformation, this is why order of application is important.
Its quite simple if you are just using the CGAffineTransformScale and not the other transformations like rotation, you can use the view frame and bounds size to calculate the resulting scale values.
float scaleX = view.frame.size.width/view.bounds.size.width;
float scaleY = view.frame.size.height/view.bounds.size.height;
Related
I have a grid of game objects in which I can change the number of game objects that fit inside the grid. The grid is a child of a game object. I wish to rescale all other grids to match my 4X4 grid size programmatically.
Desired size
Grid to rescale
Each game object is 1 unit and the parent transform scale is (1,1,1). I know that if my grid is 8X8 that I would probably need to rescale to 0.5. I only have an issue in trying to calculate the rescale number.
So again as said it is pretty simple maths.
You have a grid with side length 5, you want 4.
So you normalize it via
currentSize / 5.0f * 4.0f
which would be a factor of 0.8f.
Since you need to apply it to each side of your grid you share that so it has to be 0.8f * 0.8f which is a factor of 0.16f.
Or if you say it is 8x8 then the same calculations
currentSize / 8f * 4f
so a factor of 0.5. then squared so 0.25f.
#derHugo Answer was good. For me, I answered my answer was:
gridScaleratio = 1.0f / ((gridSize * gridSize) / (gridSize * 4.0f));
...
playerGrid.transform.localScale = new Vector3(gridScaleratio, gridScaleratio, gridScaleratio);
I am trying to determine a players depth position on a plane, which defines the walkable ground in a 2D brawler game. The problem is depictured in the following drawing:
C represents the players current position. I need to find the magnitude of vector V. Since I am not strong on linear algebra, the one thing I can think of is: determining the intersection point P of L1 and L2, and then take the magnitude from AP. However, I get the feeling there must be an easier way to find V, since I already know the angle the vector should have, given by vector from AB.
Any input would be appreciated, since I am looking forward to step up my linear algebra game.
Edit: As it is unclear thanks to my lack of drawing skills: the geometry depicted above is a parallelogram. The vector V I am looking for is parallel to the left and right side of the parallelogram. Depth does not mean, that I am looking for the vector perpendicular to the top side, but it refers to the fake depth of a purely 2D game. The parallelogram is therefore used as a means for creating the feeling of walking along a z axis.
The depth of your player (length of V) as measured from the top line in your drawing, is just the difference between A.y and C.y. This is seperate from the slant in the parralelogram, as we're just looking at depth.
example:
float v;
Vector2 a = new Vector2(100, 100); //The point you're measuring from
Vector2 c = new Vector2(150, 150); //Your character position
v = c.y - a.y; // This is the length of V.
//In numbers: 50 = 150 - 100
Illustrated: image not to scale
This works for any coördinate in your plane.
Now if you'd want to get the length of AC is when you'd need to apply some pythagoras, which is a² + b² = c². In the example that would mean in code:
Vector2 a = new Vector2(100, 100);
Vector2 c = new Vector2(150, 150);
float ac1 = Mathf.Sqrt(Mathf.Pow(c.x - a.x, 2) + Mathf.Pow(c.y - a.y, 2));
Now that is quite a sore to have to type out every time, and looks quite scary. But Unity has you covered! There is a Vector method called Distance
float ac2 = Vector2.Distance(a, c);
Which both return 70.71068 which is the length of AC.
This works because for any point c in your area you can draw a right angled triangle from a to c.
Edit as per comment:
If you want your "depth" vector to be parallel with the sides of the paralellogram we can just create a triangle in the parallelogram of which we calculate the hypotenuse.
Since we want the new hypotenuse of our triangle to be parallel to the parallelogram we can use the same angle θ as point B has in your drawing (indicated by pink in mine), of which I understood you know the value.
We also know the length of the adjacent (indicated in blue) side of this new triangle, as that is the height we calculated earlier (c.y - a.y).
Using these two values we can use cosine to find the length of hypotenuse (indicated in red) of the triangle, which is equal to the vector V, in parallel with the parallelogram.
the formula for that is: hypotenuse = adjacent/cos(θ)
Now if we were to put some numbers in this, and for my example I took 55 for the angle θ. It would look like this
float v = 50/(cos(55));
image not to scale
Let's call the lower right vertex of the parallelogram D.
If the long sides of the parallelogram are horizontal, you can find magnitude of V vector by:
V.magnitude = (c.y - a.y) / sin(BAD)
Or if you prefer:
V.magnitude = AB.magnitude * (c.y - a.y)/(b.y - a.y)
Having this coordinate system:
And this dominant vertical vanishing point:
I would like to rotate the image around x axis so the vanishing point is at infinity. That means that all vertical lines are parallel.
I am using matlab. I find the line segmentes using LSD and the vanishing point using homogeneous coordinates. I would like to use angle-axis representation, then convert it to a rotation matrix and pass this to imwarp and get the rotated image. Also would be good to know how to rotate the segments. The segments are as (x1,y1,x2,y2).
Image above example:
Vanishin point in homogenous coordinates:
(x,y,z) = 1.0e+05 * [0.4992 -2.2012 0.0026]
Vanishin point in cartesian coordinates (what you see in the image):
(x,y) = [190.1335 -838.3577]
Question: With this vanishing point how do I compute the rotation matrix in the world x axis as explained above?
If all you're doing is rotating the image so that the vector from the origin to the vanishing point, is instead pointing directly vertical, here's an example.
I = imread('cameraman.tif');
figure;imagesc(I);set(gcf,'colormap',gray);
vp=-[190.1335 -838.3577,0]; %3d version,just for cross-product use,-ve ?
y=[0,1,0]; %The vertical axis on the plot
u = cross(vp,y); %you know it's going to be the z-axis
theta = -acos(dot(vp/norm(vp),y)); %-ve ?
rotMat = vrrotvec2mat([u, theta]);
J=imwarp(I,affine2d (rotMat));
figure;imagesc(J);set(gcf,'colormap',gray); %tilted image
You can play with the negatives, and plotting, since I'm not sure about those parts applying to your situation. The negatives may come from plotting upside down, or from rotation of the world vs. camera coordinate system, but I don't have time to think about it right now.
EDIT
If you want to rotation about the X-axis, this might work (adapted from https://www.mathworks.com/matlabcentral/answers/113074-how-to-rotate-an-image-along-y-axis), or check out: Rotate image over X, Y and Z axis in Matlab
[rows, columns, numberOfColorChannels] = size(I);
newRows = rows * cos(theta);
rotatedImage = imresize(I, [newRows, columns]);
Imagine a dome with its centre in the +z direction. What I want to do is to move that dome's centre to a different axis (e.g. 20 degrees x axis, 20 degrees y axis, 20 degrees z axis). How can I do that ? Any hint/tip helps.
Add more info:
I've been dabbling with rotation matrices in wiki for a while. The problem is, it is not a commutative operation. RxRyRz is not same as RzRyRx. So based on the way I multiple it I get a different final results. For example, I want my final projection to have 20 degrees from the original X axis, 20 degrees from original Y axis and 20 degrees from original Z axis. Based on the matrix, giving alpha, beta, gamma values 20 (or its corresponding radian) does NOT result the intended rotation. Am I missing something? Is there a matrix that I can just put the intended angles and get it at the end ?
Using a rotation matrix is an easy way to rotate a collection of (x,y,z) points. You can calculate a rotation matrix for your case using the equations in the general rotation section. Note that figuring out the angle values to plug into those equations can be tricky. Think of it as rotating about one axis at a time and remember that the order of your rotations (order of multiplications) does matter.
An alternative to the general rotation equations is to calculate a rotation matrix from axis and angle. It may be easier for you to define correct parameters with this method.
Update: After perusing Wikipedia, I found a simple way to calculate rotation axis and angle between two vectors. Just fill in your starting and ending vectors for a and b here:
a = [0.0 0.0 1.0];
b = [0.5 0.5 0.0];
vectorMag = #(x) sqrt(sum(x.^2));
rotAngle = acos(dot(a,b) / (vectorMag(a) * vectorMag(b)))
rotAxis = cross(a,b)
rotAxis =
-0.5 0.5 0
rotAngle =
1.5708
Ok, so I realize I can find the scale value from a layer's CATransform3D like this:
float scale = [[layer valueForKeyPath: #"transform.scale"] floatValue];
But I can't for the life of me figure out how I would find the scale value from a CGAffineTransform. Say for instance I have this CGAffineTransform called "cameraTransform":
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
CGAffineTransform *cameraTransform = imagePicker.cameraViewTransform;
Now how do I get the scale value from cameraTransform?
I try to give a general answer for all kinds of CGAffineTransforms, even rotated ones.
Assuming your CGAffineTransform contains (optionally)
rotation
translation
scaling
and
NO skew
then the there’s a general formula that gives you the scale factor:
CGAffineTransform transform = ...;
CGFloat scaleFactor = sqrt(fabs(transform.a * transform.d - transform.b * transform.c));
"Mirroring" or flipping coordinate directions will be ignored, that means (x --> -x; y --> y) will result in scaleFactor == 1 instead of -1.
http://en.wikipedia.org/wiki/Determinant
"A geometric interpretation can be given to the value of the determinant of a square matrix with real entries: the absolute value of the determinant gives the scale factor by which area or volume is multiplied under the associated linear transformation, while its sign indicates whether the transformation preserves orientation. Thus a 2 × 2 matrix with determinant −2, when applied to a region of the plane with finite area, will transform that region into one with twice the area, while reversing its orientation."
The article goes on to give formulas for the determinant of a 3x3 matrix and a 2x2 matrix. CGAffineTransforms are 3x3 matrices, but their right column is always 0 0 1. The result is the determinant will be equal to the determinant of the 2x2 upper left square of the matrix. So you can use the values from the struct and compute the scale yourself.
The Quartz 2D Programming Guide tells you where to find the scale values. Compare that with the definition of the CGAffineTransform structure.