There is a mouseMove()method that makes the pointer jump to that location. I want to be able to make the mouse move smoothly throughout the screen. I need to write a method named mouseGLide() which takes a start x, start y, end x, end y, the total time the gliding should take, and the number of steps to make during the glide. It should animate the mouse pointer by moving from (start x, start y) to (end x, start y) in n steps. The total glide should take t milliseconds.
I don't know how to get started can anyone help me get started on this? Can anyone just tell me what steps I need to do in order to make this problem work.
To start off, let's just write out an empty method where the parameters are as you defined in your question.
public void mouseGlide(int x1, int y1, int x2, int y2, int t, int n) {
}
Next, let's create a Robot object and also calculate 3 pieces of information that'll help your future calculations. Don't forget to catch the exception from instantiating Robot.
Robot r = new Robot();
double dx = (x2 - x1) / ((double) n);
double dy = (y2 - y1) / ((double) n);
double dt = t / ((double) n);
dx represents the difference in your mouse's x coordinate everytime it moves while gliding. Basically it's the total move distance divided into n steps. Same thing with dy except with the y coordinate. dt is the total glide time divided into n steps.
Finally, construct a loop that executes n times, each time moving the mouse closer to the final location (taking steps of (dx, dy)). Make the thread sleep for dt milliseconds during each execution. The larger your n is, the smoother the glide will look.
Final result:
public void mouseGlide(int x1, int y1, int x2, int y2, int t, int n) {
try {
Robot r = new Robot();
double dx = (x2 - x1) / ((double) n);
double dy = (y2 - y1) / ((double) n);
double dt = t / ((double) n);
for (int step = 1; step <= n; step++) {
Thread.sleep((int) dt);
r.mouseMove((int) (x1 + dx * step), (int) (y1 + dy * step));
}
} catch (AWTException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
For all those who have been struggling with the programming as I did before, this is how you implement this method and use it correctly:
public class gliding_the_mouse {
public void mouseGlide(int x1, int y1, int x2, int y2, int t, int n) {
try {
Robot r = new Robot();
double dx = (x2 - x1) / ((double) n);
double dy = (y2 - y1) / ((double) n);
double dt = t / ((double) n);
for (int step = 1; step <= n; step++) {
Thread.sleep((int) dt);
r.mouseMove((int) (x1 + dx * step), (int) (y1 + dy * step));
}
} catch (AWTException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main (String[] args) { // program initialization
gliding_the_mouse x = new gliding_the_mouse(); // we declare what are we are going to use
x.mouseGlide(400,500,700,700,5000,10000); // the smaller the time value, the faster the mouse glides.
}
}
Using no. of steps may not be ideal in every situation. Below is the code which moves the mouse by some given pixel amount.
The idea of this logic, is we provide the start point and end point and:
we get the straight line equation for the two points
we identify the points (pixel jump) along the line
we move the mouse to each idenfied point on the line using a very minimal delay to replicate the general mouse movement.
/**
* Moves mouse from (x1,y1) to (x2, y2).
*
* #param x1 initial x
* #param y1 initial y
* #param x2 x
* #param y2 y
*/
private static void moveTo(final int x1, final int y1, final int x2, final int y2) {
int pixelJump = 10;
final double xSqu = (x2 - x1) * (x2 - x1);
final double ySqu = (y2 - y1) * (y2 - y1);
final double lineLength = Math.sqrt(xSqu + ySqu);
double dt = 0;
while (dt < lineLength) {
dt += pixelJump;
final double t = dt / lineLength;
final int dx = (int) ((1 - t) * x1 + t * x2);
final int dy = (int) ((1 - t) * y1 + t * y2);
r.mouseMove(dx, dy);
r.delay(1); // Increase this number if you need to delay the mouse movement
}
r.mouseMove(x2, y2);
}
Related
regarding the following code, can I make it better for distance() method?
It feels like it's not completely OOP with this method.. how can I change code to be better OOD for this one ?
Thanks !!
public class Line extends Shape {
private Point lineP1;
private Point lineP2;
public Line(int x1, int x2, int y1, int y2, Color myColor) {
super(x1, x2, y1, y2, myColor);
lineP1 = new Point(this.getX1(),this.getY1());
lineP2 = new Point(this.getX2(),this.getY2());
}
#Override
public void draw(Graphics g) {
g.drawLine(this.getX1(), this.getY1(), this.getX2(), this.getY2());
g.setColor(Color.GREEN);
}
#Override
public boolean contains(Point p) {
if((this.distance(lineP1, p)+this.distance(lineP2, p)) == this.distance(lineP1, lineP2))
return true;
return false;
}
/**#return distance between two given points
* This method return the distance between two given points*/
private double distance(Point p1,Point p2 ){
return Math.sqrt(Math.pow((p1.getX()-p2.getX()), 2) + Math.pow((p1.getY()-p2.getY()), 2));
}
}//class Line
Your distance method seems to be ok (but it would be more performant, if you saved the differences in variables and used the * operator to multiply those values with themselfs instear of using Math.pow).
However, since floating point calculations tend to return inexact results, I don't recomend using the sum of the distances between the end node and the point to test as criterium.
But there's another good way determining, if a point is near a line or not: using the hesse normal form. It works like this:
Let P1 and P2 be vectors corresponing to the end points. * denotes the scalar multiplication and || the length of a vector:
D = (P2 - P1) / |P2 - P1|;
Let N be the vector D with coordinates swaped and the new x coordinate multiplied with -1 (i.e. a vector ortogonal to D).
Then the distance of a point H to the line can be determined like this
| N * H - N * P1 |
Also if H is between P1 and P2 can be checked like this (assuming without loss of generality D * P1 < D * P2):
D * P1 <= D * H <= D * P2
Using scalar products has the additional benefit, that calculating a scalar product only takes 2 multiplication and 1 addition in a 2D space.
This is how you could do this in java code
// components of normal vector
private double normalX;
private double normalY;
// components of direction vector
private double directionX;
private double directionY;
// the value of (N * P) for all points P on the line
private double normalScalarProduct;
// the range allowed for (D * P) for points on the line
private double minDirectionScalarProduct;
private double maxDirectionScalarProduct;
// error ranges; adjust as appropriate
private static final double directionAllowedError = 0.1;
private static final double normalAllowedError = 0.1;
public Line(int x1, int x2, int y1, int y2, Color myColor) {
...
double dx = x2 - x1;
double dy = y2 - y1;
double length = distance(dx, dy);
if (length == 0) {
// choose arbitrary direction, if length == 0
length = 1;
dx = 1;
}
// normalize direction
dx /= length;
dy /= length;
// set D and N values
this.directionX = dx;
this.directionY = dy;
this.normalX = -dy;
this.normalY = dx;
double prod1 = scalarProduct(directionX, directionY, x1, y1);
double prod2 = scalarProduct(directionX, directionY, x2, y2);
if (prod1 < prod2) {
minDirectionScalarProduct = prod1 - directionAllowedError;
maxDirectionScalarProduct = prod2 + directionAllowedError;
} else {
minDirectionScalarProduct = prod2 - directionAllowedError;
maxDirectionScalarProduct = prod1 + directionAllowedError;
}
normalScalarProduct = scalarProduct(x1, y1, normalX, normalY);
}
private static double scalarProduct(double x1, double y1, double x2, double y2) {
return x1*x2 + y1*y2;
}
public boolean contains(Point p) {
if (Math.abs(scalarProduct(p.getX(), p.getX(), normalX, normalY) - normalScalarProduct) <= normalAllowedError) {
// close enough to the line -> check, if between end points
double d = scalarProduct(p.getX(), p.getX(), directionX, directionY);
return minDirectionScalarProduct <= d && d <= maxDirectionScalarProduct;
}
return false;
}
private double distance(double dx, double dy) {
return Math.sqrt(dx*dx + dy*dy);
}
So I finished up a program that recursively draws lines which takes an argument "n" to define the depth of the recursion. I have 2 functions, one which draws the relatively left line and another which draws the relatively right one. I tested it ant it seems to work for the first 4 levels, but then either the lines become too small to accurately represent or there's something wrong with my code because the breaks between the lines seem to become arbitrary. Was hoping somebody could test my code and see if they could find what the problem is.
The following image is of depth 10.
EDIT: fixed a part of code, still need help though
public class Art
{
//draws the relatively left line
public static void drawLeftLine(double x0, double y0, double x1, double y1)
{
//define new x coordinate for line
//double x2 = (1/3.0)*(x1 - x0);
//color of line
StdDraw.setPenColor(StdDraw.BLUE);
//draw line by adding new x coord to original
StdDraw.line(x0, y0, x1, y1);
}
//draw relatively right line
public static void drawRightLine(double x0, double y0, double x1, double y1)
{
//define new x coord for line
//double x2 = (2/3.0)*(x1 - x0);
//color of line
StdDraw.setPenColor(StdDraw.BLUE);
//draw line by adding new x coord to original
StdDraw.line(x0, y0, x1, y1);
}
public static void cantor(int n, double x0, double y0, double x1, double y1)
{
if (n == 0)
return;
drawLeftLine(x0, y0, x1, y1);
drawRightLine(x0, y0, x1, y1);
y0 = y0 - 0.1;
y1 = y1 - 0.1;
cantor(n-1, x0, y0, x0 + ((x1 - x0))/3.0, y1); //left
cantor(n-1, (2.0/ 3) * (x1 - x0) + x0, y0, x1, y1); //right
}
public static void main(String[] args)
{
//change n into integer (depth)
int n = Integer.parseInt(args[0]);
//specify inital values for line
double x0 = 0;
double y0 = 0.9;
double x1 = 0.9;
double y1 = 0.9;
//recursive function cantor
cantor(n, x0, y0, x1, y1);
}
}
I think that the drawing looks incorrect because the of the fact that all of the nice double values are being approximated with discrete pixels causing unwanted overlap between the line segments (see EDIT at the bottom). Some comments about your code however :
1) You don't need the drawLeftLine and drawRightLine methods since currently they are drawing exactly the same thing. Since at each step you are calling cantor twice (once for each side of the deleted inner third), you have one call to cantor for each line segment that has to be drawn. As such I would put all of the drawing directly into the cantor method.
2) Since y0 and y1 are both always the same, I would reduce them to just a single y variable.
3) I would simplify the math for computing the new x0 and x1 values down to
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
4) Instead of decrementing the y value by 0.1 every time, you should have a global variable that decides the amount by which this should be decremented (otherwise if you try n > 10 things will break). This value can just be set to 1.0 / n.
5) You don't need to set the color of the pen every time you paint. You can set it just once in the main method.
6) StdDraw already sets a border around the picture you are drawing so there is no need to start your coordinates from 0.9 - you can use 1 instead.
Following these suggestions the code would look like this :
private static double yIncrement;
public static void cantor(int n, double x0, double x1, double y) {
if (n == 0)
return;
StdDraw.line(x0, y, x1, y);
y = y - yIncrement;
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
}
public static void main(String[] args) {
//change n into integer (depth)
int n = Integer.parseInt(args[0]);
// specify inital values for line
double x0 = 0;
double x1 = 1;
double y = 1;
yIncrement = 1.0 / n;
StdDraw.setPenColor(Color.BLUE);
// recursive function cantor
cantor(n, x0, x1, y);
}
EDIT : Playing around with the StdDraw canvas size, canvas scaling settings, and line segment endpoint rounding mode you can get a slightly better picture (the code below produces a picture that looks mostly correct down to the 8th level)
private static double yIncrement;
public static void cantor(int n, double x0, double x1, double y) {
if (n == 0)
return;
x0 = Math.ceil(x0);
x1 = Math.floor(x1);
StdDraw.line(x0, y, x1, y);
y = y - yIncrement;
double third = (x1 - x0) / 3;
cantor(n - 1, x0, x0 + third, y); // left
cantor(n - 1, x1 - third, x1, y); // right
}
public static void main(String[] args) {
// change n into integer (depth)
int n = Integer.parseInt(args[0]);
int width = 1920;
int height = 1080;
StdDraw.setCanvasSize(width, height);
// specify inital values for line
double x0 = 0;
double x1 = width;
double y = 1;
yIncrement = 1.0 / n;
StdDraw.setPenColor(Color.BLUE);
StdDraw.setXscale(0, width);
// recursive function cantor
cantor(n, x0, x1, y);
}
To display everything down to the tenth level with absolute correctness you would need a width of 3^9 pixels (19K pixels). For level 9 that's 3^8 = 6K. For level 8 that's 3^7 = 2k, which is why it looks almost correct with 1.9K pixel width and integer rounding.
I am aware that there are a few questions about points and rotation out here, and I feel like Im almost there. I youst need a little push.
I Have a shape with 6 points like this one.
I want to rotate the Point P around Point C
And I need to do this manually so I am not interested in using AffineTransform
thanks in advance
Thread thread = new Thread() {
public void run() {
//THE RADIUS OF THE SHAPE IS 100
//GET THE POINT P
PointClass point_class = points.get(0);
//GET THE CENTER POINT C
Point center = new Point(point_class.point.x - 100, point_class.point.y);
int deg = 0;
while(deg < 360) {
//GET THE ANGLE IN RADIANS
double angle = Math.toRadians(deg);
//FIRST TRANSLATE THE DIFFERENCE
int x1 = point_class.point.x - center.x;
int y1 = point_class.point.y - center.y;
//APPLY ROTATION
x1 = (int) ((double) x1 * Math.cos(angle) - y1 * Math.sin(angle));
y1 = (int) ((double) x1 * Math.sin(angle) + y1 * Math.cos(angle));
//TRANSLATE BACK
point_class.point.x = x1 + center.x;
point_class.point.y = y1 + center.y;
//ROTATE + 1 DEEGRE NEXT TIME
deg++;
try {
//SLEEP TO SEE THE DIFFERENCE
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
thread.start();
What happens with this code is that the Point P ends up in the center like this
I think your radius is shrinking each time through the while loop due to the casting of doubles to ints. This might work better instead:
double x1 = point_class.point.x - center.x;
double y1 = point_class.point.y - center.y;
//APPLY ROTATION
x1 = x1 * Math.cos(angle) - y1 * Math.sin(angle));
y1 = x1 * Math.sin(angle) + y1 * Math.cos(angle));
//TRANSLATE BACK
point_class.point.x = (int)Math.ceil(x1) + center.x;
point_class.point.y = (int)Math.ceil(y1) + center.y;
So I figured out what was wrong.
The Translation of the two points,
//FIRST TRANSLATE THE DIFFERENCE
double x1 = point_class.point.x - center.x;
double y1 = point_class.point.y - center.y;
has to go outside of the loop, because I need to take base at that location when applying the rotation matrix. And also in the loop, I should have the deegre fixed at 1, so that it is only incrementet by 1 and not 81+82+83...Dont know why i did that.
Hope this helps someone =)
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I need to draw a fractal swirl using the algorithm Iterated Function System.
There are coefficients for this fractal:
0.745455 -0.459091 0.406061 0.887121 1.460279 0.691072 0.912675
-0.424242 -0.065152 -0.175758 -0.218182 3.809567 6.741476 0.087325
And here is my code:
import java.awt.Graphics;
import javax.swing.JPanel;
public class Surface extends JPanel {
double a1 = 0.745455;
double b1 = -0.459091;
double d1 = 0.406061;
double e1 = 0.887121;
double c1 = 1.460279;
double f1 = 0.691072;
double p1 = 0.912675;
double a2 = -0.424242;
double b2 = -0.065152;
double d2 = -0.175758;
double e2 = -0.218182;
double c2 = 3.809567;
double f2 = 6.741476;
double p2 = 0.087325;
double x1(double x, double y) {
return a1 * x + b1 * y + c1;
}
double y1(double x, double y) {
return d1 * x + e1 * y + f1;
}
double x2(double x, double y) {
return a2 * x + b2 * y + c2;
}
double y2(double x, double y) {
return d2 * x + e2 * y + f2;
}
public void paint(Graphics g) {
drawFractal(g);
}
void drawFractal(Graphics g) {
double x1 = 300;
double y1 = 300;
double x2 = 0;
double y2 = 0;
g.fillOval(300 + (int) x1, 300 + (int) y1, 3, 3);
for (int i = 0; i < 10000; i++) {
double p = Math.random();
if (p < 0.91675) {
x2 = x1(x1, y1);
y2 = y1(x1, y1);
g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
x1 = x2;
y1 = y2;
} else {
x2 = x2(x1, y1);
y2 = y2(x1, y1);
g.fillOval(300 + (int) x2, 300 + (int) y2, 3, 3);
x1 = x2;
y1 = y2;
}
}
}
}
Unfortunately, with this code I get a wrong picture:
It would be great if someone could point out my mistake.
Your generation seems correct (i.e. don't do x1 = x2 +300; y1 = y2 +300;), but your problem is you're way off the scale for the purposes of rendering. This means there are very few points that fall outside very center of the image.
Your window is [0..600]x[0..600]. Try multiplying x2 and y2 with 50, so that you're rendering the [-6..6]x[-6..6] region instead of the [-300..300]x[-300..300] region of space.
Note that it should be sufficient to draw single pixels (as lines to itself) instead of 3x3 ovals.
int xp = 300 + (int) (x2 * scale);
int yp = 300 + (int) (y2 * scale);
g.drawLine(xp, yp, xp, yp);
Depending on what gets rendered, you might need to adjust the scale slightly to get the entire image with reasonable bounds. Note the second transformation offsets by -6.7, so a scale of 30 should be about right.
Also note that by using x1 = x2 +300; y1 = y2 +300; you change the transformations and get a different fractal (at a scale at which you expect).
This is great, I was wrong thinking that exponential runtime required! The fractals appeared more dimensional than my imagination!
Thanks #Jan Dvorak!
The following also works (in my coordinates, xcenter=300, ycenter=100 and radius=50 are global drawing parameters) and works faster:
void drawFractal2(Graphics g) {
double x1 = 0;
double y1 = 0;
double x2 = 0;
double y2 = 0;
double p;
g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);
for(int i=0; i<100000; ++i) {
p = Math.random();
if (p < p1) {
x2 = x1(x1, y1);
y2 = y1(x1, y1);
}
else {
x2 = x2(x1, y1);
y2 = y2(x1, y1);
}
g.fillOval(xcenter + (int) (x2 * radius), ycenter + (int) (y2 * radius), 3, 3);
x1 = x2;
y1 = y2;
}
}
and the picture is better
BELOW IS MY INCORRECT ANSWER
But it show how fractals are bigger than the intuition, so I keep it.
I guess your algorithm should be tree-like (recursive) while your one is linear. You are just drawing one chain of points, transforming it one after one. So you get some spiral-like chain. It can't generate any fractal picture in principle.
I GOT YOUR PICTURE
You have 2 mistakes:
1) you pass 300 both into iteration and as drawing shift. This is minor.
2) You algorithm is linear. Linear algorithm can't draw tree-like picture. If you use random values, you should run algorithm multiple times. One chain draws only one random portion of the picture.
I got your picture with following recursive algorithm. It works slow but you are to improve it.
void drawFractal(Graphics g, double x1, double y1, int depth) {
double x2 = 0;
double y2 = 0;
if( depth > 20 ) {
return;
}
g.fillOval(xcenter + (int) (x1 * radius), ycenter + (int) (y1 * radius), 3, 3);
x2 = x1(x1, y1);
y2 = y1(x1, y1);
drawFractal(g, x2, y2, depth+1);
x2 = x2(x1, y1);
y2 = y2(x1, y1);
drawFractal(g, x2, y2, depth+1);
}
to run it I used
public void paint(Graphics g) {
//drawFractal(g);
drawFractal(g, 0, 0, 0);
}
parameters are
int xcenter = 300;
int ycenter = 100;
int radius = 50;
the picture is follows:
I am trying to make a small program that will move the mouse from the current position to the given position. Here is a method that i can use which will move the mouse from one point to another but without animation:
moveMouse(int x, int y);
This will move the mouse from the current coordinates to x,y on screen without animation. Now my job is to move the mouse to that coordinate, but it should also show the mouse moving one pixel at a time. I need to create a loop which moves the mouse cursor few pixels x and y at a time so that Here is what i have been thinking:
public void moveMouseAnimation(x,y){
//Integers x2 and y2 will be the current position of the mouse cursor
boolean isRunning = true;
while(isRunning){
delay(10); // <- 10 Milliseconds pause so that people can see the animation
x2 -= 1;
y2 -= 1;
moveMouse(x2,y2);
if(x2 == x && y2 == y) isRunning = false; //Ends loop
}
}
Now i need to find correct x2 and y2 values so that the mouse moves in a straight line and reaches x and y at last. Could someone help me.
You want the Bresenham's line algorithm. It is commonly used to draw a line between two points, but you, instead of drawing a line, will move the mouse along it.
Below is the code to do that. This code uses Bresenham Line Algo. For more ref on soln try http://en.wikipedia.org/wiki/Bresenham's_line_algorithm if you are looking not to have jagged lines
boolean steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep) {
int t;
// swap(x0, y0);
t = x0;
x0 = y0;
y0 = t;
// swap(x1, y1);
t = x1;
x1 = y1;
y1 = t;
}
if (x0 > x1) {
int t;
// swap(x0, x1);
t = x0;
x0 = x1;
x1 = t;
// swap(y0, y1);
t = y0;
y0 = y1;
y1 = t;
}
int deltax = x1 - x0;
int deltay = Math.abs(y1 - y0);
int error = deltax / 2;
int ystep;
int y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
for (int x = x0; x < x1; x++) {
if (steep)
moveMouse(y, x);
else
moveMouse(x, y);
error = error - deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
The problem that you are attempting to solve is that of linear interpolation, in that you have a linear function, that of a line between the starting point (x0, y0) and the ending point (x1, y1).
Luckily the solution is simple. The Wikipedia article gives examples almost exactly what you're trying to do.
http://en.wikipedia.org/wiki/Linear_interpolation
You could interpolate a straight line....basically fitting y=mx+b to the given points.