/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fge.geom; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.List; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.fge.geom.area.FGEArea; import org.openflexo.fge.geom.area.FGEBand; import org.openflexo.fge.geom.area.FGEEmptyArea; import org.openflexo.fge.geom.area.FGEExclusiveOrArea; import org.openflexo.fge.geom.area.FGEHalfBand; import org.openflexo.fge.geom.area.FGEHalfLine; import org.openflexo.fge.geom.area.FGEHalfPlane; import org.openflexo.fge.geom.area.FGEIntersectionArea; import org.openflexo.fge.geom.area.FGESubstractionArea; import org.openflexo.fge.geom.area.FGEUnionArea; import org.openflexo.fge.graphics.FGEGraphics; public class FGERectangle extends Rectangle2D.Double implements FGEGeometricObject<FGERectangle>, FGEShape<FGERectangle> { private static final Logger logger = Logger.getLogger(FGERectangle.class.getPackage().getName()); protected Filling _filling; public FGERectangle() { this(0, 0, 0, 0, Filling.NOT_FILLED); } public FGERectangle(Filling filling) { this(0, 0, 0, 0, filling); } public FGERectangle(double aX, double aY, double aWidth, double aHeight) { this(aX, aY, aWidth, aHeight, Filling.NOT_FILLED); } public FGERectangle(FGERectangle rectangle) { this(rectangle.x, rectangle.y, rectangle.width, rectangle.height, rectangle._filling); } public FGERectangle(double aX, double aY, double aWidth, double aHeight, Filling filling) { super(aX, aY, aWidth, aHeight); if (aWidth < 0) { x = x + aWidth; aWidth = -aWidth; } if (aHeight < 0) { y = y + aHeight; aHeight = -aHeight; } _filling = filling; } public FGERectangle(FGEPoint point, FGEDimension dimension, Filling filling) { this(point.x, point.y, dimension.width, dimension.height, filling); } public FGERectangle(FGEPoint p1, FGEPoint p2, Filling filling) { this(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y), Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y), filling); } public FGERectangle(Rectangle rect) { this(rect.x, rect.y, rect.width, rect.height); } @Override public boolean getIsFilled() { return _filling == Filling.FILLED; } @Override public void setIsFilled(boolean filled) { _filling = filled ? Filling.FILLED : Filling.NOT_FILLED; } @Override public FGEPoint getCenter() { return new FGEPoint(getCenterX(), getCenterY()); } /** * Creates a new object of the same class and with the same contents as this object. * * @return a clone of this instance. * @exception OutOfMemoryError * if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ @Override public FGERectangle clone() { return (FGERectangle) super.clone(); } /** * Return nearest point from point "from" following supplied orientation * * Returns null if no intersection was found * * @param from * point from which we are coming to area * @param orientation * orientation we are coming from * @return */ @Override public FGEPoint nearestPointFrom(FGEPoint from, SimplifiedCardinalDirection orientation) { FGEHalfLine hl = FGEHalfLine.makeHalfLine(from, orientation); FGEArea intersection = computeLineIntersection(hl); if (intersection instanceof FGEEmptyArea) { return null; } else if (intersection instanceof FGEPoint) { return (FGEPoint) intersection; } else if (intersection instanceof FGEPoint) { return (FGEPoint) intersection; } else if (intersection instanceof FGEUnionArea) { FGEPoint returned = null; double minimalDistanceSq = java.lang.Double.POSITIVE_INFINITY; for (FGEArea a : ((FGEUnionArea) intersection).getObjects()) { if (a instanceof FGEPoint) { double distSq = FGEPoint.distanceSq(from, (FGEPoint) a); if (distSq < minimalDistanceSq) { returned = (FGEPoint) a; minimalDistanceSq = distSq; } } } return returned; } else if (intersection instanceof FGESegment) { FGEPoint p1, p2; p1 = ((FGESegment) intersection).getP1(); p2 = ((FGESegment) intersection).getP2(); if (FGEPoint.distanceSq(from, p1) < FGEPoint.distanceSq(from, p2)) { return p1; } else { return p2; } } logger.warning("Unexpected area: " + intersection); return null; } public FGEPoint getNorthWestPt() { return getNorth().getP1(); } public FGEPoint getNorthPt() { return getNorth().getMiddle(); } public FGEPoint getNorthEastPt() { return getNorth().getP2(); } public FGEPoint getSouthWestPt() { return getSouth().getP1(); } public FGEPoint getSouthPt() { return getSouth().getMiddle(); } public FGEPoint getSouthEastPt() { return getSouth().getP2(); } public FGEPoint getEastPt() { return getEast().getMiddle(); } public FGEPoint getWestPt() { return getWest().getMiddle(); } public FGESegment getNorth() { return new FGESegment(getX(), getY(), getX() + getWidth(), getY()); } public FGESegment getSouth() { return new FGESegment(getX(), getY() + getHeight(), getX() + getWidth(), getY() + getHeight()); } public FGESegment getEast() { return new FGESegment(getX() + getWidth(), getY(), getX() + getWidth(), getY() + getHeight()); } public FGESegment getWest() { return new FGESegment(getX(), getY(), getX(), getY() + getHeight()); } public List<FGESegment> getFrameSegments() { Vector<FGESegment> returned = new Vector<FGESegment>(); returned.add(getNorth()); returned.add(getSouth()); returned.add(getEast()); returned.add(getWest()); return returned; } @Override public FGEPoint getNearestPoint(FGEPoint aPoint) { if (getIsFilled() && containsPoint(aPoint)) { return aPoint.clone(); } return nearestOutlinePoint(aPoint); } @Override public FGEPoint nearestOutlinePoint(FGEPoint aPoint) { FGEPoint returned = null; double distSq, minimalDistanceSq = java.lang.Double.POSITIVE_INFINITY; FGESegment north = getNorth(); FGESegment south = getSouth(); FGESegment east = getEast(); FGESegment west = getWest(); FGEPoint p = north.getNearestPointOnSegment(aPoint); distSq = FGEPoint.distanceSq(p, aPoint); if (distSq < minimalDistanceSq) { returned = p; minimalDistanceSq = distSq; } p = south.getNearestPointOnSegment(aPoint); distSq = FGEPoint.distanceSq(p, aPoint); if (distSq < minimalDistanceSq) { returned = p; minimalDistanceSq = distSq; } p = east.getNearestPointOnSegment(aPoint); distSq = FGEPoint.distanceSq(p, aPoint); if (distSq < minimalDistanceSq) { returned = p; minimalDistanceSq = distSq; } p = west.getNearestPointOnSegment(aPoint); distSq = FGEPoint.distanceSq(p, aPoint); if (distSq < minimalDistanceSq) { returned = p; minimalDistanceSq = distSq; } return returned; } private FGEArea computeRectangleIntersection(FGERectangle rect) { if (!getIsFilled() && rect.getIsFilled()) { return rect.computeRectangleIntersection(this); } if (rect.equals(this)) { return clone(); } double x1 = Math.max(getMinX(), rect.getMinX()); double y1 = Math.max(getMinY(), rect.getMinY()); double x2 = Math.min(getMaxX(), rect.getMaxX()); double y2 = Math.min(getMaxY(), rect.getMaxY()); if (y1 > y2 || x1 > x2) { return new FGEEmptyArea(); } // There is a common intersection FGERectangle intersection = new FGERectangle(x1, y1, x2 - x1, y2 - y1); /*if (intersection.getWidth() == 0) { if (FGEPoint.getSimplifiedOrientation(getCenter(), rect.getCenter()) == SimplifiedCardinalDirection.EAST) { return getEast().intersect(rect.getWest()); } else if (FGEPoint.getSimplifiedOrientation(getCenter(), rect.getCenter()) == SimplifiedCardinalDirection.WEST) { return getWest().intersect(rect.getEast()); } else { logger.warning("Unexpected situation encountered here while computing rectangle intersection"); } } if (intersection.getHeight() == 0) { if (FGEPoint.getSimplifiedOrientation(getCenter(), rect.getCenter()) == SimplifiedCardinalDirection.NORTH) { return getNorth().intersect(rect.getSouth()); } else if (FGEPoint.getSimplifiedOrientation(getCenter(), rect.getCenter()) == SimplifiedCardinalDirection.SOUTH) { return getSouth().intersect(rect.getNorth()); } else { logger.warning("Unexpected situation encountered here while computing rectangle intersection"); } }*/ if (getIsFilled()) { if (rect.getIsFilled()) { intersection.setIsFilled(true); return intersection; } else { FGEUnionArea returned = new FGEUnionArea(); returned.addArea(computeLineIntersection(rect.getNorth())); returned.addArea(computeLineIntersection(rect.getSouth())); returned.addArea(computeLineIntersection(rect.getEast())); returned.addArea(computeLineIntersection(rect.getWest())); if (returned.getObjects().size() == 0) { return new FGEEmptyArea(); } if (returned.getObjects().size() == 1) { return returned.getObjects().firstElement(); } return returned; } } // Both rectangle are opened FGEUnionArea returned = new FGEUnionArea(); returned.addArea(getNorth().intersect(rect.getNorth())); returned.addArea(getNorth().intersect(rect.getSouth())); returned.addArea(getNorth().intersect(rect.getEast())); returned.addArea(getNorth().intersect(rect.getWest())); returned.addArea(getSouth().intersect(rect.getNorth())); returned.addArea(getSouth().intersect(rect.getSouth())); returned.addArea(getSouth().intersect(rect.getEast())); returned.addArea(getSouth().intersect(rect.getWest())); returned.addArea(getEast().intersect(rect.getNorth())); returned.addArea(getEast().intersect(rect.getSouth())); returned.addArea(getEast().intersect(rect.getEast())); returned.addArea(getEast().intersect(rect.getWest())); returned.addArea(getWest().intersect(rect.getNorth())); returned.addArea(getWest().intersect(rect.getSouth())); returned.addArea(getWest().intersect(rect.getEast())); returned.addArea(getWest().intersect(rect.getWest())); if (returned.getObjects().size() == 0) { return new FGEEmptyArea(); } if (returned.getObjects().size() == 1) { return returned.getObjects().firstElement(); } return returned; } /*private FGEArea computeRectangleIntersection(FGERectangle rect) { Vector<FGEPoint> pts = new Vector<FGEPoint>() { @Override public synchronized boolean add(FGEPoint o) { if (!contains(o)) return super.add(o); return false; } }; List<FGESegment> sl = rect.getFrameSegments(); for (FGESegment seg : sl) { FGEArea a = intersect(seg); if (a instanceof FGEPoint) pts.add((FGEPoint)a); else if (a instanceof FGESegment) { pts.add(((FGESegment)a).getP1()); pts.add(((FGESegment)a).getP2()); } else if (a instanceof FGEUnionArea) { for (FGEArea a2: ((FGEUnionArea)a).getObjects()) { if (a2 instanceof FGEPoint) pts.add((FGEPoint)a2); if (a2 instanceof FGESegment) { pts.add(((FGESegment)a2).getP1()); pts.add(((FGESegment)a2).getP2()); } } } } FGEPoint ne,nw,se,sw; ne = new FGEPoint(x+width,y); nw = new FGEPoint(x,y); se = new FGEPoint(x+width,y+height); sw = new FGEPoint(x,y+height); if (rect.containsPoint(ne)) pts.add(ne); if (rect.containsPoint(nw)) pts.add(nw); if (rect.containsPoint(se)) pts.add(se); if (rect.containsPoint(sw)) pts.add(sw); if (pts.size() == 0) return new FGEEmptyArea(); else if (pts.size() == 2) { return new FGESegment(pts.firstElement(),pts.elementAt(1)); } else if (pts.size() != 4) { logger.warning("Strange situation here while computeRectangleIntersection between "+this+" and "+rect); } double minx = java.lang.Double.POSITIVE_INFINITY; double miny = java.lang.Double.POSITIVE_INFINITY; double maxx = java.lang.Double.NEGATIVE_INFINITY; double maxy = java.lang.Double.NEGATIVE_INFINITY; for (FGEPoint p : pts) { if (p.x<minx) minx = p.x; if (p.y<miny) miny = p.y; if (p.x>maxx) maxx = p.x; if (p.y>maxy) maxy = p.y; } return new FGERectangle(minx,miny,maxx-minx,maxy-miny,Filling.FILLED); }*/ private FGEArea computeHalfPlaneIntersection(FGEHalfPlane hp) { if (hp.containsArea(this)) { return this.clone(); } if (computeLineIntersection(hp.line) instanceof FGEEmptyArea) { return new FGEEmptyArea(); } else { if (logger.isLoggable(Level.FINE)) { logger.fine("computeHalfPlaneIntersection() for rectangle when halfplane cross rectangle"); } if (getIsFilled()) { FGEArea a = computeLineIntersection(hp.line); Vector<FGEPoint> pts = new Vector<FGEPoint>(); if (a instanceof FGEUnionArea && ((FGEUnionArea) a).isUnionOfPoints() && ((FGEUnionArea) a).getObjects().size() == 2) { pts.add((FGEPoint) ((FGEUnionArea) a).getObjects().firstElement()); pts.add((FGEPoint) ((FGEUnionArea) a).getObjects().elementAt(1)); } else if (a instanceof FGESegment) { pts.add(((FGESegment) a).getP1()); pts.add(((FGESegment) a).getP2()); } FGEPoint ne, nw, se, sw; ne = new FGEPoint(x + width, y); nw = new FGEPoint(x, y); se = new FGEPoint(x + width, y + height); sw = new FGEPoint(x, y + height); if (hp.containsPoint(ne) && !pts.contains(ne)) { pts.add(ne); } if (hp.containsPoint(nw) && !pts.contains(nw)) { pts.add(nw); } if (hp.containsPoint(se) && !pts.contains(se)) { pts.add(se); } if (hp.containsPoint(sw) && !pts.contains(sw)) { pts.add(sw); } return FGEPolygon.makeArea(Filling.FILLED, pts); } else { // open rectangle Vector<FGEArea> returned = new Vector<FGEArea>(); returned.add(hp.intersect(getNorth())); returned.add(hp.intersect(getSouth())); returned.add(hp.intersect(getEast())); returned.add(hp.intersect(getWest())); return FGEUnionArea.makeUnion(returned); } } } private FGEArea computeHalfBandIntersection(FGEHalfBand hb) { FGEArea bandIntersection = computeBandIntersection(hb.embeddingBand); FGEArea returned = bandIntersection.intersect(hb.halfPlane); return returned; } private FGEArea computeBandIntersection(FGEBand band) { if (getIsFilled()) { Vector<FGEPoint> pts = new Vector<FGEPoint>(); FGEArea a1 = intersect(new FGELine(band.line1)); if (a1 instanceof FGESegment) { FGESegment s1 = (FGESegment) a1; pts.add(s1.getP1()); pts.add(s1.getP2()); } else if (a1 instanceof FGEPoint) { pts.add((FGEPoint) a1); } else if (a1 instanceof FGEEmptyArea) { } else { logger.warning("Unexpected intersection: " + a1); } FGEArea a2 = intersect(new FGELine(band.line2)); if (a2 instanceof FGESegment) { FGESegment s2 = (FGESegment) a2; pts.add(s2.getP1()); pts.add(s2.getP2()); } else if (a2 instanceof FGEPoint) { pts.add((FGEPoint) a2); } else if (a2 instanceof FGEEmptyArea) { } else { logger.warning("Unexpected intersection: " + a2); } if (band.containsPoint(getNorthEastPt())) { pts.add(getNorthEastPt()); } if (band.containsPoint(getNorthWestPt())) { pts.add(getNorthWestPt()); } if (band.containsPoint(getSouthEastPt())) { pts.add(getSouthEastPt()); } if (band.containsPoint(getSouthWestPt())) { pts.add(getSouthWestPt()); } if (pts.size() == 0) { return new FGEEmptyArea(); } if (pts.size() == 1) { return pts.firstElement().clone(); } return FGEPolygon.makeArea(Filling.FILLED, pts); } else { // Open rectangle Vector<FGEArea> returned = new Vector<FGEArea>(); returned.add(band.intersect(getNorth())); returned.add(band.intersect(getSouth())); returned.add(band.intersect(getEast())); returned.add(band.intersect(getWest())); return FGEUnionArea.makeUnion(returned); } } private FGEArea computeLineIntersection(FGEAbstractLine line) { FGESegment north = getNorth(); FGESegment south = getSouth(); FGESegment east = getEast(); FGESegment west = getWest(); if (line == null) { return new FGEEmptyArea(); } if (line.overlap(north)) { return north.intersect(line);// north.clone(); } if (line.overlap(south)) { return south.intersect(line);// south.clone(); } if (line.overlap(east)) { return east.intersect(line);// east.clone(); } if (line.overlap(west)) { return west.intersect(line);// west.clone(); } Vector<FGEPoint> crossed = new Vector<FGEPoint>(); try { if (north.intersectsInsideSegment(line)) { FGEPoint intersection = north.getLineIntersection(line); if (line.contains(intersection) && !crossed.contains(intersection)) { crossed.add(intersection); } } } catch (ParallelLinesException e) { // don't care } try { if (south.intersectsInsideSegment(line)) { FGEPoint intersection = south.getLineIntersection(line); if (line.contains(intersection) && !crossed.contains(intersection)) { crossed.add(intersection); } } } catch (ParallelLinesException e) { // don't care } try { if (east.intersectsInsideSegment(line)) { FGEPoint intersection = east.getLineIntersection(line); if (line.contains(intersection) && !crossed.contains(intersection)) { crossed.add(intersection); } } } catch (ParallelLinesException e) { // don't care } try { if (west.intersectsInsideSegment(line)) { FGEPoint intersection = west.getLineIntersection(line); if (line.contains(intersection) && !crossed.contains(intersection)) { crossed.add(intersection); } } } catch (ParallelLinesException e) { // don't care } if (getIsFilled()) { if (line instanceof FGEHalfLine) { if (containsPoint(((FGEHalfLine) line).getLimit())) { if (!crossed.contains(((FGEHalfLine) line).getLimit())) { crossed.add(((FGEHalfLine) line).getLimit()); } } } else if (line instanceof FGESegment) { if (containsPoint(((FGESegment) line).getP1())) { if (!crossed.contains(((FGESegment) line).getP1())) { crossed.add(((FGESegment) line).getP1()); } } if (containsPoint(((FGESegment) line).getP2())) { if (!crossed.contains(((FGESegment) line).getP2())) { crossed.add(((FGESegment) line).getP2()); } } } } if (crossed.size() == 0) { return new FGEEmptyArea(); } FGEArea returned; if (crossed.size() == 1) { returned = crossed.firstElement(); } else if (crossed.size() == 2) { FGEPoint p1 = crossed.firstElement(); FGEPoint p2 = crossed.elementAt(1); if (getIsFilled()) { returned = new FGESegment(p1, p2); } else { returned = FGEUnionArea.makeUnion(p1, p2); } } else if (crossed.size() == 4) { // Crossed on edges FGEPoint p1 = crossed.firstElement(); FGEPoint p2 = crossed.elementAt(1); // Choose those because north and south tested at first (cannot intersect) if (getIsFilled()) { returned = new FGESegment(p1, p2); } else { returned = FGEUnionArea.makeUnion(p1, p2); } } else { logger.warning("crossed.size()=" + crossed.size() + " How is it possible ??? rectangle=" + this + " line=" + line + "\ncrossed=" + crossed); return null; } return returned; } @Override public FGEArea exclusiveOr(FGEArea area) { return new FGEExclusiveOrArea(this, area); } @Override public FGEArea intersect(FGEArea area) { if (area.containsArea(this)) { return this.clone(); } if (containsArea(area)) { return area.clone(); } if (area instanceof FGEAbstractLine) { return computeLineIntersection((FGEAbstractLine) area); } if (area instanceof FGERectangle) { return computeRectangleIntersection((FGERectangle) area); } if (area instanceof FGEHalfPlane) { return computeHalfPlaneIntersection((FGEHalfPlane) area); } if (area instanceof FGEBand) { return computeBandIntersection((FGEBand) area); } if (area instanceof FGEHalfBand) { return computeHalfBandIntersection((FGEHalfBand) area); } if (area instanceof FGEPolygon) { return FGEShape.AreaComputation.computeShapeIntersection(this, (FGEPolygon) area); } FGEIntersectionArea returned = new FGEIntersectionArea(this, area); if (returned.isDevelopable()) { return returned.makeDevelopped(); } else { return returned; } } @Override public FGEArea substract(FGEArea area, boolean isStrict) { return new FGESubstractionArea(this, area, isStrict); } @Override public final FGEArea union(FGEArea area) { if (containsArea(area)) { return clone(); } if (area.containsArea(this)) { return area.clone(); } if (area instanceof FGERectangle && ((FGERectangle) area).getIsFilled() == getIsFilled()) { FGERectangle r = (FGERectangle) area; if (containsArea(r.getNorth()) && getWidth() == r.getWidth() || containsArea(r.getSouth()) && getWidth() == r.getWidth() || containsArea(r.getEast()) && getHeight() == r.getHeight() || containsArea(r.getWest()) && getHeight() == r.getHeight()) { return rectangleUnion(r); } } return new FGEUnionArea(this, area); } @Override public List<FGEPoint> getControlPoints() { Vector<FGEPoint> returned = new Vector<FGEPoint>(); returned.add(new FGEPoint(x, y)); returned.add(new FGEPoint(x + width, y)); returned.add(new FGEPoint(x, y + height)); returned.add(new FGEPoint(x + width, y + height)); returned.add(getNorth().getMiddle()); returned.add(getEast().getMiddle()); returned.add(getWest().getMiddle()); returned.add(getSouth().getMiddle()); return returned; } @Override public boolean containsPoint(FGEPoint p) { if (p.x >= getX() - EPSILON && p.x <= getX() + getWidth() + EPSILON && p.y >= getY() - EPSILON && p.y <= getY() + getHeight() + EPSILON) { if (!getIsFilled()) { FGESegment north = new FGESegment(new FGEPoint(x, y), new FGEPoint(x + width, y)); FGESegment south = new FGESegment(new FGEPoint(x, y + height), new FGEPoint(x + width, y + height)); FGESegment west = new FGESegment(new FGEPoint(x, y), new FGEPoint(x, y + height)); FGESegment east = new FGESegment(new FGEPoint(x + width, y), new FGEPoint(x + width, y + height)); return north.contains(p) || south.contains(p) || east.contains(p) || west.contains(p); } else { return true; } } return false; } @Override public boolean containsLine(FGEAbstractLine l) { if (l instanceof FGEHalfLine) { return false; } if (l instanceof FGESegment) { return containsPoint(l.getP1()) && containsPoint(l.getP2()); } return false; } @Override public boolean containsArea(FGEArea a) { if (a instanceof FGEPoint) { return containsPoint((FGEPoint) a); } if (a instanceof FGESegment && !(a instanceof FGEHalfLine)) { return containsPoint(((FGESegment) a).getP1()) && containsPoint(((FGESegment) a).getP2()); } if (a instanceof FGEShape) { return FGEShape.AreaComputation.isShapeContainedInArea((FGEShape<?>) a, this); } return false; } @Override public FGEArea transform(AffineTransform t) { // Better implementation allowing rotations FGEPoint p1 = new FGEPoint(getX(), getY()).transform(t); FGEPoint p2 = new FGEPoint(getX() + getWidth(), getY()).transform(t); FGEPoint p3 = new FGEPoint(getX(), getY() + getHeight()).transform(t); FGEPoint p4 = new FGEPoint(getX() + getWidth(), getY() + getHeight()).transform(t); return FGEPolygon.makeArea(_filling, p1, p2, p3, p4); // Old implementation follows (commented) /* FGEPoint p1 = (new FGEPoint(getX(),getY())).transform(t); FGEPoint p2 = (new FGEPoint(getX()+getWidth(),getY()+getHeight())).transform(t); // TODO: if transformation contains a rotation, turn into a regular polygon return new FGERectangle( Math.min(p1.x,p2.x), Math.min(p1.y,p2.y), Math.abs(p1.x-p2.x), Math.abs(p1.y-p2.y), _filling);*/ } @Override public void paint(FGEGraphics g) { if (getIsFilled()) { g.useDefaultBackgroundStyle(); g.fillRect(getX(), getY(), getWidth(), getHeight()); } g.useDefaultForegroundStyle(); g.drawRect(getX(), getY(), getWidth(), getHeight()); } @Override public String toString() { return "FGERectangle: (" + x + "," + y + "," + width + "," + height + ")"; } @Override public String getStringRepresentation() { return toString(); } @Override public FGERectangle getBoundingBox() { return clone(); } @Override public boolean equals(Object obj) { if (obj instanceof FGERectangle) { FGERectangle p = (FGERectangle) obj; if (getIsFilled() != p.getIsFilled()) { return false; } return Math.abs(getX() - p.getX()) <= EPSILON && Math.abs(getY() - p.getY()) <= EPSILON && Math.abs(getWidth() - p.getWidth()) <= EPSILON && Math.abs(getHeight() - p.getHeight()) <= EPSILON; } return super.equals(obj); } @Override public FGEArea getOrthogonalPerspectiveArea(SimplifiedCardinalDirection orientation) { return getAnchorAreaFrom(orientation).getOrthogonalPerspectiveArea(orientation); } @Override public FGESegment getAnchorAreaFrom(SimplifiedCardinalDirection orientation) { if (orientation == SimplifiedCardinalDirection.NORTH) { return getNorth(); } else if (orientation == SimplifiedCardinalDirection.SOUTH) { return getSouth(); } else if (orientation == SimplifiedCardinalDirection.EAST) { return getEast(); } else if (orientation == SimplifiedCardinalDirection.WEST) { return getWest(); } logger.warning("Unexpected: " + orientation); return null; } public FGERectangle rectangleUnion(FGERectangle r) { double x1 = Math.min(x, r.x); double x2 = Math.max(x + width, r.x + r.width); double y1 = Math.min(y, r.y); double y2 = Math.max(y + height, r.y + r.height); return new FGERectangle(x1, y1, x2 - x1, y2 - y1, Filling.FILLED); } /** * This area is finite, so always return true */ @Override public final boolean isFinite() { return true; } /** * This area is finite, so always return null */ @Override public final FGERectangle getEmbeddingBounds() { return new FGERectangle(x, y, width, height, Filling.FILLED); } /** * Build and return new polylin representing outline * * @return */ public FGEPolylin getOutline() { return new FGEPolylin(getNorthEastPt(), getSouthEastPt(), getSouthWestPt(), getNorthWestPt()); } }