mapteksdk.data.scans module

Module containing the Scan classes.

Currently only the generic Scan class is supported.

class mapteksdk.data.scans.Scan(object_id=None, lock_type=<LockType.READWRITE: 2>)

Bases: mapteksdk.data.base.Topology, mapteksdk.data.primitives.point_properties.PointProperties

Class optimised for storing scans made by 3D laser scanners. The Cartesian points of a scan are derived from the point_ranges, vertical_angles and the horizontal_angles.

When a scan is created you can populate the points instead of the point_ranges, vertical_angles and horizontal_angles. If you populate both then the point_ranges, vertical_angles and horizontal_angles will be ignored in favour of the points.

Scans possess three types of properties:

  • Point properties.

  • Cell properties.

  • Cell point properties.

Point properties are associated with the valid points. They start with ‘point’ and have one value for each valid point in the scan. point_count will return the count of valid points once save() has been called.

Cell properties start with ‘cell’ and should have (row_count - 1) * (column_count - 1) values - one value for each cell in the scan.

Cell point properties are a special type of cell and point properties. They start with ‘cell_point’ (with the exclusion of horizontal_angles and vertical_angles) and have one value for each point in the underlying cell network (including invalid points for which point properties are not stored). Cell point properties should have cell_point_count values.

For scans created in the Python SDK, the point_count is always equal to the cell_point_count. However scans imported via applications may have point_count <= cell_point_count.

Warning

Creating a scan using Cartesian points will result in a loss of precision. The final points of the scan will not be exactly equal to the points used to create the scan.

See also

mapteksdk.data.points.PointSet

Accurate storage for Cartesian points.

Notes

The points of a scan can only be set on new scans. Setting the points on non-new scans will be ignored. Because scans have different behaviour when opened with project.new() versus project.edit(), you should never open a scan with project.new_or_edit().

Examples

Create a scan using Cartesian coordinates. Note that when the points are read from the scan, they will not be exactly equal to the points used to create the scan.

>>> from mapteksdk.project import Project
>>> from mapteksdk.data import Scan
>>> project = Project()
>>> with project.new("scans/cartesian_scan", Scan) as new_scan:
>>>     new_scan.points = [[1, 2, 4], [3, 5, 7], [6, 8, 9]]

Create a scan using spherical coordinates.

>>> import math
>>> from mapteksdk.project import Project
>>> from mapteksdk.data import Scan
>>> project = Project()
>>> with project.new("scans/spherical_scan", Scan) as new_scan:
>>>     new_scan.point_ranges = [2, 16, 34, 12]
>>>     new_scan.horizontal_angles = [3 * math.pi / 4, math.pi / 4,
>>>                                   -math.pi / 4, - 3 * math.pi / 4]
>>>     new_scan.vertical_angles = [math.pi / 4] * 4
>>>     new_scan.max_range = 50
>>>     new_scan.intensity = [256, 10000, 570, 12]
>>>     new_scan.origin = [-16, 16, -16]
classmethod static_type()

Return the type of scan as stored in a Project.

This can be used for determining if the type of an object is a scan.

property point_ranges

List of floats representing the distance of the points from the scan origin with one value per valid point. Any range value greater than max_range() will be set to max_range() when save() is called.

The ranges array can only be assigned when the scan is first created. After creation, values within the range array can be only changed via assignment and operations which work in-place on the array.

When save() is called, if there are less point_ranges than vertical_angles or horizontal_angles the ranges will be padded with zeroes. If there are more ranges than angles, the ranges will be truncated to have the same number of ranges as angles.

Raises
  • ValueError – If attempting to edit while they are read-only.

  • ValueError – If new value cannot be converted to a np.array of 32-bit floats.

Warning

When creating a new scan, you should either set the points or the ranges, vertical angles and horizontal angles. If you set both, the points will be saved and the ranges ignored.

property horizontal_angles

List of horizontal angles of the points. This is the azimuth of the point measured clockwise from the Y axis.

The horizontal angles can only be set when the scan is first created. Once save() has been called they become read-only. When save() is called, if there are more horizontal angles than vertical angles this will be padded with zeroes to be the same length.

Raises
  • ValueError – If attempting to edit while they are read-only.

  • ValueError – If new value cannot be converted to a np.array of 32 bit floats.

Warning

When creating a new scan, you should either set the points or set the ranges, vertical angles and horizontal angles. If you set both, the points will be saved and the ranges ignored.

Notes

Technically this should be cell_point_horizontal_angles, however it has been shortened to horizontal_angles. This should have cell_point_count values.

The angles of an invalid point are not defined. It is not recommended to use invalid angles in algorithms.

property vertical_angles

List of vertical angles of the points. This is the elevation angle in the spherical coordinate system.

The vertical_angles can only be set when the scan is first created. Once save() has been called they become read-only. When save() is called, if there are more vertical angles than horizontal angles this will be padded with zeroes to be the same length.

Raises
  • ValueError – If attempting to edit when the vertical angles are read-only.

  • ValueError – If new value cannot be converted to a np.array of 32 bit floats.

Warning

When creating a new scan, you should either set the points or set the ranges, vertical angles and horizontal angles. If you set both, the points will be saved and the vertical angles ignored.

Notes

Technically this should be cell_point_vertical_angles, however it has been shortened to vertical_angles. This should have cell_point_count values.

The angles of an invalid point are not defined. It is not recommended to use invalid angles in algorithms.

property row_count

The number of rows in the underlying cell network. Note that this is the logical count of the rows. This will only correspond to the major dimension for the underlying array if is_column_major() returns false.

Similar to scans imported via the custom ascii text importer, Scans created in the Python SDK will contain one row with point_count columns.

Notes

Scans appear ‘flattened’ when read in the Python SDK - a scan with ten rows and ten columns of points will appear as a flat list of one hundred points.

property column_count

The number of columns in the underlying cell network. Note that this is the logical count of the columns. This will only correspond to the minor dimension for the underlying array if is_column_major() returns false.

Similar to scans imported via the custom ascii text importer, Scans created in the Python SDK will contain one row with point_count columns.

property origin

The origin of the scan represented as a point. This should be set to the location of the scanner when the scan was taken (if known).

When creating a scan using Cartesian coordinates, if the origin is not set it will default to the centroid of the points. Changing the origin in this case will not change the points.

When creating a scan using point_range, horizontal_angles and vertical_angles the origin will default to [0, 0, 0]. Changing the origin in this case will cause the points to be centred around the new origin.

Editing the origin will translate the scan by the difference between the new origin and the old origin.

Notes

Points which are far away from the origin may suffer precision issues.

Examples

Set the origin of a scan creating using ranges and angles and print the points. The origin is set to [1, 1, 1] so the final points are translated by [1, 1, 1].

>>> import math
>>> from mapteksdk.project import Project
>>> from mapteksdk.data import Scan
>>> project = Project()
>>> with project.new("scans/angle_scan", Scan) as new_scan:
...     new_scan.point_ranges = [1, 1, 1, 1]
...     new_scan.horizontal_angles = [math.pi / 4, math.pi * 0.75,
...                                   -math.pi / 4, -math.pi * 0.75]
...     new_scan.vertical_angles = [0, 0, 0, 0]
...     new_scan.origin = [1, 1, 1]
>>> with project.read("scans/angle_scan") as read_scan:
...     print(read_scan.points)
[[1.70710668 1.70710688 1.00000019]
 [1.70710681 0.29289325 1.00000019]
 [0.29289332 1.70710688 1.00000019]
 [0.29289319 0.29289325 1.00000019]]

Unlike for spherical coordinates, Cartesian coordinates are round tripped. This means that setting the origin in new() will not translate the points.

>>> from mapteksdk.project import Project
>>> from mapteksdk.data import Scan
>>> project = Project()
>>> with project.new("scans/point_scan", Scan) as new_scan:
...     new_scan.points = [[1, 1, 1], [-1, 1, 2], [1, -1, 3], [-1, -1, 4]]
...     new_scan.origin = [2, 2, 2]
>>> with project.read("scans/point_scan") as read_scan:
...     print(read_scan.points)
[[ 0.99999997  1.00000006  1.00000008]
 [-1.00000002  1.0000001   2.00000059]
 [ 0.99999975 -1.00000013  2.99999981]
 [-1.00000004 -0.99999976  4.00000031]]

However changing the origin in edit will always translate the points. By changing the origin from [2, 2, 2] to [-2, -2, -2] the x, y and z coordinates of the scan are each reduced by four.

>>> from mapteksdk.project import Project
>>> project = Project()
>>> with project.edit("scans/point_scan") as edit_scan:
...     edit_scan.origin = [-2, -2, -2]
>>> with project.read("scans/point_scan") as read_scan:
...     print(read_scan.points)
[[-3.00000003 -2.99999994 -2.99999992]
 [-5.00000002 -2.9999999  -1.99999941]
 [-3.00000025 -5.00000013 -1.00000019]
 [-5.00000004 -4.99999976  0.00000031]]
property max_range

The maximum range the generating scanner is capable of. This is used to normalise the ranges to allow for more compact storage. Any point further away from the origin will have its range set to this value when save() is called.

If this is not set when creating a new scan, it will default to the maximum distance of any point from the origin.

This can only be set for new scans.

Raises

ValueError – If user attempts to set when this value is read-only.

property cell_point_validity

A list of booleans specifying which items in the underlying cell network are valid. Invalid points are not stored (and thus do not require point properties, such as colour to be stored for them).

For scans created in the Python SDK, all points are considered valid.

Notes

point_count() will return the count of the valid points in the scan. However row_count() * column_count() will give the count of the horizontal and vertical angles - angles are stored for invalid points.

property point_intensity

A list containing the intensity of the points - one value for each point.

Each intensity value is represented as a 16 bit unsigned integer and should be between 0 and 65535 (inclusive). If the value is outside of this range, integer overflow will occur.

property is_column_major

True if the scan is stored in a column major cell network.

All scans created via the SDK will be in row-major order.

save()

Save the changes made to the object.

Generally a user does not need to call this function because it is called automatically at the end of a with block using Project.new() or Project.edit().

property cell_point_count

Returns the number of points in the underlying cell network. This count includes invalid points for which point properties are not stored. If all points are valid, cell_point_count == point_count. If any points are invalid then cell_point_count > point_count.

This is equivalent to row_count * column_count.

See also

mapteksdk.data.primitives.PointProperties.point_count

The count of valid points in the scan.