From 78c1fd484454405c4760127a2a2eab1c948e24d7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 9 Dec 2007 15:43:49 +0000 Subject: [PATCH] From David Callu, added DBase attribute support for shapefiles --- include/osgSim/ShapeAttribute | 101 ++++++++++ src/osgPlugins/osgSim/CMakeLists.txt | 1 + src/osgPlugins/osgSim/IO_ShapeAttribute.cpp | 169 ++++++++++++++++ src/osgPlugins/shp/CMakeLists.txt | 5 +- src/osgPlugins/shp/ESRIShape.h | 7 +- src/osgPlugins/shp/ESRIType.h | 15 ++ src/osgPlugins/shp/XBaseParser.cpp | 212 ++++++++++++++++++++ src/osgPlugins/shp/XBaseParser.h | 82 ++++++++ src/osgSim/CMakeLists.txt | 2 + src/osgSim/ShapeAttribute.cpp | 129 ++++++++++++ 10 files changed, 716 insertions(+), 7 deletions(-) create mode 100644 include/osgSim/ShapeAttribute create mode 100644 src/osgPlugins/osgSim/IO_ShapeAttribute.cpp create mode 100644 src/osgPlugins/shp/ESRIType.h create mode 100644 src/osgPlugins/shp/XBaseParser.cpp create mode 100644 src/osgPlugins/shp/XBaseParser.h create mode 100644 src/osgSim/ShapeAttribute.cpp diff --git a/include/osgSim/ShapeAttribute b/include/osgSim/ShapeAttribute new file mode 100644 index 000000000..8b1103d30 --- /dev/null +++ b/include/osgSim/ShapeAttribute @@ -0,0 +1,101 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGSIM_SHAPEATTRIBUTE +#define OSGSIM_SHAPEATTRIBUTE 1 + + +#include +#include + +#include + + +namespace osgSim +{ + +class ShapeAttribute +{ + public: + + enum Type + { + UNKNOW, + INTEGER, + DOUBLE, + STRING + }; + + ShapeAttribute(); + ShapeAttribute(const char * name); + ShapeAttribute(const char * name, int value); + ShapeAttribute(const char * name, double value); + ShapeAttribute(const char * name, const char * value); + ShapeAttribute(const ShapeAttribute & sa); + + ~ShapeAttribute(); + + + const std::string & getName() const { return _name; } + const Type getType() const { return _type; } + + int getInt() const { return _integer; } + double getDouble() const { return _double; } + const char * getString() const { return _string; } + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + int compare(const osgSim::ShapeAttribute& sa) const; + + + private: + + std::string _name; + Type _type; + + union + { + int _integer; + double _double; + char * _string; + }; + + +}; + +class ShapeAttributeList : public osg::Object, public std::vector +{ + public: + META_Object(osgSim, ShapeAttributeList) + + ShapeAttributeList(): + Object() + {} + + /** Copy constructor, optional CopyOp object can be used to control + * shallow vs deep copying of dynamic data.*/ + ShapeAttributeList(const ShapeAttributeList& sal,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): + osg::Object(sal, copyop) + { + copy(sal.begin(),sal.end(), begin()); + } + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + virtual int compare(const osgSim::ShapeAttributeList& sal) const; + + protected: + virtual ~ShapeAttributeList() {} +}; + +} + +#endif // ** SHAPEATTRIBUTE_ ** // diff --git a/src/osgPlugins/osgSim/CMakeLists.txt b/src/osgPlugins/osgSim/CMakeLists.txt index 6f7dc2b7c..e341b7567 100644 --- a/src/osgPlugins/osgSim/CMakeLists.txt +++ b/src/osgPlugins/osgSim/CMakeLists.txt @@ -2,6 +2,7 @@ SET(TARGET_SRC +IO_ShapeAttribute.cpp IO_BlinkSequence.cpp IO_DOFTransform.cpp IO_Impostor.cpp diff --git a/src/osgPlugins/osgSim/IO_ShapeAttribute.cpp b/src/osgPlugins/osgSim/IO_ShapeAttribute.cpp new file mode 100644 index 000000000..4cf45c47d --- /dev/null +++ b/src/osgPlugins/osgSim/IO_ShapeAttribute.cpp @@ -0,0 +1,169 @@ +#include + +#include +#include + +#include +#include +#include +#include + +using namespace osgSim; + +bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr); +bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw); + +osgDB::RegisterDotOsgWrapperProxy ShapeAttributeList_Proxy +( + new ShapeAttributeList, + "ShapeAttributeList", + "Object ShapeAttributeList", + &ShapeAttributeList_readLocalData, + &ShapeAttributeList_writeLocalData, + osgDB::DotOsgWrapper::READ_AND_WRITE +); + + + +osgSim::ShapeAttribute::Type ShapeAttributeList_typeStringToEnum(std::string type) +{ + if (type == "STRING") return osgSim::ShapeAttribute::STRING; + else if (type == "DOUBLE") return osgSim::ShapeAttribute::DOUBLE; + else if (type == "INTEGER") return osgSim::ShapeAttribute::INTEGER; + else return osgSim::ShapeAttribute::UNKNOW; +} +void ShapeAttributeList_typeEnumToString(osgSim::ShapeAttribute::Type type, std::string & typeStr) +{ + switch (type) + { + case osgSim::ShapeAttribute::STRING: typeStr = "STRING"; break; + case osgSim::ShapeAttribute::DOUBLE: typeStr = "DOUBLE"; break; + case osgSim::ShapeAttribute::INTEGER: typeStr = "INTEGER"; break; + default: typeStr = "UNKNOW"; break; + } +} + + +bool ShapeAttributeList_readLocalData(osg::Object &obj, osgDB::Input &fr) +{ + bool iteratorAdvanced = false; + ShapeAttributeList &sal = static_cast(obj); + + + int size = 0; + + if (fr[0].matchWord("size") && fr[1].getInt(size)) + { + sal.reserve(size); + fr += 2; + iteratorAdvanced = true; + } + + if (size) + { + std::string name; + osgSim::ShapeAttribute::Type type; + for (int i = 0; i < size; ++i) + { + if (fr.matchSequence("name %s")) + { + name = fr[1].getStr(); + fr += 2; + iteratorAdvanced = true; + } + if (fr[0].matchWord("type")) + { + type = ShapeAttributeList_typeStringToEnum(fr[1].getStr()); + fr += 2; + iteratorAdvanced = true; + + switch (type) + { + case osgSim::ShapeAttribute::STRING: + { + if (fr.matchSequence("value %s")) + { + std::string value = fr[1].getStr(); + fr += 2; + iteratorAdvanced = true; + sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), (char*) value.c_str())); + } + break; + } + case osgSim::ShapeAttribute::DOUBLE: + { + double value; + if (fr[0].matchWord("value") && fr[1].getFloat(value)) + { + fr += 2; + iteratorAdvanced = true; + sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), value)); + } + break; + } + case osgSim::ShapeAttribute::INTEGER: + { + int value; + if (fr[0].matchWord("value") && fr[1].getInt(value)) + { + fr += 2; + iteratorAdvanced = true; + sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str(), value)); + } + break; + } + case osgSim::ShapeAttribute::UNKNOW: + default: + { + sal.push_back(osgSim::ShapeAttribute((const char *) name.c_str())); + break; + } + } + } + } + } + + return iteratorAdvanced; +} + + +bool ShapeAttributeList_writeLocalData(const osg::Object &obj, osgDB::Output &fw) +{ + const ShapeAttributeList &sal = static_cast(obj); + + unsigned int size = sal.size(); + fw.indent()<<"size "<< size << std::endl; + + if (size) + { + std::string type; + ShapeAttributeList::const_iterator it, end = sal.end(); + for (it = sal.begin(); it != end; ++it) + { + fw.indent()<<"name \""<< it->getName() << "\"" << std::endl; + ShapeAttributeList_typeEnumToString(it->getType(), type); + fw.indent()<<"type "<< type << std::endl; + switch (it->getType()) + { + case osgSim::ShapeAttribute::STRING: + { + fw.indent()<<"value \""<< it->getString() << "\"" << std::endl; + break; + } + case osgSim::ShapeAttribute::INTEGER: + { + fw.indent()<<"value "<< it->getInt() << std::endl; + break; + } + case osgSim::ShapeAttribute::DOUBLE: + { + fw.indent()<<"value "<< it->getDouble() << std::endl; + break; + } + case osgSim::ShapeAttribute::UNKNOW: + default: break; + } + } + } + return true; +} diff --git a/src/osgPlugins/shp/CMakeLists.txt b/src/osgPlugins/shp/CMakeLists.txt index d7d15c984..30c382cdd 100644 --- a/src/osgPlugins/shp/CMakeLists.txt +++ b/src/osgPlugins/shp/CMakeLists.txt @@ -1,7 +1,8 @@ #this file is automatically generated -SET(TARGET_SRC ESRIShape.cpp ESRIShapeParser.cpp ESRIShapeReaderWriter.cpp ) -SET(TARGET_H ESRIShape.h ESRIShapeParser.h ) +SET(TARGET_SRC ESRIShape.cpp ESRIShapeParser.cpp ESRIShapeReaderWriter.cpp XBaseParser.cpp) +SET(TARGET_H ESRIShape.h ESRIShapeParser.h XBaseParser.h) +SET(TARGET_ADDED_LIBRARIES osgSim ) #### end var setup ### SETUP_PLUGIN(shp) diff --git a/src/osgPlugins/shp/ESRIShape.h b/src/osgPlugins/shp/ESRIShape.h index aaafc1441..d48c57ea5 100644 --- a/src/osgPlugins/shp/ESRIShape.h +++ b/src/osgPlugins/shp/ESRIShape.h @@ -7,13 +7,10 @@ #endif #include +#include "ESRIType.h" + namespace ESRIShape { -typedef int Integer; -typedef short Short; -typedef unsigned char Byte; -typedef double Double; -typedef unsigned char * BytePtr; enum ByteOrder { LittleEndian, diff --git a/src/osgPlugins/shp/ESRIType.h b/src/osgPlugins/shp/ESRIType.h new file mode 100644 index 000000000..3533e78b4 --- /dev/null +++ b/src/osgPlugins/shp/ESRIType.h @@ -0,0 +1,15 @@ +#ifndef ESRITYPE_H_ +#define ESRITYPE_H_ + + +namespace ESRIShape { + +typedef int Integer; +typedef short Short; +typedef unsigned char Byte; +typedef double Double; +typedef unsigned char * BytePtr; + +} + +#endif /*ESRITYPE_H_*/ diff --git a/src/osgPlugins/shp/XBaseParser.cpp b/src/osgPlugins/shp/XBaseParser.cpp new file mode 100644 index 000000000..5bc504655 --- /dev/null +++ b/src/osgPlugins/shp/XBaseParser.cpp @@ -0,0 +1,212 @@ +#include "XBaseParser.h" + +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW32__) + #include + #include +#else + #include +#endif + +#include +#include + +namespace ESRIShape +{ + + +void XBaseHeader::print() +{ + osg::notify(osg::INFO) << "VersionNumber = " << (int) _versionNumber << std::endl + << "LastUpdate = " << 1900 + (int) _lastUpdate[0] << "/" << (int) _lastUpdate[1] << "/" << (int) _lastUpdate[2] << std::endl + << "NumRecord = " << _numRecord << std::endl + << "HeaderLength = " << _headerLength << std::endl + << "RecordLength = " << _recordLength << std::endl; +} + +bool XBaseHeader::read(int fd) +{ + int nbytes = 0; + + if ((nbytes = ::read( fd, &_versionNumber, sizeof(_versionNumber))) <= 0) return false; + if ((nbytes = ::read( fd, &_lastUpdate, sizeof(_lastUpdate))) <= 0) return false; + if ((nbytes = ::read( fd, &_numRecord, sizeof(_numRecord))) <= 0) return false; + if ((nbytes = ::read( fd, &_headerLength, sizeof(_headerLength))) <= 0) return false; + if ((nbytes = ::read( fd, &_recordLength, sizeof(_recordLength))) <= 0) return false; + if ((nbytes = ::read( fd, &_reserved, sizeof(_reserved))) <= 0) return false; + if ((nbytes = ::read( fd, &_incompleteTransaction, sizeof(_incompleteTransaction))) <= 0) return false; + if ((nbytes = ::read( fd, &_encryptionFlag, sizeof(_encryptionFlag))) <= 0) return false; + if ((nbytes = ::read( fd, &_freeRecordThread, sizeof(_freeRecordThread))) <= 0) return false; + if ((nbytes = ::read( fd, &_reservedMultiUser, sizeof(_reservedMultiUser))) <= 0) return false; + if ((nbytes = ::read( fd, &_mdxflag, sizeof(_mdxflag))) <= 0) return false; + if ((nbytes = ::read( fd, &_languageDriver, sizeof(_languageDriver))) <= 0) return false; + if ((nbytes = ::read( fd, &_reserved2, sizeof(_reserved2))) <= 0) return false; + + return true; +} + +void XBaseFieldDescriptor::print() +{ + osg::notify(osg::INFO) << "name = " << _name << std::endl + << "type = " << _fieldType << std::endl + << "length = " << (int) _fieldLength << std::endl + << "decimalCount = " << (int) _decimalCount << std::endl + << "workAreaID = " << (int) _workAreaID << std::endl + << "setFieldFlag = " << (int) _setFieldFlag << std::endl + << "indexFieldFlag = " << (int) _indexFieldFlag << std::endl; +} + +bool XBaseFieldDescriptor::read(int fd) +{ + int nbytes = 0; + + if ((nbytes = ::read( fd, &_name, sizeof(_name))) <= 0) return false; + if ((nbytes = ::read( fd, &_fieldType, sizeof(_fieldType))) <= 0) return false; + if ((nbytes = ::read( fd, &_fieldDataAddress, sizeof(_fieldDataAddress))) <= 0) return false; + if ((nbytes = ::read( fd, &_fieldLength, sizeof(_fieldLength))) <= 0) return false; + if ((nbytes = ::read( fd, &_decimalCount, sizeof(_decimalCount))) <= 0) return false; + if ((nbytes = ::read( fd, &_reservedMultiUser, sizeof(_reservedMultiUser))) <= 0) return false; + if ((nbytes = ::read( fd, &_workAreaID, sizeof(_workAreaID))) <= 0) return false; + if ((nbytes = ::read( fd, &_reservedMultiUser2, sizeof(_reservedMultiUser2))) <= 0) return false; + if ((nbytes = ::read( fd, &_setFieldFlag, sizeof(_setFieldFlag))) <= 0) return false; + if ((nbytes = ::read( fd, &_reserved, sizeof(_reserved))) <= 0) return false; + if ((nbytes = ::read( fd, &_indexFieldFlag, sizeof(_indexFieldFlag))) <= 0) return false; + + return true; +} + + +XBaseParser::XBaseParser(const std::string fileName): + _valid(false) +{ + int fd = 0; + if (fileName.empty() == false) + { +#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 = parse(fd); +} + +bool XBaseParser::parse(int fd) +{ + int nbytes; + XBaseHeader _xBaseHeader; + std::vector _xBaseFieldDescriptorList; + XBaseFieldDescriptor _xBaseFieldDescriptorTmp; + + + // ** read the header + if (_xBaseHeader.read(fd) == false) return false; +// _xBaseHeader.print(); + + + // ** read field descriptor + bool fieldDescriptorDone = false; + Byte nullTerminator; + + while (fieldDescriptorDone == false) + { + // ** store the field descriptor + if (_xBaseFieldDescriptorTmp.read(fd) == false) return false; + _xBaseFieldDescriptorList.push_back(_xBaseFieldDescriptorTmp); +// _xBaseFieldDescriptorTmp.print(); + + // ** check the terminator + if ((nbytes = ::read( fd, &nullTerminator, sizeof(nullTerminator))) <= 0) return false; + if (nullTerminator == 0x0D) + fieldDescriptorDone = true; + else + ::lseek( fd, -1, SEEK_CUR); + } + + + // ** move to the end of the Header + ::lseek( fd, _xBaseHeader._headerLength + 1, SEEK_SET); + + + // ** reserve AttributeListList + _shapeAttributeListList.reserve(_xBaseHeader._numRecord); + + + // ** read each record and store them in the ShapeAttributeListList + char record[_xBaseHeader._recordLength]; + std::vector::iterator it, end = _xBaseFieldDescriptorList.end(); + for (Integer i = 0; i < _xBaseHeader._numRecord; ++i) + { + if ((nbytes = ::read( fd, &record, sizeof(record))) <= 0) return false; + + char * recordPtr = record; + osgSim::ShapeAttributeList * shapeAttributeList = new osgSim::ShapeAttributeList; + shapeAttributeList->reserve(_xBaseFieldDescriptorList.size()); + + for (it = _xBaseFieldDescriptorList.begin(); it != end; ++it) + { + switch (it->_fieldType) + { + case 'C': + { + char str[it->_fieldLength + 1]; + memcpy(str, recordPtr, it->_fieldLength); + str[it->_fieldLength] = 0; + shapeAttributeList->push_back(osgSim::ShapeAttribute((const char *) it->_name, (char*) str)); + break; + } + case 'N': + { + char number[it->_fieldLength + 1]; + memcpy(number, recordPtr, it->_fieldLength); + number[it->_fieldLength] = 0; + shapeAttributeList->push_back(osgSim::ShapeAttribute((const char *) it->_name, (int) atoi(number))); + break; + } + case 'I': + { + int number; + memcpy(&number, record, it->_fieldLength); + shapeAttributeList->push_back(osgSim::ShapeAttribute((const char *) it->_name, (int) number)); + break; + } + case 'O': + { + double number; + memcpy(&number, record, it->_fieldLength); + shapeAttributeList->push_back(osgSim::ShapeAttribute((const char *) it->_name, (double) number)); + break; + } + default: + { + osg::notify(osg::WARN) << "ESRIShape::XBaseParser : record type " + << it->_fieldType << "not supported, skipped" << std::endl; + shapeAttributeList->push_back(osgSim::ShapeAttribute((const char *) it->_name, (double) 0)); + break; + } + + + } + + recordPtr += it->_fieldLength; + } + + _shapeAttributeListList.push_back(shapeAttributeList); + } + + close (fd); + + return true; +} + + +} + + diff --git a/src/osgPlugins/shp/XBaseParser.h b/src/osgPlugins/shp/XBaseParser.h new file mode 100644 index 000000000..9703f1730 --- /dev/null +++ b/src/osgPlugins/shp/XBaseParser.h @@ -0,0 +1,82 @@ +#ifndef XBASEPARSER_H_ +#define XBASEPARSER_H_ + + + +#include +#include + +#include "ESRIType.h" + +#include +#include + + + +namespace ESRIShape +{ + + +struct XBaseHeader +{ + Byte _versionNumber; + Byte _lastUpdate[3]; + Integer _numRecord; + Short _headerLength; + Short _recordLength; + Short _reserved; + Byte _incompleteTransaction; + Byte _encryptionFlag; + Integer _freeRecordThread; + Integer _reservedMultiUser[2]; + Byte _mdxflag; + Byte _languageDriver; + Short _reserved2; + + void print(); + bool read(int fd); +}; + +struct XBaseFieldDescriptor +{ + Byte _name[11]; + Byte _fieldType; + Integer _fieldDataAddress; + Byte _fieldLength; + Byte _decimalCount; + Short _reservedMultiUser; + Byte _workAreaID; + Short _reservedMultiUser2; + Byte _setFieldFlag; + Byte _reserved[7]; + Byte _indexFieldFlag; + + void print(); + bool read(int fd); +}; + + +class XBaseParser +{ + public: + + typedef std::vector< osg::ref_ptr > ShapeAttributeListList; + + XBaseParser(const std::string fileName); + ~XBaseParser() {} + ShapeAttributeListList & getAttributeList() { return _shapeAttributeListList; } + + private: + + XBaseParser(); + + bool parse(int fd); + + ShapeAttributeListList _shapeAttributeListList; + bool _valid; +}; + +} + + +#endif /*XBASEPARSER_H_*/ diff --git a/src/osgSim/CMakeLists.txt b/src/osgSim/CMakeLists.txt index 9119d75a2..c361dedf1 100644 --- a/src/osgSim/CMakeLists.txt +++ b/src/osgSim/CMakeLists.txt @@ -28,6 +28,7 @@ SET(LIB_PUBLIC_HEADERS ${HEADER_PATH}/ScalarBar ${HEADER_PATH}/ScalarsToColors ${HEADER_PATH}/Sector + ${HEADER_PATH}/ShapeAttribute ${HEADER_PATH}/SphereSegment ${HEADER_PATH}/Version ${HEADER_PATH}/VisibilityGroup @@ -58,6 +59,7 @@ ADD_LIBRARY(${LIB_NAME} ScalarBar.cpp ScalarsToColors.cpp Sector.cpp + ShapeAttribute.cpp SphereSegment.cpp Version.cpp VisibilityGroup.cpp diff --git a/src/osgSim/ShapeAttribute.cpp b/src/osgSim/ShapeAttribute.cpp new file mode 100644 index 000000000..795c7cfef --- /dev/null +++ b/src/osgSim/ShapeAttribute.cpp @@ -0,0 +1,129 @@ +#include + +namespace osgSim +{ +ShapeAttribute::ShapeAttribute() : + _type(UNKNOW), + _integer(0) +{} + +ShapeAttribute::ShapeAttribute(const char * name) : + _name(name), + _type(UNKNOW), + _integer(0) +{} + +ShapeAttribute::ShapeAttribute(const char * name, int value) : + _name(name), + _type(INTEGER), + _integer(value) +{} + +ShapeAttribute::ShapeAttribute(const char * name, double value) : + _name(name), + _type(DOUBLE), + _double(value) +{} + +ShapeAttribute::ShapeAttribute(const char * name, const char * value) : + _name(name), + _type(STRING) +{ + std::string str(value); + _string = new char[str.size() + 1]; + memcpy(_string, str.c_str(), str.size()); + _string[str.size()] = 0; +} + +ShapeAttribute::ShapeAttribute(const ShapeAttribute & sa) : + _name(sa._name), + _type(sa._type) +{ + switch (_type) + { + case INTEGER: + { + _integer = sa._integer; + break; + } + case STRING: + { + std::string str(sa._string); + _string = new char[str.size() + 1]; + memcpy(_string, str.c_str(), str.size()); + _string[str.size()] = 0; + break; + } + case DOUBLE: + { + _double = sa._double; + break; + } + case UNKNOW: + default: + { + _integer = 0; + break; + } + } +} + + +ShapeAttribute::~ShapeAttribute() +{ + if ((_type == STRING) && (_string)) delete [] _string; +} + + + +int ShapeAttribute::compare(const osgSim::ShapeAttribute& sa) const +{ + if (_name*rhs.*/ +int ShapeAttributeList::compare(const osgSim::ShapeAttributeList& sal) const +{ + const_iterator salIt, thisIt, thisEnd = end(); + + int ret; + for (thisIt = begin(), salIt = sal.begin(); thisIt!= thisEnd; ++thisIt, ++salIt) + if ((ret = thisIt->compare(*salIt)) != 0) return ret; + + return 0; +} + +}