void ProjectVisitor::apply(osg::Geode& node) 
{
    if (_clearEveryDrawable)
        _projector.clear();

    std::vector<osg::Drawable*> toremove;
    std::vector<osg::ref_ptr<osg::Geometry> > toadd;
    for (int i = 0; i < node.getNumDrawables(); i++) {

        osg::Timer_t t0 = osg::Timer::instance()->tick();
        node.getDrawable(i)->accept(_projector);
        double duration = osg::Timer::instance()->delta_s(t0, osg::Timer::instance()->tick());

        if (_projector.hasGeometry()) {
            toremove.push_back(node.getDrawable(i));
            std::stringstream ss;
            ss << "projected_" << _index << ".osg";
            osg::notify(osg::INFO) <<  "duration " << duration << " " << ss.str() << std::endl;
            if (_writeResultOnDisk)
                _projector.write(ss.str());
            
            if (!_mergeGeometry) {
                osg::ref_ptr<osg::Geometry> result = _projector._result.get();
                result->setUserData(node.getDrawable(i)->getUserData());
                toadd.push_back(result);
                _projector.clear();
            }
        }
        _index++;
        _cummulatedTime += duration;
    }

    if (_mergeGeometry) {
        if (_projector.hasGeometry()) {
            toadd.push_back(_projector._result.get());
        }
    }

    for (int i = 0; i < toremove.size(); i++) // remove only where success to project data
        node.removeDrawable(toremove[i]);

    for (int i = 0; i < toadd.size(); i++) {// remove only where success to project data
        node.addDrawable(toadd[i]);
    }

    if (_projectToXYZ) {
        osg::ref_ptr<LatLongHeight2xyz> visitor = new LatLongHeight2xyz();
        node.accept(*visitor);
    }

    // smooth after project
    if (_smooth) {
        osgUtil::SmoothingVisitor smooth;
        for (int i = 0; i < toadd.size(); i++) {// remove only where success to project data
            smooth.smooth(*toadd[i]);
        }
    }

}
Esempio n. 2
0
static bool readDrawables( osgDB::InputStream& is, osg::Geode& node )
{
    unsigned int size = 0; is >> size >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::ref_ptr<osg::Drawable> drawable = is.readObjectOfType<osg::Drawable>();
        if ( drawable )
        {
            node.addDrawable( drawable );
        }
    }
    is >> is.END_BRACKET;
    return true;
}
Esempio n. 3
0
static bool readDrawables( osgDB::InputStream& is, osg::Geode& node )
{
    unsigned int size = 0; is >> size >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::Drawable* drawable = dynamic_cast<osg::Drawable*>( is.readObject() );
        if ( drawable ) 
        {
            node.addDrawable( drawable );
        }
    }
    is >> is.END_BRACKET;
    return true;
}
        void apply( osg::Geode& geode )
        {
            bool makeECEF = _cx.getSession()->getMapInfo().isGeocentric();
            const SpatialReference* srs = _cx.profile()->getSRS();

            NumericExpression scaleEx = *_symbol->scale();
            osg::Matrixd scaleMatrix;

            // save the geode's drawables..
            osg::Geode::DrawableList old_drawables = geode.getDrawableList();

            // ..and clear out the drawables list.
            geode.removeDrawables( 0, geode.getNumDrawables() );

            // foreach each drawable that was originally in the geode...
            for( osg::Geode::DrawableList::iterator i = old_drawables.begin(); i != old_drawables.end(); i++ )
            {
                osg::Geometry* originalDrawable = dynamic_cast<osg::Geometry*>( i->get() );
                if ( !originalDrawable )
                    continue;

                // go through the list of input features...
                for( FeatureList::const_iterator j = _features.begin(); j != _features.end(); j++ )
                {
                    const Feature* feature = j->get();

                    if ( _symbol->scale().isSet() )
                    {
                        double scale = feature->eval( scaleEx, &_cx );
                        scaleMatrix.makeScale( scale, scale, scale );
                    }

                    ConstGeometryIterator gi( feature->getGeometry(), false );
                    while( gi.hasMore() )
                    {
                        const Geometry* geom = gi.next();

                        for( Geometry::const_iterator k = geom->begin(); k != geom->end(); ++k )
                        {
                            osg::Vec3d   point = *k;
                            osg::Matrixd mat;

                            if ( makeECEF )
                            {
                                osg::Matrixd rotation;
                                ECEF::transformAndGetRotationMatrix( point, srs, point, rotation );
                                mat = rotation * scaleMatrix * osg::Matrixd::translate(point) * _f2n->world2local();
                            }
                            else
                            {
                                mat = scaleMatrix * osg::Matrixd::translate(point) * _f2n->world2local();
                            }

                            // clone the source drawable once for each input feature.
                            osg::ref_ptr<osg::Geometry> newDrawable = osg::clone( 
                                originalDrawable, 
                                osg::CopyOp::DEEP_COPY_ARRAYS | osg::CopyOp::DEEP_COPY_PRIMITIVES );

                            osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>( newDrawable->getVertexArray() );
                            if ( verts )
                            {
                                for( osg::Vec3Array::iterator v = verts->begin(); v != verts->end(); ++v )
                                {
                                    (*v).set( (*v) * mat );
                                }
                                
                                // add the new cloned, translated drawable back to the geode.
                                geode.addDrawable( newDrawable.get() );
                            }
                        }

                    }
                }
            }

            geode.dirtyBound();

            MeshConsolidator::run( geode );

            // merge the geometry. Not sure this is necessary
            osgUtil::Optimizer opt;
            opt.optimize( &geode, osgUtil::Optimizer::MERGE_GEOMETRY | osgUtil::Optimizer::SHARE_DUPLICATE_STATE );
            
            osg::NodeVisitor::apply( geode );
        }
    void apply( osg::Geode& geode )
    {
        // save the geode's drawables..
        osg::Geode::DrawableList old_drawables = geode.getDrawableList();

        //OE_DEBUG << "ClusterVisitor geode " << &geode << " featureNode=" << _featureNode << " drawables=" << old_drawables.size() << std::endl;

        // ..and clear out the drawables list.
        geode.removeDrawables( 0, geode.getNumDrawables() );

        // foreach each drawable that was originally in the geode...
        for( osg::Geode::DrawableList::iterator i = old_drawables.begin(); i != old_drawables.end(); i++ )
        {
            osg::Geometry* originalDrawable = dynamic_cast<osg::Geometry*>( i->get() );
            if ( !originalDrawable )
                continue;

            // go through the list of input features...
            for( FeatureList::const_iterator j = _features.begin(); j != _features.end(); j++ )
            {
                Feature* feature = j->get();

                osg::Matrixd scaleMatrix;

                if ( _symbol->scale().isSet() )
                {
                    double scale = feature->eval( _scaleExpr, &_cx );
                    scaleMatrix.makeScale( scale, scale, scale );
                }

                osg::Matrixd rotationMatrix;
                if ( _modelSymbol && _modelSymbol->heading().isSet() )
                {
                    float heading = feature->eval( _headingExpr, &_cx );
                    rotationMatrix.makeRotate( osg::Quat(osg::DegreesToRadians(heading), osg::Vec3(0,0,1)) );
                }

                GeometryIterator gi( feature->getGeometry(), false );
                while( gi.hasMore() )
                {
                    Geometry* geom = gi.next();

                    // if necessary, transform the points to the target SRS:
                    if ( !_makeECEF && !_targetSRS->isEquivalentTo(_srs) )
                    {
                        _srs->transform( geom->asVector(), _targetSRS );
                    }

                    for( Geometry::const_iterator k = geom->begin(); k != geom->end(); ++k )
                    {
                        osg::Vec3d   point = *k;
                        osg::Matrixd mat;

                        if ( _makeECEF )
                        {
                            osg::Matrixd rotation;
                            ECEF::transformAndGetRotationMatrix( point, _srs, point, _targetSRS, rotation );
                            mat = rotationMatrix * rotation * scaleMatrix * osg::Matrixd::translate(point) * _f2n->world2local();
                        }
                        else
                        {
                            mat = rotationMatrix * scaleMatrix * osg::Matrixd::translate(point) * _f2n->world2local();
                        }

                        // clone the source drawable once for each input feature.
                        osg::ref_ptr<osg::Geometry> newDrawable = osg::clone( 
                            originalDrawable, 
                            osg::CopyOp::DEEP_COPY_ARRAYS | osg::CopyOp::DEEP_COPY_PRIMITIVES );

                        osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>( newDrawable->getVertexArray() );
                        if ( verts )
                        {
                            for( osg::Vec3Array::iterator v = verts->begin(); v != verts->end(); ++v )
                            {
                                (*v).set( (*v) * mat );
                            }

                            // add the new cloned, translated drawable back to the geode.
                            geode.addDrawable( newDrawable.get() );

                            if ( _cx.featureIndex() )
                                _cx.featureIndex()->tagPrimitiveSets( newDrawable.get(), feature );
                        }
                    }

                }
            }
        }

        geode.dirtyBound();

        MeshConsolidator::run( geode );

        osg::NodeVisitor::apply( geode );
    }
Esempio n. 6
0
void
MeshConsolidator::run( osg::Geode& geode )
{
    bool useVBOs = false;
    
    // NOTE: we'd rather use the IndexMeshVisitor instead of our own code here,
    // but the IMV does not preserve the user data attached to the primitive sets.
    // We need that since it holds the feature index information.
    //osgUtil::IndexMeshVisitor mesher;
    //geode.accept(mesher);

    // trivial bailout:
    if ( geode.getNumDrawables() <= 1 )
        return;

    // list of geometries to consolidate and not to consolidate.
    DrawableList consolidate, dontConsolidate;

    // list of texture coordinate array image units in use
    std::vector<unsigned> texCoordArrayUnits;
    texCoordArrayUnits.reserve(32);

    // sort the drawables:
    for( unsigned i=0; i<geode.getNumDrawables(); ++i )
    {
        osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
        if ( geom )
        {
            if ( canOptimize(*geom) )
            {
                // convert all primitives to triangles.
                convertToTriangles( *geom );

                // NOTE!! tex/attrib array counts much already be equal.
                if ( texCoordArrayUnits.size() == 0 )
                {
                    for( unsigned u=0; u<32; ++u ) {
                        if ( geom->getTexCoordArray(u) != 0L )
                            texCoordArrayUnits.push_back( u );
                    }

                    if ( geom->getUseVertexBufferObjects() )
                        useVBOs = true;
                }

                consolidate.push_back(geom);
            }
            else
            {
                dontConsolidate.push_back(geom);
            }
        }
    }

    // start consolidating the geometries.
    unsigned targetNumVertsPerGeom = 100000; //TODO: configurable?
    DrawableList results;

    unsigned numVerts = 0, numColors = 0, numNormals = 0;
    DrawableList::iterator start = consolidate.begin();

    for( DrawableList::iterator end = consolidate.begin(); end != consolidate.end(); )
    {
        osg::Geometry* geom = end->get()->asGeometry(); // already type-checked this earlier.
        unsigned geomNumVerts = geom->getVertexArray()->getNumElements();

        ++end;

        numVerts += geomNumVerts;
        if ( geom->getColorArray() )
            numColors += geom->getColorArray()->getNumElements();
        if ( geom->getNormalArray() )
            numNormals += geom->getNormalArray()->getNumElements();

        if ( numVerts > targetNumVertsPerGeom || end == consolidate.end() )
        {
            OE_DEBUG << LC << "Merging " << ((unsigned)(end-start)) << " geoms with " << numVerts << " verts." << std::endl;

            merge( start, end, numVerts, numColors, numNormals, texCoordArrayUnits, useVBOs, results );

            start = end;
            numVerts = 0, numColors = 0, numNormals = 0;
        }
    }

    // re-build the geode:
    geode.removeDrawables( 0, geode.getNumDrawables() );

    for( DrawableList::iterator i = results.begin(); i != results.end(); ++i )
        geode.addDrawable( i->get() );

    for( DrawableList::iterator i = dontConsolidate.begin(); i != dontConsolidate.end(); ++i )
        geode.addDrawable( i->get() );
}
Esempio n. 7
0
	nave(int x,int y, int z, int tamaño)
		{
		pyramidGeode = new osg::Geode();
		pyramidGeometry = new osg::Geometry();
		pyramidGeode->addDrawable(pyramidGeometry);
		
		osg::Vec3Array* pyramidVertices = new osg::Vec3Array;
	
	//0-4
	pyramidVertices->push_back( osg::Vec3(       x,       y,       z) ); // front left
    //1-5
	pyramidVertices->push_back( osg::Vec3(tamaño+x,       y,       z) ); // front right
    //2-6
	pyramidVertices->push_back( osg::Vec3(tamaño+x,tamaño+y,       z) ); // back right
    //3-7
	pyramidVertices->push_back( osg::Vec3(       x,tamaño+y,       z) ); // back left
	//4-0
    pyramidVertices->push_back( osg::Vec3(	     x,		  y,tamaño+z) ); // peak
    //5-1
	pyramidVertices->push_back( osg::Vec3(tamaño+x,       y,tamaño+z) ); // front right
    //6-2
	pyramidVertices->push_back( osg::Vec3(tamaño+x,tamaño+y,tamaño+z) ); // back right
    //7-3
	pyramidVertices->push_back( osg::Vec3(       x,tamaño+y,tamaño+z) ); // back left	
		
	pyramidGeometry->setVertexArray( pyramidVertices );
		
		osg::DrawElementsUInt* pyramidBase =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidBase->push_back(3);
    pyramidBase->push_back(2);
    pyramidBase->push_back(1);
    pyramidBase->push_back(0);
    pyramidGeometry->addPrimitiveSet(pyramidBase);

	osg::DrawElementsUInt* pyramidTop =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidTop->push_back(4);
    pyramidTop->push_back(5);
    pyramidTop->push_back(6);
    pyramidTop->push_back(7);
    pyramidGeometry->addPrimitiveSet(pyramidTop);

    //Repeat the same for each of the four sides. Again, vertices are
    //specified in counter-clockwise order.

    osg::DrawElementsUInt* pyramidFaceOne =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidFaceOne->push_back(0);
    pyramidFaceOne->push_back(1);
	pyramidFaceOne->push_back(5);
    pyramidFaceOne->push_back(4);
	pyramidGeometry->addPrimitiveSet(pyramidFaceOne);

    osg::DrawElementsUInt* pyramidFaceTwo =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidFaceTwo->push_back(1);
    pyramidFaceTwo->push_back(2);
    pyramidFaceTwo->push_back(6);
	pyramidFaceTwo->push_back(5);
    pyramidGeometry->addPrimitiveSet(pyramidFaceTwo);

    osg::DrawElementsUInt* pyramidFaceThree =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidFaceThree->push_back(2);
    pyramidFaceThree->push_back(3);
    pyramidFaceThree->push_back(7);
	pyramidFaceThree->push_back(6);
    pyramidGeometry->addPrimitiveSet(pyramidFaceThree);

    osg::DrawElementsUInt* pyramidFaceFour =
        new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
    pyramidFaceFour->push_back(3);
    pyramidFaceFour->push_back(0);
    pyramidFaceThree->push_back(4);
	pyramidFaceFour->push_back(7);
    pyramidGeometry->addPrimitiveSet(pyramidFaceFour);

    //Declare and load an array of Vec4 elements to store colors.

    osg::Vec4Array* colors = new osg::Vec4Array;
    colors->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) ); //index 0 red
    colors->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) ); //index 1 green
    colors->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) ); //index 2 blue
    colors->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f) ); //index 3 white
    colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 4 red
	 colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 4 red
	  colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 4 red
	   colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); //index 4 red

    //The next step is to associate the array of colors with the geometry,
    //assign the color indices created above to the geometry and set the
    //binding mode to _PER_VERTEX.

    pyramidGeometry->setColorArray(colors);
    pyramidGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	
		};
void
MeshConsolidator::run( osg::Geode& geode )
{
	unsigned numVerts = 0;
	unsigned numColors = 0;
	unsigned numNormals = 0;
	unsigned numTexCoordArrays = 0;
	unsigned numVertAttribArrays = 0;
    std::vector<unsigned> texCoordArrayUnits;
    texCoordArrayUnits.reserve(32);

	osg::Geometry::AttributeBinding newColorsBinding;
	osg::Geometry::AttributeBinding newNormalsBinding;
    bool useVBOs = false;
    GLenum usage = GL_STATIC_DRAW_ARB;

	// first, triangulate all the geometries and count all the components:
	for( unsigned i=0; i<geode.getNumDrawables(); ++i )
	{
		osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
		if ( geom )
		{
            if ( !canOptimize(*geom) )
                continue;

            if ( geom->getUseVertexBufferObjects() )
            {
                useVBOs = true;
                osg::BufferObject* bo = geom->getVertexArray()->getVertexBufferObject();
                if ( bo )
                    usage = bo->getUsage();
            }

			// optimize it into triangles first:
			MeshConsolidator::run( *geom );

			osg::Array* verts = geom->getVertexArray();
			if ( verts )
				numVerts += verts->getNumElements();

			osg::Array* colors = geom->getColorArray();
			if ( colors )
				numColors += colors->getNumElements();

			osg::Array* normals = geom->getNormalArray();
			if ( normals )
				numNormals += normals->getNumElements();

            // NOTE!! tex/attrib array counts much already be equal.
            if ( texCoordArrayUnits.size() == 0 )
            {
                for( unsigned u=0; u<32; ++u ) {
                    if ( geom->getTexCoordArray(u) != 0L )
                        texCoordArrayUnits.push_back( u );
                }
            }

			numVertAttribArrays += geom->getNumVertexAttribArrays();
		}
	}

	// bail if there are unsupported items in there.
	if (geode.getNumDrawables() < 2 ||
        //numTexCoordArrays       > 0 ||
		numVertAttribArrays     > 0 )
	{
		return;
	}


	osg::Vec3Array* newVerts = new osg::Vec3Array();
	newVerts->reserve( numVerts );

	osg::Vec4Array* newColors =0L;
	if ( numColors > 0 )
	{
		newColors = new osg::Vec4Array();
        newColors->reserve( numVerts );
        newColorsBinding = osg::Geometry::BIND_PER_VERTEX;
        //newColors->reserve( numColors==numVerts? numColors : 1 );
        //newColorsBinding = numColors==numVerts? osg::Geometry::BIND_PER_VERTEX : osg::Geometry::BIND_OVERALL;
	}

	osg::Vec3Array* newNormals =0L;
	if ( numNormals > 0 )
	{
		newNormals = new osg::Vec3Array();
        newNormals->reserve( numVerts );
        newNormalsBinding = osg::Geometry::BIND_PER_VERTEX;
        //newNormals->reserve( numNormals==numVerts? numNormals : 1 );
        //newNormalsBinding = numNormals==numVerts? osg::Geometry::BIND_PER_VERTEX : osg::Geometry::BIND_OVERALL;
    }

    std::vector<osg::Vec2Array*> newTexCoordsArrays;
    for( unsigned i=0; i<texCoordArrayUnits.size(); ++i )
    {
        osg::Vec2Array* newTexCoords = new osg::Vec2Array();
        newTexCoords->reserve( numVerts );
        newTexCoordsArrays.push_back( newTexCoords );
	}

	unsigned offset = 0;
	osg::Geometry::PrimitiveSetList newPrimSets;

    std::vector<osg::ref_ptr<osg::Geometry> > nonOptimizedGeoms;

    osg::StateSet* unifiedStateSet = 0L;

	for( unsigned i=0; i<geode.getNumDrawables(); ++i )
	{
		osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
		if ( geom )
		{
            if ( !canOptimize(*geom) )
			{
                nonOptimizedGeoms.push_back(geom);
                continue;
			}

            // merge in the stateset:
            if ( unifiedStateSet == 0L )
                unifiedStateSet = geom->getStateSet();
            else if ( geom->getStateSet() )
                unifiedStateSet->merge( *geom->getStateSet() );            

			// copy over the verts:
			osg::Vec3Array* geomVerts = dynamic_cast<osg::Vec3Array*>( geom->getVertexArray() );
			if ( geomVerts )
			{
				std::copy( geomVerts->begin(), geomVerts->end(), std::back_inserter(*newVerts) );

				if ( newColors )
				{
					osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>( geom->getColorArray() );
					if ( colors )
					{
						if ( newColorsBinding == osg::Geometry::BIND_PER_VERTEX )
						{
							std::copy( colors->begin(), colors->end(), std::back_inserter(*newColors) );
						}
						else if ( i == 0 ) // overall
						{
							newColors->push_back( (*colors)[0] );
						}
					}
				}

				if ( newNormals )
				{
					osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>( geom->getNormalArray() );
					if ( normals )
					{
						if ( newNormalsBinding == osg::Geometry::BIND_PER_VERTEX )
						{
							std::copy( normals->begin(), normals->end(), std::back_inserter(*newNormals) );
						}
						else if ( i == 0 ) // overall
						{
							newNormals->push_back( (*normals)[0] );
						}
					}
				}

                if ( newTexCoordsArrays.size() > 0 )
                {
                    for( unsigned a=0; a<texCoordArrayUnits.size(); ++a )
                    {
                        unsigned unit = texCoordArrayUnits[a];
                        osg::Vec2Array* texCoords = dynamic_cast<osg::Vec2Array*>( geom->getTexCoordArray(unit) );
                        if ( texCoords )
                        {
                            osg::Vec2Array* newTexCoords = newTexCoordsArrays[a];
                            std::copy( texCoords->begin(), texCoords->end(), std::back_inserter(*newTexCoords) );
                        }
                    }
                }

                osg::ref_ptr<osg::Referenced> sharedUserData;

				for( unsigned j=0; j < geom->getNumPrimitiveSets(); ++j )
				{
					osg::PrimitiveSet* pset = geom->getPrimitiveSet(j);
					osg::PrimitiveSet* newpset = 0L;

                    // all primsets have the same user data (or else we would not have made it this far
                    // since canOptimize would be false)
                    if ( !sharedUserData.valid() )
                        sharedUserData = pset->getUserData();

					if ( dynamic_cast<osg::DrawElementsUByte*>(pset) )
						newpset = remake( static_cast<osg::DrawElementsUByte*>(pset), numVerts, offset );
					else if ( dynamic_cast<osg::DrawElementsUShort*>(pset) )
						newpset = remake( static_cast<osg::DrawElementsUShort*>(pset), numVerts, offset );
					else if ( dynamic_cast<osg::DrawElementsUInt*>(pset) )
						newpset = remake( static_cast<osg::DrawElementsUInt*>(pset), numVerts, offset );
					else if ( dynamic_cast<osg::DrawArrays*>(pset) )
                        newpset = convertDAtoDE( static_cast<osg::DrawArrays*>(pset), numVerts, offset );

					if ( newpset )
					{
                        newpset->setUserData( sharedUserData.get() );

						newPrimSets.push_back( newpset );
					}
				}

				offset += geomVerts->size();
			}
		}
	}

	// assemble the new geometry.
	osg::Geometry* newGeom = new osg::Geometry();
    newGeom->setUseVertexBufferObjects( useVBOs );

	newGeom->setVertexArray( newVerts );
    if ( useVBOs && newVerts->getVertexBufferObject() )
        newVerts->getVertexBufferObject()->setUsage( usage );

	if ( newColors )
	{
		newGeom->setColorArray( newColors );
		newGeom->setColorBinding( newColorsBinding );
	}

	if ( newNormals )
	{
		newGeom->setNormalArray( newNormals );
		newGeom->setNormalBinding( newNormalsBinding );
	}

    if ( newTexCoordsArrays.size() > 0 )
    {
        for( unsigned a=0; a<texCoordArrayUnits.size(); ++a )
        {
            unsigned unit = texCoordArrayUnits[a];
            newGeom->setTexCoordArray( unit, newTexCoordsArrays[a] );
        }
    }

	newGeom->setPrimitiveSetList( newPrimSets );
    newGeom->setStateSet( unifiedStateSet );

	// replace the geode's drawables
	geode.removeDrawables( 0, geode.getNumDrawables() );
	geode.addDrawable( newGeom );
    for( std::vector<osg::ref_ptr<osg::Geometry> >::iterator i = nonOptimizedGeoms.begin(); i != nonOptimizedGeoms.end(); ++i )
        geode.addDrawable( i->get() );
}