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, helios_lib.clearError)
29LiDARProgressCallback = ctypes.CFUNCTYPE(
None, ctypes.c_float, ctypes.c_char_p)
35 helios_lib.createLiDARcloud.argtypes = []
36 helios_lib.createLiDARcloud.restype = ctypes.POINTER(ULiDARcloud)
37 helios_lib.createLiDARcloud.errcheck = _check_error
39 helios_lib.destroyLiDARcloud.argtypes = [ctypes.POINTER(ULiDARcloud)]
40 helios_lib.destroyLiDARcloud.restype =
None
43 helios_lib.addLiDARScan.argtypes = [
44 ctypes.POINTER(ULiDARcloud),
45 ctypes.POINTER(ctypes.c_float),
56 ctypes.POINTER(ctypes.c_char_p),
62 helios_lib.addLiDARScan.restype = ctypes.c_uint
63 helios_lib.addLiDARScan.errcheck = _check_error
65 helios_lib.addLiDARScanMoving.argtypes = [
66 ctypes.POINTER(ULiDARcloud),
77 ctypes.POINTER(ctypes.c_char_p),
79 ctypes.POINTER(ctypes.c_double),
80 ctypes.POINTER(ctypes.c_float),
81 ctypes.POINTER(ctypes.c_float),
84 ctypes.POINTER(ctypes.c_float),
85 ctypes.POINTER(ctypes.c_float),
89 helios_lib.addLiDARScanMoving.restype = ctypes.c_uint
90 helios_lib.addLiDARScanMoving.errcheck = _check_error
92 helios_lib.addLiDARScanSpinning.argtypes = [
93 ctypes.POINTER(ULiDARcloud),
94 ctypes.POINTER(ctypes.c_float),
102 ctypes.POINTER(ctypes.c_char_p),
104 ctypes.POINTER(ctypes.c_double),
105 ctypes.POINTER(ctypes.c_float),
106 ctypes.POINTER(ctypes.c_float),
109 ctypes.POINTER(ctypes.c_float),
110 ctypes.POINTER(ctypes.c_float),
113 helios_lib.addLiDARScanSpinning.restype = ctypes.c_uint
114 helios_lib.addLiDARScanSpinning.errcheck = _check_error
116 helios_lib.addLiDARScanMovingRaster.argtypes = [
117 ctypes.POINTER(ULiDARcloud),
129 ctypes.POINTER(ctypes.c_char_p),
131 ctypes.POINTER(ctypes.c_double),
132 ctypes.POINTER(ctypes.c_float),
133 ctypes.POINTER(ctypes.c_float),
135 ctypes.POINTER(ctypes.c_float),
136 ctypes.POINTER(ctypes.c_float),
139 helios_lib.addLiDARScanMovingRaster.restype = ctypes.c_uint
140 helios_lib.addLiDARScanMovingRaster.errcheck = _check_error
142 helios_lib.addLiDARScanRisley.argtypes = [
143 ctypes.POINTER(ULiDARcloud),
144 ctypes.POINTER(ctypes.c_double),
152 ctypes.POINTER(ctypes.c_char_p),
154 ctypes.POINTER(ctypes.c_double),
155 ctypes.POINTER(ctypes.c_float),
156 ctypes.POINTER(ctypes.c_float),
159 ctypes.POINTER(ctypes.c_float),
160 ctypes.POINTER(ctypes.c_float),
163 helios_lib.addLiDARScanRisley.restype = ctypes.c_uint
164 helios_lib.addLiDARScanRisley.errcheck = _check_error
167 helios_lib.getLiDARScanMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
168 helios_lib.getLiDARScanMode.restype = ctypes.c_int
169 helios_lib.getLiDARScanMode.errcheck = _check_error
171 helios_lib.getLiDARScanStepsPerRev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
172 helios_lib.getLiDARScanStepsPerRev.restype = ctypes.c_uint
173 helios_lib.getLiDARScanStepsPerRev.errcheck = _check_error
175 helios_lib.getLiDARScanRotationRate.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
176 helios_lib.getLiDARScanRotationRate.restype = ctypes.c_double
177 helios_lib.getLiDARScanRotationRate.errcheck = _check_error
179 helios_lib.getLiDARScanRevolutions.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
180 helios_lib.getLiDARScanRevolutions.restype = ctypes.c_double
181 helios_lib.getLiDARScanRevolutions.errcheck = _check_error
183 helios_lib.getLiDARScanRisleyPrismCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
184 helios_lib.getLiDARScanRisleyPrismCount.restype = ctypes.c_uint
185 helios_lib.getLiDARScanRisleyPrismCount.errcheck = _check_error
187 helios_lib.getLiDARScanRisleyPrisms.argtypes = [
188 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
189 ctypes.POINTER(ctypes.c_double),
192 helios_lib.getLiDARScanRisleyPrisms.restype =
None
193 helios_lib.getLiDARScanRisleyPrisms.errcheck = _check_error
195 helios_lib.getLiDARScanRisleyRefractiveIndexAir.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
196 helios_lib.getLiDARScanRisleyRefractiveIndexAir.restype = ctypes.c_double
197 helios_lib.getLiDARScanRisleyRefractiveIndexAir.errcheck = _check_error
200 helios_lib.getLiDARScanReturnMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
201 helios_lib.getLiDARScanReturnMode.restype = ctypes.c_int
202 helios_lib.getLiDARScanReturnMode.errcheck = _check_error
204 helios_lib.setLiDARScanReturnMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
205 helios_lib.setLiDARScanReturnMode.restype =
None
206 helios_lib.setLiDARScanReturnMode.errcheck = _check_error
208 helios_lib.getLiDARScanSingleReturnSelection.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
209 helios_lib.getLiDARScanSingleReturnSelection.restype = ctypes.c_int
210 helios_lib.getLiDARScanSingleReturnSelection.errcheck = _check_error
212 helios_lib.setLiDARScanSingleReturnSelection.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
213 helios_lib.setLiDARScanSingleReturnSelection.restype =
None
214 helios_lib.setLiDARScanSingleReturnSelection.errcheck = _check_error
216 helios_lib.getLiDARScanMaxReturns.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
217 helios_lib.getLiDARScanMaxReturns.restype = ctypes.c_int
218 helios_lib.getLiDARScanMaxReturns.errcheck = _check_error
220 helios_lib.setLiDARScanMaxReturns.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
221 helios_lib.setLiDARScanMaxReturns.restype =
None
222 helios_lib.setLiDARScanMaxReturns.errcheck = _check_error
224 helios_lib.getLiDARScanPulseWidth.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
225 helios_lib.getLiDARScanPulseWidth.restype = ctypes.c_float
226 helios_lib.getLiDARScanPulseWidth.errcheck = _check_error
228 helios_lib.setLiDARScanPulseWidth.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float]
229 helios_lib.setLiDARScanPulseWidth.restype =
None
230 helios_lib.setLiDARScanPulseWidth.errcheck = _check_error
232 helios_lib.getLiDARScanDetectionThreshold.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
233 helios_lib.getLiDARScanDetectionThreshold.restype = ctypes.c_float
234 helios_lib.getLiDARScanDetectionThreshold.errcheck = _check_error
236 helios_lib.setLiDARScanDetectionThreshold.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float]
237 helios_lib.setLiDARScanDetectionThreshold.restype =
None
238 helios_lib.setLiDARScanDetectionThreshold.errcheck = _check_error
240 helios_lib.getLiDARScanCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
241 helios_lib.getLiDARScanCount.restype = ctypes.c_uint
242 helios_lib.getLiDARScanCount.errcheck = _check_error
244 helios_lib.getLiDARScanOrigin.argtypes = [
245 ctypes.POINTER(ULiDARcloud),
247 ctypes.POINTER(ctypes.c_float)
249 helios_lib.getLiDARScanOrigin.restype =
None
250 helios_lib.getLiDARScanOrigin.errcheck = _check_error
252 helios_lib.getLiDARScanSizeTheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
253 helios_lib.getLiDARScanSizeTheta.restype = ctypes.c_uint
254 helios_lib.getLiDARScanSizeTheta.errcheck = _check_error
256 helios_lib.getLiDARScanSizePhi.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
257 helios_lib.getLiDARScanSizePhi.restype = ctypes.c_uint
258 helios_lib.getLiDARScanSizePhi.errcheck = _check_error
260 helios_lib.getLiDARScanRangeNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
261 helios_lib.getLiDARScanRangeNoiseStdDev.restype = ctypes.c_float
262 helios_lib.getLiDARScanRangeNoiseStdDev.errcheck = _check_error
264 helios_lib.getLiDARScanAngleNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
265 helios_lib.getLiDARScanAngleNoiseStdDev.restype = ctypes.c_float
266 helios_lib.getLiDARScanAngleNoiseStdDev.errcheck = _check_error
268 helios_lib.getLiDARScanTiltRoll.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
269 helios_lib.getLiDARScanTiltRoll.restype = ctypes.c_float
270 helios_lib.getLiDARScanTiltRoll.errcheck = _check_error
272 helios_lib.getLiDARScanTiltPitch.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
273 helios_lib.getLiDARScanTiltPitch.restype = ctypes.c_float
274 helios_lib.getLiDARScanTiltPitch.errcheck = _check_error
276 helios_lib.getLiDARScanAzimuthOffset.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
277 helios_lib.getLiDARScanAzimuthOffset.restype = ctypes.c_float
278 helios_lib.getLiDARScanAzimuthOffset.errcheck = _check_error
280 helios_lib.getLiDARScanPattern.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
281 helios_lib.getLiDARScanPattern.restype = ctypes.c_int
282 helios_lib.getLiDARScanPattern.errcheck = _check_error
284 helios_lib.getLiDARScanBeamZenithAngleCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
285 helios_lib.getLiDARScanBeamZenithAngleCount.restype = ctypes.c_uint
286 helios_lib.getLiDARScanBeamZenithAngleCount.errcheck = _check_error
288 helios_lib.getLiDARScanBeamZenithAngles.argtypes = [
289 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
290 ctypes.POINTER(ctypes.c_float), ctypes.c_uint,
292 helios_lib.getLiDARScanBeamZenithAngles.restype =
None
293 helios_lib.getLiDARScanBeamZenithAngles.errcheck = _check_error
296 helios_lib.isLiDARHitMiss.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
297 helios_lib.isLiDARHitMiss.restype = ctypes.c_int
298 helios_lib.isLiDARHitMiss.errcheck = _check_error
300 helios_lib.lidarHasMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
301 helios_lib.lidarHasMisses.restype = ctypes.c_int
302 helios_lib.lidarHasMisses.errcheck = _check_error
304 helios_lib.getLiDARMissDistance.argtypes = []
305 helios_lib.getLiDARMissDistance.restype = ctypes.c_float
309 helios_lib.addLiDARHitPoint.argtypes = [
310 ctypes.POINTER(ULiDARcloud),
312 ctypes.POINTER(ctypes.c_float),
313 ctypes.POINTER(ctypes.c_float)
315 helios_lib.addLiDARHitPoint.restype =
None
316 helios_lib.addLiDARHitPoint.errcheck = _check_error
318 helios_lib.addLiDARHitPointRGB.argtypes = [
319 ctypes.POINTER(ULiDARcloud),
321 ctypes.POINTER(ctypes.c_float),
322 ctypes.POINTER(ctypes.c_float),
323 ctypes.POINTER(ctypes.c_float)
325 helios_lib.addLiDARHitPointRGB.restype =
None
326 helios_lib.addLiDARHitPointRGB.errcheck = _check_error
328 helios_lib.addLiDARHitPoints.argtypes = [
329 ctypes.POINTER(ULiDARcloud),
331 ctypes.POINTER(ctypes.c_float),
332 ctypes.POINTER(ctypes.c_float),
334 ctypes.POINTER(ctypes.c_float)
336 helios_lib.addLiDARHitPoints.restype =
None
337 helios_lib.addLiDARHitPoints.errcheck = _check_error
339 helios_lib.addLiDARHitPointsWithData.argtypes = [
340 ctypes.POINTER(ULiDARcloud),
342 ctypes.POINTER(ctypes.c_float),
343 ctypes.POINTER(ctypes.c_float),
345 ctypes.POINTER(ctypes.c_float),
346 ctypes.POINTER(ctypes.c_char_p),
348 ctypes.POINTER(ctypes.c_double)
350 helios_lib.addLiDARHitPointsWithData.restype =
None
351 helios_lib.addLiDARHitPointsWithData.errcheck = _check_error
353 helios_lib.getLiDARHitCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
354 helios_lib.getLiDARHitCount.restype = ctypes.c_uint
355 helios_lib.getLiDARHitCount.errcheck = _check_error
357 helios_lib.getLiDARHitXYZ.argtypes = [
358 ctypes.POINTER(ULiDARcloud),
360 ctypes.POINTER(ctypes.c_float)
362 helios_lib.getLiDARHitXYZ.restype =
None
363 helios_lib.getLiDARHitXYZ.errcheck = _check_error
365 helios_lib.getLiDARHitOrigin.argtypes = [
366 ctypes.POINTER(ULiDARcloud),
368 ctypes.POINTER(ctypes.c_float)
370 helios_lib.getLiDARHitOrigin.restype =
None
371 helios_lib.getLiDARHitOrigin.errcheck = _check_error
373 helios_lib.getLiDARHitRaydir.argtypes = [
374 ctypes.POINTER(ULiDARcloud),
376 ctypes.POINTER(ctypes.c_float)
378 helios_lib.getLiDARHitRaydir.restype =
None
379 helios_lib.getLiDARHitRaydir.errcheck = _check_error
381 helios_lib.getLiDARHitColor.argtypes = [
382 ctypes.POINTER(ULiDARcloud),
384 ctypes.POINTER(ctypes.c_float)
386 helios_lib.getLiDARHitColor.restype =
None
387 helios_lib.getLiDARHitColor.errcheck = _check_error
389 helios_lib.getLiDARHitScanID.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
390 helios_lib.getLiDARHitScanID.restype = ctypes.c_int
391 helios_lib.getLiDARHitScanID.errcheck = _check_error
393 helios_lib.doesLiDARHitDataExist.argtypes = [
394 ctypes.POINTER(ULiDARcloud),
398 helios_lib.doesLiDARHitDataExist.restype = ctypes.c_int
399 helios_lib.doesLiDARHitDataExist.errcheck = _check_error
401 helios_lib.getLiDARHitData.argtypes = [
402 ctypes.POINTER(ULiDARcloud),
406 helios_lib.getLiDARHitData.restype = ctypes.c_double
407 helios_lib.getLiDARHitData.errcheck = _check_error
409 helios_lib.getLiDARHitData_all.argtypes = [
410 ctypes.POINTER(ULiDARcloud),
412 ctypes.POINTER(ctypes.c_float),
415 helios_lib.getLiDARHitData_all.restype =
None
416 helios_lib.getLiDARHitData_all.errcheck = _check_error
418 helios_lib.getLiDARHitDataColumn.argtypes = [
419 ctypes.POINTER(ULiDARcloud),
421 ctypes.POINTER(ctypes.c_double),
425 helios_lib.getLiDARHitDataColumn.restype =
None
426 helios_lib.getLiDARHitDataColumn.errcheck = _check_error
428 helios_lib.getLiDARHitDataColumnIndex.argtypes = [
429 ctypes.POINTER(ULiDARcloud),
432 helios_lib.getLiDARHitDataColumnIndex.restype = ctypes.c_int
433 helios_lib.getLiDARHitDataColumnIndex.errcheck = _check_error
435 helios_lib.getLiDARHitsXYZRGB_all.argtypes = [
436 ctypes.POINTER(ULiDARcloud),
437 ctypes.POINTER(ctypes.c_float),
438 ctypes.POINTER(ctypes.c_float),
441 helios_lib.getLiDARHitsXYZRGB_all.restype =
None
442 helios_lib.getLiDARHitsXYZRGB_all.errcheck = _check_error
444 helios_lib.getLiDARHitScanID_all.argtypes = [
445 ctypes.POINTER(ULiDARcloud),
446 ctypes.POINTER(ctypes.c_int),
449 helios_lib.getLiDARHitScanID_all.restype =
None
450 helios_lib.getLiDARHitScanID_all.errcheck = _check_error
452 helios_lib.isLiDARHitMiss_all.argtypes = [
453 ctypes.POINTER(ULiDARcloud),
454 ctypes.POINTER(ctypes.c_int),
457 helios_lib.isLiDARHitMiss_all.restype =
None
458 helios_lib.isLiDARHitMiss_all.errcheck = _check_error
460 helios_lib.deleteLiDARHitPoint.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
461 helios_lib.deleteLiDARHitPoint.restype =
None
462 helios_lib.deleteLiDARHitPoint.errcheck = _check_error
465 helios_lib.lidarCoordinateShift.argtypes = [
466 ctypes.POINTER(ULiDARcloud),
467 ctypes.POINTER(ctypes.c_float)
469 helios_lib.lidarCoordinateShift.restype =
None
470 helios_lib.lidarCoordinateShift.errcheck = _check_error
472 helios_lib.lidarCoordinateRotation.argtypes = [
473 ctypes.POINTER(ULiDARcloud),
474 ctypes.POINTER(ctypes.c_float)
476 helios_lib.lidarCoordinateRotation.restype =
None
477 helios_lib.lidarCoordinateRotation.errcheck = _check_error
480 helios_lib.lidarTriangulateHitPoints.argtypes = [
481 ctypes.POINTER(ULiDARcloud),
485 helios_lib.lidarTriangulateHitPoints.restype =
None
486 helios_lib.lidarTriangulateHitPoints.errcheck = _check_error
488 helios_lib.getLiDARTriangleCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
489 helios_lib.getLiDARTriangleCount.restype = ctypes.c_uint
490 helios_lib.getLiDARTriangleCount.errcheck = _check_error
492 helios_lib.getLiDARTriangulationStats.argtypes = [
493 ctypes.POINTER(ULiDARcloud),
494 ctypes.POINTER(ctypes.c_uint),
496 helios_lib.getLiDARTriangulationStats.restype =
None
497 helios_lib.getLiDARTriangulationStats.errcheck = _check_error
499 helios_lib.getLiDARTriangleVertices_all.argtypes = [
500 ctypes.POINTER(ULiDARcloud),
501 ctypes.POINTER(ctypes.c_float),
502 ctypes.POINTER(ctypes.c_int),
505 helios_lib.getLiDARTriangleVertices_all.restype =
None
506 helios_lib.getLiDARTriangleVertices_all.errcheck = _check_error
508 helios_lib.lidarSetExternalTriangulation.argtypes = [
509 ctypes.POINTER(ULiDARcloud),
510 ctypes.POINTER(ctypes.c_float),
511 ctypes.POINTER(ctypes.c_int),
514 helios_lib.lidarSetExternalTriangulation.restype =
None
515 helios_lib.lidarSetExternalTriangulation.errcheck = _check_error
518 helios_lib.lidarDistanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
519 helios_lib.lidarDistanceFilter.restype =
None
520 helios_lib.lidarDistanceFilter.errcheck = _check_error
522 helios_lib.lidarReflectanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
523 helios_lib.lidarReflectanceFilter.restype =
None
524 helios_lib.lidarReflectanceFilter.errcheck = _check_error
526 helios_lib.lidarFirstHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
527 helios_lib.lidarFirstHitFilter.restype =
None
528 helios_lib.lidarFirstHitFilter.errcheck = _check_error
530 helios_lib.lidarLastHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
531 helios_lib.lidarLastHitFilter.restype =
None
532 helios_lib.lidarLastHitFilter.errcheck = _check_error
535 helios_lib.exportLiDARPointCloud.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p, ctypes.c_bool]
536 helios_lib.exportLiDARPointCloud.restype =
None
537 helios_lib.exportLiDARPointCloud.errcheck = _check_error
539 helios_lib.exportLiDARLeafAreaUncertainty.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
540 helios_lib.exportLiDARLeafAreaUncertainty.restype =
None
541 helios_lib.exportLiDARLeafAreaUncertainty.errcheck = _check_error
543 helios_lib.exportLiDARScans.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
544 helios_lib.exportLiDARScans.restype =
None
545 helios_lib.exportLiDARScans.errcheck = _check_error
547 helios_lib.loadLiDARXML.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
548 helios_lib.loadLiDARXML.restype =
None
549 helios_lib.loadLiDARXML.errcheck = _check_error
552 helios_lib.lidarDisableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
553 helios_lib.lidarDisableMessages.restype =
None
554 helios_lib.lidarDisableMessages.errcheck = _check_error
556 helios_lib.lidarEnableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
557 helios_lib.lidarEnableMessages.restype =
None
558 helios_lib.lidarEnableMessages.errcheck = _check_error
561 helios_lib.addLiDARGrid.argtypes = [
562 ctypes.POINTER(ULiDARcloud),
563 ctypes.POINTER(ctypes.c_float),
564 ctypes.POINTER(ctypes.c_float),
565 ctypes.POINTER(ctypes.c_int),
568 helios_lib.addLiDARGrid.restype =
None
569 helios_lib.addLiDARGrid.errcheck = _check_error
571 helios_lib.addLiDARGridTerrainFollowing.argtypes = [
572 ctypes.POINTER(ULiDARcloud),
573 ctypes.POINTER(ctypes.c_float),
574 ctypes.POINTER(ctypes.c_float),
575 ctypes.POINTER(ctypes.c_int),
577 ctypes.POINTER(ctypes.c_float),
580 helios_lib.addLiDARGridTerrainFollowing.restype =
None
581 helios_lib.addLiDARGridTerrainFollowing.errcheck = _check_error
583 helios_lib.addLiDARGridCell.argtypes = [
584 ctypes.POINTER(ULiDARcloud),
585 ctypes.POINTER(ctypes.c_float),
586 ctypes.POINTER(ctypes.c_float),
589 helios_lib.addLiDARGridCell.restype =
None
590 helios_lib.addLiDARGridCell.errcheck = _check_error
592 helios_lib.getLiDARGridCellCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
593 helios_lib.getLiDARGridCellCount.restype = ctypes.c_uint
594 helios_lib.getLiDARGridCellCount.errcheck = _check_error
596 helios_lib.getLiDARCellCenter.argtypes = [
597 ctypes.POINTER(ULiDARcloud),
599 ctypes.POINTER(ctypes.c_float)
601 helios_lib.getLiDARCellCenter.restype =
None
602 helios_lib.getLiDARCellCenter.errcheck = _check_error
604 helios_lib.getLiDARCellSize.argtypes = [
605 ctypes.POINTER(ULiDARcloud),
607 ctypes.POINTER(ctypes.c_float)
609 helios_lib.getLiDARCellSize.restype =
None
610 helios_lib.getLiDARCellSize.errcheck = _check_error
612 helios_lib.getLiDARCellRotation.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
613 helios_lib.getLiDARCellRotation.restype = ctypes.c_float
614 helios_lib.getLiDARCellRotation.errcheck = _check_error
616 helios_lib.getLiDARCellLeafArea.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
617 helios_lib.getLiDARCellLeafArea.restype = ctypes.c_float
618 helios_lib.getLiDARCellLeafArea.errcheck = _check_error
620 helios_lib.getLiDARCellLeafAreaDensity.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
621 helios_lib.getLiDARCellLeafAreaDensity.restype = ctypes.c_float
622 helios_lib.getLiDARCellLeafAreaDensity.errcheck = _check_error
625 helios_lib.getLiDARCellBeamCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
626 helios_lib.getLiDARCellBeamCount.restype = ctypes.c_int
627 helios_lib.getLiDARCellBeamCount.errcheck = _check_error
629 helios_lib.getLiDARCellRelativeDensityIndex.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
630 helios_lib.getLiDARCellRelativeDensityIndex.restype = ctypes.c_float
631 helios_lib.getLiDARCellRelativeDensityIndex.errcheck = _check_error
633 helios_lib.getLiDARCellMeanPathLength.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
634 helios_lib.getLiDARCellMeanPathLength.restype = ctypes.c_float
635 helios_lib.getLiDARCellMeanPathLength.errcheck = _check_error
637 helios_lib.getLiDARCellLADVariance.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
638 helios_lib.getLiDARCellLADVariance.restype = ctypes.c_float
639 helios_lib.getLiDARCellLADVariance.errcheck = _check_error
641 helios_lib.getLiDARCellLeafAreaConfidenceInterval.argtypes = [
642 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float,
643 ctypes.POINTER(ctypes.c_float),
645 helios_lib.getLiDARCellLeafAreaConfidenceInterval.restype = ctypes.c_int
646 helios_lib.getLiDARCellLeafAreaConfidenceInterval.errcheck = _check_error
648 helios_lib.getLiDARGroupLADConfidenceInterval.argtypes = [
649 ctypes.POINTER(ULiDARcloud),
650 ctypes.POINTER(ctypes.c_uint),
651 ctypes.c_uint, ctypes.c_float,
652 ctypes.POINTER(ctypes.c_float),
654 helios_lib.getLiDARGroupLADConfidenceInterval.restype = ctypes.c_int
655 helios_lib.getLiDARGroupLADConfidenceInterval.errcheck = _check_error
657 helios_lib.calculateLiDARHitGridCell.argtypes = [ctypes.POINTER(ULiDARcloud)]
658 helios_lib.calculateLiDARHitGridCell.restype =
None
659 helios_lib.calculateLiDARHitGridCell.errcheck = _check_error
662 helios_lib.syntheticLiDARScan.argtypes = [
663 ctypes.POINTER(ULiDARcloud),
664 ctypes.POINTER(UContext)
666 helios_lib.syntheticLiDARScan.restype =
None
667 helios_lib.syntheticLiDARScan.errcheck = _check_error
669 helios_lib.syntheticLiDARScanAppend.argtypes = [
670 ctypes.POINTER(ULiDARcloud),
671 ctypes.POINTER(UContext),
674 helios_lib.syntheticLiDARScanAppend.restype =
None
675 helios_lib.syntheticLiDARScanAppend.errcheck = _check_error
677 helios_lib.setLiDARCancelFlag.argtypes = [
678 ctypes.POINTER(ULiDARcloud),
679 ctypes.POINTER(ctypes.c_int),
681 helios_lib.setLiDARCancelFlag.restype =
None
682 helios_lib.setLiDARCancelFlag.errcheck = _check_error
684 helios_lib.setLiDARSyntheticScanMemoryBudget.argtypes = [
685 ctypes.POINTER(ULiDARcloud),
688 helios_lib.setLiDARSyntheticScanMemoryBudget.restype =
None
689 helios_lib.setLiDARSyntheticScanMemoryBudget.errcheck = _check_error
691 helios_lib.getLiDARSyntheticScanMemoryBudget.argtypes = [ctypes.POINTER(ULiDARcloud)]
692 helios_lib.getLiDARSyntheticScanMemoryBudget.restype = ctypes.c_size_t
693 helios_lib.getLiDARSyntheticScanMemoryBudget.errcheck = _check_error
695 helios_lib.setLiDARSyntheticScanProgressPointer.argtypes = [
696 ctypes.POINTER(ULiDARcloud),
697 ctypes.POINTER(ctypes.c_int),
699 helios_lib.setLiDARSyntheticScanProgressPointer.restype =
None
700 helios_lib.setLiDARSyntheticScanProgressPointer.errcheck = _check_error
702 helios_lib.setLiDARProgressCallback.argtypes = [
703 ctypes.POINTER(ULiDARcloud),
704 LiDARProgressCallback,
706 helios_lib.setLiDARProgressCallback.restype =
None
707 helios_lib.setLiDARProgressCallback.errcheck = _check_error
709 helios_lib.syntheticLiDARScanDiscrete.argtypes = [
710 ctypes.POINTER(ULiDARcloud),
711 ctypes.POINTER(UContext),
716 helios_lib.syntheticLiDARScanDiscrete.restype =
None
717 helios_lib.syntheticLiDARScanDiscrete.errcheck = _check_error
719 helios_lib.syntheticLiDARScanWaveform.argtypes = [
720 ctypes.POINTER(ULiDARcloud),
721 ctypes.POINTER(UContext),
725 helios_lib.syntheticLiDARScanWaveform.restype =
None
726 helios_lib.syntheticLiDARScanWaveform.errcheck = _check_error
728 helios_lib.syntheticLiDARScanFull.argtypes = [
729 ctypes.POINTER(ULiDARcloud),
730 ctypes.POINTER(UContext),
737 helios_lib.syntheticLiDARScanFull.restype =
None
738 helios_lib.syntheticLiDARScanFull.errcheck = _check_error
740 helios_lib.syntheticLiDARScanReturnMode.argtypes = [
741 ctypes.POINTER(ULiDARcloud),
742 ctypes.POINTER(UContext),
750 helios_lib.syntheticLiDARScanReturnMode.restype =
None
751 helios_lib.syntheticLiDARScanReturnMode.errcheck = _check_error
754 helios_lib.calculateLiDARLeafArea.argtypes = [
755 ctypes.POINTER(ULiDARcloud),
756 ctypes.POINTER(UContext)
758 helios_lib.calculateLiDARLeafArea.restype =
None
759 helios_lib.calculateLiDARLeafArea.errcheck = _check_error
761 helios_lib.calculateLiDARLeafAreaMinHits.argtypes = [
762 ctypes.POINTER(ULiDARcloud),
763 ctypes.POINTER(UContext),
766 helios_lib.calculateLiDARLeafAreaMinHits.restype =
None
767 helios_lib.calculateLiDARLeafAreaMinHits.errcheck = _check_error
769 helios_lib.calculateLiDARLeafAreaUncertainty.argtypes = [
770 ctypes.POINTER(ULiDARcloud),
771 ctypes.POINTER(UContext),
775 helios_lib.calculateLiDARLeafAreaUncertainty.restype =
None
776 helios_lib.calculateLiDARLeafAreaUncertainty.errcheck = _check_error
778 helios_lib.calculateLiDARLeafAreaGtheta.argtypes = [
779 ctypes.POINTER(ULiDARcloud),
780 ctypes.POINTER(UContext),
785 helios_lib.calculateLiDARLeafAreaGtheta.restype =
None
786 helios_lib.calculateLiDARLeafAreaGtheta.errcheck = _check_error
788 helios_lib.calculateSyntheticLiDARLeafArea.argtypes = [
789 ctypes.POINTER(ULiDARcloud),
790 ctypes.POINTER(UContext)
792 helios_lib.calculateSyntheticLiDARLeafArea.restype =
None
793 helios_lib.calculateSyntheticLiDARLeafArea.errcheck = _check_error
795 helios_lib.calculateSyntheticLiDARGtheta.argtypes = [
796 ctypes.POINTER(ULiDARcloud),
797 ctypes.POINTER(UContext)
799 helios_lib.calculateSyntheticLiDARGtheta.restype =
None
800 helios_lib.calculateSyntheticLiDARGtheta.errcheck = _check_error
802 helios_lib.getLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
803 helios_lib.getLiDARCellGtheta.restype = ctypes.c_float
804 helios_lib.getLiDARCellGtheta.errcheck = _check_error
806 helios_lib.setLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float, ctypes.c_uint]
807 helios_lib.setLiDARCellGtheta.restype =
None
808 helios_lib.setLiDARCellGtheta.errcheck = _check_error
810 helios_lib.gapfillLiDARMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
811 helios_lib.gapfillLiDARMisses.restype =
None
812 helios_lib.gapfillLiDARMisses.errcheck = _check_error
814 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
815 helios_lib.exportLiDARGtheta.restype =
None
816 helios_lib.exportLiDARGtheta.errcheck = _check_error
819 helios_lib.exportLiDARTriangleNormals.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
820 helios_lib.exportLiDARTriangleNormals.restype =
None
821 helios_lib.exportLiDARTriangleNormals.errcheck = _check_error
823 helios_lib.exportLiDARTriangleAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
824 helios_lib.exportLiDARTriangleAreas.restype =
None
825 helios_lib.exportLiDARTriangleAreas.errcheck = _check_error
827 helios_lib.exportLiDARLeafAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
828 helios_lib.exportLiDARLeafAreas.restype =
None
829 helios_lib.exportLiDARLeafAreas.errcheck = _check_error
831 helios_lib.exportLiDARLeafAreaDensities.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
832 helios_lib.exportLiDARLeafAreaDensities.restype =
None
833 helios_lib.exportLiDARLeafAreaDensities.errcheck = _check_error
836 helios_lib.addLiDARTrianglesToContext.argtypes = [
837 ctypes.POINTER(ULiDARcloud),
838 ctypes.POINTER(UContext)
840 helios_lib.addLiDARTrianglesToContext.restype =
None
841 helios_lib.addLiDARTrianglesToContext.errcheck = _check_error
843 helios_lib.initializeLiDARCollisionDetection.argtypes = [
844 ctypes.POINTER(ULiDARcloud),
845 ctypes.POINTER(UContext)
847 helios_lib.initializeLiDARCollisionDetection.restype =
None
848 helios_lib.initializeLiDARCollisionDetection.errcheck = _check_error
850 helios_lib.enableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
851 helios_lib.enableLiDARCDGPUAcceleration.restype =
None
852 helios_lib.enableLiDARCDGPUAcceleration.errcheck = _check_error
854 helios_lib.disableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
855 helios_lib.disableLiDARCDGPUAcceleration.restype =
None
856 helios_lib.disableLiDARCDGPUAcceleration.errcheck = _check_error
858 helios_lib.isLiDARGPUAvailable.argtypes = [ctypes.POINTER(ULiDARcloud)]
859 helios_lib.isLiDARGPUAvailable.restype = ctypes.c_int
860 helios_lib.isLiDARGPUAvailable.errcheck = _check_error
862 helios_lib.isLiDARGPUAccelerationEnabled.argtypes = [ctypes.POINTER(ULiDARcloud)]
863 helios_lib.isLiDARGPUAccelerationEnabled.restype = ctypes.c_int
864 helios_lib.isLiDARGPUAccelerationEnabled.errcheck = _check_error
866 _LIDAR_FUNCTIONS_AVAILABLE =
True
868except AttributeError:
869 _LIDAR_FUNCTIONS_AVAILABLE =
False
874 """Create LiDARcloud instance"""
875 if not _LIDAR_FUNCTIONS_AVAILABLE:
876 raise NotImplementedError(
877 "LiDAR functions not available. Rebuild PyHelios with lidar plugin:\n"
878 " build_scripts/build_helios --plugins lidar"
880 return helios_lib.createLiDARcloud()
884 """Destroy LiDARcloud instance"""
885 if cloud_ptr
and _LIDAR_FUNCTIONS_AVAILABLE:
886 helios_lib.destroyLiDARcloud(cloud_ptr)
890 origin: List[float], Ntheta: int, theta_range: Tuple[float, float],
891 Nphi: int, phi_range: Tuple[float, float],
892 exit_diameter: float, beam_divergence: float,
893 column_format: Optional[List[str]] =
None,
894 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
895 scan_tilt_roll: float = 0.0, scan_tilt_pitch: float = 0.0,
896 scan_azimuth_offset: float = 0.0) -> int:
897 """Add a LiDAR scan to the point cloud"""
898 if not _LIDAR_FUNCTIONS_AVAILABLE:
899 raise NotImplementedError(
"LiDAR functions not available")
902 raise ValueError(
"Origin must be a 3-element array [x, y, z]")
904 origin_array = (ctypes.c_float * 3)(*origin)
907 column_array = (ctypes.c_char_p * len(column_format))(
908 *[c.encode(
'utf-8')
for c
in column_format]
910 n_cols = len(column_format)
915 return helios_lib.addLiDARScan(
916 cloud_ptr, origin_array, Ntheta, theta_range[0], theta_range[1],
917 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
918 float(range_noise_stddev), float(angle_noise_stddev),
919 column_array, n_cols,
920 float(scan_tilt_roll), float(scan_tilt_pitch), float(scan_azimuth_offset)
925 Ntheta: int, theta_range: Tuple[float, float],
926 Nphi: int, phi_range: Tuple[float, float],
927 exit_diameter: float, beam_divergence: float,
928 traj_t: List[float], traj_pos: List[List[float]],
929 traj_rot: List[List[float]], rot_is_quaternion: bool,
930 pulse_rate_hz: float,
931 lever_arm: Optional[List[float]] =
None,
932 boresight_rpy: Optional[List[float]] =
None,
933 column_format: Optional[List[str]] =
None,
934 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
935 t0: float = 0.0) -> int:
936 """Add a moving-platform (mobile/airborne) raster LiDAR scan driven by a 6-DOF pose trajectory.
938 traj_rot entries are length-4 quaternions (qx,qy,qz,qw) if rot_is_quaternion is True,
939 otherwise length-3 roll/pitch/yaw Euler angles (radians, intrinsic Z-Y-X).
941 if not _LIDAR_FUNCTIONS_AVAILABLE:
942 raise NotImplementedError(
"LiDAR functions not available")
946 raise ValueError(
"traj_t must contain at least one trajectory sample")
947 if len(traj_pos) != M
or len(traj_rot) != M:
948 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
949 if pulse_rate_hz <= 0.0:
950 raise ValueError(
"pulse_rate_hz must be greater than 0")
952 rot_stride = 4
if rot_is_quaternion
else 3
953 if any(len(p) != 3
for p
in traj_pos):
954 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
955 if any(len(r) != rot_stride
for r
in traj_rot):
957 f
"Each traj_rot entry must have {rot_stride} elements "
958 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
961 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
962 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
963 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
964 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
965 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
967 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
968 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
969 if len(lever) != 3
or len(boresight) != 3:
970 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
971 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
972 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
975 column_array = (ctypes.c_char_p * len(column_format))(
976 *[c.encode(
'utf-8')
for c
in column_format]
978 n_cols = len(column_format)
983 return helios_lib.addLiDARScanMoving(
984 cloud_ptr, Ntheta, theta_range[0], theta_range[1],
985 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
986 float(range_noise_stddev), float(angle_noise_stddev),
987 column_array, n_cols,
988 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
989 lever_array, boresight_array, float(pulse_rate_hz), float(t0)
994 beam_elevation_angles: List[float],
995 azimuth_step_rad: float, pulse_rate_hz: float,
996 traj_t: List[float], traj_pos: List[List[float]],
997 traj_rot: List[List[float]], rot_is_quaternion: bool,
998 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
999 lever_arm: Optional[List[float]] =
None,
1000 boresight_rpy: Optional[List[float]] =
None,
1001 column_format: Optional[List[str]] =
None,
1002 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1003 t0: float = 0.0) -> int:
1004 """Add a continuously-spinning multibeam scan from physical instrument parameters.
1006 beam_elevation_angles are per-channel ELEVATION angles above the horizon (radians), NOT zenith.
1007 traj_rot entries are length-4 quaternions (qx,qy,qz,qw) if rot_is_quaternion is True,
1008 otherwise length-3 roll/pitch/yaw Euler angles (radians, intrinsic Z-Y-X).
1010 if not _LIDAR_FUNCTIONS_AVAILABLE:
1011 raise NotImplementedError(
"LiDAR functions not available")
1013 n_angles = len(beam_elevation_angles)
1015 raise ValueError(
"beam_elevation_angles must contain at least one per-channel angle")
1016 if azimuth_step_rad <= 0.0:
1017 raise ValueError(
"azimuth_step_rad must be greater than 0")
1018 if pulse_rate_hz <= 0.0:
1019 raise ValueError(
"pulse_rate_hz must be greater than 0")
1023 raise ValueError(
"traj_t must contain at least one trajectory sample")
1024 if len(traj_pos) != M
or len(traj_rot) != M:
1025 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
1027 rot_stride = 4
if rot_is_quaternion
else 3
1028 if any(len(p) != 3
for p
in traj_pos):
1029 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1030 if any(len(r) != rot_stride
for r
in traj_rot):
1032 f
"Each traj_rot entry must have {rot_stride} elements "
1033 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
1036 beam_array = (ctypes.c_float * n_angles)(*[float(a)
for a
in beam_elevation_angles])
1037 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1038 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1039 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1040 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
1041 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
1043 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1044 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1045 if len(lever) != 3
or len(boresight) != 3:
1046 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1047 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1048 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1051 column_array = (ctypes.c_char_p * len(column_format))(
1052 *[c.encode(
'utf-8')
for c
in column_format]
1054 n_cols = len(column_format)
1059 return helios_lib.addLiDARScanSpinning(
1060 cloud_ptr, beam_array, n_angles, float(azimuth_step_rad), float(pulse_rate_hz),
1061 float(exit_diameter), float(beam_divergence),
1062 float(range_noise_stddev), float(angle_noise_stddev),
1063 column_array, n_cols,
1064 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
1065 lever_array, boresight_array, float(t0)
1070 Ntheta: int, theta_range: Tuple[float, float],
1071 Nphi: int, phi_range: Tuple[float, float],
1072 pulse_rate_hz: float,
1073 traj_t: List[float], traj_pos: List[List[float]],
1074 traj_quat: List[List[float]],
1075 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
1076 lever_arm: Optional[List[float]] =
None,
1077 boresight_rpy: Optional[List[float]] =
None,
1078 column_format: Optional[List[str]] =
None,
1079 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1080 t0: float = 0.0) -> int:
1081 """Add a moving-platform raster scan: a fixed angular fan swept along a quaternion trajectory.
1083 traj_quat entries are length-4 quaternions (qx,qy,qz,qw), Hamilton body->world.
1085 if not _LIDAR_FUNCTIONS_AVAILABLE:
1086 raise NotImplementedError(
"LiDAR functions not available")
1090 raise ValueError(
"traj_t must contain at least one trajectory sample")
1091 if len(traj_pos) != M
or len(traj_quat) != M:
1092 raise ValueError(
"traj_t, traj_pos, and traj_quat must all have the same length M")
1093 if pulse_rate_hz <= 0.0:
1094 raise ValueError(
"pulse_rate_hz must be greater than 0")
1095 if any(len(p) != 3
for p
in traj_pos):
1096 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1097 if any(len(q) != 4
for q
in traj_quat):
1098 raise ValueError(
"Each traj_quat entry must be a 4-element [qx, qy, qz, qw]")
1100 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1101 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1102 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1103 quat_flat = [float(c)
for q
in traj_quat
for c
in q]
1104 quat_array = (ctypes.c_float * (4 * M))(*quat_flat)
1106 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1107 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1108 if len(lever) != 3
or len(boresight) != 3:
1109 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1110 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1111 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1114 column_array = (ctypes.c_char_p * len(column_format))(
1115 *[c.encode(
'utf-8')
for c
in column_format]
1117 n_cols = len(column_format)
1122 return helios_lib.addLiDARScanMovingRaster(
1123 cloud_ptr, Ntheta, theta_range[0], theta_range[1],
1124 Nphi, phi_range[0], phi_range[1], float(pulse_rate_hz),
1125 float(exit_diameter), float(beam_divergence),
1126 float(range_noise_stddev), float(angle_noise_stddev),
1127 column_array, n_cols,
1128 t_array, pos_array, quat_array, M,
1129 lever_array, boresight_array, float(t0)
1134 prisms: List[List[float]], refractive_index_air: float,
1135 pulse_rate_hz: float,
1136 traj_t: List[float], traj_pos: List[List[float]],
1137 traj_rot: List[List[float]], rot_is_quaternion: bool,
1138 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
1139 lever_arm: Optional[List[float]] =
None,
1140 boresight_rpy: Optional[List[float]] =
None,
1141 column_format: Optional[List[str]] =
None,
1142 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1143 t0: float = 0.0) -> int:
1144 """Add a rotating-Risley-prism (Livox-style rosette) scan from physical instrument parameters.
1146 prisms is a list of 4-element [wedge_angle, refractive_index, rotor_rate, phase] entries in
1147 beam-traversal order (at least one). traj_rot entries are length-4 quaternions (qx,qy,qz,qw)
1148 if rot_is_quaternion is True, otherwise length-3 roll/pitch/yaw Euler angles (radians).
1150 if not _LIDAR_FUNCTIONS_AVAILABLE:
1151 raise NotImplementedError(
"LiDAR functions not available")
1153 n_prisms = len(prisms)
1155 raise ValueError(
"prisms must contain at least one Risley prism")
1156 if any(len(p) != 4
for p
in prisms):
1157 raise ValueError(
"Each prism must be a 4-element [wedge_angle, refractive_index, rotor_rate, phase]")
1158 if pulse_rate_hz <= 0.0:
1159 raise ValueError(
"pulse_rate_hz must be greater than 0")
1163 raise ValueError(
"traj_t must contain at least one trajectory sample")
1164 if len(traj_pos) != M
or len(traj_rot) != M:
1165 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
1167 rot_stride = 4
if rot_is_quaternion
else 3
1168 if any(len(p) != 3
for p
in traj_pos):
1169 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1170 if any(len(r) != rot_stride
for r
in traj_rot):
1172 f
"Each traj_rot entry must have {rot_stride} elements "
1173 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
1176 prism_flat = [float(c)
for p
in prisms
for c
in p]
1177 prism_array = (ctypes.c_double * (4 * n_prisms))(*prism_flat)
1178 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1179 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1180 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1181 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
1182 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
1184 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1185 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1186 if len(lever) != 3
or len(boresight) != 3:
1187 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1188 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1189 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1192 column_array = (ctypes.c_char_p * len(column_format))(
1193 *[c.encode(
'utf-8')
for c
in column_format]
1195 n_cols = len(column_format)
1200 return helios_lib.addLiDARScanRisley(
1201 cloud_ptr, prism_array, n_prisms, float(refractive_index_air), float(pulse_rate_hz),
1202 float(exit_diameter), float(beam_divergence),
1203 float(range_noise_stddev), float(angle_noise_stddev),
1204 column_array, n_cols,
1205 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
1206 lever_array, boresight_array, float(t0)
1210def getLiDARScanMode(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> int:
1211 """Get the acquisition mode (0 = static raster, 1 = moving raster, 2 = spinning, 3 = Risley prism)."""
1212 if not _LIDAR_FUNCTIONS_AVAILABLE:
1213 raise NotImplementedError(
"LiDAR functions not available")
1214 return helios_lib.getLiDARScanMode(cloud_ptr, scanID)
1218 """Get the number of azimuth firing steps per revolution (spinning scans; 0 otherwise)."""
1219 if not _LIDAR_FUNCTIONS_AVAILABLE:
1220 raise NotImplementedError(
"LiDAR functions not available")
1221 return helios_lib.getLiDARScanStepsPerRev(cloud_ptr, scanID)
1225 """Get the sensor-head rotation rate in revolutions/second (spinning scans; 0 otherwise)."""
1226 if not _LIDAR_FUNCTIONS_AVAILABLE:
1227 raise NotImplementedError(
"LiDAR functions not available")
1228 return helios_lib.getLiDARScanRotationRate(cloud_ptr, scanID)
1232 """Get the number of revolutions the sensor head made (spinning scans; 0 otherwise)."""
1233 if not _LIDAR_FUNCTIONS_AVAILABLE:
1234 raise NotImplementedError(
"LiDAR functions not available")
1235 return helios_lib.getLiDARScanRevolutions(cloud_ptr, scanID)
1239 """Get the rotating wedge prisms of a Risley-prism scan.
1241 Returns a list of [wedge_angle, refractive_index, rotor_rate, phase] entries in
1242 beam-traversal order (empty for scans that are not Risley-prism)."""
1243 if not _LIDAR_FUNCTIONS_AVAILABLE:
1244 raise NotImplementedError(
"LiDAR functions not available")
1245 count = helios_lib.getLiDARScanRisleyPrismCount(cloud_ptr, scanID)
1248 out = (ctypes.c_double * (4 * count))()
1249 helios_lib.getLiDARScanRisleyPrisms(cloud_ptr, scanID, out, count)
1250 return [[float(out[4 * i]), float(out[4 * i + 1]), float(out[4 * i + 2]), float(out[4 * i + 3])]
1251 for i
in range(count)]
1255 """Get the refractive index of the medium surrounding the prisms of a Risley-prism scan (1.0 for non-Risley)."""
1256 if not _LIDAR_FUNCTIONS_AVAILABLE:
1257 raise NotImplementedError(
"LiDAR functions not available")
1258 return helios_lib.getLiDARScanRisleyRefractiveIndexAir(cloud_ptr, scanID)
1262 """Get the return-reporting mode (0 = multi, 1 = single)."""
1263 if not _LIDAR_FUNCTIONS_AVAILABLE:
1264 raise NotImplementedError(
"LiDAR functions not available")
1265 return helios_lib.getLiDARScanReturnMode(cloud_ptr, scanID)
1268def setLiDARScanReturnMode(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, return_mode: int) ->
None:
1269 """Set the return-reporting mode (0 = multi, 1 = single)."""
1270 if not _LIDAR_FUNCTIONS_AVAILABLE:
1271 raise NotImplementedError(
"LiDAR functions not available")
1272 helios_lib.setLiDARScanReturnMode(cloud_ptr, scanID, return_mode)
1276 """Get the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last, 3 = strongest+last)."""
1277 if not _LIDAR_FUNCTIONS_AVAILABLE:
1278 raise NotImplementedError(
"LiDAR functions not available")
1279 return helios_lib.getLiDARScanSingleReturnSelection(cloud_ptr, scanID)
1283 """Set the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last, 3 = strongest+last)."""
1284 if not _LIDAR_FUNCTIONS_AVAILABLE:
1285 raise NotImplementedError(
"LiDAR functions not available")
1286 helios_lib.setLiDARScanSingleReturnSelection(cloud_ptr, scanID, selection)
1290 """Get the maximum returns per pulse used in single/limited-return mode."""
1291 if not _LIDAR_FUNCTIONS_AVAILABLE:
1292 raise NotImplementedError(
"LiDAR functions not available")
1293 return helios_lib.getLiDARScanMaxReturns(cloud_ptr, scanID)
1296def setLiDARScanMaxReturns(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, max_returns: int) ->
None:
1297 """Set the maximum returns per pulse used in single/limited-return mode (must be >= 1)."""
1298 if not _LIDAR_FUNCTIONS_AVAILABLE:
1299 raise NotImplementedError(
"LiDAR functions not available")
1300 helios_lib.setLiDARScanMaxReturns(cloud_ptr, scanID, max_returns)
1304 """Get the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument)."""
1305 if not _LIDAR_FUNCTIONS_AVAILABLE:
1306 raise NotImplementedError(
"LiDAR functions not available")
1307 return helios_lib.getLiDARScanPulseWidth(cloud_ptr, scanID)
1310def setLiDARScanPulseWidth(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, pulse_width: float) ->
None:
1311 """Set the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument)."""
1312 if not _LIDAR_FUNCTIONS_AVAILABLE:
1313 raise NotImplementedError(
"LiDAR functions not available")
1314 helios_lib.setLiDARScanPulseWidth(cloud_ptr, scanID, float(pulse_width))
1318 """Get the detection threshold (energy fraction, noise floor) of a scan."""
1319 if not _LIDAR_FUNCTIONS_AVAILABLE:
1320 raise NotImplementedError(
"LiDAR functions not available")
1321 return helios_lib.getLiDARScanDetectionThreshold(cloud_ptr, scanID)
1325 """Set the detection threshold (energy fraction, noise floor) of a scan."""
1326 if not _LIDAR_FUNCTIONS_AVAILABLE:
1327 raise NotImplementedError(
"LiDAR functions not available")
1328 helios_lib.setLiDARScanDetectionThreshold(cloud_ptr, scanID, float(detection_threshold))
1332 """Get the global scanner tilt roll angle (radians) for a scan."""
1333 if not _LIDAR_FUNCTIONS_AVAILABLE:
1334 raise NotImplementedError(
"LiDAR functions not available")
1335 return helios_lib.getLiDARScanTiltRoll(cloud_ptr, scanID)
1339 """Get the global scanner tilt pitch angle (radians) for a scan."""
1340 if not _LIDAR_FUNCTIONS_AVAILABLE:
1341 raise NotImplementedError(
"LiDAR functions not available")
1342 return helios_lib.getLiDARScanTiltPitch(cloud_ptr, scanID)
1346 """Get the global scanner azimuth (heading) offset angle (radians) for a scan."""
1347 if not _LIDAR_FUNCTIONS_AVAILABLE:
1348 raise NotImplementedError(
"LiDAR functions not available")
1349 return helios_lib.getLiDARScanAzimuthOffset(cloud_ptr, scanID)
1353 """Get the scan pattern (0 = raster, 1 = spinning multibeam)."""
1354 if not _LIDAR_FUNCTIONS_AVAILABLE:
1355 raise NotImplementedError(
"LiDAR functions not available")
1356 return helios_lib.getLiDARScanPattern(cloud_ptr, scanID)
1360 """Get the per-channel beam zenith angles (radians) for a multibeam scan (empty for raster)."""
1361 if not _LIDAR_FUNCTIONS_AVAILABLE:
1362 raise NotImplementedError(
"LiDAR functions not available")
1363 count = helios_lib.getLiDARScanBeamZenithAngleCount(cloud_ptr, scanID)
1366 out = (ctypes.c_float * count)()
1367 helios_lib.getLiDARScanBeamZenithAngles(cloud_ptr, scanID, out, count)
1368 return [float(out[i])
for i
in range(count)]
1371def isLiDARHitMiss(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> bool:
1372 """Return True if the hit is a miss (a transmitted beam that returned nothing)."""
1373 if not _LIDAR_FUNCTIONS_AVAILABLE:
1374 raise NotImplementedError(
"LiDAR functions not available")
1375 return bool(helios_lib.isLiDARHitMiss(cloud_ptr, index))
1378def lidarHasMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
1379 """Return True if the cloud contains at least one miss."""
1380 if not _LIDAR_FUNCTIONS_AVAILABLE:
1381 raise NotImplementedError(
"LiDAR functions not available")
1382 return bool(helios_lib.lidarHasMisses(cloud_ptr))
1386 """Return the LIDAR_MISS_DISTANCE constant (meters)."""
1387 if not _LIDAR_FUNCTIONS_AVAILABLE:
1388 raise NotImplementedError(
"LiDAR functions not available")
1389 return helios_lib.getLiDARMissDistance()
1393 """Get number of scans in the cloud"""
1394 if not _LIDAR_FUNCTIONS_AVAILABLE:
1395 raise NotImplementedError(
"LiDAR functions not available")
1396 return helios_lib.getLiDARScanCount(cloud_ptr)
1399def getLiDARScanOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> List[float]:
1400 """Get origin of a specific scan"""
1401 if not _LIDAR_FUNCTIONS_AVAILABLE:
1402 raise NotImplementedError(
"LiDAR functions not available")
1404 origin = (ctypes.c_float * 3)()
1405 helios_lib.getLiDARScanOrigin(cloud_ptr, scanID, origin)
1410 """Get number of zenith scan points"""
1411 if not _LIDAR_FUNCTIONS_AVAILABLE:
1412 raise NotImplementedError(
"LiDAR functions not available")
1413 return helios_lib.getLiDARScanSizeTheta(cloud_ptr, scanID)
1417 """Get number of azimuthal scan points"""
1418 if not _LIDAR_FUNCTIONS_AVAILABLE:
1419 raise NotImplementedError(
"LiDAR functions not available")
1420 return helios_lib.getLiDARScanSizePhi(cloud_ptr, scanID)
1424 """Get the range (along-beam) measurement noise standard deviation for a scan (meters)"""
1425 if not _LIDAR_FUNCTIONS_AVAILABLE:
1426 raise NotImplementedError(
"LiDAR functions not available")
1427 return helios_lib.getLiDARScanRangeNoiseStdDev(cloud_ptr, scanID)
1431 """Get the angular (beam-pointing) jitter standard deviation for a scan (radians)"""
1432 if not _LIDAR_FUNCTIONS_AVAILABLE:
1433 raise NotImplementedError(
"LiDAR functions not available")
1434 return helios_lib.getLiDARScanAngleNoiseStdDev(cloud_ptr, scanID)
1438 xyz: List[float], direction: List[float]) ->
None:
1439 """Add a hit point to the cloud"""
1440 if not _LIDAR_FUNCTIONS_AVAILABLE:
1441 raise NotImplementedError(
"LiDAR functions not available")
1444 raise ValueError(
"XYZ must be a 3-element array")
1445 if len(direction) < 2:
1446 raise ValueError(
"Direction must have at least 2 elements [radius, elevation]")
1448 xyz_array = (ctypes.c_float * 3)(*xyz)
1449 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
1450 helios_lib.addLiDARHitPoint(cloud_ptr, scanID, xyz_array, direction_array)
1454 xyz: List[float], direction: List[float], color: List[float]) ->
None:
1455 """Add a hit point with color to the cloud"""
1456 if not _LIDAR_FUNCTIONS_AVAILABLE:
1457 raise NotImplementedError(
"LiDAR functions not available")
1460 raise ValueError(
"XYZ must be a 3-element array")
1461 if len(direction) < 2:
1462 raise ValueError(
"Direction must have at least 2 elements")
1464 raise ValueError(
"Color must be a 3-element array [r, g, b]")
1466 xyz_array = (ctypes.c_float * 3)(*xyz)
1467 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
1468 color_array = (ctypes.c_float * 3)(*color)
1469 helios_lib.addLiDARHitPointRGB(cloud_ptr, scanID, xyz_array, direction_array, color_array)
1473 xyzs, directions, count: int, colors=
None) ->
None:
1474 """Add many hit points to the cloud in a single call (bulk ingestion).
1476 xyzs and directions must be contiguous float32 buffers (e.g. numpy arrays)
1477 of shape (count, 3). colors, if given, must be a contiguous float32 buffer
1478 of shape (count, 3); pass None to add without color. The buffers are passed
1479 straight through to C without per-point Python marshalling.
1481 if not _LIDAR_FUNCTIONS_AVAILABLE:
1482 raise NotImplementedError(
"LiDAR functions not available")
1484 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1485 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1486 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
1487 helios_lib.addLiDARHitPoints(cloud_ptr, scanID, xyzs_ptr, directions_ptr, count, colors_ptr)
1491 xyzs, directions, count: int, colors=
None,
1492 labels=
None, data_values=
None) ->
None:
1493 """Bulk-ingest hit points carrying a per-hit data map in one call.
1495 xyzs/directions (and colors, if given) must be contiguous float32 buffers of
1496 shape (count, 3); directions is (radius, elevation, azimuth). labels is a
1497 list of data-map key names; data_values must be a contiguous float64 buffer
1498 of shape (count, len(labels)). Pass labels=None/empty (and data_values=None)
1499 to ingest with an empty data map.
1501 if not _LIDAR_FUNCTIONS_AVAILABLE:
1502 raise NotImplementedError(
"LiDAR functions not available")
1504 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1505 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1506 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
1508 labels = list(labels
or [])
1509 n_labels = len(labels)
1511 labels_arr = (ctypes.c_char_p * n_labels)(*[s.encode(
'utf-8')
for s
in labels])
1512 values_ptr = data_values.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
1517 helios_lib.addLiDARHitPointsWithData(cloud_ptr, scanID, xyzs_ptr, directions_ptr,
1518 count, colors_ptr, labels_arr, n_labels, values_ptr)
1522 """Get total number of hit points"""
1523 if not _LIDAR_FUNCTIONS_AVAILABLE:
1524 raise NotImplementedError(
"LiDAR functions not available")
1525 return helios_lib.getLiDARHitCount(cloud_ptr)
1528def getLiDARHitXYZ(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1529 """Get coordinates of a hit point"""
1530 if not _LIDAR_FUNCTIONS_AVAILABLE:
1531 raise NotImplementedError(
"LiDAR functions not available")
1533 xyz = (ctypes.c_float * 3)()
1534 helios_lib.getLiDARHitXYZ(cloud_ptr, index, xyz)
1538def getLiDARHitOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1539 """Get the (x,y,z) beam-emission origin of a hit point.
1541 For moving-platform scans this is the per-pulse origin; for static scans it falls back to
1542 the single scan origin of the hit's scan.
1544 if not _LIDAR_FUNCTIONS_AVAILABLE:
1545 raise NotImplementedError(
"LiDAR functions not available")
1547 xyz = (ctypes.c_float * 3)()
1548 helios_lib.getLiDARHitOrigin(cloud_ptr, index, xyz)
1552def getLiDARHitRaydir(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1553 """Get ray direction of a hit point"""
1554 if not _LIDAR_FUNCTIONS_AVAILABLE:
1555 raise NotImplementedError(
"LiDAR functions not available")
1557 direction = (ctypes.c_float * 3)()
1558 helios_lib.getLiDARHitRaydir(cloud_ptr, index, direction)
1559 return list(direction)
1562def getLiDARHitColor(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1563 """Get color of a hit point"""
1564 if not _LIDAR_FUNCTIONS_AVAILABLE:
1565 raise NotImplementedError(
"LiDAR functions not available")
1567 color = (ctypes.c_float * 3)()
1568 helios_lib.getLiDARHitColor(cloud_ptr, index, color)
1572def getLiDARHitScanID(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> int:
1573 """Get the scan ID a hit point belongs to"""
1574 if not _LIDAR_FUNCTIONS_AVAILABLE:
1575 raise NotImplementedError(
"LiDAR functions not available")
1576 return helios_lib.getLiDARHitScanID(cloud_ptr, index)
1580 """Check whether a named scalar data value exists for a hit point"""
1581 if not _LIDAR_FUNCTIONS_AVAILABLE:
1582 raise NotImplementedError(
"LiDAR functions not available")
1583 return bool(helios_lib.doesLiDARHitDataExist(cloud_ptr, index, label.encode(
'utf-8')))
1586def getLiDARHitData(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int, label: str) -> float:
1587 """Get a named scalar data value for a hit point"""
1588 if not _LIDAR_FUNCTIONS_AVAILABLE:
1589 raise NotImplementedError(
"LiDAR functions not available")
1590 return helios_lib.getLiDARHitData(cloud_ptr, index, label.encode(
'utf-8'))
1593def getLiDARHitData_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), label: str, n: int) -> List[float]:
1594 """Bulk-export a named scalar data value for all hit points in one call"""
1595 if not _LIDAR_FUNCTIONS_AVAILABLE:
1596 raise NotImplementedError(
"LiDAR functions not available")
1598 out = (ctypes.c_float * n)()
1599 helios_lib.getLiDARHitData_all(cloud_ptr, label.encode(
'utf-8'), out, n)
1603def getLiDARHitsXYZRGB_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), n: int) -> Tuple[List[float], List[float]]:
1604 """Bulk-export XYZ coordinates and RGB colors for all hit points in one call.
1606 Returns a tuple (xyz_flat, rgb_flat) of flat 3*n-element lists.
1608 if not _LIDAR_FUNCTIONS_AVAILABLE:
1609 raise NotImplementedError(
"LiDAR functions not available")
1611 xyz = (ctypes.c_float * (3 * n))()
1612 rgb = (ctypes.c_float * (3 * n))()
1613 helios_lib.getLiDARHitsXYZRGB_all(cloud_ptr, xyz, rgb, n)
1614 return list(xyz), list(rgb)
1618 """Bulk-export XYZ + RGB for all hits as numpy arrays (no per-element Python).
1620 Returns (xyz, rgb), each an (n, 3) float32 array. Much faster than the
1621 list-returning variant for million-point clouds — np.frombuffer copies the
1622 contiguous ctypes buffer in one shot.
1625 if not _LIDAR_FUNCTIONS_AVAILABLE:
1626 raise NotImplementedError(
"LiDAR functions not available")
1627 xyz = (ctypes.c_float * (3 * n))()
1628 rgb = (ctypes.c_float * (3 * n))()
1629 helios_lib.getLiDARHitsXYZRGB_all(cloud_ptr, xyz, rgb, n)
1630 xyz_np = np.frombuffer(xyz, dtype=np.float32, count=3 * n).copy().reshape(n, 3)
1631 rgb_np = np.frombuffer(rgb, dtype=np.float32, count=3 * n).copy().reshape(n, 3)
1632 return xyz_np, rgb_np
1636 """Bulk-export a named scalar field for all hits as an (n,) float32 numpy array
1637 (NaN where the label is absent for a hit)."""
1639 if not _LIDAR_FUNCTIONS_AVAILABLE:
1640 raise NotImplementedError(
"LiDAR functions not available")
1641 out = (ctypes.c_float * n)()
1642 helios_lib.getLiDARHitData_all(cloud_ptr, label.encode(
'utf-8'), out, n)
1643 return np.frombuffer(out, dtype=np.float32, count=n).copy()
1647 absent_value: float = -9999.0) -> List[float]:
1648 """Bulk-export a named scalar column via the native cache-linear columnar path.
1650 Faster than getLiDARHitData_all for whole-field reads (single cache-linear pass over the
1651 contiguous native column). Entries are absent_value where the label is absent for a hit.
1652 Returns a list of doubles of length min(n, hit count).
1654 if not _LIDAR_FUNCTIONS_AVAILABLE:
1655 raise NotImplementedError(
"LiDAR functions not available")
1657 out = (ctypes.c_double * n)()
1658 helios_lib.getLiDARHitDataColumn(cloud_ptr, label.encode(
'utf-8'), out, n, float(absent_value))
1663 """Get the internal column slot index for a hit-data label (-1 if never set on any hit)."""
1664 if not _LIDAR_FUNCTIONS_AVAILABLE:
1665 raise NotImplementedError(
"LiDAR functions not available")
1666 return helios_lib.getLiDARHitDataColumnIndex(cloud_ptr, label.encode(
'utf-8'))
1670 absent_value: float = -9999.0):
1671 """Bulk-export a named scalar column as an (n,) float64 numpy array via the columnar path
1672 (absent_value where the label is absent for a hit)."""
1674 if not _LIDAR_FUNCTIONS_AVAILABLE:
1675 raise NotImplementedError(
"LiDAR functions not available")
1676 out = (ctypes.c_double * n)()
1677 helios_lib.getLiDARHitDataColumn(cloud_ptr, label.encode(
'utf-8'), out, n, float(absent_value))
1678 return np.frombuffer(out, dtype=np.float64, count=n).copy()
1682 """Bulk-export the scan ID of every hit as an (n,) int32 numpy array."""
1684 if not _LIDAR_FUNCTIONS_AVAILABLE:
1685 raise NotImplementedError(
"LiDAR functions not available")
1686 out = (ctypes.c_int * n)()
1687 helios_lib.getLiDARHitScanID_all(cloud_ptr, out, n)
1688 return np.frombuffer(out, dtype=np.int32, count=n).copy()
1692 """Bulk-export the miss flag of every hit as an (n,) int32 numpy array (1=miss)."""
1694 if not _LIDAR_FUNCTIONS_AVAILABLE:
1695 raise NotImplementedError(
"LiDAR functions not available")
1696 out = (ctypes.c_int * n)()
1697 helios_lib.isLiDARHitMiss_all(cloud_ptr, out, n)
1698 return np.frombuffer(out, dtype=np.int32, count=n).copy()
1702 """Delete a hit point from the cloud"""
1703 if not _LIDAR_FUNCTIONS_AVAILABLE:
1704 raise NotImplementedError(
"LiDAR functions not available")
1705 helios_lib.deleteLiDARHitPoint(cloud_ptr, index)
1709 """Translate all hit points by a shift vector"""
1710 if not _LIDAR_FUNCTIONS_AVAILABLE:
1711 raise NotImplementedError("LiDAR functions not available")
1714 raise ValueError("Shift must be a 3-element array [x, y, z]")
1716 shift_array = (ctypes.c_float * 3)(*shift)
1717 helios_lib.lidarCoordinateShift(cloud_ptr, shift_array)
1720def lidarCoordinateRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), rotation: List[float]) -> None:
1721 """Rotate all hit points by spherical rotation angles"""
1722 if not _LIDAR_FUNCTIONS_AVAILABLE:
1723 raise NotImplementedError("LiDAR functions not available")
1725 if len(rotation) < 2:
1726 raise ValueError("Rotation must have at least 2 elements [radius, elevation]")
1728 rotation_array = (ctypes.c_float * 3)(rotation[0], rotation[1], rotation[2] if len(rotation) > 2 else 0)
1729 helios_lib.lidarCoordinateRotation(cloud_ptr, rotation_array)
1732def lidarTriangulateHitPoints(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1733 Lmax: float, max_aspect_ratio: float) -> None:
1734 """Generate triangle mesh from hit points"""
1735 if not _LIDAR_FUNCTIONS_AVAILABLE:
1736 raise NotImplementedError("LiDAR functions not available")
1737 helios_lib.lidarTriangulateHitPoints(cloud_ptr, Lmax, max_aspect_ratio)
1740def getLiDARTriangleCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
1741 """Get number of triangles in the mesh"""
1742 if not _LIDAR_FUNCTIONS_AVAILABLE:
1743 raise NotImplementedError("LiDAR functions not available")
1744 return helios_lib.getLiDARTriangleCount(cloud_ptr)
1747def getLiDARTriangulationStats(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> dict:
1748 """Filter diagnostics from the most recent triangulateHitPoints() call.
1750 Returns a dict with candidate/dropped counts. Each dropped triangle is
1751 attributed to one primary reason, so:
1752 candidates == kept + dropped_lmax + dropped_aspect + dropped_degenerate
1753 where `kept` equals getLiDARTriangleCount(). All zero if triangulation has
1756 if not _LIDAR_FUNCTIONS_AVAILABLE:
1757 raise NotImplementedError("LiDAR functions not available")
1758 out = (ctypes.c_uint * 4)()
1759 helios_lib.getLiDARTriangulationStats(cloud_ptr, out)
1761 "candidates": int(out[0]),
1762 "dropped_lmax": int(out[1]),
1763 "dropped_aspect": int(out[2]),
1764 "dropped_degenerate": int(out[3]),
1768def getLiDARTriangleVertices_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), tri_count: int):
1769 """Bulk-export every triangle's vertices (and source scan) in one call.
1771 Returns (xyz_flat, scan_ids) as numpy arrays: xyz_flat is (tri_count*9,)
1772 float32 laid out [v0x,v0y,v0z, v1x,v1y,v1z, v2x,v2y,v2z] per triangle, and
1773 scan_ids is (tri_count,) int32. Returns empty arrays when tri_count is 0.
1776 if not _LIDAR_FUNCTIONS_AVAILABLE:
1777 raise NotImplementedError("LiDAR functions not available")
1779 return np.empty((0,), dtype=np.float32), np.empty((0,), dtype=np.int32)
1781 xyz = np.empty((tri_count * 9,), dtype=np.float32)
1782 scan = np.empty((tri_count,), dtype=np.int32)
1783 helios_lib.getLiDARTriangleVertices_all(
1785 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
1786 scan.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
1792def lidarSetExternalTriangulation(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1793 xyz_flat, scan_ids, tri_count: int) -> None:
1794 """Replace the internal triangulation with an externally-supplied mesh.
1796 xyz_flat is (tri_count*9,) float32 laid out [v0x,v0y,v0z, v1x,v1y,v1z,
1797 v2x,v2y,v2z] per triangle (the same layout getLiDARTriangleVertices_all
1798 exports). scan_ids is (tri_count,) int32, one required source scan per
1799 triangle. No-op when tri_count is 0.
1802 if not _LIDAR_FUNCTIONS_AVAILABLE:
1803 raise NotImplementedError("LiDAR functions not available")
1807 xyz = np.ascontiguousarray(xyz_flat, dtype=np.float32)
1808 scan = np.ascontiguousarray(scan_ids, dtype=np.int32)
1809 if xyz.size != tri_count * 9:
1810 raise ValueError(f"xyz_flat has {xyz.size} floats, expected {tri_count * 9} (9 per triangle)")
1811 if scan.size != tri_count:
1812 raise ValueError(f"scan_ids has {scan.size} entries, expected {tri_count} (one per triangle)")
1814 helios_lib.lidarSetExternalTriangulation(
1816 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
1817 scan.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
1822def lidarDistanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), maxdistance: float) -> None:
1823 """Filter hit points by maximum distance"""
1824 if not _LIDAR_FUNCTIONS_AVAILABLE:
1825 raise NotImplementedError("LiDAR functions not available")
1826 helios_lib.lidarDistanceFilter(cloud_ptr, maxdistance)
1829def lidarReflectanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), minreflectance: float) -> None:
1830 """Filter hit points by minimum reflectance"""
1831 if not _LIDAR_FUNCTIONS_AVAILABLE:
1832 raise NotImplementedError("LiDAR functions not available")
1833 helios_lib.lidarReflectanceFilter(cloud_ptr, minreflectance)
1836def lidarFirstHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1837 """Keep only first return hit points"""
1838 if not _LIDAR_FUNCTIONS_AVAILABLE:
1839 raise NotImplementedError("LiDAR functions not available")
1840 helios_lib.lidarFirstHitFilter(cloud_ptr)
1843def lidarLastHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1844 """Keep only last return hit points"""
1845 if not _LIDAR_FUNCTIONS_AVAILABLE:
1846 raise NotImplementedError("LiDAR functions not available")
1847 helios_lib.lidarLastHitFilter(cloud_ptr)
1850def exportLiDARPointCloud(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str,
1851 write_header: bool = True) -> None:
1852 """Export point cloud to ASCII file (optionally with a '#'-prefixed column header)"""
1853 if not _LIDAR_FUNCTIONS_AVAILABLE:
1854 raise NotImplementedError("LiDAR functions not available")
1855 helios_lib.exportLiDARPointCloud(cloud_ptr, filename.encode('utf-8'), bool(write_header))
1858def exportLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1859 """Export per-voxel leaf-area sampling uncertainty to a self-describing ASCII file"""
1860 if not _LIDAR_FUNCTIONS_AVAILABLE:
1861 raise NotImplementedError("LiDAR functions not available")
1862 helios_lib.exportLiDARLeafAreaUncertainty(cloud_ptr, filename.encode('utf-8'))
1865def exportLiDARScans(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1866 """Export all scans to an XML metadata file plus one ASCII data file per scan"""
1867 if not _LIDAR_FUNCTIONS_AVAILABLE:
1868 raise NotImplementedError("LiDAR functions not available")
1869 helios_lib.exportLiDARScans(cloud_ptr, filename.encode('utf-8'))
1872def loadLiDARXML(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
1873 """Load scan metadata from XML file"""
1874 if not _LIDAR_FUNCTIONS_AVAILABLE:
1875 raise NotImplementedError("LiDAR functions not available")
1876 helios_lib.loadLiDARXML(cloud_ptr, filename.encode('utf-8'))
1879def lidarDisableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1880 """Disable console output messages"""
1881 if not _LIDAR_FUNCTIONS_AVAILABLE:
1882 raise NotImplementedError("LiDAR functions not available")
1883 helios_lib.lidarDisableMessages(cloud_ptr)
1886def lidarEnableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
1887 """Enable console output messages"""
1888 if not _LIDAR_FUNCTIONS_AVAILABLE:
1889 raise NotImplementedError("LiDAR functions not available")
1890 helios_lib.lidarEnableMessages(cloud_ptr)
1893def addLiDARGrid(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
1894 size: List[float], ndiv: List[int], rotation: float) -> None:
1895 """Add a rectangular grid of voxel cells"""
1896 if not _LIDAR_FUNCTIONS_AVAILABLE:
1897 raise NotImplementedError("LiDAR functions not available")
1899 if len(center) != 3:
1900 raise ValueError("Center must be a 3-element array [x, y, z]")
1902 raise ValueError("Size must be a 3-element array [x, y, z]")
1904 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
1906 center_array = (ctypes.c_float * 3)(*center)
1907 size_array = (ctypes.c_float * 3)(*size)
1908 ndiv_array = (ctypes.c_int * 3)(*ndiv)
1909 helios_lib.addLiDARGrid(cloud_ptr, center_array, size_array, ndiv_array, rotation)
1912def addLiDARGridTerrainFollowing(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
1913 size: List[float], ndiv: List[int], rotation: float,
1914 column_z_offsets: List[float]) -> None:
1915 """Add a rectangular grid of voxel cells with per-column vertical offsets"""
1916 if not _LIDAR_FUNCTIONS_AVAILABLE:
1917 raise NotImplementedError("LiDAR functions not available")
1919 if len(center) != 3:
1920 raise ValueError("Center must be a 3-element array [x, y, z]")
1922 raise ValueError("Size must be a 3-element array [x, y, z]")
1924 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
1926 expected = ndiv[0] * ndiv[1]
1927 if len(column_z_offsets) != expected:
1929 f"column_z_offsets must have length ndiv[0]*ndiv[1] = {expected}, "
1930 f"got {len(column_z_offsets)}"
1933 center_array = (ctypes.c_float * 3)(*center)
1934 size_array = (ctypes.c_float * 3)(*size)
1935 ndiv_array = (ctypes.c_int * 3)(*ndiv)
1936 offsets_array = (ctypes.c_float * len(column_z_offsets))(*column_z_offsets)
1937 helios_lib.addLiDARGridTerrainFollowing(cloud_ptr, center_array, size_array, ndiv_array,
1938 rotation, offsets_array, len(column_z_offsets))
1941def addLiDARGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
1942 size: List[float], rotation: float) -> None:
1943 """Add a single grid cell"""
1944 if not _LIDAR_FUNCTIONS_AVAILABLE:
1945 raise NotImplementedError("LiDAR functions not available")
1947 if len(center) != 3:
1948 raise ValueError("Center must be a 3-element array [x, y, z]")
1950 raise ValueError("Size must be a 3-element array [x, y, z]")
1952 center_array = (ctypes.c_float * 3)(*center)
1953 size_array = (ctypes.c_float * 3)(*size)
1954 helios_lib.addLiDARGridCell(cloud_ptr, center_array, size_array, rotation)
1957def getLiDARGridCellCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
1958 """Get number of grid cells"""
1959 if not _LIDAR_FUNCTIONS_AVAILABLE:
1960 raise NotImplementedError("LiDAR functions not available")
1961 return helios_lib.getLiDARGridCellCount(cloud_ptr)
1964def getLiDARCellCenter(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1965 """Get center position of a grid cell"""
1966 if not _LIDAR_FUNCTIONS_AVAILABLE:
1967 raise NotImplementedError("LiDAR functions not available")
1969 center = (ctypes.c_float * 3)()
1970 helios_lib.getLiDARCellCenter(cloud_ptr, index, center)
1974def getLiDARCellSize(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1975 """Get size of a grid cell"""
1976 if not _LIDAR_FUNCTIONS_AVAILABLE:
1977 raise NotImplementedError("LiDAR functions not available")
1979 size = (ctypes.c_float * 3)()
1980 helios_lib.getLiDARCellSize(cloud_ptr, index, size)
1984def getLiDARCellRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1985 """Get azimuthal rotation of a grid cell about the z-axis, in degrees"""
1986 if not _LIDAR_FUNCTIONS_AVAILABLE:
1987 raise NotImplementedError("LiDAR functions not available")
1988 return helios_lib.getLiDARCellRotation(cloud_ptr, index)
1991def getLiDARCellLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1992 """Get leaf area of a grid cell"""
1993 if not _LIDAR_FUNCTIONS_AVAILABLE:
1994 raise NotImplementedError("LiDAR functions not available")
1995 return helios_lib.getLiDARCellLeafArea(cloud_ptr, index)
1998def getLiDARCellLeafAreaDensity(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
1999 """Get leaf area density of a grid cell"""
2000 if not _LIDAR_FUNCTIONS_AVAILABLE:
2001 raise NotImplementedError("LiDAR functions not available")
2002 return helios_lib.getLiDARCellLeafAreaDensity(cloud_ptr, index)
2005def calculateLiDARHitGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2006 """Calculate hit point grid cell assignments"""
2007 if not _LIDAR_FUNCTIONS_AVAILABLE:
2008 raise NotImplementedError("LiDAR functions not available")
2009 helios_lib.calculateLiDARHitGridCell(cloud_ptr)
2012def syntheticLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2013 context_ptr: ctypes.POINTER(UContext)) -> None:
2014 """Perform synthetic discrete-return LiDAR scan"""
2015 if not _LIDAR_FUNCTIONS_AVAILABLE:
2016 raise NotImplementedError("LiDAR functions not available")
2017 helios_lib.syntheticLiDARScan(cloud_ptr, context_ptr)
2020def syntheticLiDARScanAppend(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2021 context_ptr: ctypes.POINTER(UContext),
2022 append: bool) -> None:
2023 """Perform synthetic scan with append control"""
2024 if not _LIDAR_FUNCTIONS_AVAILABLE:
2025 raise NotImplementedError("LiDAR functions not available")
2026 helios_lib.syntheticLiDARScanAppend(cloud_ptr, context_ptr, append)
2029def setLiDARCancelFlag(cloud_ptr: ctypes.POINTER(ULiDARcloud), flag) -> None:
2030 """Register an external cancellation flag polled during syntheticScan.
2032 `flag` is a ctypes.c_int (pass by ref) that, when set non-zero from another
2033 thread, aborts the scan's ray loop mid-trace. Pass None to clear."""
2034 if not _LIDAR_FUNCTIONS_AVAILABLE:
2035 raise NotImplementedError("LiDAR functions not available")
2036 ptr = ctypes.byref(flag) if flag is not None else None
2037 helios_lib.setLiDARCancelFlag(cloud_ptr, ptr)
2040def setLiDARSyntheticScanMemoryBudget(cloud_ptr: ctypes.POINTER(ULiDARcloud), bytes: int) -> None:
2041 """Set the soft memory budget (bytes) for syntheticScan's transient trace buffers.
2043 Bounds the live ray-tracing scratch buffers so large scans are chunked rather
2044 than traced in one OOM-prone batch. `bytes` must be > 0; if never set, Helios
2045 uses an automatic path-dependent default (4 GiB CPU / 8 GiB GPU)."""
2046 if not _LIDAR_FUNCTIONS_AVAILABLE:
2047 raise NotImplementedError("LiDAR functions not available")
2048 helios_lib.setLiDARSyntheticScanMemoryBudget(cloud_ptr, ctypes.c_size_t(bytes))
2051def getLiDARSyntheticScanMemoryBudget(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
2052 """Get the soft memory budget (bytes) for syntheticScan's transient buffers.
2054 Returns the explicitly configured budget, or 0 if using the automatic
2055 path-dependent default (4 GiB CPU / 8 GiB GPU)."""
2056 if not _LIDAR_FUNCTIONS_AVAILABLE:
2057 raise NotImplementedError("LiDAR functions not available")
2058 return int(helios_lib.getLiDARSyntheticScanMemoryBudget(cloud_ptr))
2061def setLiDARSyntheticScanProgressPointer(cloud_ptr: ctypes.POINTER(ULiDARcloud), ptr) -> None:
2062 """Register an external per-scan progress counter polled during syntheticScan.
2064 `ptr` is a ctypes.c_int (pass by ref) into which syntheticScan writes the 0-based
2065 index of the scan currently being ray-traced, set to getScanCount() when finished.
2066 Pass None to clear."""
2067 if not _LIDAR_FUNCTIONS_AVAILABLE:
2068 raise NotImplementedError("LiDAR functions not available")
2069 p = ctypes.byref(ptr) if ptr is not None else None
2070 helios_lib.setLiDARSyntheticScanProgressPointer(cloud_ptr, p)
2073def setLiDARProgressCallback(cloud_ptr: ctypes.POINTER(ULiDARcloud), callback) -> None:
2074 """Register a progress callback fired with (progress_fraction, message) during syntheticScan.
2076 `callback` must be a LiDARProgressCallback ctypes instance (or None to clear). The
2077 caller is responsible for keeping the LiDARProgressCallback alive for as long as it is
2078 registered (ctypes does not hold a reference)."""
2079 if not _LIDAR_FUNCTIONS_AVAILABLE:
2080 raise NotImplementedError("LiDAR functions not available")
2081 # A bare None is NOT accepted for a CFUNCTYPE argtype (ctypes wants a CFunctionType instance);
2082 # cast None to the callback type to pass a null function pointer that clears the callback.
2083 cb = callback if callback is not None else ctypes.cast(None, LiDARProgressCallback)
2084 helios_lib.setLiDARProgressCallback(cloud_ptr, cb)
2087def syntheticLiDARScanDiscrete(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2088 context_ptr: ctypes.POINTER(UContext),
2089 scan_grid_only: bool, record_misses: bool, append: bool) -> None:
2090 """Perform discrete-return synthetic scan with miss-recording control"""
2091 if not _LIDAR_FUNCTIONS_AVAILABLE:
2092 raise NotImplementedError("LiDAR functions not available")
2093 helios_lib.syntheticLiDARScanDiscrete(cloud_ptr, context_ptr, scan_grid_only, record_misses, append)
2096def syntheticLiDARScanWaveform(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2097 context_ptr: ctypes.POINTER(UContext),
2098 rays_per_pulse: int,
2099 pulse_distance_threshold: float) -> None:
2100 """Perform synthetic full-waveform LiDAR scan"""
2101 if not _LIDAR_FUNCTIONS_AVAILABLE:
2102 raise NotImplementedError("LiDAR functions not available")
2103 helios_lib.syntheticLiDARScanWaveform(cloud_ptr, context_ptr, rays_per_pulse, pulse_distance_threshold)
2106def syntheticLiDARScanFull(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2107 context_ptr: ctypes.POINTER(UContext),
2108 rays_per_pulse: int,
2109 pulse_distance_threshold: float,
2110 scan_grid_only: bool,
2111 record_misses: bool,
2112 append: bool) -> None:
2113 """Perform synthetic scan with full control"""
2114 if not _LIDAR_FUNCTIONS_AVAILABLE:
2115 raise NotImplementedError("LiDAR functions not available")
2116 helios_lib.syntheticLiDARScanFull(cloud_ptr, context_ptr, rays_per_pulse,
2117 pulse_distance_threshold, scan_grid_only,
2118 record_misses, append)
2121def syntheticLiDARScanReturnMode(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2122 context_ptr: ctypes.POINTER(UContext),
2123 rays_per_pulse: int,
2124 pulse_distance_threshold: float,
2126 scan_grid_only: bool = False,
2127 record_misses: bool = False,
2128 append: bool = True) -> None:
2129 """Perform an analytic-waveform synthetic scan with an explicit return mode.
2131 return_mode is 0 (multi) or 1 (single); it overrides each scan's stored returnMode for this
2132 call only. In single mode up to each scan's maxReturns returns per pulse are reported.
2134 if not _LIDAR_FUNCTIONS_AVAILABLE:
2135 raise NotImplementedError("LiDAR functions not available")
2136 helios_lib.syntheticLiDARScanReturnMode(cloud_ptr, context_ptr, rays_per_pulse,
2137 pulse_distance_threshold, return_mode,
2138 scan_grid_only, record_misses, append)
2141def calculateLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2142 context_ptr: ctypes.POINTER(UContext)) -> None:
2143 """Calculate leaf area for each grid cell"""
2144 if not _LIDAR_FUNCTIONS_AVAILABLE:
2145 raise NotImplementedError("LiDAR functions not available")
2146 helios_lib.calculateLiDARLeafArea(cloud_ptr, context_ptr)
2149def calculateLiDARLeafAreaMinHits(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2150 context_ptr: ctypes.POINTER(UContext),
2151 min_voxel_hits: int) -> None:
2152 """Calculate leaf area with minimum voxel hits threshold"""
2153 if not _LIDAR_FUNCTIONS_AVAILABLE:
2154 raise NotImplementedError("LiDAR functions not available")
2155 helios_lib.calculateLiDARLeafAreaMinHits(cloud_ptr, context_ptr, min_voxel_hits)
2158def calculateLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2159 context_ptr: ctypes.POINTER(UContext),
2160 min_voxel_hits: int, element_width: float) -> None:
2161 """Calculate leaf area plus per-voxel sampling uncertainty (Pimont et al. 2018)"""
2162 if not _LIDAR_FUNCTIONS_AVAILABLE:
2163 raise NotImplementedError("LiDAR functions not available")
2164 helios_lib.calculateLiDARLeafAreaUncertainty(
2165 cloud_ptr, context_ptr, min_voxel_hits, float(element_width))
2168def calculateLiDARLeafAreaGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2169 context_ptr: ctypes.POINTER(UContext),
2170 Gtheta: float, min_voxel_hits: int, element_width: float) -> None:
2171 """Calculate leaf area using a caller-supplied G(theta), without requiring triangulation.
2173 Suitable for moving-platform scans (which cannot be triangulated). Gtheta must be in (0,1]
2174 (0.5 = spherical leaf-angle distribution).
2176 if not _LIDAR_FUNCTIONS_AVAILABLE:
2177 raise NotImplementedError("LiDAR functions not available")
2178 helios_lib.calculateLiDARLeafAreaGtheta(
2179 cloud_ptr, context_ptr, float(Gtheta), min_voxel_hits, float(element_width))
2182def getLiDARCellBeamCount(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> int:
2183 """Get the beam count N entering a grid cell (-1 if calculateLeafArea not run)."""
2184 if not _LIDAR_FUNCTIONS_AVAILABLE:
2185 raise NotImplementedError("LiDAR functions not available")
2186 return helios_lib.getLiDARCellBeamCount(cloud_ptr, index)
2189def getLiDARCellRelativeDensityIndex(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2190 """Get the relative density index I_rdi for a grid cell."""
2191 if not _LIDAR_FUNCTIONS_AVAILABLE:
2192 raise NotImplementedError("LiDAR functions not available")
2193 return helios_lib.getLiDARCellRelativeDensityIndex(cloud_ptr, index)
2196def getLiDARCellMeanPathLength(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2197 """Get the mean beam path length (m) through a grid cell."""
2198 if not _LIDAR_FUNCTIONS_AVAILABLE:
2199 raise NotImplementedError("LiDAR functions not available")
2200 return helios_lib.getLiDARCellMeanPathLength(cloud_ptr, index)
2203def getLiDARCellLADVariance(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2204 """Get the per-voxel LAD sampling variance (-1 if unavailable)."""
2205 if not _LIDAR_FUNCTIONS_AVAILABLE:
2206 raise NotImplementedError("LiDAR functions not available")
2207 return helios_lib.getLiDARCellLADVariance(cloud_ptr, index)
2210def getLiDARCellLeafAreaConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int,
2211 confidence_level: float = 0.95):
2212 """Single-voxel leaf-area confidence interval.
2214 Returns (valid, lower, upper). ``valid`` is False when the interval is gated
2215 out by the Pimont validity envelope (the bounds are then not trustworthy).
2217 if not _LIDAR_FUNCTIONS_AVAILABLE:
2218 raise NotImplementedError("LiDAR functions not available")
2219 out = (ctypes.c_float * 2)()
2220 valid = helios_lib.getLiDARCellLeafAreaConfidenceInterval(
2221 cloud_ptr, index, float(confidence_level), out)
2222 return bool(valid), float(out[0]), float(out[1])
2225def getLiDARGroupLADConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2226 indices: List[int], confidence_level: float = 0.95):
2227 """Group-scale LAD confidence interval over a set of cells (recommended path).
2229 Returns (valid, mean_lad, lower, upper).
2231 if not _LIDAR_FUNCTIONS_AVAILABLE:
2232 raise NotImplementedError("LiDAR functions not available")
2234 raise ValueError("indices must contain at least one cell index")
2236 idx_array = (ctypes.c_uint * n)(*[int(i) for i in indices])
2237 out = (ctypes.c_float * 3)()
2238 valid = helios_lib.getLiDARGroupLADConfidenceInterval(
2239 cloud_ptr, idx_array, n, float(confidence_level), out)
2240 return bool(valid), float(out[0]), float(out[1]), float(out[2])
2243def exportLiDARTriangleNormals(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2244 """Export triangle normal vectors"""
2245 if not _LIDAR_FUNCTIONS_AVAILABLE:
2246 raise NotImplementedError("LiDAR functions not available")
2247 helios_lib.exportLiDARTriangleNormals(cloud_ptr, filename.encode('utf-8'))
2250def exportLiDARTriangleAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2251 """Export triangle areas"""
2252 if not _LIDAR_FUNCTIONS_AVAILABLE:
2253 raise NotImplementedError("LiDAR functions not available")
2254 helios_lib.exportLiDARTriangleAreas(cloud_ptr, filename.encode('utf-8'))
2257def exportLiDARLeafAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2258 """Export leaf areas for each grid cell"""
2259 if not _LIDAR_FUNCTIONS_AVAILABLE:
2260 raise NotImplementedError("LiDAR functions not available")
2261 helios_lib.exportLiDARLeafAreas(cloud_ptr, filename.encode('utf-8'))
2264def exportLiDARLeafAreaDensities(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2265 """Export leaf area densities for each grid cell"""
2266 if not _LIDAR_FUNCTIONS_AVAILABLE:
2267 raise NotImplementedError("LiDAR functions not available")
2268 helios_lib.exportLiDARLeafAreaDensities(cloud_ptr, filename.encode('utf-8'))
2271def exportLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2272 """Export G(theta) values for each grid cell"""
2273 if not _LIDAR_FUNCTIONS_AVAILABLE:
2274 raise NotImplementedError("LiDAR functions not available")
2275 helios_lib.exportLiDARGtheta(cloud_ptr, filename.encode('utf-8'))
2278def getLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2279 """Get G(theta) value for a grid cell"""
2280 if not _LIDAR_FUNCTIONS_AVAILABLE:
2281 raise NotImplementedError("LiDAR functions not available")
2282 return helios_lib.getLiDARCellGtheta(cloud_ptr, index)
2285def setLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), Gtheta: float, index: int) -> None:
2286 """Set G(theta) value for a grid cell"""
2287 if not _LIDAR_FUNCTIONS_AVAILABLE:
2288 raise NotImplementedError("LiDAR functions not available")
2289 helios_lib.setLiDARCellGtheta(cloud_ptr, Gtheta, index)
2292def gapfillLiDARMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2293 """Gapfill sky/miss points"""
2294 if not _LIDAR_FUNCTIONS_AVAILABLE:
2295 raise NotImplementedError("LiDAR functions not available")
2296 helios_lib.gapfillLiDARMisses(cloud_ptr)
2299def calculateSyntheticLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2300 context_ptr: ctypes.POINTER(UContext)) -> None:
2301 """Calculate synthetic leaf area for validation"""
2302 if not _LIDAR_FUNCTIONS_AVAILABLE:
2303 raise NotImplementedError("LiDAR functions not available")
2304 helios_lib.calculateSyntheticLiDARLeafArea(cloud_ptr, context_ptr)
2307def calculateSyntheticLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2308 context_ptr: ctypes.POINTER(UContext)) -> None:
2309 """Calculate synthetic G(theta) for validation"""
2310 if not _LIDAR_FUNCTIONS_AVAILABLE:
2311 raise NotImplementedError("LiDAR functions not available")
2312 helios_lib.calculateSyntheticLiDARGtheta(cloud_ptr, context_ptr)
2315def addLiDARTrianglesToContext(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2316 context_ptr: ctypes.POINTER(UContext)) -> None:
2317 """Add triangulated mesh to Context as primitives"""
2318 if not _LIDAR_FUNCTIONS_AVAILABLE:
2319 raise NotImplementedError("LiDAR functions not available")
2320 helios_lib.addLiDARTrianglesToContext(cloud_ptr, context_ptr)
2323def initializeLiDARCollisionDetection(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2324 context_ptr: ctypes.POINTER(UContext)) -> None:
2325 """Initialize CollisionDetection for ray tracing"""
2326 if not _LIDAR_FUNCTIONS_AVAILABLE:
2327 raise NotImplementedError("LiDAR functions not available")
2328 helios_lib.initializeLiDARCollisionDetection(cloud_ptr, context_ptr)
2331def enableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2332 """Enable GPU acceleration for collision detection"""
2333 if not _LIDAR_FUNCTIONS_AVAILABLE:
2334 raise NotImplementedError("LiDAR functions not available")
2335 helios_lib.enableLiDARCDGPUAcceleration(cloud_ptr)
2338def disableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2339 """Disable GPU acceleration for collision detection"""
2340 if not _LIDAR_FUNCTIONS_AVAILABLE:
2341 raise NotImplementedError("LiDAR functions not available")
2342 helios_lib.disableLiDARCDGPUAcceleration(cloud_ptr)
2345def isLiDARGPUAvailable(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
2346 """Return True if a CUDA-capable GPU is available for collision-detection acceleration."""
2347 if not _LIDAR_FUNCTIONS_AVAILABLE:
2348 raise NotImplementedError("LiDAR functions not available")
2349 return bool(helios_lib.isLiDARGPUAvailable(cloud_ptr))
2352def isLiDARGPUAccelerationEnabled(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
2353 """Return True if GPU acceleration is currently enabled for collision detection."""
2354 if not _LIDAR_FUNCTIONS_AVAILABLE:
2355 raise NotImplementedError("LiDAR functions not available")
2356 return bool(helios_lib.isLiDARGPUAccelerationEnabled(cloud_ptr))
2359# Mock mode for development
2360if not _LIDAR_FUNCTIONS_AVAILABLE:
2361 def mock_createLiDARcloud(*args, **kwargs):
2363 "Mock mode: LiDAR not available. "
2364 "This would create a LiDAR cloud instance with native library."
2367 def mock_lidar_operation(*args, **kwargs):
2369 "Mock mode: LiDAR operation not available. "
2370 "This would execute LiDAR operations with native library."
2373 # Replace functions with mocks for development
2374 createLiDARcloud = mock_createLiDARcloud
2375 addLiDARScan = mock_lidar_operation
2376 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).
List[float] getLiDARHitOrigin(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get the (x,y,z) beam-emission origin of a hit point.
_check_error(result, func, args)
Automatic error checking for all LiDAR functions.
List[List[float]] getLiDARScanRisleyPrisms(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the rotating wedge prisms of a Risley-prism scan.
int getLiDARScanMaxReturns(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the maximum returns per pulse used in single/limited-return mode.
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.
getLiDARHitScanID_all(ctypes.POINTER(ULiDARcloud) cloud_ptr, int n)
Bulk-export the scan ID of every hit as an (n,) int32 numpy array.
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).
bool isLiDARHitMiss(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Return True if the hit is a miss (a transmitted beam that returned nothing).
getLiDARHitDataColumn_np(ctypes.POINTER(ULiDARcloud) cloud_ptr, str label, int n, float absent_value=-9999.0)
Bulk-export a named scalar column as an (n,) float64 numpy array via the columnar path (absent_value ...
None setLiDARScanReturnMode(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, int return_mode)
Set the return-reporting mode (0 = multi, 1 = single).
None setLiDARScanSingleReturnSelection(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, int selection)
Set the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last,...
isLiDARHitMiss_all(ctypes.POINTER(ULiDARcloud) cloud_ptr, int n)
Bulk-export the miss flag of every hit as an (n,) int32 numpy array (1=miss).
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.
int getLiDARScanReturnMode(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the return-reporting mode (0 = multi, 1 = single).
List[float] getLiDARHitDataColumn(ctypes.POINTER(ULiDARcloud) cloud_ptr, str label, int n, float absent_value=-9999.0)
Bulk-export a named scalar column via the native cache-linear columnar path.
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).
float getLiDARScanRotationRate(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the sensor-head rotation rate in revolutions/second (spinning scans; 0 otherwise).
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.
float getLiDARScanPulseWidth(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument).
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 getLiDARScanAzimuthOffset(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the global scanner azimuth (heading) offset angle (radians) for a scan.
getLiDARHitData_all_np(ctypes.POINTER(ULiDARcloud) cloud_ptr, str label, int n)
Bulk-export a named scalar field for all hits as an (n,) float32 numpy array (NaN where the label is ...
float getLiDARScanAngleNoiseStdDev(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the angular (beam-pointing) jitter standard deviation for a scan (radians)
int getLiDARScanSingleReturnSelection(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last,...
float getLiDARScanRevolutions(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the number of revolutions the sensor head made (spinning scans; 0 otherwise).
int addLiDARScanMoving(ctypes.POINTER(ULiDARcloud) cloud_ptr, int Ntheta, Tuple[float, float] theta_range, int Nphi, Tuple[float, float] phi_range, float exit_diameter, float beam_divergence, List[float] traj_t, List[List[float]] traj_pos, List[List[float]] traj_rot, bool rot_is_quaternion, float pulse_rate_hz, Optional[List[float]] lever_arm=None, Optional[List[float]] boresight_rpy=None, Optional[List[str]] column_format=None, float range_noise_stddev=0.0, float angle_noise_stddev=0.0, float t0=0.0)
Add a moving-platform (mobile/airborne) raster LiDAR scan driven by a 6-DOF pose trajectory.
float getLiDARScanRisleyRefractiveIndexAir(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the refractive index of the medium surrounding the prisms of a Risley-prism scan (1....
int addLiDARScanMovingRaster(ctypes.POINTER(ULiDARcloud) cloud_ptr, int Ntheta, Tuple[float, float] theta_range, int Nphi, Tuple[float, float] phi_range, float pulse_rate_hz, List[float] traj_t, List[List[float]] traj_pos, List[List[float]] traj_quat, float exit_diameter=0.0, float beam_divergence=0.0, Optional[List[float]] lever_arm=None, Optional[List[float]] boresight_rpy=None, Optional[List[str]] column_format=None, float range_noise_stddev=0.0, float angle_noise_stddev=0.0, float t0=0.0)
Add a moving-platform raster scan: a fixed angular fan swept along a quaternion trajectory.
None setLiDARScanPulseWidth(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, float pulse_width)
Set the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument).
None setLiDARScanMaxReturns(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, int max_returns)
Set the maximum returns per pulse used in single/limited-return mode (must be >= 1).
int addLiDARScanSpinning(ctypes.POINTER(ULiDARcloud) cloud_ptr, List[float] beam_elevation_angles, float azimuth_step_rad, float pulse_rate_hz, List[float] traj_t, List[List[float]] traj_pos, List[List[float]] traj_rot, bool rot_is_quaternion, float exit_diameter=0.0, float beam_divergence=0.0, Optional[List[float]] lever_arm=None, Optional[List[float]] boresight_rpy=None, Optional[List[str]] column_format=None, float range_noise_stddev=0.0, float angle_noise_stddev=0.0, float t0=0.0)
Add a continuously-spinning multibeam scan from physical instrument parameters.
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.
int getLiDARScanStepsPerRev(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the number of azimuth firing steps per revolution (spinning scans; 0 otherwise).
int getLiDARScanMode(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the acquisition mode (0 = static raster, 1 = moving raster, 2 = spinning, 3 = Risley prism).
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.
getLiDARHitsXYZRGB_all_np(ctypes.POINTER(ULiDARcloud) cloud_ptr, int n)
Bulk-export XYZ + RGB for all hits as numpy arrays (no per-element Python).
None setLiDARScanDetectionThreshold(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, float detection_threshold)
Set the detection threshold (energy fraction, noise floor) of a scan.
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 addLiDARScanRisley(ctypes.POINTER(ULiDARcloud) cloud_ptr, List[List[float]] prisms, float refractive_index_air, float pulse_rate_hz, List[float] traj_t, List[List[float]] traj_pos, List[List[float]] traj_rot, bool rot_is_quaternion, float exit_diameter=0.0, float beam_divergence=0.0, Optional[List[float]] lever_arm=None, Optional[List[float]] boresight_rpy=None, Optional[List[str]] column_format=None, float range_noise_stddev=0.0, float angle_noise_stddev=0.0, float t0=0.0)
Add a rotating-Risley-prism (Livox-style rosette) scan from physical instrument parameters.
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.
int getLiDARHitDataColumnIndex(ctypes.POINTER(ULiDARcloud) cloud_ptr, str label)
Get the internal column slot index for a hit-data label (-1 if never set on any hit).
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.
float getLiDARScanDetectionThreshold(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get the detection threshold (energy fraction, noise floor) of a scan.