How to check if circles intersect each other? - java

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.

Related

In Java how should I command a 2D point to move along the vector line of distance to another point?

I have a simple class 2Dpoints with two fields, x and y. I want to write a code so that I could command one point to moves slowly to another point, like so that it moves on the vector line of their distances. But I don't know how?
I've first thought  that it should contain a for loop so that it would know, it should move till it reaches the other point
something like for(int d=0 ; d<distance ; d++) but I don't know how should I then command it so that it would move on the line?
import java.lang.Math.*;
public class Punkt {
private int x;
private int y;
public Punkt(int x, int y) {
this.x=x;
this.y=y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int distance) {
x = x + distance;
}
public void setY(int distance) {
y = y + distance;
}
public void moveAbout(int dx, int dy) {
x = x + dx;
y = y + dy;
}
/// method for calculating the distance to another point
public double giveDistance(Punkt otherPoint) {
return Math.sqrt(
(otherPoint.getY() - y) *
(otherPoint.getY() - y) +
(otherPoint.getX() - x) *
(otherPoint.getX() - x));
}
}
I've commented the major lines:
import static java.lang.Math.*;
/**
* Immutable structure. Functional way
*/
class Point {
public final double x;
public final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
/**
* Here you are. This is what you want to implement.
* from.moveTo(0.0, to) => from
* from.moveTo(1.0, to) => to
*
* #param by - from 0.0 to 1.0 (from 0% to 100%)
* #param target - move toward target by delta
*/
public Point moveTo(double by, Point target) {
Point delta = target.sub(this);
return add(delta.dot(by));
}
public Point add(Point point) {
return new Point(x + point.x, y + point.y);
}
public Point sub(Point point) {
return new Point(x - point.x, y - point.y);
}
public Point dot(double v) {
return new Point(v * x, v * y);
}
public double dist(Point point) {
return sub(point).len();
}
public double len() {
return sqrt(x * x + y * y);
}
public String toString() {
return x + ":" + y;
}
}
class Main {
public static void main(String[] args) {
Point source = new Point(2, 3);
Point target = new Point(-4, 9);
// You can utilize the cycle or implement kind of timer to animate something
for (int t = 0; t <= 100; t++) {
System.out.println(source.moveTo(0.01 * t, target));
}
}
}
https://replit.com/join/sucvdhpqoa-redneckz
#AlexanderAlexandrov I've change the type of my variables to double accordingly, now in one of my classes I have a method givePoints, which uses Scanner for asking a user how many points he wants and what are the coordinates then it saves them into an array of points with first element being always(0,0).
Another method takes an array of points as parameter and sort them in order of their distances to point(0,0).
These methods work perfectly. The problem is with method hitThepoints.
Here I want to first create the array of points, sort them, and then command my robot to hit all the points. robot is an object of class Robot extends circle, with position of type Point, that at first is at point(0,0)
public void hitThePoints(){
Point[] poi=sortPoints (givePoints()); //Creates a sorted array of points
Point short=new Point(poi[1].getX(),poi[1].getY());
System.out.println(" the nearest point is :");
System.out.println("("+short.getX()+ ","+short.getY()+")");
for(int i=1; i<poi.length;i++){
Point source=robot.position;
Point target=new Point(poi[i].getX(), poi[i].getY());
while(source.getX()!=target.getX() &&
source.getY()!=target.getY()){
robot.bewegeUm((source.moveTo(0.01,target)).getX(),
(source.moveTo(0.01,target)).getY());
if(source.getX()!=target.getX() &&
source.getY()!=target.getY()){break;}
System.out.println(source.getX() +","+ source.getY());
}
}
}

return true if circle c overlaps any other circle in the arraylist

I have an assigment in my beginners class in coding, in java. This is the assignment (translated from swedish to english by me, therefor I'm sorry in advance);
The class CircleList keeps track of a number of circles. Implement the class.
Guidance
This task should, not only give practice in using ArrayList, but also give practice in breaking down a problem in several methods. Therefor you should use the method overlapsinside of the method add.
And for the method overlaps to be easier to write, you should, in overlaps use the private method circleOverlaps.
Two circles overlaps if the distance between their origos are less than the sum of their radiuses.
The class Circle looks like this;
class Circle {
private double radius;
private double x;
private double y;
/** Constructs a circle with the radie radius and the
center in x, y. */
public Circle(double x, double y, double radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
/** Returns the x coordinate of the center. */
public double getX() {
return x;
}
/** Returns the y coordinate of the center. */
public double getY() {
return y;
}
/** Returns the radius. */
public double radius() {
return radius;
}
/** Returns the area. */
public double area() {
return Math.PI * radius * radius;
}
}
And this is what I've come up with so far, (the methods were already declared but not implemented);
public class CircleList {
private ArrayList<Circle> circles;
/** Constructs an empty list for circles. */
public CircleList() {
circles = new ArrayList<Circle>();
}
/** Adds the circle c to the list if it not ovelaps
with any circle in the list. Return true if
circle has been added. */
public boolean add(Circle c) {
circles.add(c);
}
/** Returns true if the circle c ovelaps with any
one circle in this list. */
public boolean overlaps(Circle c) {
}
private boolean circlesOverlaps(Circle c1, Circle c2) {
double r1 = Circle.radius(c1); //radius, x- & y-value of circle 1 (c1)
double x1 = Circle.getX(c1);
double y1 = Circle.getY(c1);
double r2 = Circle.radius(c2); //radius, x- & y-value för circle 2 (c2)
double x2 = Circle.getX(c2);
double y2 = Circle.getY(c2);
double distance = Math.pow((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2), 0.5);
if (r2 >= r1 && distance <= (r2 - r1)){ //c1 is inside c2
}
else if (r1 >= r2 && distance <= (r1 - r2) ) { //c2 is inside c1
}
else if (distance > (r1 + r2)){ //c2 doesn't overlap c1
}
else { //c2 overlaps c1
}
}
}
I don't really know where to start. And I don't really have anyone to ask at the moment. I understand if this is too much to even start with. But thank you anyways.
Take care.
Basically you have to iterate over all circles and check if the given circle overlaps with any like
public boolean overlaps(Circle c) {
return circles.stream()
.anyMatch(circle -> circlesOverlaps(c, circle));
}
and you have to return true or false from your if conditions in circlesOverlaps method, depending on whether you consider one circle inside another as an overlap or not for your problem.
One other place you need to correct is
public boolean add(Circle c) {
return circles.add(c);
}
basically adding return as you need to return a boolean based on your return type.

Point Class Coordinates

I have an assignment explaining like this:
Write a definition of a class named Point that might be used to store and manipulate the location of a point on the plane. The point is stored as two coordinates: x and y. You will need to declare and implement the following methods:
Two constructors:
a. no-argument constructor that sets the point coordinates to (0,0), and
b. a constructor that takes x and y coordinate of the point and sets member
variables.
Method set that sets the private data after an object of this class is created.
A method to move the point by an amount along the vertical and horizontal directions specified by the first and second arguments: move(double dx, double dy)
The method to rotate the point by 90 degrees clockwise around the origin. Hint: when point is getting rotated 90 clockwise around the origin the following changes happen to its coordinates: xrotated = y; yrotated = -x .
two accessor methods to retrieve the coordinates of the point.
It should be 2 different call. these items on second one (not main class)
I will call this on main class. (I do that).
This is my code but I dont understand what I should do next.
private double x;
private double y;
public Point(double initialX, double initialY) {
x = initialX;
y = initialY;
}
public Point() {
x = 0;
y = 0;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void move(double dx, double dy) {
x += dx;
y += dy;
}
You have almost everything, good job. For the rotate by 90 function, you're given a pretty good clue about what to do. Imagine you have a point (1,2), and you rotate it. you'll end up with (2,-1). if you rotate it again, you'll get (-1,-2). once more gives you (-2,1), and a fourth 90 degree rotation gives (1,2), which is what you started with. come up with a function that does this. It shouldn't be longer than 3 lines.
The setter functions (functions used to set, or change, the values) are simply functions you can use to set the values of the point. so, you'd have a function "setX(...) { ... }" and a function "setY(...) { ... }". These should be very straightforward.
Feel free to ask further questions if you're still confused.
private double x;
private double y;
public Point(double dx, double dy) {
x = dx;
y = dy;
}
public Point() {
x = 0;
y = 0;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void SetX(double dx)
{
x = dx;
}
public void SetY(double dy)
{
y = dy;
}
public void move(double dx, double dy)
{
x = x + dx;
y = y + dy;
}
public double rotateX()
{
double temp = x;
x=y;
y=temp;
return x;
}
public double rotateY()
{
y=-y;
return y;
}
main page
public static void main(String[] args) {
// TODO Auto-generated method stub
Point p = new Point();
p.SetX(50);
p.SetY(17);
System.out.println("X and Y coordinates are : \n("+p.getX()+","+p.getY()+")");
System.out.println("after 90 degree clockwise rotate: ");
System.out.println(p.rotateX()+","+p.rotateY());

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.

Determining if a coordinate is on a line

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;
}
}

Categories