/*---------------- 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
53177 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.ogcwebservices.wpvs.j3d;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.media.j3d.Material;
import javax.vecmath.Color3f;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.BootLogger;
import org.deegree.framework.util.ImageUtils;
import org.deegree.framework.util.StringTools;
import org.deegree.framework.xml.XMLException;
import org.deegree.framework.xml.XMLFragment;
import org.deegree.framework.xml.XSLTDocument;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.feature.GMLFeatureCollectionDocument;
import org.deegree.model.filterencoding.AbstractFilter;
import org.deegree.model.filterencoding.Filter;
import org.deegree.model.filterencoding.FilterConstructionException;
import org.deegree.model.spatialschema.Envelope;
import org.deegree.model.spatialschema.GMLGeometryAdapter;
import org.deegree.model.spatialschema.Surface;
import org.deegree.ogcbase.PropertyPath;
import org.xml.sax.SAXException;
/**
*
*
*
* @version $Revision: 1.3 $
* @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
* @author last edited by: $Author: bezema $
*
* @version 1.0. $Revision: 1.3 $, $Date: 2006/11/27 16:57:26 $
*
* @since 2.0
*/
public class Object3DFactory {
private static final ILogger LOG = LoggerFactory.getLogger( Object3DFactory.class );
private URL xslt = Object3DFactory.class.getResource( "toWPVS.xsl" );
/**
* all texture images will be stored on a Map to avoid double loading
* and creating a BufferedImage from a image source (textureMap property)
*/
private static Map<String, BufferedImage> textImgMap;
private static QualifiedName objectID;
private static QualifiedName textMapQn;
private static QualifiedName textCoordsQn;
private static QualifiedName shininessQn;
private static QualifiedName transparencyQn;
private static QualifiedName ambientintensityQn;
private static QualifiedName specularcolorQn;
private static QualifiedName diffusecolorQn;
private static QualifiedName emissivecolorQn;
static {
try {
if ( textImgMap == null ) {
textImgMap = new HashMap<String, BufferedImage>( 200 );
textMapQn = new QualifiedName( "app", "texturemap",
new URI( "http://www.deegree.org/app" ) );
textCoordsQn = new QualifiedName( "app", "texturecoordinates",
new URI( "http://www.deegree.org/app" ) );
shininessQn = new QualifiedName( "app", "shininess",
new URI( "http://www.deegree.org/app" ) );
transparencyQn = new QualifiedName( "app", "transparency",
new URI( "http://www.deegree.org/app" ) );
ambientintensityQn = new QualifiedName( "app", "ambientintensity",
new URI( "http://www.deegree.org/app" ) );
specularcolorQn = new QualifiedName( "app", "specularcolor",
new URI( "http://www.deegree.org/app" ) );
diffusecolorQn = new QualifiedName( "app", "diffusecolor",
new URI( "http://www.deegree.org/app" ) );
emissivecolorQn = new QualifiedName( "app", "emissivecolor",
new URI( "http://www.deegree.org/app" ) );
objectID = new QualifiedName( "app", "fk_feature",
new URI( "http://www.deegree.org/app" ) );
}
} catch ( URISyntaxException e ) {
BootLogger.logError( e.getMessage(), e );
}
}
/**
* creates a Surface from the passed feature. It is assumed the feature
* is simple, contains one surfac/polygon geometry and optional has
* material and/or texture informations. The GML schema for a valid
* feature is defined as:
* <pre>
* <xsd:schema targetNamespace="http://www.deegree.org/app" xmlns:app="http://www.deegree.org/app" xmlns:ogc="http://www.opengis.net/ogc" xmlns:deegreewfs="http://www.deegree.org/wfs" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" attributeFormDefault="unqualified">
* <xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/feature.xsd"/>
* <xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/geometryAggregates.xsd"/>
* <xsd:element name="WPVS" type="app:WPVSType" substitutionGroup="gml:_Feature"/>
* <xsd:complexType name="WPVSType">
* <xsd:complexContent>
* <xsd:extension base="gml:AbstractFeatureType">
* <xsd:sequence>
* <xsd:element name="fk_feature" type="xsd:double"/>
* <xsd:element name="geometry" type="gml:GeometryPropertyType"/>
* <xsd:element name="shininess" type="xsd:double" minOccurs="0"/>
* <xsd:element name="transparency" type="xsd:double" minOccurs="0"/>
* <xsd:element name="ambientintensity" type="xsd:double" minOccurs="0"/>
* <xsd:element name="specularcolor" type="xsd:string" minOccurs="0"/>
* <xsd:element name="diffusecolor" type="xsd:string" minOccurs="0"/>
* <xsd:element name="emissivecolor" type="xsd:string" minOccurs="0"/>
* <xsd:element name="texturemap" type="xsd:string" minOccurs="0"/>
* <xsd:element name="texturecoordinates" type="xsd:string" minOccurs="0"/>
* <xsd:element name="texturetype" type="xsd:string" minOccurs="0"/>
* <xsd:element name="repeat" type="xsd:integer" minOccurs="0"/>
* </xsd:sequence>
* </xsd:extension>
* </xsd:complexContent>
* </xsd:complexType>
* </xsd:schema>
* </pre>
* @param feature
* @return a DefaultSurface which is derivtive of a Shape3D.
*/
public DefaultSurface createSurface( Feature feature ){
double oId = (Double) feature.getDefaultProperty( objectID ).getValue( -1d );
BufferedImage textImage = null;
FeatureProperty[] fp = feature.getProperties( textMapQn );
if ( fp != null && fp.length > 0 ) {
String tmp = (String) feature.getProperties( textMapQn )[0].getValue();
if ( ( textImage = textImgMap.get( tmp ) ) == null ) {
String lt = tmp.toLowerCase();
try {
if ( lt.startsWith( "file:" ) || lt.startsWith( "http:" ) ) {
textImage = ImageUtils.loadImage( new URL( tmp ) );
} else {
textImage = ImageUtils.loadImage( tmp );
}
} catch ( MalformedURLException e ) {
e.printStackTrace();
} catch ( IOException e ) {
e.printStackTrace();
}
textImgMap.put( tmp, textImage );
}
}
float[][] textCoords = new float[1][];
fp = feature.getProperties( textCoordsQn );
if ( fp != null && fp.length > 0 ) {
String tmp = (String) feature.getProperties( textCoordsQn )[0].getValue();
if ( tmp != null ) {
textCoords[0] = StringTools.toArrayFloat( tmp, ", " );
}
}
double shininess = (Double) feature.getDefaultProperty( shininessQn ).getValue( 1d );
double transparency = (Double) feature.getDefaultProperty( transparencyQn ).getValue( 0d );
double ambientintensity = (Double) feature.getDefaultProperty( ambientintensityQn ).getValue(
1d );
Color3f ambientcolor = new Color3f( (float) ambientintensity, (float) ambientintensity,
(float) ambientintensity );
String tmp = (String) feature.getDefaultProperty( specularcolorQn ).getValue( "1 1 1" );
float[] tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
Color3f specularcolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
tmp = (String) feature.getDefaultProperty( diffusecolorQn ).getValue( "1 1 1" );
tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
Color3f diffusecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
tmp = (String) feature.getDefaultProperty( emissivecolorQn ).getValue( "1 1 1" );
tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
Color3f emissivecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
Material material = new Material( ambientcolor, emissivecolor, diffusecolor, specularcolor,
(float) shininess );
Surface geom = (Surface) feature.getDefaultGeometryPropertyValue();
LOG.logDebug( "3D-Surface: ", geom );
DefaultSurface surface = null;
if ( textImage != null ) {
surface = new TexturedSurface( feature.getId(), String.valueOf(oId), geom, material, (float) transparency,
textImage, textCoords );
} else {
surface = new ColoredSurface( feature.getId(), String.valueOf(oId), geom, material, (float) transparency );
}
surface.compile();
return surface;
}
public Composite3DObject createComposite3DObject( Feature feature ) {
// TODO
throw new UnsupportedOperationException();
}
/**
* creates a Composite3DObject from a FeatureCollection
* @param fc
* @return
* @throws IOException
*/
public Composite3DObject createComposite3DObject( FeatureCollection fc )
throws IOException {
List<DefaultSurface> list = new ArrayList<DefaultSurface>( fc.size() );
for ( int i = 0; i < fc.size(); i++ ) {
DefaultSurface sur = createSurface( fc.getFeature( i ) );
list.add( sur );
}
return new Composite3DObject( fc.getId(), list );
}
/**
* performs a GetFeature request against the passed URL using the also
* passed featureType and Filter (least one may be <code>null</code>)
*
* @param url
* @param featureType
* @param filter
* @return
* @throws HttpException
* @throws IOException
* @throws XMLException
* @throws SAXException
*/
public Composite3DObject createComposite3DObject( URL url, QualifiedName featureType,
Filter filter )
throws IOException, XMLException {
StringBuffer sb = new StringBuffer( 2000 );
sb.append( "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>" );
sb.append( "<wfs:GetFeature version=\"1.1.0\" outputFormat=\"text/xml; " );
sb.append( "subtype=gml/3.1.1\" xmlns:wfs=\"http://www.opengis.net/wfs\" " );
sb.append( "xmlns:" ).append( featureType.getPrefix() ).append( "='" );
sb.append( featureType.getNamespace().toASCIIString() ).append( "' " );
sb.append( "><wfs:Query " );
sb.append( "typeName='" ).append( featureType.getPrefix() ).append( ':' );
sb.append( featureType.getLocalName() ).append( "'>" );
if ( filter != null ) {
sb.append( filter.toXML() );
}
sb.append( "</wfs:Query></wfs:GetFeature>" );
LOG.logDebug( "GetFeature for access 3D objects", sb.toString() );
PostMethod post = new PostMethod( "http://localhost:8081/wfs/services" );
StringRequestEntity sre = new StringRequestEntity( sb.toString() );
post.setRequestEntity( sre );
HttpClient client = new HttpClient();
client.executeMethod( post );
GMLFeatureCollectionDocument doc = new GMLFeatureCollectionDocument();
try {
doc.load( post.getResponseBodyAsStream(), url.toExternalForm() );
} catch ( SAXException e ) {
LOG.logError( e.getMessage(), e );
throw new XMLException( e );
}
return createComposite3DObject( doc );
}
/**
* performs a GetFeature request against the passed URL using the also
* passed featureType and a @see Filter constructed from the passed
* envelope
*
* @param url
* @param featureType
* @param geomProperty
* @param envelope
* @return
* @throws XMLException
* @throws IOException
*/
public Composite3DObject createComposite3DObject( URL url, QualifiedName featureType,
PropertyPath geomProperty, Envelope envelope )
throws XMLException, IOException {
StringBuffer sb = new StringBuffer( 1000 );
sb.append( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\"" );
sb.append( "><ogc:BBOX>" );
sb.append( "<ogc:PropertyName>" ).append( geomProperty.getAsString() );
sb.append( "</ogc:PropertyName>" );
sb.append( GMLGeometryAdapter.exportAsBox( envelope ) );
sb.append( "</ogc:BBOX></ogc:Filter>" );
XMLFragment xml = new XMLFragment();
try {
xml.load( new StringReader( sb.toString() ), XMLFragment.DEFAULT_URL );
} catch ( SAXException e ) {
LOG.logError( e.getMessage(), e );
throw new XMLException( e );
}
Filter filter = null;
try {
filter = AbstractFilter.buildFromDOM( xml.getRootElement() );
} catch ( FilterConstructionException e ) {
LOG.logError( e.getMessage(), e );
throw new XMLException( e );
}
return createComposite3DObject( url, featureType, filter );
}
/**
*
* @param gml
* @return
* @throws IOException
*/
public Composite3DObject createComposite3DObject( GMLFeatureCollectionDocument gml )
throws IOException {
FeatureCollection fc = null;
try {
XSLTDocument xsltDoc = new XSLTDocument( xslt );
XMLFragment xml = xsltDoc.transform( gml );
gml = new GMLFeatureCollectionDocument();
gml.setRootElement( xml.getRootElement() );
fc = gml.parse();
} catch ( Exception e ) {
LOG.logError( e.getMessage(), e );
throw new IOException( "could not load/parse GML feature collection: " + e.getMessage() );
}
return createComposite3DObject( fc );
}
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: Object3DFactory.java,v $
Revision 1.3 2006/11/27 16:57:26 bezema
cleaning up the code
Revision 1.2 2006/11/27 09:07:52 poth
JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code.
Revision 1.1 2006/11/23 11:46:40 bezema
The initial version of the new wpvs
Revision 1.1 2006/10/23 09:01:25 ap
*** empty log message ***
********************************************************************** */