How do I use double dispatch to analyze intersection of graphic primitives? - java

I am analyzing the interaction of graphics primitives (rect, line, circle, etc.) and computing the overlap, relative orientation, merging, etc. This is quoted as a prime example of Double Dispatch (e.g. Wikipedia)
Adaptive collision algorithms usually require that collisions between
different objects be handled in different ways. A typical example is
in a game environment where the collision between a spaceship and an
asteroid is computed differently than the collision between a
spaceship and a spacestation.1
but I haven't understood the main explanations and I also don't generally understand the answers on SO.
My current code (Java) uses a superclass Shape and is something like:
for (int i = 0; i < shapes.size() - 1; i++) {
for (int j = i + 1; j < shapes.size(); j++) {
Shape shape = shapes.get(i).intersectionWith(shapes.get(j));
}
}
with specific implementations in subclasses (here Rect) such as
public class Rect extends Shape {
public Shape intersectionWith(Shape shape) {
if (shape instanceof Rect) {
return this.getCommonBoundingBox((Rect)shape);
} else if (shape instanceof Line) {
return this.intersection((Line)shape);
} else if (shape instanceof Text) {
return this.intersection((Text) shape);
}
}
}
I have to write all the n*(n-1)/2 methods anyway (and have done so). I also have to have extensible code to accommodate (say) at a later date:
} else if (shape instanceof Circle) {
return this.intersection((Circle)shape);
I don't see how to use, or the value of, the double dispatch pattern and would appreciate a concrete example using Java graphics primitives or similar pseudocde.
UPDATE: I have accepted #Flavio as (I think) it answers the exact question asked. However I have actually implemented #Slanec as it solves my problem and (to me) is simpler and easier to read. I have a subsidiary question "Do the solutions depend on the relationship being symmetric?".
"A intersects B" is usually identical to "B intersects A" but "A collides with B" is not always the same as "B collides with A". (A == car, B == cyclist). It is conceivable that my intersections may not be symmetric in futute (e.g. "Rect partially obscures Circle" is not symmetric and may have different semantics.
#Flavio addresses the maintenance problem well, and points out that the compiler can check for problems. #Slanec does this through reflection which looks as if it is a useful maintenance aid - I don't know what the performance hit is.

You can implement double dispatch in Java through the Visitor pattern.
public interface ShapeVisitor<P, R> {
R visitRect(Rect rect, P param);
R visitLine(Line line, P param);
R visitText(Text text, P param);
}
public interface Shape {
<P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor);
Shape intersectionWith(Shape shape);
}
public class Rect implements Shape {
public <P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor) {
return visitor.visitRect(this, param);
}
public Shape intersectionWith(Shape shape) {
return shape.accept(this, RectIntersection);
}
public static ShapeVisitor<Rect, Shape> RectIntersection = new ShapeVisitor<Rect, Shape>() {
public Shape visitRect(Rect otherShape, Rect thisShape) {
// TODO...
}
public Shape visitLine(Line otherShape, Rect thisShape) {
// TODO...
}
public Shape visitText(Text otherShape, Rect thisShape) {
// TODO...
}
};
}
When you add a new Shape subclass, you must add a new method to the ShapeVisitor interface, and you get compile errors for all the methods you are missing. This is useful, but can become a big problem if you are writing a library and your users are allowed to add Shape subclasses (but clearly can not extend the ShapeVisitor interface).

I think it would be something like this:
import java.util.ArrayList;
import java.util.List;
public class DoubleDispatchTest {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<Shape>();
shapes.add(new Line());
shapes.add(new Circle());
shapes.add(new Rect());
for (int i = 0; i < shapes.size() - 1; i++) {
for (int j = i + 1; j < shapes.size(); j++) {
Shape shape = shapes.get(i).intersection(shapes.get(j));
}
}
}
abstract static class Shape {
abstract Shape intersection(Shape shape);
abstract Shape intersection(Line line);
abstract Shape intersection(Circle line);
abstract Shape intersection(Rect line);
}
static class Line extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("line + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("line + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("line + rect");
return null;
}
}
static class Circle extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("circle + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("circle + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("circle + rect");
return null;
}
}
static class Rect extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("rect + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("rect + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("rect + rect");
return null;
}
}
}
The output of the example is:
circle + line
rect + line
rect + circle

Disclaimer: I am not really familiar with Double dispatch. I've seen it, I've read the wiki article, but that's it. I am simply trying to tackle the problem the best I can.
The instanceof hell
We can leverage that the class information about both intersected Shape objects is known at runtime. The Rect running your code knows it's a Rect and the shape parameter is of type Shape, but when a method is ran on it, it will invoke the correctly overridden version of the concrete Shape type.
In the code below, the correct intersect() overload will be called on the correct Shape type:
public interface Shape {
public Shape intersect(Shape shape);
public Shape intersect(Line line);
public Shape intersect(Rect rect);
}
public class Line implements Shape {
#Override
public Shape intersect(Shape shape) {
return shape.intersect(this);
}
#Override
public Shape intersect(Line line) {
System.out.println("Line - Line");
return null;
}
#Override
public Shape intersect(Rect rect) {
System.out.println("Line - Rect");
return null;
}
}
The generic implementation of public Shape intersect(Shape shape); must be copypasted into all implementing classes. If you tried to change the Shape interface to a an abstract class and have the method there, it wouldn't work, because the method will call itself recursively:
public abstract class Shape {
public final Shape intersect(Shape shape) {
return shape.intersect(this);
}
public abstract Shape intersect(Line line);
public abstract Shape intersect(Rect rect);
}
However, you can use reflection to get it done:
public abstract class Shape {
public final Shape intersect(Shape shape) {
try {
Method intersect = this.getClass().getMethod("intersect", shape.getClass());
return (Shape)intersect.invoke(this, shape);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public abstract Shape intersect(Line line);
public abstract Shape intersect(Rect rect);
}

Related

How to call a method from all implement java

I have one interface
public interface GeometricObject {
public String getInfo();
}
And I have 2 classes, which implement the above interface.
public class Circle implements GeometricObject {
#Override
public String getInfo() {
return "Circle[center,radius]";
}
}
public class Triangle implements GeometricObject {
#Override
public String getInfo() {
return "Triangle[p1,p2,p3]";
}
}
And now I have this class to show all info that:
public class shapeUtils{
public String printInfo(List<GeometricObject> shapes) {
//code here
}
}
How can I call that method in all implements to that list
e.g.
Circle:
Circle[(1,2),r=3]
Circle[(5,6),r=2]
Triangle:
Triangle[(1,2),(2,3),(3,0)]
Triangle[(-1,-3),(-5,3),(0,0)]
Just call it
for (GeometricObject shp : shapes) {
System.out.println (shp.getInfo());
}
I you want more simplicity.
shapes.forEach(shape -> System.out.println(shape.getInfo()));
First you have to add the fields that you need to your shapes. For example in the triangle you need p1, p2, p3. They must be part of the class if you want to get the right values printed.
E.g:
public class Circle implements GeometricObject {
private double center;
private double radius;
#Override
public String getInfo() {
return "Circle[ " + this.center + ", " + this.radius + " ]";
}
// Getters and setters
}
You do the same for all the shapes.
You can fill a list with objects like this:
java.util.List<GeometricObject> shapes = new ArrayList<>();
Circle circle = new Circle(); // Initialize it
circle.setCenter(2); // Set the values
circle.setRadius(2);
shapes.add(circle); // Add it to the list
// Add some more objects into the list...
// Print them:
for (GeometricObject shape : shapes) {
System.out.println(shape.getInfo());
}

Java Polymorphism Subclass Functioncall

I am pretty sure I can find an answer on Stackoverflow for this question. Unfortunately I do not know the specific formulation to do so.
Given following code I have the problem, that I want to avoid typechecks. The comments will probably describe it better than my words.
Right now I am trying to have a shapesystem where every shape can collide with every possible specificShape.
CollisionClass:
public class ShapeCollision {
public static boolean intersects(RectShape rectShape1, RectShape rectShape2) { return true; }
public static boolean intersects(LineShape lineShape, RectShape rectShape) { return true; }
public static boolean intersects(RectShape rectShape1, Shape shape) { return true; }
public static boolean intersects(LineShape lineShape, Shape shape) { return true; }
public static boolean intersects(Shape shape1, Shape shape2){ return true; }
}
ShapeClasses:
public class RectShape extends Shape {
Vector size;
public RectShape(Vector pos, Vector size) {
super(pos);
this.size = size;
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
public class LineShape extends Shape {
Vector pos2;
public LineShape(Vector pos, Vector pos2) {
super(pos);
this.pos2 = pos2;
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
public class Shape implements IShape {
protected Vector pos;
public Shape(Vector pos) {
this.pos = pos;
}
#Override
public Vector getPos() {
return pos;
}
#Override
public void setPos(Vector pos) {
this.pos = pos;
}
#Override
public void move(Vector movementAmount) {
pos.add(movementAmount);
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
Here is the confusing part for me:
Shape rect = new RectShape(new Vector(0,0), new Vector(20,20));
Shape rect2 = new RectShape(new Vector(0,0), new Vector(20,20));
Shape line = new LineShape(new Vector(0,0), new Vector(20,20));
//Since I am saving shape and no specific shapetype, it will pass shape and pick the specific superFunction
//Right now it calls the intersects(RectShape rectShape1, Shape shape) function due to calling it through the shape variable
rect.intersects(rect2);
//This calls the intersects(LineShape lineShape, Shape shape) function
rect.intersects(line);
//This calls the intersects(Shape shape1, Shape shape2) function
ShapeCollision.intersects(rect, line);
How can I achieve it without specifying the type of the variable, that the 'correct' function with the subclass parameter is called. (e.g.: (LineShape lineShape, RectShape rectShape))
I do not want to make any typechecks in those functions and call the functions specifically, but to use some DesignPatters or something similar if possible :)
What you want is NOT achievable without some type checking inside the functions or some explicit casting done on the Shape instances before passing them to the function calls.
Of course you could declare the objects references with the specific classes, but i guess that is not really helpful.

Regarding casting in Java within class hierarchies [duplicate]

I have a base class called Geometry from which there exists a subclass Sphere:
public class Geometry
{
String shape_name;
String material;
public Geometry()
{
System.out.println("New geometric object created.");
}
}
and a subclass:
public class Sphere extends Geometry
{
Vector3d center;
double radius;
public Sphere(Vector3d coords, double radius, String sphere_name, String material)
{
this.center = coords;
this.radius = radius;
super.shape_name = sphere_name;
super.material = material;
}
}
I have an ArrayList that contains all Geometry objects and I want to iterate over it to check whether the data from a text file is read in correctly. Here is my iterator method so far:
public static void check()
{
Iterator<Geometry> e = objects.iterator();
while (e.hasNext())
{
Geometry g = (Geometry) e.next();
if (g instanceof Sphere)
{
System.out.println(g.shape_name);
System.out.println(g.material);
}
}
}
How do I access and print out the Sphere's radius and center fields?
Thanks in advance :)
If you want to access properties of a subclass, you're going to have to cast to the subclass.
if (g instanceof Sphere)
{
Sphere s = (Sphere) g;
System.out.println(s.radius);
....
}
This isn't the most OO way to do things, though: once you have more subclasses of Geometry you're going to need to start casting to each of those types, which quickly becomes a big mess. If you want to print the properties of an object, you should have a method on your Geometry object called print() or something along those lines, that will print each of the properties in the object. Something like this:
class Geometry {
...
public void print() {
System.out.println(shape_name);
System.out.println(material);
}
}
class Shape extends Geometry {
...
public void print() {
System.out.println(radius);
System.out.println(center);
super.print();
}
}
This way, you don't need to do the casting and you can just call g.print() inside your while loop.
You have to cast (specifically, downcast):
((Sphere) g).radius
I agree with rwhat, but instead of implementing your own print() function, it might benefit you (and be more Object Oriented) to avoid the downcasts by overriding the toString() function.
public class Geometry
{
String shape_name;
String material;
public Geometry()
{
System.out.println("New geometric object created.");
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Shape name: " + shape_name + "\t");
result.append("Material: " + material + "\t");
return result.toString();
}
public static void check (Geometry[] gList) {
for (Geometry g: gList) {
System.out.println(g.toString());
}
}
Note the check() doesn't care whether g is a Sphere or a Cube. This will help minimize the calls to instanceof.
Over in Sphere...
public class Sphere extends Geometry
{
Vector3d center;
double radius;
public Sphere(Vector3d coords, double radius, String sphere_name, String material)
{
this.center = coords;
this.radius = radius;
shape_name = sphere_name;
super.material = material;
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Radius: " + radius + "\t");
result.append("Center: " + center.toString() + "\t");
result.append(super.toString());
return result.toString();
}
}
Any new shape (e.g., Cone) would benefit by having the toString() function, but lacking it would just print out Geometry's version.
use instanceof and Cast to the desired subclass. You might want to make those fields public or the standard idiom of private fields with getters and setters too.

best way to implement collision detector in oop

I am making a simple physics based game in java and i am stuck in implementing the collision detection methods. I have several classes which inherits from a comman base class shape. I am storing all the visible objects in an arraylist of shape class. I have created several collision detection methods for every possible collision of objects.
When i started implementing the methods i ended up with a code like this:
private void collision_detector(Shape s1,Shape s2){
if(s1.getClass()==Ball.class)
if(s2.getClass() == Block.class) collision_detector((Ball)s1,(Block)s2);
else collision_detector((Ball)s1,(Ball)s2);
else if(s1.getClass()==Block.class)
if(s2.getClass()==Block.class) collision_detector((Block)s1,(Block)s2);
else collision_detector((Ball)s2,(Block)s1);
}
It just doesn't feel like the right way to implement the collision detection because i have to update this method to check for every possible combination every time i add a new shape like triangle or hexagon.
I know a bit about Visitor patterns. But Is there any better way to do this ?
If you don't mind putting collision detection code in the objects themselves, you could eliminate one side of the checks by doing something like:
public abstract class Shape {
public abstract boolean collidesWith (Shape s);
}
public class Ball extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return Collision.blockBall((Block)s, this);
else if (s instanceof Ball)
return Collision.ballBall(this, (Ball)s);
else
return false;
}
}
public class Block extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return Collision.blockBlock(this, (Block)s);
else if (s instanceof Ball)
return Collision.blockBall(this, (Ball)s);
else
return false;
}
}
public class Collision {
public static boolean blockBlock (Block a, Block b) { ... }
public static boolean blockBall (Block a, Ball b) { ... }
public static boolean ballBall (Ball a, Ball b) { ... }
}
That also gives you the freedom to implement collision algorithms for certain combinations of Shapes in the Shape itself if necessary -- you can even get rid of Collision and just make e.g. Block.collideWithBall, Block.collideWithBlock, and Ball.collideWithBlock, calling those as appropriate, e.g.:
public abstract class Shape {
public abstract boolean collidesWith (Shape s);
}
public class Ball extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return collidesWithBlock((Block)s);
else if (s instanceof Ball)
return collidesWithBall((Ball)s);
else
return false;
}
public boolean collidesWithBall (Ball b) {
...
}
public boolean collidesWithBlock (Block b) {
...
}
}
public class Block extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return collidesWithBlock((Block)s);
else if (s instanceof Ball)
return ((Ball)s).collidesWithBlock(this);
else
return false;
}
public boolean collidesWithBlock (Block b) {
...
}
}
Personally, I kind of like the latter better, since it keeps collision code contained in the relevant classes. Note that Block.collidesWithBall is unnecessary, as Ball.collidesWithBlock can be used.
You still have to update the above code each time you add a new shape. If performance is not an issue, you could do something like this as well:
public abstract class CollisionAlgorithm {
public abstract boolean canCollide (Class<? extends Shape> a, Class<? extends Shape> b);
public abstract boolean collide (Shape a, Shape b);
}
public class Collider {
private static final List<CollisionAlgorithm> algorithms;
public static void registerAlgorithm (CollisionAlgorithm a) {
algorithms.append(a);
}
public static CollisionAlgorithm findAlgorithm (Class<? extends Shape> a, Class<? extends Shape> b) {
for (CollisionAlgorithm algo : algorithms)
if (algo.canCollide(a, b))
return algo;
return null;
}
public static boolean collide (Shape a, Shape b) {
if (a == null || b == null)
return false;
CollisionAlgorithm algo = findAlgorithm(a.getClass(), b.getClass());
if (algo != null)
return algo.collide(a, b);
algo = findAlgorithm(b.getClass(), a.getClass()); // try swapped order
if (algo != null)
return algo.collide(b, a);
return false;
}
}
// usage: first register algorithms
Collider.registerAlgorithm(new BallBallAlgorithm());
Collider.registerAlgorithm(new BallBlockAlgorithm());
Collider.registerAlgorithm(new BlockBlockAlgorithm());
// then
Shape myShape1 = ...;
Shape myShape2 = ...;
boolean collide = Collider.collide(myShape1, myShape2);
Please note: I typed this here quickly, and it's meant to illustrate a concept -- many improvements can be made. For example, a map can be used with the two Shape classes as a key to improve performance, or CollisionAlgorithm can be given generic parameters to eliminate the need for casting Shapes. Still, keep in mind, this approach requires a lookup in the algorithm container every time you need to perform a collision test.

Access subclass fields from a base class in Java

I have a base class called Geometry from which there exists a subclass Sphere:
public class Geometry
{
String shape_name;
String material;
public Geometry()
{
System.out.println("New geometric object created.");
}
}
and a subclass:
public class Sphere extends Geometry
{
Vector3d center;
double radius;
public Sphere(Vector3d coords, double radius, String sphere_name, String material)
{
this.center = coords;
this.radius = radius;
super.shape_name = sphere_name;
super.material = material;
}
}
I have an ArrayList that contains all Geometry objects and I want to iterate over it to check whether the data from a text file is read in correctly. Here is my iterator method so far:
public static void check()
{
Iterator<Geometry> e = objects.iterator();
while (e.hasNext())
{
Geometry g = (Geometry) e.next();
if (g instanceof Sphere)
{
System.out.println(g.shape_name);
System.out.println(g.material);
}
}
}
How do I access and print out the Sphere's radius and center fields?
Thanks in advance :)
If you want to access properties of a subclass, you're going to have to cast to the subclass.
if (g instanceof Sphere)
{
Sphere s = (Sphere) g;
System.out.println(s.radius);
....
}
This isn't the most OO way to do things, though: once you have more subclasses of Geometry you're going to need to start casting to each of those types, which quickly becomes a big mess. If you want to print the properties of an object, you should have a method on your Geometry object called print() or something along those lines, that will print each of the properties in the object. Something like this:
class Geometry {
...
public void print() {
System.out.println(shape_name);
System.out.println(material);
}
}
class Shape extends Geometry {
...
public void print() {
System.out.println(radius);
System.out.println(center);
super.print();
}
}
This way, you don't need to do the casting and you can just call g.print() inside your while loop.
You have to cast (specifically, downcast):
((Sphere) g).radius
I agree with rwhat, but instead of implementing your own print() function, it might benefit you (and be more Object Oriented) to avoid the downcasts by overriding the toString() function.
public class Geometry
{
String shape_name;
String material;
public Geometry()
{
System.out.println("New geometric object created.");
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Shape name: " + shape_name + "\t");
result.append("Material: " + material + "\t");
return result.toString();
}
public static void check (Geometry[] gList) {
for (Geometry g: gList) {
System.out.println(g.toString());
}
}
Note the check() doesn't care whether g is a Sphere or a Cube. This will help minimize the calls to instanceof.
Over in Sphere...
public class Sphere extends Geometry
{
Vector3d center;
double radius;
public Sphere(Vector3d coords, double radius, String sphere_name, String material)
{
this.center = coords;
this.radius = radius;
shape_name = sphere_name;
super.material = material;
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Radius: " + radius + "\t");
result.append("Center: " + center.toString() + "\t");
result.append(super.toString());
return result.toString();
}
}
Any new shape (e.g., Cone) would benefit by having the toString() function, but lacking it would just print out Geometry's version.
use instanceof and Cast to the desired subclass. You might want to make those fields public or the standard idiom of private fields with getters and setters too.

Categories

Resources