Cogs.Core
SwathPathChunks.cpp
1#include <string>
2#include <iostream>
3#include <algorithm>
4#include "SwathPathChunks.h"
5#include "SwathPathResamplingPositions.h"
6
7//#define VERBOSE_WRAP(a) do {(a);} while(0)
8#define VERBOSE_WRAP(a) do ; while(0)
9
10namespace {
11
12 const std::string package = "SwathPathChunks: ";
13
14}
15
16Cogs::Core::EchoSounder::SwathPathChunks::SwathPathChunks(uint32_t preferredExtent, uint32_t skirtSize)
17 : preferredExtent(preferredExtent),
18 skirtSize(skirtSize)
19{
20}
21
22void Cogs::Core::EchoSounder::SwathPathChunks::clear()
23{
24 chunks.clear();
25
26 VERBOSE_WRAP(std::cerr << package << "Clear\n");
27}
28
29bool Cogs::Core::EchoSounder::SwathPathChunks::retireEvictedPositions(const SwathPathResamplingPositions& positions)
30{
31 bool rv = false;
32 const auto & entries = positions.getEntries();
33
34 while (!chunks.empty() && !entries.validIndex(chunks.front().support.a)) {
35 VERBOSE_WRAP(std::cerr << package << "Popped chunk " << chunks.frontIndex() << " [" << chunks.front().support.a << ", " << chunks.front().support.b << "]\n");
36 chunks.popFront();
37 rv = true;
38 }
39 return rv;
40}
41
42
43bool Cogs::Core::EchoSounder::SwathPathChunks::seedIfQueueEmpty(const SwathPathResamplingPositions& positions)
44{
45 if (!chunks.empty()) return false;
46
47 const auto leastRecentIndex = positions.getEntries().frontIndex();
48 const auto mostRecentIndex = positions.getEntries().backIndex();
49
50 uint32_t m = mostRecentIndex - leastRecentIndex;
51
52 SwathPathChunk chunk;
53 chunk.extent.b = mostRecentIndex;
54 chunk.extent.a = mostRecentIndex - std::min(preferredExtent, m);
55 chunk.support.b = mostRecentIndex;
56 chunk.support.a = mostRecentIndex - std::min(preferredExtent + skirtSize, m);
57 assert(chunk.extent.a - chunk.support.a <= chunk.support.b - chunk.support.a);
58 assert(chunk.extent.b - chunk.support.a <= chunk.support.b - chunk.support.a);
59
60 chunks.pushBack(chunk);
61 VERBOSE_WRAP(std::cerr << package << "seed: " <<
62 chunks.back().support.a << "/" << chunks.back().extent.a << "..." <<
63 chunks.back().extent.b << "/" << chunks.back().support.b << " [" << leastRecentIndex << ":" << mostRecentIndex << "\n");
64
65 generation++;
66
67 return true;
68}
69
70bool Cogs::Core::EchoSounder::SwathPathChunks::tryGrowMoreRecent(const SwathPathResamplingPositions& positions)
71{
72 if (chunks.empty()) return false;
73
74 const auto & entries = positions.getEntries();
75 const auto leastRecentIndex = entries.frontIndex();
76 const auto mostRecentIndex = entries.backIndex();
77
78 if (chunks.back().extent.b == mostRecentIndex) return false; // Fully covered.
79
80 bool rv = false;
81
82 // Try make most recent chunk fully sized.
83 {
84 auto & c = chunks.back();
85
86 auto extent_b = c.extent.a + std::min(preferredExtent, mostRecentIndex - c.extent.a);
87 auto support_b = c.extent.a + std::min(preferredExtent + skirtSize, mostRecentIndex - c.extent.a);
88 rv = rv || (c.extent.b != extent_b) || (c.support.b != support_b);
89 c.extent.b = extent_b;
90 c.support.b = support_b;
91
92 assert(c.extent.a - c.support.a <= c.support.b - c.support.a);
93 assert(c.extent.b - c.support.a <= c.support.b - c.support.a);
94 }
95
96
97 // Try to let chunks have full support towards recent.
98 for (uint32_t i = 0; i < chunks.count(); i++) {
99 auto & c = chunks[chunks.frontIndex() + i];
100 if (c.support.b - c.extent.b < skirtSize) {
101 auto support_b = c.extent.b + std::min(skirtSize, mostRecentIndex - c.extent.b);
102 rv = rv || (c.support.b != support_b);
103 c.support.b = support_b;
104
105 assert(c.extent.a - c.support.a <= c.support.b - c.support.a);
106 assert(c.extent.b - c.support.a <= c.support.b - c.support.a);
107 }
108 }
109
110 // And add new chunks
111 while (static_cast<int32_t>(mostRecentIndex - chunks.back().extent.b) > 0) {
112
113 SwathPathChunk chunk;
114 chunk.extent.a = chunks.back().extent.b;
115 chunk.support.a = chunk.extent.a - std::min(skirtSize, chunk.extent.a - leastRecentIndex);
116
117 chunk.extent.b = chunk.extent.a + std::min(preferredExtent, mostRecentIndex - chunk.extent.a);
118 chunk.support.b = chunk.extent.b + std::min(skirtSize, mostRecentIndex - chunk.extent.b);
119
120 chunk.flags = SwathPathChunkFlag::None;
121
122 assert(chunk.extent.a - chunk.support.a <= chunk.support.b - chunk.support.a);
123 assert(chunk.extent.b - chunk.support.a <= chunk.support.b - chunk.support.a);
124
125 // Distance to most recent index should shrink, otherwise something is really broken.
126 assert(static_cast<int32_t>(mostRecentIndex - chunk.extent.b) < static_cast<int32_t>(mostRecentIndex - chunks.back().extent.b));
127
128 chunks.pushBack(chunk);
129 rv = true;
130 }
131
132 return rv;
133}
134
135bool Cogs::Core::EchoSounder::SwathPathChunks::tryGrowLessRecent(const SwathPathResamplingPositions& positions)
136{
137 if (chunks.empty()) return false;
138
139 const auto & entries = positions.getEntries();
140 const auto leastRecentIndex = entries.frontIndex();
141 const auto mostRecentIndex = entries.backIndex();
142
143 bool rv = false;
144 while (1 < static_cast<int32_t>(chunks.front().extent.a - leastRecentIndex)) {
145
146 SwathPathChunk chunk;
147 chunk.extent.b = chunks.front().extent.a;
148 chunk.support.b = chunk.extent.b + std::min(skirtSize, mostRecentIndex - chunk.extent.b);
149
150 chunk.extent.a = chunk.extent.b - std::min(preferredExtent, chunk.extent.b - leastRecentIndex);
151 chunk.support.a = chunk.extent.a - std::min(skirtSize, chunk.extent.a - leastRecentIndex);
152
153 assert(chunk.extent.a - chunk.support.a <= chunk.support.b - chunk.support.a);
154 assert(chunk.extent.b - chunk.support.a <= chunk.support.b - chunk.support.a);
155
156 assert(static_cast<int32_t>(chunk.extent.a - leastRecentIndex) < static_cast<int32_t>(chunks.front().extent.a - leastRecentIndex));
157
158 chunks.pushFront(chunk);
159 rv = true;
160 }
161 return rv;
162}
163
164bool Cogs::Core::EchoSounder::SwathPathChunks::update(const SwathPathResamplingPositions& positions)
165{
166 if (positions.getEntries().count() < 2) {
167 auto count = chunks.count();
168 chunks.clear();
169 return count != 0;
170 }
171
172 bool rv0 = false;
173 if (resamplingPosGen != positions.getGeneration()) {
174 resamplingPosGen = positions.getGeneration();
175 chunks.clear();
176 rv0 = true;
177 }
178
179 //const auto leastRecentIndex = positions.getEntries().frontIndex();
180 //const auto mostRecentIndex = positions.getEntries().backIndex();
181
182 bool rv1 = retireEvictedPositions(positions);
183 bool rv2 = seedIfQueueEmpty(positions);
184 bool rv3 = tryGrowMoreRecent(positions);
185 bool rv4 = tryGrowLessRecent(positions);
186
187 bool rv = rv0 || rv1 || rv2 || rv3 || rv4;
188
189 if (rv && !chunks.empty()) {
190 for (uint32_t i = 0; i < chunks.count(); i++) {
191 chunks[chunks.frontIndex() + i].flags = SwathPathChunkFlag::None;
192 }
193 chunks[chunks.frontIndex()].flags |= SwathPathChunkFlag::Tail;
194 chunks[chunks.backIndex()].flags |= SwathPathChunkFlag::Head;
195 }
196
197
198 if (rv) {
199 VERBOSE_WRAP(std::cerr << "--- Chunks: " << rv0 << "-" << rv1 << "-" << rv2 << "-" << rv3 << "-" << rv4 << "\n");
200 for (uint32_t i = 0; i < chunks.count(); i++) {
201 const auto & c = chunks[chunks.frontIndex() + i];
202 VERBOSE_WRAP(std::cerr << (chunks.frontIndex() + i) << ": "
203 << "extent={" << c.extent.a << ", " << c.extent.b << "}, "
204 << "suppport={" << c.support.a << ", " << c.support.b << "}, "
205 << "closed={" << ((c.flags & 1) != 0) << ", " << ((c.flags & 2) != 0) << "}\n");
206
207
208 assert(c.extent.a - c.support.a <= c.support.b - c.support.a);
209 assert(c.extent.b - c.support.a <= c.support.b - c.support.a);
210
211 if (0 < i) {
212 assert(chunks[chunks.frontIndex() + i - 1].extent.b == c.extent.a);
213 }
214 if (i + 1 < chunks.count()) {
215 assert(c.extent.b == chunks[chunks.frontIndex() + i + 1].extent.a);
216 }
217
218 assert(positions.getEntries().validIndex(c.extent.a));
219 assert(positions.getEntries().validIndex(c.extent.b));
220 assert(positions.getEntries().validIndex(c.support.a));
221 assert(positions.getEntries().validIndex(c.support.b));
222 }
223 }
224
225 return rv;
226}