001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/j3d/Object3DFactory.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2007 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: 7956 $
075     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
076     * @author last edited by: $Author: rbezema $
077     * 
078     * $Revision: 7956 $, $Date: 2007-08-09 11:59:18 +0200 (Do, 09 Aug 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 URL xslt = Object3DFactory.class.getResource( "toWPVS.xsl" );
097    
098        /**
099         * all texture images will be stored on a Map to avoid double loading and creating a
100         * BufferedImage from a image source (textureMap property)
101         */
102        private static Map<String, BufferedImage> textImgMap;
103    
104        private static QualifiedName objectID;
105    
106        private static QualifiedName textMapQn;
107    
108        private static QualifiedName textCoordsQn;
109    
110        private static QualifiedName shininessQn;
111    
112        private static QualifiedName transparencyQn;
113    
114        private static QualifiedName ambientintensityQn;
115    
116        private static QualifiedName specularcolorQn;
117    
118        private static QualifiedName diffusecolorQn;
119    
120        private static QualifiedName emissivecolorQn;
121        static {
122            try {
123                if ( textImgMap == null ) {
124                    textImgMap = new HashMap<String, BufferedImage>( 200 );
125                    textMapQn = new QualifiedName( "app", "texturemap",
126                                                   new URI( "http://www.deegree.org/app" ) );
127                    textCoordsQn = new QualifiedName( "app", "texturecoordinates",
128                                                      new URI( "http://www.deegree.org/app" ) );
129                    shininessQn = new QualifiedName( "app", "shininess",
130                                                     new URI( "http://www.deegree.org/app" ) );
131                    transparencyQn = new QualifiedName( "app", "transparency",
132                                                        new URI( "http://www.deegree.org/app" ) );
133                    ambientintensityQn = new QualifiedName( "app", "ambientintensity",
134                                                            new URI( "http://www.deegree.org/app" ) );
135                    specularcolorQn = new QualifiedName( "app", "specularcolor",
136                                                         new URI( "http://www.deegree.org/app" ) );
137                    diffusecolorQn = new QualifiedName( "app", "diffusecolor",
138                                                        new URI( "http://www.deegree.org/app" ) );
139                    emissivecolorQn = new QualifiedName( "app", "emissivecolor",
140                                                         new URI( "http://www.deegree.org/app" ) );
141                    objectID = new QualifiedName( "app", "fk_feature",
142                                                  new URI( "http://www.deegree.org/app" ) );
143                }
144            } catch ( URISyntaxException e ) {
145                BootLogger.logError( e.getMessage(), e );
146            }
147        }
148    
149        /**
150         * creates a Surface from the passed feature. It is assumed the feature is simple, contains one
151         * surfac/polygon geometry and optional has material and/or texture informations. The GML schema
152         * for a valid feature is defined as:
153         * 
154         * <pre>
155         *    &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;
156         *        &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;
157         *         &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;
158         *         &lt;xsd:element name=&quot;WPVS&quot; type=&quot;app:WPVSType&quot; substitutionGroup=&quot;gml:_Feature&quot;/&gt;
159         *         &lt;xsd:complexType name=&quot;WPVSType&quot;&gt;
160         *             &lt;xsd:complexContent&gt;
161         *                 &lt;xsd:extension base=&quot;gml:AbstractFeatureType&quot;&gt;
162         *                     &lt;xsd:sequence&gt;
163         *                         &lt;xsd:element name=&quot;fk_feature&quot; type=&quot;xsd:double&quot;/&gt;
164         *                         &lt;xsd:element name=&quot;geometry&quot; type=&quot;gml:GeometryPropertyType&quot;/&gt;
165         *                         &lt;xsd:element name=&quot;shininess&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
166         *                         &lt;xsd:element name=&quot;transparency&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
167         *                         &lt;xsd:element name=&quot;ambientintensity&quot; type=&quot;xsd:double&quot; minOccurs=&quot;0&quot;/&gt;
168         *                         &lt;xsd:element name=&quot;specularcolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
169         *                         &lt;xsd:element name=&quot;diffusecolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
170         *                         &lt;xsd:element name=&quot;emissivecolor&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
171         *                         &lt;xsd:element name=&quot;texturemap&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
172         *                         &lt;xsd:element name=&quot;texturecoordinates&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
173         *                         &lt;xsd:element name=&quot;texturetype&quot; type=&quot;xsd:string&quot; minOccurs=&quot;0&quot;/&gt;
174         *                         &lt;xsd:element name=&quot;repeat&quot; type=&quot;xsd:integer&quot; minOccurs=&quot;0&quot;/&gt;
175         *                     &lt;/xsd:sequence&gt;
176         *                 &lt;/xsd:extension&gt;
177         *             &lt;/xsd:complexContent&gt;
178         *         &lt;/xsd:complexType&gt;
179         *     &lt;/xsd:schema&gt;
180         * </pre>
181         * 
182         * @param feature
183         * @return a DefaultSurface which is derivtive of a Shape3D.
184         */
185        public DefaultSurface createSurface( Feature feature ) {
186    
187            double oId = -1d;
188            if ( feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) instanceof BigDecimal ) {
189                oId = ( (BigDecimal) feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) ).doubleValue();
190            } else if ( feature.getDefaultProperty( objectID ).getValue( new Double( -1 ) ) instanceof Double ) {
191                oId = ( (Double) feature.getDefaultProperty( objectID ).getValue( new Double( -1d ) ) ).doubleValue();
192            }
193    
194            // read texture informations (if available) from feature
195            BufferedImage textImage = null;
196            FeatureProperty[] fp = feature.getProperties( textMapQn );
197            if ( fp != null && fp.length > 0 ) {
198                String tmp = (String) feature.getProperties( textMapQn )[0].getValue();
199                if ( tmp != null && ( textImage = textImgMap.get( tmp ) ) == null ) {
200                    String lt = tmp.toLowerCase();
201                    try {
202                        if ( lt.startsWith( "file:" ) || lt.startsWith( "http:" ) ) {
203                            textImage = ImageUtils.loadImage( new URL( tmp ) );
204                        } else {
205                            textImage = ImageUtils.loadImage( tmp );
206                        }
207                    } catch ( MalformedURLException e ) {
208                        e.printStackTrace();
209                    } catch ( IOException e ) {
210                        e.printStackTrace();
211                    }
212                    textImgMap.put( tmp, textImage );
213                }
214            }
215            float[][] textCoords = new float[1][];
216            fp = feature.getProperties( textCoordsQn );
217            if ( fp != null && fp.length > 0 ) {
218                String tmp = (String) feature.getProperties( textCoordsQn )[0].getValue();
219                if ( tmp != null ) {
220                    textCoords[0] = StringTools.toArrayFloat( tmp, ", " );
221                }
222            }
223    
224            // read color informations from feature. If not available use default values
225            // from material.properties
226            Double shininess = new Double( material.getProperty( "shininess" ) );
227            shininess = (Double) feature.getDefaultProperty( shininessQn ).getValue( shininess );
228            Double transparency = new Double( material.getProperty( "transparency" ) );
229            transparency = (Double) feature.getDefaultProperty( transparencyQn ).getValue(
230                                                                                           new Double(
231                                                                                                       0 ) );
232            Double ambientintensity = new Double( material.getProperty( "ambientintensity" ) );
233            ambientintensity = (Double) feature.getDefaultProperty( ambientintensityQn ).getValue(
234                                                                                                   new Double(
235                                                                                                               1 ) );
236            Color3f ambientcolor = new Color3f( ambientintensity.floatValue(),
237                                                ambientintensity.floatValue(),
238                                                ambientintensity.floatValue() );
239    
240            String tmp = material.getProperty( "specularcolor" );
241            tmp = (String) feature.getDefaultProperty( specularcolorQn ).getValue( tmp );
242            float[] tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
243            Color3f specularcolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
244    
245            tmp = material.getProperty( "diffusecolor" );
246            tmp = (String) feature.getDefaultProperty( diffusecolorQn ).getValue( tmp );
247            tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
248            Color3f diffusecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
249    
250            tmp = material.getProperty( "emissivecolor" );
251            tmp = (String) feature.getDefaultProperty( emissivecolorQn ).getValue( tmp );
252            tmpFl = StringTools.toArrayFloat( tmp.trim(), " " );
253            Color3f emissivecolor = new Color3f( tmpFl[0], tmpFl[1], tmpFl[2] );
254            Material material = new Material( ambientcolor, emissivecolor, diffusecolor, specularcolor,
255                                              shininess.floatValue() );
256            // for diffuse-color to work the ambient lighting must be switched on
257            material.setColorTarget( Material.AMBIENT_AND_DIFFUSE );
258            Surface geom = (Surface) feature.getDefaultGeometryPropertyValue();
259            LOG.logDebug( "3D-Surface: ", geom );
260    
261            DefaultSurface surface = null;
262            if ( textImage != null ) {
263                surface = new TexturedSurface( feature.getId(), String.valueOf( oId ), geom, material,
264                                               transparency.floatValue(), textImage, textCoords );
265            } else {
266                surface = new ColoredSurface( feature.getId(), String.valueOf( oId ), geom, material,
267                                              transparency.floatValue() );
268            }
269    
270            surface.compile();
271            return surface;
272        }
273    
274    }