Files
OpenSpace/src/scenegraph/scenegraphnode.cpp
2014-02-18 16:26:54 -05:00

258 lines
6.6 KiB
C++

// open space includes
#include "scenegraph/scenegraphnode.h"
#include "util/spice.h"
// ghoul includes
#include "ghoul/logging/logmanager.h"
#include "ghoul/logging/consolelog.h"
namespace openspace {
SceneGraphNode::SceneGraphNode() {
nodeName_ = "";
// init pointers with nullptr
renderable_ = nullptr;
parent_ = nullptr;
boundingSphereVisible_ = false;
renderableVisible_ = false;
// spice not used when spiceID_ is 0, 0 is the sun barycenter
spiceID_ = 0;
parentSpiceID_ = 0;
}
SceneGraphNode::~SceneGraphNode() {
// logger string
std::string _loggerCat = "SceneGraphNode::~SceneGraphNode()";
LDEBUG("Deallocating: " << nodeName_);
// deallocate the renderable
if(renderable_)
delete renderable_;
// deallocate the child nodes and delete them, iterate c++11 style
for( auto &child: children_) {
delete child;
}
// empty the vector
children_.erase (children_.begin(),children_.end());
}
// essential
void SceneGraphNode::update() {
if(spiceID_ > 0) {
double state[3];
//double orientation[3][3];
Spice::ref().spk_getPosition(spiceID_, parentSpiceID_, state);
// multiply with factor 1000, spice uses km as standard and Open Space uses m
position_ = psc::CreatePSC(state[0]*1000.0,state[1]*1000.0,state[2]*1000.0);
// update rotation
//if(Spice::ref().spk_getOrientation(spiceName_,orientation)) {
// printf("%s\n",spiceName_);
// printf("%.5f %.5f %.5f \n", orientation[0][0], orientation[0][1], orientation[0][2]);
// printf("%.5f %.5f %.5f \n", orientation[1][0], orientation[1][1], orientation[1][2]);
// printf("%.5f %.5f %.5f \n", orientation[2][0], orientation[2][1], orientation[2][2]);
//}
}
if(renderable_) {
renderable_->update();
}
}
void SceneGraphNode::evaluate(const Camera *camera, const psc & parentPosition) {
const psc thisPosition = parentPosition + position_;
const psc camPos = camera->getPosition();
const psc toCamera = thisPosition - camPos;
// init as not visible
boundingSphereVisible_ = true;
renderableVisible_ = false;
// check if camera is outside the node boundingsphere
if(toCamera.length() > boundingSphere_) {
// check if the boudningsphere is visible before avaluating children
if( ! sphereInsideFrustum(thisPosition, boundingSphere_, camera)) {
// the node is completely outside of the camera view, stop evaluating this node
return;
}
}
boundingSphereVisible_ = true;
// inside boudningsphere or parts of the sphere is visible, individual children needs to be evaluated
// this node has an renderable
if(renderable_) {
// check if the renderable boundingsphere is visible
renderableVisible_ = sphereInsideFrustum(thisPosition, renderable_->getBoundingSphere(), camera);
}
// evaluate all the children, tail-recursive function(?)
for(auto &child: children_) {
child->evaluate(camera,thisPosition);
}
}
void SceneGraphNode::render(const Camera *camera, const psc & parentPosition) {
const psc thisPosition = parentPosition + position_;
// check if camera is outside the node boundingsphere
if( ! boundingSphereVisible_) {
return;
}
if(renderableVisible_) {
if (nodeName_ == "earth")
nodeName_ = nodeName_;
renderable_->render(camera,thisPosition);
}
// evaluate all the children, tail-recursive function(?)
for(auto &child: children_) {
child->render(camera,thisPosition);
}
}
// set & get
void SceneGraphNode::addNode(SceneGraphNode *child) {
// add a child node and set this node to be the parent
child->setParent(this);
children_.push_back(child);
}
void SceneGraphNode::setName(const std::string &name) {
nodeName_ = name;
}
void SceneGraphNode::setParent(SceneGraphNode *parent) {
parent_ = parent;
}
void SceneGraphNode::setPosition(const psc &position) {
position_ = position;
}
void SceneGraphNode::setSpiceID(const int spiceID, const int parentSpiceID) {
spiceID_ = spiceID;
parentSpiceID_ = parentSpiceID;
update();
}
void SceneGraphNode::setSpiceName(const std::string &name) {
spiceName_ = name;
}
const int SceneGraphNode::getSpiceID() const {
return spiceID_;
}
const std::string & SceneGraphNode::getSpiceName() {
return spiceName_;
}
const psc &SceneGraphNode::getPosition() const {
return position_;
}
psc SceneGraphNode::getWorldPosition() const {
// recursive up the hierarchy if there are parents available
if(parent_) {
return position_ + parent_->getWorldPosition();
} else {
return position_;
}
}
// bounding sphere
pss SceneGraphNode::calculateBoundingSphere() {
// set the vounding sphere to 0.0
boundingSphere_ = 0.0;
if(children_.size() > 0) { // node
pss maxChild;
// loop though all children and find the one furthest away/with the largest bounding sphere
for(size_t i = 0; i < children_.size(); ++i) {
// when positions is dynamix, change this part to fins the most distant position
pss child = children_.at(i)->getPosition().length() + children_.at(i)->calculateBoundingSphere();
if(child > maxChild) {
maxChild = child;
}
}
boundingSphere_ += maxChild;
} else { // leaf
// if has a renderable, use that boundingsphere
if(renderable_)
boundingSphere_ += renderable_->getBoundingSphere();
}
return boundingSphere_;
}
// renderable
void SceneGraphNode::setRenderable(Renderable *renderable) {
renderable_ = renderable;
update();
}
const Renderable * SceneGraphNode::getRenderable() const{
return renderable_;
}
// private helper methods
bool SceneGraphNode::sphereInsideFrustum(const psc s_pos, const pss & s_rad, const Camera *camera) {
// direction the camera is looking at in power scale
psc psc_camdir = psc(camera->getViewDirection());
// the position of the camera, moved backwards in the view direction to encapsulate the sphere radius
psc U = camera->getPosition() - psc_camdir * s_rad * ( 1.0 / camera->getSinMaxFov());
// the vector to the object from the new position
psc D = s_pos - U;
// check if outside the maximum angle
if (nodeName_ == "earth") {
//psc tmp = s_pos - camera->getPosition();
//LINFOC("", "Angle: " << psc_camdir.angle(D));
//LINFOC("", "Pos: " << tmp.getVec4f()[0] << " " << tmp.getVec4f()[1] << " " << tmp.getVec4f()[2] << " " << tmp.getVec4f()[3]);
}
const double a = psc_camdir.angle(D);
if ( a < camera->getMaxFov())
{
// center is inside K''
D = s_pos - camera->getPosition();
if ( D.length()* psc_camdir.length() *camera->getSinMaxFov() <= -psc_camdir.dot(D)) {
// center is inside K'' and inside K'
return D.length() <= s_rad;
} else {
// center is inside K'' and outside K'
return true;
}
} else {
// outside the maximum angle
return false;
}
}
} // namespace openspace