From 170386d652ad0b676b0d172cc3e43ca3182dd179 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Fri, 3 Mar 2023 18:21:09 -0800 Subject: [PATCH 1/4] add light api Signed-off-by: Ian Chen --- include/ignition/gazebo/Light.hh | 291 ++++++++++++++++++ src/CMakeLists.txt | 2 + src/Light.cc | 511 +++++++++++++++++++++++++++++++ src/Light_TEST.cc | 83 +++++ 4 files changed, 887 insertions(+) create mode 100644 include/ignition/gazebo/Light.hh create mode 100644 src/Light.cc create mode 100644 src/Light_TEST.cc diff --git a/include/ignition/gazebo/Light.hh b/include/ignition/gazebo/Light.hh new file mode 100644 index 0000000000..f3680991dd --- /dev/null +++ b/include/ignition/gazebo/Light.hh @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef IGNITION_GAZEBO_LIGHT_HH_ +#define IGNITION_GAZEBO_LIGHT_HH_ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "ignition/gazebo/config.hh" +#include "ignition/gazebo/EntityComponentManager.hh" +#include "ignition/gazebo/Export.hh" +#include "ignition/gazebo/Types.hh" + +namespace ignition +{ + namespace gazebo + { + // Inline bracket to help doxygen filtering. + inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { + // + /// \class Light Light.hh ignition/gazebo/Light.hh + /// \brief This class provides wrappers around entities and components + /// which are more convenient and straight-forward to use than dealing + /// with the `EntityComponentManager` directly. + /// All the functions provided here are meant to be used with a light + /// entity. + /// + /// For example, given a light's entity, find the value of its + /// name component, one could use the entity-component manager (`ecm`) + /// directly as follows: + /// + /// std::string name = ecm.Component(entity)->Data(); + /// + /// Using this class however, the same information can be obtained with + /// a simpler function call: + /// + /// Light light(entity); + /// std::string name = light.Name(ecm); + /// + class IGNITION_GAZEBO_VISIBLE Light + { + /// \brief Constructor + /// \param[in] _entity Light entity + public: explicit Light(gazebo::Entity _entity = kNullEntity); + + /// \brief Get the entity which this Light is related to. + /// \return Light entity. + public: gazebo::Entity Entity() const; + + /// \brief Reset Entity to a new one + /// \param[in] _newEntity New light entity. + public: void ResetEntity(gazebo::Entity _newEntity); + + /// \brief Check whether this light correctly refers to an entity that + /// has a components::Light. + /// \param[in] _ecm Entity-component manager. + /// \return True if it's a valid light in the manager. + public: bool Valid(const EntityComponentManager &_ecm) const; + + /// \brief Get the light's unscoped name. + /// \param[in] _ecm Entity-component manager. + /// \return Light's name or nullopt if the entity does not have a + /// components::Name component + public: std::optional Name( + const EntityComponentManager &_ecm) const; + + /// \brief Get the pose of the light. + /// The pose is given w.r.t the light's parent. which can be a world or + /// a link. + /// \param[in] _ecm Entity-component manager. + /// \return Pose of the light or nullopt if the entity does not + /// have a components::Pose component. + public: std::optional Pose( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light type + /// \param[in] _ecm Entity-component manager. + /// \return Type of the light or nullopt if the entity does not + /// have a components::LightType component. + public: std::optional Type( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light diffuse color + /// \param[in] _ecm Entity-component manager. + /// \return Diffuse color of the light or nullopt if the entity does not + /// have a components::Light component. + public: std::optional DiffuseColor( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light specular color + /// \param[in] _ecm Entity-component manager. + /// \return Specular color of the light or nullopt if the entity does not + /// have a components::Light component. + public: std::optional SpecularColor( + const EntityComponentManager &_ecm) const; + + /// \brief Get whether the light casts shadows + /// \param[in] _ecm Entity-component manager. + /// \return Cast shadow bool value of light or nullopt if the entity does + /// not have a components::CastShadows component. + public: std::optional CastShadows( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light intensity. + /// \param[in] _ecm Entity-component manager. + /// \return Intensity of light or nullopt if the entity does not + /// have a components::Light component. + public: std::optional Intensity( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light direction. + /// \param[in] _ecm Entity-component manager. + /// \return Direction of light or nullopt if the entity does not + /// have a components::Light component. + public: std::optional Direction( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light attenuation range. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _ecm Entity-component manager. + /// \return Attenuation range of light or nullopt if the entity does not + /// have a components::Light component. + public: std::optional AttenuationRange( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light attenuation constant value. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _ecm Entity-component manager. + /// \return Attenuation constant value of light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional AttenuationConstant( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light attenuation linear value. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _ecm Entity-component manager. + /// \return Attenuation linear value of light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional AttenuationLinear( + const EntityComponentManager &_ecm) const; + + /// \brief Get the light attenuation quadratic value. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _ecm Entity-component manager. + /// \return Attenuation quadratic value of light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional AttenuationQuadratic( + const EntityComponentManager &_ecm) const; + + /// \brief Get the inner angle of light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \return Inner angle of spot light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional SpotInnerAngle( + const EntityComponentManager &_ecm) const; + + /// \brief Get the outer angle of light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \return Outer angle of spot light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional SpotOuterAngle( + const EntityComponentManager &_ecm) const; + + /// \brief Get the fall off value of light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \return Fall off value of spot light or nullopt if the entity + /// does not have a components::Light component. + public: std::optional SpotFalloff( + const EntityComponentManager &_ecm) const; + + /// \brief Set the pose of this light. + /// \param[in] _ecm Entity-component manager. + /// Pose is set w.r.t. the light's parent which can be a world or a link. + /// \param[in] _pose Pose to set the light to. + public: void SetPose(EntityComponentManager &_ecm, + const math::Pose3d &_pose); + + /// \brief Set the diffuse color of this light. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _color Diffuse color to set the light to + public: void SetDiffuseColor(EntityComponentManager &_ecm, + const math::Color &_color); + + /// \brief Set the specular color of this light. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _color Specular color to set the light to + public: void SetSpecularColor(EntityComponentManager &_ecm, + const math::Color &_color); + + /// \brief Set whether the light casts shadows. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _bool True to cast shadows, false to not cast shadows. + public: void SetCastShadows(EntityComponentManager &_ecm, + bool _castShadows); + + /// \brief Set light intensity. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _value Intensity value + public: void SetIntensity(EntityComponentManager &_ecm, + double _value); + + /// \brief Set light direction. Applies to directional lights + /// \param[in] _ecm Entity-component manager. + /// and spot lights only. + /// \param[in] _dir Direction to set + public: void SetDirection(EntityComponentManager &_ecm, + const math::Vector3d &_dir); + + /// \brief Set attenuation range of this light. + /// \param[in] _ecm Entity-component manager. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _bool True to cast shadows, false to not cast shadows. + public: void SetAttenuationRange(EntityComponentManager &_ecm, + double _range); + + /// \brief Set attenuation constant value of this light. + /// \param[in] _ecm Entity-component manager. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _value Attenuation constant value to set + public: void SetAttenuationConstant(EntityComponentManager &_ecm, + double _value); + + /// \brief Set attenuation linear value of this light. + /// \param[in] _ecm Entity-component manager. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _value Attenuation linear value to set + public: void SetAttenuationLinear(EntityComponentManager &_ecm, + double _value); + + /// \brief Set attenuation quadratic value of this light. + /// \param[in] _ecm Entity-component manager. + /// Light attenuation is not applicable to directional lights. + /// \param[in] _value Attenuation quadratic value to set + public: void SetAttenuationQuadratic(EntityComponentManager &_ecm, + double _value); + + /// \brief Set inner angle for this light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _angle Angle to set. + public: void SetSpotInnerAngle(EntityComponentManager &_ecm, + const math::Angle &_angle); + + /// \brief Set outer angle for this light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _angle Angle to set. + public: void SetSpotOuterAngle(EntityComponentManager &_ecm, + const math::Angle &_angle); + + /// \brief Set fall off value for this light. Applies to spot lights only. + /// \param[in] _ecm Entity-component manager. + /// \param[in] _fallOff Fall off value + public: void SetSpotFalloff(EntityComponentManager &_ecm, + double _falloff); + + /// \brief Get the parent entity. This can be a world or a link. + /// \param[in] _ecm Entity-component manager. + /// \return Parent entity or nullopt if the entity does not have a + /// components::ParentEntity component. + public: std::optional Parent( + const EntityComponentManager &_ecm) const; + + /// \brief Private data pointer. + IGN_UTILS_IMPL_PTR(dataPtr) + }; + } + } +} +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97b0a48238..dcd75bc1d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ set (sources EntityComponentManager.cc Joint.cc LevelManager.cc + Light.cc Link.cc Model.cc Primitives.cc @@ -81,6 +82,7 @@ set (gtest_sources EntityComponentManager_TEST.cc EventManager_TEST.cc Joint_TEST.cc + Light_TEST.cc Link_TEST.cc Model_TEST.cc Primitives_TEST.cc diff --git a/src/Light.cc b/src/Light.cc new file mode 100644 index 0000000000..0adf974956 --- /dev/null +++ b/src/Light.cc @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include + +#include "ignition/gazebo/components/CastShadows.hh" +#include "ignition/gazebo/components/Light.hh" +#include "ignition/gazebo/components/LightType.hh" +#include "ignition/gazebo/components/LightCmd.hh" +#include "ignition/gazebo/components/Name.hh" +#include "ignition/gazebo/components/Pose.hh" + +#include "ignition/gazebo/Light.hh" +#include "ignition/gazebo/Util.hh" + +using namespace ignition; +using namespace gazebo; + + +class ignition::gazebo::Light::Implementation +{ + /// \brief Id of light entity. + public: gazebo::Entity id{kNullEntity}; +}; + +////////////////////////////////////////////////// +Light::Light(gazebo::Entity _entity) + : dataPtr(utils::MakeImpl()) +{ + this->dataPtr->id = _entity; +} + +////////////////////////////////////////////////// +gazebo::Entity Light::Entity() const +{ + return this->dataPtr->id; +} + +////////////////////////////////////////////////// +void Light::ResetEntity(gazebo::Entity _newEntity) +{ + this->dataPtr->id = _newEntity; +} + +////////////////////////////////////////////////// +bool Light::Valid(const EntityComponentManager &_ecm) const +{ + return nullptr != _ecm.Component(this->dataPtr->id); +} + +////////////////////////////////////////////////// +std::optional Light::Name(const EntityComponentManager &_ecm) const +{ + return _ecm.ComponentData(this->dataPtr->id); +} + +////////////////////////////////////////////////// +std::optional Light::Type( + const EntityComponentManager &_ecm) const +{ + auto lightType = _ecm.Component(this->dataPtr->id); + + if (!lightType) + return std::nullopt; + + return std::optional(lightType->Data()); +} + +////////////////////////////////////////////////// +std::optional Light::Pose( + const EntityComponentManager &_ecm) const +{ + auto pose = _ecm.Component(this->dataPtr->id); + + if (!pose) + return std::nullopt; + + return std::optional(pose->Data()); +} + +////////////////////////////////////////////////// +std::optional Light::CastShadows( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().CastShadows()); +} + +////////////////////////////////////////////////// +std::optional Light::Intensity( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().Intensity()); +} + +////////////////////////////////////////////////// +std::optional Light::Direction( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().Direction()); +} + +////////////////////////////////////////////////// +std::optional Light::DiffuseColor( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().Diffuse()); +} + +////////////////////////////////////////////////// +std::optional Light::SpecularColor( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().Specular()); +} + +////////////////////////////////////////////////// +std::optional Light::AttenuationRange( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().AttenuationRange()); +} + +////////////////////////////////////////////////// +std::optional Light::AttenuationConstant( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().ConstantAttenuationFactor()); +} + +////////////////////////////////////////////////// +std::optional Light::AttenuationLinear( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().LinearAttenuationFactor()); +} + +////////////////////////////////////////////////// +std::optional Light::AttenuationQuadratic( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().QuadraticAttenuationFactor()); +} + +////////////////////////////////////////////////// +std::optional Light::SpotInnerAngle( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().SpotInnerAngle()); +} + +////////////////////////////////////////////////// +std::optional Light::SpotOuterAngle( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().SpotOuterAngle()); +} + +////////////////////////////////////////////////// +std::optional Light::SpotFalloff( + const EntityComponentManager &_ecm) const +{ + auto light = _ecm.Component(this->dataPtr->id); + + if (!light) + return std::nullopt; + + return std::optional(light->Data().SpotFalloff()); +} + +////////////////////////////////////////////////// +void Light::SetPose(EntityComponentManager &_ecm, + const math::Pose3d &_pose) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + msgs::Set(lightMsg.mutable_pose(), _pose); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetCastShadows(EntityComponentManager &_ecm, + bool _castShadows) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_cast_shadows(_castShadows); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetIntensity(EntityComponentManager &_ecm, + double _intensity) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_intensity(_intensity); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetDirection(EntityComponentManager &_ecm, + const math::Vector3d &_dir) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + msgs::Set(lightMsg.mutable_direction(), _dir); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetDiffuseColor(EntityComponentManager &_ecm, + const math::Color &_color) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + msgs::Set(lightMsg.mutable_diffuse(), _color); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetSpecularColor(EntityComponentManager &_ecm, + const math::Color &_color) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + msgs::Set(lightMsg.mutable_specular(), _color); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetAttenuationRange(EntityComponentManager &_ecm, + double _range) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_range(_range); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetAttenuationConstant(EntityComponentManager &_ecm, + double _value) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_attenuation_constant(_value); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} +////////////////////////////////////////////////// +void Light::SetAttenuationLinear(EntityComponentManager &_ecm, + double _value) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_attenuation_linear(_value); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetAttenuationQuadratic(EntityComponentManager &_ecm, + double _value) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_attenuation_quadratic(_value); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetSpotInnerAngle(EntityComponentManager &_ecm, + const math::Angle &_angle) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_spot_inner_angle(_angle.Radian()); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetSpotOuterAngle(EntityComponentManager &_ecm, + const math::Angle &_angle) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_spot_outer_angle(_angle.Radian()); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} + +////////////////////////////////////////////////// +void Light::SetSpotFalloff(EntityComponentManager &_ecm, + double _falloff) +{ + auto lightCmd = + _ecm.Component(this->dataPtr->id); + + msgs::Light lightMsg; + lightMsg.set_spot_falloff(_falloff); + if (!lightCmd) + { + _ecm.CreateComponent( + this->dataPtr->id, + components::LightCmd(lightMsg)); + } + else + { + lightCmd->Data() = lightMsg; + } +} diff --git a/src/Light_TEST.cc b/src/Light_TEST.cc new file mode 100644 index 0000000000..c435f3acd8 --- /dev/null +++ b/src/Light_TEST.cc @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include + +#include + +#include "ignition/gazebo/EntityComponentManager.hh" +#include "ignition/gazebo/Light.hh" +#include "ignition/gazebo/components/Light.hh" +#include "ignition/gazebo/components/Name.hh" +#include "ignition/gazebo/components/ParentEntity.hh" +#include "ignition/gazebo/components/Sensor.hh" + +///////////////////////////////////////////////// +TEST(LightTest, Constructor) +{ + ignition::gazebo::Light lightNull; + EXPECT_EQ(ignition::gazebo::kNullEntity, lightNull.Entity()); + + ignition::gazebo::Entity id(3); + ignition::gazebo::Light light(id); + + EXPECT_EQ(id, light.Entity()); +} + +///////////////////////////////////////////////// +TEST(LightTest, CopyConstructor) +{ + ignition::gazebo::Entity id(3); + ignition::gazebo::Light light(id); + + // Marked nolint because we are specifically testing copy + // constructor here (clang wants unnecessary copies removed) + ignition::gazebo::Light lightCopy(light); // NOLINT + EXPECT_EQ(light.Entity(), lightCopy.Entity()); +} + +///////////////////////////////////////////////// +TEST(LightTest, CopyAssignmentOperator) +{ + ignition::gazebo::Entity id(3); + ignition::gazebo::Light light(id); + + ignition::gazebo::Light lightCopy; + lightCopy = light; + EXPECT_EQ(light.Entity(), lightCopy.Entity()); +} + +///////////////////////////////////////////////// +TEST(LightTest, MoveConstructor) +{ + ignition::gazebo::Entity id(3); + ignition::gazebo::Light light(id); + + ignition::gazebo::Light lightMoved(std::move(light)); + EXPECT_EQ(id, lightMoved.Entity()); +} + +///////////////////////////////////////////////// +TEST(LightTest, MoveAssignmentOperator) +{ + ignition::gazebo::Entity id(3); + ignition::gazebo::Light light(id); + + ignition::gazebo::Light lightMoved; + lightMoved = std::move(light); + EXPECT_EQ(id, lightMoved.Entity()); +} From dfa7b372aa17d19a2e027e170de5e0a12ee0b547 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Mon, 6 Mar 2023 15:23:46 -0800 Subject: [PATCH 2/4] add integration test Signed-off-by: Ian Chen --- src/Light.cc | 1 - test/integration/CMakeLists.txt | 1 + test/integration/light.cc | 752 ++++++++++++++++++++++++++++++++ 3 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 test/integration/light.cc diff --git a/src/Light.cc b/src/Light.cc index 0adf974956..c5e4adad8c 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -19,7 +19,6 @@ #include -#include "ignition/gazebo/components/CastShadows.hh" #include "ignition/gazebo/components/Light.hh" #include "ignition/gazebo/components/LightType.hh" #include "ignition/gazebo/components/LightCmd.hh" diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 8a5c61814d..e6a39fb206 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -36,6 +36,7 @@ set(tests lift_drag_system.cc level_manager.cc level_manager_runtime_performers.cc + light.cc link.cc logical_camera_system.cc logical_audio_sensor_plugin.cc diff --git a/test/integration/light.cc b/test/integration/light.cc new file mode 100644 index 0000000000..8c326019cc --- /dev/null +++ b/test/integration/light.cc @@ -0,0 +1,752 @@ +/* + * Copyright (C) 2023 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../helpers/EnvTestFixture.hh" + +using namespace ignition; +using namespace gazebo; + +class LightIntegrationTest : public InternalFixture<::testing::Test> +{ +}; + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Valid) +{ + EntityComponentManager ecm; + + // No ID + { + Light light; + EXPECT_FALSE(light.Valid(ecm)); + } + + // Missing light component + { + auto id = ecm.CreateEntity(); + Light light(id); + EXPECT_FALSE(light.Valid(ecm)); + } + + // Valid + { + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + EXPECT_TRUE(light.Valid(ecm)); + } +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Name) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + // No name + EXPECT_EQ(std::nullopt, light.Name(ecm)); + + // Add name + ecm.CreateComponent(id, components::Name("light_name")); + EXPECT_EQ("light_name", light.Name(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Pose) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + // No pose + EXPECT_EQ(std::nullopt, light.Pose(ecm)); + + // Add pose + math::Pose3d pose(1, 2, 3, 0.1, 0.2, 0.3); + ecm.CreateComponent(id, + components::Pose(pose)); + EXPECT_EQ(pose, light.Pose(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Type) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + // No light type + EXPECT_EQ(std::nullopt, light.Type(ecm)); + + // Add type + std::string lightType = "point"; + ecm.CreateComponent(id, + components::LightType(lightType)); + EXPECT_EQ(lightType, light.Type(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, CastShadows) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + lightSdf.SetCastShadows(true); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_TRUE(*light.CastShadows(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Intensity) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double intensity = 0.2; + lightSdf.SetIntensity(intensity); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(intensity, *light.Intensity(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Direction) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + math::Vector3d dir(1.0, 0.0, 0.0); + lightSdf.SetDirection(dir); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_EQ(dir, *light.Direction(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, DiffuseColor) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + math::Color color(1.0, 1.0, 0.0); + lightSdf.SetDiffuse(color); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_EQ(color, *light.DiffuseColor(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SpecularColor) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + math::Color color(1.0, 1.0, 0.0); + lightSdf.SetSpecular(color); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_EQ(color, *light.SpecularColor(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, AttenuationRange) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double range = 2.4; + lightSdf.SetAttenuationRange(range); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(range, *light.AttenuationRange(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, AttenuationConstant) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double value = 0.2; + lightSdf.SetConstantAttenuationFactor(value); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(value, *light.AttenuationConstant(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, AttenuationLinear) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double value = 0.1; + lightSdf.SetLinearAttenuationFactor(value); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(value, *light.AttenuationLinear(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, AttenuationQuadratic) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double value = 0.01; + lightSdf.SetQuadraticAttenuationFactor(value); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(value, *light.AttenuationQuadratic(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SpotInnerAngle) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + math::Angle angle(1.57); + lightSdf.SetSpotInnerAngle(angle); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_EQ(angle, *light.SpotInnerAngle(ecm)); +} + + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SpotOuterAngle) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + math::Angle angle(2.3); + lightSdf.SetSpotOuterAngle(angle); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_EQ(angle, *light.SpotOuterAngle(ecm)); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SpotFalloff) +{ + EntityComponentManager ecm; + + auto id = ecm.CreateEntity(); + ecm.CreateComponent(id, components::Light()); + + Light light(id); + + sdf::Light lightSdf; + double falloff(0.3); + lightSdf.SetSpotFalloff(falloff); + ecm.CreateComponent(id, + components::Light(lightSdf)); + EXPECT_DOUBLE_EQ(falloff, *light.SpotFalloff(ecm)); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetPose) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Pose3d poseCmd(0.1, -2, 30, 0.2, 0.3, 0.8); + light.SetPose(ecm, poseCmd); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_EQ(poseCmd, msgs::Convert( + ecm.Component(eLight)->Data().pose())); + + // Make sure the light cmd is updated + math::Pose3d poseCmd2(9.3, -8, -1, 0.0, -0.3, 3.8); + light.SetPose(ecm, poseCmd2); + EXPECT_EQ(poseCmd2, msgs::Convert( + ecm.Component(eLight)->Data().pose())); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetCastShadows) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + bool castShadows = true; + light.SetCastShadows(ecm, castShadows); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_EQ(castShadows, + ecm.Component(eLight)->Data().cast_shadows()); + + // Make sure the light cmd is updated + bool castShadows2 = false; + light.SetCastShadows(ecm, castShadows2); + EXPECT_EQ(castShadows2, + ecm.Component(eLight)->Data().cast_shadows()); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetIntensity) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double intensity = 0.3; + light.SetIntensity(ecm, intensity); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(intensity, + ecm.Component(eLight)->Data().intensity()); + + // Make sure the light cmd is updated + double intensity2 = 0.001; + light.SetIntensity(ecm, intensity2); + EXPECT_FLOAT_EQ(intensity2, + ecm.Component(eLight)->Data().intensity()); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetDirection) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Vector3d dir(0.3, 0.4, 0.6); + light.SetDirection(ecm, dir); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_EQ(dir, msgs::Convert( + ecm.Component(eLight)->Data().direction())); + + // Make sure the light cmd is updated + math::Vector3d dir2(1.0, 0.0, 0.0); + light.SetDirection(ecm, dir2); + EXPECT_EQ(dir2, msgs::Convert( + ecm.Component(eLight)->Data().direction())); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetDiffuseColor) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Color color(1.0, 0.0, 1.0); + light.SetDiffuseColor(ecm, color); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_EQ(color, msgs::Convert( + ecm.Component(eLight)->Data().diffuse())); + + // Make sure the light cmd is updated + math::Color color2(1.0, 0.5, 0.5); + light.SetDiffuseColor(ecm, color2); + EXPECT_EQ(color2, msgs::Convert( + ecm.Component(eLight)->Data().diffuse())); +} + +///////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetSpecularColor) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Color color(1.0, 1.0, 0.0); + light.SetSpecularColor(ecm, color); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_EQ(color, msgs::Convert( + ecm.Component(eLight)->Data().specular())); + + // Make sure the light cmd is updated + math::Color color2(0.0, 1.0, 0.0); + light.SetSpecularColor(ecm, color2); + EXPECT_EQ(color2, msgs::Convert( + ecm.Component(eLight)->Data().specular())); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetAttenuationRange) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double range = 56.2; + light.SetAttenuationRange(ecm, range); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(range, + ecm.Component(eLight)->Data().range()); + + // Make sure the light cmd is updated + double range2 = 2777.9; + light.SetAttenuationRange(ecm, range2); + EXPECT_FLOAT_EQ(range2, + ecm.Component(eLight)->Data().range()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetAttenuationConstant) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double value = 3.0; + light.SetAttenuationConstant(ecm, value); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(value, + ecm.Component(eLight)->Data().attenuation_constant()); + + // Make sure the light cmd is updated + double value2 = 5.0; + light.SetAttenuationConstant(ecm, value2); + EXPECT_FLOAT_EQ(value2, + ecm.Component(eLight)->Data().attenuation_constant()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetAttenuationLinear) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double value = 0.1; + light.SetAttenuationLinear(ecm, value); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(value, + ecm.Component(eLight)->Data().attenuation_linear()); + + // Make sure the light cmd is updated + double value2 = 0.2; + light.SetAttenuationLinear(ecm, value2); + EXPECT_FLOAT_EQ(value2, + ecm.Component(eLight)->Data().attenuation_linear()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetAttenuationQuadratic) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double value = 0.3; + light.SetAttenuationQuadratic(ecm, value); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(value, + ecm.Component(eLight)->Data().attenuation_quadratic()); + + // Make sure the light cmd is updated + double value2 = 0.7; + light.SetAttenuationQuadratic(ecm, value2); + EXPECT_FLOAT_EQ(value2, + ecm.Component(eLight)->Data().attenuation_quadratic()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetSpotInnerAngle) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Angle angle(2.9); + light.SetSpotInnerAngle(ecm, angle.Radian()); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(angle.Radian(), + ecm.Component(eLight)->Data().spot_inner_angle()); + + // Make sure the light cmd is updated + math::Angle angle2(0.9); + light.SetSpotInnerAngle(ecm, angle2.Radian()); + EXPECT_FLOAT_EQ(angle2.Radian(), + ecm.Component(eLight)->Data().spot_inner_angle()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetSpotOuterAngle) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + math::Angle angle(3.1); + light.SetSpotOuterAngle(ecm, angle.Radian()); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(angle.Radian(), + ecm.Component(eLight)->Data().spot_outer_angle()); + + // Make sure the light cmd is updated + math::Angle angle2(0.8); + light.SetSpotOuterAngle(ecm, angle2.Radian()); + EXPECT_FLOAT_EQ(angle2.Radian(), + ecm.Component(eLight)->Data().spot_outer_angle()); +} + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, SetSpotFalloff) +{ + EntityComponentManager ecm; + + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + + ASSERT_TRUE(light.Valid(ecm)); + + // No LightCmd should exist by default + EXPECT_EQ(nullptr, ecm.Component(eLight)); + + double falloff = 0.3; + light.SetSpotFalloff(ecm, falloff); + + // light cmd should exist + EXPECT_NE(nullptr, ecm.Component(eLight)); + EXPECT_FLOAT_EQ(falloff, + ecm.Component(eLight)->Data().spot_falloff()); + + // Make sure the light cmd is updated + double falloff2 = 1.0; + light.SetSpotFalloff(ecm, falloff2); + EXPECT_FLOAT_EQ(falloff2, + ecm.Component(eLight)->Data().spot_falloff()); +} From fb6064923ff9ea5c801dfc49d93b42606a8c6bf1 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Mon, 6 Mar 2023 15:36:33 -0800 Subject: [PATCH 3/4] add api to get parent Signed-off-by: Ian Chen --- src/Light.cc | 12 +++++++++ test/integration/light.cc | 50 ++++++++++++++++++++++++++++++++++++++ test/integration/sensor.cc | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/Light.cc b/src/Light.cc index c5e4adad8c..a3337bf110 100644 --- a/src/Light.cc +++ b/src/Light.cc @@ -23,6 +23,7 @@ #include "ignition/gazebo/components/LightType.hh" #include "ignition/gazebo/components/LightCmd.hh" #include "ignition/gazebo/components/Name.hh" +#include "ignition/gazebo/components/ParentEntity.hh" #include "ignition/gazebo/components/Pose.hh" #include "ignition/gazebo/Light.hh" @@ -508,3 +509,14 @@ void Light::SetSpotFalloff(EntityComponentManager &_ecm, lightCmd->Data() = lightMsg; } } + +////////////////////////////////////////////////// +std::optional Light::Parent(const EntityComponentManager &_ecm) const +{ + auto parent = _ecm.Component(this->dataPtr->id); + + if (!parent) + return std::nullopt; + + return std::optional(parent->Data()); +} diff --git a/test/integration/light.cc b/test/integration/light.cc index 8c326019cc..fa14a48be3 100644 --- a/test/integration/light.cc +++ b/test/integration/light.cc @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include #include "../helpers/EnvTestFixture.hh" @@ -750,3 +752,51 @@ TEST_F(LightIntegrationTest, SetSpotFalloff) EXPECT_FLOAT_EQ(falloff2, ecm.Component(eLight)->Data().spot_falloff()); } + +////////////////////////////////////////////////// +TEST_F(LightIntegrationTest, Parent) +{ + EntityComponentManager ecm; + + { + // Link as parent + auto eLink = ecm.CreateEntity(); + ecm.CreateComponent(eLink, components::Link()); + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + EXPECT_FALSE(light.Parent(ecm).has_value()); + + ecm.CreateComponent(eLight, + components::ParentEntity(eLink)); + ASSERT_TRUE(light.Valid(ecm)); + + // Check parent link + EXPECT_EQ(eLink, ecm.ParentEntity(eLight)); + auto parentLink = light.Parent(ecm); + EXPECT_EQ(eLink, parentLink); + } + + { + // World as parent + auto eWorld = ecm.CreateEntity(); + ecm.CreateComponent(eWorld, components::World()); + auto eLight = ecm.CreateEntity(); + ecm.CreateComponent(eLight, components::Light()); + + Light light(eLight); + EXPECT_EQ(eLight, light.Entity()); + EXPECT_FALSE(light.Parent(ecm).has_value()); + + ecm.CreateComponent(eLight, + components::ParentEntity(eWorld)); + ASSERT_TRUE(light.Valid(ecm)); + + // Check parent world + EXPECT_EQ(eWorld, ecm.ParentEntity(eLight)); + auto parentWorld = light.Parent(ecm); + EXPECT_EQ(eWorld, parentWorld); + } +} diff --git a/test/integration/sensor.cc b/test/integration/sensor.cc index c90848552c..7536e00d27 100644 --- a/test/integration/sensor.cc +++ b/test/integration/sensor.cc @@ -149,7 +149,7 @@ TEST_F(SensorIntegrationTest, Parent) } { - // Joint tas parent + // Joint as parent auto eJoint = ecm.CreateEntity(); ecm.CreateComponent(eJoint, components::Joint()); auto eSensor = ecm.CreateEntity(); From a8f4bb16fac9f16d1b5a18b8b2b33e3c653e3d9c Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Tue, 7 Mar 2023 10:31:47 -0800 Subject: [PATCH 4/4] style Signed-off-by: Ian Chen --- test/integration/light.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/integration/light.cc b/test/integration/light.cc index fa14a48be3..abc20be990 100644 --- a/test/integration/light.cc +++ b/test/integration/light.cc @@ -651,13 +651,15 @@ TEST_F(LightIntegrationTest, SetAttenuationQuadratic) // light cmd should exist EXPECT_NE(nullptr, ecm.Component(eLight)); EXPECT_FLOAT_EQ(value, - ecm.Component(eLight)->Data().attenuation_quadratic()); + ecm.Component( + eLight)->Data().attenuation_quadratic()); // Make sure the light cmd is updated double value2 = 0.7; light.SetAttenuationQuadratic(ecm, value2); EXPECT_FLOAT_EQ(value2, - ecm.Component(eLight)->Data().attenuation_quadratic()); + ecm.Component( + eLight)->Data().attenuation_quadratic()); } //////////////////////////////////////////////////