I am trying to do some experiments with path. I have two points (x0,y0) and (x2,y2). Now I have to find a point (x1,y1) that should be some distance from the final point (x2,y2).
For example
Start Point (0,0) End Point (0,5)
Point i want to find is (0,2)
For a line between
The point at distance d from the first point, (positive) in the direction of the second point, is given by:
Where L is the distance between the two points defining the line:
(For your case just take L - d instead of d)
Imagine the two points define two rectangle triangles. The bigger triangle has sides with sizes x1, y1. the smaller has sides of sizes xt, yt.
1) Now apply Pythagoras' Theorem two calculate the bigger hypotenuse, h, using the equation h^2 = x1^2 + y1^2; (where h^2 means h power of two)
2) the difference ( h - the distance) is the hypotenuse of the smaller triangle. let's call it ht.
3) Calculate xt and yt as directly proportional to hypot bigger/hypot smaller.
x1/xt = h/ht
y1/yt = h/ht
/* I used user3235832 formula and write this code and its solve my problem.
Code in java.
sourcePoint(x,y);
destinationPoint(w,h);*/
//--------------------------------------------------------------------
double l = Math.sqrt(Math.pow((w - x), 2) + Math.pow((h - y), 2));
double d = l / 10;//you can use your own value for d.
int newX = (int) (w + (((x - w) / (l) * d)));
int newy = (int) (h + (((y - h) / (l) * d)));
//--------------------------------------------------------------------
/* if you use like me Graphic2D and use g2d.fillOval() function for draw a oval
on the line you need line slop. code for this: */
double m = Double.POSITIVE_INFINITY;//line slop
if (w - x != 0) {
m = (h - y) / (w - x);
}
int r = 6;//size of Oval
if (m == 0) {
g2d.fillOval(newX, (newy - (r/2)), r, r);
} else if (m == Double.POSITIVE_INFINITY) {
g2d.fillOval((newX - (r/2)), newy, r, r);
} else if (m < 0) {
g2d.fillOval((newX - (r/2)), (newy - (r/2)), r, r);
} else {
g2d.fillOval(newX, newy, r, r);
}
Related
I have the following Banach Fractal problem:
The so-called Banach Curve can be generated using the following fractal rule:
Draw a circle.
Draw 9 smaller circles, each with a radius ⅓ of the original
circle. One of the smaller circles should have the same center as that of the original circle. The centers of the remaining
8 smaller circles should be equally spaced along the circumference of the original circle.
Repeat step b with each of the smaller circles.
Note: The circle of radius r centered at point (x, y) is the set of all the points
(x + r · cos(t), y + r · sin(t)) where 0 ≤ t ≤ 2π , and t is given in radians. I can use Math.toRadians()
Guidelines:
Only recursive solutions, no loops allowed
No imports & no lists (so no map or so) & no ?
I can only use the functions public static void banachCurve(int n) and help functions private static void banachCurve(double x, double y, double r, int n)
Can only use StdDraw to draw or call other functions from it, no other Std classes are allowed
I thought of adding circles each time since there are supposed to be 9 at the edges and 1 in the center each time, however I can only seem to get the circles on the right or left, and for some reason a RuntimeError.
public static void banachCurve(int n) {
banachCurve (0.5,0.5,1,n);
}
private static void banachCurve(double x, double y, double r, int n) {
if (n == 0) {
return;
}
double d = (r/3);
StdDraw.circle (x,y,d);
// StdDraw.ellipse(x, y, r, r);
banachCurve (x + d, y, d, n - 1); // centre
banachCurve (x + d+ d, y+d, d, n--); // left
banachCurve (x , y + d, d, n--); // right
banachCurve (x+d , y +d+ d, d, n--);
banachCurve (x+d , y +d, d, n--);
}
my output:
stages of Banach Curve:
Every time you call n--, you are passing n to the function and then decrementing it by one for the next call. Instead, you need to pass n - 1 to each call, as the call itself will decrement n further in its own recursive call, eventually stopping at 0 as you correctly have.
For the four cardinal points, using (x + d, y), (x, y + d), (x - d, y) and (x, y - d) works correctly, but for the four diagonal points, you will need to use either the square root (Math.sqrt) for the Pythagoras method, or the sine and cosine (Math.sin and Math.cos) for the trigonometric method. Using (x + d, y + d) and the like would place them on a square instead.
Assuming that x and y mark the centre of your circle, your function will then become:
private static void banachCurve(final double x, final double y, final double r, final int n) {
if (n == 0) {
return;
}
final double d = r / 3;
StdDraw.circle (x, y, d);
banachCurve (x, y, d, n - 1); // centre
banachCurve (x, y + d, d, n - 1); // north
banachCurve (x + d, y, d, n - 1); // east
banachCurve (x, y - d, d, n - 1); // south
banachCurve (x - d, y, d, n - 1); // west
// Get the diagonal radius for a point at 45 degrees on the circle
final double diagD = Math.cos(Math.toRadians(45)) * d;
banachCurve (x + diagD, y + diagD, d, n - 1); // north-east
banachCurve (x + diagD, y - diagD, d, n - 1); // south-east
banachCurve (x - diagD, y - diagD, d, n - 1); // south-west
banachCurve (x - diagD, y + diagD, d, n - 1); // north-west
}
Here is the output for banachCurve(0.5, 0.5, 1, 6);:
If you're going to drag Math.cos() into the picture, a la the currenly accepted answer, why not go the whole hog and use sine and cosine to move around the circle:
private static void banachCurve(double x, double y, double r, int n) {
if (n == 0) {
return;
}
double d = r / 3;
StdDraw.circle (x, y, d);
banachCurve (x, y, d, n - 1); // center
for (double angle = 0; angle < 360; angle += 45) {
double theta = Math.toRadians(angle);
double dx = x + d * Math.cos(theta);
double dy = y + d * Math.sin(theta);
banachCurve (dx, dy, d, n - 1);
}
}
Output for banachCurve(0.5, 0.5, 1, 3);
This approach makes easy work of testing out #tucuxi's suggestion, of six instead of eight surrounding circles. Just increase the increment angle in the for loop from 45 to 60:
Though I can't say its an improvement over the original design. Though seven surrounding circles, again trivial to test given this code design, catches one's eye:
I'm trying to check if triangle2D is contain another triangle or overlapping it.
I can do that with circle e.g:
/** Return true if the specified point
* (x, y) is inside this circle */
public boolean contains(double x, double y) {
return Math.sqrt(Math.pow(x - this.x, 2) +
Math.pow(y - this.y, 2))
< radius;
}
/** Return true if the specified
* circle is inside this circle */
public boolean contains(Circle2D circle) {
return Math.sqrt(Math.pow(circle.getX() - x, 2) +
Math.pow(circle.getY() - y, 2))
<= Math.abs(radius - circle.getRadius());
}
/** Return true if the specified
* circle overlaps with this circle */
public boolean overlaps(Circle2D circle) {
return Math.sqrt(Math.pow(circle.getX() - x, 2) +
Math.pow(circle.getY() - y, 2))
<= radius + circle.getRadius();
}
But I don't know how to do that with triangle.
I've found this question for point only, but I don't how to do that if triangle contain other triangle or overlapping it.
You can use Line2D#contains, Line2D#linesIntersect methods inside java.awt.geom.Line2D.
Edit:
Thinking in Math:
To detect whether a point is inside a triangle, draw three dashed lines, if the point is inside a triangle, each dashed line should intersect a side only once. if a dashed line intersect a side twice, then the point must be outside the triangle.
So We can use the way in the other question (you mentioned) like below:
public boolean contains(MyPoint p) {
// double area1 = calcArea(p, p1, p2);
// double area2 = calcArea(p, p2, p3);
// double area3 = calcArea(p, p3, p1);
// double area = Math.round((area1 + area2 + area3) * 100) / 100;
// double triangleArea = Math.round(getArea() * 100) / 100;
// return (triangleArea == area)
}
But it's not efficient way, so we will implement it as below, in order to reuse it with other cases.
We should have three methods one for check max x, y, one for checking min x, y and other for checking the lineSegment.
The lineSegment would be look like:
double position = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
return position <= 0.0000000001 && ((x0 <= x2 && x2 <= x1) || (x0 >= x2 && x2 >= x1));
/**
* returns true if the specified point is inside this triangle
**/
public boolean contains(MyPoint p) {
return contains(p.getX(), p.getY());
}
public boolean contains(double x, double y) {
// Get max X & Y
double maxX = getMax(p1.getX(), p2.getY(), p3.getX());
double maxY = getMax(p1.getY(), p2.getY(), p3.getX());
// Get min X & Y
double minX = getMin(p1.getX(), p2.getX(), p3.getX());
double minY = getMin(p1.getY(), p2.getY(), p3.getY());
// Outside the bounding rectangle of the triangle
if (x < minX || x > maxX || y < minY || y > maxY) return false;
// Check if point is the border of the triangle
MyPoint p = new MyPoint(x, y);
boolean side1 = p.onTheLineSegment(p1, p2); //assume A to B
boolean side2 = p.onTheLineSegment(p1, p3); //assume B to C
boolean side3 = p.onTheLineSegment(p2, p3); //assume C to A
return side1 || side2 || side3; //return true if any point of these vertices inside triangle.
}
So to check if triangle contain other one, our method would be look like:
public boolean contains(Triangle t) {
return contains(t.p1) && contains(t.p2) && contains(t.p3); //All three points is inside the triangle
}
Or simply by using Line2D class as I mention above:
Line2D line2D = new Line2D.Double(p1.getX(), p1.getY(), p2.getX(), p2.getY());
return line2D.contains(....); //check if contain triangle or point
For the case of containing you can check all vertices of a triangle. If all of them are existed inner of the other, one of them contains the other one.
For the case of overlapping, You should consider is there any intersection between any edge of these two triangle or not. If there is not and the containing case was not happened, they are separated. For the case of intersecting two edges (as two segments) on the plane, you can using this post.
Use the LeftOf predicate, which is true when the algebraic area of the triangle ABC is positive (using the appropriate sign convention), telling you that C is on the left of the line AB.
Then check if all three vertices of the first triangle lie left of some side of the second one. If not, repeat after exchanging the two triangles.
Finally if yes, the triangles do not interfere.
I'm attempting to implement a curve interesection algorithm known as bezier clipping, which is described in a section towards the end of this article (though the article calls it "fat line clipping"). I've been following through the article and source code of the example (available here).
Note: Additional sources include this paper. More will be posted if I can find them.
A central part of this algorithm is calculating a "distance function" between curve1 and a "baseline" of curve2 (which is a line from one end point of curve2 to another). So I'd have something to compare my results to, I used the curves from the source code of the first example. I managed to replicate the shape of the distance function from the example, but the distance location of the function was off. Upon trying another curve, the distance function was nowhere near the other two curves, despite both clearly intersecting. I might be naive to the workings of this algorithm, but I think that would result in no intersection being detected.
From what I understand (which could quite possibly be wrong), the process of defining the distance function involves expressing the baseline of curve 2 in the form xa + yb + c = 0, where a2 + b2 = 1. The coefficients were obtained by rearranging the terms of the line in the form y = ux + v, where u is equal to the slope, and x and y are any points on the baseline. The formula can be rearranged to give v: v = y - ux. Rearranging the formula again, we obtain -u*x + 1*y - v = 0, where a = -u, b = 1, and c = -v. To assure the condition a2 + b2 = 1, the coefficients are divided by a scalar of Math.sqrt(uu + 1). This representation of the line is then substituted into the function of the other curve (the one the baseline isn't associated with) to get the distance function. This distance function is represented as a bezier curve, with yi = aPi x + b*Pi y + c and xi = (1 - t)x1 + tx2, where t is equal to 0, 1/3, 2/3, and 3m x1 and x2 are the endpoints of the baseline, and Pi are the control points of the curve1.
Below are a few cuts of the source code of the example program (written in the language processing) involved with calculating the distance function, which, oddly, uses a slightly different approach to the above paragraph for calculating the alternative representation of the baseline.
/**
* Set up four points, to form a cubic curve, and a static curve that is used for intersection checks
*/
void setupPoints()
{
points = new Point[4];
points[0] = new Point(85,30);
points[1] = new Point(180,50);
points[2] = new Point(30,155);
points[3] = new Point(130,160);
curve = new Bezier3(175,25, 55,40, 140,140, 85,210);
curve.setShowControlPoints(false);
}
...
flcurve = new Bezier3(points[0].getX(), points[0].getY(),
points[1].getX(), points[1].getY(),
points[2].getX(), points[2].getY(),
points[3].getX(), points[3].getY());
...
void drawClipping()
{
double[] bounds = flcurve.getBoundingBox();
// get the distances from C1's baseline to the two other lines
Point p0 = flcurve.points[0];
// offset distances from baseline
double dx = p0.x - bounds[0];
double dy = p0.y - bounds[1];
double d1 = sqrt(dx*dx+dy*dy);
dx = p0.x - bounds[2];
dy = p0.y - bounds[3];
double d2 = sqrt(dx*dx+dy*dy);
...
double a, b, c;
a = dy / dx;
b = -1;
c = -(a * flcurve.points[0].x - flcurve.points[0].y);
// normalize so that a² + b² = 1
double scale = sqrt(a*a+b*b);
a /= scale; b /= scale; c /= scale;
// set up the coefficients for the Bernstein polynomial that
// describes the distance from curve 2 to curve 1's baseline
double[] coeff = new double[4];
for(int i=0; i<4; i++) { coeff[i] = a*curve.points[i].x + b*curve.points[i].y + c; }
double[] vals = new double[4];
for(int i=0; i<4; i++) { vals[i] = computeCubicBaseValue(i*(1/3), coeff[0], coeff[1], coeff[2], coeff[3]); }
translate(0,100);
...
// draw the distance Bezier function
double range = 200;
for(float t = 0; t<1.0; t+=1.0/range) {
double y = computeCubicBaseValue(t, coeff[0], coeff[1], coeff[2], coeff[3]);
params.drawPoint(t*range, y, 0,0,0,255); }
...
translate(0,-100);
}
...
/**
* compute the value for the cubic bezier function at time=t
*/
double computeCubicBaseValue(double t, double a, double b, double c, double d) {
double mt = 1-t;
return mt*mt*mt*a + 3*mt*mt*t*b + 3*mt*t*t*c + t*t*t*d; }
And here is the class (an extension of javax.swing.JPanel) I wrote to recreate the above code:
package bezierclippingdemo2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class ReplicateBezierClippingPanel extends JPanel {
CubicCurveExtended curve1, curve2;
public ReplicateBezierClippingPanel(CubicCurveExtended curve1, CubicCurveExtended curve2) {
this.curve1 = curve1;
this.curve2 = curve2;
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.black);
drawCurve1(g2d);
drawCurve2(g2d);
drawDistanceFunction(g2d);
}
public void drawCurve1(Graphics2D g2d) {
double range = 200;
double t = 0;
double prevx = curve1.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrlx1*(1 - t)*(1 - t)*t + 3*curve1.ctrlx2*(1 - t)*t*t + curve1.x2*t*t*t;
double prevy = curve1.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrly1*(1 - t)*(1 - t)*t + 3*curve1.ctrly2*(1 - t)*t*t + curve1.y2*t*t*t;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = curve1.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrlx1*(1 - t)*(1 - t)*t + 3*curve1.ctrlx2*(1 - t)*t*t + curve1.x2*t*t*t;
double y = curve1.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve1.ctrly1*(1 - t)*(1 - t)*t + 3*curve1.ctrly2*(1 - t)*t*t + curve1.y2*t*t*t;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
public void drawCurve2(Graphics2D g2d) {
double range = 200;
double t = 0;
double prevx = curve2.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrlx1*(1 - t)*(1 - t)*t + 3*curve2.ctrlx2*(1 - t)*t*t + curve2.x2*t*t*t;
double prevy = curve2.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrly1*(1 - t)*(1 - t)*t + 3*curve2.ctrly2*(1 - t)*t*t + curve2.y2*t*t*t;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = curve2.x1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrlx1*(1 - t)*(1 - t)*t + 3*curve2.ctrlx2*(1 - t)*t*t + curve2.x2*t*t*t;
double y = curve2.y1*(1 - t)*(1 - t)*(1 - t) + 3*curve2.ctrly1*(1 - t)*(1 - t)*t + 3*curve2.ctrly2*(1 - t)*t*t + curve2.y2*t*t*t;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
public void drawDistanceFunction(Graphics2D g2d) {
double a = (curve1.y2 - curve1.y1)/(curve1.x2 - curve1.x1);
double b = -1;
double c = -(a*curve1.x1 - curve1.y1);
double scale = Math.sqrt(a*a + b*b);
a /= scale;
b /= scale;
c /= scale;
double y1 = a*curve2.x1 + b*curve2.y1 + c;
double y2 = a*curve2.ctrlx1 + b*curve2.ctrly1 + c;
double y3 = a*curve2.ctrlx1 + b*curve2.ctrly2 + c;
double y4 = a*curve2.x2 + b*curve2.y2 + c;
double range = 200;
double t = 0;
double prevx = t*range;
double prevy = (1 - t)*(1 - t)*(1 - t)*y1 + 3*(1 - t)*(1 - t)*t*y2 + 3*(1 - t)*t*t*y3 + t*t*t*y4;
for(t += 1.0/range; t < 1.0; t += 1.0/range) {
double x = t*range;
double y = (1 - t)*(1 - t)*(1 - t)*y1 + 3*(1 - t)*(1 - t)*t*y2 + 3*(1 - t)*t*t*y3 + t*t*t*y4;
g2d.draw(new LineExtended(prevx, prevy, x, y));
prevx = x;
prevy = y;
}
}
}
Where CubicCurveExtended and LineExtended are minor extensions of java.awt.geom.CubicCurve2D.Double and java.awt.geom.Line2D.Double. Before the curves are passed into the constructor, the curves are rotated uniformly so curve1's endpoints are level, resulting in a slope of zero for the baseline.
For an input of (485, 430, 580, 60, 430, 115, 530, 160) for curve 1 and (575, 25, 455, 60, 541, 140, 486, 210) for curve2 (keep in mind that these values are rotated by the negative angle between the endpoints of curve1), the result is shown below (the distance function is the relatively smooth looking curve off in the distance):
I'm really not sure what I got wrong. The y values seem to be arranged in the right pattern, but are distant from the two curves it's based on. I realize it's possible I have the x values might be arranged at intervals along the curve rather than the baseline, but the y values are what I'm really confused about. If someone can take a look at this and explain what I got wrong, I'd really appreciate it. Thanks for taking the time to read this rather lengthy question. If more details are needed, feel free to tell me in comments.
Update: I've tested the representation of the line I've calculated. The ax + by + c = 0 representation apparently still represents the same line, as I can still plug in x1 and get y1. Additionally, for any two coordinate pairs plugged into the function, f(x, y) = 0 holds. Furthermore, I've found both the representation described in the article and the one actually used in the source code interchangeably represent the same line. From all this, I can assume the problem doesn't lie in calculating the line. An additional point of interest
Your distance function should not necessarily be anywhere near your two original curves: It's using a completely different coordinate system, i.e. t vs D, as opposed to your original curves using x and y. [edit] i.e. t only goes up to 1.0, and measures how far along, as a ratio of the total length, you are along your curve, and D measuring the distance your curve2 is from curve1's baseline.
Also, when you say ""distance function" between curve1 and a "baseline" of curve2" I think you've mixed up curve1 and curve2 here as in your code you are clearly using the baseline of curve1.
Also the algorithm assumes that "every Bézier curve is fully contained by the polygon that connects all the start/control/end points, known as its "convex hull"" which [edit] in your case for curve1 is a triangle, where the control point for the second starting value is not a vertex. I'm not sure how this affects the algorithm though.
Otherwise, it looks like your distance calculations are fine (although you could really do with optimising things a bit :) ).
I am trying to write a simple proof of concept app that allows a user to rotate minute hand of a clock. I am having hard time coming up with the right logic for OnTouchEvent.
So far I have the following code:
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
//find an approximate angle between them.
float dx = x-cx;
float dy = y-cy;
double a=Math.atan2(dy,dx);
this.degree = Math.toDegrees(a);
this.invalidate();
}
return true;
}
protected void onDraw(Canvas canvas) {
super .onDraw(canvas);
boolean changed = mChanged;
if (changed) {
mChanged = false;
}
int availableWidth = getRight() - getLeft();
int availableHeight = getBottom() - getTop();
int x = availableWidth / 2;
int y = availableHeight / 2;
cx = x;
cy = y;
final Drawable dial = mDial;
int w = dial.getIntrinsicWidth() + 100;
int h = dial.getIntrinsicHeight() + 100;
boolean scaled = false;
if (availableWidth < w || availableHeight < h) {
scaled = true;
float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h);
canvas.save();
canvas.scale(scale, scale, x, y);
}
if (changed)
{
dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
dial.draw(canvas);
canvas.save();
float hour = mHour / 12.0f * 360.0f;
canvas.rotate(hour, x, y);
final Drawable hourHand = mHourHand;
if (changed) {
w = hourHand.getIntrinsicWidth() + 30;
h = hourHand.getIntrinsicHeight() + 30;
hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
}
hourHand.draw(canvas);
canvas.restore();
canvas.save();
float minute = mMinutes / 60.0f * 360.0f;
if (bearing == 0)
{
canvas.rotate(minute, x, y);
}
else
{
canvas.rotate((float)bearing, x, y);
}
final Drawable minuteHand = mMinuteHand;
if (changed) {
w = minuteHand.getIntrinsicWidth() + 30;
h = minuteHand.getIntrinsicHeight() + 30;
minuteHand.setBounds(x - w, y - h, x + w, y + h);
}
minuteHand.draw(canvas);
canvas.restore();
if (scaled) {
canvas.restore();
}
}
Then based on that, my OnDraw method rotates the minute hand to the specified "this.degree"(just calls canvas.rotate). I am assuming my math is off here. I tried to follow the example here: Calculate angle for rotation in Pie Chart, but that's still not rotating the minute hand correctly. Any help would be appreciated.
The math looks correct. Your calculations should give you the angle of the touch event, where a touch that is to the exact right of the center point should give you 0 degrees.
A few things to watch out for
Make sure that you're rotating in the correct direction. It is hard to keep this straight, and thus easy to screw it up
Make sure that you're taking into account that a value of 0 means that the minute hand should be pointing to the right. For example, if you start out with a minute hand that is pointing upwards, you would have to add/subtract 90 degrees to the result of your calculation (depending on the direction of rotation - not sure which is correct offhand)
Make sure that (cx, cy) is the center point around which you want to calculate the angle
When rotating, you'll need to either use the 3 arg Canvas.rotate(float, float, float) method, or add an additional translation seperately, to make sure that you are rotating around the correct point. Without any translation, it will rotate around (0,0) (the top left corner of the view)
More on rotation:
Rotation always happens around the "current" (0,0) point. By "current", I mean the (0,0) point after the current matrix has been applied. When you first enter onDraw, the (0,0) point should be the upper-left corner of the view. Whenever you apply a translation/scaling/etc, you will potentially change where the (0,0) point is, relative to the view.
I think something like the following should work, in regards to setting the correct center of rotation:
//first we save the initial matrix, so we can easily get
//back to this state after we're done rotating
canvas.save();
//I *think* you need to negate the center offsets here,
//because you are conceptually moving the canvas, rather
//than moving the center directly
canvas.translate(-cx, -cy);
//<perform the rotation and draw the clock hand>
//...
//and now restore the matrix back to the initial state
canvas.restore();
Your calculation is good for measuring angle for minutes hand to
rotate in corresponding quadrants in analog clock... here with little
bit changes can make either minutes or hours hand to rotate at the
touch position....call the below method in onTouch() method for action move
public float getRotationAngle(float x, float y) {
float dx = x - cx;
float dy = y - cy;
double a = Math.atan2(dy, dx);
double degree = Math.toDegrees(a)+90;
if(angle<0){
degree=degree+360;
}
return (float) degree;
}
i have this approach with as vectors concept for calculating the angle but if little bit more than your code if u want i will give that logic....
I'm trying to move a sprite across the screen in a straight line, towards on the location where've I touched the screen, what i did was upon the update() in each loop , it checks to see if the current sprite's location x y is == to the destination x ,y . if it hasn't sprite's x++ and y++...
the thing is ..it ain't moving in a straight line... as there are cases where the x or y coordinate reaches the destination x or y first... how do i changed it so that the both x and y meets the destination together?
my current pseudo code for the sprite object
destX = destination X
destY = destination Y
posX = current X
posY = current Y
public void update(){
if(destX > posX && destY < posY)
{
posX++;
posY--;
}
else if (destX > posX && destY > posY){
posX++;
posY++;
}
else if(destX < posX && destY > posY)
{
posX--;
posY++;
}
else if(destX < posX && destY < posY){
posX--;
posY--;
}
else if(destX < posX)
posX--;
else if(destX > posX)
posX++;
else if(destY < posY)
posY--;
else if(destY > posY)
posY++;
Check out: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
This simple algorithm will tell you each X,Y coordinate on a line between two points. You could use this algorithm to compute all of the positions it needs to visit, store the coordinates in an array, and iterate over the array as you update the position.
From the Article:
function line(x0, x1, y0, y1)
int deltax := x1 - x0
int deltay := y1 - y0
real error := 0
real deltaerr := abs (deltay / deltax) // Assume deltax != 0 (line is not vertical),
// note that this division needs to be done in a way that preserves the fractional part
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0
This is the most primitive version. The article contains a better generalized algorithm that you should look at.
I am dealing with a similair problem as yours. (I have an arraylist holding the history of positions my player has gone and I want to use that to rewind the game.)
Instead of simply increasing x and y position with 1 you can:
Calculate the angle between the source postion and your destination
position.
Calculate the new direction using a variable which
represents the speed
Update your postion using calculated direction
I made a class of that. I hope it is usefull.
import java.awt.geom.Point2D;
public class MyVelocityCalculator {
public static void main(String[] args) {
Point2D.Double currentPosition = new Point2D.Double();
Point2D.Double destinationPosition = new Point2D.Double();
currentPosition.setLocation(100, 100);
destinationPosition.setLocation(50, 50);
Double speed = 0.5;
Point2D.Double nextPosition = MyVelocityCalculator.getVelocity(currentPosition, destinationPosition, speed);
System.out.println("player was initially at: "+currentPosition);
System.out.println("player destination is at: "+destinationPosition);
System.out.println("half seconds later player should be at: "+nextPosition);
}
public static final Point2D.Double getVelocity(Point2D.Double currentPosition, Point2D.Double destinationPosition, double speed){
Point2D.Double nextPosition = new Point2D.Double();
double angle = calcAngleBetweenPoints(currentPosition, destinationPosition);
double distance = speed;
Point2D.Double velocityPoint = getVelocity(angle, distance);
nextPosition.x = currentPosition.x + velocityPoint.x;
nextPosition.y = currentPosition.y + velocityPoint.y;
return nextPosition;
}
public static final double calcAngleBetweenPoints(Point2D.Double p1, Point2D.Double p2)
{
return Math.toDegrees( Math.atan2( p2.getY()-p1.getY(), p2.getX()-p1.getX() ) );
}
public static final Point2D.Double getVelocity(double angle, double speed){
double x = Math.cos(Math.toRadians(angle))*speed;
double y = Math.sin(Math.toRadians(angle))*speed;
return (new Point2D.Double(x, y));
}
}
Don't use integers. This is a very bad idea to work with ints. Use floats. The main concept is: define the number of steps you want to perform (s). Compute differences in X and Y (diffX and diffY). Don't take absolute values: Compute them this way
float diffX = destX - currentX;
Then compute the xMove and yMove values by dividing diffX and diffY by s (number of steps).
float moveX = diffX / s;
float moveY = diffY / s;
And now you have to add for each iteration the moveX and moveY values to the current position.
And for drawing it, you should use Graphics2D, which supports floating points. If you don't want to use Graphics2D, you can round the floats to ints, using Math.round(float).