Determining if a coordinate is on a line - java

I´m coding a little app that allows the user to draw multiple shapes and then remove or resize them. It´s working perfectly on rectangles and ovals, but I´m having issues with lines.
Here´s a method that I wrote to find if the clicked spot on the screen is part of a specific line:
public boolean containsLocation(int x, int y) {
int m = (getY2() - getY()) / (getX2() - getX());
int b = getY() - (m * getX());
if (y == (m * x) + b) {
return true;
}
return false;
I´m using the famous y = mx + b formula and replacing y and x, wich are the coordinates on the spot clicked, to find if the clicked spot is part of the line.
The original coordinates are determined using the getters getX(), getY() and getX2(), getY2()
The problem is when I click on the screen to remove the line, it only works if I click on the very fist coordinate (x,y) where the line starts.
Nothing happens when I click anywhere else along the line.
Since math is not a strongest suit, can anyone shed a light on what I´m doing wrong?
Here´s my Line full class:
public class Line extends Shape{
private int x2, y2;
public Line (int x, int y, int x2, int y2, Color lineColor) {
super(x, y, lineColor);
this.x2 = x2;
this.y2 = y2;
}
public void draw(Graphics g) {
g.setColor(getLineColor());
g.drawLine(getX(), getY(), getX2(), getY2());
}
#Override
public boolean containsLocation(int x, int y) {
int m = (getY2() - getY()) / (getX2() - getX());
int b = getY() - (m * getX());
if (y == (m * x) + b) {
return true;
}
return false;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getY2() {
return y2;
}
public void setY2(int y2) {
this.y2 = y2;
}
}
Here´s the Shape class that is being extended by Line:
public abstract class Shape {
private int x, y;
private Color lineColor;
public Shape(int x, int y, Color lineColor) {
this.x = x;
this.y = y;
this.lineColor = lineColor;
}
public abstract void draw(Graphics g);
public abstract boolean containsLocation(int x, int y);
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Color getLineColor() {
return lineColor;
}
public void setLineColor(Color lineColor) {
this.lineColor = lineColor;
}
}
Here´s the method that calls containsLocation:
public Shape shapeFinder(int x, int y){
for (int i = shapes.size()-1; i >=0; i--){
if (shapes.get(i).containsLocation(x, y)){
return shapes.get(i);
}
}
return null;
}
And here´s the method that should remove the line (it´s working for Ovals and Rectangles):
public void mousePressed(MouseEvent e) {
if (model.getAction() == Model.REMOVE) {
startX = e.getX();
startY = e.getY();
shape = model.shapeFinder(startX, startY);
if (shape != null) {
model.getShape().remove(model.shapeFinder(startX, startY));
}

You're using integer division to calculate your slope. I used my example of (100,100) to (120, 153) and it gave me a slope of 2. It should be a slope of 2.65.
But regardless, you'll never find any integer points in the middle of my line - there are no points along my line where both x and y are integers. If you calculate the slope correctly you'll be able to get the endpoints recognized but you need to find a different way of calculating points in the middle. Maybe introduce some sort of epsilon to your method?

Actually, you need to compute the direction of the line (its angle in radians) using something like Math.atan2. Then, you can apply an inverse rotation to one of the points of the line, considering the other point as the center, and also to the mouse coordinate. Your line is now a horizontal one, so checking if the mouse is over it is straight-forward.
See rotation matrices.
public class LineDemo {
public static void main(String[] args) {
System.out.println(containsLocation(50, 75, 50, 50, 50, 100));
}
public static boolean containsLocation(int x, int y, int x1, int y1, int x2, int y2) {
double dy = y2 - y1;
double dx = x2 - x1;
double dist = Math.sqrt(dx*dx + dy*dy);
double angle = Math.atan2(dy, dx);
double cos = Math.cos(-angle);
double sin = Math.sin(-angle);
double xRot = (x - x1) * cos - (y - y1) * sin;
double yRot = (x - x1) * sin + (y - y1) * cos;
// Actually, I only rotated the mouse point, since
// I can use the first point of the line and its
// euclidian distance to know where the rotated
// second point would end.
if (0 <= xRot && xRot <= dist) {
double tolerance = 3; // distance tolerance in pixels
if (Math.abs(yRot) <= tolerance) {
return true;
}
}
return false;
}
}

Related

Android Studio How to draw a hexagon

I was trying to draw a hexagon on a canvas. But I have not found something that could help me. I wasn't able to do it on my one. My problem is that the hexagon line points aren't drawing.
The green dots are the circles I want to draw and the black lines should be the hexagon when I draw it with lines
My Hexagon class
public class Hexagon extends Rotateables {
public float radius;
public Hexagon(Game game, Vector2 position, float radius) {
super(game, position.x, position.y, 0, 0, 0);
this.radius = radius;
}
public void drawHexagon(Canvas canvas) {
for (int angle = 0; angle < 360;angle += 45) {
setAngle(angle);
Vector2 drawPos = getMovement();
Paint paint;
paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawCircle(drawPos.getX(), drawPos.getY(), radius, paint);
}
}
}
My Rotateables class
public abstract class Rotateables {
protected double x ,y , angle; // angle
protected int w, h; // width and height
// constructor
public Rotateables(double x, double y, double angle, int w, int h) {
this.x = x;
this.y = y;
this.angle = angle;
this.w = w;
this.h = h;
}
// returning all the necessary value of this class
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getAngle() {
return angle;
}
public int getW() {
return w;
}
public int getH() {
return h;
}
// setting the angle
public void setAngle(int aa) {
angle = Math.toRadians(aa);
}
// move toward the angle
// //forward
public void moveForward() {
x += Math.cos(angle);
y += Math.sin(angle);
}
public Vector2 getMovement() {
double x = Math.cos(angle) + this.x;
double y = Math.sin(angle) + this.y;
return new Vector2(x,y);
}
public void moveForward(float speed, boolean drawVertex) {
x += Math.cos(angle)*speed;
y += Math.sin(angle)*speed;
}
//backward
public void moveBackward() {
x -= Math.cos(angle);
y -= Math.sin(angle);
}
public void setAngle(Point p1)
{
double xDiff = x - p1.x;
double yDiff = y - p1.y;
double _angle = Math.toDegrees(Math.atan2(yDiff, xDiff));
setAngle((int)_angle);
}
public static double getAngle(Point p1, Point p2)
{
double xDiff = p2.x - p1.x;
double yDiff = p2.y - p1.y;
return Math.toDegrees(Math.atan2(yDiff, xDiff));
}
}

How to check if circles intersect each other?

This is my test class,
public class Shape2DTester {
public static void main(String[] args) {
GeometricObject2D geoObject1 = new ComparableCircle2D(0, 5, 2);
GeometricObject2D geoObject3 = new ComparableCircle2D(0, 0, 2);
System.out.println("geoObject1 overlaps geoObject3: "
+ geoObject1.intersect(geoObject3));
}
}
This is my circle class,
public class ComparableCircle2D extends GeometricObject2D<ComparableCircle2D> {
public double x, y;
public double radius;
ComparableCircle2D() {
super();
this.radius = 1.0;
}
ComparableCircle2D(double radius) {
super();
this.radius = Math.abs(radius);
}
ComparableCircle2D(double x, double y, double radius) {
super(x, y);
this.radius = Math.abs(radius);
}
public double getArea() {
return Math.PI * getRadius() * getRadius();
}
public double getPerimeter() {
return 2 * Math.PI * getRadius();
}
public void setRadius(double setRadius) {
this.radius = Math.abs(setRadius);
}
public double getRadius() {
return radius;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
#Override
public boolean intersect(GeometricObject2D g) {
ComparableCircle2D other = (ComparableCircle2D) g;
double dx = other.x - getX();
double dy = other.y - getY();
double radi = other.radius + getRadius();
return (dx * dx + dy * dy < radi * radi);
}
}
}
this is my superclass,
public abstract class GeometricObject2D<T extends GeometricObject2D> implements
Comparable<GeometricObject2D> {
public double x, y;
GeometricObject2D() {
this.x = 0;
this.y = 0;
}
GeometricObject2D(double x, double y) {
this.x = x;
this.y = y;
}
public abstract double getArea();
public abstract double getPerimeter();
public abstract boolean intersect(GeometricObject2D g);
#Override
public int compareTo(GeometricObject2D o) {
// TODO Auto-generated method stub
return 0;
}
}
I want to find out possibility of intersecting two circles but there is an error in my code that I didn't realize.
For example I create two circle object coordinates-1(0,0) , radius-1=2 and coordinates-2(0,5) ,radius-2=2. That above method must return false but returns true. I didn't find error.
System.out.println("geoObject1 intersects geoObject3: "
+ geoObject1.intersect(geoObject3));
prints geoObject1 intersects geoObject3: true
As #Pshemo said, your code (now that you've shown it) has an extra } at the end that shouldn't be there.
How, if we paste all that code into IDEONE, and run it, we confirm your error.
If we then DEBUG the code by adding a single print statement, we see:
dx=0.0, dy=0.0, radi=4.0
Hmmm, why is dy = 0 when it should be 5?
Answer: Because you added another set of x and y fields to your subclass, that is hiding the fields from the base class!!!!
Simple debugging would have shown you this yourself. This is what #PeterLawrey was talking about in his comment:
you mistake is it is likely to be; the values are not what you think they are. This is where debugging your code can show this.
Of course, if you had used a good IDE, you wouldn't even need to debug, because the IDE would have warned you about the field hiding.
Rather than Math.pow(x, 2) it is more efficient to do x * x, and instead of using Math.sqrt you can square the sum of the radii.
public boolean intersect(GeometricObject2D g) {
ComparableCircle2D other = (ComparableCircle2D) g;
double dx = other.x - x; // e.g. 0 - 0
double dy = other.y - y; // e.g. 5 - 0
double radii = other.radius + radius; // e.g. 2 + 2
return dx * dx + dy * dy < radii * radii ; // e.g. 0 + 25 < 16 is false.
}
You never assign the fields x and y. Therefore dx = dy = 0.
You have to either assign the field's values or use the fields in the superclass (but you shouldn't have fields with the same information in the same object, so remove the fields created in ComparableCircle2D).
Also if your circle is defined as contour, not as area, then the test for intercepting circles is incorrect. Consider the case where 2 circles with the same center have different radii: dx² + dy² = 0 < dr², but the contours don't intersect; only the areas inside the circles overlap.

Set Color and Radius using command java

I would like to be able to have the user change the color and radius of the ball, I would also like to be able to change the color of the ball when it has already been created.
I have tried using the setColor but I does not get it to work.
Here is my code:
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Ball {
public static final double BILLION = 1_000_000_000.0;
private double x, y; // position of the balls center
private double dx, dy; // velocity measured in pixels/second
private double radius;
private Color color;
public Ball(double x0, double y0) {
x = x0;
y = y0;
radius = 10;
color = Color.YELLOW;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double newX) {
x = newX;
}
public void setY(double newY) {
y = newY;
}
public double getRadius() {
return radius;
}
public double getDx() {
return dx;
}
public double getDy() {
return dy;
}
public void setVelocity(double newDx, double newDy) {
dx = newDx;
dy = newDy;
}
public void moveTo(double newX, double newY) {
x = newX;
y = newY;
}
public void setColor(Color col) {
color = col;
}
public void move(long elapsedTimeNs) {
x += dx * elapsedTimeNs / BILLION;
y += dy * elapsedTimeNs / BILLION;
}
public void paint(GraphicsContext gc) {
gc.setFill(color);
// arguments to fillOval: see the javadoc for GraphicsContext
gc.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
public boolean intersectsArea(
double rectX, double rectY,
double rectWidth, double rectHeight) {
double closestX = clamp(x, rectX, rectX + rectWidth);
double closestY = clamp(y, rectY, rectY + rectHeight);
double distanceX = x - closestX;
double distanceY = y - closestY;
return (distanceX * distanceX) + (distanceY * distanceY)
< (radius * radius);
}
private double clamp(double value, double lower, double upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
return value;
}
}
Any tips on how to proceed?
Thanks!
My guess is that you do not call paint after setting the color, you need to redraw to have the color changed

How to project 3D on a 2D plane?

I created a simple Application which is meant to display, in 2D, dots which are hypothetically on a 3D plane (these points are of type Vector, written below). The class uses the XYZ Coordinates of the Camera and the XYZ Coordinates of the Vector, and uses that information to quickly translate the Vector XYZ Coordinates into XY Coordinates.
The only class needed in this question is the Vector class given below. All other classes used are omitted because they essentially fire mouse movements and redraw the frame.
--My concern is that, as the camera moves, the Vector points jump around as if the formula that I'm using is totally unreliable. Are these formulas (found under Perspective Projection) completely incorrect? The use of those formulas can be found within my set2D method. Am I doing something completely wrong, skipping steps, or perhaps have I translated the formula into code incorrectly?
Thanks!
import java.awt.Color;
import java.awt.Graphics;
public class Vector
{
private int cX, cY, cZ; //Camera Coordinates
private int aX, aY, aZ; //Object Coordinates
private double bX, bY; //3D to 2D Plane Coordinates
public Vector(int aX, int aY, int aZ, int cX, int cY, int cZ)
{
this.aX = aX;
this.aY = aY;
this.aZ = aZ;
this.cX = cX;
this.cY = cY;
this.cY = cZ;
set2D();
}
//SETS
public void setCameraX(int cX)
{
this.cX = cX;
set2D();
}
public void setCameraY(int cY)
{
this.cY = cY;
set2D();
}
public void setCameraZ(int cZ)
{
this.cZ = cZ;
set2D();
}
public void setCameraXYZ(int cX, int cY, int cZ)
{
setCameraX(cX);
setCameraY(cY);
setCameraZ(cZ);
}
public void setObjX(int x)
{
this.aX = x;
}
public void setObjY(int y)
{
this.aY = y;
}
public void setObjZ(int z)
{
this.aZ = z;
}
public void setObjXYZ(int x, int y, int z)
{
this.aX = x;
this.aY = y;
this.aZ = z;
}
public void set2D()
{
//---
//the viewer's position relative to the display surface which goes through point C representing the camera.
double eX = aX - cX;
double eY = aY - cY;
double eZ = aZ - cZ;
//----
double cosX = Math.cos(eX);
double cosY = Math.cos(eY);
double cosZ = Math.cos(eZ);
double sinX = Math.sin(eX);
double sinY = Math.sin(eY);
double sinZ = Math.sin(eZ);
//---
//The position of point A with respect to a coordinate system defined by the camera, with origin in C and rotated by Theta with respect to the initial coordinate system.
double dX = ((cosY*sinZ*eY) + (cosY*cosZ*eX)) - (sinY * eZ);
double dY = ((sinX*cosY*eZ) + (sinX*sinY*sinZ*eY) + (sinX*sinY*cosZ*eX)) + ((cosX*cosZ*eY) - (cosX*sinZ*eX));
double dZ = ((cosX*cosY*eZ) + (cosX*sinY*sinZ*eY) + (cosX*sinY*cosZ*eX)) - ((-sinX*cosZ*eY) - (-sinX*sinZ*eX));
//---
//---
//The 2D projection coordinates of the 3D object
bX = (int)(((eZ / dZ) * dX) - eX);
bY = (int)(((eZ / dZ) * dY) - eY);
//---
System.out.println(bX + " " + bY);
}
//GETS
public int getCameraX()
{
return cX;
}
public int getCameraY()
{
return cY;
}
public int getCameraZ()
{
return cZ;
}
public int getObjX()
{
return aX;
}
public int getObjY()
{
return aY;
}
public int getObjZ()
{
return aY;
}
public int get2DX()
{
return (int)bX;
}
public int get2DY()
{
return (int)bY;
}
//DRAW
public void draw(Graphics g)
{
g.setColor(Color.red);
g.fillOval((int)bX, (int)bY, 3, 3);
}
//TO STRING
public String toString()
{
return (aX + " " + aY + " " + aZ);
}
}
The following line of your code does not match with the formula you are using:
double dZ = ((cosX*cosY*eZ) + (cosX*sinY*sinZ*eY) + (cosX*sinY*cosZ*eX)) - ((-sinX*cosZ*eY) - (-sinX*sinZ*eX));
Notice the part - ((-sinX*cosZ*eY) - (-sinX*sinZ*eX))
This should be - ((sinX*cosZ*eY) - (sinX*sinZ*eX))
Since if you take sinX and multiply it, the -ve sign stays outside. If however you multiple -sinX then the sign outside the brackets should become +ve.

Trying to test rectangles for intersection in Java, what am I doing wrong?

here is my code:
public class Rectangles
{
private final double x;
private final double y;
private final double width;
private final double height;
public Rectangles(double x0, double y0, double w, double h)
{
x = x0;
y = y0;
width = w;
height = h;
}
public double area()
{
return width * height;
}
public double perimeter()
{
return 2*width + 2*height;
}
public boolean intersects(Rectangles b)
{
boolean leftof = ((b.x + b.width)<(x-width));
boolean rightof = ((b.x-b.width)>(x+width));
boolean above = ((b.y-b.height)>(y+height));
boolean below = ((b.y+b.height)<(y-height));
if (leftof==false && rightof==false && above==false && below==false)
return false;
else return true;
}
public void show()
{
StdDraw.setYscale((0),(y+height));
StdDraw.setXscale((0), (x+width));
StdDraw.setPenColor();
StdDraw.rectangle(x,y,.5*width,.5*height);
}
public static void main(String[] args)
{
Rectangles a = new Rectangles(Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Double.parseDouble(args[2]),
Double.parseDouble(args[3]));
Rectangles b = new Rectangles(0,0,1,1);
System.out.println(a.area());
System.out.println(a.perimeter());
System.out.println(a.intersects(b));
a.show();
b.show();
}
}
I am new to this. This is from a lab assignment based on creating data types. Everything is going well except that System.out.println(a.intersects(b)) is returning true for rectangles that definitely should not intersect. Worse still, the drawing created by show() is showing that they intersect when they definitely should not. For example, (and tell me if I'm completely wrong) %java Rectangles 5 5 3 6 should definitely not return true, right? because a rectangle centered at 5,5 whose width is three would definitely not intersect with a rectangle centered at 0,0 whose width is one.
help is appreciated. I would post a pic of the image displayed, but it says I have to have more reputation to post images. oh well. It was intersecting rectangles.
based on some comments, I edited my code and it now looks like this:
public class Rectangles
{
private final double x;
private final double y;
private final double width;
private final double height;
public Rectangles(double x0, double y0, double w, double h)
{
x = x0;
y = y0;
width = w;
height = h;
}
public double area()
{
return width * height;
}
public double perimeter()
{
return 2*width + 2*height;
}
public boolean intersects(Rectangles b)
{
boolean intersects = ((b.width / 2) + (width / 2) < Math.abs(b.x - x) &&
(b.height / 2) + (height / 2) < Math.abs(b.y - y));
if (intersects==false)
return false;
else return true;
}
public void show()
{
StdDraw.setYscale((0),(y+height));
StdDraw.setXscale((0), (x+width));
StdDraw.setPenColor();
StdDraw.rectangle(x,y,.5*width,.5*height);
}
public static void main(String[] args)
{
Rectangles a = new Rectangles(Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Double.parseDouble(args[2]),
Double.parseDouble(args[3]));
Rectangles b = new Rectangles(1.0,1.0,1.0,1.0);
System.out.println(a.area());
System.out.println(a.perimeter());
System.out.println(b.intersects(a));
a.show();
b.show();
}
}
I am still getting funky answers for intersects, and for some reason my drawings always have intersecting rectangles. I don't know what I'm doing wrong. After changing code I tried %java Rectangles 5 5 3 6 and it said they intersect and also drew an image of intersecting rectangles. What is going on?
I fixed it.
public class Rectangles
{
private final double x;
private final double y;
private final double width;
private final double height;
public Rectangles(double x0, double y0, double w, double h)
{
x = x0;
y = y0;
width = w;
height = h;
}
public double area()
{
return width * height;
}
public double perimeter()
{
return 2*width + 2*height;
}
public boolean intersects(Rectangles b)
{
boolean leftof = ((b.x + (0.5*b.width))<(x-(0.5*width)));
boolean rightof = ((b.x-(0.5*b.width))>(x+(0.5*width)));
boolean above = ((b.y-(0.5*b.height))>(y+(0.5*height)));
boolean below = ((b.y+(0.5*b.height))<(y-(0.5*height)));
if (leftof==true || rightof==true || above==true || below==true)
return false;
else return true;
}
public void show()
{
double j = Math.max((x+(0.5*height)), (y+(0.5*height)));
StdDraw.setYscale((0),j+1);
StdDraw.setXscale((0),j+1);
StdDraw.setPenColor();
StdDraw.rectangle(x,y,.5*width,.5*height);
}
public static void main(String[] args)
{
Rectangles a = new Rectangles(Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Double.parseDouble(args[2]),
Double.parseDouble(args[3]));
Rectangles b = new Rectangles(2,2,2,2);
System.out.println(a.area());
System.out.println(a.perimeter());
System.out.println(a.intersects(b));
a.show();
}
}
There is an error in formula for intersection, try this one
((x < b.x && (x + width) > b.x) || (x > b.x && x < (b.x + b.width))) &&
((y < b.y && (y + height) > b.y) || (y > b.y && y < (b.y + b.height)))
If we think geometrically,
(b.width / 2) + (width / 2) < abs(b.x - x) &&
(b.height / 2) + (height / 2) < abs(b.y - y)
should be enough and easier to understand.

Categories