package com.studiofortress.sf.structure.intersection;
import com.studiofortress.sf.structure.Actor;
import com.studiofortress.sf.util.Angle;
import java.awt.geom.Ellipse2D;
/**
* An EllipseIntersection represents the given Actor as an
* ellipse or circle when detecting intersections. It also
* gives some specific optimisations for comparing an
* EllipseIntersection to another EllipseIntersection.
*
* The width and height of the EllipseIntersection will be
* equal to the Actors width and height at the moment when
* the EllipseIntersection was created.
*
* Users should note that EllipseIntersections are compared
* with other EllipseIntersections for an intersection, if
* both EllipseIntersections are a circle (the Actor has the
* same width and height) then the comparison is far faster
* then if one of them was an ellipse.
*
* @author Joseph Lenton
* @version 03/08/2008
*/
public class EllipseIntersection extends ShapeIntersection
{
/**
* Creates a new EllipseIntersection which represents the given Actor as an ellipse,
* using that actors current width and height for the width and height of the EllipseIntersection.
* @param actor The actor this will be used to represent during intersections, cannot be null.
*/
public EllipseIntersection(Actor actor)
{
this(actor, actor.getWidth(), actor.getHeight());
}
/**
* Creates the EllipseIntersection as a perfect circle
* using the given diameter. The getWidth and getHeight methods
* will return the same diameter value.
* @param actor The Actor to associate with this intersection. Cannot be null.
* @param diameter The diameter of this circular EllipseIntersection. Must be greater then 0.
*/
public EllipseIntersection(Actor actor, int diameter)
{
this(actor, diameter, diameter);
}
/**
* Creates an elliptical EllipseIntersection using the given width
* and height. Those values are the width and height across the
* entire ellipse.
* @param actor The Actor to associate with this intersection. Cannot be null.
* @param width The width of this EllipseIntersection. Must be greater then 0.
* @param height The height of this EllipseIntersection. Must be greater then 0.
*/
public EllipseIntersection(Actor actor, int width, int height)
{
super(actor, new Ellipse2D.Float( -width/2, -height/2, width, height ));
}
/**
* An override of isIntersectionToShape to add EllipseIntersection
* to EllipseIntersetion intersection checking optimisations.
* If the given ShapeIntersection is not an EllipseIntersection then
* none of these optimisations are applied and it is the same as
* calling the isIntersectionToShape in the ShapeIntersection class.
* @param other The ShapeIntersection to check an intersection against.
* @return True if this EllipseIntersection intersects with the given ShapeIntersection, false if not.
*/
@Override
protected boolean isIntersectionToShape(ShapeIntersection other)
{
Actor thisActor = this.getActor();
Actor otherActor = other.getActor();
/* the use of '>> 1' is instead of 'divide by 2', they perform the same thing */
if (other instanceof EllipseIntersection) {
int thisHalfWidth = thisActor.getWidth() >> 1;
int thisHalfHeight = thisActor.getHeight() >> 1;
int otherHalfWidth = otherActor.getWidth() >> 1;
int otherHalfHeight = otherActor.getHeight() >> 1;
int xDiff = (int)Math.abs(otherActor.getX() - thisActor.getX());
int yDiff = (int)Math.abs(otherActor.getY() - thisActor.getY());
// is it definitely outside the ellipse?
if (xDiff > thisHalfWidth + otherHalfWidth | yDiff > thisHalfHeight + otherHalfHeight) {
return false;
// is it definitely inside the ellipse?
} else if (xDiff < (thisHalfWidth >> 1) && yDiff < (thisHalfHeight >> 1)) {
return true;
/* it's intersection is somewhere between certain success and fail,
* here we test if both are circles */
} else if (thisHalfWidth == thisHalfHeight && otherHalfWidth == otherHalfHeight) {
int hypot = thisHalfWidth+otherHalfWidth;
// width and height are the same value, they are both the radius
return xDiff*xDiff + yDiff*yDiff <= hypot*hypot;
// it's somewhere in between and it's an ellipse, lets do some expensive maths
} else {
float angle = Angle.atan2(yDiff, xDiff);
float hypotSqr = xDiff*xDiff + yDiff*yDiff;
float collideX = (thisHalfWidth + otherHalfWidth)*Angle.cos(angle);
float collideY = (thisHalfHeight + otherHalfHeight)*Angle.sin(angle);
float collideHypotSqr = collideX*collideX + collideY*collideY;
return collideHypotSqr >= hypotSqr;
}
}
return Intersection.intersectionShapeToShape(thisActor, getShape(), otherActor, other.getShape());
}
}
|