diff --git a/src/mobility/hierarchical-mobility-model.cc b/src/mobility/hierarchical-mobility-model.cc index 7a129f052..7896a1f82 100644 --- a/src/mobility/hierarchical-mobility-model.cc +++ b/src/mobility/hierarchical-mobility-model.cc @@ -52,15 +52,46 @@ HierarchicalMobilityModel::HierarchicalMobilityModel () void HierarchicalMobilityModel::SetChild (Ptr model) { + Ptr oldChild = m_child; + Vector pos; + if (m_child) + { + pos = GetPosition (); + m_child->TraceDisconnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); + } m_child = model; m_child->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ChildChanged, this)); + + // if we had a child before, then we had a valid position before; + // try to preserve the old absolute position. + if (oldChild) + { + SetPosition (pos); + } } void HierarchicalMobilityModel::SetParent (Ptr model) { + Vector pos; + if (m_child) + { + pos = GetPosition (); + } + if (m_parent) + { + m_parent->TraceDisconnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); + } m_parent = model; - m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); + if (m_parent) + { + m_parent->TraceConnectWithoutContext ("CourseChange", MakeCallback (&HierarchicalMobilityModel::ParentChanged, this)); + } + // try to preserve the old position across parent changes + if (m_child) + { + SetPosition (pos); + } } @@ -79,6 +110,10 @@ HierarchicalMobilityModel::GetParent (void) const Vector HierarchicalMobilityModel::DoGetPosition (void) const { + if (!m_parent) + { + return m_child->GetPosition (); + } Vector parentPosition = m_parent->GetPosition (); Vector childPosition = m_child->GetPosition (); return Vector (parentPosition.x + childPosition.x, @@ -88,27 +123,41 @@ HierarchicalMobilityModel::DoGetPosition (void) const void HierarchicalMobilityModel::DoSetPosition (const Vector &position) { - if (m_parent == 0 || m_child == 0) + if (m_child == 0) { return; } // This implementation of DoSetPosition is really an arbitraty choice. // anything else would have been ok. - Vector parentPosition = m_parent->GetPosition (); - Vector childPosition (position.x - parentPosition.x, - position.y - parentPosition.y, - position.z - parentPosition.z); - m_child->SetPosition (childPosition); + if (m_parent) + { + Vector parentPosition = m_parent->GetPosition (); + Vector childPosition (position.x - parentPosition.x, + position.y - parentPosition.y, + position.z - parentPosition.z); + m_child->SetPosition (childPosition); + } + else + { + m_child->SetPosition (position); + } } Vector HierarchicalMobilityModel::DoGetVelocity (void) const { - Vector parentSpeed = m_parent->GetVelocity (); - Vector childSpeed = m_child->GetVelocity (); - Vector speed (parentSpeed.x + childSpeed.x, - parentSpeed.y + childSpeed.y, - parentSpeed.z + childSpeed.z); - return speed; + if (m_parent) + { + Vector parentSpeed = m_parent->GetVelocity (); + Vector childSpeed = m_child->GetVelocity (); + Vector speed (parentSpeed.x + childSpeed.x, + parentSpeed.y + childSpeed.y, + parentSpeed.z + childSpeed.z); + return speed; + } + else + { + return m_child->GetVelocity (); + } } void diff --git a/src/mobility/hierarchical-mobility-model.h b/src/mobility/hierarchical-mobility-model.h index f2d1cda70..5ef664863 100644 --- a/src/mobility/hierarchical-mobility-model.h +++ b/src/mobility/hierarchical-mobility-model.h @@ -27,8 +27,31 @@ namespace ns3 { /** * \brief a hierachical mobility model. * - * This model allows you to specify the position of a - * child object relative to a parent object. + * This model allows you to specify the position of a child object + * relative to a parent object. + * + * Basically this is a mobility model that combines two other mobility + * models: a "parent" model and a "child" model. The position of the + * hierarchical model is always the vector sum of the parent + child + * positions, so that if the parent model "moves", then this model + * will report an equal relative movement. Useful, for instance, if + * you want to simulate a node inside another node that moves, such as + * a vehicle. + * + * Setting the position on this model is always done using world + * absolute coordinates, and it changes only the child mobility model + * position, never the parent. The child mobility model always uses a + * coordinate sytem relative to the parent model position. + * + * @note: as a special case, the parent model may be NULL, which is + * semantically equivalent to having a ConstantPositionMobilityModel + * as parent positioned at origin (0,0,0). In other words, setting + * the parent model to NULL makes the child model and the hierarchical + * model start using world absolute coordinates. + * + * @warning: changing the parent/child mobility models in the middle + * of a simulation will probably not play very well with the + * ConfigStore APIs, so do this only if you know what you are doing. */ class HierarchicalMobilityModel : public MobilityModel { @@ -52,14 +75,26 @@ public: * position by the child mobility model. */ Ptr GetParent (void) const; + /** + * Sets the child mobility model to a new one. If before there + * already existed a child model, then the child mobility model + * current position is also modified to ensure that the composite + * position is preserved. + */ + void SetChild (Ptr model); + /** + * Sets the parent mobility model to a new one. If before there + * already existed a child model, then the child mobility model + * current position is also modified to ensure that the composite + * position is preserved. + */ + void SetParent (Ptr model); private: virtual Vector DoGetPosition (void) const; virtual void DoSetPosition (const Vector &position); virtual Vector DoGetVelocity (void) const; - void SetChild (Ptr model); - void SetParent (Ptr model); void ParentChanged (Ptr model); void ChildChanged (Ptr model);