If I use this:
mCamera.rotateY(45);
mCamera.getMatrix(mMatrix);
mMatrix.preTranslate(-pivotX, -pivotY);
mMatrix.postTranslate(pivotX + centerX, pivotY + centerY);
And do:
canvas.drawBitmap(bitmap, mMatrix, null);
Then the drawn picture will be taller and slimmer and the matrix will be nicely applied to the whole picture. Now, is there any way to calculate the rotated size? I want to fit the image by scaling it and now when I rotate it some of the top and bottom is clipped because of the parent's constraints. Thanks!
EDIT:
What I am going to do is spin the image and the range for rotateY will be from 0 to 90.
Well, you could easily let the matrix map the corners of your bitmap and then calculate the bounds, as the mapped corners will be the max / min for x and y coordinate. Maybe you can do it without too many if clauses :)
Edit:
Check out
RectF r = new RectF(/*your bitmap's corners*/);
matrix.mapRect(r);
That way you should get r's new size.
If you stick to 45° then Pythagoras is the key
Related
I have a question regarding transformations in OpenGL ES 2. I'm currently drawing a rectangle using triangle fans as depicted in the image below. The origin is located in its center, while its width and height are 0.6 and 2 respectively. I assume that these sizes are related to the model space. However, in order to maintain the ratio of height and width on a tablet or phone one has to do a projection that considers the proportion of the device lengths (again width and height). This is why I call orthoM(projectionMatrix, 0, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f);and the aspectRatio is given by float aspectRatio = (float) width / (float) height. This finally leads to the rectangle shown in the image below. Now, I would like to move the rectangle along the x-axis to the border of the screen. However, I was not able to come up with the correct calculation to do so, either I moved it too little or too much. So how would the calculation look like? Furtermore, I'm a little bit confused about the sizes given in the model space. What are the max and min values that can be achieved there?
Thanks a lot!
Vertex position of the rectangle are in world space. A way to do this it could be get the screen coordinates you want to move to and then transform them into world space.
For example:
If the screen is 300 x 200 and you are in the center 0,0 in world space (or 150, 100) in screen space). You want to translate to 300.
So the transformation should be screen_position to normalized device coordiantes and then multiply by inverseOf(projection matrix * view matrix) and divided by the w component.
Here it is explained for mouse that it is finally the same, just that you know the z because it is the one you used for your rectangle already (if it is on the plane x,y): OpenGL Math - Projecting Screen space to World space coords.
I have an Image View which displays an image (e.g 2000x1000 pixels) and I have a coordinate (X,Y) on that image (not the image view). The canvas of my Image View is 600x800 for example. How can I convert the point (X,Y) to screen coordinate so that I can draw a path with them on the OnDraw(...) method of Image View. Any help is appreciated! Thank you.
Update: If I use matrix to draw the path between coordinates, it works but the path and objects i draw become really small. Here is the code i used.
final Matrix matrix = canvas.getMatrix();
matrix.preConcat( _view.getImageMatrix() );
matrix.preScale( 1.0f /_inSampleSize, 1.0f / _inSampleSize);
canvas.setMatrix( matrix );
//I draw the path here
Update: I add a picture to show the effect when using matrix to draw the path. I would like to have the 4 line and the 4 corner balls to be in normal size. The red color is the boundary of the Image View which holds the picture.
I think that might depend on how exactly you are displaying your image. Your ImageView (600x800) is not the same aspect ratio as your bitmap (2000x1000).
You are keeping the bitmap's aspect ratio stable as you scale it down? If so, which part (height or width) takes up the full screen and which has black (or whatever else) as padding? This will help you determine your scale factor.
scale_factor = goal_height/height1; //if height is what you are scaling by
scale_factor = goal_width/width1; //if width is what you are scaling by.
I would try:
x_goal = x1 * scale_factor;
y_goal = y1 * scale_factor;
That is, if you have a point (1333, 900) in your image, and your image takes up the full width, you would multiply both x and y by 600/2000 to get (399.9, 270). (you might want to round that decimal).
If you are NOT keeping the bitmaps aspect ratio stable (that is, you're squeezing it to fit), then you'd have a height_scale_factor and a width_scale factor. So you'd take (1333,900) and multiply x by 600/2000 and y by 800/1000 to get (399.9,720).
I'm implementing 3d card flip animation for android (api > 14) and have an issue with big screen tablets (> 2048 dpi). During problem investigation i've come to the following basic block:
Tried to just transform a view (simple ImageView) using matrix and rotateY of camera by some angle and it works ok for angle < 60 and angle > 120 (transformed and displayed) but image disappears (just not displayed) when angle is between 60 and 120. Here is the code I use:
private void applyTransform(float degree)
{
float [] values = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
float centerX = image1.getMeasuredWidth() / 2.0f;
float centerY = image1.getMeasuredHeight() / 2.0f;
Matrix m = new Matrix();
m.setValues(values);
Camera camera = new Camera();
camera.save();
camera.rotateY(degree);
camera.getMatrix(m);
camera.restore();
m.preTranslate(-centerX, -centerY); // 1 draws fine without these 2 lines
m.postTranslate(centerX, centerY); // 2
image1.setImageMatrix(m);
}
And here is my layout XML
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/naponer"
android:clickable="true"
android:scaleType="matrix">
</ImageView>
</FrameLayout>
So I have the following cases:
works fine for any angle, any center point if running on small screens 800X480, 1024x720, etc...
works ok for angle < 60 and > 120 when running on big screen devices 2048x1536, 2560x1600...
works ok for any angle on any device if rotation not centered (matrix pre and post translations commented out )
fails (image disappears) when running on big screen device, rotation centered and angle is between 60 and 120 degrees.
Please tell what I'm doing wrong and advise some workaround... thank you!!!
This problem is caused by the camera distance used to calculate the transformation. While the Camera class itself doesn't say much about the subject, it is better explained in the documentation for the View.setCameraDistance() method (emphasis mine):
Sets the distance along the Z axis (orthogonal to the X/Y plane on
which views are drawn) from the camera to this view. The camera's
distance affects 3D transformations, for instance rotations around the
X and Y axis. (...)
The distance of the camera from the view plane can have an affect on
the perspective distortion of the view when it is rotated around the x
or y axis. For example, a large distance will result in a large
viewing angle, and there will not be much perspective distortion of
the view as it rotates. A short distance may cause much more
perspective distortion upon rotation, and can also result in some
drawing artifacts if the rotated view ends up partially behind the
camera (which is why the recommendation is to use a distance at
least as far as the size of the view, if the view is to be rotated.)
To be honest, I hadn't seen this particular effect (not drawing at all) before, but I suspected it could be related to this question related to perspective distortion I'd encountered in the past. :)
Therefore, the solution is to use the Camera.setLocation() method to ensure this doesn't happen.
An important distinction with the View.setCameraDistance() method is that the units are not the same, since setLocation() doesn't use pixels. While setCameraDistance() adjusts for density, setLocation() does not. Therefore, if you wanted to calculate an appropriate z-distance based on the view's dimensions, remember to adjust for density. For example:
float cameraDistance = Math.max(image1.getMeasuredHeight(), image1.getMeasuredWidth()) * 5;
float densityDpi = getResources().getDisplayMetrics().densityDpi;
camera.setLocation(0, 0, -cameraDistance / densityDpi);
Instead of using 12 lines to create rotation matrix, you could just implement this one in first line http://en.wikipedia.org/wiki/Rotation_matrix
Depending of effect you want, you might want to center image to axis you want to rotate around.
http://en.wikipedia.org/wiki/Transformation_matrix
Hmm for image disappearing, I would guess it has something to do with either memory (out of memory - although this would bring exception) or rounding problems. Maybe you could try increasing precision to double precision?
One thing that comes to mind is that cos(alpha) goes toward 0 when alpha goes toward PI/2. Other than that I don's see any correlation between angles and why it doesn't work for big images.
You need to adjust your Translate coordinates. When calculating the translation for your image you need to take image size into account too. When you perform matrix calculations you set android:scaleType="matrix" for your ImageView. This aligns your image at the top left corner by default. Then, when you apply your pre/post translation, your image may get off the bounds of your ImageView (especially if the ImageView is relatively large and your image is relatively small, like in case of beeg screen tablets).
The following translation results in the image being rotated around its center Y axis and keeps the image aligned to the top left corner:
m.preTranslate(-imageWidth/2, 0);
m.postTranslate(imageWidth/2, 0);
The following alternative results in the image being rotated around its center Y/X axises and aligns the image to the center of the ImageView:
m.preTranslate(-imageWidth/2, -imageHeight/2);
m.postTranslate(centerX, centerY);
If your image is a bitmap you can use intrinsic width/height:
Drawable drawable = image1.getDrawable();
imageHeight = drawable.getIntrinsicHeight();
imageWidth = drawable.getIntrinsicWidth();
I want to calculate rotated image size, Image is inside rectangle. I have rectangle width, height and angle of rotated image. Any one tell me
how to calculate rotated image size?
So you have width, height and angle means you already got RotatedRect.
Now using the method
Rect RotatedRect::boundingRect();
you can easly calculate the bounding box for rotated rect.
for more info see RotatedRect.
Edit:
As per your comment below is the way how to find the width and height of rotated rect.
So you know the four corners of rectangle, lets say (x1,y1),(x2,y2),(x3,y3),(x4,y4), now you need to find the transformed point after rotation by the given angle, let it be (xT1,yT1),(xT2,yT2),etc...
where
xT = x0+(x-x0)*cos(theta)+(y-y0)*sin(theta)
yT = y0-(x-x0)*sin(theta)+(y-y0)*cos(theta)
here (x0,y0) is the center around which you are rotating. and theta = angle * CV_PI / 180.0
Using above calculate four transformed points, finally calculate the height and width by finding the distance between transformed points.
How can I rotate an image around it's center point? This rotates it but also moves it:
Matrix mat = new Matrix();
mat.postRotate(45);
Bitmap bMapRotate = Bitmap.createBitmap(dialBM, 0, 0, dialBM.getWidth(),dialBM.getHeight(), mat, true);
dial.setImageBitmap(bMapRotate);
I've checked other examples on this site, but they either fail to work or use canvas, I do not wish to use canvas.
The second and third arguments to postRotate is the x and y pivot point.
mat.postRotate(45, dialBM.getWidth()/2, dialBM.getHeight()/2);
Probably because your matrix rotates around (0,0), and not the middle of your bitmap. You should declare two additional matrices - one for moving the bitmap's center to (0,0) (shift by -getWidth()/2, -getHeight(2)) and one to move the bitmap's center back to (0,0). Multiply the three matrices, and then the result.