Im trying to create an custom view that displays a dial with the numbers 1-10 around it. Im using trigonometry to find the X and Y positions for the numbers of the dial. I have no problems to find the positions around the circle but im unable to align them further in towards center of the dial. Look at number 6 for example, i just want it to be placed slightly above the thick white tick mark.
I have tried versions of "shortening the radius".
val diameter = Math.min(width, height)
val radius = diameter / 2
val distance = radius * 0.20f //20% of radius
And then deduct 'distance' from radius to find the X and Y positions there and then add the numbers on those positions with no luck.
Below is the code that calculates the X and Y positions and adds the numbers displayed in the dial screenshot.
for (i in 1..10) {
canvas?.drawText(i.toString(),cx.toFloat() +
(Math.cos(Math.toRadians(degrees.getInt(feetNumber,0).toDouble())).toFloat()) *
radius - (paint.measureText(i.toString()) / 2),
cy.toFloat() +
(Math.sin(Math.toRadians(degrees.getInt(feetNumber,0).toDouble())).toFloat()) *
radius + (paint.measureText(i.toString()) / 2), paint)
feetNumber++;
}
I have added the degrees in a array resource file.
<resources>
<array
name="degrees">
<item>270</item>
<item>306</item>
<item>342</item>
<item>18</item>
<item>54</item>
<item>90</item>
<item>126</item>
<item>162</item>
<item>198</item>
<item>234</item>
</array>
</resources>
I would be very grateful if any one can help me to understand how to draw the numbers a short space after the thick tick marks where you usually find the numbers in a dial.
I have found a solution to my problem. The problem was that i cant calulate the radius in the canvas?.drawText() so i needed to privide pre-calculated value.
val radius = diameter / 2
val mark = radius * 0.30f
val shorterRadius = radius - mark
and then use the shorterRadius inside canvas?.drawText() along with the rest of the calculations.
Then my dial look like the attached picture.
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
Render labels in circular path and aligned center to the width of the arc,
Intially, i have tried by point on the circle formula to position the label as below,
label_X_Position = (float) (centreX) - (labelRadius ) * Math.sin(angleForLabel));
label_Y_Position = (float) ((centreY) + (labelRadius) * Math.cos(angleForLabel));
canvas.drawText(String.valueOf(labelText), (float) label_X_Position, (float) label_Y_Position, paint);
but when the length of the label value increased it doesn't looks like circular path. For better understanding i have attached a diagramatic representation for my requirment,
in the above image, while placing the value 100000 as per existing implementation, the text value will start from the arc. I need that to be shared based on its length.
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)
See image below:
illustration http://img28.imageshack.us/img28/5286/pic1we.png
Assume it's on android device screen. Dot #1 is the current position. I want to get the (x,y) position of Dot #2 following the linear blue line (let's say the range between dot #2 and dot #1 is 50dp). The black box is the source point of the blue line.
What is the term for this? Translation?
Is there anyone know the algorithm?
I developed android application using AndEngine, if you know there is built-in function for that, please let me know. Same too for android openGL ES library.
Note: I'm not looking for a way to move object using MoveModifier.
Thx in advance.
Authman's answer is good, but doesn't include how to get a specific distance away. If you're looking for p2 along the line, IMO it's easier to think about this in vectors. First you find the vector along the blue line, which is similar to the process that Authman describes above. If the black box has position v0 = (x0, y0) and the first dot has position v1 = (x1, y1), then your "direction vector" is going to be v1 - v0 = (x1 - x0, y1 - y0). This is a vector that points along the blue line. Once you have that, you normalize it so that the length is 1, and then multiply it by your desired distance, in your case 50. If you want to do it component-wise, here's some quick pseudocode:
find_v2(x0, y0, x1, y1):
direction_x = x1 - x0
direction_y = y1 - y0
norm = sqrt(direction_x^2 + direction_y^2)
direction_x *= 50 / norm
direction_y *= 50 / norm
x2 = x1 + direction_x
y2 = y1 + direction_y
Hope that helps! I'm not sure how comfortable you are with vector math, but if you're doing graphics stuff, it can be really, really useful for problems like this; I'd recommend checking out some of the Khan Academy Linear Algebra courses.
The term you are looking for is extrapolation.
If the black dot is dot '0', then you first calculate your line equation's slope:
m = ( (d0.y-d1.y) / (d0.x-d1.x) )
Then you can extrapolate along that line, either positively (away from point 0) or negatively (towards it, until you get to it, and then eventually again away from in continuing in the line of motion).
dot2.x = d0.x + m*percentage
dot2.y = d0.y + m*percentage
Where percentage is how close you are to dot 1. Thus 1 (eg 100%) would put you on dot 1 exactly. percentage=0 would put you on dot 0 exactly. >1, would put you closer to dot 2. <1 would move you past dot 0, etc.
--
Slight correction there:
dot2.y = d0.x + m*percentage
dot2.x = (dot2.y - dot0.y) / m
The slope as i set it up is only useful for calculating the y coordinate of dot2. Since you already have the equation of the line, you can solve for dot2's x-coord directly using it.
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