From BjornHein, "attached a proposal for an extension for the the stl-File ReaderWriter. It allows saving of an osg node tree as stl file in ASCII-Format.
Standard is to generate one stl file. With an additional option it is possible to write one file per Geode. This option is not very "useful" for typical application, I use it for separating and conversion of geometric data. So it could be removed if considered to special."
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <osgUtil/TriStripVisitor>
|
||||
#include <osgUtil/SmoothingVisitor>
|
||||
#include <osg/TriangleFunctor>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
@@ -50,6 +51,7 @@ public:
|
||||
supportsExtension("stl","STL binary format");
|
||||
supportsExtension("sta","STL ASCII format");
|
||||
supportsOption("smooth", "run SmoothingVisitor");
|
||||
supportsOption("separateFiles", "Save every geode in a different file. Can be a Huge amount of Files!!!");
|
||||
}
|
||||
|
||||
virtual const char* className() const {
|
||||
@@ -57,7 +59,7 @@ public:
|
||||
}
|
||||
|
||||
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*) const;
|
||||
|
||||
virtual WriteResult writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const Options* =NULL) const ;
|
||||
private:
|
||||
|
||||
struct ReaderObject
|
||||
@@ -76,6 +78,94 @@ private:
|
||||
bool readStlAscii(FILE* fp);
|
||||
bool readStlBinary(FILE* fp);
|
||||
};
|
||||
|
||||
class CreateStlVisitor : public osg::NodeVisitor {
|
||||
public:
|
||||
|
||||
CreateStlVisitor( std::string const & fout, const osgDB::ReaderWriter::Options* options = 0): osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN ), counter(0), m_fout(fout), m_options(options) {
|
||||
if (options && (options->getOptionString() == "separateFiles")) {
|
||||
osg::notify(osg::INFO) << "ReaderWriterSTL::writeNode: Files are seperated written" << std::endl;
|
||||
} else {
|
||||
m_f = new std::ofstream(m_fout.c_str());
|
||||
*m_f << "solid " << counter << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
std::string i2s( int i) {
|
||||
char buf[16]; // -2^31 == -2147483648 needs 11 chars + \0 -> 12 (+4 for security ;-)
|
||||
sprintf(buf,"%d",i);
|
||||
return buf;
|
||||
}
|
||||
|
||||
virtual void apply( osg::Geode& node ){
|
||||
osg::Matrix mat = osg::computeLocalToWorld( getNodePath() );
|
||||
|
||||
if (m_options && (m_options->getOptionString() == "separateFiles")) {
|
||||
std::string sepFile = m_fout + i2s(counter);
|
||||
m_f = new std::ofstream(sepFile.c_str());
|
||||
*m_f << "solid " << std::endl;
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < node.getNumDrawables(); ++i ) {
|
||||
osg::TriangleFunctor<PushPoints> tf;
|
||||
tf.m_stream = m_f;
|
||||
tf.m_mat = mat;
|
||||
node.getDrawable( i )->accept( tf );
|
||||
}
|
||||
|
||||
if (m_options && (m_options->getOptionString() == "separateFiles")) {
|
||||
*m_f << "endsolid " << std::endl;
|
||||
m_f->close();
|
||||
delete m_f;
|
||||
}
|
||||
|
||||
++counter;
|
||||
traverse(node);
|
||||
|
||||
}
|
||||
// nHandle->SetLocation( Frame( mat ) );
|
||||
~CreateStlVisitor() {
|
||||
if (m_options && (m_options->getOptionString() == "separateFiles")) {
|
||||
osg::notify(osg::INFO) << "ReaderWriterSTL::writeNode: " << counter-1 << "Files were written" << std::endl;
|
||||
} else {
|
||||
*m_f << "endsolid " << std::endl;
|
||||
m_f->close();
|
||||
delete m_f;
|
||||
}
|
||||
}
|
||||
private:
|
||||
int counter;
|
||||
std::ofstream* m_f;
|
||||
std::string m_fout;
|
||||
osgDB::ReaderWriter::Options const * m_options;
|
||||
|
||||
|
||||
struct PushPoints {
|
||||
std::ofstream* m_stream;
|
||||
osg::Matrix m_mat;
|
||||
inline void operator () ( const osg::Vec3& _v1, const osg::Vec3& _v2, const osg::Vec3& _v3, bool treatVertexDataAsTemporary ) {
|
||||
osg::Vec3 v1 = _v1 * m_mat;
|
||||
osg::Vec3 v2 = _v2 * m_mat;
|
||||
osg::Vec3 v3 = _v3 * m_mat;
|
||||
osg::Vec3 vV1V2 = v2-v1;
|
||||
osg::Vec3 vV1V3 = v3-v1;
|
||||
osg::Vec3 vNormal = vV1V2.operator ^(vV1V3);
|
||||
*m_stream << "facet normal " << vNormal[0] << " " << vNormal[1] << " " << vNormal[2] << std::endl;
|
||||
*m_stream << "outer loop" << std::endl;
|
||||
*m_stream << "vertex " << v1[0] << " " << v1[1] << " " << v1[2] << std::endl;
|
||||
*m_stream << "vertex " << v2[0] << " " << v2[1] << " " << v2[2] << std::endl;
|
||||
*m_stream << "vertex " << v3[0] << " " << v3[1] << " " << v3[2] << std::endl;
|
||||
*m_stream << "endloop" << std::endl;
|
||||
*m_stream << "endfacet " << std::endl;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -355,3 +445,21 @@ bool ReaderWriterSTL::ReaderObject::readStlBinary(FILE* fp)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::WriteResult ReaderWriterSTL::writeNode(const osg::Node& node,const std::string& fout, const Options* opts) const {
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(fout);
|
||||
if (ext != "stl" ){
|
||||
// sta - extension implies STL-Binary...
|
||||
osg::notify(osg::FATAL) << "ReaderWriterSTL::writeNode: Only STL-ASCII-files supported'" << std::endl;
|
||||
return WriteResult::FILE_NOT_HANDLED;
|
||||
}
|
||||
|
||||
try {
|
||||
CreateStlVisitor createStlVisitor( fout, opts );
|
||||
const_cast<osg::Node&>(node).accept( createStlVisitor );
|
||||
} catch(...) {
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
}
|
||||
|
||||
return WriteResult::FILE_SAVED;
|
||||
}
|
||||
|
||||
@@ -334,6 +334,16 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager)
|
||||
__unsigned_int__getDataToCompileListSize,
|
||||
"Report how many items are in the _dataToCompileList queue. ",
|
||||
"");
|
||||
I_Method0(unsigned int, getDataToMergeListSize,
|
||||
Properties::NON_VIRTUAL,
|
||||
__unsigned_int__getDataToMergeListSize,
|
||||
"Report how many items are in the _dataToCompileList queue. ",
|
||||
"");
|
||||
I_Method0(bool, getRequestsInProgress,
|
||||
Properties::NON_VIRTUAL,
|
||||
__bool__getRequestsInProgress,
|
||||
"Report whether any requests are in the pager. ",
|
||||
"");
|
||||
I_Method0(double, getMinimumTimeToMergeTile,
|
||||
Properties::NON_VIRTUAL,
|
||||
__double__getMinimumTimeToMergeTile,
|
||||
@@ -417,6 +427,9 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager)
|
||||
I_SimpleProperty(unsigned int, DataToCompileListSize,
|
||||
__unsigned_int__getDataToCompileListSize,
|
||||
0);
|
||||
I_SimpleProperty(unsigned int, DataToMergeListSize,
|
||||
__unsigned_int__getDataToMergeListSize,
|
||||
0);
|
||||
I_SimpleProperty(bool, DatabasePagerThreadPause,
|
||||
__bool__getDatabasePagerThreadPause,
|
||||
__void__setDatabasePagerThreadPause__bool);
|
||||
@@ -463,6 +476,9 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager)
|
||||
I_SimpleProperty(int, ReleaseFrames,
|
||||
__int__getReleaseFrames,
|
||||
__void__setReleaseFrames__int);
|
||||
I_SimpleProperty(bool, RequestsInProgress,
|
||||
__bool__getRequestsInProgress,
|
||||
0);
|
||||
I_SimpleProperty(OpenThreads::Thread::ThreadPriority, SchedulePriority,
|
||||
0,
|
||||
__int__setSchedulePriority__OpenThreads_Thread_ThreadPriority);
|
||||
@@ -500,6 +516,16 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager::DatabaseThread)
|
||||
__bool__getDone,
|
||||
"",
|
||||
"");
|
||||
I_Method1(void, setActive, IN, bool, active,
|
||||
Properties::NON_VIRTUAL,
|
||||
__void__setActive__bool,
|
||||
"",
|
||||
"");
|
||||
I_Method0(bool, getActive,
|
||||
Properties::NON_VIRTUAL,
|
||||
__bool__getActive,
|
||||
"",
|
||||
"");
|
||||
I_Method0(int, cancel,
|
||||
Properties::VIRTUAL,
|
||||
__int__cancel,
|
||||
@@ -510,6 +536,9 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager::DatabaseThread)
|
||||
__void__run,
|
||||
"Thread's run method. ",
|
||||
"Must be implemented by derived classes. This is where the action happens. ");
|
||||
I_SimpleProperty(bool, Active,
|
||||
__bool__getActive,
|
||||
__void__setActive__bool);
|
||||
I_SimpleProperty(bool, Done,
|
||||
__bool__getDone,
|
||||
__void__setDone__bool);
|
||||
|
||||
Reference in New Issue
Block a user