Skip to content

feat: report area, point density and pulse density in summarise() - #326

Open
agrigoriev wants to merge 1 commit into
develfrom
feat/summarise-density
Open

feat: report area, point density and pulse density in summarise()#326
agrigoriev wants to merge 1 commit into
develfrom
feat/summarise-density

Conversation

@agrigoriev

@agrigoriev agrigoriev commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Ports lidR's scalar density() quality-control check into lasR. The
summary stage now computes the coverage area in a single streaming pass
and exposes three new fields in the summarise() output list:

  • area — processed bounding-box area (sum of per-chunk core extents,
    buffer excluded)
  • density — point density (npoints / area)
  • pulse_density — pulse density (first returns / area)
u <- exec(reader() + summarise(), on = f)
u$area; u$density; u$pulse_density

Semantics

  • Area uses the sum of per-chunk core (buffer-excluded) extents, matching
    lidR's density(LAScatalog) (sum of per-file bounding boxes).
  • Following lidR's print/summary convention, the number of pulses is the
    count of first returns (ReturnNumber == 1), already collected by the
    stage as npoints_per_return[1]. It is not derived from
    gpstime-based pulse identification (retrieve_pulses).
  • Density is buffer-independent: buffer points are excluded from both
    npoints and area.

Implementation

  • summary.hdouble area member + set_chunk override.
  • summary.cpp — accumulate core-extent bbox area per chunk in
    set_chunk; sum in merge; emit area, density, pulse_density in
    both to_R() and to_json().
  • R/stages.R + man/summarise.Rd — document the new fields and the
    "pulses = first returns" convention.

Tests

Added to tests/testthat/test-summarise.R:

  • single-file relational check (density == npoints/area,
    pulse_density == npoints_per_return["1"]/area)
  • multi-file (bcts) check that pulse density uses the first-return count

Verified bbox bcts values: 13.7 points/m², 9.6 pulses/m².

Port lidR's scalar density() QC check into lasR. The summary stage now
accumulates the coverage bounding-box area (sum of per-chunk core
extents, buffer excluded) and exposes three new fields in its output:

  - area          : processed bounding-box area
  - density       : point density (npoints / area)
  - pulse_density  : pulse density (first returns / area)

Following lidR's print/summary convention, the number of pulses is the
number of first returns (ReturnNumber == 1), not a gpstime-based pulse
identification. Density is buffer-independent: buffer points are excluded
from both npoints and area.
@agrigoriev
agrigoriev force-pushed the feat/summarise-density branch from dc586af to cec3307 Compare May 27, 2026 08:06
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.27%. Comparing base (6ec1b89) to head (cec3307).
⚠️ Report is 22 commits behind head on devel.

Files with missing lines Patch % Lines
src/LASRstages/summary.cpp 84.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            devel     #326      +/-   ##
==========================================
+ Coverage   72.15%   72.27%   +0.11%     
==========================================
  Files         230      230              
  Lines       17576    17657      +81     
==========================================
+ Hits        12682    12761      +79     
- Misses       4894     4896       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant