Cogs.Core
Utils.h
1#pragma once
2
3#include <glm/glm.hpp>
4#include <glm/gtc/type_ptr.hpp>
5
6#include <vector>
7#include <type_traits>
8#include <algorithm>
9#include <sstream>
10#include "Components/Core/MeshComponent.h"
11
12#include "Components/DataSetComponent.h"
13#include "Components/DataRefComponent.h"
14#include "Systems/DataSetSystem.h"
15#include "Foundation/Logging/Logger.h"
16
17
18#define ECHOSOUNDER_ASSERT_EQUAL(a,b) do { if(!((a)==(b))) EchosounderDump(#a, a, #b, b,"==", __FILE__, __LINE__);} while(0)
19#define ECHOSOUNDER_ASSERT_NOT_EQUAL(a,b) do { if(!((a)!=(b))) EchosounderDump(#a, a, #b, b,"!=", __FILE__, __LINE__);} while(0)
20
21#define ECHOSOUNDER_ASSERT_LESS(a,b) do { if(!((a)<(b))) EchosounderDump(#a, a, #b, b,"<", __FILE__, __LINE__);} while(0)
22#define ECHOSOUNDER_ASSERT_LESS_EQUAL(a,b) do { if(!((a)<=(b))) EchosounderDump(#a, a, #b, b,"<=", __FILE__, __LINE__);} while(0)
23#define ECHOSOUNDER_ASSERT_LESS_EQUAL_FLAG(a,b) do { if(!((a)<=(b))) {EchosounderDump(#a, a, #b, b,"<=", __FILE__, __LINE__); error = true;}} while(0)
24#define ECHOSOUNDER_ASSERT_EQUAL_FLAG(a,b) do { if(!((a)==(b))) {EchosounderDump(#a, a, #b, b,"==", __FILE__, __LINE__); error = true;}} while(0)
25
26#define ECHOSOUNDER_ASSERT_IS_FINITE(a) do { if(!std::isfinite(a)) { LOG_ERROR(Cogs::Logging::getLogger("EchoSounder"), "%s@%d: %s is not finite (=%f).", __FILE__, __LINE__, #a, a); } } while(0)
27
28#define ECHOSOUNDER_ASSERT_THROW_EQUAL(a,b) do { if(!((a)==(b))) throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"==", __FILE__, __LINE__));} while(0)
29#define ECHOSOUNDER_ASSERT_THROW_NOT_EQUAL(a,b) do { if(!((a)!=(b))) throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"!=", __FILE__, __LINE__));} while(0)
30
31#define ECHOSOUNDER_ASSERT_THROW_LESS(a,b) do { if(!((a)<(b))) throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"<", __FILE__, __LINE__));} while(0)
32#define ECHOSOUNDER_ASSERT_THROW_LESS_EQUAL(a,b) do { if(!((a)<=(b))) throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"<=", __FILE__, __LINE__));} while(0)
33#define ECHOSOUNDER_ASSERT_THROW_LESS_EQUAL_FLAG(a,b) do { if(!((a)<=(b))) {throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"<=", __FILE__, __LINE__)); error = true;}} while(0)
34#define ECHOSOUNDER_ASSERT_THROW_EQUAL_FLAG(a,b) do { if(!((a)==(b))) {throw std::runtime_error(EchosounderDumpString(#a, a, #b, b,"==", __FILE__, __LINE__)); error = true;}} while(0)
35
36#define ECHOSOUNDER_ASSERT_THROW_IS_FINITE(a) do { if(!std::isfinite(a)) {throw std::runtime_error(EchoSounderWhereString(__FILE__, __LINE__, "Is not finite.")); } } while(0)
37
38
39namespace {
40
41 std::string EchoSounderWhereString(const std::string& file, int line, const std::string& msg)
42 {
43 std::stringstream o;
44 o << file << '@' << line << ": " << msg;
45 return o.str();
46 }
47
48 template<typename S, typename T>
49 std::string EchosounderDumpString(const std::string& aStr, const S& a,
50 const std::string& bStr, const T& b,
51 const std::string& op,
52 const std::string& file, int line)
53 {
54 std::stringstream o;
55 o << file << '@' << line << ": " << aStr << "(=" << a << ") " << op << ' ' << bStr << "(=" << b << ") failed.";
56 return o.str();
57 }
58
59 template<typename S, typename T>
60 void EchosounderDump(const std::string& aStr, const S& a,
61 const std::string& bStr, const T& b,
62 const std::string& op,
63 const std::string& file, int line)
64 {
65 LOG_ERROR(Cogs::Logging::getLogger("EchoSounder"), "%s", EchosounderDumpString(aStr, a, bStr, b, op, file, line).c_str());
66#ifdef _DEBUG
67 assert(false);
68#endif
69 }
70
71 inline uint32_t unwrappedDistance(const uint32_t hi, const uint32_t lo, const uint32_t wrap)
72 {
73 return hi - lo + (hi < lo ? wrap : 0);
74 }
75
76 template<typename S, typename D>
77 inline void wrappableMemCopy(D& dst, const S& src, int lo, int hi, int period, int stride)
78 {
79 static_assert(std::is_same<S::value_type, D::value_type>::value, "Source and destination types must match");
80
81 if (lo < hi) {
82 dst.resize(stride*(hi - lo));
83
84 auto o = lo*stride;
85 auto n = (hi - lo)*stride;
86 debug_assert(o + n <= src.size());
87 std::memcpy(dst.data(), src.data() + o, sizeof(S::value_type)*n);
88 }
89 else {
90 dst.resize(stride*(hi - lo + period));
91
92 auto o = lo*stride;
93 auto n = (period - lo)*stride;
94 debug_assert(o + n <= src.size());
95 std::memcpy(dst.data(), src.data() + o, sizeof(S::value_type)*n);
96
97 o = (period - lo)*stride;
98 n = hi*stride;
99 debug_assert(o + n <= src.size());
100 std::memcpy(dst.data() + o, src.data(), sizeof(S::value_type)*n);
101 }
102 }
103
104
105 void clearGeometry(Cogs::ComponentModel::Component & comp)
106 {
107 auto * meshComp = comp.getComponent<Cogs::Core::MeshComponent>();
109 meshComp->setChanged();
110 }
111
112
113
114 template<typename Container>
115 int locateContainingInterval(const int fullIndexRange_a, // The range of indices (inclusive) to search.
116 const int fullIndexRange_b,
117 const int M, // Buffer count
118 const Container& timestamp, // All timestamps
119 const int64_t time) // Timestamp to find the range for.
120 {
121 auto currentIndexRange_a = fullIndexRange_a;
122 auto currentIndexRange_b = fullIndexRange_b;
123 auto currentTickRange_a = timestamp[currentIndexRange_a];
124 auto currentTickRange_b = timestamp[currentIndexRange_b % M];
125
126 int index = currentIndexRange_a;
127
128 bisectLoop:
129 if (time <= currentTickRange_a) { // Timestamp is older than search-able range,
130 index = currentIndexRange_a; // clamp to start and stop.
131 }
132 else if (currentTickRange_b <= time) { // Timestamp is more recent than search-able range,
133 index = currentIndexRange_b; // clamp to end and stop.
134 }
135 else if (currentIndexRange_b - currentIndexRange_a < 2) { // Timestamp is between two slices in search-able range,
136 index = currentIndexRange_a; // choose the oldest slice and stop.
137 }
138 else { // Timestamp is in a range of more than two slices.
139
140 // Choose bisection pivot. Pivot is placed proportionally with tick-range sizes.
141 int d = currentIndexRange_b - currentIndexRange_a - 2;
142 int i = static_cast<int>(((time - currentTickRange_a)*d) / (currentTickRange_b - currentTickRange_a));
143
144 // Clamping not strictly necessary, but guarantees termination in case timestamps are garbage.
145 int mi = currentIndexRange_a + 1 + std::max(0, std::min(d, i));
146
147 int64_t mt = timestamp[mi % M];
148 if (time < mt) { // Timestamp is older than pivot.
149
150 currentIndexRange_b = mi;
151 currentTickRange_b = mt;
152 }
153 else { // Timestamp is more recent than pivot.
154 currentIndexRange_a = mi;
155 currentTickRange_a = mt;
156 }
157 goto bisectLoop;
158 }
159
160 if (fullIndexRange_a < index) {
161 ECHOSOUNDER_ASSERT_THROW_LESS_EQUAL(timestamp[index % M], time);
162 }
163 if (index + 2 <= fullIndexRange_b) {
164 ECHOSOUNDER_ASSERT_THROW_LESS(time, timestamp[(index + 1) % M]);
165 }
166
167 return index;
168 }
169
170
171 bool getDataSet(const Cogs::Core::EchoSounder::DataSetComponent** dataCompOut,
172 const Cogs::Core::EchoSounder::DataSetData** dataDataOut,
174 const Cogs::Core::EchoSounder::DataSetSystem* dataSetSystem)
175 {
176 *dataCompOut = nullptr;
177 *dataDataOut = nullptr;
178
179 const auto * refComp = comp.getComponent<Cogs::Core::EchoSounder::DataRefComponent>();
180 if (refComp->data) {
181
182 auto * dataComp = refComp->data->getComponent<Cogs::Core::EchoSounder::DataSetComponent>();
183 auto * dataData = &dataSetSystem->getData(dataComp);
184
185 if (1 <= dataData->persistent->buffer.sliceCount) {
186 *dataCompOut = dataComp;
187 *dataDataOut = dataData;
188
189 return true;
190 }
191
192 else if (dataComp->hasChanged() || refComp->hasChanged()) {
193 clearGeometry(comp);
194 }
195
196 }
197
198 else if (refComp->hasChanged()) {
199 clearGeometry(comp);
200 }
201
202 return false;
203 }
204}
Base class for Component instances.
Definition: Component.h:143
ComponentType * getComponent() const
Definition: Component.h:159
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Definition: MeshComponent.h:29
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.