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

point-data.mddocs/

0

# Point Data Handling

1

2

Comprehensive point format management including standard LAS point formats, custom extra dimensions, and efficient point record processing with coordinate scaling. This module provides the foundation for all point data operations in laspy.

3

4

## Capabilities

5

6

### Point Format Management

7

8

Define and manage LAS point formats including standard formats and custom extra dimensions.

9

10

```python { .api }

11

class PointFormat:

12

def __init__(self, point_format_id: int):

13

"""

14

Create point format from standard LAS point format ID.

15

16

Parameters:

17

- point_format_id: int - Standard LAS point format (0-10)

18

"""

19

20

@property

21

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

22

@property

23

def dimensions(self) -> List[DimensionInfo]: ...

24

@property

25

def standard_dimensions(self) -> Iterable[DimensionInfo]: ...

26

@property

27

def extra_dimensions(self) -> Iterable[DimensionInfo]: ...

28

@property

29

def size(self) -> int: ... # Total point size in bytes

30

@property

31

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

32

@property

33

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

34

@property

35

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

36

37

def dimension_by_name(self, name: str) -> DimensionInfo:

38

"""Get dimension info by name."""

39

40

def add_extra_dimension(self, params: ExtraBytesParams):

41

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

42

43

def remove_extra_dimension(self, name: str):

44

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

45

46

def dtype(self) -> np.dtype:

47

"""Get NumPy dtype for this point format."""

48

```

49

50

**Usage Example:**

51

```python

52

import laspy

53

from laspy import PointFormat, ExtraBytesParams

54

55

# Create standard point format

56

fmt = PointFormat(3) # Point format 3 (X,Y,Z,Intensity,Returns,Classification,etc.)

57

print(f"Format {fmt.id} has {len(fmt.dimensions)} dimensions")

58

print(f"Standard size: {fmt.num_standard_bytes} bytes")

59

60

# Add custom extra dimension

61

extra_param = ExtraBytesParams(

62

name="temperature",

63

type="f4", # 32-bit float

64

description="Temperature in Celsius"

65

)

66

fmt.add_extra_dimension(extra_param)

67

print(f"With extra dims: {fmt.size} bytes total")

68

69

# Get dimension info

70

temp_dim = fmt.dimension_by_name("temperature")

71

print(f"Temperature dimension: {temp_dim.kind}, {temp_dim.num_bits} bits")

72

```

73

74

### Extra Dimension Parameters

75

76

Define custom extra dimensions with proper typing, scaling, and metadata.

77

78

```python { .api }

79

class ExtraBytesParams:

80

def __init__(self, name: str, type, description="", offsets=None, scales=None, no_data=None):

81

"""

82

Define parameters for extra bytes dimension.

83

84

Parameters:

85

- name: str - Dimension name

86

- type: str, np.dtype, or type - Data type ('u1', 'f4', np.uint8, etc.)

87

- description: str - Human-readable description

88

- offsets: array-like - Offset values for scaling

89

- scales: array-like - Scale factors

90

- no_data: array-like - No-data sentinel values

91

"""

92

93

@property

94

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

95

@property

96

def type(self) -> np.dtype: ...

97

@property

98

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

99

@property

100

def offsets(self) -> Optional[np.ndarray]: ...

101

@property

102

def scales(self) -> Optional[np.ndarray]: ...

103

@property

104

def no_data(self) -> Optional[np.ndarray]: ...

105

```

106

107

**Usage Examples:**

108

```python

109

import numpy as np

110

from laspy import ExtraBytesParams

111

112

# Simple integer field

113

intensity_extra = ExtraBytesParams(

114

name="intensity_corrected",

115

type="u2", # 16-bit unsigned int

116

description="Radiometrically corrected intensity"

117

)

118

119

# Scaled float field

120

temperature = ExtraBytesParams(

121

name="temperature",

122

type="u1", # Store as uint8 to save space

123

description="Temperature in Celsius",

124

scales=np.array([0.1]), # Scale factor: stored_value * 0.1 = actual_value

125

offsets=np.array([-20.0]), # Offset: (stored_value * scale) + offset = actual_value

126

no_data=np.array([255]) # 255 = no data

127

)

128

129

# Multi-element field (RGB)

130

rgb_extra = ExtraBytesParams(

131

name="rgb_corrected",

132

type="3u1", # 3 uint8 values

133

description="Color-corrected RGB values"

134

)

135

```

136

137

### Dimension Information

138

139

Detailed metadata about point dimensions including data types, scaling, and validation.

140

141

```python { .api }

142

class DimensionInfo:

143

name: str

144

kind: DimensionKind

145

num_bits: int

146

num_elements: int

147

is_standard: bool

148

description: str

149

offsets: Optional[np.ndarray]

150

scales: Optional[np.ndarray]

151

no_data: Optional[np.ndarray]

152

153

@property

154

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

155

@property

156

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

157

@property

158

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

159

@property

160

def dtype(self) -> Optional[np.dtype]: ...

161

@property

162

def max(self): ...

163

@property

164

def min(self): ...

165

166

def type_str(self) -> Optional[str]: ...

167

168

@classmethod

169

def from_extra_bytes_param(cls, params: ExtraBytesParams) -> DimensionInfo: ...

170

@classmethod

171

def from_dtype(cls, name: str, dtype: np.dtype, is_standard=True, description="", offsets=None, scales=None) -> DimensionInfo: ...

172

@classmethod

173

def from_bitmask(cls, name: str, bit_mask: int, is_standard=False) -> DimensionInfo: ...

174

175

class DimensionKind(Enum):

176

SignedInteger = 0

177

UnsignedInteger = 1

178

FloatingPoint = 2

179

BitField = 3

180

181

@classmethod

182

def from_letter(cls, letter: str) -> DimensionKind: ...

183

def letter(self) -> Optional[str]: ...

184

```

185

186

### Packed Point Records

187

188

Raw packed point data containers providing direct access to binary point data.

189

190

```python { .api }

191

class PackedPointRecord:

192

def __init__(self, data: np.ndarray, point_format: PointFormat):

193

"""

194

Create packed point record from raw data array.

195

196

Parameters:

197

- data: np.ndarray - Raw point data

198

- point_format: PointFormat - Point format definition

199

"""

200

201

@property

202

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

203

@property

204

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

205

@property

206

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

207

208

@staticmethod

209

def zeros(point_count, point_format) -> PackedPointRecord:

210

"""Create zero-initialized point record."""

211

212

@staticmethod

213

def empty(point_format) -> PackedPointRecord:

214

"""Create empty point record."""

215

216

@classmethod

217

def from_point_record(cls, other_point_record, new_point_format) -> PackedPointRecord:

218

"""Create from existing point record with format conversion."""

219

220

@classmethod

221

def from_buffer(cls, buffer, point_format, count=-1, offset=0) -> PackedPointRecord:

222

"""Create from memory buffer."""

223

224

def copy_fields_from(self, other_record: PackedPointRecord):

225

"""Copy compatible fields from another record."""

226

227

def copy(self) -> PackedPointRecord:

228

"""Create deep copy."""

229

230

def memoryview(self) -> memoryview:

231

"""Get memory view of underlying data."""

232

233

def resize(self, new_size: int):

234

"""Resize point record."""

235

236

def validate_dimension_name(self, key: str) -> DimensionNameValidity:

237

"""Validate dimension name."""

238

239

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

240

def __getitem__(self, key): ... # Access dimension by name or index

241

def __setitem__(self, key, value): ... # Set dimension values

242

def __getattr__(self, name): ... # Direct attribute access to dimensions

243

def __setattr__(self, name, value): ... # Direct attribute setting

244

```

245

246

**Usage Example:**

247

```python

248

import laspy

249

import numpy as np

250

251

# Create point format and empty record

252

point_format = laspy.PointFormat(3)

253

points = laspy.PackedPointRecord.zeros(1000, point_format)

254

255

# Set point data

256

points.x = np.random.uniform(0, 100, 1000).astype(np.int32)

257

points.y = np.random.uniform(0, 100, 1000).astype(np.int32)

258

points.z = np.random.uniform(0, 10, 1000).astype(np.int32)

259

points.classification = np.full(1000, 2, dtype=np.uint8) # Ground class

260

261

# Access data

262

print(f"Point count: {len(points)}")

263

print(f"X range: {points.x.min()} to {points.x.max()}")

264

265

# Copy and modify

266

subset = points.copy()

267

subset.resize(100) # Keep only first 100 points

268

```

269

270

### Scale-Aware Point Records

271

272

Point records with automatic coordinate scaling and transformation support.

273

274

```python { .api }

275

class ScaleAwarePointRecord(PackedPointRecord):

276

def __init__(self, array, point_format, scales, offsets):

277

"""

278

Create scale-aware point record with coordinate transformation.

279

280

Parameters:

281

- array: np.ndarray - Raw point data

282

- point_format: PointFormat - Point format definition

283

- scales: np.ndarray - Scale factors for X,Y,Z coordinates

284

- offsets: np.ndarray - Offset values for X,Y,Z coordinates

285

"""

286

287

@property

288

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

289

@property

290

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

291

292

@staticmethod

293

def zeros(point_count, *, point_format=None, scales=None, offsets=None, header=None) -> ScaleAwarePointRecord:

294

"""Create zero-initialized scaled point record."""

295

296

@staticmethod

297

def empty(point_format=None, scales=None, offsets=None, header=None) -> ScaleAwarePointRecord:

298

"""Create empty scaled point record."""

299

300

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

301

"""Update coordinate scaling parameters."""

302

```

303

304

**Usage Example:**

305

```python

306

import laspy

307

import numpy as np

308

309

# Create with coordinate scaling

310

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

311

offsets = np.array([500000, 4000000, 0]) # UTM-like offsets

312

313

points = laspy.ScaleAwarePointRecord.zeros(

314

1000,

315

point_format=laspy.PointFormat(3),

316

scales=scales,

317

offsets=offsets

318

)

319

320

# Set scaled coordinates (automatically converted to/from raw integers)

321

points.x = np.random.uniform(500000, 501000, 1000) # Real-world coordinates

322

points.y = np.random.uniform(4000000, 4001000, 1000)

323

points.z = np.random.uniform(100, 200, 1000)

324

325

# Access scaled values (real-world coordinates)

326

print(f"Real X range: {points.x.min():.2f} to {points.x.max():.2f}")

327

328

# Change scaling if needed

329

new_scales = np.array([0.001, 0.001, 0.0001]) # Higher precision

330

points.change_scaling(scales=new_scales)

331

```

332

333

### Array Views

334

335

Specialized array views for scaled coordinates and bit field access.

336

337

```python { .api }

338

class ArrayView:

339

"""Abstract base class for specialized array views."""

340

def __array__(self): ...

341

def __getitem__(self, key): ...

342

def __setitem__(self, key, value): ...

343

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

344

345

@property

346

def dtype(self): ...

347

@property

348

def shape(self): ...

349

@property

350

def ndim(self): ...

351

352

class ScaledArrayView(ArrayView):

353

def __init__(self, array: np.ndarray, scale, offset):

354

"""

355

Array view with automatic scaling/offset transformation.

356

357

Parameters:

358

- array: np.ndarray - Raw integer array

359

- scale: float or np.ndarray - Scale factor(s)

360

- offset: float or np.ndarray - Offset value(s)

361

"""

362

363

def scaled_array(self):

364

"""Get scaled floating-point array."""

365

366

class SubFieldView(ArrayView):

367

def __init__(self, array: np.ndarray, bit_mask):

368

"""

369

Array view for bit field access.

370

371

Parameters:

372

- array: np.ndarray - Raw array containing bit fields

373

- bit_mask: int - Bit mask for field extraction

374

"""

375

376

def masked_array(self):

377

"""Get underlying masked array."""

378

```

379

380

## Point Format Conversion

381

382

Utilities for converting between point formats and checking compatibility.

383

384

```python { .api }

385

def lost_dimensions(point_fmt_in, point_fmt_out) -> List[str]:

386

"""

387

Get list of dimension names that will be lost in format conversion.

388

389

Parameters:

390

- point_fmt_in: PointFormat - Source point format

391

- point_fmt_out: PointFormat - Target point format

392

393

Returns:

394

List[str]: Names of dimensions that will be lost

395

"""

396

```

397

398

**Usage Example:**

399

```python

400

import laspy

401

from laspy.point.format import lost_dimensions

402

403

# Check what gets lost converting from format 6 to format 3

404

fmt_6 = laspy.PointFormat(6) # Has GPS time, RGB

405

fmt_3 = laspy.PointFormat(3) # Basic format

406

407

lost = lost_dimensions(fmt_6, fmt_3)

408

print(f"Converting 6->3 loses: {lost}") # ['gps_time', 'red', 'green', 'blue']

409

410

# Check reverse conversion

411

lost_reverse = lost_dimensions(fmt_3, fmt_6)

412

print(f"Converting 3->6 loses: {lost_reverse}") # [] (no data lost, new fields get defaults)

413

```

414

415

## Validation

416

417

Dimension name validation for safe attribute access.

418

419

```python { .api }

420

class DimensionNameValidity(Enum):

421

Valid = ... # Valid dimension name

422

Unsupported = ... # Valid but not supported in this format

423

Invalid = ... # Invalid dimension name

424

```