Java tutorial
/*---------------- 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 *** ********************************************************************** */