# Geometry¶

Classes:

 `Distance`([pairwise, n_dim, metric, squareform]) Given an n_samples x n_dimensions array, compute pairwise or mean distances `Angle`([abs, degrees]) Get angle between line formed by two points and horizontal axis `IMU_Orientation`([use_kalman, invert_gyro]) Compute absolute orientation (roll, pitch) from accelerometer and gyroscope measurements (eg from `hardware.i2c.I2C_9DOF` ) `Rotate`([dims, rotation_type, degrees, ...]) Rotate in 3 dimensions using `scipy.spatial.transform.Rotation` `Spheroid`([target, source, fit]) Fit and transform 3d coordinates according to some spheroid.

Functions:

 `_ellipsoid_func`(fit, a, b, c, x, y, z) Ellipsoid equation for use with `Ellipsoid.fit()`
class Distance(pairwise: bool = False, n_dim: int = 2, metric: str = 'euclidean', squareform: bool = True, *args, **kwargs)[source]

Given an n_samples x n_dimensions array, compute pairwise or mean distances

Parameters
• pairwise (bool) – If False (default), return mean distance. if True, return all distances

• n_dim (int) – number of dimensions (input array will be filtered like `input[:,0:n_dim]`

• metric (str) – any metric acceptable to :func:`scipy.spatial.distance.pdist

• squareform (bool) – if pairwise is True, if True return square distance matrix, otherwise return compressed distance matrix (dist(X[i], X[j] = y[i*j])

• *args

• **kwargs

Attributes:

Methods:

 `process`(input)
format_in = {'type': <class 'numpy.ndarray'>}
format_out = {'type': <class 'numpy.ndarray'>}
process(input: numpy.ndarray)[source]
class Angle(abs=True, degrees=True, *args, **kwargs)[source]

Get angle between line formed by two points and horizontal axis

Attributes:

Methods:

 `process`(input)
format_in = {'type': <class 'numpy.ndarray'>}
format_out = {'type': <class 'float'>}
process(input)[source]
class IMU_Orientation(use_kalman: bool = True, invert_gyro: bool = False, *args, **kwargs)[source]

Compute absolute orientation (roll, pitch) from accelerometer and gyroscope measurements (eg from `hardware.i2c.I2C_9DOF` )

Uses a `timeseries.Kalman` filter, and implements [PPT+18] to fuse the sensors

Can be used with accelerometer data only, or with combined accelerometer/gyroscope data for greater accuracy

Parameters
• invert_gyro (bool) – if the gyroscope’s orientation is inverted from accelerometer measurement, multiply gyro readings by -1 before using

• use_kalman (bool) – Whether to use kalman filtering (True, default), or return raw trigonometric transformation of accelerometer readings (if provided, gyroscope readings will be ignored)

Variables

kalman (`transform.timeseries.Kalman`) – If `use_kalman == True` , the Kalman Filter.

References

[PPT+18] [ABCO15]

Methods:

 `process`(accelgyro) Parameters accelgyro (tuple, `numpy.ndarray`) -- tuple of (accelerometer[x,y,z], gyro[x,y,z]) readings as arrays, or
process(accelgyro: Union[Tuple[numpy.ndarray, numpy.ndarray], numpy.ndarray]) [source]
Parameters

accelgyro (tuple, `numpy.ndarray`) – tuple of (accelerometer[x,y,z], gyro[x,y,z]) readings as arrays, or an array of just accelerometer[x,y,z]

Returns

filtered [roll, pitch] calculations in degrees

Return type

`numpy.ndarray`

class Rotate(dims='xyz', rotation_type='euler', degrees=True, inverse='', rotation=None, *args, **kwargs)[source]

Rotate in 3 dimensions using `scipy.spatial.transform.Rotation`

Parameters
• dims (“xyz”) – string specifying which axes the rotation will be around, eg `"xy"` , `"xyz"``

• rotation_type (str) – Format of rotation input, must be one available to the `Rotation` class (but currently only euler angles are supported)

• degrees (bool) – whether to output rotation in degrees (True, default) or radians

• inverse (“xyz”) – dimensions in the “rotation” input to `Rotate.process()` to inverse before applying rotation

• rotation (tuple, list, `numpy.ndarray`, None) – If supplied, use the same rotation for all processed data. If None, `Rotate.process()` will expect a tuple of (data, rotation).

Methods:

 `process`(input) Parameters input (tuple, `numpy.ndarray`) -- a tuple of (input[x,y,z], rotation[x,y,z]) where input is to be rotated
process(input)[source]
Parameters

input (tuple, `numpy.ndarray`) – a tuple of (input[x,y,z], rotation[x,y,z]) where input is to be rotated according to the axes in rotation (indicated in `Rotate.dims` ). If only an input array is provided, a static rotation array must have been provided in the constructor (otherwise the most recent rotation will be used)

Returns

`numpy.ndarray` - rotated input array

class Spheroid(target=(1, 1, 1, 0, 0, 0), source: tuple = (None, None, None, None, None, None), fit: Optional[numpy.ndarray] = None, *args, **kwargs)[source]

Fit and transform 3d coordinates according to some spheroid.

Eg. for calibrating accelerometer readings by transforming them from their uncalibrated spheroid to the expected sphere with radius == 9.8m/s/s centered at (0,0,0).

Does not estimate/correct for rotation of the spheroid.

Examples

```# Calibrate an accelerometer by transforming
>>> sphere = Spheroid(target=(9.8,9.8,9.8,0,0,0))

# imagine we're taking them from some sensor idk
# say our sensor slightly exaggerates gravity
# in the z-axis...

# fit our object (need >>1 sample)

# transform to proper gravity
[0., 0., 9.8]
```
Parameters
• target (tuple) – parameterization of spheroid to transform to, if none is passed, transform to unit circle centered at (0,0,0). parameterized as:

```(a, # radius of x dimension
```

b, # radius of y dimension c, # radius of z dimension x, # x-offset y, # y-offset z) # z-offset

• source (tuple) – parameterization of spheroid to transform from in the same 6-tuple form as `target`, if None is passed, assume we will use `Spheroid.fit()`

• fit (None, `numpy.ndarray`) – Initialize with values to fit, if None assume fit will be called later.

References

Methods:

 `fit`(points, **kwargs) Fit a spheroid from a set of noisy measurements `process`(input) Transform input (x,y,z) points such that points in `source` are mapped to those in `target` `generate`(n[, which, noise]) Generate random points from the ellipsoid
fit(points, **kwargs)[source]

Fit a spheroid from a set of noisy measurements

updates the `_scale` and `_offset` private arrays used to manipulate input data

Note

It’s usually important to pass `bounds` to `scipy.optimize.curve_fit()` !!! passed as a 2-tuple of `((min_a, min_b, ...), (max_a, max_b...))` In particular such that a, b, and c are positive. If no bounds are passed, assume at least that much.

Parameters
Returns

parameters of fit ellipsoid (a,b,c,x,y,z)

Return type

tuple

process(input: numpy.ndarray)[source]

Transform input (x,y,z) points such that points in `source` are mapped to those in `target`

Parameters

input (`numpy.ndarray`) – x, y, and z coordinates

Returns

coordinates transformed according to the spheroid requested

Return type

`numpy.ndarray`

generate(n: int, which: str = 'source', noise: float = 0)[source]

Generate random points from the ellipsoid

Parameters
• n (int) – number of points to generate

• which (‘str’) – which spheroid to generate from? (‘source’ - default, or ‘target’)

• noise (float) – noise to add to points

Returns

(n, 3) array of generated points

Return type

`numpy.ndarray`

_ellipsoid_func(fit, a, b, c, x, y, z)[source]

Ellipsoid equation for use with `Ellipsoid.fit()`

Parameters
• fit (`numpy.ndarray`) – (M, 3) array of x,y,z points to fit

• a (float) – X-scale parameter to fit

• b (float) – Y-scale parameter to fit

• c (float) – Z-scale parameter to fit

• x (float) – X-offset parameter to fit

• y (float) – Y-offset parameter to fit

• z (float) – Z-offset parameter to fit

Returns

result of ellipsoid function, minimize parameters to == 1

Return type

float