Improvements to reduce number of tests in the visitor and calculate surface area.
Also I include an example based on osgViewer to display the physical properties of a shape loaded from a file.
Geoff
InertiaVisitor
Description: Binary data
#include <osgUtil/InertiaVisitor>
// included as separate file to ensure that InertiaVisitor is compiled into
// libraries.
void InertiaVisitor::apply(osg::Geode& geode) {
osg::NodePath nodePath = getNodePath();
unsigned int i;
osg::Matrix totalmat; // accumulated matrix above this point
for(i=0; i<nodePath.size()-1; ++i)
{
osg::Transform* transform = nodePath[i]->asTransform();
if (transform) { // concatenate to totalmat.
transform->computeLocalToWorldMatrix(totalmat, this);
}
}
for (unsigned int i=0; i<geode.getNumDrawables(); i++) {
osg::Geometry *dr=dynamic_cast<osg::Geometry
*>(geode.getDrawable(i));
if (dr) {
// 200409 use ComputeInertiaTriangleFunctor to
calculate volume, MI etc
osg::TriangleFunctor<ComputeInertiaTriangleFunctor>
inert;
inert.setMatrix(totalmat);
dr->accept(inert);
_m+=inert.getVolume();
_Cx+=inert.getCx();
_Cy+=inert.getCy();
_Cz+=inert.getCz();
_xx+=inert.getixx();
_yy+=inert.getiyy();
_zz+=inert.getizz();
_zx+=inert.getizx();
_yx+=inert.getiyx();
_zy+=inert.getizy();
Area+=inert.getArea();
ntris+=inert.getntris();
osg::Vec2 xr=inert.getXrange();
if (xr.x()<xmin) xmin=xr.x();
if (xr.y()>xmax) xmax=xr.y();
osg::Vec2 yr=inert.getYrange();
if (yr.x()<ymin) ymin=yr.x();
if (yr.y()>ymax) ymax=yr.y();
osg::Vec2 zr=inert.getZrange();
if (zr.x()<zmin) zmin=zr.x();
if (zr.y()>zmax) zmax=zr.y();
}
}
finish(); // construct the actual Inertia from the partial sums.
}
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial applications,
* as long as this copyright notice is maintained.* * This application 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.
*/
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>
#include <osg/Switch>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgUtil/InertiaVisitor>
#include <iostream>
#include <sstream>
/* osginertiaviewer - loads an object and displays it (direct copy of osgviewer
application)
* AND calculates the volume, centre of gravity and moments of inertia (around
the CG).
* Use parallel axis theorem for any other rotation point.
* The calculated volume & moments of inertia need to be multiplied by density
to give mass and
* true MI (to be used in a dynamics sumulation).
* Also the MI calculation assumes that the object displayed is:
* i) a closed surface or sirfaces - no holes in hte surface
* ii) is of constant density throughout (shells such as tennis balls need to
have their
* inner wall modelled to get an accurate value.
*/
// borrowed from osgfont.cpp
osg::Camera* createOrthoCamera(double width, double height)
{
osg::Camera* camera = new osg::Camera();
camera->getOrCreateStateSet()->setMode(
GL_LIGHTING,
osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF
);
osg::Matrix m = osg::Matrix::ortho2D(0.0f, width, 0.0f, height);
camera->setProjectionMatrix(m);
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setViewMatrix(osg::Matrix::identity());
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
camera->setRenderOrder(osg::Camera::POST_RENDER);
return camera;
}
osgText::Text* createLabel(const std::string& l, osgText::Font* font, unsigned
int size)
// borrowed and modified from osgfont.cpp
{
static osg::Vec3 pos(0.0f, 160.0f, 0.0f);
osgText::Text* label = new osgText::Text();
label->setFont(font);
label->setCharacterSize(size);
label->setFontResolution(size, size);
label->setColor(osg::Vec4(1.0f, 1.0f, .5f, 1.0f));
label->setPosition(pos);
label->setAlignment(osgText::Text::LEFT_BOTTOM);
label->setAxisAlignment(osgText::Text::SCREEN);
label->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
label->setText(l);
pos.y() -= size*.75f;
return label;
}
int main(int argc, char** argv)
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+"
is an OpenSceneGraph example to load and visualise a 3d model and calculate its Mass, centre
of gravity and Moments of Inertia.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+"
[options] filename ...");
osgViewer::Viewer viewer(arguments);
unsigned int helpType = 0;
if ((helpType = arguments.readHelpType()))
{
arguments.getApplicationUsage()->write(std::cout, helpType);
return 1;
}
// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
if (arguments.argc()<=1)
{
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}
std::string url, username, password;
while(arguments.read("--login",url, username, password))
{
if (!osgDB::Registry::instance()->getAuthenticationMap())
{
osgDB::Registry::instance()->setAuthenticationMap(new
osgDB::AuthenticationMap);
osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(
url,
new osgDB::AuthenticationDetails(username, password)
);
}
}
// set up the camera manipulators.
{
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator =
new osgGA::KeySwitchMatrixManipulator;
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new
osgGA::TrackballManipulator() );
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new
osgGA::FlightManipulator() );
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new
osgGA::DriveManipulator() );
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new
osgGA::TerrainManipulator() );
std::string pathfile;
char keyForAnimationPath = '5';
while (arguments.read("-p",pathfile))
{
osgGA::AnimationPathManipulator* apm = new
osgGA::AnimationPathManipulator(pathfile);
if (apm || !apm->valid())
{
unsigned int num =
keyswitchManipulator->getNumMatrixManipulators();
keyswitchManipulator->addMatrixManipulator( keyForAnimationPath,
"Path", apm );
keyswitchManipulator->selectMatrixManipulator(num);
++keyForAnimationPath;
}
}
viewer.setCameraManipulator( keyswitchManipulator.get() );
}
// add the state manipulator
viewer.addEventHandler( new
osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
// add the thread model handler
viewer.addEventHandler(new osgViewer::ThreadingHandler); // add the window size toggle handler viewer.addEventHandler(new osgViewer::WindowSizeHandler);// add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler); // add the help handler viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage())); // add the record camera path handler viewer.addEventHandler(new osgViewer::RecordCameraPathHandler); // add the LOD Scale handler viewer.addEventHandler(new osgViewer::LODScaleHandler); // add the screen capture handler viewer.addEventHandler(new osgViewer::ScreenCaptureHandler); // load the data osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);if (!loadedModel) {
std::cout << arguments.getApplicationName() <<": No data loaded" <<
std::endl;
return 1;
}
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occurred when parsing the program
arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// optimize the scene graph, remove redundant nodes and state etc.
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel.get());
osg::Group* toplevel = new osg::Group(); // overall holder
toplevel->addChild(loadedModel.get());
{
InertiaVisitor inert;
// automatically called: inert.zeroInertiaTensor(); // call if
reusing
loadedModel->accept(inert);
osg::Vec2 xr=inert.getXrange();
osg::Vec2 yr=inert.getYrange();
osg::Vec2 zr=inert.getZrange();
osg::Vec3 centreOfGravity=inert.getCentroid();
osg::notify(osg::WARN) << "* MI sizes " << xr.y()-xr.x()<< ","<<yr.y()-yr.x()<<
","<<zr.y()-zr.x() << std::endl;
osg::notify(osg::WARN) << "* MI dxx " << xr.x()<< ","<<xr.y()<<
std::endl;
osg::notify(osg::WARN) << "* MI dyy " << yr.x()<< ","<<yr.y()<<
std::endl;
osg::notify(osg::WARN) << "* MI dzz " << zr.x()<< ","<<zr.y()<<
std::endl;
osg::notify(osg::WARN) << "* MI volume " <<
inert.getVolume()<<std::endl;
osg::notify(osg::WARN) << "* Surface Area " <<
inert.getArea()<<std::endl;
osg::notify(osg::WARN) << "* C gravity " << centreOfGravity.x() <<","<<centreOfGravity.y()
<<","<<centreOfGravity.z() << std::endl;
osg::Matrix inertia=inert.getInertiaTensor();
osg::notify(osg::WARN) << "* MI tensor " << inertia(0,0) << " "<< inertia(1,0) <<
" "<< inertia(2,0) << std::endl;
osg::notify(osg::WARN) << "* MI tensor " << inertia(0,1) << " "<< inertia(1,1) <<
" "<< inertia(2,1) << std::endl;
osg::notify(osg::WARN) << "* MI tensor " << inertia(0,2) << " "<< inertia(1,2) <<
" "<< inertia(2,2) << std::endl;
unsigned int size=28; // size of text.
osg::Camera* camera = createOrthoCamera(1280.0f, 1024.0f);
osgText::Font* font = osgText::readFontFile("fonts/arial.ttf");
osg::Geode* geode = new osg::Geode(); // for text display of
inertia
std::stringstream strvol;
strvol.setf(std::ios::fixed,std::ios::floatfield); //
floatfield set to fixed
strvol.precision(5);
strvol.str("Inertia:");
for (int ic = 0 ; ic<argc ; ic++) {
strvol<<" " << osgDB::getSimpleFileName(argv[ic]);
}
geode->addDrawable(createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"Volume " << inert.getVolume() << " Area "<<
inert.getArea();
geode->addDrawable(createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"Sizes " << xr.y()-xr.x()<< ","<<yr.y()-yr.x()<<
","<<zr.y()-zr.x();
geode->addDrawable(createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"C gravity " << centreOfGravity.x() <<","<<centreOfGravity.y()
<<","<<centreOfGravity.z();
geode->addDrawable( createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"MI tensor " << inertia(0,0) << " "<< inertia(0,1) << "
"<< inertia(0,2);
geode->addDrawable( createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"MI tensor " << inertia(1,0) << " "<< inertia(1,1) << "
"<< inertia(1,2);
geode->addDrawable( createLabel(strvol.str(), font, size));
strvol.str("");
strvol<<"MI tensor " << inertia(2,0) << " "<< inertia(2,1) << "
"<< inertia(2,2);
geode->addDrawable( createLabel(strvol.str(), font, size));
camera->addChild(geode);
toplevel->addChild(camera);
}
viewer.setSceneData( toplevel );
viewer.realize();
return viewer.run();
}
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
