REPROJECT_LAS
Reprojects a LiDAR point cloud from one coordinate reference system (CRS) to another. The workflow retrieves projection definitions from epsg.io and builds a PDAL pipeline that transforms the dataset using filters.reprojection. Both simple horizontal CRS transformations and compound horizontal+vertical CRS transformations are supported.
The resulting dataset is written as a COPC (Cloud Optimized Point Cloud) file with appropriate scaling and offsets and returned as a LAS-compatible artifact.
If the source and target CRS are the same, or if either parameter is absent, the executor returns the input artifact unchanged without downloading, processing, or reuploading any data. This makes it safe to include REPROJECT_LAS in every pipeline regardless of whether reprojection is actually needed.
Typical use: normalizing datasets into a common coordinate system before further processing, tiling, or visualization. Usually the first step in any pipeline that works with data in a non-standard CRS.
Contract
| Type | REPROJECT_LAS |
| Accepts | input_las: las |
| Produces | output_las: las |
| Params | source_epsg (string), target_epsg (string) |
Inputs
| Slot | Type | Description |
|---|---|---|
input_las | las | Source point cloud dataset |
Outputs
| Slot | Type | Description |
|---|---|---|
output_las | las | Reprojected point cloud dataset |
Parameters
| Name | Type | Description |
|---|---|---|
source_epsg | string | CRS of the input dataset (e.g. "EPSG:2271" or "EPSG:26915+EPSG:5703") |
target_epsg | string | Target CRS to transform into (e.g. "EPSG:3857") |
Both parameters accept standard EPSG codes, ESRI codes, and compound CRS strings (horizontal+vertical).
Passthrough behavior
Before any data movement occurs, the executor checks three conditions:
source_epsgis not null or emptytarget_epsgis not null or emptysource_epsg≠target_epsg
If all three conditions hold, the full reprojection pipeline runs. If any condition fails — same EPSG, blank parameter, or parameter absent — the executor returns the input artifact directly as output_las (same URI, hash, and metadata). No data is downloaded, processed, or uploaded.
This means pipelines can include REPROJECT_LAS unconditionally: jobs that don't require reprojection simply supply equal or empty EPSG values and the step resolves in milliseconds with no I/O cost.
What it does internally
0. Check source vs. target CRS
If source_epsg and target_epsg are both non-empty and differ, execution continues. Otherwise, the input artifact is returned immediately as the output and the remaining steps are skipped.
1. Parse CRS definitions
CRS strings are split on + to separate horizontal and vertical components, allowing support for compound CRS such as EPSG:26915+EPSG:5703.
2. Fetch WKT definitions
For each CRS component, the workflow queries https://epsg.io/{code}.wkt to retrieve the full WKT projection definition. PDAL performs more reliably with explicit WKT than with bare EPSG codes in some edge cases.
3. Build PDAL pipeline
Depending on whether the CRS is simple or compound, one of two pipelines is used:
Simple reprojection (horizontal only):
LAS → filters.reprojection → writers.copcCompound reprojection (horizontal + vertical):
LAS → filters.reprojection (horizontal) → filters.reprojection (vertical) → writers.copcThis enables vertical datum transformations (e.g. ellipsoidal height → NAVD88).
4. Write output
Output is written with writers.copc using scale_x/y/z = 0.001 and offset = auto for correct quantization.
Recipe usage
json
{
"id": "reproject",
"type": "REPROJECT_LAS",
"inputs": { "input_las": "job:input_las" },
"outputs": { "output_las": "step:reproject.output_las" },
"param_keys": ["source_epsg", "target_epsg"]
}Job params:
json
"params": {
"reproject": {
"source_epsg": "EPSG:2271",
"target_epsg": "EPSG:3857"
}
}Artifact storage path
artifacts/job_{id}/reproject/output.las