Geometry API reference

motmot.geometry.area(polygon)[source]

Calculate the area of arbitrary polygons.

Return type

ndarray

motmot.geometry.center_of_mass(points, weights=None)[source]

The (weighted) mean of points.

motmot.geometry.closest(points, target)[source]

Select from points the point which is closest to to.

Parameters
  • points – An array of vertices to choose from.

  • target – A single target vertex to be closest to.

Returns

One vertex from points.

motmot.geometry.furthest(points, direction, n=None, return_projection=False, return_args=False)[source]

Select the point the furthest in direction.

Parameters
  • points (numpy.ndarray) – Some points.

  • direction (numpy.ndarray or UnitVector) – A direction.

  • n (int or None) – Specify the furthest n points instead of just one.

  • return_projection (bool) – If true, also return the projection of the furthest point(s).

  • return_args (bool) – If true, also return the index(es) similar to numpy.argmax().

motmot.geometry.get_components(points, *unit_vectors)[source]

Get the inner product for each unit vector as separate arrays.

Parameters
Returns

Projections for each unit vector.

Return type

tuple[numpy.ndarray]

motmot.geometry.get_components_zipped(points, *unit_vectors)[source]

Get the inner product for each unit vector.

Parameters
Returns

Projections as one array.

Return type

numpy.ndarray

The unit-vector iteration corresponds to the last axis of the output. i.e

out[..., i] == inner_product(unit_vectors[i], points)

The more linear-algebra savvy developer will know that this is just a matrix multiplication. This function is purely to reduce confusion for those (like me) who can never remember if you pre or post multiply and when to transpose.

motmot.geometry.inner_product(a, b, keepdims=False)[source]

Calculates the scalar/inner/interior/dot/”whatever you want to call it” product of vectors a and b, returning a scalar.

Arguments a and b must be numpy-broadcastable.

See also

The UnitVector class for a more convenient way to perform multiple inner_product() calls.

motmot.geometry.magnitude(vector, keepdims=False)[source]

Calculate the hypotenuse/magnitude/length of a vector.

motmot.geometry.magnitude_sqr(vector, keepdims=False)[source]

Calculate the square of the hypotenuse of a vector.

This is faster than magnitude() because it skips taking the square root and can be used to compare or sort distances.

motmot.geometry.normalise(vector)[source]

Modify in-place vector so that it has magnitude 1.0.

Parameters

vector (numpy.ndarray) – Vector(s) to normalise.

Returns

The original magnitudes of vector.

Return type

numpy.ndarray

See also

normalised() which leaves the original as-is.

motmot.geometry.normalised(vector)[source]

Return a normalised copy of vector.

See also

normalise() to modify in-place.

motmot.geometry.snap_to_plane(point, origin, normal)[source]

Map point to its nearest point on a plane.

Parameters
  • point – A vertex or vertices to move.

  • origin – The plane’s origin. Or any point already on the plane(s).

  • normal – A unit normal to the plane.

Return type

ndarray

Returns

The translated points.

Alternatively, you may think of this as move point along normal until the resulting output point satisfies:

inner_product(normal, output) == inner_product(normal, point)
motmot.geometry.unzip(points)[source]

Separate each component from an array of points.

Parameters

points – Some points.

Return type

Tuple[ndarray, …]

Returns

Each axis separately as a tuple.

This is the inverse of zip().

motmot.geometry.zip(*axes)[source]

Combine separate x, y, z arrays into a single points array.

Parameters

axes – Each separate axis to combine.

Return type

ndarray

Returns

A single array with shape[-1] == len(axes).

All axes must have the matching or broadcast-able shapes. The number of axes doesn’t have to be 3.

>>> zip(np.arange(5), np.arange(-2, 3))
array([[ 0, -2],
       [ 1, -1],
       [ 2,  0],
       [ 3,  1],
       [ 4,  2]])

>>> zip(np.arange(10), 4, np.arange(-5, 5))
array([[ 0,  4, -5],
       [ 1,  4, -4],
       [ 2,  4, -3],
       [ 3,  4, -2],
       [ 4,  4, -1],
       [ 5,  4,  0],
       [ 6,  4,  1],
       [ 7,  4,  2],
       [ 8,  4,  3],
       [ 9,  4,  4]])

See also

unzip() for the reverse.

This function is similar to numpy.c_ except that it is not limited to 2D arrays.

class motmot.geometry.UnitVector(vector)[source]

Unit vectors symbolise directions.

A UnitVector wraps around an numpy array, stored in the vector attribute, which contains the actual data. It behaves exactly like an array but with extra methods.

It is also callable, which applies the inner-product.

Usage Example:

Suppose we have a point cloud of 100 points called points.

import numpy as np
from motmot import geometry

points = np.random.uniform(-30, 30, (100, 3))

In a wonky coordinate system that has been so that up is actually the diagonal unit-vector below.

\[\begin{bmatrix} \frac{3}{5}\quad \frac{4}{5}\quad 0 \end{bmatrix}\]

Which is passed to Python using the following. Note that the vector is normalised automatically.

>>> up = geometry.UnitVector([3, 4, 0])
>>> up
UnitVector([0.6 0.8 0. ])

This can do everything a numpy array can do. Any outputs produced are of type numpy.ndarray.

>>> up * 2
array([1.2, 1.6, 0. ])
>>> up + 1
array([1.6, 1.8, 1. ])
>>> up + up
array([1.2, 1.6, 0. ])

There is one exception to the above: Negating it returns another UnitVector.

>>> -up
UnitVector([-0.6 -0.8 -0. ])

To get the heights of points use the inner product.

heights = up.inner_product(points)

A typical 3D analysis will involve lots of inner-product calls so the above gets combersome pretty quickly. For convenience, you may instead call the vector directly.

heights = up(points)

Once you have your heights, the following numpy functions are your friends:

heights.min()   # minimum height
heights.max()   # maximum height
heights.mean()  # average height
heights.ptp()   # `peak to peak` equivalent to max - min

Get the highest point using:

highest = up.furthest(points)

Or:

highest, max_height = up.furthest(points, return_projection=True)

If you actually want the lowest then invert up to get a down vector.

lowest = (-up).furthest(points)

Methods get_component() and remove_component() split a point into parts parallel and perpendicular to up.

Methods with_() and match() return points modified to have specified heights. They both have the effect of mapping the input onto a plane with up as the plane normal.

# Get `points` but with a height of 10.
up.with_projection(points, 10)
# Get `points` but with the same height as ``points[0]``.
up.match_projection(points, points[0])
__init__(vector)[source]
Parameters

vector (numpy.ndarray or UnitVector or str or list or tuple) – The direction as a vector, or an axis name as a string.

vector is normalised automatically.

The str axis name format is an optional sign (+-) followed by any of 'ijkxyz'. Whitespaces and case are ignored.

>>> UnitVector("Z")
UnitVector([0. 0. 1.])
>>> UnitVector("+x")
UnitVector([1. 0. 0.])
>>> UnitVector("-y")
UnitVector([ 0. -1.  0.])
>>> UnitVector("-j")
UnitVector([ 0. -1.  0.])
furthest(points, n=None, return_projection=False, return_args=False)[source]

Select, from points, the point with the highest projection in this direction.

get_component(vector)[source]

Get the component of vector parallel to this direction.

inner_product(vector, keepdims=False)

Call self as a function.

match(point, target_point)[source]

Translate point so that self(point) == self(target_point)

Or the returned point is inline with target_point.

matched_sign(vector)[source]

Return a reversed copy of vector if self(vector) < 0. i.e if the angle between this vector and vector is more than 180°.

remove_component(vector)[source]

Get the components of vector perpendicular to this direction.

vector: numpy.ndarray

The raw numpy vector.

with_(point, projection)[source]

Translate point along this direction so that self(point) == projection.

The output is a modified copy.