/*
* (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.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.util.Vector;
import java.util.logging.Logger;
import org.openflexo.fge.geom.area.FGEArea;
import org.openflexo.fge.geom.area.FGEEmptyArea;
import org.openflexo.fge.geom.area.FGEUnionArea;
public interface FGEShape<O extends FGEGeometricObject> extends FGEGeometricObject<O>, Shape {
static final Logger logger = Logger.getLogger(FGEShape.class.getPackage().getName());
public boolean getIsFilled();
public void setIsFilled(boolean aFlag);
public FGEPoint nearestOutlinePoint(FGEPoint aPoint);
public FGEPoint getCenter();
public FGERectangle getBoundingBox();
public static class AreaComputation {
public static <O extends FGEGeometricObject> boolean isShapeContainedInArea(FGEShape<O> shape, FGEArea area) {
if (shape.getControlPoints().size() == 0) {
return false;
}
for (FGEPoint p : shape.getControlPoints()) {
if (!area.containsPoint(p)) {
return false;
}
}
return true;
}
public static FGEArea computeShapeIntersection(FGEShape shape1, FGEShape shape2) {
// System.out.println("computeShapeIntersection() with "+shape1+" and "+shape2);
Area area1 = new Area(shape1);
// System.out.println(">>> First shape: ");
// debugPathIterator(area1.getPathIterator(new AffineTransform()));
Area area2 = new Area(shape2);
// System.out.println(">>> Second shape: ");
// debugPathIterator(area2.getPathIterator(new AffineTransform()));
area1.intersect(area2);
// System.out.println(">>> Third shape: ");
// debugPathIterator(area1.getPathIterator(new AffineTransform()));
if (isPolygonalPathIterator(area1.getPathIterator(new AffineTransform()))) {
FGEArea returned = makePolygonalShapeFromPathIterator(area1.getPathIterator(new AffineTransform()));
if (returned instanceof FGEEmptyArea) {
// In some cases, path iterator computation can miss something
// From here, assert that both shapes have null intersection with path iterator method
if (shape1 instanceof FGEPolygon) {
if (shape2 instanceof FGEPolygon) {
return ((FGEPolygon) shape1).getOutline().intersect(((FGEPolygon) shape2).getOutline());
} else if (shape2 instanceof FGERectangle) {
return ((FGEPolygon) shape1).getOutline().intersect(((FGERectangle) shape2).getOutline());
}
} else if (shape1 instanceof FGERectangle) {
if (shape2 instanceof FGEPolygon) {
return ((FGERectangle) shape1).getOutline().intersect(((FGEPolygon) shape2).getOutline());
} else if (shape2 instanceof FGERectangle) {
return ((FGERectangle) shape1).getOutline().intersect(((FGERectangle) shape2).getOutline());
}
}
}
return returned;
} else {
logger.warning("Non-polygonal shapes not supported yet...");
return new FGEEmptyArea();
}
}
protected static FGEArea makePolygonalShapeFromPathIterator(PathIterator pathIterator) {
Vector<FGEPolygon> polygons = new Vector<FGEPolygon>();
Vector<FGEPoint> currentPolygon = new Vector<FGEPoint>();
while (!pathIterator.isDone()) {
double[] coords = new double[6];
int i = pathIterator.currentSegment(coords);
String pathType = "";
switch (i) {
case PathIterator.SEG_LINETO:
pathType = "SEG_LINETO";
currentPolygon.add(new FGEPoint(coords[0], coords[1]));
break;
case PathIterator.SEG_MOVETO:
pathType = "SEG_MOVETO";
currentPolygon = new Vector<FGEPoint>();
currentPolygon.add(new FGEPoint(coords[0], coords[1]));
break;
case PathIterator.SEG_CLOSE:
pathType = "SEG_CLOSE";
polygons.add(new FGEPolygon(Filling.FILLED, currentPolygon));
break;
default:
logger.warning("Unexpected PathIterator item found: " + i);
return new FGEEmptyArea();
}
// logger.info(pathType+" "+coords[0]+" "+coords[1]+" "+coords[2]+" "+coords[3]+" "+coords[4]+" "+coords[5]);
pathIterator.next();
}
if (polygons.size() == 0) {
return new FGEEmptyArea();
}
if (polygons.size() == 1) {
return polygons.firstElement();
}
return FGEUnionArea.makeUnion(polygons);
}
protected static boolean isPolygonalPathIterator(PathIterator pathIterator) {
double[] coords = new double[6];
while (!pathIterator.isDone()) {
int i = pathIterator.currentSegment(coords);
switch (i) {
case PathIterator.SEG_CUBICTO:
return false;
case PathIterator.SEG_QUADTO:
return false;
default:
break;
}
pathIterator.next();
}
// Only PathIterator.SEG_LINETO, PathIterator.SEG_MOVETO, PathIterator.SEG_CLOSE found
return true;
}
private static void debugPathIterator(PathIterator pi) {
while (!pi.isDone()) {
double[] coords = new double[6];
int i = pi.currentSegment(coords);
String pathType = "";
switch (i) {
case PathIterator.SEG_LINETO:
pathType = "SEG_LINETO";
break;
case PathIterator.SEG_MOVETO:
pathType = "SEG_MOVETO";
break;
case PathIterator.SEG_CUBICTO:
pathType = "SEG_CUBICTO";
break;
case PathIterator.SEG_QUADTO:
pathType = "SEG_QUADTO";
break;
case PathIterator.SEG_CLOSE:
pathType = "SEG_CLOSE";
break;
default:
break;
}
System.out.println(pathType + " " + coords[0] + " " + coords[1] + " " + coords[2] + " " + coords[3] + " " + coords[4] + " "
+ coords[5]);
pi.next();
}
}
}
}