Retrieves LiDAR data points from DuckDB based on the specified filter.
137{
138 std::shared_lock<std::shared_mutex> lkReadLock(m_muQueryMutex);
139 std::chrono::time_point<std::chrono::high_resolution_clock> tmStartTime = std::chrono::high_resolution_clock::now();
140
141 if (!m_bIsDBOpen)
142 {
143 LOG_ERROR(logging::g_qSharedLogger, "Database is not open.");
144 return {};
145 }
146
147
148 std::vector<std::string> vClauses;
150
151
152
153 vClauses.emplace_back("p.easting BETWEEN ? AND ?");
154 vBindValues.push_back(
duckdb::Value(stPointFilter.dEasting - stPointFilter.dRadius));
155 vBindValues.push_back(
duckdb::Value(stPointFilter.dEasting + stPointFilter.dRadius));
156
157 vClauses.emplace_back("p.northing BETWEEN ? AND ?");
158 vBindValues.push_back(
duckdb::Value(stPointFilter.dNorthing - stPointFilter.dRadius));
159 vBindValues.push_back(
duckdb::Value(stPointFilter.dNorthing + stPointFilter.dRadius));
160
161
162 if (stPointFilter.szClassification && !stPointFilter.szClassification->empty())
163 {
164 vClauses.emplace_back("c.label = ?");
165 vBindValues.push_back(
duckdb::Value(*stPointFilter.szClassification));
166 }
167
168
169 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.normal_x, 0.0)", stPointFilter.dNormalX);
170 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.normal_y, 0.0)", stPointFilter.dNormalY);
171 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.normal_z, 0.0)", stPointFilter.dNormalZ);
172 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.slope, 0.0)", stPointFilter.dSlope);
173 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.rough, 0.0)", stPointFilter.dRoughness);
174 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.curvature, 0.0)", stPointFilter.dCurvature);
175 this->
AddRangeFilter(vClauses, vBindValues,
"COALESCE(p.trav_score, 0.0)", stPointFilter.dTraversalScore);
176
177
178 std::ostringstream stdOSS;
179 stdOSS << "SELECT p.id, p.easting, p.northing, p.altitude, z.label, c.label,"
180 << " COALESCE(p.normal_x, 0.0), COALESCE(p.normal_y, 0.0), COALESCE(p.normal_z, 0.0),"
181 << " COALESCE(p.slope, 0.0), COALESCE(p.rough, 0.0), COALESCE(p.curvature, 0.0), COALESCE(p.trav_score, 0.0)"
182 << " FROM ProcessedLiDARPoints AS p"
183 << " LEFT JOIN Zones AS z ON p.zone_id = z.id"
184 << " LEFT JOIN Classifications AS c ON p.class_code = c.code"
185 << " WHERE ";
186
187 for (size_t siIter = 0; siIter < vClauses.size(); ++siIter)
188 {
189 if (siIter > 0)
190 stdOSS << " AND ";
191 stdOSS << vClauses[siIter];
192 }
193
194 std::vector<PointRow> vResults;
195
196 try
197 {
198
200
201
203 if (stPreparedStmt->HasError())
204 {
205 LOG_ERROR(logging::g_qSharedLogger, "Failed to prepare DuckDB SQL: {}", stPreparedStmt->GetError());
206 return {};
207 }
208
209
211 if (stResult->HasError())
212 {
213 LOG_ERROR(logging::g_qSharedLogger, "Execution Error: {}", stResult->GetError());
214 return {};
215 }
216
217
218
220 {
221 size_t siRows = stChunk->size();
222 for (size_t siIter = 0; siIter < siRows; siIter++)
223 {
224 PointRow stRow;
225
226
227 stRow.nID = stChunk->GetValue(0, siIter).GetValue<
int32_t>();
228 stRow.dEasting = stChunk->GetValue(1, siIter).GetValue<double>();
229 stRow.dNorthing = stChunk->GetValue(2, siIter).GetValue<double>();
230 stRow.dAltitude = stChunk->GetValue(3, siIter).IsNull() ? 0.0 : stChunk->GetValue(3, siIter).GetValue<double>();
231
233 stRow.szZone = valZone.IsNull() ? "Unknown" : valZone.GetValue<std::string>();
234
236 stRow.szClassification = valClass.IsNull() ? "Unclassified" : valClass.GetValue<std::string>();
237
238
239 stRow.dNormalX = stChunk->GetValue(6, siIter).GetValue<double>();
240 stRow.dNormalY = stChunk->GetValue(7, siIter).GetValue<double>();
241 stRow.dNormalZ = stChunk->GetValue(8, siIter).GetValue<double>();
242 stRow.dSlope = stChunk->GetValue(9, siIter).GetValue<double>();
243 stRow.dRoughness = stChunk->GetValue(10, siIter).GetValue<double>();
244 stRow.dCurvature = stChunk->GetValue(11, siIter).GetValue<double>();
245 stRow.dTraversalScore = stChunk->GetValue(12, siIter).GetValue<double>();
246
247 vResults.push_back(stRow);
248 }
249 }
250 }
252 {
253 LOG_ERROR(logging::g_qSharedLogger, "DuckDB threw an exception in GetLiDARData: {}", e.what());
254 return {};
255 }
256 catch (const std::exception& e)
257 {
258 LOG_ERROR(logging::g_qSharedLogger, "A standard exception was thrown in GetLiDARData: {}", e.what());
259 return {};
260 }
261
262 std::chrono::time_point<std::chrono::high_resolution_clock> tmEndTime = std::chrono::high_resolution_clock::now();
263 double dQueryTime = std::chrono::duration<double>(tmEndTime - tmStartTime).count();
264
265 if (dQueryTime > 0.2)
266 {
267 LOG_WARNING(logging::g_qSharedLogger, "Query took {:.2f} seconds to execute.", dQueryTime);
268 }
269 else
270 {
271 LOG_DEBUG(logging::g_qSharedLogger, "Query took {} seconds to execute.", dQueryTime);
272 }
273
274 if (vResults.empty())
275 {
276 LOG_WARNING(logging::g_qSharedLogger, "Query returned no results.");
277 }
278 return vResults;
279}
void AddRangeFilter(std::vector< std::string > &vClauses, duckdb::vector< duckdb::Value > &vBindValues, const char *pColumn, const std::optional< PointFilter::Range< T > > &stdOptRange)
Adds a range filter to the SQL query clauses and dynamically bound values.
Definition LiDARHandler.cpp:308
Definition duckdb.hpp:42284
Definition duckdb.hpp:5647
Definition duckdb.hpp:960