/*---------------- 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.graphics.displayelements;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.graphics.sld.FeatureTypeStyle;
import org.deegree.graphics.sld.Geometry;
import org.deegree.graphics.sld.LineSymbolizer;
import org.deegree.graphics.sld.PointSymbolizer;
import org.deegree.graphics.sld.PolygonSymbolizer;
import org.deegree.graphics.sld.RasterSymbolizer;
import org.deegree.graphics.sld.Rule;
import org.deegree.graphics.sld.Symbolizer;
import org.deegree.graphics.sld.TextSymbolizer;
import org.deegree.graphics.sld.UserStyle;
import org.deegree.io.datastore.PropertyPathResolvingException;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.filterencoding.Filter;
import org.deegree.model.filterencoding.FilterEvaluationException;
import org.deegree.model.spatialschema.Curve;
import org.deegree.model.spatialschema.GeometryException;
import org.deegree.model.spatialschema.GeometryFactory;
import org.deegree.model.spatialschema.MultiCurve;
import org.deegree.model.spatialschema.MultiPoint;
import org.deegree.model.spatialschema.MultiPrimitive;
import org.deegree.model.spatialschema.MultiSurface;
import org.deegree.model.spatialschema.Point;
import org.deegree.model.spatialschema.Position;
import org.deegree.model.spatialschema.Surface;
import org.opengis.coverage.grid.GridCoverage;
/**
* Factory class for the different kinds of <tt>DisplayElement</tt>s.
* <p>
*
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider</a>
* @version $Revision: 1.20 $ $Date: 2006/07/29 08:51:12 $
*/
public class DisplayElementFactory {
private static final ILogger LOG = LoggerFactory.getLogger( DisplayElementFactory.class );
/**
* returns the display elements associated to a feature
* @throws PropertyPathResolvingException
*/
public DisplayElement[] createDisplayElement( Object o, UserStyle[] styles )
throws ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException,
GeometryException, PropertyPathResolvingException {
ArrayList list = new ArrayList( 20 );
if ( o instanceof Feature ) {
Feature feature = (Feature) o;
try {
String featureTypeName = feature.getFeatureType().getName().getAsString();
for (int i = 0; i < styles.length; i++) {
if ( styles[i] == null ) {
// create display element from default style
DisplayElement de = buildDisplayElement( feature );
if ( de != null ) {
list.add( de );
}
} else {
FeatureTypeStyle[] fts = styles[i].getFeatureTypeStyles();
for (int k = 0; k < fts.length; k++) {
if ( fts[k].getFeatureTypeName() == null
|| featureTypeName.equals( fts[k].getFeatureTypeName() ) ) {
Rule[] rules = fts[k].getRules();
for (int n = 0; n < rules.length; n++) {
// does the filter rule apply?
Filter filter = rules[n].getFilter();
if ( filter != null ) {
try {
if ( !filter.evaluate( feature ) ) {
continue;
}
} catch (FilterEvaluationException e) {
LOG.logError( "Error evaluating filter: ", e );
continue;
}
}
// Filter expression is true for this feature, so a
// corresponding DisplayElement has to be added to the
// list
Symbolizer[] symbolizers = rules[n].getSymbolizers();
for (int u = 0; u < symbolizers.length; u++) {
DisplayElement displayElement = DisplayElementFactory
.buildDisplayElement( feature, symbolizers[u] );
if ( displayElement != null ) {
list.add( displayElement );
}
}
}
}
}
}
}
} catch (IncompatibleGeometryTypeException e) {
e.printStackTrace();
}
} else {
RasterSymbolizer symbolizer = new RasterSymbolizer();
list.add( buildRasterDisplayElement( (GridCoverage) o, symbolizer ) );
}
DisplayElement[] de = new DisplayElement[list.size()];
return (DisplayElement[]) list.toArray( de );
}
/**
* Builds a <tt>DisplayElement</tt> using the given <tt>Feature</tt> or raster and
* <tt>Symbolizer</tt>.
* <p>
*
* @param o
* contains the geometry or raster information (Feature or raster)
* @param symbolizer
* contains the drawing (style) information and selects the geometry property of the
* <tt>Feature</tt> to be drawn
* @throws IncompatibleGeometryTypeException
* if the selected geometry of the <tt>Feature</tt> is not compatible with the
* <tt>Symbolizer</tt>
* @return constructed <tt>DisplayElement</tt>
* @throws PropertyPathResolvingException
*/
public static DisplayElement buildDisplayElement( Object o, Symbolizer symbolizer )
throws IncompatibleGeometryTypeException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException,
GeometryException,
PropertyPathResolvingException {
DisplayElement displayElement = null;
if ( o instanceof Feature ) {
Feature feature = (Feature) o;
// determine the geometry property to be used
org.deegree.model.spatialschema.Geometry geometry = null;
Geometry symbolizerGeometry = symbolizer.getGeometry();
if ( symbolizerGeometry != null ) {
FeatureProperty property =
feature.getDefaultProperty( symbolizerGeometry.getPropertyPath() );
if ( property != null ) {
geometry = (org.deegree.model.spatialschema.Geometry) property.getValue();
}
} else {
geometry = feature.getDefaultGeometryPropertyValue();
}
// if the geometry is null, do not build a DisplayElement
if ( geometry == null ) {
return null;
}
// PointSymbolizer
if ( symbolizer instanceof PointSymbolizer ) {
displayElement = buildPointDisplayElement( feature, geometry,
(PointSymbolizer) symbolizer );
} // LineSymbolizer
else if ( symbolizer instanceof LineSymbolizer ) {
displayElement = buildLineStringDisplayElement( feature, geometry,
(LineSymbolizer) symbolizer );
} // PolygonSymbolizer
else if ( symbolizer instanceof PolygonSymbolizer ) {
displayElement = buildPolygonDisplayElement( feature, geometry,
(PolygonSymbolizer) symbolizer );
} else if ( symbolizer instanceof TextSymbolizer ) {
displayElement = buildLabelDisplayElement( feature, geometry,
(TextSymbolizer) symbolizer );
}
} else {
if ( symbolizer instanceof RasterSymbolizer ) {
displayElement = buildRasterDisplayElement( (GridCoverage) o,
(RasterSymbolizer) symbolizer );
}
}
return displayElement;
}
/**
* Builds a <tt>DisplayElement</tt> using the given <tt>Feature</tt> or Raster and a default
* <tt>Symbolizer</tt>.
* <p>
*
* @param o
* contains the geometry or raster information (Feature or raster)
* @throws IncompatibleGeometryTypeException
* if the selected geometry of the <tt>Feature</tt> is not compatible with the
* <tt>Symbolizer</tt>
* @return constructed <tt>DisplayElement</tt>
*/
public static DisplayElement buildDisplayElement( Object o )
throws IncompatibleGeometryTypeException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException,
GeometryException {
DisplayElement displayElement = null;
if ( o instanceof GridCoverage ) {
RasterSymbolizer symbolizer = new RasterSymbolizer();
displayElement = buildRasterDisplayElement( (GridCoverage) o, symbolizer );
} else {
Feature feature = (Feature) o;
// determine the geometry property to be used
org.deegree.model.spatialschema.Geometry geoProperty = feature
.getDefaultGeometryPropertyValue();
// if the geometry property is null, do not build a DisplayElement
if ( geoProperty == null ) {
return null;
}
// PointSymbolizer
if ( geoProperty instanceof Point
|| geoProperty instanceof MultiPoint ) {
PointSymbolizer symbolizer = new PointSymbolizer();
displayElement = buildPointDisplayElement( feature, geoProperty, symbolizer );
} // LineSymbolizer
else if ( geoProperty instanceof Curve
|| geoProperty instanceof MultiCurve ) {
LineSymbolizer symbolizer = new LineSymbolizer();
displayElement = buildLineStringDisplayElement( feature, geoProperty, symbolizer );
} // PolygonSymbolizer
else if ( geoProperty instanceof Surface
|| geoProperty instanceof MultiSurface ) {
PolygonSymbolizer symbolizer = new PolygonSymbolizer();
displayElement = buildPolygonDisplayElement( feature, geoProperty, symbolizer );
} else {
throw new IncompatibleGeometryTypeException( "not a valid geometry type" );
}
}
return displayElement;
}
/**
* Creates a <tt>PointDisplayElement</tt> using the given geometry and style information.
* <p>
*
* @param feature
* associated <tt>Feature<tt>
* @param geom geometry information
* @param sym style information
* @return constructed <tt>PointDisplayElement</tt>
*/
public static PointDisplayElement buildPointDisplayElement(
Feature feature,
org.deegree.model.spatialschema.Geometry geom,
PointSymbolizer sym )
throws ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException {
// if the geometry is not a point geometry, the centroid(s) of the
// geometry will be used
PointDisplayElement displayElement = null;
String className = sym.getResponsibleClass();
Class clss = Class.forName( className );
Object[] values = new Object[] { feature, geom, sym };
if ( geom instanceof Point ) {
Class[] param = new Class[] { Feature.class, Point.class, PointSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (PointDisplayElement) constructor.newInstance( values );
} else if ( geom instanceof MultiPoint ) {
Class[] param = new Class[] { Feature.class, MultiPoint.class, PointSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (PointDisplayElement) constructor.newInstance( values );
} else if ( geom instanceof MultiPrimitive ) {
// Primitive[] primitives = ( (MultiPrimitive) geom ).getAllPrimitives();
// Point[] centroids = new Point[primitives.length];
Point[] centroids = new Point[1];
centroids[0] = geom.getCentroid();
// for ( int i = 0; i < primitives.length; i++ ) {
// centroids[i] = primitives[i].getCentroid();
// }
try {
Class[] param = new Class[] { Feature.class, MultiPoint.class,
PointSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
values[1] = GeometryFactory.createMultiPoint( centroids );
displayElement = (PointDisplayElement) constructor.newInstance( values );
} catch (Exception e) {
e.printStackTrace();
}
} else {
Class[] param = new Class[] { Feature.class, Point.class, PointSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
values[1] = geom.getCentroid();
displayElement = (PointDisplayElement) constructor.newInstance( values );
}
return displayElement;
}
/**
* Creates a <tt>LineStringDisplayElement</tt> using the given geometry and style information.
* <p>
*
* @param feature
* associated <tt>Feature<tt>
* @param geom geometry information
* @param sym style information
* @throws IncompatibleGeometryTypeException if the geometry property is not
* a <tt>Curve</tt> or a <tt>MultiCurve</tt>
* @return constructed <tt>LineStringDisplayElement</tt>
*/
public static LineStringDisplayElement buildLineStringDisplayElement(Feature feature,
org.deegree.model.spatialschema.Geometry geom,
LineSymbolizer sym )
throws IncompatibleGeometryTypeException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException,
GeometryException {
LineStringDisplayElement displayElement = null;
String className = sym.getResponsibleClass();
Class clss = Class.forName( className );
Object[] values = new Object[] { feature, geom, sym };
if ( geom instanceof Curve ) {
Class[] param = new Class[] { Feature.class, Curve.class, LineSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (LineStringDisplayElement) constructor.newInstance( values );
} else if ( geom instanceof MultiCurve ) {
Class[] param = new Class[] { Feature.class, MultiCurve.class, LineSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (LineStringDisplayElement) constructor.newInstance( values );
} else if ( geom instanceof Surface ) {
// according to OGC SLD specification it is possible to assign a
// LineSymbolizer to a polygon. To handle this the border of the
// polygon will be transformed into a lines (curves)
MultiCurve mc = surfaceToCurve( (Surface) geom );
displayElement = buildLineStringDisplayElement( feature, mc, sym );
} else if ( geom instanceof MultiSurface ) {
// according to OGC SLD specification it is possible to assign a
// LineSymbolizer to a multipolygon. To handle this the borders of the
// multipolygons will be transformed into a lines (curves)
MultiSurface ms = (MultiSurface) geom;
List list = new ArrayList( 500 );
for (int i = 0; i < ms.getSize(); i++) {
MultiCurve mc = surfaceToCurve( ms.getSurfaceAt( i ) );
for (int j = 0; j < mc.getSize(); j++) {
list.add( mc.getCurveAt( j ) );
}
}
Curve[] curves = (Curve[]) list.toArray( new Curve[list.size()] );
MultiCurve mc = GeometryFactory.createMultiCurve( curves );
displayElement = buildLineStringDisplayElement( feature, mc, sym );
} else {
throw new IncompatibleGeometryTypeException(
"Tried to create a LineStringDisplayElement from a geometry with "
+ "an incompatible / unsupported type: '" + geom.getClass().getName() + "'!" );
}
return displayElement;
}
/**
* transforms a Surface into a (Multi)Curve
*
* @param geom
* @return
* @throws Exception
*/
private static MultiCurve surfaceToCurve( Surface geom ) throws GeometryException {
List list = new ArrayList( 100 );
int k = geom.getNumberOfSurfacePatches();
for (int i = 0; i < k; i++) {
Position[] pos = geom.getSurfacePatchAt( i ).getExteriorRing();
Curve curve = GeometryFactory.createCurve( pos, geom.getCoordinateSystem() );
list.add( curve );
Position[][] inn = geom.getSurfacePatchAt( i ).getInteriorRings();
if ( inn != null ) {
for (int j = 0; j < inn.length; j++) {
curve = GeometryFactory.createCurve( inn[j], geom.getCoordinateSystem() );
list.add( curve );
}
}
}
Curve[] curves = (Curve[]) list.toArray( new Curve[list.size()] );
MultiCurve mc = GeometryFactory.createMultiCurve( curves );
return mc;
}
/**
* Creates a <tt>PolygonDisplayElement</tt> using the given geometry and style information.
* <p>
*
* @param feature
* associated <tt>Feature<tt>
* @param gmObject geometry information
* @param sym style information
* @throws IncompatibleGeometryTypeException if the geometry property is not
* a <tt>Surface</tt> or a <tt>MultiSurface</tt>
* @return constructed <tt>PolygonDisplayElement</tt>
*/
public static PolygonDisplayElement buildPolygonDisplayElement(
Feature feature,
org.deegree.model.spatialschema.Geometry gmObject,
PolygonSymbolizer sym )
throws IncompatibleGeometryTypeException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException {
PolygonDisplayElement displayElement = null;
String className = sym.getResponsibleClass();
Class clss = Class.forName( className );
Object[] values = new Object[] { feature, gmObject, sym };
if ( gmObject instanceof Surface ) {
Class[] param = new Class[] { Feature.class, Surface.class, PolygonSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (PolygonDisplayElement) constructor.newInstance( values );
} else if ( gmObject instanceof MultiSurface ) {
Class[] param = new Class[] { Feature.class, MultiSurface.class,
PolygonSymbolizer.class };
Constructor constructor = clss.getConstructor( param );
displayElement = (PolygonDisplayElement) constructor.newInstance( values );
} else {
throw new IncompatibleGeometryTypeException(
"Tried to create a LineStringDisplayElement from a geometry with "
+ "an incompatible / unsupported type: '" + gmObject.getClass().getName()
+ "'!" );
}
return displayElement;
}
/**
* Creates a <tt>LabelDisplayElement</tt> using the given geometry and style information.
* <p>
*
* @param feature
* <tt>Feature</tt> to be used (necessary for evaluation of the label expression)
* @param gmObject
* geometry information
* @param sym
* style information
* @throws IncompatibleGeometryTypeException
* if the geometry property is not a <tt>Point</tt>, a <tt>Surface</tt> or
* <tt>MultiSurface</tt>
* @return constructed <tt>PolygonDisplayElement</tt>
*/
public static LabelDisplayElement buildLabelDisplayElement(
Feature feature,
org.deegree.model.spatialschema.Geometry gmObject,
TextSymbolizer sym )
throws IncompatibleGeometryTypeException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
NoSuchMethodException,
InvocationTargetException {
LabelDisplayElement displayElement = null;
if ( gmObject instanceof Point
|| gmObject instanceof MultiPoint || gmObject instanceof Surface
|| gmObject instanceof MultiSurface || gmObject instanceof Curve
|| gmObject instanceof MultiCurve ) {
String className = sym.getResponsibleClass();
Class clss = Class.forName( className );
Class[] param = new Class[] { Feature.class,
org.deegree.model.spatialschema.Geometry.class,
TextSymbolizer.class };
Object[] values = new Object[] { feature, gmObject, sym };
Constructor constructor = clss.getConstructor( param );
displayElement = (LabelDisplayElement) constructor.newInstance( values );
} else {
throw new IncompatibleGeometryTypeException(
"Tried to create a LabelDisplayElement from a geometry with "
+ "an incompatible / unsupported type: '" + gmObject.getClass().getName()
+ "'!" );
}
return displayElement;
}
/**
* Creates a <tt>RasterDisplayElement</tt> from the submitted image. The submitted
* <tt>Envelope</tt> holds the bounding box of the imgae/raster data.
*
* @param gc
* grid coverage
* @param sym
* raster symbolizer
*
* @return RasterDisplayElement
*/
public static RasterDisplayElement buildRasterDisplayElement( GridCoverage gc,
RasterSymbolizer sym ) {
return new RasterDisplayElement( gc, sym );
}
}/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: DisplayElementFactory.java,v $
Revision 1.20 2006/07/29 08:51:12 poth
references to deprecated classes removed
Revision 1.19 2006/07/12 14:46:16 poth
comment footer added
********************************************************************** */