diff --git a/CHANGELOG.md b/CHANGELOG.md index 809f60e..5218c5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ ### Changed - Change implementation status of `IMU.heading` and `IMU.reset_heading`. They are now implemented, with some limitations as noted in a note box. +- Moved `Matrix` and `vector` from `pybricks.geometry` to `pybricks.tools`. +- Moved `Axis` from `pybricks.geometry` to `pybricks.parameters`. + +### Removed +- Removed `pybricks.geometry` module. + +### Changed ## 3.2.0 - 2022-12-20 diff --git a/doc/common/extensions/requirements-static.py b/doc/common/extensions/requirements-static.py index 991dd3c..3162a3e 100644 --- a/doc/common/extensions/requirements-static.py +++ b/doc/common/extensions/requirements-static.py @@ -10,7 +10,6 @@ FEATURES_SMALL = set() # Medium feature set. FEATURES_MEDIUM = FEATURES_SMALL | { - "pybricks-geometry", "pybricks-common-control", "pybricks-iodevices", "stm32-extra", diff --git a/doc/main/geometry.rst b/doc/main/geometry.rst deleted file mode 100644 index 0e1077d..0000000 --- a/doc/main/geometry.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. pybricks-requirements:: stm32-float - -:mod:`geometry ` -- Geometry and algebra -============================================================ - -.. module:: pybricks.geometry - -.. autoclass:: pybricks.geometry.Matrix - :no-members: - - .. autoattribute:: pybricks.geometry::Matrix.T - - .. autoattribute:: pybricks.geometry::Matrix.shape - -.. autofunction:: pybricks.geometry.vector - -.. autoclass:: pybricks.geometry.Axis - :no-members: - -.. _robotframe: - -Reference frames ------------------------ - -The Pybricks module and this documentation use the following conventions: - -- X: Positive means forward. Negative means backward. -- Y: Positive means to the left. Negative means to the right. -- Z: Positive means upward. Negative means downward. - -To make sure that all hub measurements (such as acceleration) have the correct -value and sign, you can specify how the hub is mounted in your creation. This -adjust the measurements so that it is easy to see how your *robot* is moving, -rather than how the *hub* is moving. - -For example, the hub may be mounted upside down in your design. If you -configure the settings as shown in :numref:`fig_imuexamples`, the hub -measurements will be adjusted accordingly. This way, a positive acceleration -value in the X direction means that your *robot* accelerates forward, even -though the *hub* accelerates backward. - -.. _fig_imuexamples: - -.. figure:: ../main/diagrams/imuexamples.png - :width: 100 % - - How to configure the ``top_side`` and ``front_side`` settings for three - different robot designs. The same technique can be applied to other hubs - and other creations, by noting which way the top and - front :class:`Side ` of the hub are pointing. The example - on the left is the default configuration. diff --git a/doc/main/index.rst b/doc/main/index.rst index 63d90d5..e594a38 100644 --- a/doc/main/index.rst +++ b/doc/main/index.rst @@ -60,7 +60,6 @@ above to reveal this menu. parameters/index tools/index robotics - geometry signaltypes .. toctree:: diff --git a/doc/main/parameters/axis.rst b/doc/main/parameters/axis.rst new file mode 100644 index 0000000..49b19ff --- /dev/null +++ b/doc/main/parameters/axis.rst @@ -0,0 +1,7 @@ +.. pybricks-requirements:: stm32-float + +Axis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: pybricks.parameters.Axis + :no-members: diff --git a/doc/main/parameters/index.rst b/doc/main/parameters/index.rst index caa1600..16532fd 100644 --- a/doc/main/parameters/index.rst +++ b/doc/main/parameters/index.rst @@ -10,6 +10,7 @@ :maxdepth: 1 :hidden: + axis button color direction @@ -18,6 +19,8 @@ side stop +.. pybricks-classlink:: Axis + .. pybricks-classlink:: Button .. pybricks-classlink:: Color diff --git a/doc/main/signaltypes.rst b/doc/main/signaltypes.rst index 8fea369..675aeae 100644 --- a/doc/main/signaltypes.rst +++ b/doc/main/signaltypes.rst @@ -260,3 +260,36 @@ Fahrenheit (°F) or Kelvin (K), you can use the following conversion formulas: hue: deg -------------- Hue of a color (0-359 degrees). + +.. _robotframe: + +Reference frames +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Pybricks module and this documentation use the following conventions: + +- X: Positive means forward. Negative means backward. +- Y: Positive means to the left. Negative means to the right. +- Z: Positive means upward. Negative means downward. + +To make sure that all hub measurements (such as acceleration) have the correct +value and sign, you can specify how the hub is mounted in your creation. This +adjust the measurements so that it is easy to see how your *robot* is moving, +rather than how the *hub* is moving. + +For example, the hub may be mounted upside down in your design. If you +configure the settings as shown in :numref:`fig_imuexamples`, the hub +measurements will be adjusted accordingly. This way, a positive acceleration +value in the X direction means that your *robot* accelerates forward, even +though the *hub* accelerates backward. + +.. _fig_imuexamples: + +.. figure:: ../main/diagrams/imuexamples.png + :width: 100 % + + How to configure the ``top_side`` and ``front_side`` settings for three + different robot designs. The same technique can be applied to other hubs + and other creations, by noting which way the top and + front :class:`Side ` of the hub are pointing. The example + on the left is the default configuration. diff --git a/doc/main/tools/index.rst b/doc/main/tools/index.rst index 73e4074..5adbeff 100644 --- a/doc/main/tools/index.rst +++ b/doc/main/tools/index.rst @@ -19,3 +19,15 @@ .. automethod:: pybricks.tools.StopWatch.reset +.. pybricks-requirements:: stm32-float + +.. autoclass:: pybricks.tools.Matrix + :no-members: + + .. autoattribute:: pybricks.tools::Matrix.T + + .. autoattribute:: pybricks.tools::Matrix.shape + +.. pybricks-requirements:: stm32-float + +.. autofunction:: pybricks.tools.vector diff --git a/examples/pup/hub_common/imu_read_scalar.py b/examples/pup/hub_common/imu_read_scalar.py index ef94d02..ce0b6b4 100644 --- a/examples/pup/hub_common/imu_read_scalar.py +++ b/examples/pup/hub_common/imu_read_scalar.py @@ -1,7 +1,7 @@ # ThisHub = TechnicHub PrimeHub EssentialHub from pybricks.hubs import ThisHub from pybricks.tools import wait -from pybricks.geometry import Axis +from pybricks.parameters import Axis # Initialize the hub. hub = ThisHub() diff --git a/examples/pup/hub_common/imu_tilt_blast.py b/examples/pup/hub_common/imu_tilt_blast.py index 8abe06b..5d1cbdb 100644 --- a/examples/pup/hub_common/imu_tilt_blast.py +++ b/examples/pup/hub_common/imu_tilt_blast.py @@ -1,7 +1,7 @@ # ThisHub = TechnicHub PrimeHub EssentialHub from pybricks.hubs import ThisHub from pybricks.tools import wait -from pybricks.geometry import Axis +from pybricks.parameters import Axis # Initialize the hub. In this case, specify that the hub is mounted with the # top side facing forward and the front side facing to the right. diff --git a/examples/pup/hub_primehub/display_matrix.py b/examples/pup/hub_primehub/display_matrix.py index b3631f1..278500c 100644 --- a/examples/pup/hub_primehub/display_matrix.py +++ b/examples/pup/hub_primehub/display_matrix.py @@ -1,6 +1,5 @@ from pybricks.hubs import PrimeHub -from pybricks.tools import wait -from pybricks.geometry import Matrix +from pybricks.tools import wait, Matrix # Initialize the hub. hub = PrimeHub() diff --git a/jedi/src/pybricks_jedi/__init__.py b/jedi/src/pybricks_jedi/__init__.py index 638be69..2175f38 100644 --- a/jedi/src/pybricks_jedi/__init__.py +++ b/jedi/src/pybricks_jedi/__init__.py @@ -13,7 +13,6 @@ from typing_extensions import NotRequired, TypedDict PYBRICKS_CODE_PACKAGES = { "micropython", "pybricks", - "pybricks.geometry", "pybricks.hubs", "pybricks.iodevices", "pybricks.parameters", @@ -489,7 +488,6 @@ def initialize(): "pybricks._common", "pybricks.ev3dev", "pybricks.ev3dev.speaker", - "pybricks.geometry", "pybricks.hubs", "pybricks.iodevices", "pybricks.parameters", diff --git a/jedi/tests/test_complete_import.py b/jedi/tests/test_complete_import.py index e69a424..92e5c96 100644 --- a/jedi/tests/test_complete_import.py +++ b/jedi/tests/test_complete_import.py @@ -59,7 +59,6 @@ def test_from_pybricks_import(): code = "from pybricks import " completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) assert [c["insertText"] for c in completions] == [ - "geometry", "hubs", "iodevices", "parameters", @@ -74,7 +73,6 @@ def test_from_pybricks_dot(): code = "from pybricks." completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) assert [c["insertText"] for c in completions] == [ - "geometry", "hubs", "iodevices", "parameters", @@ -84,16 +82,6 @@ def test_from_pybricks_dot(): ] -def test_from_pybricks_geometry_import(): - code = "from pybricks.geometry import " - completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) - assert [c["insertText"] for c in completions] == [ - "Axis", - "Matrix", - "vector", - ] - - def test_from_pybricks_hubs_import(): code = "from pybricks.hubs import " completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) @@ -127,6 +115,7 @@ def test_from_pybricks_parameters_import(): code = "from pybricks.parameters import " completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) assert [c["insertText"] for c in completions] == [ + "Axis", "Button", "Color", "Direction", @@ -167,7 +156,9 @@ def test_from_pybricks_tools_import(): completions: list[CompletionItem] = json.loads(complete(code, 1, len(code) + 1)) assert [c["insertText"] for c in completions] == [ "DataLog", + "Matrix", "StopWatch", + "vector", "wait", ] diff --git a/jedi/tests/test_get_signature.py b/jedi/tests/test_get_signature.py index e8ec4ee..b3dc771 100644 --- a/jedi/tests/test_get_signature.py +++ b/jedi/tests/test_get_signature.py @@ -31,7 +31,7 @@ def _get_function_signature(module: str, function: str) -> SignatureHelp: FUNCTION_PARAMS = [ pytest.param("pybricks.tools", "wait", [(["time: Number"], "None")]), pytest.param( - "pybricks.geometry", + "pybricks.tools", "vector", [ (["x: float", "y: float"], "Matrix"), @@ -152,7 +152,7 @@ CONSTRUCTOR_PARAMS = [ ], ), pytest.param( - "pybricks.geometry", + "pybricks.tools", "Matrix", [["rows: Sequence[Sequence[float]]"]], ), diff --git a/src/pybricks/_common.py b/src/pybricks/_common.py index 97df1f9..37a9acd 100644 --- a/src/pybricks/_common.py +++ b/src/pybricks/_common.py @@ -8,8 +8,8 @@ from __future__ import annotations from typing import Union, Iterable, overload, Optional, Tuple, Collection, TYPE_CHECKING -from .geometry import Matrix, Axis -from .parameters import Direction, Stop, Button, Port, Color, Side +from .tools import Matrix +from .parameters import Axis, Direction, Stop, Button, Port, Color, Side if TYPE_CHECKING: from .parameters import Number @@ -794,7 +794,7 @@ class LightMatrix: Arguments: matrices (iter): Sequence of - :class:`Matrix ` of intensities. + :class:`Matrix ` of intensities. interval (Number, ms): Time to display each image in the list. """ diff --git a/src/pybricks/geometry.py b/src/pybricks/geometry.py deleted file mode 100644 index 136dd21..0000000 --- a/src/pybricks/geometry.py +++ /dev/null @@ -1,132 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright (c) 2018-2022 The Pybricks Authors - -"""Core linear algebra functionality for orientation sensors and robotics.""" - -from __future__ import annotations - -from typing import Sequence, Tuple, overload - - -class Matrix: - """Mathematical representation of a matrix. It supports - addition (``A + B``), subtraction (``A - B``), - and matrix multiplication (``A * B``) for matrices of compatible size. - - It also supports scalar multiplication (``c * A`` or ``A * c``) - and scalar division (``A / c``). - - A :class:`.Matrix` object is immutable.""" - - def __add__(self, other) -> Matrix: - ... - - def __iadd__(self, other) -> Matrix: - ... - - def __sub__(self, other) -> Matrix: - ... - - def __isub__(self, other) -> Matrix: - ... - - def __mul__(self, other) -> Matrix: - ... - - def __rmul__(self, other) -> Matrix: - ... - - def __imul__(self, other) -> Matrix: - ... - - def __truediv__(self, other) -> Matrix: - ... - - def __itruediv__(self, other) -> Matrix: - ... - - def __floordiv__(self, other) -> Matrix: - ... - - def __ifloordiv__(self, other) -> Matrix: - ... - - def __init__(self, rows: Sequence[Sequence[float]]): - """Matrix(rows) - - Arguments: - rows (list): List of rows. Each row is itself a list of numbers. - - """ - - @property - def T(self) -> Matrix: # noqa: N802 - """Returns a new :class:`.Matrix` that is the transpose of the - original.""" - - @property - def shape(self) -> Tuple[int, int]: - """Returns a tuple (``m``, ``n``), - where ``m`` is the number of rows and ``n`` is the number of columns. - """ - - -@overload -def vector(x: float, y: float) -> Matrix: - """ - Convenience function to create a :class:`.Matrix` with the shape (``2``, ``1``). - - Arguments: - x (float): x-coordinate of the vector. - y (float): y-coordinate of the vector. - - Returns: - A matrix with the shape of a column vector. - """ - - -@overload -def vector(x: float, y: float, z: float) -> Matrix: - """ - Convenience function to create a :class:`.Matrix` with the shape (``3``, ``1``). - - Arguments: - x (float): x-coordinate of the vector. - y (float): y-coordinate of the vector. - z (float): z-coordinate of the vector. - - Returns: - A matrix with the shape of a column vector. - """ - - -def vector(*args): - """ - vector(x, y) -> Matrix - vector(x, y, z) -> Matrix - - Convenience function to create a :class:`.Matrix` with the - shape (``2``, ``1``) or (``3``, ``1``). - - Arguments: - x (float): x-coordinate of the vector. - y (float): y-coordinate of the vector. - z (float): z-coordinate of the vector (optional). - - Returns: - A matrix with the shape of a column vector. - """ - - -class Axis: - """Unit axes of a coordinate system. - - .. data:: X = vector(1, 0, 0) - .. data:: Y = vector(0, 1, 0) - .. data:: Z = vector(0, 0, 1) - - """ - - X: Matrix = vector(1, 0, 0) - Y: Matrix = vector(0, 1, 0) - Z: Matrix = vector(0, 0, 1) diff --git a/src/pybricks/hubs.py b/src/pybricks/hubs.py index ccb4ac0..edd1bb0 100644 --- a/src/pybricks/hubs.py +++ b/src/pybricks/hubs.py @@ -4,9 +4,8 @@ """LEGO® Programmable Hubs.""" from . import _common from .ev3dev import _speaker -from .geometry import Axis from .media.ev3dev import Image as _Image -from .parameters import Button as _Button +from .parameters import Button as _Button, Axis class EV3Brick: diff --git a/src/pybricks/parameters.py b/src/pybricks/parameters.py index 9102b0f..9ccd0fe 100644 --- a/src/pybricks/parameters.py +++ b/src/pybricks/parameters.py @@ -9,7 +9,7 @@ from enum import Enum from typing import Union, TYPE_CHECKING import os -from .geometry import Matrix as _Matrix +from .tools import Matrix as _Matrix, vector as _vector if TYPE_CHECKING or os.environ.get("SPHINX_BUILD") == "True": Number = Union[int, float] @@ -57,6 +57,20 @@ class _PybricksEnum(Enum, metaclass=_PybricksEnumMeta): return str(self) +class Axis: + """Unit axes of a coordinate system. + + .. data:: X = vector(1, 0, 0) + .. data:: Y = vector(0, 1, 0) + .. data:: Z = vector(0, 0, 1) + + """ + + X: _Matrix = _vector(1, 0, 0) + Y: _Matrix = _vector(0, 1, 0) + Z: _Matrix = _vector(0, 0, 1) + + class Color: """Light or surface color.""" diff --git a/src/pybricks/tools.py b/src/pybricks/tools.py index ddd76a6..d1da379 100644 --- a/src/pybricks/tools.py +++ b/src/pybricks/tools.py @@ -1,11 +1,11 @@ # SPDX-License-Identifier: MIT # Copyright (c) 2018-2022 The Pybricks Authors -"""Common tools for timing and data logging.""" +"""Common tools for timing, data logging, and geometry math tools.""" from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Sequence, Tuple, overload if TYPE_CHECKING: from .parameters import Number @@ -97,6 +97,116 @@ class DataLog: """ +class Matrix: + """Mathematical representation of a matrix. It supports + addition (``A + B``), subtraction (``A - B``), + and matrix multiplication (``A * B``) for matrices of compatible size. + + It also supports scalar multiplication (``c * A`` or ``A * c``) + and scalar division (``A / c``). + + A :class:`.Matrix` object is immutable.""" + + def __add__(self, other) -> Matrix: + ... + + def __iadd__(self, other) -> Matrix: + ... + + def __sub__(self, other) -> Matrix: + ... + + def __isub__(self, other) -> Matrix: + ... + + def __mul__(self, other) -> Matrix: + ... + + def __rmul__(self, other) -> Matrix: + ... + + def __imul__(self, other) -> Matrix: + ... + + def __truediv__(self, other) -> Matrix: + ... + + def __itruediv__(self, other) -> Matrix: + ... + + def __floordiv__(self, other) -> Matrix: + ... + + def __ifloordiv__(self, other) -> Matrix: + ... + + def __init__(self, rows: Sequence[Sequence[float]]): + """Matrix(rows) + + Arguments: + rows (list): List of rows. Each row is itself a list of numbers. + + """ + + @property + def T(self) -> Matrix: # noqa: N802 + """Returns a new :class:`.Matrix` that is the transpose of the + original.""" + + @property + def shape(self) -> Tuple[int, int]: + """Returns a tuple (``m``, ``n``), + where ``m`` is the number of rows and ``n`` is the number of columns. + """ + + +@overload +def vector(x: float, y: float) -> Matrix: + """ + Convenience function to create a :class:`.Matrix` with the shape (``2``, ``1``). + + Arguments: + x (float): x-coordinate of the vector. + y (float): y-coordinate of the vector. + + Returns: + A matrix with the shape of a column vector. + """ + + +@overload +def vector(x: float, y: float, z: float) -> Matrix: + """ + Convenience function to create a :class:`.Matrix` with the shape (``3``, ``1``). + + Arguments: + x (float): x-coordinate of the vector. + y (float): y-coordinate of the vector. + z (float): z-coordinate of the vector. + + Returns: + A matrix with the shape of a column vector. + """ + + +def vector(*args): + """ + vector(x, y) -> Matrix + vector(x, y, z) -> Matrix + + Convenience function to create a :class:`.Matrix` with the + shape (``2``, ``1``) or (``3``, ``1``). + + Arguments: + x (float): x-coordinate of the vector. + y (float): y-coordinate of the vector. + z (float): z-coordinate of the vector (optional). + + Returns: + A matrix with the shape of a column vector. + """ + + # HACK: hide from jedi if TYPE_CHECKING: del Number