diff --git a/include/sdf/CMakeLists.txt b/include/sdf/CMakeLists.txt index 7b096e901..1704b4d9c 100644 --- a/include/sdf/CMakeLists.txt +++ b/include/sdf/CMakeLists.txt @@ -40,6 +40,7 @@ set (headers SDFImpl.hh SemanticPose.hh Sensor.hh + Sky.hh Sphere.hh Surface.hh Types.hh diff --git a/include/sdf/Scene.hh b/include/sdf/Scene.hh index b4fea303b..27dc1a326 100644 --- a/include/sdf/Scene.hh +++ b/include/sdf/Scene.hh @@ -20,6 +20,7 @@ #include #include "sdf/Element.hh" +#include "sdf/Sky.hh" #include "sdf/Types.hh" #include "sdf/sdf_config.h" #include "sdf/system_util.hh" @@ -107,6 +108,14 @@ namespace sdf /// \param[in] enabled True to enable shadows public: void SetShadows(const bool _shadows); + /// \brief Set sky + /// \param[in] _sky Sky to set to + public: void SetSky(const Sky &_sky); + + /// \brief Get sky + /// \return Sky + public: const sdf::Sky *Sky() const; + /// \brief Get a pointer to the SDF element that was used during /// load. /// \return SDF element pointer. The value will be nullptr if Load has diff --git a/include/sdf/Sky.hh b/include/sdf/Sky.hh new file mode 100644 index 000000000..84f327a24 --- /dev/null +++ b/include/sdf/Sky.hh @@ -0,0 +1,146 @@ +/* + * Copyright 2020 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 SDF_SKY_HH_ +#define SDF_SKY_HH_ + +#include + +#include "sdf/Element.hh" +#include "sdf/Types.hh" +#include "sdf/sdf_config.h" +#include "sdf/system_util.hh" + +namespace sdf +{ + // Inline bracket to help doxygen filtering. + inline namespace SDF_VERSION_NAMESPACE { + // + + // Forward declarations. + class SkyPrivate; + + class SDFORMAT_VISIBLE Sky + { + /// \brief Default constructor + public: Sky(); + + /// \brief Copy constructor + /// \param[in] _sky Sky element to copy. + public: Sky(const Sky &_sky); + + /// \brief Move constructor + /// \param[in] _sky Sky to move. + public: Sky(Sky &&_sky) noexcept; + + /// \brief Destructor + public: ~Sky(); + + /// \brief Assignment operator. + /// \param[in] _sky The sky to set values from. + /// \return *this + public: Sky &operator=(const Sky &_sky); + + /// \brief Move assignment operator. + /// \param[in] _workflow The sky to move from. + /// \return *this + public: Sky &operator=(Sky &&_sky); + + /// \brief Get time of day [0..24] + /// \return Time of day + public: double Time() const; + + /// \brief Set time of day + /// \param[in] _time Time of day [0..24] + public: void SetTime(double _time); + + /// \brief Get sunrise time + /// \return sunrise time [0..24] + public: double Sunrise() const; + + /// \brief Set Sunrise time + /// \param[in] _time Sunrise time [0..24] + public: void SetSunrise(double _time); + + /// \brief Get sunset time + /// \return sunset time [0..24] + public: double Sunset() const; + + /// \brief Set Sunset time + /// \param[in] _time Sunset time [0..24] + public: void SetSunset(double _time); + + /// \brief Get cloud speed + /// \return cloud speed in meters per second + public: double CloudSpeed() const; + + /// \brief Set cloud speed + /// \param[in] _speed cloud speed in meters per second. + public: void SetCloudSpeed(double _speed); + + /// \brief Get cloud direction angle (angle around up axis) + /// \return cloud direction angle in world frame + public: ignition::math::Angle CloudDirection() const; + + /// \brief Set cloud direction angle (angle around up axis) + /// \param[in] _angle Cloud direction angle in world frame. + public: void SetCloudDirection(const ignition::math::Angle &_angle); + + /// \brief Get cloud humidity + /// \return cloud humidity [0..1] + public: double CloudHumidity() const; + + /// \brief Set cloud humidity + /// \param[in] _humidity cloud humidity [0..1] + public: void SetCloudHumidity(double _humidity); + + /// \brief Get cloud mean size + /// \return cloud mean size [0..1] + public: double CloudMeanSize() const; + + /// \brief Set cloud mean siz + /// \param[in] _size cloud mean size [0..1] + public: void SetCloudMeanSize(double _size); + + /// \brief Get cloud ambient color + /// \return cloud ambient color + public: ignition::math::Color CloudAmbient() const; + + /// \brief Set cloud ambient color + /// \param[in] _ambient cloud ambient color + public: void SetCloudAmbient(const ignition::math::Color &_ambient); + + /// \brief Load the sky based on a element pointer. This is *not* the + /// usual entry point. Typical usage of the SDF DOM is through the Root + /// object. + /// \param[in] _sdf The SDF Element pointer + /// \return Errors, which is a vector of Error objects. Each Error includes + /// an error code and message. An empty vector indicates no error. + public: Errors Load(ElementPtr _sdf); + + /// \brief Get a pointer to the SDF element that was used during + /// load. + /// \return SDF element pointer. The value will be nullptr if Load has + /// not been called. + public: sdf::ElementPtr Element() const; + + /// \brief Private data pointer. + private: SkyPrivate *dataPtr = nullptr; + }; + } +} +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4625a432e..383e15e88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,7 @@ set (sources SDFExtension.cc SemanticPose.cc Sensor.cc + Sky.cc Sphere.cc Surface.cc Types.cc @@ -118,6 +119,7 @@ if (BUILD_SDF_TEST) SemanticPose_TEST.cc SDF_TEST.cc Sensor_TEST.cc + Sky_TEST.cc Sphere_TEST.cc Surface_TEST.cc Types_TEST.cc diff --git a/src/Scene.cc b/src/Scene.cc index 9458d0dbb..a042a1b07 100644 --- a/src/Scene.cc +++ b/src/Scene.cc @@ -22,6 +22,16 @@ using namespace sdf; /// \brief Scene private data. class sdf::ScenePrivate { + /// \brief Default constructor + public: ScenePrivate() = default; + + /// \brief Copy constructor + /// \param[in] _scenePrivate private data to copy + public: explicit ScenePrivate(const ScenePrivate &_scenePrivate); + + // Delete copy assignment so it is not accidentally used + public: ScenePrivate &operator=(const ScenePrivate &) = delete; + /// \brief True if grid should be enabled public: bool grid = true; @@ -39,10 +49,29 @@ class sdf::ScenePrivate public: ignition::math::Color background = ignition::math::Color(0.7f, 0.7f, .7f); + /// \brief Pointer to the sky properties. + public: std::unique_ptr sky; + /// \brief The SDF element pointer used during load. public: sdf::ElementPtr sdf; }; +///////////////////////////////////////////////// +ScenePrivate::ScenePrivate(const ScenePrivate &_scenePrivate) + : grid(_scenePrivate.grid), + shadows(_scenePrivate.shadows), + originVisual(_scenePrivate.originVisual), + ambient(_scenePrivate.ambient), + background(_scenePrivate.background), + sdf(_scenePrivate.sdf) +{ + if (_scenePrivate.sky) + { + this->sky = + std::make_unique(*(_scenePrivate.sky)); + } +} + ///////////////////////////////////////////////// Scene::Scene() : dataPtr(new ScenePrivate) @@ -118,6 +147,14 @@ Errors Scene::Load(ElementPtr _sdf) this->dataPtr->originVisual = _sdf->Get("origin_visual", this->dataPtr->originVisual).first; + // load sky + if (_sdf->HasElement("sky")) + { + this->dataPtr->sky = std::make_unique(); + Errors err = this->dataPtr->sky->Load(_sdf->GetElement("sky")); + errors.insert(errors.end(), err.begin(), err.end()); + } + return errors; } @@ -180,6 +217,18 @@ void Scene::SetOriginVisual(const bool _enabled) this->dataPtr->originVisual = _enabled; } +///////////////////////////////////////////////// +void Scene::SetSky(const sdf::Sky &_sky) +{ + this->dataPtr->sky = std::make_unique(_sky); +} + +///////////////////////////////////////////////// +const sdf::Sky *Scene::Sky() const +{ + return this->dataPtr->sky.get(); +} + ///////////////////////////////////////////////// sdf::ElementPtr Scene::Element() const { diff --git a/src/Scene_TEST.cc b/src/Scene_TEST.cc index e9a423970..0e10ece0d 100644 --- a/src/Scene_TEST.cc +++ b/src/Scene_TEST.cc @@ -27,6 +27,7 @@ TEST(DOMScene, Construction) EXPECT_TRUE(scene.Grid()); EXPECT_TRUE(scene.Shadows()); EXPECT_TRUE(scene.OriginVisual()); + EXPECT_EQ(nullptr, scene.Sky()); } ///////////////////////////////////////////////// @@ -41,6 +42,8 @@ TEST(DOMScene, CopyConstruction) scene.SetGrid(false); scene.SetShadows(false); scene.SetOriginVisual(false); + sdf::Sky sky; + scene.SetSky(sky); sdf::Scene scene2(scene); EXPECT_EQ(ignition::math::Color::Blue, scene2.Ambient()); @@ -48,6 +51,7 @@ TEST(DOMScene, CopyConstruction) EXPECT_FALSE(scene2.Grid()); EXPECT_FALSE(scene2.Shadows()); EXPECT_FALSE(scene2.OriginVisual()); + EXPECT_NE(nullptr, scene2.Sky()); EXPECT_NE(nullptr, scene2.Element()); EXPECT_EQ(scene.Element(), scene2.Element()); @@ -62,6 +66,8 @@ TEST(DOMScene, MoveConstruction) scene.SetGrid(false); scene.SetShadows(false); scene.SetOriginVisual(false); + sdf::Sky sky; + scene.SetSky(sky); sdf::Scene scene2(std::move(scene)); EXPECT_EQ(ignition::math::Color::Blue, scene2.Ambient()); @@ -69,6 +75,7 @@ TEST(DOMScene, MoveConstruction) EXPECT_FALSE(scene2.Grid()); EXPECT_FALSE(scene2.Shadows()); EXPECT_FALSE(scene2.OriginVisual()); + EXPECT_NE(nullptr, scene2.Sky()); } ///////////////////////////////////////////////// @@ -80,6 +87,8 @@ TEST(DOMScene, MoveAssignmentOperator) scene.SetGrid(false); scene.SetShadows(false); scene.SetOriginVisual(false); + sdf::Sky sky; + scene.SetSky(sky); sdf::Scene scene2; scene2 = std::move(scene); @@ -88,6 +97,7 @@ TEST(DOMScene, MoveAssignmentOperator) EXPECT_FALSE(scene2.Grid()); EXPECT_FALSE(scene2.Shadows()); EXPECT_FALSE(scene2.OriginVisual()); + EXPECT_NE(nullptr, scene2.Sky()); } ///////////////////////////////////////////////// @@ -99,6 +109,8 @@ TEST(DOMScene, AssignmentOperator) scene.SetGrid(false); scene.SetShadows(false); scene.SetOriginVisual(false); + sdf::Sky sky; + scene.SetSky(sky); sdf::Scene scene2; scene2 = scene; @@ -107,6 +119,7 @@ TEST(DOMScene, AssignmentOperator) EXPECT_FALSE(scene2.Grid()); EXPECT_FALSE(scene2.Shadows()); EXPECT_FALSE(scene2.OriginVisual()); + EXPECT_NE(nullptr, scene2.Sky()); } ///////////////////////////////////////////////// @@ -152,4 +165,8 @@ TEST(DOMScene, Set) EXPECT_TRUE(scene.OriginVisual()); scene.SetOriginVisual(false); EXPECT_FALSE(scene.OriginVisual()); + + sdf::Sky sky; + scene.SetSky(sky); + EXPECT_NE(nullptr, scene.Sky()); } diff --git a/src/Sky.cc b/src/Sky.cc new file mode 100644 index 000000000..2ce2ffb0a --- /dev/null +++ b/src/Sky.cc @@ -0,0 +1,235 @@ +/* + * Copyright 2020 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 "sdf/Sky.hh" +#include "Utils.hh" + +using namespace sdf; + +/// \brief Sky private data. +class sdf::SkyPrivate +{ + /// \brief Time of day + public: double time = 10.0; + + /// \brief Sunrise time + public: double sunrise = 6.0; + + /// \brief Sunset time + public: double sunset = 20.0; + + /// \brief Cloud speed + public: double cloudSpeed = 0.6; + + /// \brief Cloud direction. + public: ignition::math::Angle cloudDirection; + + /// \brief Cloud humidity + public: double cloudHumidity = 0.5; + + /// \brief Cloud mean size + public: double cloudMeanSize = 0.5; + + /// \brief Cloud ambient color + public: ignition::math::Color cloudAmbient = + ignition::math::Color(0.8f, 0.8f, 0.8f); + + /// \brief The SDF element pointer used during load. + public: sdf::ElementPtr sdf; +}; + +///////////////////////////////////////////////// +Sky::Sky() + : dataPtr(new SkyPrivate) +{ +} + +///////////////////////////////////////////////// +Sky::~Sky() +{ + delete this->dataPtr; + this->dataPtr = nullptr; +} + +///////////////////////////////////////////////// +Sky::Sky(const Sky &_sky) + : dataPtr(new SkyPrivate(*_sky.dataPtr)) +{ +} + +///////////////////////////////////////////////// +Sky::Sky(Sky &&_sky) noexcept + : dataPtr(std::exchange(_sky.dataPtr, nullptr)) +{ +} + +///////////////////////////////////////////////// +Sky &Sky::operator=(const Sky &_sky) +{ + return *this = Sky(_sky); +} + +///////////////////////////////////////////////// +Sky &Sky::operator=(Sky &&_sky) +{ + std::swap(this->dataPtr, _sky.dataPtr); + return *this; +} + +///////////////////////////////////////////////// +double Sky::Time() const +{ + return this->dataPtr->time; +} + +///////////////////////////////////////////////// +void Sky::SetTime(double _time) +{ + this->dataPtr->time = _time; +} + +///////////////////////////////////////////////// +double Sky::Sunrise() const +{ + return this->dataPtr->sunrise; +} + +///////////////////////////////////////////////// +void Sky::SetSunrise(double _sunrise) +{ + this->dataPtr->sunrise = _sunrise; +} + +///////////////////////////////////////////////// +double Sky::Sunset() const +{ + return this->dataPtr->sunset; +} + +///////////////////////////////////////////////// +void Sky::SetSunset(double _sunset) +{ + this->dataPtr->sunset = _sunset; +} + +///////////////////////////////////////////////// +double Sky::CloudSpeed() const +{ + return this->dataPtr->cloudSpeed; +} + +///////////////////////////////////////////////// +void Sky::SetCloudSpeed(double _speed) +{ + this->dataPtr->cloudSpeed = _speed; +} + +///////////////////////////////////////////////// +ignition::math::Angle Sky::CloudDirection() const +{ + return this->dataPtr->cloudDirection; +} + +///////////////////////////////////////////////// +void Sky::SetCloudDirection(const ignition::math::Angle &_angle) +{ + this->dataPtr->cloudDirection = _angle; +} + +///////////////////////////////////////////////// +double Sky::CloudHumidity() const +{ + return this->dataPtr->cloudHumidity; +} + +///////////////////////////////////////////////// +void Sky::SetCloudHumidity(double _humidity) +{ + this->dataPtr->cloudHumidity = _humidity; +} + +///////////////////////////////////////////////// +double Sky::CloudMeanSize() const +{ + return this->dataPtr->cloudMeanSize; +} + +///////////////////////////////////////////////// +void Sky::SetCloudMeanSize(double _size) +{ + this->dataPtr->cloudMeanSize = _size; +} + +///////////////////////////////////////////////// +ignition::math::Color Sky::CloudAmbient() const +{ + return this->dataPtr->cloudAmbient; +} + +///////////////////////////////////////////////// +void Sky::SetCloudAmbient(const ignition::math::Color &_ambient) +{ + this->dataPtr->cloudAmbient = _ambient; +} + +///////////////////////////////////////////////// +Errors Sky::Load(ElementPtr _sdf) +{ + Errors errors; + + this->dataPtr->sdf = _sdf; + + // Check that the provided SDF element is a element. + // This is an error that cannot be recovered, so return an error. + if (_sdf->GetName() != "sky") + { + errors.push_back({ErrorCode::ELEMENT_INCORRECT_TYPE, + "Attempting to load a Sky, but the provided SDF element is not a " + "."}); + return errors; + } + + this->dataPtr->time = _sdf->Get("time", this->dataPtr->time).first; + this->dataPtr->sunrise = + _sdf->Get("sunrise", this->dataPtr->sunrise).first; + this->dataPtr->sunset = + _sdf->Get("sunset", this->dataPtr->sunset).first; + + if ( _sdf->HasElement("clouds")) + { + sdf::ElementPtr cloudElem = _sdf->GetElement("clouds"); + this->dataPtr->cloudSpeed = + cloudElem->Get("speed", this->dataPtr->cloudSpeed).first; + this->dataPtr->cloudDirection = + cloudElem->Get("direction", + this->dataPtr->cloudDirection).first; + this->dataPtr->cloudHumidity = + cloudElem->Get("humidity", this->dataPtr->cloudHumidity).first; + this->dataPtr->cloudMeanSize = + cloudElem->Get("mean_size", this->dataPtr->cloudMeanSize).first; + this->dataPtr->cloudAmbient = + cloudElem->Get("ambient", + this->dataPtr->cloudAmbient).first; + } + + return errors; +} + +///////////////////////////////////////////////// +sdf::ElementPtr Sky::Element() const +{ + return this->dataPtr->sdf; +} diff --git a/src/Sky_TEST.cc b/src/Sky_TEST.cc new file mode 100644 index 000000000..03461bc43 --- /dev/null +++ b/src/Sky_TEST.cc @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2020 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 "sdf/Sky.hh" + +///////////////////////////////////////////////// +TEST(DOMSky, Construction) +{ + sdf::Sky sky; + EXPECT_DOUBLE_EQ(10.0, sky.Time()); + EXPECT_DOUBLE_EQ(6.0, sky.Sunrise()); + EXPECT_DOUBLE_EQ(20.0, sky.Sunset()); + EXPECT_DOUBLE_EQ(0.6, sky.CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(), sky.CloudDirection()); + EXPECT_DOUBLE_EQ(0.5, sky.CloudHumidity()); + EXPECT_DOUBLE_EQ(0.5, sky.CloudMeanSize()); + EXPECT_EQ(ignition::math::Color(0.8f, 0.8f, 0.8f), + sky.CloudAmbient()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, CopyConstruction) +{ + sdf::ElementPtr sdf(std::make_shared()); + + sdf::Sky sky; + sky.Load(sdf); + sky.SetTime(1.0); + sky.SetSunrise(5.0); + sky.SetSunset(15.0); + sky.SetCloudSpeed(0.3); + sky.SetCloudDirection(ignition::math::Angle(1.2)); + sky.SetCloudHumidity(0.9); + sky.SetCloudMeanSize(0.123); + sky.SetCloudAmbient(ignition::math::Color::Blue); + + sdf::Sky sky2(sky); + EXPECT_DOUBLE_EQ(1.0, sky2.Time()); + EXPECT_DOUBLE_EQ(5.0, sky2.Sunrise()); + EXPECT_DOUBLE_EQ(15.0, sky2.Sunset()); + EXPECT_DOUBLE_EQ(0.3, sky2.CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(1.2), sky2.CloudDirection()); + EXPECT_DOUBLE_EQ(0.9, sky2.CloudHumidity()); + EXPECT_DOUBLE_EQ(0.123, sky2.CloudMeanSize()); + EXPECT_EQ(ignition::math::Color::Blue, sky2.CloudAmbient()); + + EXPECT_NE(nullptr, sky2.Element()); + EXPECT_EQ(sky.Element(), sky2.Element()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, MoveConstruction) +{ + sdf::Sky sky; + sky.SetTime(1.0); + sky.SetSunrise(5.0); + sky.SetSunset(15.0); + sky.SetCloudSpeed(0.3); + sky.SetCloudDirection(ignition::math::Angle(1.2)); + sky.SetCloudHumidity(0.9); + sky.SetCloudMeanSize(0.123); + sky.SetCloudAmbient(ignition::math::Color::Blue); + + sdf::Sky sky2(std::move(sky)); + EXPECT_DOUBLE_EQ(1.0, sky2.Time()); + EXPECT_DOUBLE_EQ(5.0, sky2.Sunrise()); + EXPECT_DOUBLE_EQ(15.0, sky2.Sunset()); + EXPECT_DOUBLE_EQ(0.3, sky2.CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(1.2), sky2.CloudDirection()); + EXPECT_DOUBLE_EQ(0.9, sky2.CloudHumidity()); + EXPECT_DOUBLE_EQ(0.123, sky2.CloudMeanSize()); + EXPECT_EQ(ignition::math::Color::Blue, sky2.CloudAmbient()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, MoveAssignmentOperator) +{ + sdf::Sky sky; + sky.SetTime(1.0); + sky.SetSunrise(5.0); + sky.SetSunset(15.0); + sky.SetCloudSpeed(0.3); + sky.SetCloudDirection(ignition::math::Angle(1.2)); + sky.SetCloudHumidity(0.9); + sky.SetCloudMeanSize(0.123); + sky.SetCloudAmbient(ignition::math::Color::Blue); + + sdf::Sky sky2; + sky2 = std::move(sky); + EXPECT_DOUBLE_EQ(1.0, sky2.Time()); + EXPECT_DOUBLE_EQ(5.0, sky2.Sunrise()); + EXPECT_DOUBLE_EQ(15.0, sky2.Sunset()); + EXPECT_DOUBLE_EQ(0.3, sky2.CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(1.2), sky2.CloudDirection()); + EXPECT_DOUBLE_EQ(0.9, sky2.CloudHumidity()); + EXPECT_DOUBLE_EQ(0.123, sky2.CloudMeanSize()); + EXPECT_EQ(ignition::math::Color::Blue, sky2.CloudAmbient()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, AssignmentOperator) +{ + sdf::Sky sky; + sky.SetTime(1.0); + sky.SetSunrise(5.0); + sky.SetSunset(15.0); + sky.SetCloudSpeed(0.3); + sky.SetCloudDirection(ignition::math::Angle(1.2)); + sky.SetCloudHumidity(0.9); + sky.SetCloudMeanSize(0.123); + sky.SetCloudAmbient(ignition::math::Color::Blue); + + sdf::Sky sky2; + sky2 = sky; + EXPECT_DOUBLE_EQ(1.0, sky2.Time()); + EXPECT_DOUBLE_EQ(5.0, sky2.Sunrise()); + EXPECT_DOUBLE_EQ(15.0, sky2.Sunset()); + EXPECT_DOUBLE_EQ(0.3, sky2.CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(1.2), sky2.CloudDirection()); + EXPECT_DOUBLE_EQ(0.9, sky2.CloudHumidity()); + EXPECT_DOUBLE_EQ(0.123, sky2.CloudMeanSize()); + EXPECT_EQ(ignition::math::Color::Blue, sky2.CloudAmbient()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, CopyAssignmentAfterMove) +{ + sdf::Sky sky1; + sky1.SetTime(21.0); + + sdf::Sky sky2; + sky2.SetTime(1.0); + + // This is similar to what std::swap does except it uses std::move for each + // assignment + sdf::Sky tmp = std::move(sky1); + sky1 = sky2; + sky2 = tmp; + + EXPECT_DOUBLE_EQ(1.0, sky1.Time()); + EXPECT_DOUBLE_EQ(21.0, sky2.Time()); +} + +///////////////////////////////////////////////// +TEST(DOMSky, Set) +{ + sdf::Sky sky; + + sky.SetTime(1.0); + EXPECT_DOUBLE_EQ(1.0, sky.Time()); + + sky.SetSunrise(5.0); + EXPECT_DOUBLE_EQ(5.0, sky.Sunrise()); + + sky.SetSunset(15.0); + EXPECT_DOUBLE_EQ(15.0, sky.Sunset()); + + sky.SetCloudSpeed(0.3); + EXPECT_DOUBLE_EQ(0.3, sky.CloudSpeed()); + + sky.SetCloudDirection(ignition::math::Angle(1.2)); + EXPECT_EQ(ignition::math::Angle(1.2), sky.CloudDirection()); + + sky.SetCloudHumidity(0.9); + EXPECT_DOUBLE_EQ(0.9, sky.CloudHumidity()); + + sky.SetCloudMeanSize(0.123); + EXPECT_DOUBLE_EQ(0.123, sky.CloudMeanSize()); + + sky.SetCloudAmbient(ignition::math::Color(0.1f, 0.2f, 0.3f)); + EXPECT_EQ(ignition::math::Color(0.1f, 0.2f, 0.3f), + sky.CloudAmbient()); +} diff --git a/test/integration/CMakeLists.txt b/test/integration/CMakeLists.txt index 42fd7d6e8..e9cc14b14 100644 --- a/test/integration/CMakeLists.txt +++ b/test/integration/CMakeLists.txt @@ -33,6 +33,7 @@ set(tests plugin_include.cc provide_feedback.cc root_dom.cc + scene_dom.cc sdf_basic.cc sdf_custom.cc surface_dom.cc diff --git a/test/integration/scene_dom.cc b/test/integration/scene_dom.cc new file mode 100644 index 000000000..84ae92805 --- /dev/null +++ b/test/integration/scene_dom.cc @@ -0,0 +1,73 @@ +/* + * Copyright 2020 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 "sdf/Filesystem.hh" +#include "sdf/parser.hh" +#include "sdf/Root.hh" +#include "sdf/Scene.hh" +#include "sdf/SDFImpl.hh" +#include "sdf/Sky.hh" +#include "sdf/World.hh" + +#include "test_config.h" + +////////////////////////////////////////////////// +TEST(DOMScene, LoadScene) +{ + const std::string testFile = + sdf::filesystem::append(PROJECT_SOURCE_PATH, "test", "sdf", + "scene_with_sky.sdf"); + + sdf::Root root; + sdf::Errors errors = root.Load(testFile); + for (auto e : errors) + std::cout << e.Message() << std::endl; + EXPECT_TRUE(errors.empty()); + + ASSERT_NE(nullptr, root.Element()); + EXPECT_EQ(testFile, root.Element()->FilePath()); + + const sdf::World *world = root.WorldByIndex(0); + ASSERT_NE(nullptr, world); + + const sdf::Scene *scene = world->Scene(); + ASSERT_NE(nullptr, scene); + + EXPECT_EQ(ignition::math::Color(0.3f, 0.4f, 0.5f), scene->Ambient()); + EXPECT_EQ(ignition::math::Color(0.6f, 0.7f, 0.8f), scene->Background()); + EXPECT_TRUE(scene->Grid()); + EXPECT_TRUE(scene->Shadows()); + EXPECT_TRUE(scene->OriginVisual()); + + const sdf::Sky *sky = scene->Sky(); + ASSERT_NE(nullptr, sky); + + EXPECT_DOUBLE_EQ(3.0, sky->Time()); + EXPECT_DOUBLE_EQ(4.0, sky->Sunrise()); + EXPECT_DOUBLE_EQ(21.0, sky->Sunset()); + EXPECT_DOUBLE_EQ(1.2, sky->CloudSpeed()); + EXPECT_EQ(ignition::math::Angle(1.5), sky->CloudDirection()); + EXPECT_DOUBLE_EQ(0.2, sky->CloudMeanSize()); + EXPECT_DOUBLE_EQ(0.9, sky->CloudHumidity()); + EXPECT_EQ(ignition::math::Color(0.1f, 0.2f, 0.3f), sky->CloudAmbient()); +} diff --git a/test/sdf/scene_with_sky.sdf b/test/sdf/scene_with_sky.sdf new file mode 100644 index 000000000..1f794c443 --- /dev/null +++ b/test/sdf/scene_with_sky.sdf @@ -0,0 +1,26 @@ + + + + + + 0.3 0.4 0.5 + 0.6 0.7 0.8 + true + true + true + + + 4 + 21 + + 1.2 + 1.5 + 0.2 + 0.9 + 0.1 0.2 0.3 + + + + + +