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

Commit

Permalink
Add more scaled extra bytes tests
Browse files Browse the repository at this point in the history
Test that if scales are provided, offsets are too and vice versa

Test that the len of the scales and offsets array matches the number of
elements of the extra dimensions
  • Loading branch information
tmontaigu committed Dec 29, 2020
1 parent 1819e98 commit 233ac4c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 29 deletions.
19 changes: 19 additions & 0 deletions pylas/point/dims.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ def from_type_str(
offsets: Optional[np.ndarray] = None,
scales: Optional[np.ndarray] = None,
) -> "DimensionInfo":
if (
offsets is not None
and scales is None
or offsets is None
and scales is not None
):
raise ValueError("Cannot provide scales without offsets and vice-versa")

first_digits = "".join(itertools.takewhile(lambda l: l.isdigit(), type_str))
if first_digits:
num_elements = int(first_digits)
Expand All @@ -340,6 +348,17 @@ def from_type_str(
dtype = np.dtype(type_str)
kind = DimensionKind.from_letter(type_str[0])
num_bits = num_elements * dtype.itemsize * 8

if offsets is not None and len(offsets) != num_elements:
raise ValueError(
f"len(offsets) ({len(offsets)}) is not the same as the number of elements ({num_elements})"
)

if scales is not None and len(scales) != num_elements:
raise ValueError(
f"len(scales) ({len(scales)}) is not the same as the number of elements ({num_elements})"
)

return cls(
name,
kind,
Expand Down
8 changes: 0 additions & 8 deletions pylas/point/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ def __init__(
offsets: Optional[np.ndarray] = None,
scales: Optional[np.ndarray] = None,
) -> None:
if (
offsets is not None
and scales is None
or offsets is None
and scales is not None
):
raise ValueError("Both scales and offsets needs to be provided")

self.name = name
""" The name of the extra dimension """
self.type = type
Expand Down
16 changes: 14 additions & 2 deletions pylas/vlrs/known.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,16 @@ def type_str(self):
return "{}u1".format(self.options)
return get_type_for_extra_dim(self.data_type)

def num_elements(self) -> int:
if self.data_type == 0:
return self.options
elif self.data_type <= 10:
return 1
elif self.data_type <= 20:
return 2
else:
return 3

@staticmethod
def size():
return ctypes.sizeof(ExtraBytesStruct)
Expand Down Expand Up @@ -307,13 +317,15 @@ def record_data_bytes(self):
def type_of_extra_dims(self) -> List[ExtraBytesParams]:
dim_info_list: List[ExtraBytesParams] = []
for eb_struct in self.extra_bytes_structs:
num_elements = eb_struct.num_elements()

scales = eb_struct.scale
if scales is not None:
scales = np.array(scales)
scales = np.array(scales[:num_elements])

offsets = eb_struct.offset
if offsets is not None:
offsets = np.array(offsets)
offsets = np.array(offsets[:num_elements])

dim_info_list.append(
ExtraBytesParams(
Expand Down
92 changes: 73 additions & 19 deletions pylastests/test_extrabytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ def test_read_write_example_extra_bytes_file(las_file_path_with_extra_bytes):
assert np.allclose(las[name], original[name])


def test_adding_extra_bytes_keeps_values_of_all_existing_fields(extra_bytes_params, simple_las_path):
def test_adding_extra_bytes_keeps_values_of_all_existing_fields(
extra_bytes_params, simple_las_path
):
"""
Test that when extra bytes are added, the existing fields keep their
values and then we don't somehow drop them
Expand Down Expand Up @@ -78,7 +80,7 @@ def test_creating_scaled_extra_bytes(extra_bytes_params, simple_las_path):
extra_bytes_params.name,
extra_bytes_params.type,
offsets=np.array([2.0] * num_elements),
scales=np.array([1.0] * num_elements)
scales=np.array([1.0] * num_elements),
)
las.add_extra_dim(params)

Expand All @@ -97,12 +99,14 @@ def test_scaled_extra_byte_array_type(simple_las_path):
"""
las = pylas.read(simple_las_path)

las.add_extra_dim(pylas.ExtraBytesParams(
name="test_dim",
type="3int32",
scales=np.array([1.0, 2.0, 3.0], np.float64),
offsets=np.array([10.0, 20.0, 30.0], np.float64),
))
las.add_extra_dim(
pylas.ExtraBytesParams(
name="test_dim",
type="3int32",
scales=np.array([1.0, 2.0, 3.0], np.float64),
offsets=np.array([10.0, 20.0, 30.0], np.float64),
)
)

assert np.allclose(las.test_dim[..., 0], 10.0)
assert np.allclose(las.test_dim[..., 1], 20.0)
Expand Down Expand Up @@ -147,8 +151,7 @@ def test_extra_bytes_with_spaces_in_name(simple_las_path):
as de normal '.name' won't work
"""
las = pylas.read(simple_las_path)
las.add_extra_dim(
pylas.ExtraBytesParams(name="Name With Spaces", type="int32"))
las.add_extra_dim(pylas.ExtraBytesParams(name="Name With Spaces", type="int32"))

assert np.alltrue(las["Name With Spaces"] == 0)
las["Name With Spaces"][:] = 789_464
Expand All @@ -165,17 +168,15 @@ def test_conversion_keeps_eb(las_file_path_with_extra_bytes):
converted_las = pylas.convert(original, point_format_id=0)

assert len(list(original.point_format.extra_dimension_names)) == 5
assert (
list(converted_las.point_format.extra_dimension_names)
== list(original.point_format.extra_dimension_names)
assert list(converted_las.point_format.extra_dimension_names) == list(
original.point_format.extra_dimension_names
)
for name in converted_las.point_format.extra_dimension_names:
assert np.allclose(converted_las[name], original[name])

converted_las = pylas.lib.write_then_read_again(converted_las)
assert (
list(converted_las.point_format.extra_dimension_names)
== list(original.point_format.extra_dimension_names)
assert list(converted_las.point_format.extra_dimension_names) == list(
original.point_format.extra_dimension_names
)
for name in converted_las.point_format.extra_dimension_names:
assert np.allclose(converted_las[name], original[name])
Expand All @@ -190,7 +191,9 @@ def test_creating_bytes_with_name_too_long(simple_las_path):
las.add_extra_dim(
pylas.ExtraBytesParams(
name="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus",
type="int32"))
type="int32",
)
)

assert str(error.value) == "bytes too long (70, maximum length 32)"

Expand All @@ -206,7 +209,9 @@ def test_creating_bytes_with_description_too_long(simple_las_path):
name="a fine name",
type="int32",
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
" Sed non risus"))
" Sed non risus",
)
)

assert str(error.value) == "bytes too long (70, maximum length 32)"

Expand All @@ -217,4 +222,53 @@ def test_creating_extra_byte_with_invalid_type(simple_las_path):
"""
las = pylas.read(simple_las_path)
with pytest.raises(TypeError):
las.add_extra_dim(pylas.ExtraBytesParams("just_a_test", 'i16'))
las.add_extra_dim(pylas.ExtraBytesParams("just_a_test", "i16"))


def test_cant_create_scaled_extra_bytes_without_both_offsets_and_scales():
las = pylas.create()
with pytest.raises(ValueError):
las.add_extra_dim(
pylas.ExtraBytesParams("must fail", "int64", scales=np.array([0.1]))
)

with pytest.raises(ValueError):
las.add_extra_dim(
pylas.ExtraBytesParams("must fail", "int64", offsets=np.array([0.1]))
)


@pytest.mark.parametrize("num_elements", [1, 2, 3])
def test_cant_create_scaled_extra_bytes_with_offsets_array_smaller(num_elements):
las = pylas.create()
with pytest.raises(ValueError) as error:
las.add_extra_dim(
pylas.ExtraBytesParams(
"must fail",
f"{num_elements}int64",
scales=np.array([0.1] * num_elements),
offsets=np.array([0.0] * (num_elements - 1)),
)
)
assert (
str(error.value)
== f"len(offsets) ({num_elements - 1}) is not the same as the number of elements ({num_elements})"
)


@pytest.mark.parametrize("num_elements", [1, 2, 3])
def test_cant_create_scaled_extra_bytes_with_scales_array_smaller(num_elements):
las = pylas.create()
with pytest.raises(ValueError) as error:
las.add_extra_dim(
pylas.ExtraBytesParams(
"must fail",
f"{num_elements}int64",
scales=np.array([0.1] * (num_elements - 1)),
offsets=np.array([0.0] * num_elements),
)
)
assert (
str(error.value)
== f"len(scales) ({num_elements - 1}) is not the same as the number of elements ({num_elements})"
)

0 comments on commit 233ac4c

Please sign in to comment.