/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
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; either
version 2.1 of the License, or (at your option) any later version.
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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.spatialschema;
import java.io.Serializable;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
/**
* default implementation of the Surface interface from package jago.model.
* <p>
* </p>
* for simplicity of the implementation it is assumed that a surface is build from just one surface
* patch. this isn't completly confrom to the ISO 19107 and the OGC GAIA specification but
* sufficient for most applications.
* <p>
* </p>
* It will be extended to fullfill the complete specs as soon as possible.
*
* @version 05.04.2002
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
*/
public class SurfaceImpl extends OrientableSurfaceImpl implements Surface, GenericSurface,
Serializable {
/** Use serialVersionUID for interoperability. */
private final static long serialVersionUID = -2148069106391096842L;
private static final ILogger LOG = LoggerFactory.getLogger( SurfaceImpl.class );
protected SurfacePatch[] patch = null;
private double area = 0;
/**
* initializes the surface with default orientation submitting one surface patch.
*
* @param surfacePatch
* patches of the surface.
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( SurfacePatch surfacePatch ) throws GeometryException {
this( '+', surfacePatch );
}
/**
* initializes the surface with default orientation submitting one surface patch.
*
* @param surfacePatches
* patches of the surface.
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( SurfacePatch[] surfacePatches ) throws GeometryException {
this( '+', surfacePatches );
}
/**
* initializes the surface submitting the orientation and one surface patch.
*
* @param orientation
* of the surface
*
* @param surfacePatch
* patches of the surface.
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( char orientation, SurfacePatch surfacePatch ) throws GeometryException {
super( surfacePatch.getCoordinateSystem(), orientation );
patch = new SurfacePatch[] { surfacePatch };
setValid( false );
}
/**
* initializes the surface submitting the orientation and one surface patch.
*
* @param orientation
* of the surface
*
* @param surfacePatches
* patches of the surface.
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( char orientation, SurfacePatch[] surfacePatches ) throws GeometryException {
super( surfacePatches[0].getCoordinateSystem(), orientation );
patch = surfacePatches;
setValid( false );
}
/**
* initializes the surface with default orientation submitting the surfaces boundary
*
* @param boundary
* boundary of the surface
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( SurfaceBoundary boundary ) throws GeometryException {
this( '+', boundary );
}
/**
* initializes the surface submitting the orientation and the surfaces boundary.
*
* @param orientation
* of the surface
*
* @param boundary
* boundary of the surface
*
* @throws GeometryException
* will be thrown if orientation is invalid
*/
public SurfaceImpl( char orientation, SurfaceBoundary boundary ) throws GeometryException {
// todo
// extracting surface patches from the boundary
super( boundary.getCoordinateSystem(), orientation );
this.boundary = boundary;
}
/**
* calculates the centroid and area of the surface
*/
private void calculateCentroidArea() {
double x = 0;
double y = 0;
area = 0;
for ( int i = 0; i < patch.length; i++ ) {
x += ( patch[i].getCentroid().getX() * patch[i].getArea() );
y += ( patch[i].getCentroid().getY() * patch[i].getArea() );
area += patch[i].getArea();
}
centroid = GeometryFactory.createPoint( x / area, y / area, this.crs );
}
/**
* calculates the boundary and area of the surface
*/
private void calculateBoundary() {
// TODO
// consider more than one patch
try {
Ring ext = new RingImpl( patch[0].getExteriorRing(), crs );
Position[][] inn_ = patch[0].getInteriorRings();
Ring[] inn = null;
if ( inn_ != null ) {
inn = new RingImpl[inn_.length];
for ( int i = 0; i < inn_.length; i++ ) {
inn[i] = new RingImpl( inn_[i], crs );
}
}
boundary = new SurfaceBoundaryImpl( ext, inn );
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
}
/**
* calculates area, centroid and the envelope of the surface
*/
@Override
protected void calculateParam() {
calculateCentroidArea();
try {
calculateEnvelope();
} catch ( GeometryException e ) {
LOG.logError( e.getMessage(), e );
}
calculateBoundary();
setValid( true );
}
/**
* calculates the envelope of the surface
*/
private void calculateEnvelope()
throws GeometryException {
envelope = patch[0].getEnvelope();
for ( int i = 1; i < patch.length; i++ ) {
envelope = envelope.merge( patch[i].getEnvelope() );
}
}
/**
* returns the length of all boundaries of the surface in a reference system appropriate for
* measuring distances.
*/
public double getPerimeter() {
return -1;
}
/**
* The operation "area" shall return the area of this GenericSurface. The area of a 2
* dimensional geometric object shall be a numeric measure of its surface area Since area is an
* accumulation (integral) of the product of two distances, its return value shall be in a unit
* of measure appropriate for measuring distances squared.
*/
public double getArea() {
if ( !isValid() ) {
calculateParam();
}
return area;
}
public SurfaceBoundary getSurfaceBoundary() {
if ( !isValid() ) {
calculateParam();
}
return (SurfaceBoundary) boundary;
}
public int getNumberOfSurfacePatches() {
return patch.length;
}
public SurfacePatch getSurfacePatchAt( int index )
throws GeometryException {
if ( index >= patch.length ) {
throw new GeometryException( "invalid index/position to get a patch!" );
}
return patch[index];
}
/**
* checks if this surface is completly equal to the submitted geometry
*
* @param other
* object to compare to
*/
@Override
public boolean equals( Object other ) {
if ( !super.equals( other ) ) {
return false;
}
if ( !( other instanceof SurfaceImpl ) ) {
return false;
}
if ( envelope == null ) {
try {
calculateEnvelope();
} catch ( GeometryException e1 ) {
return false;
}
}
if ( !envelope.equals( ( (Geometry) other ).getEnvelope() ) ) {
return false;
}
try {
for ( int i = 0; i < patch.length; i++ ) {
if ( !patch[i].equals( ( (Surface) other ).getSurfacePatchAt( i ) ) ) {
return false;
}
}
} catch ( Exception e ) {
return false;
}
return true;
}
/**
* The operation "dimension" shall return the inherent dimension of this Geometry, which shall
* be less than or equal to the coordinate dimension. The dimension of a collection of geometric
* objects shall be the largest dimension of any of its pieces. Points are 0-dimensional, curves
* are 1-dimensional, surfaces are 2-dimensional, and solids are 3-dimensional.
*/
public int getDimension() {
return 2;
}
/**
* The operation "coordinateDimension" shall return the dimension of the coordinates that define
* this Geometry, which must be the same as the coordinate dimension of the coordinate reference
* system for this Geometry.
*/
public int getCoordinateDimension() {
return patch[0].getExteriorRing()[0].getCoordinateDimension();
}
/**
* @return a shallow copy of the geometry
*/
@Override
public Object clone() {
Surface s = null;
try {
s = new SurfaceImpl( getOrientation(), patch );
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
}
return s;
}
/**
* translate each point of the surface with the values of the submitted double array.
*/
@Override
public void translate( double[] d ) {
for ( int i = 0; i < patch.length; i++ ) {
Position[] ext = patch[i].getExteriorRing();
Position[][] inn = patch[i].getInteriorRings();
for ( int j = 0; j < ext.length; j++ ) {
ext[j].translate( d );
}
if ( inn != null ) {
for ( int j = 0; j < inn.length; j++ ) {
for ( int k = 0; k < inn[j].length; k++ ) {
inn[j][k].translate( d );
}
}
}
}
setValid( false );
}
/**
* The boolean valued operation "intersects" shall return TRUE if this <tt>SurfaceImpl</tt>
* intersects with the given <tt>Geometry</t>.
* Within a <tt>Complex</tt>, the <tt>Primitives</tt> do not
* intersect one another. In general, topologically structured data uses
* shared geometric objects to capture intersection information.
* @param gmo the <tt>Geometry</tt> to test for intersection
* @return true if the <tt>Geometry</tt> intersects with this
*/
@Override
public boolean intersects( Geometry gmo ) {
if ( !isValid() ) {
calculateParam();
}
for ( int i = 0; i < patch.length; i++ ) {
if ( patch[i].intersects( gmo ) ) {
return true;
}
}
return false;
}
/**
* The Boolean valued operation "contains" shall return TRUE if this Geometry contains a single
* point given by a coordinate.
* <p>
* </p>
*/
@Override
public boolean contains( Position position ) {
return contains( new PointImpl( position, null ) );
}
/**
* The Boolean valued operation "contains" shall return TRUE if this Geometry contains another
* Geometry.
* <p>
* </p>
*/
@Override
public boolean contains( Geometry gmo ) {
if ( !isValid() ) {
calculateParam();
}
return boundary.contains( gmo );
}
/**
*
*
* @return the Stringrepresenation of this surface.
*/
@Override
public String toString() {
StringBuffer ret = new StringBuffer( 2000 );
ret.append( "\n------------------------------------------\n" );
ret.append( getClass().getName() ).append( ":\n" );
ret.append( "envelope = " ).append( envelope ).append( "\n" );
ret.append( "patch = " ).append( patch.length ).append( "\n" );
for ( int i = 0; i < patch.length; i++ ) {
Position[] pos = patch[i].getExteriorRing();
ret.append( "Exterior Ring: \n" );
ret.append( "length: " ).append( pos.length ).append("\n" );
for ( int j = 0; j < pos.length; j++ ) {
ret.append( pos[j]+"\n" );
}
}
ret.append( "\n------------------------------------------\n" );
return ret.toString();
}
}
/* **********************************************************************************************
* Changes to this class. What the people have been up to:
* $Log: SurfaceImpl.java,v $
* Revision 1.22 2006/11/23 09:20:03 bezema
* changed the to String method, so that each Surface resides inside a textual box
*
* Revision 1.21 2006/10/16 18:10:58 poth
* toString method adjusted
*
* Revision 1.20 2006/10/16 12:49:23 poth
* toString method adjusted
*
* Revision 1.19 2006/10/12 15:44:26 poth
* useless code fragment removed / footer comment corrected
*
* Revision 1.18 2006/10/02 07:33:28 bezema
* formatted and documentation
* Revision
* 1.17 2006/09/18 12:39:48 bezema added annotations and javadoc
*
* Revision 1.16 2006/07/12 14:46:15 poth comment footer added
*
********************************************************************************************* */