or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compression.mdcopc.mdcore-io.mddata-containers.mdindex.mdio-handlers.mdpoint-data.mdvlr.md

copc.mddocs/

0

# COPC Operations

1

2

Cloud Optimized Point Cloud (COPC) support for efficient web-based and spatial querying of large LiDAR datasets. COPC enables selective data access and HTTP streaming, making it ideal for web applications and large-scale data processing.

3

4

## Capabilities

5

6

### COPC Reader

7

8

Specialized reader for COPC files with support for spatial and level-based queries.

9

10

```python { .api }

11

class CopcReader:

12

def __init__(self, stream, close_fd=True, http_num_threads=8, decompression_selection=None):

13

"""

14

Initialize COPC reader.

15

16

Parameters:

17

- stream: BinaryIO - COPC file stream

18

- close_fd: bool - Whether to close file descriptor (default: True)

19

- http_num_threads: int - Number of HTTP worker threads (default: 8)

20

- decompression_selection: DecompressionSelection - Fields to decompress

21

"""

22

23

@classmethod

24

def open(cls, source, http_num_threads=8, decompression_selection=None) -> CopcReader:

25

"""

26

Open COPC file from local path or HTTP URL.

27

28

Parameters:

29

- source: str, Path, or URL - COPC file location

30

- http_num_threads: int - Number of HTTP worker threads for remote files

31

- decompression_selection: DecompressionSelection - Fields to decompress

32

33

Returns:

34

CopcReader: COPC reader instance

35

"""

36

37

@property

38

def header(self) -> LasHeader:

39

"""Get LAS header for the COPC file."""

40

41

def query(self, bounds=None, resolution=None, level=None) -> ScaleAwarePointRecord:

42

"""

43

General query method supporting spatial bounds, resolution, and level constraints.

44

45

Parameters:

46

- bounds: Bounds - Spatial bounds for query (optional)

47

- resolution: float - Target point resolution/density (optional)

48

- level: int or range - Octree level(s) to query (optional)

49

50

Returns:

51

ScaleAwarePointRecord: Points matching query criteria

52

"""

53

54

def spatial_query(self, bounds: Bounds) -> ScaleAwarePointRecord:

55

"""

56

Query points within specified spatial bounds.

57

58

Parameters:

59

- bounds: Bounds - Spatial query bounds

60

61

Returns:

62

ScaleAwarePointRecord: Points within bounds

63

"""

64

65

def level_query(self, level) -> ScaleAwarePointRecord:

66

"""

67

Query points at specific octree level(s).

68

69

Parameters:

70

- level: int or range - Octree level or level range

71

72

Returns:

73

ScaleAwarePointRecord: Points at specified level(s)

74

"""

75

76

def close(self):

77

"""Close COPC reader and free resources."""

78

79

def __enter__(self) -> CopcReader: ...

80

def __exit__(self, exc_type, exc_val, exc_tb): ...

81

```

82

83

**Usage Examples:**

84

85

```python

86

import laspy

87

from laspy import CopcReader, Bounds

88

89

# Open local COPC file

90

with CopcReader.open('data.copc.laz') as reader:

91

print(f"COPC file has {reader.header.point_count} points")

92

93

# Query all points

94

all_points = reader.query()

95

print(f"Retrieved {len(all_points)} points")

96

97

# Open remote COPC file via HTTP

98

url = "https://example.com/data.copc.laz"

99

with CopcReader.open(url, http_num_threads=4) as reader:

100

# Spatial query

101

bounds = Bounds(

102

mins=[100, 200, 0],

103

maxs=[200, 300, 50]

104

)

105

spatial_points = reader.spatial_query(bounds)

106

print(f"Spatial query returned {len(spatial_points)} points")

107

108

# Level-based query for different detail levels

109

with CopcReader.open('data.copc.laz') as reader:

110

# Get coarse overview (low levels)

111

overview = reader.level_query(range(0, 3))

112

113

# Get detailed data (high levels)

114

detailed = reader.level_query(range(8, 12))

115

116

print(f"Overview: {len(overview)} points")

117

print(f"Detailed: {len(detailed)} points")

118

```

119

120

### Spatial Bounds

121

122

Geometric bounds definition for spatial queries and region-of-interest operations.

123

124

```python { .api }

125

class Bounds:

126

def __init__(self, mins, maxs):

127

"""

128

Create spatial bounds.

129

130

Parameters:

131

- mins: array-like - Minimum coordinates [x, y] or [x, y, z]

132

- maxs: array-like - Maximum coordinates [x, y] or [x, y, z]

133

"""

134

135

@property

136

def mins(self) -> np.ndarray:

137

"""Minimum coordinate values."""

138

139

@property

140

def maxs(self) -> np.ndarray:

141

"""Maximum coordinate values."""

142

143

def overlaps(self, other: Bounds) -> bool:

144

"""

145

Check if bounds overlap with another bounds.

146

147

Parameters:

148

- other: Bounds - Other bounds to check against

149

150

Returns:

151

bool: True if bounds overlap

152

"""

153

154

@staticmethod

155

def ensure_3d(mins, maxs) -> Bounds:

156

"""

157

Ensure bounds are 3D by extending 2D bounds.

158

159

Parameters:

160

- mins: array-like - Minimum coordinates

161

- maxs: array-like - Maximum coordinates

162

163

Returns:

164

Bounds: 3D bounds object

165

"""

166

```

167

168

**Usage Examples:**

169

170

```python

171

import numpy as np

172

from laspy import Bounds

173

174

# Create 2D bounds (Z dimension will be unlimited)

175

bounds_2d = Bounds(

176

mins=[1000, 2000],

177

maxs=[1500, 2500]

178

)

179

180

# Create 3D bounds

181

bounds_3d = Bounds(

182

mins=[1000, 2000, 100],

183

maxs=[1500, 2500, 200]

184

)

185

186

# Check bounds properties

187

print(f"2D bounds mins: {bounds_2d.mins}")

188

print(f"2D bounds maxs: {bounds_2d.maxs}")

189

190

# Check overlap

191

other_bounds = Bounds([1400, 2400], [1600, 2600])

192

overlaps = bounds_2d.overlaps(other_bounds)

193

print(f"Bounds overlap: {overlaps}")

194

195

# Convert 2D to 3D bounds

196

bounds_3d_converted = Bounds.ensure_3d([1000, 2000], [1500, 2500])

197

print(f"3D converted: {bounds_3d_converted.mins} to {bounds_3d_converted.maxs}")

198

```

199

200

## Advanced COPC Usage

201

202

### Multi-Region Queries

203

204

```python

205

import laspy

206

from laspy import CopcReader, Bounds

207

208

def query_multiple_regions(copc_file, regions):

209

"""Query multiple spatial regions efficiently."""

210

with CopcReader.open(copc_file) as reader:

211

all_points = []

212

213

for region_name, (mins, maxs) in regions.items():

214

bounds = Bounds(mins, maxs)

215

points = reader.spatial_query(bounds)

216

print(f"Region '{region_name}': {len(points)} points")

217

all_points.append(points)

218

219

return all_points

220

221

# Define regions of interest

222

regions = {

223

"downtown": ([1000, 2000, 0], [1200, 2200, 100]),

224

"park": ([1500, 2500, 0], [1700, 2700, 50]),

225

"industrial": ([2000, 3000, 0], [2300, 3300, 80])

226

}

227

228

results = query_multiple_regions('city.copc.laz', regions)

229

```

230

231

### Progressive Level-of-Detail

232

233

```python

234

import laspy

235

from laspy import CopcReader

236

237

def progressive_query(copc_file, max_points=1000000):

238

"""Query with progressive level-of-detail until point limit reached."""

239

with CopcReader.open(copc_file) as reader:

240

level = 0

241

total_points = 0

242

243

while total_points < max_points:

244

level_points = reader.level_query(level)

245

if len(level_points) == 0:

246

break

247

248

total_points += len(level_points)

249

print(f"Level {level}: {len(level_points)} points (total: {total_points})")

250

251

# Process level points

252

yield level, level_points

253

level += 1

254

255

# Use progressive querying

256

for level, points in progressive_query('large.copc.laz'):

257

# Process points at this level of detail

258

density = len(points) / (points.x.max() - points.x.min()) / (points.y.max() - points.y.min())

259

print(f"Level {level} density: {density:.2f} points/unit²")

260

```

261

262

### HTTP Streaming with Custom Threading

263

264

```python

265

import laspy

266

from laspy import CopcReader, DecompressionSelection

267

268

# Optimize for network access

269

def stream_copc_efficiently(url, regions, num_threads=16):

270

"""Stream COPC data with optimized HTTP settings."""

271

272

# Use selective decompression to reduce bandwidth

273

selection = DecompressionSelection.base() # Only essential fields

274

275

with CopcReader.open(url,

276

http_num_threads=num_threads,

277

decompression_selection=selection) as reader:

278

279

print(f"Streaming from: {url}")

280

print(f"File bounds: {reader.header.mins} to {reader.header.maxs}")

281

282

for region_name, bounds in regions.items():

283

print(f"Fetching region: {region_name}")

284

points = reader.spatial_query(bounds)

285

286

# Process immediately to minimize memory usage

287

ground_points = points[points.classification == 2]

288

yield region_name, ground_points

289

290

# Stream from cloud storage

291

url = "https://cloud-storage.example.com/lidar/city.copc.laz"

292

regions = {

293

"area1": Bounds([1000, 2000], [1100, 2100]),

294

"area2": Bounds([1200, 2200], [1300, 2300])

295

}

296

297

for region_name, ground_points in stream_copc_efficiently(url, regions):

298

print(f"Processing {len(ground_points)} ground points from {region_name}")

299

```

300

301

## Integration with Standard LAS Operations

302

303

COPC data can be seamlessly integrated with standard laspy operations:

304

305

```python

306

import laspy

307

from laspy import CopcReader, Bounds

308

309

# Query COPC data and write to standard LAS

310

with CopcReader.open('input.copc.laz') as reader:

311

# Query region of interest

312

bounds = Bounds([1000, 2000, 0], [1500, 2500, 100])

313

points = reader.spatial_query(bounds)

314

315

# Create LAS data container

316

las = laspy.LasData(reader.header, points)

317

318

# Apply filters

319

las.points = las.points[las.classification.isin([2, 3, 4])] # Ground, low/med vegetation

320

321

# Write filtered data

322

las.write('filtered_region.las')

323

324

# Convert COPC query results to different point format

325

with CopcReader.open('input.copc.laz') as reader:

326

points = reader.query()

327

las = laspy.LasData(reader.header, points)

328

329

# Convert to point format with RGB

330

converted = laspy.convert(las, point_format_id=7)

331

converted.write('converted.las')

332

```

333

334

## Error Handling

335

336

COPC operations can raise specific exceptions:

337

338

```python

339

import laspy

340

from laspy import CopcReader, Bounds

341

from laspy.errors import LaspyException

342

343

try:

344

with CopcReader.open('https://example.com/missing.copc.laz') as reader:

345

points = reader.spatial_query(Bounds([0, 0], [100, 100]))

346

except LaspyException as e:

347

print(f"COPC error: {e}")

348

except Exception as e:

349

print(f"Network or other error: {e}")

350

```