This commit is contained in:
LiXiaoqi 2024-10-18 13:19:59 +08:00
commit 220ecf68c6
16357 changed files with 3306405 additions and 0 deletions

View File

@ -0,0 +1,75 @@
// 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/AtomicSharedPtr.h"
#include "carla/NonCopyable.h"
#include <algorithm>
#include <mutex>
#include <vector>
namespace carla {
namespace client {
namespace detail {
/// Holds an atomic pointer to a list.
///
/// @warning Only Load method is atomic, modifications to the list are locked
/// with a mutex.
template <typename T>
class AtomicList : private NonCopyable {
using ListT = std::vector<T>;
public:
AtomicList() : _list(std::make_shared<ListT>()) {}
template <typename ValueT>
void Push(ValueT &&value) {
std::lock_guard<std::mutex> lock(_mutex);
auto new_list = std::make_shared<ListT>(*Load());
new_list->emplace_back(std::forward<ValueT>(value));
_list = new_list;
}
void DeleteByIndex(size_t index) {
std::lock_guard<std::mutex> lock(_mutex);
auto new_list = std::make_shared<ListT>(*Load());
auto begin = new_list->begin();
std::advance(begin, index);
new_list->erase(begin);
_list = new_list;
}
template <typename ValueT>
void DeleteByValue(const ValueT &value) {
std::lock_guard<std::mutex> lock(_mutex);
auto new_list = std::make_shared<ListT>(*Load());
new_list->erase(std::remove(new_list->begin(), new_list->end(), value), new_list->end());
_list = new_list;
}
void Clear() {
std::lock_guard<std::mutex> lock(_mutex);
_list = std::make_shared<ListT>();
}
/// Returns a pointer to the list.
std::shared_ptr<const ListT> Load() const {
return _list.load();
}
private:
std::mutex _mutex;
AtomicSharedPtr<const ListT> _list;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,65 @@
// 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 <memory>
namespace carla {
/// A very simple atomic shared ptr with release-acquire memory order.
template <typename T>
class AtomicSharedPtr {
public:
template <typename... Args>
explicit AtomicSharedPtr(Args &&... args)
: _ptr(std::forward<Args>(args)...) {}
AtomicSharedPtr(const AtomicSharedPtr &rhs)
: _ptr(rhs.load()) {}
AtomicSharedPtr(AtomicSharedPtr &&) = delete;
void store(std::shared_ptr<T> ptr) noexcept {
std::atomic_store_explicit(&_ptr, ptr, std::memory_order_release);
}
void reset(std::shared_ptr<T> ptr = nullptr) noexcept {
store(ptr);
}
std::shared_ptr<T> load() const noexcept {
return std::atomic_load_explicit(&_ptr, std::memory_order_acquire);
}
bool compare_exchange(std::shared_ptr<T> *expected, std::shared_ptr<T> desired) noexcept {
return std::atomic_compare_exchange_strong_explicit(
&_ptr,
expected,
desired,
std::memory_order_acq_rel,
std::memory_order_acq_rel);
}
AtomicSharedPtr &operator=(std::shared_ptr<T> ptr) noexcept {
store(std::move(ptr));
return *this;
}
AtomicSharedPtr &operator=(const AtomicSharedPtr &rhs) noexcept {
store(rhs.load());
return *this;
}
AtomicSharedPtr &operator=(AtomicSharedPtr &&) = delete;
private:
std::shared_ptr<T> _ptr;
};
} // namespace carla

14
include/carla/Buffer.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "carla/Buffer.h"
#include "carla/BufferPool.h"
namespace carla {
void Buffer::ReuseThisBuffer() {
auto pool = _parent_pool.lock();
if (pool != nullptr) {
pool->Push(std::move(*this));
}
}
} // namespace carla

375
include/carla/Buffer.h Normal file
View File

@ -0,0 +1,375 @@
// 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/Debug.h"
#include "carla/Exception.h"
#include "carla/Logging.h"
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <limits>
#include <memory>
#include <type_traits>
#ifdef LIBCARLA_INCLUDED_FROM_UE4
#include <compiler/enable-ue4-macros.h>
#include "Containers/Array.h"
#include <compiler/disable-ue4-macros.h>
#endif // LIBCARLA_INCLUDED_FROM_UE4
namespace carla {
class BufferPool;
class BufferView;
/// A piece of raw data.
///
/// Note that if more capacity is needed, a new memory block is allocated and
/// the old one is deleted. This means that by default the buffer can only
/// grow. To release the memory use `clear` or `pop`.
///
/// This is a move-only type, meant to be cheap to pass by value. If the
/// buffer is retrieved from a BufferPool, the memory is automatically pushed
/// back to the pool on destruction.
///
/// @warning Creating a buffer bigger than max_size() is undefined.
class Buffer {
// =========================================================================
/// @name Member types
// =========================================================================
/// @{
public:
using value_type = unsigned char;
using size_type = uint32_t;
using iterator = value_type *;
using const_iterator = const value_type *;
/// @}
// =========================================================================
/// @name Construction and destruction
// =========================================================================
/// @{
public:
/// Create an empty buffer.
Buffer() = default;
/// Create a buffer with @a size bytes allocated.
explicit Buffer(size_type size)
: _size(size),
_capacity(size),
_data(std::make_unique<value_type[]>(size)) {}
/// @copydoc Buffer(size_type)
explicit Buffer(uint64_t size)
: Buffer([size]() {
if (size > max_size()) {
throw_exception(std::invalid_argument("message size too big"));
}
return static_cast<size_type>(size);
} ()) {}
/// Copy @a source into this buffer. Allocates the necessary memory.
template <typename T>
explicit Buffer(const T &source) {
copy_from(source);
}
explicit Buffer(const value_type *data, size_type size) {
copy_from(data, size);
}
/// @copydoc Buffer(size_type)
explicit Buffer(const value_type *data, uint64_t size)
: Buffer(data, [size]() {
if (size > max_size()) {
throw_exception(std::invalid_argument("message size too big"));
}
return static_cast<size_type>(size);
} ()) {}
Buffer(const Buffer &) = delete;
Buffer(Buffer &&rhs) noexcept
: _parent_pool(std::move(rhs._parent_pool)),
_size(rhs._size),
_capacity(rhs._capacity),
_data(rhs.pop()) {}
~Buffer() {
if (_capacity > 0u) {
ReuseThisBuffer();
}
}
/// @}
// =========================================================================
/// @name Assignment
// =========================================================================
/// @{
public:
Buffer &operator=(const Buffer &) = delete;
Buffer &operator=(Buffer &&rhs) noexcept {
_parent_pool = std::move(rhs._parent_pool);
_size = rhs._size;
_capacity = rhs._capacity;
_data = rhs.pop();
return *this;
}
/// @}
// =========================================================================
/// @name Data access
// =========================================================================
/// @{
public:
/// Access the byte at position @a i.
const value_type &operator[](size_t i) const {
return _data[i];
}
/// Access the byte at position @a i.
value_type &operator[](size_t i) {
return _data[i];
}
/// Direct access to the allocated memory or nullptr if no memory is
/// allocated.
const value_type *data() const noexcept {
return _data.get();
}
/// Direct access to the allocated memory or nullptr if no memory is
/// allocated.
value_type *data() noexcept {
return _data.get();
}
/// Make a boost::asio::buffer from this buffer.
///
/// @warning Boost.Asio buffers do not own the data, it's up to the caller
/// to not delete the memory that this buffer holds until the asio buffer is
/// no longer used.
boost::asio::const_buffer cbuffer() const noexcept {
return {data(), size()};
}
/// @copydoc cbuffer()
boost::asio::const_buffer buffer() const noexcept {
return cbuffer();
}
/// @copydoc cbuffer()
boost::asio::mutable_buffer buffer() noexcept {
return {data(), size()};
}
/// @}
// =========================================================================
/// @name Capacity
// =========================================================================
/// @{
public:
bool empty() const noexcept {
return _size == 0u;
}
size_type size() const noexcept {
return _size;
}
static constexpr size_type max_size() noexcept {
return (std::numeric_limits<size_type>::max)();
}
size_type capacity() const noexcept {
return _capacity;
}
/// @}
// =========================================================================
/// @name Iterators
// =========================================================================
/// @{
public:
const_iterator cbegin() const noexcept {
return _data.get();
}
const_iterator begin() const noexcept {
return cbegin();
}
iterator begin() noexcept {
return _data.get();
}
const_iterator cend() const noexcept {
return cbegin() + size();
}
const_iterator end() const noexcept {
return cend();
}
iterator end() noexcept {
return begin() + size();
}
/// @}
// =========================================================================
/// @name Modifiers
// =========================================================================
/// @{
public:
/// Reset the size of this buffer. If the capacity is not enough, the
/// current memory is discarded and a new block of size @a size is
/// allocated.
void reset(size_type size) {
if (_capacity < size) {
log_debug("allocating buffer of", size, "bytes");
_data = std::make_unique<value_type[]>(size);
_capacity = size;
}
_size = size;
}
/// @copydoc reset(size_type)
void reset(uint64_t size) {
if (size > max_size()) {
throw_exception(std::invalid_argument("message size too big"));
}
reset(static_cast<size_type>(size));
}
/// Resize the buffer, a new block of size @a size is
/// allocated if the capacity is not enough and the data is copied.
void resize(uint64_t size) {
if(_capacity < size) {
std::unique_ptr<value_type[]> data = std::move(_data);
uint64_t old_size = size;
reset(size);
copy_from(data.get(), static_cast<size_type>(old_size));
}
_size = static_cast<size_type>(size);
}
/// Release the contents of this buffer and set its size and capacity to
/// zero.
std::unique_ptr<value_type[]> pop() noexcept {
_size = 0u;
_capacity = 0u;
return std::move(_data);
}
/// Clear the contents of this buffer and set its size and capacity to zero.
/// Deletes allocated memory.
void clear() noexcept {
pop();
}
/// @}
// =========================================================================
/// @name copy_from
// =========================================================================
/// @{
public:
/// Copy @a source into this buffer. Allocates memory if necessary.
template <typename T>
void copy_from(const T &source) {
copy_from(0u, source);
}
/// Copy @a size bytes of the memory pointed by @a data into this buffer.
/// Allocates memory if necessary.
void copy_from(const value_type *data, size_type size) {
copy_from(0u, data, size);
}
/// Copy @a source into this buffer leaving at the front an offset of @a
/// offset bytes uninitialized. Allocates memory if necessary.
void copy_from(size_type offset, const Buffer &rhs) {
copy_from(offset, rhs.buffer());
}
/// @copydoc copy_from(size_type, const Buffer &)
template <typename T>
typename std::enable_if<boost::asio::is_const_buffer_sequence<T>::value>::type
copy_from(size_type offset, const T &source) {
reset(boost::asio::buffer_size(source) + offset);
DEBUG_ASSERT(boost::asio::buffer_size(source) == size() - offset);
DEBUG_ONLY(auto bytes_copied = )
boost::asio::buffer_copy(buffer() + offset, source);
DEBUG_ASSERT(bytes_copied == size() - offset);
}
/// @copydoc copy_from(size_type, const Buffer &)
template <typename T>
typename std::enable_if<!boost::asio::is_const_buffer_sequence<T>::value>::type
copy_from(size_type offset, const T &source) {
copy_from(offset, boost::asio::buffer(source));
}
#ifdef LIBCARLA_INCLUDED_FROM_UE4
/// @copydoc copy_from(size_type, const Buffer &)
template <typename T>
void copy_from(size_type offset, const TArray<T> &source) {
copy_from(
offset,
reinterpret_cast<const value_type *>(source.GetData()),
sizeof(T) * source.Num());
}
#endif // LIBCARLA_INCLUDED_FROM_UE4
/// Copy @a size bytes of the memory pointed by @a data into this buffer,
/// leaving at the front an offset of @a offset bytes uninitialized.
/// Allocates memory if necessary.
void copy_from(size_type offset, const value_type *data, size_type size) {
copy_from(offset, boost::asio::buffer(data, size));
}
/// @}
private:
void ReuseThisBuffer();
friend class BufferPool;
friend class BufferView;
std::weak_ptr<BufferPool> _parent_pool;
size_type _size = 0u;
size_type _capacity = 0u;
std::unique_ptr<value_type[]> _data = nullptr;
};
} // namespace carla

View File

@ -0,0 +1,60 @@
// 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/Buffer.h"
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wold-style-cast"
#endif
#include "moodycamel/ConcurrentQueue.h"
#if defined(__clang__)
# pragma clang diagnostic pop
#endif
#include <memory>
namespace carla {
/// A pool of Buffer. Buffers popped from this pool automatically return to
/// the pool on destruction so the allocated memory can be reused.
///
/// @warning Buffers adjust their size only by growing, they never shrink
/// unless explicitly cleared. The allocated memory is only deleted when this
/// pool is destroyed.
class BufferPool : public std::enable_shared_from_this<BufferPool> {
public:
BufferPool() = default;
explicit BufferPool(size_t estimated_size) : _queue(estimated_size) {}
/// Pop a Buffer from the queue, creates a new one if the queue is empty.
Buffer Pop() {
Buffer item;
_queue.try_dequeue(item); // we don't care if it fails.
#if __cplusplus >= 201703L // C++17
item._parent_pool = weak_from_this();
#else
item._parent_pool = shared_from_this();
#endif
return item;
}
private:
friend class Buffer;
void Push(Buffer &&buffer) {
_queue.enqueue(std::move(buffer));
}
moodycamel::ConcurrentQueue<Buffer> _queue;
};
} // namespace carla

153
include/carla/BufferView.h Normal file
View File

@ -0,0 +1,153 @@
// Copyright (c) 2023 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/Buffer.h"
#include "carla/Debug.h"
#include "carla/Exception.h"
#include "carla/Logging.h"
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <limits>
#include <memory>
#include <type_traits>
#ifdef LIBCARLA_INCLUDED_FROM_UE4
#include <compiler/enable-ue4-macros.h>
#include "Containers/Array.h"
#include <compiler/disable-ue4-macros.h>
#endif // LIBCARLA_INCLUDED_FROM_UE4
namespace carla {
class BufferPool;
/// Creating a constant view from an existing buffer
class BufferView : public std::enable_shared_from_this<BufferView> {
// =========================================================================
/// @name Member types
// =========================================================================
/// @{
public:
using value_type = unsigned char;
using size_type = uint32_t;
using const_iterator = const value_type *;
/// @}
// =========================================================================
/// @name Construction and destruction
// =========================================================================
/// @{
public:
BufferView() = delete;
BufferView(const BufferView &) = delete;
static std::shared_ptr<BufferView> CreateFrom(Buffer &&buffer) {
return std::shared_ptr<BufferView>(new BufferView(std::move(buffer)));
}
private:
BufferView(Buffer &&rhs) noexcept
: _buffer(std::move(rhs)) {}
/// @}
// =========================================================================
/// @name Data access
// =========================================================================
/// @{
public:
/// Access the byte at position @a i.
const value_type &operator[](size_t i) const {
return _buffer.data()[i];
}
/// Direct access to the allocated memory or nullptr if no memory is
/// allocated.
const value_type *data() const noexcept {
return _buffer.data();
}
/// Make a boost::asio::buffer from this buffer.
///
/// @warning Boost.Asio buffers do not own the data, it's up to the caller
/// to not delete the memory that this buffer holds until the asio buffer is
/// no longer used.
boost::asio::const_buffer cbuffer() const noexcept {
return {_buffer.data(), _buffer.size()};
}
/// @copydoc cbuffer()
boost::asio::const_buffer buffer() const noexcept {
return cbuffer();
}
/// @}
// =========================================================================
/// @name Capacity
// =========================================================================
/// @{
public:
bool empty() const noexcept {
return _buffer.size() == 0u;
}
size_type size() const noexcept {
return _buffer.size();
}
static constexpr size_type max_size() noexcept {
return (std::numeric_limits<size_type>::max)();
}
size_type capacity() const noexcept {
return _buffer.capacity();
}
/// @}
// =========================================================================
/// @name Iterators
// =========================================================================
/// @{
public:
const_iterator cbegin() const noexcept {
return _buffer.data();
}
const_iterator begin() const noexcept {
return _buffer.cbegin();
}
const_iterator cend() const noexcept {
return _buffer.cbegin() + _buffer.size();
}
const_iterator end() const noexcept {
return _buffer.cend();
}
private:
const Buffer _buffer;
};
using SharedBufferView = std::shared_ptr<BufferView>;
} // namespace carla

84
include/carla/Debug.h Normal file
View File

@ -0,0 +1,84 @@
// Copyright (c) 2019 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>.
/// Macro utilities for assertions and debug-only code.
///
/// Defines three levels of assertions: debug, development, and release. By
/// default, if NDEBUG is defined the level is set to development, otherwise is
/// set to debug.
///
/// The following macros are defined here:
///
/// * DEBUG_ONLY(code) - Code is evaluated only if assertion level is set to
/// debug.
///
/// * DEVELOPMENT_ONLY(code) - Code is evaluated only if assertion level is
/// set to development or higher.
///
/// * DEBUG_ASSERT(predicate) - Effectively calls assert(predicate).
///
/// * DEVELOPMENT_ASSERT(predicate) - Throws an exception if assertion is
/// set to development or higher, and predicate evaluates to false.
///
/// * RELEASE_ASSERT(predicate) - Throws an exception if predicate evaluates
/// to false.
#pragma once
#include "carla/Exception.h"
#include <stdexcept>
#define LIBCARLA_ASSERT_LEVEL_DEBUG 30
#define LIBCARLA_ASSERT_LEVEL_DEVELOPMENT 20
#define LIBCARLA_ASSERT_LEVEL_RELEASE 10
#ifndef LIBCARLA_ASSERT_LEVEL
# ifdef NDEBUG
# define LIBCARLA_ASSERT_LEVEL LIBCARLA_ASSERT_LEVEL_DEVELOPMENT
# else
# define LIBCARLA_ASSERT_LEVEL LIBCARLA_ASSERT_LEVEL_DEBUG
# endif // NDEBUG
#endif // LIBCARLA_ASSERT_LEVEL
#if (LIBCARLA_ASSERT_LEVEL >= LIBCARLA_ASSERT_LEVEL_DEBUG)
# ifdef NDEBUG
# error Cannot have debug asserts with NDEBUG enabled.
# endif
# include <cassert>
#endif // NDEBUG
#if (LIBCARLA_ASSERT_LEVEL >= LIBCARLA_ASSERT_LEVEL_DEBUG)
# define DEBUG_ONLY(code) code
#else
# define DEBUG_ONLY(code)
#endif
#if (LIBCARLA_ASSERT_LEVEL >= LIBCARLA_ASSERT_LEVEL_DEVELOPMENT)
# define DEVELOPMENT_ONLY(code) code
#else
# define DEVELOPMENT_ONLY(code)
#endif
#define DEBUG_ASSERT(predicate) DEBUG_ONLY(assert(predicate));
#define DEBUG_ERROR DEBUG_ASSERT(false);
#ifdef LIBCARLA_WITH_GTEST
# include <gtest/gtest.h>
# define DEBUG_ASSERT_EQ(lhs, rhs) DEBUG_ONLY(EXPECT_EQ(lhs, rhs));DEBUG_ASSERT(lhs == rhs);
# define DEBUG_ASSERT_NE(lhs, rhs) DEBUG_ONLY(EXPECT_NE(lhs, rhs));DEBUG_ASSERT(lhs != rhs);
#else
# define DEBUG_ASSERT_EQ(lhs, rhs) DEBUG_ASSERT((lhs) == (rhs))
# define DEBUG_ASSERT_NE(lhs, rhs) DEBUG_ASSERT((lhs) != (rhs))
#endif // LIBCARLA_WITH_GTEST
#define LIBCARLA_ASSERT_THROW__(pred, msg) if (!(pred)) { ::carla::throw_exception(std::runtime_error(msg)); }
#define DEVELOPMENT_ASSERT(pred) DEVELOPMENT_ONLY(LIBCARLA_ASSERT_THROW__(pred, #pred))
#define RELEASE_ASSERT(pred) LIBCARLA_ASSERT_THROW__(pred, #pred)

View File

@ -0,0 +1,57 @@
// 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"
#include <boost/assert/source_location.hpp>
// =============================================================================
// -- Define boost::throw_exception --------------------------------------------
// =============================================================================
#ifdef BOOST_NO_EXCEPTIONS
namespace boost {
void throw_exception(const std::exception &e) {
carla::throw_exception(e);
}
void throw_exception(
const std::exception &e,
boost::source_location const & loc) {
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

43
include/carla/Exception.h Normal file
View File

@ -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

View File

@ -0,0 +1,54 @@
// 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/FileSystem.h"
#include "carla/Exception.h"
#include "carla/StringUtil.h"
#include <boost/filesystem/operations.hpp>
namespace carla {
namespace fs = boost::filesystem;
void FileSystem::ValidateFilePath(std::string &filepath, const std::string &ext) {
fs::path path(filepath);
if (path.extension().empty() && !ext.empty()) {
if (ext[0] != '.') {
path += '.';
}
path += ext;
}
auto parent = path.parent_path();
if (!parent.empty()) {
fs::create_directories(parent);
}
filepath = path.string();
}
std::vector<std::string> FileSystem::ListFolder(
const std::string &folder_path,
const std::string &wildcard_pattern) {
fs::path root(folder_path);
if (!fs::exists(root) || !fs::is_directory(root)) {
throw_exception(std::invalid_argument(folder_path + ": no such folder"));
}
std::vector<std::string> results;
fs::directory_iterator end;
for (fs::directory_iterator it(root); it != end; ++it) {
if (fs::is_regular_file(*it)) {
const std::string filename = it->path().filename().string();
if (StringUtil::Match(filename, wildcard_pattern)) {
results.emplace_back(filename);
}
}
}
return results;
}
} // namespace carla

View File

@ -0,0 +1,40 @@
// 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 <string>
#include <vector>
namespace carla {
/// Static functions for accessing the file system.
///
/// @warning Using this file requires linking against boost_filesystem.
class FileSystem {
public:
/// Convenient function to validate a path before creating a file.
///
/// 1) Ensures all the parent directories are created if missing.
/// 2) If @a filepath is missing the extension, @a default_extension is
/// appended to the path.
static void ValidateFilePath(
std::string &filepath,
const std::string &default_extension = "");
/// List (not recursively) regular files at @a folder_path matching
/// @a wildcard_pattern.
///
/// @throw std::invalid_argument if folder does not exist.
///
/// @todo Do permission check.
static std::vector<std::string> ListFolder(
const std::string &folder_path,
const std::string &wildcard_pattern);
};
} // namespace carla

View File

@ -0,0 +1,77 @@
// 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 <utility>
namespace carla {
class Functional {
public:
/// Creates a recursive callable object, where the itself is passed as first
/// argument to @a func. Use case: create recursive lambda.
template <typename FuncT>
static auto MakeRecursive(FuncT &&func) {
return Recursive<FuncT>(std::forward<FuncT>(func));
}
/// Creates an "overloaded callable object" out of one or more callable
/// objects, each callable object will contribute with an overload of
/// operator(). Use case: combine several lambdas into a single lambda.
template <typename... FuncTs>
static auto MakeOverload(FuncTs &&... fs) {
return Overload<FuncTs...>(std::forward<FuncTs>(fs)...);
}
/// @see MakeRecursive and MakeOverload.
template <typename... FuncTs>
static auto MakeRecursiveOverload(FuncTs &&... fs) {
return MakeRecursive(MakeOverload(std::forward<FuncTs>(fs)...));
}
private:
template <typename... Ts>
struct Overload;
template <typename T, typename... Ts>
struct Overload<T, Ts...> : T, Overload<Ts...> {
Overload(T &&func, Ts &&... rest)
: T(std::forward<T>(func)),
Overload<Ts...>(std::forward<Ts>(rest)...) {}
using T::operator();
using Overload<Ts...>::operator();
};
template <typename T>
struct Overload<T> : T {
Overload(T &&func) : T(std::forward<T>(func)) {}
using T::operator();
};
template<typename T>
struct Recursive {
explicit Recursive(T &&func) : _func(std::forward<T>(func)) {}
template<typename... Ts>
auto operator()(Ts &&... arguments) const {
return _func(*this, std::forward<Ts>(arguments)...);
}
private:
T _func;
};
};
} // namespace carla

51
include/carla/Iterator.h Normal file
View File

@ -0,0 +1,51 @@
// 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/iterator/transform_iterator.hpp>
namespace carla {
namespace iterator {
/// Creates an iterator over non-const references to the keys of a map.
template <typename It>
inline static auto make_map_keys_iterator(It it) {
using first_value_type = typename It::value_type::first_type;
using decay_first_value_type = typename std::remove_cv_t<typename std::remove_reference_t<first_value_type>>;
using ref_to_first = decay_first_value_type &;
return boost::make_transform_iterator(it, [](auto &pair) -> ref_to_first { return pair.first; });
}
/// Creates an iterator over const references to the keys of a map.
template <typename It>
inline static auto make_map_keys_const_iterator(It it) {
using first_value_type = typename It::value_type::first_type;
using decay_first_value_type = typename std::remove_cv_t<typename std::remove_reference_t<first_value_type>>;
using const_ref_to_first = const decay_first_value_type &;
return boost::make_transform_iterator(it, [](const auto &pair) -> const_ref_to_first { return pair.first; });
}
/// Creates an iterator over non-const references to the values of a map.
template <typename It>
inline static auto make_map_values_iterator(It it) {
using second_value_type = typename It::value_type::second_type;
using decay_second_value_type = typename std::remove_cv_t<typename std::remove_reference_t<second_value_type>>;
using ref_to_second = decay_second_value_type &;
return boost::make_transform_iterator(it, [](auto &pair) -> ref_to_second { return pair.second; });
}
/// Creates an iterator over const references to the values of a map.
template <typename It>
inline static auto make_map_values_const_iterator(It it) {
using second_value_type = typename It::value_type::second_type;
using decay_second_value_type = typename std::remove_cv_t<typename std::remove_reference_t<second_value_type>>;
using const_ref_to_second = const decay_second_value_type &;
return boost::make_transform_iterator(it, [](const auto &pair) -> const_ref_to_second { return pair.second; });
}
} // namespace iterator
} // namespace carla

87
include/carla/ListView.h Normal file
View File

@ -0,0 +1,87 @@
// 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/Debug.h"
#include <type_traits>
#include <iterator>
namespace carla {
/// A view over a range of elements in a container. Basically a pair of begin
/// and end iterators.
template<typename IT>
class ListView {
public:
using iterator = IT;
using const_iterator = typename std::add_const<IT>::type;
using size_type = size_t;
using difference_type = typename std::iterator_traits<iterator>::difference_type;
using value_type = typename std::iterator_traits<iterator>::value_type;
using pointer = typename std::iterator_traits<iterator>::pointer;
using reference = typename std::iterator_traits<iterator>::reference;
explicit ListView(iterator begin, iterator end)
: _begin(begin), _end(end) {
DEBUG_ASSERT(std::distance(_begin, _end) >= 0);
}
ListView(const ListView &) = default;
ListView &operator=(const ListView &) = delete;
iterator begin() {
return _begin;
}
const_iterator begin() const {
return _begin;
}
const_iterator cbegin() const {
return _begin;
}
iterator end() {
return _end;
}
const_iterator end() const {
return _end;
}
const_iterator cend() const {
return _end;
}
bool empty() const {
return _begin == _end;
}
size_type size() const {
return static_cast<size_t>(std::distance(begin(), end()));
}
private:
const iterator _begin;
const iterator _end;
};
template <typename Iterator>
static inline auto MakeListView(Iterator begin, Iterator end) {
return ListView<Iterator>(begin, end);
}
template <typename Container>
static inline auto MakeListView(Container &c) {
return MakeListView(std::begin(c), std::end(c));
}
} // namespace carla

151
include/carla/Logging.h Normal file
View File

@ -0,0 +1,151 @@
// 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/Platform.h"
#define LIBCARLA_LOG_LEVEL_DEBUG 10
#define LIBCARLA_LOG_LEVEL_INFO 20
#define LIBCARLA_LOG_LEVEL_WARNING 30
#define LIBCARLA_LOG_LEVEL_ERROR 40
#define LIBCARLA_LOG_LEVEL_CRITICAL 50
#define LIBCARLA_LOG_LEVEL_NONE 100
#ifndef LIBCARLA_LOG_LEVEL
# ifdef NDEBUG
# define LIBCARLA_LOG_LEVEL LIBCARLA_LOG_LEVEL_WARNING
# else
# define LIBCARLA_LOG_LEVEL LIBCARLA_LOG_LEVEL_INFO
# endif // NDEBUG
#endif // LIBCARLA_LOG_LEVEL
// The following log functions are available, they are only active if
// LIBCARLA_LOG_LEVEL is greater equal the function's log level.
//
// * log_debug
// * log_info
// * log_error
// * log_critical
//
// And macros
//
// * LOG_DEBUG_ONLY(/* code here */)
// * LOG_INFO_ONLY(/* code here */)
// =============================================================================
// -- Implementation of log functions ------------------------------------------
// =============================================================================
#include <iostream>
namespace carla {
namespace logging {
// https://stackoverflow.com/a/27375675
template <typename Arg, typename ... Args>
LIBCARLA_NOINLINE
static void write_to_stream(std::ostream &out, Arg &&arg, Args && ... args) {
out << std::boolalpha << std::forward<Arg>(arg);
using expander = int[];
(void) expander{0, (void(out << ' ' << std::forward<Args>(args)), 0) ...};
}
template <typename ... Args>
static inline void log(Args && ... args) {
logging::write_to_stream(std::cout, std::forward<Args>(args) ..., '\n');
}
} // namespace logging
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_DEBUG
template <typename ... Args>
static inline void log_debug(Args && ... args) {
logging::write_to_stream(std::cout, "DEBUG:", std::forward<Args>(args) ..., '\n');
}
#else
template <typename ... Args>
static inline void log_debug(Args && ...) {}
#endif
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_INFO
template <typename ... Args>
static inline void log_info(Args && ... args) {
logging::write_to_stream(std::cout, "INFO: ", std::forward<Args>(args) ..., '\n');
}
#else
template <typename ... Args>
static inline void log_info(Args && ...) {}
#endif
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_WARNING
template <typename ... Args>
static inline void log_warning(Args && ... args) {
logging::write_to_stream(std::cerr, "WARNING:", std::forward<Args>(args) ..., '\n');
}
#else
template <typename ... Args>
static inline void log_warning(Args && ...) {}
#endif
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_ERROR
template <typename ... Args>
static inline void log_error(Args && ... args) {
logging::write_to_stream(std::cerr, "ERROR:", std::forward<Args>(args) ..., '\n');
}
#else
template <typename ... Args>
static inline void log_error(Args && ...) {}
#endif
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_CRITICAL
template <typename ... Args>
static inline void log_critical(Args && ... args) {
logging::write_to_stream(std::cerr, "CRITICAL:", std::forward<Args>(args) ..., '\n');
}
#else
template <typename ... Args>
static inline void log_critical(Args && ...) {}
#endif
} // namespace carla
// =============================================================================
// -- Implementation of macros -------------------------------------------------
// =============================================================================
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_DEBUG
# define LOG_DEBUG_ONLY(code) code
#else
# define LOG_DEBUG_ONLY(code)
#endif
#if LIBCARLA_LOG_LEVEL <= LIBCARLA_LOG_LEVEL_INFO
# define LOG_INFO_ONLY(code) code
#else
# define LOG_INFO_ONLY(code)
#endif

33
include/carla/Memory.h Normal file
View File

@ -0,0 +1,33 @@
// Copyright (c) 2019 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/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
namespace carla {
/// Use this SharedPtr (boost::shared_ptr) to keep compatibility with
/// boost::python, but it would be nice if in the future we can make a Python
/// adaptor for std::shared_ptr.
template <typename T>
using SharedPtr = boost::shared_ptr<T>;
template <typename T>
using WeakPtr = boost::weak_ptr<T>;
template <typename T>
using EnableSharedFromThis = boost::enable_shared_from_this<T>;
template <typename T, typename... Args>
static inline auto MakeShared(Args &&... args) {
return boost::make_shared<T>(std::forward<Args>(args)...);
}
} // namespace carla

View File

@ -0,0 +1,38 @@
// Copyright (c) 2019 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 <type_traits>
#include <utility>
namespace carla {
namespace detail {
template <typename FunctorT>
struct MoveWrapper : FunctorT {
MoveWrapper(FunctorT &&f) : FunctorT(std::move(f)) {}
MoveWrapper(MoveWrapper &&) = default;
MoveWrapper& operator=(MoveWrapper &&) = default;
MoveWrapper(const MoveWrapper &);
MoveWrapper& operator=(const MoveWrapper &);
};
} // namespace detail
/// Hack to trick asio into accepting move-only handlers, if the handler were
/// actually copied it would result in a link error.
///
/// @see https://stackoverflow.com/a/22891509.
template <typename FunctorT>
auto MoveHandler(FunctorT &&func) {
using F = typename std::decay<FunctorT>::type;
return detail::MoveWrapper<F>{std::move(func)};
}
} // namespace carla

39
include/carla/MsgPack.h Normal file
View File

@ -0,0 +1,39 @@
// 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/Buffer.h"
#include <rpc/msgpack.hpp>
namespace carla {
class MsgPack {
public:
template <typename T>
static Buffer Pack(const T &obj) {
namespace mp = ::clmdep_msgpack;
mp::sbuffer sbuf;
mp::pack(sbuf, obj);
return Buffer(reinterpret_cast<const unsigned char *>(sbuf.data()), sbuf.size());
}
template <typename T>
static T UnPack(const Buffer &buffer) {
namespace mp = ::clmdep_msgpack;
return mp::unpack(reinterpret_cast<const char *>(buffer.data()), buffer.size()).template as<T>();
}
template <typename T>
static T UnPack(const unsigned char *data, size_t size) {
namespace mp = ::clmdep_msgpack;
return mp::unpack(reinterpret_cast<const char *>(data), size).template as<T>();
}
};
} // namespace carla

View File

@ -0,0 +1,171 @@
// 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>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4583)
#pragma warning(disable:4582)
#include <boost/variant2/variant.hpp>
#pragma warning(pop)
#else
#include <boost/variant2/variant.hpp>
#endif
#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::variant2::variant ----------------------------------
// ===========================================================================
template<typename... Ts>
struct convert<boost::variant2::variant<Ts...>> {
const clmdep_msgpack::object &operator()(
const clmdep_msgpack::object &o,
boost::variant2::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<uint64_t>();
copy_to_variant(index, o, v, std::make_index_sequence<sizeof...(Ts)>());
return o;
}
private:
template <uint64_t I>
static void copy_to_variant_impl(
const clmdep_msgpack::object &o,
boost::variant2::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 <uint64_t... Is>
static void copy_to_variant(
const uint64_t index,
const clmdep_msgpack::object &o,
boost::variant2::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::variant2::variant<Ts...>> {
template <typename Stream>
packer<Stream> &operator()(
clmdep_msgpack::packer<Stream> &o,
const boost::variant2::variant<Ts...> &v) const {
o.pack_array(2);
o.pack(static_cast<uint64_t>(v.index()));
boost::variant2::visit([&](const auto &value) { o.pack(value); }, v);
return o;
}
};
template<typename... Ts>
struct object_with_zone<boost::variant2::variant<Ts...>> {
void operator()(
clmdep_msgpack::object::with_zone &o,
const boost::variant2::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<uint64_t>(v.index()), o.zone);
boost::variant2::visit([&](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

View File

@ -0,0 +1,37 @@
// 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
namespace carla {
/// Inherit (privately) to suppress copy/move construction and assignment.
class NonCopyable {
public:
NonCopyable() = default;
NonCopyable(const NonCopyable &) = delete;
NonCopyable &operator=(const NonCopyable &) = delete;
NonCopyable(NonCopyable &&) = delete;
NonCopyable &operator=(NonCopyable &&) = delete;
};
/// Inherit (privately) to suppress copy construction and assignment.
class MovableNonCopyable {
public:
MovableNonCopyable() = default;
MovableNonCopyable(const MovableNonCopyable &) = delete;
MovableNonCopyable &operator=(const MovableNonCopyable &) = delete;
MovableNonCopyable(MovableNonCopyable &&) = default;
MovableNonCopyable &operator=(MovableNonCopyable &&) = default;
};
} // namespace carla

22
include/carla/Platform.h Normal file
View File

@ -0,0 +1,22 @@
// 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
#if defined(_MSC_VER)
# define LIBCARLA_FORCEINLINE __forceinline
# define LIBCARLA_NOINLINE __declspec(noinline)
#elif defined(__clang__) || defined(__GNUC__)
# if defined(NDEBUG)
# define LIBCARLA_FORCEINLINE inline __attribute__((always_inline))
# else
# define LIBCARLA_FORCEINLINE inline
# endif // NDEBUG
# define LIBCARLA_NOINLINE __attribute__((noinline))
#else
# warning Compiler not supported.
# define LIBCARLA_NOINLINE
#endif

116
include/carla/PythonUtil.h Normal file
View File

@ -0,0 +1,116 @@
// 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/NonCopyable.h"
#ifdef LIBCARLA_WITH_PYTHON_SUPPORT
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-register"
# endif
# include <boost/python.hpp>
# if defined(__clang__)
# pragma clang diagnostic pop
# endif
#endif // LIBCARLA_WITH_PYTHON_SUPPORT
namespace carla {
class PythonUtil {
public:
static bool ThisThreadHasTheGIL() {
#ifdef LIBCARLA_WITH_PYTHON_SUPPORT
# if PY_MAJOR_VERSION >= 3
return PyGILState_Check();
# else
PyThreadState *tstate = _PyThreadState_Current;
return (tstate != nullptr) && (tstate == PyGILState_GetThisThreadState());
# endif // PYTHON3
#else
return false;
#endif // LIBCARLA_WITH_PYTHON_SUPPORT
}
#ifdef LIBCARLA_WITH_PYTHON_SUPPORT
/// Acquires a lock on the Python's Global Interpreter Lock, necessary for
/// calling Python code from a different thread.
class AcquireGIL : private NonCopyable {
public:
AcquireGIL() : _state(PyGILState_Ensure()) {}
~AcquireGIL() {
PyGILState_Release(_state);
}
private:
PyGILState_STATE _state;
};
/// Releases the lock on the Python's Global Interpreter Lock, use it when doing
/// blocking I/O operations.
class ReleaseGIL : private NonCopyable {
public:
ReleaseGIL() : _state(PyEval_SaveThread()) {}
~ReleaseGIL() {
PyEval_RestoreThread(_state);
}
private:
PyThreadState *_state;
};
#else // LIBCARLA_WITH_PYTHON_SUPPORT
class AcquireGIL : private NonCopyable {};
class ReleaseGIL : private NonCopyable {};
#endif // LIBCARLA_WITH_PYTHON_SUPPORT
/// A deleter that can be passed to a smart pointer to acquire the GIL
/// before destroying the object.
class AcquireGILDeleter {
public:
template <typename T>
void operator()(T *ptr) const {
#ifdef LIBCARLA_WITH_PYTHON_SUPPORT
if (ptr != nullptr && !PythonUtil::ThisThreadHasTheGIL()) {
AcquireGIL lock;
delete ptr;
} else
#endif // LIBCARLA_WITH_PYTHON_SUPPORT
delete ptr;
}
};
/// A deleter that can be passed to a smart pointer to release the GIL
/// before destroying the object.
class ReleaseGILDeleter {
public:
template <typename T>
void operator()(T *ptr) const {
#ifdef LIBCARLA_WITH_PYTHON_SUPPORT
if (ptr != nullptr && PythonUtil::ThisThreadHasTheGIL()) {
ReleaseGIL lock;
delete ptr;
} else
#endif // LIBCARLA_WITH_PYTHON_SUPPORT
delete ptr;
}
};
};
} // namespace carla

View File

@ -0,0 +1,143 @@
// 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/Time.h"
#include <boost/optional.hpp>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4583)
#pragma warning(disable:4582)
#include <boost/variant2/variant.hpp>
#pragma warning(pop)
#else
#include <boost/variant2/variant.hpp>
#endif
#include <condition_variable>
#include <exception>
#include <map>
#include <mutex>
namespace carla {
namespace detail {
class SharedException;
} // namespace detail
// ===========================================================================
// -- RecurrentSharedFuture --------------------------------------------------
// ===========================================================================
/// This class is meant to be used similar to a shared future, but the value
/// can be set any number of times.
template <typename T>
class RecurrentSharedFuture {
public:
using SharedException = detail::SharedException;
/// Wait until the next value is set. Any number of threads can be waiting
/// simultaneously.
///
/// @return empty optional if the timeout is met.
boost::optional<T> WaitFor(time_duration timeout);
/// Set the value and notify all waiting threads.
template <typename T2>
void SetValue(const T2 &value);
/// Set a exception, this exception will be thrown on all the threads
/// waiting.
///
/// @note The @a exception will be stored on a SharedException and thrown
/// as such.
template <typename ExceptionT>
void SetException(ExceptionT &&exception);
private:
std::mutex _mutex;
std::condition_variable _cv;
struct mapped_type {
bool should_wait;
boost::variant2::variant<SharedException, T> value;
};
std::map<const char *, mapped_type> _map;
};
// ===========================================================================
// -- RecurrentSharedFuture implementation -----------------------------------
// ===========================================================================
namespace detail {
static thread_local const char thread_tag{};
class SharedException : public std::exception {
public:
SharedException()
: _exception(std::make_shared<std::runtime_error>("uninitialized SharedException")) {}
SharedException(std::shared_ptr<std::exception> e)
: _exception(std::move(e)) {}
const char *what() const noexcept override {
return _exception->what();
}
std::shared_ptr<std::exception> GetException() const {
return _exception;
}
private:
std::shared_ptr<std::exception> _exception;
};
} // namespace detail
template <typename T>
boost::optional<T> RecurrentSharedFuture<T>::WaitFor(time_duration timeout) {
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; })) {
return {};
}
if (r.value.index() == 0) {
throw_exception(boost::variant2::get<SharedException>(r.value));
}
return boost::variant2::get<T>(std::move(r.value));
}
template <typename T>
template <typename T2>
void RecurrentSharedFuture<T>::SetValue(const T2 &value) {
std::lock_guard<std::mutex> lock(_mutex);
for (auto &pair : _map) {
pair.second.should_wait = false;
pair.second.value = value;
}
_cv.notify_all();
}
template <typename T>
template <typename ExceptionT>
void RecurrentSharedFuture<T>::SetException(ExceptionT &&e) {
SetValue(SharedException(std::make_shared<ExceptionT>(std::forward<ExceptionT>(e))));
}
} // namespace carla

19
include/carla/Sockets.h Normal file
View File

@ -0,0 +1,19 @@
// Copyright (c) 2020 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
#if _WIN32
#include <winsock2.h> ///< socket
#include <Ws2tcpip.h>
#else
#include <sys/socket.h> ///< socket
#include <netinet/in.h> ///< sockaddr_in
#include <arpa/inet.h> ///< getsockname
#include <unistd.h> ///< close
#endif
#define SOCK_INVALID_INDEX -1

60
include/carla/StopWatch.h Normal file
View File

@ -0,0 +1,60 @@
// 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 <chrono>
#include <cstdint>
namespace carla {
namespace detail {
template <typename CLOCK>
class StopWatchTmpl {
static_assert(CLOCK::is_steady, "The StopWatch's clock must be steady");
public:
using clock = CLOCK;
StopWatchTmpl() : _start(clock::now()), _end(), _is_running(true) {}
void Restart() {
_is_running = true;
_start = clock::now();
}
void Stop() {
_end = clock::now();
_is_running = false;
}
typename clock::duration GetDuration() const {
return _is_running ? clock::now() - _start : _end - _start;
}
template <class RESOLUTION=std::chrono::milliseconds>
size_t GetElapsedTime() const {
return static_cast<size_t>(std::chrono::duration_cast<RESOLUTION>(GetDuration()).count());
}
bool IsRunning() const {
return _is_running;
}
private:
typename clock::time_point _start;
typename clock::time_point _end;
bool _is_running;
};
} // namespace detail
using StopWatch = detail::StopWatchTmpl<std::chrono::steady_clock>;
} // namespace carla

View File

@ -0,0 +1,25 @@
// 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/StringUtil.h"
#ifdef _WIN32
# include <shlwapi.h>
#else
# include <fnmatch.h>
#endif // _WIN32
namespace carla {
bool StringUtil::Match(const char *str, const char *test) {
#ifdef _WIN32
return PathMatchSpecA(str, test);
#else
return 0 == fnmatch(test, str, 0);
#endif // _WIN32
}
} // namespace carla

View File

@ -0,0 +1,80 @@
// 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/algorithm/string.hpp>
namespace carla {
class StringUtil {
public:
static const char *ToConstCharPtr(const char *str) {
return str;
}
template <typename StringT>
static const char *ToConstCharPtr(const StringT &str) {
return str.c_str();
}
template <typename Range1T, typename Range2T>
static bool StartsWith(const Range1T &input, const Range2T &test) {
return boost::algorithm::istarts_with(input, test);
}
template <typename Range1T, typename Range2T>
static bool EndsWith(const Range1T &input, const Range2T &test) {
return boost::algorithm::iends_with(input, test);
}
template <typename WritableRangeT>
static void ToLower(WritableRangeT &str) {
boost::algorithm::to_lower(str);
}
template <typename SequenceT>
static auto ToLowerCopy(const SequenceT &str) {
return boost::algorithm::to_lower_copy(str);
}
template <typename WritableRangeT>
static void ToUpper(WritableRangeT &str) {
boost::algorithm::to_upper(str);
}
template <typename SequenceT>
static auto ToUpperCopy(const SequenceT &str) {
return boost::algorithm::to_upper_copy(str);
}
template <typename WritableRangeT>
static void Trim(WritableRangeT &str) {
boost::algorithm::trim(str);
}
template <typename SequenceT>
static auto TrimCopy(const SequenceT &str) {
return boost::algorithm::trim_copy(str);
}
template<typename Container, typename Range1T, typename Range2T>
static void Split(Container &destination, const Range1T &str, const Range2T &separators) {
boost::split(destination, str, boost::is_any_of(separators));
}
/// Match @a str with the Unix shell-style @a wildcard_pattern.
static bool Match(const char *str, const char *wildcard_pattern);
/// Match @a str with the Unix shell-style @a wildcard_pattern.
template <typename String1T, typename String2T>
static bool Match(const String1T &str, const String2T &wildcard_pattern) {
return Match(ToConstCharPtr(str), ToConstCharPtr(wildcard_pattern));
}
};
} // namespace carla

View File

@ -0,0 +1,54 @@
// 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/Debug.h"
#include "carla/NonCopyable.h"
#include <thread>
#include <vector>
namespace carla {
class ThreadGroup : private NonCopyable {
public:
ThreadGroup() = default;
~ThreadGroup() {
JoinAll();
}
template <typename F>
void CreateThread(F &&functor) {
_threads.emplace_back(std::forward<F>(functor));
}
template <typename F>
void CreateThreads(size_t count, F functor) {
_threads.reserve(_threads.size() + count);
for (size_t i = 0u; i < count; ++i) {
CreateThread(functor);
}
}
void JoinAll() {
for (auto &thread : _threads) {
DEBUG_ASSERT_NE(thread.get_id(), std::this_thread::get_id());
if (thread.joinable()) {
thread.join();
}
}
_threads.clear();
}
private:
std::vector<std::thread> _threads;
};
} // namespace carla

View File

@ -0,0 +1,90 @@
// Copyright (c) 2019 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/MoveHandler.h"
#include "carla/NonCopyable.h"
#include "carla/ThreadGroup.h"
#include "carla/Time.h"
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <future>
#include <thread>
#include <type_traits>
namespace carla {
/// A thread pool based on Boost.Asio's io context.
class ThreadPool : private NonCopyable {
public:
ThreadPool() : _work_to_do(_io_context) {}
/// Stops the ThreadPool and joins all its threads.
~ThreadPool() {
Stop();
}
/// Return the underlying io_context.
auto &io_context() {
return _io_context;
}
/// Post a task to the pool.
template <typename FunctorT, typename ResultT = typename std::result_of<FunctorT()>::type>
std::future<ResultT> Post(FunctorT &&functor) {
auto task = std::packaged_task<ResultT()>(std::forward<FunctorT>(functor));
auto future = task.get_future();
boost::asio::post(_io_context, carla::MoveHandler(task));
return future;
}
/// Launch threads to run tasks asynchronously. Launch specific number of
/// threads if @a worker_threads is provided, otherwise use all available
/// hardware concurrency.
void AsyncRun(size_t worker_threads) {
_workers.CreateThreads(worker_threads, [this]() { Run(); });
}
/// @copydoc AsyncRun(size_t)
void AsyncRun() {
AsyncRun(std::thread::hardware_concurrency());
}
/// Run tasks in this thread.
///
/// @warning This function blocks until the ThreadPool has been stopped.
void Run() {
_io_context.run();
}
/// Run tasks in this thread for an specific @a duration.
///
/// @warning This function blocks until the ThreadPool has been stopped, or
/// until the specified time duration has elapsed.
void RunFor(time_duration duration) {
_io_context.run_for(duration.to_chrono());
}
/// Stop the ThreadPool and join all its threads.
void Stop() {
_io_context.stop();
_workers.JoinAll();
}
private:
boost::asio::io_context _io_context;
boost::asio::io_context::work _work_to_do;
ThreadGroup _workers;
};
} // namespace carla

67
include/carla/Time.h Normal file
View File

@ -0,0 +1,67 @@
// 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/Debug.h"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <chrono>
namespace carla {
/// Positive time duration up to milliseconds resolution. Automatically casts
/// between std::chrono::duration and boost::posix_time::time_duration.
class time_duration {
public:
static inline time_duration seconds(size_t timeout) {
return std::chrono::seconds(timeout);
}
static inline time_duration milliseconds(size_t timeout) {
return std::chrono::milliseconds(timeout);
}
constexpr time_duration() noexcept : _milliseconds(0u) {}
template <typename Rep, typename Period>
time_duration(std::chrono::duration<Rep, Period> duration)
: _milliseconds([=]() {
const auto count = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
DEBUG_ASSERT(count >= 0);
return static_cast<size_t>(count);
}()) {}
time_duration(boost::posix_time::time_duration timeout)
: time_duration(std::chrono::milliseconds(timeout.total_milliseconds())) {}
time_duration(const time_duration &) = default;
time_duration &operator=(const time_duration &) = default;
boost::posix_time::time_duration to_posix_time() const {
return boost::posix_time::milliseconds(_milliseconds);
}
constexpr auto to_chrono() const {
return std::chrono::milliseconds(_milliseconds);
}
operator boost::posix_time::time_duration() const {
return to_posix_time();
}
constexpr size_t milliseconds() const noexcept {
return _milliseconds;
}
private:
size_t _milliseconds;
};
} // namespace carla

View File

@ -0,0 +1,26 @@
// 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 <type_traits>
namespace carla {
template <typename... Ts>
struct are_same;
template <typename T0, typename T1, typename... Ts>
struct are_same<T0, T1, Ts...> {
static constexpr bool value = std::is_same<T0, T1>::value && are_same<T0, Ts...>::value;
};
template <typename T0, typename T1>
struct are_same<T0, T1> {
static constexpr bool value = std::is_same<T0, T1>::value;
};
} // namespace carla

15
include/carla/Version.h Normal file
View File

@ -0,0 +1,15 @@
// 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
namespace carla {
constexpr const char *version() {
return "0.9.15";
}
} // namespace carla

View File

@ -0,0 +1,117 @@
// 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/client/Actor.h"
#include "carla/Logging.h"
#include "carla/client/detail/Simulator.h"
namespace carla {
namespace client {
geom::Location Actor::GetLocation() const {
return GetEpisode().Lock()->GetActorLocation(*this);
}
geom::Transform Actor::GetTransform() const {
return GetEpisode().Lock()->GetActorTransform(*this);
}
geom::Vector3D Actor::GetVelocity() const {
return GetEpisode().Lock()->GetActorVelocity(*this);
}
geom::Vector3D Actor::GetAngularVelocity() const {
return GetEpisode().Lock()->GetActorAngularVelocity(*this);
}
geom::Vector3D Actor::GetAcceleration() const {
return GetEpisode().Lock()->GetActorAcceleration(*this);
}
void Actor::SetLocation(const geom::Location &location) {
GetEpisode().Lock()->SetActorLocation(*this, location);
}
void Actor::SetTransform(const geom::Transform &transform) {
GetEpisode().Lock()->SetActorTransform(*this, transform);
}
void Actor::SetTargetVelocity(const geom::Vector3D &vector) {
GetEpisode().Lock()->SetActorTargetVelocity(*this, vector);
}
void Actor::SetTargetAngularVelocity(const geom::Vector3D &vector) {
GetEpisode().Lock()->SetActorTargetAngularVelocity(*this, vector);
}
void Actor::EnableConstantVelocity(const geom::Vector3D &vector) {
GetEpisode().Lock()->EnableActorConstantVelocity(*this, vector);
}
void Actor::DisableConstantVelocity() {
GetEpisode().Lock()->DisableActorConstantVelocity(*this);
}
void Actor::AddImpulse(const geom::Vector3D &impulse) {
GetEpisode().Lock()->AddActorImpulse(*this, impulse);
}
void Actor::AddImpulse(const geom::Vector3D &impulse, const geom::Vector3D &location) {
GetEpisode().Lock()->AddActorImpulse(*this, impulse, location);
}
void Actor::AddForce(const geom::Vector3D &force) {
GetEpisode().Lock()->AddActorForce(*this, force);
}
void Actor::AddForce(const geom::Vector3D &force, const geom::Vector3D &location) {
GetEpisode().Lock()->AddActorForce(*this, force, location);
}
void Actor::AddAngularImpulse(const geom::Vector3D &vector) {
GetEpisode().Lock()->AddActorAngularImpulse(*this, vector);
}
void Actor::AddTorque(const geom::Vector3D &torque) {
GetEpisode().Lock()->AddActorTorque(*this, torque);
}
void Actor::SetSimulatePhysics(const bool enabled) {
GetEpisode().Lock()->SetActorSimulatePhysics(*this, enabled);
}
void Actor::SetCollisions(const bool enabled) {
GetEpisode().Lock()->SetActorCollisions(*this, enabled);
}
void Actor::SetActorDead() {
GetEpisode().Lock()->SetActorDead(*this);
}
void Actor::SetEnableGravity(const bool enabled) {
GetEpisode().Lock()->SetActorEnableGravity(*this, enabled);
}
rpc::ActorState Actor::GetActorState() const {
return GetEpisode().Lock()->GetActorState(*this);
}
bool Actor::Destroy() {
rpc::ActorState actor_state = GetActorState();
bool result = false;
if (actor_state != rpc::ActorState::Invalid) {
result = GetEpisode().Lock()->DestroyActor(*this);
} else {
log_warning(
"attempting to destroy an actor that is already dead:",
GetDisplayId());
}
return result;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,141 @@
// 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/Debug.h"
#include "carla/Memory.h"
#include "carla/client/detail/ActorState.h"
#include "carla/profiler/LifetimeProfiled.h"
namespace carla {
namespace client {
/// Represents an actor in the simulation.
class Actor
: public EnableSharedFromThis<Actor>,
private profiler::LifetimeProfiled,
public detail::ActorState {
using Super = detail::ActorState;
public:
explicit Actor(ActorInitializer init)
: LIBCARLA_INITIALIZE_LIFETIME_PROFILER(init.GetDisplayId()),
Super(std::move(init)) {}
using ActorState::GetBoundingBox;
virtual ~Actor() = default;
/// Return the current location of the actor.
///
/// @note This function does not call the simulator, it returns the location
/// received in the last tick.
geom::Location GetLocation() const;
/// Return the current transform of the actor.
///
/// @note This function does not call the simulator, it returns the
/// transform received in the last tick.
geom::Transform GetTransform() const;
/// Return the current 3D velocity of the actor.
///
/// @note This function does not call the simulator, it returns the
/// 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
/// acceleration calculated after the actor's velocity.
geom::Vector3D GetAcceleration() const;
/// Teleport the actor to @a location.
void SetLocation(const geom::Location &location);
/// Teleport and rotate the actor to @a transform.
void SetTransform(const geom::Transform &transform);
/// Set the actor velocity before applying physics.
void SetTargetVelocity(const geom::Vector3D &vector);
/// Set the angular velocity of the actor before applying physics.
void SetTargetAngularVelocity(const geom::Vector3D &vector);
/// Enable a constant velocity mode
void EnableConstantVelocity(const geom::Vector3D &vector);
/// Disable the constant velocity mode
void DisableConstantVelocity();
/// Add impulse to the actor at its center of mass.
void AddImpulse(const geom::Vector3D &vector);
/// Add impulse to the actor at certain location.
void AddImpulse(const geom::Vector3D &impulse, const geom::Vector3D &location);
/// Add force to the actor at its center of mass.
void AddForce(const geom::Vector3D &force);
/// Add force to the actor at certain location.
void AddForce(const geom::Vector3D &force, const geom::Vector3D &location);
/// Add angular impulse to the actor.
void AddAngularImpulse(const geom::Vector3D &vector);
/// Add a torque to the actor.
void AddTorque(const geom::Vector3D &vector);
/// Enable or disable physics simulation on this actor.
void SetSimulatePhysics(bool enabled = true);
/// Enable or disable collisions on this actor.
void SetCollisions(bool enabled = true);
/// Set actor as dead and starts his life span
void SetActorDead();
/// Enable or disable gravity on this actor.
void SetEnableGravity(bool enabled = true);
rpc::ActorState GetActorState() const;
bool IsAlive() const {
return GetEpisode().IsValid() && (GetActorState() != rpc::ActorState::PendingKill && GetActorState() != rpc::ActorState::Invalid) ;
}
bool IsDormant() const {
return GetEpisode().IsValid() && GetActorState() == rpc::ActorState::Dormant;
}
bool IsActive() const {
return GetEpisode().IsValid() && GetActorState() == rpc::ActorState::Active;
}
/// Tell the simulator to destroy this Actor, and return whether the actor
/// was successfully destroyed.
///
/// @note It has no effect if the Actor was already successfully destroyed.
///
/// @warning This function blocks until the destruction operation is
/// completed by the simulator.
virtual bool Destroy();
const auto &Serialize() const {
return Super::GetActorDescription();
}
};
} // namespace client
} // namespace carla

View File

@ -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 "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_exception(InvalidAttributeValue(GetId() + ": " + message));
#define LIBCARLA_THROW_BAD_VALUE_CAST(type) \
if (GetType() != rpc::ActorAttributeType:: type) { \
throw_exception(BadAttributeCast(GetId() + ": bad attribute cast: cannot convert to " #type)); \
}
void ActorAttribute::Set(std::string value) {
if (!_attribute.is_modifiable) {
LIBCARLA_THROW_INVALID_VALUE("read-only attribute");
}
if (GetType() == rpc::ActorAttributeType::Bool) {
StringUtil::ToLower(value);
}
_attribute.value = std::move(value);
Validate();
}
template <>
bool ActorAttributeValueAccess::As<bool>() const {
LIBCARLA_THROW_BAD_VALUE_CAST(Bool);
auto value = StringUtil::ToLowerCopy(GetValue());
if (value == "true") {
return true;
} else if (value == "false") {
return false;
}
LIBCARLA_THROW_INVALID_VALUE("invalid bool: " + GetValue());
}
template<>
int ActorAttributeValueAccess::As<int>() const {
LIBCARLA_THROW_BAD_VALUE_CAST(Int);
return std::atoi(GetValue().c_str());
}
template<>
float ActorAttributeValueAccess::As<float>() const {
LIBCARLA_THROW_BAD_VALUE_CAST(Float);
double x = std::atof(GetValue().c_str());
if ((x > std::numeric_limits<float>::max()) ||
(x < std::numeric_limits<float>::lowest())) {
LIBCARLA_THROW_INVALID_VALUE("float overflow");
}
return static_cast<float>(x);
}
template <>
std::string ActorAttributeValueAccess::As<std::string>() const {
LIBCARLA_THROW_BAD_VALUE_CAST(String);
return GetValue();
}
template <>
sensor::data::Color ActorAttributeValueAccess::As<sensor::data::Color>() const {
LIBCARLA_THROW_BAD_VALUE_CAST(RGBColor);
std::vector<std::string> channels;
StringUtil::Split(channels, GetValue(), ",");
if (channels.size() != 3u) {
log_error("invalid color", GetValue());
LIBCARLA_THROW_INVALID_VALUE("colors must have 3 channels (R,G,B)");
}
auto to_int = [this](const std::string &str) {
int i = std::atoi(str.c_str());
if (i > std::numeric_limits<uint8_t>::max()) {
LIBCARLA_THROW_INVALID_VALUE("integer overflow in color channel");
}
return static_cast<uint8_t>(i);
};
return {to_int(channels[0u]), to_int(channels[1u]), to_int(channels[2u])};
}
void ActorAttributeValueAccess::Validate() const {
switch (GetType()) {
case rpc::ActorAttributeType::Bool: As<rpc::ActorAttributeType::Bool>(); break;
case rpc::ActorAttributeType::Int: As<rpc::ActorAttributeType::Int>(); break;
case rpc::ActorAttributeType::Float: As<rpc::ActorAttributeType::Float>(); break;
case rpc::ActorAttributeType::String: As<rpc::ActorAttributeType::String>(); break;
case rpc::ActorAttributeType::RGBColor: As<rpc::ActorAttributeType::RGBColor>(); break;
default:
LIBCARLA_THROW_INVALID_VALUE("invalid value type");
}
}
#undef LIBCARLA_THROW_BAD_VALUE_CAST
#undef LIBCARLA_THROW_INVALID_VALUE
} // namespace client
} // namespace carla

View File

@ -0,0 +1,241 @@
// 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/rpc/ActorAttribute.h"
#include "carla/sensor/data/Color.h"
#include <cstdlib>
#include <exception>
#include <type_traits>
namespace carla {
namespace client {
// ===========================================================================
// -- InvalidAttributeValue --------------------------------------------------
// ===========================================================================
/// Exception thrown when the value given to an ActorAttribute cannot be
/// converted to its type.
class InvalidAttributeValue : public std::invalid_argument {
public:
InvalidAttributeValue(const std::string &what) : std::invalid_argument(what) {}
};
// ===========================================================================
// -- BadAttributeCast -------------------------------------------------------
// ===========================================================================
/// Exception thrown when the value of an ActorAttribute cannot be cast to the
/// requested type.
class BadAttributeCast : public std::logic_error {
public:
BadAttributeCast(const std::string &what) : std::logic_error(what) {}
};
// ===========================================================================
// -- ActorAttribute ---------------------------------------------------------
// ===========================================================================
class ActorAttributeValueAccess
{
public:
ActorAttributeValueAccess() = default;
ActorAttributeValueAccess(ActorAttributeValueAccess const &) = default;
ActorAttributeValueAccess(ActorAttributeValueAccess &&) = default;
virtual ~ActorAttributeValueAccess() = default;
ActorAttributeValueAccess & operator= (ActorAttributeValueAccess const & ) = default;
ActorAttributeValueAccess & operator= (ActorAttributeValueAccess && ) = default;
virtual const std::string &GetId() const = 0;
virtual rpc::ActorAttributeType GetType() const = 0;
/// Cast the value to the given type.
///
/// @throw BadAttributeCast if the cast fails.
template <typename T>
T As() const;
/// Cast the value to the type specified by the enum
/// carla::rpc::ActorAttributeType.
///
/// @throw BadAttributeCast if the cast fails.
template <rpc::ActorAttributeType Type>
auto As() const;
template <typename T>
bool operator==(const T &rhs) const;
template <typename T>
bool operator!=(const T &rhs) const {
return !(*this == rhs);
}
protected:
virtual const std::string &GetValue() const = 0;
void Validate() const;
};
template <>
bool ActorAttributeValueAccess::As<bool>() const;
template <>
int ActorAttributeValueAccess::As<int>() const;
template <>
float ActorAttributeValueAccess::As<float>() const;
template <>
std::string ActorAttributeValueAccess::As<std::string>() const;
template <>
sensor::data::Color ActorAttributeValueAccess::As<sensor::data::Color>() const;
template <>
inline auto ActorAttributeValueAccess::As<rpc::ActorAttributeType::Bool>() const {
return As<bool>();
}
template <>
inline auto ActorAttributeValueAccess::As<rpc::ActorAttributeType::Int>() const {
return As<int>();
}
template <>
inline auto ActorAttributeValueAccess::As<rpc::ActorAttributeType::Float>() const {
return As<float>();
}
template <>
inline auto ActorAttributeValueAccess::As<rpc::ActorAttributeType::String>() const {
return As<std::string>();
}
template <>
inline auto ActorAttributeValueAccess::As<rpc::ActorAttributeType::RGBColor>() const {
return As<sensor::data::Color>();
}
template <typename T>
inline bool ActorAttributeValueAccess::operator==(const T &rhs) const {
return As<T>() == rhs;
}
template <>
inline bool ActorAttributeValueAccess::operator==(const ActorAttributeValueAccess &rhs) const {
return
(GetType() == rhs.GetType()) &&
(GetValue() == rhs.GetValue());
}
class ActorAttributeValue: public ActorAttributeValueAccess {
public:
ActorAttributeValue(rpc::ActorAttributeValue attribute):
_attribute(std::move(attribute))
{
Validate();
}
ActorAttributeValue(ActorAttributeValue const &) = default;
ActorAttributeValue(ActorAttributeValue &&) = default;
virtual ~ActorAttributeValue() = default;
ActorAttributeValue & operator= (ActorAttributeValue const & ) = default;
ActorAttributeValue & operator= (ActorAttributeValue && ) = default;
virtual const std::string &GetId() const override {
return _attribute.id;
}
virtual rpc::ActorAttributeType GetType() const override {
return _attribute.type;
}
/// Serialize this object as a carla::rpc::ActorAttributeValue.
operator rpc::ActorAttributeValue() const{
return _attribute;
}
virtual const std::string &GetValue() const override {
return _attribute.value;
}
private:
rpc::ActorAttributeValue _attribute;
};
template <>
inline bool ActorAttributeValueAccess::operator==(const ActorAttributeValue &rhs) const {
return rhs.operator==(*this);
}
/// An attribute of an ActorBlueprint.
class ActorAttribute: public ActorAttributeValueAccess {
public:
ActorAttribute(rpc::ActorAttribute attribute)
: ActorAttributeValueAccess(),
_attribute(std::move(attribute)) {
Validate();
}
ActorAttribute(ActorAttribute const &) = default;
ActorAttribute(ActorAttribute &&) = default;
virtual ~ActorAttribute() = default;
ActorAttribute & operator= (ActorAttribute const & ) = default;
ActorAttribute & operator= (ActorAttribute && ) = default;
virtual const std::string &GetId() const override {
return _attribute.id;
}
virtual rpc::ActorAttributeType GetType() const override {
return _attribute.type;
}
const std::vector<std::string> &GetRecommendedValues() const {
return _attribute.recommended_values;
}
bool IsModifiable() const {
return _attribute.is_modifiable;
}
/// Set the value of this attribute.
///
/// @throw InvalidAttributeValue if attribute is not modifiable.
/// @throw InvalidAttributeValue if format does not match this type.
void Set(std::string value);
/// Serialize this object as a carla::rpc::ActorAttributeValue.
operator rpc::ActorAttributeValue() const {
return _attribute;
}
virtual const std::string &GetValue() const override {
return _attribute.value;
}
private:
rpc::ActorAttribute _attribute;
};
template <>
inline bool ActorAttributeValueAccess::operator==(const ActorAttribute &rhs) const {
return rhs.operator==(*this);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,66 @@
// 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/client/ActorBlueprint.h"
#include "carla/Exception.h"
#include "carla/StringUtil.h"
#include <algorithm>
namespace carla {
namespace client {
template <typename Map, typename Container>
static void FillMap(Map &destination, Container &source) {
destination.reserve(source.size());
for (auto &item : source) {
auto id = item.id;
destination.emplace(id, std::move(item));
}
}
ActorBlueprint::ActorBlueprint(rpc::ActorDefinition definition)
: _uid(definition.uid),
_id(std::move(definition.id)) {
StringUtil::Split(_tags, definition.tags, ",");
FillMap(_attributes, definition.attributes);
}
bool ActorBlueprint::MatchTags(const std::string &wildcard_pattern) const {
return
StringUtil::Match(_id, wildcard_pattern) ||
std::any_of(_tags.begin(), _tags.end(), [&](const auto &tag) {
return StringUtil::Match(tag, wildcard_pattern);
});
}
const ActorAttribute &ActorBlueprint::GetAttribute(const std::string &id) const {
auto it = _attributes.find(id);
if (it == _attributes.end()) {
using namespace std::string_literals;
throw_exception(std::out_of_range("attribute '"s + id + "' not found"));
}
return it->second;
}
void ActorBlueprint::SetAttribute(const std::string &id, std::string value) {
const_cast<ActorAttribute &>(GetAttribute(id)).Set(std::move(value));
}
rpc::ActorDescription ActorBlueprint::MakeActorDescription() const {
rpc::ActorDescription description;
description.uid = _uid;
description.id = _id;
description.attributes.reserve(_attributes.size());
for (const auto &attribute : *this) {
description.attributes.push_back(attribute);
}
return description;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,124 @@
// 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/Debug.h"
#include "carla/Iterator.h"
#include "carla/client/ActorAttribute.h"
#include "carla/rpc/ActorDefinition.h"
#include "carla/rpc/ActorDescription.h"
#include <exception>
#include <unordered_map>
#include <unordered_set>
namespace carla {
namespace client {
/// Contains all the necessary information for spawning an Actor.
class ActorBlueprint {
public:
// =========================================================================
/// @name Constructor
// =========================================================================
/// @{
explicit ActorBlueprint(rpc::ActorDefinition actor_definition);
/// @}
// =========================================================================
/// @name Id
// =========================================================================
/// @{
public:
const std::string &GetId() const {
return _id;
}
/// @}
// =========================================================================
/// @name Tags
// =========================================================================
/// @{
public:
bool ContainsTag(const std::string &tag) const {
return _tags.find(tag) != _tags.end();
}
/// Test if any of the flags matches @a wildcard_pattern.
///
/// @a wildcard_pattern follows Unix shell-style wildcards.
bool MatchTags(const std::string &wildcard_pattern) const;
std::vector<std::string> GetTags() const {
return {_tags.begin(), _tags.end()};
}
/// @}
// =========================================================================
/// @name Attributes
// =========================================================================
/// @{
public:
bool ContainsAttribute(const std::string &id) const {
return _attributes.find(id) != _attributes.end();
}
/// @throw std::out_of_range if no such element exists.
const ActorAttribute &GetAttribute(const std::string &id) const;
/// Set the value of the attribute given by @a id.
///
/// @throw std::out_of_range if no such element exists.
/// @throw InvalidAttributeValue if attribute is not modifiable.
/// @throw InvalidAttributeValue if format does not match the attribute type.
void SetAttribute(const std::string &id, std::string value);
size_t size() const {
return _attributes.size();
}
auto begin() const {
return iterator::make_map_values_const_iterator(_attributes.begin());
}
auto end() const {
return iterator::make_map_values_const_iterator(_attributes.end());
}
/// @}
// =========================================================================
/// @name ActorDescription
// =========================================================================
/// @{
public:
rpc::ActorDescription MakeActorDescription() const;
/// @}
private:
uint32_t _uid = 0u;
std::string _id;
std::unordered_set<std::string> _tags;
std::unordered_map<std::string, ActorAttribute> _attributes;
};
} // namespace client
} // namespace carla

View File

@ -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>.
#include "carla/client/ActorList.h"
#include "carla/StringUtil.h"
#include "carla/client/detail/ActorFactory.h"
#include <iterator>
namespace carla {
namespace client {
ActorList::ActorList(
detail::EpisodeProxy episode,
std::vector<rpc::Actor> actors)
: _episode(std::move(episode)),
_actors(std::make_move_iterator(actors.begin()), std::make_move_iterator(actors.end())) {}
SharedPtr<Actor> ActorList::Find(const ActorId actor_id) const {
for (auto &actor : _actors) {
if (actor_id == actor.GetId()) {
return actor.Get(_episode);
}
}
return nullptr;
}
SharedPtr<ActorList> ActorList::Filter(const std::string &wildcard_pattern) const {
SharedPtr<ActorList> filtered (new ActorList(_episode, {}));
for (auto &&actor : _actors) {
if (StringUtil::Match(actor.GetTypeId(), wildcard_pattern)) {
filtered->_actors.push_back(actor);
}
}
return filtered;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,72 @@
// 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/client/detail/ActorVariant.h"
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
namespace carla {
namespace client {
class ActorList : public EnableSharedFromThis<ActorList> {
private:
template <typename It>
auto MakeIterator(It it) const {
return boost::make_transform_iterator(it, [this](auto &v) {
return v.Get(_episode);
});
}
public:
/// Find an actor by id.
SharedPtr<Actor> Find(ActorId actor_id) const;
/// Filters a list of Actor with type id matching @a wildcard_pattern.
SharedPtr<ActorList> Filter(const std::string &wildcard_pattern) const;
SharedPtr<Actor> operator[](size_t pos) const {
return _actors[pos].Get(_episode);
}
SharedPtr<Actor> at(size_t pos) const {
return _actors.at(pos).Get(_episode);
}
auto begin() const {
return MakeIterator(_actors.begin());
}
auto end() const {
return MakeIterator(_actors.end());
}
bool empty() const {
return _actors.empty();
}
size_t size() const {
return _actors.size();
}
private:
friend class World;
ActorList(detail::EpisodeProxy episode, std::vector<rpc::Actor> actors);
detail::EpisodeProxy _episode;
std::vector<detail::ActorVariant> _actors;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,29 @@
// Copyright (c) 2021 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/geom/Transform.h"
#include "carla/geom/Vector3D.h"
#include "carla/rpc/ActorId.h"
#include "carla/rpc/ActorState.h"
#include "carla/sensor/data/ActorDynamicState.h"
namespace carla {
namespace client {
struct ActorSnapshot {
ActorId id = 0u;
rpc::ActorState actor_state;
geom::Transform transform;
geom::Vector3D velocity;
geom::Vector3D angular_velocity;
geom::Vector3D acceleration;
sensor::data::ActorDynamicState::TypeDependentState state;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,89 @@
// 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/client/BlueprintLibrary.h"
#include "carla/Exception.h"
#include <algorithm>
#include <iterator>
namespace carla {
namespace client {
BlueprintLibrary::BlueprintLibrary(
const std::vector<rpc::ActorDefinition> &blueprints) {
_blueprints.reserve(blueprints.size());
for (auto &definition : blueprints) {
_blueprints.emplace(definition.id, ActorBlueprint{definition});
}
}
SharedPtr<BlueprintLibrary> BlueprintLibrary::Filter(
const std::string &wildcard_pattern) const {
map_type result;
for (auto &pair : _blueprints) {
if (pair.second.MatchTags(wildcard_pattern)) {
result.emplace(pair);
}
}
return SharedPtr<BlueprintLibrary>{new BlueprintLibrary(result)};
}
SharedPtr<BlueprintLibrary> BlueprintLibrary::FilterByAttribute(
const std::string &name, const std::string& value) const {
map_type result;
for (auto &pair : _blueprints) {
if (!pair.second.ContainsAttribute(name))
continue;
const ActorAttribute &Attribute = pair.second.GetAttribute(name);
const std::vector<std::string> &Values = Attribute.GetRecommendedValues();
if (Values.empty())
{
const std::string &AttributeValue = Attribute.GetValue();
if (value == AttributeValue)
result.emplace(pair);
}
else
{
for (const std::string &Value : Values)
{
if (Value == value)
{
result.emplace(pair);
break;
}
}
}
}
return SharedPtr<BlueprintLibrary>{new BlueprintLibrary(result)};
}
BlueprintLibrary::const_pointer BlueprintLibrary::Find(const std::string &key) const {
auto it = _blueprints.find(key);
return it != _blueprints.end() ? &it->second : nullptr;
}
BlueprintLibrary::const_reference BlueprintLibrary::at(const std::string &key) const {
auto it = _blueprints.find(key);
if (it == _blueprints.end()) {
using namespace std::string_literals;
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_exception(std::out_of_range("index out of range"));
}
return operator[](pos);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,88 @@
// 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/Debug.h"
#include "carla/Iterator.h"
#include "carla/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/client/ActorBlueprint.h"
#include <type_traits>
#include <unordered_map>
#include <vector>
namespace carla {
namespace client {
/// @todo Works as a list but its actually a map. We should assess the use
/// cases and reconsider this implementation.
class BlueprintLibrary
: public EnableSharedFromThis<BlueprintLibrary>,
private MovableNonCopyable {
using map_type = std::unordered_map<std::string, ActorBlueprint>;
public:
// Here we force a bit the typedefs to make this class look like a list.
using key_type = map_type::key_type;
using value_type = map_type::mapped_type;
using size_type = map_type::size_type;
using const_iterator = decltype(carla::iterator::make_map_values_const_iterator<map_type::const_iterator>(map_type::const_iterator{}));
using const_reference = const value_type &;
using const_pointer = const value_type *;
explicit BlueprintLibrary(const std::vector<rpc::ActorDefinition> &blueprints);
BlueprintLibrary(BlueprintLibrary &&) = default;
BlueprintLibrary &operator=(BlueprintLibrary &&) = default;
/// Filters a list of ActorBlueprint with id or tags matching
/// @a wildcard_pattern.
SharedPtr<BlueprintLibrary> Filter(const std::string &wildcard_pattern) const;
SharedPtr<BlueprintLibrary> FilterByAttribute(const std::string &name, const std::string& value) const;
const_pointer Find(const std::string &key) const;
/// @throw std::out_of_range if no such element exists.
const_reference at(const std::string &key) const;
/// @warning Linear complexity.
const_reference operator[](size_type pos) const {
using diff_t = std::iterator_traits<const_iterator>::difference_type;
return std::next(_blueprints.begin(), static_cast<diff_t>(pos))->second;
}
/// @warning Linear complexity.
/// @throw std::out_of_range if !(pos < size()).
const_reference at(size_type pos) const;
const_iterator begin() const /*noexcept*/ {
return iterator::make_map_values_const_iterator(_blueprints.begin());
}
const_iterator end() const /*noexcept*/ {
return iterator::make_map_values_const_iterator(_blueprints.end());
}
bool empty() const /*noexcept*/ {
return _blueprints.empty();
}
size_type size() const /*noexcept*/ {
return _blueprints.size();
}
private:
BlueprintLibrary(map_type blueprints)
: _blueprints(std::move(blueprints)) {}
map_type _blueprints;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,192 @@
// 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/client/detail/Simulator.h"
#include "carla/client/World.h"
#include "carla/client/Map.h"
#include "carla/PythonUtil.h"
#include "carla/trafficmanager/TrafficManager.h"
namespace carla {
namespace client {
using namespace carla::traffic_manager;
class Client {
public:
/// Construct a carla client.
///
/// @param host IP address of the host machine running the simulator.
/// @param port TCP port to connect with the simulator.
/// @param worker_threads number of asynchronous threads to use, or 0 to use
/// all available hardware concurrency.
explicit Client(
const std::string &host,
uint16_t port,
size_t worker_threads = 0u);
/// Set a timeout for networking operations. If set, any networking
/// operation taking longer than @a timeout throws rpc::timeout.
void SetTimeout(time_duration timeout) {
_simulator->SetNetworkingTimeout(timeout);
}
time_duration GetTimeout() {
return _simulator->GetNetworkingTimeout();
}
/// Return the version string of this client API.
std::string GetClientVersion() const {
return _simulator->GetClientVersion();
}
/// Return the version string of the simulator we are connected to.
std::string GetServerVersion() const {
return _simulator->GetServerVersion();
}
std::vector<std::string> GetAvailableMaps() const {
return _simulator->GetAvailableMaps();
}
bool SetFilesBaseFolder(const std::string &path) {
return _simulator->SetFilesBaseFolder(path);
}
std::vector<std::string> GetRequiredFiles(const std::string &folder = "", const bool download = true) const {
return _simulator->GetRequiredFiles(folder, download);
}
void RequestFile(const std::string &name) const {
_simulator->RequestFile(name);
}
World ReloadWorld(bool reset_settings = true) const {
return World{_simulator->ReloadEpisode(reset_settings)};
}
World LoadWorld(
std::string map_name,
bool reset_settings = true,
rpc::MapLayer map_layers = rpc::MapLayer::All) const {
return World{_simulator->LoadEpisode(std::move(map_name), reset_settings, map_layers)};
}
/// Return (and load) a new world (map) only when the requested map is different from the current one
void LoadWorldIfDifferent(
std::string map_name,
bool reset_settings = true,
rpc::MapLayer map_layers = rpc::MapLayer::All) const {
carla::client::World world = GetWorld();
carla::SharedPtr<carla::client::Map> current_map = world.GetMap();
std::string current_map_name = current_map->GetName();
std::string map_name_prefix = "Carla/Maps/";
std::string map_name_without_prefix = map_name;
std::string map_name_with_prefix = map_name_prefix + map_name;
if(!(map_name_without_prefix == current_map_name) && !(map_name_with_prefix == current_map_name)){
World World{_simulator->LoadEpisode(std::move(map_name), reset_settings, map_layers)};
}else{}
}
World GenerateOpenDriveWorld(
std::string opendrive,
const rpc::OpendriveGenerationParameters & params,
bool reset_settings = true) const {
return World{_simulator->LoadOpenDriveEpisode(
std::move(opendrive), params, reset_settings)};
}
/// Return an instance of the world currently active in the simulator.
World GetWorld() const {
return World{_simulator->GetCurrentEpisode()};
}
/// Return an instance of the TrafficManager currently active in the simulator.
TrafficManager GetInstanceTM(uint16_t port = TM_DEFAULT_PORT) const {
return TrafficManager(_simulator->GetCurrentEpisode(), port);
}
/// Return an instance of the Episode currently active in the simulator.
carla::client::detail::EpisodeProxy GetCurrentEpisode() const {
return _simulator->GetCurrentEpisode();
}
std::string StartRecorder(std::string name, bool additional_data = false) {
return _simulator->StartRecorder(name, additional_data);
}
void StopRecorder(void) {
_simulator->StopRecorder();
}
std::string ShowRecorderFileInfo(std::string name, bool show_all) {
return _simulator->ShowRecorderFileInfo(name, show_all);
}
std::string ShowRecorderCollisions(std::string name, char type1, char type2) {
return _simulator->ShowRecorderCollisions(name, type1, type2);
}
std::string ShowRecorderActorsBlocked(std::string name, double min_time, double min_distance) {
return _simulator->ShowRecorderActorsBlocked(name, min_time, min_distance);
}
std::string ReplayFile(std::string name, double start, double duration,
uint32_t follow_id, bool replay_sensors) {
return _simulator->ReplayFile(name, start, duration, follow_id, replay_sensors);
}
void StopReplayer(bool keep_actors) {
_simulator->StopReplayer(keep_actors);
}
void SetReplayerTimeFactor(double time_factor) {
_simulator->SetReplayerTimeFactor(time_factor);
}
void SetReplayerIgnoreHero(bool ignore_hero) {
_simulator->SetReplayerIgnoreHero(ignore_hero);
}
void SetReplayerIgnoreSpectator(bool ignore_spectator) {
_simulator->SetReplayerIgnoreSpectator(ignore_spectator);
}
void ApplyBatch(
std::vector<rpc::Command> commands,
bool do_tick_cue = false) const {
_simulator->ApplyBatch(std::move(commands), do_tick_cue);
}
std::vector<rpc::CommandResponse> ApplyBatchSync(
std::vector<rpc::Command> commands,
bool do_tick_cue = false) const {
auto responses = _simulator->ApplyBatchSync(std::move(commands), false);
if (do_tick_cue)
_simulator->Tick(_simulator->GetNetworkingTimeout());
return responses;
}
private:
std::shared_ptr<detail::Simulator> _simulator;
};
inline Client::Client(
const std::string &host,
uint16_t port,
size_t worker_threads)
: _simulator(
new detail::Simulator(host, port, worker_threads),
PythonUtil::ReleaseGILDeleter()) {}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,21 @@
// 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/client/Sensor.h"
namespace carla {
namespace client {
class ClientSideSensor : public Sensor {
public:
using Sensor::Sensor;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,85 @@
// 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/client/DebugHelper.h"
#include "carla/client/detail/Simulator.h"
#include "carla/rpc/DebugShape.h"
namespace carla {
namespace client {
using Shape = rpc::DebugShape;
template <typename T>
static void DrawShape(
detail::EpisodeProxy &episode,
const T &primitive,
rpc::Color color,
float life_time,
bool persistent_lines) {
const Shape shape{primitive, color, life_time, persistent_lines};
episode.Lock()->DrawDebugShape(shape);
}
void DebugHelper::DrawPoint(
const geom::Location &location,
float size,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::Point point{location, size};
DrawShape(_episode, point, color, life_time, persistent_lines);
}
void DebugHelper::DrawLine(
const geom::Location &begin,
const geom::Location &end,
float thickness,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::Line line{begin, end, thickness};
DrawShape(_episode, line, color, life_time, persistent_lines);
}
void DebugHelper::DrawArrow(
const geom::Location &begin,
const geom::Location &end,
float thickness,
float arrow_size,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::Line line{begin, end, thickness};
Shape::Arrow arrow{line, arrow_size};
DrawShape(_episode, arrow, color, life_time, persistent_lines);
}
void DebugHelper::DrawBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
float thickness,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::Box the_box{box, rotation, thickness};
DrawShape(_episode, the_box, color, life_time, persistent_lines);
}
void DebugHelper::DrawString(
const geom::Location &location,
const std::string &text,
bool draw_shadow,
sensor::data::Color color,
float life_time,
bool persistent_lines) {
Shape::String string{location, text, draw_shadow};
DrawShape(_episode, string, color, life_time, persistent_lines);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,72 @@
// 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/client/detail/EpisodeProxy.h"
#include "carla/geom/BoundingBox.h"
#include "carla/geom/Location.h"
#include "carla/geom/Rotation.h"
#include "carla/sensor/data/Color.h"
namespace carla {
namespace client {
class DebugHelper {
public:
using Color = sensor::data::Color;
explicit DebugHelper(detail::EpisodeProxy episode)
: _episode(std::move(episode)) {}
void DrawPoint(
const geom::Location &location,
float size = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawLine(
const geom::Location &begin,
const geom::Location &end,
float thickness = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawArrow(
const geom::Location &begin,
const geom::Location &end,
float thickness = 0.1f,
float arrow_size = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawBox(
const geom::BoundingBox &box,
const geom::Rotation &rotation,
float thickness = 0.1f,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
void DrawString(
const geom::Location &location,
const std::string &text,
bool draw_shadow = false,
Color color = Color{255u, 0u, 0u},
float life_time = -1.0f,
bool persistent_lines = true);
private:
detail::EpisodeProxy _episode;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,82 @@
// Copyright (c) 2021 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 "FileTransfer.h"
#include "carla/Version.h"
namespace carla {
namespace client {
#ifdef _WIN32
std::string FileTransfer::_filesBaseFolder = std::string(getenv("USERPROFILE")) + "/carlaCache/";
#else
std::string FileTransfer::_filesBaseFolder = std::string(getenv("HOME")) + "/carlaCache/";
#endif
bool FileTransfer::SetFilesBaseFolder(const std::string &path) {
if (path.empty()) return false;
// Check that the path ends in a slash, add it otherwise
if (path[path.size() - 1] != '/' && path[path.size() - 1] != '\\') {
_filesBaseFolder = path + "/";
}
return true;
}
const std::string& FileTransfer::GetFilesBaseFolder() {
return _filesBaseFolder;
}
bool FileTransfer::FileExists(std::string file) {
// Check if the file exists or not
struct stat buffer;
std::string fullpath = _filesBaseFolder;
fullpath += "/";
fullpath += ::carla::version();
fullpath += "/";
fullpath += file;
return (stat(fullpath.c_str(), &buffer) == 0);
}
bool FileTransfer::WriteFile(std::string path, std::vector<uint8_t> content) {
std::string writePath = _filesBaseFolder;
writePath += "/";
writePath += ::carla::version();
writePath += "/";
writePath += path;
// Validate and create the file path
carla::FileSystem::ValidateFilePath(writePath);
// Open the file to truncate it in binary mode
std::ofstream out(writePath, std::ios::trunc | std::ios::binary);
if(!out.good()) return false;
// Write the content on and close it
for(auto file : content) {
out << file;
}
out.close();
return true;
}
std::vector<uint8_t> FileTransfer::ReadFile(std::string path) {
std::string fullpath = _filesBaseFolder;
fullpath += "/";
fullpath += ::carla::version();
fullpath += "/";
fullpath += path;
// Read the binary file from the base folder
std::ifstream file(fullpath, std::ios::binary);
std::vector<uint8_t> content(std::istreambuf_iterator<char>(file), {});
return content;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,42 @@
// Copyright (c) 2021 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/FileSystem.h"
#include <fstream>
#include <iostream>
#include <string>
#include <sys/stat.h>
namespace carla {
namespace client {
class FileTransfer {
public:
FileTransfer() = delete;
static bool SetFilesBaseFolder(const std::string &path);
static const std::string& GetFilesBaseFolder();
static bool FileExists(std::string file);
static bool WriteFile(std::string path, std::vector<uint8_t> content);
static std::vector<uint8_t> ReadFile(std::string path);
private:
static std::string _filesBaseFolder;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,19 @@
// 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
namespace carla {
namespace client {
enum class GarbageCollectionPolicy {
Disabled,
Enabled,
Inherit
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,29 @@
// Copyright (c) 2020 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/client/Junction.h"
#include "carla/client/Map.h"
#include "carla/road/element/Waypoint.h"
namespace carla {
namespace client {
Junction::Junction(SharedPtr<const Map> parent, const road::Junction *junction) : _parent(parent) {
_bounding_box = junction->GetBoundingBox();
_id = junction->GetId();
}
std::vector<std::pair<SharedPtr<Waypoint>, SharedPtr<Waypoint>>> Junction::GetWaypoints(
road::Lane::LaneType type) const {
return _parent->GetJunctionWaypoints(GetId(), type);
}
geom::BoundingBox Junction::GetBoundingBox() const {
return _bounding_box;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,52 @@
// Copyright (c) 2020 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/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/road/Junction.h"
#include "carla/road/RoadTypes.h"
#include "carla/geom/BoundingBox.h"
#include "carla/client/Waypoint.h"
#include <vector>
namespace carla {
namespace client {
class Map;
class Junction
: public EnableSharedFromThis<Junction>,
private NonCopyable
{
public:
carla::road::JuncId GetId() const {
return _id;
}
std::vector<std::pair<SharedPtr<Waypoint>,SharedPtr<Waypoint>>> GetWaypoints(
road::Lane::LaneType type = road::Lane::LaneType::Driving) const;
geom::BoundingBox GetBoundingBox() const;
private:
friend class Map;
Junction(SharedPtr<const Map> parent, const road::Junction *junction);
SharedPtr<const Map> _parent;
geom::BoundingBox _bounding_box;
road::JuncId _id;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,143 @@
// Copyright (c) 2020 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/Memory.h"
#include "carla/client/Waypoint.h"
#include "carla/geom/Transform.h"
#include "carla/geom/BoundingBox.h"
#include "carla/road/element/RoadInfoSignal.h"
#include <string>
namespace carla {
namespace client {
/// Class containing a reference to RoadInfoSignal
class Landmark {
public:
SharedPtr<Waypoint> GetWaypoint() const {
return _waypoint;
}
const geom::Transform &GetTransform() const {
return _signal->GetSignal()->GetTransform();
}
road::RoadId GetRoadId() const {
return _signal->GetRoadId();
}
double GetDistance() const {
return _distance_from_search;
}
double GetS() const {
return _signal->GetS();
}
double GetT() const {
return _signal->GetT();
}
std::string GetId() const {
return _signal->GetSignalId();
}
std::string GetName() const {
return _signal->GetSignal()->GetName();
}
bool IsDynamic() const {
return _signal->IsDynamic();
}
road::SignalOrientation GetOrientation() const {
return _signal->GetOrientation();
}
double GetZOffset() const {
return _signal->GetSignal()->GetZOffset();
}
std::string GetCountry() const {
return _signal->GetSignal()->GetCountry();
}
std::string GetType() const {
return _signal->GetSignal()->GetType();
}
std::string GetSubType() const {
return _signal->GetSignal()->GetSubtype();
}
double GetValue() const {
return _signal->GetSignal()->GetValue();
}
std::string GetUnit() const {
return _signal->GetSignal()->GetUnit();
}
double GetHeight() const {
return _signal->GetSignal()->GetHeight();
}
double GetWidth() const {
return _signal->GetSignal()->GetWidth();
}
std::string GetText() const {
return _signal->GetSignal()->GetText();
}
double GethOffset() const {
return _signal->GetSignal()->GetHOffset();
}
double GetPitch() const {
return _signal->GetSignal()->GetPitch();
}
double GetRoll() const {
return _signal->GetSignal()->GetRoll();
}
const auto &GetValidities() const {
return _signal->GetValidities();
}
private:
friend Waypoint;
friend Map;
Landmark(
SharedPtr<Waypoint> waypoint,
SharedPtr<const Map> parent,
const road::element::RoadInfoSignal* signal,
double distance_from_search = 0)
: _waypoint(waypoint),
_parent(parent),
_signal(signal),
_distance_from_search(distance_from_search) {}
/// waypoint where the signal is affecting
SharedPtr<Waypoint> _waypoint;
SharedPtr<const Map> _parent;
const road::element::RoadInfoSignal* _signal;
double _distance_from_search;
};
} // client
} // carla

View File

@ -0,0 +1,183 @@
// Copyright (c) 2019 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/client/LaneInvasionSensor.h"
#include "carla/Logging.h"
#include "carla/client/Map.h"
#include "carla/client/Vehicle.h"
#include "carla/client/detail/Simulator.h"
#include "carla/geom/Location.h"
#include "carla/geom/Math.h"
#include "carla/sensor/data/LaneInvasionEvent.h"
#include <exception>
namespace carla {
namespace client {
// ===========================================================================
// -- Static local methods ---------------------------------------------------
// ===========================================================================
static geom::Location Rotate(float yaw, const geom::Location &location) {
yaw *= geom::Math::Pi<float>() / 180.0f;
const float c = std::cos(yaw);
const float s = std::sin(yaw);
return {
c * location.x - s * location.y,
s * location.x + c * location.y,
location.z};
}
// ===========================================================================
// -- LaneInvasionCallback ---------------------------------------------------
// ===========================================================================
class LaneInvasionCallback {
public:
LaneInvasionCallback(
const Vehicle &vehicle,
SharedPtr<Map> &&map,
Sensor::CallbackFunctionType &&user_callback)
: _parent(vehicle.GetId()),
_parent_bounding_box(vehicle.GetBoundingBox()),
_map(std::move(map)),
_callback(std::move(user_callback)) {
DEBUG_ASSERT(_map != nullptr);
}
void Tick(const WorldSnapshot &snapshot) const;
private:
struct Bounds {
size_t frame;
std::array<geom::Location, 4u> corners;
};
std::shared_ptr<const Bounds> MakeBounds(
size_t frame,
const geom::Transform &vehicle_transform) const;
ActorId _parent;
geom::BoundingBox _parent_bounding_box;
SharedPtr<const Map> _map;
Sensor::CallbackFunctionType _callback;
mutable AtomicSharedPtr<const Bounds> _bounds;
};
void LaneInvasionCallback::Tick(const WorldSnapshot &snapshot) const {
// Make sure the parent is alive.
auto parent = snapshot.Find(_parent);
if (!parent) {
return;
}
auto next = MakeBounds(snapshot.GetFrame(), parent->transform);
auto prev = _bounds.load();
// First frame it'll be null.
if ((prev == nullptr) && _bounds.compare_exchange(&prev, next)) {
return;
}
// Make sure the distance is long enough.
constexpr float distance_threshold = 10.0f * std::numeric_limits<float>::epsilon();
for (auto i = 0u; i < 4u; ++i) {
if ((next->corners[i] - prev->corners[i]).Length() < distance_threshold) {
return;
}
}
// Make sure the current frame is up-to-date.
do {
if (prev->frame >= next->frame) {
return;
}
} while (!_bounds.compare_exchange(&prev, next));
// Finally it's safe to compute the crossed lanes.
std::vector<road::element::LaneMarking> crossed_lanes;
for (auto i = 0u; i < 4u; ++i) {
const auto lanes = _map->CalculateCrossedLanes(prev->corners[i], next->corners[i]);
crossed_lanes.insert(crossed_lanes.end(), lanes.begin(), lanes.end());
}
if (!crossed_lanes.empty()) {
_callback(MakeShared<sensor::data::LaneInvasionEvent>(
snapshot.GetTimestamp().frame,
snapshot.GetTimestamp().elapsed_seconds,
parent->transform,
_parent,
std::move(crossed_lanes)));
}
}
std::shared_ptr<const LaneInvasionCallback::Bounds> LaneInvasionCallback::MakeBounds(
const size_t frame,
const geom::Transform &transform) const {
const auto &box = _parent_bounding_box;
const auto location = transform.location + box.location;
const auto yaw = transform.rotation.yaw;
return std::make_shared<Bounds>(Bounds{frame, {
location + Rotate(yaw, geom::Location( box.extent.x, box.extent.y, 0.0f)),
location + Rotate(yaw, geom::Location(-box.extent.x, box.extent.y, 0.0f)),
location + Rotate(yaw, geom::Location( box.extent.x, -box.extent.y, 0.0f)),
location + Rotate(yaw, geom::Location(-box.extent.x, -box.extent.y, 0.0f))}});
}
// ===========================================================================
// -- LaneInvasionSensor -----------------------------------------------------
// ===========================================================================
LaneInvasionSensor::~LaneInvasionSensor() {
Stop();
}
void LaneInvasionSensor::Listen(CallbackFunctionType callback) {
auto vehicle = boost::dynamic_pointer_cast<Vehicle>(GetParent());
if (vehicle == nullptr) {
log_error(GetDisplayId(), ": not attached to a vehicle");
return;
}
auto episode = GetEpisode().Lock();
auto cb = std::make_shared<LaneInvasionCallback>(
*vehicle,
episode->GetCurrentMap(),
std::move(callback));
const size_t callback_id = episode->RegisterOnTickEvent([cb=std::move(cb)](const auto &snapshot) {
try {
cb->Tick(snapshot);
} catch (const std::exception &e) {
log_error("LaneInvasionSensor:", e.what());
}
});
const size_t previous = _callback_id.exchange(callback_id);
if (previous != 0u) {
episode->RemoveOnTickEvent(previous);
}
}
void LaneInvasionSensor::Stop() {
const size_t previous = _callback_id.exchange(0u);
auto episode = GetEpisode().TryLock();
if ((previous != 0u) && (episode != nullptr)) {
episode->RemoveOnTickEvent(previous);
}
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,50 @@
// Copyright (c) 2019 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/client/ClientSideSensor.h"
#include <atomic>
namespace carla {
namespace client {
class Map;
class Vehicle;
class LaneInvasionSensor final : public ClientSideSensor {
public:
using ClientSideSensor::ClientSideSensor;
~LaneInvasionSensor();
/// Register a @a callback to be executed each time a new measurement is
/// received.
///
/// @warning Calling this function on a sensor that is already listening
/// steals the data stream from the previously set callback. Note that
/// several instances of Sensor (even in different processes) may point to
/// the same sensor in the simulator.
void Listen(CallbackFunctionType callback) override;
/// Stop listening for new measurements.
void Stop() override;
/// Return whether this Sensor instance is currently listening to the
/// associated sensor in the simulator.
bool IsListening() const override {
return _callback_id != 0u;
}
private:
std::atomic_size_t _callback_id{0u};
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,92 @@
// Copyright (c) 2020 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/client/Light.h"
#include "carla/client/LightManager.h"
#include <assert.h>
namespace carla {
namespace client {
using LightGroup = rpc::LightState::LightGroup;
Color Light::GetColor() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->GetColor(_id);
}
float Light::GetIntensity() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->GetIntensity(_id);
}
LightGroup Light::GetLightGroup() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->GetLightGroup(_id);
}
LightState Light::GetLightState() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->GetLightState(_id);
}
bool Light::IsOn() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->IsActive(_id) == true;
}
bool Light::IsOff() const {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
return light_manager->IsActive(_id) == false;
}
void Light::SetColor(Color color) {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetColor(_id, color);
}
void Light::SetIntensity(float intensity) {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetIntensity(_id, intensity);
}
void Light::SetLightGroup(LightGroup group) {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetLightGroup(_id, group);
}
void Light::SetLightState(const LightState& state) {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetLightState(_id, state);
}
void Light::TurnOn() {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetActive(_id, true);
}
void Light::TurnOff() {
auto light_manager = _light_manager.lock();
assert(light_manager && "No light_manager");
light_manager->SetActive(_id, false);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,80 @@
// Copyright (c) 2020 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/Memory.h"
#include "carla/client/LightState.h"
#include "carla/geom/Location.h"
#include "carla/geom/Rotation.h"
#include "carla/rpc/LightState.h"
namespace carla {
namespace client {
class LightManager;
class Light {
using LightGroup = rpc::LightState::LightGroup;
public:
Light() {}
Color GetColor() const;
LightId GetId() const {
return _id;
}
float GetIntensity() const;
const geom::Location GetLocation() const {
return _location;
}
LightGroup GetLightGroup() const;
LightState GetLightState() const;
bool IsOn() const;
bool IsOff() const;
void SetColor(Color color);
void SetIntensity(float intensity);
void SetLightGroup(LightGroup group);
void SetLightState(const LightState& state);
void TurnOn();
void TurnOff();
private:
friend class LightManager;
Light(WeakPtr<LightManager> light_manager,
geom::Location location,
LightId id)
: _light_manager(light_manager),
_location (location),
_id (id) {}
WeakPtr<LightManager> _light_manager;
geom::Location _location;
LightId _id;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,335 @@
// Copyright (c) 2020 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/client/LightManager.h"
#include "carla/client/detail/Simulator.h"
namespace carla {
namespace client {
using LightGroup = rpc::LightState::LightGroup;
LightManager::~LightManager(){
if(_episode.IsValid()) {
_episode.Lock()->RemoveOnTickEvent(_on_light_update_register_id);
_episode.Lock()->RemoveLightUpdateChangeEvent(_on_light_update_register_id);
}
UpdateServerLightsState(true);
}
void LightManager::SetEpisode(detail::WeakEpisodeProxy episode) {
_episode = episode;
_on_tick_register_id = _episode.Lock()->RegisterOnTickEvent(
[&](const WorldSnapshot&) {
UpdateServerLightsState();
});
_on_light_update_register_id = _episode.Lock()->RegisterLightUpdateChangeEvent(
[&](const WorldSnapshot& ) {
QueryLightsStateToServer();
ApplyChanges();
});
QueryLightsStateToServer();
}
std::vector<Light> LightManager::GetAllLights(LightGroup type) const {
std::vector<Light> result;
for(auto lights_state : _lights_state) {
LightGroup group = lights_state.second._group;
if((type == LightGroup::None) || (group == type)) {
auto it_light = _lights.find(lights_state.first);
result.push_back(it_light->second);
}
}
return result;
}
void LightManager::TurnOn(std::vector<Light>& lights) {
for(Light& light : lights) {
SetActive(light._id, true);
}
}
void LightManager::TurnOff(std::vector<Light>& lights) {
for(Light& light : lights) {
SetActive(light._id, false);
}
}
void LightManager::SetActive(std::vector<Light>& lights, std::vector<bool>& active) {
size_t lights_to_update = (lights.size() < active.size()) ? lights.size() : active.size();
for(size_t i = 0; i < lights_to_update; i++) {
SetActive(lights[i]._id, active[i]);
}
}
std::vector<bool> LightManager::IsActive(std::vector<Light>& lights) const {
std::vector<bool> result;
for(Light& light : lights) {
result.push_back( IsActive(light._id) );
}
return result;
}
std::vector<Light> LightManager::GetTurnedOnLights(LightGroup type) const {
std::vector<Light> result;
for(auto lights_state : _lights_state) {
LightState& state = lights_state.second;
LightGroup group = state._group;
if( (type == LightGroup::None || group == type) && state._active ) {
auto it_light = _lights.find(lights_state.first);
result.push_back(it_light->second);
}
}
return result;
}
std::vector<Light> LightManager::GetTurnedOffLights(LightGroup type) const {
std::vector<Light> result;
for(auto lights_state : _lights_state) {
LightState& state = lights_state.second;
LightGroup group = state._group;
if( (type == LightGroup::None || group == type) && !state._active ) {
auto it_light = _lights.find(lights_state.first);
result.push_back(it_light->second);
}
}
return result;
}
void LightManager::SetColor(std::vector<Light>& lights, Color color) {
for(Light& light : lights) {
SetColor(light._id, color);
}
}
void LightManager::SetColor(std::vector<Light>& lights, std::vector<Color>& colors) {
size_t lights_to_update = (lights.size() < colors.size()) ? lights.size() : colors.size();
for(size_t i = 0; i < lights_to_update; i++) {
SetColor(lights[i]._id, colors[i]);
}
}
std::vector<Color> LightManager::GetColor(std::vector<Light>& lights) const {
std::vector<Color> result;
for(Light& light : lights) {
result.push_back( GetColor(light._id) );
}
return result;
}
void LightManager::SetIntensity(std::vector<Light>& lights, float intensity) {
for(Light& light : lights) {
SetIntensity(light._id, intensity);
}
}
void LightManager::SetIntensity(std::vector<Light>& lights, std::vector<float>& intensities) {
size_t lights_to_update = (lights.size() < intensities.size()) ? lights.size() : intensities.size();
for(size_t i = 0; i < lights_to_update; i++) {
SetIntensity(lights[i]._id, intensities[i]);
}
}
std::vector<float> LightManager::GetIntensity(std::vector<Light>& lights) const {
std::vector<float> result;
for(Light& light : lights) {
result.push_back( GetIntensity(light._id) );
}
return result;
}
void LightManager::SetLightGroup(std::vector<Light>& lights, LightGroup group) {
for(Light& light : lights) {
SetLightGroup(light._id, group);
}
}
void LightManager::SetLightGroup(std::vector<Light>& lights, std::vector<LightGroup>& groups) {
size_t lights_to_update = (lights.size() < groups.size()) ? lights.size() : groups.size();
for(size_t i = 0; i < lights_to_update; i++) {
SetLightGroup(lights[i]._id, groups[i]);
}
}
std::vector<LightGroup> LightManager::GetLightGroup(std::vector<Light>& lights) const {
std::vector<LightGroup> result;
for(Light& light : lights) {
result.push_back( GetLightGroup(light._id) );
}
return result;
}
void LightManager::SetLightState(std::vector<Light>& lights, LightState state) {
for(Light& light : lights) {
SetLightState(light._id, state);
}
}
void LightManager::SetLightState(std::vector<Light>& lights, std::vector<LightState>& states) {
size_t lights_to_update = (lights.size() < states.size()) ? lights.size() : states.size();
for(size_t i = 0; i < lights_to_update; i++) {
SetLightState(lights[i]._id, states[i]);
}
}
std::vector<LightState> LightManager::GetLightState(std::vector<Light>& lights) const {
std::vector<LightState> result;
for(Light& light : lights) {
result.push_back( RetrieveLightState(light._id) );
}
return result;
}
Color LightManager::GetColor(LightId id) const {
return RetrieveLightState(id)._color;
}
float LightManager::GetIntensity(LightId id) const {
return RetrieveLightState(id)._intensity;
}
LightState LightManager::GetLightState(LightId id) const {
return RetrieveLightState(id);
}
LightGroup LightManager::GetLightGroup(LightId id) const {
return RetrieveLightState(id)._group;
}
bool LightManager::IsActive(LightId id) const {
return RetrieveLightState(id)._active;
}
void LightManager::SetActive(LightId id, bool active) {
std::lock_guard<std::mutex> lock(_mutex);
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state._active = active;
_lights_changes[id] = state;
_dirty = true;
}
void LightManager::SetColor(LightId id, Color color) {
std::lock_guard<std::mutex> lock(_mutex);
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state._color = color;
_lights_changes[id] = state;
_dirty = true;
}
void LightManager::SetIntensity(LightId id, float intensity) {
std::lock_guard<std::mutex> lock(_mutex);
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state._intensity = intensity;
_lights_changes[id] = state;
_dirty = true;
}
void LightManager::SetLightState(LightId id, const LightState& new_state) {
std::lock_guard<std::mutex> lock(_mutex);
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state = new_state;
_lights_changes[id] = state;
_dirty = true;
}
void LightManager::SetLightStateNoLock(LightId id, const LightState& new_state) {
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state = new_state;
_lights_changes[id] = state;
}
void LightManager::SetLightGroup(LightId id, LightGroup group) {
std::lock_guard<std::mutex> lock(_mutex);
LightState& state = const_cast<LightState&>(RetrieveLightState(id));
state._group = group;
_lights_changes[id] = state;
_dirty = true;
}
const LightState& LightManager::RetrieveLightState(LightId id) const {
auto it = _lights_state.find(id);
if(it == _lights_state.end()) {
carla::log_warning("Invalid light", id);
return _state;
}
return it->second;
}
void LightManager::QueryLightsStateToServer() {
std::lock_guard<std::mutex> lock(_mutex);
// Send blocking query
std::vector<rpc::LightState> lights_snapshot = _episode.Lock()->QueryLightsStateToServer();
// Update lights
SharedPtr<LightManager> lm = _episode.Lock()->GetLightManager();
for(const auto& it : lights_snapshot) {
_lights_state[it._id] = LightState(
it._intensity,
Color(it._color.r, it._color.g, it._color.b),
static_cast<LightState::LightGroup>(it._group),
it._active
);
if(_lights.find(it._id) == _lights.end())
{
_lights[it._id] = Light(lm, it._location, it._id);
}
}
}
void LightManager::UpdateServerLightsState(bool discard_client) {
std::lock_guard<std::mutex> lock(_mutex);
if(_dirty) {
std::vector<rpc::LightState> message;
for(auto it : _lights_changes) {
auto it_light = _lights.find(it.first);
if(it_light != _lights.end()) {
rpc::LightState state(
it_light->second.GetLocation(),
it.second._intensity,
it.second._group,
rpc::Color(it.second._color.r, it.second._color.g, it.second._color.b),
it.second._active
);
state._id = it.first;
// Add to command
message.push_back(state);
}
}
_episode.Lock()->UpdateServerLightsState(message, discard_client);
_lights_changes.clear();
_dirty = false;
}
}
void LightManager::ApplyChanges() {
std::lock_guard<std::mutex> lock(_mutex);
for(const auto& it : _lights_changes) {
SetLightStateNoLock(it.first, it.second);
}
}
void LightManager::SetDayNightCycle(const bool active) {
_episode.Lock()->UpdateDayNightCycle(active);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,113 @@
// Copyright (c) 2020 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 <mutex>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include "carla/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/client/detail/Episode.h"
#include "carla/client/Light.h"
#include "carla/client/LightState.h"
#include "carla/rpc/LightState.h"
namespace carla {
namespace client {
class LightManager
: public EnableSharedFromThis<LightManager> {
using LightGroup = rpc::LightState::LightGroup;
public:
LightManager() {}
~LightManager();
LightManager(const LightManager& other) : EnableSharedFromThis<LightManager>() {
_lights_state = other._lights_state;
_lights_changes = other._lights_changes;
_lights = other._lights;
_episode = other._episode;
_on_tick_register_id = other._on_tick_register_id;
_on_light_update_register_id = other._on_light_update_register_id;
_dirty = other._dirty;
}
void SetEpisode(detail::WeakEpisodeProxy episode);
std::vector<Light> GetAllLights(LightGroup type = LightGroup::None) const;
// TODO: std::vector<Light> GetAllLightsInRoad(RoadId id, LightGroup type = LightGroup::None);
// TODO: std::vector<Light> GetAllLightsInDistance(Vec3 origin, float distance, LightGroup type = Light::LightType::None);
void TurnOn(std::vector<Light>& lights);
void TurnOff(std::vector<Light>& lights);
void SetActive(std::vector<Light>& lights, std::vector<bool>& active);
std::vector<bool> IsActive(std::vector<Light>& lights) const;
std::vector<Light> GetTurnedOnLights(LightGroup type = LightGroup::None) const;
std::vector<Light> GetTurnedOffLights(LightGroup type = LightGroup::None) const;
void SetColor(std::vector<Light>& lights, Color color);
void SetColor(std::vector<Light>& lights, std::vector<Color>& colors);
std::vector<Color> GetColor(std::vector<Light>& lights) const;
void SetIntensity(std::vector<Light>& lights, float intensity);
void SetIntensity(std::vector<Light>& lights, std::vector<float>& intensities);
std::vector<float> GetIntensity(std::vector<Light>& lights) const;
void SetLightGroup(std::vector<Light>& lights, LightGroup group);
void SetLightGroup(std::vector<Light>& lights, std::vector<LightGroup>& groups);
std::vector<LightGroup> GetLightGroup(std::vector<Light>& lights) const;
void SetLightState(std::vector<Light>& lights, LightState state);
void SetLightState(std::vector<Light>& lights, std::vector<LightState>& states);
std::vector<LightState> GetLightState(std::vector<Light>& lights) const;
Color GetColor(LightId id) const;
float GetIntensity(LightId id) const;
LightState GetLightState(LightId id) const;
LightGroup GetLightGroup(LightId id) const;
bool IsActive(LightId id) const;
void SetActive(LightId id, bool active);
void SetColor(LightId id, Color color);
void SetIntensity(LightId id, float intensity);
void SetLightState(LightId id, const LightState& new_state);
void SetLightStateNoLock(LightId id, const LightState& new_state);
void SetLightGroup(LightId id, LightGroup group);
void SetDayNightCycle(const bool active);
private:
const LightState& RetrieveLightState(LightId id) const;
void QueryLightsStateToServer();
void UpdateServerLightsState(bool discard_client = false);
void ApplyChanges();
std::unordered_map<LightId, LightState> _lights_state;
std::unordered_map<LightId, LightState> _lights_changes;
std::unordered_map<LightId, Light> _lights;
detail::WeakEpisodeProxy _episode;
std::mutex _mutex;
LightState _state;
size_t _on_tick_register_id = 0;
size_t _on_light_update_register_id = 0;
bool _dirty = false;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,50 @@
// Copyright (c) 2020 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/sensor/data/Color.h"
#include "carla/rpc/LightState.h"
namespace carla {
namespace client {
using Color = sensor::data::Color;
using LightId = uint32_t;
struct LightState {
using LightGroup = rpc::LightState::LightGroup;
LightState() {}
LightState(
float intensity,
Color color,
LightGroup group,
bool active)
: _intensity(intensity),
_color(color),
_group(group),
_active(active){}
void Reset () {
_intensity = 0.0f;
_color.r = 0;
_color.g = 0;
_color.b = 0;
_group = LightGroup::None;
_active = false;
}
float _intensity = 0.0f;
Color _color;
LightGroup _group = LightGroup::None;
bool _active = false;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,192 @@
// 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/client/Map.h"
#include "carla/client/Junction.h"
#include "carla/client/Waypoint.h"
#include "carla/opendrive/OpenDriveParser.h"
#include "carla/road/Map.h"
#include "carla/road/RoadTypes.h"
#include "carla/trafficmanager/InMemoryMap.h"
#include <sstream>
namespace carla {
namespace client {
static auto MakeMap(const std::string &opendrive_contents) {
auto stream = std::istringstream(opendrive_contents);
auto map = opendrive::OpenDriveParser::Load(stream.str());
if (!map.has_value()) {
throw_exception(std::runtime_error("failed to generate map"));
}
return std::move(*map);
}
Map::Map(rpc::MapInfo description, std::string xodr_content)
: _description(std::move(description)),
_map(MakeMap(xodr_content)){
open_drive_file = xodr_content;
}
Map::Map(std::string name, std::string xodr_content)
: Map(rpc::MapInfo{
std::move(name),
std::vector<geom::Transform>{}}, xodr_content) {
open_drive_file = xodr_content;
}
Map::~Map() = default;
SharedPtr<Waypoint> Map::GetWaypoint(
const geom::Location &location,
bool project_to_road,
int32_t lane_type) const {
boost::optional<road::element::Waypoint> waypoint;
if (project_to_road) {
waypoint = _map.GetClosestWaypointOnRoad(location, lane_type);
} else {
waypoint = _map.GetWaypoint(location, lane_type);
}
return waypoint.has_value() ?
SharedPtr<Waypoint>(new Waypoint{shared_from_this(), *waypoint}) :
nullptr;
}
SharedPtr<Waypoint> Map::GetWaypointXODR(
carla::road::RoadId road_id,
carla::road::LaneId lane_id,
float s) const {
boost::optional<road::element::Waypoint> waypoint;
waypoint = _map.GetWaypoint(road_id, lane_id, s);
return waypoint.has_value() ?
SharedPtr<Waypoint>(new Waypoint{shared_from_this(), *waypoint}) :
nullptr;
}
Map::TopologyList Map::GetTopology() const {
namespace re = carla::road::element;
std::unordered_map<re::Waypoint, SharedPtr<Waypoint>> waypoints;
auto get_or_make_waypoint = [&](const auto &waypoint) {
auto it = waypoints.find(waypoint);
if (it == waypoints.end()) {
it = waypoints.emplace(
waypoint,
SharedPtr<Waypoint>(new Waypoint{shared_from_this(), waypoint})).first;
}
return it->second;
};
TopologyList result;
auto topology = _map.GenerateTopology();
result.reserve(topology.size());
for (const auto &pair : topology) {
result.emplace_back(
get_or_make_waypoint(pair.first),
get_or_make_waypoint(pair.second));
}
return result;
}
std::vector<SharedPtr<Waypoint>> Map::GenerateWaypoints(double distance) const {
std::vector<SharedPtr<Waypoint>> result;
const auto waypoints = _map.GenerateWaypoints(distance);
result.reserve(waypoints.size());
for (const auto &waypoint : waypoints) {
result.emplace_back(SharedPtr<Waypoint>(new Waypoint{shared_from_this(), waypoint}));
}
return result;
}
std::vector<road::element::LaneMarking> Map::CalculateCrossedLanes(
const geom::Location &origin,
const geom::Location &destination) const {
return _map.CalculateCrossedLanes(origin, destination);
}
const geom::GeoLocation &Map::GetGeoReference() const {
return _map.GetGeoReference();
}
std::vector<geom::Location> Map::GetAllCrosswalkZones() const {
return _map.GetAllCrosswalkZones();
}
SharedPtr<Junction> Map::GetJunction(const Waypoint &waypoint) const {
const road::Junction *juncptr = GetMap().GetJunction(waypoint.GetJunctionId());
auto junction = SharedPtr<Junction>(new Junction(shared_from_this(), juncptr));
return junction;
}
std::vector<std::pair<SharedPtr<Waypoint>, SharedPtr<Waypoint>>> Map::GetJunctionWaypoints(
road::JuncId id,
road::Lane::LaneType lane_type) const {
std::vector<std::pair<SharedPtr<Waypoint>, SharedPtr<Waypoint>>> result;
auto junction_waypoints = GetMap().GetJunctionWaypoints(id, lane_type);
for (auto &waypoint_pair : junction_waypoints) {
result.emplace_back(
std::make_pair(SharedPtr<Waypoint>(new Waypoint(shared_from_this(), waypoint_pair.first)),
SharedPtr<Waypoint>(new Waypoint(shared_from_this(), waypoint_pair.second))));
}
return result;
}
std::vector<SharedPtr<Landmark>> Map::GetAllLandmarks() const {
std::vector<SharedPtr<Landmark>> result;
auto signal_references = _map.GetAllSignalReferences();
for(auto* signal_reference : signal_references) {
result.emplace_back(
new Landmark(nullptr, shared_from_this(), signal_reference, 0));
}
return result;
}
std::vector<SharedPtr<Landmark>> Map::GetLandmarksFromId(std::string id) const {
std::vector<SharedPtr<Landmark>> result;
auto signal_references = _map.GetAllSignalReferences();
for(auto* signal_reference : signal_references) {
if(signal_reference->GetSignalId() == id) {
result.emplace_back(
new Landmark(nullptr, shared_from_this(), signal_reference, 0));
}
}
return result;
}
std::vector<SharedPtr<Landmark>> Map::GetAllLandmarksOfType(std::string type) const {
std::vector<SharedPtr<Landmark>> result;
auto signal_references = _map.GetAllSignalReferences();
for(auto* signal_reference : signal_references) {
if(signal_reference->GetSignal()->GetType() == type) {
result.emplace_back(
new Landmark(nullptr, shared_from_this(), signal_reference, 0));
}
}
return result;
}
std::vector<SharedPtr<Landmark>>
Map::GetLandmarkGroup(const Landmark &landmark) const {
std::vector<SharedPtr<Landmark>> result;
auto &controllers = landmark._signal->GetSignal()->GetControllers();
for (auto& controller_id : controllers) {
const auto &controller = _map.GetControllers().at(controller_id);
for(auto& signal_id : controller->GetSignals()) {
auto& signal = _map.GetSignals().at(signal_id);
auto new_landmarks = GetLandmarksFromId(signal->GetSignalId());
result.insert(result.end(), new_landmarks.begin(), new_landmarks.end());
}
}
return result;
}
void Map::CookInMemoryMap(const std::string& path) const {
traffic_manager::InMemoryMap::Cook(shared_from_this(), path);
}
} // namespace client
} // namespace carla

110
include/carla/client/Map.h Normal file
View File

@ -0,0 +1,110 @@
// 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/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/road/element/LaneMarking.h"
#include "carla/road/Lane.h"
#include "carla/road/Map.h"
#include "carla/road/RoadTypes.h"
#include "carla/rpc/MapInfo.h"
#include "Landmark.h"
#include <string>
namespace carla {
namespace geom { class GeoLocation; }
namespace client {
class Waypoint;
class Junction;
class Map
: public EnableSharedFromThis<Map>,
private NonCopyable {
public:
explicit Map(rpc::MapInfo description, std::string xodr_content);
explicit Map(std::string name, std::string xodr_content);
~Map();
const std::string &GetName() const {
return _description.name;
}
const road::Map &GetMap() const {
return _map;
}
const std::string &GetOpenDrive() const {
return open_drive_file;
}
const std::vector<geom::Transform> &GetRecommendedSpawnPoints() const {
return _description.recommended_spawn_points;
}
SharedPtr<Waypoint> GetWaypoint(
const geom::Location &location,
bool project_to_road = true,
int32_t lane_type = static_cast<uint32_t>(road::Lane::LaneType::Driving)) const;
SharedPtr<Waypoint> GetWaypointXODR(
carla::road::RoadId road_id,
carla::road::LaneId lane_id,
float s) const;
using TopologyList = std::vector<std::pair<SharedPtr<Waypoint>, SharedPtr<Waypoint>>>;
TopologyList GetTopology() const;
std::vector<SharedPtr<Waypoint>> GenerateWaypoints(double distance) const;
std::vector<road::element::LaneMarking> CalculateCrossedLanes(
const geom::Location &origin,
const geom::Location &destination) const;
const geom::GeoLocation &GetGeoReference() const;
std::vector<geom::Location> GetAllCrosswalkZones() const;
SharedPtr<Junction> GetJunction(const Waypoint &waypoint) const;
/// Returns a pair of waypoints (start and end) for each lane in the
/// junction
std::vector<std::pair<SharedPtr<Waypoint>, SharedPtr<Waypoint>>> GetJunctionWaypoints(
road::JuncId id, road::Lane::LaneType type) const;
/// Returns all the larndmarks in the map
std::vector<SharedPtr<Landmark>> GetAllLandmarks() const;
/// Returns all the larndmarks in the map with a specific OpenDRIVE id
std::vector<SharedPtr<Landmark>> GetLandmarksFromId(std::string id) const;
/// Returns all the landmarks in the map of a specific type
std::vector<SharedPtr<Landmark>> GetAllLandmarksOfType(std::string type) const;
/// Returns all the landmarks in the same group including this one
std::vector<SharedPtr<Landmark>> GetLandmarkGroup(const Landmark &landmark) const;
/// Cooks InMemoryMap used by the traffic manager
void CookInMemoryMap(const std::string& path) const;
private:
std::string open_drive_file;
const rpc::MapInfo _description;
const road::Map _map;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,36 @@
// 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/client/Actor.h"
#include <functional>
namespace carla {
namespace sensor { class SensorData; }
namespace client {
class Sensor : public Actor {
public:
using CallbackFunctionType = std::function<void(SharedPtr<sensor::SensorData>)>;
using Actor::Actor;
/// Register a @a callback to be executed each time a new measurement is
/// received.
virtual void Listen(CallbackFunctionType callback) = 0;
/// Stop listening for new measurements.
virtual void Stop() = 0;
/// Return whether this Sensor instance is currently listening to new data.
virtual bool IsListening() const = 0;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,109 @@
// 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/client/ServerSideSensor.h"
#include "carla/Logging.h"
#include "carla/client/detail/Simulator.h"
#include <exception>
constexpr size_t GBufferTextureCount = 13;
namespace carla {
namespace client {
ServerSideSensor::~ServerSideSensor() {
if (IsAlive() && IsListening()) {
log_warning(
"sensor object went out of the scope but the sensor is still alive",
"in the simulation:",
GetDisplayId());
}
if (IsListening() && GetEpisode().IsValid()) {
try {
for (uint32_t i = 1; i != GBufferTextureCount + 1; ++i) {
if (listening_mask.test(i))
StopGBuffer(i - 1);
}
Stop();
} catch (const std::exception &e) {
log_error("exception trying to stop sensor:", GetDisplayId(), ':', e.what());
}
}
}
void ServerSideSensor::Listen(CallbackFunctionType callback) {
log_debug("calling sensor Listen() ", GetDisplayId());
log_debug(GetDisplayId(), ": subscribing to stream");
GetEpisode().Lock()->SubscribeToSensor(*this, std::move(callback));
listening_mask.set(0);
}
void ServerSideSensor::Stop() {
log_debug("calling sensor Stop() ", GetDisplayId());
if (!IsListening()) {
log_warning(
"attempting to unsubscribe from stream but sensor wasn't listening:",
GetDisplayId());
return;
}
GetEpisode().Lock()->UnSubscribeFromSensor(*this);
listening_mask.reset(0);
}
void ServerSideSensor::ListenToGBuffer(uint32_t GBufferId, CallbackFunctionType callback) {
log_debug(GetDisplayId(), ": subscribing to gbuffer stream");
RELEASE_ASSERT(GBufferId < GBufferTextureCount);
if (GetActorDescription().description.id != "sensor.camera.rgb")
{
log_warning("GBuffer methods are not supported on non-RGB sensors (sensor.camera.rgb).");
return;
}
GetEpisode().Lock()->SubscribeToGBuffer(*this, GBufferId, std::move(callback));
listening_mask.set(0);
listening_mask.set(GBufferId + 1);
}
void ServerSideSensor::StopGBuffer(uint32_t GBufferId) {
log_debug(GetDisplayId(), ": unsubscribing from gbuffer stream");
RELEASE_ASSERT(GBufferId < GBufferTextureCount);
if (GetActorDescription().description.id != "sensor.camera.rgb")
{
log_warning("GBuffer methods are not supported on non-RGB sensors (sensor.camera.rgb).");
return;
}
GetEpisode().Lock()->UnSubscribeFromGBuffer(*this, GBufferId);
listening_mask.reset(GBufferId + 1);
}
void ServerSideSensor::EnableForROS() {
GetEpisode().Lock()->EnableForROS(*this);
}
void ServerSideSensor::DisableForROS() {
GetEpisode().Lock()->DisableForROS(*this);
}
bool ServerSideSensor::IsEnabledForROS(){
return GetEpisode().Lock()->IsEnabledForROS(*this);
}
bool ServerSideSensor::Destroy() {
log_debug("calling sensor Destroy() ", GetDisplayId());
if (IsListening()) {
for (uint32_t i = 1; i != GBufferTextureCount + 1; ++i) {
if (listening_mask.test(i)) {
StopGBuffer(i - 1);
}
}
Stop();
}
return Actor::Destroy();
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,70 @@
// 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/client/Sensor.h"
#include <bitset>
namespace carla {
namespace client {
class ServerSideSensor final : public Sensor {
public:
using Sensor::Sensor;
~ServerSideSensor();
/// Register a @a callback to be executed each time a new measurement is
/// received.
///
/// @warning Calling this function on a sensor that is already listening
/// steals the data stream from the previously set callback. Note that
/// several instances of Sensor (even in different processes) may point to
/// the same sensor in the simulator.
void Listen(CallbackFunctionType callback) override;
/// Stop listening for new measurements.
void Stop() override;
/// Return whether this Sensor instance is currently listening to the
/// associated sensor in the simulator.
bool IsListening() const override {
return listening_mask.test(0);
}
/// Listen fr
void ListenToGBuffer(uint32_t GBufferId, CallbackFunctionType callback);
/// Stop listening for a specific gbuffer stream.
void StopGBuffer(uint32_t GBufferId);
inline bool IsListeningGBuffer(uint32_t id) const {
return listening_mask.test(id + 1);
}
/// Enable this sensor for ROS2 publishing
void EnableForROS();
/// Disable this sensor for ROS2 publishing
void DisableForROS();
/// Return if the sensor is publishing for ROS2
bool IsEnabledForROS();
/// @copydoc Actor::Destroy()
///
/// Additionally stop listening.
bool Destroy() override;
private:
std::bitset<16> listening_mask;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,23 @@
// 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/client/TimeoutException.h"
namespace carla {
namespace client {
using namespace std::string_literals;
TimeoutException::TimeoutException(
const std::string &endpoint,
time_duration timeout)
: std::runtime_error(
"time-out of "s + std::to_string(timeout.milliseconds()) +
"ms while waiting for the simulator, "
"make sure the simulator is ready and connected to " + endpoint) {}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,26 @@
// 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/Time.h"
#include <stdexcept>
#include <string>
namespace carla {
namespace client {
class TimeoutException : public std::runtime_error {
public:
explicit TimeoutException(
const std::string &endpoint,
time_duration timeout);
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,72 @@
// 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 <cstdint>
namespace carla {
namespace client {
class Timestamp {
public:
Timestamp() = default;
Timestamp(
std::size_t in_frame,
double in_elapsed_seconds,
double in_delta_seconds,
double in_platform_timestamp)
: frame(in_frame),
elapsed_seconds(in_elapsed_seconds),
delta_seconds(in_delta_seconds),
platform_timestamp(in_platform_timestamp) {}
/// Number of frames elapsed since the simulator was launched.
std::size_t frame = 0u;
/// Simulated seconds elapsed since the beginning of the current episode.
double elapsed_seconds = 0.0;
/// Simulated seconds elapsed since previous frame.
double delta_seconds = 0.0;
/// Time-stamp of the frame at which this measurement was taken, in seconds
/// as given by the OS.
double platform_timestamp = 0.0;
bool operator==(const Timestamp &rhs) const {
return frame == rhs.frame;
}
bool operator!=(const Timestamp &rhs) const {
return !(*this == rhs);
}
};
} // namespace client
} // namespace carla
namespace std {
/**
* \brief standard ostream operator
*
* \param[in/out] out The output stream to write to
* \param[in] timestamp the timestamp to stream out
*
* \returns The stream object.
*
*/
inline std::ostream &operator<<(std::ostream &out, const ::carla::client::Timestamp &timestamp) {
out << "Timestamp(frame=" << std::to_string(timestamp.frame)
<< ",elapsed_seconds=" << std::to_string(timestamp.elapsed_seconds)
<< ",delta_seconds=" << std::to_string(timestamp.delta_seconds)
<< ",platform_timestamp=" << std::to_string(timestamp.platform_timestamp) << ')';
return out;
}
} // namespace std

View File

@ -0,0 +1,140 @@
// 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/client/TrafficLight.h"
#include "carla/client/detail/Simulator.h"
#include "carla/client/ActorList.h"
#include <unordered_map>
#include <unordered_set>
namespace carla {
namespace client {
void TrafficLight::SetState(rpc::TrafficLightState state) {
GetEpisode().Lock()->SetTrafficLightState(*this, state);
}
rpc::TrafficLightState TrafficLight::GetState() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.state;
}
void TrafficLight::SetGreenTime(float green_time) {
GetEpisode().Lock()->SetTrafficLightGreenTime(*this, green_time);
}
float TrafficLight::GetGreenTime() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.green_time;
}
void TrafficLight::SetYellowTime(float yellow_time) {
GetEpisode().Lock()->SetTrafficLightYellowTime(*this, yellow_time);
}
float TrafficLight::GetYellowTime() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.yellow_time;
}
void TrafficLight::SetRedTime(float red_time) {
GetEpisode().Lock()->SetTrafficLightRedTime(*this, red_time);
}
float TrafficLight::GetRedTime() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.red_time;
}
float TrafficLight::GetElapsedTime() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.elapsed_time;
}
void TrafficLight::Freeze(bool freeze) {
//GetEpisode().Lock()->FreezeTrafficLight(*this, freeze);
GetEpisode().Lock()->FreezeAllTrafficLights(freeze);
}
bool TrafficLight::IsFrozen() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.time_is_frozen;
}
uint32_t TrafficLight::GetPoleIndex()
{
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.pole_index;
}
std::vector<SharedPtr<TrafficLight>> TrafficLight::GetGroupTrafficLights() {
std::vector<SharedPtr<TrafficLight>> result;
auto ids = GetEpisode().Lock()->GetGroupTrafficLights(*this);
for (auto id : ids) {
SharedPtr<Actor> actor = GetWorld().GetActors()->Find(id);
result.push_back(boost::static_pointer_cast<TrafficLight>(actor));
}
return result;
}
void TrafficLight::ResetGroup() {
GetEpisode().Lock()->ResetTrafficLightGroup(*this);
}
std::vector<SharedPtr<Waypoint>> TrafficLight::GetAffectedLaneWaypoints() const {
std::vector<SharedPtr<Waypoint>> result;
SharedPtr<Map> carla_map = GetEpisode().Lock()->GetCurrentMap();
std::vector<SharedPtr<Landmark>> landmarks = carla_map->GetLandmarksFromId(GetOpenDRIVEID());
for (auto& landmark : landmarks) {
for (const road::LaneValidity& validity : landmark->GetValidities()) {
if (validity._from_lane < validity._to_lane) {
for (int lane_id = validity._from_lane; lane_id <= validity._to_lane; ++lane_id) {
if(lane_id == 0) continue;
result.emplace_back(
carla_map->GetWaypointXODR(
landmark->GetRoadId(), lane_id, static_cast<float>(landmark->GetS())));
}
} else {
for (int lane_id = validity._from_lane; lane_id >= validity._to_lane; --lane_id) {
if(lane_id == 0) continue;
result.emplace_back(
carla_map->GetWaypointXODR(
landmark->GetRoadId(), lane_id, static_cast<float>(landmark->GetS())));
}
}
}
}
return result;
}
std::vector<geom::BoundingBox> TrafficLight::GetLightBoxes() const {
return GetEpisode().Lock()->GetLightBoxes(*this);
}
road::SignId TrafficLight::GetOpenDRIVEID() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.sign_id;
}
std::vector<SharedPtr<Waypoint>> TrafficLight::GetStopWaypoints() const {
std::vector<SharedPtr<Waypoint>> result;
SharedPtr<Map> carla_map = GetEpisode().Lock()->GetCurrentMap();
geom::BoundingBox box = GetTriggerVolume();
geom::Transform transform = GetTransform();
geom::Location box_position = box.location;
transform.TransformPoint(box_position);
geom::Vector3D right_direction = transform.GetForwardVector();
float min_x = -0.9f*box.extent.x;
float max_x = 0.9f*box.extent.x;
float current_x = min_x;
std::unordered_map<road::RoadId, std::unordered_set<road::LaneId>> road_lanes_map;
while (current_x < max_x) {
geom::Location query_point = box_position + geom::Location(right_direction*current_x);
SharedPtr<Waypoint> waypoint = carla_map->GetWaypoint(query_point);
if (road_lanes_map[waypoint->GetRoadId()].count(waypoint->GetLaneId()) == 0) {
road_lanes_map[waypoint->GetRoadId()].insert(waypoint->GetLaneId());
result.emplace_back(waypoint);
}
current_x += 1.f;
}
return result;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,82 @@
// 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/client/TrafficSign.h"
#include "carla/rpc/TrafficLightState.h"
#include "carla/client/Waypoint.h"
#include "carla/client/Map.h"
#include "carla/geom/BoundingBox.h"
namespace carla {
namespace client {
class TrafficLight : public TrafficSign {
public:
explicit TrafficLight(ActorInitializer init) : TrafficSign(std::move(init)) {}
void SetState(rpc::TrafficLightState state);
/// Return the current state of the traffic light.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
rpc::TrafficLightState GetState() const;
void SetGreenTime(float green_time);
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
float GetGreenTime() const;
void SetYellowTime(float yellow_time);
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
float GetYellowTime() const;
void SetRedTime(float red_time);
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
float GetRedTime() const;
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
float GetElapsedTime() const;
void Freeze(bool freeze);
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
bool IsFrozen() const;
/// Returns the index of the pole in the traffic light group
uint32_t GetPoleIndex();
/// Return all traffic lights in the group this one belongs to.
///
/// @note This function calls the simulator
std::vector<SharedPtr<TrafficLight>> GetGroupTrafficLights();
// resets the timers and states of all groups
void ResetGroup();
std::vector<SharedPtr<Waypoint>> GetAffectedLaneWaypoints() const;
std::vector<geom::BoundingBox> GetLightBoxes() const;
road::SignId GetOpenDRIVEID() const;
std::vector<SharedPtr<Waypoint>> GetStopWaypoints() const;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,19 @@
// 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/client/TrafficSign.h"
#include "carla/client/detail/Simulator.h"
#include "carla/client/ActorList.h"
namespace carla {
namespace client {
carla::road::SignId TrafficSign::GetSignId() const {
return std::string(GetEpisode().Lock()->GetActorSnapshot(*this).state.traffic_light_data.sign_id);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,29 @@
// 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/client/Actor.h"
#include "carla/road/RoadTypes.h"
namespace carla {
namespace client {
class TrafficSign : public Actor {
public:
explicit TrafficSign(ActorInitializer init) : Actor(std::move(init)) {}
const geom::BoundingBox &GetTriggerVolume() const {
return ActorState::GetBoundingBox();
}
carla::road::SignId GetSignId() const;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,152 @@
// Copyright (c) 2019 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/client/Vehicle.h"
#include "carla/client/ActorList.h"
#include "carla/client/detail/Simulator.h"
#include "carla/client/TrafficLight.h"
#include "carla/Memory.h"
#include "carla/rpc/TrafficLightState.h"
#include "carla/trafficmanager/TrafficManager.h"
namespace carla {
using TM = traffic_manager::TrafficManager;
namespace client {
template <typename AttributesT>
static bool GetControlIsSticky(const AttributesT &attributes) {
for (auto &&attribute : attributes) {
if (attribute.GetId() == "sticky_control") {
return attribute.template As<bool>();
}
}
return true;
}
Vehicle::Vehicle(ActorInitializer init)
: Actor(std::move(init)),
_is_control_sticky(GetControlIsSticky(GetAttributes())) {}
void Vehicle::SetAutopilot(bool enabled, uint16_t tm_port) {
TM tm(GetEpisode(), tm_port);
if (enabled) {
tm.RegisterVehicles({shared_from_this()});
} else {
tm.UnregisterVehicles({shared_from_this()});
}
}
void Vehicle::ShowDebugTelemetry(bool enabled) {
GetEpisode().Lock()->ShowVehicleDebugTelemetry(*this, enabled);
}
void Vehicle::ApplyControl(const Control &control) {
if (!_is_control_sticky || (control != _control)) {
GetEpisode().Lock()->ApplyControlToVehicle(*this, control);
_control = control;
}
}
void Vehicle::ApplyAckermannControl(const AckermannControl &control) {
GetEpisode().Lock()->ApplyAckermannControlToVehicle(*this, control);
}
rpc::AckermannControllerSettings Vehicle::GetAckermannControllerSettings() const {
return GetEpisode().Lock()->GetAckermannControllerSettings(*this);
}
void Vehicle::ApplyAckermannControllerSettings(const rpc::AckermannControllerSettings &settings) {
GetEpisode().Lock()->ApplyAckermannControllerSettings(*this, settings);
}
void Vehicle::ApplyPhysicsControl(const PhysicsControl &physics_control) {
GetEpisode().Lock()->ApplyPhysicsControlToVehicle(*this, physics_control);
}
void Vehicle::OpenDoor(const VehicleDoor door_idx) {
GetEpisode().Lock()->OpenVehicleDoor(*this, rpc::VehicleDoor(door_idx));
}
void Vehicle::CloseDoor(const VehicleDoor door_idx) {
GetEpisode().Lock()->CloseVehicleDoor(*this, rpc::VehicleDoor(door_idx));
}
void Vehicle::SetLightState(const LightState &light_state) {
GetEpisode().Lock()->SetLightStateToVehicle(*this, rpc::VehicleLightState(light_state));
}
void Vehicle::SetWheelSteerDirection(WheelLocation wheel_location, float angle_in_deg) {
GetEpisode().Lock()->SetWheelSteerDirection(*this, wheel_location, angle_in_deg);
}
float Vehicle::GetWheelSteerAngle(WheelLocation wheel_location) {
return GetEpisode().Lock()->GetWheelSteerAngle(*this, wheel_location);
}
Vehicle::Control Vehicle::GetControl() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.control;
}
Vehicle::PhysicsControl Vehicle::GetPhysicsControl() const {
return GetEpisode().Lock()->GetVehiclePhysicsControl(*this);
}
Vehicle::LightState Vehicle::GetLightState() const {
return GetEpisode().Lock()->GetVehicleLightState(*this).GetLightStateEnum();
}
float Vehicle::GetSpeedLimit() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.speed_limit;
}
rpc::TrafficLightState Vehicle::GetTrafficLightState() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.traffic_light_state;
}
bool Vehicle::IsAtTrafficLight() {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.has_traffic_light;
}
SharedPtr<TrafficLight> Vehicle::GetTrafficLight() const {
auto id = GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.traffic_light_id;
return boost::static_pointer_cast<TrafficLight>(GetWorld().GetActor(id));
}
void Vehicle::EnableCarSim(std::string simfile_path) {
GetEpisode().Lock()->EnableCarSim(*this, simfile_path);
}
void Vehicle::UseCarSimRoad(bool enabled) {
GetEpisode().Lock()->UseCarSimRoad(*this, enabled);
}
void Vehicle::EnableChronoPhysics(
uint64_t MaxSubsteps,
float MaxSubstepDeltaTime,
std::string VehicleJSON,
std::string PowertrainJSON,
std::string TireJSON,
std::string BaseJSONPath) {
GetEpisode().Lock()->EnableChronoPhysics(*this,
MaxSubsteps,
MaxSubstepDeltaTime,
VehicleJSON,
PowertrainJSON,
TireJSON,
BaseJSONPath);
}
rpc::VehicleFailureState Vehicle::GetFailureState() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.vehicle_data.failure_state;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,151 @@
// Copyright (c) 2019 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/client/Actor.h"
#include "carla/rpc/AckermannControllerSettings.h"
#include "carla/rpc/TrafficLightState.h"
#include "carla/rpc/VehicleAckermannControl.h"
#include "carla/rpc/VehicleControl.h"
#include "carla/rpc/VehicleDoor.h"
#include "carla/rpc/VehicleLightState.h"
#include "carla/rpc/VehiclePhysicsControl.h"
#include "carla/rpc/VehicleWheels.h"
#include "carla/trafficmanager/TrafficManager.h"
using carla::traffic_manager::constants::Networking::TM_DEFAULT_PORT;
namespace carla {
namespace traffic_manager {
class TrafficManager;
}
namespace client {
class TrafficLight;
class Vehicle : public Actor {
public:
using Control = rpc::VehicleControl;
using AckermannControl = rpc::VehicleAckermannControl;
using PhysicsControl = rpc::VehiclePhysicsControl;
using LightState = rpc::VehicleLightState::LightState;
using TM = traffic_manager::TrafficManager;
using VehicleDoor = rpc::VehicleDoor;
using WheelLocation = carla::rpc::VehicleWheelLocation;
explicit Vehicle(ActorInitializer init);
/// Switch on/off this vehicle's autopilot.
void SetAutopilot(bool enabled = true, uint16_t tm_port = TM_DEFAULT_PORT);
/// Switch on/off this vehicle's autopilot.
void ShowDebugTelemetry(bool enabled = true);
/// Apply @a control to this vehicle.
void ApplyControl(const Control &control);
/// Apply @a control to this vehicle.
void ApplyAckermannControl(const AckermannControl &control);
/// Return the last Ackermann controller settings applied to this vehicle.
///
/// @warning This function does call the simulator.
rpc::AckermannControllerSettings GetAckermannControllerSettings() const;
/// Apply Ackermann control settings to this vehicle
void ApplyAckermannControllerSettings(const rpc::AckermannControllerSettings &settings);
/// Apply physics control to this vehicle.
void ApplyPhysicsControl(const PhysicsControl &physics_control);
/// Open a door in this vehicle
void OpenDoor(const VehicleDoor door_idx);
/// Close a door in this vehicle
void CloseDoor(const VehicleDoor door_idx);
/// Sets a @a LightState to this vehicle.
void SetLightState(const LightState &light_state);
/// Sets a @a Rotation to a wheel of the vehicle (affects the bone of the car skeleton, not the physics)
void SetWheelSteerDirection(WheelLocation wheel_location, float angle_in_deg);
/// Return a @a Rotation from a wheel of the vehicle
///
/// @note The function returns the rotation of the vehicle based on the it's physics
float GetWheelSteerAngle(WheelLocation wheel_location);
/// Return the control last applied to this vehicle.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
Control GetControl() const;
/// Return the physics control last applied to this vehicle.
///
/// @warning This function does call the simulator.
PhysicsControl GetPhysicsControl() const;
/// Return the current open lights (LightState) of this vehicle.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
LightState GetLightState() const;
/// Return the speed limit currently affecting this vehicle.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
float GetSpeedLimit() const;
/// Return the state of the traffic light currently affecting this vehicle.
///
/// @return Green If no traffic light is affecting the vehicle.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
rpc::TrafficLightState GetTrafficLightState() const;
/// Return whether a traffic light is affecting this vehicle.
///
/// @note This function does not call the simulator, it returns the data
/// received in the last tick.
bool IsAtTrafficLight();
/// Retrieve the traffic light actor currently affecting this vehicle.
SharedPtr<TrafficLight> GetTrafficLight() const;
/// Enables CarSim simulation if it is availiable
void EnableCarSim(std::string simfile_path);
/// Enables the use of CarSim internal road definition instead of unreal's
void UseCarSimRoad(bool enabled);
void EnableChronoPhysics(
uint64_t MaxSubsteps,
float MaxSubstepDeltaTime,
std::string VehicleJSON = "",
std::string PowertrainJSON = "",
std::string TireJSON = "",
std::string BaseJSONPath = "");
/// Returns the failure state of the vehicle
rpc::VehicleFailureState GetFailureState() const;
private:
const bool _is_control_sticky;
Control _control;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,42 @@
// 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/client/Walker.h"
#include "carla/client/detail/Simulator.h"
namespace carla {
namespace client {
void Walker::ApplyControl(const Control &control) {
if (control != _control) {
GetEpisode().Lock()->ApplyControlToWalker(*this, control);
_control = control;
}
}
Walker::Control Walker::GetWalkerControl() const {
return GetEpisode().Lock()->GetActorSnapshot(*this).state.walker_control;
}
Walker::BoneControlOut Walker::GetBonesTransform() {
return GetEpisode().Lock()->GetBonesTransform(*this);
}
void Walker::SetBonesTransform(const Walker::BoneControlIn &bones) {
return GetEpisode().Lock()->SetBonesTransform(*this, bones);
}
void Walker::BlendPose(float blend) {
return GetEpisode().Lock()->BlendPose(*this, blend);
}
void Walker::GetPoseFromAnimation() {
return GetEpisode().Lock()->GetPoseFromAnimation(*this);
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,48 @@
// 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/client/Actor.h"
#include "carla/rpc/WalkerControl.h"
#include "carla/rpc/WalkerBoneControlIn.h"
#include "carla/rpc/WalkerBoneControlOut.h"
namespace carla {
namespace client {
class Walker : public Actor {
public:
using Control = rpc::WalkerControl;
using BoneControlIn = rpc::WalkerBoneControlIn;
using BoneControlOut = rpc::WalkerBoneControlOut;
explicit Walker(ActorInitializer init) : Actor(std::move(init)) {}
/// Apply @a control to this Walker.
void ApplyControl(const Control &control);
/// Return the control last applied to this Walker.
///
/// @note This function does not call the simulator, it returns the Control
/// received in the last tick.
Control GetWalkerControl() const;
BoneControlOut GetBonesTransform();
void SetBonesTransform(const BoneControlIn &bones);
void BlendPose(float blend);
void ShowPose() { BlendPose(1.0f); };
void HidePose() { BlendPose(0.0f); };
void GetPoseFromAnimation();
private:
Control _control;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,84 @@
// Copyright (c) 2019 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/client/WalkerAIController.h"
#include "carla/client/detail/Simulator.h"
#include "carla/client/detail/WalkerNavigation.h"
namespace carla {
namespace client {
WalkerAIController::WalkerAIController(ActorInitializer init)
: Actor(std::move(init)) {}
void WalkerAIController::Start() {
GetEpisode().Lock()->RegisterAIController(*this);
// add the walker in the Recast & Detour
auto walker = GetParent();
if (walker != nullptr) {
auto nav = GetEpisode().Lock()->GetNavigation();
if (nav != nullptr) {
nav->AddWalker(walker->GetId(), walker->GetLocation());
// disable physics and collision of walker actor
GetEpisode().Lock()->SetActorSimulatePhysics(*walker, false);
GetEpisode().Lock()->SetActorCollisions(*walker, false);
}
}
}
void WalkerAIController::Stop() {
GetEpisode().Lock()->UnregisterAIController(*this);
// remove the walker from the Recast & Detour
auto walker = GetParent();
if (walker != nullptr) {
auto nav = GetEpisode().Lock()->GetNavigation();
if (nav != nullptr) {
nav->RemoveWalker(walker->GetId());
}
}
}
boost::optional<geom::Location> WalkerAIController::GetRandomLocation() {
auto nav = GetEpisode().Lock()->GetNavigation();
if (nav != nullptr) {
return nav->GetRandomLocation();
}
return {};
}
void WalkerAIController::GoToLocation(const carla::geom::Location &destination) {
auto nav = GetEpisode().Lock()->GetNavigation();
if (nav != nullptr) {
auto walker = GetParent();
if (walker != nullptr) {
if (!nav->SetWalkerTarget(walker->GetId(), destination)) {
log_warning("NAV: Failed to set request to go to ", destination.x, destination.y, destination.z);
}
} else {
log_warning("NAV: Failed to set request to go to ", destination.x, destination.y, destination.z, "(parent does not exist)");
}
}
}
void WalkerAIController::SetMaxSpeed(const float max_speed) {
auto nav = GetEpisode().Lock()->GetNavigation();
if (nav != nullptr) {
auto walker = GetParent();
if (walker != nullptr) {
if (!nav->SetWalkerMaxSpeed(walker->GetId(), max_speed)) {
log_warning("NAV: failed to set max speed");
}
} else {
log_warning("NAV: failed to set max speed (parent does not exist)");
}
}
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,34 @@
// Copyright (c) 2019 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/client/Actor.h"
#include "carla/geom/Vector3D.h"
#include <boost/optional.hpp>
namespace carla {
namespace client {
class WalkerAIController : public Actor {
public:
explicit WalkerAIController(ActorInitializer init);
void Start();
void Stop();
boost::optional<geom::Location> GetRandomLocation();
void GoToLocation(const carla::geom::Location &destination);
void SetMaxSpeed(const float max_speed);
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,256 @@
// 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/client/Waypoint.h"
#include "carla/client/Map.h"
#include "carla/client/Junction.h"
#include "carla/client/Landmark.h"
#include <unordered_set>
namespace carla {
namespace client {
Waypoint::Waypoint(SharedPtr<const Map> parent, road::element::Waypoint waypoint)
: _parent(std::move(parent)),
_waypoint(std::move(waypoint)),
_transform(_parent->GetMap().ComputeTransform(_waypoint)),
_mark_record(_parent->GetMap().GetMarkRecord(_waypoint)) {}
Waypoint::~Waypoint() = default;
road::JuncId Waypoint::GetJunctionId() const {
return _parent->GetMap().GetJunctionId(_waypoint.road_id);
}
bool Waypoint::IsJunction() const {
return _parent->GetMap().IsJunction(_waypoint.road_id);
}
SharedPtr<Junction> Waypoint::GetJunction() const {
if (IsJunction()) {
return _parent->GetJunction(*this);
}
return nullptr;
}
double Waypoint::GetLaneWidth() const {
return _parent->GetMap().GetLaneWidth(_waypoint);
}
road::Lane::LaneType Waypoint::GetType() const {
return _parent->GetMap().GetLaneType(_waypoint);
}
std::vector<SharedPtr<Waypoint>> Waypoint::GetNext(double distance) const {
auto waypoints = _parent->GetMap().GetNext(_waypoint, distance);
std::vector<SharedPtr<Waypoint>> result;
result.reserve(waypoints.size());
for (auto &waypoint : waypoints) {
result.emplace_back(SharedPtr<Waypoint>(new Waypoint(_parent, std::move(waypoint))));
}
return result;
}
std::vector<SharedPtr<Waypoint>> Waypoint::GetPrevious(double distance) const {
auto waypoints = _parent->GetMap().GetPrevious(_waypoint, distance);
std::vector<SharedPtr<Waypoint>> result;
result.reserve(waypoints.size());
for (auto &waypoint : waypoints) {
result.emplace_back(SharedPtr<Waypoint>(new Waypoint(_parent, std::move(waypoint))));
}
return result;
}
std::vector<SharedPtr<Waypoint>> Waypoint::GetNextUntilLaneEnd(double distance) const {
std::vector<SharedPtr<Waypoint>> result;
std::vector<SharedPtr<Waypoint>> next = GetNext(distance);
while (next.size() == 1 && next.front()->GetRoadId() == GetRoadId()) {
result.emplace_back(next.front());
next = result.back()->GetNext(distance);
}
double current_s = GetDistance();
if(result.size()) {
current_s = result.back()->GetDistance();
}
double remaining_length;
double road_length = _parent->GetMap().GetLane(_waypoint).GetRoad()->GetLength();
if(_waypoint.lane_id < 0) {
remaining_length = road_length - current_s;
} else {
remaining_length = current_s;
}
remaining_length -= std::numeric_limits<double>::epsilon();
if(result.size()) {
result.emplace_back(result.back()->GetNext(remaining_length).front());
} else {
result.emplace_back(GetNext(remaining_length).front());
}
return result;
}
std::vector<SharedPtr<Waypoint>> Waypoint::GetPreviousUntilLaneStart(double distance) const {
std::vector<SharedPtr<Waypoint>> result;
std::vector<SharedPtr<Waypoint>> prev = GetPrevious(distance);
while (prev.size() == 1 && prev.front()->GetRoadId() == GetRoadId()) {
result.emplace_back(prev.front());
prev = result.back()->GetPrevious(distance);
}
double current_s = GetDistance();
if(result.size()) {
current_s = result.back()->GetDistance();
}
double remaining_length;
double road_length = _parent->GetMap().GetLane(_waypoint).GetRoad()->GetLength();
if(_waypoint.lane_id < 0) {
remaining_length = road_length - current_s;
} else {
remaining_length = current_s;
}
remaining_length -= std::numeric_limits<double>::epsilon();
if(result.size()) {
result.emplace_back(result.back()->GetPrevious(remaining_length).front());
} else {
result.emplace_back(GetPrevious(remaining_length).front());
}
return result;
}
SharedPtr<Waypoint> Waypoint::GetRight() const {
auto right_lane_waypoint =
_parent->GetMap().GetRight(_waypoint);
if (right_lane_waypoint.has_value()) {
return SharedPtr<Waypoint>(new Waypoint(_parent, std::move(*right_lane_waypoint)));
}
return nullptr;
}
SharedPtr<Waypoint> Waypoint::GetLeft() const {
auto left_lane_waypoint =
_parent->GetMap().GetLeft(_waypoint);
if (left_lane_waypoint.has_value()) {
return SharedPtr<Waypoint>(new Waypoint(_parent, std::move(*left_lane_waypoint)));
}
return nullptr;
}
boost::optional<road::element::LaneMarking> Waypoint::GetRightLaneMarking() const {
if (_mark_record.first != nullptr) {
return road::element::LaneMarking(*_mark_record.first);
}
return boost::optional<road::element::LaneMarking>{};
}
boost::optional<road::element::LaneMarking> Waypoint::GetLeftLaneMarking() const {
if (_mark_record.second != nullptr) {
return road::element::LaneMarking(*_mark_record.second);
}
return boost::optional<road::element::LaneMarking>{};
}
template <typename EnumT>
static EnumT operator&(EnumT lhs, EnumT rhs) {
return static_cast<EnumT>(
static_cast<typename std::underlying_type<EnumT>::type>(lhs) &
static_cast<typename std::underlying_type<EnumT>::type>(rhs));
}
template <typename EnumT>
static EnumT operator|(EnumT lhs, EnumT rhs) {
return static_cast<EnumT>(
static_cast<typename std::underlying_type<EnumT>::type>(lhs) |
static_cast<typename std::underlying_type<EnumT>::type>(rhs));
}
road::element::LaneMarking::LaneChange Waypoint::GetLaneChange() const {
using lane_change_type = road::element::LaneMarking::LaneChange;
const auto lane_change_right_info = _mark_record.first;
lane_change_type c_right;
if (lane_change_right_info != nullptr) {
const auto lane_change_right = lane_change_right_info->GetLaneChange();
c_right = static_cast<lane_change_type>(lane_change_right);
} else {
c_right = lane_change_type::Both;
}
const auto lane_change_left_info = _mark_record.second;
lane_change_type c_left;
if (lane_change_left_info != nullptr) {
const auto lane_change_left = lane_change_left_info->GetLaneChange();
c_left = static_cast<lane_change_type>(lane_change_left);
} else {
c_left = lane_change_type::Both;
}
if (_waypoint.lane_id > 0) {
// if road goes backward
if (c_right == lane_change_type::Right) {
c_right = lane_change_type::Left;
} else if (c_right == lane_change_type::Left) {
c_right = lane_change_type::Right;
}
}
if (((_waypoint.lane_id > 0) ? _waypoint.lane_id - 1 : _waypoint.lane_id + 1) > 0) {
// if road goes backward
if (c_left == lane_change_type::Right) {
c_left = lane_change_type::Left;
} else if (c_left == lane_change_type::Left) {
c_left = lane_change_type::Right;
}
}
return (c_right & lane_change_type::Right) | (c_left & lane_change_type::Left);
}
std::vector<SharedPtr<Landmark>> Waypoint::GetAllLandmarksInDistance(
double distance, bool stop_at_junction) const {
std::vector<SharedPtr<Landmark>> result;
auto signals = _parent->GetMap().GetSignalsInDistance(
_waypoint, distance, stop_at_junction);
std::unordered_set<const road::element::RoadInfoSignal*> added_signals; // check for repeated signals
for(auto &signal_data : signals){
if(added_signals.count(signal_data.signal) > 0) {
continue;
}
added_signals.insert(signal_data.signal);
auto waypoint = SharedPtr<Waypoint>(new Waypoint(_parent, signal_data.waypoint));
result.emplace_back(
new Landmark(waypoint, _parent, signal_data.signal, signal_data.accumulated_s));
}
return result;
}
std::vector<SharedPtr<Landmark>> Waypoint::GetLandmarksOfTypeInDistance(
double distance, std::string filter_type, bool stop_at_junction) const {
std::vector<SharedPtr<Landmark>> result;
std::unordered_set<const road::element::RoadInfoSignal*> added_signals; // check for repeated signals
auto signals = _parent->GetMap().GetSignalsInDistance(
_waypoint, distance, stop_at_junction);
for(auto &signal_data : signals){
if(signal_data.signal->GetSignal()->GetType() == filter_type) {
if(added_signals.count(signal_data.signal) > 0) {
continue;
}
auto waypoint = SharedPtr<Waypoint>(new Waypoint(_parent, signal_data.waypoint));
result.emplace_back(
new Landmark(waypoint, _parent, signal_data.signal, signal_data.accumulated_s));
}
}
return result;
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,122 @@
// 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/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/geom/Transform.h"
#include "carla/road/element/LaneMarking.h"
#include "carla/road/element/RoadInfoMarkRecord.h"
#include "carla/road/element/Waypoint.h"
#include "carla/road/Lane.h"
#include "carla/road/RoadTypes.h"
#include <boost/optional.hpp>
namespace carla {
namespace client {
class Map;
class Junction;
class Landmark;
class Waypoint
: public EnableSharedFromThis<Waypoint>,
private NonCopyable {
public:
~Waypoint();
/// Returns an unique Id identifying this waypoint.
///
/// The Id takes into account OpenDrive's road Id, lane Id, and s distance
/// on its road segment up to half-centimetre precision.
uint64_t GetId() const {
return std::hash<road::element::Waypoint>()(_waypoint);
}
auto GetRoadId() const {
return _waypoint.road_id;
}
auto GetSectionId() const {
return _waypoint.section_id;
}
auto GetLaneId() const {
return _waypoint.lane_id;
}
auto GetDistance() const {
return _waypoint.s;
}
const geom::Transform &GetTransform() const {
return _transform;
}
road::JuncId GetJunctionId() const;
bool IsJunction() const;
SharedPtr<Junction> GetJunction() const;
double GetLaneWidth() const;
road::Lane::LaneType GetType() const;
std::vector<SharedPtr<Waypoint>> GetNext(double distance) const;
std::vector<SharedPtr<Waypoint>> GetPrevious(double distance) const;
/// Returns a list of waypoints separated by distance from the current waypoint
/// to the end of the lane
std::vector<SharedPtr<Waypoint>> GetNextUntilLaneEnd(double distance) const;
/// Returns a list of waypoints separated by distance from the current waypoint
/// to the start of the lane
std::vector<SharedPtr<Waypoint>> GetPreviousUntilLaneStart(double distance) const;
SharedPtr<Waypoint> GetRight() const;
SharedPtr<Waypoint> GetLeft() const;
boost::optional<road::element::LaneMarking> GetRightLaneMarking() const;
boost::optional<road::element::LaneMarking> GetLeftLaneMarking() const;
road::element::LaneMarking::LaneChange GetLaneChange() const;
/// Returns a list of landmarks from the current position to a certain distance
std::vector<SharedPtr<Landmark>> GetAllLandmarksInDistance(
double distance, bool stop_at_junction = false) const;
/// Returns a list of landmarks from the current position to a certain distance
/// Filters by specified type
std::vector<SharedPtr<Landmark>> GetLandmarksOfTypeInDistance(
double distance, std::string filter_type, bool stop_at_junction = false) const;
private:
friend class Map;
Waypoint(SharedPtr<const Map> parent, road::element::Waypoint waypoint);
SharedPtr<const Map> _parent;
road::element::Waypoint _waypoint;
geom::Transform _transform;
// Mark record right and left respectively.
std::pair<
const road::element::RoadInfoMarkRecord *,
const road::element::RoadInfoMarkRecord *> _mark_record;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,387 @@
// 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/client/World.h"
#include "carla/Logging.h"
#include "carla/client/Actor.h"
#include "carla/client/ActorBlueprint.h"
#include "carla/client/ActorList.h"
#include "carla/client/detail/Simulator.h"
#include "carla/StringUtil.h"
#include "carla/road/SignalType.h"
#include "carla/road/Junction.h"
#include "carla/client/TrafficLight.h"
#include <exception>
namespace carla {
namespace client {
SharedPtr<Map> World::GetMap() const {
return _episode.Lock()->GetCurrentMap();
}
void World::LoadLevelLayer(rpc::MapLayer map_layers) const {
_episode.Lock()->LoadLevelLayer(map_layers);
}
void World::UnloadLevelLayer(rpc::MapLayer map_layers) const {
_episode.Lock()->UnloadLevelLayer(map_layers);
}
SharedPtr<BlueprintLibrary> World::GetBlueprintLibrary() const {
return _episode.Lock()->GetBlueprintLibrary();
}
rpc::VehicleLightStateList World::GetVehiclesLightStates() const {
return _episode.Lock()->GetVehiclesLightStates();
}
boost::optional<geom::Location> World::GetRandomLocationFromNavigation() const {
return _episode.Lock()->GetRandomLocationFromNavigation();
}
SharedPtr<Actor> World::GetSpectator() const {
return _episode.Lock()->GetSpectator();
}
rpc::EpisodeSettings World::GetSettings() const {
return _episode.Lock()->GetEpisodeSettings();
}
uint64_t World::ApplySettings(const rpc::EpisodeSettings &settings, time_duration timeout) {
rpc::EpisodeSettings new_settings = settings;
uint64_t id = _episode.Lock()->SetEpisodeSettings(settings);
time_duration local_timeout = timeout.milliseconds() == 0 ?
_episode.Lock()->GetNetworkingTimeout() : timeout;
if (settings.fixed_delta_seconds.has_value()) {
using namespace std::literals::chrono_literals;
const auto number_of_attemps = 30u;
uint64_t tics_correct = 0;
for (auto i = 0u; i < number_of_attemps; i++) {
const auto curr_snapshot = GetSnapshot();
const double error = abs(new_settings.fixed_delta_seconds.get() - curr_snapshot.GetTimestamp().delta_seconds);
if (error < std::numeric_limits<float>::epsilon())
tics_correct++;
if (tics_correct >= 2)
return id;
Tick(local_timeout);
}
log_warning("World::ApplySettings: After", number_of_attemps, " attemps, the settings were not correctly set. Please check that everything is consistent.");
}
return id;
}
rpc::WeatherParameters World::GetWeather() const {
return _episode.Lock()->GetWeatherParameters();
}
void World::SetWeather(const rpc::WeatherParameters &weather) {
_episode.Lock()->SetWeatherParameters(weather);
}
WorldSnapshot World::GetSnapshot() const {
return _episode.Lock()->GetWorldSnapshot();
}
SharedPtr<Actor> World::GetActor(ActorId id) const {
auto simulator = _episode.Lock();
auto description = simulator->GetActorById(id);
return description.has_value() ?
simulator->MakeActor(std::move(*description)) :
nullptr;
}
SharedPtr<ActorList> World::GetActors() const {
return SharedPtr<ActorList>{new ActorList{
_episode,
_episode.Lock()->GetAllTheActorsInTheEpisode()}};
}
SharedPtr<ActorList> World::GetActors(const std::vector<ActorId> &actor_ids) const {
return SharedPtr<ActorList>{new ActorList{
_episode,
_episode.Lock()->GetActorsById(actor_ids)}};
}
SharedPtr<Actor> World::SpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent_actor,
rpc::AttachmentType attachment_type) {
return _episode.Lock()->SpawnActor(blueprint, transform, parent_actor, attachment_type);
}
SharedPtr<Actor> World::TrySpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent_actor,
rpc::AttachmentType attachment_type) noexcept {
try {
return SpawnActor(blueprint, transform, parent_actor, attachment_type);
} catch (const std::exception &) {
return nullptr;
}
}
WorldSnapshot World::WaitForTick(time_duration timeout) const {
time_duration local_timeout = timeout.milliseconds() == 0 ?
_episode.Lock()->GetNetworkingTimeout() : timeout;
return _episode.Lock()->WaitForTick(local_timeout);
}
size_t World::OnTick(std::function<void(WorldSnapshot)> callback) {
return _episode.Lock()->RegisterOnTickEvent(std::move(callback));
}
void World::RemoveOnTick(size_t callback_id) {
_episode.Lock()->RemoveOnTickEvent(callback_id);
}
uint64_t World::Tick(time_duration timeout) {
time_duration local_timeout = timeout.milliseconds() == 0 ?
_episode.Lock()->GetNetworkingTimeout() : timeout;
return _episode.Lock()->Tick(local_timeout);
}
void World::SetPedestriansCrossFactor(float percentage) {
_episode.Lock()->SetPedestriansCrossFactor(percentage);
}
void World::SetPedestriansSeed(unsigned int seed) {
_episode.Lock()->SetPedestriansSeed(seed);
}
SharedPtr<Actor> World::GetTrafficSign(const Landmark& landmark) const {
SharedPtr<ActorList> actors = GetActors();
SharedPtr<TrafficSign> result;
std::string landmark_id = landmark.GetId();
for (size_t i = 0; i < actors->size(); i++) {
SharedPtr<Actor> actor = actors->at(i);
if (StringUtil::Match(actor->GetTypeId(), "*traffic.*")) {
TrafficSign* sign = static_cast<TrafficSign*>(actor.get());
if(sign && (sign->GetSignId() == landmark_id)) {
return actor;
}
}
}
return nullptr;
}
SharedPtr<Actor> World::GetTrafficLight(const Landmark& landmark) const {
SharedPtr<ActorList> actors = GetActors();
SharedPtr<TrafficLight> result;
std::string landmark_id = landmark.GetId();
for (size_t i = 0; i < actors->size(); i++) {
SharedPtr<Actor> actor = actors->at(i);
if (StringUtil::Match(actor->GetTypeId(), "*traffic_light*")) {
TrafficLight* tl = static_cast<TrafficLight*>(actor.get());
if(tl && (tl->GetSignId() == landmark_id)) {
return actor;
}
}
}
return nullptr;
}
SharedPtr<Actor> World::GetTrafficLightFromOpenDRIVE(const road::SignId& sign_id) const {
SharedPtr<ActorList> actors = GetActors();
SharedPtr<TrafficLight> result;
for (size_t i = 0; i < actors->size(); i++) {
SharedPtr<Actor> actor = actors->at(i);
if (StringUtil::Match(actor->GetTypeId(), "*traffic_light*")) {
TrafficLight* tl = static_cast<TrafficLight*>(actor.get());
if(tl && (tl->GetSignId() == sign_id)) {
return actor;
}
}
}
return nullptr;
}
void World::ResetAllTrafficLights() {
_episode.Lock()->ResetAllTrafficLights();
}
SharedPtr<LightManager> World::GetLightManager() const {
return _episode.Lock()->GetLightManager();
}
void World::FreezeAllTrafficLights(bool frozen) {
_episode.Lock()->FreezeAllTrafficLights(frozen);
}
std::vector<geom::BoundingBox> World::GetLevelBBs(uint8_t queried_tag) const {
return _episode.Lock()->GetLevelBBs(queried_tag);
}
std::vector<rpc::EnvironmentObject> World::GetEnvironmentObjects(uint8_t queried_tag) const {
return _episode.Lock()->GetEnvironmentObjects(queried_tag);
}
void World::EnableEnvironmentObjects(
std::vector<uint64_t> env_objects_ids,
bool enable) const {
_episode.Lock()->EnableEnvironmentObjects(env_objects_ids, enable);
}
boost::optional<rpc::LabelledPoint> World::ProjectPoint(
geom::Location location, geom::Vector3D direction, float search_distance) const {
auto result = _episode.Lock()->ProjectPoint(location, direction, search_distance);
if (result.first) {
return result.second;
}
return {};
}
boost::optional<rpc::LabelledPoint> World::GroundProjection(
geom::Location location, float search_distance) const {
const geom::Vector3D DownVector(0,0,-1);
return ProjectPoint(location, DownVector, search_distance);
}
std::vector<rpc::LabelledPoint> World::CastRay(
geom::Location start_location, geom::Location end_location) const {
return _episode.Lock()->CastRay(start_location, end_location);
}
std::vector<SharedPtr<Actor>> World::GetTrafficLightsFromWaypoint(
const Waypoint& waypoint, double distance) const {
std::vector<SharedPtr<Actor>> Result;
std::vector<SharedPtr<Landmark>> landmarks =
waypoint.GetAllLandmarksInDistance(distance);
std::set<std::string> added_signals;
for (auto& landmark : landmarks) {
if (road::SignalType::IsTrafficLight(landmark->GetType())) {
SharedPtr<Actor> traffic_light = GetTrafficLight(*(landmark.get()));
if (traffic_light) {
if(added_signals.count(landmark->GetId()) == 0) {
Result.emplace_back(traffic_light);
added_signals.insert(landmark->GetId());
}
}
}
}
return Result;
}
std::vector<SharedPtr<Actor>> World::GetTrafficLightsInJunction(
const road::JuncId junc_id) const {
std::vector<SharedPtr<Actor>> Result;
SharedPtr<Map> map = GetMap();
const road::Junction* junction = map->GetMap().GetJunction(junc_id);
for (const road::ContId& cont_id : junction->GetControllers()) {
const std::unique_ptr<road::Controller>& controller =
map->GetMap().GetControllers().at(cont_id);
for (road::SignId sign_id : controller->GetSignals()) {
SharedPtr<Actor> traffic_light = GetTrafficLightFromOpenDRIVE(sign_id);
if (traffic_light) {
Result.emplace_back(traffic_light);
}
}
}
return Result;
}
void World::ApplyColorTextureToObject(
const std::string &object_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture) {
_episode.Lock()->ApplyColorTextureToObjects({object_name}, parameter, Texture);
}
void World::ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture) {
_episode.Lock()->ApplyColorTextureToObjects(objects_name, parameter, Texture);
}
void World::ApplyFloatColorTextureToObject(
const std::string &object_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture) {
_episode.Lock()->ApplyColorTextureToObjects({object_name}, parameter, Texture);
}
void World::ApplyFloatColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture) {
_episode.Lock()->ApplyColorTextureToObjects(objects_name, parameter, Texture);
}
std::vector<std::string> World::GetNamesOfAllObjects() const {
return _episode.Lock()->GetNamesOfAllObjects();
}
void World::ApplyTexturesToObject(
const std::string &object_name,
const rpc::TextureColor& diffuse_texture,
const rpc::TextureFloatColor& emissive_texture,
const rpc::TextureFloatColor& normal_texture,
const rpc::TextureFloatColor& ao_roughness_metallic_emissive_texture)
{
if (diffuse_texture.GetWidth() && diffuse_texture.GetHeight()) {
ApplyColorTextureToObject(
object_name, rpc::MaterialParameter::Tex_Diffuse, diffuse_texture);
}
if (normal_texture.GetWidth() && normal_texture.GetHeight()) {
ApplyFloatColorTextureToObject(
object_name, rpc::MaterialParameter::Tex_Normal, normal_texture);
}
if (ao_roughness_metallic_emissive_texture.GetWidth() &&
ao_roughness_metallic_emissive_texture.GetHeight()) {
ApplyFloatColorTextureToObject(
object_name,
rpc::MaterialParameter::Tex_Ao_Roughness_Metallic_Emissive,
ao_roughness_metallic_emissive_texture);
}
if (emissive_texture.GetWidth() && emissive_texture.GetHeight()) {
ApplyFloatColorTextureToObject(
object_name, rpc::MaterialParameter::Tex_Emissive, emissive_texture);
}
}
void World::ApplyTexturesToObjects(
const std::vector<std::string> &objects_names,
const rpc::TextureColor& diffuse_texture,
const rpc::TextureFloatColor& emissive_texture,
const rpc::TextureFloatColor& normal_texture,
const rpc::TextureFloatColor& ao_roughness_metallic_emissive_texture)
{
if (diffuse_texture.GetWidth() && diffuse_texture.GetHeight()) {
ApplyColorTextureToObjects(
objects_names, rpc::MaterialParameter::Tex_Diffuse, diffuse_texture);
}
if (normal_texture.GetWidth() && normal_texture.GetHeight()) {
ApplyFloatColorTextureToObjects(
objects_names, rpc::MaterialParameter::Tex_Normal, normal_texture);
}
if (ao_roughness_metallic_emissive_texture.GetWidth() &&
ao_roughness_metallic_emissive_texture.GetHeight()) {
ApplyFloatColorTextureToObjects(
objects_names,
rpc::MaterialParameter::Tex_Ao_Roughness_Metallic_Emissive,
ao_roughness_metallic_emissive_texture);
}
if (emissive_texture.GetWidth() && emissive_texture.GetHeight()) {
ApplyFloatColorTextureToObjects(
objects_names, rpc::MaterialParameter::Tex_Emissive, emissive_texture);
}
}
} // namespace client
} // namespace carla

View File

@ -0,0 +1,239 @@
// 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/Memory.h"
#include "carla/Time.h"
#include "carla/client/DebugHelper.h"
#include "carla/client/Landmark.h"
#include "carla/client/Waypoint.h"
#include "carla/client/Junction.h"
#include "carla/client/LightManager.h"
#include "carla/client/Timestamp.h"
#include "carla/client/WorldSnapshot.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/geom/Transform.h"
#include "carla/rpc/Actor.h"
#include "carla/rpc/AttachmentType.h"
#include "carla/rpc/EpisodeSettings.h"
#include "carla/rpc/EnvironmentObject.h"
#include "carla/rpc/LabelledPoint.h"
#include "carla/rpc/MapLayer.h"
#include "carla/rpc/VehiclePhysicsControl.h"
#include "carla/rpc/WeatherParameters.h"
#include "carla/rpc/VehicleLightStateList.h"
#include "carla/rpc/Texture.h"
#include "carla/rpc/MaterialParameter.h"
#include <boost/optional.hpp>
namespace carla {
namespace client {
class Actor;
class ActorBlueprint;
class ActorList;
class BlueprintLibrary;
class Map;
class TrafficLight;
class TrafficSign;
class World {
public:
explicit World(detail::EpisodeProxy episode) : _episode(std::move(episode)) {}
~World(){}
World(const World &) = default;
World(World &&) = default;
World &operator=(const World &) = default;
World &operator=(World &&) = default;
/// Get the id of the episode associated with this world.
uint64_t GetId() const {
return _episode.GetId();
}
/// Return the map that describes this world.
SharedPtr<Map> GetMap() const;
void LoadLevelLayer(rpc::MapLayer map_layers) const;
void UnloadLevelLayer(rpc::MapLayer map_layers) const;
/// Return the list of blueprints available in this world. This blueprints
/// can be used to spawning actor into the world.
SharedPtr<BlueprintLibrary> GetBlueprintLibrary() const;
/// Returns a list of pairs where the firts element is the vehicle ID
/// and the second one is the light state
rpc::VehicleLightStateList GetVehiclesLightStates() const;
/// Get a random location from the pedestrians navigation mesh
boost::optional<geom::Location> GetRandomLocationFromNavigation() const;
/// Return the spectator actor. The spectator controls the view in the
/// simulator window.
SharedPtr<Actor> GetSpectator() const;
rpc::EpisodeSettings GetSettings() const;
/// @return The id of the frame when the settings were applied.
uint64_t ApplySettings(const rpc::EpisodeSettings &settings, time_duration timeout);
/// Retrieve the weather parameters currently active in the world.
rpc::WeatherParameters GetWeather() const;
/// Change the weather in the simulation.
void SetWeather(const rpc::WeatherParameters &weather);
/// Return a snapshot of the world at this moment.
WorldSnapshot GetSnapshot() const;
/// Find actor by id, return nullptr if not found.
SharedPtr<Actor> GetActor(ActorId id) const;
/// Return a list with all the actors currently present in the world.
SharedPtr<ActorList> GetActors() const;
/// Return a list with the actors requested by ActorId.
SharedPtr<ActorList> GetActors(const std::vector<ActorId> &actor_ids) const;
/// Spawn an actor into the world based on the @a blueprint provided at @a
/// transform. If a @a parent is provided, the actor is attached to
/// @a parent.
SharedPtr<Actor> SpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent = nullptr,
rpc::AttachmentType attachment_type = rpc::AttachmentType::Rigid);
/// Same as SpawnActor but return nullptr on failure instead of throwing an
/// exception.
SharedPtr<Actor> TrySpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent = nullptr,
rpc::AttachmentType attachment_type = rpc::AttachmentType::Rigid) noexcept;
/// Block calling thread until a world tick is received.
WorldSnapshot WaitForTick(time_duration timeout) const;
/// Register a @a callback to be called every time a world tick is received.
///
/// @return ID of the callback, use it to remove the callback.
size_t OnTick(std::function<void(WorldSnapshot)> callback);
/// Remove a callback registered with OnTick.
void RemoveOnTick(size_t callback_id);
/// Signal the simulator to continue to next tick (only has effect on
/// synchronous mode).
///
/// @return The id of the frame that this call started.
uint64_t Tick(time_duration timeout);
/// set the probability that an agent could cross the roads in its path following
/// percentage of 0.0f means no pedestrian can cross roads
/// percentage of 0.5f means 50% of all pedestrians can cross roads
/// percentage of 1.0f means all pedestrians can cross roads if needed
void SetPedestriansCrossFactor(float percentage);
/// set the seed to use with random numbers in the pedestrians module
void SetPedestriansSeed(unsigned int seed);
SharedPtr<Actor> GetTrafficSign(const Landmark& landmark) const;
SharedPtr<Actor> GetTrafficLight(const Landmark& landmark) const;
SharedPtr<Actor> GetTrafficLightFromOpenDRIVE(const road::SignId& sign_id) const;
void ResetAllTrafficLights();
SharedPtr<LightManager> GetLightManager() const;
DebugHelper MakeDebugHelper() const {
return DebugHelper{_episode};
}
detail::EpisodeProxy GetEpisode() const {
return _episode;
};
void FreezeAllTrafficLights(bool frozen);
/// Returns all the BBs of all the elements of the level
std::vector<geom::BoundingBox> GetLevelBBs(uint8_t queried_tag) const;
std::vector<rpc::EnvironmentObject> GetEnvironmentObjects(uint8_t queried_tag) const;
void EnableEnvironmentObjects(
std::vector<uint64_t> env_objects_ids,
bool enable) const;
boost::optional<rpc::LabelledPoint> ProjectPoint(
geom::Location location, geom::Vector3D direction, float search_distance = 10000.f) const;
boost::optional<rpc::LabelledPoint> GroundProjection(
geom::Location location, float search_distance = 10000.0) const;
std::vector<rpc::LabelledPoint> CastRay(
geom::Location start_location, geom::Location end_location) const;
std::vector<SharedPtr<Actor>> GetTrafficLightsFromWaypoint(
const Waypoint& waypoint, double distance) const;
std::vector<SharedPtr<Actor>> GetTrafficLightsInJunction(
const road::JuncId junc_id) const;
// std::vector<std::string> GetObjectNameList();
void ApplyColorTextureToObject(
const std::string &actor_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture);
void ApplyColorTextureToObjects(
const std::vector<std::string> &objects_names,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture);
void ApplyFloatColorTextureToObject(
const std::string &actor_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture);
void ApplyFloatColorTextureToObjects(
const std::vector<std::string> &objects_names,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture);
void ApplyTexturesToObject(
const std::string &actor_name,
const rpc::TextureColor& diffuse_texture,
const rpc::TextureFloatColor& emissive_texture,
const rpc::TextureFloatColor& normal_texture,
const rpc::TextureFloatColor& ao_roughness_metallic_emissive_texture);
void ApplyTexturesToObjects(
const std::vector<std::string> &objects_names,
const rpc::TextureColor& diffuse_texture,
const rpc::TextureFloatColor& emissive_texture,
const rpc::TextureFloatColor& normal_texture,
const rpc::TextureFloatColor& ao_roughness_metallic_emissive_texture);
std::vector<std::string> GetNamesOfAllObjects() const;
private:
detail::EpisodeProxy _episode;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,77 @@
// Copyright (c) 2019 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/client/Timestamp.h"
#include "carla/client/ActorSnapshot.h"
#include "carla/client/detail/EpisodeState.h"
#include <boost/optional.hpp>
namespace carla {
namespace client {
class WorldSnapshot {
public:
WorldSnapshot(std::shared_ptr<const detail::EpisodeState> state)
: _state(std::move(state)) {}
/// Get the id of the episode associated with this world.
uint64_t GetId() const {
return _state->GetEpisodeId();
}
size_t GetFrame() const {
return GetTimestamp().frame;
}
/// Get timestamp of this snapshot.
const Timestamp &GetTimestamp() const {
return _state->GetTimestamp();
}
/// Check if an actor is present in this snapshot.
bool Contains(ActorId actor_id) const {
return _state->ContainsActorSnapshot(actor_id);
}
/// Find an ActorSnapshot by id.
boost::optional<ActorSnapshot> Find(ActorId actor_id) const {
return _state->GetActorSnapshotIfPresent(actor_id);
}
/// Return number of ActorSnapshots present in this WorldSnapshot.
size_t size() const {
return _state->size();
}
/// Return a begin iterator to the list of ActorSnapshots.
auto begin() const {
return _state->begin();
}
/// Return a past-the-end iterator to the list of ActorSnapshots.
auto end() const {
return _state->end();
}
bool operator==(const WorldSnapshot &rhs) const {
return GetTimestamp() == rhs.GetTimestamp();
}
bool operator!=(const WorldSnapshot &rhs) const {
return !(*this == rhs);
}
private:
std::shared_ptr<const detail::EpisodeState> _state;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,102 @@
// 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/client/detail/ActorFactory.h"
#include "carla/Logging.h"
#include "carla/StringUtil.h"
#include "carla/client/Actor.h"
#include "carla/client/LaneInvasionSensor.h"
#include "carla/client/ServerSideSensor.h"
#ifdef RSS_ENABLED
#include "carla/rss/RssSensor.h"
#endif
#include "carla/client/TrafficLight.h"
#include "carla/client/TrafficSign.h"
#include "carla/client/Vehicle.h"
#include "carla/client/Walker.h"
#include "carla/client/WalkerAIController.h"
#include "carla/client/World.h"
#include "carla/client/detail/Client.h"
#include <rpc/config.h>
#include <rpc/rpc_error.h>
#include <exception>
namespace carla {
namespace client {
namespace detail {
// A deleter cannot throw exceptions; and unlike std::unique_ptr, the deleter
// of (std|boost)::shared_ptr is invoked even if the managed pointer is null.
struct GarbageCollector {
void operator()(::carla::client::Actor *ptr) const noexcept {
if ((ptr != nullptr) && ptr->IsAlive()) {
try {
ptr->Destroy();
delete ptr;
} catch (const ::rpc::timeout &timeout) {
log_error(timeout.what());
log_error(
"timeout while trying to garbage collect Actor",
ptr->GetDisplayId(),
"actor hasn't been removed from the simulation");
} catch (const std::exception &e) {
log_critical(
"exception thrown while trying to garbage collect Actor",
ptr->GetDisplayId(),
e.what());
std::terminate();
} catch (...) {
log_critical(
"unknown exception thrown while trying to garbage collect an Actor :",
ptr->GetDisplayId());
std::terminate();
}
}
}
};
template <typename ActorT>
static auto MakeActorImpl(ActorInitializer init, GarbageCollectionPolicy gc) {
if (gc == GarbageCollectionPolicy::Enabled) {
return SharedPtr<ActorT>{new ActorT(std::move(init)), GarbageCollector()};
}
DEBUG_ASSERT(gc == GarbageCollectionPolicy::Disabled);
return SharedPtr<ActorT>{new ActorT(std::move(init))};
}
SharedPtr<Actor> ActorFactory::MakeActor(
EpisodeProxy episode,
rpc::Actor description,
GarbageCollectionPolicy gc) {
auto init = ActorInitializer{description, episode};
if (description.description.id == "sensor.other.lane_invasion") {
return MakeActorImpl<LaneInvasionSensor>(std::move(init), gc);
#ifdef RSS_ENABLED
} else if (description.description.id == "sensor.other.rss") {
return MakeActorImpl<RssSensor>(std::move(init), gc);
#endif
} else if (description.HasAStream()) {
return MakeActorImpl<ServerSideSensor>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "vehicle.")) {
return MakeActorImpl<Vehicle>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "walker.")) {
return MakeActorImpl<Walker>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "traffic.traffic_light")) {
return MakeActorImpl<TrafficLight>(std::move(init), gc);
} else if (StringUtil::StartsWith(description.description.id, "traffic.")) {
return MakeActorImpl<TrafficSign>(std::move(init), gc);
} else if (description.description.id == "controller.ai.walker") {
return MakeActorImpl<WalkerAIController>(std::move(init), gc);
}
return MakeActorImpl<Actor>(std::move(init), gc);
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,40 @@
// 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/Memory.h"
#include "carla/client/GarbageCollectionPolicy.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/rpc/Actor.h"
namespace carla {
namespace client {
class Actor;
namespace detail {
class ActorFactory {
public:
/// Create an Actor based on the provided @a actor_description. @a episode
/// must point to the episode in which the actor is living.
///
/// Do not call this class directly, use Simulator::MakeActor.
///
/// If @a garbage_collection_policy is GarbageCollectionPolicy::Enabled, the
/// shared pointer returned is provided with a custom deleter that calls
/// Destroy() on the actor.
static SharedPtr<Actor> MakeActor(
EpisodeProxy episode,
rpc::Actor actor_description,
GarbageCollectionPolicy garbage_collection_policy);
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,38 @@
// 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/client/detail/ActorState.h"
#include <string>
#include <iterator>
namespace carla {
namespace client {
namespace detail {
ActorState::ActorState(
rpc::Actor description,
EpisodeProxy episode)
: _description(std::move(description)),
_episode(std::move(episode)),
_display_id([](const auto &desc) {
using namespace std::string_literals;
return
"Actor "s +
std::to_string(desc.id) +
" (" + desc.description.id + ')';
}(_description)),
_attributes(_description.description.attributes.begin(), _description.description.attributes.end())
{}
SharedPtr<Actor> ActorState::GetParent() const {
auto parent_id = GetParentId();
return parent_id != 0u ? GetWorld().GetActor(parent_id) : nullptr;
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,102 @@
// 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/NonCopyable.h"
#include "carla/client/World.h"
#include "carla/client/ActorAttribute.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/rpc/Actor.h"
namespace carla {
namespace client {
namespace detail {
class ActorFactory;
/// Internal state of an Actor.
class ActorState : private MovableNonCopyable {
public:
ActorId GetId() const {
return _description.id;
}
const std::string &GetTypeId() const {
return _description.description.id;
}
const std::string &GetDisplayId() const {
return _display_id;
}
ActorId GetParentId() const {
return _description.parent_id;
}
const std::vector<uint8_t> &GetSemanticTags() const {
return _description.semantic_tags;
}
SharedPtr<Actor> GetParent() const;
World GetWorld() const {
return World{_episode};
}
const std::vector<ActorAttributeValue> &GetAttributes() const
{
return _attributes;
}
protected:
explicit ActorState(rpc::Actor description, EpisodeProxy episode);
const geom::BoundingBox &GetBoundingBox() const {
return _description.bounding_box;
}
const rpc::Actor &GetActorDescription() const {
return _description;
}
EpisodeProxy &GetEpisode() {
return _episode;
}
const EpisodeProxy &GetEpisode() const {
return _episode;
}
private:
friend class Simulator;
rpc::Actor _description;
EpisodeProxy _episode;
std::string _display_id;
std::vector<ActorAttributeValue> _attributes;
};
} // namespace detail
/// Used to initialize Actor classes. Only the ActorFactory can create this
/// object, thus only the ActorFactory can create actors.
class ActorInitializer : public detail::ActorState {
public:
ActorInitializer(ActorInitializer &&) = default;
private:
friend class detail::ActorFactory;
using detail::ActorState::ActorState;
};
} // namespace client
} // namespace carla

View File

@ -0,0 +1,25 @@
// 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/client/detail/ActorVariant.h"
#include "carla/client/detail/ActorFactory.h"
#include "carla/client/ActorList.h"
namespace carla {
namespace client {
namespace detail {
void ActorVariant::MakeActor(EpisodeProxy episode) const {
_value = detail::ActorFactory::MakeActor(
episode,
boost::variant2::get<rpc::Actor>(std::move(_value)),
GarbageCollectionPolicy::Disabled);
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,99 @@
// 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/Debug.h"
#include "carla/Memory.h"
#include "carla/client/Actor.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/rpc/Actor.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4583)
#pragma warning(disable:4582)
#include <boost/variant2/variant.hpp>
#pragma warning(pop)
#else
#include <boost/variant2/variant.hpp>
#endif
namespace carla {
namespace client {
namespace detail {
/// Holds an Actor, but only instantiates it when needed.
class ActorVariant {
public:
ActorVariant(rpc::Actor actor)
: _value(actor) {}
ActorVariant(SharedPtr<client::Actor> actor)
: _value(actor) {}
ActorVariant &operator=(rpc::Actor actor) {
_value = actor;
return *this;
}
ActorVariant &operator=(SharedPtr<client::Actor> actor) {
_value = actor;
return *this;
}
SharedPtr<client::Actor> Get(EpisodeProxy episode) const {
if (_value.index() == 0u) {
MakeActor(episode);
}
DEBUG_ASSERT(_value.index() == 1u);
return boost::variant2::get<SharedPtr<client::Actor>>(_value);
}
const rpc::Actor &Serialize() const {
return boost::variant2::visit(Visitor(), _value);
}
ActorId GetId() const {
return Serialize().id;
}
ActorId GetParentId() const {
return Serialize().parent_id;
}
const std::string &GetTypeId() const {
return Serialize().description.id;
}
bool operator==(ActorVariant rhs) const {
return GetId() == rhs.GetId();
}
bool operator!=(ActorVariant rhs) const {
return !(*this == rhs);
}
private:
struct Visitor {
const rpc::Actor &operator()(const rpc::Actor &actor) const {
return actor;
}
const rpc::Actor &operator()(const SharedPtr<const client::Actor> &actor) const {
return actor->Serialize();
}
};
void MakeActor(EpisodeProxy episode) const;
mutable boost::variant2::variant<rpc::Actor, SharedPtr<client::Actor>> _value;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,126 @@
// 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/NonCopyable.h"
#include "carla/rpc/Actor.h"
#include <boost/iterator/transform_iterator.hpp>
#include <algorithm>
#include <iterator>
#include <mutex>
namespace carla {
namespace client {
namespace detail {
// ===========================================================================
// -- CachedActorList --------------------------------------------------------
// ===========================================================================
/// Keeps a list of actor descriptions to avoid requesting each time the
/// descriptions to the server.
///
/// @todo Dead actors are never removed from the list.
class CachedActorList : private MovableNonCopyable {
public:
/// Inserts an actor into the list.
void Insert(rpc::Actor actor);
/// Inserts a @a range containing actors.
template <typename RangeT>
void InsertRange(RangeT range);
/// Return the actor ids present in @a range that haven't been added to this
/// list.
template <typename RangeT>
std::vector<ActorId> GetMissingIds(const RangeT &range) const;
/// Retrieve the actor matching @a id, or empty optional if actor is not
/// cached.
boost::optional<rpc::Actor> GetActorById(ActorId id) const;
/// Retrieve the actors matching the ids in @a range.
template <typename RangeT>
std::vector<rpc::Actor> GetActorsById(const RangeT &range) const;
void Clear();
private:
mutable std::mutex _mutex;
std::unordered_map<ActorId, rpc::Actor> _actors;
};
// ===========================================================================
// -- CachedActorList implementation -----------------------------------------
// ===========================================================================
inline void CachedActorList::Insert(rpc::Actor actor) {
std::lock_guard<std::mutex> lock(_mutex);
auto id = actor.id;
_actors.emplace(id, std::move(actor));
}
template <typename RangeT>
inline void CachedActorList::InsertRange(RangeT range) {
auto make_a_pair = [](rpc::Actor actor) {
auto id = actor.id;
return std::make_pair(id, std::move(actor));
};
auto make_iterator = [&make_a_pair](auto it) {
return boost::make_transform_iterator(std::make_move_iterator(it), make_a_pair);
};
std::lock_guard<std::mutex> lock(_mutex);
_actors.insert(make_iterator(std::begin(range)), make_iterator(std::end(range)));
}
template <typename RangeT>
inline std::vector<ActorId> CachedActorList::GetMissingIds(const RangeT &range) const {
std::vector<ActorId> result;
result.reserve(range.size());
std::lock_guard<std::mutex> lock(_mutex);
std::copy_if(std::begin(range), std::end(range), std::back_inserter(result), [this](auto id) {
return _actors.find(id) == _actors.end();
});
return result;
}
inline boost::optional<rpc::Actor> CachedActorList::GetActorById(ActorId id) const {
std::lock_guard<std::mutex> lock(_mutex);
auto it = _actors.find(id);
if (it != _actors.end()) {
return it->second;
}
return boost::none;
}
template <typename RangeT>
inline std::vector<rpc::Actor> CachedActorList::GetActorsById(const RangeT &range) const {
std::vector<rpc::Actor> result;
result.reserve(range.size());
std::lock_guard<std::mutex> lock(_mutex);
for (auto &&id : range) {
auto it = _actors.find(id);
if (it != _actors.end()) {
result.emplace_back(it->second);
}
}
return result;
}
inline void CachedActorList::Clear() {
std::lock_guard<std::mutex> lock(_mutex);
_actors.clear();
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,73 @@
// 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/AtomicList.h"
#include "carla/NonCopyable.h"
#include <atomic>
#include <functional>
namespace carla {
namespace client {
namespace detail {
template <typename... InputsT>
class CallbackList : private NonCopyable {
public:
using CallbackType = std::function<void(InputsT...)>;
void Call(InputsT... args) const {
auto list = _list.Load();
for (auto &item : *list) {
item.callback(args...);
}
}
size_t Push(CallbackType &&callback) {
auto id = ++_counter;
DEBUG_ASSERT(id != 0u);
_list.Push(Item{id, std::move(callback)});
return id;
}
void Remove(size_t id) {
_list.DeleteByValue(id);
}
void Clear() {
_list.Clear();
}
private:
struct Item {
size_t id;
CallbackType callback;
friend bool operator==(const Item &lhs, const Item &rhs) {
return lhs.id == rhs.id;
}
friend bool operator==(const Item &lhs, size_t rhs) {
return lhs.id == rhs;
}
friend bool operator==(size_t lhs, const Item &rhs) {
return lhs == rhs.id;
}
};
std::atomic_size_t _counter{0u};
AtomicList<Item> _list;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,699 @@
// 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/client/detail/Client.h"
#include "carla/Exception.h"
#include "carla/Version.h"
#include "carla/client/FileTransfer.h"
#include "carla/client/TimeoutException.h"
#include "carla/rpc/AckermannControllerSettings.h"
#include "carla/rpc/ActorDescription.h"
#include "carla/rpc/BoneTransformDataIn.h"
#include "carla/rpc/Client.h"
#include "carla/rpc/DebugShape.h"
#include "carla/rpc/Response.h"
#include "carla/rpc/VehicleAckermannControl.h"
#include "carla/rpc/VehicleControl.h"
#include "carla/rpc/VehicleLightState.h"
#include "carla/rpc/WalkerBoneControlIn.h"
#include "carla/rpc/WalkerBoneControlOut.h"
#include "carla/rpc/WalkerControl.h"
#include "carla/streaming/Client.h"
#include <rpc/rpc_error.h>
#include <thread>
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 ----------------------------------------------------------
// ===========================================================================
class Client::Pimpl {
public:
Pimpl(const std::string &host, uint16_t port, size_t worker_threads)
: endpoint(host + ":" + std::to_string(port)),
rpc_client(host, port),
streaming_client(host) {
rpc_client.set_timeout(5000u);
streaming_client.AsyncRun(
worker_threads > 0u ? worker_threads : std::thread::hardware_concurrency());
}
template <typename ... Args>
auto RawCall(const std::string &function, Args && ... args) {
try {
return rpc_client.call(function, std::forward<Args>(args) ...);
} catch (const ::rpc::timeout &) {
throw_exception(TimeoutException(endpoint, GetTimeout()));
}
}
template <typename T, typename ... Args>
auto CallAndWait(const std::string &function, Args && ... args) {
auto object = RawCall(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>
void AsyncCall(const std::string &function, Args && ... args) {
// Discard returned future.
rpc_client.async_call(function, std::forward<Args>(args) ...);
}
time_duration GetTimeout() const {
auto timeout = rpc_client.get_timeout();
DEBUG_ASSERT(timeout.has_value());
return time_duration::milliseconds(static_cast<size_t>(*timeout));
}
const std::string endpoint;
rpc::Client rpc_client;
streaming::Client streaming_client;
};
// ===========================================================================
// -- Client -----------------------------------------------------------------
// ===========================================================================
Client::Client(
const std::string &host,
const uint16_t port,
const size_t worker_threads)
: _pimpl(std::make_unique<Pimpl>(host, port, worker_threads)) {}
bool Client::IsTrafficManagerRunning(uint16_t port) const {
return _pimpl->CallAndWait<bool>("is_traffic_manager_running", port);
}
std::pair<std::string, uint16_t> Client::GetTrafficManagerRunning(uint16_t port) const {
return _pimpl->CallAndWait<std::pair<std::string, uint16_t>>("get_traffic_manager_running", port);
};
bool Client::AddTrafficManagerRunning(std::pair<std::string, uint16_t> trafficManagerInfo) const {
return _pimpl->CallAndWait<bool>("add_traffic_manager_running", trafficManagerInfo);
};
void Client::DestroyTrafficManager(uint16_t port) const {
_pimpl->AsyncCall("destroy_traffic_manager", port);
}
Client::~Client() = default;
void Client::SetTimeout(time_duration timeout) {
_pimpl->rpc_client.set_timeout(static_cast<int64_t>(timeout.milliseconds()));
}
time_duration Client::GetTimeout() const {
return _pimpl->GetTimeout();
}
const std::string Client::GetEndpoint() const {
return _pimpl->endpoint;
}
std::string Client::GetClientVersion() {
return ::carla::version();
}
std::string Client::GetServerVersion() {
return _pimpl->CallAndWait<std::string>("version");
}
void Client::LoadEpisode(std::string map_name, bool reset_settings, rpc::MapLayer map_layer) {
// Await response, we need to be sure in this one.
_pimpl->CallAndWait<void>("load_new_episode", std::move(map_name), reset_settings, map_layer);
}
void Client::LoadLevelLayer(rpc::MapLayer map_layer) const {
// Await response, we need to be sure in this one.
_pimpl->CallAndWait<void>("load_map_layer", map_layer);
}
void Client::UnloadLevelLayer(rpc::MapLayer map_layer) const {
// Await response, we need to be sure in this one.
_pimpl->CallAndWait<void>("unload_map_layer", map_layer);
}
void Client::CopyOpenDriveToServer(std::string opendrive, const rpc::OpendriveGenerationParameters & params) {
// Await response, we need to be sure in this one.
_pimpl->CallAndWait<void>("copy_opendrive_to_file", std::move(opendrive), params);
}
void Client::ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture) {
_pimpl->CallAndWait<void>("apply_color_texture_to_objects", objects_name, parameter, Texture);
}
void Client::ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture) {
_pimpl->CallAndWait<void>("apply_float_color_texture_to_objects", objects_name, parameter, Texture);
}
std::vector<std::string> Client::GetNamesOfAllObjects() const {
return _pimpl->CallAndWait<std::vector<std::string>>("get_names_of_all_objects");
}
rpc::EpisodeInfo Client::GetEpisodeInfo() {
return _pimpl->CallAndWait<rpc::EpisodeInfo>("get_episode_info");
}
rpc::MapInfo Client::GetMapInfo() {
return _pimpl->CallAndWait<rpc::MapInfo>("get_map_info");
}
std::string Client::GetMapData() const{
return _pimpl->CallAndWait<std::string>("get_map_data");
}
std::vector<uint8_t> Client::GetNavigationMesh() const {
return _pimpl->CallAndWait<std::vector<uint8_t>>("get_navigation_mesh");
}
bool Client::SetFilesBaseFolder(const std::string &path) {
return FileTransfer::SetFilesBaseFolder(path);
}
std::vector<std::string> Client::GetRequiredFiles(const std::string &folder, const bool download) const {
// Get the list of required files
auto requiredFiles = _pimpl->CallAndWait<std::vector<std::string>>("get_required_files", folder);
if (download) {
// For each required file, check if it exists and request it otherwise
for (auto requiredFile : requiredFiles) {
if (!FileTransfer::FileExists(requiredFile)) {
RequestFile(requiredFile);
log_info("Could not find the required file in cache, downloading... ", requiredFile);
} else {
log_info("Found the required file in cache! ", requiredFile);
}
}
}
return requiredFiles;
}
void Client::RequestFile(const std::string &name) const {
// Download the binary content of the file from the server and write it on the client
auto content = _pimpl->CallAndWait<std::vector<uint8_t>>("request_file", name);
FileTransfer::WriteFile(name, content);
}
std::vector<uint8_t> Client::GetCacheFile(const std::string &name, const bool request_otherwise) const {
// Get the file from the cache in the file transfer
std::vector<uint8_t> file = FileTransfer::ReadFile(name);
// If it isn't in the cache, download it if request otherwise is true
if (file.empty() && request_otherwise) {
RequestFile(name);
file = FileTransfer::ReadFile(name);
}
return file;
}
std::vector<std::string> Client::GetAvailableMaps() {
return _pimpl->CallAndWait<std::vector<std::string>>("get_available_maps");
}
std::vector<rpc::ActorDefinition> Client::GetActorDefinitions() {
return _pimpl->CallAndWait<std::vector<rpc::ActorDefinition>>("get_actor_definitions");
}
rpc::Actor Client::GetSpectator() {
return _pimpl->CallAndWait<carla::rpc::Actor>("get_spectator");
}
rpc::EpisodeSettings Client::GetEpisodeSettings() {
return _pimpl->CallAndWait<rpc::EpisodeSettings>("get_episode_settings");
}
uint64_t Client::SetEpisodeSettings(const rpc::EpisodeSettings &settings) {
return _pimpl->CallAndWait<uint64_t>("set_episode_settings", settings);
}
rpc::WeatherParameters Client::GetWeatherParameters() {
return _pimpl->CallAndWait<rpc::WeatherParameters>("get_weather_parameters");
}
void Client::SetWeatherParameters(const rpc::WeatherParameters &weather) {
_pimpl->AsyncCall("set_weather_parameters", weather);
}
std::vector<rpc::Actor> Client::GetActorsById(
const std::vector<ActorId> &ids) {
using return_t = std::vector<rpc::Actor>;
return _pimpl->CallAndWait<return_t>("get_actors_by_id", ids);
}
rpc::VehiclePhysicsControl Client::GetVehiclePhysicsControl(
rpc::ActorId vehicle) const {
return _pimpl->CallAndWait<carla::rpc::VehiclePhysicsControl>("get_physics_control", vehicle);
}
rpc::VehicleLightState Client::GetVehicleLightState(
rpc::ActorId vehicle) const {
return _pimpl->CallAndWait<carla::rpc::VehicleLightState>("get_vehicle_light_state", vehicle);
}
void Client::ApplyPhysicsControlToVehicle(
rpc::ActorId vehicle,
const rpc::VehiclePhysicsControl &physics_control) {
return _pimpl->AsyncCall("apply_physics_control", vehicle, physics_control);
}
void Client::SetLightStateToVehicle(
rpc::ActorId vehicle,
const rpc::VehicleLightState &light_state) {
return _pimpl->AsyncCall("set_vehicle_light_state", vehicle, light_state);
}
void Client::OpenVehicleDoor(
rpc::ActorId vehicle,
const rpc::VehicleDoor door_idx) {
return _pimpl->AsyncCall("open_vehicle_door", vehicle, door_idx);
}
void Client::CloseVehicleDoor(
rpc::ActorId vehicle,
const rpc::VehicleDoor door_idx) {
return _pimpl->AsyncCall("close_vehicle_door", vehicle, door_idx);
}
void Client::SetWheelSteerDirection(
rpc::ActorId vehicle,
rpc::VehicleWheelLocation vehicle_wheel,
float angle_in_deg) {
return _pimpl->AsyncCall("set_wheel_steer_direction", vehicle, vehicle_wheel, angle_in_deg);
}
float Client::GetWheelSteerAngle(
rpc::ActorId vehicle,
rpc::VehicleWheelLocation wheel_location){
return _pimpl->CallAndWait<float>("get_wheel_steer_angle", vehicle, wheel_location);
}
rpc::Actor Client::SpawnActor(
const rpc::ActorDescription &description,
const geom::Transform &transform) {
return _pimpl->CallAndWait<rpc::Actor>("spawn_actor", description, transform);
}
rpc::Actor Client::SpawnActorWithParent(
const rpc::ActorDescription &description,
const geom::Transform &transform,
rpc::ActorId parent,
rpc::AttachmentType attachment_type) {
if (attachment_type == rpc::AttachmentType::SpringArm ||
attachment_type == rpc::AttachmentType::SpringArmGhost)
{
const auto a = transform.location.MakeSafeUnitVector(std::numeric_limits<float>::epsilon());
const auto z = geom::Vector3D(0.0f, 0.f, 1.0f);
constexpr float OneEps = 1.0f - std::numeric_limits<float>::epsilon();
if (geom::Math::Dot(a, z) > OneEps) {
std::cout << "WARNING: Transformations with translation only in the 'z' axis are ill-formed when \
using SpringArm or SpringArmGhost attachment. Please, be careful with that." << std::endl;
}
}
return _pimpl->CallAndWait<rpc::Actor>("spawn_actor_with_parent",
description,
transform,
parent,
attachment_type);
}
bool Client::DestroyActor(rpc::ActorId actor) {
try {
return _pimpl->CallAndWait<bool>("destroy_actor", actor);
} catch (const std::exception &e) {
log_error("failed to destroy actor", actor, ':', e.what());
return false;
}
}
void Client::SetActorLocation(rpc::ActorId actor, const geom::Location &location) {
_pimpl->AsyncCall("set_actor_location", actor, location);
}
void Client::SetActorTransform(rpc::ActorId actor, const geom::Transform &transform) {
_pimpl->AsyncCall("set_actor_transform", actor, transform);
}
void Client::SetActorTargetVelocity(rpc::ActorId actor, const geom::Vector3D &vector) {
_pimpl->AsyncCall("set_actor_target_velocity", actor, vector);
}
void Client::SetActorTargetAngularVelocity(rpc::ActorId actor, const geom::Vector3D &vector) {
_pimpl->AsyncCall("set_actor_target_angular_velocity", actor, vector);
}
void Client::EnableActorConstantVelocity(rpc::ActorId actor, const geom::Vector3D &vector) {
_pimpl->AsyncCall("enable_actor_constant_velocity", actor, vector);
}
void Client::DisableActorConstantVelocity(rpc::ActorId actor) {
_pimpl->AsyncCall("disable_actor_constant_velocity", actor);
}
void Client::AddActorImpulse(rpc::ActorId actor, const geom::Vector3D &impulse) {
_pimpl->AsyncCall("add_actor_impulse", actor, impulse);
}
void Client::AddActorImpulse(rpc::ActorId actor, const geom::Vector3D &impulse, const geom::Vector3D &location) {
_pimpl->AsyncCall("add_actor_impulse_at_location", actor, impulse, location);
}
void Client::AddActorForce(rpc::ActorId actor, const geom::Vector3D &force) {
_pimpl->AsyncCall("add_actor_force", actor, force);
}
void Client::AddActorForce(rpc::ActorId actor, const geom::Vector3D &force, const geom::Vector3D &location) {
_pimpl->AsyncCall("add_actor_force_at_location", actor, force, location);
}
void Client::AddActorAngularImpulse(rpc::ActorId actor, const geom::Vector3D &vector) {
_pimpl->AsyncCall("add_actor_angular_impulse", actor, vector);
}
void Client::AddActorTorque(rpc::ActorId actor, const geom::Vector3D &vector) {
_pimpl->AsyncCall("add_actor_torque", actor, vector);
}
void Client::SetActorSimulatePhysics(rpc::ActorId actor, const bool enabled) {
_pimpl->CallAndWait<void>("set_actor_simulate_physics", actor, enabled);
}
void Client::SetActorCollisions(rpc::ActorId actor, const bool enabled) {
_pimpl->CallAndWait<void>("set_actor_collisions", actor, enabled);
}
void Client::SetActorDead(rpc::ActorId actor) {
_pimpl->AsyncCall("set_actor_dead", actor);
}
void Client::SetActorEnableGravity(rpc::ActorId actor, const bool enabled) {
_pimpl->AsyncCall("set_actor_enable_gravity", actor, enabled);
}
void Client::SetActorAutopilot(rpc::ActorId vehicle, const bool enabled) {
_pimpl->AsyncCall("set_actor_autopilot", vehicle, enabled);
}
void Client::ShowVehicleDebugTelemetry(rpc::ActorId vehicle, const bool enabled) {
_pimpl->AsyncCall("show_vehicle_debug_telemetry", vehicle, enabled);
}
void Client::ApplyControlToVehicle(rpc::ActorId vehicle, const rpc::VehicleControl &control) {
_pimpl->AsyncCall("apply_control_to_vehicle", vehicle, control);
}
void Client::ApplyAckermannControlToVehicle(rpc::ActorId vehicle, const rpc::VehicleAckermannControl &control) {
_pimpl->AsyncCall("apply_ackermann_control_to_vehicle", vehicle, control);
}
rpc::AckermannControllerSettings Client::GetAckermannControllerSettings(
rpc::ActorId vehicle) const {
return _pimpl->CallAndWait<carla::rpc::AckermannControllerSettings>("get_ackermann_controller_settings", vehicle);
}
void Client::ApplyAckermannControllerSettings(rpc::ActorId vehicle, const rpc::AckermannControllerSettings &settings) {
_pimpl->AsyncCall("apply_ackermann_controller_settings", vehicle, settings);
}
void Client::EnableCarSim(rpc::ActorId vehicle, std::string simfile_path) {
_pimpl->AsyncCall("enable_carsim", vehicle, simfile_path);
}
void Client::UseCarSimRoad(rpc::ActorId vehicle, bool enabled) {
_pimpl->AsyncCall("use_carsim_road", vehicle, enabled);
}
void Client::EnableChronoPhysics(
rpc::ActorId vehicle,
uint64_t MaxSubsteps,
float MaxSubstepDeltaTime,
std::string VehicleJSON,
std::string PowertrainJSON,
std::string TireJSON,
std::string BaseJSONPath) {
_pimpl->AsyncCall("enable_chrono_physics",
vehicle,
MaxSubsteps,
MaxSubstepDeltaTime,
VehicleJSON,
PowertrainJSON,
TireJSON,
BaseJSONPath);
}
void Client::ApplyControlToWalker(rpc::ActorId walker, const rpc::WalkerControl &control) {
_pimpl->AsyncCall("apply_control_to_walker", walker, control);
}
rpc::WalkerBoneControlOut Client::GetBonesTransform(rpc::ActorId walker) {
auto res = _pimpl->CallAndWait<rpc::WalkerBoneControlOut>("get_bones_transform", walker);
return res;
}
void Client::SetBonesTransform(rpc::ActorId walker, const rpc::WalkerBoneControlIn &bones) {
_pimpl->AsyncCall("set_bones_transform", walker, bones);
}
void Client::BlendPose(rpc::ActorId walker, float blend) {
_pimpl->AsyncCall("blend_pose", walker, blend);
}
void Client::GetPoseFromAnimation(rpc::ActorId walker) {
_pimpl->AsyncCall("get_pose_from_animation", walker);
}
void Client::SetTrafficLightState(
rpc::ActorId traffic_light,
const rpc::TrafficLightState traffic_light_state) {
_pimpl->AsyncCall("set_traffic_light_state", traffic_light, traffic_light_state);
}
void Client::SetTrafficLightGreenTime(rpc::ActorId traffic_light, float green_time) {
_pimpl->AsyncCall("set_traffic_light_green_time", traffic_light, green_time);
}
void Client::SetTrafficLightYellowTime(rpc::ActorId traffic_light, float yellow_time) {
_pimpl->AsyncCall("set_traffic_light_yellow_time", traffic_light, yellow_time);
}
void Client::SetTrafficLightRedTime(rpc::ActorId traffic_light, float red_time) {
_pimpl->AsyncCall("set_traffic_light_red_time", traffic_light, red_time);
}
void Client::FreezeTrafficLight(rpc::ActorId traffic_light, bool freeze) {
_pimpl->AsyncCall("freeze_traffic_light", traffic_light, freeze);
}
void Client::ResetTrafficLightGroup(rpc::ActorId traffic_light) {
_pimpl->AsyncCall("reset_traffic_light_group", traffic_light);
}
void Client::ResetAllTrafficLights() {
_pimpl->CallAndWait<void>("reset_all_traffic_lights");
}
void Client::FreezeAllTrafficLights(bool frozen) {
_pimpl->AsyncCall("freeze_all_traffic_lights", frozen);
}
std::vector<geom::BoundingBox> Client::GetLightBoxes(rpc::ActorId traffic_light) const {
using return_t = std::vector<geom::BoundingBox>;
return _pimpl->CallAndWait<return_t>("get_light_boxes", traffic_light);
}
rpc::VehicleLightStateList Client::GetVehiclesLightStates() {
return _pimpl->CallAndWait<std::vector<std::pair<carla::ActorId, uint32_t>>>("get_vehicle_light_states");
}
std::vector<ActorId> Client::GetGroupTrafficLights(rpc::ActorId traffic_light) {
using return_t = std::vector<ActorId>;
return _pimpl->CallAndWait<return_t>("get_group_traffic_lights", traffic_light);
}
std::string Client::StartRecorder(std::string name, bool additional_data) {
return _pimpl->CallAndWait<std::string>("start_recorder", name, additional_data);
}
void Client::StopRecorder() {
return _pimpl->AsyncCall("stop_recorder");
}
std::string Client::ShowRecorderFileInfo(std::string name, bool show_all) {
return _pimpl->CallAndWait<std::string>("show_recorder_file_info", name, show_all);
}
std::string Client::ShowRecorderCollisions(std::string name, char type1, char type2) {
return _pimpl->CallAndWait<std::string>("show_recorder_collisions", name, type1, type2);
}
std::string Client::ShowRecorderActorsBlocked(std::string name, double min_time, double min_distance) {
return _pimpl->CallAndWait<std::string>("show_recorder_actors_blocked", name, min_time, min_distance);
}
std::string Client::ReplayFile(std::string name, double start, double duration,
uint32_t follow_id, bool replay_sensors) {
return _pimpl->CallAndWait<std::string>("replay_file", name, start, duration,
follow_id, replay_sensors);
}
void Client::StopReplayer(bool keep_actors) {
_pimpl->AsyncCall("stop_replayer", keep_actors);
}
void Client::SetReplayerTimeFactor(double time_factor) {
_pimpl->AsyncCall("set_replayer_time_factor", time_factor);
}
void Client::SetReplayerIgnoreHero(bool ignore_hero) {
_pimpl->AsyncCall("set_replayer_ignore_hero", ignore_hero);
}
void Client::SetReplayerIgnoreSpectator(bool ignore_spectator) {
_pimpl->AsyncCall("set_replayer_ignore_spectator", ignore_spectator);
}
void Client::SubscribeToStream(
const streaming::Token &token,
std::function<void(Buffer)> callback) {
carla::streaming::detail::token_type thisToken(token);
streaming::Token receivedToken = _pimpl->CallAndWait<streaming::Token>("get_sensor_token", thisToken.get_stream_id());
_pimpl->streaming_client.Subscribe(receivedToken, std::move(callback));
}
void Client::UnSubscribeFromStream(const streaming::Token &token) {
_pimpl->streaming_client.UnSubscribe(token);
}
void Client::EnableForROS(const streaming::Token &token) {
carla::streaming::detail::token_type thisToken(token);
_pimpl->AsyncCall("enable_sensor_for_ros", thisToken.get_stream_id());
}
void Client::DisableForROS(const streaming::Token &token) {
carla::streaming::detail::token_type thisToken(token);
_pimpl->AsyncCall("disable_sensor_for_ros", thisToken.get_stream_id());
}
bool Client::IsEnabledForROS(const streaming::Token &token) {
carla::streaming::detail::token_type thisToken(token);
return _pimpl->CallAndWait<bool>("is_sensor_enabled_for_ros", thisToken.get_stream_id());
}
void Client::SubscribeToGBuffer(
rpc::ActorId ActorId,
uint32_t GBufferId,
std::function<void(Buffer)> callback)
{
std::vector<unsigned char> token_data = _pimpl->CallAndWait<std::vector<unsigned char>>("get_gbuffer_token", ActorId, GBufferId);
streaming::Token token;
std::memcpy(&token.data[0u], token_data.data(), token_data.size());
_pimpl->streaming_client.Subscribe(token, std::move(callback));
}
void Client::UnSubscribeFromGBuffer(
rpc::ActorId ActorId,
uint32_t GBufferId)
{
std::vector<unsigned char> token_data = _pimpl->CallAndWait<std::vector<unsigned char>>("get_gbuffer_token", ActorId, GBufferId);
streaming::Token token;
std::memcpy(&token.data[0u], token_data.data(), token_data.size());
_pimpl->streaming_client.UnSubscribe(token);
}
void Client::DrawDebugShape(const rpc::DebugShape &shape) {
_pimpl->AsyncCall("draw_debug_shape", shape);
}
void Client::ApplyBatch(std::vector<rpc::Command> commands, bool do_tick_cue) {
_pimpl->AsyncCall("apply_batch", std::move(commands), do_tick_cue);
}
std::vector<rpc::CommandResponse> Client::ApplyBatchSync(
std::vector<rpc::Command> commands,
bool do_tick_cue) {
auto result = _pimpl->RawCall("apply_batch", std::move(commands), do_tick_cue);
return result.as<std::vector<rpc::CommandResponse>>();
}
uint64_t Client::SendTickCue() {
return _pimpl->CallAndWait<uint64_t>("tick_cue");
}
std::vector<rpc::LightState> Client::QueryLightsStateToServer() const {
using return_t = std::vector<rpc::LightState>;
return _pimpl->CallAndWait<return_t>("query_lights_state", _pimpl->endpoint);
}
void Client::UpdateServerLightsState(std::vector<rpc::LightState>& lights, bool discard_client) const {
_pimpl->AsyncCall("update_lights_state", _pimpl->endpoint, std::move(lights), discard_client);
}
void Client::UpdateDayNightCycle(const bool active) const {
_pimpl->AsyncCall("update_day_night_cycle", _pimpl->endpoint, active);
}
std::vector<geom::BoundingBox> Client::GetLevelBBs(uint8_t queried_tag) const {
using return_t = std::vector<geom::BoundingBox>;
return _pimpl->CallAndWait<return_t>("get_all_level_BBs", queried_tag);
}
std::vector<rpc::EnvironmentObject> Client::GetEnvironmentObjects(uint8_t queried_tag) const {
using return_t = std::vector<rpc::EnvironmentObject>;
return _pimpl->CallAndWait<return_t>("get_environment_objects", queried_tag);
}
void Client::EnableEnvironmentObjects(
std::vector<uint64_t> env_objects_ids,
bool enable) const {
_pimpl->AsyncCall("enable_environment_objects", std::move(env_objects_ids), enable);
}
std::pair<bool,rpc::LabelledPoint> Client::ProjectPoint(
geom::Location location, geom::Vector3D direction, float search_distance) const {
using return_t = std::pair<bool,rpc::LabelledPoint>;
return _pimpl->CallAndWait<return_t>("project_point", location, direction, search_distance);
}
std::vector<rpc::LabelledPoint> Client::CastRay(
geom::Location start_location, geom::Location end_location) const {
using return_t = std::vector<rpc::LabelledPoint>;
return _pimpl->CallAndWait<return_t>("cast_ray", start_location, end_location);
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,440 @@
// 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/Memory.h"
#include "carla/NonCopyable.h"
#include "carla/Time.h"
#include "carla/geom/Transform.h"
#include "carla/geom/Location.h"
#include "carla/rpc/Actor.h"
#include "carla/rpc/ActorDefinition.h"
#include "carla/rpc/AttachmentType.h"
#include "carla/rpc/Command.h"
#include "carla/rpc/CommandResponse.h"
#include "carla/rpc/EnvironmentObject.h"
#include "carla/rpc/EpisodeInfo.h"
#include "carla/rpc/EpisodeSettings.h"
#include "carla/rpc/LabelledPoint.h"
#include "carla/rpc/LightState.h"
#include "carla/rpc/MapInfo.h"
#include "carla/rpc/MapLayer.h"
#include "carla/rpc/OpendriveGenerationParameters.h"
#include "carla/rpc/TrafficLightState.h"
#include "carla/rpc/VehicleDoor.h"
#include "carla/rpc/VehicleLightStateList.h"
#include "carla/rpc/VehicleLightState.h"
#include "carla/rpc/VehiclePhysicsControl.h"
#include "carla/rpc/VehicleWheels.h"
#include "carla/rpc/WeatherParameters.h"
#include "carla/rpc/Texture.h"
#include "carla/rpc/MaterialParameter.h"
#include <functional>
#include <memory>
#include <string>
#include <vector>
// Forward declarations.
namespace carla {
class Buffer;
namespace rpc {
class AckermannControllerSettings;
class ActorDescription;
class DebugShape;
class VehicleAckermannControl;
class VehicleControl;
class WalkerControl;
class WalkerBoneControlIn;
class WalkerBoneControlOut;
}
namespace sensor {
class SensorData;
}
namespace streaming {
class Token;
}
}
namespace carla {
namespace client {
namespace detail {
/// Provides communication with the rpc and streaming servers of a CARLA
/// simulator.
class Client : private NonCopyable {
public:
explicit Client(
const std::string &host,
uint16_t port,
size_t worker_threads = 0u);
~Client();
/// Querry to know if a Traffic Manager is running on port
bool IsTrafficManagerRunning(uint16_t port) const;
/// Gets a pair filled with the <IP, port> of the Trafic Manager running on port.
/// If there is no Traffic Manager running the pair will be ("", 0)
std::pair<std::string, uint16_t> GetTrafficManagerRunning(uint16_t port) const;
/// Informs the server that a Traffic Manager is running on <IP, port>
bool AddTrafficManagerRunning(std::pair<std::string, uint16_t> trafficManagerInfo) const;
void DestroyTrafficManager(uint16_t port) const;
void SetTimeout(time_duration timeout);
time_duration GetTimeout() const;
const std::string GetEndpoint() const;
std::string GetClientVersion();
std::string GetServerVersion();
void LoadEpisode(std::string map_name, bool reset_settings = true, rpc::MapLayer map_layer = rpc::MapLayer::All);
void LoadLevelLayer(rpc::MapLayer map_layer) const;
void UnloadLevelLayer(rpc::MapLayer map_layer) const;
void CopyOpenDriveToServer(
std::string opendrive, const rpc::OpendriveGenerationParameters & params);
void ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture);
void ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture);
std::vector<std::string> GetNamesOfAllObjects() const;
rpc::EpisodeInfo GetEpisodeInfo();
rpc::MapInfo GetMapInfo();
std::vector<uint8_t> GetNavigationMesh() const;
bool SetFilesBaseFolder(const std::string &path);
std::vector<std::string> GetRequiredFiles(const std::string &folder = "", const bool download = true) const;
std::string GetMapData() const;
void RequestFile(const std::string &name) const;
std::vector<uint8_t> GetCacheFile(const std::string &name, const bool request_otherwise = true) const;
std::vector<std::string> GetAvailableMaps();
std::vector<rpc::ActorDefinition> GetActorDefinitions();
rpc::Actor GetSpectator();
rpc::EpisodeSettings GetEpisodeSettings();
uint64_t SetEpisodeSettings(const rpc::EpisodeSettings &settings);
rpc::WeatherParameters GetWeatherParameters();
void SetWeatherParameters(const rpc::WeatherParameters &weather);
std::vector<rpc::Actor> GetActorsById(const std::vector<ActorId> &ids);
rpc::VehiclePhysicsControl GetVehiclePhysicsControl(rpc::ActorId vehicle) const;
rpc::VehicleLightState GetVehicleLightState(rpc::ActorId vehicle) const;
void ApplyPhysicsControlToVehicle(
rpc::ActorId vehicle,
const rpc::VehiclePhysicsControl &physics_control);
void SetLightStateToVehicle(
rpc::ActorId vehicle,
const rpc::VehicleLightState &light_state);
void OpenVehicleDoor(
rpc::ActorId vehicle,
const rpc::VehicleDoor door_idx);
void CloseVehicleDoor(
rpc::ActorId vehicle,
const rpc::VehicleDoor door_idx);
rpc::Actor SpawnActor(
const rpc::ActorDescription &description,
const geom::Transform &transform);
rpc::Actor SpawnActorWithParent(
const rpc::ActorDescription &description,
const geom::Transform &transform,
rpc::ActorId parent,
rpc::AttachmentType attachment_type);
bool DestroyActor(rpc::ActorId actor);
void SetActorLocation(
rpc::ActorId actor,
const geom::Location &location);
void SetActorTransform(
rpc::ActorId actor,
const geom::Transform &transform);
void SetActorTargetVelocity(
rpc::ActorId actor,
const geom::Vector3D &vector);
void SetActorTargetAngularVelocity(
rpc::ActorId actor,
const geom::Vector3D &vector);
void EnableActorConstantVelocity(
rpc::ActorId actor,
const geom::Vector3D &vector);
void DisableActorConstantVelocity(
rpc::ActorId actor);
void AddActorImpulse(
rpc::ActorId actor,
const geom::Vector3D &impulse);
void AddActorImpulse(
rpc::ActorId actor,
const geom::Vector3D &impulse,
const geom::Vector3D &location);
void AddActorForce(
rpc::ActorId actor,
const geom::Vector3D &force);
void AddActorForce(
rpc::ActorId actor,
const geom::Vector3D &force,
const geom::Vector3D &location);
void AddActorAngularImpulse(
rpc::ActorId actor,
const geom::Vector3D &vector);
void AddActorTorque(
rpc::ActorId actor,
const geom::Vector3D &vector);
void SetActorSimulatePhysics(
rpc::ActorId actor,
bool enabled);
void SetActorCollisions(
rpc::ActorId actor,
bool enabled);
void SetActorDead(
rpc::ActorId actor);
void SetActorEnableGravity(
rpc::ActorId actor,
bool enabled);
void SetActorAutopilot(
rpc::ActorId vehicle,
bool enabled);
void ShowVehicleDebugTelemetry(
rpc::ActorId vehicle,
bool enabled);
void ApplyControlToVehicle(
rpc::ActorId vehicle,
const rpc::VehicleControl &control);
void ApplyAckermannControlToVehicle(
rpc::ActorId vehicle,
const rpc::VehicleAckermannControl &control);
rpc::AckermannControllerSettings GetAckermannControllerSettings(rpc::ActorId vehicle) const;
void ApplyAckermannControllerSettings(
rpc::ActorId vehicle,
const rpc::AckermannControllerSettings &settings);
void EnableCarSim(
rpc::ActorId vehicle,
std::string simfile_path);
void UseCarSimRoad(
rpc::ActorId vehicle,
bool enabled);
void SetWheelSteerDirection(
rpc::ActorId vehicle,
rpc::VehicleWheelLocation vehicle_wheel,
float angle_in_deg
);
float GetWheelSteerAngle(
rpc::ActorId vehicle,
rpc::VehicleWheelLocation wheel_location
);
void EnableChronoPhysics(
rpc::ActorId vehicle,
uint64_t MaxSubsteps,
float MaxSubstepDeltaTime,
std::string VehicleJSON,
std::string PowertrainJSON,
std::string TireJSON,
std::string BaseJSONPath);
void ApplyControlToWalker(
rpc::ActorId walker,
const rpc::WalkerControl &control);
rpc::WalkerBoneControlOut GetBonesTransform(
rpc::ActorId walker);
void SetBonesTransform(
rpc::ActorId walker,
const rpc::WalkerBoneControlIn &bones);
void BlendPose(
rpc::ActorId walker,
float blend);
void GetPoseFromAnimation(
rpc::ActorId walker);
void SetTrafficLightState(
rpc::ActorId traffic_light,
const rpc::TrafficLightState trafficLightState);
void SetTrafficLightGreenTime(
rpc::ActorId traffic_light,
float green_time);
void SetTrafficLightYellowTime(
rpc::ActorId traffic_light,
float yellow_time);
void SetTrafficLightRedTime(
rpc::ActorId traffic_light,
float red_time);
void FreezeTrafficLight(
rpc::ActorId traffic_light,
bool freeze);
void ResetTrafficLightGroup(
rpc::ActorId traffic_light);
void ResetAllTrafficLights();
void FreezeAllTrafficLights(bool frozen);
std::vector<geom::BoundingBox> GetLightBoxes(
rpc::ActorId traffic_light) const;
/// Returns a list of pairs where the firts element is the vehicle ID
/// and the second one is the light state
rpc::VehicleLightStateList GetVehiclesLightStates();
std::vector<ActorId> GetGroupTrafficLights(
rpc::ActorId traffic_light);
std::string StartRecorder(std::string name, bool additional_data);
void StopRecorder();
std::string ShowRecorderFileInfo(std::string name, bool show_all);
std::string ShowRecorderCollisions(std::string name, char type1, char type2);
std::string ShowRecorderActorsBlocked(std::string name, double min_time, double min_distance);
std::string ReplayFile(std::string name, double start, double duration,
uint32_t follow_id, bool replay_sensors);
void SetReplayerTimeFactor(double time_factor);
void SetReplayerIgnoreHero(bool ignore_hero);
void SetReplayerIgnoreSpectator(bool ignore_spectator);
void StopReplayer(bool keep_actors);
void SubscribeToStream(
const streaming::Token &token,
std::function<void(Buffer)> callback);
void SubscribeToGBuffer(
rpc::ActorId ActorId,
uint32_t GBufferId,
std::function<void(Buffer)> callback);
void UnSubscribeFromStream(const streaming::Token &token);
void EnableForROS(const streaming::Token &token);
void DisableForROS(const streaming::Token &token);
bool IsEnabledForROS(const streaming::Token &token);
void UnSubscribeFromGBuffer(
rpc::ActorId ActorId,
uint32_t GBufferId);
void DrawDebugShape(const rpc::DebugShape &shape);
void ApplyBatch(
std::vector<rpc::Command> commands,
bool do_tick_cue);
std::vector<rpc::CommandResponse> ApplyBatchSync(
std::vector<rpc::Command> commands,
bool do_tick_cue);
uint64_t SendTickCue();
std::vector<rpc::LightState> QueryLightsStateToServer() const;
void UpdateServerLightsState(
std::vector<rpc::LightState>& lights,
bool discard_client = false) const;
void UpdateDayNightCycle(const bool active) const;
/// Returns all the BBs of all the elements of the level
std::vector<geom::BoundingBox> GetLevelBBs(uint8_t queried_tag) const;
std::vector<rpc::EnvironmentObject> GetEnvironmentObjects(uint8_t queried_tag) const;
void EnableEnvironmentObjects(
std::vector<uint64_t> env_objects_ids,
bool enable) const;
std::pair<bool,rpc::LabelledPoint> ProjectPoint(
geom::Location location, geom::Vector3D direction, float search_distance) const;
std::vector<rpc::LabelledPoint> CastRay(
geom::Location start_location, geom::Location end_location) const;
private:
class Pimpl;
const std::unique_ptr<Pimpl> _pimpl;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,166 @@
// 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/client/detail/Episode.h"
#include "carla/Logging.h"
#include "carla/client/detail/Client.h"
#include "carla/client/detail/WalkerNavigation.h"
#include "carla/sensor/Deserializer.h"
#include "carla/trafficmanager/TrafficManager.h"
#include <exception>
namespace carla {
namespace client {
namespace detail {
using namespace std::chrono_literals;
static auto &CastData(const sensor::SensorData &data) {
using target_t = const sensor::data::RawEpisodeState;
return static_cast<target_t &>(data);
}
template <typename RangeT>
static auto GetActorsById_Impl(Client &client, CachedActorList &actors, const RangeT &actor_ids) {
auto missing_ids = actors.GetMissingIds(actor_ids);
if (!missing_ids.empty()) {
actors.InsertRange(client.GetActorsById(missing_ids));
}
return actors.GetActorsById(actor_ids);
}
Episode::Episode(Client &client, std::weak_ptr<Simulator> simulator)
: Episode(client, client.GetEpisodeInfo(), simulator) {}
Episode::Episode(Client &client, const rpc::EpisodeInfo &info, std::weak_ptr<Simulator> simulator)
: _client(client),
_state(std::make_shared<EpisodeState>(info.id)),
_simulator(simulator),
_token(info.token) {}
Episode::~Episode() {
try {
_client.UnSubscribeFromStream(_token);
} catch (const std::exception &e) {
log_error("exception trying to disconnect from episode:", e.what());
}
}
void Episode::Listen() {
std::weak_ptr<Episode> weak = shared_from_this();
_client.SubscribeToStream(_token, [weak](auto buffer) {
auto self = weak.lock();
if (self != nullptr) {
auto data = sensor::Deserializer::Deserialize(std::move(buffer));
auto next = std::make_shared<const EpisodeState>(CastData(*data));
auto prev = self->GetState();
// TODO: Update how the map change is detected
bool HasMapChanged = next->HasMapChanged();
bool UpdateLights = next->IsLightUpdatePending();
/// Check for pending exceptions (Mainly TM server closed)
if(self->_pending_exceptions) {
/// Mark pending exception false
self->_pending_exceptions = false;
/// Create exception for the error message
auto exception(self->_pending_exceptions_msg);
// Notify waiting threads that exception occurred
self->_snapshot.SetException(std::runtime_error(exception));
}
/// Sensor case: inconsistent data
else {
bool episode_changed = (next->GetEpisodeId() != prev->GetEpisodeId());
do {
if (prev->GetFrame() >= next->GetFrame() && !episode_changed) {
self->_on_tick_callbacks.Call(next);
return;
}
} while (!self->_state.compare_exchange(&prev, next));
if(UpdateLights || HasMapChanged) {
self->_on_light_update_callbacks.Call(next);
}
if(HasMapChanged) {
self->_should_update_map = true;
}
/// Episode change
if(episode_changed) {
self->OnEpisodeChanged();
}
// Notify waiting threads and do the callbacks.
self->_snapshot.SetValue(next);
// Call user callbacks.
self->_on_tick_callbacks.Call(next);
}
}
});
}
boost::optional<rpc::Actor> Episode::GetActorById(ActorId id) {
auto actor = _actors.GetActorById(id);
if (!actor.has_value()) {
auto actor_list = _client.GetActorsById({id});
if (!actor_list.empty()) {
actor = std::move(actor_list.front());
_actors.Insert(*actor);
}
}
return actor;
}
std::vector<rpc::Actor> Episode::GetActorsById(const std::vector<ActorId> &actor_ids) {
return GetActorsById_Impl(_client, _actors, actor_ids);
}
std::vector<rpc::Actor> Episode::GetActors() {
return GetActorsById_Impl(_client, _actors, GetState()->GetActorIds());
}
void Episode::OnEpisodeStarted() {
_actors.Clear();
_on_tick_callbacks.Clear();
_walker_navigation.reset();
traffic_manager::TrafficManager::Release();
}
void Episode::OnEpisodeChanged() {
traffic_manager::TrafficManager::Reset();
}
bool Episode::HasMapChangedSinceLastCall() {
if(_should_update_map) {
_should_update_map = false;
return true;
}
return false;
}
std::shared_ptr<WalkerNavigation> Episode::CreateNavigationIfMissing() {
std::shared_ptr<WalkerNavigation> nav;
do {
nav = _walker_navigation.load();
if (nav == nullptr) {
auto new_nav = std::make_shared<WalkerNavigation>(_simulator);
_walker_navigation.compare_exchange(&nav, new_nav);
}
} while (nav == nullptr);
return nav;
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,141 @@
// 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/AtomicSharedPtr.h"
#include "carla/NonCopyable.h"
#include "carla/RecurrentSharedFuture.h"
#include "carla/client/Timestamp.h"
#include "carla/client/WorldSnapshot.h"
#include "carla/client/detail/CachedActorList.h"
#include "carla/client/detail/CallbackList.h"
#include "carla/client/detail/EpisodeState.h"
#include "carla/client/detail/EpisodeProxy.h"
#include "carla/rpc/EpisodeInfo.h"
#include <vector>
namespace carla {
namespace client {
namespace detail {
class Client;
class WalkerNavigation;
/// Holds the current episode, and the current episode state.
///
/// The episode state changes in the background each time a world tick is
/// received. The episode may change with any background update if the
/// simulator has loaded a new episode.
class Episode
: public std::enable_shared_from_this<Episode>,
private NonCopyable {
public:
explicit Episode(Client &client, std::weak_ptr<Simulator> simulator);
~Episode();
void Listen();
auto GetId() const {
return GetState()->GetEpisodeId();
}
std::shared_ptr<const EpisodeState> GetState() const {
return _state.load();
}
void RegisterActor(rpc::Actor actor) {
_actors.Insert(std::move(actor));
}
boost::optional<rpc::Actor> GetActorById(ActorId id);
std::vector<rpc::Actor> GetActorsById(const std::vector<ActorId> &actor_ids);
std::vector<rpc::Actor> GetActors();
boost::optional<WorldSnapshot> WaitForState(time_duration timeout) {
return _snapshot.WaitFor(timeout);
}
size_t RegisterOnTickEvent(std::function<void(WorldSnapshot)> callback) {
return _on_tick_callbacks.Push(std::move(callback));
}
void RemoveOnTickEvent(size_t id) {
_on_tick_callbacks.Remove(id);
}
size_t RegisterOnMapChangeEvent(std::function<void(WorldSnapshot)> callback) {
return _on_map_change_callbacks.Push(std::move(callback));
}
void RemoveOnMapChangeEvent(size_t id) {
_on_map_change_callbacks.Remove(id);
}
size_t RegisterLightUpdateChangeEvent(std::function<void(WorldSnapshot)> callback) {
return _on_light_update_callbacks.Push(std::move(callback));
}
void RemoveLightUpdateChangeEvent(size_t id) {
_on_light_update_callbacks.Remove(id);
}
void SetPedestriansCrossFactor(float percentage);
void SetPedestriansSeed(unsigned int seed);
void AddPendingException(std::string e) {
_pending_exceptions = true;
_pending_exceptions_msg = e;
}
bool HasMapChangedSinceLastCall();
std::shared_ptr<WalkerNavigation> CreateNavigationIfMissing();
private:
Episode(Client &client, const rpc::EpisodeInfo &info, std::weak_ptr<Simulator> simulator);
void OnEpisodeStarted();
void OnEpisodeChanged();
Client &_client;
AtomicSharedPtr<const EpisodeState> _state;
std::string _pending_exceptions_msg;
CachedActorList _actors;
CallbackList<WorldSnapshot> _on_tick_callbacks;
CallbackList<WorldSnapshot> _on_map_change_callbacks;
CallbackList<WorldSnapshot> _on_light_update_callbacks;
RecurrentSharedFuture<WorldSnapshot> _snapshot;
AtomicSharedPtr<WalkerNavigation> _walker_navigation;
const streaming::Token _token;
bool _pending_exceptions = false;
bool _should_update_map = true;
std::weak_ptr<Simulator> _simulator;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,60 @@
// 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/client/detail/EpisodeProxy.h"
#include "carla/Exception.h"
#include "carla/client/detail/Simulator.h"
#include <exception>
namespace carla {
namespace client {
namespace detail {
static EpisodeProxyPointerType::Shared Load(EpisodeProxyPointerType::Strong ptr) {
return ptr.load();
}
static EpisodeProxyPointerType::Shared Load(EpisodeProxyPointerType::Weak ptr) {
return ptr.lock();
}
template <typename T>
EpisodeProxyImpl<T>::EpisodeProxyImpl(SharedPtrType simulator)
: _episode_id(simulator != nullptr ? simulator->GetCurrentEpisodeId() : 0u),
_simulator(std::move(simulator)) {}
template <typename T>
typename EpisodeProxyImpl<T>::SharedPtrType EpisodeProxyImpl<T>::TryLock() const noexcept {
auto ptr = Load(_simulator);
const bool is_valid = (ptr != nullptr) && (_episode_id == ptr->GetCurrentEpisodeId());
return is_valid ? ptr : nullptr;
}
template <typename T>
typename EpisodeProxyImpl<T>::SharedPtrType EpisodeProxyImpl<T>::Lock() const {
auto ptr = Load(_simulator);
if (ptr == nullptr) {
throw_exception(std::runtime_error(
"trying to operate on a destroyed actor; an actor's function "
"was called, but the actor is already destroyed."));
}
return ptr;
}
template <typename T>
void EpisodeProxyImpl<T>::Clear() noexcept {
_simulator.reset();
}
template class EpisodeProxyImpl<EpisodeProxyPointerType::Strong>;
template class EpisodeProxyImpl<EpisodeProxyPointerType::Weak>;
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,75 @@
// 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/AtomicSharedPtr.h"
#include <cstdint>
namespace carla {
namespace client {
namespace detail {
class Simulator;
struct EpisodeProxyPointerType {
using Shared = std::shared_ptr<Simulator>;
using Strong = AtomicSharedPtr<Simulator>;
using Weak = std::weak_ptr<Simulator>;
};
/// Provides access to the Simulator during a given episode. After the episode
/// is ended any access to the simulator throws an std::runtime_error.
template <typename PointerT>
class EpisodeProxyImpl {
public:
using SharedPtrType = EpisodeProxyPointerType::Shared;
EpisodeProxyImpl() = default;
EpisodeProxyImpl(SharedPtrType simulator);
template <typename T>
EpisodeProxyImpl(EpisodeProxyImpl<T> other)
: _episode_id(other._episode_id),
_simulator(other._simulator) {}
auto GetId() const noexcept {
return _episode_id;
}
SharedPtrType TryLock() const noexcept;
/// Same as TryLock but never return nullptr.
///
/// @throw std::runtime_error if episode is gone.
SharedPtrType Lock() const;
bool IsValid() const noexcept {
return TryLock() != nullptr;
}
void Clear() noexcept;
private:
template <typename T>
friend class EpisodeProxyImpl;
uint64_t _episode_id;
PointerT _simulator;
};
using EpisodeProxy = EpisodeProxyImpl<EpisodeProxyPointerType::Strong>;
using WeakEpisodeProxy = EpisodeProxyImpl<EpisodeProxyPointerType::Weak>;
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,41 @@
// 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/client/detail/EpisodeState.h"
namespace carla {
namespace client {
namespace detail {
EpisodeState::EpisodeState(const sensor::data::RawEpisodeState &state)
: _episode_id(state.GetEpisodeId()),
_timestamp(
state.GetFrame(),
state.GetGameTimeStamp(),
state.GetDeltaSeconds(),
state.GetPlatformTimeStamp()),
_map_origin(state.GetMapOrigin()),
_simulation_state(state.GetSimulationState()) {
_actors.reserve(state.size());
for (auto &&actor : state) {
DEBUG_ONLY(auto result = )
_actors.emplace(
actor.id,
ActorSnapshot{
actor.id,
actor.actor_state,
actor.transform,
actor.velocity,
actor.angular_velocity,
actor.acceleration,
actor.state});
DEBUG_ASSERT(result.second);
}
}
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,120 @@
// 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/Iterator.h"
#include "carla/ListView.h"
#include "carla/NonCopyable.h"
#include "carla/client/ActorSnapshot.h"
#include "carla/client/Timestamp.h"
#include "carla/geom/Vector3DInt.h"
#include "carla/sensor/data/RawEpisodeState.h"
#include <boost/optional.hpp>
#include <memory>
#include <unordered_map>
namespace carla {
namespace client {
namespace detail {
/// Represents the state of all the actors of an episode at a given frame.
class EpisodeState
: public std::enable_shared_from_this<EpisodeState>,
private NonCopyable {
using SimulationState = sensor::s11n::EpisodeStateSerializer::SimulationState;
public:
explicit EpisodeState(uint64_t episode_id) : _episode_id(episode_id) {}
explicit EpisodeState(const sensor::data::RawEpisodeState &state);
auto GetEpisodeId() const {
return _episode_id;
}
auto GetFrame() const {
return _timestamp.frame;
}
const auto &GetTimestamp() const {
return _timestamp;
}
SimulationState GetsimulationState() const {
return _simulation_state;
}
bool HasMapChanged() const {
return (_simulation_state & SimulationState::MapChange) != SimulationState::None;
}
bool IsLightUpdatePending() const {
return (_simulation_state & SimulationState::PendingLightUpdate) != 0;
}
bool ContainsActorSnapshot(ActorId actor_id) const {
return _actors.find(actor_id) != _actors.end();
}
ActorSnapshot GetActorSnapshot(ActorId id) const {
ActorSnapshot state;
CopyActorSnapshotIfPresent(id, state);
return state;
}
boost::optional<ActorSnapshot> GetActorSnapshotIfPresent(ActorId id) const {
boost::optional<ActorSnapshot> state;
CopyActorSnapshotIfPresent(id, state);
return state;
}
auto GetActorIds() const {
return MakeListView(
iterator::make_map_keys_const_iterator(_actors.begin()),
iterator::make_map_keys_const_iterator(_actors.end()));
}
size_t size() const {
return _actors.size();
}
auto begin() const {
return iterator::make_map_values_const_iterator(_actors.begin());
}
auto end() const {
return iterator::make_map_values_const_iterator(_actors.end());
}
private:
template <typename T>
void CopyActorSnapshotIfPresent(ActorId id, T &value) const {
auto it = _actors.find(id);
if (it != _actors.end()) {
value = it->second;
}
}
const uint64_t _episode_id;
const Timestamp _timestamp;
geom::Vector3DInt _map_origin;
SimulationState _simulation_state;
std::unordered_map<ActorId, ActorSnapshot> _actors;
};
} // namespace detail
} // namespace client
} // namespace carla

View File

@ -0,0 +1,466 @@
// 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/client/detail/Simulator.h"
#include "carla/Debug.h"
#include "carla/Exception.h"
#include "carla/Logging.h"
#include "carla/RecurrentSharedFuture.h"
#include "carla/client/BlueprintLibrary.h"
#include "carla/client/FileTransfer.h"
#include "carla/client/Map.h"
#include "carla/client/Sensor.h"
#include "carla/client/TimeoutException.h"
#include "carla/client/WalkerAIController.h"
#include "carla/client/detail/ActorFactory.h"
#include "carla/client/detail/WalkerNavigation.h"
#include "carla/trafficmanager/TrafficManager.h"
#include "carla/sensor/Deserializer.h"
#include <exception>
#include <thread>
using namespace std::string_literals;
namespace carla {
namespace client {
namespace detail {
// ===========================================================================
// -- Static local methods ---------------------------------------------------
// ===========================================================================
static void ValidateVersions(Client &client) {
const auto vc = client.GetClientVersion();
const auto vs = client.GetServerVersion();
if (vc != vs) {
log_warning(
"Version mismatch detected: You are trying to connect to a simulator",
"that might be incompatible with this API");
log_warning("Client API version =", vc);
log_warning("Simulator API version =", vs);
}
}
static bool SynchronizeFrame(uint64_t frame, const Episode &episode, time_duration timeout) {
bool result = true;
auto start = std::chrono::system_clock::now();
while (frame > episode.GetState()->GetTimestamp().frame) {
std::this_thread::yield();
auto end = std::chrono::system_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end-start);
if(timeout.to_chrono() < diff) {
result = false;
break;
}
}
if(result) {
carla::traffic_manager::TrafficManager::Tick();
}
return result;
}
// ===========================================================================
// -- Constructor ------------------------------------------------------------
// ===========================================================================
Simulator::Simulator(
const std::string &host,
const uint16_t port,
const size_t worker_threads,
const bool enable_garbage_collection)
: LIBCARLA_INITIALIZE_LIFETIME_PROFILER("SimulatorClient("s + host + ":" + std::to_string(port) + ")"),
_client(host, port, worker_threads),
_light_manager(new LightManager()),
_gc_policy(enable_garbage_collection ?
GarbageCollectionPolicy::Enabled : GarbageCollectionPolicy::Disabled) {}
// ===========================================================================
// -- Load a new episode -----------------------------------------------------
// ===========================================================================
EpisodeProxy Simulator::LoadEpisode(std::string map_name, bool reset_settings, rpc::MapLayer map_layers) {
const auto id = GetCurrentEpisode().GetId();
_client.LoadEpisode(std::move(map_name), reset_settings, map_layers);
// We are waiting 50ms for the server to reload the episode.
// If in this time we have not detected a change of episode, we try again
// 'number_of_attempts' times.
// TODO This time is completly arbitrary so we need to improve
// this pipeline to not depend in this time because this timeout
// could result that the client resume the simulation in different
// initial ticks when loading a map in syncronous mode.
size_t number_of_attempts = _client.GetTimeout().milliseconds() / 50u;
for (auto i = 0u; i < number_of_attempts; ++i) {
using namespace std::literals::chrono_literals;
if (_client.GetEpisodeSettings().synchronous_mode)
_client.SendTickCue();
_episode->WaitForState(50ms);
auto episode = GetCurrentEpisode();
if (episode.GetId() != id) {
return episode;
}
}
throw_exception(std::runtime_error("failed to connect to newly created map"));
}
EpisodeProxy Simulator::LoadOpenDriveEpisode(
std::string opendrive,
const rpc::OpendriveGenerationParameters & params, bool reset_settings) {
// The "OpenDriveMap" is an ".umap" located in:
// "carla/Unreal/CarlaUE4/Content/Carla/Maps/"
// It will load the last sended OpenDRIVE by client's "LoadOpenDriveEpisode()"
constexpr auto custom_opendrive_map = "OpenDriveMap";
_client.CopyOpenDriveToServer(std::move(opendrive), params);
return LoadEpisode(custom_opendrive_map, reset_settings);
}
// ===========================================================================
// -- Access to current episode ----------------------------------------------
// ===========================================================================
void Simulator::GetReadyCurrentEpisode() {
if (_episode == nullptr) {
ValidateVersions(_client);
_episode = std::make_shared<Episode>(_client, std::weak_ptr<Simulator>(shared_from_this()));
_episode->Listen();
if (!GetEpisodeSettings().synchronous_mode) {
WaitForTick(_client.GetTimeout());
}
_light_manager->SetEpisode(WeakEpisodeProxy{shared_from_this()});
}
}
EpisodeProxy Simulator::GetCurrentEpisode() {
GetReadyCurrentEpisode();
return EpisodeProxy{shared_from_this()};
}
bool Simulator::ShouldUpdateMap(rpc::MapInfo& map_info) {
if (!_cached_map) {
return true;
}
if (map_info.name != _cached_map->GetName() ||
_open_drive_file.size() != _cached_map->GetOpenDrive().size()) {
return true;
}
return false;
}
SharedPtr<Map> Simulator::GetCurrentMap() {
DEBUG_ASSERT(_episode != nullptr);
if (!_cached_map || _episode->HasMapChangedSinceLastCall()) {
rpc::MapInfo map_info = _client.GetMapInfo();
std::string map_name;
std::string map_base_path;
bool fill_base_string = false;
for (int i = map_info.name.size() - 1; i >= 0; --i) {
if (fill_base_string == false && map_info.name[i] != '/') {
map_name += map_info.name[i];
} else {
map_base_path += map_info.name[i];
fill_base_string = true;
}
}
std::reverse(map_name.begin(), map_name.end());
std::reverse(map_base_path.begin(), map_base_path.end());
std::string XODRFolder = map_base_path + "/OpenDrive/" + map_name + ".xodr";
if (FileTransfer::FileExists(XODRFolder) == false) _client.GetRequiredFiles();
_open_drive_file = _client.GetMapData();
_cached_map = MakeShared<Map>(map_info, _open_drive_file);
}
return _cached_map;
}
// ===========================================================================
// -- Required files ---------------------------------------------------------
// ===========================================================================
bool Simulator::SetFilesBaseFolder(const std::string &path) {
return _client.SetFilesBaseFolder(path);
}
std::vector<std::string> Simulator::GetRequiredFiles(const std::string &folder, const bool download) const {
return _client.GetRequiredFiles(folder, download);
}
void Simulator::RequestFile(const std::string &name) const {
_client.RequestFile(name);
}
std::vector<uint8_t> Simulator::GetCacheFile(const std::string &name, const bool request_otherwise) const {
return _client.GetCacheFile(name, request_otherwise);
}
// ===========================================================================
// -- Tick -------------------------------------------------------------------
// ===========================================================================
WorldSnapshot Simulator::WaitForTick(time_duration timeout) {
DEBUG_ASSERT(_episode != nullptr);
// tick pedestrian navigation
NavigationTick();
auto result = _episode->WaitForState(timeout);
if (!result.has_value()) {
throw_exception(TimeoutException(_client.GetEndpoint(), timeout));
}
return *result;
}
uint64_t Simulator::Tick(time_duration timeout) {
DEBUG_ASSERT(_episode != nullptr);
// tick pedestrian navigation
NavigationTick();
// send tick command
const auto frame = _client.SendTickCue();
// waits until new episode is received
bool result = SynchronizeFrame(frame, *_episode, timeout);
if (!result) {
throw_exception(TimeoutException(_client.GetEndpoint(), timeout));
}
return frame;
}
// ===========================================================================
// -- Access to global objects in the episode --------------------------------
// ===========================================================================
SharedPtr<BlueprintLibrary> Simulator::GetBlueprintLibrary() {
auto defs = _client.GetActorDefinitions();
return MakeShared<BlueprintLibrary>(std::move(defs));
}
rpc::VehicleLightStateList Simulator::GetVehiclesLightStates() {
return _client.GetVehiclesLightStates();
}
SharedPtr<Actor> Simulator::GetSpectator() {
return MakeActor(_client.GetSpectator());
}
uint64_t Simulator::SetEpisodeSettings(const rpc::EpisodeSettings &settings) {
if (settings.synchronous_mode && !settings.fixed_delta_seconds) {
log_warning(
"synchronous mode enabled with variable delta seconds. It is highly "
"recommended to set 'fixed_delta_seconds' when running on synchronous mode.");
}
else if (settings.synchronous_mode && settings.substepping) {
if(settings.max_substeps < 1 || settings.max_substeps > 16) {
log_warning(
"synchronous mode and substepping are enabled but the number of substeps is not valid. "
"Please be aware that this value needs to be in the range [1-16].");
}
double n_substeps = settings.fixed_delta_seconds.get() / settings.max_substep_delta_time;
if (n_substeps > static_cast<double>(settings.max_substeps)) {
log_warning(
"synchronous mode and substepping are enabled but the values for the simulation are not valid. "
"The values should fulfil fixed_delta_seconds <= max_substep_delta_time * max_substeps. "
"Be very careful about that, the time deltas are not guaranteed.");
}
}
const auto frame = _client.SetEpisodeSettings(settings);
using namespace std::literals::chrono_literals;
SynchronizeFrame(frame, *_episode, 1s);
return frame;
}
// ===========================================================================
// -- AI ---------------------------------------------------------------------
// ===========================================================================
std::shared_ptr<WalkerNavigation> Simulator::GetNavigation() {
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
return nav;
}
// tick pedestrian navigation
void Simulator::NavigationTick() {
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
nav->Tick(_episode);
}
void Simulator::RegisterAIController(const WalkerAIController &controller) {
auto walker = controller.GetParent();
if (walker == nullptr) {
throw_exception(std::runtime_error(controller.GetDisplayId() + ": not attached to walker"));
return;
}
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
nav->RegisterWalker(walker->GetId(), controller.GetId());
}
void Simulator::UnregisterAIController(const WalkerAIController &controller) {
auto walker = controller.GetParent();
if (walker == nullptr) {
throw_exception(std::runtime_error(controller.GetDisplayId() + ": not attached to walker"));
return;
}
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
nav->UnregisterWalker(walker->GetId(), controller.GetId());
}
boost::optional<geom::Location> Simulator::GetRandomLocationFromNavigation() {
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
return nav->GetRandomLocation();
}
void Simulator::SetPedestriansCrossFactor(float percentage) {
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
nav->SetPedestriansCrossFactor(percentage);
}
void Simulator::SetPedestriansSeed(unsigned int seed) {
DEBUG_ASSERT(_episode != nullptr);
auto nav = _episode->CreateNavigationIfMissing();
nav->SetPedestriansSeed(seed);
}
// ===========================================================================
// -- General operations with actors -----------------------------------------
// ===========================================================================
SharedPtr<Actor> Simulator::SpawnActor(
const ActorBlueprint &blueprint,
const geom::Transform &transform,
Actor *parent,
rpc::AttachmentType attachment_type,
GarbageCollectionPolicy gc) {
rpc::Actor actor;
if (parent != nullptr) {
actor = _client.SpawnActorWithParent(
blueprint.MakeActorDescription(),
transform,
parent->GetId(),
attachment_type);
} else {
actor = _client.SpawnActor(
blueprint.MakeActorDescription(),
transform);
}
DEBUG_ASSERT(_episode != nullptr);
_episode->RegisterActor(actor);
const auto gca = (gc == GarbageCollectionPolicy::Inherit ? _gc_policy : gc);
auto result = ActorFactory::MakeActor(GetCurrentEpisode(), actor, gca);
log_debug(
result->GetDisplayId(),
"created",
gca == GarbageCollectionPolicy::Enabled ? "with" : "without",
"garbage collection");
return result;
}
bool Simulator::DestroyActor(Actor &actor) {
bool success = true;
success = _client.DestroyActor(actor.GetId());
if (success) {
// Remove it's persistent state so it cannot access the client anymore.
actor.GetEpisode().Clear();
log_debug(actor.GetDisplayId(), "destroyed.");
} else {
log_debug("failed to destroy", actor.GetDisplayId());
}
return success;
}
// ===========================================================================
// -- Operations with sensors ------------------------------------------------
// ===========================================================================
void Simulator::SubscribeToSensor(
const Sensor &sensor,
std::function<void(SharedPtr<sensor::SensorData>)> callback) {
DEBUG_ASSERT(_episode != nullptr);
_client.SubscribeToStream(
sensor.GetActorDescription().GetStreamToken(),
[cb=std::move(callback), ep=WeakEpisodeProxy{shared_from_this()}](auto buffer) {
auto data = sensor::Deserializer::Deserialize(std::move(buffer));
data->_episode = ep.TryLock();
cb(std::move(data));
});
}
void Simulator::UnSubscribeFromSensor(Actor &sensor) {
_client.UnSubscribeFromStream(sensor.GetActorDescription().GetStreamToken());
// If in the future we need to unsubscribe from each gbuffer individually, it should be done here.
}
void Simulator::EnableForROS(const Sensor &sensor) {
_client.EnableForROS(sensor.GetActorDescription().GetStreamToken());
}
void Simulator::DisableForROS(const Sensor &sensor) {
_client.DisableForROS(sensor.GetActorDescription().GetStreamToken());
}
bool Simulator::IsEnabledForROS(const Sensor &sensor) {
return _client.IsEnabledForROS(sensor.GetActorDescription().GetStreamToken());
}
void Simulator::SubscribeToGBuffer(
Actor &actor,
uint32_t gbuffer_id,
std::function<void(SharedPtr<sensor::SensorData>)> callback) {
_client.SubscribeToGBuffer(actor.GetId(), gbuffer_id,
[cb=std::move(callback), ep=WeakEpisodeProxy{shared_from_this()}](auto buffer) {
auto data = sensor::Deserializer::Deserialize(std::move(buffer));
data->_episode = ep.TryLock();
cb(std::move(data));
});
}
void Simulator::UnSubscribeFromGBuffer(Actor &actor, uint32_t gbuffer_id) {
_client.UnSubscribeFromGBuffer(actor.GetId(), gbuffer_id);
}
void Simulator::FreezeAllTrafficLights(bool frozen) {
_client.FreezeAllTrafficLights(frozen);
}
// =========================================================================
/// -- Texture updating operations
// =========================================================================
void Simulator::ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureColor& Texture) {
_client.ApplyColorTextureToObjects(objects_name, parameter, Texture);
}
void Simulator::ApplyColorTextureToObjects(
const std::vector<std::string> &objects_name,
const rpc::MaterialParameter& parameter,
const rpc::TextureFloatColor& Texture) {
_client.ApplyColorTextureToObjects(objects_name, parameter, Texture);
}
std::vector<std::string> Simulator::GetNamesOfAllObjects() const {
return _client.GetNamesOfAllObjects();
}
} // namespace detail
} // namespace client
} // namespace carla

Some files were not shown because too many files have changed in this diff Show More