I have a textview with some text. Textview have touch events, so user can rotate, scale and translate text. For translation, rotation
and scaling i'm using canvas. Canvas is doing this inside onDraw() function. Now i want to have outer bounds of text when it is scaled or rotated, can anybody help me.
Thanks in Advance.
I try this piece of code to translate,rotate and scale text on canvas:
canvas.scale(fScaledFactorForTextview,fScaledFactorForTextview,getTextWidth() / (2.0f * getLineCount()) + fTranslationX, (getTextSize() * getLineCount()) / 2.0f + fTranslationY);
canvas.rotate(fDegrees, getTextWidth() / (2.0f * getLineCount()) + fTranslationX, (getTextSize() * getLineCount()) / 2.0f + fTranslationY);
canvas.translate(fTranslationX,fTranslationY);
In general it's easier to do this if you use a matrix, rather than direct rotate and scale calls like this. If you use a matrix, you can just apply those same adjustments to the matrix. Then you can easily translate any point from normal Cartesion coordinates to the altered coordinates by multiplying the coordinates by that matrix. Matrix even provides the mapPoints function to do that.
Related
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 hoping someone can help me out. I'm making an image manipulation app, and I found I needed a better way to load in large images.
My plan, is to iterate through "hypothetical" pixels of an image (a "for loop" that covers width/height of the base image, so each iteration represents a pixel), scale/translate/rotate that pixels position relative to the view, then use this information to determine which pixels are being displayed in the view itself, then use a combination of BitmapRegionDecoder and BitmapFactory.Options to load in only the section of image that the output actually needs rather than a full (even if scaled) image.
So far I seem to have covered scale of the image and translation properly, but I can't seem to figure out how to calculate rotation. Since it's not a real Bitmap pixel I can't use Matrix.rotate =( Here is the image translations in the onDraw of the view, imgPosX and imgPosY hold the center point of the image:
m.setTranslate(-userImage.getWidth() / 2.0f, -userImage.getHeight() / 2.0f);
m.postScale(curScale, curScale);
m.postRotate(angle);
m.postTranslate(imgPosX, imgPosY);
mCanvas.drawBitmap(userImage.get(), m, paint);
and here is the math so far of how I'm trying to determine if an images pixel is on the screen:
for(int j = 0;j < imageHeight;j++) {
for(int i = 0;i < imageWidth;i++) {
//image starts completely center in view, assume image is original size for simplicity
//this is the original starting position for each pixel
int x = Math.round(((float) viewSizeWidth / 2.0f) - ((float) newImageWidth / 2.0f) + i);
int y = Math.round(((float) viewSizeHeight / 2.0f) - ((float) newImageHeight / 2.0f) + j);
//first we scale the pixel here, easy operation
x = Math.round(x * imageScale);
y = Math.round(y * imageScale);
//now we translate, we do this by determining how many pixels
//our images x/y coordinates have differed from it's original
//starting point, imgPosX and imgPosY in the view start in center
//of view
x = x + Math.round((imgPosX - ((float) viewSizeWidth / 2.0f)));
y = y + Math.round((imgPosY - ((float) viewSizeHeight / 2.0f)));
//TODO need rotation here
}
}
so, assuming my math up until rotation is correct (probably not but it appears to be working so far), how would I then calculate the rotation from that pixels position? I've tried other similar questions like:
Link 1
Link 2
Link 3
without using rotation the pixels I expect to actually be on the screen are represented (I made text file that outputs the results in 1's and 0's so I can have a visual representation of whats on the screen), but with the formula found in those questions the information isn't what is expected. (Scenario: I've rotated an image so only the top left corner is visible in the view. Using the info from Here to rotate the pixel, I should expect to see a triangular set of 1's in the upper left corner of the output file, but that's not the case)
So, how would I calculate a a pixels position after rotation without using the Android matrix? But still get the same results.
And if I've just messed it up entirely my apologies =( Any help would be appreciated, this project has gone on for so long and I want to finally be done lol
If you need any more information I will provide as much as I possibly can =) Thank you for your time
I realize this question is particularly difficult so I will be posting a bounty as soon as SO allows.
You do not need to create your own Matrix, use the existing one.
http://developer.android.com/reference/android/graphics/Matrix.html
You can map bitmap coordinates to screen coordinates by using
float[] coords = {x, y};
m.mapPoints(coords);
float sx = coords[0];
float sy = coords[1];
If you want to map screen to bitmap coordinates, you can create the inverse matrix
Matrix inverse = new Matrix(m);
inverse.inverse();
inverse.mapPoints(...)
I think your overall approach is going to be slow, as doing the pixel manipulation on the CU from Java has a lot of overhead. When drawing bitmaps normally, the pixel manipulation is done on the GPU.
So the scenario is that I have a surfaceView of size 640 x 480 on which I am showing on camera preview. Now I draw a something vertically on the screen. After that I am rotating the canvas using
canvas.rotate(90, getWidth()/2, getHeight/2);
Once I do that, I am expecting my drawing to be scaled and drawn horizontally. It does draw it horizontally but it is not scaling it according the width and height.
Here is the pictorial example explanation to help you understand better.
https://lh4.googleusercontent.com/-2wlImCt0m88/UcHzhKUSGBI/AAAAAAAAB9Y/bGNMOTu9DqM/s1440/canvas_rotation.png
Is there a way or an algorithm by which I can rotate the canvas and then scale it accordingly?
let me know if you need any further explanation.
Thanks in advance.
Well so I figured out the solution to it. What we can do is that we can use
canvas.scale( newX, newY, pivotX, pivotY);
/*
* Where
* newX = oldX * (newWidth/oldWidth);
* newY = oldY * (newHeight/oldHeight);
* pivotX = same as before;
* pivotY = same as before;
*/
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
I'm still facing a difficulty to project a list of geological positions to pixels. I have a custom view (derived from SurvaceView) for simply painting the coordinates.
My code:
x = (int) sView.getHeight() * ( (pos.getLat() - minLat) / (maxLat - minLat)) + margin;
...
myPoints.add(new Point(x,y));
onDraw(Canvas canvas) {
for (Point p : myPoints) {
canvas.drawPoint(p.x, p.y, myPaint);
}
.... doesn't fit the entire view. I am becoming desperate. Do you have a idea?
Thanks
It's a bit unclear what you want.
But if I understand you correctly, you want to plot a set of GPS-coordinates to a bitmap, and you want the resulting plot to fit the size of the bitmap.
If so, I suggest going for the following strategy:
Find the minimum and maximum latitudes and longitudes, MinLon, MaxLon, MinLat and MaxLat.
Subtract the minimum values from all the points (rebasing the data set to (0,0)).
Find the horizontal scale factor: ScaleX := (MyBitmap.Width) / (MaxLat - MinLat)
Find the vertical scale factor: ScaleY := (MyBitmap.Height) / (MaxLon - MinLon)
Loop through all the points in your dataset, and apply the lowest scale factor of ScaleX and ScaleY.
You will then have a set of points with coordinates that can be plotted to your bitmap.
It will not be a cartographically correct projection, but it'll probably serve a starting point, at least.