Celestia
1// frametree.cpp
2//
3// Reference frame tree
4//
5// Copyright (C) 2008, the Celestia Development Team
6// Initial version by Chris Laurel, claurel@gmail.com
7//
8// This program is free software; you can redistribute it and/or
9// modify it under the terms of the GNU General Public License
10// as published by the Free Software Foundation; either version 2
11// of the License, or (at your option) any later version.
12
13#include <algorithm>14#include <cassert>15#include "celengine/frametree.h"16#include "celengine/timeline.h"17#include "celengine/timelinephase.h"18#include "celengine/frame.h"19#include <celengine/star.h>20#include <celengine/location.h>21#include <celengine/deepskyobj.h>22
23/* A FrameTree is hierarchy of solar system bodies organized according to
24* the relationship of their reference frames. An object will appear in as
25* a child in the tree of whatever object is the center of its orbit frame.
26* Since an object may have several orbit frames in its timeline, the
27* structure is a bit more complicated than a straightforward tree
28* of Body objects. A Body has exactly a single parent in the frame tree
29* at a given time, but may have many over it's lifespan. An object's
30* timeline contains a list of timeline phases; each phase can point to
31* a different parent. Thus, the timeline can be thought of as a list of
32* parents.
33*
34* The FrameTree hiearchy is designed for fast visibility culling. There are
35* two values stored in each node for this purpose: the bounding sphere
36* radius, and the maximum child object radius. The bounding sphere is large
37* enough to contain the orbits of all child objects, as well as the child
38* objects themselves. Change tracking is performed whenever the frame tree
39* is modified: adding a node, removing a node, or changing the radius of an
40* object will all cause the tree to be marked as changed.
41*/
42
43using namespace std;44
45/*! Create a frame tree associated with a star.
46*/
47FrameTree::FrameTree(Star* star) :48starParent(star),49bodyParent(nullptr),50m_changed(true),51// Default frame for a star is J2000 ecliptical, centered52// on the star.53defaultFrame(new J2000EclipticFrame(Selection(star)))54{
55}
56
57
58/*! Create a frame tree associated with a planet or other solar system body.
59*/
60FrameTree::FrameTree(Body* body) :61starParent(nullptr),62bodyParent(body),63m_changed(true),64// Default frame for a solar system body is the mean equatorial frame of the body.65defaultFrame(new BodyMeanEquatorFrame(Selection(body), Selection(body)))66{
67}
68
69
70/*! Return the default reference frame for the object a frame tree is associated
71* with.
72*/
73const ReferenceFrame::SharedConstPtr&74FrameTree::getDefaultReferenceFrame() const75{
76return defaultFrame;77}
78
79
80/*! Mark this node of the frame hierarchy as changed. The changed flag
81* is propagated up toward the root of the tree.
82*/
83void
84FrameTree::markChanged()85{
86if (!m_changed)87{88m_changed = true;89if (bodyParent != nullptr)90bodyParent->markChanged();91}92}
93
94
95/*! Mark this node of the frame hierarchy as updated. The changed flag
96* is marked false in this node and in all child nodes that
97* were marked changed.
98*/
99void
100FrameTree::markUpdated()101{
102if (m_changed)103{104m_changed = false;105for (const auto &child : children)106child->body()->markUpdated();107}108}
109
110
111/*! Recompute the bounding sphere for this tree and all subtrees marked
112* as having changed. The bounding sphere is large enough to accommodate
113* the orbits (and radii) of all child bodies. This method also recomputes
114* the maximum child radius, secondary illuminator status, and child
115* class mask.
116*/
117void
118FrameTree::recomputeBoundingSphere()119{
120if (m_changed)121{122m_boundingSphereRadius = 0.0;123m_maxChildRadius = 0.0;124m_containsSecondaryIlluminators = false;125m_childClassMask = BodyClassification::EmptyMask;126
127for (const auto &phase : children)128{129double bodyRadius = phase->body()->getRadius();130double r = phase->body()->getCullingRadius() + phase->orbit()->getBoundingRadius();131m_maxChildRadius = max(m_maxChildRadius, bodyRadius);132m_containsSecondaryIlluminators = m_containsSecondaryIlluminators || phase->body()->isSecondaryIlluminator();133m_childClassMask |= phase->body()->getClassification();134
135FrameTree* tree = phase->body()->getFrameTree();136if (tree != nullptr)137{138tree->recomputeBoundingSphere();139r += tree->m_boundingSphereRadius;140m_maxChildRadius = max(m_maxChildRadius, tree->m_maxChildRadius);141m_containsSecondaryIlluminators = m_containsSecondaryIlluminators || tree->containsSecondaryIlluminators();142m_childClassMask |= tree->childClassMask();143}144
145m_boundingSphereRadius = max(m_boundingSphereRadius, r);146}147}148}
149
150
151/*! Add a new phase to this tree.
152*/
153void
154FrameTree::addChild(const TimelinePhase::SharedConstPtr &phase)155{
156children.push_back(phase);157markChanged();158}
159
160
161/*! Remove a phase from the tree. This method does nothing if the specified
162* phase doesn't exist in the tree.
163*/
164void
165FrameTree::removeChild(const TimelinePhase::SharedConstPtr &phase)166{
167auto iter = find(children.begin(), children.end(), phase);168if (iter != children.end())169{170children.erase(iter);171markChanged();172}173}
174
175
176/*! Return the child at the specified index. */
177const TimelinePhase*178FrameTree::getChild(unsigned int n) const179{
180return children[n].get();181}
182
183
184/*! Get the number of immediate children of this tree. */
185unsigned int186FrameTree::childCount() const187{
188return children.size();189}
190