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

data-containers.mddocs/

0

# Data Container Classes

1

2

Primary data container classes for managing LAS file components including headers, point data, and metadata integration. These classes provide the core data structures that synchronize all aspects of LAS files.

3

4

## Capabilities

5

6

### LAS Data Container

7

8

Main container class that synchronizes header, points, and VLRs into a cohesive LAS file representation.

9

10

```python { .api }

11

class LasData:

12

def __init__(self, header: LasHeader, points=None):

13

"""

14

Create LAS data container.

15

16

Parameters:

17

- header: LasHeader - LAS file header

18

- points: PackedPointRecord or ScaleAwarePointRecord - Point data (optional)

19

"""

20

21

@property

22

def point_format(self) -> PointFormat:

23

"""Point format definition."""

24

25

@property

26

def xyz(self) -> np.ndarray:

27

"""XYZ coordinates as Nx3 array."""

28

29

@property

30

def points(self) -> PackedPointRecord:

31

"""Point record data."""

32

33

@property

34

def vlrs(self) -> VLRList:

35

"""Variable Length Records."""

36

37

@property

38

def evlrs(self) -> Optional[VLRList]:

39

"""Extended Variable Length Records."""

40

41

@property

42

def header(self) -> LasHeader:

43

"""LAS file header."""

44

45

def add_extra_dim(self, params: ExtraBytesParams):

46

"""

47

Add single extra dimension to point format.

48

49

Parameters:

50

- params: ExtraBytesParams - Extra dimension parameters

51

"""

52

53

def add_extra_dims(self, params: List[ExtraBytesParams]):

54

"""

55

Add multiple extra dimensions to point format.

56

57

Parameters:

58

- params: List[ExtraBytesParams] - List of extra dimension parameters

59

"""

60

61

def remove_extra_dim(self, name: str):

62

"""

63

Remove extra dimension by name.

64

65

Parameters:

66

- name: str - Name of dimension to remove

67

"""

68

69

def remove_extra_dims(self, names: Iterable[str]):

70

"""

71

Remove multiple extra dimensions.

72

73

Parameters:

74

- names: Iterable[str] - Names of dimensions to remove

75

"""

76

77

def update_header(self):

78

"""Update header statistics from current point data."""

79

80

def write(self, destination, do_compress=None, laz_backend=None):

81

"""

82

Write LAS data to file.

83

84

Parameters:

85

- destination: str, Path, or file-like - Output destination

86

- do_compress: bool - Force compression on/off (optional)

87

- laz_backend: LazBackend - Compression backend (optional)

88

"""

89

90

def change_scaling(self, scales=None, offsets=None):

91

"""

92

Change coordinate scaling factors.

93

94

Parameters:

95

- scales: array-like - New scale factors for X,Y,Z (optional)

96

- offsets: array-like - New offset values for X,Y,Z (optional)

97

"""

98

99

def __getattr__(self, name):

100

"""Access point dimensions as attributes (e.g., las.x, las.classification)."""

101

102

def __setattr__(self, name, value):

103

"""Set point dimension values as attributes."""

104

105

def __getitem__(self, key):

106

"""Access point dimensions by name or index."""

107

108

def __setitem__(self, key, value):

109

"""Set point dimension values by name or index."""

110

111

def __len__(self) -> int:

112

"""Get number of points."""

113

```

114

115

**Usage Examples:**

116

117

```python

118

import laspy

119

import numpy as np

120

121

# Create new LAS data

122

header = laspy.LasHeader(point_format=3, version=(1, 2))

123

las = laspy.LasData(header)

124

125

# Add point data via attributes

126

las.x = np.random.uniform(0, 1000, 5000)

127

las.y = np.random.uniform(0, 1000, 5000)

128

las.z = np.random.uniform(0, 100, 5000)

129

las.classification = np.random.choice([1, 2, 3, 4], 5000)

130

131

# Access XYZ as single array

132

coordinates = las.xyz # Shape: (5000, 3)

133

print(f"Point cloud bounds: {coordinates.min(axis=0)} to {coordinates.max(axis=0)}")

134

135

# Update header with current data statistics

136

las.update_header()

137

print(f"Header bounds: {las.header.mins} to {las.header.maxs}")

138

139

# Add custom extra dimension

140

extra_param = laspy.ExtraBytesParams(

141

name="intensity_normalized",

142

type="f4",

143

description="Normalized intensity values"

144

)

145

las.add_extra_dim(extra_param)

146

las.intensity_normalized = np.random.uniform(0, 1, len(las))

147

148

# Write to file

149

las.write('output.laz', do_compress=True)

150

```

151

152

### LAS Header Management

153

154

Comprehensive header management including metadata, coordinate systems, and format specifications.

155

156

```python { .api }

157

class LasHeader:

158

def __init__(self, *, version=None, point_format=None):

159

"""

160

Create LAS header.

161

162

Parameters:

163

- version: Version or tuple - LAS version (default: (1, 2))

164

- point_format: PointFormat or int - Point format (default: 3)

165

"""

166

167

@property

168

def version(self) -> Version: ...

169

@property

170

def point_format(self) -> PointFormat: ...

171

@property

172

def file_source_id(self) -> int: ...

173

@property

174

def global_encoding(self) -> GlobalEncoding: ...

175

@property

176

def uuid(self) -> UUID: ...

177

@property

178

def system_identifier(self) -> str: ...

179

@property

180

def generating_software(self) -> str: ...

181

@property

182

def creation_date(self) -> date: ...

183

@property

184

def point_count(self) -> int: ...

185

@property

186

def scales(self) -> np.ndarray: ...

187

@property

188

def offsets(self) -> np.ndarray: ...

189

@property

190

def maxs(self) -> np.ndarray: ...

191

@property

192

def mins(self) -> np.ndarray: ...

193

@property

194

def x_scale(self) -> float: ...

195

@property

196

def y_scale(self) -> float: ...

197

@property

198

def z_scale(self) -> float: ...

199

@property

200

def x_offset(self) -> float: ...

201

@property

202

def y_offset(self) -> float: ...

203

@property

204

def z_offset(self) -> float: ...

205

@property

206

def x_max(self) -> float: ...

207

@property

208

def y_max(self) -> float: ...

209

@property

210

def z_max(self) -> float: ...

211

@property

212

def x_min(self) -> float: ...

213

@property

214

def y_min(self) -> float: ...

215

@property

216

def z_min(self) -> float: ...

217

@property

218

def vlrs(self) -> VLRList: ...

219

@property

220

def evlrs(self) -> Optional[VLRList]: ...

221

@property

222

def number_of_points_by_return(self) -> np.ndarray: ...

223

224

def add_extra_dims(self, params: List[ExtraBytesParams]):

225

"""Add multiple extra dimensions to point format."""

226

227

def add_extra_dim(self, params: ExtraBytesParams):

228

"""Add single extra dimension to point format."""

229

230

def add_crs(self, crs, keep_compatibility=True):

231

"""

232

Add coordinate reference system information.

233

234

Parameters:

235

- crs: pyproj.CRS or CRS-like - Coordinate reference system

236

- keep_compatibility: bool - Maintain compatibility with older software

237

"""

238

239

def remove_extra_dim(self, name: str):

240

"""Remove extra dimension by name."""

241

242

def remove_extra_dims(self, names: Iterable[str]):

243

"""Remove multiple extra dimensions."""

244

245

def set_version_and_point_format(self, version: Version, point_format: PointFormat):

246

"""

247

Set version and point format together (ensures compatibility).

248

249

Parameters:

250

- version: Version - Target LAS version

251

- point_format: PointFormat - Target point format

252

"""

253

254

def partial_reset(self):

255

"""Reset header statistics (keeps metadata)."""

256

257

def update(self, points: PackedPointRecord):

258

"""

259

Update header statistics from point data.

260

261

Parameters:

262

- points: PackedPointRecord - Point data to analyze

263

"""

264

265

def grow(self, points: PackedPointRecord):

266

"""

267

Grow header bounds to include new points.

268

269

Parameters:

270

- points: PackedPointRecord - Additional points to include

271

"""

272

273

def set_compressed(self, state: bool):

274

"""

275

Set compression state in header.

276

277

Parameters:

278

- state: bool - True for compressed, False for uncompressed

279

"""

280

281

def max_point_count(self) -> int:

282

"""Get maximum point count for this LAS version."""

283

284

def copy(self) -> LasHeader:

285

"""Create deep copy of header."""

286

287

def parse_crs(self, prefer_wkt=True) -> Optional[pyproj.CRS]:

288

"""

289

Parse coordinate reference system from VLRs.

290

291

Parameters:

292

- prefer_wkt: bool - Prefer WKT over GeoTIFF keys if both present

293

294

Returns:

295

Optional[pyproj.CRS]: Parsed CRS or None if not found

296

"""

297

298

def read_evlrs(self, stream):

299

"""Read Extended VLRs from stream."""

300

301

def write_to(self, stream, ensure_same_size=False, encoding_errors="strict"):

302

"""

303

Write header to stream.

304

305

Parameters:

306

- stream: BinaryIO - Output stream

307

- ensure_same_size: bool - Ensure header stays same size

308

- encoding_errors: str - How to handle encoding errors

309

"""

310

311

@classmethod

312

def read_from(cls, original_stream: BinaryIO, read_evlrs=False) -> LasHeader:

313

"""

314

Read header from stream.

315

316

Parameters:

317

- original_stream: BinaryIO - Input stream

318

- read_evlrs: bool - Whether to read Extended VLRs

319

320

Returns:

321

LasHeader: Parsed header

322

"""

323

```

324

325

**Usage Examples:**

326

327

```python

328

import laspy

329

from datetime import date

330

import numpy as np

331

332

# Create header with specific settings

333

header = laspy.LasHeader(

334

version=(1, 4), # LAS 1.4

335

point_format=6 # Point format 6 (includes GPS time and RGB)

336

)

337

338

# Set metadata

339

header.system_identifier = "My LiDAR System"

340

header.generating_software = "My Processing Software v1.0"

341

header.creation_date = date.today()

342

343

# Set coordinate system scaling

344

header.scales = np.array([0.01, 0.01, 0.001]) # 1cm XY, 1mm Z

345

header.offsets = np.array([500000, 4000000, 0]) # UTM zone offsets

346

347

# Add CRS information (requires pyproj)

348

try:

349

import pyproj

350

crs = pyproj.CRS.from_epsg(32633) # UTM Zone 33N

351

header.add_crs(crs)

352

print("Added CRS information")

353

except ImportError:

354

print("pyproj not available, skipping CRS")

355

356

# Create data and update header statistics

357

las = laspy.LasData(header)

358

# ... add point data ...

359

las.update_header()

360

361

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

362

print(f"Point count: {header.point_count}")

363

```

364

365

### Header Version and Encoding

366

367

Version management and global encoding settings for LAS files.

368

369

```python { .api }

370

class Version:

371

major: int

372

minor: int

373

374

@classmethod

375

def from_str(cls, string: str) -> Version:

376

"""Parse version from string (e.g., '1.4')."""

377

378

def __str__(self) -> str: ...

379

380

class GpsTimeType(IntEnum):

381

WEEK_TIME = 0

382

STANDARD = 1

383

384

class GlobalEncoding:

385

def __init__(self, value=0):

386

"""

387

Create global encoding flags.

388

389

Parameters:

390

- value: int - Raw encoding value

391

"""

392

393

@property

394

def gps_time_type(self) -> GpsTimeType: ...

395

@property

396

def waveform_data_packets_internal(self) -> bool: ...

397

@property

398

def waveform_data_packets_external(self) -> bool: ...

399

@property

400

def synthetic_return_numbers(self) -> bool: ...

401

@property

402

def wkt(self) -> bool: ...

403

404

@classmethod

405

def read_from(cls, stream: BinaryIO) -> GlobalEncoding: ...

406

407

def write_to(self, stream: BinaryIO): ...

408

```

409

410

## Advanced Data Container Usage

411

412

### Working with Large Datasets

413

414

```python

415

import laspy

416

import numpy as np

417

418

def process_large_dataset(input_file, output_file, chunk_size=1000000):

419

"""Process large LAS file in chunks to manage memory."""

420

421

with laspy.open(input_file) as reader:

422

# Copy header for output

423

header = reader.header.copy()

424

425

with laspy.open(output_file, mode='w', header=header) as writer:

426

total_written = 0

427

428

for chunk in reader.chunk_iterator(chunk_size):

429

# Apply processing to chunk

430

processed = process_chunk(chunk)

431

432

# Write processed chunk

433

writer.write_points(processed)

434

total_written += len(processed)

435

436

print(f"Processed {total_written} points")

437

438

print(f"Processing complete: {total_written} total points")

439

440

def process_chunk(points):

441

"""Apply processing to point chunk."""

442

# Example: normalize intensity values

443

if hasattr(points, 'intensity'):

444

max_intensity = points.intensity.max()

445

if max_intensity > 0:

446

points.intensity = (points.intensity / max_intensity * 65535).astype(np.uint16)

447

448

return points

449

```

450

451

### Multi-Scale Coordinate Handling

452

453

```python

454

import laspy

455

import numpy as np

456

457

def handle_multi_scale_data(las_data):

458

"""Handle data with different coordinate scales."""

459

460

# Get current scaling

461

current_scales = las_data.header.scales

462

current_offsets = las_data.header.offsets

463

464

print(f"Current scales: {current_scales}")

465

print(f"Current offsets: {current_offsets}")

466

467

# Check coordinate precision

468

x_precision = 1.0 / current_scales[0]

469

y_precision = 1.0 / current_scales[1]

470

z_precision = 1.0 / current_scales[2]

471

472

print(f"Coordinate precision: X={x_precision}m, Y={y_precision}m, Z={z_precision}m")

473

474

# Increase precision if needed (e.g., for high-accuracy surveys)

475

if x_precision > 0.001: # If precision worse than 1mm

476

new_scales = np.array([0.001, 0.001, 0.0001]) # 1mm XY, 0.1mm Z

477

las_data.change_scaling(scales=new_scales)

478

print(f"Updated to higher precision: {new_scales}")

479

480

return las_data

481

```

482

483

### Header Validation and Repair

484

485

```python

486

import laspy

487

from datetime import date

488

489

def validate_and_repair_header(las_data):

490

"""Validate and repair common header issues."""

491

492

header = las_data.header

493

changes_made = []

494

495

# Check creation date

496

if header.creation_date is None:

497

header.creation_date = date.today()

498

changes_made.append("Set creation date to today")

499

500

# Check software identifier

501

if not header.generating_software.strip():

502

header.generating_software = "laspy"

503

changes_made.append("Set generating software")

504

505

# Validate point count

506

actual_count = len(las_data.points)

507

if header.point_count != actual_count:

508

header.point_count = actual_count

509

changes_made.append(f"Updated point count to {actual_count}")

510

511

# Check bounds consistency

512

if len(las_data.points) > 0:

513

las_data.update_header()

514

changes_made.append("Updated header bounds from point data")

515

516

# Validate scales (prevent zero or negative scales)

517

if np.any(header.scales <= 0):

518

header.scales = np.where(header.scales <= 0, 0.01, header.scales)

519

changes_made.append("Fixed invalid scale factors")

520

521

if changes_made:

522

print(f"Header repairs made: {'; '.join(changes_made)}")

523

else:

524

print("Header validation passed")

525

526

return las_data

527

```