    001    //$HeadURL: $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036
    037    package org.deegree.tools.app3d;
    038
    039    import static java.lang.System.exit;
    040    import static org.deegree.ogcbase.CommonNamespaces.CITYGMLNS;
    041    import static org.deegree.ogcbase.CommonNamespaces.CITYGML_PREFIX;
    042    import static org.deegree.ogcbase.CommonNamespaces.GMLNS;
    043    import static org.deegree.ogcbase.CommonNamespaces.GML_PREFIX;
    044
    045    import java.awt.image.BufferedImage;
    046    import java.io.BufferedReader;
    047    import java.io.BufferedWriter;
    048    import java.io.File;
    049    import java.io.FileNotFoundException;
    050    import java.io.FileWriter;
    051    import java.io.IOException;
    052    import java.io.InputStreamReader;
    053    import java.util.Calendar;
    054    import java.util.Enumeration;
    055    import java.util.GregorianCalendar;
    056    import java.util.HashMap;
    057    import java.util.Map;
    058
    059    import javax.imageio.ImageIO;
    060    import javax.media.j3d.Appearance;
    061    import javax.media.j3d.Background;
    062    import javax.media.j3d.BoundingBox;
    063    import javax.media.j3d.Bounds;
    064    import javax.media.j3d.BranchGroup;
    065    import javax.media.j3d.Geometry;
    066    import javax.media.j3d.GeometryArray;
    067    import javax.media.j3d.Group;
    068    import javax.media.j3d.ImageComponent;
    069    import javax.media.j3d.ImageComponent2D;
    070    import javax.media.j3d.Leaf;
    071    import javax.media.j3d.Material;
    072    import javax.media.j3d.Node;
    073    import javax.media.j3d.Shape3D;
    074    import javax.media.j3d.Texture;
    075    import javax.media.j3d.Transform3D;
    076    import javax.media.j3d.TransformGroup;
    077    import javax.media.j3d.TriangleArray;
    078    import javax.vecmath.AxisAngle4d;
    079    import javax.vecmath.Color3f;
    080    import javax.vecmath.Point3d;
    081    import javax.vecmath.TexCoord2f;
    082    import javax.vecmath.Vector3d;
    083
    084    import org.deegree.framework.log.ILogger;
    085    import org.deegree.framework.log.LoggerFactory;
    086    import org.deegree.framework.xml.XMLFragment;
    087    import org.deegree.framework.xml.XMLTools;
    088    import org.deegree.ogcbase.CommonNamespaces;
    089    import org.jdesktop.j3d.loaders.vrml97.VrmlLoader;
    090    import org.w3c.dom.Document;
    091    import org.w3c.dom.Element;
    092
    093    import com.sun.j3d.loaders.IncorrectFormatException;
    094    import com.sun.j3d.loaders.ParsingErrorException;
    095    import com.sun.j3d.loaders.Scene;
    096    import com.sun.j3d.utils.geometry.GeometryInfo;
    097
    098    /**
    099     * The <code>J3DToCityGMLExporter</code> exports a J3D scene to citygml level 1.
    100     *
    101     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
    102     *
    103     * @author last edited by: $Author:$
    104     *
    105     * @version $Revision:$, $Date:$
    106     *
    107     */
    108
    109    public class J3DToCityGMLExporter implements J3DExporter {
    110        static {
    111            try {
    112                new VrmlLoader();
    113            } catch ( NoClassDefFoundError c ) {
    114                libHelp( c );
    115            }
    116        }
    117
    118        private static ILogger LOG = LoggerFactory.getLogger( J3DToCityGMLExporter.class );
    119
    120        private final static String PRE_C = CITYGML_PREFIX + ":";
    121
    122        private final static String PRE_G = GML_PREFIX + ":";
    123
    124        private static int textureCount = 0;
    125
    126        // Instance variables.
    127        private String name = null;
    128
    129        private String crsName = "EPSG:31466";
    130
    131        private String cityGMLFunction = "1001";
    132
    133        private String textureOutputDir;
    134
    135        private boolean asWFSTransaction = false;
    136
    137        // Will hold the texture file names if two different geometries use a single texture.
    138        // private Map<String, String> savedTextures = new HashMap<String, String>( 200 );
    139
    140        private static int numberOfSurfaces = 0;
    141
    142        private Transform3D transformMatrix = null;
    143
    144        private Transform3D rotationMatrix = null;
    145
    146        private boolean inverseYZ = true;
    147
    148        private HashMap<BufferedImage, String> cachedTextures = new HashMap<BufferedImage, String>();
    149
    150        /**
    151         * A default constructor allows the instantiation of this exported to supply the getParameterList method.
    152         * <p>
    153         * <b>NOTE</b> this constructor is only convenient, it should not be used carelessly. Instead use one of the other
    154         * constructors for correct instantiation of this class.
    155         * </p>
    156         */
    157        public J3DToCityGMLExporter() {
    158            // nothing
    159        }
    160
    161        /**
    162         * @param params
    163         *            a hashmap to extract values from. For a list of supported parameters
    164         * @throws IOException
    165         *             if the key 'texdir' points to a file which is not a directory or is not writable
    166         */
    167        public J3DToCityGMLExporter( Map<String, String> params ) throws IOException {
    168            String texDir = params.get( "texdir" );
    169            if ( texDir == null || "".equals( texDir.trim() ) ) {
    170                LOG.logInfo( "Setting tex dir to " + System.getProperty( "user.home" ) + "/j3dTextures/" );
    171                texDir = System.getProperty( "user.home" ) + "/j3dTextures/";
    172                File t = new File( texDir );
    173                t.mkdir();
    174            }
    175            File tmp = new File( texDir );
    176
    177            if ( !tmp.isDirectory() ) {
    178                throw new IOException( "Given file: " + tmp.getAbsoluteFile()
    179                                       + " exists, but is not a directory, please specify a valid directory." );
    180            }
    181            if ( !tmp.canWrite() ) {
    182                throw new IOException( "Can not write to specified directory: " + tmp.getAbsoluteFile()
    183                                       + ", please specify directory which can be written to." );
    184            }
    185            textureOutputDir = texDir;
    186            if ( !textureOutputDir.endsWith( File.separator ) ) {
    187                // just make sure the given path ends with the separator.
    188                textureOutputDir += File.separator;
    189            }
    190
    191            double xTrans = 0;
    192            String t = params.get( "xtranslation" );
    193            if ( t != null && !"".equals( t ) ) {
    194                try {
    195                    xTrans = Double.parseDouble( t );
    196                } catch ( NumberFormatException nfe ) {
    197                    // nottin
    198                }
    199            }
    200            double yTrans = 0;
    201            t = params.get( "ytranslation" );
    202            if ( t != null && !"".equals( t ) ) {
    203                try {
    204                    yTrans = Double.parseDouble( t );
    205                } catch ( NumberFormatException nfe ) {
    206                    // nottin
    207                }
    208            }
    209            double zTrans = 0;
    210            t = params.get( "ztranslation" );
    211            if ( t != null && !"".equals( t ) ) {
    212                try {
    213                    zTrans = Double.parseDouble( t );
    214                } catch ( NumberFormatException nfe ) {
    215                    // nottin
    216                }
    217            }
    218            AxisAngle4d rotAngle = null;
    219            t = params.get( "rotationangle" );
    220            if ( t != null && !"".equals( t ) ) {
    221                try {
    222                    String[] values = t.split( "," );
    223                    LOG.logDebug( "Using rotation angle: " + t );
    224                    if ( values.length != 4 ) {
    225                        LOG.logError( "The rotation angle must have 4 values and must be separated by a ',' (without spaces) with following form x,y,z,rotation (in radians) . Ignoring your values." );
    226                    } else {
    227                        rotAngle = new AxisAngle4d( Double.parseDouble( values[0] ), Double.parseDouble( values[1] ),
    228                                                    Double.parseDouble( values[2] ), Double.parseDouble( values[3] ) );
    229                    }
    230                } catch ( NumberFormatException nfe ) {
    231                    // nottin
    232                }
    233            }
    234            transformMatrix = new Transform3D();
    235            transformMatrix.setTranslation( new Vector3d( xTrans, yTrans, zTrans ) );
    236            if ( rotAngle != null ) {
    237                rotationMatrix = new Transform3D();
    238                rotationMatrix.setRotation( rotAngle );
    239            }
    240
    241            this.asWFSTransaction = false;
    242            t = params.get( "wfstransaction" );
    243            if ( t != null && !"".equals( t ) ) {
    244                this.asWFSTransaction = t.equalsIgnoreCase( "y" ) || t.equalsIgnoreCase( "yes" );
    245            }
    246            this.name = "building";
    247            t = params.get( "name" );
    248            if ( t != null && !"".equals( t.trim() ) ) {
    249                this.name = t;
    250            }
    251
    252            crsName = "EPSG:4326";
    253            t = params.get( "srs" );
    254            if ( t != null && !"".equals( t.trim() ) ) {
    255                this.crsName = t;
    256            }
    257
    258            this.cityGMLFunction = "1001";
    259            t = params.get( "buildingFunction" );
    260            if ( t != null && !"".equals( t.trim() ) ) {
    261                this.cityGMLFunction = t;
    262            }
    263            this.inverseYZ = false;
    264            t = params.get( "inverseyz" );
    265            if ( t != null && !"".equals( t.trim() ) ) {
    266                this.inverseYZ = t.equalsIgnoreCase( "y" ) || t.equalsIgnoreCase( "yes" );
    267            }
    268        }
    269
    270        /**
    271         * @param citygmlName
    272         *            of the exported branchgroup.
    273         * @param crsName
    274         *            of the crs to set the srsName of gmlNodes to, if <code>null</code> 'epsg:31466' will be used.
    275         * @param cityGMLFunction
    276         *            to insert om the gml
    277         * @param textureOutputDirectory
    278         *            the directory to output the textures to, if any.
    279         * @param translationX
    280         *            a value to add up to the found x - coordinates. If NaN, 0 will be used.
    281         * @param translationY
    282         *            a value to add up to the found y - coordinates. If NaN, 0 will be used.
    283         * @param translationZ
    284         *            a value to add up to the found z - coordinates. If NaN, 0 will be used.
    285         * @param rotAngle
    286         *            the rotation angle to which the all geometries should be rotated.
    287         * @param asWFSTransaction
    288         *            true if the scene should be exported as a wfs:Transaction document (the root node is wfs:Transaction)
    289         *            or a cityGML document (the root node is citygml:Building).
    290         * @param inverseYZ
    291         * @throws IOException
    292         *             if the something went wrong with wile creating, referring or addressing the given filePath.
    293         */
    294        public J3DToCityGMLExporter( String citygmlName, String crsName, String cityGMLFunction,
    295                                     String textureOutputDirectory, double translationX, double translationY,
    296                                     double translationZ, AxisAngle4d rotAngle, boolean asWFSTransaction, boolean inverseYZ )
    297                                throws IOException {
    298            if ( citygmlName != null && !"".equals( citygmlName.trim() ) ) {
    299                this.name = citygmlName;
    300            }
    301
    302            if ( crsName != null && !"".equals( crsName.trim() ) ) {
    303                this.crsName = crsName;
    304            }
    305
    306            if ( cityGMLFunction != null && !"".equals( cityGMLFunction.trim() ) ) {
    307                this.cityGMLFunction = cityGMLFunction;
    308            }
    309
    310            if ( textureOutputDirectory != null && !"".equals( textureOutputDirectory.trim() ) ) {
    311                File tmp = new File( textureOutputDirectory );
    312                if ( !tmp.exists() ) {
    313                    System.out.print( "The directory: " + textureOutputDirectory + " does not exist, create?: " );
    314                    BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
    315                    String answer = in.readLine();
    316                    if ( answer != null && ( "yes".equalsIgnoreCase( answer ) || "y".equalsIgnoreCase( answer ) ) ) {
    317                        if ( !tmp.mkdir() ) {
    318                            throw new IOException( "Could not create given directory: " + tmp.getAbsoluteFile()
    319                                                   + " please create it first!" );
    320                        }
    321                    } else {
    322                        throw new IOException( "Given directory: " + tmp.getAbsoluteFile()
    323                                               + " does not exist, please create it first!" );
    324                    }
    325                }
    326                if ( !tmp.isDirectory() ) {
    327                    throw new IOException( "Given file: " + tmp.getAbsoluteFile()
    328                                           + " exists, but is not a directory, please specify a valid directory." );
    329                }
    330                if ( !tmp.canWrite() ) {
    331                    throw new IOException( "Can not write to specified directory: " + tmp.getAbsoluteFile()
    332                                           + ", please specify directory which can be written to." );
    333                }
    334                textureOutputDir = textureOutputDirectory;
    335                if ( !textureOutputDirectory.endsWith( File.separator ) ) {
    336                    // just make sure the given path ends with the separator.
    337                    textureOutputDir += File.separator;
    338                }
    339
    340            } else {
    341                throw new IOException( "No directory was given for the output textures." );
    342            }
    343            transformMatrix = new Transform3D();
    344            if ( Double.isNaN( translationX ) ) {
    345                translationX = 0;
    346            }
    347            if ( Double.isNaN( translationY ) ) {
    348                translationY = 0;
    349            }
    350            if ( Double.isNaN( translationZ ) ) {
    351                translationZ = 0;
    352            }
    353            transformMatrix.setTranslation( new Vector3d( translationX, translationY, translationZ ) );
    354            LOG.logDebug( "Hier:\n" + transformMatrix + "\nrotanlge: " + rotAngle );
    355            if ( rotAngle != null ) {
    356                // transformMatrix.setRotation( rotAngle );
    357                rotationMatrix = new Transform3D();
    358                rotationMatrix.setRotation( rotAngle );
    359            }
    360            LOG.logDebug( "Hier2:\n" + transformMatrix );
    361
    362            this.inverseYZ = inverseYZ;
    363            this.asWFSTransaction = asWFSTransaction;
    364        }
    365
    366        public void export( StringBuilder result, Group j3dScene ) {
    367            if ( j3dScene != null ) {
    368                if ( j3dScene.getCapability( Group.ALLOW_CHILDREN_READ ) ) {
    369                    Document doc = XMLTools.create();
    370                    Element root = null;
    371                    Element building = doc.createElementNS( CommonNamespaces.CITYGMLNS.toASCIIString(), PRE_C + "Building" );
    372                    if ( asWFSTransaction ) {
    373                        root = doc.createElementNS( CommonNamespaces.WFSNS.toASCIIString(), CommonNamespaces.WFS_PREFIX
    374                                                                                            + ":Transaction" );
    375                        root.setAttribute( "version", "1.1.0" );
    376                        root.setAttribute( "service", "WFS" );
    377                        Element insert = XMLTools.appendElement( root, CommonNamespaces.WFSNS, CommonNamespaces.WFS_PREFIX
    378                                                                                               + ":Insert" );
    379                        // Element featureCollection = XMLTools.appendElement( insert,
    380                        // CommonNamespaces.WFSNS,
    381                        // CommonNamespaces.WFS_PREFIX + ":FeatureCollection" );
    382
    383                        // building = (Element)featureCollection.appendChild( building );
    384                        building = (Element) insert.appendChild( building );
    385
    386                    } else {
    387                        root = doc.createElementNS( CITYGMLNS.toASCIIString(), PRE_C + "CityModel" );
    388                        Element member = XMLTools.appendElement( root, CITYGMLNS, PRE_C + "cityObjectMember" );
    389                        member.appendChild( building );
    390                    }
    391
    392                    // set the name element
    393                    if ( name == null ) {
    394                        name = j3dScene.getName();
    395                    }
    396                    XMLTools.appendElement( building, CommonNamespaces.GMLNS, PRE_G + "name", name );
    397                    boolean calcBounds = false;
    398                    Point3d lower = new Point3d( Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE );
    399                    Point3d upper = new Point3d( Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE );
    400                    if ( j3dScene.getCapability( Node.ALLOW_BOUNDS_READ ) ) {
    401                        Bounds b = j3dScene.getBounds();
    402                        if ( b != null ) {
    403                            BoundingBox bBox = new BoundingBox( b );
    404                            bBox.getLower( lower );
    405                            bBox.getUpper( upper );
    406                            // lower.x += transformMatrix.ttranslationX;
    407                            // lower.y += translationY;
    408                            transformMatrix.transform( lower );
    409                            // upper.x += translationX;
    410                            // upper.y += translationY;
    411                            transformMatrix.transform( upper );
    412                            Element boundBy = XMLTools.appendElement( building, GMLNS, PRE_G + "boundedBy" );
    413                            Element env = XMLTools.appendElement( boundBy, GMLNS, PRE_G + "Envelope" );
    414                            env.setAttribute( "srsName", crsName );
    415                            Element lowerPos = XMLTools.appendElement( env, GMLNS, PRE_G + "pos", lower.x + " " + lower.y
    416                                                                                                  + " " + lower.z );
    417                            lowerPos.setAttribute( "srsDimension", "" + 3 );
    418                            Element upperPos = XMLTools.appendElement( env, GMLNS, PRE_G + "pos", upper.x + " " + upper.y
    419                                                                                                  + " " + upper.z );
    420                            upperPos.setAttribute( "srsDimension", "" + 3 );
    421                        }
    422                    } else {
    423                        LOG.logInfo( "The gml bounded by may not be read, it will be calculated from Hand." );
    424                        calcBounds = true;
    425                    }
    426                    // citygml creation date
    427                    GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
    428                    String timeStamp = cal.get( Calendar.YEAR ) + "-" + ( cal.get( Calendar.MONTH ) + 1 ) + "-"
    429                                       + cal.get( Calendar.DAY_OF_MONTH ) + "T" + cal.get( Calendar.HOUR_OF_DAY ) + ":"
    430                                       + cal.get( Calendar.MINUTE );
    431                    XMLTools.appendElement( building, CITYGMLNS, PRE_C + "creationDate", timeStamp );
    432                    XMLTools.appendElement( building, CITYGMLNS, PRE_C + "function", this.cityGMLFunction );
    433                    Element multiSurfaceLod2 = XMLTools.appendElement( building, CITYGMLNS, PRE_C + "lod2MultiSurface" );
    434                    Element multiSurfaceParent = XMLTools.appendElement( multiSurfaceLod2, GMLNS, PRE_G + "MultiSurface" );
    435                    multiSurfaceParent.setAttribute( "srsName", crsName );
    436                    outputGroup( j3dScene, multiSurfaceParent, transformMatrix, calcBounds, lower, upper );
    437                    root = (Element) doc.importNode( root, true );
    438                    XMLFragment frag = new XMLFragment( root );
    439                    result.append( frag.getAsPrettyString() );
    440                    LOG.logDebug( "\n\nExported " + numberOfSurfaces + " surfaces." );
    441                } else {
    442                    LOG.logInfo( "The given branchgroup may not read it's children, nothing to export." );
    443                }
    444            } else {
    445                LOG.logInfo( "The given branchgroup may not be null, nothing to export." );
    446            }
    447
    448        }
    449
    450        /**
    451         * Iterates over all children of the given branchgroup and appends their citygml representation to the rootNode.
    452         *
    453         * @param j3dScene
    454         *            to export
    455         * @param rootNode
    456         *            to append to.
    457         * @param calcBounds
    458         *            if true the bounds should be calculated and placed in lower and upper.
    459         * @param upper
    460         *            bound
    461         * @param lower
    462         *            bound
    463         */
    464        @SuppressWarnings("unchecked")
    465        private void outputGroup( Group j3dScene, Element rootNode, Transform3D transformation, boolean calcBounds,
    466                                  Point3d lower, Point3d upper ) {
    467            Enumeration<Node> en = j3dScene.getAllChildren();
    468            LOG.logDebug( "Outputting a group." );
    469            while ( en.hasMoreElements() ) {
    470                Node n = en.nextElement();
    471                if ( n != null ) {
    472                    if ( n instanceof Group ) {
    473                        LOG.logDebug( "A group: " + n );
    474                        Transform3D tmpTrans = null;
    475                        if ( n instanceof TransformGroup ) {
    476                            TransformGroup tmp = (TransformGroup) n;
    477                            tmpTrans = new Transform3D();
    478                            tmp.getTransform( tmpTrans );
    479                            if ( tmpTrans.getBestType() != Transform3D.IDENTITY ) {
    480                                if ( inverseYZ ) {
    481                                    Vector3d trans = new Vector3d();
    482                                    tmpTrans.get( trans );
    483                                    double tmpY = trans.y;
    484                                    trans.y = -trans.z;
    485                                    trans.z = tmpY;
    486                                    tmpTrans.set( trans );
    487                                }
    488                                LOG.logDebug( "A transform group with transform:\n" + tmpTrans );
    489                                if ( transformation != null ) {
    490                                    transformation.mul( tmpTrans );
    491                                }
    492                                LOG.logDebug( "Resulting transform:\n" + transformation );
    493                            }
    494                        }
    495                        outputGroup( (Group) n, rootNode, transformation, calcBounds, lower, upper );
    496                        if ( tmpTrans != null && tmpTrans.getBestType() != Transform3D.IDENTITY ) {
    497                            transformation.mulInverse( tmpTrans );
    498                            LOG.logDebug( "After undoing the inverse of transformGroup transform:\n" + transformation );
    499                        }
    500                    } else if ( n instanceof Leaf ) {
    501                        outputLeaf( (Leaf) n, rootNode, transformation, calcBounds, lower, upper );
    502                    }
    503                }
    504            }
    505
    506        }
    507
    508        /**
    509         * Checks if the given leaf is a shape3D or background leaf, and if so, their cityGML representation will be
    510         * appended to the parent node.
    511         *
    512         * @param l
    513         *            a j3d leaf.
    514         * @param parent
    515         *            to append to.
    516         * @param transformation
    517         * @param calcBounds
    518         *            if true the bounds should be calculated and placed in lower and upper.
    519         * @param upper
    520         *            bound
    521         * @param lower
    522         *            bound
    523         */
    524        private void outputLeaf( Leaf l, Element parent, Transform3D transformation, boolean calcBounds, Point3d lower,
    525                                 Point3d upper ) {
    526            if ( l != null ) {
    527                if ( l instanceof Shape3D ) {
    528                    outputShape3D( (Shape3D) l, parent, transformation, calcBounds, lower, upper );
    529                } else if ( l instanceof Background ) {
    530                    outputBackground( (Background) l, parent );
    531                } else {
    532                    LOG.logInfo( "Don't know howto output object of instance: " + l.getClass().getName() );
    533                }
    534            }
    535        }
    536
    537        /**
    538         * Appends the citygml representation to the given parent node.
    539         *
    540         * @param shape
    541         *            (of the j3dScene) to append
    542         * @param parent
    543         *            to append to.
    544         * @param transformation
    545         * @param calcBounds
    546         *            if true the bounds should be calculated and placed in lower and upper.
    547         * @param upper
    548         *            bound
    549         * @param lower
    550         *            bound
    551         */
    552        @SuppressWarnings("unchecked")
    553        private void outputShape3D( Shape3D shape, Element parent, Transform3D transformation, boolean calcBounds,
    554                                    Point3d lower, Point3d upper ) {
    555            Enumeration<Geometry> geoms = shape.getAllGeometries();
    556            String shapeName = shape.getName();
    557            LOG.logDebug( "Outputting a Shape3d with name: " + shapeName );
    558            Appearance app = shape.getAppearance();
    559            float ambientIntensity = 0.5f;
    560            Color3f ambient = new Color3f( 0.8f, 0.8f, 0.8f );
    561            Color3f diffuse = new Color3f( 0.8f, 0.8f, 0.8f );
    562            Color3f specular = new Color3f( 0.8f, 0.8f, 0.8f );
    563
    564            if ( app != null ) {
    565                Material mat = app.getMaterial();
    566                if ( mat != null ) {
    567                    mat.getAmbientColor( ambient );
    568                    mat.getDiffuseColor( diffuse );
    569                    mat.getSpecularColor( specular );
    570                }
    571            } else {
    572                LOG.logInfo( "Shape3D has no material!, setting to gray!" );
    573            }
    574            while ( geoms.hasMoreElements() ) {
    575                Geometry geom = geoms.nextElement();
    576                if ( geom != null ) {
    577                    if ( geom instanceof GeometryArray ) {
    578                        GeometryArray ga = (GeometryArray) geom;
    579                        if ( !( ga instanceof TriangleArray ) ) {
    580                            LOG.logDebug( "Not a triangle Array geometry -> convert to triangles, original type is: " + ga );
    581                            try {
    582                                GeometryInfo inf = new GeometryInfo( ga );
    583                                inf.convertToIndexedTriangles();
    584                                ga = inf.getGeometryArray();
    585                                LOG.logDebug( "The converted type is: " + ga );
    586                            } catch ( IllegalArgumentException e ) {
    587                                LOG.logInfo( "Could not create a triangle array of the: " + ga
    588                                              );
    589                            }
    590                        }
    591
    592                        int vertexCount = ga.getVertexCount();
    593                        if ( vertexCount == 0 ) {
    594                            LOG.logError( "No coordinates found in the geometryArray, this may not be." );
    595                        } else {
    596                            LOG.logDebug( "Number of vertices in shape3d: " + vertexCount );
    597
    598                            Element appearance = parent.getOwnerDocument().createElementNS( CITYGMLNS.toASCIIString(),
    599                                                                                            PRE_C + "appearance" );
    600                            Element simpleTexture = parent.getOwnerDocument().createElementNS( CITYGMLNS.toASCIIString(),
    601                                                                                               PRE_C + "SimpleTexture" );
    602
    603                            int vertexFormat = ga.getVertexFormat();
    604
    605                            /**
    606                             * Textures
    607                             */
    608                            TexCoord2f[] texCoords = null;
    609                            if ( ( GeometryArray.TEXTURE_COORDINATE_2 & vertexFormat ) == GeometryArray.TEXTURE_COORDINATE_2 ) {
    610                                LOG.logDebug( "The Geometry has a texture attached to it." );
    611
    612                                texCoords = new TexCoord2f[vertexCount];
    613                                for ( int i = 0; i < texCoords.length; ++i ) {
    614                                    texCoords[i] = new TexCoord2f( 0, 0 );
    615                                }
    616                                ga.getTextureCoordinates( 0, ga.getInitialTexCoordIndex( 0 ), texCoords );
    617                                StringBuilder texCoordsAsString = new StringBuilder( texCoords.length * 2 );
    618                                for ( TexCoord2f coord : texCoords ) {
    619                                    texCoordsAsString.append( coord.x ).append( " " ).append( coord.y ).append( " " );
    620                                }
    621
    622                                // TODO try to get all textures of all texture units
    623                                if ( app != null ) {
    624                                    Texture tex = app.getTexture();
    625                                    if ( tex != null ) {
    626                                        String texName = tex.getName();
    627                                        LOG.logDebug( "Texture name: " + texName );
    628                                        ImageComponent ic = tex.getImage( 0 );
    629                                        if ( ic != null ) {
    630                                            if ( ic instanceof ImageComponent2D ) {
    631                                                LOG.logDebug( "ImageComponent name: " + ( (ImageComponent2D) ic ).getName() );
    632                                                BufferedImage bi = ( (ImageComponent2D) ic ).getImage();
    633                                                if ( bi != null ) {
    634                                                    if ( !cachedTextures.containsKey( bi ) ) {
    635                                                        if ( texName == null || "".equals( texName.trim() ) ) {
    636                                                            texName = name + "_texture_" + textureCount++;
    637                                                        }
    638                                                        texName += ( ".jpg" );
    639                                                        LOG.logDebug( "No cached texture found: " + texName );
    640                                                        try {
    641                                                            File f = new File( textureOutputDir, texName );
    642                                                            ImageIO.write( bi, "jpg", f );
    643                                                            LOG.logDebug( "Wrote texture to: " + f.getAbsolutePath() );
    644                                                        } catch ( IOException e ) {
    645                                                            LOG.logError( "Failed to write texture: " + texName, e );
    646                                                        }
    647                                                        cachedTextures.put( bi, texName );
    648                                                    } else {
    649                                                        LOG.logDebug( "Using old texture reference: " + texName );
    650                                                        texName = cachedTextures.get( bi );
    651                                                    }
    652
    653                                                    // add the texture to the appearance node
    654
    655                                                    XMLTools.appendElement( simpleTexture, CITYGMLNS, PRE_C + "textureMap",
    656                                                                            textureOutputDir + texName );
    657                                                    XMLTools.appendElement( simpleTexture, CITYGMLNS,
    658                                                                            PRE_C + "textureType", "specific" );
    659                                                    XMLTools.appendElement( simpleTexture, CITYGMLNS, PRE_C + "repeat", "0" );
    660                                                }
    661                                            }
    662                                        }
    663                                    }
    664                                }
    665                            } else {
    666                                Element material = XMLTools.appendElement( appearance, CITYGMLNS, PRE_C + "Material" );
    667                                XMLTools.appendElement( material, CITYGMLNS, PRE_C + "ambientIntensity", ""
    668                                                                                                         + ambientIntensity );
    669                                // although the citgml spec does not contain it, we set the ambient color :(
    670                                XMLTools.appendElement( material, CITYGMLNS, PRE_C + "ambientColor", ambient.x + " "
    671                                                                                                     + ambient.y + " "
    672                                                                                                     + ambient.z );
    673                                XMLTools.appendElement( material, CITYGMLNS, PRE_C + "specularColor", specular.x + " "
    674                                                                                                      + specular.y + " "
    675                                                                                                      + specular.z );
    676                                XMLTools.appendElement( material, CITYGMLNS, PRE_C + "diffuseColor", diffuse.x + " "
    677                                                                                                     + diffuse.y + " "
    678                                                                                                     + diffuse.z );
    679                            }
    680
    681                            Point3d[] coords = new Point3d[vertexCount];
    682                            for ( int i = 0; i < coords.length; ++i ) {
    683                                coords[i] = new Point3d( 0, 0, 0 );
    684                            }
    685                            ga.getCoordinates( ga.getInitialVertexIndex(), coords );
    686                            LOG.logDebug( "Number of coords in geometry: " + coords.length );
    687
    688                            if ( coords.length > 0 && coords[0] != null ) {
    689
    690                                if ( ga instanceof TriangleArray ) {
    691                                    LOG.logInfo( "Using triangles for the coords." );
    692                                    int i = 0;
    693                                    for ( ; i < coords.length; i += 3 ) {
    694                                        Element surfaceMember = XMLTools.appendElement( parent, GMLNS, PRE_G
    695                                                                                                       + "surfaceMember" );
    696
    697                                        Element texturedSurface = XMLTools.appendElement( surfaceMember, CITYGMLNS,
    698                                                                                          PRE_C + "TexturedSurface" );
    699                                        texturedSurface.setAttribute( "orientation", "+" );
    700
    701                                        Element baseSurface = XMLTools.appendElement( texturedSurface, GMLNS,
    702                                                                                      PRE_G + "baseSurface" );
    703                                        Element polygon = XMLTools.appendElement( baseSurface, GMLNS, PRE_G + "Polygon" );
    704                                        Element exterior = XMLTools.appendElement( polygon, GMLNS, PRE_G + "exterior" );
    705                                        Element lRing = XMLTools.appendElement( exterior, GMLNS, PRE_G + "LinearRing" );
    706                                        if ( ( i + 3 ) <= coords.length ) {
    707                                            for ( int j = 0; j < 3; j++ ) {
    708                                                Point3d coord = coords[i + j];
    709                                                // System.out.println( "Untranslated point: " + coord );
    710                                                // transformMatrix.transform( coord );
    711                                                // first do a transform on the old coords,
    712                                                if ( inverseYZ ) {
    713                                                    double coordY = coord.y;
    714                                                    coord.y = -coord.z;
    715                                                    coord.z = coordY;
    716                                                }
    717                                                if ( rotationMatrix != null ) {
    718                                                    rotationMatrix.transform( coord );
    719                                                }
    720                                                // than translate
    721                                                transformation.transform( coord );
    722
    723                                                // use point3d.equals method to see if already present.
    724                                                // if ( resultingPoints.contains( coord ) ) {
    725                                                // resultingPoints.add( coord );
    726                                                // check the bounds if set
    727                                                if ( calcBounds ) {
    728                                                    if ( coord.x < lower.x ) {
    729                                                        lower.x = coord.x;
    730                                                    }
    731                                                    if ( coord.y < lower.y ) {
    732                                                        lower.y = coord.y;
    733                                                    }
    734                                                    if ( coord.z < lower.z ) {
    735                                                        lower.z = coord.z;
    736                                                    }
    737                                                    if ( coord.x > upper.x ) {
    738                                                        upper.x = coord.x;
    739                                                    }
    740                                                    if ( coord.y > upper.y ) {
    741                                                        upper.y = coord.y;
    742                                                    }
    743                                                    if ( coord.z > upper.z ) {
    744                                                        upper.z = coord.z;
    745                                                    }
    746                                                }
    747                                                XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", coord.x + " "
    748                                                                                                     + coord.y + " "
    749                                                                                                     + coord.z );
    750
    751                                            }
    752                                            Point3d tmp = coords[i];
    753                                            XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", tmp.x + " " + tmp.y + " "
    754                                                                                                 + tmp.z );
    755                                        } else {// no three points are left;
    756                                            LOG.logInfo( "One of the geometries have an inconsistent number of points ("
    757                                                         + ( coords.length - i ) + ")to create triangles-> correcting!" );
    758                                            Point3d current = coords[i];
    759                                            // transformMatrix.transform( current );
    760                                            transformation.transform( current );
    761                                            Point3d previous = coords[i - 1];
    762                                            // transformMatrix.transform( previous );
    763                                            transformation.transform( previous );
    764                                            Point3d tmp = null;
    765                                            switch ( coords.length - i ) {
    766                                            case 1: // take last two nodes and create a triangle.
    767                                                tmp = coords[i - 2];
    768                                                break;
    769                                            default: // take last node and create a triangle.
    770                                                tmp = coords[i + 1];
    771                                                break;
    772                                            }
    773                                            // transformMatrix.transform( tmp );
    774                                            transformation.transform( tmp );
    775                                            XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", current.x + " "
    776                                                                                                 + current.y + " "
    777                                                                                                 + current.z );
    778                                            XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", previous.x + " "
    779                                                                                                 + previous.y + " "
    780                                                                                                 + previous.z );
    781                                            XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", tmp.x + " " + tmp.y + " "
    782                                                                                                 + tmp.z );
    783                                            XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", current.x + " "
    784                                                                                                 + current.y + " "
    785                                                                                                 + current.z );
    786
    787                                        }
    788
    789                                        // add the appearance
    790                                        Element tmp = (Element) appearance.cloneNode( true );
    791                                        if ( texCoords != null && ( i + 2 ) < texCoords.length ) {
    792                                            Element sTex = (Element) simpleTexture.cloneNode( true );
    793                                            XMLTools.appendElement( sTex, CITYGMLNS, PRE_C + "textureCoordinates",
    794                                                                    texCoords[i].x + " " + texCoords[i].y + " "
    795                                                                                            + texCoords[i + 1].x + " "
    796                                                                                            + texCoords[i + 1].y + " "
    797                                                                                            + texCoords[i + 2].x + " "
    798                                                                                            + texCoords[i + 2].y + " "
    799                                                                                            + texCoords[i].x + " "
    800                                                                                            + texCoords[i].y );
    801                                            tmp.appendChild( sTex );
    802                                        }
    803                                        texturedSurface.appendChild( tmp );
    804                                        numberOfSurfaces++;
    805                                    }
    806                                } else { // try to set as polygon.
    807                                    LOG.logInfo( "Setting points as polygon." );
    808                                    Point3d firstCoord = coords[0];
    809                                    // transformMatrix.transform( firstCoord );
    810                                    transformation.transform( firstCoord );
    811                                    Point3d lastCoord = null;
    812                                    Element texturedSurface = XMLTools.appendElement( parent, CITYGMLNS,
    813                                                                                      PRE_C + "TexturedSurface" );
    814                                    texturedSurface.setAttribute( "orientation", "+" );
    815
    816                                    Element baseSurface = XMLTools.appendElement( texturedSurface, GMLNS, PRE_G
    817                                                                                                          + "baseSurface" );
    818                                    Element polygon = XMLTools.appendElement( baseSurface, GMLNS, PRE_G + "Polygon" );
    819                                    Element exterior = XMLTools.appendElement( polygon, GMLNS, PRE_G + "exterior" );
    820                                    Element lRing = XMLTools.appendElement( exterior, GMLNS, PRE_G + "LinearRing" );
    821
    822                                    for ( int i = 0; i < coords.length; ++i ) {
    823                                        Point3d coord = coords[i];
    824                                        // transformMatrix.transform( coord );
    825                                        transformation.transform( coord );
    826                                        if ( calcBounds ) {
    827                                            if ( coord.x < lower.x ) {
    828                                                lower.x = coord.x;
    829                                            }
    830                                            if ( coord.y < lower.y ) {
    831                                                lower.y = coord.y;
    832                                            }
    833                                            if ( coord.z < lower.z ) {
    834                                                lower.z = coord.z;
    835                                            }
    836                                            if ( coord.x > upper.x ) {
    837                                                upper.x = coord.x;
    838                                            }
    839                                            if ( coord.y > upper.y ) {
    840                                                upper.y = coord.y;
    841                                            }
    842                                            if ( coord.z > upper.z ) {
    843                                                upper.z = coord.z;
    844                                            }
    845                                        }
    846                                        XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", coord.x + " " + coord.y + " "
    847                                                                                             + coord.z );
    848                                        lastCoord = coord;// coords[i];
    849                                    }
    850                                    if ( !firstCoord.equals( lastCoord ) ) {
    851                                        XMLTools.appendElement( lRing, GMLNS, PRE_G + "pos", firstCoord.x + " "
    852                                                                                             + firstCoord.y + " "
    853                                                                                             + firstCoord.z );
    854                                    }
    855
    856                                    // add the appearance
    857                                    Element tmp = (Element) appearance.cloneNode( true );
    858                                    texturedSurface.appendChild( tmp );
    859                                }
    860
    861                            }
    862
    863                            /**
    864                             * NORMALS
    865                             */
    866                            if ( ( GeometryArray.NORMALS & vertexFormat ) == GeometryArray.NORMALS ) {
    867                                LOG.logDebug( "The Geometry has normals, but they are not exported (yet)." );
    868                                // Vector3f[] normals = new Vector3f[vertexCount];
    869                                // for ( int i = 0; i < normals.length; ++i ) {
    870                                // normals[i] = new Vector3f( 0, 0, 0 );
    871                                // }
    872                                // ga.getNormals( 0, normals );
    873                                // for ( Vector3f normal : normals ) {
    874                                // parent.append( normal ).append( " " );
    875                                // }
    876                            }
    877                            /**
    878                             * Colors 3f
    879                             */
    880                            if ( ( GeometryArray.COLOR_3 & vertexFormat ) == GeometryArray.COLOR_3 ) {
    881                                LOG.logDebug( "The Geometry has Colors per Vertex with 3 chanels, but they are not exported (yet)." );
    882                                // Color3f[] colors = new Color3f[vertexCount];
    883                                // for ( int i = 0; i < colors.length; ++i ) {
    884                                // colors[i] = new Color3f( 0, 0, 0 );
    885                                // }
    886                                // ga.getColors( 0, colors );
    887                                // parent.append( "\n - Colors3f (" ).append( numberOfGeom ).append( "):
    888                                // " );
    889                                // for ( Color3f color : colors ) {
    890                                // parent.append( color ).append( " " );
    891                                // }
    892                            }
    893
    894                            /**
    895                             * Colors 4f
    896                             */
    897                            if ( ( GeometryArray.COLOR_4 & vertexFormat ) == GeometryArray.COLOR_4 ) {
    898                                LOG.logDebug( "The Geometry has Colors per Vertex with 4 chanels, but they are not exported (yet)." );
    899                                // Color4f[] colors = new Color4f[vertexCount];
    900                                // for ( int i = 0; i < colors.length; ++i ) {
    901                                // colors[i] = new Color4f( 0, 0, 0, 0 );
    902                                // }
    903                                // ga.getColors( 0, colors );
    904                                // parent.append( "\n - Colors4f (" ).append( numberOfGeom ).append( "):
    905                                // " );
    906                                // for ( Color4f color : colors ) {
    907                                // parent.append( color ).append( " " );
    908                                // }
    909                            }
    910
    911                            // Element appearance = XMLTools.appendElement( texturedSurface,
    912                            // CITYGMLNS,
    913                            // PRE_C + "appearance" );
    914                        }
    915                    } else {
    916                        LOG.logInfo( "Only Shape3d Objects with geometry rasters are supported for outputing" );
    917                    }
    918                }
    919            }
    920
    921        }
    922
    923        /**
    924         * Don't know how to export the background yet.
    925         *
    926         * @param b
    927         *            leaf of the j3dScene
    928         * @param parent
    929         *            to append to.
    930         */
    931        private void outputBackground( @SuppressWarnings("unused")
    932        Background b, @SuppressWarnings("unused")
    933        Element parent ) {
    934            LOG.logError( "Cannot output a background yet." );
    935        }
    936
    937        public String getName() {
    938            return "CityGML exporter";
    939        }
    940
    941        public String getShortDescription() {
    942            return "Convert a given j3d:BranchGroup to CityGML LOD1";
    943        }
    944
    945        /**
    946         * @param args
    947         */
    948        public static void main( String[] args ) {
    949            if ( args.length == 0 ) {
    950                outputHelp();
    951            }
    952            Map<String, String> params = new HashMap<String, String>( 5 );
    953            for ( int i = 0; i < args.length; i++ ) {
    954                String arg = args[i];
    955                if ( arg != null && !"".equals( arg.trim() ) ) {
    956                    arg = arg.trim();
    957                    if ( arg.startsWith( "-" ) ) {
    958                        arg = arg.substring( 1 );
    959                    }
    960                    if ( arg.equalsIgnoreCase( "?" ) || arg.equalsIgnoreCase( "h" ) ) {
    961                        outputHelp();
    962                    } else {
    963                        if ( i + 1 < args.length ) {
    964                            String val = args[++i];
    965                            if ( val != null && !"".equals( val.trim() ) ) {
    966                                params.put( arg.toLowerCase(), val.trim() );
    967                            } else {
    968                                LOG.logError( "Invalid value for parameter: " + arg );
    969                            }
    970                        } else {
    971                            LOG.logError( "No value for parameter: " + arg );
    972                        }
    973                    }
    974                }
    975            }
    976
    977            String fileName = params.get( "infile" );
    978            if ( fileName == null || "".equals( fileName.trim() ) ) {
    979                System.out.println( "\n\n" );
    980                LOG.logError( "The -inFile parameter must be defined." );
    981                System.out.println( "\n\n" );
    982                outputHelp();
    983            }
    984            File tmpFile = new File( fileName );
    985            if ( !tmpFile.exists() ) {
    986                System.out.println( "\n\n" );
    987                LOG.logError( "The file '" + fileName + "' given by the -inFile parameter does not exist." );
    988                System.out.println( "\n\n" );
    989                System.exit( 1 );
    990            }
    991            LOG.logInfo( "\n\nTrying to load scene, if you see no message beneath this message, please check your vrml file: "
    992                         + fileName
    993                         + "if the refrerred textures are java qouted.\nIf using a Windows os, the quoted directory separator (\\\\) should be used instead of a single one (\\)" );
    994            VrmlLoader loader = new VrmlLoader();
    995            try {
    996                J3DToCityGMLExporter converter = new J3DToCityGMLExporter( params );
    997                Scene scene = loader.load( fileName );
    998                if ( scene != null ) {
    999                    LOG.logInfo( "Successfully loaded the scene, trying to retrieve the branchgroup." );
    1000                    BranchGroup bg = scene.getSceneGroup();
    1001                    if ( bg != null && bg.numChildren() > 0 ) {
    1002                        LOG.logInfo( "Retrieval of the j3d.Branchgroup was successful." );
    1003                        StringBuilder output = new StringBuilder( 20000 );
    1004                        converter.export( output, bg );
    1005                        String outFile = params.get( "outfile" );
    1006                        if ( outFile == null || "".equals( outFile.trim() ) ) {
    1007                            System.out.println( output.toString() );
    1008                        } else {
    1009                            BufferedWriter fWriter = new BufferedWriter( new FileWriter( new File( outFile ) ) );
    1010                            fWriter.write( output.toString() );
    1011                            fWriter.flush();
    1012                            fWriter.close();
    1013                        }
    1014                    } else {
    1015                        System.out.println( "The branchgroup is null or has no childres, which means that the scene was not loaded correctly (did you correctly quoted the texture paths in your vrml-file: "
    1016                                            + fileName + ")" );
    1017                    }
    1018                } else {
    1019                    System.out.println( "The scene was not loaded (did you correctly quoted the texture paths in your vrml-file: "
    1020                                        + fileName + ")" );
    1021                }
    1022            } catch ( NoClassDefFoundError c ) {
    1023                libHelp( c );
    1024            } catch ( FileNotFoundException e ) {
    1025                LOG.logError( "Could not load vrm-file because: " + e.getMessage(), e );
    1026            } catch ( IncorrectFormatException e ) {
    1027                LOG.logError( "Could not load vrm-file because: " + e.getMessage(), e );
    1028            } catch ( ParsingErrorException e ) {
    1029                LOG.logError( "Could not load vrm-file because: " + e.getMessage(), e );
    1030            } catch ( IOException e ) {
    1031                LOG.logError( "Could not create converter because: " + e.getMessage(), e );
    1032            } catch ( Exception e ) {
    1033                LOG.logError( "Error while loading the file: " + fileName + " because: " + e.getMessage(), e );
    1034            } catch ( Throwable t ) {
    1035                LOG.logError( "Error while loading the file: " + fileName + " because: " + t.getMessage(), t );
    1036            }
    1037        }
    1038
    1039        private static void outputHelp() {
    1040            StringBuilder sb = new StringBuilder();
    1041            sb.append( "The J3DToCityGMLExported program can be used to export a j3d branchgroup created from a vrml-file to citygml. \n" );
    1042            sb.append( "Following parameters are supported:\n" );
    1043            sb.append( "-inFile the /path/to/vrml-file\n" );
    1044            sb.append( "-texDir directory to output the found textures to.\n" );
    1045            sb.append( "[-outFile] the /path/to/the/output/file or standard output if not supplied.\n" );
    1046            sb.append( "[-wfsTransaction y/n] output the citygml as part of a wfs-insert request (if omitted the citygml-building element will be root element).\n" );
    1047            sb.append( "[-buildingFunction] the function this citygml building will have (if omitted 1001 will be used).\n" );
    1048            sb.append( "[-srs] the coordinateSystem used for the citygml (if omitted 'EPSG:31466' will be used).\n" );
    1049            sb.append( "[-xTranslation] the amount to add up to the x part of the found coordinates(if omitted '0' will be used).\n" );
    1050            sb.append( "[-yTranslation] the amount to add up to the y part of the found coordinates(if omitted '0' will be used).\n" );
    1051            sb.append( "[-zTranslation] the amount to add up to the z part of the found coordinates(if omitted '0' will be used).\n" );
    1052            sb.append( "[-rotationAngle] the rotation angle given by comma seperated values as x,y,z,rotation(in radians)(if omitted no rotation will be applied).\n" );
    1053            sb.append( "[-inverseYZ] (y/n)signal that the y and z coordinates should be inversed.\n" );
    1054            sb.append( "-?|-h output this text\n" );
    1055            sb.append( "example usage (converting the cool.vrml to a wfs:Transaction in 'epsg:12345' wit a xtranslation of 10000 and yTranslation of 50,\n" );
    1056            sb.append( "outputing to cool_tower.xml in the directory my_output_dir (relative to the current dir)\n" );
    1057            sb.append( "java -cp deegree.jar:lib/j3d/j3d-vrml97.jar:lib/log4j/log4j-1.2.9.jar:/lib/xml/jaxen-1.1-beta-8.jar org.deegree.tools.app3d.J3DToCityGMLExporter -inFile 'cool.vrml' -texDir 'my_output_dir' -outFile 'cool_tower.xml' -wfsTransaction 'y' -buildingFunction 'home office buildings' -xTranslation 10000 -yTranslation 50\n" );
    1058            System.out.println( sb.toString() );
    1059            System.exit( 1 );
    1060        }
    1061
    1062        private static void libHelp( NoClassDefFoundError c ) {
    1063            StringBuilder sb = new StringBuilder( 800 );
    1064            sb.append( "Could not load vrm-file because a specific class (" );
    1065            sb.append( c.getMessage() );
    1066            sb.append( ") was not found, the vrmlImporter uses following libraries: " );
    1067            sb.append( "\n - $deegree-base$/lib/java3d/vecmath.jar" );
    1068            sb.append( "\n - $deegree-base$/lib/java3d/j3dutils.jar" );
    1069            sb.append( "\n - $deegree-base$/lib/java3d/j3dcore.jar" );
    1070            sb.append( "\n - $deegree-base$/lib/j3d/j3d-vrml97.jar" );
    1071            sb.append( "\n - $deegree-base$/lib/commons/commons-logging.jar" );
    1072            sb.append( "\n - $deegree-base$/lib/log4j/log4j-1.2.9.jar" );
    1073            sb.append( "\n - $deegree-base$/lib/xml/jaxen-1.1-beta-8.jar" );
    1074            // LOG.logError( sb.toString() );
    1075            System.out.println( sb.toString() );
    1076            exit( 1 );
    1077        }
    1078
    1079        /*
    1080         * (non-Javadoc)
    1081         *
    1082         * @see org.deegree.tools.app3d.J3DExporter#getParameterList()
    1083         */
    1084        public Map<String, String> getParameterMap() {
    1085            Map<String, String> params = new HashMap<String, String>();
    1086            params.put( "name", "The name of the building" );
    1087            params.put( "texdir", "The directory to output the j3d objects' textures to." );
    1088            params.put( "wfstransaction", "(yes/no) Output the citygml as part of a wfs-insert request." );
    1089            params.put( "buildingfunction", "The function this citygml building will have." );
    1090            params.put( "srs", "the coordinateSystem used." );
    1091            params.put( "xtranslation", "The x translation." );
    1092            params.put( "ytranslation", "The y translation." );
    1093            params.put( "ztranslation", "The z translation." );
    1094            params.put( "rotationangle", "Comma seperated values as x,y,z,rotation(in radians)." );
    1095            params.put( "inverseyz", "(yes/no) Signal that the y and z coordinates should be swapped." );
    1096            return params;
    1097        }
    1098
    1099    }