init
This commit is contained in:
commit
220ecf68c6
75
include/carla/AtomicList.h
Normal file
75
include/carla/AtomicList.h
Normal 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
|
65
include/carla/AtomicSharedPtr.h
Normal file
65
include/carla/AtomicSharedPtr.h
Normal 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
14
include/carla/Buffer.cpp
Normal 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
375
include/carla/Buffer.h
Normal 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
|
60
include/carla/BufferPool.h
Normal file
60
include/carla/BufferPool.h
Normal 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
153
include/carla/BufferView.h
Normal 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
84
include/carla/Debug.h
Normal 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)
|
57
include/carla/Exception.cpp
Normal file
57
include/carla/Exception.cpp
Normal 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
43
include/carla/Exception.h
Normal 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
|
54
include/carla/FileSystem.cpp
Normal file
54
include/carla/FileSystem.cpp
Normal 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
|
40
include/carla/FileSystem.h
Normal file
40
include/carla/FileSystem.h
Normal 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
|
77
include/carla/Functional.h
Normal file
77
include/carla/Functional.h
Normal 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
51
include/carla/Iterator.h
Normal 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
87
include/carla/ListView.h
Normal 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
151
include/carla/Logging.h
Normal 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
33
include/carla/Memory.h
Normal 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
|
38
include/carla/MoveHandler.h
Normal file
38
include/carla/MoveHandler.h
Normal 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
39
include/carla/MsgPack.h
Normal 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
|
171
include/carla/MsgPackAdaptors.h
Normal file
171
include/carla/MsgPackAdaptors.h
Normal 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
|
37
include/carla/NonCopyable.h
Normal file
37
include/carla/NonCopyable.h
Normal 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
22
include/carla/Platform.h
Normal 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
116
include/carla/PythonUtil.h
Normal 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
|
143
include/carla/RecurrentSharedFuture.h
Normal file
143
include/carla/RecurrentSharedFuture.h
Normal 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
19
include/carla/Sockets.h
Normal 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
60
include/carla/StopWatch.h
Normal 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
|
25
include/carla/StringUtil.cpp
Normal file
25
include/carla/StringUtil.cpp
Normal 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
|
80
include/carla/StringUtil.h
Normal file
80
include/carla/StringUtil.h
Normal 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
|
54
include/carla/ThreadGroup.h
Normal file
54
include/carla/ThreadGroup.h
Normal 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
|
90
include/carla/ThreadPool.h
Normal file
90
include/carla/ThreadPool.h
Normal 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
67
include/carla/Time.h
Normal 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
|
26
include/carla/TypeTraits.h
Normal file
26
include/carla/TypeTraits.h
Normal 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
15
include/carla/Version.h
Normal 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
|
117
include/carla/client/Actor.cpp
Normal file
117
include/carla/client/Actor.cpp
Normal 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
|
141
include/carla/client/Actor.h
Normal file
141
include/carla/client/Actor.h
Normal 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
|
107
include/carla/client/ActorAttribute.cpp
Normal file
107
include/carla/client/ActorAttribute.cpp
Normal 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
|
241
include/carla/client/ActorAttribute.h
Normal file
241
include/carla/client/ActorAttribute.h
Normal 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
|
66
include/carla/client/ActorBlueprint.cpp
Normal file
66
include/carla/client/ActorBlueprint.cpp
Normal 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
|
124
include/carla/client/ActorBlueprint.h
Normal file
124
include/carla/client/ActorBlueprint.h
Normal 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
|
43
include/carla/client/ActorList.cpp
Normal file
43
include/carla/client/ActorList.cpp
Normal 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
|
72
include/carla/client/ActorList.h
Normal file
72
include/carla/client/ActorList.h
Normal 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
|
29
include/carla/client/ActorSnapshot.h
Normal file
29
include/carla/client/ActorSnapshot.h
Normal 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
|
89
include/carla/client/BlueprintLibrary.cpp
Normal file
89
include/carla/client/BlueprintLibrary.cpp
Normal 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
|
88
include/carla/client/BlueprintLibrary.h
Normal file
88
include/carla/client/BlueprintLibrary.h
Normal 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
|
192
include/carla/client/Client.h
Normal file
192
include/carla/client/Client.h
Normal 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
|
21
include/carla/client/ClientSideSensor.h
Normal file
21
include/carla/client/ClientSideSensor.h
Normal 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
|
85
include/carla/client/DebugHelper.cpp
Normal file
85
include/carla/client/DebugHelper.cpp
Normal 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
|
72
include/carla/client/DebugHelper.h
Normal file
72
include/carla/client/DebugHelper.h
Normal 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
|
82
include/carla/client/FIleTransfer.cpp
Normal file
82
include/carla/client/FIleTransfer.cpp
Normal 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
|
42
include/carla/client/FileTransfer.h
Normal file
42
include/carla/client/FileTransfer.h
Normal 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
|
19
include/carla/client/GarbageCollectionPolicy.h
Normal file
19
include/carla/client/GarbageCollectionPolicy.h
Normal 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
|
29
include/carla/client/Junction.cpp
Normal file
29
include/carla/client/Junction.cpp
Normal 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
|
52
include/carla/client/Junction.h
Normal file
52
include/carla/client/Junction.h
Normal 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
|
143
include/carla/client/Landmark.h
Normal file
143
include/carla/client/Landmark.h
Normal 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
|
183
include/carla/client/LaneInvasionSensor.cpp
Normal file
183
include/carla/client/LaneInvasionSensor.cpp
Normal 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
|
50
include/carla/client/LaneInvasionSensor.h
Normal file
50
include/carla/client/LaneInvasionSensor.h
Normal 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
|
92
include/carla/client/Light.cpp
Normal file
92
include/carla/client/Light.cpp
Normal 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
|
80
include/carla/client/Light.h
Normal file
80
include/carla/client/Light.h
Normal 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
|
335
include/carla/client/LightManager.cpp
Normal file
335
include/carla/client/LightManager.cpp
Normal 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
|
113
include/carla/client/LightManager.h
Normal file
113
include/carla/client/LightManager.h
Normal 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
|
50
include/carla/client/LightState.h
Normal file
50
include/carla/client/LightState.h
Normal 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
|
192
include/carla/client/Map.cpp
Normal file
192
include/carla/client/Map.cpp
Normal 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
110
include/carla/client/Map.h
Normal 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
|
36
include/carla/client/Sensor.h
Normal file
36
include/carla/client/Sensor.h
Normal 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
|
109
include/carla/client/ServerSideSensor.cpp
Normal file
109
include/carla/client/ServerSideSensor.cpp
Normal 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
|
70
include/carla/client/ServerSideSensor.h
Normal file
70
include/carla/client/ServerSideSensor.h
Normal 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
|
23
include/carla/client/TimeoutException.cpp
Normal file
23
include/carla/client/TimeoutException.cpp
Normal 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
|
26
include/carla/client/TimeoutException.h
Normal file
26
include/carla/client/TimeoutException.h
Normal 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
|
72
include/carla/client/Timestamp.h
Normal file
72
include/carla/client/Timestamp.h
Normal 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 ×tamp) {
|
||||
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
|
140
include/carla/client/TrafficLight.cpp
Normal file
140
include/carla/client/TrafficLight.cpp
Normal 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
|
82
include/carla/client/TrafficLight.h
Normal file
82
include/carla/client/TrafficLight.h
Normal 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
|
19
include/carla/client/TrafficSign.cpp
Normal file
19
include/carla/client/TrafficSign.cpp
Normal 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
|
29
include/carla/client/TrafficSign.h
Normal file
29
include/carla/client/TrafficSign.h
Normal 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
|
152
include/carla/client/Vehicle.cpp
Normal file
152
include/carla/client/Vehicle.cpp
Normal 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
|
151
include/carla/client/Vehicle.h
Normal file
151
include/carla/client/Vehicle.h
Normal 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
|
42
include/carla/client/Walker.cpp
Normal file
42
include/carla/client/Walker.cpp
Normal 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
|
48
include/carla/client/Walker.h
Normal file
48
include/carla/client/Walker.h
Normal 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
|
84
include/carla/client/WalkerAIController.cpp
Normal file
84
include/carla/client/WalkerAIController.cpp
Normal 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
|
34
include/carla/client/WalkerAIController.h
Normal file
34
include/carla/client/WalkerAIController.h
Normal 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
|
256
include/carla/client/Waypoint.cpp
Normal file
256
include/carla/client/Waypoint.cpp
Normal 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
|
122
include/carla/client/Waypoint.h
Normal file
122
include/carla/client/Waypoint.h
Normal 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
|
387
include/carla/client/World.cpp
Normal file
387
include/carla/client/World.cpp
Normal 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
|
239
include/carla/client/World.h
Normal file
239
include/carla/client/World.h
Normal 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
|
77
include/carla/client/WorldSnapshot.h
Normal file
77
include/carla/client/WorldSnapshot.h
Normal 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
|
102
include/carla/client/detail/ActorFactory.cpp
Normal file
102
include/carla/client/detail/ActorFactory.cpp
Normal 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
|
40
include/carla/client/detail/ActorFactory.h
Normal file
40
include/carla/client/detail/ActorFactory.h
Normal 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
|
38
include/carla/client/detail/ActorState.cpp
Normal file
38
include/carla/client/detail/ActorState.cpp
Normal 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
|
102
include/carla/client/detail/ActorState.h
Normal file
102
include/carla/client/detail/ActorState.h
Normal 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
|
25
include/carla/client/detail/ActorVariant.cpp
Normal file
25
include/carla/client/detail/ActorVariant.cpp
Normal 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
|
99
include/carla/client/detail/ActorVariant.h
Normal file
99
include/carla/client/detail/ActorVariant.h
Normal 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
|
126
include/carla/client/detail/CachedActorList.h
Normal file
126
include/carla/client/detail/CachedActorList.h
Normal 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
|
73
include/carla/client/detail/CallbackList.h
Normal file
73
include/carla/client/detail/CallbackList.h
Normal 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
|
699
include/carla/client/detail/Client.cpp
Normal file
699
include/carla/client/detail/Client.cpp
Normal 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
|
440
include/carla/client/detail/Client.h
Normal file
440
include/carla/client/detail/Client.h
Normal 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
|
166
include/carla/client/detail/Episode.cpp
Normal file
166
include/carla/client/detail/Episode.cpp
Normal 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
|
141
include/carla/client/detail/Episode.h
Normal file
141
include/carla/client/detail/Episode.h
Normal 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
|
60
include/carla/client/detail/EpisodeProxy.cpp
Normal file
60
include/carla/client/detail/EpisodeProxy.cpp
Normal 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
|
75
include/carla/client/detail/EpisodeProxy.h
Normal file
75
include/carla/client/detail/EpisodeProxy.h
Normal 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
|
41
include/carla/client/detail/EpisodeState.cpp
Normal file
41
include/carla/client/detail/EpisodeState.cpp
Normal 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
|
120
include/carla/client/detail/EpisodeState.h
Normal file
120
include/carla/client/detail/EpisodeState.h
Normal 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
|
466
include/carla/client/detail/Simulator.cpp
Normal file
466
include/carla/client/detail/Simulator.cpp
Normal 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
Loading…
Reference in New Issue
Block a user