/**
* Copyright (c) 2009-2011, chunquedong(YangJiandong)
*
* This file is part of ChunMap project
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
*
* History:
* 2010-05-05 Jed Young Creation
*/
package chunmap.model.geom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import chunmap.model.coord.Transform;
import chunmap.model.elem.Envelope;
import chunmap.model.elem.PointLineBag;
import chunmap.model.relate.ComputeIm;
import chunmap.model.relate.IntersectionMatrix;
import chunmap.model.relate.relateop.Polygon_Polygon;
/**
* @author chunquedong
*
*/
public class Polygon extends AbstractGeometry implements Iterable<Ring> {
private final Ring shell;
private final List<Ring> holes;
/**
* @param shell
* @param holes
*/
public Polygon(Ring shell, List<Ring> holes) {
if (shell == null) {
throw new NullPointerException();
}
this.shell = shell;
List<Ring> newHoles = new ArrayList<Ring>();
if (holes != null) {
for (Ring r : holes) {
newHoles.add(r);
}
}
this.holes = newHoles;
}
public Polygon(Ring shell) {
this(shell, null);
}
public Ring getShell() {
return shell;
}
public List<Ring> getHoles() {
List<Ring> newHoles = new ArrayList<Ring>();
for (Ring r : holes) {
newHoles.add(r);
}
return newHoles;
}
public int ringCount() {
return holes.size() + 1;
}
@Override
protected Envelope calculateEnvelop() {
return shell.getEnvelop();
}
@Override
public GeometryType getGeometryType() {
return GeometryType.Polygon;
}
@Override
public String toString() {
return "POLYGON" + toMyString();
}
public String toMyString() {
StringBuilder str = new StringBuilder();
str.append("(");
str.append(shell.toMyString());
for (Ring g : holes) {
str.append("," + g.toMyString());
}
str.append(")");
return str.toString();
}
@Override
public Geometry getBoundary() {
List<LineString> bs = new ArrayList<LineString>();
bs.add(shell);
bs.addAll(holes);
return new MultiLineString(bs);
}
@Override
protected boolean isSimple() {
if (!shell.isValid())
return false;
for (Ring r : holes) {
if (!r.isValid()) {
return false;
}
}
for (Ring r : holes) {
if (!shell.containLineStringIn(r)) {
return false;
}
}
for (int i = 0, n = holes.size(); i < n; i++) {
for (int j = i + 1; j < n; j++) {
Ring r1 = holes.get(i);
Ring r2 = holes.get(i);
ComputeIm ac = new Polygon_Polygon(r1.toPolygon(), r2
.toPolygon());
if (ac.getIM().get(IntersectionMatrix.Inner,
IntersectionMatrix.Inner) != IntersectionMatrix.EmptyDim) {
return false;
}
}
}
return true;
}
@Override
public GeometryCollection toGeometryCollection() {
List<Polygon> gs = new ArrayList<Polygon>();
gs.add(this);
return new MultiPolygon(gs);
}
@Override
public Geometry transform(Transform transf) {
Ring lr = ((LineString) (shell.transform(transf))).toLinearRing();
List<Ring> newHoles = new ArrayList<Ring>();
for (Ring r : holes) {
Ring newr = (Ring) (r.transform(transf));
newHoles.add(newr);
}
return new Polygon(lr, newHoles);
}
public double computeArea() {
double area = Math.abs(shell.computeArea());
for (Ring r : holes) {
double holesA = Math.abs(r.computeArea());
area -= holesA;
}
return area;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((holes == null) ? 0 : holes.hashCode());
result = prime * result + ((shell == null) ? 0 : shell.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Polygon other = (Polygon) obj;
if (holes == null) {
if (other.holes != null)
return false;
} else if (!holes.equals(other.holes))
return false;
if (shell == null) {
if (other.shell != null)
return false;
} else if (!shell.equals(other.shell))
return false;
return true;
}
/**
* 是否完全落在孔中
*
* @param line
* @return
*/
public boolean inHoles(LineString line) {
// 打断
List<LineString> lines = new ArrayList<LineString>();
lines.add(line);
for (Ring r : holes) {
breakLine(r, lines);
}
for (LineString l : lines) {
if (!this.inOneHoles(l)) {
return false;
}
}
return true;
}
/**
* 完全落在一个孔里
*
* @param line
* @return
*/
private boolean inOneHoles(LineString line) {
for (Ring r : holes) {
if (r.containLineStringIn(line)) {
return true;
}
}
return false;
}
private void breakLine(Ring r, List<LineString> lines) {
for (int i = 0, n = lines.size(); i < n; i++) {
LineString line = lines.get(i);
PointLineBag bag = line.intersection(r);
List<LineString> newLines = bag.breakLine(line);
if (newLines.size() > 1) {
lines.remove(i);
lines.addAll(newLines);
return;
}
}
}
@Override
public Iterator<Ring> iterator() {
return new Iterator<Ring>() {
Iterator<Ring> it = holes.iterator();
int i = 0;
@Override
public boolean hasNext() {
if (i == 0)
return true;
else {
return it.hasNext();
}
}
@Override
public Ring next() {
if (i == 0)
return shell;
else
return it.next();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}