0.1.15
Loading...
Searching...
No Matches
ULiDARWrapper.py
Go to the documentation of this file.
1"""
2ULiDARWrapper - ctypes wrapper for LiDAR plugin
3
4Provides low-level ctypes interface to LiDAR C++ plugin for point cloud processing,
5synthetic scanning, triangulation, and leaf area calculations.
6"""
7
8import ctypes
9from typing import List, Tuple, Optional
10from .UContextWrapper import UContext
11from ..plugins import helios_lib
12from ..exceptions import check_helios_error
13
14
15# Opaque structure for LiDARcloud
16class ULiDARcloud(ctypes.Structure):
17 """Opaque structure for LiDARcloud C++ class"""
18 pass
19
20
21# Error checking callback
22def _check_error(result, func, args):
23 """Automatic error checking for all LiDAR functions"""
24 check_helios_error(helios_lib.getLastErrorCode, helios_lib.getLastErrorMessage)
25 return result
26
27
28# Function prototypes with availability detection
29try:
30 # Cloud lifecycle
31 helios_lib.createLiDARcloud.argtypes = []
32 helios_lib.createLiDARcloud.restype = ctypes.POINTER(ULiDARcloud)
33 helios_lib.createLiDARcloud.errcheck = _check_error
35 helios_lib.destroyLiDARcloud.argtypes = [ctypes.POINTER(ULiDARcloud)]
36 helios_lib.destroyLiDARcloud.restype = None
37
38 # Scan management
39 helios_lib.addLiDARScan.argtypes = [
40 ctypes.POINTER(ULiDARcloud),
41 ctypes.POINTER(ctypes.c_float), # origin[3]
42 ctypes.c_uint, # Ntheta
43 ctypes.c_float, # thetaMin
44 ctypes.c_float, # thetaMax
45 ctypes.c_uint, # Nphi
46 ctypes.c_float, # phiMin
47 ctypes.c_float, # phiMax
48 ctypes.c_float, # exitDiameter
49 ctypes.c_float # beamDivergence
50 ]
51 helios_lib.addLiDARScan.restype = ctypes.c_uint
52 helios_lib.addLiDARScan.errcheck = _check_error
53
54 helios_lib.getLiDARScanCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
55 helios_lib.getLiDARScanCount.restype = ctypes.c_uint
56 helios_lib.getLiDARScanCount.errcheck = _check_error
57
58 helios_lib.getLiDARScanOrigin.argtypes = [
59 ctypes.POINTER(ULiDARcloud),
60 ctypes.c_uint,
61 ctypes.POINTER(ctypes.c_float)
62 ]
63 helios_lib.getLiDARScanOrigin.restype = None
64 helios_lib.getLiDARScanOrigin.errcheck = _check_error
65
66 helios_lib.getLiDARScanSizeTheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
67 helios_lib.getLiDARScanSizeTheta.restype = ctypes.c_uint
68 helios_lib.getLiDARScanSizeTheta.errcheck = _check_error
69
70 helios_lib.getLiDARScanSizePhi.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
71 helios_lib.getLiDARScanSizePhi.restype = ctypes.c_uint
72 helios_lib.getLiDARScanSizePhi.errcheck = _check_error
73
74 # Hit point operations
75 helios_lib.addLiDARHitPoint.argtypes = [
76 ctypes.POINTER(ULiDARcloud),
77 ctypes.c_uint,
78 ctypes.POINTER(ctypes.c_float),
79 ctypes.POINTER(ctypes.c_float)
80 ]
81 helios_lib.addLiDARHitPoint.restype = None
82 helios_lib.addLiDARHitPoint.errcheck = _check_error
83
84 helios_lib.addLiDARHitPointRGB.argtypes = [
85 ctypes.POINTER(ULiDARcloud),
86 ctypes.c_uint,
87 ctypes.POINTER(ctypes.c_float),
88 ctypes.POINTER(ctypes.c_float),
89 ctypes.POINTER(ctypes.c_float)
90 ]
91 helios_lib.addLiDARHitPointRGB.restype = None
92 helios_lib.addLiDARHitPointRGB.errcheck = _check_error
93
94 helios_lib.getLiDARHitCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
95 helios_lib.getLiDARHitCount.restype = ctypes.c_uint
96 helios_lib.getLiDARHitCount.errcheck = _check_error
97
98 helios_lib.getLiDARHitXYZ.argtypes = [
99 ctypes.POINTER(ULiDARcloud),
100 ctypes.c_uint,
101 ctypes.POINTER(ctypes.c_float)
102 ]
103 helios_lib.getLiDARHitXYZ.restype = None
104 helios_lib.getLiDARHitXYZ.errcheck = _check_error
105
106 helios_lib.getLiDARHitRaydir.argtypes = [
107 ctypes.POINTER(ULiDARcloud),
108 ctypes.c_uint,
109 ctypes.POINTER(ctypes.c_float)
110 ]
111 helios_lib.getLiDARHitRaydir.restype = None
112 helios_lib.getLiDARHitRaydir.errcheck = _check_error
113
114 helios_lib.getLiDARHitColor.argtypes = [
115 ctypes.POINTER(ULiDARcloud),
116 ctypes.c_uint,
117 ctypes.POINTER(ctypes.c_float)
118 ]
119 helios_lib.getLiDARHitColor.restype = None
120 helios_lib.getLiDARHitColor.errcheck = _check_error
121
122 helios_lib.deleteLiDARHitPoint.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
123 helios_lib.deleteLiDARHitPoint.restype = None
124 helios_lib.deleteLiDARHitPoint.errcheck = _check_error
125
126 # Transformations
127 helios_lib.lidarCoordinateShift.argtypes = [
128 ctypes.POINTER(ULiDARcloud),
129 ctypes.POINTER(ctypes.c_float)
130 ]
131 helios_lib.lidarCoordinateShift.restype = None
132 helios_lib.lidarCoordinateShift.errcheck = _check_error
133
134 helios_lib.lidarCoordinateRotation.argtypes = [
135 ctypes.POINTER(ULiDARcloud),
136 ctypes.POINTER(ctypes.c_float)
137 ]
138 helios_lib.lidarCoordinateRotation.restype = None
139 helios_lib.lidarCoordinateRotation.errcheck = _check_error
140
141 # Triangulation
142 helios_lib.lidarTriangulateHitPoints.argtypes = [
143 ctypes.POINTER(ULiDARcloud),
144 ctypes.c_float,
145 ctypes.c_float
146 ]
147 helios_lib.lidarTriangulateHitPoints.restype = None
148 helios_lib.lidarTriangulateHitPoints.errcheck = _check_error
149
150 helios_lib.getLiDARTriangleCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
151 helios_lib.getLiDARTriangleCount.restype = ctypes.c_uint
152 helios_lib.getLiDARTriangleCount.errcheck = _check_error
153
154 # Filters
155 helios_lib.lidarDistanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
156 helios_lib.lidarDistanceFilter.restype = None
157 helios_lib.lidarDistanceFilter.errcheck = _check_error
158
159 helios_lib.lidarReflectanceFilter.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float]
160 helios_lib.lidarReflectanceFilter.restype = None
161 helios_lib.lidarReflectanceFilter.errcheck = _check_error
162
163 helios_lib.lidarFirstHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
164 helios_lib.lidarFirstHitFilter.restype = None
165 helios_lib.lidarFirstHitFilter.errcheck = _check_error
166
167 helios_lib.lidarLastHitFilter.argtypes = [ctypes.POINTER(ULiDARcloud)]
168 helios_lib.lidarLastHitFilter.restype = None
169 helios_lib.lidarLastHitFilter.errcheck = _check_error
170
171 # File I/O
172 helios_lib.exportLiDARPointCloud.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
173 helios_lib.exportLiDARPointCloud.restype = None
174 helios_lib.exportLiDARPointCloud.errcheck = _check_error
175
176 helios_lib.loadLiDARXML.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
177 helios_lib.loadLiDARXML.restype = None
178 helios_lib.loadLiDARXML.errcheck = _check_error
179
180 # Message control
181 helios_lib.lidarDisableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
182 helios_lib.lidarDisableMessages.restype = None
183 helios_lib.lidarDisableMessages.errcheck = _check_error
184
185 helios_lib.lidarEnableMessages.argtypes = [ctypes.POINTER(ULiDARcloud)]
186 helios_lib.lidarEnableMessages.restype = None
187 helios_lib.lidarEnableMessages.errcheck = _check_error
188
189 # Grid cell management
190 helios_lib.addLiDARGrid.argtypes = [
191 ctypes.POINTER(ULiDARcloud),
192 ctypes.POINTER(ctypes.c_float),
193 ctypes.POINTER(ctypes.c_float),
194 ctypes.POINTER(ctypes.c_int),
195 ctypes.c_float
196 ]
197 helios_lib.addLiDARGrid.restype = None
198 helios_lib.addLiDARGrid.errcheck = _check_error
199
200 helios_lib.addLiDARGridCell.argtypes = [
201 ctypes.POINTER(ULiDARcloud),
202 ctypes.POINTER(ctypes.c_float),
203 ctypes.POINTER(ctypes.c_float),
204 ctypes.c_float
205 ]
206 helios_lib.addLiDARGridCell.restype = None
207 helios_lib.addLiDARGridCell.errcheck = _check_error
208
209 helios_lib.getLiDARGridCellCount.argtypes = [ctypes.POINTER(ULiDARcloud)]
210 helios_lib.getLiDARGridCellCount.restype = ctypes.c_uint
211 helios_lib.getLiDARGridCellCount.errcheck = _check_error
212
213 helios_lib.getLiDARCellCenter.argtypes = [
214 ctypes.POINTER(ULiDARcloud),
215 ctypes.c_uint,
216 ctypes.POINTER(ctypes.c_float)
217 ]
218 helios_lib.getLiDARCellCenter.restype = None
219 helios_lib.getLiDARCellCenter.errcheck = _check_error
220
221 helios_lib.getLiDARCellSize.argtypes = [
222 ctypes.POINTER(ULiDARcloud),
223 ctypes.c_uint,
224 ctypes.POINTER(ctypes.c_float)
225 ]
226 helios_lib.getLiDARCellSize.restype = None
227 helios_lib.getLiDARCellSize.errcheck = _check_error
228
229 helios_lib.getLiDARCellLeafArea.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
230 helios_lib.getLiDARCellLeafArea.restype = ctypes.c_float
231 helios_lib.getLiDARCellLeafArea.errcheck = _check_error
232
233 helios_lib.getLiDARCellLeafAreaDensity.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
234 helios_lib.getLiDARCellLeafAreaDensity.restype = ctypes.c_float
235 helios_lib.getLiDARCellLeafAreaDensity.errcheck = _check_error
236
237 helios_lib.calculateLiDARHitGridCell.argtypes = [ctypes.POINTER(ULiDARcloud)]
238 helios_lib.calculateLiDARHitGridCell.restype = None
239 helios_lib.calculateLiDARHitGridCell.errcheck = _check_error
240
241 # Synthetic scanning
242 helios_lib.syntheticLiDARScan.argtypes = [
243 ctypes.POINTER(ULiDARcloud),
244 ctypes.POINTER(UContext)
245 ]
246 helios_lib.syntheticLiDARScan.restype = None
247 helios_lib.syntheticLiDARScan.errcheck = _check_error
248
249 helios_lib.syntheticLiDARScanAppend.argtypes = [
250 ctypes.POINTER(ULiDARcloud),
251 ctypes.POINTER(UContext),
252 ctypes.c_bool
253 ]
254 helios_lib.syntheticLiDARScanAppend.restype = None
255 helios_lib.syntheticLiDARScanAppend.errcheck = _check_error
256
257 helios_lib.syntheticLiDARScanWaveform.argtypes = [
258 ctypes.POINTER(ULiDARcloud),
259 ctypes.POINTER(UContext),
260 ctypes.c_int,
261 ctypes.c_float
262 ]
263 helios_lib.syntheticLiDARScanWaveform.restype = None
264 helios_lib.syntheticLiDARScanWaveform.errcheck = _check_error
265
266 helios_lib.syntheticLiDARScanFull.argtypes = [
267 ctypes.POINTER(ULiDARcloud),
268 ctypes.POINTER(UContext),
269 ctypes.c_int,
270 ctypes.c_float,
271 ctypes.c_bool,
272 ctypes.c_bool,
273 ctypes.c_bool
274 ]
275 helios_lib.syntheticLiDARScanFull.restype = None
276 helios_lib.syntheticLiDARScanFull.errcheck = _check_error
277
278 # Leaf area calculations
279 helios_lib.calculateLiDARLeafArea.argtypes = [
280 ctypes.POINTER(ULiDARcloud),
281 ctypes.POINTER(UContext)
282 ]
283 helios_lib.calculateLiDARLeafArea.restype = None
284 helios_lib.calculateLiDARLeafArea.errcheck = _check_error
285
286 helios_lib.calculateLiDARLeafAreaMinHits.argtypes = [
287 ctypes.POINTER(ULiDARcloud),
288 ctypes.POINTER(UContext),
289 ctypes.c_int
290 ]
291 helios_lib.calculateLiDARLeafAreaMinHits.restype = None
292 helios_lib.calculateLiDARLeafAreaMinHits.errcheck = _check_error
293
294 helios_lib.calculateSyntheticLiDARLeafArea.argtypes = [
295 ctypes.POINTER(ULiDARcloud),
296 ctypes.POINTER(UContext)
297 ]
298 helios_lib.calculateSyntheticLiDARLeafArea.restype = None
299 helios_lib.calculateSyntheticLiDARLeafArea.errcheck = _check_error
300
301 helios_lib.calculateSyntheticLiDARGtheta.argtypes = [
302 ctypes.POINTER(ULiDARcloud),
303 ctypes.POINTER(UContext)
304 ]
305 helios_lib.calculateSyntheticLiDARGtheta.restype = None
306 helios_lib.calculateSyntheticLiDARGtheta.errcheck = _check_error
307
308 helios_lib.getLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_uint]
309 helios_lib.getLiDARCellGtheta.restype = ctypes.c_float
310 helios_lib.getLiDARCellGtheta.errcheck = _check_error
311
312 helios_lib.setLiDARCellGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_float, ctypes.c_uint]
313 helios_lib.setLiDARCellGtheta.restype = None
314 helios_lib.setLiDARCellGtheta.errcheck = _check_error
315
316 helios_lib.gapfillLiDARMisses.argtypes = [ctypes.POINTER(ULiDARcloud)]
317 helios_lib.gapfillLiDARMisses.restype = None
318 helios_lib.gapfillLiDARMisses.errcheck = _check_error
319
320 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
321 helios_lib.exportLiDARGtheta.restype = None
322 helios_lib.exportLiDARGtheta.errcheck = _check_error
323
324 # Additional export functions
325 helios_lib.exportLiDARTriangleNormals.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
326 helios_lib.exportLiDARTriangleNormals.restype = None
327 helios_lib.exportLiDARTriangleNormals.errcheck = _check_error
328
329 helios_lib.exportLiDARTriangleAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
330 helios_lib.exportLiDARTriangleAreas.restype = None
331 helios_lib.exportLiDARTriangleAreas.errcheck = _check_error
332
333 helios_lib.exportLiDARLeafAreas.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
334 helios_lib.exportLiDARLeafAreas.restype = None
335 helios_lib.exportLiDARLeafAreas.errcheck = _check_error
336
337 helios_lib.exportLiDARLeafAreaDensities.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
338 helios_lib.exportLiDARLeafAreaDensities.restype = None
339 helios_lib.exportLiDARLeafAreaDensities.errcheck = _check_error
340
341 helios_lib.exportLiDARGtheta.argtypes = [ctypes.POINTER(ULiDARcloud), ctypes.c_char_p]
342 helios_lib.exportLiDARGtheta.restype = None
343 helios_lib.exportLiDARGtheta.errcheck = _check_error
344
345 # Context integration
346 helios_lib.addLiDARTrianglesToContext.argtypes = [
347 ctypes.POINTER(ULiDARcloud),
348 ctypes.POINTER(UContext)
349 ]
350 helios_lib.addLiDARTrianglesToContext.restype = None
351 helios_lib.addLiDARTrianglesToContext.errcheck = _check_error
352
353 helios_lib.initializeLiDARCollisionDetection.argtypes = [
354 ctypes.POINTER(ULiDARcloud),
355 ctypes.POINTER(UContext)
356 ]
357 helios_lib.initializeLiDARCollisionDetection.restype = None
358 helios_lib.initializeLiDARCollisionDetection.errcheck = _check_error
359
360 helios_lib.enableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
361 helios_lib.enableLiDARCDGPUAcceleration.restype = None
362 helios_lib.enableLiDARCDGPUAcceleration.errcheck = _check_error
363
364 helios_lib.disableLiDARCDGPUAcceleration.argtypes = [ctypes.POINTER(ULiDARcloud)]
365 helios_lib.disableLiDARCDGPUAcceleration.restype = None
366 helios_lib.disableLiDARCDGPUAcceleration.errcheck = _check_error
367
368 _LIDAR_FUNCTIONS_AVAILABLE = True
369
370except AttributeError:
371 _LIDAR_FUNCTIONS_AVAILABLE = False
372
374# Python wrapper functions
375def createLiDARcloud() -> ctypes.POINTER(ULiDARcloud):
376 """Create LiDARcloud instance"""
377 if not _LIDAR_FUNCTIONS_AVAILABLE:
378 raise NotImplementedError(
379 "LiDAR functions not available. Rebuild PyHelios with lidar plugin:\n"
380 " build_scripts/build_helios --plugins lidar"
381 )
382 return helios_lib.createLiDARcloud()
383
384
385def destroyLiDARcloud(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
386 """Destroy LiDARcloud instance"""
387 if cloud_ptr and _LIDAR_FUNCTIONS_AVAILABLE:
388 helios_lib.destroyLiDARcloud(cloud_ptr)
389
390
391def addLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
392 origin: List[float], Ntheta: int, theta_range: Tuple[float, float],
393 Nphi: int, phi_range: Tuple[float, float],
394 exit_diameter: float, beam_divergence: float) -> int:
395 """Add a LiDAR scan to the point cloud"""
396 if not _LIDAR_FUNCTIONS_AVAILABLE:
397 raise NotImplementedError("LiDAR functions not available")
398
399 if len(origin) != 3:
400 raise ValueError("Origin must be a 3-element array [x, y, z]")
401
402 origin_array = (ctypes.c_float * 3)(*origin)
403 return helios_lib.addLiDARScan(
404 cloud_ptr, origin_array, Ntheta, theta_range[0], theta_range[1],
405 Nphi, phi_range[0], phi_range[1], exit_diameter, beam_divergence
406 )
407
408
409def getLiDARScanCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
410 """Get number of scans in the cloud"""
411 if not _LIDAR_FUNCTIONS_AVAILABLE:
412 raise NotImplementedError("LiDAR functions not available")
413 return helios_lib.getLiDARScanCount(cloud_ptr)
414
415
416def getLiDARScanOrigin(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> List[float]:
417 """Get origin of a specific scan"""
418 if not _LIDAR_FUNCTIONS_AVAILABLE:
419 raise NotImplementedError("LiDAR functions not available")
420
421 origin = (ctypes.c_float * 3)()
422 helios_lib.getLiDARScanOrigin(cloud_ptr, scanID, origin)
423 return list(origin)
424
426def getLiDARScanSizeTheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> int:
427 """Get number of zenith scan points"""
428 if not _LIDAR_FUNCTIONS_AVAILABLE:
429 raise NotImplementedError("LiDAR functions not available")
430 return helios_lib.getLiDARScanSizeTheta(cloud_ptr, scanID)
431
432
433def getLiDARScanSizePhi(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int) -> int:
434 """Get number of azimuthal scan points"""
435 if not _LIDAR_FUNCTIONS_AVAILABLE:
436 raise NotImplementedError("LiDAR functions not available")
437 return helios_lib.getLiDARScanSizePhi(cloud_ptr, scanID)
438
439
440def addLiDARHitPoint(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int,
441 xyz: List[float], direction: List[float]) -> None:
442 """Add a hit point to the cloud"""
443 if not _LIDAR_FUNCTIONS_AVAILABLE:
444 raise NotImplementedError("LiDAR functions not available")
445
446 if len(xyz) != 3:
447 raise ValueError("XYZ must be a 3-element array")
448 if len(direction) < 2:
449 raise ValueError("Direction must have at least 2 elements [radius, elevation]")
450
451 xyz_array = (ctypes.c_float * 3)(*xyz)
452 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2] if len(direction) > 2 else 0)
453 helios_lib.addLiDARHitPoint(cloud_ptr, scanID, xyz_array, direction_array)
454
455
456def addLiDARHitPointRGB(cloud_ptr: ctypes.POINTER(ULiDARcloud), scanID: int,
457 xyz: List[float], direction: List[float], color: List[float]) -> None:
458 """Add a hit point with color to the cloud"""
459 if not _LIDAR_FUNCTIONS_AVAILABLE:
460 raise NotImplementedError("LiDAR functions not available")
461
462 if len(xyz) != 3:
463 raise ValueError("XYZ must be a 3-element array")
464 if len(direction) < 2:
465 raise ValueError("Direction must have at least 2 elements")
466 if len(color) != 3:
467 raise ValueError("Color must be a 3-element array [r, g, b]")
468
469 xyz_array = (ctypes.c_float * 3)(*xyz)
470 direction_array = (ctypes.c_float * 3)(direction[0], direction[1], direction[2] if len(direction) > 2 else 0)
471 color_array = (ctypes.c_float * 3)(*color)
472 helios_lib.addLiDARHitPointRGB(cloud_ptr, scanID, xyz_array, direction_array, color_array)
473
474
475def getLiDARHitCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
476 """Get total number of hit points"""
477 if not _LIDAR_FUNCTIONS_AVAILABLE:
478 raise NotImplementedError("LiDAR functions not available")
479 return helios_lib.getLiDARHitCount(cloud_ptr)
480
481
482def getLiDARHitXYZ(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
483 """Get coordinates of a hit point"""
484 if not _LIDAR_FUNCTIONS_AVAILABLE:
485 raise NotImplementedError("LiDAR functions not available")
486
487 xyz = (ctypes.c_float * 3)()
488 helios_lib.getLiDARHitXYZ(cloud_ptr, index, xyz)
489 return list(xyz)
490
492def getLiDARHitRaydir(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
493 """Get ray direction of a hit point"""
494 if not _LIDAR_FUNCTIONS_AVAILABLE:
495 raise NotImplementedError("LiDAR functions not available")
496
497 direction = (ctypes.c_float * 3)()
498 helios_lib.getLiDARHitRaydir(cloud_ptr, index, direction)
499 return list(direction)
500
502def getLiDARHitColor(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
503 """Get color of a hit point"""
504 if not _LIDAR_FUNCTIONS_AVAILABLE:
505 raise NotImplementedError("LiDAR functions not available")
506
507 color = (ctypes.c_float * 3)()
508 helios_lib.getLiDARHitColor(cloud_ptr, index, color)
509 return list(color)
510
512def deleteLiDARHitPoint(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> None:
513 """Delete a hit point from the cloud"""
514 if not _LIDAR_FUNCTIONS_AVAILABLE:
515 raise NotImplementedError("LiDAR functions not available")
516 helios_lib.deleteLiDARHitPoint(cloud_ptr, index)
517
518
519def lidarCoordinateShift(cloud_ptr: ctypes.POINTER(ULiDARcloud), shift: List[float]) -> None:
520 """Translate all hit points by a shift vector"""
521 if not _LIDAR_FUNCTIONS_AVAILABLE:
522 raise NotImplementedError("LiDAR functions not available")
523
524 if len(shift) != 3:
525 raise ValueError("Shift must be a 3-element array [x, y, z]")
526
527 shift_array = (ctypes.c_float * 3)(*shift)
528 helios_lib.lidarCoordinateShift(cloud_ptr, shift_array)
529
530
531def lidarCoordinateRotation(cloud_ptr: ctypes.POINTER(ULiDARcloud), rotation: List[float]) -> None:
532 """Rotate all hit points by spherical rotation angles"""
533 if not _LIDAR_FUNCTIONS_AVAILABLE:
534 raise NotImplementedError("LiDAR functions not available")
535
536 if len(rotation) < 2:
537 raise ValueError("Rotation must have at least 2 elements [radius, elevation]")
538
539 rotation_array = (ctypes.c_float * 3)(rotation[0], rotation[1], rotation[2] if len(rotation) > 2 else 0)
540 helios_lib.lidarCoordinateRotation(cloud_ptr, rotation_array)
541
542
543def lidarTriangulateHitPoints(cloud_ptr: ctypes.POINTER(ULiDARcloud),
544 Lmax: float, max_aspect_ratio: float) -> None:
545 """Generate triangle mesh from hit points"""
546 if not _LIDAR_FUNCTIONS_AVAILABLE:
547 raise NotImplementedError("LiDAR functions not available")
548 helios_lib.lidarTriangulateHitPoints(cloud_ptr, Lmax, max_aspect_ratio)
549
550
551def getLiDARTriangleCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
552 """Get number of triangles in the mesh"""
553 if not _LIDAR_FUNCTIONS_AVAILABLE:
554 raise NotImplementedError("LiDAR functions not available")
555 return helios_lib.getLiDARTriangleCount(cloud_ptr)
556
557
558def lidarDistanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), maxdistance: float) -> None:
559 """Filter hit points by maximum distance"""
560 if not _LIDAR_FUNCTIONS_AVAILABLE:
561 raise NotImplementedError("LiDAR functions not available")
562 helios_lib.lidarDistanceFilter(cloud_ptr, maxdistance)
563
564
565def lidarReflectanceFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud), minreflectance: float) -> None:
566 """Filter hit points by minimum reflectance"""
567 if not _LIDAR_FUNCTIONS_AVAILABLE:
568 raise NotImplementedError("LiDAR functions not available")
569 helios_lib.lidarReflectanceFilter(cloud_ptr, minreflectance)
570
571
572def lidarFirstHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
573 """Keep only first return hit points"""
574 if not _LIDAR_FUNCTIONS_AVAILABLE:
575 raise NotImplementedError("LiDAR functions not available")
576 helios_lib.lidarFirstHitFilter(cloud_ptr)
577
578
579def lidarLastHitFilter(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
580 """Keep only last return hit points"""
581 if not _LIDAR_FUNCTIONS_AVAILABLE:
582 raise NotImplementedError("LiDAR functions not available")
583 helios_lib.lidarLastHitFilter(cloud_ptr)
584
585
586def exportLiDARPointCloud(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
587 """Export point cloud to ASCII file"""
588 if not _LIDAR_FUNCTIONS_AVAILABLE:
589 raise NotImplementedError("LiDAR functions not available")
590 helios_lib.exportLiDARPointCloud(cloud_ptr, filename.encode('utf-8'))
591
592
593def loadLiDARXML(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
594 """Load scan metadata from XML file"""
595 if not _LIDAR_FUNCTIONS_AVAILABLE:
596 raise NotImplementedError("LiDAR functions not available")
597 helios_lib.loadLiDARXML(cloud_ptr, filename.encode('utf-8'))
598
599
600def lidarDisableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
601 """Disable console output messages"""
602 if not _LIDAR_FUNCTIONS_AVAILABLE:
603 raise NotImplementedError("LiDAR functions not available")
604 helios_lib.lidarDisableMessages(cloud_ptr)
605
606
607def lidarEnableMessages(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
608 """Enable console output messages"""
609 if not _LIDAR_FUNCTIONS_AVAILABLE:
610 raise NotImplementedError("LiDAR functions not available")
611 helios_lib.lidarEnableMessages(cloud_ptr)
612
613
614def addLiDARGrid(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
615 size: List[float], ndiv: List[int], rotation: float) -> None:
616 """Add a rectangular grid of voxel cells"""
617 if not _LIDAR_FUNCTIONS_AVAILABLE:
618 raise NotImplementedError("LiDAR functions not available")
619
620 if len(center) != 3:
621 raise ValueError("Center must be a 3-element array [x, y, z]")
622 if len(size) != 3:
623 raise ValueError("Size must be a 3-element array [x, y, z]")
624 if len(ndiv) != 3:
625 raise ValueError("Ndiv must be a 3-element array [nx, ny, nz]")
626
627 center_array = (ctypes.c_float * 3)(*center)
628 size_array = (ctypes.c_float * 3)(*size)
629 ndiv_array = (ctypes.c_int * 3)(*ndiv)
630 helios_lib.addLiDARGrid(cloud_ptr, center_array, size_array, ndiv_array, rotation)
631
632
633def addLiDARGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud), center: List[float],
634 size: List[float], rotation: float) -> None:
635 """Add a single grid cell"""
636 if not _LIDAR_FUNCTIONS_AVAILABLE:
637 raise NotImplementedError("LiDAR functions not available")
638
639 if len(center) != 3:
640 raise ValueError("Center must be a 3-element array [x, y, z]")
641 if len(size) != 3:
642 raise ValueError("Size must be a 3-element array [x, y, z]")
643
644 center_array = (ctypes.c_float * 3)(*center)
645 size_array = (ctypes.c_float * 3)(*size)
646 helios_lib.addLiDARGridCell(cloud_ptr, center_array, size_array, rotation)
647
648
649def getLiDARGridCellCount(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> int:
650 """Get number of grid cells"""
651 if not _LIDAR_FUNCTIONS_AVAILABLE:
652 raise NotImplementedError("LiDAR functions not available")
653 return helios_lib.getLiDARGridCellCount(cloud_ptr)
654
655
656def getLiDARCellCenter(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
657 """Get center position of a grid cell"""
658 if not _LIDAR_FUNCTIONS_AVAILABLE:
659 raise NotImplementedError("LiDAR functions not available")
660
661 center = (ctypes.c_float * 3)()
662 helios_lib.getLiDARCellCenter(cloud_ptr, index, center)
663 return list(center)
664
666def getLiDARCellSize(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> List[float]:
667 """Get size of a grid cell"""
668 if not _LIDAR_FUNCTIONS_AVAILABLE:
669 raise NotImplementedError("LiDAR functions not available")
670
671 size = (ctypes.c_float * 3)()
672 helios_lib.getLiDARCellSize(cloud_ptr, index, size)
673 return list(size)
674
676def getLiDARCellLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
677 """Get leaf area of a grid cell"""
678 if not _LIDAR_FUNCTIONS_AVAILABLE:
679 raise NotImplementedError("LiDAR functions not available")
680 return helios_lib.getLiDARCellLeafArea(cloud_ptr, index)
681
682
683def getLiDARCellLeafAreaDensity(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
684 """Get leaf area density of a grid cell"""
685 if not _LIDAR_FUNCTIONS_AVAILABLE:
686 raise NotImplementedError("LiDAR functions not available")
687 return helios_lib.getLiDARCellLeafAreaDensity(cloud_ptr, index)
688
689
690def calculateLiDARHitGridCell(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
691 """Calculate hit point grid cell assignments"""
692 if not _LIDAR_FUNCTIONS_AVAILABLE:
693 raise NotImplementedError("LiDAR functions not available")
694 helios_lib.calculateLiDARHitGridCell(cloud_ptr)
695
696
697def syntheticLiDARScan(cloud_ptr: ctypes.POINTER(ULiDARcloud),
698 context_ptr: ctypes.POINTER(UContext)) -> None:
699 """Perform synthetic discrete-return LiDAR scan"""
700 if not _LIDAR_FUNCTIONS_AVAILABLE:
701 raise NotImplementedError("LiDAR functions not available")
702 helios_lib.syntheticLiDARScan(cloud_ptr, context_ptr)
703
704
705def syntheticLiDARScanAppend(cloud_ptr: ctypes.POINTER(ULiDARcloud),
706 context_ptr: ctypes.POINTER(UContext),
707 append: bool) -> None:
708 """Perform synthetic scan with append control"""
709 if not _LIDAR_FUNCTIONS_AVAILABLE:
710 raise NotImplementedError("LiDAR functions not available")
711 helios_lib.syntheticLiDARScanAppend(cloud_ptr, context_ptr, append)
712
713
714def syntheticLiDARScanWaveform(cloud_ptr: ctypes.POINTER(ULiDARcloud),
715 context_ptr: ctypes.POINTER(UContext),
716 rays_per_pulse: int,
717 pulse_distance_threshold: float) -> None:
718 """Perform synthetic full-waveform LiDAR scan"""
719 if not _LIDAR_FUNCTIONS_AVAILABLE:
720 raise NotImplementedError("LiDAR functions not available")
721 helios_lib.syntheticLiDARScanWaveform(cloud_ptr, context_ptr, rays_per_pulse, pulse_distance_threshold)
722
724def syntheticLiDARScanFull(cloud_ptr: ctypes.POINTER(ULiDARcloud),
725 context_ptr: ctypes.POINTER(UContext),
726 rays_per_pulse: int,
727 pulse_distance_threshold: float,
728 scan_grid_only: bool,
729 record_misses: bool,
730 append: bool) -> None:
731 """Perform synthetic scan with full control"""
732 if not _LIDAR_FUNCTIONS_AVAILABLE:
733 raise NotImplementedError("LiDAR functions not available")
734 helios_lib.syntheticLiDARScanFull(cloud_ptr, context_ptr, rays_per_pulse,
735 pulse_distance_threshold, scan_grid_only,
736 record_misses, append)
737
738
739def calculateLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
740 context_ptr: ctypes.POINTER(UContext)) -> None:
741 """Calculate leaf area for each grid cell"""
742 if not _LIDAR_FUNCTIONS_AVAILABLE:
743 raise NotImplementedError("LiDAR functions not available")
744 helios_lib.calculateLiDARLeafArea(cloud_ptr, context_ptr)
745
746
747def calculateLiDARLeafAreaMinHits(cloud_ptr: ctypes.POINTER(ULiDARcloud),
748 context_ptr: ctypes.POINTER(UContext),
749 min_voxel_hits: int) -> None:
750 """Calculate leaf area with minimum voxel hits threshold"""
751 if not _LIDAR_FUNCTIONS_AVAILABLE:
752 raise NotImplementedError("LiDAR functions not available")
753 helios_lib.calculateLiDARLeafAreaMinHits(cloud_ptr, context_ptr, min_voxel_hits)
754
755
756def exportLiDARTriangleNormals(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
757 """Export triangle normal vectors"""
758 if not _LIDAR_FUNCTIONS_AVAILABLE:
759 raise NotImplementedError("LiDAR functions not available")
760 helios_lib.exportLiDARTriangleNormals(cloud_ptr, filename.encode('utf-8'))
761
762
763def exportLiDARTriangleAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
764 """Export triangle areas"""
765 if not _LIDAR_FUNCTIONS_AVAILABLE:
766 raise NotImplementedError("LiDAR functions not available")
767 helios_lib.exportLiDARTriangleAreas(cloud_ptr, filename.encode('utf-8'))
768
769
770def exportLiDARLeafAreas(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
771 """Export leaf areas for each grid cell"""
772 if not _LIDAR_FUNCTIONS_AVAILABLE:
773 raise NotImplementedError("LiDAR functions not available")
774 helios_lib.exportLiDARLeafAreas(cloud_ptr, filename.encode('utf-8'))
775
776
777def exportLiDARLeafAreaDensities(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
778 """Export leaf area densities for each grid cell"""
779 if not _LIDAR_FUNCTIONS_AVAILABLE:
780 raise NotImplementedError("LiDAR functions not available")
781 helios_lib.exportLiDARLeafAreaDensities(cloud_ptr, filename.encode('utf-8'))
782
783
784def exportLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), filename: str) -> None:
785 """Export G(theta) values for each grid cell"""
786 if not _LIDAR_FUNCTIONS_AVAILABLE:
787 raise NotImplementedError("LiDAR functions not available")
788 helios_lib.exportLiDARGtheta(cloud_ptr, filename.encode('utf-8'))
789
790
791def getLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), index: int) -> float:
792 """Get G(theta) value for a grid cell"""
793 if not _LIDAR_FUNCTIONS_AVAILABLE:
794 raise NotImplementedError("LiDAR functions not available")
795 return helios_lib.getLiDARCellGtheta(cloud_ptr, index)
796
797
798def setLiDARCellGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud), Gtheta: float, index: int) -> None:
799 """Set G(theta) value for a grid cell"""
800 if not _LIDAR_FUNCTIONS_AVAILABLE:
801 raise NotImplementedError("LiDAR functions not available")
802 helios_lib.setLiDARCellGtheta(cloud_ptr, Gtheta, index)
803
804
805def gapfillLiDARMisses(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
806 """Gapfill sky/miss points"""
807 if not _LIDAR_FUNCTIONS_AVAILABLE:
808 raise NotImplementedError("LiDAR functions not available")
809 helios_lib.gapfillLiDARMisses(cloud_ptr)
810
811
812def calculateSyntheticLiDARLeafArea(cloud_ptr: ctypes.POINTER(ULiDARcloud),
813 context_ptr: ctypes.POINTER(UContext)) -> None:
814 """Calculate synthetic leaf area for validation"""
815 if not _LIDAR_FUNCTIONS_AVAILABLE:
816 raise NotImplementedError("LiDAR functions not available")
817 helios_lib.calculateSyntheticLiDARLeafArea(cloud_ptr, context_ptr)
818
819
820def calculateSyntheticLiDARGtheta(cloud_ptr: ctypes.POINTER(ULiDARcloud),
821 context_ptr: ctypes.POINTER(UContext)) -> None:
822 """Calculate synthetic G(theta) for validation"""
823 if not _LIDAR_FUNCTIONS_AVAILABLE:
824 raise NotImplementedError("LiDAR functions not available")
825 helios_lib.calculateSyntheticLiDARGtheta(cloud_ptr, context_ptr)
826
827
828def addLiDARTrianglesToContext(cloud_ptr: ctypes.POINTER(ULiDARcloud),
829 context_ptr: ctypes.POINTER(UContext)) -> None:
830 """Add triangulated mesh to Context as primitives"""
831 if not _LIDAR_FUNCTIONS_AVAILABLE:
832 raise NotImplementedError("LiDAR functions not available")
833 helios_lib.addLiDARTrianglesToContext(cloud_ptr, context_ptr)
834
835
836def initializeLiDARCollisionDetection(cloud_ptr: ctypes.POINTER(ULiDARcloud),
837 context_ptr: ctypes.POINTER(UContext)) -> None:
838 """Initialize CollisionDetection for ray tracing"""
839 if not _LIDAR_FUNCTIONS_AVAILABLE:
840 raise NotImplementedError("LiDAR functions not available")
841 helios_lib.initializeLiDARCollisionDetection(cloud_ptr, context_ptr)
842
843
844def enableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
845 """Enable GPU acceleration for collision detection"""
846 if not _LIDAR_FUNCTIONS_AVAILABLE:
847 raise NotImplementedError("LiDAR functions not available")
848 helios_lib.enableLiDARCDGPUAcceleration(cloud_ptr)
849
850
851def disableLiDARCDGPUAcceleration(cloud_ptr: ctypes.POINTER(ULiDARcloud)) -> None:
852 """Disable GPU acceleration for collision detection"""
853 if not _LIDAR_FUNCTIONS_AVAILABLE:
854 raise NotImplementedError("LiDAR functions not available")
855 helios_lib.disableLiDARCDGPUAcceleration(cloud_ptr)
856
857
858# Mock mode for development
859if not _LIDAR_FUNCTIONS_AVAILABLE:
860 def mock_createLiDARcloud(*args, **kwargs):
861 raise RuntimeError(
862 "Mock mode: LiDAR not available. "
863 "This would create a LiDAR cloud instance with native library."
864 )
865
866 def mock_lidar_operation(*args, **kwargs):
867 raise RuntimeError(
868 "Mock mode: LiDAR operation not available. "
869 "This would execute LiDAR operations with native library."
870 )
871
872 # Replace functions with mocks for development
873 createLiDARcloud = mock_createLiDARcloud
874 addLiDARScan = mock_lidar_operation
875 addLiDARHitPoint = mock_lidar_operation
Opaque structure for LiDARcloud C++ class.
_check_error(result, func, args)
Automatic error checking for all LiDAR functions.
None addLiDARHitPointRGB(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID, List[float] xyz, List[float] direction, List[float] color)
Add a hit point with color to the cloud.
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 getLiDARScanSizeTheta(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get number of zenith scan points.
int getLiDARScanSizePhi(ctypes.POINTER(ULiDARcloud) cloud_ptr, int scanID)
Get number of azimuthal scan points.
List[float] getLiDARHitXYZ(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get coordinates of a hit point.
None deleteLiDARHitPoint(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Delete a hit point from the cloud.
List[float] getLiDARHitColor(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get color of a hit point.
List[float] getLiDARHitRaydir(ctypes.POINTER(ULiDARcloud) cloud_ptr, int index)
Get ray direction of a hit point.
None destroyLiDARcloud(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Destroy LiDARcloud instance.
createLiDARcloud
Create LiDARcloud instance.
int getLiDARHitCount(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Get total number of hit points.
int getLiDARScanCount(ctypes.POINTER(ULiDARcloud) cloud_ptr)
Get number of scans in the cloud.