From Neil Salter, added osgSim::SphereSegment and osgSim::ScalarBar, and
osgspheresegment and osgscalarbar, and osgsimulation examples.
This commit is contained in:
38
src/osgSim/ColorRange.cpp
Normal file
38
src/osgSim/ColorRange.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <osgSim/ColorRange>
|
||||
|
||||
using namespace osgSim;
|
||||
|
||||
ColorRange::ColorRange(float min, float max, const std::vector<osg::Vec4>& colors): ScalarsToColors(min,max)
|
||||
{
|
||||
setColors(colors);
|
||||
};
|
||||
|
||||
void ColorRange::setColors(const std::vector<osg::Vec4>& colors)
|
||||
{
|
||||
if(colors.size()>1)
|
||||
{
|
||||
_colors=colors;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to something sensible
|
||||
_colors.push_back(osg::Vec4(1.0,0.0,0.0,1.0)); // R
|
||||
_colors.push_back(osg::Vec4(1.0,1.0,0.0,1.0)); // Y
|
||||
_colors.push_back(osg::Vec4(0.0,1.0,0.0,1.0)); // G
|
||||
_colors.push_back(osg::Vec4(0.0,1.0,1.0,1.0)); // C
|
||||
_colors.push_back(osg::Vec4(0.0,0.0,1.0,1.0)); // B
|
||||
}
|
||||
}
|
||||
|
||||
osg::Vec4 ColorRange::getColor(float scalar) const
|
||||
{
|
||||
if(scalar<getMin()) return _colors.front();
|
||||
if(scalar>getMax()) return _colors.back();
|
||||
|
||||
float r = ((scalar - getMin())/(getMax() - getMin())) * (_colors.size()-1);
|
||||
int lower = static_cast<int>(floor(r));
|
||||
int upper = static_cast<int>(ceil(r));
|
||||
|
||||
osg::Vec4 color = _colors[lower] + ((_colors[upper] - _colors[lower]) * (r-lower));
|
||||
return color;
|
||||
}
|
||||
@@ -3,14 +3,16 @@ include $(TOPDIR)/Make/makedefs
|
||||
|
||||
|
||||
CXXFILES = \
|
||||
ColorRange.cpp\
|
||||
ScalarBar.cpp\
|
||||
ScalarsToColors.cpp\
|
||||
BlinkSequence.cpp\
|
||||
LightPoint.cpp\
|
||||
LightPointDrawable.cpp\
|
||||
LightPointNode.cpp\
|
||||
Sector.cpp\
|
||||
SphereSegment.cpp\
|
||||
Version.cpp\
|
||||
|
||||
# SphereSegment.cpp\
|
||||
|
||||
DEF += -DOSGSIM_LIBRARY
|
||||
|
||||
|
||||
300
src/osgSim/ScalarBar.cpp
Normal file
300
src/osgSim/ScalarBar.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
#include <osgSim/ScalarBar>
|
||||
#include <osgText/Text>
|
||||
#include <osg/Geometry>
|
||||
#include <sstream>
|
||||
|
||||
using namespace osgSim;
|
||||
|
||||
std::string ScalarBar::ScalarPrinter::printScalar(float scalar)
|
||||
{
|
||||
std::stringstream ostr;
|
||||
ostr<<scalar;
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
void ScalarBar::setNumColors(int numColors)
|
||||
{
|
||||
_numColors = numColors;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
int ScalarBar::getNumColors() const
|
||||
{
|
||||
return _numColors;
|
||||
}
|
||||
|
||||
void ScalarBar::setNumLabels(int numLabels)
|
||||
{
|
||||
_numLabels = numLabels;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
int ScalarBar::getNumLabels() const
|
||||
{
|
||||
return _numLabels;
|
||||
}
|
||||
|
||||
void ScalarBar::setScalarsToColors(ScalarsToColors* stc)
|
||||
{
|
||||
_stc = stc;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
const ScalarsToColors* ScalarBar::getScalarsToColors() const
|
||||
{
|
||||
return _stc.get();
|
||||
}
|
||||
|
||||
void ScalarBar::setTitle(const std::string& title)
|
||||
{
|
||||
_title = title;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
std::string ScalarBar::getTitle() const
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
void ScalarBar::setOrientation(ScalarBar::Orientation orientation)
|
||||
{
|
||||
_orientation = orientation;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
ScalarBar::Orientation ScalarBar::getOrientation() const
|
||||
{
|
||||
return _orientation;
|
||||
}
|
||||
|
||||
void ScalarBar::setAspectRatio(float aspectRatio)
|
||||
{
|
||||
_aspectRatio = aspectRatio;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
float ScalarBar::getAspectRatio() const
|
||||
{
|
||||
return _aspectRatio;
|
||||
}
|
||||
|
||||
void ScalarBar::setScalarPrinter(ScalarPrinter* sp)
|
||||
{
|
||||
_sp = sp;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
const ScalarBar::ScalarPrinter* ScalarBar::getScalarPrinter() const
|
||||
{
|
||||
return _sp.get();
|
||||
}
|
||||
|
||||
|
||||
void ScalarBar::setTextProperties(const TextProperties& tp)
|
||||
{
|
||||
_textProperties = tp;
|
||||
createDrawables();
|
||||
}
|
||||
|
||||
const ScalarBar::TextProperties& ScalarBar::getTextProperties() const
|
||||
{
|
||||
return _textProperties;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MaxCoordLess
|
||||
{
|
||||
enum Axis{X_AXIS, Y_AXIS, Z_AXIS};
|
||||
Axis _axis;
|
||||
|
||||
MaxCoordLess(Axis axis): _axis(axis) {}
|
||||
|
||||
bool operator()(const osgText::Text* d1, const osgText::Text* d2)
|
||||
{
|
||||
if(_axis == X_AXIS ) return d1->getBound().xMax() < d2->getBound().xMax();
|
||||
else if(_axis == Y_AXIS) return d1->getBound().yMax() < d2->getBound().yMax();
|
||||
else if(_axis == Z_AXIS) return d1->getBound().zMax() < d2->getBound().zMax();
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct AlignCentreOnYValue
|
||||
{
|
||||
float _y;
|
||||
AlignCentreOnYValue(float y): _y(y) {}
|
||||
void operator()(osgText::Text* t)
|
||||
{
|
||||
t->setPosition(osg::Vec3(t->getBound().center().x(), _y, t->getBound().center().z()));
|
||||
t->setAlignment(osgText::Text::CENTER_CENTER);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void ScalarBar::createDrawables()
|
||||
{
|
||||
// Remove any existing Drawables
|
||||
_drawables.erase(_drawables.begin(), _drawables.end());
|
||||
|
||||
// 1. First the bar
|
||||
// =================
|
||||
osg::ref_ptr<osg::Geometry> bar = new osg::Geometry();
|
||||
|
||||
// Create the bar - created in 'real' coordinate space the moment,
|
||||
// with xyz values reflecting those of the actual scalar values in play.
|
||||
// FIXME: Consider positioning at origin! Should be easy enough to do.
|
||||
|
||||
// Vertices
|
||||
osg::ref_ptr<osg::Vec3Array> vs(new osg::Vec3Array);
|
||||
vs->reserve(2*(_numColors+1));
|
||||
|
||||
float incr = (_stc->getMax() - _stc->getMin()) / _numColors;
|
||||
float arOffset;
|
||||
if(_orientation==HORIZONTAL)
|
||||
{
|
||||
arOffset = _numColors * incr * _aspectRatio; // Bar height for a horizontal bar
|
||||
}
|
||||
else
|
||||
{
|
||||
arOffset = (_numColors*incr)/_aspectRatio; // Bar width for a vertical bar
|
||||
}
|
||||
|
||||
for(int i=1; i<=_numColors; ++i)
|
||||
{
|
||||
// Make a quad
|
||||
if(_orientation==HORIZONTAL)
|
||||
{
|
||||
vs->push_back(osg::Vec3(_stc->getMin() + (i-1) * incr, 0.0f, 0.0f));
|
||||
vs->push_back(osg::Vec3(_stc->getMin() + (i-1) * incr, arOffset, 0.0f));
|
||||
vs->push_back(osg::Vec3(_stc->getMin() + i * incr, arOffset, 0.0f));
|
||||
vs->push_back(osg::Vec3(_stc->getMin() + i * incr, 0.0f, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
vs->push_back(osg::Vec3(0.0f, _stc->getMin() + (i-1) * incr, 0.0f));
|
||||
vs->push_back(osg::Vec3(arOffset, _stc->getMin() + (i-1) * incr, 0.0f));
|
||||
vs->push_back(osg::Vec3(arOffset, _stc->getMin() + i * incr, 0.0f));
|
||||
vs->push_back(osg::Vec3(0.0f, _stc->getMin() + i * incr, 0.0f));
|
||||
}
|
||||
}
|
||||
bar->setVertexArray(vs.get());
|
||||
|
||||
// Colours
|
||||
osg::ref_ptr<osg::Vec4Array> cs(new osg::Vec4Array);
|
||||
cs->reserve(_numColors);
|
||||
const float halfIncr = incr*0.5;
|
||||
for(int i=0; i<_numColors; ++i)
|
||||
{
|
||||
// We add half an increment to the color look-up to get the color
|
||||
// square in the middle of the 'block'.
|
||||
cs->push_back(_stc->getColor(_stc->getMin() + (i*incr) + halfIncr));
|
||||
}
|
||||
bar->setColorArray(cs.get());
|
||||
bar->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE);
|
||||
|
||||
// Normal
|
||||
osg::ref_ptr<osg::Vec3Array> ns(new osg::Vec3Array);
|
||||
ns->push_back(osg::Vec3(0.0f,0.0f,1.0f));
|
||||
bar->setNormalArray(ns.get());
|
||||
bar->setNormalBinding(osg::Geometry::BIND_OVERALL);
|
||||
|
||||
// The Quad strip that represents the bar
|
||||
bar->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,vs->size()));
|
||||
|
||||
addDrawable(bar.get());
|
||||
|
||||
// 2. Then the text labels
|
||||
// =======================
|
||||
|
||||
// Check the character size, if it's 0, estimate a good character size
|
||||
float characterSize = _textProperties._characterSize;
|
||||
if(characterSize == 0) characterSize = ((_stc->getMax()-_stc->getMin())*0.3)/_numLabels;
|
||||
|
||||
osgText::Font* font = osgText::readFontFile(_textProperties._fontFile.c_str());
|
||||
|
||||
std::vector<osgText::Text*> texts(_numLabels); // We'll need to collect pointers to these for later
|
||||
float labelIncr = (_stc->getMax()-_stc->getMin())/(_numLabels-1);
|
||||
for(int i=0; i<_numLabels; ++i)
|
||||
{
|
||||
osgText::Text* text = new osgText::Text;
|
||||
text->setFont(font);
|
||||
text->setColor(_textProperties._color);
|
||||
text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
|
||||
text->setCharacterSize(characterSize);
|
||||
text->setText(_sp->printScalar(_stc->getMin()+(i*labelIncr)));
|
||||
|
||||
if(_orientation == HORIZONTAL)
|
||||
{
|
||||
text->setPosition(osg::Vec3(_stc->getMin() + (i*labelIncr), arOffset, 0.0f));
|
||||
text->setAlignment(osgText::Text::CENTER_BOTTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
text->setPosition(osg::Vec3(arOffset, _stc->getMin() + (i*labelIncr), 0.0f));
|
||||
text->setAlignment(osgText::Text::LEFT_CENTER);
|
||||
}
|
||||
|
||||
addDrawable(text);
|
||||
|
||||
texts[i] = text;
|
||||
}
|
||||
|
||||
// Make sure the text labels are all properly aligned - different words will have a different
|
||||
// vertical alignment depending on the letters used in the labels. E.g. a 'y' has a dangling tail.
|
||||
if(_orientation == HORIZONTAL)
|
||||
{
|
||||
std::vector<osgText::Text*>::iterator maxYIt = max_element(texts.begin(), texts.end(), MaxCoordLess(MaxCoordLess::Y_AXIS));
|
||||
for_each(texts.begin(), texts.end(), AlignCentreOnYValue((*maxYIt)->getBound().center().y()));
|
||||
}
|
||||
|
||||
// 3. And finally the title
|
||||
// ========================
|
||||
|
||||
if(_title != "")
|
||||
{
|
||||
osgText::Text* text = new osgText::Text;
|
||||
text->setFont(font);
|
||||
text->setColor(_textProperties._color);
|
||||
text->setFontResolution(_textProperties._fontResolution.first,_textProperties._fontResolution.second);
|
||||
text->setCharacterSize(characterSize);
|
||||
text->setText(_title);
|
||||
|
||||
if(_orientation==HORIZONTAL)
|
||||
{
|
||||
// Horizontal bars have the title above the scalar bar and the labels.
|
||||
// Need to move the title above any labels, using maximum y value of the
|
||||
// existing text objects
|
||||
|
||||
std::vector<osgText::Text*>::iterator maxYIt = max_element(texts.begin(), texts.end(), MaxCoordLess(MaxCoordLess::Y_AXIS));
|
||||
|
||||
float titleY;
|
||||
if(maxYIt != texts.end()) titleY = (*maxYIt)->getBound().yMax() * 1.1f;
|
||||
else titleY = arOffset; // No labels, so just use arOffset
|
||||
|
||||
// Position the title at the middle of the bar above any labels.
|
||||
text->setPosition(osg::Vec3(_stc->getMin() + ((_stc->getMax()-_stc->getMin())/2.0f), titleY, 0.0f));
|
||||
text->setAlignment(osgText::Text::CENTER_BOTTOM);
|
||||
}
|
||||
else if(_orientation==VERTICAL)
|
||||
{
|
||||
// Vertical bars have the title to the right of the scalar bar and the labels.
|
||||
// Need to move the title out beyond any labels, using the maximum x value of the
|
||||
// existing text objects
|
||||
|
||||
std::vector<osgText::Text*>::iterator maxXIt = max_element(texts.begin(), texts.end(), MaxCoordLess(MaxCoordLess::X_AXIS));
|
||||
|
||||
float titleX;
|
||||
if(maxXIt != texts.end()) titleX = (*maxXIt)->getBound().xMax() * 1.1f;
|
||||
else titleX = arOffset; // No labels, so just use arOffset
|
||||
|
||||
// Position the title in the at the middle of the bar, to the right of any labels.
|
||||
text->setPosition(osg::Vec3(titleX, _stc->getMin() + ((_stc->getMax()-_stc->getMin())/2.0f), 0.0f));
|
||||
text->setAlignment(osgText::Text::LEFT_CENTER);
|
||||
}
|
||||
|
||||
addDrawable(text);
|
||||
}
|
||||
}
|
||||
26
src/osgSim/ScalarsToColors.cpp
Normal file
26
src/osgSim/ScalarsToColors.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <osgSim/ScalarsToColors>
|
||||
|
||||
using namespace osgSim;
|
||||
|
||||
ScalarsToColors::ScalarsToColors(float scalarMin, float scalarMax): _min(scalarMin), _max(scalarMax)
|
||||
{
|
||||
}
|
||||
|
||||
osg::Vec4 ScalarsToColors::getColor(float scalar) const
|
||||
{
|
||||
if(scalar<_min) return osg::Vec4(0.0f,0.0f,0.0f,0.0f);
|
||||
if(scalar>_max) return osg::Vec4(0.0f,0.0f,0.0f,0.0f);
|
||||
|
||||
float c = (_min+scalar)/(_max-_min);
|
||||
return osg::Vec4(c,c,c,1.0);
|
||||
}
|
||||
|
||||
float ScalarsToColors::getMin() const
|
||||
{
|
||||
return _min;
|
||||
}
|
||||
|
||||
float ScalarsToColors::getMax() const
|
||||
{
|
||||
return _max;
|
||||
}
|
||||
757
src/osgSim/SphereSegment.cpp
Normal file
757
src/osgSim/SphereSegment.cpp
Normal file
@@ -0,0 +1,757 @@
|
||||
#include <osgSim/SphereSegment>
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osgSim;
|
||||
|
||||
// Define the collection of nested classes, all Drawables, which make
|
||||
// up the parts of the sphere segment.
|
||||
|
||||
/**
|
||||
SphereSegment::Surface is the Drawable which represents the specified area of the
|
||||
sphere's surface.
|
||||
*/
|
||||
class SphereSegment::Surface: public osg::Drawable
|
||||
{
|
||||
public:
|
||||
Surface(SphereSegment* ss): Drawable(), _ss(ss) {}
|
||||
|
||||
Surface():_ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Surface() default constructor"<<std::endl;
|
||||
}
|
||||
|
||||
Surface(const Surface& rhs, const osg::CopyOp& co=osg::CopyOp::SHALLOW_COPY):Drawable(*this,co), _ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Surface() copy constructor"<<std::endl;
|
||||
}
|
||||
|
||||
META_Object(osgSim,Surface)
|
||||
|
||||
void drawImplementation(osg::State& state) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool computeBound() const;
|
||||
|
||||
private:
|
||||
|
||||
SphereSegment* _ss;
|
||||
};
|
||||
|
||||
void SphereSegment::Surface::drawImplementation(osg::State& state) const
|
||||
{
|
||||
_ss->Surface_drawImplementation(state);
|
||||
}
|
||||
|
||||
bool SphereSegment::Surface::computeBound() const
|
||||
{
|
||||
_bbox_computed = _ss->Surface_computeBound(_bbox);
|
||||
return _bbox_computed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
SphereSegment::EdgeLine is the Drawable which represents the line around the edge
|
||||
of the specified area of the sphere's EdgeLine.
|
||||
*/
|
||||
class SphereSegment::EdgeLine: public osg::Drawable
|
||||
{
|
||||
public:
|
||||
EdgeLine(SphereSegment* ss): Drawable(), _ss(ss) {}
|
||||
|
||||
EdgeLine():_ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::EdgeLine() default constructor"<<std::endl;
|
||||
}
|
||||
|
||||
EdgeLine(const EdgeLine& rhs, const osg::CopyOp& co=osg::CopyOp::SHALLOW_COPY):Drawable(*this,co), _ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::EdgeLine() copy constructor"<<std::endl;
|
||||
}
|
||||
|
||||
META_Object(osgSim,EdgeLine)
|
||||
|
||||
void drawImplementation(osg::State& state) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool computeBound() const;
|
||||
|
||||
private:
|
||||
|
||||
SphereSegment* _ss;
|
||||
};
|
||||
|
||||
void SphereSegment::EdgeLine::drawImplementation(osg::State& state) const
|
||||
{
|
||||
_ss->EdgeLine_drawImplementation(state);
|
||||
}
|
||||
|
||||
bool SphereSegment::EdgeLine::computeBound() const
|
||||
{
|
||||
_bbox_computed = _ss->EdgeLine_computeBound(_bbox);
|
||||
return _bbox_computed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
SphereSegment::Plane is a Drawable which represents one of the
|
||||
planar areas, at either the minimum or maxium azimuth.
|
||||
*/
|
||||
class SphereSegment::Plane: public osg::Drawable
|
||||
{
|
||||
public:
|
||||
Plane(SphereSegment* ss, SphereSegment::PlaneOrientation po, SphereSegment::BoundaryAngle pa):
|
||||
Drawable(), _ss(ss), _planeOrientation(po), _BoundaryAngle(pa) {}
|
||||
|
||||
Plane():_ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Plane() default constructor"<<std::endl;
|
||||
}
|
||||
|
||||
Plane(const Plane& rhs, const osg::CopyOp& co=osg:: CopyOp::SHALLOW_COPY): Drawable(*this,co), _ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Plane() copy constructor"<<std::endl;
|
||||
}
|
||||
|
||||
META_Object(osgSim,Plane)
|
||||
|
||||
void drawImplementation(osg::State& state) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool computeBound() const;
|
||||
|
||||
private:
|
||||
SphereSegment* _ss;
|
||||
SphereSegment::PlaneOrientation _planeOrientation;
|
||||
SphereSegment::BoundaryAngle _BoundaryAngle;
|
||||
};
|
||||
|
||||
|
||||
void SphereSegment::Plane::drawImplementation(osg::State& state) const
|
||||
{
|
||||
_ss->Plane_drawImplementation(state, _planeOrientation, _BoundaryAngle);
|
||||
}
|
||||
|
||||
bool SphereSegment::Plane::computeBound() const
|
||||
{
|
||||
_bbox_computed = _ss->Plane_computeBound(_bbox, _planeOrientation, _BoundaryAngle);
|
||||
return _bbox_computed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
SphereSegment::Spoke is a Drawable which represents a spoke.
|
||||
*/
|
||||
class SphereSegment::Spoke: public osg::Drawable
|
||||
{
|
||||
public:
|
||||
Spoke(SphereSegment* ss, SphereSegment::BoundaryAngle azAngle, SphereSegment::BoundaryAngle elevAngle):
|
||||
Drawable(), _ss(ss), _azAngle(azAngle), _elevAngle(elevAngle) {}
|
||||
|
||||
Spoke():_ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Spoke() default constructor"<<std::endl;
|
||||
}
|
||||
|
||||
Spoke(const Spoke& rhs, const osg::CopyOp& co=osg:: CopyOp::SHALLOW_COPY): Drawable(*this,co), _ss(0)
|
||||
{
|
||||
osg::notify(osg::WARN)<<
|
||||
"Warning: unexpected call to osgSim::SphereSegment::Spoke() copy constructor"<<std::endl;
|
||||
}
|
||||
|
||||
META_Object(osgSim,Spoke)
|
||||
|
||||
void drawImplementation(osg::State& state) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool computeBound() const;
|
||||
|
||||
private:
|
||||
SphereSegment* _ss;
|
||||
SphereSegment::BoundaryAngle _azAngle, _elevAngle;
|
||||
};
|
||||
|
||||
void SphereSegment::Spoke::drawImplementation(osg::State& state) const
|
||||
{
|
||||
_ss->Spoke_drawImplementation(state, _azAngle, _elevAngle);
|
||||
}
|
||||
|
||||
bool SphereSegment::Spoke::computeBound() const
|
||||
{
|
||||
_bbox_computed = _ss->Spoke_computeBound(_bbox, _azAngle, _elevAngle);
|
||||
return _bbox_computed;
|
||||
}
|
||||
|
||||
SphereSegment::SphereSegment(const osg::Vec3& centre, float radius, const osg::Vec3& vec, float azRange,
|
||||
float elevRange, int density):
|
||||
Geode(),
|
||||
_centre(centre), _radius(radius),
|
||||
_density(density),
|
||||
_drawMask(DrawMask(ALL))
|
||||
{
|
||||
// Rather than store the vector, we'll work out the azimuth boundaries and elev
|
||||
// boundaries now, rather than at draw time.
|
||||
setArea(vec, azRange, elevRange);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
void SphereSegment::setCentre(const osg::Vec3& c)
|
||||
{
|
||||
_centre = c;
|
||||
dirtyAllDrawableDisplayLists();
|
||||
dirtyAllDrawableBounds();
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
const osg::Vec3& SphereSegment::getCentre() const
|
||||
{
|
||||
return _centre;
|
||||
}
|
||||
|
||||
void SphereSegment::setRadius(float r)
|
||||
{
|
||||
_radius = r;
|
||||
dirtyAllDrawableDisplayLists();
|
||||
dirtyAllDrawableBounds();
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
float SphereSegment::getRadius() const
|
||||
{
|
||||
return _radius;
|
||||
}
|
||||
|
||||
|
||||
void SphereSegment::setArea(const osg::Vec3& v, float azRange, float elevRange)
|
||||
{
|
||||
osg::Vec3 vec(v);
|
||||
|
||||
vec.normalize(); // Make sure we're unit length
|
||||
|
||||
// Calculate the elevation range
|
||||
float elev = asin(vec.z()); // Elevation angle
|
||||
elevRange /= 2.0f;
|
||||
_elevMin = elev - elevRange;
|
||||
_elevMax = elev + elevRange;
|
||||
|
||||
// Calculate the azimuth range, cater for trig ambiguities
|
||||
float xyLen = cos(elev);
|
||||
float az;
|
||||
if(vec.x() != 0.0f) az = asin(vec.x()/xyLen);
|
||||
else az = acos(vec.y()/xyLen);
|
||||
|
||||
azRange /= 2.0f;
|
||||
_azMin = az - azRange;
|
||||
_azMax = az + azRange;
|
||||
|
||||
dirtyAllDrawableDisplayLists();
|
||||
dirtyAllDrawableBounds();
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
void SphereSegment::getArea(osg::Vec3& vec, float& azRange, float& elevRange) const
|
||||
{
|
||||
azRange = _azMax - _azMin;
|
||||
elevRange = _elevMax - _elevMin;
|
||||
|
||||
float az = azRange/2.0f;
|
||||
float elev = elevRange/2.0f;
|
||||
vec.set(cos(elev)*sin(az), cos(elev)*cos(az), sin(elev));
|
||||
}
|
||||
|
||||
void SphereSegment::setDensity(int density)
|
||||
{
|
||||
_density = density;
|
||||
dirtyAllDrawableDisplayLists();
|
||||
}
|
||||
|
||||
int SphereSegment::getDensity() const
|
||||
{
|
||||
return _density;
|
||||
}
|
||||
|
||||
void SphereSegment::init()
|
||||
{
|
||||
addDrawable(new Surface(this));
|
||||
|
||||
addDrawable(new EdgeLine(this));
|
||||
|
||||
addDrawable(new Plane(this,AZIM,MIN));
|
||||
addDrawable(new Plane(this,AZIM,MAX));
|
||||
addDrawable(new Plane(this,ELEV,MIN));
|
||||
addDrawable(new Plane(this,ELEV,MAX));
|
||||
|
||||
addDrawable(new Spoke(this,MIN,MIN));
|
||||
addDrawable(new Spoke(this,MIN,MAX));
|
||||
addDrawable(new Spoke(this,MAX,MIN));
|
||||
addDrawable(new Spoke(this,MAX,MAX));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct DirtyDisplayList
|
||||
{
|
||||
void operator()(osg::ref_ptr<osg::Drawable>& dptr)
|
||||
{
|
||||
dptr->dirtyDisplayList();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void SphereSegment::dirtyAllDrawableDisplayLists()
|
||||
{
|
||||
for_each(_drawables.begin(), _drawables.end(), DirtyDisplayList());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct DirtyBound
|
||||
{
|
||||
void operator()(osg::ref_ptr<osg::Drawable>& dptr)
|
||||
{
|
||||
dptr->dirtyBound();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void SphereSegment::dirtyAllDrawableBounds()
|
||||
{
|
||||
for_each(_drawables.begin(), _drawables.end(), DirtyBound());
|
||||
}
|
||||
|
||||
void SphereSegment::Surface_drawImplementation(osg::State& /* state */) const
|
||||
{
|
||||
const float azIncr = (_azMax - _azMin)/_density;
|
||||
const float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
// Draw the area on the sphere surface if needed
|
||||
// ---------------------------------------------
|
||||
if(_drawMask & SURFACE)
|
||||
{
|
||||
glColor4fv(_surfaceColor.ptr());
|
||||
|
||||
for(int i=0; i+1<=_density; i++)
|
||||
{
|
||||
// Because we're drawing quad strips, we need to work out
|
||||
// two azimuth values, to form each edge of the (z-vertical)
|
||||
// strips
|
||||
float az1 = _azMin + (i*azIncr);
|
||||
float az2 = _azMin + ((i+1)*azIncr);
|
||||
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
|
||||
// QuadStrip Edge formed at az1
|
||||
// ----------------------------
|
||||
|
||||
// Work out the sphere normal
|
||||
float x = cos(elev)*sin(az1);
|
||||
float y = cos(elev)*cos(az1);
|
||||
float z = sin(elev);
|
||||
|
||||
glNormal3f(x, y, z);
|
||||
glVertex3f(_centre.x() + _radius*x,
|
||||
_centre.y() + _radius*y,
|
||||
_centre.z() + _radius*z);
|
||||
|
||||
// QuadStrip Edge formed at az2
|
||||
// ----------------------------
|
||||
|
||||
// Work out the sphere normal
|
||||
x = cos(elev)*sin(az2);
|
||||
y = cos(elev)*cos(az2);
|
||||
// z = sin(elev); z doesn't change
|
||||
|
||||
glNormal3f(x, y, z);
|
||||
glVertex3f(_centre.x() + _radius*x,
|
||||
_centre.y() + _radius*y,
|
||||
_centre.z() + _radius*z);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SphereSegment::Surface_computeBound(osg::BoundingBox& bbox) const
|
||||
{
|
||||
bbox.init();
|
||||
|
||||
float azIncr = (_azMax - _azMin)/_density;
|
||||
float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
for(int i=0; i<=_density; i++){
|
||||
|
||||
float az = _azMin + (i*azIncr);
|
||||
|
||||
for(int j=0; j<=_density; j++){
|
||||
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
|
||||
bbox.expandBy(
|
||||
osg::Vec3(_centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev))
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SphereSegment::EdgeLine_drawImplementation(osg::State& /* state */) const
|
||||
{
|
||||
// FIXME: Disable lighting for this draw routine
|
||||
|
||||
const float azIncr = (_azMax - _azMin)/_density;
|
||||
const float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
// Draw the edgeline if necessary
|
||||
// ------------------------------
|
||||
if(_drawMask & EDGELINE)
|
||||
{
|
||||
glColor4fv(_edgeLineColor.ptr());
|
||||
|
||||
// Top edge
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
glVertex3f(
|
||||
_centre.x() + _radius*cos(_elevMax)*sin(az),
|
||||
_centre.y() + _radius*cos(_elevMax)*cos(az),
|
||||
_centre.z() + _radius*sin(_elevMax));
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Bottom edge
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
glVertex3f(
|
||||
_centre.x() + _radius*cos(_elevMin)*sin(az),
|
||||
_centre.y() + _radius*cos(_elevMin)*cos(az),
|
||||
_centre.z() + _radius*sin(_elevMin));
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Left edge
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
glVertex3f(
|
||||
_centre.x() + _radius*cos(elev)*sin(_azMin),
|
||||
_centre.y() + _radius*cos(elev)*cos(_azMin),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
glEnd();
|
||||
|
||||
// Right edge
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for(int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
glVertex3f(
|
||||
_centre.x() + _radius*cos(elev)*sin(_azMax),
|
||||
_centre.y() + _radius*cos(elev)*cos(_azMax),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
bool SphereSegment::EdgeLine_computeBound(osg::BoundingBox& bbox) const
|
||||
{
|
||||
bbox.init();
|
||||
|
||||
float azIncr = (_azMax - _azMin)/_density;
|
||||
float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
// Top edge
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(_elevMax)*sin(az),
|
||||
_centre.y() + _radius*cos(_elevMax)*cos(az),
|
||||
_centre.z() + _radius*sin(_elevMax));
|
||||
}
|
||||
|
||||
// Bottom edge
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(_elevMin)*sin(az),
|
||||
_centre.y() + _radius*cos(_elevMin)*cos(az),
|
||||
_centre.z() + _radius*sin(_elevMin));
|
||||
}
|
||||
|
||||
// Left edge
|
||||
for(int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(elev)*sin(_azMin),
|
||||
_centre.y() + _radius*cos(elev)*cos(_azMin),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
|
||||
// Right edge
|
||||
for(int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(elev)*sin(_azMax),
|
||||
_centre.y() + _radius*cos(elev)*cos(_azMax),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SphereSegment::Plane_drawImplementation(osg::State& /* state */,
|
||||
SphereSegment::PlaneOrientation orientation,
|
||||
SphereSegment::BoundaryAngle boundaryAngle) const
|
||||
{
|
||||
// Draw the planes if necessary
|
||||
// ----------------------------
|
||||
if(_drawMask & PLANES)
|
||||
{
|
||||
if(orientation == AZIM) // This is a plane at a given azimuth
|
||||
{
|
||||
const float az = (boundaryAngle==MIN?_azMin:_azMax);
|
||||
const float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
// Normal
|
||||
osg::Vec3 normal = osg::Vec3(cos(_elevMin)*sin(az), cos(_elevMin)*cos(az), sin(_elevMin))
|
||||
^ osg::Vec3(cos(_elevMax)*sin(az), cos(_elevMax)*cos(az), sin(_elevMax));
|
||||
if(boundaryAngle==MIN) normal = -normal; // Make sure normals orientationint 'outwards'
|
||||
glNormal3fv(normal.ptr());
|
||||
|
||||
// Tri fan
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3fv(_centre.ptr());
|
||||
for (int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
glVertex3f( _centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
else if(orientation == ELEV) // This is a plane at a given elevation
|
||||
{
|
||||
const float elev = (boundaryAngle==MIN?_elevMin:_elevMax);
|
||||
const float azIncr = (_azMax - _azMin)/_density;
|
||||
|
||||
// Normal
|
||||
osg::Vec3 normal = osg::Vec3(cos(elev)*sin(_azMax), cos(elev)*cos(_azMax), sin(elev))
|
||||
^ osg::Vec3(cos(elev)*sin(_azMin), cos(elev)*cos(_azMin), sin(elev));
|
||||
if(boundaryAngle==MIN) normal = -normal; // Make sure normals orientationint 'outwards'
|
||||
glNormal3fv(normal.ptr());
|
||||
|
||||
// Tri fan
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3fv(_centre.ptr());
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
glVertex3f( _centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SphereSegment::Plane_computeBound(osg::BoundingBox& bbox,
|
||||
SphereSegment::PlaneOrientation orientation,
|
||||
SphereSegment::BoundaryAngle boundaryAngle) const
|
||||
{
|
||||
bbox.init();
|
||||
bbox.expandBy(_centre);
|
||||
|
||||
if(orientation == AZIM) // This is a plane at a given azimuth
|
||||
{
|
||||
const float az = (boundaryAngle==MIN?_azMin:_azMax);
|
||||
const float elevIncr = (_elevMax - _elevMin)/_density;
|
||||
|
||||
for (int j=0; j<=_density; j++)
|
||||
{
|
||||
float elev = _elevMin + (j*elevIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
}
|
||||
else if(orientation == ELEV) // This is a plane at a given elevation
|
||||
{
|
||||
const float elev = (boundaryAngle==MIN?_elevMin:_elevMax);
|
||||
const float azIncr = (_azMax - _azMin)/_density;
|
||||
|
||||
for(int i=0; i<=_density; i++)
|
||||
{
|
||||
float az = _azMin + (i*azIncr);
|
||||
bbox.expandBy(
|
||||
_centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SphereSegment::Spoke_drawImplementation(osg::State&, BoundaryAngle azAngle, BoundaryAngle elevAngle) const
|
||||
{
|
||||
// FIXME: Disable lighting for this draw routine
|
||||
|
||||
if(_drawMask & SPOKES){
|
||||
|
||||
glColor4fv(_spokeColor.ptr());
|
||||
|
||||
const float az = (azAngle==MIN?_azMin:_azMax);
|
||||
const float elev = (elevAngle==MIN?_elevMin:_elevMax);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex3fv(_centre.ptr());
|
||||
glVertex3f( _centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
bool SphereSegment::Spoke_computeBound(osg::BoundingBox& bbox, BoundaryAngle azAngle, BoundaryAngle elevAngle) const
|
||||
{
|
||||
const float az = (azAngle==MIN?_azMin:_azMax);
|
||||
const float elev = (elevAngle==MIN?_elevMin:_elevMax);
|
||||
|
||||
bbox.expandBy(_centre);
|
||||
bbox.expandBy( _centre.x() + _radius*cos(elev)*sin(az),
|
||||
_centre.y() + _radius*cos(elev)*cos(az),
|
||||
_centre.z() + _radius*sin(elev));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SphereSegment::setDrawMask(DrawMask dm)
|
||||
{
|
||||
_drawMask=dm;
|
||||
dirtyAllDrawableDisplayLists();
|
||||
dirtyAllDrawableBounds();
|
||||
dirtyBound();
|
||||
}
|
||||
|
||||
namespace{
|
||||
|
||||
struct ActivateTransparencyOnType
|
||||
{
|
||||
ActivateTransparencyOnType(const std::type_info& t): _t(t) {}
|
||||
|
||||
void operator()(osg::ref_ptr<osg::Drawable>& dptr) const
|
||||
{
|
||||
if(typeid(*dptr)==_t)
|
||||
{
|
||||
osg::StateSet* ss = dptr->getStateSet();
|
||||
if(!ss)
|
||||
{
|
||||
ss = new osg::StateSet();
|
||||
dptr->setStateSet(ss);
|
||||
}
|
||||
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
|
||||
osg::BlendFunc* trans = new osg::BlendFunc;
|
||||
trans->setFunction(osg::BlendFunc::ONE,osg::BlendFunc::ONE);
|
||||
|
||||
ss->setAttributeAndModes(trans,osg::StateAttribute::ON);
|
||||
|
||||
dptr->dirtyDisplayList();
|
||||
}
|
||||
}
|
||||
|
||||
const std::type_info& _t;
|
||||
};
|
||||
|
||||
struct DeactivateTransparencyOnType
|
||||
{
|
||||
DeactivateTransparencyOnType(const std::type_info& t): _t(t) {}
|
||||
|
||||
void operator()(osg::ref_ptr<osg::Drawable>& dptr) const
|
||||
{
|
||||
if(typeid(*dptr)==_t)
|
||||
{
|
||||
osg::StateSet* ss = dptr->getStateSet();
|
||||
if(ss) ss->setRenderingHint(osg::StateSet::OPAQUE_BIN);
|
||||
|
||||
dptr->dirtyDisplayList();
|
||||
}
|
||||
}
|
||||
|
||||
const std::type_info& _t;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void SphereSegment::setSurfaceColor(const osg::Vec4& c)
|
||||
{
|
||||
_surfaceColor=c;
|
||||
|
||||
if(c.w() != 1.0) for_each(_drawables.begin(), _drawables.end(), ActivateTransparencyOnType(typeid(Surface)));
|
||||
else for_each(_drawables.begin(), _drawables.end(), DeactivateTransparencyOnType(typeid(Surface)));
|
||||
}
|
||||
|
||||
void SphereSegment::setSpokeColor(const osg::Vec4& c)
|
||||
{
|
||||
_spokeColor=c;
|
||||
|
||||
if(c.w() != 1.0) for_each(_drawables.begin(), _drawables.end(), ActivateTransparencyOnType(typeid(Spoke)));
|
||||
else for_each(_drawables.begin(), _drawables.end(), DeactivateTransparencyOnType(typeid(Spoke)));
|
||||
}
|
||||
|
||||
void SphereSegment::setEdgeLineColor(const osg::Vec4& c)
|
||||
{
|
||||
_edgeLineColor=c;
|
||||
|
||||
if(c.w() != 1.0) for_each(_drawables.begin(), _drawables.end(), ActivateTransparencyOnType(typeid(EdgeLine)));
|
||||
else for_each(_drawables.begin(), _drawables.end(), DeactivateTransparencyOnType(typeid(EdgeLine)));
|
||||
}
|
||||
|
||||
void SphereSegment::setPlaneColor(const osg::Vec4& c)
|
||||
{
|
||||
_planeColor=c;
|
||||
|
||||
if(c.w() != 1.0) for_each(_drawables.begin(), _drawables.end(), ActivateTransparencyOnType(typeid(Plane)));
|
||||
else for_each(_drawables.begin(), _drawables.end(), DeactivateTransparencyOnType(typeid(Plane)));
|
||||
}
|
||||
|
||||
void SphereSegment::setAllColors(const osg::Vec4& c)
|
||||
{
|
||||
setSurfaceColor(c);
|
||||
setSpokeColor(c);
|
||||
setEdgeLineColor(c);
|
||||
setPlaneColor(c);
|
||||
}
|
||||
Reference in New Issue
Block a user