Skip to content

Commit 74cbbe0

Browse files
committed
[1.3.74] 2026-06-10
- Added two read-only shoot-topology accessors: `PlantArchitecture::getAllShootIDs()` returns the contiguous, 0-based list of shoot IDs for a plant (shoot 0 is always the base stem), and `PlantArchitecture::getPlantShoot()` returns a const reference to the `shared_ptr<Shoot>` for a given shoot, exposing its topology (rank, parent/child IDs, parent node index) and woody internode geometry for inspecting a plant's ground-truth structure. Both fail fast with `helios_runtime_error()` on a nonexistent plant ID, and `getPlantShoot()` also on an out-of-range shoot ID. - Fixed terminal fruiting buds being created at full size and then abruptly snapping to 25% scale on the first fruit-growth step: `appendPhytomerToShoot()` now initializes a terminal bud entering the `BUD_FRUITING` state at a 0.25 inflorescence scale fraction (matching the existing `setFloralBudState()` behavior), so the fruit/panicle grows in gradually instead of regrowing after a sudden shrink. - Fixed `syntheticScan()` producing NaN ray directions for a single-row or single-column scan: the inclusive-endpoint angular step now guards its `N-1` denominator so a scan with `Nphi==1` or `Ntheta==1` samples once at the minimum angle instead of dividing by zero. - Added an optional global scanner tilt for synthetic scans, configured per scan via a new `<scanTilt>` XML element (`roll pitch` in degrees; default `0 0` = perfectly level) and exposed through new `scanTilt_roll`/`scanTilt_pitch` fields on `ScanMetadata`, two trailing constructor arguments, and `LiDARcloud::getScanTiltRoll()` / `getScanTiltPitch()` accessors. This models the residual tilt of the scanner spin axis away from plumb that a real terrestrial scanner's dual-axis inclinometer reports. During `syntheticScan()` the entire fan of ray directions is rotated about the scanner origin using right-hand rotations in a right-handed, Z-up body frame (matching commercial scanners such as RIEGL SOCS): the forward axis is the horizontal projection of the azimuth-zero (`phiMin`) heading, the lateral axis completes the frame, roll rotates about the lateral axis and pitch about the forward axis, with roll applied first. The new field round-trips through `exportScans()`/`loadXML()`. - Reworked leaf-area inversion onto a single miss-aware, beam-based equal-weighting algorithm that handles both single- and multi-return data, replacing the previous auto-detected split between a single-return "standard" path and a multi-return "equal weighting" path (the now-unused `filterRaysByBoundingBox()`, `calculateVoxelPathLengths()`, and `findRayIndexByDirection()` helpers and the entire single-return path were removed). Misses (fired pulses that returned nothing — the transmitted beams that form the denominator of the per-voxel transmission probability) are now the canonical input: they are flagged with a per-hit `is_miss` data field (set by `syntheticScan()` and `gapfillMisses()`, carried through imported data when present), queryable via new `LiDARcloud::isHitMiss()` / `hasMisses()` methods and the `LIDAR_MISS_DISTANCE` constant. `calculateLeafArea()` now fails fast with an explicit error if the cloud contains no misses, rather than silently producing biased LAD. Also fixed `invertLAD()` to no longer report a stalled secant solve (which left the estimate near the 0.1 initial guess) as converged — convergence now requires the achieved error to fall below tolerance, so a stalled solve correctly falls back to the average-`dr` formulation. - Made the leaf-area inversion's per-beam voxel classification independent of how far out a miss point is placed along its beam. Previously a transmitted beam was counted toward the transmission probability only when its hit point fell within a hard-coded 5000 m `scanner_range` (so a miss placed at the synthetic-scan distance and a miss placed at `LIDAR_MISS_DISTANCE` by `gapfillMisses()` were classified differently, and moving the placement distance silently doubled the inverted LAD). A beam is now classified purely geometrically: any beam that passes through the voxel exit is "after voxel" (transmitted) regardless of placement distance, folding misses into the same `E_after` count as any other transmitted return. The `scanner_range` threshold and the separate all-miss-only probability branch were removed. Results are unchanged for existing data; only the previously fragile coupling between the miss placement distance and the inversion is eliminated. - Documented and made explicit the synthetic-scan return-intensity radiometric model: the `intensity` recorded by `syntheticScan()` is the *range-normalized* return amplitude \f$\rho\cos\theta\f$ (per-primitive `reflectivity_lidar` reflectivity times the incidence-angle cosine) with the \f$1/R^2\f$ range loss of the LiDAR range equation divided back out, so a surface returns the same intensity regardless of scanner-to-target range. The normalization is now routed through a new `LiDARcloud::applyRangeIntensityCorrection()` helper (identity on the value, since the synthetic intensity is generated directly as \f$\rho\cos\theta\f$) that is the single place to switch to a raw range-dependent convention. Full-waveform partial-footprint attenuation is deliberately preserved (it is carried by the fraction of beam sub-rays striking the target — a target property, not a range-geometry loss). - Added an optional `reflectance` synthetic-scan output column: when `reflectance` is listed in a scan's `ASCII_format`, `syntheticScan()` records the return reflectance in decibels, \f$10\log_{10}|I|\f$ of the range-normalized intensity, following the terrestrial-laser-scanner convention (e.g. RIEGL) in which a perfect Lambertian reflector at normal incidence is 0 dB and all real returns are negative. Returns with no detectable signal (misses, fully grazing, or back-facing hits) are floored at -999 dB rather than \f$-\infty\f$. The `reflectance` token is treated as a computed output rather than a primitive-data field, so it is not overwritten by same-named primitive data. - Added a robust row/column miss gap-filling path and made `gapfillMisses()` auto-select between it and the existing timestamp path. When returns carry native scan-grid `row`/`column` hit data the new `gapfillMisses_rowcolumn()` fits a per-row generative model (median zenith per row; Theil-Sen azimuth line `intercept + slope·column`, with cross-row Theil-Sen extrapolation of the per-row parameters so blank near-zenith rows are extrapolated rather than only interpolated), which is robust to scanner tilt, azimuth shear, and angular noise without requiring a level or regular scan; the timestamp path is renamed `gapfillMisses_timestamp()` and used as the fallback. Row/column is preferred when both are present; a scan with returns carrying neither now fails fast, while a scan with no returns at all is skipped gracefully. The ASCII loader now retains `row`/`column` columns as hit data (previously discarded) so imported clouds can use this path. - Made exported ASCII point clouds self-describing: `exportPointCloud()` now writes a leading `#`-prefixed comment-line header listing the column field names (matching the `ASCII_format` columns, including user-defined fields), following the convention recognized by tools such as CloudCompare. A new optional `write_header` argument (default true) suppresses it, and the loader now skips any `#`-prefixed line, so headered files round-trip through `loadXML()` unchanged. - Added read-only triangulation diagnostics to `triangulateHitPoints()`: the run now tallies the number of candidate triangles the Delaunay pass produced and how many were dropped by each filter, exposed through new `LiDARcloud::getTriangulationCandidateCount()`, `getTriangulationDroppedByLmax()`, `getTriangulationDroppedByAspect()`, and `getTriangulationDroppedByDegenerate()` accessors. The filtering logic was refactored so each dropped triangle is attributed to exactly one primary reason in priority order (`Lmax`, then aspect/separation-ratio, then degenerate area), so the counts reconcile as `candidates == kept + dropped_lmax + dropped_aspect + dropped_degenerate`. No change to which triangles are kept. - Added per-voxel statistical sampling uncertainty for the leaf-area inversion, following Pimont et al. (2018, RSE 215:343-370). A new `calculateLeafArea()` overload taking a characteristic vegetation `element_width` computes, alongside the unchanged leaf-area point estimate, the sampling variance of LAD via a Beer-Lambert delta-method propagation with two terms: a finite-beam term that decays as 1/N (the binomial variance of the relative density index, guarded against the larger empirical spread of multi-return per-beam transmittance fractions), and an N-independent element-position-variability term derived from the single-element optical depth (omitted, leaving a sampling-only variance, when `element_width <= 0`); the existing two-argument overload delegates to it with a default 5 cm width. The per-voxel sufficient statistics and variance are stored on each `GridCell` (beam count N, relative density index, mean/variance of beam path length, single-element optical depth, LAD variance, and a precomputed 95% CI-validity flag) and exposed through new `getCellBeamCount()`, `getCellRelativeDensityIndex()`, `getCellMeanPathLength()`, `getCellLADVariance()`, single-voxel `getCellLeafAreaConfidenceInterval()`, and group-scale `getGroupLADConfidenceInterval()` (the recommended path; Eq. 39, assuming voxel independence) accessors. Confidence intervals are gated by the Pimont Table-3 validity envelope (`ciValidPimont()`) so untrustworthy single-voxel intervals are refused rather than emitted, with the two-sided z-multiplier obtained from an Acklam normal-quantile approximation. A new `exportLeafAreaUncertainty()` writes a self-describing per-cell file (`cell_index leaf_area beam_count I_rdi LAD_std_error ci_valid`). The uncertainty is conditional on the beams that entered each voxel and does not capture occlusion/coverage bias. - Added a spinning multibeam scan pattern modeling a rotating multi-channel sensor (e.g. Velodyne, Ouster, Hesai), in addition to the existing uniform-angular-grid raster pattern. A new `ScanPattern` enum (`SCAN_PATTERN_RASTER`/`SCAN_PATTERN_SPINNING_MULTIBEAM`) and `scanPattern`/`beamZenithAngles` fields on `ScanMetadata` are set through a new `ScanMetadata` constructor that takes a vector of per-channel zenith angles in place of `Ntheta` and the zenith range. Each scan-table row is a laser channel fired at its own fixed (generally non-uniformly spaced) zenith angle while each column is a uniform azimuth step, so the pattern reuses the same `Ntheta`×`Nphi` table storage and all downstream processing (ray tracing, hit tables, leaf-area/leaf-angle inversion) is shared with raster scans; `rc2direction()`/`direction2rc()` map a multibeam row to the nearest channel rather than interpolating, and `syntheticScan()` fires each row at its channel angle and records the firing channel index as a `channel` hit-data column. The pattern round-trips through `exportScans()`/`loadXML()` via a new `<scanPattern>` element plus `<beamElevationAngles>` (space-separated per-channel elevation angles in degrees above the horizon, converted internally to zenith) and `<Nphi>` (azimuth-step count), and is queryable through new `LiDARcloud::getScanPattern()` / `getScanBeamZenithAngles()` accessors.
1 parent cfd8127 commit 74cbbe0

30 files changed

Lines changed: 10704 additions & 3270 deletions

doc/CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Changelog
22

3+
# [1.3.74] 2026-06-10
4+
5+
## Plant Architecture
6+
- Added two read-only shoot-topology accessors: `PlantArchitecture::getAllShootIDs()` returns the contiguous, 0-based list of shoot IDs for a plant (shoot 0 is always the base stem), and `PlantArchitecture::getPlantShoot()` returns a const reference to the `shared_ptr<Shoot>` for a given shoot, exposing its topology (rank, parent/child IDs, parent node index) and woody internode geometry for inspecting a plant's ground-truth structure. Both fail fast with `helios_runtime_error()` on a nonexistent plant ID, and `getPlantShoot()` also on an out-of-range shoot ID.
7+
- Fixed terminal fruiting buds being created at full size and then abruptly snapping to 25% scale on the first fruit-growth step: `appendPhytomerToShoot()` now initializes a terminal bud entering the `BUD_FRUITING` state at a 0.25 inflorescence scale fraction (matching the existing `setFloralBudState()` behavior), so the fruit/panicle grows in gradually instead of regrowing after a sudden shrink.
8+
9+
## LiDAR
10+
- Fixed `syntheticScan()` producing NaN ray directions for a single-row or single-column scan: the inclusive-endpoint angular step now guards its `N-1` denominator so a scan with `Nphi==1` or `Ntheta==1` samples once at the minimum angle instead of dividing by zero.
11+
- Added an optional global scanner tilt for synthetic scans, configured per scan via a new `<scanTilt>` XML element (`roll pitch` in degrees; default `0 0` = perfectly level) and exposed through new `scanTilt_roll`/`scanTilt_pitch` fields on `ScanMetadata`, two trailing constructor arguments, and `LiDARcloud::getScanTiltRoll()` / `getScanTiltPitch()` accessors. This models the residual tilt of the scanner spin axis away from plumb that a real terrestrial scanner's dual-axis inclinometer reports. During `syntheticScan()` the entire fan of ray directions is rotated about the scanner origin using right-hand rotations in a right-handed, Z-up body frame (matching commercial scanners such as RIEGL SOCS): the forward axis is the horizontal projection of the azimuth-zero (`phiMin`) heading, the lateral axis completes the frame, roll rotates about the lateral axis and pitch about the forward axis, with roll applied first. The new field round-trips through `exportScans()`/`loadXML()`.
12+
- Reworked leaf-area inversion onto a single miss-aware, beam-based equal-weighting algorithm that handles both single- and multi-return data, replacing the previous auto-detected split between a single-return "standard" path and a multi-return "equal weighting" path (the now-unused `filterRaysByBoundingBox()`, `calculateVoxelPathLengths()`, and `findRayIndexByDirection()` helpers and the entire single-return path were removed). Misses (fired pulses that returned nothing — the transmitted beams that form the denominator of the per-voxel transmission probability) are now the canonical input: they are flagged with a per-hit `is_miss` data field (set by `syntheticScan()` and `gapfillMisses()`, carried through imported data when present), queryable via new `LiDARcloud::isHitMiss()` / `hasMisses()` methods and the `LIDAR_MISS_DISTANCE` constant. `calculateLeafArea()` now fails fast with an explicit error if the cloud contains no misses, rather than silently producing biased LAD. Also fixed `invertLAD()` to no longer report a stalled secant solve (which left the estimate near the 0.1 initial guess) as converged — convergence now requires the achieved error to fall below tolerance, so a stalled solve correctly falls back to the average-`dr` formulation.
13+
- Made the leaf-area inversion's per-beam voxel classification independent of how far out a miss point is placed along its beam. Previously a transmitted beam was counted toward the transmission probability only when its hit point fell within a hard-coded 5000 m `scanner_range` (so a miss placed at the synthetic-scan distance and a miss placed at `LIDAR_MISS_DISTANCE` by `gapfillMisses()` were classified differently, and moving the placement distance silently doubled the inverted LAD). A beam is now classified purely geometrically: any beam that passes through the voxel exit is "after voxel" (transmitted) regardless of placement distance, folding misses into the same `E_after` count as any other transmitted return. The `scanner_range` threshold and the separate all-miss-only probability branch were removed. Results are unchanged for existing data; only the previously fragile coupling between the miss placement distance and the inversion is eliminated.
14+
- Documented and made explicit the synthetic-scan return-intensity radiometric model: the `intensity` recorded by `syntheticScan()` is the *range-normalized* return amplitude \f$\rho\cos\theta\f$ (per-primitive `reflectivity_lidar` reflectivity times the incidence-angle cosine) with the \f$1/R^2\f$ range loss of the LiDAR range equation divided back out, so a surface returns the same intensity regardless of scanner-to-target range. The normalization is now routed through a new `LiDARcloud::applyRangeIntensityCorrection()` helper (identity on the value, since the synthetic intensity is generated directly as \f$\rho\cos\theta\f$) that is the single place to switch to a raw range-dependent convention. Full-waveform partial-footprint attenuation is deliberately preserved (it is carried by the fraction of beam sub-rays striking the target — a target property, not a range-geometry loss).
15+
- Added an optional `reflectance` synthetic-scan output column: when `reflectance` is listed in a scan's `ASCII_format`, `syntheticScan()` records the return reflectance in decibels, \f$10\log_{10}|I|\f$ of the range-normalized intensity, following the terrestrial-laser-scanner convention (e.g. RIEGL) in which a perfect Lambertian reflector at normal incidence is 0 dB and all real returns are negative. Returns with no detectable signal (misses, fully grazing, or back-facing hits) are floored at -999 dB rather than \f$-\infty\f$. The `reflectance` token is treated as a computed output rather than a primitive-data field, so it is not overwritten by same-named primitive data.
16+
- Added a robust row/column miss gap-filling path and made `gapfillMisses()` auto-select between it and the existing timestamp path. When returns carry native scan-grid `row`/`column` hit data the new `gapfillMisses_rowcolumn()` fits a per-row generative model (median zenith per row; Theil-Sen azimuth line `intercept + slope·column`, with cross-row Theil-Sen extrapolation of the per-row parameters so blank near-zenith rows are extrapolated rather than only interpolated), which is robust to scanner tilt, azimuth shear, and angular noise without requiring a level or regular scan; the timestamp path is renamed `gapfillMisses_timestamp()` and used as the fallback. Row/column is preferred when both are present; a scan with returns carrying neither now fails fast, while a scan with no returns at all is skipped gracefully. The ASCII loader now retains `row`/`column` columns as hit data (previously discarded) so imported clouds can use this path.
17+
- Made exported ASCII point clouds self-describing: `exportPointCloud()` now writes a leading `#`-prefixed comment-line header listing the column field names (matching the `ASCII_format` columns, including user-defined fields), following the convention recognized by tools such as CloudCompare. A new optional `write_header` argument (default true) suppresses it, and the loader now skips any `#`-prefixed line, so headered files round-trip through `loadXML()` unchanged.
18+
- Added read-only triangulation diagnostics to `triangulateHitPoints()`: the run now tallies the number of candidate triangles the Delaunay pass produced and how many were dropped by each filter, exposed through new `LiDARcloud::getTriangulationCandidateCount()`, `getTriangulationDroppedByLmax()`, `getTriangulationDroppedByAspect()`, and `getTriangulationDroppedByDegenerate()` accessors. The filtering logic was refactored so each dropped triangle is attributed to exactly one primary reason in priority order (`Lmax`, then aspect/separation-ratio, then degenerate area), so the counts reconcile as `candidates == kept + dropped_lmax + dropped_aspect + dropped_degenerate`. No change to which triangles are kept.
19+
- Added per-voxel statistical sampling uncertainty for the leaf-area inversion, following Pimont et al. (2018, RSE 215:343-370). A new `calculateLeafArea()` overload taking a characteristic vegetation `element_width` computes, alongside the unchanged leaf-area point estimate, the sampling variance of LAD via a Beer-Lambert delta-method propagation with two terms: a finite-beam term that decays as 1/N (the binomial variance of the relative density index, guarded against the larger empirical spread of multi-return per-beam transmittance fractions), and an N-independent element-position-variability term derived from the single-element optical depth (omitted, leaving a sampling-only variance, when `element_width <= 0`); the existing two-argument overload delegates to it with a default 5 cm width. The per-voxel sufficient statistics and variance are stored on each `GridCell` (beam count N, relative density index, mean/variance of beam path length, single-element optical depth, LAD variance, and a precomputed 95% CI-validity flag) and exposed through new `getCellBeamCount()`, `getCellRelativeDensityIndex()`, `getCellMeanPathLength()`, `getCellLADVariance()`, single-voxel `getCellLeafAreaConfidenceInterval()`, and group-scale `getGroupLADConfidenceInterval()` (the recommended path; Eq. 39, assuming voxel independence) accessors. Confidence intervals are gated by the Pimont Table-3 validity envelope (`ciValidPimont()`) so untrustworthy single-voxel intervals are refused rather than emitted, with the two-sided z-multiplier obtained from an Acklam normal-quantile approximation. A new `exportLeafAreaUncertainty()` writes a self-describing per-cell file (`cell_index leaf_area beam_count I_rdi LAD_std_error ci_valid`). The uncertainty is conditional on the beams that entered each voxel and does not capture occlusion/coverage bias.
20+
- Added a spinning multibeam scan pattern modeling a rotating multi-channel sensor (e.g. Velodyne, Ouster, Hesai), in addition to the existing uniform-angular-grid raster pattern. A new `ScanPattern` enum (`SCAN_PATTERN_RASTER`/`SCAN_PATTERN_SPINNING_MULTIBEAM`) and `scanPattern`/`beamZenithAngles` fields on `ScanMetadata` are set through a new `ScanMetadata` constructor that takes a vector of per-channel zenith angles in place of `Ntheta` and the zenith range. Each scan-table row is a laser channel fired at its own fixed (generally non-uniformly spaced) zenith angle while each column is a uniform azimuth step, so the pattern reuses the same `Ntheta`×`Nphi` table storage and all downstream processing (ray tracing, hit tables, leaf-area/leaf-angle inversion) is shared with raster scans; `rc2direction()`/`direction2rc()` map a multibeam row to the nearest channel rather than interpolating, and `syntheticScan()` fires each row at its channel angle and records the firing channel index as a `channel` hit-data column. The pattern round-trips through `exportScans()`/`loadXML()` via a new `<scanPattern>` element plus `<beamElevationAngles>` (space-separated per-channel elevation angles in degrees above the horizon, converted internally to zenith) and `<Nphi>` (azimuth-step count), and is queryable through new `LiDARcloud::getScanPattern()` / `getScanBeamZenithAngles()` accessors.
21+
322
# [1.3.73] 2026-06-06
423

524
## Core
@@ -31,6 +50,7 @@
3150
- Added optional Gaussian angular (beam-pointing) jitter for synthetic scans, the across-beam complement of the range noise above, configured per scan via a new `<angleNoiseStdDev>` XML element (radians; default 0 = no jitter) and exposed through a new `angleNoiseStdDev` field on `ScanMetadata`, the constructor argument, and a `LiDARcloud::getScanAngleNoiseStdDev()` accessor. During `syntheticScan()` the nominal direction of each pulse is perturbed by an independent zero-mean Gaussian angular offset (small-angle tilt in the plane perpendicular to the beam) before ray tracing, so the whole beam — including any divergence cone and finite aperture — rotates together; the resulting lateral positional error scales with range (≈ range·σ), giving the across-beam axis of the per-point error ellipsoid (distinct from beam divergence, which models within-beam footprint spread). Misses are not perturbed. The new field round-trips through `exportScans()`/`loadXML()`.
3251
- Generalized synthetic-scan primitive-data transfer: `syntheticScan()` now copies *any* scalar primitive-data field (`float`/`double`/`int`/`uint`) named in a scan's ASCII column format onto its hit points, rather than only the hardcoded `object_label` and `reflectivity_lidar` labels. The scan column format is the source of truth — adding a non-standard label to it makes the scanner sample that primitive data per hit — and the special `reflectivity_lidar` semantics (modulating hit intensity) are preserved. Geometry/standard tokens (coordinates, colors, row/column, zenith/azimuth, `raydir`) continue to be handled by the file I/O path and are never treated as primitive-data labels.
3352
- Hardened `gapfillMisses()` against out-of-bounds reads and runaway fills on ASCII point clouds that lack row/column indices (whose angular grid is reconstructed from timestamps). Unsigned `size() - 1` loop bounds that could underflow on empty/single-hit tables were rewritten as `r + 1 < size()`; per-beam `dt`/`dtheta` arrays are now value-initialized; the routine bails out early (returning no filled points) when fewer than two cleaned hits remain or when the reconstructed timestamp spacing is non-finite or non-positive; the per-gap fill count is capped at the scan's row count; and reconstructed grid positions outside the scan's row/column range are skipped. This fixes a non-deterministic crash on the multi-return file-import path.
53+
- Replaced the s_hull_pro 2D Delaunay triangulation library with [CDT](https://github.com/artem-ogre/CDT) (v1.4.4, bundled header-only in `plugins/lidar/lib/CDT`) as the engine behind `triangulateHitPoints()`. CDT uses robust geometric predicates, so the previous per-scan rotate-and-retry recovery loop (which retried triangulation up to three times, rotating the azimuth coordinate by 0.25·π each time to dodge s_hull's non-robust-predicate failures) was removed; a triangulation failure is now deterministic and the affected scan is skipped. The `Shx`/`Triad` point/triangle types and the `de_duplicate()` helper that `LiDAR.cpp` still relies on were reduced to minimal self-contained definitions in the new `triangulation_cdt.h` adapter, and `s_hull_pro` was deleted entirely. The 1e-6 input-coordinate snapping (for cross-architecture determinism of the `cart2sphere` inputs) is retained. This also resolves a latent licensing mismatch — s_hull_pro is GPL-3.0 while Helios is GPL-2.0; CDT is MPL-2.0. No public API change.
3454

3555
## Solar Position
3656
- Fixed `SolarPosition` to honor fractional UTC offsets: the local standard time meridian (`LSTM`) was truncated to an integer, so half-hour zones (e.g. India, +05:30) snapped to the nearest whole hour. `LSTM` is now computed in floating point.

doc/UserGuide.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ This will first rotate the patch by 0.25\f$\pi\f$ rad about the x-axis such that
962962

963963
\subsection TextureColor Coloring Primitives by Texture Map
964964

965-
Patches: To color a Patch based on an image, simply pass the path to a PNG or JPEG image to the appropriate argument of the addPatch() command. Note that the path should either be absolute, or relative to the directory where the executable will be run (typically the `build' directory).
965+
Patches: To color a Patch based on an image, simply pass the path to a PNG or JPEG image to the appropriate argument of the addPatch() command. Note that the path should either be absolute, or relative to the directory where the executable will be run (typically the 'build' directory).
966966

967967
~~~~~~{.cpp}
968968
vec3 center = make_vec3(0,0,1);

plugins/lidar/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ if(NOT "visualizer" IN_LIST PLUGINS AND NOT TARGET visualizer)
2020
target_link_libraries(visualizer PUBLIC helios)
2121
endif()
2222

23-
add_library(lidar STATIC "src/LiDAR.cpp" "src/fileIO.cpp" "tests/selfTest.cpp" "../../core/lib/pugixml/pugixml.cpp" "lib/s_hull_pro/s_hull_pro.cpp")
23+
add_library(lidar STATIC "src/LiDAR.cpp" "src/fileIO.cpp" "tests/selfTest.cpp" "../../core/lib/pugixml/pugixml.cpp")
2424

2525
target_include_directories(lidar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
26-
target_include_directories(lidar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib/s_hull_pro)
26+
target_include_directories(lidar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib/CDT/include)
2727

2828
target_link_libraries(lidar PUBLIC visualizer collisiondetection)
2929
add_dependencies(lidar visualizer collisiondetection)

0 commit comments

Comments
 (0)