Skip to content
This repository has been archived by the owner on Aug 18, 2022. It is now read-only.

Commit

Permalink
Add headers in the docs and doctests
Browse files Browse the repository at this point in the history
  • Loading branch information
tmontaigu committed Jun 27, 2018
1 parent f16b4da commit ba81bc1
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 5 deletions.
1 change: 1 addition & 0 deletions docs/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ Submodules
pylas.evlrs
pylas.errors
pylas.compression
pylas.headers

7 changes: 7 additions & 0 deletions docs/api/pylas.headers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pylas.headers.rawheader module
==============================

.. automodule:: pylas.headers.rawheader
:members:
:undoc-members:
:show-inheritance:
21 changes: 21 additions & 0 deletions docs/basic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ You obtain this type of object by using one of the function above,
use its method :meth:`pylas.lasdatas.base.LasBase.write` to write to a file or a stream.


Accessing the file header
=========================

You can access the header of a las file you read or opened by retrieving the 'header' attribute:

.. code-block:: python
las = pylas.read('somefile.las')
header = las.header
print("Point count: {}".format(header.point_count))
# or
with pylas.open('somefile.las') as f:
header = f.header
print("Point count: {}".format(header.point_count))
you can see the accessible fields in :class:`pylas.headers.rawheader.RawHeader1_1` and its sub-classes.

Manipulating VLRs
=================
Expand Down
93 changes: 88 additions & 5 deletions pylas/headers/rawheader.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ def __init__(self):

@property
def point_count(self):
""" Returns the number of points in the file
"""
return self.legacy_point_count

@point_count.setter
Expand All @@ -115,6 +117,7 @@ def number_of_points_by_return(self, value):

@property
def version(self):
""" Return the file version as a str"""
return "{}.{}".format(self.version_major, self.version_minor)

@version.setter
Expand All @@ -128,6 +131,13 @@ def version(self, new_version):

@property
def date(self):
""" Returns the creation date stored in the las file
Returns
-------
datetime.date
"""
try:
return datetime.date(self.creation_year, 1, 1) + datetime.timedelta(
self.creation_day_of_year - 1
Expand All @@ -149,10 +159,14 @@ def point_format_id(self):

@point_format_id.setter
def point_format_id(self, value):
""" Returns the point format id of the points
"""
self._point_data_format_id = value

@property
def point_size(self):
""" Returns the number of bits each point takes
"""
return self.point_data_record_length

@point_size.setter
Expand All @@ -169,6 +183,8 @@ def uuid(self, new_uuid):

@property
def are_points_compressed(self):
""" Returns True if the point_format_id indicates that the points are stored compressed
"""
return compression.is_point_format_compressed(self._point_data_format_id)


Expand Down Expand Up @@ -212,23 +228,56 @@ def number_of_points_by_return(self, value):


class HeaderFactory:
version_to_header = {
""" Factory to create a new header by specifying the version.
This Factory also handles converting headers between different
versions.
"""
_version_to_header = {
"1.1": RawHeader1_1,
"1.2": RawHeader1_2,
"1.3": RawHeader1_3,
"1.4": RawHeader1_4,
}
offset_to_major_version = RawHeader1_1.version_major.offset
_offset_to_major_version = RawHeader1_1.version_major.offset

@classmethod
def header_class_for_version(cls, version):
"""
>>> HeaderFactory.header_class_for_version(2.0)
Traceback (most recent call last):
...
pylas.errors.FileVersionNotSupported: 2.0
>>> HeaderFactory.header_class_for_version(1.2)
<class 'pylas.headers.rawheader.RawHeader1_2'>
>>> header_class = HeaderFactory.header_class_for_version(1.4)
>>> header_class()
<LasHeader(1.4)>
"""
try:
return cls.version_to_header[str(version)]
return cls._version_to_header[str(version)]
except KeyError:
raise errors.FileVersionNotSupported(version)

@classmethod
def new(cls, version):
""" Returns a new instance of a header.
Parameters
----------
version : float or str
The header version
>>> HeaderFactory.new(1.4)
<LasHeader(1.4)>
>>> HeaderFactory.new('1.2')
<LasHeader(1.2)>
"""
return cls.header_class_for_version(version)()

@classmethod
Expand All @@ -246,21 +295,55 @@ def from_mmap(cls, mmap):

@classmethod
def peek_file_version(cls, stream):
""" seeks to the position of the las version header fields
in the stream and returns it as a str
Parameters
----------
stream io.BytesIO
Returns
-------
str
file version read from the stream
"""
old_pos = stream.tell()
stream.seek(cls.offset_to_major_version)
stream.seek(cls._offset_to_major_version)
major = int.from_bytes(stream.read(ctypes.sizeof(ctypes.c_uint8)), "little")
minor = int.from_bytes(stream.read(ctypes.sizeof(ctypes.c_uint8)), "little")
stream.seek(old_pos)
return "{}.{}".format(major, minor)

@classmethod
def convert_header(cls, old_header, new_version):
""" Converts a header to a another version
Parameters
----------
old_header: the old header instance
new_version: float or str
Returns
-------
The converted header
>>> old_header = HeaderFactory.new(1.2)
>>> HeaderFactory.convert_header(old_header, 1.4)
<LasHeader(1.4)>
>>> old_header = HeaderFactory.new('1.4')
>>> HeaderFactory.convert_header(old_header, '1.2')
<LasHeader(1.2)>
"""
new_header_class = cls.header_class_for_version(new_version)

b = bytearray(old_header)
b += b"\x00" * (ctypes.sizeof(new_header_class) - len(b))
new_header = new_header_class.from_buffer(b)
new_header.version = new_version
new_header.version = str(new_version)

return new_header

Expand Down

0 comments on commit ba81bc1

Please sign in to comment.