Merge branch 'master' into NoRenderingMode
This commit is contained in:
commit
23ef5d73cc
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -4,11 +4,25 @@
|
|||
* Upgraded Boost to 1.69.0
|
||||
* Added point transformation functionality for LibCarla and PythonAPI
|
||||
* Added "sensor_tick" attribute to sensors (cameras and lidars) to specify the capture rate in seconds
|
||||
* Added Export/Import map tools
|
||||
* Added "get_forward_vector()" to rotation and transform, retrieves the unit vector on the rotation's X-axis
|
||||
* Added support for Deepin in PythonAPI's setup.py
|
||||
* Added support for spawning and controlling walkers (pedestrians)
|
||||
* Renamed vehicle.get_vehicle_control() to vehicle.get_control() to be consistent with walkers
|
||||
* Remove crash reporter from packaged build
|
||||
* Added a few methods to manage an actor:
|
||||
- set_velocity: for setting the linear velocity
|
||||
- set_angular_velocity: for setting the angular velocity
|
||||
- get_angular_velocity: for getting the angular velocity
|
||||
- add_impulse: for applying an impulse (in world axis)
|
||||
* Added support for gnss_sensor
|
||||
* Fixed TCP accept error, too many open files while creating and destroying a lot of sensors
|
||||
* Fixed lost error messages in client-side, now when a request fails it reports the reason
|
||||
* Improved simulator fatal error handling, now uses UE4 fatal error system
|
||||
* Fixed crash when an actor was destroyed but not de-registered, e.g. falling out of world bounds
|
||||
* LibCarla server pipeline now compiles with exceptions disabled for better performance and compatibility with UE4
|
||||
* OpenDriveActor has been rewritten using the Waypoint API, this has fixed some bugs
|
||||
* Updated BasicAgent to allow setting target_speed and handle US-style traffic lights properly
|
||||
|
||||
## CARLA 0.9.2
|
||||
|
||||
|
|
|
@ -28,10 +28,13 @@ C++
|
|||
rare occasions if it results in clearer code.
|
||||
* Compilation should not give any error or warning
|
||||
(`clang++-6.0 -Wall -Wextra -std=C++14 -Wno-missing-braces`).
|
||||
* The use of `throw` is forbidden, use `carla::throw_exception` instead.
|
||||
* Unreal C++ code (CarlaUE4 and Carla plugin) follow the
|
||||
[Unreal Engine's Coding Standard][ue4link] with the exception of using
|
||||
spaces instead of tabs.
|
||||
* LibCarla uses a variation of [Google's style guide][googlelink].
|
||||
* Uses of `try-catch` blocks should be surrounded by
|
||||
`#ifndef LIBCARLA_NO_EXCEPTIONS` if the code is used in the server-side.
|
||||
|
||||
[ue4link]: https://docs.unrealengine.com/latest/INT/Programming/Development/CodingStandard/
|
||||
[googlelink]: https://google.github.io/styleguide/cppguide.html
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<h1>Importing and exporting maps for distribution builds</h1>
|
||||
|
||||
!!! important
|
||||
The given scripts only works if the files are kept in the folders
|
||||
detailed below and on Linux.
|
||||
|
||||
This method and its scripts are aimed to reducing the size of the distribution
|
||||
build, allowing to import maps on distributed builds with a script, exporting
|
||||
them with yet another script from the editor.
|
||||
|
||||
<h4>How to export a map</h4>
|
||||
The current script only work for content placed into the
|
||||
"CarlaRoot/Unreal/CarlaUE4/Content/Carla/ExportedMaps" folder, inside the unreal's project
|
||||
structure. Once all the changes are saved in the editor and the maps to export
|
||||
are located in that folder, running
|
||||
|
||||
```sh
|
||||
make export-maps
|
||||
```
|
||||
|
||||
will clean, cook and pack the necessary assets with the maps. Please, note that
|
||||
there is no way of knowing what assets are on the project-to-import-to, so the
|
||||
final package will usually contain assets needed for the current project to work
|
||||
even though they might not be directly used in the exported map. Also, the maps
|
||||
referenced inside the Editor Properties will be exported due to the current way
|
||||
of cooking provided by Unreal.
|
||||
|
||||
!!! important
|
||||
This will only work if "Use pak file" is unchecked under the Packaging settings
|
||||
|
||||
Once the script is completed, the packed file can be found under ExportedMaps in
|
||||
the project's root.
|
||||
|
||||
<h4>How to import a map</h4>
|
||||
In order to do so, the file generated in the import phase has to be placed in a folder
|
||||
at the root of the distributed folder called "ExportedMaps". Once the zip is placed there,
|
||||
by running
|
||||
|
||||
```sh
|
||||
./ImportMaps.sh
|
||||
```
|
||||
|
||||
the content will get extracted and located properly where the executable can reach it. All
|
||||
the imported maps can be loaded by passing the convenient argument to the CarlaUE4.sh script.
|
|
@ -19,7 +19,7 @@ Also:
|
|||
- [Visual Studio](https://www.visualstudio.com/downloads/) (2017)
|
||||
|
||||
<h3>Environment Setup</h3>
|
||||
In order to build CARLA you must **enable the x64 Visual C++ Toolset**.
|
||||
In order to build CARLA you must **enable the x64 Visual C++ Toolset**. The Windows 8.1 SDK is also required for installation.
|
||||
I recommend to use this environment for everything you do in this tutorial.
|
||||
You have different options:
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* [Running in a Docker](carla_docker.md)
|
||||
* [How to make a new map with RoadRunner](how_to_make_a_new_map.md)
|
||||
* [How to link Epic's Automotive Materials](epic_automotive_materials.md)
|
||||
* [How to export and import maps to distribution builds](export_import_dist.md)
|
||||
|
||||
<h3>Contributing</h3>
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ pipeline {
|
|||
stage('Setup') {
|
||||
steps {
|
||||
sh 'make setup'
|
||||
sh './Update.sh'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,6 +42,12 @@ pipeline {
|
|||
}
|
||||
}
|
||||
|
||||
stage('Retrieve Content') {
|
||||
steps {
|
||||
sh './Update.sh'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Package') {
|
||||
steps {
|
||||
sh 'make package'
|
||||
|
|
|
@ -13,10 +13,11 @@ if (CMAKE_BUILD_TYPE STREQUAL "Client")
|
|||
add_subdirectory("client")
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Server")
|
||||
add_subdirectory("server")
|
||||
|
||||
if (NOT WIN32) # TODO(Andrei): Fix compilation for Windows
|
||||
add_subdirectory("test")
|
||||
endif()
|
||||
else ()
|
||||
message(FATAL_ERROR "Unknown build type '${CMAKE_BUILD_TYPE}'")
|
||||
endif ()
|
||||
|
||||
# GTest is not compiled on Windows.
|
||||
if (NOT WIN32)
|
||||
add_subdirectory("test")
|
||||
endif()
|
||||
|
|
|
@ -77,29 +77,35 @@ endif()
|
|||
|
||||
# carla_server library.
|
||||
|
||||
file(GLOB_RECURSE libcarla_server_sources
|
||||
"${libcarla_source_path}/carla/*.cpp"
|
||||
file(GLOB libcarla_server_sources
|
||||
"${libcarla_source_path}/carla/*.h"
|
||||
"${libcarla_source_path}/carla/Buffer.cpp"
|
||||
"${libcarla_source_path}/carla/Exception.cpp"
|
||||
"${libcarla_source_path}/carla/geom/*.cpp"
|
||||
"${libcarla_source_path}/carla/geom/*.h"
|
||||
"${libcarla_source_path}/carla/opendrive/*.cpp"
|
||||
"${libcarla_source_path}/carla/opendrive/*.h"
|
||||
"${libcarla_source_path}/carla/map/*.cpp"
|
||||
"${libcarla_source_path}/carla/map/*.h"
|
||||
"${libcarla_source_path}/carla/map/element/*.cpp"
|
||||
"${libcarla_source_path}/carla/map/element/*.h"
|
||||
"${libcarla_source_path}/carla/map/element/cephes/*.cpp"
|
||||
"${libcarla_source_path}/carla/map/element/cephes/*.h"
|
||||
"${libcarla_source_path}/carla/opendrive/parser/*.cpp"
|
||||
"${libcarla_source_path}/carla/opendrive/parser/*.h"
|
||||
"${libcarla_source_path}/carla/opendrive/parser/pugixml/*.cpp"
|
||||
"${libcarla_source_path}/carla/opendrive/parser/pugixml/*.hpp"
|
||||
"${libcarla_source_path}/carla/road/*.cpp"
|
||||
"${libcarla_source_path}/carla/road/*.h"
|
||||
"${libcarla_source_path}/carla/road/element/*.cpp"
|
||||
"${libcarla_source_path}/carla/road/element/*.h"
|
||||
"${libcarla_source_path}/carla/road/element/cephes/*.cpp"
|
||||
"${libcarla_source_path}/carla/road/element/cephes/*.h"
|
||||
"${libcarla_source_path}/carla/rpc/*.cpp"
|
||||
"${libcarla_source_path}/carla/rpc/*.h"
|
||||
"${libcarla_source_path}/carla/sensor/*.cpp"
|
||||
"${libcarla_source_path}/carla/sensor/*.h"
|
||||
"${libcarla_source_path}/carla/sensor/s11n/*.cpp"
|
||||
"${libcarla_source_path}/carla/sensor/s11n/*.h"
|
||||
"${libcarla_source_path}/carla/streaming/*.cpp"
|
||||
"${libcarla_source_path}/carla/streaming/*.h")
|
||||
"${libcarla_source_path}/carla/sensor/s11n/SensorHeaderSerializer.cpp"
|
||||
"${libcarla_source_path}/carla/streaming/*.h"
|
||||
"${libcarla_source_path}/carla/streaming/detail/*.cpp"
|
||||
"${libcarla_source_path}/carla/streaming/detail/*.h"
|
||||
"${libcarla_source_path}/carla/streaming/detail/tcp/*.cpp"
|
||||
"${libcarla_source_path}/carla/streaming/detail/tcp/*.h"
|
||||
"${libcarla_source_path}/carla/streaming/low_level/*.h")
|
||||
|
||||
# Create targets for debug and release in the same build type.
|
||||
foreach(target carla_server_debug carla_server)
|
||||
|
|
|
@ -1,18 +1,30 @@
|
|||
cmake_minimum_required(VERSION 3.5.1)
|
||||
project(libcarla-unit-tests)
|
||||
|
||||
file(GLOB_RECURSE libcarla_test_sources
|
||||
"${libcarla_source_path}/carla/profiler/*.h"
|
||||
"${libcarla_source_path}/carla/profiler/*.cpp"
|
||||
"${libcarla_source_path}/test/*.h"
|
||||
"${libcarla_source_path}/test/*.cpp")
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Client")
|
||||
set(carla_config client)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Server")
|
||||
set(carla_config server)
|
||||
endif ()
|
||||
|
||||
link_directories(
|
||||
${RPCLIB_LIB_PATH}
|
||||
${GTEST_LIB_PATH})
|
||||
|
||||
file(GLOB libcarla_test_sources
|
||||
"${libcarla_source_path}/carla/profiler/*.cpp"
|
||||
"${libcarla_source_path}/carla/profiler/*.h"
|
||||
"${libcarla_source_path}/test/*.cpp"
|
||||
"${libcarla_source_path}/test/*.h"
|
||||
"${libcarla_source_path}/test/${carla_config}/*.cpp"
|
||||
"${libcarla_source_path}/test/${carla_config}/*.h"
|
||||
"${libcarla_source_path}/test/common/*.cpp"
|
||||
"${libcarla_source_path}/test/common/*.h")
|
||||
|
||||
file(GLOB libcarla_test_client_sources "")
|
||||
|
||||
# Create targets for debug and release in the same build type.
|
||||
foreach(target libcarla_test_debug libcarla_test_release)
|
||||
foreach(target libcarla_test_${carla_config}_debug libcarla_test_${carla_config}_release)
|
||||
add_executable(${target} ${libcarla_test_sources})
|
||||
|
||||
target_compile_definitions(${target} PUBLIC
|
||||
|
@ -22,7 +34,8 @@ foreach(target libcarla_test_debug libcarla_test_release)
|
|||
target_include_directories(${target} PRIVATE
|
||||
"${BOOST_INCLUDE_PATH}"
|
||||
"${RPCLIB_INCLUDE_PATH}"
|
||||
"${GTEST_INCLUDE_PATH}")
|
||||
"${GTEST_INCLUDE_PATH}"
|
||||
"${libcarla_source_path}/test")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(${target} "gtest_main.lib")
|
||||
|
@ -38,10 +51,10 @@ foreach(target libcarla_test_debug libcarla_test_release)
|
|||
endforeach(target)
|
||||
|
||||
# Specific options for debug.
|
||||
set_target_properties(libcarla_test_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
target_link_libraries(libcarla_test_debug "carla_server_debug")
|
||||
target_compile_definitions(libcarla_test_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
set_target_properties(libcarla_test_${carla_config}_debug PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
target_link_libraries(libcarla_test_${carla_config}_debug "carla_${carla_config}_debug")
|
||||
target_compile_definitions(libcarla_test_${carla_config}_debug PUBLIC -DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
|
||||
|
||||
# Specific options for release.
|
||||
set_target_properties(libcarla_test_release PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
target_link_libraries(libcarla_test_release "carla_server")
|
||||
set_target_properties(libcarla_test_${carla_config}_release PROPERTIES COMPILE_FLAGS ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
target_link_libraries(libcarla_test_${carla_config}_release "carla_${carla_config}")
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/Logging.h"
|
||||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
@ -72,7 +73,9 @@ namespace carla {
|
|||
/// @copydoc Buffer(size_type)
|
||||
explicit Buffer(uint64_t size)
|
||||
: Buffer([size]() {
|
||||
DEBUG_ASSERT(size <= max_size());
|
||||
if (size > max_size()) {
|
||||
throw_exception(std::invalid_argument("message size too big"));
|
||||
}
|
||||
return static_cast<size_type>(size);
|
||||
} ()) {}
|
||||
|
||||
|
@ -245,7 +248,9 @@ namespace carla {
|
|||
|
||||
/// @copydoc reset(size_type)
|
||||
void reset(uint64_t size) {
|
||||
DEBUG_ASSERT(size <= max_size());
|
||||
if (size > max_size()) {
|
||||
throw_exception(std::invalid_argument("message size too big"));
|
||||
}
|
||||
reset(static_cast<size_type>(size));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/Exception.h"
|
||||
|
||||
// =============================================================================
|
||||
// -- Define boost::throw_exception --------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#ifdef BOOST_NO_EXCEPTIONS
|
||||
|
||||
namespace boost {
|
||||
|
||||
void throw_exception(const std::exception &e) {
|
||||
carla::throw_exception(e);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_NO_EXCEPTIONS
|
||||
|
||||
// =============================================================================
|
||||
// -- Workaround for Boost.Asio bundled with rpclib ----------------------------
|
||||
// =============================================================================
|
||||
|
||||
#ifdef ASIO_NO_EXCEPTIONS
|
||||
|
||||
#include <exception>
|
||||
#include <system_error>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace clmdep_asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Exception>
|
||||
void throw_exception(const Exception& e) {
|
||||
carla::throw_exception(e);
|
||||
}
|
||||
|
||||
template void throw_exception<std::bad_cast>(const std::bad_cast &);
|
||||
template void throw_exception<std::exception>(const std::exception &);
|
||||
template void throw_exception<std::system_error>(const std::system_error &);
|
||||
|
||||
} // namespace detail
|
||||
} // namespace clmdep_asio
|
||||
|
||||
#endif // ASIO_NO_EXCEPTIONS
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef LIBCARLA_NO_EXCEPTIONS
|
||||
|
||||
namespace std {
|
||||
|
||||
class exception;
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace carla {
|
||||
|
||||
/// User define function, similar to Boost throw_exception.
|
||||
///
|
||||
/// @important Boost exceptions are also routed to this function.
|
||||
///
|
||||
/// When compiled with LIBCARLA_NO_EXCEPTIONS, this function is left undefined
|
||||
/// in LibCarla, and the modules using LibCarla are expected to supply an
|
||||
/// appropriate definition. Callers of throw_exception are allowed to assume
|
||||
/// that the function never returns; therefore, if the user-defined
|
||||
/// throw_exception returns, the behavior is undefined.
|
||||
[[ noreturn ]] void throw_exception(const std::exception &e);
|
||||
|
||||
} // namespace carla
|
||||
|
||||
#else
|
||||
|
||||
namespace carla {
|
||||
|
||||
template <typename T>
|
||||
[[ noreturn ]] void throw_exception(const T &e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
} // namespace carla
|
||||
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
|
@ -0,0 +1,162 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/MsgPack.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace clmdep_msgpack {
|
||||
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
|
||||
namespace adaptor {
|
||||
|
||||
// ===========================================================================
|
||||
// -- Adaptors for boost::optional -------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
template<typename T>
|
||||
struct convert<boost::optional<T>> {
|
||||
const clmdep_msgpack::object &operator()(
|
||||
const clmdep_msgpack::object &o,
|
||||
boost::optional<T> &v) const {
|
||||
if (o.type != clmdep_msgpack::type::ARRAY) {
|
||||
::carla::throw_exception(clmdep_msgpack::type_error());
|
||||
}
|
||||
if (o.via.array.size == 1) {
|
||||
v.reset();
|
||||
} else if (o.via.array.size == 2) {
|
||||
v.reset(o.via.array.ptr[1].as<T>());
|
||||
} else {
|
||||
::carla::throw_exception(clmdep_msgpack::type_error());
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pack<boost::optional<T>> {
|
||||
template <typename Stream>
|
||||
packer<Stream> &operator()(
|
||||
clmdep_msgpack::packer<Stream> &o,
|
||||
const boost::optional<T> &v) const {
|
||||
if (v.has_value()) {
|
||||
o.pack_array(2);
|
||||
o.pack(true);
|
||||
o.pack(*v);
|
||||
} else {
|
||||
o.pack_array(1);
|
||||
o.pack(false);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct object_with_zone<boost::optional<T>> {
|
||||
void operator()(
|
||||
clmdep_msgpack::object::with_zone &o,
|
||||
const boost::optional<T> &v) const {
|
||||
o.type = type::ARRAY;
|
||||
if (v.has_value()) {
|
||||
o.via.array.size = 2;
|
||||
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
|
||||
sizeof(clmdep_msgpack::object) * o.via.array.size,
|
||||
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
|
||||
o.via.array.ptr[0] = clmdep_msgpack::object(true, o.zone);
|
||||
o.via.array.ptr[1] = clmdep_msgpack::object(*v, o.zone);
|
||||
} else {
|
||||
o.via.array.size = 1;
|
||||
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
|
||||
sizeof(clmdep_msgpack::object) * o.via.array.size,
|
||||
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
|
||||
o.via.array.ptr[0] = clmdep_msgpack::object(false, o.zone);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// -- Adaptors for boost::variant --------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
template<typename... Ts>
|
||||
struct convert<boost::variant<Ts...>> {
|
||||
|
||||
const clmdep_msgpack::object &operator()(
|
||||
const clmdep_msgpack::object &o,
|
||||
boost::variant<Ts...> &v) const {
|
||||
if (o.type != clmdep_msgpack::type::ARRAY) {
|
||||
::carla::throw_exception(clmdep_msgpack::type_error());
|
||||
}
|
||||
if (o.via.array.size != 2) {
|
||||
::carla::throw_exception(clmdep_msgpack::type_error());
|
||||
}
|
||||
const auto index = o.via.array.ptr[0].as<int>();
|
||||
copy_to_variant(index, o, v, std::make_index_sequence<sizeof...(Ts)>());
|
||||
return o;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <size_t I>
|
||||
static void copy_to_variant_impl(
|
||||
const clmdep_msgpack::object &o,
|
||||
boost::variant<Ts...> &v) {
|
||||
/// @todo Workaround for finding the type.
|
||||
auto dummy = std::get<I>(std::tuple<Ts...>{});
|
||||
using T = decltype(dummy);
|
||||
v = o.via.array.ptr[1].as<T>();
|
||||
}
|
||||
|
||||
template <size_t... Is>
|
||||
static void copy_to_variant(
|
||||
const size_t index,
|
||||
const clmdep_msgpack::object &o,
|
||||
boost::variant<Ts...> &v,
|
||||
std::index_sequence<Is...>) {
|
||||
std::initializer_list<int> ({
|
||||
(index == Is ? copy_to_variant_impl<Is>(o, v), 0 : 0)...
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct pack<boost::variant<Ts...>> {
|
||||
template <typename Stream>
|
||||
packer<Stream> &operator()(
|
||||
clmdep_msgpack::packer<Stream> &o,
|
||||
const boost::variant<Ts...> &v) const {
|
||||
o.pack_array(2);
|
||||
o.pack(static_cast<int>(v.which()));
|
||||
boost::apply_visitor([&](const auto &value) { o.pack(value); }, v);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct object_with_zone<boost::variant<Ts...>> {
|
||||
void operator()(
|
||||
clmdep_msgpack::object::with_zone &o,
|
||||
const boost::variant<Ts...> &v) const {
|
||||
o.type = type::ARRAY;
|
||||
o.via.array.size = 2;
|
||||
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
|
||||
sizeof(clmdep_msgpack::object) * o.via.array.size,
|
||||
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
|
||||
o.via.array.ptr[0] = clmdep_msgpack::object(static_cast<int>(v.which()), o.zone);
|
||||
boost::apply_visitor([&](const auto &value) {
|
||||
o.via.array.ptr[1] = clmdep_msgpack::object(value, o.zone);
|
||||
}, v);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adaptor
|
||||
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
|
||||
} // namespace msgpack
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace carla {
|
||||
|
||||
template <typename T>
|
||||
class Optional : private boost::optional<T> {
|
||||
using parent_type = boost::optional<T>;
|
||||
public:
|
||||
|
||||
template <typename... Args>
|
||||
explicit Optional(Args &&... args)
|
||||
: parent_type(std::forward<Args>(args)...) {}
|
||||
|
||||
using parent_type::operator*;
|
||||
using parent_type::operator->;
|
||||
using parent_type::operator=;
|
||||
using parent_type::emplace;
|
||||
using parent_type::reset;
|
||||
using parent_type::swap;
|
||||
// using parent_type::value; disabled to avoid exceptions.
|
||||
using parent_type::value_or;
|
||||
|
||||
bool has_value() const {
|
||||
return parent_type::is_initialized();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace carla
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/Time.h"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
@ -99,10 +100,12 @@ namespace detail {
|
|||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
auto &r = _map[&detail::thread_tag];
|
||||
r.should_wait = true;
|
||||
if (!_cv.wait_for(lock, timeout.to_chrono(), [&]() { return !r.should_wait; }))
|
||||
throw std::runtime_error("RecurrentSharedFuture.WaitFor: time-out");
|
||||
if (r.value.which() == 1)
|
||||
throw boost::get<SharedException>(r.value);
|
||||
if (!_cv.wait_for(lock, timeout.to_chrono(), [&]() { return !r.should_wait; })) {
|
||||
throw_exception(std::runtime_error("RecurrentSharedFuture.WaitFor: time-out"));
|
||||
}
|
||||
if (r.value.which() == 1) {
|
||||
throw_exception(boost::get<SharedException>(r.value));
|
||||
}
|
||||
return boost::get<T>(std::move(r.value));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,14 @@ namespace client {
|
|||
return GetEpisode().Lock()->GetActorVelocity(*this);
|
||||
}
|
||||
|
||||
geom::Vector3D Actor::GetAngularVelocity() const {
|
||||
return GetEpisode().Lock()->GetActorAngularVelocity(*this);
|
||||
}
|
||||
|
||||
void Actor::SetAngularVelocity(const geom::Vector3D &vector) {
|
||||
GetEpisode().Lock()->SetActorAngularVelocity(*this, vector);
|
||||
}
|
||||
|
||||
geom::Vector3D Actor::GetAcceleration() const {
|
||||
return GetEpisode().Lock()->GetActorAcceleration(*this);
|
||||
}
|
||||
|
@ -36,6 +44,14 @@ namespace client {
|
|||
GetEpisode().Lock()->SetActorTransform(*this, transform);
|
||||
}
|
||||
|
||||
void Actor::SetVelocity(const geom::Vector3D &vector) {
|
||||
GetEpisode().Lock()->SetActorVelocity(*this, vector);
|
||||
}
|
||||
|
||||
void Actor::AddImpulse(const geom::Vector3D &vector) {
|
||||
GetEpisode().Lock()->AddActorImpulse(*this, vector);
|
||||
}
|
||||
|
||||
void Actor::SetSimulatePhysics(const bool enabled) {
|
||||
GetEpisode().Lock()->SetActorSimulatePhysics(*this, enabled);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ namespace client {
|
|||
/// velocity received in the last tick.
|
||||
geom::Vector3D GetVelocity() const;
|
||||
|
||||
/// Return the current 3D angular velocity of the actor.
|
||||
///
|
||||
/// @note This function does not call the simulator, it returns the
|
||||
/// angular velocity received in the last tick.
|
||||
geom::Vector3D GetAngularVelocity() const;
|
||||
|
||||
/// Return the current 3D acceleration of the actor.
|
||||
///
|
||||
/// @note This function does not call the simulator, it returns the
|
||||
|
@ -58,9 +64,18 @@ namespace client {
|
|||
/// Teleport and rotate the actor to @a transform.
|
||||
void SetTransform(const geom::Transform &transform);
|
||||
|
||||
/// Set the actor velocity.
|
||||
void SetVelocity(const geom::Vector3D &vector);
|
||||
|
||||
/// Add impulse to the actor.
|
||||
void AddImpulse(const geom::Vector3D &vector);
|
||||
|
||||
/// Enable or disable physics simulation on this actor.
|
||||
void SetSimulatePhysics(bool enabled = true);
|
||||
|
||||
/// Set the angular velocity of the actor
|
||||
void SetAngularVelocity(const geom::Vector3D &vector);
|
||||
|
||||
/// @warning This method only checks whether this instance of Actor has
|
||||
/// called the Destroy() method, it does not check whether the actor is
|
||||
/// actually alive in the simulator.
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
|
||||
#include "carla/client/ActorAttribute.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/StringUtil.h"
|
||||
|
||||
namespace carla {
|
||||
namespace client {
|
||||
|
||||
#define LIBCARLA_THROW_INVALID_VALUE(message) throw InvalidAttributeValue(GetId() + ": " + message);
|
||||
#define LIBCARLA_THROW_INVALID_VALUE(message) throw_exception(InvalidAttributeValue(GetId() + ": " + message));
|
||||
#define LIBCARLA_THROW_BAD_VALUE_CAST(type) \
|
||||
if (GetType() != rpc::ActorAttributeType:: type) { \
|
||||
throw BadAttributeCast(GetId() + ": bad attribute cast: cannot convert to " #type); \
|
||||
throw_exception(BadAttributeCast(GetId() + ": bad attribute cast: cannot convert to " #type)); \
|
||||
}
|
||||
|
||||
void ActorAttribute::Set(std::string value) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "carla/client/ActorBlueprint.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/StringUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -41,7 +42,7 @@ namespace client {
|
|||
auto it = _attributes.find(id);
|
||||
if (it == _attributes.end()) {
|
||||
using namespace std::string_literals;
|
||||
throw std::out_of_range("attribute '"s + id + "' not found");
|
||||
throw_exception(std::out_of_range("attribute '"s + id + "' not found"));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "carla/client/BlueprintLibrary.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
|
@ -40,14 +42,15 @@ namespace client {
|
|||
auto it = _blueprints.find(key);
|
||||
if (it == _blueprints.end()) {
|
||||
using namespace std::string_literals;
|
||||
throw std::out_of_range("blueprint '"s + key + "' not found");
|
||||
throw_exception(std::out_of_range("blueprint '"s + key + "' not found"));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
BlueprintLibrary::const_reference BlueprintLibrary::at(size_type pos) const {
|
||||
if (pos >= size())
|
||||
throw std::out_of_range("index out of range");
|
||||
if (pos >= size()) {
|
||||
throw_exception(std::out_of_range("index out of range"));
|
||||
}
|
||||
return operator[](pos);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace client {
|
|||
}
|
||||
|
||||
if (GetParent() == nullptr) {
|
||||
throw std::runtime_error(GetDisplayId() + ": not attached to vehicle");
|
||||
throw_exception(std::runtime_error(GetDisplayId() + ": not attached to vehicle"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace client {
|
|||
}
|
||||
|
||||
void LaneDetector::Stop() {
|
||||
throw std::runtime_error("LaneDetector::Stop(): not implemented.");
|
||||
throw_exception(std::runtime_error("LaneDetector::Stop(): not implemented."));
|
||||
}
|
||||
|
||||
SharedPtr<sensor::SensorData> LaneDetector::TickLaneDetector(
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace client {
|
|||
const geom::Location &location,
|
||||
bool project_to_road) const {
|
||||
DEBUG_ASSERT(_map != nullptr);
|
||||
Optional<road::element::Waypoint> waypoint;
|
||||
boost::optional<road::element::Waypoint> waypoint;
|
||||
if (project_to_road) {
|
||||
waypoint = _map->GetClosestWaypointOnRoad(location);
|
||||
} else {
|
||||
|
|
|
@ -55,12 +55,7 @@ namespace client {
|
|||
const ActorBlueprint &blueprint,
|
||||
const geom::Transform &transform,
|
||||
Actor *parent_actor) {
|
||||
try {
|
||||
return _episode.Lock()->SpawnActor(blueprint, transform, parent_actor);
|
||||
} catch (const std::exception &e) {
|
||||
log_warning("SpawnActor: failed with:", e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<Actor> World::TrySpawnActor(
|
||||
|
@ -69,7 +64,7 @@ namespace client {
|
|||
Actor *parent_actor) noexcept {
|
||||
try {
|
||||
return SpawnActor(blueprint, transform, parent_actor);
|
||||
} catch (const std::exception &) {
|
||||
} catch (const std::exception &e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "carla/rpc/ActorDescription.h"
|
||||
#include "carla/rpc/Client.h"
|
||||
#include "carla/rpc/DebugShape.h"
|
||||
#include "carla/rpc/Response.h"
|
||||
#include "carla/rpc/VehicleControl.h"
|
||||
#include "carla/rpc/WalkerControl.h"
|
||||
#include "carla/streaming/Client.h"
|
||||
|
@ -20,6 +21,15 @@ namespace carla {
|
|||
namespace client {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
static T Get(carla::rpc::Response<T> &response) {
|
||||
return response.Get();
|
||||
}
|
||||
|
||||
static bool Get(carla::rpc::Response<void> &) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Client::Pimpl ----------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
@ -35,8 +45,14 @@ namespace detail {
|
|||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T CallAndWait(const std::string &function, Args &&... args) {
|
||||
return rpc_client.call(function, std::forward<Args>(args)...).template as<T>();
|
||||
auto CallAndWait(const std::string &function, Args &&... args) {
|
||||
auto object = rpc_client.call(function, std::forward<Args>(args)...);
|
||||
using R = typename carla::rpc::Response<T>;
|
||||
auto response = object.template as<R>();
|
||||
if (response.HasError()) {
|
||||
throw_exception(std::runtime_error(response.GetError().What()));
|
||||
}
|
||||
return Get(response);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
|
@ -121,7 +137,13 @@ namespace detail {
|
|||
}
|
||||
|
||||
bool Client::DestroyActor(const rpc::Actor &actor) {
|
||||
return _pimpl->CallAndWait<bool>("destroy_actor", actor);
|
||||
try {
|
||||
return _pimpl->CallAndWait<void>("destroy_actor", actor);
|
||||
} catch (const std::exception &e) {
|
||||
log_error("failed to destroy actor:", actor.id, actor.description.id);
|
||||
log_error(e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SetActorLocation(const rpc::Actor &actor, const geom::Location &location) {
|
||||
|
@ -148,6 +170,18 @@ namespace detail {
|
|||
_pimpl->AsyncCall("apply_control_to_walker", walker, control);
|
||||
}
|
||||
|
||||
void Client::SetActorVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) {
|
||||
_pimpl->AsyncCall("set_actor_velocity", actor, vector);
|
||||
}
|
||||
|
||||
void Client::SetActorAngularVelocity(const rpc::Actor &actor, const geom::Vector3D &vector) {
|
||||
_pimpl->AsyncCall("set_actor_angular_velocity", actor, vector);
|
||||
}
|
||||
|
||||
void Client::AddActorImpulse(const rpc::Actor &actor, const geom::Vector3D &vector) {
|
||||
_pimpl->AsyncCall("add_actor_impulse", actor, vector);
|
||||
}
|
||||
|
||||
void Client::SubscribeToStream(
|
||||
const streaming::Token &token,
|
||||
std::function<void(Buffer)> callback) {
|
||||
|
|
|
@ -107,6 +107,18 @@ namespace detail {
|
|||
const rpc::Actor &walker,
|
||||
const rpc::WalkerControl &control);
|
||||
|
||||
void SetActorVelocity(
|
||||
const rpc::Actor &actor,
|
||||
const geom::Vector3D &vector);
|
||||
|
||||
void SetActorAngularVelocity(
|
||||
const rpc::Actor &actor,
|
||||
const geom::Vector3D &vector);
|
||||
|
||||
void AddActorImpulse(
|
||||
const rpc::Actor &actor,
|
||||
const geom::Vector3D &vector);
|
||||
|
||||
void SubscribeToStream(
|
||||
const streaming::Token &token,
|
||||
std::function<void(Buffer)> callback);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "carla/client/detail/EpisodeProxy.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/client/detail/Simulator.h"
|
||||
|
||||
#include <exception>
|
||||
|
@ -38,14 +39,14 @@ namespace detail {
|
|||
typename EpisodeProxyImpl<T>::SharedPtrType EpisodeProxyImpl<T>::Lock() const {
|
||||
auto ptr = Load(_simulator);
|
||||
if (ptr == nullptr) {
|
||||
throw std::runtime_error(
|
||||
throw_exception(std::runtime_error(
|
||||
"trying to operate on a destroyed actor; an actor's function "
|
||||
"was called, but the actor is already destroyed.");
|
||||
"was called, but the actor is already destroyed."));
|
||||
}
|
||||
if (_episode_id != ptr->GetCurrentEpisodeId()) {
|
||||
throw std::runtime_error(
|
||||
throw_exception(std::runtime_error(
|
||||
"trying to access an expired episode; a new episode was started "
|
||||
"in the simulation but an object tried accessing the old one.");
|
||||
"in the simulation but an object tried accessing the old one."));
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace detail {
|
|||
DEBUG_ONLY(auto result = )
|
||||
next->_actors.emplace(
|
||||
actor.id,
|
||||
ActorState{actor.transform, actor.velocity, acceleration, actor.state});
|
||||
ActorState{actor.transform, actor.velocity, actor.angular_velocity, acceleration, actor.state});
|
||||
DEBUG_ASSERT(result.second);
|
||||
}
|
||||
return next;
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace detail {
|
|||
struct ActorState {
|
||||
geom::Transform transform;
|
||||
geom::Vector3D velocity;
|
||||
geom::Vector3D angular_velocity;
|
||||
geom::Vector3D acceleration;
|
||||
sensor::data::ActorDynamicState::TypeDependentState state;
|
||||
};
|
||||
|
|
|
@ -173,6 +173,22 @@ namespace detail {
|
|||
return GetActorDynamicState(actor).velocity;
|
||||
}
|
||||
|
||||
void SetActorVelocity(const Actor &actor, const geom::Vector3D &vector) {
|
||||
_client.SetActorVelocity(actor.Serialize(), vector);
|
||||
}
|
||||
|
||||
geom::Vector3D GetActorAngularVelocity(const Actor &actor) const {
|
||||
return GetActorDynamicState(actor).angular_velocity;
|
||||
}
|
||||
|
||||
void SetActorAngularVelocity(const Actor &actor, const geom::Vector3D &vector) {
|
||||
_client.SetActorAngularVelocity(actor.Serialize(), vector);
|
||||
}
|
||||
|
||||
void AddActorImpulse(const Actor &actor, const geom::Vector3D &vector) {
|
||||
_client.AddActorImpulse(actor.Serialize(), vector);
|
||||
}
|
||||
|
||||
geom::Vector3D GetActorAcceleration(const Actor &actor) const {
|
||||
return GetActorDynamicState(actor).acceleration;
|
||||
}
|
||||
|
|
|
@ -131,6 +131,35 @@ namespace geom {
|
|||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// -- Conversions to UE4 types ---------------------------------------------
|
||||
// =========================================================================
|
||||
|
||||
#ifdef LIBCARLA_INCLUDED_FROM_UE4
|
||||
|
||||
Vector3D(const FVector &vector)
|
||||
: Vector3D(vector.X, vector.Y, vector.Z) {}
|
||||
|
||||
Vector3D &ToMeters(void) { // from centimeters to meters.
|
||||
x *= 0.001f;
|
||||
y *= 0.001f;
|
||||
z *= 0.001f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3D &ToCentimeters(void) { // from meters to centimeters.
|
||||
x *= 100.0f;
|
||||
y *= 100.0f;
|
||||
z *= 100.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator FVector() const {
|
||||
return FVector{x, y, z};
|
||||
}
|
||||
|
||||
#endif // LIBCARLA_INCLUDED_FROM_UE4
|
||||
|
||||
// =========================================================================
|
||||
/// @todo The following is copy-pasted from MSGPACK_DEFINE_ARRAY.
|
||||
/// This is a workaround for an issue in msgpack library. The
|
||||
|
|
|
@ -17,16 +17,16 @@ namespace road {
|
|||
return Waypoint(shared_from_this(), loc);
|
||||
}
|
||||
|
||||
Optional<Waypoint> Map::GetWaypoint(const geom::Location &loc) const {
|
||||
boost::optional<Waypoint> Map::GetWaypoint(const geom::Location &loc) const {
|
||||
Waypoint w = Waypoint(shared_from_this(), loc);
|
||||
auto d = geom::Math::Distance2D(w.ComputeTransform().location, loc);
|
||||
const RoadInfoLane *inf = _data.GetRoad(w._road_id)->GetInfo<RoadInfoLane>(w._dist);
|
||||
|
||||
if (d < inf->getLane(w._lane_id)->_width * 0.5) {
|
||||
return Optional<Waypoint>(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
return Optional<Waypoint>();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<element::LaneMarking> Map::CalculateCrossedLanes(
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
|
||||
#include "carla/Memory.h"
|
||||
#include "carla/NonCopyable.h"
|
||||
#include "carla/Optional.h"
|
||||
#include "carla/road/MapData.h"
|
||||
#include "carla/road/element/LaneMarking.h"
|
||||
#include "carla/road/element/Waypoint.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace carla {
|
||||
|
@ -29,7 +30,7 @@ namespace road {
|
|||
|
||||
element::Waypoint GetClosestWaypointOnRoad(const geom::Location &) const;
|
||||
|
||||
Optional<element::Waypoint> GetWaypoint(const geom::Location &) const;
|
||||
boost::optional<element::Waypoint> GetWaypoint(const geom::Location &) const;
|
||||
|
||||
std::vector<element::LaneMarking> CalculateCrossedLanes(
|
||||
const geom::Location &origin,
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace road {
|
|||
waypoint.GetRoadSegment().GetPrevLane(this_lane_id);
|
||||
|
||||
if (next_lanes.empty()) {
|
||||
log_error("lane id =", this_lane_id, " road id=", this_road_id, ": missing next lanes");
|
||||
log_error("road id =", this_road_id, "lane id =", this_lane_id, ": missing next lanes");
|
||||
}
|
||||
|
||||
std::vector<Waypoint> result;
|
||||
|
@ -120,6 +120,40 @@ namespace road {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<Waypoint> WaypointGenerator::GenerateLaneBegin(
|
||||
const Map &map) {
|
||||
std::vector<Waypoint> result;
|
||||
for (auto &&road_segment : map.GetData().GetRoadSegments()) {
|
||||
ForEachDrivableLane(road_segment, 0.0, [&](auto lane_id) {
|
||||
auto distance = lane_id < 0 ? 0.0 : road_segment.GetLength();
|
||||
auto this_waypoint = Waypoint(
|
||||
map.shared_from_this(),
|
||||
road_segment.GetId(),
|
||||
lane_id,
|
||||
distance);
|
||||
result.push_back(this_waypoint);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Waypoint> WaypointGenerator::GenerateLaneEnd(
|
||||
const Map &map) {
|
||||
std::vector<Waypoint> result;
|
||||
for (auto &&road_segment : map.GetData().GetRoadSegments()) {
|
||||
ForEachDrivableLane(road_segment, 0.0, [&](auto lane_id) {
|
||||
auto distance = lane_id > 0 ? 0.0 : road_segment.GetLength();
|
||||
auto this_waypoint = Waypoint(
|
||||
map.shared_from_this(),
|
||||
road_segment.GetId(),
|
||||
lane_id,
|
||||
distance);
|
||||
result.push_back(this_waypoint);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::pair<Waypoint, Waypoint>> WaypointGenerator::GenerateTopology(
|
||||
const Map &map) {
|
||||
std::vector<std::pair<Waypoint, Waypoint>> result;
|
||||
|
|
|
@ -38,10 +38,19 @@ namespace road {
|
|||
const Map &map,
|
||||
double approx_distance);
|
||||
|
||||
/// Returns a list of waypoints at the beginning of each lane of the map.
|
||||
static std::vector<Waypoint> GenerateLaneBegin(
|
||||
const Map &map);
|
||||
|
||||
/// Returns a list of waypoints at the end of each lane of the map.
|
||||
static std::vector<Waypoint> GenerateLaneEnd(
|
||||
const Map &map);
|
||||
|
||||
/// Generate the minimum set of waypoints that define the topology of @a
|
||||
/// map. The waypoints are placed at the entrance of each lane.
|
||||
static std::vector<std::pair<Waypoint, Waypoint>> GenerateTopology(
|
||||
const Map &map);
|
||||
|
||||
};
|
||||
|
||||
} // namespace road
|
||||
|
|
|
@ -24,7 +24,8 @@ namespace rpc {
|
|||
|
||||
actor_id_type id = 0u;
|
||||
|
||||
actor_id_type parent_id;
|
||||
/// @todo parent should not be here as it may change during the simulation.
|
||||
actor_id_type parent_id = 0u;
|
||||
|
||||
ActorDescription description;
|
||||
|
||||
|
|
|
@ -6,15 +6,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "carla/MsgPack.h"
|
||||
#include "carla/MsgPackAdaptors.h"
|
||||
#include "carla/geom/BoundingBox.h"
|
||||
#include "carla/geom/Location.h"
|
||||
#include "carla/geom/Rotation.h"
|
||||
#include "carla/rpc/Color.h"
|
||||
#include "carla/rpc/Variant.h"
|
||||
|
||||
// #include <rpc/msgpack/adaptor/boost/msgpack_variant.hpp>
|
||||
|
||||
// #include <boost/variant.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace carla {
|
||||
namespace rpc {
|
||||
|
@ -55,7 +54,7 @@ namespace rpc {
|
|||
MSGPACK_DEFINE_ARRAY(location, text, draw_shadow);
|
||||
};
|
||||
|
||||
Variant<Point, Line, Arrow, Box, String> primitive;
|
||||
boost::variant<Point, Line, Arrow, Box, String> primitive;
|
||||
|
||||
Color color = {255u, 0u, 0u};
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/MsgPack.h"
|
||||
#include "carla/MsgPackAdaptors.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace carla {
|
||||
namespace rpc {
|
||||
|
||||
class ResponseError {
|
||||
public:
|
||||
|
||||
ResponseError() = default;
|
||||
|
||||
explicit ResponseError(std::string message)
|
||||
: _what(std::move(message)) {}
|
||||
|
||||
const std::string &What() const {
|
||||
return _what;
|
||||
}
|
||||
|
||||
MSGPACK_DEFINE_ARRAY(_what)
|
||||
|
||||
private:
|
||||
|
||||
std::string _what;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Response {
|
||||
public:
|
||||
|
||||
using value_type = T;
|
||||
|
||||
using error_type = ResponseError;
|
||||
|
||||
Response() = default;
|
||||
|
||||
template <typename TValue>
|
||||
Response(TValue &&value) : _data(std::forward<TValue>(value)) {}
|
||||
|
||||
template <typename TValue>
|
||||
void Reset(TValue &&value) {
|
||||
_data = std::forward<TValue>(value);
|
||||
}
|
||||
|
||||
bool HasError() const {
|
||||
return _data.which() == 0;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void SetError(Ts &&... args) {
|
||||
_data = error_type(std::forward<Ts>(args)...);
|
||||
}
|
||||
|
||||
const error_type &GetError() const {
|
||||
DEBUG_ASSERT(HasError());
|
||||
return boost::get<error_type>(_data);
|
||||
}
|
||||
|
||||
value_type &Get() {
|
||||
DEBUG_ASSERT(!HasError());
|
||||
return boost::get<value_type>(_data);
|
||||
}
|
||||
|
||||
const value_type &Get() const {
|
||||
DEBUG_ASSERT(!HasError());
|
||||
return boost::get<value_type>(_data);
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return !HasError();
|
||||
}
|
||||
|
||||
MSGPACK_DEFINE_ARRAY(_data)
|
||||
|
||||
private:
|
||||
|
||||
boost::variant<error_type, value_type> _data;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Response<void> {
|
||||
public:
|
||||
|
||||
using value_type = void;
|
||||
|
||||
using error_type = ResponseError;
|
||||
|
||||
static Response Success() {
|
||||
return success_flag{};
|
||||
}
|
||||
|
||||
Response() : _data(error_type{}) {}
|
||||
|
||||
Response(ResponseError error) : _data(std::move(error)) {}
|
||||
|
||||
bool HasError() const {
|
||||
return _data.has_value();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void SetError(Ts &&... args) {
|
||||
_data = error_type(std::forward<Ts>(args)...);
|
||||
}
|
||||
|
||||
const error_type &GetError() const {
|
||||
DEBUG_ASSERT(HasError());
|
||||
return *_data;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return !HasError();
|
||||
}
|
||||
|
||||
MSGPACK_DEFINE_ARRAY(_data)
|
||||
|
||||
private:
|
||||
|
||||
struct success_flag {};
|
||||
|
||||
Response(success_flag) {}
|
||||
|
||||
boost::optional<error_type> _data;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace carla
|
|
@ -108,8 +108,6 @@ namespace detail {
|
|||
_server.stop();
|
||||
}
|
||||
|
||||
static void RespondError(std::string error_message);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service _sync_io_service;
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "carla/MsgPack.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace carla {
|
||||
namespace rpc {
|
||||
|
||||
/// @todo Workaround for packing boost::variant; it uses tuple instead so it's
|
||||
/// quite inefficient memory-wise.
|
||||
template <typename... Ts>
|
||||
class Variant {
|
||||
private:
|
||||
|
||||
size_t _index = 0u;
|
||||
|
||||
std::tuple<Ts...> _tuple;
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
struct IndexFromType;
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct IndexFromType<T, std::tuple<T, Types...>> {
|
||||
static constexpr size_t value = 0u;
|
||||
};
|
||||
|
||||
template <typename T, typename U, typename... Types>
|
||||
struct IndexFromType<T, std::tuple<U, Types...>> {
|
||||
static constexpr size_t value = 1u + IndexFromType<T, std::tuple<Types...>>::value;
|
||||
};
|
||||
|
||||
template <typename VisitorT, size_t... Is>
|
||||
void ApplyVisitorImpl(VisitorT &visitor, std::index_sequence<Is...>) const {
|
||||
std::initializer_list<int> ({ (_index == Is ? visitor(std::get<Is>(_tuple)), 0 : 0)... });
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Variant() = default;
|
||||
|
||||
template <typename ObjT>
|
||||
Variant(ObjT &&rhs) {
|
||||
(*this) = std::forward<ObjT>(rhs);
|
||||
}
|
||||
|
||||
template <typename ObjT>
|
||||
Variant &operator=(ObjT &&rhs) {
|
||||
constexpr auto index = IndexFromType<typename std::decay<ObjT>::type, decltype(_tuple)>::value;
|
||||
_index = index;
|
||||
std::get<index>(_tuple) = std::forward<ObjT>(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename VisitorT>
|
||||
void ApplyVisitor(VisitorT visitor) const {
|
||||
return ApplyVisitorImpl(visitor, std::make_index_sequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
MSGPACK_DEFINE_ARRAY(_index, _tuple);
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
} // namespace carla
|
|
@ -4,16 +4,14 @@
|
|||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "carla/rpc/Server.h"
|
||||
#pragma once
|
||||
|
||||
#include <rpc/this_handler.h>
|
||||
#include "carla/geom/Vector3D.h"
|
||||
|
||||
namespace carla {
|
||||
namespace rpc {
|
||||
|
||||
void Server::RespondError(std::string error_message) {
|
||||
::rpc::this_handler().respond_error(std::move(error_message));
|
||||
}
|
||||
using Vector3D = geom::Vector3D;
|
||||
|
||||
} // namespace carla
|
||||
} // namespace rpc
|
||||
} // namespace carla
|
|
@ -88,6 +88,8 @@ namespace detail {
|
|||
|
||||
geom::Vector3D velocity;
|
||||
|
||||
geom::Vector3D angular_velocity;
|
||||
|
||||
union TypeDependentState {
|
||||
rpc::TrafficLightState traffic_light_state;
|
||||
detail::PackedVehicleControl vehicle_control;
|
||||
|
@ -98,7 +100,7 @@ namespace detail {
|
|||
#pragma pack(pop)
|
||||
|
||||
static_assert(
|
||||
sizeof(ActorDynamicState) == 10u * sizeof(uint32_t) + sizeof(detail::PackedVehicleControl),
|
||||
sizeof(ActorDynamicState) == 13u * sizeof(uint32_t) + sizeof(detail::PackedVehicleControl),
|
||||
"Invalid ActorDynamicState size!");
|
||||
|
||||
} // namespace data
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/sensor/SensorData.h"
|
||||
|
||||
#include <exception>
|
||||
|
@ -107,14 +108,14 @@ namespace data {
|
|||
|
||||
reference at(size_type pos) {
|
||||
if (!(pos < size())) {
|
||||
throw std::out_of_range("Array index out of range");
|
||||
throw_exception(std::out_of_range("Array index out of range"));
|
||||
}
|
||||
return operator[](pos);
|
||||
}
|
||||
|
||||
const_reference at(size_type pos) const {
|
||||
if (!(pos < size())) {
|
||||
throw std::out_of_range("Array index out of range");
|
||||
throw_exception(std::out_of_range("Array index out of range"));
|
||||
}
|
||||
return operator[](pos);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "carla/streaming/detail/Dispatcher.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/streaming/detail/MultiStreamState.h"
|
||||
#include "carla/streaming/detail/StreamState.h"
|
||||
|
@ -21,7 +22,7 @@ namespace detail {
|
|||
auto ptr = std::make_shared<StreamStateT>(cached_token);
|
||||
auto result = stream_map.emplace(std::make_pair(cached_token.get_stream_id(), ptr));
|
||||
if (!result.second) {
|
||||
throw std::runtime_error("failed to create stream!");
|
||||
throw_exception(std::runtime_error("failed to create stream!"));
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
@ -31,11 +32,18 @@ namespace detail {
|
|||
// session remaining since at this point the io_service should be already
|
||||
// stopped.
|
||||
for (auto &pair : _stream_map) {
|
||||
#ifndef LIBCARLA_NO_EXCEPTIONS
|
||||
try {
|
||||
pair.second->ClearSessions();
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
||||
auto stream_state = pair.second.lock();
|
||||
if (stream_state != nullptr) {
|
||||
stream_state->ClearSessions();
|
||||
}
|
||||
#ifndef LIBCARLA_NO_EXCEPTIONS
|
||||
} catch (const std::exception &e) {
|
||||
log_error("failed to clear sessions:", e.what());
|
||||
}
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,22 +64,36 @@ namespace detail {
|
|||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
auto search = _stream_map.find(session->get_stream_id());
|
||||
if (search != _stream_map.end()) {
|
||||
DEBUG_ASSERT(search->second != nullptr);
|
||||
search->second->ConnectSession(std::move(session));
|
||||
auto stream_state = search->second.lock();
|
||||
if (stream_state != nullptr) {
|
||||
stream_state->ConnectSession(std::move(session));
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
log_error("Invalid session: no stream available with id", session->get_stream_id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatcher::DeregisterSession(std::shared_ptr<Session> session) {
|
||||
DEBUG_ASSERT(session != nullptr);
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
ClearExpiredStreams();
|
||||
auto search = _stream_map.find(session->get_stream_id());
|
||||
if (search != _stream_map.end()) {
|
||||
DEBUG_ASSERT(search->second != nullptr);
|
||||
search->second->DisconnectSession(session);
|
||||
auto stream_state = search->second.lock();
|
||||
if (stream_state != nullptr) {
|
||||
stream_state->DisconnectSession(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatcher::ClearExpiredStreams() {
|
||||
for (auto it = _stream_map.begin(); it != _stream_map.end(); ) {
|
||||
if (it->second.expired()) {
|
||||
it = _stream_map.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ namespace detail {
|
|||
|
||||
private:
|
||||
|
||||
void ClearExpiredStreams();
|
||||
|
||||
// We use a mutex here, but we assume that sessions and streams won't be
|
||||
// created too often.
|
||||
std::mutex _mutex;
|
||||
|
@ -51,7 +53,7 @@ namespace detail {
|
|||
/// them alive the whole run.
|
||||
std::unordered_map<
|
||||
stream_id_type,
|
||||
std::shared_ptr<StreamStateBase>> _stream_map;
|
||||
std::weak_ptr<StreamStateBase>> _stream_map;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "carla/streaming/detail/Token.h"
|
||||
|
||||
#include "carla/Exception.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
|
||||
|
@ -21,7 +23,7 @@ namespace detail {
|
|||
_token.address_type = token_data::address::ip_v6;
|
||||
_token.address.v6 = addr.to_v6().to_bytes();
|
||||
} else {
|
||||
throw std::invalid_argument("invalid ip address!");
|
||||
throw_exception(std::invalid_argument("invalid ip address!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "carla/BufferPool.h"
|
||||
#include "carla/Debug.h"
|
||||
#include "carla/Exception.h"
|
||||
#include "carla/Logging.h"
|
||||
#include "carla/Time.h"
|
||||
|
||||
|
@ -75,7 +76,7 @@ namespace tcp {
|
|||
_connection_timer(io_service),
|
||||
_buffer_pool(std::make_shared<BufferPool>()) {
|
||||
if (!_token.protocol_is_tcp()) {
|
||||
throw std::invalid_argument("invalid token, only TCP tokens supported");
|
||||
throw_exception(std::invalid_argument("invalid token, only TCP tokens supported"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ namespace tcp {
|
|||
auto handle_query = [this, self, callback=std::move(on_opened)](
|
||||
const boost::system::error_code &ec,
|
||||
size_t DEBUG_ONLY(bytes_received)) {
|
||||
DEBUG_ASSERT_EQ(bytes_received, sizeof(_stream_id));
|
||||
if (!ec) {
|
||||
DEBUG_ASSERT_EQ(bytes_received, sizeof(_stream_id));
|
||||
log_debug("session", _session_id, "for stream", _stream_id, " started");
|
||||
_socket.get_io_service().post([=]() { callback(self); });
|
||||
} else {
|
||||
|
|
|
@ -14,16 +14,14 @@
|
|||
#endif // BOOST_ERROR_CODE_HEADER_ONLY
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
# define BOOST_NO_EXCEPTIONS
|
||||
# error LibCarla should be compiled with -DBOOST_NO_EXCEPTIONS inside UE4.
|
||||
#endif // BOOST_NO_EXCEPTIONS
|
||||
|
||||
namespace boost {
|
||||
|
||||
static inline void throw_exception(const std::exception &e) {
|
||||
UE_LOG(LogCarla, Fatal, TEXT("Exception thrown on Boost libraries: %s"), UTF8_TO_TCHAR(e.what()));
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
#ifndef ASIO_NO_EXCEPTIONS
|
||||
# error LibCarla should be compiled with -DASIO_NO_EXCEPTIONS inside UE4.
|
||||
#endif // ASIO_NO_EXCEPTIONS
|
||||
#ifndef LIBCARLA_NO_EXCEPTIONS
|
||||
# error LibCarla should be compiled with -DLIBCARLA_NO_EXCEPTIONS inside UE4.
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
||||
|
||||
#endif // LIBCARLA_INCLUDED_DISABLE_UE4_MACROS_HEADER
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Notice: This file has been slightly adapted for its use by CARLA.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -156,18 +157,29 @@ namespace moodycamel { namespace details {
|
|||
#define MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ~~~ @begin Modified for CARLA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#include <carla/Exception.h>
|
||||
|
||||
#if (defined(LIBCARLA_NO_EXCEPTIONS) && defined(MOODYCAMEL_EXCEPTIONS_ENABLED))
|
||||
# undef MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
#endif
|
||||
|
||||
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
#define MOODYCAMEL_TRY try
|
||||
#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__)
|
||||
#define MOODYCAMEL_RETHROW throw
|
||||
#define MOODYCAMEL_THROW(expr) throw (expr)
|
||||
#define MOODYCAMEL_THROW(expr) ::carla::throw_exception(expr)
|
||||
#else
|
||||
#define MOODYCAMEL_TRY if (true)
|
||||
#define MOODYCAMEL_CATCH(...) else if (false)
|
||||
#define MOODYCAMEL_RETHROW
|
||||
#define MOODYCAMEL_THROW(expr)
|
||||
#define MOODYCAMEL_THROW(expr) ::carla::throw_exception(expr)
|
||||
#endif
|
||||
|
||||
// ~~~ @end Modified for CARLA ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#ifndef MOODYCAMEL_NOEXCEPT
|
||||
#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED)
|
||||
#define MOODYCAMEL_NOEXCEPT
|
||||
|
|
|
@ -6,7 +6,16 @@
|
|||
|
||||
#include "Buffer.h"
|
||||
|
||||
/// @todo This header uses deprecated functionality, please re-enable
|
||||
/// pragma-messages after upgrading Boost 1.69 if possible.
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-W#pragma-messages"
|
||||
#endif
|
||||
# include <boost/random/independent_bits.hpp>
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <climits>
|
||||
#include <random>
|
|
@ -6,9 +6,11 @@
|
|||
|
||||
#include "test.h"
|
||||
|
||||
#include <carla/MsgPackAdaptors.h>
|
||||
#include <carla/ThreadGroup.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <carla/rpc/Client.h>
|
||||
#include <carla/rpc/Response.h>
|
||||
#include <carla/rpc/Server.h>
|
||||
|
||||
#include <thread>
|
||||
|
@ -57,21 +59,3 @@ TEST(rpc, server_bind_sync_run_on_game_thread) {
|
|||
std::cout << "game thread: run " << i << " slices.\n";
|
||||
ASSERT_TRUE(done);
|
||||
}
|
||||
|
||||
TEST(rpc, msgpack) {
|
||||
namespace c = carla;
|
||||
namespace cg = carla::geom;
|
||||
Actor actor;
|
||||
actor.id = 42u;
|
||||
actor.description.uid = 2u;
|
||||
actor.description.id = "actor.random.whatever";
|
||||
actor.bounding_box = cg::BoundingBox{cg::Vector3D{1.0f, 2.0f, 3.0f}};
|
||||
|
||||
auto buffer = c::MsgPack::Pack(actor);
|
||||
auto result = c::MsgPack::UnPack<Actor>(buffer);
|
||||
|
||||
ASSERT_EQ(result.id, actor.id);
|
||||
ASSERT_EQ(result.description.uid, actor.description.uid);
|
||||
ASSERT_EQ(result.description.id, actor.description.id);
|
||||
ASSERT_EQ(result.bounding_box, actor.bounding_box);
|
||||
}
|
|
@ -112,10 +112,13 @@ TEST(buffer, memcpy) {
|
|||
ASSERT_EQ(*cpy, *msg);
|
||||
}
|
||||
|
||||
/// @todo What to do with exceptions?
|
||||
// TEST(buffer, message_too_big) {
|
||||
// ASSERT_THROW(Buffer(4294967296ul), std::invalid_argument);
|
||||
// }
|
||||
#ifndef LIBCARLA_NO_EXCEPTIONS
|
||||
TEST(buffer, message_too_big) {
|
||||
ASSERT_THROW(Buffer(4294967296ul), std::invalid_argument);
|
||||
Buffer buf;
|
||||
ASSERT_THROW(buf.reset(4294967296ul), std::invalid_argument);
|
||||
}
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
||||
|
||||
TEST(buffer, buffer_pool) {
|
||||
const std::string str = "Hello buffer!";
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include <carla/MsgPackAdaptors.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <carla/rpc/Response.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
using namespace carla::rpc;
|
||||
|
||||
TEST(msgpack, response) {
|
||||
using mp = carla::MsgPack;
|
||||
const std::string error = "Uh ah an error!";
|
||||
Response<int> r = ResponseError(error);
|
||||
auto s = mp::UnPack<decltype(r)>(mp::Pack(r));
|
||||
ASSERT_TRUE(r.HasError());
|
||||
ASSERT_EQ(r.GetError().What(), error);
|
||||
ASSERT_TRUE(s.HasError());
|
||||
ASSERT_EQ(s.GetError().What(), error);
|
||||
r.Reset(42);
|
||||
s = mp::UnPack<decltype(r)>(mp::Pack(r));
|
||||
ASSERT_FALSE(r.HasError());
|
||||
ASSERT_EQ(r.Get(), 42);
|
||||
ASSERT_FALSE(s.HasError());
|
||||
ASSERT_EQ(s.Get(), 42);
|
||||
r.SetError(error);
|
||||
s = mp::UnPack<decltype(r)>(mp::Pack(r));
|
||||
ASSERT_FALSE(r);
|
||||
ASSERT_EQ(r.GetError().What(), error);
|
||||
ASSERT_FALSE(s);
|
||||
ASSERT_EQ(s.GetError().What(), error);
|
||||
Response<std::vector<float>> rv;
|
||||
auto sv = mp::UnPack<decltype(rv)>(mp::Pack(rv));
|
||||
ASSERT_TRUE(rv.HasError());
|
||||
ASSERT_TRUE(sv.HasError());
|
||||
Response<void> er;
|
||||
ASSERT_TRUE(er.HasError());
|
||||
er = Response<void>::Success();
|
||||
auto es = mp::UnPack<decltype(er)>(mp::Pack(er));
|
||||
ASSERT_FALSE(er.HasError());
|
||||
ASSERT_FALSE(es.HasError());
|
||||
er.SetError(error);
|
||||
es = mp::UnPack<decltype(er)>(mp::Pack(er));
|
||||
ASSERT_FALSE(er);
|
||||
ASSERT_EQ(er.GetError().What(), error);
|
||||
ASSERT_FALSE(es);
|
||||
ASSERT_EQ(es.GetError().What(), error);
|
||||
}
|
||||
|
||||
TEST(msgpack, actor) {
|
||||
namespace c = carla;
|
||||
namespace cg = carla::geom;
|
||||
Actor actor;
|
||||
actor.id = 42u;
|
||||
actor.description.uid = 2u;
|
||||
actor.description.id = "actor.random.whatever";
|
||||
actor.bounding_box = cg::BoundingBox{cg::Vector3D{1.0f, 2.0f, 3.0f}};
|
||||
|
||||
auto buffer = c::MsgPack::Pack(actor);
|
||||
auto result = c::MsgPack::UnPack<Actor>(buffer);
|
||||
|
||||
ASSERT_EQ(result.id, actor.id);
|
||||
ASSERT_EQ(result.description.uid, actor.description.uid);
|
||||
ASSERT_EQ(result.description.id, actor.description.id);
|
||||
ASSERT_EQ(result.bounding_box, actor.bounding_box);
|
||||
}
|
||||
|
||||
TEST(msgpack, variant) {
|
||||
using mp = carla::MsgPack;
|
||||
|
||||
boost::variant<bool, float, std::string> var;
|
||||
|
||||
var = true;
|
||||
auto result = mp::UnPack<decltype(var)>(mp::Pack(var));
|
||||
ASSERT_EQ(result.which(), 0);
|
||||
ASSERT_EQ(boost::get<bool>(result), true);
|
||||
|
||||
var = 42.0f;
|
||||
result = mp::UnPack<decltype(var)>(mp::Pack(var));
|
||||
ASSERT_EQ(result.which(), 1);
|
||||
ASSERT_EQ(boost::get<float>(result), 42.0f);
|
||||
|
||||
var = std::string("hola!");
|
||||
result = mp::UnPack<decltype(var)>(mp::Pack(var));
|
||||
ASSERT_EQ(result.which(), 2);
|
||||
ASSERT_EQ(boost::get<std::string>(result), "hola!");
|
||||
}
|
||||
|
||||
TEST(msgpack, optional) {
|
||||
using mp = carla::MsgPack;
|
||||
|
||||
boost::optional<float> var;
|
||||
|
||||
auto result = mp::UnPack<decltype(var)>(mp::Pack(var));
|
||||
ASSERT_FALSE(result.has_value());
|
||||
|
||||
var = 42.0f;
|
||||
result = mp::UnPack<decltype(var)>(mp::Pack(var));
|
||||
ASSERT_TRUE(result.has_value());
|
||||
ASSERT_EQ(*result, 42.0f);
|
||||
}
|
|
@ -122,7 +122,7 @@ private:
|
|||
};
|
||||
|
||||
static size_t get_max_concurrency() {
|
||||
size_t concurrency = 0.75 * std::thread::hardware_concurrency();
|
||||
size_t concurrency = std::thread::hardware_concurrency() / 2u;
|
||||
return std::max(2ul, concurrency);
|
||||
}
|
||||
|
||||
|
@ -154,9 +154,9 @@ TEST(benchmark_streaming, image_200x200_mt) {
|
|||
}
|
||||
|
||||
TEST(benchmark_streaming, image_800x600_mt) {
|
||||
benchmark_image(800u * 600u, get_max_concurrency(), 0.8);
|
||||
benchmark_image(800u * 600u, get_max_concurrency(), 0.9);
|
||||
}
|
||||
|
||||
TEST(benchmark_streaming, image_1920x1080_mt) {
|
||||
benchmark_image(1920u * 1080u, get_max_concurrency(), 0.7);
|
||||
benchmark_image(1920u * 1080u, get_max_concurrency(), 0.9);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#ifdef LIBCARLA_NO_EXCEPTIONS
|
||||
|
||||
#include <carla/Exception.h>
|
||||
#include <carla/Logging.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace carla {
|
||||
|
||||
void throw_exception(const std::exception &e) {
|
||||
log_critical("carla::throw_exception:", e.what());
|
||||
log_critical("calling std::terminate because exceptions are disabled.");
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
} // namespace carla
|
||||
|
||||
#endif // LIBCARLA_NO_EXCEPTIONS
|
|
@ -10,7 +10,7 @@
|
|||
# define LIBCARLA_LOG_LEVEL LIBCARLA_LOG_LEVEL_INFO
|
||||
#endif // NDEBUG
|
||||
|
||||
#include "test/util/Buffer.h"
|
||||
#include "test/Buffer.h"
|
||||
|
||||
#include <carla/Logging.h>
|
||||
#include <carla/profiler/Profiler.h>
|
||||
|
|
|
@ -37,6 +37,7 @@ class Agent(object):
|
|||
self._vehicle = vehicle
|
||||
self._world = self._vehicle.get_world()
|
||||
self._map = self._vehicle.get_world().get_map()
|
||||
self._last_traffic_light = None
|
||||
|
||||
|
||||
def run_step(self, debug=False):
|
||||
|
@ -137,8 +138,14 @@ class Agent(object):
|
|||
if sel_traffic_light is not None:
|
||||
if debug:
|
||||
print('=== Magnitude = {} | Angle = {} | ID = {}'.format(sel_magnitude, min_angle, sel_traffic_light.id))
|
||||
if sel_traffic_light.state == carla.libcarla.TrafficLightState.Red:
|
||||
return (True, sel_traffic_light)
|
||||
|
||||
if self._last_traffic_light is None:
|
||||
self._last_traffic_light = sel_traffic_light
|
||||
|
||||
if self._last_traffic_light.state == carla.libcarla.TrafficLightState.Red:
|
||||
return (True, self._last_traffic_light)
|
||||
else:
|
||||
self._last_traffic_light = None
|
||||
|
||||
return (False, None)
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class BasicAgent(Agent):
|
|||
target destination. This agent respects traffic lights and other vehicles.
|
||||
"""
|
||||
|
||||
def __init__(self, vehicle):
|
||||
def __init__(self, vehicle, target_speed=20):
|
||||
"""
|
||||
|
||||
:param vehicle: actor to apply to local planner logic onto
|
||||
|
@ -30,7 +30,7 @@ class BasicAgent(Agent):
|
|||
|
||||
self._proximity_threshold = 10.0 # meters
|
||||
self._state = AgentState.NAVIGATING
|
||||
self._local_planner = LocalPlanner(self._vehicle)
|
||||
self._local_planner = LocalPlanner(self._vehicle, opt_dict={'target_speed' : target_speed})
|
||||
|
||||
# setting up global router
|
||||
self._current_plan = None
|
||||
|
|
|
@ -59,9 +59,13 @@ void export_actor() {
|
|||
.def("get_location", &cc::Actor::GetLocation)
|
||||
.def("get_transform", &cc::Actor::GetTransform)
|
||||
.def("get_velocity", &cc::Actor::GetVelocity)
|
||||
.def("get_angular_velocity", &cc::Actor::GetAngularVelocity)
|
||||
.def("get_acceleration", &cc::Actor::GetAcceleration)
|
||||
.def("set_location", &cc::Actor::SetLocation, (arg("location")))
|
||||
.def("set_transform", &cc::Actor::SetTransform, (arg("transform")))
|
||||
.def("set_velocity", &cc::Actor::SetVelocity, (arg("vector")))
|
||||
.def("set_angular_velocity", &cc::Actor::SetAngularVelocity, (arg("vector")))
|
||||
.def("add_impulse", &cc::Actor::AddImpulse, (arg("vector")))
|
||||
.def("set_simulate_physics", &cc::Actor::SetSimulatePhysics, (arg("enabled")=true))
|
||||
.def("destroy", CALL_WITHOUT_GIL(cc::Actor, Destroy))
|
||||
.def(self_ns::str(self_ns::self))
|
||||
|
|
|
@ -28,7 +28,7 @@ r.DefaultFeature.AmbientOcclusionStaticFraction=False
|
|||
r.DefaultFeature.AutoExposure=False
|
||||
r.CustomDepth=3
|
||||
r.Streaming.PoolSize=2000
|
||||
r.TextureStreaming=True
|
||||
r.TextureStreaming=False
|
||||
|
||||
[/Script/AIModule.AISense_Sight]
|
||||
bAutoRegisterAllPawnsAsSources=False
|
||||
|
|
|
@ -39,7 +39,7 @@ IncludeAppLocalPrerequisites=False
|
|||
bShareMaterialShaderCode=False
|
||||
bSharedMaterialNativeLibraries=False
|
||||
ApplocalPrerequisitesDirectory=(Path="")
|
||||
IncludeCrashReporter=True
|
||||
IncludeCrashReporter=False
|
||||
InternationalizationPreset=English
|
||||
-CulturesToStage=en
|
||||
+CulturesToStage=en
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "GameFramework/Controller.h"
|
||||
|
||||
void FActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
|
||||
void UActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Functor)
|
||||
{
|
||||
if (UActorBlueprintFunctionLibrary::CheckActorDefinition(Definition))
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ void FActorDispatcher::Bind(FActorDefinition Definition, SpawnFunctionType Funct
|
|||
}
|
||||
}
|
||||
|
||||
void FActorDispatcher::Bind(ACarlaActorFactory &ActorFactory)
|
||||
void UActorDispatcher::Bind(ACarlaActorFactory &ActorFactory)
|
||||
{
|
||||
for (const auto &Definition : ActorFactory.GetDefinitions())
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ void FActorDispatcher::Bind(ACarlaActorFactory &ActorFactory)
|
|||
}
|
||||
}
|
||||
|
||||
TPair<EActorSpawnResultStatus, FActorView> FActorDispatcher::SpawnActor(
|
||||
TPair<EActorSpawnResultStatus, FActorView> UActorDispatcher::SpawnActor(
|
||||
const FTransform &Transform,
|
||||
FActorDescription Description)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ TPair<EActorSpawnResultStatus, FActorView> FActorDispatcher::SpawnActor(
|
|||
Result.Status = EActorSpawnResultStatus::UnknownError;
|
||||
}
|
||||
|
||||
auto View = Result.IsValid() ? Registry.Register(*Result.Actor, std::move(Description)) : FActorView();
|
||||
auto View = Result.IsValid() ? RegisterActor(*Result.Actor, std::move(Description)) : FActorView();
|
||||
|
||||
if (!View.IsValid())
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ TPair<EActorSpawnResultStatus, FActorView> FActorDispatcher::SpawnActor(
|
|||
return MakeTuple(Result.Status, View);
|
||||
}
|
||||
|
||||
bool FActorDispatcher::DestroyActor(AActor *Actor)
|
||||
bool UActorDispatcher::DestroyActor(AActor *Actor)
|
||||
{
|
||||
if (Actor == nullptr) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Trying to destroy nullptr actor"));
|
||||
|
@ -83,7 +83,7 @@ bool FActorDispatcher::DestroyActor(AActor *Actor)
|
|||
UE_LOG(LogCarla, Warning, TEXT("Trying to destroy actor that is not in the registry"));
|
||||
return false;
|
||||
}
|
||||
const auto &Id = View.GetActorDescription()->Id;
|
||||
const auto &Id = View.GetActorInfo()->Description.Id;
|
||||
|
||||
// Destroy its controller if present.
|
||||
auto Pawn = Cast<APawn>(Actor);
|
||||
|
@ -102,9 +102,18 @@ bool FActorDispatcher::DestroyActor(AActor *Actor)
|
|||
UE_LOG(LogCarla, Log, TEXT("Destroying actor: '%s'"), *Id);
|
||||
if (Actor->Destroy())
|
||||
{
|
||||
Registry.Deregister(Actor);
|
||||
return true;
|
||||
}
|
||||
UE_LOG(LogCarla, Error, TEXT("Failed to destroy actor: '%s'"), *Id);
|
||||
return false;
|
||||
}
|
||||
|
||||
FActorView UActorDispatcher::RegisterActor(AActor &Actor, FActorDescription Description)
|
||||
{
|
||||
auto View = Registry.Register(Actor, std::move(Description));
|
||||
if (View.IsValid())
|
||||
{
|
||||
Actor.OnDestroyed.AddDynamic(this, &UActorDispatcher::OnActorDestroyed);
|
||||
}
|
||||
return View;
|
||||
}
|
||||
|
|
|
@ -14,12 +14,17 @@
|
|||
#include "Containers/Array.h"
|
||||
#include "Templates/Function.h"
|
||||
|
||||
#include "ActorDispatcher.generated.h"
|
||||
|
||||
class ACarlaActorFactory;
|
||||
|
||||
/// Actor in charge of binding ActorDefinitions to spawn functions, as well as
|
||||
/// Object in charge of binding ActorDefinitions to spawn functions, as well as
|
||||
/// keeping the registry of all the actors spawned.
|
||||
class FActorDispatcher
|
||||
UCLASS()
|
||||
class CARLA_API UActorDispatcher : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
using SpawnFunctionType = TFunction<FActorSpawnResult(const FTransform &, const FActorDescription &)>;
|
||||
|
@ -51,16 +56,15 @@ public:
|
|||
/// destruction, false if indestructible or nullptr.
|
||||
bool DestroyActor(AActor *Actor);
|
||||
|
||||
/// Register an actor that was not created using "SpawnActor" function but
|
||||
/// that should be kept in the registry.
|
||||
FActorView RegisterActor(AActor &Actor, FActorDescription ActorDescription);
|
||||
|
||||
const TArray<FActorDefinition> &GetActorDefinitions() const
|
||||
{
|
||||
return Definitions;
|
||||
}
|
||||
|
||||
FActorRegistry &GetActorRegistry()
|
||||
{
|
||||
return Registry;
|
||||
}
|
||||
|
||||
const FActorRegistry &GetActorRegistry() const
|
||||
{
|
||||
return Registry;
|
||||
|
@ -68,6 +72,12 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
UFUNCTION()
|
||||
void OnActorDestroyed(AActor *Actor)
|
||||
{
|
||||
Registry.Deregister(Actor);
|
||||
}
|
||||
|
||||
TArray<FActorDefinition> Definitions;
|
||||
|
||||
TArray<SpawnFunctionType> SpawnFunctions;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorDescription.h"
|
||||
#include "Carla/Game/Tagger.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
/// A view over an actor and its properties.
|
||||
struct FActorInfo
|
||||
{
|
||||
public:
|
||||
|
||||
FActorDescription Description;
|
||||
|
||||
TSet<ECityObjectLabel> SemanticTags;
|
||||
|
||||
FBoundingBox BoundingBox;
|
||||
|
||||
carla::rpc::Actor SerializedData;
|
||||
};
|
|
@ -11,12 +11,15 @@
|
|||
|
||||
#include "Carla/Game/Tagger.h"
|
||||
#include "Carla/Traffic/TrafficLightBase.h"
|
||||
#include "Carla/Util/BoundingBoxCalculator.h"
|
||||
|
||||
static FActorView::ActorType FActorRegistry_GetActorType(const FActorView &View)
|
||||
{
|
||||
if (View.IsValid())
|
||||
if (!View.IsValid())
|
||||
{
|
||||
if (nullptr != Cast<ACarlaWheeledVehicle>(View.GetActor()))
|
||||
return FActorView::ActorType::INVALID;
|
||||
}
|
||||
else if (nullptr != Cast<ACarlaWheeledVehicle>(View.GetActor()))
|
||||
{
|
||||
return FActorView::ActorType::Vehicle;
|
||||
}
|
||||
|
@ -28,13 +31,15 @@ static FActorView::ActorType FActorRegistry_GetActorType(const FActorView &View)
|
|||
{
|
||||
return FActorView::ActorType::TrafficLight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FActorView::ActorType::Other;
|
||||
}
|
||||
}
|
||||
|
||||
static FString GetRelevantTagAsString(const FActorView &View)
|
||||
static FString GetRelevantTagAsString(const TSet<ECityObjectLabel> &SemanticTags)
|
||||
{
|
||||
for (auto &&Tag : View.GetSemanticTags())
|
||||
for (auto &&Tag : SemanticTags)
|
||||
{
|
||||
if ((Tag != ECityObjectLabel::None) && (Tag != ECityObjectLabel::Other))
|
||||
{
|
||||
|
@ -61,9 +66,7 @@ FActorView FActorRegistry::Register(AActor &Actor, FActorDescription Description
|
|||
}
|
||||
Ids.Emplace(&Actor, Id);
|
||||
|
||||
auto View = FActorView(Id, Actor, std::move(Description));
|
||||
ATagger::GetTagsOfTaggedActor(Actor, View.SemanticTags);
|
||||
View.Type = FActorRegistry_GetActorType(View);
|
||||
auto View = MakeView(Id, Actor, std::move(Description));
|
||||
|
||||
auto Result = ActorDatabase.emplace(Id, View);
|
||||
check(Result.second);
|
||||
|
@ -74,7 +77,7 @@ FActorView FActorRegistry::Register(AActor &Actor, FActorDescription Description
|
|||
void FActorRegistry::Deregister(IdType Id)
|
||||
{
|
||||
check(Contains(Id));
|
||||
AActor *Actor = FindActor(Id);
|
||||
AActor *Actor = Find(Id).GetActor();
|
||||
check(Actor != nullptr);
|
||||
ActorDatabase.erase(Id);
|
||||
Actors.Remove(Id);
|
||||
|
@ -84,26 +87,53 @@ void FActorRegistry::Deregister(IdType Id)
|
|||
|
||||
void FActorRegistry::Deregister(AActor *Actor)
|
||||
{
|
||||
check(Actor != nullptr);
|
||||
auto View = Find(Actor);
|
||||
check(View.IsValid());
|
||||
check(View.GetActor() == Actor);
|
||||
Deregister(View.GetActorId());
|
||||
}
|
||||
|
||||
FActorView FActorRegistry::FindOrFake(AActor *Actor) const
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
auto View = Find(Actor);
|
||||
if (!View.IsValid())
|
||||
{
|
||||
View.TheActor = Actor;
|
||||
ATagger::GetTagsOfTaggedActor(*Actor, View.SemanticTags);
|
||||
auto Description = MakeShared<FActorDescription>();
|
||||
Description->Id = TEXT("static.") + GetRelevantTagAsString(View);
|
||||
View.Description = Description;
|
||||
check(View.IsValid());
|
||||
const bool bFakeActor = (View.GetActor() == nullptr) && (Actor != nullptr);
|
||||
return bFakeActor ? MakeView(0u, *Actor, FActorDescription{}) : View;
|
||||
}
|
||||
|
||||
FActorView FActorRegistry::MakeView(
|
||||
IdType Id,
|
||||
AActor &Actor,
|
||||
FActorDescription Description) const
|
||||
{
|
||||
auto Info = MakeShared<FActorInfo>();
|
||||
Info->Description = std::move(Description);
|
||||
ATagger::GetTagsOfTaggedActor(Actor, Info->SemanticTags);
|
||||
Info->BoundingBox = UBoundingBoxCalculator::GetActorBoundingBox(&Actor);
|
||||
|
||||
if (Info->Description.Id.IsEmpty())
|
||||
{
|
||||
// This is a fake actor, let's fake the id based on their semantic tags.
|
||||
Info->Description.Id = TEXT("static.") + GetRelevantTagAsString(Info->SemanticTags);
|
||||
}
|
||||
|
||||
Info->SerializedData.id = Id;
|
||||
Info->SerializedData.description = Info->Description;
|
||||
Info->SerializedData.bounding_box = Info->BoundingBox;
|
||||
Info->SerializedData.semantic_tags.reserve(Info->SemanticTags.Num());
|
||||
for (auto &&Tag : Info->SemanticTags)
|
||||
{
|
||||
using tag_t = decltype(Info->SerializedData.semantic_tags)::value_type;
|
||||
Info->SerializedData.semantic_tags.emplace_back(static_cast<tag_t>(Tag));
|
||||
}
|
||||
auto *Sensor = Cast<ASensor>(&Actor);
|
||||
if (Sensor != nullptr)
|
||||
{
|
||||
const auto &Token = Sensor->GetToken();
|
||||
Info->SerializedData.stream_token = decltype(Info->SerializedData.stream_token)(
|
||||
std::begin(Token.data),
|
||||
std::end(Token.data));
|
||||
}
|
||||
auto View = FActorView{Id, Actor, std::move(Info)};
|
||||
View.Type = FActorRegistry_GetActorType(View);
|
||||
return View;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
#include "Containers/Map.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/Iterator.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
/// A registry of all the Carla actors.
|
||||
|
@ -72,12 +76,6 @@ public:
|
|||
return PtrToId != nullptr ? Find(*PtrToId) : FActorView();
|
||||
}
|
||||
|
||||
AActor *FindActor(IdType Id) const
|
||||
{
|
||||
auto View = Find(Id);
|
||||
return View.IsValid() ? View.GetActor() : nullptr;
|
||||
}
|
||||
|
||||
/// If the actor is not found in the registry, create a fake actor view. The
|
||||
/// returned FActorView has some information about the @a Actor but will have
|
||||
/// an invalid id.
|
||||
|
@ -90,24 +88,23 @@ public:
|
|||
/// @{
|
||||
public:
|
||||
|
||||
using key_type = DatabaseType::key_type;
|
||||
using mapped_type = DatabaseType::mapped_type;
|
||||
using value_type = DatabaseType::value_type;
|
||||
using const_iterator = DatabaseType::const_iterator;
|
||||
using value_type = DatabaseType::mapped_type;
|
||||
|
||||
const_iterator begin() const noexcept
|
||||
auto begin() const noexcept
|
||||
{
|
||||
return ActorDatabase.begin();
|
||||
return carla::iterator::make_map_values_iterator(ActorDatabase.begin());
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept
|
||||
auto end() const noexcept
|
||||
{
|
||||
return ActorDatabase.end();
|
||||
return carla::iterator::make_map_values_iterator(ActorDatabase.end());
|
||||
}
|
||||
|
||||
/// @}
|
||||
private:
|
||||
|
||||
FActorView MakeView(IdType Id, AActor &Actor, FActorDescription Description) const;
|
||||
|
||||
TMap<IdType, AActor *> Actors;
|
||||
|
||||
TMap<AActor *, IdType> Ids;
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorDescription.h"
|
||||
#include "Carla/Game/Tagger.h"
|
||||
#include "Carla/Actor/ActorInfo.h"
|
||||
|
||||
class AActor;
|
||||
|
||||
|
@ -22,15 +21,17 @@ public:
|
|||
Other,
|
||||
Vehicle,
|
||||
Walker,
|
||||
TrafficLight
|
||||
TrafficLight,
|
||||
INVALID
|
||||
};
|
||||
|
||||
FActorView() = default;
|
||||
FActorView(const FActorView &) = default;
|
||||
FActorView(FActorView &&) = default;
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (TheActor != nullptr) && Description.IsValid();
|
||||
return (TheActor != nullptr) && !TheActor->IsPendingKill();
|
||||
}
|
||||
|
||||
IdType GetActorId() const
|
||||
|
@ -53,24 +54,19 @@ public:
|
|||
return TheActor;
|
||||
}
|
||||
|
||||
const FActorDescription *GetActorDescription() const
|
||||
const FActorInfo *GetActorInfo() const
|
||||
{
|
||||
return Description.Get();
|
||||
}
|
||||
|
||||
const TSet<ECityObjectLabel> &GetSemanticTags() const
|
||||
{
|
||||
return SemanticTags;
|
||||
return Info.Get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class FActorRegistry;
|
||||
|
||||
FActorView(IdType ActorId, AActor &Actor, FActorDescription Description)
|
||||
FActorView(IdType ActorId, AActor &Actor, TSharedPtr<const FActorInfo> Info)
|
||||
: Id(ActorId),
|
||||
TheActor(&Actor),
|
||||
Description(MakeShared<FActorDescription>(std::move(Description))) {}
|
||||
Info(std::move(Info)) {}
|
||||
|
||||
IdType Id = 0u;
|
||||
|
||||
|
@ -78,7 +74,5 @@ private:
|
|||
|
||||
AActor *TheActor = nullptr;
|
||||
|
||||
TSharedPtr<const FActorDescription> Description = nullptr;
|
||||
|
||||
TSet<ECityObjectLabel> SemanticTags;
|
||||
TSharedPtr<const FActorInfo> Info = nullptr;
|
||||
};
|
||||
|
|
|
@ -135,7 +135,9 @@ public class Carla : ModuleRules
|
|||
PublicIncludePaths.Add(LibCarlaIncludePath);
|
||||
PrivateIncludePaths.Add(LibCarlaIncludePath);
|
||||
|
||||
/// @todo This is necessary because rpclib uses exceptions to notify errors.
|
||||
bEnableExceptions = true;
|
||||
PublicDefinitions.Add("ASIO_NO_EXCEPTIONS");
|
||||
PublicDefinitions.Add("BOOST_NO_EXCEPTIONS");
|
||||
PublicDefinitions.Add("LIBCARLA_NO_EXCEPTIONS");
|
||||
PublicDefinitions.Add("PUGIXML_NO_EXCEPTIONS");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,3 +85,23 @@ bool FCarlaModule::HandleSettingsSaved()
|
|||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FCarlaModule, Carla)
|
||||
|
||||
// =============================================================================
|
||||
// -- Implement carla throw_exception ------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/Exception.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace carla {
|
||||
|
||||
void throw_exception(const std::exception &e) {
|
||||
UE_LOG(LogCarla, Fatal, TEXT("Exception thrown: %s"), UTF8_TO_TCHAR(e.what()));
|
||||
// It should never reach this part.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
} // namespace carla
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
#include "Carla/Util/BoundingBoxCalculator.h"
|
||||
#include "Carla/Vehicle/VehicleSpawnPoint.h"
|
||||
|
||||
#include "EngineUtils.h"
|
||||
|
@ -36,9 +38,11 @@ UCarlaEpisode::UCarlaEpisode(const FObjectInitializer &ObjectInitializer)
|
|||
Id([]() {
|
||||
static uint32 COUNTER = 0u;
|
||||
return ++COUNTER;
|
||||
}()) {}
|
||||
}()) {
|
||||
ActorDispatcher = CreateDefaultSubobject<UActorDispatcher>(TEXT("ActorDispatcher"));
|
||||
}
|
||||
|
||||
TArray<FTransform> UCarlaEpisode::GetRecommendedStartTransforms() const
|
||||
TArray<FTransform> UCarlaEpisode::GetRecommendedSpawnPoints() const
|
||||
{
|
||||
TArray<FTransform> SpawnPoints;
|
||||
for (TActorIterator<AVehicleSpawnPoint> It(GetWorld()); It; ++It) {
|
||||
|
@ -47,22 +51,29 @@ TArray<FTransform> UCarlaEpisode::GetRecommendedStartTransforms() const
|
|||
return SpawnPoints;
|
||||
}
|
||||
|
||||
const AWorldObserver *UCarlaEpisode::StartWorldObserver(carla::streaming::MultiStream Stream)
|
||||
carla::rpc::Actor UCarlaEpisode::SerializeActor(FActorView ActorView) const
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Starting AWorldObserver sensor"));
|
||||
check(WorldObserver == nullptr);
|
||||
auto *World = GetWorld();
|
||||
check(World != nullptr);
|
||||
WorldObserver = World->SpawnActorDeferred<AWorldObserver>(
|
||||
AWorldObserver::StaticClass(),
|
||||
FTransform(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
|
||||
WorldObserver->SetEpisode(*this);
|
||||
WorldObserver->SetStream(std::move(Stream));
|
||||
UGameplayStatics::FinishSpawningActor(WorldObserver, FTransform());
|
||||
return WorldObserver;
|
||||
carla::rpc::Actor Actor;
|
||||
if (ActorView.IsValid())
|
||||
{
|
||||
Actor = ActorView.GetActorInfo()->SerializedData;
|
||||
auto Parent = ActorView.GetActor()->GetOwner();
|
||||
if (Parent != nullptr)
|
||||
{
|
||||
Actor.parent_id = FindActor(Parent).GetActorId();
|
||||
}
|
||||
} else {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Trying to serialize invalid actor"));
|
||||
}
|
||||
return Actor;
|
||||
}
|
||||
|
||||
void UCarlaEpisode::AttachActors(AActor *Child, AActor *Parent)
|
||||
{
|
||||
check(Child != nullptr);
|
||||
check(Parent != nullptr);
|
||||
Child->AttachToActor(Parent, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
Child->SetOwner(Parent);
|
||||
}
|
||||
|
||||
void UCarlaEpisode::InitializeAtBeginPlay()
|
||||
|
@ -81,7 +92,7 @@ void UCarlaEpisode::InitializeAtBeginPlay()
|
|||
FActorDescription Description;
|
||||
Description.Id = TEXT("spectator");
|
||||
Description.Class = Spectator->GetClass();
|
||||
ActorDispatcher.GetActorRegistry().Register(*Spectator, Description);
|
||||
ActorDispatcher->RegisterActor(*Spectator, Description);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -95,6 +106,6 @@ void UCarlaEpisode::InitializeAtBeginPlay()
|
|||
FActorDescription Description;
|
||||
Description.Id = UCarlaEpisode_GetTrafficSignId(Actor->GetTrafficSignState());
|
||||
Description.Class = Actor->GetClass();
|
||||
ActorDispatcher.GetActorRegistry().Register(*Actor, Description);
|
||||
ActorDispatcher->RegisterActor(*Actor, Description);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
#include "Carla/Sensor/WorldObserver.h"
|
||||
#include "Carla/Weather/Weather.h"
|
||||
|
||||
#include "GameFramework/Pawn.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/rpc/Actor.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
#include "CarlaEpisode.generated.h"
|
||||
|
||||
/// A simulation episode.
|
||||
|
@ -20,21 +26,51 @@ class CARLA_API UCarlaEpisode : public UObject
|
|||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// ===========================================================================
|
||||
// -- Constructor ------------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
UCarlaEpisode(const FObjectInitializer &ObjectInitializer);
|
||||
|
||||
// ===========================================================================
|
||||
// -- Retrieve info about this episode ---------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Return the unique id of this episode.
|
||||
auto GetId() const
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
/// Return the name of the map loaded in this episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const FString &GetMapName() const
|
||||
{
|
||||
return MapName;
|
||||
}
|
||||
|
||||
/// Return the list of actor definitions that are available to be spawned this
|
||||
/// episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const TArray<FActorDefinition> &GetActorDefinitions() const
|
||||
{
|
||||
return ActorDispatcher->GetActorDefinitions();
|
||||
}
|
||||
|
||||
/// Return the list of recommended spawn points for vehicles.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<FTransform> GetRecommendedSpawnPoints() const;
|
||||
|
||||
// ===========================================================================
|
||||
// -- Retrieve special actors ------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
APawn *GetSpectatorPawn() const
|
||||
{
|
||||
|
@ -47,17 +83,55 @@ public:
|
|||
return Weather;
|
||||
}
|
||||
|
||||
/// Return the list of actor definitions that are available to be spawned this
|
||||
/// episode.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
const TArray<FActorDefinition> &GetActorDefinitions() const
|
||||
const AWorldObserver *GetWorldObserver() const
|
||||
{
|
||||
return ActorDispatcher.GetActorDefinitions();
|
||||
return WorldObserver;
|
||||
}
|
||||
|
||||
/// Return the list of recommended start positions.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<FTransform> GetRecommendedStartTransforms() const;
|
||||
const FActorRegistry &GetActorRegistry() const
|
||||
{
|
||||
return ActorDispatcher->GetActorRegistry();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Actor look up methods --------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Find a Carla actor by id.
|
||||
///
|
||||
/// If the actor is not found or is pending kill, the returned view is
|
||||
/// invalid.
|
||||
FActorView FindActor(FActorView::IdType ActorId) const
|
||||
{
|
||||
return ActorDispatcher->GetActorRegistry().Find(ActorId);
|
||||
}
|
||||
|
||||
/// Find the actor view of @a Actor.
|
||||
///
|
||||
/// If the actor is not found or is pending kill, the returned view is
|
||||
/// invalid.
|
||||
FActorView FindActor(AActor *Actor) const
|
||||
{
|
||||
return ActorDispatcher->GetActorRegistry().Find(Actor);
|
||||
}
|
||||
|
||||
/// Find the actor view of @a Actor. If the actor is not found, a "fake" view
|
||||
/// is returned emulating an existing Carla actor. Use this to return views
|
||||
/// over static actors present in the map.
|
||||
///
|
||||
/// If the actor is pending kill, the returned view is invalid.
|
||||
FActorView FindOrFakeActor(AActor *Actor) const
|
||||
{
|
||||
return ActorDispatcher->GetActorRegistry().FindOrFake(Actor);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// -- Actor handling methods -------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
public:
|
||||
|
||||
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
|
||||
/// despawn an actor created with this function call DestroyActor.
|
||||
|
@ -69,7 +143,7 @@ public:
|
|||
const FTransform &Transform,
|
||||
FActorDescription ActorDescription)
|
||||
{
|
||||
return ActorDispatcher.SpawnActor(Transform, std::move(ActorDescription));
|
||||
return ActorDispatcher->SpawnActor(Transform, std::move(ActorDescription));
|
||||
}
|
||||
|
||||
/// Spawns an actor based on @a ActorDescription at @a Transform. To properly
|
||||
|
@ -86,24 +160,31 @@ public:
|
|||
return SpawnActorWithInfo(Transform, std::move(ActorDescription)).Value.GetActor();
|
||||
}
|
||||
|
||||
/// Attach @a Child to @a Parent.
|
||||
///
|
||||
/// @pre Actors cannot be null.
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void AttachActors(AActor *Child, AActor *Parent);
|
||||
|
||||
/// @copydoc FActorDispatcher::DestroyActor(AActor*)
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool DestroyActor(AActor *Actor)
|
||||
{
|
||||
return ActorDispatcher.DestroyActor(Actor);
|
||||
return ActorDispatcher->DestroyActor(Actor);
|
||||
}
|
||||
|
||||
const FActorRegistry &GetActorRegistry() const
|
||||
{
|
||||
return ActorDispatcher.GetActorRegistry();
|
||||
}
|
||||
// ===========================================================================
|
||||
// -- Other methods ----------------------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
const AWorldObserver *StartWorldObserver(carla::streaming::MultiStream Stream);
|
||||
public:
|
||||
|
||||
const AWorldObserver *GetWorldObserver() const
|
||||
{
|
||||
return WorldObserver;
|
||||
}
|
||||
/// Create a serializable object describing the actor.
|
||||
carla::rpc::Actor SerializeActor(FActorView ActorView) const;
|
||||
|
||||
// ===========================================================================
|
||||
// -- Private methods and members --------------------------------------------
|
||||
// ===========================================================================
|
||||
|
||||
private:
|
||||
|
||||
|
@ -113,7 +194,7 @@ private:
|
|||
|
||||
void RegisterActorFactory(ACarlaActorFactory &ActorFactory)
|
||||
{
|
||||
ActorDispatcher.Bind(ActorFactory);
|
||||
ActorDispatcher->Bind(ActorFactory);
|
||||
}
|
||||
|
||||
const uint32 Id = 0u;
|
||||
|
@ -121,7 +202,8 @@ private:
|
|||
UPROPERTY(VisibleAnywhere)
|
||||
FString MapName;
|
||||
|
||||
FActorDispatcher ActorDispatcher;
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
UActorDispatcher *ActorDispatcher = nullptr;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
APawn *Spectator = nullptr;
|
||||
|
|
|
@ -25,7 +25,7 @@ UCarlaGameInstance::UCarlaGameInstance() {
|
|||
CarlaSettings->LogSettings();
|
||||
}
|
||||
|
||||
UCarlaGameInstance::~UCarlaGameInstance() {}
|
||||
UCarlaGameInstance::~UCarlaGameInstance() = default;
|
||||
|
||||
void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
|
||||
const FMockGameControllerSettings &MockControllerSettings)
|
||||
|
@ -40,7 +40,7 @@ void UCarlaGameInstance::InitializeGameControllerIfNotPresent(
|
|||
}
|
||||
}
|
||||
|
||||
void UCarlaGameInstance::NotifyBeginEpisode(UCarlaEpisode &Episode)
|
||||
void UCarlaGameInstance::StartServer()
|
||||
{
|
||||
if (!bServerIsRunning)
|
||||
{
|
||||
|
@ -48,10 +48,4 @@ void UCarlaGameInstance::NotifyBeginEpisode(UCarlaEpisode &Episode)
|
|||
Server.AsyncRun(GetNumberOfThreadsForRPCServer());
|
||||
bServerIsRunning = true;
|
||||
}
|
||||
Server.NotifyBeginEpisode(Episode);
|
||||
}
|
||||
|
||||
void UCarlaGameInstance::NotifyEndEpisode()
|
||||
{
|
||||
Server.NotifyEndEpisode();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@ public:
|
|||
void InitializeGameControllerIfNotPresent(
|
||||
const FMockGameControllerSettings &MockControllerSettings);
|
||||
|
||||
/// Starts the Carla server if not already running.
|
||||
void StartServer();
|
||||
|
||||
ICarlaGameControllerBase &GetGameController()
|
||||
{
|
||||
check(GameController != nullptr);
|
||||
|
@ -58,19 +61,33 @@ public:
|
|||
return CarlaSettings;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UCarlaEpisode *GetCarlaEpisode()
|
||||
{
|
||||
return CurrentEpisode;
|
||||
}
|
||||
|
||||
FDataRouter &GetDataRouter()
|
||||
{
|
||||
return DataRouter;
|
||||
}
|
||||
|
||||
void NotifyBeginEpisode(UCarlaEpisode &Episode);
|
||||
void NotifyBeginEpisode(UCarlaEpisode &Episode)
|
||||
{
|
||||
CurrentEpisode = &Episode;
|
||||
Server.NotifyBeginEpisode(Episode);
|
||||
}
|
||||
|
||||
void Tick(float /*DeltaSeconds*/)
|
||||
{
|
||||
Server.RunSome(10u); /// @todo
|
||||
}
|
||||
|
||||
void NotifyEndEpisode();
|
||||
void NotifyEndEpisode()
|
||||
{
|
||||
Server.NotifyEndEpisode();
|
||||
CurrentEpisode = nullptr;
|
||||
}
|
||||
|
||||
const FTheNewCarlaServer &GetServer() const
|
||||
{
|
||||
|
@ -85,6 +102,9 @@ private:
|
|||
UPROPERTY(Category = "CARLA Settings", EditAnywhere)
|
||||
UCarlaSettings *CarlaSettings = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
UCarlaEpisode *CurrentEpisode = nullptr;
|
||||
|
||||
FDataRouter DataRouter;
|
||||
|
||||
TUniquePtr<ICarlaGameControllerBase> GameController;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
#include "Carla/Game/CarlaGameInstance.h"
|
||||
#include "Carla/Game/TheNewCarlaGameModeBase.h"
|
||||
#include "Carla/Settings/CarlaSettings.h"
|
||||
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
|
||||
#include "CarlaStatics.generated.h"
|
||||
|
||||
// =============================================================================
|
||||
// -- UCarlaStatics declaration ------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
UCLASS()
|
||||
class CARLA_API UCarlaStatics : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="CARLA", meta=(WorldContext="WorldContextObject"))
|
||||
static ATheNewCarlaGameModeBase *GetGameMode(const UObject *WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="CARLA", meta=(WorldContext="WorldContextObject"))
|
||||
static UCarlaGameInstance *GetGameInstance(const UObject *WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="CARLA", meta=(WorldContext="WorldContextObject"))
|
||||
static UCarlaEpisode *GetCurrentEpisode(const UObject *WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="CARLA", meta=(WorldContext="WorldContextObject"))
|
||||
static UCarlaSettings *GetCarlaSettings(const UObject *WorldContextObject);
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// -- UCarlaStatics implementation ---------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
inline ATheNewCarlaGameModeBase *UCarlaStatics::GetGameMode(const UObject *WorldContext)
|
||||
{
|
||||
return Cast<ATheNewCarlaGameModeBase>(UGameplayStatics::GetGameMode(WorldContext));
|
||||
}
|
||||
|
||||
inline UCarlaGameInstance *UCarlaStatics::GetGameInstance(const UObject *WorldContext)
|
||||
{
|
||||
return Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(WorldContext));
|
||||
}
|
||||
|
||||
inline UCarlaEpisode *UCarlaStatics::GetCurrentEpisode(const UObject *WorldContext)
|
||||
{
|
||||
auto GameInstance = GetGameInstance(WorldContext);
|
||||
return GameInstance != nullptr ? GameInstance->GetCarlaEpisode() : nullptr;
|
||||
}
|
||||
|
||||
inline UCarlaSettings *UCarlaStatics::GetCarlaSettings(const UObject *WorldContext)
|
||||
{
|
||||
auto GameInstance = GetGameInstance(WorldContext);
|
||||
return GameInstance != nullptr ? GameInstance->GetCARLASettings() : nullptr;
|
||||
}
|
||||
|
|
@ -75,6 +75,12 @@ void ATheNewCarlaGameModeBase::InitGame(
|
|||
UE_LOG(LogCarla, Error, TEXT("Missing weather class!"));
|
||||
}
|
||||
|
||||
GameInstance->StartServer();
|
||||
|
||||
Episode->WorldObserver = World->SpawnActor<AWorldObserver>();
|
||||
Episode->WorldObserver->SetEpisode(*Episode);
|
||||
Episode->WorldObserver->SetStream(GameInstance->GetServer().OpenMultiStream());
|
||||
|
||||
SpawnActorFactories();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,60 +11,70 @@
|
|||
#include "Util/OpenDrive.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/road/WaypointGenerator.h>
|
||||
#include <carla/rpc/String.h>
|
||||
#include <carla/geom/Math.h>
|
||||
#include <carla/road/element/Waypoint.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
TArray<FVector> DirectedPointArray2FVectorArray(
|
||||
const TArray<AOpenDriveActor::DirectedPoint> &DirectedPoints)
|
||||
static TArray<FVector> WaypointVector2FVectorArray(
|
||||
const std::vector<carla::road::element::Waypoint> &Waypoints,
|
||||
const float TriggersHeight)
|
||||
{
|
||||
TArray<FVector> Positions;
|
||||
Positions.Reserve(DirectedPoints.Num());
|
||||
for (int i = 0; i < DirectedPoints.Num(); ++i)
|
||||
Positions.Reserve(Waypoints.size());
|
||||
for (int i = 0; i < Waypoints.size(); ++i)
|
||||
{
|
||||
Positions.Add(DirectedPoints[i].location);
|
||||
// Add the trigger height because the z position of the points does not
|
||||
// influence on the driver AI and is easy to visualize in the editor
|
||||
Positions.Add(Waypoints[i].ComputeTransform().location +
|
||||
FVector(0.f, 0.f, TriggersHeight));
|
||||
}
|
||||
return Positions;
|
||||
}
|
||||
|
||||
AOpenDriveActor::AOpenDriveActor(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer)
|
||||
AOpenDriveActor::AOpenDriveActor(const FObjectInitializer &ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// Structure to hold one-time initialization
|
||||
static struct FConstructorStatics
|
||||
{
|
||||
// A helper class object we use to find target UTexture2D object in resource package
|
||||
// A helper class object we use to find target UTexture2D object in resource
|
||||
// package
|
||||
ConstructorHelpers::FObjectFinderOptional<UTexture2D> TextureObject;
|
||||
FName Category;
|
||||
FText Name;
|
||||
FConstructorStatics()
|
||||
// Use helper class object to find the texture resource path
|
||||
: TextureObject(TEXT("/Carla/Icons/OpenDriveActorIcon"))
|
||||
, Category(TEXT("OpenDriveActor"))
|
||||
, Name(NSLOCTEXT("SpriteCategory", "OpenDriveActor", "OpenDriveActor"))
|
||||
{
|
||||
}
|
||||
: TextureObject(TEXT("/Carla/Icons/OpenDriveActorIcon")),
|
||||
Category(TEXT("OpenDriveActor")),
|
||||
Name(NSLOCTEXT("SpriteCategory", "OpenDriveActor", "OpenDriveActor"))
|
||||
{}
|
||||
} ConstructorStatics;
|
||||
|
||||
// We need a scene component to attach Icon sprite
|
||||
USceneComponent* SceneComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComp"));
|
||||
USceneComponent *SceneComponent =
|
||||
ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComp"));
|
||||
RootComponent = SceneComponent;
|
||||
RootComponent->Mobility = EComponentMobility::Static;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
SpriteComponent = ObjectInitializer.CreateEditorOnlyDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
|
||||
SpriteComponent =
|
||||
ObjectInitializer.CreateEditorOnlyDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
|
||||
if (SpriteComponent)
|
||||
{
|
||||
SpriteComponent->Sprite = ConstructorStatics.TextureObject.Get(); // Get the sprite texture from helper class object
|
||||
SpriteComponent->SpriteInfo.Category = ConstructorStatics.Category; // Assign sprite category name
|
||||
SpriteComponent->SpriteInfo.DisplayName = ConstructorStatics.Name; // Assign sprite display name
|
||||
SpriteComponent->SetupAttachment(RootComponent); // Attach sprite to scene component
|
||||
// Get the sprite texture from helper class object
|
||||
SpriteComponent->Sprite = ConstructorStatics.TextureObject.Get();
|
||||
// Assign sprite category name
|
||||
SpriteComponent->SpriteInfo.Category = ConstructorStatics.Category;
|
||||
// Assign sprite display name
|
||||
SpriteComponent->SpriteInfo.DisplayName = ConstructorStatics.Name;
|
||||
// Attach sprite to scene component
|
||||
SpriteComponent->SetupAttachment(RootComponent);
|
||||
SpriteComponent->Mobility = EComponentMobility::Static;
|
||||
SpriteComponent->SetEditorScale(1.0f);
|
||||
SpriteComponent->SetEditorScale(1.f);
|
||||
}
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
@ -129,35 +139,21 @@ void AOpenDriveActor::PostEditChangeProperty(struct FPropertyChangedEvent& Event
|
|||
}
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
ARoutePlanner *AOpenDriveActor::GenerateRoutePlanner(const TArray<DirectedPoint> &DirectedPoints)
|
||||
{
|
||||
using CarlaMath = carla::geom::Math;
|
||||
|
||||
TArray<FVector> Positions = DirectedPointArray2FVectorArray(DirectedPoints);
|
||||
ARoutePlanner *RoutePlanner = GetWorld()->SpawnActor<ARoutePlanner>();
|
||||
|
||||
RoutePlanner->SetActorRotation(FRotator(0.0f, CarlaMath::to_degrees(DirectedPoints[0].tangent), 0.0f));
|
||||
RoutePlanner->SetActorLocation(DirectedPoints[0].location);
|
||||
RoutePlanner->SetBoxExtent(FVector(70.0f, 70.0f, 50.0f));
|
||||
RoutePlanner->AddRoute(1.0f, Positions);
|
||||
RoutePlanner->Init();
|
||||
RoutePlanners.Add(RoutePlanner);
|
||||
return RoutePlanner;
|
||||
}
|
||||
|
||||
void AOpenDriveActor::BuildRoutes()
|
||||
{
|
||||
using CarlaMath = carla::geom::Math;
|
||||
using IdType = carla::road::element::id_type;
|
||||
using Waypoint = carla::road::element::Waypoint;
|
||||
using WaypointGen = carla::road::WaypointGenerator;
|
||||
|
||||
std::string ParseError;
|
||||
|
||||
// NOTE(Andrei): As the OpenDrive file has the same name as level,
|
||||
// build the path to the xodr file using the lavel name and the
|
||||
// game content directory.
|
||||
FString MapName = GetWorld()->GetMapName();
|
||||
FString XodrContent = FOpenDrive::Load(MapName);
|
||||
// As the OpenDrive file has the same name as level, build the path to the
|
||||
// xodr file using the lavel name and the game content directory.
|
||||
const FString XodrContent = FOpenDrive::Load(GetWorld()->GetMapName());
|
||||
|
||||
auto map_ptr = carla::opendrive::OpenDrive::Load(TCHAR_TO_UTF8(*XodrContent),
|
||||
auto map_ptr = carla::opendrive::OpenDrive::Load(
|
||||
TCHAR_TO_UTF8(*XodrContent),
|
||||
XmlInputType::CONTENT,
|
||||
&ParseError);
|
||||
|
||||
|
@ -168,63 +164,59 @@ void AOpenDriveActor::BuildRoutes()
|
|||
}
|
||||
|
||||
const auto &map = map_ptr->GetData();
|
||||
std::vector<carla::road::lane_junction_t> JunctionInfo = map.GetJunctionInformation();
|
||||
|
||||
// NOTE(Andrei): Build the roads that are not junctions
|
||||
auto RoadIDsView = map.GetAllIds();
|
||||
std::vector<IdType> roadIDs(RoadIDsView.begin(), RoadIDsView.end());
|
||||
std::sort(roadIDs.begin(), roadIDs.end());
|
||||
// List with waypoints, each one at the end of each lane of the map
|
||||
const std::vector<Waypoint> MapLaneBeginWaypoint =
|
||||
WaypointGen::GenerateLaneEnd(*map_ptr);
|
||||
|
||||
for (auto &&id : roadIDs)
|
||||
for (auto &&EndLaneWaypoint : MapLaneBeginWaypoint)
|
||||
{
|
||||
GenerateWaypointsRoad(map.GetRoad(id));
|
||||
}
|
||||
std::vector<Waypoint> Successors = WaypointGen::GetSuccessors(EndLaneWaypoint);
|
||||
|
||||
// NOTE(Andrei): Build the roads that are junctions as one RoutePlanner
|
||||
// can have more than one path that can be taken
|
||||
// generate the RoutePlanner
|
||||
ARoutePlanner *RoutePlanner = GetWorld()->SpawnActor<ARoutePlanner>();
|
||||
RoutePlanner->bIsIntersection = std::any_of(Successors.begin(), Successors.end(), [](auto w) {
|
||||
return w.IsIntersection();
|
||||
});
|
||||
RoutePlanner->SetBoxExtent(FVector(70.f, 70.f, 50.f));
|
||||
RoutePlanner->SetActorRotation(EndLaneWaypoint.ComputeTransform().rotation);
|
||||
RoutePlanner->SetActorLocation(EndLaneWaypoint.ComputeTransform().location +
|
||||
FVector(0.f, 0.f, TriggersHeight));
|
||||
|
||||
// junctionId roadID laneID
|
||||
std::map<int, std::map<int, std::map<int, ARoutePlanner *>>> Junctions;
|
||||
|
||||
for (auto && Junction : JunctionInfo)
|
||||
// fill the RoutePlanner with all the needed roads
|
||||
for (auto &&Successor : Successors)
|
||||
{
|
||||
TArray<TArray<DirectedPoint>> Waypoints;
|
||||
const IdType RoadId = Successor.GetRoadId();
|
||||
const float MaxDist = map.GetRoad(RoadId)->GetLength();
|
||||
|
||||
int FromRoadID = Junction.incomming_road;
|
||||
int ToRoadID = Junction.connection_road;
|
||||
int JunctonID = Junction.junction_id;
|
||||
std::vector<Waypoint> Waypoints;
|
||||
|
||||
GenerateWaypointsJunction(map.GetRoad(ToRoadID), Waypoints);
|
||||
ARoutePlanner *routePlanner = nullptr;
|
||||
Waypoints.emplace_back(Successor);
|
||||
|
||||
std::sort(Junction.from_lane.begin(), Junction.from_lane.end(), std::greater<int>());
|
||||
|
||||
if (Junction.from_lane[0] < 0)
|
||||
for (float Dist = RoadAccuracy; Dist < MaxDist; Dist += RoadAccuracy)
|
||||
{
|
||||
std::reverse(Junction.from_lane.begin(), Junction.from_lane.end());
|
||||
const auto NewWaypoint = WaypointGen::GetNext(Successor, Dist);
|
||||
|
||||
check(Dist < MaxDist);
|
||||
check(NewWaypoint.size() == 1);
|
||||
|
||||
Waypoints.emplace_back(NewWaypoint[0]);
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < Junction.from_lane.size(); ++n)
|
||||
{
|
||||
int FromLaneID = Junction.from_lane[n];
|
||||
routePlanner = Junctions[JunctonID][FromRoadID][FromLaneID];
|
||||
// merge with the first waypoint of the next lane if needed
|
||||
Waypoints.emplace_back(WaypointGen::GetNext(
|
||||
Successor, CarlaMath::clamp(MaxDist - 0.1f, 0.f, MaxDist))[0]);
|
||||
|
||||
if (routePlanner == nullptr)
|
||||
{
|
||||
routePlanner = GenerateRoutePlanner(Waypoints[n]);
|
||||
routePlanner->SetSplineColor(FColor::MakeRandomColor());
|
||||
Junctions[JunctonID][FromRoadID][FromLaneID] = routePlanner;
|
||||
}
|
||||
else
|
||||
{
|
||||
routePlanner->AddRoute(1.0, DirectedPointArray2FVectorArray(Waypoints[n]));
|
||||
}
|
||||
check(Waypoints.size() >= 2);
|
||||
|
||||
TArray<FVector> Positions = WaypointVector2FVectorArray(Waypoints, TriggersHeight);
|
||||
|
||||
RoutePlanner->AddRoute(1.f, Positions);
|
||||
RoutePlanners.Add(RoutePlanner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all the existing ARoutePlanner and VehicleSpawners previously
|
||||
/// generated by this class to avoid overlapping
|
||||
void AOpenDriveActor::RemoveRoutes()
|
||||
{
|
||||
const int rp_num = RoutePlanners.Num();
|
||||
|
@ -238,171 +230,6 @@ void AOpenDriveActor::RemoveRoutes()
|
|||
RoutePlanners.Empty();
|
||||
}
|
||||
|
||||
TArray<AOpenDriveActor::DirectedPoint> AOpenDriveActor::GenerateLaneZeroPoints(
|
||||
const RoadSegment *road)
|
||||
{
|
||||
using RoadElevationInfo = carla::road::element::RoadElevationInfo;
|
||||
|
||||
size_t LanesOffsetIndex = 0;
|
||||
TArray<DirectedPoint> LaneZeroPoints;
|
||||
|
||||
const RoadGeneralInfo *generalInfo =
|
||||
road->GetInfo<RoadGeneralInfo>(0.0);
|
||||
std::vector<std::pair<double, double>> LanesOffset = generalInfo->GetLanesOffset();
|
||||
|
||||
for (float WaypointsOffset = 0.0f; WaypointsOffset < road->GetLength() + RoadAccuracy; WaypointsOffset += RoadAccuracy)
|
||||
{
|
||||
// NOTE(Andrei): Calculate the which laneOffset has to be used
|
||||
if (LanesOffsetIndex < LanesOffset.size() - 1 &&
|
||||
WaypointsOffset >= LanesOffset[LanesOffsetIndex + 1].first)
|
||||
{
|
||||
++LanesOffsetIndex;
|
||||
}
|
||||
|
||||
// NOTE(Andrei): Get waypoin at the offset, and invert the y axis
|
||||
DirectedPoint Waypoint = road->GetDirectedPointIn(WaypointsOffset);
|
||||
|
||||
// Elevate the generated road 1m because the triggers and visualization
|
||||
Waypoint.location.z += 1;
|
||||
|
||||
// NOTE(Andrei): Applyed the laneOffset of the lane section
|
||||
Waypoint.ApplyLateralOffset(LanesOffset[LanesOffsetIndex].second);
|
||||
|
||||
LaneZeroPoints.Add(Waypoint);
|
||||
}
|
||||
|
||||
return LaneZeroPoints;
|
||||
}
|
||||
|
||||
TArray<TArray<AOpenDriveActor::DirectedPoint>> AOpenDriveActor::GenerateRightLaneWaypoints(
|
||||
const RoadSegment *road,
|
||||
const TArray<DirectedPoint> &laneZeroPoints)
|
||||
{
|
||||
const RoadInfoLane *lanesInfo =
|
||||
road->GetInfo<RoadInfoLane>(0.0);
|
||||
std::vector<int> rightLanes =
|
||||
lanesInfo->getLanesIDs(RoadInfoLane::which_lane_e::Right);
|
||||
|
||||
TArray<TArray<DirectedPoint>> retWaypoints;
|
||||
double currentOffset = 0.0;
|
||||
|
||||
for (size_t j = 0; j < rightLanes.size(); ++j)
|
||||
{
|
||||
const LaneInfo *laneInfo = lanesInfo->getLane(rightLanes[j]);
|
||||
const float HalfWidth = laneInfo->_width * 0.5;
|
||||
|
||||
currentOffset += HalfWidth;
|
||||
if (laneInfo->_type == "driving")
|
||||
{
|
||||
TArray<DirectedPoint> roadWaypoints;
|
||||
for (int i = 0; i < laneZeroPoints.Num(); ++i)
|
||||
{
|
||||
DirectedPoint currentPoint = laneZeroPoints[i];
|
||||
currentPoint.ApplyLateralOffset(-currentOffset);
|
||||
roadWaypoints.Add(currentPoint);
|
||||
}
|
||||
if (roadWaypoints.Num() >= 2)
|
||||
{
|
||||
retWaypoints.Add(roadWaypoints);
|
||||
}
|
||||
}
|
||||
currentOffset += HalfWidth;
|
||||
}
|
||||
return retWaypoints;
|
||||
}
|
||||
|
||||
TArray<TArray<AOpenDriveActor::DirectedPoint>> AOpenDriveActor::GenerateLeftLaneWaypoints(
|
||||
const RoadSegment *road,
|
||||
const TArray<DirectedPoint> &laneZeroPoints)
|
||||
{
|
||||
using CarlaMath = carla::geom::Math;
|
||||
|
||||
const RoadInfoLane *lanesInfo =
|
||||
road->GetInfo<RoadInfoLane>(0.0);
|
||||
std::vector<int> leftLanes = lanesInfo->getLanesIDs(RoadInfoLane::which_lane_e::Left);
|
||||
|
||||
TArray<TArray<DirectedPoint>> retWaypoints;
|
||||
double currentOffset = 0.0;
|
||||
|
||||
for (size_t j = 0; j < leftLanes.size(); ++j)
|
||||
{
|
||||
const LaneInfo *laneInfo = lanesInfo->getLane(leftLanes[j]);
|
||||
const float HalfWidth = laneInfo->_width * 0.5;
|
||||
|
||||
currentOffset += HalfWidth;
|
||||
if (laneInfo->_type == "driving")
|
||||
{
|
||||
TArray<DirectedPoint> roadWaypoints;
|
||||
for (int i = 0; i < laneZeroPoints.Num(); ++i)
|
||||
{
|
||||
DirectedPoint currentPoint = laneZeroPoints[i];
|
||||
currentPoint.ApplyLateralOffset(currentOffset);
|
||||
if (currentPoint.tangent + CarlaMath::pi() < CarlaMath::pi_double())
|
||||
{
|
||||
currentPoint.tangent += CarlaMath::pi();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPoint.tangent -= CarlaMath::pi();
|
||||
}
|
||||
roadWaypoints.Add(currentPoint);
|
||||
}
|
||||
if (roadWaypoints.Num() >= 2)
|
||||
{
|
||||
Algo::Reverse(roadWaypoints);
|
||||
retWaypoints.Add(roadWaypoints);
|
||||
}
|
||||
}
|
||||
currentOffset += HalfWidth;
|
||||
}
|
||||
return retWaypoints;
|
||||
}
|
||||
|
||||
void AOpenDriveActor::GenerateWaypointsRoad(const RoadSegment *road)
|
||||
{
|
||||
const RoadGeneralInfo *generalInfo =
|
||||
road->GetInfo<RoadGeneralInfo>(0.0);
|
||||
if (generalInfo->GetJunctionId() > -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<DirectedPoint> laneZeroPoints = GenerateLaneZeroPoints(road);
|
||||
|
||||
TArray<TArray<DirectedPoint>> rightLaneWaypoints = GenerateRightLaneWaypoints(road, laneZeroPoints);
|
||||
TArray<TArray<DirectedPoint>> leftLaneWaypoints = GenerateLeftLaneWaypoints(road, laneZeroPoints);
|
||||
|
||||
for (int i = 0; i < rightLaneWaypoints.Num(); ++i)
|
||||
{
|
||||
GenerateRoutePlanner(rightLaneWaypoints[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < leftLaneWaypoints.Num(); ++i)
|
||||
{
|
||||
GenerateRoutePlanner(leftLaneWaypoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void AOpenDriveActor::GenerateWaypointsJunction(
|
||||
const RoadSegment *road,
|
||||
TArray<TArray<DirectedPoint>> &out_waypoints)
|
||||
{
|
||||
const RoadGeneralInfo *generalInfo =
|
||||
road->GetInfo<RoadGeneralInfo>(0.0);
|
||||
if (generalInfo->GetJunctionId() == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<DirectedPoint> laneZeroPoints = GenerateLaneZeroPoints(road);
|
||||
out_waypoints = GenerateRightLaneWaypoints(road, laneZeroPoints);
|
||||
|
||||
if (out_waypoints.Num() == 0)
|
||||
{
|
||||
out_waypoints = GenerateLeftLaneWaypoints(road, laneZeroPoints);
|
||||
}
|
||||
}
|
||||
|
||||
void AOpenDriveActor::DebugRoutes() const
|
||||
{
|
||||
for (int i = 0; i < RoutePlanners.Num(); ++i)
|
||||
|
@ -426,15 +253,22 @@ void AOpenDriveActor::AddSpawners()
|
|||
for (int i = 0; i < RoutePlanners.Num(); ++i)
|
||||
{
|
||||
if (RoutePlanners[i] != nullptr)
|
||||
{
|
||||
if (!bOnIntersections && RoutePlanners[i]->bIsIntersection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
FTransform Trans = RoutePlanners[i]->GetActorTransform();
|
||||
AVehicleSpawnPoint *Spawner = GetWorld()->SpawnActor<AVehicleSpawnPoint>();
|
||||
Spawner->SetActorRotation(Trans.GetRotation());
|
||||
Spawner->SetActorLocation(Trans.GetTranslation() + FVector(0.0f, 0.0f, SpawnersHeight));
|
||||
Spawner->SetActorLocation(Trans.GetTranslation() + FVector(0.f, 0.f, SpawnersHeight));
|
||||
VehicleSpawners.Add(Spawner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOpenDriveActor::RemoveSpawners()
|
||||
{
|
||||
|
|
|
@ -28,9 +28,11 @@ class CARLA_API AOpenDriveActor : public AActor
|
|||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
// A UBillboardComponent to hold Icon sprite
|
||||
|
||||
/// A UBillboardComponent to hold Icon sprite
|
||||
UBillboardComponent *SpriteComponent;
|
||||
// Sprite for the Billboard Component
|
||||
|
||||
/// Sprite for the Billboard Component
|
||||
UTexture2D *SpriteTexture;
|
||||
|
||||
private:
|
||||
|
@ -42,17 +44,23 @@ private:
|
|||
TArray<AVehicleSpawnPoint *> VehicleSpawners;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
/// Generate the road network using an OpenDrive file (named as the current .umap)
|
||||
/// Generate the road network using an OpenDrive file (named as the current
|
||||
/// .umap)
|
||||
UPROPERTY(Category = "Generate", EditAnywhere)
|
||||
bool bGenerateRoutes = false;
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
||||
/// Distance between waypoints where the cars will drive
|
||||
UPROPERTY(Category = "Generate", EditAnywhere, meta = (ClampMin = "0.01", UIMin = "0.01"))
|
||||
float RoadAccuracy = 2.0f;
|
||||
float RoadAccuracy = 2.f;
|
||||
|
||||
/// Trigger elevantion
|
||||
UPROPERTY(Category = "Generate", EditAnywhere, meta = (ClampMin = "0.01", UIMin = "0.01"))
|
||||
float TriggersHeight = 100.f;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
/// Remove the previously generated road network. Also, it will remove spawners if necessary
|
||||
/// Remove the previously generated road network. Also, it will remove
|
||||
/// spawners if necessary
|
||||
UPROPERTY(Category = "Generate", EditAnywhere)
|
||||
bool bRemoveRoutes = false;
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
@ -61,9 +69,14 @@ private:
|
|||
UPROPERTY(Category = "Spawners", EditAnywhere)
|
||||
bool bAddSpawners = false;
|
||||
|
||||
/// Determine the height where the spawners will be placed, relative to each RoutePlanner
|
||||
/// If true, spawners will be placed on junctions too
|
||||
UPROPERTY(Category = "Spawners", EditAnywhere)
|
||||
float SpawnersHeight = 300.0;
|
||||
bool bOnIntersections = false;
|
||||
|
||||
/// Determine the height where the spawners will be placed, relative to each
|
||||
/// RoutePlanner
|
||||
UPROPERTY(Category = "Spawners", EditAnywhere)
|
||||
float SpawnersHeight = 300.f;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
/// Remove already placed spawners if necessary
|
||||
|
@ -79,16 +92,12 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
using RoadSegment = carla::road::element::RoadSegment;
|
||||
using DirectedPoint = carla::road::element::DirectedPoint;
|
||||
using LaneInfo = carla::road::element::LaneInfo;
|
||||
using RoadGeneralInfo = carla::road::element::RoadGeneralInfo;
|
||||
using RoadInfoLane = carla::road::element::RoadInfoLane;
|
||||
|
||||
AOpenDriveActor(const FObjectInitializer &ObjectInitializer);
|
||||
|
||||
void BuildRoutes();
|
||||
|
||||
/// Remove all the existing ARoutePlanner and VehicleSpawners previously
|
||||
/// generated by this class to avoid overlapping
|
||||
void RemoveRoutes();
|
||||
|
||||
void DebugRoutes() const;
|
||||
|
@ -97,28 +106,11 @@ public:
|
|||
|
||||
#if WITH_EDITOR
|
||||
void PostEditChangeProperty(struct FPropertyChangedEvent &PropertyChangedEvent);
|
||||
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
ARoutePlanner *GenerateRoutePlanner(const TArray<DirectedPoint> &waypoints);
|
||||
|
||||
TArray<DirectedPoint> GenerateLaneZeroPoints(
|
||||
const RoadSegment *road);
|
||||
|
||||
TArray<TArray<DirectedPoint>> GenerateRightLaneWaypoints(
|
||||
const RoadSegment *road,
|
||||
const TArray<DirectedPoint> &laneZeroPoints);
|
||||
|
||||
TArray<TArray<DirectedPoint>> GenerateLeftLaneWaypoints(
|
||||
const RoadSegment *road,
|
||||
const TArray<DirectedPoint> &laneZeroPoints);
|
||||
|
||||
void GenerateWaypointsJunction(
|
||||
const RoadSegment *road,
|
||||
TArray<TArray<DirectedPoint>> &waypoints);
|
||||
|
||||
void GenerateWaypointsRoad(const RoadSegment *road);
|
||||
|
||||
void AddSpawners();
|
||||
|
||||
void RemoveSpawners();
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/Buffer.h>
|
||||
#include <carla/sensor/SensorRegistry.h>
|
||||
#include <carla/sensor/s11n/SensorHeaderSerializer.h>
|
||||
#include <carla/streaming/Stream.h>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
template <typename T>
|
||||
class FDataStreamTmpl;
|
||||
|
||||
// =============================================================================
|
||||
// -- FAsyncDataStreamTmpl -----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
/// A streaming channel for sending sensor data to clients, supports sending
|
||||
/// data asynchronously. Data sent by the "Send" functions is passed to the
|
||||
/// serializer registered with the sensor at carla::sensor:SensorRegistry before
|
||||
/// being sent down the stream.
|
||||
///
|
||||
/// @warning This is a single-use object, a new one needs to be created for each
|
||||
/// new message.
|
||||
///
|
||||
/// FAsyncDataStream also has a pool of carla::Buffer that allows reusing the
|
||||
/// allocated memory, use it whenever possible.
|
||||
template <typename T>
|
||||
class FAsyncDataStreamTmpl
|
||||
{
|
||||
public:
|
||||
|
||||
using StreamType = T;
|
||||
|
||||
FAsyncDataStreamTmpl(FAsyncDataStreamTmpl &&) = default;
|
||||
|
||||
/// Return the token that allows subscribing to this stream.
|
||||
auto GetToken() const
|
||||
{
|
||||
return Stream.GetToken();
|
||||
}
|
||||
|
||||
/// Pop a Buffer from the pool. Buffers in the pool can reuse the memory
|
||||
/// allocated by previous messages, significantly improving performance for
|
||||
/// big messages.
|
||||
carla::Buffer PopBufferFromPool()
|
||||
{
|
||||
return Stream.MakeBuffer();
|
||||
}
|
||||
|
||||
/// Send some data down the stream.
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
void Send(SensorT &Sensor, ArgsT &&... Args);
|
||||
|
||||
private:
|
||||
|
||||
friend class FDataStreamTmpl<T>;
|
||||
|
||||
/// @pre This functions needs to be called in the game-thread.
|
||||
template <typename SensorT>
|
||||
explicit FAsyncDataStreamTmpl(const SensorT &InSensor, StreamType InStream);
|
||||
|
||||
StreamType Stream;
|
||||
|
||||
carla::Buffer Header;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// -- FAsyncDataStream and FAsyncDataMultiStream -------------------------------
|
||||
// =============================================================================
|
||||
|
||||
using FAsyncDataStream = FAsyncDataStreamTmpl<carla::streaming::Stream>;
|
||||
|
||||
using FAsyncDataMultiStream = FAsyncDataStreamTmpl<carla::streaming::MultiStream>;
|
||||
|
||||
// =============================================================================
|
||||
// -- FAsyncDataStreamTmpl implementation --------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
template <typename T>
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
inline void FAsyncDataStreamTmpl<T>::Send(SensorT &Sensor, ArgsT &&... Args)
|
||||
{
|
||||
Stream.Write(
|
||||
std::move(Header),
|
||||
carla::sensor::SensorRegistry::Serialize(Sensor, std::forward<ArgsT>(Args)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename SensorT>
|
||||
inline FAsyncDataStreamTmpl<T>::FAsyncDataStreamTmpl(
|
||||
const SensorT &Sensor,
|
||||
StreamType InStream)
|
||||
: Stream(std::move(InStream)),
|
||||
Header([&Sensor]() {
|
||||
check(IsInGameThread());
|
||||
using Serializer = carla::sensor::s11n::SensorHeaderSerializer;
|
||||
return Serializer::Serialize(
|
||||
carla::sensor::SensorRegistry::template get<SensorT*>::index,
|
||||
GFrameCounter,
|
||||
Sensor.GetActorTransform());
|
||||
}()) {}
|
|
@ -50,13 +50,6 @@ void ACollisionSensor::BeginPlay()
|
|||
return;
|
||||
}
|
||||
Episode = &GameMode->GetCarlaEpisode();
|
||||
|
||||
GameInstance = Cast<UCarlaGameInstance>(GetGameInstance());
|
||||
if (GameMode == nullptr)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("ACollisionSensor: Game instance not compatible with this sensor"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ACollisionSensor::OnCollisionEvent(
|
||||
|
@ -65,16 +58,14 @@ void ACollisionSensor::OnCollisionEvent(
|
|||
FVector NormalImpulse,
|
||||
const FHitResult &Hit)
|
||||
{
|
||||
if ((Episode != nullptr) && (GameInstance != nullptr) && (Actor != nullptr) && (OtherActor != nullptr))
|
||||
if ((Episode != nullptr) && (Actor != nullptr) && (OtherActor != nullptr))
|
||||
{
|
||||
const auto &Registry = Episode->GetActorRegistry();
|
||||
const auto &Server = GameInstance->GetServer();
|
||||
constexpr float TO_METERS = 1e-2;
|
||||
NormalImpulse *= TO_METERS;
|
||||
GetDataStream().Send_GameThread(
|
||||
GetDataStream(*this).Send(
|
||||
*this,
|
||||
Server.SerializeActor(Registry.FindOrFake(Actor)),
|
||||
Server.SerializeActor(Registry.FindOrFake(OtherActor)),
|
||||
Episode->SerializeActor(Episode->FindOrFakeActor(Actor)),
|
||||
Episode->SerializeActor(Episode->FindOrFakeActor(OtherActor)),
|
||||
carla::geom::Vector3D{NormalImpulse.X, NormalImpulse.Y, NormalImpulse.Z});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
|
||||
#include "CollisionSensor.generated.h"
|
||||
|
@ -40,7 +41,4 @@ private:
|
|||
|
||||
UPROPERTY()
|
||||
const UCarlaEpisode *Episode = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
const UCarlaGameInstance *GameInstance = nullptr;
|
||||
};
|
||||
|
|
|
@ -6,47 +6,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Sensor/AsyncDataStream.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
#include <carla/Buffer.h>
|
||||
#include <carla/Optional.h>
|
||||
#include <carla/sensor/SensorRegistry.h>
|
||||
#include <carla/sensor/s11n/SensorHeaderSerializer.h>
|
||||
#include <carla/streaming/Stream.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <compiler/enable-ue4-macros.h>
|
||||
|
||||
// =============================================================================
|
||||
// -- FSensorMessageHeader -----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
/// Contains meta-information of a sensor message.
|
||||
class FSensorMessageHeader
|
||||
{
|
||||
public:
|
||||
|
||||
FSensorMessageHeader(FSensorMessageHeader &&) = default;
|
||||
|
||||
private:
|
||||
|
||||
FSensorMessageHeader(carla::Buffer InBuffer) : Buffer(std::move(InBuffer)) {}
|
||||
|
||||
template <typename T>
|
||||
friend class FDataStreamTmpl;
|
||||
|
||||
carla::Buffer Buffer;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// -- FDataStreamTmpl ----------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
/// A streaming channel for sending sensor data to clients. Each sensor has its
|
||||
/// own FDataStream. Use Send_GameThread and Send_Async for sending data
|
||||
/// generated by the sensor. Data sent by these functions is passed to the
|
||||
/// serializer registered with the sensor at carla::sensor:SensorRegistry before
|
||||
/// being sent down the stream.
|
||||
///
|
||||
/// FDataStream also has a pool of carla::Buffer that allows reusing the
|
||||
/// allocated memory, use it whenever possible.
|
||||
/// own FDataStream. Note however that this class does not provide a send
|
||||
/// function. In order to send data, a FAsyncDataStream needs to be created
|
||||
/// using "MakeAsyncDataStream" function. FAsyncDataStream allows sending data
|
||||
/// from any thread.
|
||||
template <typename T>
|
||||
class FDataStreamTmpl
|
||||
{
|
||||
|
@ -56,37 +31,28 @@ public:
|
|||
|
||||
FDataStreamTmpl() = default;
|
||||
|
||||
FDataStreamTmpl(FDataStreamTmpl &&) = default;
|
||||
FDataStreamTmpl &operator=(FDataStreamTmpl &&) = default;
|
||||
|
||||
FDataStreamTmpl(StreamType InStream) : Stream(std::move(InStream)) {}
|
||||
|
||||
/// Create the meta-information header associated with the sensor message.
|
||||
/// This functions needs to be called in the game-thread.
|
||||
/// Create a FAsyncDataStream object.
|
||||
///
|
||||
/// @pre This functions needs to be called in the game-thread.
|
||||
template <typename SensorT>
|
||||
FSensorMessageHeader MakeHeader(const SensorT &Sensor);
|
||||
auto MakeAsyncDataStream(const SensorT &Sensor)
|
||||
{
|
||||
check(Stream.has_value());
|
||||
return FAsyncDataStreamTmpl<T>{Sensor, *Stream};
|
||||
}
|
||||
|
||||
/// Pop a Buffer from the pool. Buffers in the pool can reuse the memory
|
||||
/// allocated by previous messages, significantly improving performance for
|
||||
/// big messages.
|
||||
carla::Buffer PopBufferFromPool();
|
||||
|
||||
/// Send some data down the stream. This function can only be called from the
|
||||
/// game-thread. No need to provide a FSensorMessageHeader to this function.
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
void Send_GameThread(SensorT &Sensor, ArgsT &&... Args);
|
||||
|
||||
/// Send some data down the stream. This function can be called from a
|
||||
/// different thread. It requires you however to provide a
|
||||
/// FSensorMessageHeader previously generated in the game-thread.
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
void Send_Async(FSensorMessageHeader Header, SensorT &Sensor, ArgsT &&... Args);
|
||||
|
||||
auto GetToken() const;
|
||||
/// Return the token that allows subscribing to this stream.
|
||||
auto GetToken() const
|
||||
{
|
||||
check(Stream.has_value());
|
||||
return (*Stream).token();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
carla::Optional<StreamType> Stream;
|
||||
boost::optional<StreamType> Stream;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
@ -96,64 +62,3 @@ private:
|
|||
using FDataStream = FDataStreamTmpl<carla::streaming::Stream>;
|
||||
|
||||
using FDataMultiStream = FDataStreamTmpl<carla::streaming::MultiStream>;
|
||||
|
||||
// =============================================================================
|
||||
// -- FDataStreamTmpl implementation -------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
template <typename T>
|
||||
template <typename SensorT>
|
||||
inline FSensorMessageHeader FDataStreamTmpl<T>::MakeHeader(const SensorT &Sensor)
|
||||
{
|
||||
check(IsInGameThread());
|
||||
using Serializer = carla::sensor::s11n::SensorHeaderSerializer;
|
||||
return {Serializer::Serialize(
|
||||
carla::sensor::SensorRegistry::template get<SensorT*>::index,
|
||||
GFrameCounter,
|
||||
Sensor.GetActorTransform())};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline carla::Buffer FDataStreamTmpl<T>::PopBufferFromPool()
|
||||
{
|
||||
#ifdef WITH_EDITOR
|
||||
if (!Stream.has_value())
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Sensor does not have a stream!"));
|
||||
return {};
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
check(Stream.has_value());
|
||||
return (*Stream).MakeBuffer();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
inline void FDataStreamTmpl<T>::Send_Async(FSensorMessageHeader Header, SensorT &Sensor, ArgsT &&... Args)
|
||||
{
|
||||
#ifdef WITH_EDITOR
|
||||
if (!Stream.has_value())
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Sensor does not have a stream!"));
|
||||
return;
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
check(Stream.has_value());
|
||||
(*Stream).Write(
|
||||
std::move(Header.Buffer),
|
||||
carla::sensor::SensorRegistry::Serialize(Sensor, std::forward<ArgsT>(Args)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename SensorT, typename... ArgsT>
|
||||
inline void FDataStreamTmpl<T>::Send_GameThread(SensorT &Sensor, ArgsT &&... Args)
|
||||
{
|
||||
Send_Async(MakeHeader(Sensor), Sensor, std::forward<ArgsT>(Args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline auto FDataStreamTmpl<T>::GetToken() const
|
||||
{
|
||||
check(Stream.has_value());
|
||||
return (*Stream).token();
|
||||
}
|
||||
|
|
|
@ -87,26 +87,31 @@ void FPixelReader::SendPixelsInRenderThread(TSensor &Sensor)
|
|||
|
||||
// First we create the message header (needs to be created in the
|
||||
// game-thread).
|
||||
auto Header = Sensor.GetDataStream().MakeHeader(Sensor);
|
||||
auto AsyncStream = Sensor.GetDataStream(Sensor);
|
||||
|
||||
// We need a shared ptr here because UE4 macros do not move the arguments -_-
|
||||
auto HeaderPtr = MakeShared<decltype(Header)>(std::move(Header));
|
||||
auto StreamPtr = std::make_shared<decltype(AsyncStream)>(std::move(AsyncStream));
|
||||
|
||||
// Then we enqueue commands in the render-thread that will write the image
|
||||
// buffer to the data stream.
|
||||
|
||||
auto WriteAndSend = [&Sensor, Hdr=std::move(HeaderPtr)](auto &InRHICmdList) mutable {
|
||||
auto &Stream = Sensor.GetDataStream();
|
||||
auto Buffer = Stream.PopBufferFromPool();
|
||||
auto WriteAndSend = [&Sensor, Stream=std::move(StreamPtr)](auto &InRHICmdList) mutable
|
||||
{
|
||||
/// @todo Can we make sure the sensor is not going to be destroyed?
|
||||
if (!Sensor.IsPendingKill())
|
||||
{
|
||||
auto Buffer = Stream->PopBufferFromPool();
|
||||
WritePixelsToBuffer(
|
||||
*Sensor.CaptureRenderTarget,
|
||||
Buffer,
|
||||
carla::sensor::SensorRegistry::get<TSensor *>::type::header_offset,
|
||||
InRHICmdList);
|
||||
Stream.Send_Async(std::move(*Hdr), Sensor, std::move(Buffer));
|
||||
Stream->Send(Sensor, std::move(Buffer));
|
||||
}
|
||||
};
|
||||
|
||||
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
|
||||
FWritePixels_Vulkan,
|
||||
FWritePixels_SendPixelsInRenderThread,
|
||||
std::function<void(FRHICommandListImmediate &)>, WriteAndSendFunction, std::move(WriteAndSend),
|
||||
{
|
||||
WriteAndSendFunction(RHICmdList);
|
||||
|
|
|
@ -69,8 +69,8 @@ void ARayCastLidar::Tick(const float DeltaTime)
|
|||
|
||||
ReadPoints(DeltaTime);
|
||||
|
||||
auto &DataStream = GetDataStream();
|
||||
DataStream.Send_GameThread(*this, LidarMeasurement, DataStream.PopBufferFromPool());
|
||||
auto DataStream = GetDataStream(*this);
|
||||
DataStream.Send(*this, LidarMeasurement, DataStream.PopBufferFromPool());
|
||||
}
|
||||
|
||||
void ARayCastLidar::ReadPoints(const float DeltaTime)
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Carla/Sensor/PixelReader.h"
|
||||
#include "Carla/Sensor/SceneCaptureSensor.h"
|
||||
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
#include "Carla/Sensor/PixelReader.h"
|
||||
|
||||
#include "SceneCaptureCamera.generated.h"
|
||||
|
||||
/// A sensor that captures images from the scene.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Sensor/SceneCaptureSensor.h"
|
||||
|
||||
#include "Carla/Game/CarlaStatics.h"
|
||||
|
||||
#include "Components/DrawFrustumComponent.h"
|
||||
#include "Components/SceneCaptureComponent2D.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
|
@ -28,10 +30,9 @@ namespace SceneCaptureSensor_local_ns {
|
|||
|
||||
static auto GetQualitySettings(UWorld *World)
|
||||
{
|
||||
check(World != nullptr);
|
||||
const auto *GameInstance = Cast<UCarlaGameInstance>(World->GetGameInstance());
|
||||
check(GameInstance != nullptr);
|
||||
return GameInstance->GetCarlaSettings().GetQualityLevel();
|
||||
auto Settings = UCarlaStatics::GetCarlaSettings(World);
|
||||
check(Settings != nullptr);
|
||||
return Settings->GetQualityLevel();
|
||||
}
|
||||
|
||||
} // namespace SceneCaptureSensor_local_ns
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "Carla/Sensor/ShaderBasedSensor.h"
|
||||
|
||||
#include "Carla/Actor/ActorDefinition.h"
|
||||
|
||||
#include "SemanticSegmentationCamera.generated.h"
|
||||
|
||||
/// Sensor that produces "semantic segmentation" images.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
|
||||
// de Barcelona (UAB).
|
||||
//
|
||||
// This work is licensed under the terms of the MIT license.
|
||||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#include "Carla.h"
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
|
||||
#include "Carla/Actor/ActorDescription.h"
|
||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||
|
||||
void ASensor::Set(const FActorDescription &Description)
|
||||
{
|
||||
// set the tick interval of the sensor
|
||||
if (Description.Variations.Contains("sensor_tick"))
|
||||
{
|
||||
SetActorTickInterval(
|
||||
UActorBlueprintFunctionLibrary::ActorAttributeToFloat(Description.Variations["sensor_tick"],
|
||||
0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void ASensor::EndPlay(EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
Super::EndPlay(EndPlayReason);
|
||||
Stream = FDataStream();
|
||||
}
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
|
||||
#include "Carla/Actor/ActorDescription.h"
|
||||
#include "Carla/Actor/ActorBlueprintFunctionLibrary.h"
|
||||
#include "Carla/Sensor/DataStream.h"
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
|
||||
#include "Sensor.generated.h"
|
||||
|
||||
struct FActorDescription;
|
||||
|
||||
/// Base class for sensors.
|
||||
UCLASS(Abstract, hidecategories = (Collision, Attachment, Actor))
|
||||
class CARLA_API ASensor : public AActor
|
||||
|
@ -22,16 +22,7 @@ class CARLA_API ASensor : public AActor
|
|||
|
||||
public:
|
||||
|
||||
virtual void Set(const FActorDescription &Description)
|
||||
{
|
||||
// set the tick interval of the sensor
|
||||
if (Description.Variations.Contains("sensor_tick"))
|
||||
{
|
||||
SetActorTickInterval(
|
||||
UActorBlueprintFunctionLibrary::ActorAttributeToFloat(Description.Variations["sensor_tick"],
|
||||
0.0f));
|
||||
}
|
||||
}
|
||||
virtual void Set(const FActorDescription &Description);
|
||||
|
||||
/// Replace the FDataStream associated with this sensor.
|
||||
///
|
||||
|
@ -41,12 +32,24 @@ public:
|
|||
Stream = std::move(InStream);
|
||||
}
|
||||
|
||||
/// Return the token that allows subscribing to this sensor's stream.
|
||||
auto GetToken() const
|
||||
{
|
||||
return Stream.GetToken();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void EndPlay(EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
/// Return the FDataStream associated with this sensor.
|
||||
FDataStream &GetDataStream()
|
||||
///
|
||||
/// You need to provide a reference to self, this is necessary for template
|
||||
/// deduction.
|
||||
template <typename SensorT>
|
||||
FAsyncDataStream GetDataStream(const SensorT &Self)
|
||||
{
|
||||
return Stream;
|
||||
return Stream.MakeAsyncDataStream(Self);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Carla.h"
|
||||
#include "Carla/Sensor/SensorFactory.h"
|
||||
|
||||
#include "Carla/Game/CarlaGameInstance.h"
|
||||
#include "Carla/Game/CarlaStatics.h"
|
||||
#include "Carla/Sensor/Sensor.h"
|
||||
|
||||
#include <compiler/disable-ue4-macros.h>
|
||||
|
@ -109,6 +111,14 @@ FActorSpawnResult ASensorFactory::SpawnActor(
|
|||
UE_LOG(LogCarla, Error, TEXT("ASensorFactory: cannot spawn sensor into an empty world."));
|
||||
return {};
|
||||
}
|
||||
|
||||
UCarlaGameInstance *GameInstance = UCarlaStatics::GetGameInstance(World);
|
||||
if (GameInstance == nullptr)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("ASensorFactory: cannot spawn sensor, incompatible game instance."));
|
||||
return {};
|
||||
}
|
||||
|
||||
auto *Sensor = World->SpawnActorDeferred<ASensor>(
|
||||
Description.Class,
|
||||
Transform,
|
||||
|
@ -122,6 +132,7 @@ FActorSpawnResult ASensorFactory::SpawnActor(
|
|||
else
|
||||
{
|
||||
Sensor->Set(Description);
|
||||
Sensor->SetDataStream(GameInstance->GetServer().OpenStream());
|
||||
}
|
||||
UGameplayStatics::FinishSpawningActor(Sensor, Transform);
|
||||
return FActorSpawnResult{Sensor};
|
||||
|
|
|
@ -75,16 +75,21 @@ static carla::Buffer AWorldObserver_Serialize(
|
|||
write_data(header);
|
||||
|
||||
// Write every actor.
|
||||
for (auto &&pair : Registry) {
|
||||
auto &&actor_view = pair.second;
|
||||
check(actor_view.GetActor() != nullptr);
|
||||
for (auto &&View : Registry) {
|
||||
check(View.IsValid());
|
||||
constexpr float TO_METERS = 1e-2;
|
||||
const auto velocity = TO_METERS * actor_view.GetActor()->GetVelocity();
|
||||
const auto velocity = TO_METERS * View.GetActor()->GetVelocity();
|
||||
// get the angular velocity
|
||||
const auto RootComponent = Cast<UPrimitiveComponent>(View.GetActor()->GetRootComponent());
|
||||
FVector angularVelocity { 0.0f, 0.0f, 0.0f };
|
||||
if (RootComponent != nullptr)
|
||||
angularVelocity = RootComponent->GetPhysicsAngularVelocityInDegrees();
|
||||
ActorDynamicState info = {
|
||||
actor_view.GetActorId(),
|
||||
actor_view.GetActor()->GetActorTransform(),
|
||||
View.GetActorId(),
|
||||
View.GetActor()->GetActorTransform(),
|
||||
carla::geom::Vector3D{velocity.X, velocity.Y, velocity.Z},
|
||||
AWorldObserver_GetActorState(actor_view)
|
||||
carla::geom::Vector3D{angularVelocity.X, angularVelocity.Y, angularVelocity.Z},
|
||||
AWorldObserver_GetActorState(View)
|
||||
};
|
||||
write_data(info);
|
||||
}
|
||||
|
@ -107,11 +112,13 @@ void AWorldObserver::Tick(float DeltaSeconds)
|
|||
|
||||
GameTimeStamp += DeltaSeconds;
|
||||
|
||||
auto AsyncStream = Stream.MakeAsyncDataStream(*this);
|
||||
|
||||
auto buffer = AWorldObserver_Serialize(
|
||||
Stream.PopBufferFromPool(),
|
||||
AsyncStream.PopBufferFromPool(),
|
||||
GameTimeStamp,
|
||||
FPlatformTime::Seconds(),
|
||||
Episode->GetActorRegistry());
|
||||
|
||||
Stream.Send_GameThread(*this, std::move(buffer));
|
||||
AsyncStream.Send(*this, std::move(buffer));
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue