Rogue: Savage Rats, a retro-themed dungeon crawler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
rogue-savage-rats/src/mightypork/utils/math/coord/Rect.java

868 lines
13 KiB

package mightypork.utils.math.coord;
import mightypork.gamecore.gui.constraints.NumberConstraint;
import mightypork.gamecore.gui.constraints.RectConstraint;
import mightypork.utils.math.Calc;
/**
* Rectangle determined by two coordinates - min and max.
*
* @author MightyPork
*/
public class Rect implements RectConstraint {
public static final Rect ZERO = new Rect(0, 0, 0, 0).freeze();
public static final Rect ONE = new Rect(0, 0, 1, 1).freeze();
/**
* Rectangle from size; coords are copied.
*
* @param min min coord
* @param size rect size
* @return the rect
*/
public static Rect fromSize(Coord min, Coord size)
{
return fromSize(min, size.xi(), size.yi());
}
/**
* Make rect from min coord and size; coords are copied.
*
* @param min min coord
* @param width size x
* @param height size y
* @return the new rect
*/
public static Rect fromSize(Coord min, double width, double height)
{
return new Rect(min.copy(), min.add(width, height));
}
/**
* Rectangle from size
*
* @param sizeX size x
* @param sizeY size y
* @return rect
*/
public static Rect fromSize(double sizeX, double sizeY)
{
return fromSize(0, 0, sizeX, sizeY);
}
/**
* Get rect from size
*
* @param size size
* @return rect
*/
public static Rect fromSize(Coord size)
{
return fromSize(0, 0, size.x(), size.y());
}
/**
* Make rect from min coord and size
*
* @param xmin min x
* @param ymin min y
* @param width size x
* @param height size y
* @return the new rect
*/
public static Rect fromSize(double xmin, double ymin, double width, double height)
{
return new Rect(xmin, ymin, xmin + width, ymin + height);
}
/** Lowest coordinates xy */
protected final Coord min;
/** Highest coordinates xy */
protected final Coord max;
// view of secondary corners.
//@formatter:off
private final ConstraintCoordView HMinVMax = new ConstraintCoordView(
new NumberConstraint() {
@Override
public double getValue()
{
return min.x();
}
},
new NumberConstraint() {
@Override
public double getValue()
{
return max.y();
}
},
null
);
private final ConstraintCoordView HMaxVMin = new ConstraintCoordView(
new NumberConstraint() {
@Override
public double getValue() {
return max.x();
}
},
new NumberConstraint() {
@Override
public double getValue()
{
return min.y();
}
},
null
);
//@formatter:on
private boolean frozen;
public boolean isWritable()
{
return !frozen && !isView();
}
public boolean isView()
{
return false;
}
public Rect freeze()
{
min.freeze();
max.freeze();
frozen = true;
return this;
}
/**
* Get a readonly view
*
* @return view
*/
public RectView view()
{
return new RectView(this);
}
protected void assertWritable()
{
if (!isWritable()) {
throw new UnsupportedOperationException("This Rect is not writable.");
}
}
/**
* New Rect [0, 0, 0, 0]
*/
public Rect() {
this(0, 0, 0, 0);
}
/**
* Rect [0, 0, size.x, size.y]
*
* @param size size coord
*/
public Rect(Coord size) {
this(0, 0, size.x(), size.y());
}
/**
* New rect of two coords; Coords are plugged in directly (ie. views can be
* used for frozen rect representing another)
*
* @param min coord 1
* @param max coord 2
*/
public Rect(Coord min, Coord max) {
this.min = min; // must not copy
this.max = max; // must not copy
}
/**
* New Rect
*
* @param xmin lower x
* @param ymin lower y
* @param xmax upper x
* @param ymax upper y
*/
public Rect(double xmin, double ymin, double xmax, double ymax) {
min = new Coord(xmin, ymin);
max = new Coord(xmax, ymax);
}
/**
* Rect [0, 0, x, y]
*
* @param x width
* @param y height
*/
public Rect(double x, double y) {
this(0, 0, x, y);
}
/**
* New rect as a copy of other rect
*
* @param r other rect
*/
public Rect(Rect r) {
this(r.min.copy(), r.max.copy());
}
/**
* Get offset copy (add)
*
* @param move offset vector
* @return offset copy
*/
public Rect add(Coord move)
{
return copy().add_ip(move);
}
/**
* Add X and Y to all coordinates in a copy
*
* @param x x to add
* @param y y to add
* @return copy changed
*/
public Rect add(double x, double y)
{
return add(new Coord(x, y));
}
/**
* Offset in place (add)
*
* @param move offset vector
* @return this
*/
public Rect add_ip(Coord move)
{
min.add_ip(move);
max.add_ip(move);
return this;
}
/**
* Add X and Y to all coordinates in place
*
* @param x x to add
* @param y y to add
* @return this
*/
public Rect add_ip(double x, double y)
{
return add_ip(new Coord(x, y));
}
/**
* Get a copy
*
* @return copy
*/
public Rect copy()
{
return new Rect(this);
}
/**
* Get rect center
*
* @return center
*/
public Coord getCenter()
{
return min.midTo(max).freeze();
}
/**
* Get center of the lower edge.
*
* @return center
*/
public Coord getCenterVMin()
{
return new Coord((max.x() + min.x()) / 2D, min.y()).freeze();
}
/**
* Get center of the left edge.
*
* @return center
*/
public Coord getCenterHMin()
{
return new Coord(min.x(), (max.y() + min.y()) / 2D).freeze();
}
/**
* Get center of the right edge.
*
* @return center
*/
public Coord getCenterHMax()
{
return new Coord(max.x(), (max.y() + min.y()) / 2D).freeze();
}
/**
* Get center of the top edge.
*
* @return center
*/
public Coord getCenterVMax()
{
return new Coord((max.x() + min.x()) / 2D, max.y()).freeze();
}
/**
* Get left bottom
*
* @return center
*/
public Coord getHMinVMin()
{
return min.view();
}
/**
* Get left top
*
* @return center
*/
public Coord getHMinVMax()
{
return HMinVMax;
}
/**
* Get right bottom
*
* @return center
*/
public Coord getHMaxVMin()
{
return HMaxVMin;
}
/**
* Get right top
*
* @return center
*/
public Coord getHMaxVMax()
{
return max.view();
}
/**
* Alias for getX2Y2
*
* @return highest coordinates xy
*/
public Coord getMax()
{
return getHMaxVMax();
}
/**
* Alias for getX1Y1
*
* @return lowest coordinates xy
*/
public Coord getMin()
{
return getHMinVMin();
}
/**
* Alias for getX1Y1
*
* @return lowest coordinates xy
*/
public Coord getOrigin()
{
return getHMinVMin();
}
/**
* Shrink to sides in copy
*
* @param shrink shrink size (added to each side)
* @return shrinkn copy
*/
public Rect shrink(Coord shrink)
{
return copy().shrink_ip(shrink);
}
/**
* Shrink to sides in copy
*
* @param x x to add
* @param y y to add
* @return changed copy
*/
public Rect shrink(double x, double y)
{
return copy().shrink_ip(x, y);
}
/**
* Shrink to sides in place
*
* @param shrink shrink size (added to each side)
* @return this
*/
public Rect shrink_ip(Coord shrink)
{
shrink_ip(shrink.x(), shrink.y());
return this;
}
/**
* Shrink to sides in place
*
* @param x horizontal shrink
* @param y vertical shrink
* @return this
*/
public Rect shrink_ip(double x, double y)
{
min.sub_ip(x, y);
max.add_ip(-x, -y);
return this;
}
/**
* Shrink the rect
*
* @param xmin shrink
* @param ymin shrink
* @param xmax shrink
* @param ymax shrink
* @return changed copy
*/
public Rect shrink(double xmin, double ymin, double xmax, double ymax)
{
return copy().shrink_ip(xmin, ymin, xmax, ymax);
}
/**
* Shrink the rect in place
*
* @param xmin shrink
* @param ymin shrink
* @param xmax shrink
* @param ymax shrink
* @return this
*/
public Rect shrink_ip(double xmin, double ymin, double xmax, double ymax)
{
min.add_ip(xmin, ymin);
max.add_ip(-xmax, -ymax);
return this;
}
/**
* Grow to sides in copy
*
* @param grow grow size (added to each side)
* @return grown copy
*/
public Rect grow(Coord grow)
{
return copy().grow_ip(grow);
}
/**
* Grow to sides in copy
*
* @param x horizontal grow
* @param y vertical grow
* @return changed copy
*/
public Rect grow(double x, double y)
{
return copy().grow_ip(x, y);
}
/**
* Grow to sides in place
*
* @param grow grow size (added to each side)
* @return this
*/
public Rect grow_ip(Coord grow)
{
grow_ip(grow.x(), grow.y());
return this;
}
/**
* Grow to sides in place
*
* @param x horizontal grow
* @param y vertical grow
* @return this
*/
public Rect grow_ip(double x, double y)
{
min.sub_ip(x, y);
max.add_ip(x, y);
return this;
}
/**
* Grow the rect
*
* @param xmin growth
* @param ymin growth
* @param xmax growth
* @param ymax growth
* @return changed copy
*/
public Rect grow(double xmin, double ymin, double xmax, double ymax)
{
return copy().grow_ip(xmin, ymin, xmax, ymax);
}
/**
* Grow the rect in place
*
* @param xmin growth
* @param ymin growth
* @param xmax growth
* @param ymax growth
* @return this
*/
public Rect grow_ip(double xmin, double ymin, double xmax, double ymax)
{
min.add_ip(-xmin, -ymin);
max.add_ip(xmax, ymax);
return this;
}
/**
* Check if point is inside this rectangle
*
* @param point point to test
* @return is inside
*/
public boolean isInside(Coord point)
{
return Calc.inRange(point.x(), min.x(), max.x()) && Calc.inRange(point.y(), min.y(), max.y());
}
/**
* Multiply in copy
*
* @param factor multiplier
* @return offset copy
*/
public Rect mul(double factor)
{
return copy().mul_ip(factor);
}
/**
* Multiply by number (useful for centered rects)
*
* @param x x multiplier
* @param y y multiplier
* @return copy multiplied
*/
public Rect mul(double x, double y)
{
return copy().mul_ip(x, y);
}
/**
* Multiply coord in place
*
* @param factor multiplier
* @return this
*/
public Rect mul_ip(double factor)
{
min.mul_ip(factor);
max.mul_ip(factor);
return this;
}
/**
* Multiply coord in place
*
* @param x multiplier x
* @param y multiplier y
* @return this
*/
public Rect mul_ip(double x, double y)
{
min.mul_ip(x, y, 1);
max.mul_ip(x, y, 1);
return this;
}
/**
* Round coords in copy
*
* @return copy, rounded
*/
public Rect round()
{
return new Rect(min.round(), max.round());
}
/**
* Round this in place
*
* @return this
*/
public Rect round_ip()
{
min.round_ip();
max.round_ip();
return this;
}
/**
* Set to coordinates
*
* @param xmin lower x
* @param ymin lower y
* @param xmax upper x
* @param ymax upper y
*/
public void setTo(double xmin, double ymin, double xmax, double ymax)
{
min.setTo(Math.min(xmin, xmax), Math.min(ymin, ymax));
max.setTo(Math.max(xmin, xmax), Math.max(ymin, ymax));
}
/**
* Set to other rect's coordinates
*
* @param r other rect
*/
public void setTo(Rect r)
{
min.setTo(r.min);
max.setTo(r.max);
}
/**
* Subtract X and Y from all coordinates in a copy
*
* @param x x to subtract
* @param y y to subtract
* @return copy changed
*/
public Rect sub(double x, double y)
{
return sub(new Coord(x, y));
}
/**
* Get offset copy (subtract)
*
* @param move offset vector
* @return offset copy
*/
public Rect sub(Coord move)
{
return copy().sub_ip(move);
}
/**
* Subtract X and Y from all coordinates in place
*
* @param x x to subtract
* @param y y to subtract
* @return this
*/
public Rect sub_ip(double x, double y)
{
return sub_ip(new Coord(x, y));
}
/**
* Offset in place (subtract)
*
* @param move offset vector
* @return this
*/
public Rect sub_ip(Coord move)
{
min.sub_ip(move);
max.sub_ip(move);
return this;
}
@Override
public String toString()
{
return String.format("[%s-%s]", min.toString(), max.toString());
}
/**
* @return lower x
*/
public double xMin()
{
return min.x();
}
/**
* @return upper x
*/
public double xMax()
{
return max.x();
}
/**
* @return lower y
*/
public double yMin()
{
return min.y();
}
/**
* @return upper y
*/
public double yMax()
{
return max.y();
}
public double getHeight()
{
return max.y() - min.y();
}
public double getWidth()
{
return max.x() - min.x();
}
/**
* Get size (width, height) as (x,y)
*
* @return coord of width,height
*/
public Coord getSize()
{
return new Coord(max.x() - min.x(), max.y() - min.y());
}
@Override
public Rect getRect()
{
return this;
}
/**
* Generate zero rect
*
* @return zero
*/
public static Rect zero()
{
return ZERO.copy();
}
/**
* Generate 0,0-1,1 rect
*
* @return one
*/
public static Rect one()
{
return ZERO.copy();
}
}