Check 3DEP lidar coverage
You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.
GET /domains/{domain_id}/pointclouds/3dep/coverage answers four questions
about a domain before you spend anything on it: is there public lidar here,
whose is it, how dense is it, and will a fetch fit the budget?
It is a catalog lookup and some geometry — no point data is read — so it returns immediately. Every failure mode of fetching a 3DEP point cloud is visible here first, which is the reason to run it.
Prerequisites
Section titled “Prerequisites”-
An API key: my-api-key.
-
A domain: your-domain-id. See Create a domain.
Run the check
Section titled “Run the check”curl -X 'GET' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/pointclouds/3dep/coverage' \ -H 'accept: application/json' \ -H 'api-key: my-api-key'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
# A single fetch is capped at 200 million points; compare the estimate to it.POINT_BUDGET = 200_000_000
domain = ff.Domain.from_id("your-domain-id")coverage = ff.point_clouds.check_3dep_coverage(domain)
if not coverage.available: raise SystemExit("No 3DEP lidar covers this domain.")
if coverage.estimated_point_count > POINT_BUDGET: raise SystemExit( f"Estimated {coverage.estimated_point_count:,} points exceeds the " f"{POINT_BUDGET:,} budget — use a smaller domain." )
# Pin an acquisition by passing a dataset's .name back on the create request.{ "available": true, "coverage_fraction": 1.0, "datasets": [ { "name": "MT_Statewide_P3_4_B21", "url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/MT_Statewide_P3_4_B21/ept.json", "contribution_fraction": 1.0, "estimated_density": 14.811981421134373, "estimated_points": 7847291 } ], "estimated_point_count": 7847291}Reading the response
Section titled “Reading the response”| Field | What to do with it |
|---|---|
available | false means a create request will be rejected. Stop here. |
coverage_fraction | The share of the domain any 3DEP lidar covers, 0.0–1.0. See the caveat below. |
estimated_point_count | Roughly how many points a fetch would return. |
point_budget | The per-fetch ceiling — 200,000,000 points. |
exceeds_point_budget | true means a create request will be rejected. Shrink the domain. |
datasets[] | The acquisitions that would be read, in the order they would be used. |
Each entry in datasets[] describes one USGS acquisition:
name— pass it back indatasetson the create request to pin the fetch to this acquisition.contribution_fraction— the share of the domain this acquisition would supply. Acquisitions overlap freely, so this is what is left over after the ones listed before it have taken their part, not the raw overlap. The values are disjoint and sum tocoverage_fraction.estimated_density— average points per square metre over the acquisition’s full published extent.estimated_points— derived from density and area, so treat it as an order of magnitude rather than a count.
No lidar here
Section titled “No lidar here”Some parts of the country do not have 3DEP lidar data available. When that is the
case the response is unambiguous and datasets is empty:
{ "available": false, "coverage_fraction": 0.0, "datasets": [], "estimated_point_count": 0, "point_budget": 200000000, "exceeds_point_budget": false}A create request against this domain returns a 422. Your options are a different
area, or a canopy source that does not need lidar — NAIP and Meta both produce a
chm band without one, and neither has coverage gaps. See
Choosing a source.
More than one acquisition
Section titled “More than one acquisition”When no single survey covers the domain, the backend combines the fewest that fill it. Here two acquisitions are needed, and they are not equivalent — the first supplies 87.7% of the domain at 28.3 pts/m², the second the remaining 12.3% at 3.0 pts/m², an order of magnitude sparser:
{ "available": true, "coverage_fraction": 1.0, "datasets": [ { "name": "AZ_MohaveCoconino_1_D23", "url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/AZ_MohaveCoconino_1_D23/ept.json", "contribution_fraction": 0.8773581560283717, "estimated_density": 28.31556851085709, "estimated_points": 9534173 }, { "name": "AZ_MohaveCo_2_2021", "url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/AZ_MohaveCo_2_2021/ept.json", "contribution_fraction": 0.12264184397162811, "estimated_density": 2.9543377555480443, "estimated_points": 139052 } ], "estimated_point_count": 9673225, "point_budget": 200000000, "exceeds_point_budget": false}
The same two acquisitions, by share of the domain and by density. The minority acquisition is nearly ten times sparser — read both panels, not just the first.
This is worth looking at rather than skipping past. A mosaic puts a seam between flights of different dates and densities through your data, and downstream products inherit it — a CHM built across this domain is detailed on one side of the seam and coarse on the other. If that matters, pin the better acquisition and accept partial coverage rather than taking both.
Too many points
Section titled “Too many points”A single fetch is capped at 200 million points. Density and area together decide whether you are over it, so a small domain over dense lidar can exceed the budget as easily as a large one over sparse lidar:
{ "available": true, "coverage_fraction": 1.0, "datasets": [ { "name": "MT_Statewide_P3_4_B21", "url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/MT_Statewide_P3_4_B21/ept.json", "contribution_fraction": 1.0, "estimated_density": 14.811981421134373, "estimated_points": 227552496 } ], "estimated_point_count": 227552496, "point_budget": 200000000, "exceeds_point_budget": true}Attempting the fetch anyway returns a 422 naming both numbers. Shrink the domain — note that domains are capped at 16 km² regardless — and check again.
Next steps
Section titled “Next steps”- Fetch a 3DEP point cloud — pin the acquisition this check found and pull the points.
- Inspect a point cloud — the check that catches what this one cannot.
- About point clouds — what 3DEP is,
why acquisitions are published separately, and what
sourcerecords.
Common pitfalls
Section titled “Common pitfalls”- Skipping the pre-flight and reading
source.coverage_fractionafterwards. Both report the same number, but only one of them is free. A rejected create request costs a round trip; a fetch that succeeds with a hole in it costs a background job and everything you build on it. - Treating
estimated_point_countas a count. It is derived from published density over published extent. In a verified run the estimate was 7,847,291 and the fetch returned 10,512,255 — within an order of magnitude, not within a rounding error. - Assuming a covered domain is a uniformly covered domain. Read
datasets[].estimated_densitybefore you assume the far corner is as good as the near one. - Pinning an acquisition without checking coverage first. Names come from this endpoint. An acquisition that does not exist, or that exists but does not overlap your domain, is a 422 with two different messages.