Size comparisons (circumference/square perimeter) etc - java

3 diffrent classes 1 for handling Circle isntances ,1 for Square instances and the 3rd for comparrisons between them(main) . In the main function i find the circle (between c1..c4) and square (between s1...s5) and print the biggest circumference and area of them respectively.[so circle-circle and square-square comparison]
!!!! NOTE : Only the ones with the biggers radius or sides have the biggest circumference or area , so i only use r and a for comparisons.i dont know if its possible to return this if i use the area/circumference method(no , cause then i will only handle numbers ?).Correct me please.
Now i want to print the characteristics(x,y,r/a) of the geometric shape (circle/square) with the biggest perimeter. How can i do this ? Where do i compare?New class?[square-circle comparison]
public class Circle {
public double x,y,r;
public double circumference() {
return 2*(3.14)*r;
}
public double area() {
return 3.14*r*r;
}
public Circle bigger(Circle c){
if(c.r>r) return c; else return this;
}
public Circle(double x, double y, double r) {
this.x=x;
this.y=y;
this.r=r;
}
}
public class Square {
public double x,y,a;
public double perimeter() {
return 4*a;
}
public double area() {
return a*a;
}
public Square bigger(Square s){
if(s.a>a) return s; else return this;
}
public Square(double x, double y, double a) {
this.x=x;
this.y=y;
this.a=a;
}
}
public class CircleAndSquareTest {
public static void main(String[] args) {
Circle c1 = new Circle(0.0,0.0,1.0);
Circle c2 = new Circle(1.0,0.0,2.0);
Circle c3 = new Circle(0.0,2.0,4.0);
Circle c4 = new Circle(1.0,3.0,1.0);
Circle cb = c1.bigger(c2).bigger(c3).bigger(c4);
System.out.println("The circle with the biggest circumference has:\n");
System.out.println("x-axis value: " + cb.x + " y-axis value: " + cb.y + " radius: " + cb.r+"\n");
Square s1 = new Square(0.0,0.0,1.0);
Square s2 = new Square(0.0,0.0,1.0);
Square s3 = new Square(0.0,0.0,5.0);
Square s4 = new Square(4.0,2.0,2.0);
Square s5 = new Square(0.0,0.0,1.0);
Square sb = s1.bigger(s2).bigger(s3).bigger(s4).bigger(s5);
System.out.println("The square with the biggest area has:\n");
System.out.println("x-axis value: " + sb.x + " y-axis value: " +
sb.y + " side: " + sb.a);
}
}

Here's how to do it using Comparators and the Collections class to find the max value. This is untested but it should do what you want. Note I'm using static inner classes here but they can be standard classes defined in their own file if needs be - this is just for the purpose of creating a quick answer.
public interface Shape {
double getPerimeter();
double getArea();
}
public static class PerimeterComparator implements Comparator<Shape> {
#Override
public int compare(Shape a, Shape b) {
return Double.compare(a.getPerimeter(), b.getPerimeter());
}
}
public static class AreaComparator implements Comparator<Shape> {
#Override
public int compare(Shape a, Shape b) {
return Double.compare(a.getArea(), b.getArea());
}
}
public static class Circle implements Shape {
private final double x, y, r;
#Override
public double getPerimeter() {
return 2 * (3.14) * r;
}
#Override
public double getArea() {
return 3.14 * r * r;
}
public Circle(double x, double y, double r) {
this.x = x;
this.y = y;
this.r = r;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getR() {
return r;
}
}
public static class Square implements Shape{
private final double x, y, a;
#Override
public double getPerimeter() {
return 4 * a;
}
#Override
public double getArea() {
return a * a;
}
public Square(double x, double y, double a) {
this.x = x;
this.y = y;
this.a = a;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getA() {
return a;
}
}
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
List<Circle> circles = new ArrayList<>();
circles.add(new Circle(0.0,0.0,1.0));
circles.add(new Circle(1.0,0.0,2.0));
circles.add(new Circle(0.0,2.0,4.0));
circles.add(new Circle(1.0,3.0,1.0));
Circle largestCircle = Collections.max(circles, new PerimeterComparator());
System.out.println("The circle with the biggest circumference has:\n");
System.out.println("x-axis value: " + largestCircle.getX() + " y-axis value: " + largestCircle.getY() + " radius: " + largestCircle.getPerimeter() +"\n");
List<Square> squares = new ArrayList<>();
squares.add(new Square(0.0,0.0,1.0));
squares.add(new Square(0.0,0.0,1.0));
squares.add(new Square(0.0,0.0,5.0));
squares.add(new Square(4.0,2.0,2.0));
squares.add(new Square(0.0,0.0,1.0));
Square largestSquare = Collections.max(squares, new PerimeterComparator());
System.out.println("The square with the biggest area has:\n");
System.out.println("x-axis value: " + largestSquare.getX() + " y-axis value: " + largestSquare.getY() + " side: " + largestSquare.getA());
shapes.addAll(circles);
shapes.addAll(squares);
Shape largestPerimeter = Collections.max(shapes, new PerimeterComparator());
Shape largestArea = Collections.max(shapes, new AreaComparator());
System.out.printf("\nThe shape with the biggest perimeter is a %s and has has: a perimeter of: %f\n", largestPerimeter.getClass().getSimpleName(), largestPerimeter.getPerimeter());
System.out.printf("The shape with the biggest area is a %s and has has: an area of: %f\n", largestArea.getClass().getSimpleName(), largestArea.getArea());
}

Start by declaring a base interface, maybe called Shape that defines a method getPerimeterLength() for example.
Have all your shape classes implement that interface, and the corresponding method(s).
Now, a Square is also a Shape, and so is a Circle. Then you could put all these objects into an array of Shape. You iterate that array, and identify that entry with the maximum perimeter length. Then you simply call toString() on that object. Because you also overwrite the toString() method in all your classes to print the (different!) details each class has internally.

Related

Unable to find solution of a ray colliding a list of circles

I am coding a method that calculates the intersection of a line and a circle as a first step to write some kind of ray casting demo. In case an intersection is calculated it gets the shortest distance to the two points of intersection that will be the collision point, then it repeats the process where the new line originates from the collision point.
I was motivated by this video of a laser hitting different circles.
The method receives the angle of the line, the point where it originates, the size of the window, the radius of the circles, the array of centers of the circles and the GraphicsContext object from JavaFX.
The method has a couple of booleans to determine whether a collision has been made or not, and an ArrayList to store the collisions that will be later drawn on a JavaFX Canvas.
Inside a while loop the equation of the line is defined with the form y = m*x + b. Then checks which of the circles has a distance between the circle center and the line smaller than the radius of the line, this is calculated with the method explained here: math.stackexchange.com.
In case the distance to the center is smaller than the radius a collision occurs against that circle. As far as I know to find the intersection between a line and a circle you need to solve the equation system: y = m*x + b, (x-x1)^2 + (y-y1)^2 = r^2, that I solved via substitution. This results in a second degree polinomial equation that has a real solution if: p1*p1 >= 4*p0*p2.
The solution with the shortest distance to the origin point is the one that the line hits first and is the solution to our problem. A new angle is calculated with the center of the circle, the collision point and the origin point. With this a new line is defined and the loop repeats until no collision against the circles is calculated, situation where the collision against the borders of the window is calculated.
At the end a for loop draws all of the lines defined as couples of points inside collisionList.
This is the code, I've tried to comment it as best as I could:
private void extendPoint(double angle, Point origin, double x, double y, double radius, ArrayList<Point> pointList) {
double newAngle = angle; //Angle that defines the direction of the line
//This is used if the line does not hit a circle
double angle11 = Math.atan2(origin.getY(), origin.getX());
double angle_11 = Math.atan2(origin.getY(), -origin.getX());
double angle_1_1 = angle11 + Math.PI;
double angle1_1 = angle_11 + Math.PI;
boolean noCollision = true; //Will be true if the line does not hit a circle
boolean repeat = true; //If no collision has been made the while loop stops with this
Point currentPoint = Point.copy(origin); // (x0, y0)
Point collision = new Point(-1,-1); //Stores the collision point
Point newDirection = new Point(-1,-1); //Stores the new direction after a collision, returns(magnitud, angle) of a vector
ArrayList <Point> collisionList = new ArrayList<>(); //ArrayList of collision points that will be drawn later
collisionList.add(origin); //The origin point is added as a collision for representation purposes
while(repeat == true) {
//Line equation that passes through a point with an angle
//y = a*x - a*x0 + y0; -> y = m*x + b;
double m = Math.tan(-newAngle);
double a = m;
double b = -m*currentPoint.getX() + (currentPoint.getY());
for(int i = 0; i < pointList.size(); i++) {
Point gridPoint = pointList.get(i); //(x1, y1)
//From: https://math.stackexchange.com/questions/2552687/distance-between-line-and-point
//Given a line defined as A*x + B*y + C = 0
//x*(y1-y0)+y*(x1-x0)+(-y0*(x1-x0)-x0*(y1-y0)
double A = gridPoint.getY()-currentPoint.getY();
double B = gridPoint.getX()-currentPoint.getX();
double C = -currentPoint.getY()*B + currentPoint.getX()*A;
// double d_cp_gp = Math.abs(m*gridPoint.getX()-b*(gridPoint.getY()))/(Math.sqrt(m*m + 1));
double d_cp_gp = Math.abs(A + B + C)/Math.sqrt(A*A + B*B);
if(d_cp_gp < radius) {
System.out.println("radio " + d_cp_gp);
//The intersection between a line and a circunference:
//Circunference: (x-x1)^2 + (y-y1)^2 = r^2
//Line: y = tan(alpha)*(x-x0)+y0 -> y = a*x + b; a = tan(alfa), b = -tan(alfa)*x0 + y0
//Substituting the line equation in the circunference equation:
//x^2*(1+a^2) + x*(-2x1 + 2*a*b) + 2*a*b + x1^2+b^2-r^2 = 0
double p2 = 1 + a*a;
double p1 = -2*gridPoint.getX() + 2*a*b;
double p0 = gridPoint.getX()*gridPoint.getX() + b*b - radius*radius;
double p0_ = 4*p0*p2;
System.out.println(p1*p1 + " " + p0_);
//Check if the second order equation has solutions
if(p1*p1 >= p0_) {
System.out.println("IT HAS SOLUTION");
//Solution
double root = Math.sqrt(p1*p1 - p0_);
double sol1x = (-p1 + root)/(2*p2);
double sol2x = (-p1 - root)/(2*p2);
double sol1y = a*sol1x - a*currentPoint.getX() + currentPoint.getY();
double sol2y = a*sol1x - a*currentPoint.getX() + currentPoint.getY();
//The line will intersect twice with the circle, we want the solution
//with the shortest distance to currentPoint (x0,y0)
double distSol1 = Math.sqrt(Math.pow(currentPoint.getX()- sol1x, 2) +
Math.pow(currentPoint.getY() - sol1y, 2));
double distSol2 = Math.sqrt(Math.pow(currentPoint.getX()- sol2x, 2) +
Math.pow(currentPoint.getY() - sol2y, 2));
//The collision point is the point that the line hits first
if(distSol1 < distSol2) {
collision.setXY(sol1x, sol1y);
}
else {
collision.setXY(sol2x, sol2y);
}
//newAngle returns a vector with the form (magnitude, angle)
newDirection = newAngle(currentPoint, gridPoint, collision, radius);
currentPoint = collision;
//The new line after the collision is defined here
m = Math.tan(-newDirection.getY());
a = m;
b = -m*collision.getX() + (collision.getY());
collisionList.add(collision);
System.out.println("A collision has been calculated successfully: " + collision.toString());
//If a collision
noCollision= false;
}
}
//If no collisions have been detected at the end of the for loop exit the while loop
if(i == pointList.size() - 1 && noCollision == true) {
repeat = false;
}
}
//If no collision has been calculated with the circles this
//calculates the collision with the limits of the window
if(noCollision == true && repeat == false) {
if(angle<angle11 || angle > angle1_1) {
collision.setXY(x, m*x + b);
}
else if(angle > angle11 && angle < angle_11){
collision.setXY((0 - b)/m, 0);
}
else if(angle > angle_11 && angle < angle_1_1) {
collision.setXY(0, m*0 + b);
}
else if(angle> angle_1_1 && angle < angle1_1) {
collision.setXY((y - b)/m, y);
}
collisionList.add(collision);
}
}
System.out.println("Number of collisions: " + (int)(collisionList.size() - 1));
}
My main problem is that the shortest distance to a circle doesn't seem to be calculated properly, which directly difficults if the rest of the code works properly.
I've tried different methods to find the shortest distance and this is the one that I liked the most as I find it easy to understand, however the implementation doesn't work properly. I've thought that this could be because of JavaFX coordinate system (x increases to the right and y to the bottom) but I'm not sure, I'm a bit lost at this point.
Thanks for your time.
Edit:
As suggested I am adding some extra code to facilitate reproducibility.
The Point and Vector classes are defined as follows:
public class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;}
public double getX() {
return x;}
public double getY() {
return y;}
public void setX(double x) {
this.x = x;}
public void setY(double y) {
this.y = y;}
public void setXY(double x, double y) {
this.x = x;
this.y = y;}
#Override
public String toString() {
return("(" + this.x + "," + this.y + ")");
}
public static Point copy(Point a) {
return new Point(a.getX(), a.getY());
}
}
public class Vector {
private double vx;
private double vy;
private double ptoApX;
private double ptoApY;
private double angle;
private double modulo;
public Vector(double vx, double vy) {
this.vx = vx;
this.vy = vy;
this.ptoApX = 0;
this.ptoApY = 0;
this.angle = angle(vx,vy);
this.modulo = modulo(vx,vy);
}
//Getters
public double getVx() {
return this.vx;
}
public double getVy() {
return this.vy;
}
public double getPtoApX() {
return this.ptoApX;
}
public double getPtoApY() {
return this.ptoApY;
}
public double getAngle() {
return this.angle;
}
public double getModulo() {
return this.modulo;
}
//Setters
public void setVx(double vx) {
this.vx = vx;
}
public void setVy(double vy) {
this.vy = vy;
}
public void setPtoApX(double ptoApX) {
this.ptoApX = ptoApX;
}
public void setPtoApY(double ptoApY) {
this.ptoApY = ptoApY;
}
public void setAngle(double angle) {
this.angle = angle;
}
public void setModulo(double modulo) {
this.modulo = modulo;
}
//To String
#Override
public String toString() {
return "("+this.getVx()+","+this.getVy()+")";
}
public static double dotProduct(Vector a, Vector b) {
return a.getVx()*b.getVx() + a.getVy()*b.getVy();
}
public static Vector escalarProduct(Vector v, double n) {
return new Vector(n*v.getVx(), n*v.getVy());
}
public static Vector vectorWith2Points(Point a, Point b) {
Point p = Point.resta(a,b);
return new Vector(p.getX(),p.getY());
}
public static Vector vectorPointAngle(Point a, double angle, double modulo) {
double angleRadians = Math.toRadians(angle);
Point b = new Point(Math.cos(angleRadians)*modulo, Math.sin(angleRadians)*modulo);
return vectorWith2Points(a,b);
}
public static double modulo(double vx, double vy) {
return Math.sqrt(vx*vx + vy*vy);
}
public static double angle(double vx, double vy) {
return Math.atan2(vy, vx);
}
public static Vector normalize(Vector v) {
return new Vector(v.getVx()/v.getModulo(),v.getVy()/v.getModulo());
}
public static double angle2vectors(Vector u, Vector v) {
double argument = dotProduct(u,v)/(u.getModulo()*v.getModulo());
return Math.acos(argument);
}
public static Point polar2cart(double r, double angle) {
return new Point(r*Math.cos(angle), r*Math.sin(angle));
}
public static Point cart2polar(Point p) {
return new Point(modulo(p.getX(), p.getY()), angle(p.getX(), p.getY()));
}
}
And the method to obtain the new angle after a collision:
private Point newAngle(Point origin, Point center, Point c, double radius) {
//Normal vector
Vector n = Vector.vectorWith2Points(c, center);
Vector nNorm = Vector.normalize(n);
//Incident vector
Vector d = Vector.vectorWith2Points(c, origin);
//Tangent vector
Vector tg = new Vector(-nNorm.getVy(), nNorm.getVx());
//Reflected vector
double product = Vector.dotProduct(d,tg);
Vector r = new Vector(d.getVx()-2*product*tg.getVx(),
d.getVy() - 2*product*tg.getVy());
return new Point(r.getModulo(), r.getAngle());
}
An example of the code of different angles where a collision should be detected:
double x = 600;
double y = 400;
double radius = 10;
Point origin = new Point(x/2, y/2);
ArrayList<Point> pointList = new ArrayList<>();
pointList.add(new Point(40,40));
pointList.add(new Point(500,100));
pointList.add(new Point(40,330));
pointList.add(new Point(450,300));
//This should return a solution
extendPoint(0.4363323129985824, origin, x, y, radius, pointList);
extendPoint(2.6179938779914944, origin, x, y, radius, pointList);
//this returns a solution when it should not
extendPoint(1.5707963267948966, origin, x, y, radius, pointList);
extendPoint(-1.5707963267948966, origin, x, y, radius, pointList);
I wrote an class with everything needed to run the code here: https://pastebin.com/wMjUh9pZ
I think you should create a class that represents an intersection by a ray.
class Intersection{
double distance;
Point loc;
double normal;
}
That way, distance is along the ray and normal is the normal of the object intersected.
Then I would have a method for finding the intersetion of a circle and a point.
List<Intersection> lineAndCircle( Point org, double angle, Point center, double radius){...}
You seem to have a similar method but you're doing more work in it.
Then you also want to check the edge of the screen.
Intersection lineAndBoundary( Point org, double angle){ ... }
You have a very similar method, but you seem to be doing a lot more work in the method. . This way you are testing separate methods. Then your algorithm works as.
1 go through circles and find intersections.
2 get the intersection with the boundary.
3 find the closest intersection ( the smallest distance greater than 0 )
Doing it this way makes it a bit more extensible. First our ray is re-used a lot. Lets make a class.
class Ray{
Point origin;
double angle;
}
Then we collide a ray with multiple objects.
interface Interceptable{
List<Intersection> intercepts(Ray r);
}
Then we can use different classes.
class Circle implements Interceptable{
Point pos;
double radius;
#Override
List<Intersection> collides(Ray r){
...
}
}
Now you can right collides and testable.
Circle a = new Circle( new Point( 40, 40 ), 5 );
List<Intersection> yes = a.collides( new Ray( new Point(0, 0), 3.14/4 ) );
List<Intersection> no = a.collides( new Ray( new Point(0, 0), 0) ) );
Then you can narrow your example down to. "How do I write a collide method?" or "Why doesn't my collide method work for this ray/circle pair? I expect it to hit at two points, but it misses." etc.
Here is a complete runnable example that creates a swing window. I kinda enjoy making toy programs like this.
Note that I used an interface for the Intersectable. So now it is circles, but it could be anything that returns a list of Intersection
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.*;
import java.util.*;
public class RayAndCircle{
public static void main(String[] args){
List<Intersectable> circles = new ArrayList<>();
for(int i = 0; i<250; i++){
double r = Math.random()*50 + 50;
double x = 2048*Math.random();
double y = 2048*Math.random();
circles.add( new Circle( r, new double[]{x,y}));
}
List<LineSegment> segments = new ArrayList<>();
JFrame frame = new JFrame("Ray caster");
JPanel panel = new JPanel(){
#Override
public Dimension getPreferredSize(){
return new Dimension(2048, 2048);
}
#Override
public void paintComponent( Graphics g){
g.setColor(Color.RED);
for( Intersectable c: circles ){
c.draw(g);
}
g.setColor(Color.BLACK);
for( LineSegment segment: segments){
g.drawLine( (int) segment.a[0], (int) segment.a[1],(int)segment.b[0], (int)segment.b[1]);
}
}
};
panel.addMouseListener( new MouseAdapter(){
#Override
public void mouseClicked( MouseEvent evt ){
double x = evt.getPoint().getX();
double y = evt.getPoint().getY();
double theta = Math.random() * Math.PI * 2;
double dx = Math.cos( theta );
double dy = Math.sin( theta );
Ray ray = new Ray( new double[] {x, y}, new double[]{ dx, dy } );
int count = 500;
Intersectable last = null;
while( ray != null && count > 0 ){
Intersection hit = null;
Intersectable next = null;
for(Intersectable c: circles){
if(c == last){
continue;
}
List<Intersection> intersections = c.intersects(ray);
for(Intersection i : intersections){
if( hit == null ){
hit = i;
next = c;
} else{
if( hit.s > i.s ){
hit = i;
next = c;
}
}
}
}
if(hit != null){
last = next;
segments.add( new LineSegment( ray.origin, new double[]{ hit.pos[0], hit.pos[1] } ) );
count--;
//reflected portion of ray.
double dot = hit.normal[0]*ray.direction[0] + hit.normal[1]*ray.direction[1];
double rx = ray.direction[0] - 2 * hit.normal[0]*dot;
double ry = ray.direction[1] - 2 * hit.normal[1]*dot;
double z = Math.sqrt(rx*rx + ry*ry);
ray = new Ray(hit.pos, new double[] { rx/z, ry/z});
} else{
ray = null;
}
}
panel.repaint();
}
});
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class Ray{
double[] origin; double[] direction;
public Ray( double[] origin, double[] direction){
this.origin = new double[]{origin[0], origin[1]};
this.direction = new double[]{direction[0], direction[1]};
}
}
class Intersection{
double s;
double[] pos;
double[] normal;
Circle b;
public Intersection(double s, double[] pos, double[] normal){
this.s = s;
this.pos = pos;
setNormal(normal);
}
public void setNormal(double[] normal){
double m = Math.sqrt(normal[0]*normal[0] + normal[1]*normal[1]);
if( Double.isNaN(m) || m == 0) throw new RuntimeException("Invalid normal! Magnitude of" + m);
this.normal = new double[] { normal[0]/m , normal[1]/m };
}
}
interface Intersectable{
List<Intersection> intersects(Ray ray);
void draw(Graphics g);
}
class Circle implements Intersectable{
double[] origin;
double radius;
public Circle( double radius, double[] origin){
this.radius = radius;
this.origin = new double[]{origin[0], origin[1]};
}
Intersection intersectionAt(Ray ray, double s){
//intersection.
double locx = ray.origin[0] + s*ray.direction[0];
double locy = ray.origin[1] + s*ray.direction[1];
double nx = (locx - origin[0])/radius;
double ny = (locy - origin[1])/radius;
return new Intersection( s, new double[]{ locx, locy }, new double[]{nx, ny} );
}
public List<Intersection> intersects(Ray ray){
double rx = origin[0] - ray.origin[0];
double ry = origin[1] - ray.origin[1];
double m2 = rx*rx + ry*ry;
double m = Math.sqrt(m2);
//position along ray that is closest to circles origin.
double s = rx*ray.direction[0] + ry*ray.direction[1];
//closest distance to circle.
double approach = Math.sqrt(m2 - s*s);
List<Intersection> result = new ArrayList<>();
if( approach < radius ){
//two intersections at points on circle.
//radius is hypotenuse and approach is one of the lengths.
double l = Math.sqrt( radius*radius - approach*approach);
double s1 = s - l;
if(s1 > 0){
result.add( intersectionAt(ray, s1) );
}
double s2 = s + l;
if(s2 > 0){
//intersection!
result.add(intersectionAt(ray, s2) );
}
} else if(approach == radius){
//one intersection tangent.
if( s > 0 ){
result.add( intersectionAt(ray, s) );
}
} else{
//miss.
}
return result;
}
public void draw(Graphics g){
g.fillOval(
(int)(origin[0] - radius),
(int)(origin[1] - radius),
(int)radius*2,
(int)radius*2
);
}
}
class LineSegment{
double[] a, b;
public LineSegment( double[] a, double[] b){
this.a = new double[]{a[0], a[1]};
this.b = new double[]{b[0], b[1]};
}
}
You'll probably be most interested in the intersects method of the Circle class, and the small chunk of code burried in the mouseClicked method that calculates the reflected ray.
If you only want to know if the line intersects if a given circle, create a second line which originates at the center of the given circle and the direction is the direction of your initial line rotated by 90 degrees. Then compute the intersection of the two lines. If then the distance between the intersection point and the center of the circle is smaller then the radius, both intersect.
A while ago I wrote a small Geometry lib, I striped out the sections which are relevant for you, here is my code:
Line class
public class Line {
final Vector2D positionVector;
final Vector2D directionVector;
public Line(final Vector2D positionVector, final Vector2D directionVector) {
this.positionVector = positionVector;
this.directionVector = directionVector;
}
public OptionalDouble computeIntersection(final Line line) {
final double numerator = line.getPositionVector().subtract(this.positionVector).cross(this.directionVector);
final double denominator = this.directionVector.cross(line.directionVector);
if (Math.abs(numerator) < 1e-10 && Math.abs(denominator) < 1e-10) {
// collinear
return OptionalDouble.of(Double.POSITIVE_INFINITY);
} else if (Math.abs(denominator) < 1e-10) {
// parallel
return OptionalDouble.empty(); // Lines are parallel.
}
final double t = line.getPositionVector().subtract(this.positionVector).cross(line.directionVector) / denominator;
return OptionalDouble.of(t);
}
public Vector2D getPositionVector() {
return positionVector;
}
public Vector2D getDirectionVector() {
return directionVector;
}
public Point2D getClosestPointOnLine(final Point2D point) {
final Line line = new Line(new Vector2D(point.getX(), point.getY()), this.directionVector.turn90DegreeClockwise());
final OptionalDouble intersection = this.computeIntersection(line);
final Vector2D result = this.positionVector.add(this.directionVector.lerp(intersection.getAsDouble()));
return new Point2D(result.getX(), result.getY());
}
}
intersection function
public static PointResult intersection(final Line l1, final Circle c1) {
final Point2D intersection = l1.getClosestPointOnLine(c1.getCenter());
final double dist = intersection.distance(c1.getCenter());
if (Math.abs(dist - c1.getRadius()) < 1e-10) {
final List<Point2D> result = new LinkedList<>();
result.add(intersection);
return new PointResult(Collections.unmodifiableList(result));
} else if (dist < c1.getRadius()) {
// we have two points
final double adjacentLeg = Math.sqrt(c1.getRadius() * c1.getRadius() - dist * dist);
final Point2D pt1 = intersection.pointAt(l1.getDirectionVector().angle(), adjacentLeg);
final Point2D pt2 = intersection.pointAt(l1.getDirectionVector().angle() + Math.PI, adjacentLeg);
final List<Point2D> result = new LinkedList<>();
result.add(pt1);
result.add(pt2);
return new PointResult(Collections.unmodifiableList(result));
}
return new PointResult();
}
TestCase
#Test
void testIntersectionLineCircleTwoPoints() {
final Point2D ptCircleCenter = new Point2D(2.0, 5.0);
final Point2D ptLineCircleIntersection = new Point2D(5.0, 2.0);
final Point2D pt1 = new Point2D(3.0, 0.0);
final Point2D pt2 = new Point2D(7.0, 4.0);
final double a = Math.sqrt((2.0 * 2.0) + (2.0 * 2.0));
final double b = ptCircleCenter.diff(ptLineCircleIntersection).norm();
final double radius = Math.sqrt((a * a) + (b * b));
final Line l1 = new Line(pt1, pt2);
final Circle circle = new Circle(ptCircleCenter, radius);
PointResult intersection = GeometryOperation.intersection(l1, circle);
assertTrue(intersection.getPoints().isPresent());
assertEquals(2, intersection.getPoints().get().size());
assertEquals(7.0, intersection.getPoints().get().get(0).getX(), 1e-10);
assertEquals(4.0, intersection.getPoints().get().get(0).getY(), 1e-10);
assertEquals(3.0, intersection.getPoints().get().get(1).getX(), 1e-10);
assertEquals(0.0, intersection.getPoints().get().get(1).getY(), 1e-10);
}
I did not add the Circle, Vector2D and Point2D class because they are trivial. And the class PointResult is just a list.

Java error unable to identify mistake

This is Java code, I have created 4 classes 3 constructor and I am getting error of:
method area in class Rect cannot be applied to given types
There is a similar error for rest of 2 class as well. In this program basically I have created 4 classes, 1 for calculating area of rect, 1 for calculating area of Tri and 1 for calculating area of Square and last one is to access main function.
I have created 3 constructor for all the 3 classes rect tri and square and I am unable to spot the mistake in this program.
class Rect //1st class rect
{
double l, b; //variables
Rect(double l, double b) //constructor for rect
{
this.l = l;
this.b = b;
}
double area(double l, double b) //method to cal Rect area
{
return l * b;
}
}
class Square //square class
{
double s;
Square(Double s) //constructor for class
{
this.s = s;
}
double area(double s) //method to cal area for square
{
return s * s;
}
}
class Tri // class for triangle
{
double l, b, h; //variables
Tri(double l, double b, double h) // constructor for tri
{
this.l = l;
this.h = h;
this.b = b;
}
double area(double l, double b, double h) //method to cal area for tri
{
return 0.5 * l * b * h;
}
}
class Area3 {
public static void main(String args[]) {
Rect r = new Rect(10, 10); //constructor initialization for Rect
Square s = new Square(15.0);//constructor initialization for Square
Tri t = new Tri(10.0, 20.0, 30.0);//constructor initialization for Tri
System.out.print(" " + r.area() + "" + s.area() + "" + t.area()); //print areas
}
}
Your area method declarations state that the area methods take in arguments. With those declarations you can't say
Rect r = new Rect(1,4);
r.area();
Simply remove the double argument values from the area methods
You have to create area method without parameters, here the solution,
class Rect // 1st class rect
{
double l, b; // variables
Rect(double l, double b) // constructor for rect
{
this.l = l;
this.b = b;
}
double area(){
return this.l * this.b;
}
double area(double l, double b) // method to cal Rect area
{
return l * b;
}
}
class Square // square class
{
double s;
Square(Double s) // constructor for class
{
this.s = s;
}
double area(){
return this.s * this.s;
}
double area(double s) // method to cal area for square
{
return s * s;
}
}
class Tri // class for triangle
{
double l, b, h; // variables
Tri(double l, double b, double h) // constructor for tri
{
this.l = l;
this.h = h;
this.b = b;
}
double area(){
return 0.5 * this.l * this.b * this.h;
}
double area(double l, double b, double h) // method to cal area for tri
{
return 0.5 * l * b * h;
}
}
class Area3 {
public static void main(String args[]) {
Rect r = new Rect(10, 10); // constructor initialization for Rect
Square s = new Square(15.0);// constructor initialization for Square
Tri t = new Tri(10.0, 20.0, 30.0);// constructor initialization for Tri
System.out.print(" " + r.area() + " and " + s.area() + " and " + t.area()); // print
// areas
}
}
Hope this help, BTW it's work in my PC.
look at your contractors, they all receive an arguments.
and all your area()'s are getting also a arguments.
but!! in your main, you are calling the area() and do not give any values.
just delete from area()'s functions the receiving arguments.

Math from class isn't carrying in to object

I have to make a program that has the Circle class which calculates the area and circumference of a circle by accepting a parameter for r from a new circle object in main. I fed it the radius value of 14. This is what it should output:
***** Circle *****
radius 14.0
area 615.75164
circumference 87.96452
But instead I'm getting this
***** Circle *****
radius 14.0
area 0.0
circumference 0.0
Why is this happening and how can I fix it? I was given the overall shell of the code to make work in java and I have to keep it for the most part how it was presented to me, so while I appreciate the intention of giving recommendations on better ways to structure things and make this program in general, the teacher wants me to do it this way. The only thing I'm not sure of is what to do with setRadius(), and whether or not I should have declared r at the top of the class.
package shapedemo;
class Circle {
private double radius;
private double circumference;
private double area;
private double r;
// constructors
public Circle(){
radius = 1;
}
public Circle(double r) {
radius = r;
}
// setters and getters
public void setRadius(double radius){
this.radius = radius;
}
public double getRadius(){
return radius;
}
// other methods
public double calcArea() {
area = Math.PI * r * r;
return area;
}
public double calcCircumference(){
circumference = Math.PI * 2 * r;
return circumference;
}
// display method
public void display() {
/*blank line
***** Circle *****
radius nnnn.nn
area nnnn.nn
circumference nnnn.nn
blank line
*/
System.out.println("\n***** Circle *****\nradius " + radius + "\narea " + area + "\ncircumference " + circumference + "\n");
}
}
public class ShapeDemo {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Circle circle1 = new Circle(14);
circle1.display();
}
}
Your area and circumference variables are only being set if you call the appropriate calculation methods (calcArea and calcCircumference). You're not calling them, so they have the default values of 0.
You could fix this in your main method:
public static void main(String[] args) {
Circle circle = new Circle(14);
circle.calcArea();
circle.calcCircumference();
circle.display();
}
... although you'd also have to fix your methods to use radius instead of r, as you're never setting r.
Personally I think it would be better to either move the logic into your constructor or calculate it on demand with methods rather than having fields at all for them.
First approach, in the constructor:
final class Circle {
private final double radius;
private final double circumference;
private final double area;
public Circle() {
this(1); // Delegate to other constructor
}
public Circle(double r) {
radius = r;
area = Math.PI * radius * radius;
circumference = Math.PI * 2 * radius;
}
public void display() {
System.out.println(
"\n***** Circle *****" +
"\nradius " + radius +
"\narea " + area +
"\ncircumference " + circumference + "\n");
}
}
Second approach, making methods compute the values:
final class Circle {
private final double radius;
public Circle() {
this(1); // Delegate to other constructor
}
public Circle(double r) {
radius = r;
}
public double getRadius() {
return radius;
}
public double getArea() {
return Math.PI * radius * radius;
}
public double getCircumference() {
return Math.PI * 2 * radius;
}
public void display() {
System.out.println(
"\n***** Circle *****" +
"\nradius " + radius +
"\narea " + getArea() +
"\ncircumference " + getCircumference() + "\n");
}
}
In both cases, I've made this an immutable type - while you can keep it mutable, in the first case that would mean recomputing the area and circumference. In that case you'd probably want your constructor to just call setRadius() and make that method do all the computations.
For example:
final class Circle {
private double radius;
private double circumference;
private double area;
public Circle() {
this(1); // Delegate to other constructor
}
public Circle(double r) {
setRadius(r);
}
public void setRadius(double r) {
radius = r;
area = Math.PI * radius * radius;
circumference = Math.PI * 2 * radius;
}
public double getRadius() {
return radius;
}
public double getArea() {
return area;
}
public double getCircumference() {
return circumference;
}
public void display() {
System.out.println(
"\n***** Circle *****" +
"\nradius " + radius +
"\narea " + area +
"\ncircumference " + circumference + "\n");
}
}
You never call to calcArea() and calcCircumference(), so circumference and area have the intial 0 value.
Circle circle1 = new Circle(14);
circle1.calcArea();
circle1.calcCircumference();
circle1.display();
Or change your constructor to
public Circle(double r) {
radius = r;
calcArea();
alcCircumference();
}
You're not calling the calcArea and calcCircumference so they retain the default value 0.0d
this should be your public static void main()
public static void main(String[] args) {
Circle circle1 = new Circle(14);
circle1.calcArea();
circle1.calcCircumference();
circle1.display();
}
Also, change your return type of calcArea() and calcCircumference() to void

Static method to turn shapes red

so i made this program and i am trying to add in my testing file a static method that turns a random array of shapes all "red".
public abstract class Shape
shape class
public abstract class Shape
{
private String color;
public Shape() { color = "white";}
public String getColor() { return color;}
public void setColor(String c) { color = c; }
public abstract double area();
public abstract double perimeter();
public abstract void display();
}
circle class
public class Circle extends Shape {
private double radius;
public Circle( double r)
{
super();
radius = r;
}
public double getRadius()
{ return radius; }
//Implement area, perimeter and display
public double area()
{
return Math.PI * radius* radius;
}
public double perimeter()
{
return 2* Math.PI *radius;
}
//Circle class - continued
public void display()
{
System.out.println( this);
}
public String toString()
{
return "Circle: radius:" + radius
+ "\tColor: " + getColor();
}
}
my main class for testing
public class TestingShapes {
public static double sumArea( Shape[] b)
{
double sum = 0.0;
for( int k = 0; k < b.length; k++)
{
sum = sum + b[k].area();
}
return sum;
}
public static void printArray( Shape[] b)
{
for (Shape u: b)
System.out.println(u + "\tArearea " + u.area());
System.out.println();
}
public static void main( String[] args)
{
Shape[] list = new Shape[20]; //Not creating Shapes
for ( int k = 0 ; k < list.length; k++)
{
double z = Math.random();
if( z < 0.33 )
list[k] = new Circle(1 + Math.random() * 10);
else if(z<0.66)
list[k] = new Rectangle ( 3*(k+1), 4*(k+1), 5*(k+1),6*(k+1));
else
list[k] = new Triangle ( 3*(k+1), 4*(k+1), 5*(k+1));
}
printArray(list);
System.out.println();
double sum = sumArea(list);
System.out.println("Sum of List Area: " + sum);
}
To turn some shapes randomly red, you would create a method accepting the array of shapes, and loop over it. You can use Math.random() to get a random floating point number between 0 and 1. To turn, say, 20% of shapes red, you would just compare Math.random() to 20%: if (Math.random() < 0.2) { call the shape's setColor method with "red" }. Since arrays/collections in Java are passed by reference, you don't need to return anything from the method, it will modify the copy that the caller owns.

Multi-Level inheritance not working

I'm working on a lab for school and I have it almost completed, but there's one part that I can't get to work. The inheritance works except when I get to Cube. For some reason, it won't calculate the Area or Volume (it just comes up with 0). I'm thinking it's a problem with the way I have the inheritance from Square to Cube. Help would be awesome!
package InheritanceTest;
import javax.swing.JOptionPane;
public class InheritanceTest {
public static void main(String[] args) {
String input = "";
Point point = new Point();
input = getinput("Set variable X");
point.setx(input);
input = getinput("Set variable Y");
point.sety(input);
System.out.println("Point, x = " + point.getx() + " y = " + point.gety());
Square square = new Square();
input = getinput("Set variable Side Length");
square.setSideLength(input);
System.out.println("Square, x = " + point.getx() + " y = " + point.gety()
+ " Area = " + square.getAreaOfSquare() + " Perimeter = "
+ square.getPerimeterOfSquare());
Cube cube = new Cube();
input = getinput("Set variable depth");
cube.setDepth(input);
System.out.println("cube, x = " + point.getx() + " y = " + point.gety()
+ " Depth = " + cube.getDepth() + " Area = " + cube.getAreaOfCube()
+ " Volume = " + cube.getVolumeOfCube());
}
private static String getinput(String string) {
String x = JOptionPane.showInputDialog(string);
return x;
}
}
package InheritanceTest;
public class Cube extends Square {
private int depth;
Cube() {
super();
depth = 0;
}
Cube(int x, int y, int sideLength, int d) {
super(x, y, sideLength);
this.depth = d;
}
public int getAreaOfCube() {
return (6 * sideLength * sideLength);
}
public int getVolumeOfCube() {
return (sideLength * sideLength * sideLength);
}
public String getDepth() {
return Integer.toString(depth);
}
public void setDepth(String i) {
depth = Integer.parseInt(i);
}
}
package InheritanceTest;
public class Point {
private int x;
private int y;
Point() {
x = 0;
y = 0;
}
Point(int x, int y) {
this.x = x;
this.y = y;
}
public String getx() {
return Integer.toString(x);
}
public String gety() {
return Integer.toString(y);
}
public void setx(String input) {
x = Integer.parseInt(input);
}
public void sety(String input) {
y = Integer.parseInt(input);
}
}
package InheritanceTest;
public class Square extends Point {
protected int sideLength;
Square() {
super();
sideLength = 0;
}
Square(int x, int y, int l) {
super(x, y);
this.sideLength = l;
}
public int getAreaOfSquare() {
return sideLength * sideLength;
}
public int getPerimeterOfSquare() {
return sideLength + sideLength;
}
public String getSideLength() {
return Integer.toString(sideLength);
}
public void setSideLength(String input) {
sideLength = Integer.parseInt(input);
}
}
When you create cube (new Cube()) you aren't setting the side length (or x and y) for the Square Object it extends.
Cube(){
// This is the constructor called.
super();
depth = 0;
}
Cube(int x, int y, int sideLength, int d){
super(x, y, sideLength);
this.depth = d;
}
You probably want extract the x,y and length values into variables and use "new Cube(x, y, length, depth)"
Something like the following
String x = getinput("Set variable X");
String y = getinput("Set variable Y");
String sideLength = getinput("Set variable Side Length");
String depth getinput("Set variable depth");
Cube cube = new Cube(x, y, sideLength, depth);
Look at how you are defining getVolumeOfCube(). You are calculating volume with sideLength, but you never set sideLength to any non-zero value. Change sideLength to depth and you will get the value you are looking for.

Categories

Resources