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)
34LiDARTriangulationSinkCallback = ctypes.CFUNCTYPE(
35 None, ctypes.c_uint, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_int),
36 ctypes.c_uint, ctypes.c_void_p)
40LiDARSyntheticScanHitSinkCallback = ctypes.CFUNCTYPE(
41 None, ctypes.c_size_t, ctypes.c_size_t, ctypes.c_void_p)
47 helios_lib.createLiDARcloud.argtypes = []
48 helios_lib.createLiDARcloud.restype = ctypes.POINTER(ULiDARcloud)
49 helios_lib.createLiDARcloud.errcheck = _check_error
51 helios_lib.destroyLiDARcloud.argtypes = [ctypes.POINTER(ULiDARcloud)]
52 helios_lib.destroyLiDARcloud.restype =
None
55 helios_lib.addLiDARScan.argtypes = [
56 ctypes.POINTER(ULiDARcloud),
57 ctypes.POINTER(ctypes.c_float),
68 ctypes.POINTER(ctypes.c_char_p),
74 helios_lib.addLiDARScan.restype = ctypes.c_uint
75 helios_lib.addLiDARScan.errcheck = _check_error
77 helios_lib.addLiDARScanMoving.argtypes = [
78 ctypes.POINTER(ULiDARcloud),
89 ctypes.POINTER(ctypes.c_char_p),
91 ctypes.POINTER(ctypes.c_double),
92 ctypes.POINTER(ctypes.c_float),
93 ctypes.POINTER(ctypes.c_float),
96 ctypes.POINTER(ctypes.c_float),
97 ctypes.POINTER(ctypes.c_float),
101 helios_lib.addLiDARScanMoving.restype = ctypes.c_uint
102 helios_lib.addLiDARScanMoving.errcheck = _check_error
104 helios_lib.addLiDARScanSpinning.argtypes = [
105 ctypes.POINTER(ULiDARcloud),
106 ctypes.POINTER(ctypes.c_float),
114 ctypes.POINTER(ctypes.c_char_p),
116 ctypes.POINTER(ctypes.c_double),
117 ctypes.POINTER(ctypes.c_float),
118 ctypes.POINTER(ctypes.c_float),
121 ctypes.POINTER(ctypes.c_float),
122 ctypes.POINTER(ctypes.c_float),
125 helios_lib.addLiDARScanSpinning.restype = ctypes.c_uint
126 helios_lib.addLiDARScanSpinning.errcheck = _check_error
128 helios_lib.addLiDARScanMovingRaster.argtypes = [
129 ctypes.POINTER(ULiDARcloud),
141 ctypes.POINTER(ctypes.c_char_p),
143 ctypes.POINTER(ctypes.c_double),
144 ctypes.POINTER(ctypes.c_float),
145 ctypes.POINTER(ctypes.c_float),
147 ctypes.POINTER(ctypes.c_float),
148 ctypes.POINTER(ctypes.c_float),
151 helios_lib.addLiDARScanMovingRaster.restype = ctypes.c_uint
152 helios_lib.addLiDARScanMovingRaster.errcheck = _check_error
154 helios_lib.addLiDARScanRisley.argtypes = [
155 ctypes.POINTER(ULiDARcloud),
156 ctypes.POINTER(ctypes.c_double),
164 ctypes.POINTER(ctypes.c_char_p),
166 ctypes.POINTER(ctypes.c_double),
167 ctypes.POINTER(ctypes.c_float),
168 ctypes.POINTER(ctypes.c_float),
171 ctypes.POINTER(ctypes.c_float),
172 ctypes.POINTER(ctypes.c_float),
175 helios_lib.addLiDARScanRisley.restype = ctypes.c_uint
176 helios_lib.addLiDARScanRisley.errcheck = _check_error
179 helios_lib.getLiDARScanMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
180 helios_lib.getLiDARScanMode.restype = ctypes.c_int
181 helios_lib.getLiDARScanMode.errcheck = _check_error
183 helios_lib.getLiDARScanStepsPerRev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
184 helios_lib.getLiDARScanStepsPerRev.restype = ctypes.c_uint
185 helios_lib.getLiDARScanStepsPerRev.errcheck = _check_error
187 helios_lib.getLiDARScanRotationRate.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
188 helios_lib.getLiDARScanRotationRate.restype = ctypes.c_double
189 helios_lib.getLiDARScanRotationRate.errcheck = _check_error
191 helios_lib.getLiDARScanRevolutions.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
192 helios_lib.getLiDARScanRevolutions.restype = ctypes.c_double
193 helios_lib.getLiDARScanRevolutions.errcheck = _check_error
195 helios_lib.getLiDARScanRisleyPrismCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
196 helios_lib.getLiDARScanRisleyPrismCount.restype = ctypes.c_uint
197 helios_lib.getLiDARScanRisleyPrismCount.errcheck = _check_error
199 helios_lib.getLiDARScanRisleyPrisms.argtypes = [
200 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
201 ctypes.POINTER(ctypes.c_double),
204 helios_lib.getLiDARScanRisleyPrisms.restype =
None
205 helios_lib.getLiDARScanRisleyPrisms.errcheck = _check_error
207 helios_lib.getLiDARScanRisleyRefractiveIndexAir.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
208 helios_lib.getLiDARScanRisleyRefractiveIndexAir.restype = ctypes.c_double
209 helios_lib.getLiDARScanRisleyRefractiveIndexAir.errcheck = _check_error
212 helios_lib.getLiDARScanReturnMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
213 helios_lib.getLiDARScanReturnMode.restype = ctypes.c_int
214 helios_lib.getLiDARScanReturnMode.errcheck = _check_error
216 helios_lib.setLiDARScanReturnMode.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
217 helios_lib.setLiDARScanReturnMode.restype =
None
218 helios_lib.setLiDARScanReturnMode.errcheck = _check_error
220 helios_lib.getLiDARScanSingleReturnSelection.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
221 helios_lib.getLiDARScanSingleReturnSelection.restype = ctypes.c_int
222 helios_lib.getLiDARScanSingleReturnSelection.errcheck = _check_error
224 helios_lib.setLiDARScanSingleReturnSelection.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
225 helios_lib.setLiDARScanSingleReturnSelection.restype =
None
226 helios_lib.setLiDARScanSingleReturnSelection.errcheck = _check_error
228 helios_lib.getLiDARScanMaxReturns.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
229 helios_lib.getLiDARScanMaxReturns.restype = ctypes.c_int
230 helios_lib.getLiDARScanMaxReturns.errcheck = _check_error
232 helios_lib.setLiDARScanMaxReturns.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int]
233 helios_lib.setLiDARScanMaxReturns.restype =
None
234 helios_lib.setLiDARScanMaxReturns.errcheck = _check_error
236 helios_lib.getLiDARScanPulseWidth.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
237 helios_lib.getLiDARScanPulseWidth.restype = ctypes.c_float
238 helios_lib.getLiDARScanPulseWidth.errcheck = _check_error
240 helios_lib.setLiDARScanPulseWidth.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float]
241 helios_lib.setLiDARScanPulseWidth.restype =
None
242 helios_lib.setLiDARScanPulseWidth.errcheck = _check_error
244 helios_lib.getLiDARScanDetectionThreshold.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
245 helios_lib.getLiDARScanDetectionThreshold.restype = ctypes.c_float
246 helios_lib.getLiDARScanDetectionThreshold.errcheck = _check_error
248 helios_lib.setLiDARScanDetectionThreshold.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float]
249 helios_lib.setLiDARScanDetectionThreshold.restype =
None
250 helios_lib.setLiDARScanDetectionThreshold.errcheck = _check_error
252 helios_lib.getLiDARScanCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
253 helios_lib.getLiDARScanCount.restype = ctypes.c_uint
254 helios_lib.getLiDARScanCount.errcheck = _check_error
256 helios_lib.getLiDARScanOrigin.argtypes = [
257 ctypes.POINTER(ULiDARcloud),
259 ctypes.POINTER(ctypes.c_float)
261 helios_lib.getLiDARScanOrigin.restype =
None
262 helios_lib.getLiDARScanOrigin.errcheck = _check_error
264 helios_lib.getLiDARScanSizeTheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
265 helios_lib.getLiDARScanSizeTheta.restype = ctypes.c_uint
266 helios_lib.getLiDARScanSizeTheta.errcheck = _check_error
268 helios_lib.getLiDARScanSizePhi.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
269 helios_lib.getLiDARScanSizePhi.restype = ctypes.c_uint
270 helios_lib.getLiDARScanSizePhi.errcheck = _check_error
272 helios_lib.getLiDARScanRangeNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
273 helios_lib.getLiDARScanRangeNoiseStdDev.restype = ctypes.c_float
274 helios_lib.getLiDARScanRangeNoiseStdDev.errcheck = _check_error
276 helios_lib.getLiDARScanAngleNoiseStdDev.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
277 helios_lib.getLiDARScanAngleNoiseStdDev.restype = ctypes.c_float
278 helios_lib.getLiDARScanAngleNoiseStdDev.errcheck = _check_error
280 helios_lib.getLiDARScanTiltRoll.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
281 helios_lib.getLiDARScanTiltRoll.restype = ctypes.c_float
282 helios_lib.getLiDARScanTiltRoll.errcheck = _check_error
284 helios_lib.getLiDARScanTiltPitch.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
285 helios_lib.getLiDARScanTiltPitch.restype = ctypes.c_float
286 helios_lib.getLiDARScanTiltPitch.errcheck = _check_error
288 helios_lib.getLiDARScanAzimuthOffset.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
289 helios_lib.getLiDARScanAzimuthOffset.restype = ctypes.c_float
290 helios_lib.getLiDARScanAzimuthOffset.errcheck = _check_error
292 helios_lib.getLiDARScanPattern.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
293 helios_lib.getLiDARScanPattern.restype = ctypes.c_int
294 helios_lib.getLiDARScanPattern.errcheck = _check_error
296 helios_lib.getLiDARScanBeamZenithAngleCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
297 helios_lib.getLiDARScanBeamZenithAngleCount.restype = ctypes.c_uint
298 helios_lib.getLiDARScanBeamZenithAngleCount.errcheck = _check_error
300 helios_lib.getLiDARScanBeamZenithAngles.argtypes = [
301 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
302 ctypes.POINTER(ctypes.c_float), ctypes.c_uint,
304 helios_lib.getLiDARScanBeamZenithAngles.restype =
None
305 helios_lib.getLiDARScanBeamZenithAngles.errcheck = _check_error
308 helios_lib.isLiDARHitMiss.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
309 helios_lib.isLiDARHitMiss.restype = ctypes.c_int
310 helios_lib.isLiDARHitMiss.errcheck = _check_error
312 helios_lib.lidarHasMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
313 helios_lib.lidarHasMisses.restype = ctypes.c_int
314 helios_lib.lidarHasMisses.errcheck = _check_error
316 helios_lib.getLiDARMissDistance.argtypes = []
317 helios_lib.getLiDARMissDistance.restype = ctypes.c_float
321 helios_lib.addLiDARHitPoint.argtypes = [
322 ctypes.POINTER(ULiDARcloud),
324 ctypes.POINTER(ctypes.c_float),
325 ctypes.POINTER(ctypes.c_float)
327 helios_lib.addLiDARHitPoint.restype =
None
328 helios_lib.addLiDARHitPoint.errcheck = _check_error
330 helios_lib.addLiDARHitPointRGB.argtypes = [
331 ctypes.POINTER(ULiDARcloud),
333 ctypes.POINTER(ctypes.c_float),
334 ctypes.POINTER(ctypes.c_float),
335 ctypes.POINTER(ctypes.c_float)
337 helios_lib.addLiDARHitPointRGB.restype =
None
338 helios_lib.addLiDARHitPointRGB.errcheck = _check_error
340 helios_lib.addLiDARHitPoints.argtypes = [
341 ctypes.POINTER(ULiDARcloud),
343 ctypes.POINTER(ctypes.c_float),
344 ctypes.POINTER(ctypes.c_float),
346 ctypes.POINTER(ctypes.c_float)
348 helios_lib.addLiDARHitPoints.restype =
None
349 helios_lib.addLiDARHitPoints.errcheck = _check_error
351 helios_lib.addLiDARHitPointsWithData.argtypes = [
352 ctypes.POINTER(ULiDARcloud),
354 ctypes.POINTER(ctypes.c_float),
355 ctypes.POINTER(ctypes.c_float),
357 ctypes.POINTER(ctypes.c_float),
358 ctypes.POINTER(ctypes.c_char_p),
360 ctypes.POINTER(ctypes.c_double)
362 helios_lib.addLiDARHitPointsWithData.restype =
None
363 helios_lib.addLiDARHitPointsWithData.errcheck = _check_error
365 helios_lib.getLiDARHitCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
366 helios_lib.getLiDARHitCount.restype = ctypes.c_uint
367 helios_lib.getLiDARHitCount.errcheck = _check_error
369 helios_lib.getLiDARHitXYZ.argtypes = [
370 ctypes.POINTER(ULiDARcloud),
372 ctypes.POINTER(ctypes.c_float)
374 helios_lib.getLiDARHitXYZ.restype =
None
375 helios_lib.getLiDARHitXYZ.errcheck = _check_error
377 helios_lib.getLiDARHitOrigin.argtypes = [
378 ctypes.POINTER(ULiDARcloud),
380 ctypes.POINTER(ctypes.c_float)
382 helios_lib.getLiDARHitOrigin.restype =
None
383 helios_lib.getLiDARHitOrigin.errcheck = _check_error
385 helios_lib.getLiDARHitRaydir.argtypes = [
386 ctypes.POINTER(ULiDARcloud),
388 ctypes.POINTER(ctypes.c_float)
390 helios_lib.getLiDARHitRaydir.restype =
None
391 helios_lib.getLiDARHitRaydir.errcheck = _check_error
393 helios_lib.getLiDARHitColor.argtypes = [
394 ctypes.POINTER(ULiDARcloud),
396 ctypes.POINTER(ctypes.c_float)
398 helios_lib.getLiDARHitColor.restype =
None
399 helios_lib.getLiDARHitColor.errcheck = _check_error
401 helios_lib.getLiDARHitScanID.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
402 helios_lib.getLiDARHitScanID.restype = ctypes.c_int
403 helios_lib.getLiDARHitScanID.errcheck = _check_error
405 helios_lib.doesLiDARHitDataExist.argtypes = [
406 ctypes.POINTER(ULiDARcloud),
410 helios_lib.doesLiDARHitDataExist.restype = ctypes.c_int
411 helios_lib.doesLiDARHitDataExist.errcheck = _check_error
413 helios_lib.getLiDARHitData.argtypes = [
414 ctypes.POINTER(ULiDARcloud),
418 helios_lib.getLiDARHitData.restype = ctypes.c_double
419 helios_lib.getLiDARHitData.errcheck = _check_error
421 helios_lib.getLiDARHitData_all.argtypes = [
422 ctypes.POINTER(ULiDARcloud),
424 ctypes.POINTER(ctypes.c_float),
427 helios_lib.getLiDARHitData_all.restype =
None
428 helios_lib.getLiDARHitData_all.errcheck = _check_error
430 helios_lib.getLiDARHitDataColumn.argtypes = [
431 ctypes.POINTER(ULiDARcloud),
433 ctypes.POINTER(ctypes.c_double),
437 helios_lib.getLiDARHitDataColumn.restype =
None
438 helios_lib.getLiDARHitDataColumn.errcheck = _check_error
440 helios_lib.getLiDARHitDataColumnIndex.argtypes = [
441 ctypes.POINTER(ULiDARcloud),
444 helios_lib.getLiDARHitDataColumnIndex.restype = ctypes.c_int
445 helios_lib.getLiDARHitDataColumnIndex.errcheck = _check_error
447 helios_lib.getLiDARHitsXYZRGB_all.argtypes = [
448 ctypes.POINTER(ULiDARcloud),
449 ctypes.POINTER(ctypes.c_float),
450 ctypes.POINTER(ctypes.c_float),
453 helios_lib.getLiDARHitsXYZRGB_all.restype =
None
454 helios_lib.getLiDARHitsXYZRGB_all.errcheck = _check_error
456 helios_lib.getLiDARHitScanID_all.argtypes = [
457 ctypes.POINTER(ULiDARcloud),
458 ctypes.POINTER(ctypes.c_int),
461 helios_lib.getLiDARHitScanID_all.restype =
None
462 helios_lib.getLiDARHitScanID_all.errcheck = _check_error
464 helios_lib.isLiDARHitMiss_all.argtypes = [
465 ctypes.POINTER(ULiDARcloud),
466 ctypes.POINTER(ctypes.c_int),
469 helios_lib.isLiDARHitMiss_all.restype =
None
470 helios_lib.isLiDARHitMiss_all.errcheck = _check_error
472 helios_lib.deleteLiDARHitPoint.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
473 helios_lib.deleteLiDARHitPoint.restype =
None
474 helios_lib.deleteLiDARHitPoint.errcheck = _check_error
477 helios_lib.lidarCoordinateShift.argtypes = [
478 ctypes.POINTER(ULiDARcloud),
479 ctypes.POINTER(ctypes.c_float)
481 helios_lib.lidarCoordinateShift.restype =
None
482 helios_lib.lidarCoordinateShift.errcheck = _check_error
484 helios_lib.lidarCoordinateRotation.argtypes = [
485 ctypes.POINTER(ULiDARcloud),
486 ctypes.POINTER(ctypes.c_float)
488 helios_lib.lidarCoordinateRotation.restype =
None
489 helios_lib.lidarCoordinateRotation.errcheck = _check_error
492 helios_lib.lidarTriangulateHitPoints.argtypes = [
493 ctypes.POINTER(ULiDARcloud),
497 helios_lib.lidarTriangulateHitPoints.restype =
None
498 helios_lib.lidarTriangulateHitPoints.errcheck = _check_error
500 helios_lib.getLiDARTriangleCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
501 helios_lib.getLiDARTriangleCount.restype = ctypes.c_uint
502 helios_lib.getLiDARTriangleCount.errcheck = _check_error
504 helios_lib.getLiDARTriangulationStats.argtypes = [
505 ctypes.POINTER(ULiDARcloud),
506 ctypes.POINTER(ctypes.c_uint),
508 helios_lib.getLiDARTriangulationStats.restype =
None
509 helios_lib.getLiDARTriangulationStats.errcheck = _check_error
511 helios_lib.getLiDARTriangleVertices_all.argtypes = [
512 ctypes.POINTER(ULiDARcloud),
513 ctypes.POINTER(ctypes.c_float),
514 ctypes.POINTER(ctypes.c_int),
517 helios_lib.getLiDARTriangleVertices_all.restype =
None
518 helios_lib.getLiDARTriangleVertices_all.errcheck = _check_error
520 helios_lib.lidarSetExternalTriangulation.argtypes = [
521 ctypes.POINTER(ULiDARcloud),
522 ctypes.POINTER(ctypes.c_float),
523 ctypes.POINTER(ctypes.c_int),
526 helios_lib.lidarSetExternalTriangulation.restype =
None
527 helios_lib.lidarSetExternalTriangulation.errcheck = _check_error
530 helios_lib.lidarDistanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
531 helios_lib.lidarDistanceFilter.restype =
None
532 helios_lib.lidarDistanceFilter.errcheck = _check_error
534 helios_lib.lidarReflectanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
535 helios_lib.lidarReflectanceFilter.restype =
None
536 helios_lib.lidarReflectanceFilter.errcheck = _check_error
538 helios_lib.lidarFirstHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
539 helios_lib.lidarFirstHitFilter.restype =
None
540 helios_lib.lidarFirstHitFilter.errcheck = _check_error
542 helios_lib.lidarLastHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
543 helios_lib.lidarLastHitFilter.restype =
None
544 helios_lib.lidarLastHitFilter.errcheck = _check_error
547 helios_lib.exportLiDARPointCloud.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p, ctypes.c_bool]
548 helios_lib.exportLiDARPointCloud.restype =
None
549 helios_lib.exportLiDARPointCloud.errcheck = _check_error
551 helios_lib.exportLiDARLeafAreaUncertainty.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
552 helios_lib.exportLiDARLeafAreaUncertainty.restype =
None
553 helios_lib.exportLiDARLeafAreaUncertainty.errcheck = _check_error
555 helios_lib.exportLiDARScans.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
556 helios_lib.exportLiDARScans.restype =
None
557 helios_lib.exportLiDARScans.errcheck = _check_error
559 helios_lib.loadLiDARXML.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
560 helios_lib.loadLiDARXML.restype =
None
561 helios_lib.loadLiDARXML.errcheck = _check_error
564 helios_lib.lidarDisableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
565 helios_lib.lidarDisableMessages.restype =
None
566 helios_lib.lidarDisableMessages.errcheck = _check_error
568 helios_lib.lidarEnableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
569 helios_lib.lidarEnableMessages.restype =
None
570 helios_lib.lidarEnableMessages.errcheck = _check_error
573 helios_lib.addLiDARGrid.argtypes = [
574 ctypes.POINTER(ULiDARcloud),
575 ctypes.POINTER(ctypes.c_float),
576 ctypes.POINTER(ctypes.c_float),
577 ctypes.POINTER(ctypes.c_int),
580 helios_lib.addLiDARGrid.restype =
None
581 helios_lib.addLiDARGrid.errcheck = _check_error
583 helios_lib.addLiDARGridTerrainFollowing.argtypes = [
584 ctypes.POINTER(ULiDARcloud),
585 ctypes.POINTER(ctypes.c_float),
586 ctypes.POINTER(ctypes.c_float),
587 ctypes.POINTER(ctypes.c_int),
589 ctypes.POINTER(ctypes.c_float),
592 helios_lib.addLiDARGridTerrainFollowing.restype =
None
593 helios_lib.addLiDARGridTerrainFollowing.errcheck = _check_error
595 helios_lib.addLiDARGridCell.argtypes = [
596 ctypes.POINTER(ULiDARcloud),
597 ctypes.POINTER(ctypes.c_float),
598 ctypes.POINTER(ctypes.c_float),
601 helios_lib.addLiDARGridCell.restype =
None
602 helios_lib.addLiDARGridCell.errcheck = _check_error
604 helios_lib.getLiDARGridCellCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
605 helios_lib.getLiDARGridCellCount.restype = ctypes.c_uint
606 helios_lib.getLiDARGridCellCount.errcheck = _check_error
608 helios_lib.getLiDARCellCenter.argtypes = [
609 ctypes.POINTER(ULiDARcloud),
611 ctypes.POINTER(ctypes.c_float)
613 helios_lib.getLiDARCellCenter.restype =
None
614 helios_lib.getLiDARCellCenter.errcheck = _check_error
616 helios_lib.getLiDARCellCenterUnrotated.argtypes = [
617 ctypes.POINTER(ULiDARcloud),
619 ctypes.POINTER(ctypes.c_float)
621 helios_lib.getLiDARCellCenterUnrotated.restype =
None
622 helios_lib.getLiDARCellCenterUnrotated.errcheck = _check_error
624 helios_lib.getLiDARCellSize.argtypes = [
625 ctypes.POINTER(ULiDARcloud),
627 ctypes.POINTER(ctypes.c_float)
629 helios_lib.getLiDARCellSize.restype =
None
630 helios_lib.getLiDARCellSize.errcheck = _check_error
632 helios_lib.getLiDARCellRotation.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
633 helios_lib.getLiDARCellRotation.restype = ctypes.c_float
634 helios_lib.getLiDARCellRotation.errcheck = _check_error
636 helios_lib.getLiDARCellLeafArea.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
637 helios_lib.getLiDARCellLeafArea.restype = ctypes.c_float
638 helios_lib.getLiDARCellLeafArea.errcheck = _check_error
640 helios_lib.getLiDARCellLeafAreaDensity.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
641 helios_lib.getLiDARCellLeafAreaDensity.restype = ctypes.c_float
642 helios_lib.getLiDARCellLeafAreaDensity.errcheck = _check_error
645 helios_lib.getLiDARCellBeamCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
646 helios_lib.getLiDARCellBeamCount.restype = ctypes.c_int
647 helios_lib.getLiDARCellBeamCount.errcheck = _check_error
649 helios_lib.getLiDARCellRelativeDensityIndex.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
650 helios_lib.getLiDARCellRelativeDensityIndex.restype = ctypes.c_float
651 helios_lib.getLiDARCellRelativeDensityIndex.errcheck = _check_error
653 helios_lib.getLiDARCellMeanPathLength.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
654 helios_lib.getLiDARCellMeanPathLength.restype = ctypes.c_float
655 helios_lib.getLiDARCellMeanPathLength.errcheck = _check_error
657 helios_lib.getLiDARCellLADVariance.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
658 helios_lib.getLiDARCellLADVariance.restype = ctypes.c_float
659 helios_lib.getLiDARCellLADVariance.errcheck = _check_error
661 helios_lib.getLiDARCellLeafAreaConfidenceInterval.argtypes = [
662 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_float,
663 ctypes.POINTER(ctypes.c_float),
665 helios_lib.getLiDARCellLeafAreaConfidenceInterval.restype = ctypes.c_int
666 helios_lib.getLiDARCellLeafAreaConfidenceInterval.errcheck = _check_error
668 helios_lib.getLiDARGroupLADConfidenceInterval.argtypes = [
669 ctypes.POINTER(ULiDARcloud),
670 ctypes.POINTER(ctypes.c_uint),
671 ctypes.c_uint, ctypes.c_float,
672 ctypes.POINTER(ctypes.c_float),
674 helios_lib.getLiDARGroupLADConfidenceInterval.restype = ctypes.c_int
675 helios_lib.getLiDARGroupLADConfidenceInterval.errcheck = _check_error
677 helios_lib.calculateLiDARHitGridCell.argtypes = [ctypes.POINTER(ULiDARcloud)]
678 helios_lib.calculateLiDARHitGridCell.restype =
None
679 helios_lib.calculateLiDARHitGridCell.errcheck = _check_error
682 helios_lib.syntheticLiDARScan.argtypes = [
683 ctypes.POINTER(ULiDARcloud),
684 ctypes.POINTER(UContext)
686 helios_lib.syntheticLiDARScan.restype =
None
687 helios_lib.syntheticLiDARScan.errcheck = _check_error
689 helios_lib.syntheticLiDARScanAppend.argtypes = [
690 ctypes.POINTER(ULiDARcloud),
691 ctypes.POINTER(UContext),
694 helios_lib.syntheticLiDARScanAppend.restype =
None
695 helios_lib.syntheticLiDARScanAppend.errcheck = _check_error
697 helios_lib.setLiDARCancelFlag.argtypes = [
698 ctypes.POINTER(ULiDARcloud),
699 ctypes.POINTER(ctypes.c_int),
701 helios_lib.setLiDARCancelFlag.restype =
None
702 helios_lib.setLiDARCancelFlag.errcheck = _check_error
704 helios_lib.setLiDARSyntheticScanMemoryBudget.argtypes = [
705 ctypes.POINTER(ULiDARcloud),
708 helios_lib.setLiDARSyntheticScanMemoryBudget.restype =
None
709 helios_lib.setLiDARSyntheticScanMemoryBudget.errcheck = _check_error
711 helios_lib.getLiDARSyntheticScanMemoryBudget.argtypes = [ctypes.POINTER(ULiDARcloud)]
712 helios_lib.getLiDARSyntheticScanMemoryBudget.restype = ctypes.c_size_t
713 helios_lib.getLiDARSyntheticScanMemoryBudget.errcheck = _check_error
715 helios_lib.setLiDARSyntheticScanProgressPointer.argtypes = [
716 ctypes.POINTER(ULiDARcloud),
717 ctypes.POINTER(ctypes.c_int),
719 helios_lib.setLiDARSyntheticScanProgressPointer.restype =
None
720 helios_lib.setLiDARSyntheticScanProgressPointer.errcheck = _check_error
722 helios_lib.setLiDARProgressCallback.argtypes = [
723 ctypes.POINTER(ULiDARcloud),
724 LiDARProgressCallback,
726 helios_lib.setLiDARProgressCallback.restype =
None
727 helios_lib.setLiDARProgressCallback.errcheck = _check_error
729 helios_lib.syntheticLiDARScanDiscrete.argtypes = [
730 ctypes.POINTER(ULiDARcloud),
731 ctypes.POINTER(UContext),
736 helios_lib.syntheticLiDARScanDiscrete.restype =
None
737 helios_lib.syntheticLiDARScanDiscrete.errcheck = _check_error
739 helios_lib.syntheticLiDARScanWaveform.argtypes = [
740 ctypes.POINTER(ULiDARcloud),
741 ctypes.POINTER(UContext),
745 helios_lib.syntheticLiDARScanWaveform.restype =
None
746 helios_lib.syntheticLiDARScanWaveform.errcheck = _check_error
748 helios_lib.syntheticLiDARScanFull.argtypes = [
749 ctypes.POINTER(ULiDARcloud),
750 ctypes.POINTER(UContext),
757 helios_lib.syntheticLiDARScanFull.restype =
None
758 helios_lib.syntheticLiDARScanFull.errcheck = _check_error
760 helios_lib.syntheticLiDARScanReturnMode.argtypes = [
761 ctypes.POINTER(ULiDARcloud),
762 ctypes.POINTER(UContext),
770 helios_lib.syntheticLiDARScanReturnMode.restype =
None
771 helios_lib.syntheticLiDARScanReturnMode.errcheck = _check_error
774 helios_lib.calculateLiDARLeafArea.argtypes = [
775 ctypes.POINTER(ULiDARcloud),
776 ctypes.POINTER(UContext)
778 helios_lib.calculateLiDARLeafArea.restype =
None
779 helios_lib.calculateLiDARLeafArea.errcheck = _check_error
781 helios_lib.calculateLiDARLeafAreaMinHits.argtypes = [
782 ctypes.POINTER(ULiDARcloud),
783 ctypes.POINTER(UContext),
786 helios_lib.calculateLiDARLeafAreaMinHits.restype =
None
787 helios_lib.calculateLiDARLeafAreaMinHits.errcheck = _check_error
789 helios_lib.calculateLiDARLeafAreaUncertainty.argtypes = [
790 ctypes.POINTER(ULiDARcloud),
791 ctypes.POINTER(UContext),
795 helios_lib.calculateLiDARLeafAreaUncertainty.restype =
None
796 helios_lib.calculateLiDARLeafAreaUncertainty.errcheck = _check_error
798 helios_lib.calculateLiDARLeafAreaGtheta.argtypes = [
799 ctypes.POINTER(ULiDARcloud),
800 ctypes.POINTER(UContext),
805 helios_lib.calculateLiDARLeafAreaGtheta.restype =
None
806 helios_lib.calculateLiDARLeafAreaGtheta.errcheck = _check_error
808 helios_lib.calculateSyntheticLiDARLeafArea.argtypes = [
809 ctypes.POINTER(ULiDARcloud),
810 ctypes.POINTER(UContext)
812 helios_lib.calculateSyntheticLiDARLeafArea.restype =
None
813 helios_lib.calculateSyntheticLiDARLeafArea.errcheck = _check_error
815 helios_lib.calculateSyntheticLiDARGtheta.argtypes = [
816 ctypes.POINTER(ULiDARcloud),
817 ctypes.POINTER(UContext)
819 helios_lib.calculateSyntheticLiDARGtheta.restype =
None
820 helios_lib.calculateSyntheticLiDARGtheta.errcheck = _check_error
822 helios_lib.getLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
823 helios_lib.getLiDARCellGtheta.restype = ctypes.c_float
824 helios_lib.getLiDARCellGtheta.errcheck = _check_error
826 helios_lib.setLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float, ctypes.c_uint]
827 helios_lib.setLiDARCellGtheta.restype =
None
828 helios_lib.setLiDARCellGtheta.errcheck = _check_error
830 helios_lib.gapfillLiDARMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
831 helios_lib.gapfillLiDARMisses.restype =
None
832 helios_lib.gapfillLiDARMisses.errcheck = _check_error
834 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
835 helios_lib.exportLiDARGtheta.restype =
None
836 helios_lib.exportLiDARGtheta.errcheck = _check_error
839 helios_lib.exportLiDARTriangleNormals.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
840 helios_lib.exportLiDARTriangleNormals.restype =
None
841 helios_lib.exportLiDARTriangleNormals.errcheck = _check_error
843 helios_lib.exportLiDARTriangleAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
844 helios_lib.exportLiDARTriangleAreas.restype =
None
845 helios_lib.exportLiDARTriangleAreas.errcheck = _check_error
847 helios_lib.exportLiDARLeafAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
848 helios_lib.exportLiDARLeafAreas.restype =
None
849 helios_lib.exportLiDARLeafAreas.errcheck = _check_error
851 helios_lib.exportLiDARLeafAreaDensities.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
852 helios_lib.exportLiDARLeafAreaDensities.restype =
None
853 helios_lib.exportLiDARLeafAreaDensities.errcheck = _check_error
856 helios_lib.addLiDARTrianglesToContext.argtypes = [
857 ctypes.POINTER(ULiDARcloud),
858 ctypes.POINTER(UContext)
860 helios_lib.addLiDARTrianglesToContext.restype =
None
861 helios_lib.addLiDARTrianglesToContext.errcheck = _check_error
863 helios_lib.initializeLiDARCollisionDetection.argtypes = [
864 ctypes.POINTER(ULiDARcloud),
865 ctypes.POINTER(UContext)
867 helios_lib.initializeLiDARCollisionDetection.restype =
None
868 helios_lib.initializeLiDARCollisionDetection.errcheck = _check_error
870 helios_lib.enableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
871 helios_lib.enableLiDARCDGPUAcceleration.restype =
None
872 helios_lib.enableLiDARCDGPUAcceleration.errcheck = _check_error
874 helios_lib.disableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
875 helios_lib.disableLiDARCDGPUAcceleration.restype =
None
876 helios_lib.disableLiDARCDGPUAcceleration.errcheck = _check_error
878 helios_lib.isLiDARGPUAvailable.argtypes = [ctypes.POINTER(ULiDARcloud)]
879 helios_lib.isLiDARGPUAvailable.restype = ctypes.c_int
880 helios_lib.isLiDARGPUAvailable.errcheck = _check_error
882 helios_lib.isLiDARGPUAccelerationEnabled.argtypes = [ctypes.POINTER(ULiDARcloud)]
883 helios_lib.isLiDARGPUAccelerationEnabled.restype = ctypes.c_int
884 helios_lib.isLiDARGPUAccelerationEnabled.errcheck = _check_error
886 _LIDAR_FUNCTIONS_AVAILABLE =
True
888except AttributeError:
889 _LIDAR_FUNCTIONS_AVAILABLE =
False
895_LIDAR_1384_AVAILABLE =
False
897 for _fn
in (
"gapfillLiDARMissesCount",
"getLiDARVirtualMissCount",
"getLiDARMaxHitPoints"):
898 getattr(helios_lib, _fn).argtypes = [ctypes.POINTER(ULiDARcloud)]
899 getattr(helios_lib, _fn).restype = ctypes.c_ulonglong
900 getattr(helios_lib, _fn).errcheck = _check_error
902 helios_lib.estimateLiDARHitPointMemory.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_ulonglong]
903 helios_lib.estimateLiDARHitPointMemory.restype = ctypes.c_ulonglong
904 helios_lib.estimateLiDARHitPointMemory.errcheck = _check_error
906 helios_lib.gapfillLiDARMissesCountScan.argtypes = [
907 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_bool, ctypes.c_bool,
909 helios_lib.gapfillLiDARMissesCountScan.restype = ctypes.c_ulonglong
910 helios_lib.gapfillLiDARMissesCountScan.errcheck = _check_error
912 helios_lib.hasLiDARVirtualMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
913 helios_lib.hasLiDARVirtualMisses.restype = ctypes.c_bool
914 helios_lib.hasLiDARVirtualMisses.errcheck = _check_error
916 helios_lib.materializeLiDARMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
917 helios_lib.materializeLiDARMisses.restype =
None
918 helios_lib.materializeLiDARMisses.errcheck = _check_error
920 helios_lib.getLiDARScanGridDirection.argtypes = [
921 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_int, ctypes.c_int,
922 ctypes.POINTER(ctypes.c_float),
924 helios_lib.getLiDARScanGridDirection.restype =
None
925 helios_lib.getLiDARScanGridDirection.errcheck = _check_error
927 helios_lib.getLiDARHitXYZColumn.argtypes = [
928 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(ctypes.c_float), ctypes.c_uint,
930 helios_lib.getLiDARHitXYZColumn.restype =
None
931 helios_lib.getLiDARHitXYZColumn.errcheck = _check_error
933 helios_lib.getLiDARHitScanIDColumn.argtypes = [
934 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(ctypes.c_int), ctypes.c_uint,
936 helios_lib.getLiDARHitScanIDColumn.restype =
None
937 helios_lib.getLiDARHitScanIDColumn.errcheck = _check_error
939 helios_lib.setLiDARMaxHitPoints.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_ulonglong]
940 helios_lib.setLiDARMaxHitPoints.restype =
None
941 helios_lib.setLiDARMaxHitPoints.errcheck = _check_error
943 helios_lib.getLiDARDefaultMaxHitPoints.argtypes = []
944 helios_lib.getLiDARDefaultMaxHitPoints.restype = ctypes.c_ulonglong
945 helios_lib.getLiDARDefaultMaxHitPoints.errcheck = _check_error
947 helios_lib.reserveLiDARHitPoints.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_ulonglong]
948 helios_lib.reserveLiDARHitPoints.restype =
None
949 helios_lib.reserveLiDARHitPoints.errcheck = _check_error
951 helios_lib.setLiDARExactPathLengths.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_bool]
952 helios_lib.setLiDARExactPathLengths.restype =
None
953 helios_lib.setLiDARExactPathLengths.errcheck = _check_error
955 helios_lib.getLiDARExactPathLengths.argtypes = [ctypes.POINTER(ULiDARcloud)]
956 helios_lib.getLiDARExactPathLengths.restype = ctypes.c_bool
957 helios_lib.getLiDARExactPathLengths.errcheck = _check_error
959 _LIDAR_1384_AVAILABLE =
True
960except AttributeError:
961 _LIDAR_1384_AVAILABLE =
False
965_LIDAR_1385_AVAILABLE =
False
967 helios_lib.lidarIsMultiReturnData.argtypes = [ctypes.POINTER(ULiDARcloud)]
968 helios_lib.lidarIsMultiReturnData.restype = ctypes.c_int
969 helios_lib.lidarIsMultiReturnData.errcheck = _check_error
971 helios_lib.calculateLiDARLeafAreaGthetaPerCell.argtypes = [
972 ctypes.POINTER(ULiDARcloud),
973 ctypes.POINTER(UContext),
974 ctypes.POINTER(ctypes.c_float),
979 helios_lib.calculateLiDARLeafAreaGthetaPerCell.restype =
None
980 helios_lib.calculateLiDARLeafAreaGthetaPerCell.errcheck = _check_error
982 _LIDAR_1385_AVAILABLE =
True
983except AttributeError:
984 _LIDAR_1385_AVAILABLE =
False
990_LIDAR_1386_AVAILABLE =
False
992 helios_lib.createLiDARHitDataColumn.argtypes = [
993 ctypes.POINTER(ULiDARcloud), ctypes.c_char_p, ctypes.c_int,
995 helios_lib.createLiDARHitDataColumn.restype =
None
996 helios_lib.createLiDARHitDataColumn.errcheck = _check_error
998 helios_lib.getLiDARHitDataType.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
999 helios_lib.getLiDARHitDataType.restype = ctypes.c_int
1000 helios_lib.getLiDARHitDataType.errcheck = _check_error
1002 helios_lib.getLiDARHitDataColumnF32.argtypes = [
1003 ctypes.POINTER(ULiDARcloud), ctypes.c_char_p,
1004 ctypes.POINTER(ctypes.c_float), ctypes.c_uint, ctypes.c_float,
1006 helios_lib.getLiDARHitDataColumnF32.restype =
None
1007 helios_lib.getLiDARHitDataColumnF32.errcheck = _check_error
1009 helios_lib.getLiDARHitDataColumnI32.argtypes = [
1010 ctypes.POINTER(ULiDARcloud), ctypes.c_char_p,
1011 ctypes.POINTER(ctypes.c_int), ctypes.c_uint, ctypes.c_int,
1013 helios_lib.getLiDARHitDataColumnI32.restype =
None
1014 helios_lib.getLiDARHitDataColumnI32.errcheck = _check_error
1016 helios_lib.addLiDARHitPointsBulk.argtypes = [
1017 ctypes.POINTER(ULiDARcloud),
1020 ctypes.POINTER(ctypes.c_double),
1021 ctypes.POINTER(ctypes.c_float),
1022 ctypes.POINTER(ctypes.c_char_p),
1024 ctypes.POINTER(ctypes.c_double),
1026 helios_lib.addLiDARHitPointsBulk.restype =
None
1027 helios_lib.addLiDARHitPointsBulk.errcheck = _check_error
1029 helios_lib.deleteLiDARHitPoints.argtypes = [
1030 ctypes.POINTER(ULiDARcloud), ctypes.c_size_t, ctypes.c_size_t,
1032 helios_lib.deleteLiDARHitPoints.restype =
None
1033 helios_lib.deleteLiDARHitPoints.errcheck = _check_error
1035 helios_lib.setLiDARTriangulationSink.argtypes = [
1036 ctypes.POINTER(ULiDARcloud), LiDARTriangulationSinkCallback, ctypes.c_void_p,
1038 helios_lib.setLiDARTriangulationSink.restype =
None
1039 helios_lib.setLiDARTriangulationSink.errcheck = _check_error
1041 helios_lib.setLiDARSyntheticScanHitSink.argtypes = [
1042 ctypes.POINTER(ULiDARcloud), LiDARSyntheticScanHitSinkCallback, ctypes.c_void_p,
1044 helios_lib.setLiDARSyntheticScanHitSink.restype =
None
1045 helios_lib.setLiDARSyntheticScanHitSink.errcheck = _check_error
1047 helios_lib.getLiDARScanHitCount.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
1048 helios_lib.getLiDARScanHitCount.restype = ctypes.c_size_t
1049 helios_lib.getLiDARScanHitCount.errcheck = _check_error
1051 helios_lib.getLiDARScanHitIndices.argtypes = [
1052 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
1053 ctypes.POINTER(ctypes.c_uint), ctypes.c_uint,
1055 helios_lib.getLiDARScanHitIndices.restype =
None
1056 helios_lib.getLiDARScanHitIndices.errcheck = _check_error
1058 helios_lib.getLiDARScanHitXYZColumn.argtypes = [
1059 ctypes.POINTER(ULiDARcloud), ctypes.c_uint,
1060 ctypes.POINTER(ctypes.c_float), ctypes.c_uint,
1062 helios_lib.getLiDARScanHitXYZColumn.restype =
None
1063 helios_lib.getLiDARScanHitXYZColumn.errcheck = _check_error
1065 helios_lib.getLiDARScanHitDataColumn.argtypes = [
1066 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_char_p,
1067 ctypes.POINTER(ctypes.c_double), ctypes.c_uint, ctypes.c_double,
1069 helios_lib.getLiDARScanHitDataColumn.restype =
None
1070 helios_lib.getLiDARScanHitDataColumn.errcheck = _check_error
1072 helios_lib.getLiDARScanHitDataColumnF32.argtypes = [
1073 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_char_p,
1074 ctypes.POINTER(ctypes.c_float), ctypes.c_uint, ctypes.c_float,
1076 helios_lib.getLiDARScanHitDataColumnF32.restype =
None
1077 helios_lib.getLiDARScanHitDataColumnF32.errcheck = _check_error
1079 helios_lib.getLiDARScanHitDataColumnI32.argtypes = [
1080 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.c_char_p,
1081 ctypes.POINTER(ctypes.c_int), ctypes.c_uint, ctypes.c_int,
1083 helios_lib.getLiDARScanHitDataColumnI32.restype =
None
1084 helios_lib.getLiDARScanHitDataColumnI32.errcheck = _check_error
1086 helios_lib.calculateLiDARLeafAreaBlock.argtypes = [
1087 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(UContext),
1090 ctypes.POINTER(ctypes.c_int),
1091 ctypes.POINTER(ctypes.c_int),
1093 helios_lib.calculateLiDARLeafAreaBlock.restype =
None
1094 helios_lib.calculateLiDARLeafAreaBlock.errcheck = _check_error
1096 helios_lib.calculateLiDARLeafAreaGthetaBlock.argtypes = [
1097 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(UContext),
1101 ctypes.POINTER(ctypes.c_int),
1102 ctypes.POINTER(ctypes.c_int),
1104 helios_lib.calculateLiDARLeafAreaGthetaBlock.restype =
None
1105 helios_lib.calculateLiDARLeafAreaGthetaBlock.errcheck = _check_error
1107 helios_lib.calculateLiDARLeafAreaGthetaPerCellBlock.argtypes = [
1108 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(UContext),
1109 ctypes.POINTER(ctypes.c_float),
1113 ctypes.POINTER(ctypes.c_int),
1114 ctypes.POINTER(ctypes.c_int),
1116 helios_lib.calculateLiDARLeafAreaGthetaPerCellBlock.restype =
None
1117 helios_lib.calculateLiDARLeafAreaGthetaPerCellBlock.errcheck = _check_error
1119 helios_lib.getLiDARCellGlobalIJK.argtypes = [
1120 ctypes.POINTER(ULiDARcloud), ctypes.c_uint, ctypes.POINTER(ctypes.c_int),
1122 helios_lib.getLiDARCellGlobalIJK.restype =
None
1123 helios_lib.getLiDARCellGlobalIJK.errcheck = _check_error
1125 helios_lib.getLiDARGridGlobalCount.argtypes = [
1126 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(ctypes.c_int),
1128 helios_lib.getLiDARGridGlobalCount.restype =
None
1129 helios_lib.getLiDARGridGlobalCount.errcheck = _check_error
1131 helios_lib.getLiDARHitPointCapacity.argtypes = [ctypes.POINTER(ULiDARcloud)]
1132 helios_lib.getLiDARHitPointCapacity.restype = ctypes.c_size_t
1133 helios_lib.getLiDARHitPointCapacity.errcheck = _check_error
1135 _LIDAR_1386_AVAILABLE =
True
1136except AttributeError:
1137 _LIDAR_1386_AVAILABLE =
False
1142_LIDAR_CROPPED_RETURNS_AVAILABLE =
False
1144 helios_lib.getLiDARCroppedReturnStats.argtypes = [
1145 ctypes.POINTER(ULiDARcloud), ctypes.POINTER(ctypes.c_ulonglong),
1147 helios_lib.getLiDARCroppedReturnStats.restype =
None
1148 helios_lib.getLiDARCroppedReturnStats.errcheck = _check_error
1149 _LIDAR_CROPPED_RETURNS_AVAILABLE =
True
1150except AttributeError:
1151 _LIDAR_CROPPED_RETURNS_AVAILABLE =
False
1156 """Create LiDARcloud instance"""
1157 if not _LIDAR_FUNCTIONS_AVAILABLE:
1158 raise NotImplementedError(
1159 "LiDAR functions not available. Rebuild PyHelios with lidar plugin:\n"
1160 " build_scripts/build_helios --plugins lidar"
1162 return helios_lib.createLiDARcloud()
1166 """Destroy LiDARcloud instance"""
1167 if cloud_ptr
and _LIDAR_FUNCTIONS_AVAILABLE:
1168 helios_lib.destroyLiDARcloud(cloud_ptr)
1171def addLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
1172 origin: List[float], Ntheta: int, theta_range: Tuple[float, float],
1173 Nphi: int, phi_range: Tuple[float, float],
1174 exit_diameter: float, beam_divergence: float,
1175 column_format: Optional[List[str]] =
None,
1176 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1177 scan_tilt_roll: float = 0.0, scan_tilt_pitch: float = 0.0,
1178 scan_azimuth_offset: float = 0.0) -> int:
1179 """Add a LiDAR scan to the point cloud"""
1180 if not _LIDAR_FUNCTIONS_AVAILABLE:
1181 raise NotImplementedError(
"LiDAR functions not available")
1183 if len(origin) != 3:
1184 raise ValueError(
"Origin must be a 3-element array [x, y, z]")
1186 origin_array = (ctypes.c_float * 3)(*origin)
1189 column_array = (ctypes.c_char_p * len(column_format))(
1190 *[c.encode(
'utf-8')
for c
in column_format]
1192 n_cols = len(column_format)
1197 return helios_lib.addLiDARScan(
1198 cloud_ptr, origin_array, Ntheta, theta_range[0], theta_range[1],
1199 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
1200 float(range_noise_stddev), float(angle_noise_stddev),
1201 column_array, n_cols,
1202 float(scan_tilt_roll), float(scan_tilt_pitch), float(scan_azimuth_offset)
1207 Ntheta: int, theta_range: Tuple[float, float],
1208 Nphi: int, phi_range: Tuple[float, float],
1209 exit_diameter: float, beam_divergence: float,
1210 traj_t: List[float], traj_pos: List[List[float]],
1211 traj_rot: List[List[float]], rot_is_quaternion: bool,
1212 pulse_rate_hz: float,
1213 lever_arm: Optional[List[float]] =
None,
1214 boresight_rpy: Optional[List[float]] =
None,
1215 column_format: Optional[List[str]] =
None,
1216 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1217 t0: float = 0.0) -> int:
1218 """Add a moving-platform (mobile/airborne) raster LiDAR scan driven by a 6-DOF pose trajectory.
1220 traj_rot entries are length-4 quaternions (qx,qy,qz,qw) if rot_is_quaternion is True,
1221 otherwise length-3 roll/pitch/yaw Euler angles (radians, intrinsic Z-Y-X).
1223 if not _LIDAR_FUNCTIONS_AVAILABLE:
1224 raise NotImplementedError(
"LiDAR functions not available")
1228 raise ValueError(
"traj_t must contain at least one trajectory sample")
1229 if len(traj_pos) != M
or len(traj_rot) != M:
1230 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
1231 if pulse_rate_hz <= 0.0:
1232 raise ValueError(
"pulse_rate_hz must be greater than 0")
1234 rot_stride = 4
if rot_is_quaternion
else 3
1235 if any(len(p) != 3
for p
in traj_pos):
1236 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1237 if any(len(r) != rot_stride
for r
in traj_rot):
1239 f
"Each traj_rot entry must have {rot_stride} elements "
1240 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
1243 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1244 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1245 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1246 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
1247 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
1249 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1250 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1251 if len(lever) != 3
or len(boresight) != 3:
1252 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1253 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1254 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1257 column_array = (ctypes.c_char_p * len(column_format))(
1258 *[c.encode(
'utf-8')
for c
in column_format]
1260 n_cols = len(column_format)
1265 return helios_lib.addLiDARScanMoving(
1266 cloud_ptr, Ntheta, theta_range[0], theta_range[1],
1267 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence,
1268 float(range_noise_stddev), float(angle_noise_stddev),
1269 column_array, n_cols,
1270 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
1271 lever_array, boresight_array, float(pulse_rate_hz), float(t0)
1276 beam_elevation_angles: List[float],
1277 azimuth_step_rad: float, pulse_rate_hz: float,
1278 traj_t: List[float], traj_pos: List[List[float]],
1279 traj_rot: List[List[float]], rot_is_quaternion: bool,
1280 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
1281 lever_arm: Optional[List[float]] =
None,
1282 boresight_rpy: Optional[List[float]] =
None,
1283 column_format: Optional[List[str]] =
None,
1284 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1285 t0: float = 0.0) -> int:
1286 """Add a continuously-spinning multibeam scan from physical instrument parameters.
1288 beam_elevation_angles are per-channel ELEVATION angles above the horizon (radians), NOT zenith.
1289 traj_rot entries are length-4 quaternions (qx,qy,qz,qw) if rot_is_quaternion is True,
1290 otherwise length-3 roll/pitch/yaw Euler angles (radians, intrinsic Z-Y-X).
1292 if not _LIDAR_FUNCTIONS_AVAILABLE:
1293 raise NotImplementedError(
"LiDAR functions not available")
1295 n_angles = len(beam_elevation_angles)
1297 raise ValueError(
"beam_elevation_angles must contain at least one per-channel angle")
1298 if azimuth_step_rad <= 0.0:
1299 raise ValueError(
"azimuth_step_rad must be greater than 0")
1300 if pulse_rate_hz <= 0.0:
1301 raise ValueError(
"pulse_rate_hz must be greater than 0")
1305 raise ValueError(
"traj_t must contain at least one trajectory sample")
1306 if len(traj_pos) != M
or len(traj_rot) != M:
1307 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
1309 rot_stride = 4
if rot_is_quaternion
else 3
1310 if any(len(p) != 3
for p
in traj_pos):
1311 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1312 if any(len(r) != rot_stride
for r
in traj_rot):
1314 f
"Each traj_rot entry must have {rot_stride} elements "
1315 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
1318 beam_array = (ctypes.c_float * n_angles)(*[float(a)
for a
in beam_elevation_angles])
1319 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1320 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1321 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1322 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
1323 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
1325 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1326 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1327 if len(lever) != 3
or len(boresight) != 3:
1328 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1329 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1330 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1333 column_array = (ctypes.c_char_p * len(column_format))(
1334 *[c.encode(
'utf-8')
for c
in column_format]
1336 n_cols = len(column_format)
1341 return helios_lib.addLiDARScanSpinning(
1342 cloud_ptr, beam_array, n_angles, float(azimuth_step_rad), float(pulse_rate_hz),
1343 float(exit_diameter), float(beam_divergence),
1344 float(range_noise_stddev), float(angle_noise_stddev),
1345 column_array, n_cols,
1346 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
1347 lever_array, boresight_array, float(t0)
1352 Ntheta: int, theta_range: Tuple[float, float],
1353 Nphi: int, phi_range: Tuple[float, float],
1354 pulse_rate_hz: float,
1355 traj_t: List[float], traj_pos: List[List[float]],
1356 traj_quat: List[List[float]],
1357 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
1358 lever_arm: Optional[List[float]] =
None,
1359 boresight_rpy: Optional[List[float]] =
None,
1360 column_format: Optional[List[str]] =
None,
1361 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1362 t0: float = 0.0) -> int:
1363 """Add a moving-platform raster scan: a fixed angular fan swept along a quaternion trajectory.
1365 traj_quat entries are length-4 quaternions (qx,qy,qz,qw), Hamilton body->world.
1367 if not _LIDAR_FUNCTIONS_AVAILABLE:
1368 raise NotImplementedError(
"LiDAR functions not available")
1372 raise ValueError(
"traj_t must contain at least one trajectory sample")
1373 if len(traj_pos) != M
or len(traj_quat) != M:
1374 raise ValueError(
"traj_t, traj_pos, and traj_quat must all have the same length M")
1375 if pulse_rate_hz <= 0.0:
1376 raise ValueError(
"pulse_rate_hz must be greater than 0")
1377 if any(len(p) != 3
for p
in traj_pos):
1378 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1379 if any(len(q) != 4
for q
in traj_quat):
1380 raise ValueError(
"Each traj_quat entry must be a 4-element [qx, qy, qz, qw]")
1382 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1383 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1384 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1385 quat_flat = [float(c)
for q
in traj_quat
for c
in q]
1386 quat_array = (ctypes.c_float * (4 * M))(*quat_flat)
1388 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1389 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1390 if len(lever) != 3
or len(boresight) != 3:
1391 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1392 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1393 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1396 column_array = (ctypes.c_char_p * len(column_format))(
1397 *[c.encode(
'utf-8')
for c
in column_format]
1399 n_cols = len(column_format)
1404 return helios_lib.addLiDARScanMovingRaster(
1405 cloud_ptr, Ntheta, theta_range[0], theta_range[1],
1406 Nphi, phi_range[0], phi_range[1], float(pulse_rate_hz),
1407 float(exit_diameter), float(beam_divergence),
1408 float(range_noise_stddev), float(angle_noise_stddev),
1409 column_array, n_cols,
1410 t_array, pos_array, quat_array, M,
1411 lever_array, boresight_array, float(t0)
1416 prisms: List[List[float]], refractive_index_air: float,
1417 pulse_rate_hz: float,
1418 traj_t: List[float], traj_pos: List[List[float]],
1419 traj_rot: List[List[float]], rot_is_quaternion: bool,
1420 exit_diameter: float = 0.0, beam_divergence: float = 0.0,
1421 lever_arm: Optional[List[float]] =
None,
1422 boresight_rpy: Optional[List[float]] =
None,
1423 column_format: Optional[List[str]] =
None,
1424 range_noise_stddev: float = 0.0, angle_noise_stddev: float = 0.0,
1425 t0: float = 0.0) -> int:
1426 """Add a rotating-Risley-prism (Livox-style rosette) scan from physical instrument parameters.
1428 prisms is a list of 4-element [wedge_angle, refractive_index, rotor_rate, phase] entries in
1429 beam-traversal order (at least one). traj_rot entries are length-4 quaternions (qx,qy,qz,qw)
1430 if rot_is_quaternion is True, otherwise length-3 roll/pitch/yaw Euler angles (radians).
1432 if not _LIDAR_FUNCTIONS_AVAILABLE:
1433 raise NotImplementedError(
"LiDAR functions not available")
1435 n_prisms = len(prisms)
1437 raise ValueError(
"prisms must contain at least one Risley prism")
1438 if any(len(p) != 4
for p
in prisms):
1439 raise ValueError(
"Each prism must be a 4-element [wedge_angle, refractive_index, rotor_rate, phase]")
1440 if pulse_rate_hz <= 0.0:
1441 raise ValueError(
"pulse_rate_hz must be greater than 0")
1445 raise ValueError(
"traj_t must contain at least one trajectory sample")
1446 if len(traj_pos) != M
or len(traj_rot) != M:
1447 raise ValueError(
"traj_t, traj_pos, and traj_rot must all have the same length M")
1449 rot_stride = 4
if rot_is_quaternion
else 3
1450 if any(len(p) != 3
for p
in traj_pos):
1451 raise ValueError(
"Each traj_pos entry must be a 3-element [x, y, z]")
1452 if any(len(r) != rot_stride
for r
in traj_rot):
1454 f
"Each traj_rot entry must have {rot_stride} elements "
1455 f
"({'qx,qy,qz,qw' if rot_is_quaternion else 'roll,pitch,yaw'})"
1458 prism_flat = [float(c)
for p
in prisms
for c
in p]
1459 prism_array = (ctypes.c_double * (4 * n_prisms))(*prism_flat)
1460 t_array = (ctypes.c_double * M)(*[float(t)
for t
in traj_t])
1461 pos_flat = [float(c)
for p
in traj_pos
for c
in p]
1462 pos_array = (ctypes.c_float * (3 * M))(*pos_flat)
1463 rot_flat = [float(c)
for r
in traj_rot
for c
in r]
1464 rot_array = (ctypes.c_float * (rot_stride * M))(*rot_flat)
1466 lever = lever_arm
if lever_arm
is not None else [0.0, 0.0, 0.0]
1467 boresight = boresight_rpy
if boresight_rpy
is not None else [0.0, 0.0, 0.0]
1468 if len(lever) != 3
or len(boresight) != 3:
1469 raise ValueError(
"lever_arm and boresight_rpy must each be 3-element arrays")
1470 lever_array = (ctypes.c_float * 3)(*[float(c)
for c
in lever])
1471 boresight_array = (ctypes.c_float * 3)(*[float(c)
for c
in boresight])
1474 column_array = (ctypes.c_char_p * len(column_format))(
1475 *[c.encode(
'utf-8')
for c
in column_format]
1477 n_cols = len(column_format)
1482 return helios_lib.addLiDARScanRisley(
1483 cloud_ptr, prism_array, n_prisms, float(refractive_index_air), float(pulse_rate_hz),
1484 float(exit_diameter), float(beam_divergence),
1485 float(range_noise_stddev), float(angle_noise_stddev),
1486 column_array, n_cols,
1487 t_array, pos_array, rot_array, M, 1
if rot_is_quaternion
else 0,
1488 lever_array, boresight_array, float(t0)
1492def getLiDARScanMode(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> int:
1493 """Get the acquisition mode (0 = static raster, 1 = moving raster, 2 = spinning, 3 = Risley prism)."""
1494 if not _LIDAR_FUNCTIONS_AVAILABLE:
1495 raise NotImplementedError(
"LiDAR functions not available")
1496 return helios_lib.getLiDARScanMode(cloud_ptr, scanID)
1500 """Get the number of azimuth firing steps per revolution (spinning scans; 0 otherwise)."""
1501 if not _LIDAR_FUNCTIONS_AVAILABLE:
1502 raise NotImplementedError(
"LiDAR functions not available")
1503 return helios_lib.getLiDARScanStepsPerRev(cloud_ptr, scanID)
1507 """Get the sensor-head rotation rate in revolutions/second (spinning scans; 0 otherwise)."""
1508 if not _LIDAR_FUNCTIONS_AVAILABLE:
1509 raise NotImplementedError(
"LiDAR functions not available")
1510 return helios_lib.getLiDARScanRotationRate(cloud_ptr, scanID)
1514 """Get the number of revolutions the sensor head made (spinning scans; 0 otherwise)."""
1515 if not _LIDAR_FUNCTIONS_AVAILABLE:
1516 raise NotImplementedError(
"LiDAR functions not available")
1517 return helios_lib.getLiDARScanRevolutions(cloud_ptr, scanID)
1521 """Get the rotating wedge prisms of a Risley-prism scan.
1523 Returns a list of [wedge_angle, refractive_index, rotor_rate, phase] entries in
1524 beam-traversal order (empty for scans that are not Risley-prism)."""
1525 if not _LIDAR_FUNCTIONS_AVAILABLE:
1526 raise NotImplementedError(
"LiDAR functions not available")
1527 count = helios_lib.getLiDARScanRisleyPrismCount(cloud_ptr, scanID)
1530 out = (ctypes.c_double * (4 * count))()
1531 helios_lib.getLiDARScanRisleyPrisms(cloud_ptr, scanID, out, count)
1532 return [[float(out[4 * i]), float(out[4 * i + 1]), float(out[4 * i + 2]), float(out[4 * i + 3])]
1533 for i
in range(count)]
1537 """Get the refractive index of the medium surrounding the prisms of a Risley-prism scan (1.0 for non-Risley)."""
1538 if not _LIDAR_FUNCTIONS_AVAILABLE:
1539 raise NotImplementedError(
"LiDAR functions not available")
1540 return helios_lib.getLiDARScanRisleyRefractiveIndexAir(cloud_ptr, scanID)
1544 """Get the return-reporting mode (0 = multi, 1 = single)."""
1545 if not _LIDAR_FUNCTIONS_AVAILABLE:
1546 raise NotImplementedError(
"LiDAR functions not available")
1547 return helios_lib.getLiDARScanReturnMode(cloud_ptr, scanID)
1550def setLiDARScanReturnMode(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, return_mode: int) ->
None:
1551 """Set the return-reporting mode (0 = multi, 1 = single)."""
1552 if not _LIDAR_FUNCTIONS_AVAILABLE:
1553 raise NotImplementedError(
"LiDAR functions not available")
1554 helios_lib.setLiDARScanReturnMode(cloud_ptr, scanID, return_mode)
1558 """Get the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last, 3 = strongest+last)."""
1559 if not _LIDAR_FUNCTIONS_AVAILABLE:
1560 raise NotImplementedError(
"LiDAR functions not available")
1561 return helios_lib.getLiDARScanSingleReturnSelection(cloud_ptr, scanID)
1565 """Set the single/limited-return selection policy (0 = strongest, 1 = first, 2 = last, 3 = strongest+last)."""
1566 if not _LIDAR_FUNCTIONS_AVAILABLE:
1567 raise NotImplementedError(
"LiDAR functions not available")
1568 helios_lib.setLiDARScanSingleReturnSelection(cloud_ptr, scanID, selection)
1572 """Get the maximum returns per pulse used in single/limited-return mode."""
1573 if not _LIDAR_FUNCTIONS_AVAILABLE:
1574 raise NotImplementedError(
"LiDAR functions not available")
1575 return helios_lib.getLiDARScanMaxReturns(cloud_ptr, scanID)
1578def setLiDARScanMaxReturns(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, max_returns: int) ->
None:
1579 """Set the maximum returns per pulse used in single/limited-return mode (must be >= 1)."""
1580 if not _LIDAR_FUNCTIONS_AVAILABLE:
1581 raise NotImplementedError(
"LiDAR functions not available")
1582 helios_lib.setLiDARScanMaxReturns(cloud_ptr, scanID, max_returns)
1586 """Get the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument)."""
1587 if not _LIDAR_FUNCTIONS_AVAILABLE:
1588 raise NotImplementedError(
"LiDAR functions not available")
1589 return helios_lib.getLiDARScanPulseWidth(cloud_ptr, scanID)
1592def setLiDARScanPulseWidth(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int, pulse_width: float) ->
None:
1593 """Set the pulse width / range resolution (meters) of a scan (0 = use syntheticScan argument)."""
1594 if not _LIDAR_FUNCTIONS_AVAILABLE:
1595 raise NotImplementedError(
"LiDAR functions not available")
1596 helios_lib.setLiDARScanPulseWidth(cloud_ptr, scanID, float(pulse_width))
1600 """Get the detection threshold (energy fraction, noise floor) of a scan."""
1601 if not _LIDAR_FUNCTIONS_AVAILABLE:
1602 raise NotImplementedError(
"LiDAR functions not available")
1603 return helios_lib.getLiDARScanDetectionThreshold(cloud_ptr, scanID)
1607 """Set the detection threshold (energy fraction, noise floor) of a scan."""
1608 if not _LIDAR_FUNCTIONS_AVAILABLE:
1609 raise NotImplementedError(
"LiDAR functions not available")
1610 helios_lib.setLiDARScanDetectionThreshold(cloud_ptr, scanID, float(detection_threshold))
1614 """Get the global scanner tilt roll angle (radians) for a scan."""
1615 if not _LIDAR_FUNCTIONS_AVAILABLE:
1616 raise NotImplementedError(
"LiDAR functions not available")
1617 return helios_lib.getLiDARScanTiltRoll(cloud_ptr, scanID)
1621 """Get the global scanner tilt pitch angle (radians) for a scan."""
1622 if not _LIDAR_FUNCTIONS_AVAILABLE:
1623 raise NotImplementedError(
"LiDAR functions not available")
1624 return helios_lib.getLiDARScanTiltPitch(cloud_ptr, scanID)
1628 """Get the global scanner azimuth (heading) offset angle (radians) for a scan."""
1629 if not _LIDAR_FUNCTIONS_AVAILABLE:
1630 raise NotImplementedError(
"LiDAR functions not available")
1631 return helios_lib.getLiDARScanAzimuthOffset(cloud_ptr, scanID)
1635 """Get the scan pattern (0 = raster, 1 = spinning multibeam)."""
1636 if not _LIDAR_FUNCTIONS_AVAILABLE:
1637 raise NotImplementedError(
"LiDAR functions not available")
1638 return helios_lib.getLiDARScanPattern(cloud_ptr, scanID)
1642 """Get the per-channel beam zenith angles (radians) for a multibeam scan (empty for raster)."""
1643 if not _LIDAR_FUNCTIONS_AVAILABLE:
1644 raise NotImplementedError(
"LiDAR functions not available")
1645 count = helios_lib.getLiDARScanBeamZenithAngleCount(cloud_ptr, scanID)
1648 out = (ctypes.c_float * count)()
1649 helios_lib.getLiDARScanBeamZenithAngles(cloud_ptr, scanID, out, count)
1650 return [float(out[i])
for i
in range(count)]
1653def isLiDARHitMiss(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> bool:
1654 """Return True if the hit is a miss (a transmitted beam that returned nothing)."""
1655 if not _LIDAR_FUNCTIONS_AVAILABLE:
1656 raise NotImplementedError(
"LiDAR functions not available")
1657 return bool(helios_lib.isLiDARHitMiss(cloud_ptr, index))
1660def lidarHasMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
1661 """Return True if the cloud contains at least one miss."""
1662 if not _LIDAR_FUNCTIONS_AVAILABLE:
1663 raise NotImplementedError(
"LiDAR functions not available")
1664 return bool(helios_lib.lidarHasMisses(cloud_ptr))
1668 """Return the LIDAR_MISS_DISTANCE constant (meters)."""
1669 if not _LIDAR_FUNCTIONS_AVAILABLE:
1670 raise NotImplementedError(
"LiDAR functions not available")
1671 return helios_lib.getLiDARMissDistance()
1675 """Get number of scans in the cloud"""
1676 if not _LIDAR_FUNCTIONS_AVAILABLE:
1677 raise NotImplementedError(
"LiDAR functions not available")
1678 return helios_lib.getLiDARScanCount(cloud_ptr)
1681def getLiDARScanOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> List[float]:
1682 """Get origin of a specific scan"""
1683 if not _LIDAR_FUNCTIONS_AVAILABLE:
1684 raise NotImplementedError(
"LiDAR functions not available")
1686 origin = (ctypes.c_float * 3)()
1687 helios_lib.getLiDARScanOrigin(cloud_ptr, scanID, origin)
1692 """Get number of zenith scan points"""
1693 if not _LIDAR_FUNCTIONS_AVAILABLE:
1694 raise NotImplementedError(
"LiDAR functions not available")
1695 return helios_lib.getLiDARScanSizeTheta(cloud_ptr, scanID)
1699 """Get number of azimuthal scan points"""
1700 if not _LIDAR_FUNCTIONS_AVAILABLE:
1701 raise NotImplementedError(
"LiDAR functions not available")
1702 return helios_lib.getLiDARScanSizePhi(cloud_ptr, scanID)
1706 """Get the range (along-beam) measurement noise standard deviation for a scan (meters)"""
1707 if not _LIDAR_FUNCTIONS_AVAILABLE:
1708 raise NotImplementedError(
"LiDAR functions not available")
1709 return helios_lib.getLiDARScanRangeNoiseStdDev(cloud_ptr, scanID)
1713 """Get the angular (beam-pointing) jitter standard deviation for a scan (radians)"""
1714 if not _LIDAR_FUNCTIONS_AVAILABLE:
1715 raise NotImplementedError(
"LiDAR functions not available")
1716 return helios_lib.getLiDARScanAngleNoiseStdDev(cloud_ptr, scanID)
1720 xyz: List[float], direction: List[float]) ->
None:
1721 """Add a hit point to the cloud"""
1722 if not _LIDAR_FUNCTIONS_AVAILABLE:
1723 raise NotImplementedError(
"LiDAR functions not available")
1726 raise ValueError(
"XYZ must be a 3-element array")
1727 if len(direction) < 2:
1728 raise ValueError(
"Direction must have at least 2 elements [radius, elevation]")
1730 xyz_array = (ctypes.c_float * 3)(*xyz)
1731 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
1732 helios_lib.addLiDARHitPoint(cloud_ptr, scanID, xyz_array, direction_array)
1736 xyz: List[float], direction: List[float], color: List[float]) ->
None:
1737 """Add a hit point with color to the cloud"""
1738 if not _LIDAR_FUNCTIONS_AVAILABLE:
1739 raise NotImplementedError(
"LiDAR functions not available")
1742 raise ValueError(
"XYZ must be a 3-element array")
1743 if len(direction) < 2:
1744 raise ValueError(
"Direction must have at least 2 elements")
1746 raise ValueError(
"Color must be a 3-element array [r, g, b]")
1748 xyz_array = (ctypes.c_float * 3)(*xyz)
1749 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2]
if len(direction) > 2
else 0)
1750 color_array = (ctypes.c_float * 3)(*color)
1751 helios_lib.addLiDARHitPointRGB(cloud_ptr, scanID, xyz_array, direction_array, color_array)
1755 xyzs, directions, count: int, colors=
None) ->
None:
1756 """Add many hit points to the cloud in a single call (bulk ingestion).
1758 xyzs and directions must be contiguous float32 buffers (e.g. numpy arrays)
1759 of shape (count, 3). colors, if given, must be a contiguous float32 buffer
1760 of shape (count, 3); pass None to add without color. The buffers are passed
1761 straight through to C without per-point Python marshalling.
1763 if not _LIDAR_FUNCTIONS_AVAILABLE:
1764 raise NotImplementedError(
"LiDAR functions not available")
1766 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1767 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1768 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
1769 helios_lib.addLiDARHitPoints(cloud_ptr, scanID, xyzs_ptr, directions_ptr, count, colors_ptr)
1773 xyzs, directions, count: int, colors=
None,
1774 labels=
None, data_values=
None) ->
None:
1775 """Bulk-ingest hit points carrying a per-hit data map in one call.
1777 xyzs/directions (and colors, if given) must be contiguous float32 buffers of
1778 shape (count, 3); directions is (radius, elevation, azimuth). labels is a
1779 list of data-map key names; data_values must be a contiguous float64 buffer
1780 of shape (count, len(labels)). Pass labels=None/empty (and data_values=None)
1781 to ingest with an empty data map.
1783 if not _LIDAR_FUNCTIONS_AVAILABLE:
1784 raise NotImplementedError(
"LiDAR functions not available")
1786 xyzs_ptr = xyzs.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1787 directions_ptr = directions.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
1788 colors_ptr = colors.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
if colors
is not None else None
1790 labels = list(labels
or [])
1791 n_labels = len(labels)
1793 labels_arr = (ctypes.c_char_p * n_labels)(*[s.encode(
'utf-8')
for s
in labels])
1794 values_ptr = data_values.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
1799 helios_lib.addLiDARHitPointsWithData(cloud_ptr, scanID, xyzs_ptr, directions_ptr,
1800 count, colors_ptr, labels_arr, n_labels, values_ptr)
1804 """Get total number of hit points"""
1805 if not _LIDAR_FUNCTIONS_AVAILABLE:
1806 raise NotImplementedError(
"LiDAR functions not available")
1807 return helios_lib.getLiDARHitCount(cloud_ptr)
1810def getLiDARHitXYZ(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1811 """Get coordinates of a hit point"""
1812 if not _LIDAR_FUNCTIONS_AVAILABLE:
1813 raise NotImplementedError(
"LiDAR functions not available")
1815 xyz = (ctypes.c_float * 3)()
1816 helios_lib.getLiDARHitXYZ(cloud_ptr, index, xyz)
1820def getLiDARHitOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1821 """Get the (x,y,z) beam-emission origin of a hit point.
1823 For moving-platform scans this is the per-pulse origin; for static scans it falls back to
1824 the single scan origin of the hit's scan.
1826 if not _LIDAR_FUNCTIONS_AVAILABLE:
1827 raise NotImplementedError(
"LiDAR functions not available")
1829 xyz = (ctypes.c_float * 3)()
1830 helios_lib.getLiDARHitOrigin(cloud_ptr, index, xyz)
1834def getLiDARHitRaydir(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1835 """Get ray direction of a hit point"""
1836 if not _LIDAR_FUNCTIONS_AVAILABLE:
1837 raise NotImplementedError(
"LiDAR functions not available")
1839 direction = (ctypes.c_float * 3)()
1840 helios_lib.getLiDARHitRaydir(cloud_ptr, index, direction)
1841 return list(direction)
1844def getLiDARHitColor(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
1845 """Get color of a hit point"""
1846 if not _LIDAR_FUNCTIONS_AVAILABLE:
1847 raise NotImplementedError(
"LiDAR functions not available")
1849 color = (ctypes.c_float * 3)()
1850 helios_lib.getLiDARHitColor(cloud_ptr, index, color)
1854def getLiDARHitScanID(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> int:
1855 """Get the scan ID a hit point belongs to"""
1856 if not _LIDAR_FUNCTIONS_AVAILABLE:
1857 raise NotImplementedError(
"LiDAR functions not available")
1858 return helios_lib.getLiDARHitScanID(cloud_ptr, index)
1862 """Check whether a named scalar data value exists for a hit point"""
1863 if not _LIDAR_FUNCTIONS_AVAILABLE:
1864 raise NotImplementedError(
"LiDAR functions not available")
1865 return bool(helios_lib.doesLiDARHitDataExist(cloud_ptr, index, label.encode(
'utf-8')))
1868def getLiDARHitData(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int, label: str) -> float:
1869 """Get a named scalar data value for a hit point"""
1870 if not _LIDAR_FUNCTIONS_AVAILABLE:
1871 raise NotImplementedError(
"LiDAR functions not available")
1872 return helios_lib.getLiDARHitData(cloud_ptr, index, label.encode(
'utf-8'))
1875def getLiDARHitData_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), label: str, n: int) -> List[float]:
1876 """Bulk-export a named scalar data value for all hit points in one call"""
1877 if not _LIDAR_FUNCTIONS_AVAILABLE:
1878 raise NotImplementedError(
"LiDAR functions not available")
1880 out = (ctypes.c_float * n)()
1881 helios_lib.getLiDARHitData_all(cloud_ptr, label.encode(
'utf-8'), out, n)
1885def getLiDARHitsXYZRGB_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), n: int) -> Tuple[List[float], List[float]]:
1886 """Bulk-export XYZ coordinates and RGB colors for all hit points in one call.
1888 Returns a tuple (xyz_flat, rgb_flat) of flat 3*n-element lists.
1890 if not _LIDAR_FUNCTIONS_AVAILABLE:
1891 raise NotImplementedError(
"LiDAR functions not available")
1893 xyz = (ctypes.c_float * (3 * n))()
1894 rgb = (ctypes.c_float * (3 * n))()
1895 helios_lib.getLiDARHitsXYZRGB_all(cloud_ptr, xyz, rgb, n)
1896 return list(xyz), list(rgb)
1900 """Bulk-export XYZ + RGB for all hits as numpy arrays (no per-element Python).
1902 Returns (xyz, rgb), each an (n, 3) float32 array. Much faster than the
1903 list-returning variant for million-point clouds — np.frombuffer copies the
1904 contiguous ctypes buffer in one shot.
1907 if not _LIDAR_FUNCTIONS_AVAILABLE:
1908 raise NotImplementedError(
"LiDAR functions not available")
1909 xyz = (ctypes.c_float * (3 * n))()
1910 rgb = (ctypes.c_float * (3 * n))()
1911 helios_lib.getLiDARHitsXYZRGB_all(cloud_ptr, xyz, rgb, n)
1912 xyz_np = np.frombuffer(xyz, dtype=np.float32, count=3 * n).copy().reshape(n, 3)
1913 rgb_np = np.frombuffer(rgb, dtype=np.float32, count=3 * n).copy().reshape(n, 3)
1914 return xyz_np, rgb_np
1918 """Bulk-export a named scalar field for all hits as an (n,) float32 numpy array
1919 (NaN where the label is absent for a hit)."""
1921 if not _LIDAR_FUNCTIONS_AVAILABLE:
1922 raise NotImplementedError(
"LiDAR functions not available")
1923 out = (ctypes.c_float * n)()
1924 helios_lib.getLiDARHitData_all(cloud_ptr, label.encode(
'utf-8'), out, n)
1925 return np.frombuffer(out, dtype=np.float32, count=n).copy()
1929 absent_value: float = -9999.0) -> List[float]:
1930 """Bulk-export a named scalar column via the native cache-linear columnar path.
1932 Faster than getLiDARHitData_all for whole-field reads (single cache-linear pass over the
1933 contiguous native column). Entries are absent_value where the label is absent for a hit.
1934 Returns a list of doubles of length min(n, hit count).
1936 if not _LIDAR_FUNCTIONS_AVAILABLE:
1937 raise NotImplementedError(
"LiDAR functions not available")
1939 out = (ctypes.c_double * n)()
1940 helios_lib.getLiDARHitDataColumn(cloud_ptr, label.encode(
'utf-8'), out, n, float(absent_value))
1945 """Get the internal column slot index for a hit-data label (-1 if never set on any hit)."""
1946 if not _LIDAR_FUNCTIONS_AVAILABLE:
1947 raise NotImplementedError(
"LiDAR functions not available")
1948 return helios_lib.getLiDARHitDataColumnIndex(cloud_ptr, label.encode(
'utf-8'))
1952 absent_value: float = -9999.0):
1953 """Bulk-export a named scalar column as an (n,) float64 numpy array via the columnar path
1954 (absent_value where the label is absent for a hit)."""
1956 if not _LIDAR_FUNCTIONS_AVAILABLE:
1957 raise NotImplementedError(
"LiDAR functions not available")
1958 out = (ctypes.c_double * n)()
1959 helios_lib.getLiDARHitDataColumn(cloud_ptr, label.encode(
'utf-8'), out, n, float(absent_value))
1960 return np.frombuffer(out, dtype=np.float64, count=n).copy()
1964 """Bulk-export the scan ID of every hit as an (n,) int32 numpy array."""
1966 if not _LIDAR_FUNCTIONS_AVAILABLE:
1967 raise NotImplementedError(
"LiDAR functions not available")
1968 out = (ctypes.c_int * n)()
1969 helios_lib.getLiDARHitScanID_all(cloud_ptr, out, n)
1970 return np.frombuffer(out, dtype=np.int32, count=n).copy()
1974 """Bulk-export the miss flag of every hit as an (n,) int32 numpy array (1=miss)."""
1976 if not _LIDAR_FUNCTIONS_AVAILABLE:
1977 raise NotImplementedError(
"LiDAR functions not available")
1978 out = (ctypes.c_int * n)()
1979 helios_lib.isLiDARHitMiss_all(cloud_ptr, out, n)
1980 return np.frombuffer(out, dtype=np.int32, count=n).copy()
1984 """Delete a hit point from the cloud"""
1985 if not _LIDAR_FUNCTIONS_AVAILABLE:
1986 raise NotImplementedError(
"LiDAR functions not available")
1987 helios_lib.deleteLiDARHitPoint(cloud_ptr, index)
1991 """Translate all hit points by a shift vector"""
1992 if not _LIDAR_FUNCTIONS_AVAILABLE:
1993 raise NotImplementedError("LiDAR functions not available")
1996 raise ValueError("Shift must be a 3-element array [x, y, z]")
1998 shift_array = (ctypes.c_float * 3)(*shift)
1999 helios_lib.lidarCoordinateShift(cloud_ptr, shift_array)
2002def lidarCoordinateRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), rotation: List[float]) -> None:
2003 """Rotate all hit points by spherical rotation angles"""
2004 if not _LIDAR_FUNCTIONS_AVAILABLE:
2005 raise NotImplementedError("LiDAR functions not available")
2007 if len(rotation) < 2:
2008 raise ValueError("Rotation must have at least 2 elements [radius, elevation]")
2010 rotation_array = (ctypes.c_float * 3)(rotation[0], rotation[1], rotation[2] if len(rotation) > 2 else 0)
2011 helios_lib.lidarCoordinateRotation(cloud_ptr, rotation_array)
2014def lidarTriangulateHitPoints(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2015 Lmax: float, max_aspect_ratio: float) -> None:
2016 """Generate triangle mesh from hit points"""
2017 if not _LIDAR_FUNCTIONS_AVAILABLE:
2018 raise NotImplementedError("LiDAR functions not available")
2019 helios_lib.lidarTriangulateHitPoints(cloud_ptr, Lmax, max_aspect_ratio)
2022def getLiDARTriangleCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
2023 """Get number of triangles in the mesh"""
2024 if not _LIDAR_FUNCTIONS_AVAILABLE:
2025 raise NotImplementedError("LiDAR functions not available")
2026 return helios_lib.getLiDARTriangleCount(cloud_ptr)
2029def getLiDARTriangulationStats(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> dict:
2030 """Filter diagnostics from the most recent triangulateHitPoints() call.
2032 Returns a dict with candidate/dropped counts. Each dropped triangle is
2033 attributed to one primary reason, so:
2034 candidates == kept + dropped_lmax + dropped_aspect + dropped_degenerate
2035 where `kept` equals getLiDARTriangleCount(). All zero if triangulation has
2038 if not _LIDAR_FUNCTIONS_AVAILABLE:
2039 raise NotImplementedError("LiDAR functions not available")
2040 out = (ctypes.c_uint * 4)()
2041 helios_lib.getLiDARTriangulationStats(cloud_ptr, out)
2043 "candidates": int(out[0]),
2044 "dropped_lmax": int(out[1]),
2045 "dropped_aspect": int(out[2]),
2046 "dropped_degenerate": int(out[3]),
2050def getLiDARTriangleVertices_all(cloud_ptr: ctypes.POINTER(ULiDARcloud), tri_count: int):
2051 """Bulk-export every triangle's vertices (and source scan) in one call.
2053 Returns (xyz_flat, scan_ids) as numpy arrays: xyz_flat is (tri_count*9,)
2054 float32 laid out [v0x,v0y,v0z, v1x,v1y,v1z, v2x,v2y,v2z] per triangle, and
2055 scan_ids is (tri_count,) int32. Returns empty arrays when tri_count is 0.
2058 if not _LIDAR_FUNCTIONS_AVAILABLE:
2059 raise NotImplementedError("LiDAR functions not available")
2061 return np.empty((0,), dtype=np.float32), np.empty((0,), dtype=np.int32)
2063 xyz = np.empty((tri_count * 9,), dtype=np.float32)
2064 scan = np.empty((tri_count,), dtype=np.int32)
2065 helios_lib.getLiDARTriangleVertices_all(
2067 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
2068 scan.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
2074def lidarSetExternalTriangulation(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2075 xyz_flat, scan_ids, tri_count: int) -> None:
2076 """Replace the internal triangulation with an externally-supplied mesh.
2078 xyz_flat is (tri_count*9,) float32 laid out [v0x,v0y,v0z, v1x,v1y,v1z,
2079 v2x,v2y,v2z] per triangle (the same layout getLiDARTriangleVertices_all
2080 exports). scan_ids is (tri_count,) int32, one required source scan per
2081 triangle. No-op when tri_count is 0.
2084 if not _LIDAR_FUNCTIONS_AVAILABLE:
2085 raise NotImplementedError("LiDAR functions not available")
2089 xyz = np.ascontiguousarray(xyz_flat, dtype=np.float32)
2090 scan = np.ascontiguousarray(scan_ids, dtype=np.int32)
2091 if xyz.size != tri_count * 9:
2092 raise ValueError(f"xyz_flat has {xyz.size} floats, expected {tri_count * 9} (9 per triangle)")
2093 if scan.size != tri_count:
2094 raise ValueError(f"scan_ids has {scan.size} entries, expected {tri_count} (one per triangle)")
2096 helios_lib.lidarSetExternalTriangulation(
2098 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
2099 scan.ctypes.data_as(ctypes.POINTER(ctypes.c_int)),
2104def lidarDistanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), maxdistance: float) -> None:
2105 """Filter hit points by maximum distance"""
2106 if not _LIDAR_FUNCTIONS_AVAILABLE:
2107 raise NotImplementedError("LiDAR functions not available")
2108 helios_lib.lidarDistanceFilter(cloud_ptr, maxdistance)
2111def lidarReflectanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), minreflectance: float) -> None:
2112 """Filter hit points by minimum reflectance"""
2113 if not _LIDAR_FUNCTIONS_AVAILABLE:
2114 raise NotImplementedError("LiDAR functions not available")
2115 helios_lib.lidarReflectanceFilter(cloud_ptr, minreflectance)
2118def lidarFirstHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2119 """Keep only first return hit points"""
2120 if not _LIDAR_FUNCTIONS_AVAILABLE:
2121 raise NotImplementedError("LiDAR functions not available")
2122 helios_lib.lidarFirstHitFilter(cloud_ptr)
2125def lidarLastHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2126 """Keep only last return hit points"""
2127 if not _LIDAR_FUNCTIONS_AVAILABLE:
2128 raise NotImplementedError("LiDAR functions not available")
2129 helios_lib.lidarLastHitFilter(cloud_ptr)
2132def exportLiDARPointCloud(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str,
2133 write_header: bool = True) -> None:
2134 """Export point cloud to ASCII file (optionally with a '#'-prefixed column header)"""
2135 if not _LIDAR_FUNCTIONS_AVAILABLE:
2136 raise NotImplementedError("LiDAR functions not available")
2137 helios_lib.exportLiDARPointCloud(cloud_ptr, filename.encode('utf-8'), bool(write_header))
2140def exportLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2141 """Export per-voxel leaf-area sampling uncertainty to a self-describing ASCII file"""
2142 if not _LIDAR_FUNCTIONS_AVAILABLE:
2143 raise NotImplementedError("LiDAR functions not available")
2144 helios_lib.exportLiDARLeafAreaUncertainty(cloud_ptr, filename.encode('utf-8'))
2147def exportLiDARScans(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2148 """Export all scans to an XML metadata file plus one ASCII data file per scan"""
2149 if not _LIDAR_FUNCTIONS_AVAILABLE:
2150 raise NotImplementedError("LiDAR functions not available")
2151 helios_lib.exportLiDARScans(cloud_ptr, filename.encode('utf-8'))
2154def loadLiDARXML(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2155 """Load scan metadata from XML file"""
2156 if not _LIDAR_FUNCTIONS_AVAILABLE:
2157 raise NotImplementedError("LiDAR functions not available")
2158 helios_lib.loadLiDARXML(cloud_ptr, filename.encode('utf-8'))
2161def lidarDisableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2162 """Disable console output messages"""
2163 if not _LIDAR_FUNCTIONS_AVAILABLE:
2164 raise NotImplementedError("LiDAR functions not available")
2165 helios_lib.lidarDisableMessages(cloud_ptr)
2168def lidarEnableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2169 """Enable console output messages"""
2170 if not _LIDAR_FUNCTIONS_AVAILABLE:
2171 raise NotImplementedError("LiDAR functions not available")
2172 helios_lib.lidarEnableMessages(cloud_ptr)
2175def addLiDARGrid(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
2176 size: List[float], ndiv: List[int], rotation: float) -> None:
2177 """Add a rectangular grid of voxel cells"""
2178 if not _LIDAR_FUNCTIONS_AVAILABLE:
2179 raise NotImplementedError("LiDAR functions not available")
2181 if len(center) != 3:
2182 raise ValueError("Center must be a 3-element array [x, y, z]")
2184 raise ValueError("Size must be a 3-element array [x, y, z]")
2186 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
2188 center_array = (ctypes.c_float * 3)(*center)
2189 size_array = (ctypes.c_float * 3)(*size)
2190 ndiv_array = (ctypes.c_int * 3)(*ndiv)
2191 helios_lib.addLiDARGrid(cloud_ptr, center_array, size_array, ndiv_array, rotation)
2194def addLiDARGridTerrainFollowing(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
2195 size: List[float], ndiv: List[int], rotation: float,
2196 column_z_offsets: List[float]) -> None:
2197 """Add a rectangular grid of voxel cells with per-column vertical offsets"""
2198 if not _LIDAR_FUNCTIONS_AVAILABLE:
2199 raise NotImplementedError("LiDAR functions not available")
2201 if len(center) != 3:
2202 raise ValueError("Center must be a 3-element array [x, y, z]")
2204 raise ValueError("Size must be a 3-element array [x, y, z]")
2206 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
2208 expected = ndiv[0] * ndiv[1]
2209 if len(column_z_offsets) != expected:
2211 f"column_z_offsets must have length ndiv[0]*ndiv[1] = {expected}, "
2212 f"got {len(column_z_offsets)}"
2215 center_array = (ctypes.c_float * 3)(*center)
2216 size_array = (ctypes.c_float * 3)(*size)
2217 ndiv_array = (ctypes.c_int * 3)(*ndiv)
2218 offsets_array = (ctypes.c_float * len(column_z_offsets))(*column_z_offsets)
2219 helios_lib.addLiDARGridTerrainFollowing(cloud_ptr, center_array, size_array, ndiv_array,
2220 rotation, offsets_array, len(column_z_offsets))
2223def addLiDARGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
2224 size: List[float], rotation: float) -> None:
2225 """Add a single grid cell"""
2226 if not _LIDAR_FUNCTIONS_AVAILABLE:
2227 raise NotImplementedError("LiDAR functions not available")
2229 if len(center) != 3:
2230 raise ValueError("Center must be a 3-element array [x, y, z]")
2232 raise ValueError("Size must be a 3-element array [x, y, z]")
2234 center_array = (ctypes.c_float * 3)(*center)
2235 size_array = (ctypes.c_float * 3)(*size)
2236 helios_lib.addLiDARGridCell(cloud_ptr, center_array, size_array, rotation)
2239def getLiDARGridCellCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
2240 """Get number of grid cells"""
2241 if not _LIDAR_FUNCTIONS_AVAILABLE:
2242 raise NotImplementedError("LiDAR functions not available")
2243 return helios_lib.getLiDARGridCellCount(cloud_ptr)
2246def getLiDARCellCenter(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
2247 """Get center position of a grid cell"""
2248 if not _LIDAR_FUNCTIONS_AVAILABLE:
2249 raise NotImplementedError("LiDAR functions not available")
2251 center = (ctypes.c_float * 3)()
2252 helios_lib.getLiDARCellCenter(cloud_ptr, index, center)
2256def getLiDARCellCenterUnrotated(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
2257 """Get the UNROTATED (axis-aligned lattice) center position of a grid cell"""
2258 if not _LIDAR_FUNCTIONS_AVAILABLE:
2259 raise NotImplementedError("LiDAR functions not available")
2261 center = (ctypes.c_float * 3)()
2262 helios_lib.getLiDARCellCenterUnrotated(cloud_ptr, index, center)
2266def getLiDARCellSize(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
2267 """Get size of a grid cell"""
2268 if not _LIDAR_FUNCTIONS_AVAILABLE:
2269 raise NotImplementedError("LiDAR functions not available")
2271 size = (ctypes.c_float * 3)()
2272 helios_lib.getLiDARCellSize(cloud_ptr, index, size)
2276def getLiDARCellRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2277 """Get azimuthal rotation of a grid cell about the z-axis, in degrees"""
2278 if not _LIDAR_FUNCTIONS_AVAILABLE:
2279 raise NotImplementedError("LiDAR functions not available")
2280 return helios_lib.getLiDARCellRotation(cloud_ptr, index)
2283def getLiDARCellLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2284 """Get leaf area of a grid cell"""
2285 if not _LIDAR_FUNCTIONS_AVAILABLE:
2286 raise NotImplementedError("LiDAR functions not available")
2287 return helios_lib.getLiDARCellLeafArea(cloud_ptr, index)
2290def getLiDARCellLeafAreaDensity(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2291 """Get leaf area density of a grid cell"""
2292 if not _LIDAR_FUNCTIONS_AVAILABLE:
2293 raise NotImplementedError("LiDAR functions not available")
2294 return helios_lib.getLiDARCellLeafAreaDensity(cloud_ptr, index)
2297def calculateLiDARHitGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2298 """Calculate hit point grid cell assignments"""
2299 if not _LIDAR_FUNCTIONS_AVAILABLE:
2300 raise NotImplementedError("LiDAR functions not available")
2301 helios_lib.calculateLiDARHitGridCell(cloud_ptr)
2304def syntheticLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2305 context_ptr: ctypes.POINTER(UContext)) -> None:
2306 """Perform synthetic discrete-return LiDAR scan"""
2307 if not _LIDAR_FUNCTIONS_AVAILABLE:
2308 raise NotImplementedError("LiDAR functions not available")
2309 helios_lib.syntheticLiDARScan(cloud_ptr, context_ptr)
2312def syntheticLiDARScanAppend(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2313 context_ptr: ctypes.POINTER(UContext),
2314 append: bool) -> None:
2315 """Perform synthetic scan with append control"""
2316 if not _LIDAR_FUNCTIONS_AVAILABLE:
2317 raise NotImplementedError("LiDAR functions not available")
2318 helios_lib.syntheticLiDARScanAppend(cloud_ptr, context_ptr, append)
2321def setLiDARCancelFlag(cloud_ptr: ctypes.POINTER(ULiDARcloud), flag) -> None:
2322 """Register an external cancellation flag polled during syntheticScan.
2324 `flag` is a ctypes.c_int (pass by ref) that, when set non-zero from another
2325 thread, aborts the scan's ray loop mid-trace. Pass None to clear."""
2326 if not _LIDAR_FUNCTIONS_AVAILABLE:
2327 raise NotImplementedError("LiDAR functions not available")
2328 ptr = ctypes.byref(flag) if flag is not None else None
2329 helios_lib.setLiDARCancelFlag(cloud_ptr, ptr)
2332def setLiDARSyntheticScanMemoryBudget(cloud_ptr: ctypes.POINTER(ULiDARcloud), bytes: int) -> None:
2333 """Set the soft memory budget (bytes) for syntheticScan's transient trace buffers.
2335 Bounds the live ray-tracing scratch buffers so large scans are chunked rather
2336 than traced in one OOM-prone batch. `bytes` must be > 0; if never set, Helios
2337 uses an automatic path-dependent default (4 GiB CPU / 8 GiB GPU)."""
2338 if not _LIDAR_FUNCTIONS_AVAILABLE:
2339 raise NotImplementedError("LiDAR functions not available")
2340 helios_lib.setLiDARSyntheticScanMemoryBudget(cloud_ptr, ctypes.c_size_t(bytes))
2343def getLiDARSyntheticScanMemoryBudget(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
2344 """Get the soft memory budget (bytes) for syntheticScan's transient buffers.
2346 Returns the explicitly configured budget, or 0 if using the automatic
2347 path-dependent default (4 GiB CPU / 8 GiB GPU)."""
2348 if not _LIDAR_FUNCTIONS_AVAILABLE:
2349 raise NotImplementedError("LiDAR functions not available")
2350 return int(helios_lib.getLiDARSyntheticScanMemoryBudget(cloud_ptr))
2353def setLiDARSyntheticScanProgressPointer(cloud_ptr: ctypes.POINTER(ULiDARcloud), ptr) -> None:
2354 """Register an external per-scan progress counter polled during syntheticScan.
2356 `ptr` is a ctypes.c_int (pass by ref) into which syntheticScan writes the 0-based
2357 index of the scan currently being ray-traced, set to getScanCount() when finished.
2358 Pass None to clear."""
2359 if not _LIDAR_FUNCTIONS_AVAILABLE:
2360 raise NotImplementedError("LiDAR functions not available")
2361 p = ctypes.byref(ptr) if ptr is not None else None
2362 helios_lib.setLiDARSyntheticScanProgressPointer(cloud_ptr, p)
2365def setLiDARProgressCallback(cloud_ptr: ctypes.POINTER(ULiDARcloud), callback) -> None:
2366 """Register a progress callback fired with (progress_fraction, message) during syntheticScan.
2368 `callback` must be a LiDARProgressCallback ctypes instance (or None to clear). The
2369 caller is responsible for keeping the LiDARProgressCallback alive for as long as it is
2370 registered (ctypes does not hold a reference)."""
2371 if not _LIDAR_FUNCTIONS_AVAILABLE:
2372 raise NotImplementedError("LiDAR functions not available")
2373 # A bare None is NOT accepted for a CFUNCTYPE argtype (ctypes wants a CFunctionType instance);
2374 # cast None to the callback type to pass a null function pointer that clears the callback.
2375 cb = callback if callback is not None else ctypes.cast(None, LiDARProgressCallback)
2376 helios_lib.setLiDARProgressCallback(cloud_ptr, cb)
2379def syntheticLiDARScanDiscrete(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2380 context_ptr: ctypes.POINTER(UContext),
2381 scan_grid_only: bool, record_misses: bool, append: bool) -> None:
2382 """Perform discrete-return synthetic scan with miss-recording control"""
2383 if not _LIDAR_FUNCTIONS_AVAILABLE:
2384 raise NotImplementedError("LiDAR functions not available")
2385 helios_lib.syntheticLiDARScanDiscrete(cloud_ptr, context_ptr, scan_grid_only, record_misses, append)
2388def syntheticLiDARScanWaveform(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2389 context_ptr: ctypes.POINTER(UContext),
2390 rays_per_pulse: int,
2391 pulse_distance_threshold: float) -> None:
2392 """Perform synthetic full-waveform LiDAR scan"""
2393 if not _LIDAR_FUNCTIONS_AVAILABLE:
2394 raise NotImplementedError("LiDAR functions not available")
2395 helios_lib.syntheticLiDARScanWaveform(cloud_ptr, context_ptr, rays_per_pulse, pulse_distance_threshold)
2398def syntheticLiDARScanFull(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2399 context_ptr: ctypes.POINTER(UContext),
2400 rays_per_pulse: int,
2401 pulse_distance_threshold: float,
2402 scan_grid_only: bool,
2403 record_misses: bool,
2404 append: bool) -> None:
2405 """Perform synthetic scan with full control"""
2406 if not _LIDAR_FUNCTIONS_AVAILABLE:
2407 raise NotImplementedError("LiDAR functions not available")
2408 helios_lib.syntheticLiDARScanFull(cloud_ptr, context_ptr, rays_per_pulse,
2409 pulse_distance_threshold, scan_grid_only,
2410 record_misses, append)
2413def syntheticLiDARScanReturnMode(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2414 context_ptr: ctypes.POINTER(UContext),
2415 rays_per_pulse: int,
2416 pulse_distance_threshold: float,
2418 scan_grid_only: bool = False,
2419 record_misses: bool = False,
2420 append: bool = True) -> None:
2421 """Perform an analytic-waveform synthetic scan with an explicit return mode.
2423 return_mode is 0 (multi) or 1 (single); it overrides each scan's stored returnMode for this
2424 call only. In single mode up to each scan's maxReturns returns per pulse are reported.
2426 if not _LIDAR_FUNCTIONS_AVAILABLE:
2427 raise NotImplementedError("LiDAR functions not available")
2428 helios_lib.syntheticLiDARScanReturnMode(cloud_ptr, context_ptr, rays_per_pulse,
2429 pulse_distance_threshold, return_mode,
2430 scan_grid_only, record_misses, append)
2433def calculateLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2434 context_ptr: ctypes.POINTER(UContext)) -> None:
2435 """Calculate leaf area for each grid cell"""
2436 if not _LIDAR_FUNCTIONS_AVAILABLE:
2437 raise NotImplementedError("LiDAR functions not available")
2438 helios_lib.calculateLiDARLeafArea(cloud_ptr, context_ptr)
2441def calculateLiDARLeafAreaMinHits(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2442 context_ptr: ctypes.POINTER(UContext),
2443 min_voxel_hits: int) -> None:
2444 """Calculate leaf area with minimum voxel hits threshold"""
2445 if not _LIDAR_FUNCTIONS_AVAILABLE:
2446 raise NotImplementedError("LiDAR functions not available")
2447 helios_lib.calculateLiDARLeafAreaMinHits(cloud_ptr, context_ptr, min_voxel_hits)
2450def calculateLiDARLeafAreaUncertainty(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2451 context_ptr: ctypes.POINTER(UContext),
2452 min_voxel_hits: int, element_width: float) -> None:
2453 """Calculate leaf area plus per-voxel sampling uncertainty (Pimont et al. 2018)"""
2454 if not _LIDAR_FUNCTIONS_AVAILABLE:
2455 raise NotImplementedError("LiDAR functions not available")
2456 helios_lib.calculateLiDARLeafAreaUncertainty(
2457 cloud_ptr, context_ptr, min_voxel_hits, float(element_width))
2460def calculateLiDARLeafAreaGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2461 context_ptr: ctypes.POINTER(UContext),
2462 Gtheta: float, min_voxel_hits: int, element_width: float) -> None:
2463 """Calculate leaf area using a caller-supplied G(theta), without requiring triangulation.
2465 Suitable for moving-platform scans (which cannot be triangulated). Gtheta must be in (0,1]
2466 (0.5 = spherical leaf-angle distribution).
2468 if not _LIDAR_FUNCTIONS_AVAILABLE:
2469 raise NotImplementedError("LiDAR functions not available")
2470 helios_lib.calculateLiDARLeafAreaGtheta(
2471 cloud_ptr, context_ptr, float(Gtheta), min_voxel_hits, float(element_width))
2474def getLiDARCellBeamCount(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> int:
2475 """Get the beam count N entering a grid cell (-1 if calculateLeafArea not run)."""
2476 if not _LIDAR_FUNCTIONS_AVAILABLE:
2477 raise NotImplementedError("LiDAR functions not available")
2478 return helios_lib.getLiDARCellBeamCount(cloud_ptr, index)
2481def getLiDARCellRelativeDensityIndex(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2482 """Get the relative density index I_rdi for a grid cell."""
2483 if not _LIDAR_FUNCTIONS_AVAILABLE:
2484 raise NotImplementedError("LiDAR functions not available")
2485 return helios_lib.getLiDARCellRelativeDensityIndex(cloud_ptr, index)
2488def getLiDARCellMeanPathLength(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2489 """Get the mean beam path length (m) through a grid cell."""
2490 if not _LIDAR_FUNCTIONS_AVAILABLE:
2491 raise NotImplementedError("LiDAR functions not available")
2492 return helios_lib.getLiDARCellMeanPathLength(cloud_ptr, index)
2495def getLiDARCellLADVariance(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2496 """Get the per-voxel LAD sampling variance (-1 if unavailable)."""
2497 if not _LIDAR_FUNCTIONS_AVAILABLE:
2498 raise NotImplementedError("LiDAR functions not available")
2499 return helios_lib.getLiDARCellLADVariance(cloud_ptr, index)
2502def getLiDARCellLeafAreaConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int,
2503 confidence_level: float = 0.95):
2504 """Single-voxel leaf-area confidence interval.
2506 Returns (valid, lower, upper). ``valid`` is False when the interval is gated
2507 out by the Pimont validity envelope (the bounds are then not trustworthy).
2509 if not _LIDAR_FUNCTIONS_AVAILABLE:
2510 raise NotImplementedError("LiDAR functions not available")
2511 out = (ctypes.c_float * 2)()
2512 valid = helios_lib.getLiDARCellLeafAreaConfidenceInterval(
2513 cloud_ptr, index, float(confidence_level), out)
2514 return bool(valid), float(out[0]), float(out[1])
2517def getLiDARGroupLADConfidenceInterval(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2518 indices: List[int], confidence_level: float = 0.95):
2519 """Group-scale LAD confidence interval over a set of cells (recommended path).
2521 Returns (valid, mean_lad, lower, upper).
2523 if not _LIDAR_FUNCTIONS_AVAILABLE:
2524 raise NotImplementedError("LiDAR functions not available")
2526 raise ValueError("indices must contain at least one cell index")
2528 idx_array = (ctypes.c_uint * n)(*[int(i) for i in indices])
2529 out = (ctypes.c_float * 3)()
2530 valid = helios_lib.getLiDARGroupLADConfidenceInterval(
2531 cloud_ptr, idx_array, n, float(confidence_level), out)
2532 return bool(valid), float(out[0]), float(out[1]), float(out[2])
2535def exportLiDARTriangleNormals(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2536 """Export triangle normal vectors"""
2537 if not _LIDAR_FUNCTIONS_AVAILABLE:
2538 raise NotImplementedError("LiDAR functions not available")
2539 helios_lib.exportLiDARTriangleNormals(cloud_ptr, filename.encode('utf-8'))
2542def exportLiDARTriangleAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2543 """Export triangle areas"""
2544 if not _LIDAR_FUNCTIONS_AVAILABLE:
2545 raise NotImplementedError("LiDAR functions not available")
2546 helios_lib.exportLiDARTriangleAreas(cloud_ptr, filename.encode('utf-8'))
2549def exportLiDARLeafAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2550 """Export leaf areas for each grid cell"""
2551 if not _LIDAR_FUNCTIONS_AVAILABLE:
2552 raise NotImplementedError("LiDAR functions not available")
2553 helios_lib.exportLiDARLeafAreas(cloud_ptr, filename.encode('utf-8'))
2556def exportLiDARLeafAreaDensities(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2557 """Export leaf area densities for each grid cell"""
2558 if not _LIDAR_FUNCTIONS_AVAILABLE:
2559 raise NotImplementedError("LiDAR functions not available")
2560 helios_lib.exportLiDARLeafAreaDensities(cloud_ptr, filename.encode('utf-8'))
2563def exportLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
2564 """Export G(theta) values for each grid cell"""
2565 if not _LIDAR_FUNCTIONS_AVAILABLE:
2566 raise NotImplementedError("LiDAR functions not available")
2567 helios_lib.exportLiDARGtheta(cloud_ptr, filename.encode('utf-8'))
2570def getLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
2571 """Get G(theta) value for a grid cell"""
2572 if not _LIDAR_FUNCTIONS_AVAILABLE:
2573 raise NotImplementedError("LiDAR functions not available")
2574 return helios_lib.getLiDARCellGtheta(cloud_ptr, index)
2577def setLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), Gtheta: float, index: int) -> None:
2578 """Set G(theta) value for a grid cell"""
2579 if not _LIDAR_FUNCTIONS_AVAILABLE:
2580 raise NotImplementedError("LiDAR functions not available")
2581 helios_lib.setLiDARCellGtheta(cloud_ptr, Gtheta, index)
2584def gapfillLiDARMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2585 """Gapfill sky/miss points"""
2586 if not _LIDAR_FUNCTIONS_AVAILABLE:
2587 raise NotImplementedError("LiDAR functions not available")
2588 helios_lib.gapfillLiDARMisses(cloud_ptr)
2591def calculateSyntheticLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2592 context_ptr: ctypes.POINTER(UContext)) -> None:
2593 """Calculate synthetic leaf area for validation"""
2594 if not _LIDAR_FUNCTIONS_AVAILABLE:
2595 raise NotImplementedError("LiDAR functions not available")
2596 helios_lib.calculateSyntheticLiDARLeafArea(cloud_ptr, context_ptr)
2599def calculateSyntheticLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2600 context_ptr: ctypes.POINTER(UContext)) -> None:
2601 """Calculate synthetic G(theta) for validation"""
2602 if not _LIDAR_FUNCTIONS_AVAILABLE:
2603 raise NotImplementedError("LiDAR functions not available")
2604 helios_lib.calculateSyntheticLiDARGtheta(cloud_ptr, context_ptr)
2607def addLiDARTrianglesToContext(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2608 context_ptr: ctypes.POINTER(UContext)) -> None:
2609 """Add triangulated mesh to Context as primitives"""
2610 if not _LIDAR_FUNCTIONS_AVAILABLE:
2611 raise NotImplementedError("LiDAR functions not available")
2612 helios_lib.addLiDARTrianglesToContext(cloud_ptr, context_ptr)
2615def initializeLiDARCollisionDetection(cloud_ptr: ctypes.POINTER(ULiDARcloud),
2616 context_ptr: ctypes.POINTER(UContext)) -> None:
2617 """Initialize CollisionDetection for ray tracing"""
2618 if not _LIDAR_FUNCTIONS_AVAILABLE:
2619 raise NotImplementedError("LiDAR functions not available")
2620 helios_lib.initializeLiDARCollisionDetection(cloud_ptr, context_ptr)
2623def enableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2624 """Enable GPU acceleration for collision detection"""
2625 if not _LIDAR_FUNCTIONS_AVAILABLE:
2626 raise NotImplementedError("LiDAR functions not available")
2627 helios_lib.enableLiDARCDGPUAcceleration(cloud_ptr)
2630def disableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
2631 """Disable GPU acceleration for collision detection"""
2632 if not _LIDAR_FUNCTIONS_AVAILABLE:
2633 raise NotImplementedError("LiDAR functions not available")
2634 helios_lib.disableLiDARCDGPUAcceleration(cloud_ptr)
2637def isLiDARGPUAvailable(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
2638 """Return True if a CUDA-capable GPU is available for collision-detection acceleration."""
2639 if not _LIDAR_FUNCTIONS_AVAILABLE:
2640 raise NotImplementedError("LiDAR functions not available")
2641 return bool(helios_lib.isLiDARGPUAvailable(cloud_ptr))
2644def isLiDARGPUAccelerationEnabled(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> bool:
2645 """Return True if GPU acceleration is currently enabled for collision detection."""
2646 if not _LIDAR_FUNCTIONS_AVAILABLE:
2647 raise NotImplementedError("LiDAR functions not available")
2648 return bool(helios_lib.isLiDARGPUAccelerationEnabled(cloud_ptr))
2651# Mock mode for development
2652if not _LIDAR_FUNCTIONS_AVAILABLE:
2653 def mock_createLiDARcloud(*args, **kwargs):
2655 "Mock mode: LiDAR not available. "
2656 "This would create a LiDAR cloud instance with native library."
2659 def mock_lidar_operation(*args, **kwargs):
2661 "Mock mode: LiDAR operation not available. "
2662 "This would execute LiDAR operations with native library."
2665 # Replace functions with mocks for development
2666 createLiDARcloud = mock_createLiDARcloud
2667 addLiDARScan = mock_lidar_operation
2668 addLiDARHitPoint = mock_lidar_operation
2671# ---------------------------------------------------------------------------
2672# helios-core 1.3.84 additions
2673# ---------------------------------------------------------------------------
2675def _require_lidar_1384() -> None:
2676 """Raise if the native library predates the helios-core 1.3.84 LiDAR additions."""
2677 if not _LIDAR_FUNCTIONS_AVAILABLE or not _LIDAR_1384_AVAILABLE:
2679 "This LiDAR function is not available in the current native library. "
2680 "It requires helios-core v1.3.84 or newer; rebuild with "
2681 "'build_scripts/build_helios --clean'."
2685def gapfillLiDARMissesCount(cloud_ptr) -> int:
2686 """Gapfill every scan, returning only the number of points added."""
2687 _require_lidar_1384()
2688 return int(helios_lib.gapfillLiDARMissesCount(cloud_ptr))
2691def gapfillLiDARMissesCountScan(cloud_ptr, scanID: int, gapfill_grid_only: bool,
2692 add_flags: bool) -> int:
2693 """Gapfill one scan, returning only the number of points added."""
2694 _require_lidar_1384()
2695 return int(helios_lib.gapfillLiDARMissesCountScan(
2696 cloud_ptr, ctypes.c_uint(int(scanID)),
2697 ctypes.c_bool(bool(gapfill_grid_only)), ctypes.c_bool(bool(add_flags))
2701def getLiDARVirtualMissCount(cloud_ptr) -> int:
2702 """Number of gap-filled misses currently held in virtualized form."""
2703 _require_lidar_1384()
2704 return int(helios_lib.getLiDARVirtualMissCount(cloud_ptr))
2707_CROPPED_RETURN_STATS_FIELDS = (
2708 "beams_with_hidden_returns", "hidden_before", "hidden_after",
2709 "hidden_ambiguous", "beams_ambiguous", "standins_ignored",
2713def getLiDARCroppedReturnStats(cloud_ptr) -> dict:
2714 """Returns the last leaf-area inversion inferred from target_count, as a dict of counts."""
2715 if not _LIDAR_FUNCTIONS_AVAILABLE or not _LIDAR_CROPPED_RETURNS_AVAILABLE:
2717 "getLiDARCroppedReturnStats is not available in the current native library. "
2718 "It requires a helios-core newer than v1.3.84; rebuild with "
2719 "'build_scripts/build_helios --clean'."
2721 out = (ctypes.c_ulonglong * len(_CROPPED_RETURN_STATS_FIELDS))()
2722 helios_lib.getLiDARCroppedReturnStats(cloud_ptr, out)
2723 return {name: int(out[i]) for i, name in enumerate(_CROPPED_RETURN_STATS_FIELDS)}
2726def hasLiDARVirtualMisses(cloud_ptr) -> bool:
2727 """Whether any gap-filled miss is currently held in virtualized form."""
2728 _require_lidar_1384()
2729 return bool(helios_lib.hasLiDARVirtualMisses(cloud_ptr))
2732def materializeLiDARMisses(cloud_ptr) -> None:
2733 """Convert every virtualized gap-filled miss into a stored hit point."""
2734 _require_lidar_1384()
2735 helios_lib.materializeLiDARMisses(cloud_ptr)
2738def getLiDARScanGridDirection(cloud_ptr, scanID: int, row: int, column: int):
2739 """Beam direction at a scan-grid cell as (radius, elevation, azimuth)."""
2740 _require_lidar_1384()
2741 out = (ctypes.c_float * 3)()
2742 helios_lib.getLiDARScanGridDirection(
2743 cloud_ptr, ctypes.c_uint(int(scanID)), ctypes.c_int(int(row)),
2744 ctypes.c_int(int(column)), out
2746 return (float(out[0]), float(out[1]), float(out[2]))
2749def getLiDARHitXYZColumn(cloud_ptr, count: int):
2750 """Read every hit's position in index order in one pass."""
2751 _require_lidar_1384()
2754 buf = (ctypes.c_float * (3 * count))()
2755 helios_lib.getLiDARHitXYZColumn(cloud_ptr, buf, ctypes.c_uint(int(count)))
2756 return [(float(buf[3*i]), float(buf[3*i+1]), float(buf[3*i+2])) for i in range(count)]
2759def getLiDARHitScanIDColumn(cloud_ptr, count: int):
2760 """Read every hit's scan ID in index order in one pass."""
2761 _require_lidar_1384()
2764 buf = (ctypes.c_int * count)()
2765 helios_lib.getLiDARHitScanIDColumn(cloud_ptr, buf, ctypes.c_uint(int(count)))
2766 return [int(x) for x in buf]
2769def estimateLiDARHitPointMemory(cloud_ptr, hit_count: int) -> int:
2770 """Estimated resident bytes for a cloud of ``hit_count`` points."""
2771 _require_lidar_1384()
2772 return int(helios_lib.estimateLiDARHitPointMemory(cloud_ptr, ctypes.c_ulonglong(int(hit_count))))
2775def setLiDARMaxHitPoints(cloud_ptr, max_hits: int) -> None:
2776 """Set the cap on stored hit points (0 disables the check)."""
2777 _require_lidar_1384()
2778 helios_lib.setLiDARMaxHitPoints(cloud_ptr, ctypes.c_ulonglong(int(max_hits)))
2781def getLiDARMaxHitPoints(cloud_ptr) -> int:
2782 """Current cap on stored hit points."""
2783 _require_lidar_1384()
2784 return int(helios_lib.getLiDARMaxHitPoints(cloud_ptr))
2787def getLiDARDefaultMaxHitPoints() -> int:
2788 """Default cap on the number of stored hit points in a cloud."""
2789 _require_lidar_1384()
2790 return int(helios_lib.getLiDARDefaultMaxHitPoints())
2793def reserveLiDARHitPoints(cloud_ptr, hit_count: int) -> None:
2794 """Reserve capacity for hit points and every scalar-data column at once."""
2795 _require_lidar_1384()
2796 helios_lib.reserveLiDARHitPoints(cloud_ptr, ctypes.c_ulonglong(int(hit_count)))
2799def setLiDARExactPathLengths(cloud_ptr, exact: bool) -> None:
2800 """Keep every beam path length exactly, instead of binning them."""
2801 _require_lidar_1384()
2802 helios_lib.setLiDARExactPathLengths(cloud_ptr, ctypes.c_bool(bool(exact)))
2805def getLiDARExactPathLengths(cloud_ptr) -> bool:
2806 """Whether path lengths are accumulated exactly."""
2807 _require_lidar_1384()
2808 return bool(helios_lib.getLiDARExactPathLengths(cloud_ptr))
2811# ---------------------------------------------------------------------------
2812# helios-core 1.3.85 additions
2813# ---------------------------------------------------------------------------
2815def _require_lidar_1385() -> None:
2816 """Raise if the native library predates the helios-core 1.3.85 LiDAR additions."""
2817 if not _LIDAR_FUNCTIONS_AVAILABLE or not _LIDAR_1385_AVAILABLE:
2819 "This LiDAR function is not available in the current native library. "
2820 "It requires helios-core v1.3.85 or newer; rebuild with "
2821 "'build_scripts/build_helios --clean'."
2825def lidarIsMultiReturnData(cloud_ptr) -> bool:
2826 """Whether any hit has target_count > 1 (the switch triangulateHitPoints() branches on)."""
2827 _require_lidar_1385()
2828 return bool(helios_lib.lidarIsMultiReturnData(cloud_ptr))
2831def calculateLiDARLeafAreaGthetaPerCell(cloud_ptr, context_ptr, Gtheta_per_cell: List[float],
2832 min_voxel_hits: int, element_width: float) -> None:
2833 """Calculate leaf area with one caller-supplied G(theta) per grid cell, without triangulation.
2835 Gtheta_per_cell must have one entry per grid cell, in grid-cell order, every value in (0,1].
2837 _require_lidar_1385()
2838 values = [float(g) for g in Gtheta_per_cell]
2840 raise ValueError("Gtheta_per_cell must contain at least one value")
2841 arr = (ctypes.c_float * len(values))(*values)
2842 helios_lib.calculateLiDARLeafAreaGthetaPerCell(
2843 cloud_ptr, context_ptr, arr, ctypes.c_uint(len(values)),
2844 ctypes.c_int(int(min_voxel_hits)), ctypes.c_float(float(element_width)))
2847# ---------------------------------------------------------------------------
2848# helios-core 1.3.86 additions
2849# ---------------------------------------------------------------------------
2851def _require_lidar_1386() -> None:
2852 """Raise if the native library predates the helios-core 1.3.86 LiDAR additions."""
2853 if not _LIDAR_FUNCTIONS_AVAILABLE or not _LIDAR_1386_AVAILABLE:
2855 "This LiDAR function is not available in the current native library. "
2856 "It requires helios-core v1.3.86 or newer; rebuild with "
2857 "'build_scripts/build_helios --clean'."
2861def createLiDARHitDataColumn(cloud_ptr, label: str, type_code: int) -> None:
2862 """Create a per-hit scalar-data column with an explicit storage type.
2864 type_code is the HitDataType ABI integer: 0=FLOAT64, 1=FLOAT32, 2=INT32.
2866 _require_lidar_1386()
2867 helios_lib.createLiDARHitDataColumn(cloud_ptr, label.encode('utf-8'), ctypes.c_int(int(type_code)))
2870def getLiDARHitDataType(cloud_ptr, label: str) -> int:
2871 """Storage type of an existing column as the HitDataType ABI integer (raises if unknown)."""
2872 _require_lidar_1386()
2873 return int(helios_lib.getLiDARHitDataType(cloud_ptr, label.encode('utf-8')))
2876def getLiDARHitDataColumnF32(cloud_ptr, label: str, n: int,
2877 absent_value: float = -9999.0) -> List[float]:
2878 """Bulk-export a named scalar column as 32-bit floats (no widening of a FLOAT32 column)."""
2879 _require_lidar_1386()
2882 out = (ctypes.c_float * n)()
2883 helios_lib.getLiDARHitDataColumnF32(cloud_ptr, label.encode('utf-8'), out,
2884 ctypes.c_uint(int(n)), ctypes.c_float(float(absent_value)))
2885 return [float(x) for x in out]
2888def getLiDARHitDataColumnF32_np(cloud_ptr, label: str, n: int, absent_value: float = -9999.0):
2889 """Bulk-export a named scalar column as an (n,) float32 numpy array."""
2891 _require_lidar_1386()
2893 return np.empty((0,), np.float32)
2894 out = (ctypes.c_float * n)()
2895 helios_lib.getLiDARHitDataColumnF32(cloud_ptr, label.encode('utf-8'), out,
2896 ctypes.c_uint(int(n)), ctypes.c_float(float(absent_value)))
2897 return np.frombuffer(out, dtype=np.float32, count=n).copy()
2900def getLiDARHitDataColumnI32(cloud_ptr, label: str, n: int,
2901 absent_value: int = -9999) -> List[int]:
2902 """Bulk-export a named scalar column as 32-bit ints.
2904 Raises if any value is not a 32-bit integer; read such a label as doubles instead.
2906 _require_lidar_1386()
2909 out = (ctypes.c_int * n)()
2910 helios_lib.getLiDARHitDataColumnI32(cloud_ptr, label.encode('utf-8'), out,
2911 ctypes.c_uint(int(n)), ctypes.c_int(int(absent_value)))
2912 return [int(x) for x in out]
2915def getLiDARHitDataColumnI32_np(cloud_ptr, label: str, n: int, absent_value: int = -9999):
2916 """Bulk-export a named scalar column as an (n,) int32 numpy array."""
2918 _require_lidar_1386()
2920 return np.empty((0,), np.int32)
2921 out = (ctypes.c_int * n)()
2922 helios_lib.getLiDARHitDataColumnI32(cloud_ptr, label.encode('utf-8'), out,
2923 ctypes.c_uint(int(n)), ctypes.c_int(int(absent_value)))
2924 return np.frombuffer(out, dtype=np.int32, count=n).copy()
2927def addLiDARHitPointsBulk(cloud_ptr, scanID: int, xyz, dir_spherical=None,
2928 labels: Optional[List[str]] = None, values=None) -> None:
2929 """Bulk-ingest hit points through the native addHitPoints path.
2931 xyz is an (n, 3) float64 array. dir_spherical is an (n, 3) float32 array of
2932 (radius, elevation, azimuth), or None to derive each direction from the point's position
2933 relative to the scan origin. values is (n, len(labels)) float64.
2936 _require_lidar_1386()
2938 xyz = np.ascontiguousarray(xyz, dtype=np.float64)
2939 if xyz.ndim != 2 or xyz.shape[1] != 3:
2940 raise ValueError("xyz must have shape (N, 3)")
2944 if dir_spherical is not None:
2945 dir_spherical = np.ascontiguousarray(dir_spherical, dtype=np.float32)
2946 if dir_spherical.ndim != 2 or dir_spherical.shape[1] != 3:
2947 raise ValueError("dir_spherical must have shape (N, 3)")
2948 if dir_spherical.shape[0] != n:
2949 raise ValueError("dir_spherical must have the same number of rows as xyz")
2950 dir_ptr = dir_spherical.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
2952 labels = labels or []
2953 nLabels = len(labels)
2956 encoded = [s.encode('utf-8') for s in labels]
2957 label_ptr = (ctypes.c_char_p * nLabels)(*encoded)
2962 raise ValueError("values is required when labels are supplied")
2963 values = np.ascontiguousarray(values, dtype=np.float64)
2964 if values.ndim != 2 or values.shape != (n, nLabels):
2965 raise ValueError(f"values must have shape (N, len(labels)) == ({n}, {nLabels})")
2966 values_ptr = values.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
2968 helios_lib.addLiDARHitPointsBulk(
2969 cloud_ptr, ctypes.c_uint(int(scanID)), ctypes.c_size_t(int(n)),
2970 xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), dir_ptr,
2971 label_ptr, ctypes.c_uint(nLabels), values_ptr)
2974def deleteLiDARHitPoints(cloud_ptr, first: int, count: int) -> None:
2975 """Delete hits [first, first+count), preserving the order of the rest."""
2976 _require_lidar_1386()
2977 helios_lib.deleteLiDARHitPoints(cloud_ptr, ctypes.c_size_t(int(first)),
2978 ctypes.c_size_t(int(count)))
2981def setLiDARTriangulationSink(cloud_ptr, callback) -> None:
2982 """Register a per-scan triangulation sink.
2984 `callback` must be a LiDARTriangulationSinkCallback instance (or None to clear). The caller
2985 is responsible for keeping it alive for as long as native code holds it.
2987 _require_lidar_1386()
2988 cb = callback if callback is not None else ctypes.cast(None, LiDARTriangulationSinkCallback)
2989 helios_lib.setLiDARTriangulationSink(cloud_ptr, cb, None)
2992def setLiDARSyntheticScanHitSink(cloud_ptr, callback) -> None:
2993 """Register a synthetic-scan chunk sink.
2995 `callback` must be a LiDARSyntheticScanHitSinkCallback instance (or None to clear). The
2996 caller is responsible for keeping it alive for as long as native code holds it.
2998 _require_lidar_1386()
2999 cb = callback if callback is not None else ctypes.cast(None, LiDARSyntheticScanHitSinkCallback)
3000 helios_lib.setLiDARSyntheticScanHitSink(cloud_ptr, cb, None)
3003def getLiDARScanHitCount(cloud_ptr, scanID: int) -> int:
3004 """Number of hit points (stored returns plus virtualized misses) belonging to one scan."""
3005 _require_lidar_1386()
3006 return int(helios_lib.getLiDARScanHitCount(cloud_ptr, ctypes.c_uint(int(scanID))))
3009def getLiDARScanHitIndices(cloud_ptr, scanID: int, n: int) -> List[int]:
3010 """Global hit indices of one scan, in the order the per-scan readers use."""
3011 _require_lidar_1386()
3014 out = (ctypes.c_uint * n)()
3015 helios_lib.getLiDARScanHitIndices(cloud_ptr, ctypes.c_uint(int(scanID)), out,
3016 ctypes.c_uint(int(n)))
3017 return [int(x) for x in out]
3020def getLiDARScanHitXYZColumn(cloud_ptr, scanID: int, n: int):
3021 """Read one scan's hit positions in a single pass, as a list of (x, y, z) tuples."""
3022 _require_lidar_1386()
3025 buf = (ctypes.c_float * (3 * n))()
3026 helios_lib.getLiDARScanHitXYZColumn(cloud_ptr, ctypes.c_uint(int(scanID)), buf,
3027 ctypes.c_uint(int(n)))
3028 return [(float(buf[3*i]), float(buf[3*i+1]), float(buf[3*i+2])) for i in range(n)]
3031def getLiDARScanHitDataColumn(cloud_ptr, scanID: int, label: str, n: int,
3032 absent_value: float = -9999.0) -> List[float]:
3033 """Read one scan's values of a scalar-data label as doubles."""
3034 _require_lidar_1386()
3037 out = (ctypes.c_double * n)()
3038 helios_lib.getLiDARScanHitDataColumn(cloud_ptr, ctypes.c_uint(int(scanID)),
3039 label.encode('utf-8'), out, ctypes.c_uint(int(n)),
3040 ctypes.c_double(float(absent_value)))
3044def getLiDARScanHitDataColumnF32(cloud_ptr, scanID: int, label: str, n: int,
3045 absent_value: float = -9999.0) -> List[float]:
3046 """Read one scan's values of a scalar-data label as 32-bit floats."""
3047 _require_lidar_1386()
3050 out = (ctypes.c_float * n)()
3051 helios_lib.getLiDARScanHitDataColumnF32(cloud_ptr, ctypes.c_uint(int(scanID)),
3052 label.encode('utf-8'), out, ctypes.c_uint(int(n)),
3053 ctypes.c_float(float(absent_value)))
3054 return [float(x) for x in out]
3057def getLiDARScanHitDataColumnI32(cloud_ptr, scanID: int, label: str, n: int,
3058 absent_value: int = -9999) -> List[int]:
3059 """Read one scan's values of a scalar-data label as 32-bit ints."""
3060 _require_lidar_1386()
3063 out = (ctypes.c_int * n)()
3064 helios_lib.getLiDARScanHitDataColumnI32(cloud_ptr, ctypes.c_uint(int(scanID)),
3065 label.encode('utf-8'), out, ctypes.c_uint(int(n)),
3066 ctypes.c_int(int(absent_value)))
3067 return [int(x) for x in out]
3070def _ijk_array(ijk, name: str):
3071 """Marshal a 3-element lattice index into a c_int[3]."""
3072 values = [int(v) for v in ijk]
3073 if len(values) != 3:
3074 raise ValueError(f"{name} must have exactly 3 elements (i, j, k)")
3075 return (ctypes.c_int * 3)(*values)
3078def calculateLiDARLeafAreaBlock(cloud_ptr, context_ptr, min_voxel_hits: int,
3079 element_width: float, ijk_min, ijk_max) -> None:
3080 """Calculate leaf area for only a block of the voxel grid (triangulation supplies G(theta))."""
3081 _require_lidar_1386()
3082 helios_lib.calculateLiDARLeafAreaBlock(
3083 cloud_ptr, context_ptr, ctypes.c_int(int(min_voxel_hits)),
3084 ctypes.c_float(float(element_width)),
3085 _ijk_array(ijk_min, 'ijk_min'), _ijk_array(ijk_max, 'ijk_max'))
3088def calculateLiDARLeafAreaGthetaBlock(cloud_ptr, context_ptr, Gtheta: float,
3089 min_voxel_hits: int, element_width: float,
3090 ijk_min, ijk_max) -> None:
3091 """Calculate leaf area for a block of the grid with a caller-supplied G(theta)."""
3092 _require_lidar_1386()
3093 helios_lib.calculateLiDARLeafAreaGthetaBlock(
3094 cloud_ptr, context_ptr, ctypes.c_float(float(Gtheta)),
3095 ctypes.c_int(int(min_voxel_hits)), ctypes.c_float(float(element_width)),
3096 _ijk_array(ijk_min, 'ijk_min'), _ijk_array(ijk_max, 'ijk_max'))
3099def calculateLiDARLeafAreaGthetaPerCellBlock(cloud_ptr, context_ptr, Gtheta_per_cell: List[float],
3100 min_voxel_hits: int, element_width: float,
3101 ijk_min, ijk_max) -> None:
3102 """Calculate leaf area for a block of the grid with one G(theta) per grid cell.
3104 Gtheta_per_cell covers the whole grid, not just the block.
3106 _require_lidar_1386()
3107 values = [float(g) for g in Gtheta_per_cell]
3109 raise ValueError("Gtheta_per_cell must contain at least one value")
3110 arr = (ctypes.c_float * len(values))(*values)
3111 helios_lib.calculateLiDARLeafAreaGthetaPerCellBlock(
3112 cloud_ptr, context_ptr, arr, ctypes.c_uint(len(values)),
3113 ctypes.c_int(int(min_voxel_hits)), ctypes.c_float(float(element_width)),
3114 _ijk_array(ijk_min, 'ijk_min'), _ijk_array(ijk_max, 'ijk_max'))
3117def getLiDARCellGlobalIJK(cloud_ptr, index: int) -> Tuple[int, int, int]:
3118 """Lattice index (i, j, k) of a grid cell."""
3119 _require_lidar_1386()
3120 out = (ctypes.c_int * 3)()
3121 helios_lib.getLiDARCellGlobalIJK(cloud_ptr, ctypes.c_uint(int(index)), out)
3122 return (int(out[0]), int(out[1]), int(out[2]))
3125def getLiDARGridGlobalCount(cloud_ptr) -> Tuple[int, int, int]:
3126 """Number of lattice cells (nx, ny, nz); raises if the grid is empty or irregular."""
3127 _require_lidar_1386()
3128 out = (ctypes.c_int * 3)()
3129 helios_lib.getLiDARGridGlobalCount(cloud_ptr, out)
3130 return (int(out[0]), int(out[1]), int(out[2]))
3133def getLiDARHitPointCapacity(cloud_ptr) -> int:
3134 """Number of hit points the cloud can hold before its arrays reallocate."""
3135 _require_lidar_1386()
3136 return int(helios_lib.getLiDARHitPointCapacity(cloud_ptr))
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.