/* dxfReader for OpenSceneGraph Copyright (C) 2005 by GraphArchitecture ( grapharchitecture.com ) * Programmed by Paul de Repentigny * * OpenSceneGraph is (C) 2004 Robert Osfield * * This library is provided as-is, without support of any kind. * * Read DXF docs or OSG docs for any related questions. * * You may contact the author if you have suggestions/corrections/enhancements. */ /** Simulate the scene with double precision before passing it back to osg. this permits us to scale down offsets from 0,0,0 with a few matrixtransforms, in case the objects are too far from that center. */ #ifndef DXF_SCENE #define DXF_SCENE 1 #include #include #include #include #include #include #include class dxfLayerTable; class bounds { public: bounds() : _min(DBL_MAX, DBL_MAX, DBL_MAX), _max(-DBL_MAX, -DBL_MAX, -DBL_MAX) {} inline void expandBy(osg::Vec3d v) { if(v.x()<_min.x()) _min.x() = v.x(); if(v.x()>_max.x()) _max.x() = v.x(); if(v.y()<_min.y()) _min.y() = v.y(); if(v.y()>_max.y()) _max.y() = v.y(); if(v.z()<_min.z()) _min.z() = v.z(); if(v.z()>_max.z()) _max.z() = v.z(); } inline void makeMinValid() { // we count on _min to offset the whole scene // so, we make sure its at 0,0,0 if // bounds are not set (anyway, the scene should be empty, // if we need to set any value of _min to 0). if (_min.x() == DBL_MAX) _min.x() = 0; if (_min.y() == DBL_MAX) _min.y() = 0; if (_min.z() == DBL_MAX) _min.z() = 0; } osg::Vec3d _min; osg::Vec3d _max; }; static inline osg::Geometry* createLnGeometry( osg::PrimitiveSet::Mode lineType, osg::Vec3Array* vertices, osg::Vec4 color) { osg::Geometry* geom = new osg::Geometry; geom->setVertexArray(vertices); geom->addPrimitiveSet(new osg::DrawArrays(lineType, 0, vertices->size())); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(color); geom->setColorArray(colors); geom->setColorBinding(osg::Geometry::BIND_OVERALL); osg::Vec3Array *norms = new osg::Vec3Array; norms->push_back(osg::Vec3(0,0,1)); geom->setNormalArray(norms); geom->setNormalBinding(osg::Geometry::BIND_OVERALL); return geom; } static inline osg::Geometry* createTriGeometry( osg::Vec3Array* vertices, osg::Vec3Array* normals, osg::Vec4 color) { osg::Geometry* geom = new osg::Geometry; geom->setVertexArray(vertices); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->size())); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(color); geom->setColorArray(colors); geom->setColorBinding(osg::Geometry::BIND_OVERALL); geom->setNormalArray(normals); geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); return geom; } static inline osg::Geometry* createQuadGeometry( osg::Vec3Array* vertices, osg::Vec3Array* normals, osg::Vec4 color) { osg::Geometry* geom = new osg::Geometry; geom->setVertexArray(vertices); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size())); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(color); geom->setColorArray(colors); geom->setColorBinding(osg::Geometry::BIND_OVERALL); geom->setNormalArray(normals); geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); return geom; } static inline osg::Geode* createModel(std::string name, osg::Geometry* geom) { osg::Geode* geom_geode = new osg::Geode; geom_geode->addDrawable(geom); geom_geode->setName(name); return geom_geode; } static inline osg::Vec3d preMultd(const osg::Matrixd& m, const osg::Vec3d& v) { double d = 1.0f/(m(3,0)*v.x()+m(3,1)*v.y()+m(3,2)*v.z()+m(3,3)) ; return osg::Vec3d( (m(0,0)*v.x() + m(1,0)*v.y() + m(2,0)*v.z() + m(3,0))*d, (m(0,1)*v.x() + m(1,1)*v.y() + m(2,1)*v.z() + m(3,1))*d, (m(0,2)*v.x() + m(1,2)*v.y() + m(2,2)*v.z() + m(3,2))*d) ; } static inline osg::Vec3d postMultd(const osg::Matrixd& m, const osg::Vec3d& v) { double d = 1.0f/(m(3,0)*v.x()+m(3,1)*v.y()+m(3,2)*v.z()+m(3,3)) ; return osg::Vec3d( (m(0,0)*v.x() + m(0,1)*v.y() + m(0,2)*v.z() + m(0,3))*d, (m(1,0)*v.x() + m(1,1)*v.y() + m(1,2)*v.z() + m(1,3))*d, (m(2,0)*v.x() + m(2,1)*v.y() + m(2,2)*v.z() + m(2,3))*d) ; } typedef std::vector VList; typedef std::map MapVList; typedef std::vector VListList; typedef std::map MapVListList; class sceneLayer : public osg::Referenced { public: sceneLayer(std::string name) : _name(name) {} virtual ~sceneLayer() {} void layer2osg(osg::Group* root, bounds &b) { osgLines(root, b); osgTriangles(root, b); osgQuads(root, b); } MapVListList _linestrips; MapVList _lines; MapVList _triangles; MapVList _trinorms; MapVList _quads; MapVList _quadnorms; protected: std::string _name; osg::Vec4 getColor(unsigned short color); void osgLines(osg::Group* root, bounds &b) { for(MapVListList::iterator mlitr = _linestrips.begin(); mlitr != _linestrips.end(); ++mlitr) { for(VListList::iterator itr = mlitr->second.begin(); itr != mlitr->second.end(); ++itr) { if (itr->size()) { osg::Vec3Array *coords = new osg::Vec3Array; for (VList::iterator vitr = itr->begin(); vitr != itr->end(); ++vitr) { osg::Vec3 v(vitr->x() - b._min.x(), vitr->y() - b._min.y(), vitr->z() - b._min.z()); coords->push_back(v); } root->addChild(createModel(_name, createLnGeometry(osg::PrimitiveSet::LINE_STRIP, coords, getColor(mlitr->first)))); } } } for (MapVList::iterator mitr = _lines.begin(); mitr != _lines.end(); ++mitr) { osg::Vec3Array *coords = new osg::Vec3Array; for (VList::iterator itr = mitr->second.begin(); itr != mitr->second.end(); ++itr) { osg::Vec3 v(itr->x() - b._min.x(), itr->y() - b._min.y(), itr->z() - b._min.z()); coords->push_back(v); } root->addChild(createModel(_name, createLnGeometry(osg::PrimitiveSet::LINES, coords, getColor(mitr->first)))); } } void osgTriangles(osg::Group* root, bounds &b) { if (_triangles.size()) { for (MapVList::iterator mitr = _triangles.begin(); mitr != _triangles.end(); ++mitr) { osg::Vec3Array *coords = new osg::Vec3Array; VList::iterator itr; for (itr = mitr->second.begin(); itr != mitr->second.end(); ++itr) { osg::Vec3 v(itr->x() - b._min.x(), itr->y() - b._min.y(), itr->z() - b._min.z()); coords->push_back(v); } osg::Vec3Array *norms = new osg::Vec3Array; VList normlist = _trinorms[mitr->first]; for (itr = normlist.begin(); itr != normlist.end(); ++itr) { norms->push_back(osg::Vec3(itr->x(), itr->y(), itr->z())); } root->addChild(createModel(_name, createTriGeometry(coords, norms, getColor(mitr->first)))); } } } void osgQuads(osg::Group* root, bounds &b) { if (_quads.size()) { for (MapVList::iterator mitr = _quads.begin(); mitr != _quads.end(); ++mitr) { osg::Vec3Array *coords = new osg::Vec3Array; VList::iterator itr; for (itr = mitr->second.begin(); itr != mitr->second.end(); ++itr) { osg::Vec3 v(itr->x() - b._min.x(), itr->y() - b._min.y(), itr->z() - b._min.z()); coords->push_back(v); } osg::Vec3Array *norms = new osg::Vec3Array; VList normlist = _quadnorms[mitr->first]; for (itr = normlist.begin(); itr != normlist.end(); ++itr) { norms->push_back(osg::Vec3(itr->x(), itr->y(), itr->z())); } root->addChild(createModel(_name, createQuadGeometry(coords, norms, getColor(mitr->first)))); } } } }; class scene : public osg::Referenced { public: scene(dxfLayerTable* lt = NULL); virtual ~scene() {} void setLayerTable(dxfLayerTable* lt); void pushMatrix(const osg::Matrixd& m, bool protect = false) { _mStack.push_back(_m); if (protect) // equivalent to setMatrix _m = m; else _m = _m * m; } void popMatrix() { _mStack.pop_back(); if (_mStack.size()) _m = _mStack.back(); else _m.makeIdentity(); } void ocs(const osg::Matrixd& r) { _r = r; } void blockOffset(const osg::Vec3d& t) { _t = t; } void ocs_clear() { _r.makeIdentity(); } osg::Matrixd& backMatrix() { if (_mStack.size()) return _mStack.back(); else return _m; } osg::Vec3d addVertex(osg::Vec3d v); osg::Vec3d addNormal(osg::Vec3d v); sceneLayer* findOrCreateSceneLayer(std::string l) { sceneLayer* ly = _layers[l].get(); if (!ly) { ly = new sceneLayer(l); _layers[l] = ly; } return ly; } unsigned short correctedColorIndex(std::string l, unsigned short color); void addLine(std::string l, unsigned short color, osg::Vec3d s, osg::Vec3d e); void addLineStrip(std::string l, unsigned short color, std::vector vertices); void addLineLoop(std::string l, unsigned short color, std::vector vertices); void addTriangles(std::string l, unsigned short color, std::vector vertices, bool inverted=false); void addQuads(std::string l, unsigned short color, std::vector vertices, bool inverted=false); osg::Group* scene2osg() { osg::Group* root = NULL; osg::Group* child = NULL; _b.makeMinValid(); osg::Vec3 v = osg::Vec3(_b._min.x(), _b._min.y(), _b._min.z()); double x = _b._min.x() - (double)v.x(); double y = _b._min.y() - (double)v.y(); double z = _b._min.z() - (double)v.z(); osg::Matrixd m = osg::Matrixd::translate(v); root = new osg::MatrixTransform(m); if (x || y || z) { m = osg::Matrixd::translate(x,y,z); child = new osg::MatrixTransform(m); root->addChild(child); } else { child = root; } // root = mt; for (std::map >::iterator litr = _layers.begin(); litr != _layers.end(); ++litr) { sceneLayer* ly = (*litr).second.get(); if (!ly) continue; osg::Group* lg = new osg::Group; lg->setName((*litr).first); child->addChild(lg); ly->layer2osg(lg, _b); } return root; } protected: osg::Matrixd _m; osg::Matrixd _r; osg::Vec3d _t; bounds _b; std::map > _layers; std::vector _mStack; dxfLayerTable* _layerTable; }; #endif