I need to make a rotating wheel on my android App. To do so, I'm creating a custom View in order to place it anywhere I want in the App activities.
All around the wheel, I need to place TextViews.
Thanks to the width and height of the view, I can get the center point of the canvas' view.
I know the angle, I know the radius, so now I need to place textviews on the edge of the circle by calculating the coordinates on the canvas.
Does anyone knows how to achieve that ?
Thanks in advance !
A point at angle theta on the circle whose center is (x0,y0) and whose radius is r is (x0 + r cos theta, y0 + r sin theta)
Or
Once you have drawn the circle you have to rotate the canvas put the text at required angle and then again restore it as,
canvas.save();
canvas.rotate(45, x, y);
canvas.drawText("your text here", x, y, paint);
canvas.restore();
Hope that helps..!!
Related
I want to place a small triangular bitmap centered on the dotted circle as similar to as follows:
Here is my code that places the bitmap according to a specified angle:
x = (float) (center.x + radius* Math.cos(Math.toRadians(getRotationAngle())));
y = (float) (center.y + radius * Math.sin(Math.toRadians(getRotationAngle())));
canvas.drawBitmap(mCurrentTimeIndicatorBitmap, x, y, new Paint(Paint.FILTER_BITMAP_FLAG));
getRotationAngle() returns a value between 0 and 360 (inclusive). center.x, center.y are a constant 500 and radius is a constant 313.3. However, as I rotate around the circle, the bitmap's distance to the dotted line varies and I do not know why. The above picture is with rotation angle at 0, where it is farthest from the center.
Near rotation angle 90:
Near rotation angle 180, where it is the furthest from the dotted line & closest to the center:
Near rotation angle 270:
As you can see the triangle is various distances away from the dotted line. What is causing this? My code to draw the dotted lines is very similar but no issue occurs there.
When you draw bitmap, you are using left top corner as base point. So this corner walks around the circle exactly. But bitmap center moves along the circle that is shifted to right and bottom.
Just subtract half-size of bitmap to get corner coordinates at every step (or shift center coordinates)
x = (float) (center.x - mCurrentTimeIndicatorBitmap.width / 2 +
radius* Math.cos(Math.toRadians(getRotationAngle())));
y = (float) (center.y - mCurrentTimeIndicatorBitmap.height / 2 +
radius * Math.sin(Math.toRadians(getRotationAngle())));
canvas.drawBitmap(mCurrentTimeIndicatorBitmap, x, y, new Paint(Paint.FILTER_BITMAP_FLAG));
I referred the question Draw a circle within circle at a distance of 10
which comes close to my requirement. I just needed two concentric circles one inside the other inner one with radius scaled to 300 mts and outer one with radius scaled to 500 mts.
I have been able to draw the two circles scaled in pixels on my screen using a transformation method that transformed distance in metres to corresponding pixel distances.
The next step is to draw a plus inside the circle; the lines being the diameters. Hence they will pass through the center and contain two points on the circle.
1)I have the lat long and pixel details of the center of the circle.
2)I know that the angle between the center and the either points on the circle need to be 90 degrees.
3)I must use canvas.drawLine().
But what would be the best way to get these points on the circle so that a line can be drawn through these three points.
(Point on the circle at the top, center of the circle,Point on the circle at the bottom).
Greatly appreciate your help.
EDIT:
I tried the following code after some searching
//double degrees = 90.0;
//double radians = Math.toRadians(degrees);
//int x1 = (int) (500 * Math.cos(radians) + x);
//int y1 = (int) (500 * Math.sin(radians) + y);
//canvas.drawLine(x, y, x1, y1, mSelectionBrush);
canvas.drawLine(x, y-500, x, y+500, mSelectionBrush);
canvas.drawLine(x-500, y, x+500, y, mSelectionBrush);
x,y are the coordinates of the center. 500 is the radius of the outer circle.
The output I see is this. The line extends below. Am I going the right way?
I think you're on the right track. Notice that only Y changes for the vertical line.
Assuming center is given by C(a,b)
So the end-points would be
(a,b-r) and (a,b+r)
For the horizontal line only x changes:
(a-r,b) and (a+r,b) would be the end-points.
r is the radius.
I am trying to make a Re-sizable touch view which I made successfully. You can find code How to make view resizable on touch event.
It has 4 corners. You can re-size that rectangle by dragging one of corner. But now I want to enhance that logic and want to put rotation in that code. I successfully find angle when user touch center of one of the edge of rectangle. But now problem is I can't get new position of corners so that I can redraw that rectangle and rotation is possible.
Question is : How can I calculate 4 corners new position based on Angle?.
If you know the angle by which to rotate then you don't need to calculate the rectangle's vertices.
A simple way to do it would be as below
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.rotate(60.0f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRect(10, 10, 100, 100, paint);
canvas.restore();
}
As I understood, you want to calculate new coordinates based on a rotation angle... It's probably simpler than you think:
x' = x × (cosα - sinα)
y' = y × sinα × cosα
So, you just apply this programmatically, considering where x' is the rotation result of x and the same for y' and y, and α is the rotation angle.
cosα and sinα functions are available in Java as Math.cos(α) and Math.sin(α), but attention: in Java, all trigonometric functions uses radians and not degrees as angle, so you can consider this:
rad = deg * 180 / π
Applicable as:
double deg = 45d; //Put instead your degrees
double rad = deg / 180 * Math.PI; //The radians convertion
I'm trying to write a graph class I can use in Android(I'm aware pre-made ones exist), but converting all of my coordinates would be a pain. Is there an easy way to make the screen coordinates start at the bottom left?
No, I don't know of a way to move 0,0 to the bottom left and get what you would typically think of as "normal" coordinates.
But combining scale() and translate() might do the trick to achieve the same effect.
canvas.translate(0,canvas.getHeight()); // reset where 0,0 is located
canvas.scale(1,-1); // invert
You can flip your Canvas with something like canvas.scale(1, -1) and then translate it to the right place.
You can use canvas.translate() http://developer.android.com/reference/android/graphics/Canvas.html#translate(float, float) to move the origin to where you want.
The android canvas has the origin at the top left. You want to translate this to the bottom right. To do this translation, subtract the y co-ordinate from the Canvas height.
float X1 = xStart;
float Y1 = canvas.getHeight() - yStart; //canvas is a Canvas object
float X2 = xEnd;
float Y2 = canvas.getHeight() - yEnd;
canvas.drawLine(X1, Y1, X2, Y2, paint ); //paint is a Paint object
This should make your line start from the bottom left.
An example can be found here compass.java.
Api here
Even when I first answered this question a few years ago, I didn't really understand how Canvas transforms (like translate, rotate, etc.) worked. I used to think that translate moved the thing that you were drawing. Actually, translate moves the entire coordinate system. This has the desired effect of also moving the thing you are drawing.
On your screen it looks like you are moving the drawing:
What is actually happening is you are moving the coordinate system to a new place on the canvas:
I draw the tree first at (0,0). Then I translate the origin of the coordinate system to some other spot on the canvas. Then I draw the tree again at (0,0). This way my drawing code doesn't have to change anything at all. Only the coordinate system changes.
Normally (0,0) is at the top left of your view. Doing Canvas.translate moves it to some other part of your view.
Saving and Restoring the Coordinate System
You can do save() and restore() to get back to your original coordinate system.
// draw the tree the first time
canvas.drawBitmap(tree, 0, 0, mPaint);
// draw the tree the second time
canvas.save();
canvas.translate(dx, dy); // dx = change in x, dy = change in y
canvas.drawBitmap(tree, 0, 0, mPaint); // draw still thinks it is at (0,0)
canvas.restore(); // undo the translate
When you restore, the drawing is already on the canvas. Restoring doesn't change that. It just moves the coordinate system back to wherever it was when you saved it.
Why Translate
Note that you could achieve the same affect by changing the x,y coordinates of the draw method:
// draw the tree the first time
canvas.drawBitmap(tree, x, y, mPaint);
// update the x,y coordinates
x += dx;
y += dy;
// draw the tree the second time
canvas.drawBitmap(tree, x, y, mPaint);
This might be more intuitive coming from a math background. However, when you are translating, rotating, and scaling your image, it is often much easy to keep your drawing logic the same and just transform the canvas. Recalculating x and y for every draw could be very expensive.
Imagine it's a Print Head.
The easiest way to explain this is to imagine it is the print head of an inkjet or 2D printer.
translate basically "moves" the print head along the X and Y axes the number of pixels that you tell it to.
The resulting position becomes the new "origin" (0,0).
Now that we understand that, let's make a simple face by doing the following:
Starting Origin:
x
The x will (roughly) represent where the origin (or print head) is.
Draw a rectangle for the left eye:
canvas.drawRect(10, 10, 10, 10, paint);
x__
|__|
Note: The "origin" has not changed, it is still at the top left of this rectangle.
Move "origin" right by 20 points:
canvas.translate(20, 0)
__ x
|__|
Draw the right eye using the exact same rectangle command:
canvas.drawRect(10, 10, 10, 10, paint);
__ x__
|__| |__|
Move "origin" back to the original X position and move it down on the Y axis:
canvas.translate(-20, 20) // Positive numbers for the second param is "down" on the y-axis.
__ __
|__| |__|
x
And draw a mouth to finish it off:
canvas.drawLine( 0, 0, 30, 0, paint );
__ __
|__| |__|
x___________
Now just move the "origin" down 20 points to showcase our masterpiece:
canvas.translate(0, 20)
__ __
|__| |__|
___________
x
Not perfectly to scale as there's only so much you can do with a monospace font. :)
Translate - Basically do what it says. Just translate the canvas using x,y. If you want to draw two objects and the one is just translation of the other e.g x2 = x1 + 50 for each point . You don't have to make all your calculations again for the second object but you can just translate the canvas and draw again the same object. I hope this example will help you.
it will change the position of your canvaz(except scale) either x or y
if we translate & scale then it is transformation in general terminology