Ignition Gazeboに以下のようなコードがある。
void Model::SetWorldPoseCmd(EntityComponentManager &_ecm, const math::Pose3d &_pose) { auto poseCmdComp = _ecm.Component<components::WorldPoseCmd>( this->dataPtr->id); if (!poseCmdComp) { _ecm.CreateComponent(this->dataPtr->id, components::WorldPoseCmd(_pose)); } else { poseCmdComp->SetData(_pose, [](const math::Pose3d &, const math::Pose3d &){return false;}); _ecm.SetChanged(this->dataPtr->id, components::WorldPoseCmd::typeId, ComponentState::OneTimeChange); } }
イミフメイ。
ひとつわかることは、これはC++上級者が書いたコードだ。
(·∀·)つ【改訂版】「組込みソフトウェア開発向けコーディング作法ガイド ESCR [C++言語版] Ver. 2.0」の発行:IPA 独立行政法人 情報処理推進機構
なになにC++のコーディング規約とな。
プログラムはシンプルに書く
ぜんっぜんシンプルじゃない!
やりたいことはシンプル
やりたいことは簡単。モデルを動かす。
上記の実装によれば、
モデルクラスはSetWorldPoseCmdメソッドに対し、
EntityComponentManagerとPose3dを引数として渡す必要がある。
(·∀·)まぁ、それはヘッダかドキュメント見ればわかるよ。
GazeboではSetWorldPoseにマネジャークラスを渡す必要はなかったのだが、
Ignitionでは渡す実装になっている...。
複雑になってるよ...。
Next step
auto poseCmdComp = _ecm.Component<components::WorldPoseCmd>(this->dataPtr->id);
auto?
安心しろ...静的型付言語なので絶対に何らかの型はある!!
ちなみにJavascript界隈では大規模開発に不向きということで、Typescriptが流行っているようだ。
とりあえず、メソッドをVS CodeでPeek!!
出てこない!?
なるほど、実装がトリッキーすぎてVS Codeでも追えないということか。
EntityComponentManager.hh
/// \brief Get a mutable component based on a key. /// \param[in] _key A key that uniquely identifies a component. /// \return The component associated with the key, or nullptr if the /// component could not be found. public: template<typename ComponentTypeT> ComponentTypeT *Component(const ComponentKey &_key);
components名前空間にあるcomponentの型をテンプレート戻り値として返す。
したがって、戻り値の型はautoはcomponents::WorldPoseCmdとなる。
Next step
poseCmdComp->SetData(_pose, [](const math::Pose3d &, const math::Pose3d &){return false;});
すげぇ、ぱっと見いくつのパラメータがあるのかさえわからない。
SetDataをPeek!!
template <typename DataType, typename Identifier, typename Serializer> bool Component<DataType, Identifier, Serializer>::SetData( const DataType &_data, const std::function<bool(const DataType &, const DataType &)> &_eql) { bool result = !_eql(_data, this->data); this->data = _data; return result; }
どうやら2つのパラメータがある。
そして、C++11から導入されたstd::functionを使っている。
また、C++で
[]{};
のような記法が出てきたらラムダ式となる。 std::functionの使い方 in C++ - Qiita を参考に書き換えると、
std::function<bool(const DataType &, const DataType &)> _eql = [](const math::Pose3d &, const math::Pose3d &){return false;};
となり、ラムダ式を代入した_eqlを使用して評価する。
つまり、SetDataしても同じだったらfalseを返すよ。
ということか。
今度はtemplate3つ使用している。
・DataType
・Identifier
・Serializer
Datatype:今回はPose3dとして暗黙的される
Identifier,SerializerはSetDataメソッドのために書かれているわけではない。
Identifierはエイリアステンプレートで明示される。
PoseCmd.hh
using WorldPoseCmd = Component<math::Pose3d, class WorldPoseCmdTag>;
Serializerはデフォルトテンプレート引数として以下のように指定されている。
typename Serializer = serializers::DefaultSerializer<DataType>
Next step
_ecm.SetChanged(this->dataPtr->id, components::WorldPoseCmd::typeId, ComponentState::OneTimeChange);
変更されたコンポーネントを_ecmへセットする。
typIdはInline Staticのため上記のような表記となる。
それでも理解できない場合
ign-gazebo/test/integrationにテスト用コードが用意されている。
CMakeでビルド後、
ign-gazebo/build/binの中に実行バイナリが生成されているので、
それを動かせばオッケー。