I want to move an object on a circle around a given point. I am using OpenGL on Android and my viewport is the screen resolution in landscape mode (1280 * 800). The point I want to rotate an object around is e.g (500, 300) and this is where the user pressed. I also have the radius of the desired circle r.
To sum it up, I've the center of the circle, the radius, and the angle (amount I want to move the object with each iteration of the game loop)
So far I tried this:
this.setPosX(((float)Math.cos(angle)*radius + center.x) * width);
this.setPosY(((float)Math.sin(angle)*radius + center.y) * height);
This will create a movement along an ellipsis, not a circle...
Can anyone please help me?
It produces an ellipse cause circles DON'T have heights. Try this instead
this.setPosX(((float)Math.cos(angle)*radius ) + center.x);
this.setPosY(((float)Math.sin(angle)*radius ) +center.y);
Just remove the width and height factors at the end. If you want a circle you cannot multiply the coordinates with different factors.
The formula is not correct because you are multiplying the correct value for a point around a circle by other different values which are not meaningful.
Think about the fact that you have c(x,y) which is the center and you need to move around by a value which is given by r(cos(angle)*radius, sin(angle)*radius).
What you obtain is p(x + cos(angle)*radius, y + sin(angle)*radius).
If you multiply these two coordinates by two other values (width and height in your formula) you are changing the factor either for the circle either for the center so you end up with not only an ellipse but an ellipse which changes its center.
So:
circle: p(c.x + cos(angle)*r, y + sin(angle)*r)
ellipse: p(c.x + cos(angle)*w, y + sin(angle)*h)
your formula: p((c.x + cos(angle)*r)*w, (c.y + sin(angle)*r)*h) (which makes no sense)
Related
Can anyone explain to me what is the cause of this behavior?
The problem is that, from "off" to "2" always shows perfectly, above the radius I gave.
Radius is +35 than the circle's radius.
Now when I write digits, as it goes down, it starts to mess up.
And in terms of alphabets, it touches the edge and overlaps it.
can anyone tell me the reason for this? because radius is always more than the current circle's radius so the alphabets should appear similarly like "off".
computation of xy points...
// Angles are in radians.
val startAngle = Math.PI * (9 / 8.0)
val angle = startAngle + pos.ordinal * (Math.PI / 4)
x = (radius * cos(angle)).toFloat() + width / 2
y = (radius * sin(angle)).toFloat() + height / 2
I played around with the degrees and it seems like the closer to 0 degree starts to mess up, as the degrees increase, it keeps adding more space in radius.
Illustrated here... I would like to what what is causing this behavior, or just explain the reason/ math behind it. thanks
From the comments it looks like you are following this code lab code https://github.com/google-developer-training/android-advanced/tree/master/CustomFanController
You just need to take into account text ascent and decent. So draw the numbers on the circumference of the circle
val yPos = (pointPosition.y - (paint.descent() + paint.ascent()) / 2).toInt()
canvas.drawText(label, pointPosition.x, yPos.toFloat(), paint)
The above is based on Android Center text on canvas
This does draw the text at the correct place, but if the text is too large it does overlap
I have a custom drawn rectangle which i want to move in a circular path based on touch events.
It follows the direction of the touch for clockwise or anticlockwise movement but basically move in circular motion, as if moving on the edge of the circle.
My current thought process is as follows:
Based on the users current and previous x,y i shall find the angle in degrees and then move this rectangle by the same angle by re-drawing in the new position, just making sure that it moves on the edge of a circle.
But this leads to some confusion on the following:
1. how do i decide whether angle movement is clockwise or anti-clockwise.
2. I am not being able to figure out the math for this properly.
Would this be the best approach or is there a better idea for doing this?
Also, if this is the best approach, could someone please tell me the formula for calculating the angle by which i should move it while taking care of the clocking and anticlockwise ?
could someone please help?
please let me know if any more details are required.
Thanks
Steps
Here are a few steps in order to move your rectangle along a circle's rim when the user taps and holds to the side of the circle:
1. Obtain direction desired.
2. Obtain angle from current x and y coordinates.
3. Add direction (+1 if counterclockwise, -1 if clockwise) to angle.
4. Calculate new x and y coordinates.
5. Update/display rectangle.
Details
1. In pseudocode, direction = sign(Rectangle1.x - UsersFingerPosition.x). Here sign is a function returning -1 if the number was negative, 0 if it is 0, and 1 if it is positive. Note that sign(0) will only result when the user is on the exact x and y of your rectangle's location. In that case, the rectangle would not move (which should be good). In Java, the sign function is Math.signum().
2. To obtain the current angle use the following java code:
double angle = Math.toDegrees(Math.atan2(Circle.y-Rectangle1.y, Rectangle1.x-Circle.x));
Note the order of Circle.y-Rectangle.y and Rectangle.x...Circle.x. This is a result of the coordinate (0, 0) being in the top left corner instead of the center of the screen.
3. Simple enough, just add direction to angle. If desired, do something like
angle += direction*2; //So it will move more quickly
4. To get the new x and y coordinates of your rectangle, use the trigonometric functions sine and cosine:
Rectangle1.x = Math.cos(Math.toRadians(angle))*Circle.radius + Circle.x - Rectangle1.width;
Rectangle1.y = Math.sin(Math.toRadians(angle))*Circle.radius + Circle.y - Rectangle1.height;
(where Circle.x and Circle.y are the coordinates of the center of your circle and Circle.radius is naturally it's radius).
5. This one you'll have to take care of (or have already) :)!
Hope this helps you!
Steps
Here are a few steps in order to move your rectangle along a circle's rim:
1. Obtain finger position/Check that it's still dragging the rectangle.
2. Obtain angle from current x and y coordinates.
3. Calculate new x and y coordinates.
4. Update/display rectangle.
Details
1. This one is probably specific to your code, however, make sure that when the user starts dragging the rectangle, you set a variable like rectangleDragging to true. Before you run the next steps (in the code), check that rectangleDragging == true. Set it to false once the user lets go.
2. To obtain the current angle use the following java code:
double angle = Math.toDegrees(Math.atan2(Circle.y-Finger.y, Finger.x-Circle.x));
Note the order of Circle.y-Finger.y and Finger.x...Circle.x. This is a result of the coordinate (0, 0) being in the top left corner instead of the center of the screen.
3. To get the new x and y coordinates of your rectangle, use the trigonometric functions sine and cosine:
Rectangle1.x = Math.cos(Math.toRadians(angle))*Circle.radius + Circle.x - Rectangle1.width;
Rectangle1.y = Math.sin(Math.toRadians(angle))*Circle.radius + Circle.y - Rectangle1.height;
(where Circle.x and Circle.y are the coordinates of the center of your circle and Circle.radius is naturally it's radius). Subtracting the width and height of the rectangle should center it on the circle's border instead of placing the left, upper corner on the circle.
4. This one you'll have to take care of (or have already) :)!
Hope this helps you!
I want to achieve a tilt effect when a button is clicked, on Android OS.
Tilt Effect: Not the whole button will be seen as pressed. Only the part that touch event occured should seem to be pressed.
Is this easily possible on Android?
A simple way would be to use canvas draws to draw 4 sided shapes.
Consider each 4 corners. The "untouched" rectangle would be full size the touched rectangle would be smaller.
You just need to draw your four sided shape using a point you calculate for each part of the rectangle. You can get the touch position, then figure out how much "weight" to give each point.
to calculate each corner, you need to figure out how much "weight" to give the touched coordinate, and how much "weight" to give the untouched coordinate. If you touch the top left corner, that corner would use 100% of the touched coordinate, and the other three corners would all use the untouched coordinate.
If you touched the top middle, you would get a shape like this:
We can calculate the corners for any touch spot, by calculating how far from the corner your touch is
float untouchedXWeight1 = Math.abs(xt - x1)/width;
//maximum of 1, minimum of 0
float untouchedYWeight1 = Math.abs(yt - y1)/height;
float untouchedWeight1 = (untouchedXWeight1 + untouchedYWeight1)/2;
//also maximum of 1, minimum of 0
float touchedWeight1 = 1 - untouchedWeight1;
so with those weights, you can calculate your x and y positions for that corner:
x1 = xUntouched1 * untouchedWeight + xTouched1 * touchedWeight1;
y1 = yUntouched1 * untouchedWeight + yTouched1 * touchedWeight1;
Then do similarly for the other 3 corners.
I've created a first draft here : https://github.com/flavienlaurent/TiltEffect
In a second step, I will make it usable with Button etc.
Unfortunatly, I didn't use the very good (but too mathematical for me) answer of HalR
If you have a "ball" inside a 2D polygon, made up of say, 4 line segments that act as bounding walls, how do you calculate the angle of the ball after the collision with the irregularly sloped wall?
I know how to make the ball bounce if the wall is horizontal, vertical, or at a 45 degree angle. I also have my code setup to detect a collision with the wall.
I've read about dot products and normals, but I cannot figure out how to implement these in Java / Android. I'm completely stumped and feel like I've looked up everything 10 pages deep in Google 10 times now. I'm burned out trying to figure this out, I hope someone can help.
Apologies in advance: I don't know the correct Android types. I'm assuming you have a vector type with properties 'x' and 'y'.
If the wall were horizontal and the current velocity were 'vector' then it'd be as easy as:
vector.y = -vector.y;
And you'd leave the x component alone. So you need to do something analogous, but more general.
You do that by substituting the idea of the line normal (a vector perpendicular to the line) for hard coding for the y axis (which is perpendicular to the horizontal).
Since the normal is orthogonal to the line, it can be found by rotating the line by 90 degrees. In 2d, the vector (a, b) can be rotated by 90 degrees by converting it to (-b, a). Hence if you have a line from (x1, y1) to (x2, y2) then you can get the normal with:
vectorAlongLine.x = x2 - x1;
vectorAlongLine.y = y2 - y1;
normal.x = -vectorAlongLine.y;
normal.y = vectorAlongLine.x;
You don't actually care how long the original line was (and it'll affect computations later when you don't want it to), so you want to make the normal be of length 1 irrespective of its current length. You can do that by dividing it by its current length. So, e.g.
lengthOfNormal = Math.sqrt(normal.x*normal.x + normal.y*normal.y);
normal.x /= lengthOfNormal;
normal.y /= lengthOfNormal;
Using the Pythagorean theorem there to get the length.
With the horizontal line, flipping on the y axis was the same as (i) working out what the extent of the vector extends along the y axis; and (ii) subtracting that amount twice — once to get the velocity to be 0 in that direction, again to make it the negative version of the original. That is, it's the same as:
distanceAlongNormal = vector.y;
vector.y -= 2.0 * distanceAlongNormal;
The dot product is used in the general case is to work how far the vector extends along the normal. So it does the same as taking vector.y does for the horizontal line. This is where you possibly have to take a bit of a leap of faith. It's a property of the dot product and you can persuade yourself by inspecting a right-angled triangle. But for now, if you had a horizontal line, you'd have ended up with the normal (0, 1). Since the dot product would be:
vector.x * normal.x + vector.y * normal.y
You'd compute:
distanceAlongNormal = vector.x * 0.0 + vector.y * 1.0;
Which is obviously the same thing as just taking the y component.
Having worked out the distance along the normal, you actually want to then subtract that amount times the normal times two. The only additional step here is multiplying by the normal to get a 2d quantity to subtract. That's because you're looking to subtract in the order of the normal. So complete code, based on a normal computed earlier, is:
distanceAlongNormal = vector.x * normal.x + vector.y * normal.y;
vector.x -= 2.0 * distanceAlongNormal * normal.x;
vector.y -= 2.0 * distanceAlongNormal * normal.y;
If you hadn't made normal of length 1, then you'd need to divide by the length here, since the dot product would scale the distanceAlongNormal value by that amount.
This might come in handy for you
http://www.tonypa.pri.ee/vectors/tut07.html
If my X co-ordinates increment every time a frame is drawn, what formula can I employ from the math library in order to have the Y co-ordinate moving around the circumference of a circle frame by frame, creating the illusion of an orbiting object around a continuously moving central point?
I have seen it may involve sin or cos but am not sure how to adjust the variables accordingly per frame.
Many thanks for your help
You can't make a complete circle if your X coordinate increments every time, because half the time your X coordinate has to be decrementing.
What you want is polar coordinates: theta for angle and r for radius. Your r will remain constant, and your theta will increment continuously. Then your x and y are:
x = r * cos(theta)
y = r * sin(theta)
let ox,oy be the origin of your circle, and px,py be a point on the edge of the circle, with a radius of r
given: (px-ox)^2 + (py-oy)^2 = r^2 definition of circle
solve for py:
(py-oy)^2 = r^2 - (px-ox)^2
(py-oy) = sqrt(r^2 - (px-ox)^2)
py = sqrt(r^2 - (px-ox)^2) + oy <---
So as you increment px with your frames, you can find the appropriate py by recalculating the above formula.