/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotools.geometry.iso.complex;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.geotools.geometry.iso.primitive.PrimitiveImpl;
import org.geotools.geometry.iso.root.GeometryImpl;
import org.opengis.geometry.complex.Complex;
import org.opengis.geometry.primitive.Primitive;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
*
* A Complex is a collection of geometrically disjoint, simple Primitives. If a
* Primitive (other than a Point) is in a particular Complex, then there exists
* a set of primitives of lower dimension in the same complex that form the
* boundary of this primitive.
*
* NOTE A geometric complex can be thought of as a set in two distinct ways.
* First, it is a finite set of objects (via delegation to its elements member)
* and, second, it is an infinite set of point values as a subtype of geometric
* object. The dual use of delegation and subtyping is to disambiguate the two
* types of set interface. To determine if a Primitive P is an element of a
* Complex C, call: C.element().contains(P).
*
* The "element" attribute allows Complex to inherit the behavior of Set<Primitive>
* without confusing the same sort of behavior inherited from TransfiniteSet<DirectPosition2D>
* inherited through Object. Complexes shall be used in application schemas
* where the sharing of geometry is important, such as in the use of
* computational topology. In a complex, primitives may be aggregated
* many-to-many into composites for use as attributes of features. Examples of
* this are provided in the schemas in annex D.
*
* @author Jackson Roehrig & Sanjay Jena
*
* @source $URL$
*/
public abstract class ComplexImpl extends GeometryImpl implements Complex {
/**
* Contains association The association "Contains" instantiates the contains
* operation from Set<Primitive> as an association. Set<Complex> of
* Complex [0..n]
*/
private Set<Complex> subComplex = null;
private Set<Complex> superComplex = null;
/**
* The association "Complex" is defined by the "contains" operation in
* Object that is inherited from TransfiniteSet<DirectPosition2D>.
* Complex::element [1..n] : Primitive If a complex contains a Primitive,
* then it must also contain the elements of its boundary. Complex: --
* closed under the boundary operation
* self?forAll(self?includesAll(boundary()))
*
* ArrayList of Primitive [1..n]
*/
// This cannot be a collection, but needs to be an ordered collecion, which
// is a list
// protected Collection<? extends Primitive> elements = null;
protected List<? extends Primitive> elements = null;
/**
*
* @param elements
*/
public ComplexImpl(List<? extends Primitive> elements) {
super(elements.get(0).getCoordinateReferenceSystem());
if (elements.isEmpty())
throw new IllegalArgumentException(
"Array of Elements is empty. At least one element expected."); //$NON-NLS-1$
this.elements = elements;
this.subComplex = this.createBoundary();
this.superComplex = null;
}
/**
* Constructs a Complex Elements have to be added after
*
* @param crs
*/
public ComplexImpl(CoordinateReferenceSystem crs) {
super(crs);
this.elements = null;
this.subComplex = null;
this.superComplex = null;
}
/**
* Sets the elements contained by this Complex
*
* @param element
*/
public void setElements(List<? extends Primitive> element) {
this.elements = element;
}
/**
* @return Set<Complex>
*/
public abstract Set<Complex> createBoundary();
/**
* Returns elements contained in this Complex
*
* @return the primitives
*/
public Collection<? extends Primitive> getElements() {
return this.elements;
}
/**
* @param primitive
* @return
*/
boolean hasElement(PrimitiveImpl primitive) {
return this.elements.contains(primitive);
}
/**
* @param primitive
*/
void removeElement(PrimitiveImpl primitive) {
this.elements.remove(primitive);
}
/**
* The Boolean valued operation "isMaximal" shall return TRUE if and only if
* this Complex is maximal. Complex::isMaximal() : Boolean
*
* @return true if this complex is maximal
*/
public boolean isMaximal() {
return ((superComplex == null) || superComplex.isEmpty());
}
/**
* Adds an associated Sub Complex
*
* @param subComplex1
*/
protected void addSubComplex(Complex subComplex1) {
this.subComplex.add(subComplex1);
}
/**
* Adds an associated Super Complex
*
* @param superComplex1
*/
protected void addSuperComplex(ComplexImpl superComplex1) {
this.superComplex.add(superComplex1);
}
/* (non-Javadoc)
* @see org.opengis.geometry.complex.Complex#getSuperComplexes()
*/
public Complex[] getSuperComplexes() {
return (this.superComplex == null) ? null : this.superComplex
.toArray(new Complex[this.superComplex.size()]);
}
/* (non-Javadoc)
* @see org.opengis.geometry.complex.Complex#getSubComplexes()
*/
public Complex[] getSubComplexes() {
return (this.subComplex == null) ? null : this.subComplex
.toArray(new Complex[this.subComplex.size()]);
}
/**
* As a set of primitives, a Complex may be contained as a set in another
* larger Complex, referred to as a "super complex" of the original. A
* Complex is maximal if there is no such larger super complex. The
* operation "maximalComplex" shall return the set of maximal Complexes
* within which this Object is contained.
*
* Object::maximalComplex() : Set<Complex>
*
* If the application schema used does not include Complex, then this
* operation shall return a NULL value.
*
* NOTE The usual semantics of maximal complexes does not allow any
* Primitive to be in more than one maximal complex, making it a strong
* aggregation. This is not an absolute, and depending on the semantics of
* the implementation, the association between Primitives and maximal
* Complexes could be many to many. From a programming point of view, this
* would be a difficult (but not impossible) dynamic structure to maintain,
* but as a static query-only structure, it could be quite useful in
* minimizing redundant data inherent in two representations of the same
* primitive geometric object.
*
* @return the set containing only this object if it is a maximal complex or
* its maximum complexes
*
*/
/* (non-Javadoc)
* @see org.opengis.geometry.coordinate.root.Geometry#getMaximalComplex()
*/
public Set<Complex> getMaximalComplex() {
TreeSet<Complex> result = new TreeSet<Complex>();
if (this.isMaximal()) {
result.add(this);
} else {
for (Complex c : this.superComplex) {
result.addAll(c.getMaximalComplex());
}
}
return result;
}
}