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
Related
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.
When a GoogleMaps marker is rotated, I would like to move the anchor point of the InfoWindow to always be at the bottom, but offset by a larger amount than the size of the marker itself.
I made a drawing to describe my problem, but unfortunately I don't have enough reputation to upload an image.
Edit - this link hopefully works: https://i.stack.imgur.com/hM9nc.png
The code below works for Point B.
I want to move to Point C
This code (found in this answer) works well moving the anchor point to the top [0.5, 0]:
var angle = 130.0;
var x = Math.sin(-angle * Math.PI / 180) * 0.5 + 0.5;
var y = -(Math.cos(-angle * Math.PI / 180) * 0.5 - 0.5);
marker.setInfoWindowAnchor((float)x, (float)y);
However I have not been successful in adjusting it for a point located beyond the bottom, at [0.5,1.5].
I think this is because the x and the y offsets are different sizes.
NB Info Window anchor points can be beyond the 0,0 - 1,1 range, I'm just struggling to make the mathematical calculation
I have a virtual ruler being drawn on the screen. I want to be able to draw a straight line like the blue line above when touch event happen within the grown rectangle. but because touch can't be 100% straight, the movement might be like the red line. that's why I set a rectangle to listen to all the nearby touch events then draw a blue line.
I currently have
mRulerRect.set(mRulerCenter.x - mRulerBitmap.getWidth() / 2,
mRulerCenter.y - mRulerBitmap.getHeight()),
mRulerCenter.x + mRulerBitmap.getWidth() / 2,
mRulerCenter.y);
mPath.addRect(mRulerRect, Path.Direction.CCW);
mRulerMatrix.setRotate(mRulerAngle, mRulerCenter.x, mRulerCenter.y);
mPath.transform(mRulerMatrix);
mRegions.setPath(mPath, new Region(mRulerRect));
then I check if the touch even happen within brown rectangle by mRegions.contains(x,y). works perfect so far for touch detection, but the problem I have now is how to draw a straight line. I tried to fix X point then calculate Y. it works fine when ruler is horizontal then starts to behave very weird when turning from horizontal to vertical. I'm out of idea how to accomplish this. Please help! thank you.
Things that you know:
The center of that brown rect is mRulerCenter.x, mRulerCenter.y
The line that you want to draw pass through that point
The angle of the line is mRulerAngle
We're missing just one element, which is, the length of the line we want to draw. That's probably going to be a portion of the ruler's width and it should be very easy to compute mRulerRect.width() * someFactor
Now, we want to know what are the start and the end of the line, we can compute that with trigonometry functions
float halfLineLength = mRulerRect.width() * someFactor;
float startAngle = (float) Math.toRadians(mRulerAngle);
float endAngle = (float) Math.toRadians(mRulerAngle + 180);
float startX = mRulerCenter.x + (float) Math.cos(startAngle) * halfLineLength;
float startY = mRulerCenter.y + (float) Math.sin(startAngle) * halfLineLength;
float endX = mRulerCenter.x + (float) Math.cos(endAngle) * halfLineLength;
float endY = mRulerCenter.y + (float) Math.sin(endAngle) * halfLineLength;
and then draw your line from (startX, startY) to (endX, endY), actually doesn't really matter which is start and which is end
Can anyone point me in the right direction to find out how to write expressions for rotating a canvas in android studio. I'm making a watchface and I used part of the code from the provided sample but I need to understand what it means. Here's a part of the code:
float minuteRotation = time.minute/ 30f * (float) Math.PI
If this can be translated in dummy terms so I can understand how they arrive at those values.
if you look at the unit circle Math.PI is at one side and 0 is at the other side, say 0 is time.minute/30 = 0 * Math.PI = 0 or if 30 is time.minute/30 * Math.PI = 1 * Math.PI = Math.PI witch is the other side of the unit circle just like a watch
Your minuteRotation variable represents the ANGLE through which you will need to rotate the canvas in order to draw the minute hand in the right position.
According to the Android APIs this angle must be specified in Radians (not in Degrees), hence the use of the value "Math.PI".
PI radians represents HALF OF A COMPLETE ROTATION, i.e. 180 degrees - a half circle.
It is being used (in the expression that you described) merely as a SCALING FACTOR.
An alternative(and clearer,) way of writing the same equation would be :
minuteRotation = (time.minute/ 60.0f) * (float) Math.PI * 2.0f
This alternative version makes clearer the meaning of the various numbers:
- "60.0" is a floating point number that represents the maximum number of minutes possible(in a full rotation)
- "Math.PI * 2" radians is the angular equivalent of a FULL CIRCLE ROTATION (i.e. 360 degrees)
The fraction "time.minute/60.0" therefore represents the fraction of a full hour currently being used up.
Multiplying this by the expression PI*2 then yields the equivalent portion of a full circle expressed as an ANGLE (in Radians).
canvas.save();
canvas.rotate(45);
canvas.drawRect(166, 748, 314, 890, paint);
canvas.restore();
where 45 - is degrees
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)