#include #include #include #include #if defined(_MSC_VER) #include #include #endif #include "ESRIShapeParser.h" using namespace ESRIShape; ESRIShapeParser::ESRIShapeParser( const std::string fileName ): _valid(false) { int fd = 0; if( !fileName.empty() ) { #ifdef WIN32 if( (fd = open( fileName.c_str(), O_RDONLY | O_BINARY )) <= 0 ) #else if( (fd = open( fileName.c_str(), O_RDONLY )) <= 0 ) #endif { perror( fileName.c_str() ); return ; } } _valid = true; ESRIShape::ShapeHeader head; head.read(fd); //head.print(); _geode = new osg::Geode; switch( head.shapeType ) { case ESRIShape::ShapeTypeNullShape : break; case ESRIShape::ShapeTypePoint : { std::vector pts; ESRIShape::PointRecord pointRecord; while( pointRecord.read(fd) ) pts.push_back( pointRecord.point ); _process( pts ); } break; case ESRIShape::ShapeTypeMultiPoint : { std::vector mpts; ESRIShape::MultiPoint mpoint; while( mpoint.read(fd) ) mpts.push_back( mpoint ); _process( mpts ); } break; case ESRIShape::ShapeTypePolyLine : { std::vector plines; ESRIShape::PolyLine pline; while( pline.read(fd) ) plines.push_back( pline ); _process( plines ); } break; case ESRIShape::ShapeTypePolygon : { std::vector polys; ESRIShape::Polygon poly; while( poly.read(fd) ) polys.push_back( poly ); _process( polys ); } break; case ESRIShape::ShapeTypePointM : { std::vector ptms; ESRIShape::PointMRecord pointMRecord; while( pointMRecord.read(fd) ) ptms.push_back( pointMRecord.pointM ); _process( ptms ); } break; case ESRIShape::ShapeTypeMultiPointM : { std::vector mptms; ESRIShape::MultiPointM mpointm; while( mpointm.read(fd) ) mptms.push_back( mpointm ); _process( mptms ); } break; case ESRIShape::ShapeTypePolyLineM : { std::vector plinems; ESRIShape::PolyLineM plinem; while( plinem.read(fd) ) plinems.push_back( plinem ); _process( plinems ); } break; case ESRIShape::ShapeTypePolygonM : { std::vector polyms; ESRIShape::PolygonM polym; while( polym.read(fd) ) polyms.push_back( polym ); _process( polyms ); } break; case ESRIShape::ShapeTypePointZ : { std::vector ptzs; ESRIShape::PointZRecord pointZRecord; while( pointZRecord.read(fd) ) ptzs.push_back( pointZRecord.pointZ ); _process( ptzs ); } break; case ESRIShape::ShapeTypeMultiPointZ : { std::vector mptzs; ESRIShape::MultiPointZ mpointz; while( mpointz.read(fd) ) mptzs.push_back( mpointz ); _process( mptzs ); } break; case ESRIShape::ShapeTypePolyLineZ : { std::vector plinezs; ESRIShape::PolyLineZ plinez; while( plinez.read(fd) ) plinezs.push_back( plinez ); _process( plinezs ); } break; case ESRIShape::ShapeTypePolygonZ : { std::vector polyzs; ESRIShape::PolygonZ polyz; while( polyz.read(fd) ) polyzs.push_back( polyz ); _process( polyzs ); } break; case ESRIShape::ShapeTypeMultiPatch : { std::vector mpatches; ESRIShape::MultiPatch mpatch; while( mpatch.read( fd ) ) mpatches.push_back( mpatch ); _process(mpatches); } break; default: break; } } osg::Geode *ESRIShapeParser::getGeode() { return _geode.get(); } void ESRIShapeParser::_combinePointToMultipoint() { if( !_valid ) return; osg::ref_ptr coords = new osg::Vec3Array; unsigned int numDrawables = _geode->getNumDrawables(); for( unsigned int i = 0; i < numDrawables; i++ ) { osg::Geometry *geom = dynamic_cast(_geode->getDrawable(i)); if( geom != 0L ) { osg::Vec3Array *va = dynamic_cast(geom->getVertexArray()); if( va != 0L ) coords->push_back( va->front() ); } } _geode->removeDrawables( 0, numDrawables ); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, coords->size())); _geode->addDrawable( geometry.get() ); } void ESRIShapeParser::_process( const std::vector &pts ) { if( !_valid ) return; std::vector::const_iterator p; for( p = pts.begin(); p != pts.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; coords->push_back( osg::Vec3( p->x, p->y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 1)); _geode->addDrawable( geometry.get() ); } if( _geode->getNumDrawables() > 1 ) _combinePointToMultipoint(); } void ESRIShapeParser::_process( const std::vector &mpts ) { if( !_valid ) return; std::vector::const_iterator p; for( p = mpts.begin(); p != mpts.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; for( int i = 0; i < p->numPoints ; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, coords->size())); _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process(const std::vector &lines ) { if( !_valid ) return; std::vector::const_iterator p; for( p = lines.begin(); p != lines.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, index, len)); } _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &polys ) { if( !_valid ) return; std::vector::const_iterator p; for( p = polys.begin(); p != polys.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POLYGON, index, len)); } // Use osgUtil::Tesselator to handle concave polygons osg::ref_ptr tscx=new osgUtil::Tesselator; tscx->setTesselationType(osgUtil::Tesselator::TESS_TYPE_GEOMETRY); tscx->setBoundaryOnly(false); tscx->setWindingType( osgUtil::Tesselator::TESS_WINDING_ODD); tscx->retesselatePolygons(*(geometry.get())); _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &ptms ) { if( !_valid ) return; std::vector::const_iterator p; for( p = ptms.begin(); p != ptms.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; coords->push_back( osg::Vec3( p->x, p->y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 1)); _geode->addDrawable( geometry.get() ); } if( _geode->getNumDrawables() > 1 ) _combinePointToMultipoint(); } void ESRIShapeParser::_process( const std::vector &mptms ) { if( !_valid ) return; std::vector::const_iterator p; for( p = mptms.begin(); p != mptms.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; // Here is where we would use the 'M' (?) for( int i = 0; i < p->numPoints ; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, coords->size())); _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process(const std::vector &linems ) { if( !_valid ) return; std::vector::const_iterator p; for( p = linems.begin(); p != linems.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, index, len)); } _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &polyms ) { if( !_valid ) return; std::vector::const_iterator p; for( p = polyms.begin(); p != polyms.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, 0.0 )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POLYGON, index, len)); } _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &ptzs ) { if( !_valid ) return; std::vector::const_iterator p; for( p = ptzs.begin(); p != ptzs.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; coords->push_back( osg::Vec3( p->x, p->y, p->z )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 1)); _geode->addDrawable( geometry.get() ); } if( _geode->getNumDrawables() > 1 ) _combinePointToMultipoint(); } void ESRIShapeParser::_process( const std::vector &mptzs ) { if( !_valid ) return; std::vector::const_iterator p; for( p = mptzs.begin(); p != mptzs.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; // Here is where we would use the 'M' (?) for( int i = 0; i < p->numPoints ; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, p->zArray[i] )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, coords->size())); _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process(const std::vector &linezs ) { if( !_valid ) return; std::vector::const_iterator p; for( p = linezs.begin(); p != linezs.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, p->zArray[i] )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, index, len)); } _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &polyzs ) { if( !_valid ) return; std::vector::const_iterator p; for( p = polyzs.begin(); p != polyzs.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, p->zArray[i] )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::POLYGON, index, len)); } _geode->addDrawable( geometry.get() ); } } void ESRIShapeParser::_process( const std::vector &mpatches ) { if( !_valid ) return; std::vector::const_iterator p; for( p = mpatches.begin(); p != mpatches.end(); p++ ) { osg::ref_ptr coords = new osg::Vec3Array; int i; for( i = 0; i < p->numPoints; i++ ) coords->push_back( osg::Vec3( p->points[i].x, p->points[i].y, p->zArray[i] )); osg::ref_ptr geometry = new osg::Geometry; geometry->setVertexArray(coords.get()); // Lets mark poorly supported primitives with red, otherwise white osg::ref_ptr colors = new osg::Vec4Array; geometry->setColorArray(colors.get()); geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX ); for( i = 0; i < p->numParts; i++ ) { int index = p->parts[i]; int len = i < p->numParts - 1 ? p->parts[i+1] - p->parts[i] : p->numPoints - p->parts[i]; int mode = p->partTypes[i] == TriangleStrip ? osg::PrimitiveSet::TRIANGLE_STRIP : p->partTypes[i] == TriangleFan ? osg::PrimitiveSet::TRIANGLE_FAN : // HACK for now p->partTypes[i] == OuterRing ? osg::PrimitiveSet::LINE_STRIP : p->partTypes[i] == InnerRing ? osg::PrimitiveSet::LINE_STRIP : p->partTypes[i] == FirstRing ? osg::PrimitiveSet::LINE_STRIP : p->partTypes[i] == Ring ? osg::PrimitiveSet::LINE_STRIP : osg::PrimitiveSet::POINTS ; if( p->partTypes[i] == OuterRing || p->partTypes[i] == InnerRing || p->partTypes[i] == FirstRing || p->partTypes[i] == Ring ) { osg::notify(osg::WARN) << "ESRIShapeParser - MultiPatch type " << (p->partTypes[i] == TriangleStrip ? "TriangleStrip": p->partTypes[i] == TriangleFan ? "TriangleFan": p->partTypes[i] == OuterRing ? "OuterRing": p->partTypes[i] == InnerRing ? "InnerRing": p->partTypes[i] == FirstRing ? "FirstRing": p->partTypes[i] == Ring ? "Ring": "Dunno") << " poorly supported. Will be represented by a red line strip" << std::endl; } // Lets mark poorly supported primitives with red, otherwise white osg::Vec4 color = p->partTypes[i] == TriangleStrip ? osg::Vec4(1.0,1.0,1.0,1.0) : p->partTypes[i] == TriangleFan ? osg::Vec4(1.0,1.0,1.0,1.0) : // HACK for now p->partTypes[i] == OuterRing ? osg::Vec4(1.0,0.0,0.0,1.0) : p->partTypes[i] == InnerRing ? osg::Vec4(1.0,0.0,0.0,1.0) : p->partTypes[i] == FirstRing ? osg::Vec4(1.0,0.0,0.0,1.0) : p->partTypes[i] == Ring ? osg::Vec4(1.0,0.0,0.0,1.0) : osg::Vec4(1.0,0.0,0.0,1.0) ; for( int j = 0; j < len; j++ ) colors->push_back( color ); geometry->addPrimitiveSet( new osg::DrawArrays(mode, index, len )); } _geode->addDrawable( geometry.get() ); } }