/*
* 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.primitive;
import java.util.Set;
import java.util.TreeSet;
import org.geotools.geometry.iso.complex.ComplexImpl;
import org.geotools.geometry.iso.root.GeometryImpl;
import org.opengis.geometry.complex.Complex;
import org.opengis.geometry.complex.Composite;
import org.opengis.geometry.primitive.OrientablePrimitive;
import org.opengis.geometry.primitive.Primitive;
import org.opengis.geometry.primitive.PrimitiveBoundary;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
*
* Primitive is the abstract root class of the geometric primitives. Its main
* purpose is to define the basic "boundary" operation that ties the primitives
* in each dimension together. A geometric primitive is a geometric object that
* is not decomposed further into other primitives in the system. This includes
* curves and surfaces, even though they are composed of curve segments and
* surface patches, respectively. This composition is a strong aggregation:
* curve segments and surface patches cannot exist outside the context of a
* primitive.
*
* NOTE Most geometric primitives are decomposable infinitely many times. Adding
* a centre point to a line may split that line into two separate lines. A new
* curve drawn across a surface may divide that surface into two parts, each of
* which is a surface. This is the reason that the normal definition of
* primitive as "non-decomposable" is not plausible in a geometry model - the
* only non-decomposable object in geometry is a point. Any geometric object
* that is used to describe a feature is a collection of geometric primitives. A
* collection of geometric primitives may or may not be a geometric complex.
* Geometric complexes have additional properties such as closure by boundary
* operations and mutually exclusive component parts.
*
* Primitive and Complex share most semantics, in the meaning of operations,
* attributes and associations. There is an exception in that a Primitive shall
* not contain its boundary (except in the trivial case of Point where the
* boundary is empty), while a Complex shall contain its boundary in all cases.
* This means that if an instantiated object implements Object operations both
* as Primitive and as a Complex, the semantics of each set theoretic operation
* is determined by the its name resolution. Specifically, for a particular
* object such as CompositeCurve, Primitive::contains (returns FALSE for end
* points) is different from Complex::contains (returns TRUE for end points).
* Further, if that object is cast as a Primitive value and as a Complex value,
* then the two values need not be equal as Objects.
*
*
*
*
* @source $URL$
* @version <A HREF="http://www.opengis.org/docs/01-101.pdf">Abstract
* Specification V5</A>
* @author Jackson Roehrig & Sanjay Jena
*
*/
public abstract class PrimitiveImpl extends GeometryImpl implements Primitive {
/**
* The "Interior to" association associates Primitives which are by
* definition coincident with one another. This allows applications to
* override the Set<DirectPosition> interpretation and its associated
* computational geometry, and declare one Primitive to be "interior to"
* another. This association should normally be empty when the Primitives
* are within a Complex, since in that case the boundary information is
* sufficient for most cases.
*
* Primitive::coincidentSubelement [0..n] : Reference<Primitive>
* Primitive::superElement [0..n] : Reference<Primitive>
*
* This association is constrained by the set theory operators and dimension
* operators defined at Object.
*
* Primitive: superElement=>includes(p: Primitive) = Object::contains (p)
* dimension() >= coincidentSubelement. dimension()
*
* NOTE This association should not be used when the two Primitives are not
* close to one another. The intent is to allow applications to compensate
* for inherent and unavoidable round off, truncation, and other
* mathematical problems indigenous to computer calculations.
*
* The fields containedPrimitive and containingPrimitive are unset per
* default
*/
protected Set<Primitive> containedPrimitive = null;
/**
* See containedPrimitive
*/
protected Set<Primitive> containingPrimitive = null;
/**
* A Primitive may be in several Complexes. This association may not be
* navigable in this direction (from primitive to complex), depending on the
* application schema.
*
* Primitive::complex [0..n] : Reference<Complex>
*
* The field complex is unset per default
*/
protected Set<Complex> complex = null;
/**
* @param crs
* @param containedPrimitive
* @param containingPrimitive
* @param complex
*/
protected PrimitiveImpl(CoordinateReferenceSystem crs,
Set<Primitive> containedPrimitive,
Set<Primitive> containingPrimitive,
Set<Complex> complex) {
super(crs);
// the parameters may be null
this.containedPrimitive = containedPrimitive;
this.containingPrimitive = containingPrimitive;
this.complex = complex;
}
public PrimitiveImpl(CoordinateReferenceSystem coordinateReferenceSystem) {
super( coordinateReferenceSystem );
}
/* (non-Javadoc)
* @see org.opengis.geometry.primitive.Primitive#getContainingPrimitives()
*/
public Set<Primitive> getContainingPrimitives() {
return this.containingPrimitive;
}
/* (non-Javadoc)
* @see org.opengis.geometry.primitive.Primitive#getContainedPrimitives()
*/
public Set<Primitive> getContainedPrimitives() {
return this.containedPrimitive;
}
/* (non-Javadoc)
* @see org.opengis.geometry.primitive.Primitive#getComplexes()
*/
public Set<Complex> getComplexes() {
return this.complex;
}
public Composite getComposite() {
return null;
}
/**
* Adds a new subelement of same or lower dimension then this object. This
* object contains the given subelement
*
* @param newSubelement
*/
public void addContainingPrimitive(PrimitiveImpl newSubelement) {
if (this.containingPrimitive == null)
this.containingPrimitive = new TreeSet<Primitive>();
this.containingPrimitive.add(newSubelement);
}
/**
* Adds a the super element where this object in contained in
*
* @param newSuperelement
*/
public void addContainedPrimitive(PrimitiveImpl newSuperelement) {
if (this.containedPrimitive == null)
this.containedPrimitive = new TreeSet<Primitive>();
this.containedPrimitive.add(newSuperelement);
}
/**
* Adds a new complex to the set of complexes containing this primitive
*
* @param newComplex
*/
public void addComplex(ComplexImpl newComplex) {
if (this.complex == null)
this.complex = new TreeSet<Complex>();
this.complex.add(newComplex);
}
/**
* 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 of maximal complexes or null
*
*/
/* (non-Javadoc)
* @see org.opengis.geometry.coordinate.root.Geometry#getMaximalComplex()
*/
public Set<Complex> getMaximalComplex() {
if (this.complex == null)
return null;
TreeSet<Complex> result = new TreeSet<Complex>();
for (Complex c : this.complex) {
result.addAll(c.getMaximalComplex());
}
return result;
}
/* (non-Javadoc)
* @see org.geotools.geometry.featgeom.root.GeometryImpl#getBoundary()
*/
public abstract PrimitiveBoundary getBoundary();
/* (non-Javadoc)
* @see org.opengis.geometry.primitive.Primitive#getProxy()
*/
public abstract OrientablePrimitive[] getProxy();
}