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         *    &lt;xsd:schema targetNamespace=&quot;http://www.deegree.org/app&quot; xmlns:app=&quot;http://www.deegree.org/app&quot; xmlns:ogc=&quot;http://www.opengis.net/ogc&quot; xmlns:deegreewfs=&quot;http://www.deegree.org/wfs&quot; xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot; xmlns:gml=&quot;http://www.opengis.net/gml&quot; elementFormDefault=&quot;qualified&quot; attributeFormDefault=&quot;unqualified&quot;&gt;
150         *        &lt;xsd:import namespace=&quot;http://www.opengis.net/gml&quot; schemaLocation=&quot;http://schemas.opengis.net/gml/3.1.1/base/feature.xsd&quot;/&gt;
151         *         &lt;xsd:import namespace=&quot;http://www.opengis.net/gml&quot; schemaLocation=&quot;http://schemas.opengis.net/gml/3.1.1/base/geometryAggregates.xsd&quot;/&gt;
152         *         &lt;xsd:element name=&quot;WPVS&quot; type=&quot;app:WPVSType&quot; substitutionGroup=&quot;gml:_Feature&quot;/&gt;
153         *         &lt;xsd:complexType name=&quot;WPVSType&quot;&gt;
154         *             &lt;xsd:complexContent&gt;
155         *                 &lt;xsd:extension base=&quot;gml:AbstractFeatureType&quot;&gt;
156         *                     &lt;xsd:sequence&gt;
157         *                         &lt;xsd:element name=&quot;fk_feature&quot; type=&quot;xsd:double&quot;/&gt;
158         *                         &lt;xsd:element name=&quot;geometry&quot; type=&quot;gml:GeometryPropertyType&quot;/&gt;
159         *                         &lt;xsd:element name=&quot;shininess&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
160         *                         &lt;xsd:element name=&quot;transparency&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
161         *                         &lt;xsd:element name=&quot;ambientintensity&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
162         *                         &lt;xsd:element name=&quot;specularcolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
163         *                         &lt;xsd:element name=&quot;diffusecolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
164         *                         &lt;xsd:element name=&quot;emissivecolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
165         *                         &lt;xsd:element name=&quot;texturemap&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
166         *                         &lt;xsd:element name=&quot;texturecoordinates&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
167         *                         &lt;xsd:element name=&quot;texturetype&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
168         *                         &lt;xsd:element name=&quot;repeat&quot; type=&quot;xsd:integer&quot; minOccurs=&quot;0&quot;/&gt;
169         *                     &lt;/xsd:sequence&gt;
170         *                 &lt;/xsd:extension&gt;
171         *             &lt;/xsd:complexContent&gt;
172         *         &lt;/xsd:complexType&gt;
173         *     &lt;/xsd:schema&gt;
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    }