Skip to content

Commit 9d1a0e9

Browse files
authored
Merge pull request #10 from oyhj1801/main
Writing support, error handling and simplifications
2 parents 5bd682e + a7ed1df commit 9d1a0e9

20 files changed

+1578
-1905
lines changed

Cargo.toml

+13-16
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
[workspace]
2-
members = [".", "viewer"]
3-
default-members = ["."]
4-
51
[package]
62
name = "copc-rs"
7-
version = "0.3.0"
8-
authors = ["Pirmin Kalberer <[email protected]>"]
3+
version = "0.5.0"
4+
authors = ["Pirmin Kalberer <[email protected]>", "Øyvind Hjermstad @oyhj1801"]
95
edition = "2021"
106

11-
description = "Cloud Optimized Point Cloud (COPC) reader."
7+
description = "Cloud Optimized Point Cloud (COPC) reader and writer."
128
homepage = "https://github.com/pka/copc-rs"
139
repository = "https://github.com/pka/copc-rs"
1410
readme = "README.md"
1511
license = "MIT/Apache-2.0"
16-
keywords = ["lidar", "pointcloud", "copc", "las", "geo"]
17-
categories = ["science::geo", "rendering::data-formats"]
18-
exclude = [
19-
"tests/data",
20-
]
12+
keywords = ["lidar", "pointcloud", "copc", "las", "laz", "geo"]
2113

2214
[dependencies]
2315
byteorder = "1.4.3"
24-
las = "0.8.1"
25-
laz = "0.8.2"
16+
fastrand = "2.3.0"
17+
las-crs = { git = "https://github.com/oyhj1801/las-crs" }
18+
las = {version = "0.9.2", features = ["laz"]}
19+
laz = "0.9.2"
20+
log = "0.4.25"
21+
thiserror = "2.0.6"
22+
crs-definitions = "0.3.0"
2623

2724
[dev-dependencies]
28-
http-range-client = "0.7.0"
29-
env_logger = "0.10.0"
25+
env_logger = "0.11.8"
26+
http-range-client = "0.9.0" # default-features = false, features = ["ureq-sync"]

LICENSE-MIT

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2020 Pirmin Kalberer
1+
Copyright (c) 2025 Pirmin Kalberer, Øyvind Hjermstad
22

33
Permission is hereby granted, free of charge, to any
44
person obtaining a copy of this software and associated

README.md

+66-6
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,86 @@
33
[![crates.io version](https://img.shields.io/crates/v/copc-rs.svg)](https://crates.io/crates/copc-rs)
44
[![docs.rs docs](https://docs.rs/copc-rs/badge.svg)](https://docs.rs/copc-rs)
55

6+
copc-rs is a rust library for reading and writing Cloud Optimized Point Cloud ([COPC](https://copc.io/)) data.
7+
It utilizes the las and laz crates heavily and tries to offer a similiar API to las.
68

7-
copc-rs is a library for reading Cloud Optimized Point Cloud ([COPC](https://copc.io/)) data.
9+
## Usage examples
810

9-
10-
## Usage example
11+
### Reader
1112

1213
```rust
13-
let laz_file = BufReader::new(File::open("autzen-classified.copc.laz")?);
14-
let mut copc_reader = CopcReader::open(laz_file)?;
14+
let mut copc_reader = CopcReader::from_path("autzen-classified.copc.laz")?;
1515
for point in copc_reader.points(LodSelection::Level(0), BoundsSelection::All)?.take(5) {
1616
println!("Point coordinates: ({}, {}, {})", point.x, point.y, point.z);
1717
}
1818
```
1919

20+
Full example with bounds selection:
21+
```rust
22+
use copc_rs::{Bounds, BoundsSelection, CopcReader, LodSelection, Vector};
23+
24+
fn main() {
25+
let mut copc_reader = CopcReader::from_path("./lidar.copc.laz").unwrap();
26+
27+
let bounds = Bounds {
28+
min: Vector {
29+
x: 698_100.,
30+
y: 6_508_100.,
31+
z: 0.,
32+
},
33+
max: Vector {
34+
x: 698_230.,
35+
y: 6_508_189.,
36+
z: 2_000.,
37+
},
38+
};
39+
40+
for point in copc_reader
41+
.points(LodSelection::Resolution(1.), BoundsSelection::Within(bounds))
42+
.unwrap()
43+
{
44+
// do something with the points
45+
}
46+
}
47+
```
48+
2049
Run an example:
2150
```
2251
cargo run --example copc_http
2352
```
2453

54+
### Writer [[*]](#writing-is-still-a-wip)
55+
56+
```rust
57+
use copc_rs::CopcWriter;
58+
use las::Reader;
59+
60+
fn main() {
61+
let mut las_reader = Reader::from_path("./lidar.las").unwrap();
62+
63+
let header = las_reader.header().clone();
64+
let num_points = header.number_of_points() as i32;
65+
let points = las_reader.points().filter_map(las::Result::ok);
66+
67+
let mut copc_writer = CopcWriter::from_path("./lidar.copc.laz", header, -1, -1).unwrap();
68+
69+
copc_writer.write(points, num_points).unwrap();
70+
71+
println!("{:#?}", copc_writer.copc_info());
72+
}
73+
```
74+
75+
## Writing is still a WIP
76+
77+
Writing of the octree structure seem to work, so spatial queries in full resolution on copc-rs written files should be good.
78+
BUT the octree levels does not yet contain a similar point distribution as the whole cloud so results from resolution queries on copc-rs written files are wrong.
79+
This means the written files will look bad in viewers.
80+
81+
82+
I will look into it when I find time, for now I only need full resolution spatial queries in my current project anyway.
83+
84+
-oyhj1801
2585

2686
## Credits
2787

28-
This library depends heavily on the work of Thomas Montaigu (@tmontaigu) and Pete Gadomski (@gadomski).
88+
This library depends heavily on the work of Thomas Montaigu (@tmontaigu) and Pete Gadomski (@gadomski), the authors of the laz and las crates.

examples/copc_http.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use copc_rs::{BoundsSelection, CopcReader, LodSelection};
22
use http_range_client::HttpReader;
33

4-
fn main() -> laz::Result<()> {
4+
fn main() -> copc_rs::Result<()> {
55
env_logger::init();
66
let mut http_reader =
77
HttpReader::new("https://s3.amazonaws.com/hobu-lidar/autzen-classified.copc.laz");
88
// http_reader.set_min_req_size(1_048_576); // 1MB - 3 requests, 3'145'728 B
99
// http_reader.set_min_req_size(524288); // 512KB - 4 requests, 2'097'152 B
1010
http_reader.set_min_req_size(262144); // 256KB - 5 requests, 1'310'720 B
1111

12-
let mut copc_reader = CopcReader::open(http_reader)?;
12+
let mut copc_reader = CopcReader::new(http_reader)?;
1313

1414
let mut max_z: f64 = 0.0;
1515
for point in copc_reader.points(LodSelection::Level(0), BoundsSelection::All)? {

examples/copc_to_xyz.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use copc_rs::{BoundsSelection, CopcReader, LodSelection};
22
use std::env;
33
use std::fs::File;
4-
use std::io::{BufReader, BufWriter, Write};
4+
use std::io::{BufWriter, Write};
55
use std::path::Path;
66

7-
fn main() -> laz::Result<()> {
7+
fn main() -> copc_rs::Result<()> {
88
let lazfn = env::args().nth(1).expect("COPC file required");
99

10-
let laz_file = BufReader::new(File::open(&lazfn)?);
11-
let mut copc_reader = CopcReader::open(laz_file)?;
10+
let mut copc_reader = CopcReader::from_path(&lazfn)?;
1211

1312
let dest = Path::new(&lazfn).with_extension("xyz");
1413
println!("Writing {:?}", &dest);

examples/print_points.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
use copc_rs::{BoundsSelection, CopcReader, LodSelection};
22
use std::env;
3-
use std::fs::File;
4-
use std::io::BufReader;
53

6-
fn main() -> laz::Result<()> {
4+
fn main() -> copc_rs::Result<()> {
75
let lazfn = env::args().nth(1).expect("COPC file required");
86

9-
let laz_file = BufReader::new(File::open(&lazfn)?);
10-
let mut copc_reader = CopcReader::open(laz_file)?;
7+
let mut copc_reader = CopcReader::from_path(&lazfn)?;
118
for (i, point) in copc_reader
129
.points(LodSelection::Level(0), BoundsSelection::All)?
1310
.enumerate()

src/bounds.rs

-117
This file was deleted.

0 commit comments

Comments
 (0)