2ULiDARWrapper - ctypes wrapper for LiDAR plugin
4Provides low-level ctypes interface to LiDAR C++ plugin for point cloud processing,
5synthetic scanning, triangulation, and leaf area calculations.
9from typing
import List, Tuple, Optional
10from .UContextWrapper
import UContext
11from ..plugins
import helios_lib
12from ..exceptions
import check_helios_error
17 """Opaque structure for LiDARcloud C++ class"""
23 """Automatic error checking for all LiDAR functions"""
24 check_helios_error(helios_lib.getLastErrorCode, helios_lib.getLastErrorMessage)
31 helios_lib.createLiDARcloud.argtypes = []
32 helios_lib.createLiDARcloud.restype = ctypes.POINTER(ULiDARcloud)
33 helios_lib.createLiDARcloud.errcheck = _check_error
35 helios_lib.destroyLiDARcloud.argtypes = [ctypes.POINTER(ULiDARcloud)]
36 helios_lib.destroyLiDARcloud.restype =
None
39 helios_lib.addLiDARScan.argtypes = [
40 ctypes.POINTER(ULiDARcloud),
41 ctypes.POINTER(ctypes.c_float),
52 ctypes.POINTER(ctypes.c_char_p),
57 helios_lib.addLiDARScan.restype = ctypes.c_uint
58 helios_lib.addLiDARScan.errcheck = _check_error
60 helios_lib.addLiDARScanMultibeam.argtypes = [
61 ctypes.POINTER(ULiDARcloud),
62 ctypes.POINTER(ctypes.c_float),
63 ctypes.POINTER(ctypes.c_float),
72 ctypes.POINTER(ctypes.c_char_p),
77 helios_lib.addLiDARScanMultibeam.restype = ctypes.c_uint
78 helios_lib.addLiDARScanMultibeam.errcheck = _check_error
80 helios_lib.getLiDARScanCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
81 helios_lib.getLiDARScanCount.restype = ctypes.c_uint
82 helios_lib.getLiDARScanCount.errcheck = _check_error
84 helios_lib.getLiDARScanOrigin.argtypes = [
85 ctypes.POINTER(ULiDARcloud),
87 ctypes.POINTER(ctypes.c_float)
89 helios_lib.getLiDARScanOrigin.restype =
None
90 helios_lib.getLiDARScanOrigin.errcheck = _check_error
92 helios_lib.getLiDARScanSizeTheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
93 helios_lib.getLiDARScanSizeTheta.restype = ctypes.c_uint
94 helios_lib.getLiDARScanSizeTheta.errcheck = _check_error
96 helios_lib.getLiDARScanSizePhi.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
97 helios_lib.getLiDARScanSizePhi.restype = ctypes.c_uint
98 helios_lib.getLiDARScanSizePhi.errcheck = _check_error
100 helios_lib.getLiDARScanRangeNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
101 helios_lib.getLiDARScanRangeNoiseStdDev.restype = ctypes.c_float
102 helios_lib.getLiDARScanRangeNoiseStdDev.errcheck = _check_error
104 helios_lib.getLiDARScanAngleNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
105 helios_lib.getLiDARScanAngleNoiseStdDev.restype = ctypes.c_float
106 helios_lib.getLiDARScanAngleNoiseStdDev.errcheck = _check_error
108 helios_lib.getLiDARScanTiltRoll.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
109 helios_lib.getLiDARScanTiltRoll.restype = ctypes.c_float
110 helios_lib.getLiDARScanTiltRoll.errcheck = _check_error
112 helios_lib.getLiDARScanTiltPitch.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
113 helios_lib.getLiDARScanTiltPitch.restype = ctypes.c_float
114 helios_lib.getLiDARScanTiltPitch.errcheck = _check_error
116 helios_lib.getLiDARScanPattern.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
117 helios_lib.getLiDARScanPattern.restype = ctypes.c_int
118 helios_lib.getLiDARScanPattern.errcheck = _check_error
120 helios_lib.getLiDARScanBeamZenithAngleCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
121 helios_lib.getLiDARScanBeamZenithAngleCount.restype = ctypes.c_uint
122 helios_lib.getLiDARScanBeamZenithAngleCount.errcheck = _check_error
124 helios_lib.getLiDARScanBeamZenithAngles.argtypes = [
125 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
126 ctypes.POINTER(ctypes.c_float), ctypes.c_uint,
128 helios_lib.getLiDARScanBeamZenithAngles.restype =
None
129 helios_lib.getLiDARScanBeamZenithAngles.errcheck = _check_error
132 helios_lib.isLiDARHitMiss.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
133 helios_lib.isLiDARHitMiss.restype = ctypes.c_int
134 helios_lib.isLiDARHitMiss.errcheck = _check_error
136 helios_lib.lidarHasMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
137 helios_lib.lidarHasMisses.restype = ctypes.c_int
138 helios_lib.lidarHasMisses.errcheck = _check_error
140 helios_lib.getLiDARMissDistance.argtypes = []
141 helios_lib.getLiDARMissDistance.restype = ctypes.c_float
145 helios_lib.addLiDARHitPoint.argtypes = [
146 ctypes.POINTER(ULiDARcloud),
148 ctypes.POINTER(ctypes.c_float),
149 ctypes.POINTER(ctypes.c_float)
151 helios_lib.addLiDARHitPoint.restype =
None
152 helios_lib.addLiDARHitPoint.errcheck = _check_error
154 helios_lib.addLiDARHitPointRGB.argtypes = [
155 ctypes.POINTER(ULiDARcloud),
157 ctypes.POINTER(ctypes.c_float),
158 ctypes.POINTER(ctypes.c_float),
159 ctypes.POINTER(ctypes.c_float)
161 helios_lib.addLiDARHitPointRGB.restype =
None
162 helios_lib.addLiDARHitPointRGB.errcheck = _check_error
164 helios_lib.addLiDARHitPoints.argtypes = [
165 ctypes.POINTER(ULiDARcloud),
167 ctypes.POINTER(ctypes.c_float),
168 ctypes.POINTER(ctypes.c_float),
170 ctypes.POINTER(ctypes.c_float)
172 helios_lib.addLiDARHitPoints.restype =
None
173 helios_lib.addLiDARHitPoints.errcheck = _check_error
175 helios_lib.addLiDARHitPointsWithData.argtypes = [
176 ctypes.POINTER(ULiDARcloud),
178 ctypes.POINTER(ctypes.c_float),
179 ctypes.POINTER(ctypes.c_float),
181 ctypes.POINTER(ctypes.c_float),
182 ctypes.POINTER(ctypes.c_char_p),
184 ctypes.POINTER(ctypes.c_double)
186 helios_lib.addLiDARHitPointsWithData.restype =
None
187 helios_lib.addLiDARHitPointsWithData.errcheck = _check_error
189 helios_lib.getLiDARHitCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
190 helios_lib.getLiDARHitCount.restype = ctypes.c_uint
191 helios_lib.getLiDARHitCount.errcheck = _check_error
193 helios_lib.getLiDARHitXYZ.argtypes = [
194 ctypes.POINTER(ULiDARcloud),
196 ctypes.POINTER(ctypes.c_float)
198 helios_lib.getLiDARHitXYZ.restype =
None
199 helios_lib.getLiDARHitXYZ.errcheck = _check_error
201 helios_lib.getLiDARHitRaydir.argtypes = [
202 ctypes.POINTER(ULiDARcloud),
204 ctypes.POINTER(ctypes.c_float)
206 helios_lib.getLiDARHitRaydir.restype =
None
207 helios_lib.getLiDARHitRaydir.errcheck = _check_error
209 helios_lib.getLiDARHitColor.argtypes = [
210 ctypes.POINTER(ULiDARcloud),
212 ctypes.POINTER(ctypes.c_float)
214 helios_lib.getLiDARHitColor.restype =
None
215 helios_lib.getLiDARHitColor.errcheck = _check_error
217 helios_lib.getLiDARHitScanID.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
218 helios_lib.getLiDARHitScanID.restype = ctypes.c_int
219 helios_lib.getLiDARHitScanID.errcheck = _check_error
221 helios_lib.doesLiDARHitDataExist.argtypes = [
222 ctypes.POINTER(ULiDARcloud),
226 helios_lib.doesLiDARHitDataExist.restype = ctypes.c_int
227 helios_lib.doesLiDARHitDataExist.errcheck = _check_error
229 helios_lib.getLiDARHitData.argtypes = [
230 ctypes.POINTER(ULiDARcloud),
234 helios_lib.getLiDARHitData.restype = ctypes.c_double
235 helios_lib.getLiDARHitData.errcheck = _check_error
237 helios_lib.getLiDARHitData_all.argtypes = [
238 ctypes.POINTER(ULiDARcloud),
240 ctypes.POINTER(ctypes.c_float),
243 helios_lib.getLiDARHitData_all.restype =
None
244 helios_lib.getLiDARHitData_all.errcheck = _check_error
246 helios_lib.getLiDARHitsXYZRGB_all.argtypes = [
247 ctypes.POINTER(ULiDARcloud),
248 ctypes.POINTER(ctypes.c_float),
249 ctypes.POINTER(ctypes.c_float),
252 helios_lib.getLiDARHitsXYZRGB_all.restype =
None
253 helios_lib.getLiDARHitsXYZRGB_all.errcheck = _check_error
255 helios_lib.deleteLiDARHitPoint.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
256 helios_lib.deleteLiDARHitPoint.restype =
None
257 helios_lib.deleteLiDARHitPoint.errcheck = _check_error
260 helios_lib.lidarCoordinateShift.argtypes = [
261 ctypes.POINTER(ULiDARcloud),
262 ctypes.POINTER(ctypes.c_float)
264 helios_lib.lidarCoordinateShift.restype =
None
265 helios_lib.lidarCoordinateShift.errcheck = _check_error
267 helios_lib.lidarCoordinateRotation.argtypes = [
268 ctypes.POINTER(ULiDARcloud),
269 ctypes.POINTER(ctypes.c_float)
271 helios_lib.lidarCoordinateRotation.restype =
None
272 helios_lib.lidarCoordinateRotation.errcheck = _check_error
275 helios_lib.lidarTriangulateHitPoints.argtypes = [
276 ctypes.POINTER(ULiDARcloud),
280 helios_lib.lidarTriangulateHitPoints.restype =
None
281 helios_lib.lidarTriangulateHitPoints.errcheck = _check_error
283 helios_lib.getLiDARTriangleCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
284 helios_lib.getLiDARTriangleCount.restype = ctypes.c_uint
285 helios_lib.getLiDARTriangleCount.errcheck = _check_error
287 helios_lib.getLiDARTriangulationStats.argtypes = [
288 ctypes.POINTER(ULiDARcloud),
289 ctypes.POINTER(ctypes.c_uint),
291 helios_lib.getLiDARTriangulationStats.restype =
None
292 helios_lib.getLiDARTriangulationStats.errcheck = _check_error
294 helios_lib.getLiDARTriangleVertices_all.argtypes = [
295 ctypes.POINTER(ULiDARcloud),
296 ctypes.POINTER(ctypes.c_float),
297 ctypes.POINTER(ctypes.c_int),
300 helios_lib.getLiDARTriangleVertices_all.restype =
None
301 helios_lib.getLiDARTriangleVertices_all.errcheck = _check_error
304 helios_lib.lidarDistanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
305 helios_lib.lidarDistanceFilter.restype =
None
306 helios_lib.lidarDistanceFilter.errcheck = _check_error
308 helios_lib.lidarReflectanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
309 helios_lib.lidarReflectanceFilter.restype =
None
310 helios_lib.lidarReflectanceFilter.errcheck = _check_error
312 helios_lib.lidarFirstHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
313 helios_lib.lidarFirstHitFilter.restype =
None
314 helios_lib.lidarFirstHitFilter.errcheck = _check_error
316 helios_lib.lidarLastHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
317 helios_lib.lidarLastHitFilter.restype =
None
318 helios_lib.lidarLastHitFilter.errcheck = _check_error
321 helios_lib.exportLiDARPointCloud.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p, ctypes.c_bool]
322 helios_lib.exportLiDARPointCloud.restype =
None
323 helios_lib.exportLiDARPointCloud.errcheck = _check_error
325 helios_lib.exportLiDARLeafAreaUncertainty.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
326 helios_lib.exportLiDARLeafAreaUncertainty.restype =
None
327 helios_lib.exportLiDARLeafAreaUncertainty.errcheck = _check_error
329 helios_lib.exportLiDARScans.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
330 helios_lib.exportLiDARScans.restype =
None
331 helios_lib.exportLiDARScans.errcheck = _check_error
333 helios_lib.loadLiDARXML.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
334 helios_lib.loadLiDARXML.restype =
None
335 helios_lib.loadLiDARXML.errcheck = _check_error
338 helios_lib.lidarDisableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
339 helios_lib.lidarDisableMessages.restype =
None
340 helios_lib.lidarDisableMessages.errcheck = _check_error
342 helios_lib.lidarEnableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
343 helios_lib.lidarEnableMessages.restype =
None
344 helios_lib.lidarEnableMessages.errcheck = _check_error
347 helios_lib.addLiDARGrid.argtypes = [
348 ctypes.POINTER(ULiDARcloud),
349 ctypes.POINTER(ctypes.c_float),
350 ctypes.POINTER(ctypes.c_float),
351 ctypes.POINTER(ctypes.c_int),
354 helios_lib.addLiDARGrid.restype =
None
355 helios_lib.addLiDARGrid.errcheck = _check_error
357 helios_lib.addLiDARGridCell.argtypes = [
358 ctypes.POINTER(ULiDARcloud),
359 ctypes.POINTER(ctypes.c_float),
360 ctypes.POINTER(ctypes.c_float),
363 helios_lib.addLiDARGridCell.restype =
None
364 helios_lib.addLiDARGridCell.errcheck = _check_error
366 helios_lib.getLiDARGridCellCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
367 helios_lib.getLiDARGridCellCount.restype = ctypes.c_uint
368 helios_lib.getLiDARGridCellCount.errcheck = _check_error
370 helios_lib.getLiDARCellCenter.argtypes = [
371 ctypes.POINTER(ULiDARcloud),
373 ctypes.POINTER(ctypes.c_float)
375 helios_lib.getLiDARCellCenter.restype =
None
376 helios_lib.getLiDARCellCenter.errcheck = _check_error
378 helios_lib.getLiDARCellSize.argtypes = [
379 ctypes.POINTER(ULiDARcloud),
381 ctypes.POINTER(ctypes.c_float)
383 helios_lib.getLiDARCellSize.restype =
None
384 helios_lib.getLiDARCellSize.errcheck = _check_error
386 helios_lib.getLiDARCellLeafArea.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
387 helios_lib.getLiDARCellLeafArea.restype = ctypes.c_float
388 helios_lib.getLiDARCellLeafArea.errcheck = _check_error
390 helios_lib.getLiDARCellLeafAreaDensity.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
391 helios_lib.getLiDARCellLeafAreaDensity.restype = ctypes.c_float
392 helios_lib.getLiDARCellLeafAreaDensity.errcheck = _check_error
395 helios_lib.getLiDARCellBeamCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
396 helios_lib.getLiDARCellBeamCount.restype = ctypes.c_int
397 helios_lib.getLiDARCellBeamCount.errcheck = _check_error
399 helios_lib.getLiDARCellRelativeDensityIndex.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
400 helios_lib.getLiDARCellRelativeDensityIndex.restype = ctypes.c_float
401 helios_lib.getLiDARCellRelativeDensityIndex.errcheck = _check_error
403 helios_lib.getLiDARCellMeanPathLength.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
404 helios_lib.getLiDARCellMeanPathLength.restype = ctypes.c_float
405 helios_lib.getLiDARCellMeanPathLength.errcheck = _check_error
407 helios_lib.getLiDARCellLADVariance.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
408 helios_lib.getLiDARCellLADVariance.restype = ctypes.c_float
409 helios_lib.getLiDARCellLADVariance.errcheck = _check_error
411 helios_lib.getLiDARCellLeafAreaConfidenceInterval.argtypes = [
412 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float,
413 ctypes.POINTER(ctypes.c_float),
415 helios_lib.getLiDARCellLeafAreaConfidenceInterval.restype = ctypes.c_int
416 helios_lib.getLiDARCellLeafAreaConfidenceInterval.errcheck = _check_error
418 helios_lib.getLiDARGroupLADConfidenceInterval.argtypes = [
419 ctypes.POINTER(ULiDARcloud),
420 ctypes.POINTER(ctypes.c_uint),
421 ctypes.c_uint, ctypes.c_float,
422 ctypes.POINTER(ctypes.c_float),
424 helios_lib.getLiDARGroupLADConfidenceInterval.restype = ctypes.c_int
425 helios_lib.getLiDARGroupLADConfidenceInterval.errcheck = _check_error
427 helios_lib.calculateLiDARHitGridCell.argtypes = [ctypes.POINTER(ULiDARcloud)]
428 helios_lib.calculateLiDARHitGridCell.restype =
None
429 helios_lib.calculateLiDARHitGridCell.errcheck = _check_error
432 helios_lib.syntheticLiDARScan.argtypes = [
433 ctypes.POINTER(ULiDARcloud),
434 ctypes.POINTER(UContext)
436 helios_lib.syntheticLiDARScan.restype =
None
437 helios_lib.syntheticLiDARScan.errcheck = _check_error
439 helios_lib.syntheticLiDARScanAppend.argtypes = [
440 ctypes.POINTER(ULiDARcloud),
441 ctypes.POINTER(UContext),
444 helios_lib.syntheticLiDARScanAppend.restype =
None
445 helios_lib.syntheticLiDARScanAppend.errcheck = _check_error
447 helios_lib.syntheticLiDARScanDiscrete.argtypes = [
448 ctypes.POINTER(ULiDARcloud),
449 ctypes.POINTER(UContext),
454 helios_lib.syntheticLiDARScanDiscrete.restype =
None
455 helios_lib.syntheticLiDARScanDiscrete.errcheck = _check_error
457 helios_lib.syntheticLiDARScanWaveform.argtypes = [
458 ctypes.POINTER(ULiDARcloud),
459 ctypes.POINTER(UContext),
463 helios_lib.syntheticLiDARScanWaveform.restype =
None
464 helios_lib.syntheticLiDARScanWaveform.errcheck = _check_error
466 helios_lib.syntheticLiDARScanFull.argtypes = [
467 ctypes.POINTER(ULiDARcloud),
468 ctypes.POINTER(UContext),
475 helios_lib.syntheticLiDARScanFull.restype =
None
476 helios_lib.syntheticLiDARScanFull.errcheck = _check_error
479 helios_lib.calculateLiDARLeafArea.argtypes = [
480 ctypes.POINTER(ULiDARcloud),
481 ctypes.POINTER(UContext)
483 helios_lib.calculateLiDARLeafArea.restype =
None
484 helios_lib.calculateLiDARLeafArea.errcheck = _check_error
486 helios_lib.calculateLiDARLeafAreaMinHits.argtypes = [
487 ctypes.POINTER(ULiDARcloud),
488 ctypes.POINTER(UContext),
491 helios_lib.calculateLiDARLeafAreaMinHits.restype =
None
492 helios_lib.calculateLiDARLeafAreaMinHits.errcheck = _check_error
494 helios_lib.calculateLiDARLeafAreaUncertainty.argtypes = [
495 ctypes.POINTER(ULiDARcloud),
496 ctypes.POINTER(UContext),
500 helios_lib.calculateLiDARLeafAreaUncertainty.restype =
None
501 helios_lib.calculateLiDARLeafAreaUncertainty.errcheck = _check_error
503 helios_lib.calculateSyntheticLiDARLeafArea.argtypes = [
504 ctypes.POINTER(ULiDARcloud),
505 ctypes.POINTER(UContext)
507 helios_lib.calculateSyntheticLiDARLeafArea.restype =
None
508 helios_lib.calculateSyntheticLiDARLeafArea.errcheck = _check_error
510 helios_lib.calculateSyntheticLiDARGtheta.argtypes = [
511 ctypes.POINTER(ULiDARcloud),
512 ctypes.POINTER(UContext)
514 helios_lib.calculateSyntheticLiDARGtheta.restype =
None
515 helios_lib.calculateSyntheticLiDARGtheta.errcheck = _check_error
517 helios_lib.getLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
518 helios_lib.getLiDARCellGtheta.restype = ctypes.c_float
519 helios_lib.getLiDARCellGtheta.errcheck = _check_error
521 helios_lib.setLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float, ctypes.c_uint]
522 helios_lib.setLiDARCellGtheta.restype =
None
523 helios_lib.setLiDARCellGtheta.errcheck = _check_error
525 helios_lib.gapfillLiDARMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
526 helios_lib.gapfillLiDARMisses.restype =
None
527 helios_lib.gapfillLiDARMisses.errcheck = _check_error
529 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
530 helios_lib.exportLiDARGtheta.restype =
None
531 helios_lib.exportLiDARGtheta.errcheck = _check_error
534 helios_lib.exportLiDARTriangleNormals.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
535 helios_lib.exportLiDARTriangleNormals.restype =
None
536 helios_lib.exportLiDARTriangleNormals.errcheck = _check_error
538 helios_lib.exportLiDARTriangleAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
539 helios_lib.exportLiDARTriangleAreas.restype =
None
540 helios_lib.exportLiDARTriangleAreas.errcheck = _check_error
542 helios_lib.exportLiDARLeafAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
543 helios_lib.exportLiDARLeafAreas.restype =
None
544 helios_lib.exportLiDARLeafAreas.errcheck = _check_error
546 helios_lib.exportLiDARLeafAreaDensities.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
547 helios_lib.exportLiDARLeafAreaDensities.restype =
None
548 helios_lib.exportLiDARLeafAreaDensities.errcheck = _check_error
550 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
551 helios_lib.exportLiDARGtheta.restype =
None
552 helios_lib.exportLiDARGtheta.errcheck = _check_error
555 helios_lib.addLiDARTrianglesToContext.argtypes = [
556 ctypes.POINTER(ULiDARcloud),
557 ctypes.POINTER(UContext)
559 helios_lib.addLiDARTrianglesToContext.restype =
None
560 helios_lib.addLiDARTrianglesToContext.errcheck = _check_error
562 helios_lib.initializeLiDARCollisionDetection.argtypes = [
563 ctypes.POINTER(ULiDARcloud),
564 ctypes.POINTER(UContext)
566 helios_lib.initializeLiDARCollisionDetection.restype =
None
567 helios_lib.initializeLiDARCollisionDetection.errcheck = _check_error
569 helios_lib.enableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
570 helios_lib.enableLiDARCDGPUAcceleration.restype =
None
571 helios_lib.enableLiDARCDGPUAcceleration.errcheck = _check_error
573 helios_lib.disableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
574 helios_lib.disableLiDARCDGPUAcceleration.restype =
None
575 helios_lib.disableLiDARCDGPUAcceleration.errcheck = _check_error
577 _LIDAR_FUNCTIONS_AVAILABLE =
True
579except AttributeError:
580 _LIDAR_FUNCTIONS_AVAILABLE =
False
585 """Create LiDARcloud instance"""
586 if not _LIDAR_FUNCTIONS_AVAILABLE:
587 raise NotImplementedError(
588 "LiDAR functions not available. Rebuild PyHelios with lidar plugin:\n"
589 " build_scripts/build_helios --plugins lidar"
591 return helios_lib.createLiDARcloud()
595 """Destroy LiDARcloud instance"""
596 if cloud_ptr
and _LIDAR_FUNCTIONS_AVAILABLE:
597 helios_lib.destroyLiDARcloud(cloud_ptr)
601 origin: List[float], Ntheta: int, theta_range: Tuple[float, float],
602 Nphi: int, phi_range: Tuple[float, float],
603 exit_diameter: float, beam_divergence: float,
604 column_format: Optional[List[str]] =
None,
605 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
606 scan_tilt_roll: float = 0.0, scan_tilt_pitch: float = 0.0) -> int:
607 """Add a LiDAR scan to the point cloud"""
608 if not _LIDAR_FUNCTIONS_AVAILABLE:
609 raise NotImplementedError(
"LiDAR functions not available")
612 raise ValueError(
"Origin must be a 3-element array [x, y, z]")
614 origin_array = (ctypes.c_float * 3)(*origin)
617 column_array = (ctypes.c_char_p * len(column_format))(
618 *[c.encode(
'utf-8')
for c
in column_format]
620 n_cols = len(column_format)
625 return helios_lib.addLiDARScan(
626 cloud_ptr, origin_array, Ntheta, theta_range[0], theta_range[1],
627 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
628 float(range_noise_stddev), float(angle_noise_stddev),
629 column_array, n_cols,
630 float(scan_tilt_roll), float(scan_tilt_pitch)
635 origin: List[float], beam_zenith_angles: List[float],
636 Nphi: int, phi_range: Tuple[float, float],
637 exit_diameter: float, beam_divergence: float,
638 column_format: Optional[List[str]] =
None,
639 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
640 scan_tilt_roll: float = 0.0, scan_tilt_pitch: float = 0.0) -> int:
641 """Add a spinning multibeam LiDAR scan (rotating multi-channel sensor)"""
642 if not _LIDAR_FUNCTIONS_AVAILABLE:
643 raise NotImplementedError(
"LiDAR functions not available")
646 raise ValueError(
"Origin must be a 3-element array [x, y, z]")
647 if not beam_zenith_angles:
648 raise ValueError(
"beam_zenith_angles must contain at least one per-channel angle")
650 origin_array = (ctypes.c_float * 3)(*origin)
651 n_angles = len(beam_zenith_angles)
652 angles_array = (ctypes.c_float * n_angles)(*[float(a)
for a
in beam_zenith_angles])
655 column_array = (ctypes.c_char_p * len(column_format))(
656 *[c.encode(
'utf-8')
for c
in column_format]
658 n_cols = len(column_format)
663 return helios_lib.addLiDARScanMultibeam(
664 cloud_ptr, origin_array, angles_array, n_angles,
665 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
666 float(range_noise_stddev), float(angle_noise_stddev),
667 column_array, n_cols,
668 float(scan_tilt_roll), float(scan_tilt_pitch)
673 """Get the global scanner tilt roll angle (radians) for a scan."""
674 if not _LIDAR_FUNCTIONS_AVAILABLE:
675 raise NotImplementedError(
"LiDAR functions not available")
676 return helios_lib.getLiDARScanTiltRoll(cloud_ptr, scanID)
680 """Get the global scanner tilt pitch angle (radians) for a scan."""
681 if not _LIDAR_FUNCTIONS_AVAILABLE:
682 raise NotImplementedError(
"LiDAR functions not available")
683 return helios_lib.getLiDARScanTiltPitch(cloud_ptr, scanID)
687 """Get the scan pattern (0 = raster, 1 = spinning multibeam)."""
688 if not _LIDAR_FUNCTIONS_AVAILABLE:
689 raise NotImplementedError(
"LiDAR functions not available")
690 return helios_lib.getLiDARScanPattern(cloud_ptr, scanID)
694 """Get the per-channel beam zenith angles (radians) for a multibeam scan (empty for raster)."""
695 if not _LIDAR_FUNCTIONS_AVAILABLE:
696 raise NotImplementedError(
"LiDAR functions not available")
697 count = helios_lib.getLiDARScanBeamZenithAngleCount(cloud_ptr, scanID)
700 out = (ctypes.c_float * count)()
701 helios_lib.getLiDARScanBeamZenithAngles(cloud_ptr, scanID, out, count)
702 return [float(out[i])
for i
in range(count)]
705def isLiDARHitMiss(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> bool:
706 """Return True if the hit is a miss (a transmitted beam that returned nothing)."""
707 if not _LIDAR_FUNCTIONS_AVAILABLE:
708 raise NotImplementedError(
"LiDAR functions not available")
709 return bool(helios_lib.isLiDARHitMiss(cloud_ptr, index))
712def lidarHasMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
713 """Return True if the cloud contains at least one miss."""
714 if not _LIDAR_FUNCTIONS_AVAILABLE:
715 raise NotImplementedError(
"LiDAR functions not available")
716 return bool(helios_lib.lidarHasMisses(cloud_ptr))
720 """Return the LIDAR_MISS_DISTANCE constant (meters)."""
721 if not _LIDAR_FUNCTIONS_AVAILABLE:
722 raise NotImplementedError(
"LiDAR functions not available")
723 return helios_lib.getLiDARMissDistance()
727 """Get number of scans in the cloud"""
728 if not _LIDAR_FUNCTIONS_AVAILABLE:
729 raise NotImplementedError(
"LiDAR functions not available")
730 return helios_lib.getLiDARScanCount(cloud_ptr)
733def getLiDARScanOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> List[float]:
734 """Get origin of a specific scan"""
735 if not _LIDAR_FUNCTIONS_AVAILABLE:
736 raise NotImplementedError(
"LiDAR functions not available")
738 origin = (ctypes.c_float * 3)()
739 helios_lib.getLiDARScanOrigin(cloud_ptr, scanID, origin)
744 """Get number of zenith scan points"""
745 if not _LIDAR_FUNCTIONS_AVAILABLE:
746 raise NotImplementedError(
"LiDAR functions not available")
747 return helios_lib.getLiDARScanSizeTheta(cloud_ptr, scanID)
751 """Get number of azimuthal scan points"""
752 if not _LIDAR_FUNCTIONS_AVAILABLE:
753 raise NotImplementedError(
"LiDAR functions not available")
754 return helios_lib.getLiDARScanSizePhi(cloud_ptr, scanID)
758 """Get the range (along-beam) measurement noise standard deviation for a scan (meters)"""
759 if not _LIDAR_FUNCTIONS_AVAILABLE:
760 raise NotImplementedError(
"LiDAR functions not available")
761 return helios_lib.getLiDARScanRangeNoiseStdDev(cloud_ptr, scanID)
765 """Get the angular (beam-pointing) jitter standard deviation for a scan (radians)"""
766 if not _LIDAR_FUNCTIONS_AVAILABLE:
767 raise NotImplementedError(
"LiDAR functions not available")
768 return helios_lib.getLiDARScanAngleNoiseStdDev(cloud_ptr, scanID)
772 xyz: List[float], direction: List[float]) ->
None:
773 """Add a hit point to the cloud"""
774 if not _LIDAR_FUNCTIONS_AVAILABLE:
775 raise NotImplementedError(
"LiDAR functions not available")
778 raise ValueError(
"XYZ must be a 3-element array")
779 if len(direction) < 2:
780 raise ValueError(
"Direction must have at least 2 elements [radius, elevation]")
782 xyz_array = (ctypes.c_float * 3)(*xyz)
783 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
784 helios_lib.addLiDARHitPoint(cloud_ptr, scanID, xyz_array, direction_array)
788 xyz: List[float], direction: List[float], color: List[float]) ->
None:
789 """Add a hit point with color to the cloud"""
790 if not _LIDAR_FUNCTIONS_AVAILABLE:
791 raise NotImplementedError(
"LiDAR functions not available")
794 raise ValueError(
"XYZ must be a 3-element array")
795 if len(direction) < 2:
796 raise ValueError(
"Direction must have at least 2 elements")
798 raise ValueError(
"Color must be a 3-element array [r, g, b]")
800 xyz_array = (ctypes.c_float * 3)(*xyz)
801 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
802 color_array = (ctypes.c_float * 3)(*color)
803 helios_lib.addLiDARHitPointRGB(cloud_ptr, scanID, xyz_array, direction_array, color_array)
807 xyzs, directions, count: int, colors=
None) ->
None:
808 """Add many hit points to the cloud in a single call (bulk ingestion).
810 xyzs and directions must be contiguous float32 buffers (e.g. numpy arrays)
811 of shape (count, 3). colors, if given, must be a contiguous float32 buffer
812 of shape (count, 3); pass None to add without color. The buffers are passed
813 straight through to C without per-point Python marshalling.
815 if not _LIDAR_FUNCTIONS_AVAILABLE:
816 raise NotImplementedError(
"LiDAR functions not available")
818 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
819 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
820 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
821 helios_lib.addLiDARHitPoints(cloud_ptr, scanID, xyzs_ptr, directions_ptr, count, colors_ptr)
825 xyzs, directions, count: int, colors=
None,
826 labels=
None, data_values=
None) ->
None:
827 """Bulk-ingest hit points carrying a per-hit data map in one call.
829 xyzs/directions (and colors, if given) must be contiguous float32 buffers of
830 shape (count, 3); directions is (radius, elevation, azimuth). labels is a
831 list of data-map key names; data_values must be a contiguous float64 buffer
832 of shape (count, len(labels)). Pass labels=None/empty (and data_values=None)
833 to ingest with an empty data map.
835 if not _LIDAR_FUNCTIONS_AVAILABLE:
836 raise NotImplementedError(
"LiDAR functions not available")
838 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
839 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
840 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
842 labels = list(labels
or [])
843 n_labels = len(labels)
845 labels_arr = (ctypes.c_char_p * n_labels)(*[s.encode(
'utf-8')
for s
in labels])
846 values_ptr = data_values.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
851 helios_lib.addLiDARHitPointsWithData(cloud_ptr, scanID, xyzs_ptr, directions_ptr,
852 count, colors_ptr, labels_arr, n_labels, values_ptr)
856 """Get total number of hit points"""
857 if not _LIDAR_FUNCTIONS_AVAILABLE:
858 raise NotImplementedError(
"LiDAR functions not available")
859 return helios_lib.getLiDARHitCount(cloud_ptr)
862def getLiDARHitXYZ(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
863 """Get coordinates of a hit point"""
864 if not _LIDAR_FUNCTIONS_AVAILABLE:
865 raise NotImplementedError(
"LiDAR functions not available")
867 xyz = (ctypes.c_float * 3)()
868 helios_lib.getLiDARHitXYZ(cloud_ptr, index, xyz)
872def getLiDARHitRaydir(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
873 """Get ray direction of a hit point"""
874 if not _LIDAR_FUNCTIONS_AVAILABLE:
875 raise NotImplementedError(
"LiDAR functions not available")
877 direction = (ctypes.c_float * 3)()
878 helios_lib.getLiDARHitRaydir(cloud_ptr, index, direction)
879 return list(direction)
882def getLiDARHitColor(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
883 """Get color of a hit point"""
884 if not _LIDAR_FUNCTIONS_AVAILABLE:
885 raise NotImplementedError(
"LiDAR functions not available")
887 color = (ctypes.c_float * 3)()
888 helios_lib.getLiDARHitColor(cloud_ptr, index, color)
893 """Get the scan ID a hit point belongs to"""
894 if not _LIDAR_FUNCTIONS_AVAILABLE:
895 raise NotImplementedError(
"LiDAR functions not available")
896 return helios_lib.getLiDARHitScanID(cloud_ptr, index)
900 """Check whether a named scalar data value exists for a hit point"""
901 if not _LIDAR_FUNCTIONS_AVAILABLE:
902 raise NotImplementedError(
"LiDAR functions not available")
903 return bool(helios_lib.doesLiDARHitDataExist(cloud_ptr, index, label.encode(
'utf-8')))
906def getLiDARHitData(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int, label: str) -> float:
907 """Get a named scalar data value for a hit point"""
908 if not _LIDAR_FUNCTIONS_AVAILABLE:
909 raise NotImplementedError(
"LiDAR functions not available")
910 return helios_lib.getLiDARHitData(cloud_ptr, index, label.encode(
'utf-8'))
913def getLiDARHitData_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), label: str, n: int) -> List[float]:
914 """Bulk-export a named scalar data value for all hit points in one call"""
915 if not _LIDAR_FUNCTIONS_AVAILABLE:
916 raise NotImplementedError(
"LiDAR functions not available")
918 out = (ctypes.c_float * n)()
919 helios_lib.getLiDARHitData_all(cloud_ptr, label.encode(
'utf-8'), out, n)
923def getLiDARHitsXYZRGB_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), n: int) -> Tuple[List[float], List[float]]:
924 """Bulk-export XYZ coordinates and RGB colors for all hit points in one call.
926 Returns a tuple (xyz_flat, rgb_flat) of flat 3*n-element lists.
928 if not _LIDAR_FUNCTIONS_AVAILABLE:
929 raise NotImplementedError(
"LiDAR functions not available")
931 xyz = (ctypes.c_float * (3 * n))()
932 rgb = (ctypes.c_float * (3 * n))()
933 helios_lib.getLiDARHitsXYZRGB_all(cloud_ptr, xyz, rgb, n)
934 return list(xyz), list(rgb)
938 """Delete a hit point from the cloud"""
939 if not _LIDAR_FUNCTIONS_AVAILABLE:
940 raise NotImplementedError(
"LiDAR functions not available")
941 helios_lib.deleteLiDARHitPoint(cloud_ptr, index)
945 """Translate all hit points by a shift vector"""
946 if not _LIDAR_FUNCTIONS_AVAILABLE:
947 raise NotImplementedError("LiDAR functions not available")
950 raise ValueError("Shift must be a 3-element array [x, y, z]")
952 shift_array = (ctypes.c_float * 3)(*shift)
953 helios_lib.lidarCoordinateShift(cloud_ptr, shift_array)
956def lidarCoordinateRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), rotation: List[float]) -> None:
957 """Rotate all hit points by spherical rotation angles"""
958 if not _LIDAR_FUNCTIONS_AVAILABLE:
959 raise NotImplementedError("LiDAR functions not available")
961 if len(rotation) < 2:
962 raise ValueError("Rotation must have at least 2 elements [radius, elevation]")
964 rotation_array = (ctypes.c_float * 3)(rotation[0], rotation[1], rotation[2] if len(rotation) > 2 else 0)
965 helios_lib.lidarCoordinateRotation(cloud_ptr, rotation_array)
968def lidarTriangulateHitPoints(cloud_ptr: ctypes.POINTER(ULiDARcloud),
969 Lmax: float, max_aspect_ratio: float) -> None:
970 """Generate triangle mesh from hit points"""
971 if not _LIDAR_FUNCTIONS_AVAILABLE:
972 raise NotImplementedError("LiDAR functions not available")
973 helios_lib.lidarTriangulateHitPoints(cloud_ptr, Lmax, max_aspect_ratio)
976def getLiDARTriangleCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
977 """Get number of triangles in the mesh"""
978 if not _LIDAR_FUNCTIONS_AVAILABLE:
979 raise NotImplementedError("LiDAR functions not available")
980 return helios_lib.getLiDARTriangleCount(cloud_ptr)
983def getLiDARTriangulationStats(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> dict:
984 """Filter diagnostics from the most recent triangulateHitPoints() call.
986 Returns a dict with candidate/dropped counts. Each dropped triangle is
987 attributed to one primary reason, so:
988 candidates == kept + dropped_lmax + dropped_aspect + dropped_degenerate
989 where `kept` equals getLiDARTriangleCount(). All zero if triangulation has
992 if not _LIDAR_FUNCTIONS_AVAILABLE:
993 raise NotImplementedError("LiDAR functions not available")
994 out = (ctypes.c_uint * 4)()
995 helios_lib.getLiDARTriangulationStats(cloud_ptr, out)
997 "candidates": int(out[0]),
998 "dropped_lmax": int(out[1]),
999 "dropped_aspect": int(out[2]),
1000 "dropped_degenerate": int(out[3]),
1004def getLiDARTriangleVertices_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), tri_count: int):
1005 """Bulk-export every triangle's vertices (and source scan) in one call.
1007 Returns (xyz_flat, scan_ids) as numpy arrays: xyz_flat is (tri_count*9,)
1008 float32 laid out [v0x,v0y,v0z, v1x,v1y,v1z, v2x,v2y,v2z] per triangle, and
1009 scan_ids is (tri_count,) int32. Returns empty arrays when tri_count is 0.
1012 if not _LIDAR_FUNCTIONS_AVAILABLE:
1013 raise NotImplementedError("LiDAR functions not available")
1015 return np.empty((0,), dtype=np.float32), np.empty((0,), dtype=np.int32)
1017 xyz = np.empty((tri_count * 9,), dtype=np.float32)
1018 scan = np.empty((tri_count,), dtype=np.int32)
1019 helios_lib.getLiDARTriangleVertices_all(
1021 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
1022 scan.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
1028def lidarDistanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), maxdistance: float) -> None:
1029 """Filter hit points by maximum distance"""
1030 if not _LIDAR_FUNCTIONS_AVAILABLE:
1031 raise NotImplementedError("LiDAR functions not available")
1032 helios_lib.lidarDistanceFilter(cloud_ptr, maxdistance)
1035def lidarReflectanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), minreflectance: float) -> None:
1036 """Filter hit points by minimum reflectance"""
1037 if not _LIDAR_FUNCTIONS_AVAILABLE:
1038 raise NotImplementedError("LiDAR functions not available")
1039 helios_lib.lidarReflectanceFilter(cloud_ptr, minreflectance)
1042def lidarFirstHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1043 """Keep only first return hit points"""
1044 if not _LIDAR_FUNCTIONS_AVAILABLE:
1045 raise NotImplementedError("LiDAR functions not available")
1046 helios_lib.lidarFirstHitFilter(cloud_ptr)
1049def lidarLastHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1050 """Keep only last return hit points"""
1051 if not _LIDAR_FUNCTIONS_AVAILABLE:
1052 raise NotImplementedError("LiDAR functions not available")
1053 helios_lib.lidarLastHitFilter(cloud_ptr)
1056def exportLiDARPointCloud(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str,
1057 write_header: bool = True) -> None:
1058 """Export point cloud to ASCII file (optionally with a '#'-prefixed column header)"""
1059 if not _LIDAR_FUNCTIONS_AVAILABLE:
1060 raise NotImplementedError("LiDAR functions not available")
1061 helios_lib.exportLiDARPointCloud(cloud_ptr, filename.encode('utf-8'), bool(write_header))
1064def exportLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1065 """Export per-voxel leaf-area sampling uncertainty to a self-describing ASCII file"""
1066 if not _LIDAR_FUNCTIONS_AVAILABLE:
1067 raise NotImplementedError("LiDAR functions not available")
1068 helios_lib.exportLiDARLeafAreaUncertainty(cloud_ptr, filename.encode('utf-8'))
1071def exportLiDARScans(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1072 """Export all scans to an XML metadata file plus one ASCII data file per scan"""
1073 if not _LIDAR_FUNCTIONS_AVAILABLE:
1074 raise NotImplementedError("LiDAR functions not available")
1075 helios_lib.exportLiDARScans(cloud_ptr, filename.encode('utf-8'))
1078def loadLiDARXML(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1079 """Load scan metadata from XML file"""
1080 if not _LIDAR_FUNCTIONS_AVAILABLE:
1081 raise NotImplementedError("LiDAR functions not available")
1082 helios_lib.loadLiDARXML(cloud_ptr, filename.encode('utf-8'))
1085def lidarDisableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1086 """Disable console output messages"""
1087 if not _LIDAR_FUNCTIONS_AVAILABLE:
1088 raise NotImplementedError("LiDAR functions not available")
1089 helios_lib.lidarDisableMessages(cloud_ptr)
1092def lidarEnableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1093 """Enable console output messages"""
1094 if not _LIDAR_FUNCTIONS_AVAILABLE:
1095 raise NotImplementedError("LiDAR functions not available")
1096 helios_lib.lidarEnableMessages(cloud_ptr)
1099def addLiDARGrid(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
1100 size: List[float], ndiv: List[int], rotation: float) -> None:
1101 """Add a rectangular grid of voxel cells"""
1102 if not _LIDAR_FUNCTIONS_AVAILABLE:
1103 raise NotImplementedError("LiDAR functions not available")
1105 if len(center) != 3:
1106 raise ValueError("Center must be a 3-element array [x, y, z]")
1108 raise ValueError("Size must be a 3-element array [x, y, z]")
1110 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
1112 center_array = (ctypes.c_float * 3)(*center)
1113 size_array = (ctypes.c_float * 3)(*size)
1114 ndiv_array = (ctypes.c_int * 3)(*ndiv)
1115 helios_lib.addLiDARGrid(cloud_ptr, center_array, size_array, ndiv_array, rotation)
1118def addLiDARGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
1119 size: List[float], rotation: float) -> None:
1120 """Add a single grid cell"""
1121 if not _LIDAR_FUNCTIONS_AVAILABLE:
1122 raise NotImplementedError("LiDAR functions not available")
1124 if len(center) != 3:
1125 raise ValueError("Center must be a 3-element array [x, y, z]")
1127 raise ValueError("Size must be a 3-element array [x, y, z]")
1129 center_array = (ctypes.c_float * 3)(*center)
1130 size_array = (ctypes.c_float * 3)(*size)
1131 helios_lib.addLiDARGridCell(cloud_ptr, center_array, size_array, rotation)
1134def getLiDARGridCellCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
1135 """Get number of grid cells"""
1136 if not _LIDAR_FUNCTIONS_AVAILABLE:
1137 raise NotImplementedError("LiDAR functions not available")
1138 return helios_lib.getLiDARGridCellCount(cloud_ptr)
1141def getLiDARCellCenter(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1142 """Get center position of a grid cell"""
1143 if not _LIDAR_FUNCTIONS_AVAILABLE:
1144 raise NotImplementedError("LiDAR functions not available")
1146 center = (ctypes.c_float * 3)()
1147 helios_lib.getLiDARCellCenter(cloud_ptr, index, center)
1151def getLiDARCellSize(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1152 """Get size of a grid cell"""
1153 if not _LIDAR_FUNCTIONS_AVAILABLE:
1154 raise NotImplementedError("LiDAR functions not available")
1156 size = (ctypes.c_float * 3)()
1157 helios_lib.getLiDARCellSize(cloud_ptr, index, size)
1161def getLiDARCellLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1162 """Get leaf area of a grid cell"""
1163 if not _LIDAR_FUNCTIONS_AVAILABLE:
1164 raise NotImplementedError("LiDAR functions not available")
1165 return helios_lib.getLiDARCellLeafArea(cloud_ptr, index)
1168def getLiDARCellLeafAreaDensity(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1169 """Get leaf area density of a grid cell"""
1170 if not _LIDAR_FUNCTIONS_AVAILABLE:
1171 raise NotImplementedError("LiDAR functions not available")
1172 return helios_lib.getLiDARCellLeafAreaDensity(cloud_ptr, index)
1175def calculateLiDARHitGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1176 """Calculate hit point grid cell assignments"""
1177 if not _LIDAR_FUNCTIONS_AVAILABLE:
1178 raise NotImplementedError("LiDAR functions not available")
1179 helios_lib.calculateLiDARHitGridCell(cloud_ptr)
1182def syntheticLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1183 context_ptr: ctypes.POINTER(UContext)) -> None:
1184 """Perform synthetic discrete-return LiDAR scan"""
1185 if not _LIDAR_FUNCTIONS_AVAILABLE:
1186 raise NotImplementedError("LiDAR functions not available")
1187 helios_lib.syntheticLiDARScan(cloud_ptr, context_ptr)
1190def syntheticLiDARScanAppend(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1191 context_ptr: ctypes.POINTER(UContext),
1192 append: bool) -> None:
1193 """Perform synthetic scan with append control"""
1194 if not _LIDAR_FUNCTIONS_AVAILABLE:
1195 raise NotImplementedError("LiDAR functions not available")
1196 helios_lib.syntheticLiDARScanAppend(cloud_ptr, context_ptr, append)
1199def syntheticLiDARScanDiscrete(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1200 context_ptr: ctypes.POINTER(UContext),
1201 scan_grid_only: bool, record_misses: bool, append: bool) -> None:
1202 """Perform discrete-return synthetic scan with miss-recording control"""
1203 if not _LIDAR_FUNCTIONS_AVAILABLE:
1204 raise NotImplementedError("LiDAR functions not available")
1205 helios_lib.syntheticLiDARScanDiscrete(cloud_ptr, context_ptr, scan_grid_only, record_misses, append)
1208def syntheticLiDARScanWaveform(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1209 context_ptr: ctypes.POINTER(UContext),
1210 rays_per_pulse: int,
1211 pulse_distance_threshold: float) -> None:
1212 """Perform synthetic full-waveform LiDAR scan"""
1213 if not _LIDAR_FUNCTIONS_AVAILABLE:
1214 raise NotImplementedError("LiDAR functions not available")
1215 helios_lib.syntheticLiDARScanWaveform(cloud_ptr, context_ptr, rays_per_pulse, pulse_distance_threshold)
1218def syntheticLiDARScanFull(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1219 context_ptr: ctypes.POINTER(UContext),
1220 rays_per_pulse: int,
1221 pulse_distance_threshold: float,
1222 scan_grid_only: bool,
1223 record_misses: bool,
1224 append: bool) -> None:
1225 """Perform synthetic scan with full control"""
1226 if not _LIDAR_FUNCTIONS_AVAILABLE:
1227 raise NotImplementedError("LiDAR functions not available")
1228 helios_lib.syntheticLiDARScanFull(cloud_ptr, context_ptr, rays_per_pulse,
1229 pulse_distance_threshold, scan_grid_only,
1230 record_misses, append)
1233def calculateLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1234 context_ptr: ctypes.POINTER(UContext)) -> None:
1235 """Calculate leaf area for each grid cell"""
1236 if not _LIDAR_FUNCTIONS_AVAILABLE:
1237 raise NotImplementedError("LiDAR functions not available")
1238 helios_lib.calculateLiDARLeafArea(cloud_ptr, context_ptr)
1241def calculateLiDARLeafAreaMinHits(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1242 context_ptr: ctypes.POINTER(UContext),
1243 min_voxel_hits: int) -> None:
1244 """Calculate leaf area with minimum voxel hits threshold"""
1245 if not _LIDAR_FUNCTIONS_AVAILABLE:
1246 raise NotImplementedError("LiDAR functions not available")
1247 helios_lib.calculateLiDARLeafAreaMinHits(cloud_ptr, context_ptr, min_voxel_hits)
1250def calculateLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1251 context_ptr: ctypes.POINTER(UContext),
1252 min_voxel_hits: int, element_width: float) -> None:
1253 """Calculate leaf area plus per-voxel sampling uncertainty (Pimont et al. 2018)"""
1254 if not _LIDAR_FUNCTIONS_AVAILABLE:
1255 raise NotImplementedError("LiDAR functions not available")
1256 helios_lib.calculateLiDARLeafAreaUncertainty(
1257 cloud_ptr, context_ptr, min_voxel_hits, float(element_width))
1260def getLiDARCellBeamCount(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> int:
1261 """Get the beam count N entering a grid cell (-1 if calculateLeafArea not run)."""
1262 if not _LIDAR_FUNCTIONS_AVAILABLE:
1263 raise NotImplementedError("LiDAR functions not available")
1264 return helios_lib.getLiDARCellBeamCount(cloud_ptr, index)
1267def getLiDARCellRelativeDensityIndex(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1268 """Get the relative density index I_rdi for a grid cell."""
1269 if not _LIDAR_FUNCTIONS_AVAILABLE:
1270 raise NotImplementedError("LiDAR functions not available")
1271 return helios_lib.getLiDARCellRelativeDensityIndex(cloud_ptr, index)
1274def getLiDARCellMeanPathLength(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1275 """Get the mean beam path length (m) through a grid cell."""
1276 if not _LIDAR_FUNCTIONS_AVAILABLE:
1277 raise NotImplementedError("LiDAR functions not available")
1278 return helios_lib.getLiDARCellMeanPathLength(cloud_ptr, index)
1281def getLiDARCellLADVariance(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1282 """Get the per-voxel LAD sampling variance (-1 if unavailable)."""
1283 if not _LIDAR_FUNCTIONS_AVAILABLE:
1284 raise NotImplementedError("LiDAR functions not available")
1285 return helios_lib.getLiDARCellLADVariance(cloud_ptr, index)
1288def getLiDARCellLeafAreaConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int,
1289 confidence_level: float = 0.95):
1290 """Single-voxel leaf-area confidence interval.
1292 Returns (valid, lower, upper). ``valid`` is False when the interval is gated
1293 out by the Pimont validity envelope (the bounds are then not trustworthy).
1295 if not _LIDAR_FUNCTIONS_AVAILABLE:
1296 raise NotImplementedError("LiDAR functions not available")
1297 out = (ctypes.c_float * 2)()
1298 valid = helios_lib.getLiDARCellLeafAreaConfidenceInterval(
1299 cloud_ptr, index, float(confidence_level), out)
1300 return bool(valid), float(out[0]), float(out[1])
1303def getLiDARGroupLADConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1304 indices: List[int], confidence_level: float = 0.95):
1305 """Group-scale LAD confidence interval over a set of cells (recommended path).
1307 Returns (valid, mean_lad, lower, upper).
1309 if not _LIDAR_FUNCTIONS_AVAILABLE:
1310 raise NotImplementedError("LiDAR functions not available")
1312 raise ValueError("indices must contain at least one cell index")
1314 idx_array = (ctypes.c_uint * n)(*[int(i) for i in indices])
1315 out = (ctypes.c_float * 3)()
1316 valid = helios_lib.getLiDARGroupLADConfidenceInterval(
1317 cloud_ptr, idx_array, n, float(confidence_level), out)
1318 return bool(valid), float(out[0]), float(out[1]), float(out[2])
1321def exportLiDARTriangleNormals(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1322 """Export triangle normal vectors"""
1323 if not _LIDAR_FUNCTIONS_AVAILABLE:
1324 raise NotImplementedError("LiDAR functions not available")
1325 helios_lib.exportLiDARTriangleNormals(cloud_ptr, filename.encode('utf-8'))
1328def exportLiDARTriangleAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1329 """Export triangle areas"""
1330 if not _LIDAR_FUNCTIONS_AVAILABLE:
1331 raise NotImplementedError("LiDAR functions not available")
1332 helios_lib.exportLiDARTriangleAreas(cloud_ptr, filename.encode('utf-8'))
1335def exportLiDARLeafAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1336 """Export leaf areas for each grid cell"""
1337 if not _LIDAR_FUNCTIONS_AVAILABLE:
1338 raise NotImplementedError("LiDAR functions not available")
1339 helios_lib.exportLiDARLeafAreas(cloud_ptr, filename.encode('utf-8'))
1342def exportLiDARLeafAreaDensities(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1343 """Export leaf area densities for each grid cell"""
1344 if not _LIDAR_FUNCTIONS_AVAILABLE:
1345 raise NotImplementedError("LiDAR functions not available")
1346 helios_lib.exportLiDARLeafAreaDensities(cloud_ptr, filename.encode('utf-8'))
1349def exportLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1350 """Export G(theta) values for each grid cell"""
1351 if not _LIDAR_FUNCTIONS_AVAILABLE:
1352 raise NotImplementedError("LiDAR functions not available")
1353 helios_lib.exportLiDARGtheta(cloud_ptr, filename.encode('utf-8'))
1356def getLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1357 """Get G(theta) value for a grid cell"""
1358 if not _LIDAR_FUNCTIONS_AVAILABLE:
1359 raise NotImplementedError("LiDAR functions not available")
1360 return helios_lib.getLiDARCellGtheta(cloud_ptr, index)
1363def setLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), Gtheta: float, index: int) -> None:
1364 """Set G(theta) value for a grid cell"""
1365 if not _LIDAR_FUNCTIONS_AVAILABLE:
1366 raise NotImplementedError("LiDAR functions not available")
1367 helios_lib.setLiDARCellGtheta(cloud_ptr, Gtheta, index)
1370def gapfillLiDARMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1371 """Gapfill sky/miss points"""
1372 if not _LIDAR_FUNCTIONS_AVAILABLE:
1373 raise NotImplementedError("LiDAR functions not available")
1374 helios_lib.gapfillLiDARMisses(cloud_ptr)
1377def calculateSyntheticLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1378 context_ptr: ctypes.POINTER(UContext)) -> None:
1379 """Calculate synthetic leaf area for validation"""
1380 if not _LIDAR_FUNCTIONS_AVAILABLE:
1381 raise NotImplementedError("LiDAR functions not available")
1382 helios_lib.calculateSyntheticLiDARLeafArea(cloud_ptr, context_ptr)
1385def calculateSyntheticLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1386 context_ptr: ctypes.POINTER(UContext)) -> None:
1387 """Calculate synthetic G(theta) for validation"""
1388 if not _LIDAR_FUNCTIONS_AVAILABLE:
1389 raise NotImplementedError("LiDAR functions not available")
1390 helios_lib.calculateSyntheticLiDARGtheta(cloud_ptr, context_ptr)
1393def addLiDARTrianglesToContext(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1394 context_ptr: ctypes.POINTER(UContext)) -> None:
1395 """Add triangulated mesh to Context as primitives"""
1396 if not _LIDAR_FUNCTIONS_AVAILABLE:
1397 raise NotImplementedError("LiDAR functions not available")
1398 helios_lib.addLiDARTrianglesToContext(cloud_ptr, context_ptr)
1401def initializeLiDARCollisionDetection(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1402 context_ptr: ctypes.POINTER(UContext)) -> None:
1403 """Initialize CollisionDetection for ray tracing"""
1404 if not _LIDAR_FUNCTIONS_AVAILABLE:
1405 raise NotImplementedError("LiDAR functions not available")
1406 helios_lib.initializeLiDARCollisionDetection(cloud_ptr, context_ptr)
1409def enableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1410 """Enable GPU acceleration for collision detection"""
1411 if not _LIDAR_FUNCTIONS_AVAILABLE:
1412 raise NotImplementedError("LiDAR functions not available")
1413 helios_lib.enableLiDARCDGPUAcceleration(cloud_ptr)
1416def disableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1417 """Disable GPU acceleration for collision detection"""
1418 if not _LIDAR_FUNCTIONS_AVAILABLE:
1419 raise NotImplementedError("LiDAR functions not available")
1420 helios_lib.disableLiDARCDGPUAcceleration(cloud_ptr)
1423# Mock mode for development
1424if not _LIDAR_FUNCTIONS_AVAILABLE:
1425 def mock_createLiDARcloud(*args, **kwargs):
1427 "Mock mode: LiDAR not available. "
1428 "This would create a LiDAR cloud instance with native library."
1431 def mock_lidar_operation(*args, **kwargs):
1433 "Mock mode: LiDAR operation not available. "
1434 "This would execute LiDAR operations with native library."
1437 # Replace functions with mocks for development
1438 createLiDARcloud = mock_createLiDARcloud
1439 addLiDARScan = mock_lidar_operation
1440 addLiDARHitPoint = mock_lidar_operation
Opaque structure for LiDARcloud C++ class.
int getLiDARScanPattern(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the scan pattern (0 = raster, 1 = spinning multibeam).
_check_error(result, func, args)
Automatic error checking for all LiDAR functions.
None addLiDARHitPointRGB(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, List[float] xyz, List[float] direction, List[float] color)
Add a hit point with color to the cloud.
None addLiDARHitPoints(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, xyzs, directions, int count, colors=None)
Add many hit points to the cloud in a single call (bulk ingestion).
int addLiDARScanMultibeam(ctypes.POINTER(ULiDARcloud) cloud_ptr, List[float] origin, List[float] beam_zenith_angles, int Nphi, Tuple[float, float] phi_range, float exit_diameter, float beam_divergence, Optional[List[str]] column_format=None, float range_noise_stddev=0.0, float angle_noise_stddev=0.0, float scan_tilt_roll=0.0, float scan_tilt_pitch=0.0)
Add a spinning multibeam LiDAR scan (rotating multi-channel sensor)
bool isLiDARHitMiss(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Return True if the hit is a miss (a transmitted beam that returned nothing).
List[float] getLiDARScanOrigin(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get origin of a specific scan.
None lidarCoordinateShift(ctypes.POINTER(ULiDARcloud) cloud_ptr, List[float] shift)
Translate all hit points by a shift vecto.
List[float] getLiDARScanBeamZenithAngles(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the per-channel beam zenith angles (radians) for a multibeam scan (empty for raster).
int getLiDARScanSizeTheta(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get number of zenith scan points.
float getLiDARScanTiltPitch(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the global scanner tilt pitch angle (radians) for a scan.
int getLiDARScanSizePhi(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get number of azimuthal scan points.
float getLiDARScanRangeNoiseStdDev(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the range (along-beam) measurement noise standard deviation for a scan (meters)
float getLiDARScanAngleNoiseStdDev(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the angular (beam-pointing) jitter standard deviation for a scan (radians)
bool lidarHasMisses(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Return True if the cloud contains at least one miss.
List[float] getLiDARHitXYZ(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get coordinates of a hit point.
None deleteLiDARHitPoint(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Delete a hit point from the cloud.
List[float] getLiDARHitColor(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get color of a hit point.
List[float] getLiDARHitRaydir(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get ray direction of a hit point.
float getLiDARHitData(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index, str label)
Get a named scalar data value for a hit point.
None destroyLiDARcloud(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Destroy LiDARcloud instance.
int getLiDARHitScanID(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get the scan ID a hit point belongs to.
float getLiDARScanTiltRoll(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the global scanner tilt roll angle (radians) for a scan.
createLiDARcloud
Create LiDARcloud instance.
float getLiDARMissDistance()
Return the LIDAR_MISS_DISTANCE constant (meters).
int getLiDARHitCount(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Get total number of hit points.
bool doesLiDARHitDataExist(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index, str label)
Check whether a named scalar data value exists for a hit point.
Tuple[List[float], List[float]] getLiDARHitsXYZRGB_all(ctypes.POINTER(ULiDARcloud) cloud_ptr, int n)
Bulk-export XYZ coordinates and RGB colors for all hit points in one call.
None addLiDARHitPointsWithData(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, xyzs, directions, int count, colors=None, labels=None, data_values=None)
Bulk-ingest hit points carrying a per-hit data map in one call.
int getLiDARScanCount(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Get number of scans in the cloud.
List[float] getLiDARHitData_all(ctypes.POINTER(ULiDARcloud) cloud_ptr, str label, int n)
Bulk-export a named scalar data value for all hit points in one call.