001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/j3d/Object3DFactory.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2008 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 ---------------------------------------------------------------------------*/ 043 package org.deegree.ogcwebservices.wpvs.j3d; 044 045 import java.awt.image.BufferedImage; 046 import java.io.IOException; 047 import java.io.InputStream; 048 import java.math.BigDecimal; 049 import java.net.MalformedURLException; 050 import java.net.URI; 051 import java.net.URISyntaxException; 052 import java.net.URL; 053 import java.util.HashMap; 054 import java.util.Map; 055 import java.util.Properties; 056 057 import javax.media.j3d.Material; 058 import javax.vecmath.Color3f; 059 060 import org.deegree.datatypes.QualifiedName; 061 import org.deegree.framework.log.ILogger; 062 import org.deegree.framework.log.LoggerFactory; 063 import org.deegree.framework.util.BootLogger; 064 import org.deegree.framework.util.ImageUtils; 065 import org.deegree.framework.util.StringTools; 066 import org.deegree.model.feature.Feature; 067 import org.deegree.model.feature.FeatureProperty; 068 import org.deegree.model.spatialschema.Surface; 069 070 /** 071 * 072 * 073 * 074 * @version $Revision: 9345 $ 075 * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a> 076 * @author last edited by: $Author: apoth $ 077 * 078 * $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $ 079 * 080 */ 081 public class Object3DFactory { 082 083 private static InputStream materialURL = Object3DFactory.class.getResourceAsStream( "material.properties" ); 084 085 private static Properties material = new Properties(); 086 static { 087 try { 088 material.load( materialURL ); 089 } catch ( IOException e ) { 090 BootLogger.logError( e.getMessage(), e ); 091 } 092 } 093 094 private static final ILogger LOG = LoggerFactory.getLogger( Object3DFactory.class ); 095 096 private static int numberOfCreatedSurfaces = 0; 097 098 // private URL xslt = Object3DFactory.class.getResource( "toWPVS.xsl" ); 099 100 /** 101 * all texture images will be stored on a Map to avoid double loading and creating a BufferedImage from a image 102 * source (textureMap property) 103 */ 104 private static Map<String, BufferedImage> textImgMap; 105 106 private static QualifiedName objectID; 107 108 private static QualifiedName textMapQn; 109 110 private static QualifiedName textCoordsQn; 111 112 private static QualifiedName shininessQn; 113 114 private static QualifiedName transparencyQn; 115 116 private static QualifiedName ambientintensityQn; 117 118 private static QualifiedName specularcolorQn; 119 120 private static QualifiedName diffusecolorQn; 121 122 private static QualifiedName emissivecolorQn; 123 static { 124 try { 125 if ( textImgMap == null ) { 126 textImgMap = new HashMap<String, BufferedImage>( 200 ); 127 textMapQn = new QualifiedName( "app", "texturemap", new URI( "http://www.deegree.org/app" ) ); 128 textCoordsQn = new QualifiedName( "app", "texturecoordinates", new URI( "http://www.deegree.org/app" ) ); 129 shininessQn = new QualifiedName( "app", "shininess", new URI( "http://www.deegree.org/app" ) ); 130 transparencyQn = new QualifiedName( "app", "transparency", new URI( "http://www.deegree.org/app" ) ); 131 ambientintensityQn = new QualifiedName( "app", 132 "ambientintensity", 133 new URI( "http://www.deegree.org/app" ) ); 134 specularcolorQn = new QualifiedName( "app", "specularcolor", new URI( "http://www.deegree.org/app" ) ); 135 diffusecolorQn = new QualifiedName( "app", "diffusecolor", new URI( "http://www.deegree.org/app" ) ); 136 emissivecolorQn = new QualifiedName( "app", "emissivecolor", new URI( "http://www.deegree.org/app" ) ); 137 objectID = new QualifiedName( "app", "fk_feature", new URI( "http://www.deegree.org/app" ) ); 138 } 139 } catch ( URISyntaxException e ) { 140 BootLogger.logError( e.getMessage(), e ); 141 } 142 } 143 144 /** 145 * creates a Surface from the passed feature. It is assumed the feature is simple, contains one surfac/polygon 146 * geometry and optional has material and/or texture informations. The GML schema for a valid feature is defined as: 147 * 148 * <pre> 149 * <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"> 150 * <xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/feature.xsd"/> 151 * <xsd:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/geometryAggregates.xsd"/> 152 * <xsd:element name="WPVS" type="app:WPVSType" substitutionGroup="gml:_Feature"/> 153 * <xsd:complexType name="WPVSType"> 154 * <xsd:complexContent> 155 * <xsd:extension base="gml:AbstractFeatureType"> 156 * <xsd:sequence> 157 * <xsd:element name="fk_feature" type="xsd:double"/> 158 * <xsd:element name="geometry" type="gml:GeometryPropertyType"/> 159 * <xsd:element name="shininess" type="xsd:double" minOccurs="0"/> 160 * <xsd:element name="transparency" type="xsd:double" minOccurs="0"/> 161 * <xsd:element name="ambientintensity" type="xsd:double" minOccurs="0"/> 162 * <xsd:element name="specularcolor" type="xsd:string" minOccurs="0"/> 163 * <xsd:element name="diffusecolor" type="xsd:string" minOccurs="0"/> 164 * <xsd:element name="emissivecolor" type="xsd:string" minOccurs="0"/> 165 * <xsd:element name="texturemap" type="xsd:string" minOccurs="0"/> 166 * <xsd:element name="texturecoordinates" type="xsd:string" minOccurs="0"/> 167 * <xsd:element name="texturetype" type="xsd:string" minOccurs="0"/> 168 * <xsd:element name="repeat" type="xsd:integer" minOccurs="0"/> 169 * </xsd:sequence> 170 * </xsd:extension> 171 * </xsd:complexContent> 172 * </xsd:complexType> 173 * </xsd:schema> 174 * </pre> 175 * 176 * @param feature 177 * @return a DefaultSurface which is derivtive of a Shape3D. 178 */ 179 public DefaultSurface createSurface( Feature feature ) { 180 181 double oId = -1d; 182 if ( feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) instanceof BigDecimal ) { 183 oId = ( (BigDecimal) feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) ).doubleValue(); 184 } else if ( feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) instanceof Double ) { 185 oId = ( (Double) feature.getDefaultProperty( objectID ).getValue( new Double( -1d ) ) ).doubleValue(); 186 } 187 188 // read texture informations (if available) from feature 189 BufferedImage textImage = null; 190 FeatureProperty[] fp = feature.getProperties( textMapQn ); 191 if ( fp != null && fp.length > 0 ) { 192 String tmp = (String) feature.getProperties( textMapQn )[0].getValue(); 193 if ( tmp != null && ( textImage = textImgMap.get( tmp ) ) == null ) { 194 String lt = tmp.toLowerCase(); 195 try { 196 if ( lt.startsWith( "file:" ) || lt.startsWith( "http:" ) ) { 197 textImage = ImageUtils.loadImage( new URL( tmp ) ); 198 } else { 199 textImage = ImageUtils.loadImage( tmp ); 200 } 201 } catch ( MalformedURLException e ) { 202 e.printStackTrace(); 203 } catch ( IOException e ) { 204 e.printStackTrace(); 205 } 206 textImgMap.put( tmp, textImage ); 207 } 208 } 209 float[][] textCoords = new float[1][]; 210 fp = feature.getProperties( textCoordsQn ); 211 if ( fp != null && fp.length > 0 ) { 212 String tmp = (String) fp[0].getValue(); 213 LOG.logDebug( "Texture Coordinates: " + tmp ); 214 if ( tmp != null ) { 215 textCoords[0] = StringTools.toArrayFloat( tmp, ", " ); 216 } 217 } 218 219 // read color informations from feature. If not available use default values 220 // from material.properties 221 Double shininess = new Double( material.getProperty( "shininess" ) ); 222 shininess = (Double) feature.getDefaultProperty( shininessQn ).getValue( shininess ); 223 Double transparency = new Double( material.getProperty( "transparency" ) ); 224 transparency = (Double) feature.getDefaultProperty( transparencyQn ).getValue( new Double( 0 ) ); 225 Double ambientintensity = new Double( material.getProperty( "ambientintensity" ) ); 226 ambientintensity = (Double) feature.getDefaultProperty( ambientintensityQn ).getValue( new Double( 1 ) ); 227 Color3f ambientcolor = new Color3f( ambientintensity.floatValue(), 228 ambientintensity.floatValue(), 229 ambientintensity.floatValue() ); 230 231 String tmp = material.getProperty( "specularcolor" ); 232 tmp = (String) feature.getDefaultProperty( specularcolorQn ).getValue( tmp ); 233 float[] tmpFl = StringTools.toArrayFloat( tmp.trim(), " " ); 234 Color3f specularcolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] ); 235 236 tmp = material.getProperty( "diffusecolor" ); 237 tmp = (String) feature.getDefaultProperty( diffusecolorQn ).getValue( tmp ); 238 tmpFl = StringTools.toArrayFloat( tmp.trim(), " " ); 239 Color3f diffusecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] ); 240 241 tmp = material.getProperty( "emissivecolor" ); 242 tmp = (String) feature.getDefaultProperty( emissivecolorQn ).getValue( tmp ); 243 tmpFl = StringTools.toArrayFloat( tmp.trim(), " " ); 244 Color3f emissivecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] ); 245 Material material = new Material( ambientcolor, 246 emissivecolor, 247 diffusecolor, 248 specularcolor, 249 shininess.floatValue() ); 250 // for diffuse-color to work the ambient lighting must be switched on 251 material.setColorTarget( Material.AMBIENT_AND_DIFFUSE ); 252 /** 253 * Please check for the right property here. The defaultPropertyValue just delivers the first geometry defined 254 * in the wfs configuration. 255 */ 256 Surface geom = (Surface) feature.getDefaultGeometryPropertyValue(); 257 LOG.logDebug( "3D-Surface: ", geom ); 258 259 DefaultSurface surface = null; 260 if ( textImage != null ) { 261 surface = new TexturedSurface( feature.getId(), 262 String.valueOf( oId ), 263 geom, 264 material, 265 transparency.floatValue(), 266 textImage, 267 textCoords ); 268 } else { 269 surface = new ColoredSurface( feature.getId(), 270 String.valueOf( oId ), 271 geom, 272 material, 273 transparency.floatValue() ); 274 } 275 surface.compile(); 276 return surface; 277 } 278 279 }