diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..8b64dae --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: b91813fa1201a767cc40d0635dfb4bee +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/changelog.doctree b/.doctrees/changelog.doctree new file mode 100644 index 0000000..315c258 Binary files /dev/null and b/.doctrees/changelog.doctree differ diff --git a/.doctrees/contributing.doctree b/.doctrees/contributing.doctree new file mode 100644 index 0000000..6480300 Binary files /dev/null and b/.doctrees/contributing.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000..c5b2090 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 0000000..024d827 Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/installation.doctree b/.doctrees/installation.doctree new file mode 100644 index 0000000..b8806af Binary files /dev/null and b/.doctrees/installation.doctree differ diff --git a/.doctrees/license.doctree b/.doctrees/license.doctree new file mode 100644 index 0000000..db7dc28 Binary files /dev/null and b/.doctrees/license.doctree differ diff --git a/.doctrees/reference.doctree b/.doctrees/reference.doctree new file mode 100644 index 0000000..a4c359e Binary files /dev/null and b/.doctrees/reference.doctree differ diff --git a/.doctrees/reference/compas_mrr.arbitrary_pts_localization.doctree b/.doctrees/reference/compas_mrr.arbitrary_pts_localization.doctree new file mode 100644 index 0000000..69b68b4 Binary files /dev/null and b/.doctrees/reference/compas_mrr.arbitrary_pts_localization.doctree differ diff --git a/.doctrees/reference/compas_mrr.doctree b/.doctrees/reference/compas_mrr.doctree new file mode 100644 index 0000000..45c8201 Binary files /dev/null and b/.doctrees/reference/compas_mrr.doctree differ diff --git a/.doctrees/reference/compas_mrr.measurement_point.doctree b/.doctrees/reference/compas_mrr.measurement_point.doctree new file mode 100644 index 0000000..5312a4b Binary files /dev/null and b/.doctrees/reference/compas_mrr.measurement_point.doctree differ diff --git a/.doctrees/reference/compas_mrr.three_pts_localization.doctree b/.doctrees/reference/compas_mrr.three_pts_localization.doctree new file mode 100644 index 0000000..6ecd10f Binary files /dev/null and b/.doctrees/reference/compas_mrr.three_pts_localization.doctree differ diff --git a/.doctrees/reference/compas_mrr.utils.doctree b/.doctrees/reference/compas_mrr.utils.doctree new file mode 100644 index 0000000..722c78a Binary files /dev/null and b/.doctrees/reference/compas_mrr.utils.doctree differ diff --git a/.doctrees/reference/compas_mrr.xforms.doctree b/.doctrees/reference/compas_mrr.xforms.doctree new file mode 100644 index 0000000..10206c8 Binary files /dev/null and b/.doctrees/reference/compas_mrr.xforms.doctree differ diff --git a/.doctrees/usage.doctree b/.doctrees/usage.doctree new file mode 100644 index 0000000..7e0cbd9 Binary files /dev/null and b/.doctrees/usage.doctree differ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_modules/compas_mrr.html b/_modules/compas_mrr.html new file mode 100644 index 0000000..a0f3cea --- /dev/null +++ b/_modules/compas_mrr.html @@ -0,0 +1,375 @@ + + + + + + compas_mrr - compas_mrr + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr


+"""compas_mrr"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import os
+from os import path
+from distutils.version import LooseVersion
+
+import compas
+import compas.plugins
+
+from .measurement_point import *  # noqa: F401, F403
+from .three_pts_localization import *  # noqa: F401, F403
+
+if not compas.IPY:
+    from .arbitrary_pts_localization import *  # noqa: F401, F403
+
+PKG_ROOT = path.dirname(__file__)
+REPO_ROOT = path.abspath(path.join(PKG_ROOT, ".."))
+
+compas.PRECISION = "12f"
+
+
+def _get_version():  # type: () -> str
+    # from https://smarie.github.io/python-getversion/#package-versioning-best-practices
+    # and setuptools_scm docs
+    try:
+        # import from _version.py generated by setuptools_scm during release
+        from ._version import version  # type: ignore
+
+        return version
+    except ImportError:
+        try:
+            from importlib.metadata import version  # type: ignore [no-redef]
+
+            return version("rapid-clay-formations-fab")  # type: ignore [operator]
+        except ImportError:
+            try:
+                from importlib_metadata import version  # type: ignore [no-redef]
+
+                return version("rapid-clay-formations-fab")  # type: ignore [operator]
+            except ImportError:
+                pass
+
+    return "src"
+
+
+
[docs]@compas.plugins.plugin(category="install") +def installable_rhino_packages(): + return ["compas_mrr"]
+ + +__author__ = "Gramazio Kohler Research" +__copyright__ = "2020 Gramazio Kohler Research" +__license__ = "MIT License" +__email__ = "anton@tetov.se" +__version__ = _get_version() + + +__all_plugins__ = ["compas_mrr.rhino_install"] + +# Backport for path related bug with compas.rpc.Proxy +# See https://github.com/compas-dev/compas/issues/701 +# & https://github.com/compas-dev/compas/pull/720 + + +def _fixed_prepare_environment(env=None): + """Prepares an environment context to run Python on. + + Copied from https://github.com/compas-dev/compas/blob/v0.19.2/src/compas/_os.py + + If Python is being used from a conda environment, this is roughly equivalent + to activating the conda environment by setting up the correct environment + variables. + + Parameters + ---------- + env : dict, optional + Dictionary of environment variables to modify. If ``None`` is passed, then + this will create a copy of the current ``os.environ``. + + Returns + ------- + dict + Updated environment variable dictionary. + """ + from compas import WINDOWS + from compas._os import PYTHON_DIRECTORY + from compas._os import CONDA_EXE + + if env is None: + env = os.environ.copy() + + if PYTHON_DIRECTORY: + if WINDOWS: + lib_bin = os.path.join(PYTHON_DIRECTORY, "Library", "bin") + else: + lib_bin = os.path.join(PYTHON_DIRECTORY, "bin") + + if os.path.exists(lib_bin) and lib_bin not in env["PATH"]: + env["PATH"] = lib_bin + os.pathsep + env["PATH"] + + if CONDA_EXE: + env["CONDA_EXE"] = CONDA_EXE + + return env + + +if LooseVersion(compas.__version__) < LooseVersion("0.19.2"): + import compas._os + + compas._os.prepare_environment = _fixed_prepare_environment +
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/compas_mrr/arbitrary_pts_localization.html b/_modules/compas_mrr/arbitrary_pts_localization.html new file mode 100644 index 0000000..43bf521 --- /dev/null +++ b/_modules/compas_mrr/arbitrary_pts_localization.html @@ -0,0 +1,563 @@ + + + + + + compas_mrr - compas_mrr.arbitrary_pts_localization + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr.arbitrary_pts_localization


+"""
+*******************************************************************************
+Arbitrary points method for robot relocalization.
+*******************************************************************************
+"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import sys
+import tempfile
+from functools import reduce
+
+import numpy as np
+from scipy.optimize import minimize
+
+from compas_mrr.utils import TYPE_CHECKING
+
+try:
+    from pathlib import Path
+except ImportError:
+    if sys.version_info.major < 3:
+        raise Exception("Python 3 is required to run this module.")
+    else:
+        raise
+
+if TYPE_CHECKING:
+    from typing import List  # noqa: F401
+
+    from scipy.optimize import OptimizeResult  # noqa: F401
+
+
+def _objective_function(
+    x,  # type: List[float]
+    rcs_coords,  # type: List[List[float]]
+    wcs_coords,  # type: List[List[float]]
+):  # type: (...) -> float
+    """Objective function for the optimization problem.
+
+    Parameters
+    ----------
+    x
+        The optimization variable (9x1)
+    args : :obj:`tuple`
+        The localization points and the measurements as a tuple of two
+        dimensional arrays where each row is one point. The columns are the X,
+        Y and Z coordinates.
+
+    Returns
+    -------
+    :obj:`float`
+        The cost for the given optimization variable values.
+    """
+    origin = np.array(x[0:3])
+    x_vec = np.array(x[3:6])
+    y_vec = np.array(x[6:9])
+    z_vec = np.cross(x_vec, y_vec)
+
+    cost = 0
+    for point, measurement in zip(rcs_coords, wcs_coords):
+        # Calculate the deviation from the measurement using the given
+        # coordinate system (optimization variable) and add the square of it to
+        # the cost.
+        deviation = np.power(
+            origin
+            + point[0] * x_vec
+            + point[1] * y_vec
+            + point[2] * z_vec
+            - measurement,
+            2,
+        )
+        cost += sum(deviation)
+
+    return cost
+
+
+def _nonlinear_constraints(x):  # type: (List[float]) -> List[float]
+    """Constraints for the optimization problem.
+
+    Parameters
+    ----------
+    x
+        The optimization variable (9x1).
+
+    Returns
+    -------
+    :obj:`list` of :obj:`float`
+        An array that contains the values when the constraints are evaluated at
+        `x`.
+    """
+    return [
+        # x and y need to be orthogonal (i.e. scalar product = 0)
+        x[3] * x[6] + x[4] * x[7] + x[5] * x[8],
+        x[3] ** 2 + x[4] ** 2 + x[5] ** 2 - 1,  # |x| = 1
+        x[6] ** 2 + x[7] ** 2 + x[8] ** 2 - 1,  # |y| = 1
+    ]
+
+
+def _nonlinear_jacobian(x):  # type: (List[float]) -> List[List[float]]
+    """Jacobian for the constraints.
+
+    Parameters
+    ----------
+    x
+        The optimization variable (9x1).
+
+    Returns
+    -------
+        The jacobian of the nonlinear constraints.
+    """
+    return [
+        [0, 0, 0, x[6], x[7], x[8], x[3], x[4], x[5]],
+        [0, 0, 0, 2 * x[3], 2 * x[4], 2 * x[5], 0, 0, 0],
+        [0, 0, 0, 0, 0, 0, 2 * x[6], 2 * x[7], 2 * x[8]],
+    ]
+
+
+def _plot(
+    rcs_coords,  # type: List[List[float]]
+    wcs_coords,  # type: List[List[float]]
+    results,  # type: OptimizeResult
+):  # type: (...) -> None
+    """Create plots to visualize multiple consecutive results from a solver."""
+    import matplotlib.pyplot as plt
+
+    rcs_coords = np.array(rcs_coords)
+    wcs_coords = np.array(wcs_coords)
+
+    plot_dir = Path(tempfile.mkdtemp(prefix="localization_"))
+    print("Saving plots to {}".format(plot_dir))
+
+    for i, res in enumerate(results):
+        dir_ = plot_dir / str(i)
+        dir_.mkdir()
+
+        _plot_result(rcs_coords, wcs_coords, res, dir_)
+
+    # Create a plot summarizing the the different runs
+    objective_values = [result.fun for result in results]
+    summary_file_path = plot_dir / "summary.png"
+    plt.figure()
+    plt.plot(range(len(objective_values)), objective_values, "ro")
+    plt.ylabel("Objective value")
+    plt.xlabel("Run")
+    plt.title("Objective value for different x_0")
+    plt.savefig(summary_file_path)
+
+
+def _plot_result(
+    rcs_coords,  # type: np.ndarray
+    wcs_coords,  # type: np.ndarray
+    result,  # type: OptimizeResult
+    plot_dir,  # type: Path
+):  # type: (...) -> None
+    """Create some plots that illustrate the result.
+
+    Parameters
+    ----------
+    rcs_coords
+    wcs_coords
+    result
+        The result from the solver
+    folder
+        The folder in which the plots should be stored.
+
+    Returns
+    -------
+    :obj:`str`
+        The path at which the plots were stored.
+    """
+    import matplotlib.pyplot as plt
+
+    origin = result.x[0:3]
+    x_vec = result.x[3:6]
+    y_vec = result.x[6:9]
+    z_vec = np.cross(x_vec, y_vec)
+
+    x_axis = origin + 1000 * x_vec
+    y_axis = origin + 1000 * y_vec
+    # z_axis = origin + 1000 * z_vec
+
+    # Calculate the localization points in the new coordinate system
+    _transformed_points = []
+    for point in rcs_coords:
+        _transformed_points.append(
+            origin + point[0] * x_vec + point[1] * y_vec + point[2] * z_vec
+        )
+    transformed_points = np.array(_transformed_points)
+
+    plt.figure()
+    plt.plot(wcs_coords.T[0], wcs_coords.T[1], "bo")
+    plt.plot(transformed_points.T[0], wcs_coords.T[1], "rx")
+    plt.plot(origin[0], origin[1], "bx")
+    plt.plot(x_axis[0], x_axis[1], "rx")
+    plt.plot(y_axis[0], y_axis[1], "gx")
+    plt.xlabel("x")
+    plt.ylabel("y")
+    plt.title("X-Y projection")
+    plt.savefig(plot_dir / "rcs_matching_xy.png")
+
+    plt.figure()
+    plt.plot(wcs_coords.T[0], wcs_coords.T[2], "bo")
+    plt.plot(transformed_points.T[0], wcs_coords.T[2], "rx")
+    plt.plot(origin[0], origin[2], "bx")
+    plt.plot(x_axis[0], x_axis[2], "rx")
+    plt.plot(y_axis[0], y_axis[2], "gx")
+    plt.xlabel("x")
+    plt.ylabel("z")
+    plt.title("X-Z projection")
+    plt.savefig(plot_dir / "rcs_matching_xz.png")
+
+    plt.figure()
+    plt.plot(wcs_coords.T[1], wcs_coords.T[2], "bo")
+    plt.plot(transformed_points.T[1], wcs_coords.T[2], "rx")
+    plt.plot(origin[1], origin[2], "bx")
+    plt.plot(x_axis[1], x_axis[2], "rx")
+    plt.plot(y_axis[1], y_axis[2], "gx")
+    plt.xlabel("y")
+    plt.ylabel("z")
+    plt.title("Y-Z projection")
+    plt.savefig(plot_dir / "rcs_matching_yz.png")
+
+
+
[docs]def arbitrary_pts_localization( + rcs_coords, # type: List[List[float]] + wcs_coords, # type: List[List[float]] + plot_results=False, # type: bool + maxiter=200, # type: int +): # type: (...) -> List[List[float]] + """Calculate the RCS origin frame. + + Finding the origin is formulated as an optimization problem where we want + to find the origin and two orthonormal vectors defining the coordinate + system. At the same time, the position of the localization points in this + new coordinate system should match the measurements as close as possible. + Therefore the deviation from the measurements is used as the cost function. + The only constraints are that the x and y vector need to have length 1 and + be orthogonal to each other. The optimization variable is a vector with 9 + entries: X = [o, x, y] where o is the origin of the coordinate system and + x, y the vectors spanning the x-y-plane. Each of them is a 3 dimensional + vector. **Important**: Ensure that the order of rcs_coords and + measurements is identical. I.e. the i-th entry in measurements is the + measurement of the i-th localization point. + + Parameters + ---------- + rcs_coords + The points where the robot endeffector was positioned to take + measurements. These points are in the RCS. + wcs_coords + The measurements taken in the world coordinate system (WCS) with the + total station. These are the coordinates of the rcs_coords in + the WCS. + + Returns + ------- + :obj:`list` of :obj:`list` of :obj:`float` + A tuple of 3 vectors (lists with 3 elements) where the first represents + the origin of the RCS, the second is the direction of the x axis and + the third the direction of the y axis. The x and y axis are vectors + with length 1. + """ + # Setup the constraints + constraints = {"type": "eq", "fun": _nonlinear_constraints} + + results = [] + slices = 4 + for i in range(slices): + radians = np.deg2rad(360.0 / float(slices) * i) + c, s = np.cos(radians), np.sin(radians) + rotation = np.array(((c, -s, 0), (s, c, 0), (0, 0, 1))) + + x = rotation.dot(np.array([1, 0, 0])) + y = rotation.dot(np.array([0, 1, 0])) + + # We use the standard coordinate system as an initial guess. + x0 = np.array(np.concatenate(([0, 0, 0], x, y))) + res = minimize( + _objective_function, + x0, + args=(rcs_coords, wcs_coords), + method="SLSQP", # Default method for problems with constraints + constraints=constraints, + options={"disp": True, "maxiter": maxiter}, + ) + + results.append(res) + + if plot_results: + _plot(rcs_coords, wcs_coords, results) + + # Pick the result with the lowest objective value + result = reduce((lambda x, y: x if x.fun < y.fun else y), results) + + origin = result.x[0:3].tolist() + x_vec = result.x[3:6].tolist() + y_vec = result.x[6:9].tolist() + + return [origin, x_vec, y_vec]
+
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/compas_mrr/measurement_point.html b/_modules/compas_mrr/measurement_point.html new file mode 100644 index 0000000..2d494d3 --- /dev/null +++ b/_modules/compas_mrr/measurement_point.html @@ -0,0 +1,336 @@ + + + + + + compas_mrr - compas_mrr.measurement_point + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr.measurement_point


+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import compas
+import compas.geometry
+
+from compas_mrr import utils
+from compas_mrr.utils import TYPE_CHECKING
+from compas_mrr.utils import cgpoint_to_rgpoint
+
+if TYPE_CHECKING:
+    from typing import Tuple  # noqa: F401
+    from typing import Union  # noqa: F401
+
+
+
[docs]class MeasurementPoint(compas.geometry.Point): + """A :class:`compas.geometry.Point` with some CSV pointlist related methods.""" + +
[docs] def __init__( + self, + x, # type: float + y, # type: float + z, # type: float + pt_name, # type: str + attrs=None, # type: Union[None, dict] + ): # type: (...) -> None + super(MeasurementPoint, self).__init__(x, y, z) + self.pt_name = pt_name + self.attrs = attrs or {}
+ + def __repr__(self): # type: () -> str + return "Point ID: {}, Location: {}, {}, {}".format( + self.pt_name, self.x, self.y, self.z + ) + + @property + def prefix(self): # type: () -> str + """Point prefix from data source.""" + return self._split_pt_name()[0] + + @property + def idx(self): # type: () -> int + """Point index from data source.""" + return self._split_pt_name()[1] + +
[docs] def as_rgpoint(self): # type: () -> compas.geometry.Point + """Get a point representation in Rhino.""" + return cgpoint_to_rgpoint(self)
+ + def _split_pt_name(self): # type: () -> Tuple[str, int] + idx = "" + + for n, elem in enumerate(self.pt_name[::-1]): + if elem.isdigit(): + idx = elem + idx # add to front of str + else: + idx_last_char_idx = len(self.pt_name) - n + break + + prefix = self.pt_name[:idx_last_char_idx] + + try: + _idx = int(idx) + except ValueError: + _idx = 0 + + return prefix, _idx
+ + +# Make MeasurementPoint available from utils for backwards compatibility +# with compas_mrr <= v1.0.4 +utils.MeasurementPoint = MeasurementPoint # type: ignore[attr-defined] +
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/compas_mrr/three_pts_localization.html b/_modules/compas_mrr/three_pts_localization.html new file mode 100644 index 0000000..3c00c95 --- /dev/null +++ b/_modules/compas_mrr/three_pts_localization.html @@ -0,0 +1,315 @@ + + + + + + compas_mrr - compas_mrr.three_pts_localization + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr.three_pts_localization


+"""Three points method for robot relocalization"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from compas.geometry import Frame
+from compas.geometry import Transformation
+
+from compas_mrr.utils import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import List  # noqa: F401
+    from typing import Union  # noqa: F401
+
+    from compas.geometry import Point  # noqa: F401
+
+
+def _pts_to_frame(pts):  # type: (Point) -> Frame
+    return Frame.from_points(*pts)
+
+
+def _coerce_frame(frame_or_pts):  # type: (Union[List[Point], Frame]) -> Frame
+    if isinstance(frame_or_pts, Frame):
+        return frame_or_pts
+
+    return _pts_to_frame(frame_or_pts)
+
+
+
[docs]def three_pts_localization(rcs_coords, wcs_coords): # type: (List[Point], List[Point]) -> Frame + """Get the robot base frame in WCS using three points method. + + Parameters + ---------- + rcs_coords + List of the RCS coordinates used for measurements. + wcs_coords + List of the WCS coordinates used for measurements. + + Returns + ------- + The base frame of the robot in WCS. + """ + recorded_frame_rcs = _coerce_frame(rcs_coords) + recorded_frame_wcs = _coerce_frame(wcs_coords) + + T = Transformation.from_frame_to_frame(recorded_frame_rcs, recorded_frame_wcs) + + wcs_robot_base = Frame.worldXY() + wcs_robot_base.transform(T) + + return wcs_robot_base
+
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/compas_mrr/utils.html b/_modules/compas_mrr/utils.html new file mode 100644 index 0000000..29a197b --- /dev/null +++ b/_modules/compas_mrr/utils.html @@ -0,0 +1,366 @@ + + + + + + compas_mrr - compas_mrr.utils + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr.utils


+"""Utilities"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import compas
+import compas.geometry
+
+try:
+    import Rhino.Geometry  # type: ignore
+except ImportError:
+    pass
+
+
+def _ensure_rhino():  # type: () -> None
+    if not compas.RHINO:
+        raise ImportError("Can't import Rhino in current environment.")
+
+
+def _is_type_checking():  # type: () -> bool
+    try:
+        import typing  # noqa: F401
+
+        if typing.TYPE_CHECKING:
+            return True
+
+    except ImportError:
+        pass
+
+    return False
+
+
+TYPE_CHECKING = _is_type_checking()  # type: bool
+
+if TYPE_CHECKING:
+    from typing import List  # noqa: F401
+
+
+
[docs]def rgpoint_to_cgpoint(pt): + # type: (Rhino.Geometry.Point3d) -> compas.geometry.Point + """Convert :class:`Rhino.Geometry.Point3d` to :class:`compas.geometry.Point`. + + Parameters + ---------- + pt + Plane object to convert + + Returns + ------- + Resulting point object + """ + return compas.geometry.Point(pt.X, pt.Y, pt.Z)
+ + +
[docs]def cgpoint_to_rgpoint(pt): + # type: (compas.geometry.Point) -> (Rhino.Geometry.Point3d) + """Convert :class:`compas.geometry.Point` to :class:`Rhino.Geometry.Point`.""" + return Rhino.Geometry.Point3d(*list(pt))
+ + +
[docs]def cgframe_to_rgplane(frame): # type: (compas.geometry.Frame) -> Rhino.Geometry.Plane + """Convert :class:`compas.Geometry.Frame` to :class:`Rhino.Geometry.Plane`.""" # noqa: E501 + origin = Rhino.Geometry.Point3d(*list(frame.point)) + x_vec = Rhino.Geometry.Vector3d(*list(frame.xaxis)) + y_vec = Rhino.Geometry.Vector3d(*list(frame.yaxis)) + + return Rhino.Geometry.Plane(origin, x_vec, y_vec)
+ + +
[docs]def rgtransform_to_cgtransformation(rgT): + # type: (Rhino.Geometry.Transform) -> compas.geometry.Transformation + """Convert :class:`Rhino.Geometry.Transform` to :class:`compas.geometry.Transformation`.""" # noqa: E501 + M = rgtransform_to_matrix(rgT) + return compas.geometry.Transformation.from_matrix(M)
+ + +
[docs]def rgtransform_to_matrix(rgT): # type: (Rhino.Geometry.Transform) -> List[List[float]] + """Convert :class:`Rhino.Geometry.Transform` to transformation matrix.""" + return [[rgT.Item[i, j] for j in range(4)] for i in range(4)]
+ + +
[docs]def cgtransformation_to_rgtransform(cgT): + # type: (compas.geometry.Transformation) -> Rhino.Geometry.Transform + """Convert :class:`compas.geometry.Transformation` to :class:`Rhino.Geometry.Transform`.""" # noqa: E501 + _ensure_rhino() + + M = cgT.matrix + + return matrix_to_rgtransform(M)
+ + +
[docs]def matrix_to_rgtransform(M): # type: (List[List[float]]) -> Rhino.Geometry.Transform + """Create :class:`Rhino.Geometry.Transform` from a transformation matrix.""" + _ensure_rhino() + + rgT = Rhino.Geometry.Transform() + + for i, row in enumerate(M): + for j, val in enumerate(row): + rgT[i, j] = val + + return rgT
+
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/compas_mrr/xforms.html b/_modules/compas_mrr/xforms.html new file mode 100644 index 0000000..cde0647 --- /dev/null +++ b/_modules/compas_mrr/xforms.html @@ -0,0 +1,365 @@ + + + + + + compas_mrr - compas_mrr.xforms + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Source code for compas_mrr.xforms


+"""Transformations"""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import compas.geometry as cg
+
+from compas_mrr.utils import TYPE_CHECKING
+
+try:
+    from collections.abc import Sequence
+except ImportError:
+    from collections import Sequence
+
+if TYPE_CHECKING:
+    from typing import Any  # noqa: F401
+    from typing import List  # noqa: F401
+
+
+def _coerce_cg_xform(xform):  # type: (Any) -> cg.Transformation
+    try:
+        from Rhino.Geometry import Transform  # type: ignore
+
+        if isinstance(xform, Transform):
+            from compas_mrr.utils import rgtransform_to_matrix
+
+            M = rgtransform_to_matrix(xform)
+            return cg.Transformation.from_matrix(M)
+    except ImportError:
+        pass
+
+    try:
+        from numpy import ndarray
+
+        if isinstance(xform, ndarray):
+            M = xform.tolist()
+            return cg.Transformation.from_matrix(M)
+    except ImportError:
+        pass
+
+    if isinstance(xform, cg.Transformation):
+        return xform
+
+    if isinstance(xform, Sequence):
+        try:
+            T = cg.Transformation.from_matrix(xform)
+            T.decomposed()  # raises type error on invalid T
+            return T
+        except TypeError:
+            pass
+
+    raise TypeError(
+        "Can't convert {} to compas.geometry.Transformation".format(type(xform))
+    )
+
+
+
[docs]def worldxy_to_robot_base_xform(robot_base_frame): + # type: (cg.Frame) -> cg.Transformation + """Get transformation from WCS origin to RCS origin. + + Parameters + ---------- + robot_base_frame + Robot base frame in WCS. The frame origin is the location of the RCS origo + in WCS, the X axis and Y axis are the X and Y axes of the RCS in WCS. + """ + frame_from = cg.Frame.worldXY() + frame_to = robot_base_frame + + return cg.Transformation.from_change_of_basis(frame_from, frame_to)
+ + +
[docs]def xform_to_xyz_quaternion(xform): # type: (Any) -> List[float] + """Convert transformation to :obj:`list` of coords and quaternion values. + + Parameters + ---------- + xform + Transformation to be converted. Can be given as + :class:`Rhino.Geometry.Transform`, + :class:`compas.geometry.Transformation`, + :class:`numpy.ndarray`, or :obj:`list` of :obj:`list` of :obj:`float`. + + Returns + ------- + X, Y, Z, QW, QX, QY, QZ values as a list. + + >>> from compas.geometry import Frame, Rotation, Translation + >>> Tr = Translation.from_vector([100, 100, 100]) + >>> R = Rotation.from_frame(Frame.worldYZ()) + >>> T = Tr * R + >>> xform_to_xyz_quaternion(T) + [100.0, 100.0, 100.0, 0.5, 0.5, 0.5, 0.5] + """ + xform = _coerce_cg_xform(xform) + + xyz = list(xform.translation_vector) + + wxyz = cg.Quaternion.from_rotation(xform.rotation).wxyz + + return xyz + wxyz
+
+ +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..1e90430 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,265 @@ + + + + + + compas_mrr - Overview: module code + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

All modules for which code is available

+ + +
+ + + + + +
+ + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_sources/changelog.rst.txt b/_sources/changelog.rst.txt new file mode 100644 index 0000000..6336d76 --- /dev/null +++ b/_sources/changelog.rst.txt @@ -0,0 +1 @@ +.. mdinclude:: ../CHANGELOG.md diff --git a/_sources/contributing.rst.txt b/_sources/contributing.rst.txt new file mode 100644 index 0000000..4fc5016 --- /dev/null +++ b/_sources/contributing.rst.txt @@ -0,0 +1 @@ +.. mdinclude:: ../CONTRIBUTING.md diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..6630864 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,33 @@ +============================================================================== +COMPAS Mobile Robot Relocalization +============================================================================== + +Robot localization using external measuring device (total station). + +Table of contents +----------------- + +.. toctree:: + :titlesonly: + + installation + usage + reference + contributing + changelog + license + +README +------ + +.. mdinclude:: ../README.md + :start-line: 5 + +.. image in README.md not rendered, see https://github.com/CrossNox/m2r2/issues/18 and 8 + +.. mdinclude:: ../CHANGELOG.md + +License +------- + +.. literalinclude:: ../LICENSE diff --git a/_sources/installation.rst.txt b/_sources/installation.rst.txt new file mode 100644 index 0000000..26e58a9 --- /dev/null +++ b/_sources/installation.rst.txt @@ -0,0 +1,44 @@ +***************************************************************************** +Installation +***************************************************************************** + +Install +======= + +#. Create a virtual environment using your tool of choice + (e.g. ``virtualenv`` or ``conda``) and install. + + - Using `Anaconda `__ + + .. code:: bash + + conda config --add channels conda-forge + conda config --set channel_priority strict + conda create -n env_name python=3.8 compas_mrr + conda activate env_name + + - Using `virtualenv `__ + + .. code:: bash + + virtualenv --python=python3.8 {{path/to/venv}} + source {{path/to/venv}}/bin/activate + pip install compas_mrr + +#. Make package accessible in Rhino and Grasshopper + + .. code:: bash + + python -m compas_rhino.install + +Update +====== + +To update the repository run: + +.. code:: bash + + # conda + conda update compas_mrr + # pip + pip install -U compas_mrr diff --git a/_sources/license.rst.txt b/_sources/license.rst.txt new file mode 100644 index 0000000..ac51c50 --- /dev/null +++ b/_sources/license.rst.txt @@ -0,0 +1,4 @@ +============================================================================== +License +============================================================================== +.. literalinclude:: ../LICENSE diff --git a/_sources/reference.rst.txt b/_sources/reference.rst.txt new file mode 100644 index 0000000..01927af --- /dev/null +++ b/_sources/reference.rst.txt @@ -0,0 +1,12 @@ +***************************************************************************** +API reference +***************************************************************************** + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + reference/compas_mrr.three_pts_localization + reference/compas_mrr.arbitrary_pts_localization + reference/compas_mrr.xforms + reference/compas_mrr.utils diff --git a/_sources/reference/compas_mrr.arbitrary_pts_localization.rst.txt b/_sources/reference/compas_mrr.arbitrary_pts_localization.rst.txt new file mode 100644 index 0000000..c1dc8b2 --- /dev/null +++ b/_sources/reference/compas_mrr.arbitrary_pts_localization.rst.txt @@ -0,0 +1,4 @@ +.. automodule:: compas_mrr.arbitrary_pts_localization + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/reference/compas_mrr.measurement_point.rst.txt b/_sources/reference/compas_mrr.measurement_point.rst.txt new file mode 100644 index 0000000..9234210 --- /dev/null +++ b/_sources/reference/compas_mrr.measurement_point.rst.txt @@ -0,0 +1,4 @@ +.. automodule:: compas_mrr.measurement_point + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/reference/compas_mrr.rst.txt b/_sources/reference/compas_mrr.rst.txt new file mode 100644 index 0000000..d03df25 --- /dev/null +++ b/_sources/reference/compas_mrr.rst.txt @@ -0,0 +1,19 @@ +compas\_mrr package +=================== + +.. automodule:: compas_mrr + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + compas_mrr.arbitrary_pts_localization + compas_mrr.measurement_point + compas_mrr.three_pts_localization + compas_mrr.utils + compas_mrr.xforms diff --git a/_sources/reference/compas_mrr.three_pts_localization.rst.txt b/_sources/reference/compas_mrr.three_pts_localization.rst.txt new file mode 100644 index 0000000..db5d406 --- /dev/null +++ b/_sources/reference/compas_mrr.three_pts_localization.rst.txt @@ -0,0 +1,4 @@ +.. automodule:: compas_mrr.three_pts_localization + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/reference/compas_mrr.utils.rst.txt b/_sources/reference/compas_mrr.utils.rst.txt new file mode 100644 index 0000000..70e74bf --- /dev/null +++ b/_sources/reference/compas_mrr.utils.rst.txt @@ -0,0 +1,4 @@ +.. automodule:: compas_mrr.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/reference/compas_mrr.xforms.rst.txt b/_sources/reference/compas_mrr.xforms.rst.txt new file mode 100644 index 0000000..9d50f22 --- /dev/null +++ b/_sources/reference/compas_mrr.xforms.rst.txt @@ -0,0 +1,4 @@ +.. automodule:: compas_mrr.xforms + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/usage.rst.txt b/_sources/usage.rst.txt new file mode 100644 index 0000000..093bc36 --- /dev/null +++ b/_sources/usage.rst.txt @@ -0,0 +1,5 @@ +******************************************************************************** +Usage +******************************************************************************** + +TODO diff --git a/_static/PLACEHOLDER b/_static/PLACEHOLDER new file mode 100644 index 0000000..e69de29 diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..cfc60b8 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,921 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..d06a71d --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..4d1c658 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: 'src', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..250f566 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000..d96755f Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000..7107cec Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..0d49244 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..97d56a7 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..aae669d --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/changelog.html b/changelog.html new file mode 100644 index 0000000..36fece8 --- /dev/null +++ b/changelog.html @@ -0,0 +1,393 @@ + + + + + + compas_mrr - Changelog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

Changelog

+

All notable changes to this project will be documented in this file.

+

The format is based on Keep a Changelog, +and this project adheres to Semantic Versioning.

+
+

[1.0.7] - 2021-08-25

+
+

Changed

+
    +
  • Bumped max compas version to <1.8.

  • +
+
+
+
+

[1.0.6] - 2021-03-18

+
+

Changed

+
    +
  • Bumped max compas version to 1.2.

  • +
+
+
+
+

[1.0.5] - 2021-02-09

+
+

Added

+ +
+
+

Changed

+
    +
  • MeasurementPoint moved to its own module and made available as second level +import (compas_mobile_robot_reloc.MeasurementPoint). Still available from +compas_mobile_robot_reloc.utils for backwards compatibility.

  • +
+
+
+
+

[1.0.4] - 2021-02-08

+
+

Changed

+
    +
  • Dependency version specifier for compas’ low bound set to 0.17.2.

  • +
+
+
+
+

[1.0.3] - 2021-02-01

+
+

Changed

+
    +
  • Bumped compas to <2.0.

  • +
+
+
+
+

[1.0.2] - 2021-01-04

+

No changes, version bumped to give give a clear indication of which conda +package to use. (Lingering package +compas-mobile-robot-reloc +on conda forge.)

+
+
+

[1.0.1] - 2020-12-18

+
+

Added

+
    +
  • Moved MeasurementPoint from grasshopper document to compas_mobile_robot_reloc.utils.

  • +
+
+
+
+

[1.0.0] - 2020-12-18

+

Package broken out from +rapid_clay_formations_fab.

+

Typing and tests added.

+
+
+ + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contributing.html b/contributing.html new file mode 100644 index 0000000..f9d1484 --- /dev/null +++ b/contributing.html @@ -0,0 +1,364 @@ + + + + + + compas_mrr - Contributing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

Contributing

+

Contributions are welcome and very much appreciated!

+
+

Code contributions

+

We accept code contributions through pull requests. +In short, this is how that works.

+
+

Setup

+
    +
  1. Fork the repository and clone the fork.

  2. +
  3. Create a virtual environment using your tool of choice (e.g. virtualenv, conda, etc).

    +
      +
    • Using Anaconda

      +
      conda env update -f environment.yml
      +conda activate compas_mrr-dev
      +pip install -e .[dev]
      +
      +
      +
    • +
    • Using virtualenv

      +
      virtualenv --python=python3.10 {{path/to/venv}}
      +source {{path/to/venv}}/bin/activate
      +pip install -e .[dev]
      +
      +
      +
    • +
    +
  4. +
  5. (Optional) Make package accessible in Rhino and Grasshopper

    +
    python -m compas_rhino.install
    +
    +
    +
  6. +
+
+
+

Make a pull request

+
    +
  1. Make sure all tests pass on the unmodified code:

    +
    pytest
    +
    +
    +
  2. +
  3. Start making your changes to the main branch (or branch off of it) on your fork.

  4. +
  5. Make sure all tests still pass:

    +
    pytest
    +
    +
    +
  6. +
  7. Document the changes in the CHANGELOG.md

  8. +
  9. Commit your changes and push your branch to GitHub.

  10. +
  11. Create a pull request through the GitHub website.

  12. +
+
+
+
+

Bug reports

+

When reporting a bug please include:

+
    +
  • Operating system name and version.

  • +
  • Any details about your local setup that might be helpful in troubleshooting.

  • +
  • Detailed steps to reproduce the bug.

  • +
+
+
+

Feature requests

+

When proposing a new feature please include:

+
    +
  • Explain in detail how it would work.

  • +
  • Keep the scope as narrow as possible, to make it easier to implement.

  • +
+
+
+ + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..21478e0 --- /dev/null +++ b/genindex.html @@ -0,0 +1,442 @@ + + + + + Index - COMPAS Mobile Robot Relocalization src documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + +
+

Index

+
+ _ | A | C | I | M | P | R | T | W | X +
+
+
+

_

+ + +
+
+ +
+

A

+ + + +
+
+ +
+

C

+ + + +
    +
  • + compas_mrr.measurement_point + +
  • +
  • + compas_mrr.three_pts_localization + +
  • +
  • + compas_mrr.utils + +
  • +
  • + compas_mrr.xforms + +
  • +
+
+ +
+

I

+ + + +
+
+ +
+

M

+ + +
+
+ +
+

P

+ + +
+
+ +
+

R

+ + + +
+
+ +
+

T

+ + +
+
+ +
+

W

+ + +
+
+ +
+

X

+ + +
+
+ + +
+ + + + + +
+ + +
+ +
+
+ + +
+ +
+ + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..a348597 --- /dev/null +++ b/index.html @@ -0,0 +1,496 @@ + + + + + + compas_mrr - COMPAS Mobile Robot Relocalization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

COMPAS Mobile Robot Relocalization

+

Robot localization using external measuring device (total station).

+
+

Table of contents

+ +
+
+

README

+PyPI Package latest release +Conda +License +Image of total station and robot setup in Brunnen +

Photo from video shot by +MASDFAB 1920 team.

+ +
+
+

Sources

+

Code adapted from source code by Selen Ercan and Sandro Meier at Gramazio +Kohler Research, ETH Zurich (2019).

+

Original code: +gramaziokohler/IF_jamming/if_jamming/localization

+
+

Citing

+
+

Ercan, Selen, Sandro Meier, Fabio Gramazio, and Matthias Kohler. 2019. +“Automated Localization of a Mobile Construction Robot with an External +Measurement Device.” In Proceedings of the 36th International Symposium on +Automation and Robotics in Construction (ISARC 2019), 929-36. International +Association on Automation and Robotics in Construction. +https://doi.org/10.3929/ethz-b-000328442.

+
+
@inproceedings{ercan_automated_2019,
+    title = {Automated {Localization} of a {Mobile} {Construction} {Robot} with an {External} {Measurement} {Device}},
+    copyright = {http://rightsstatements.org/page/InC-NC/1.0/},
+    url = {https://www.research-collection.ethz.ch/handle/20.500.11850/328442},
+    doi = {10.3929/ethz-b-000328442},
+    language = {en},
+    booktitle = {Proceedings of the 36th {International} {Symposium} on {Automation} and {Robotics} in {Construction} ({ISARC} 2019)},
+    publisher = {International Association on Automation and Robotics in Construction},
+    author = {Ercan, Selen and Meier, Sandro and Gramazio, Fabio and Kohler, Matthias},
+    year = {2019},
+    note = {Accepted: 2019-09-11T08:51:48Z},
+    pages = {929--936},
+}
+
+
+
+

Changelog

+

All notable changes to this project will be documented in this file.

+

The format is based on Keep a Changelog, +and this project adheres to Semantic Versioning.

+
+
+
+
+

[1.0.7] - 2021-08-25

+
+

Changed

+
    +
  • Bumped max compas version to <1.8.

  • +
+
+
+
+

[1.0.6] - 2021-03-18

+
+

Changed

+
    +
  • Bumped max compas version to 1.2.

  • +
+
+
+
+

[1.0.5] - 2021-02-09

+
+

Added

+ +
+
+

Changed

+
    +
  • MeasurementPoint moved to its own module and made available as second level +import (compas_mobile_robot_reloc.MeasurementPoint). Still available from +compas_mobile_robot_reloc.utils for backwards compatibility.

  • +
+
+
+
+

[1.0.4] - 2021-02-08

+
+

Changed

+
    +
  • Dependency version specifier for compas’ low bound set to 0.17.2.

  • +
+
+
+
+

[1.0.3] - 2021-02-01

+
+

Changed

+
    +
  • Bumped compas to <2.0.

  • +
+
+
+
+

[1.0.2] - 2021-01-04

+

No changes, version bumped to give give a clear indication of which conda +package to use. (Lingering package +compas-mobile-robot-reloc +on conda forge.)

+
+
+

[1.0.1] - 2020-12-18

+
+

Added

+
    +
  • Moved MeasurementPoint from grasshopper document to compas_mobile_robot_reloc.utils.

  • +
+
+
+
+

[1.0.0] - 2020-12-18

+

Package broken out from +rapid_clay_formations_fab.

+

Typing and tests added.

+
+
+

License

+
MIT License
+
+Copyright (c) 2020 Gramazio Kohler Research
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
+
+ + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installation.html b/installation.html new file mode 100644 index 0000000..01a05e7 --- /dev/null +++ b/installation.html @@ -0,0 +1,328 @@ + + + + + + compas_mrr - Installation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

Installation

+
+

Install

+
    +
  1. Create a virtual environment using your tool of choice +(e.g. virtualenv or conda) and install.

    + +
    conda config --add channels conda-forge
    +conda config --set channel_priority strict
    +conda create -n env_name python=3.8 compas_mrr
    +conda activate env_name
    +
    +
    + +
    virtualenv --python=python3.8 {{path/to/venv}}
    +source {{path/to/venv}}/bin/activate
    +pip install compas_mrr
    +
    +
    +
  2. +
  3. Make package accessible in Rhino and Grasshopper

    +
    python -m compas_rhino.install
    +
    +
    +
  4. +
+
+
+

Update

+

To update the repository run:

+
# conda
+conda update compas_mrr
+# pip
+pip install -U compas_mrr
+
+
+
+
+ + +
+ + + + + +
+ + + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/license.html b/license.html new file mode 100644 index 0000000..132feec --- /dev/null +++ b/license.html @@ -0,0 +1,297 @@ + + + + + + compas_mrr - License + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

License

+
MIT License
+
+Copyright (c) 2020 Gramazio Kohler Research
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
+ + +
+ + + + + +
+ + + +
+ +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000..6f1446f Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 0000000..8a04f1e --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,258 @@ + + + + + + compas_mrr - Python Module Index + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference.html b/reference.html new file mode 100644 index 0000000..2f8cd76 --- /dev/null +++ b/reference.html @@ -0,0 +1,300 @@ + + + + + + compas_mrr - API reference + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.arbitrary_pts_localization.html b/reference/compas_mrr.arbitrary_pts_localization.html new file mode 100644 index 0000000..570e8c1 --- /dev/null +++ b/reference/compas_mrr.arbitrary_pts_localization.html @@ -0,0 +1,325 @@ + + + + + + compas_mrr - Arbitrary points method for robot relocalization. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+

Arbitrary points method for robot relocalization.

+
+
+
+compas_mrr.arbitrary_pts_localization.arbitrary_pts_localization(rcs_coords: List[List[float]], wcs_coords: List[List[float]], plot_results: bool = False, maxiter: int = 200) List[List[float]][source]
+

Calculate the RCS origin frame.

+

Finding the origin is formulated as an optimization problem where we want +to find the origin and two orthonormal vectors defining the coordinate +system. At the same time, the position of the localization points in this +new coordinate system should match the measurements as close as possible. +Therefore the deviation from the measurements is used as the cost function. +The only constraints are that the x and y vector need to have length 1 and +be orthogonal to each other. The optimization variable is a vector with 9 +entries: X = [o, x, y] where o is the origin of the coordinate system and +x, y the vectors spanning the x-y-plane. Each of them is a 3 dimensional +vector. Important: Ensure that the order of rcs_coords and +measurements is identical. I.e. the i-th entry in measurements is the +measurement of the i-th localization point.

+
+
Parameters:
+
    +
  • rcs_coords – The points where the robot endeffector was positioned to take +measurements. These points are in the RCS.

  • +
  • wcs_coords – The measurements taken in the world coordinate system (WCS) with the +total station. These are the coordinates of the rcs_coords in +the WCS.

  • +
+
+
Returns:
+

A tuple of 3 vectors (lists with 3 elements) where the first represents +the origin of the RCS, the second is the direction of the x axis and +the third the direction of the y axis. The x and y axis are vectors +with length 1.

+
+
Return type:
+

list of list of float

+
+
+
+ + + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.html b/reference/compas_mrr.html new file mode 100644 index 0000000..13e6092 --- /dev/null +++ b/reference/compas_mrr.html @@ -0,0 +1,300 @@ + + + + + + compas_mrr - compas_mrr package + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.measurement_point.html b/reference/compas_mrr.measurement_point.html new file mode 100644 index 0000000..c727b3e --- /dev/null +++ b/reference/compas_mrr.measurement_point.html @@ -0,0 +1,297 @@ + + + + + + compas_mrr - <no title> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +
+
+class compas_mrr.measurement_point.MeasurementPoint(x: float, y: float, z: float, pt_name: str, attrs: None | dict = None)[source]
+

Bases: Point

+

A compas.geometry.Point with some CSV pointlist related methods.

+
+
+__init__(x: float, y: float, z: float, pt_name: str, attrs: None | dict = None) None[source]
+
+ +
+
+property prefix: str
+

Point prefix from data source.

+
+ +
+
+property idx: int
+

Point index from data source.

+
+ +
+
+as_rgpoint() Point[source]
+

Get a point representation in Rhino.

+
+ +
+ + + +
+ + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.three_pts_localization.html b/reference/compas_mrr.three_pts_localization.html new file mode 100644 index 0000000..3ede047 --- /dev/null +++ b/reference/compas_mrr.three_pts_localization.html @@ -0,0 +1,301 @@ + + + + + + compas_mrr - <no title> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Three points method for robot relocalization

+
+
+compas_mrr.three_pts_localization.three_pts_localization(rcs_coords: List[Point], wcs_coords: List[Point]) Frame[source]
+

Get the robot base frame in WCS using three points method.

+
+
Parameters:
+
    +
  • rcs_coords – List of the RCS coordinates used for measurements.

  • +
  • wcs_coords – List of the WCS coordinates used for measurements.

  • +
+
+
Return type:
+

The base frame of the robot in WCS.

+
+
+
+ + + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.utils.html b/reference/compas_mrr.utils.html new file mode 100644 index 0000000..35e3b5b --- /dev/null +++ b/reference/compas_mrr.utils.html @@ -0,0 +1,340 @@ + + + + + + compas_mrr - <no title> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Utilities

+
+
+compas_mrr.utils.rgpoint_to_cgpoint(pt: Rhino.Geometry.Point3d) compas.geometry.Point[source]
+

Convert Rhino.Geometry.Point3d to compas.geometry.Point.

+
+
Parameters:
+

pt – Plane object to convert

+
+
Return type:
+

Resulting point object

+
+
+
+ +
+
+compas_mrr.utils.cgpoint_to_rgpoint(pt: compas.geometry.Point) Rhino.Geometry.Point3d[source]
+

Convert compas.geometry.Point to Rhino.Geometry.Point.

+
+ +
+
+compas_mrr.utils.cgframe_to_rgplane(frame: compas.geometry.Frame) Rhino.Geometry.Plane[source]
+

Convert compas.Geometry.Frame to Rhino.Geometry.Plane.

+
+ +
+
+compas_mrr.utils.rgtransform_to_cgtransformation(rgT: Rhino.Geometry.Transform) compas.geometry.Transformation[source]
+

Convert Rhino.Geometry.Transform to compas.geometry.Transformation.

+
+ +
+
+compas_mrr.utils.rgtransform_to_matrix(rgT: Rhino.Geometry.Transform) List[List[float]][source]
+

Convert Rhino.Geometry.Transform to transformation matrix.

+
+ +
+
+compas_mrr.utils.cgtransformation_to_rgtransform(cgT: compas.geometry.Transformation) Rhino.Geometry.Transform[source]
+

Convert compas.geometry.Transformation to Rhino.Geometry.Transform.

+
+ +
+
+compas_mrr.utils.matrix_to_rgtransform(M: List[List[float]]) Rhino.Geometry.Transform[source]
+

Create Rhino.Geometry.Transform from a transformation matrix.

+
+ + + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reference/compas_mrr.xforms.html b/reference/compas_mrr.xforms.html new file mode 100644 index 0000000..8bf112d --- /dev/null +++ b/reference/compas_mrr.xforms.html @@ -0,0 +1,322 @@ + + + + + + compas_mrr - <no title> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + + + +

Transformations

+
+
+compas_mrr.xforms.worldxy_to_robot_base_xform(robot_base_frame: Frame) Transformation[source]
+

Get transformation from WCS origin to RCS origin.

+
+
Parameters:
+

robot_base_frame – Robot base frame in WCS. The frame origin is the location of the RCS origo +in WCS, the X axis and Y axis are the X and Y axes of the RCS in WCS.

+
+
+
+ +
+
+compas_mrr.xforms.xform_to_xyz_quaternion(xform: Any) List[float][source]
+

Convert transformation to list of coords and quaternion values.

+
+
Parameters:
+

xform – Transformation to be converted. Can be given as +Rhino.Geometry.Transform, +compas.geometry.Transformation, +numpy.ndarray, or list of list of float.

+
+
Return type:
+

X, Y, Z, QW, QX, QY, QZ values as a list.

+
+
+
>>> from compas.geometry import Frame, Rotation, Translation
+>>> Tr = Translation.from_vector([100, 100, 100])
+>>> R = Rotation.from_frame(Frame.worldYZ())
+>>> T = Tr * R
+>>> xform_to_xyz_quaternion(T)
+[100.0, 100.0, 100.0, 0.5, 0.5, 0.5, 0.5]
+
+
+
+ + + +
+ + + + + + + +
+
+ + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..5159d2e --- /dev/null +++ b/search.html @@ -0,0 +1,281 @@ + + + + + + compas_mrr - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..7d3e923 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["changelog", "contributing", "index", "installation", "license", "reference", "reference/compas_mrr", "reference/compas_mrr.arbitrary_pts_localization", "reference/compas_mrr.measurement_point", "reference/compas_mrr.three_pts_localization", "reference/compas_mrr.utils", "reference/compas_mrr.xforms", "usage"], "filenames": ["changelog.rst", "contributing.rst", "index.rst", "installation.rst", "license.rst", "reference.rst", "reference/compas_mrr.rst", "reference/compas_mrr.arbitrary_pts_localization.rst", "reference/compas_mrr.measurement_point.rst", "reference/compas_mrr.three_pts_localization.rst", "reference/compas_mrr.utils.rst", "reference/compas_mrr.xforms.rst", "usage.rst"], "titles": ["Changelog", "Contributing", "COMPAS Mobile Robot Relocalization", "Installation", "License", "API reference", "compas_mrr package", "Arbitrary points method for robot relocalization.", "<no title>", "<no title>", "<no title>", "<no title>", "Usage"], "terms": {"all": [0, 1, 2, 4], "notabl": [0, 2], "thi": [0, 1, 2, 4, 7], "project": [0, 2], "document": [0, 1, 2, 4], "file": [0, 2, 4], "The": [0, 2, 4, 7, 9, 11], "format": [0, 2], "i": [0, 1, 2, 4, 7, 11], "base": [0, 2, 8, 9, 11], "keep": [0, 1, 2], "adher": [0, 2], "semant": [0, 2], "version": [0, 1, 2], "bump": [0, 2], "max": [0, 2], "compa": [0, 8, 10, 11], "8": [0, 2, 3], "monkeypatch": [0, 2], "_o": [0, 2], "prepare_environ": [0, 2], "appli": [0, 2], "less": [0, 2], "than": [0, 2], "v0": [0, 2], "19": [0, 2], "get": [0, 2, 8, 9, 11], "around": [0, 2], "bug": [0, 2], "affect": [0, 2], "rpc": [0, 2], "proxi": [0, 2], "http": [0, 2], "github": [0, 1, 2], "com": [0, 2], "dev": [0, 1, 2], "issu": [0, 2], "701": [0, 2], "_": [0, 2], "measurementpoint": [0, 2, 6, 8], "move": [0, 2], "its": [0, 2], "own": [0, 2], "modul": [0, 2], "made": [0, 2], "avail": [0, 2], "second": [0, 2, 7], "level": [0, 2], "import": [0, 2, 7, 11], "compas_mobile_robot_reloc": [0, 2], "still": [0, 1, 2], "from": [0, 2, 4, 7, 8, 10, 11], "util": [0, 2, 10], "backward": [0, 2], "compat": [0, 2], "depend": [0, 2], "specifi": [0, 2], "low": [0, 2], "bound": [0, 2], "set": [0, 2, 3], "17": [0, 2], "No": [0, 2], "give": [0, 2], "clear": [0, 2], "indic": [0, 2], "which": [0, 2], "conda": [0, 1, 2, 3], "packag": [0, 1, 2, 3], "us": [0, 1, 2, 3, 4, 7, 9], "linger": [0, 2], "mobil": 0, "robot": [0, 5, 6, 9, 11], "reloc": [0, 5, 6, 9], "forg": [0, 2, 3], "grasshopp": [0, 1, 2, 3], "broken": [0, 2], "out": [0, 2, 4], "rapid_clay_formations_fab": [0, 2], "type": [0, 2, 7, 9, 10, 11], "test": [0, 1, 2], "ar": [1, 7, 11], "welcom": 1, "veri": 1, "much": 1, "appreci": 1, "we": [1, 7], "accept": [1, 2], "through": 1, "In": [1, 2], "short": 1, "how": 1, "work": 1, "fork": 1, "repositori": [1, 3], "clone": 1, "creat": [1, 3, 10], "virtual": [1, 3], "environ": [1, 3], "your": [1, 3], "tool": [1, 3], "choic": [1, 3], "e": [1, 3, 7], "g": [1, 3], "virtualenv": [1, 3], "etc": 1, "anaconda": [1, 3], "env": 1, "updat": 1, "f": 1, "yml": 1, "activ": [1, 3], "compas_mrr": [1, 3, 7, 8, 9, 10, 11], "pip": [1, 3], "instal": [1, 2], "python": [1, 3], "python3": [1, 3], "10": [1, 2], "path": [1, 3], "venv": [1, 3], "sourc": [1, 3, 6, 7, 8, 9, 10, 11], "bin": [1, 3], "option": 1, "access": [1, 3], "rhino": [1, 3, 8, 10, 11], "m": [1, 3, 10], "compas_rhino": [1, 3], "sure": 1, "pass": 1, "unmodifi": 1, "pytest": 1, "start": 1, "chang": 1, "main": 1, "branch": 1, "off": 1, "changelog": 1, "md": 1, "commit": 1, "push": 1, "websit": 1, "when": 1, "pleas": 1, "includ": [1, 2, 4], "oper": 1, "system": [1, 7], "name": 1, "ani": [1, 2, 4, 11], "detail": 1, "about": 1, "local": [1, 2, 7], "might": 1, "help": 1, "troubleshoot": 1, "step": 1, "reproduc": 1, "propos": 1, "new": [1, 7], "explain": 1, "would": 1, "scope": 1, "narrow": 1, "possibl": [1, 7], "easier": 1, "implement": 1, "extern": 2, "measur": [2, 7, 9], "devic": 2, "total": [2, 7], "station": [2, 7], "usag": 2, "api": 2, "refer": 2, "three_pts_loc": [2, 5, 6, 9], "arbitrari": [2, 5, 6], "point": [2, 5, 6, 8, 9, 10], "method": [2, 5, 6, 8, 9], "arbitrary_pts_loc": [2, 5, 6, 7], "worldxy_to_robot_base_xform": [2, 5, 6, 11], "xform_to_xyz_quaternion": [2, 5, 6, 11], "rgpoint_to_cgpoint": [2, 5, 6, 10], "cgpoint_to_rgpoint": [2, 5, 6, 10], "cgframe_to_rgplan": [2, 5, 6, 10], "rgtransform_to_cgtransform": [2, 5, 6, 10], "rgtransform_to_matrix": [2, 5, 6, 10], "cgtransformation_to_rgtransform": [2, 5, 6, 10], "matrix_to_rgtransform": [2, 5, 6, 10], "contribut": 2, "photo": 2, "video": 2, "shot": 2, "masdfab": 2, "1920": 2, "team": 2, "tracker": 2, "code": 2, "adapt": 2, "selen": 2, "ercan": 2, "sandro": 2, "meier": 2, "gramazio": [2, 4], "kohler": [2, 4], "research": [2, 4], "eth": 2, "zurich": 2, "2019": 2, "origin": [2, 7, 11], "gramaziokohl": 2, "if_jam": 2, "fabio": 2, "matthia": 2, "autom": 2, "construct": 2, "an": [2, 4, 7], "proceed": 2, "36th": 2, "intern": 2, "symposium": 2, "isarc": 2, "929": 2, "36": 2, "associ": [2, 4], "doi": 2, "org": 2, "3929": 2, "ethz": 2, "b": 2, "000328442": 2, "inproceed": 2, "ercan_automated_2019": 2, "titl": 2, "copyright": [2, 4], "rightsstat": 2, "page": 2, "inc": 2, "nc": 2, "url": 2, "www": 2, "collect": 2, "ch": 2, "handl": 2, "20": 2, "500": 2, "11850": 2, "328442": 2, "languag": 2, "en": 2, "booktitl": 2, "publish": [2, 4], "author": [2, 4], "year": 2, "note": 2, "11t08": 2, "51": 2, "48z": 2, "936": 2, "mit": [2, 4], "c": [2, 4], "permiss": [2, 4], "herebi": [2, 4], "grant": [2, 4], "free": [2, 4], "charg": [2, 4], "person": [2, 4], "obtain": [2, 4], "copi": [2, 4], "softwar": [2, 4], "deal": [2, 4], "without": [2, 4], "restrict": [2, 4], "limit": [2, 4], "right": [2, 4], "modifi": [2, 4], "merg": [2, 4], "distribut": [2, 4], "sublicens": [2, 4], "sell": [2, 4], "permit": [2, 4], "whom": [2, 4], "furnish": [2, 4], "do": [2, 4], "so": [2, 4], "subject": [2, 4], "follow": [2, 4], "condit": [2, 4], "abov": [2, 4], "notic": [2, 4], "shall": [2, 4], "substanti": [2, 4], "portion": [2, 4], "THE": [2, 4], "provid": [2, 4], "AS": [2, 4], "warranti": [2, 4], "OF": [2, 4], "kind": [2, 4], "express": [2, 4], "OR": [2, 4], "impli": [2, 4], "BUT": [2, 4], "NOT": [2, 4], "TO": [2, 4], "merchant": [2, 4], "fit": [2, 4], "FOR": [2, 4], "A": [2, 4, 7, 8], "particular": [2, 4], "purpos": [2, 4], "AND": [2, 4], "noninfring": [2, 4], "IN": [2, 4], "NO": [2, 4], "event": [2, 4], "holder": [2, 4], "BE": [2, 4], "liabl": [2, 4], "claim": [2, 4], "damag": [2, 4], "other": [2, 4, 7], "liabil": [2, 4], "whether": [2, 4], "action": [2, 4], "contract": [2, 4], "tort": [2, 4], "otherwis": [2, 4], "aris": [2, 4], "connect": [2, 4], "WITH": [2, 4], "config": 3, "add": 3, "channel": 3, "channel_prior": 3, "strict": 3, "n": 3, "env_nam": 3, "3": [3, 7], "make": 3, "To": 3, "run": 3, "u": 3, "2020": 4, "installable_rhino_packag": 6, "__init__": [6, 8], "prefix": [6, 8], "idx": [6, 8], "as_rgpoint": [6, 8], "rcs_coord": [7, 9], "list": [7, 9, 10, 11], "float": [7, 8, 10, 11], "wcs_coord": [7, 9], "plot_result": 7, "bool": 7, "fals": 7, "maxit": 7, "int": [7, 8], "200": 7, "calcul": 7, "rc": [7, 9, 11], "frame": [7, 9, 10, 11], "find": 7, "formul": 7, "optim": 7, "problem": 7, "where": 7, "want": 7, "two": 7, "orthonorm": 7, "vector": 7, "defin": 7, "coordin": [7, 9], "At": 7, "same": 7, "time": 7, "posit": 7, "should": 7, "match": 7, "close": 7, "therefor": 7, "deviat": 7, "cost": 7, "function": 7, "onli": 7, "constraint": 7, "x": [7, 8, 11], "y": [7, 8, 11], "need": 7, "have": 7, "length": 7, "1": 7, "orthogon": 7, "each": 7, "variabl": 7, "9": 7, "entri": 7, "o": 7, "span": 7, "plane": [7, 10], "them": 7, "dimension": 7, "ensur": 7, "order": 7, "ident": 7, "th": 7, "paramet": [7, 9, 10, 11], "endeffector": 7, "wa": 7, "take": 7, "These": 7, "taken": 7, "world": 7, "wc": [7, 9, 11], "return": [7, 9, 10, 11], "tupl": 7, "element": 7, "first": 7, "repres": 7, "direct": 7, "axi": [7, 11], "third": 7, "class": 8, "measurement_point": 8, "z": [8, 11], "pt_name": 8, "str": 8, "attr": 8, "none": 8, "dict": 8, "geometri": [8, 10, 11], "some": 8, "csv": 8, "pointlist": 8, "relat": 8, "properti": 8, "data": 8, "index": 8, "represent": 8, "three": 9, "pt": 10, "point3d": 10, "convert": [10, 11], "object": 10, "result": 10, "rgt": 10, "transform": [10, 11], "matrix": 10, "cgt": 10, "xform": 11, "robot_base_fram": 11, "locat": 11, "origo": 11, "ax": 11, "coord": 11, "quaternion": 11, "valu": 11, "can": 11, "given": 11, "numpi": 11, "ndarrai": 11, "qw": 11, "qx": 11, "qy": 11, "qz": 11, "rotat": 11, "translat": 11, "tr": 11, "from_vector": 11, "100": 11, "r": 11, "from_fram": 11, "worldyz": 11, "t": 11, "0": 11, "5": 11, "todo": 12}, "objects": {"": [[6, 0, 0, "-", "compas_mrr"]], "compas_mrr": [[7, 0, 0, "-", "arbitrary_pts_localization"], [6, 1, 1, "", "installable_rhino_packages"], [8, 0, 0, "-", "measurement_point"], [9, 0, 0, "-", "three_pts_localization"], [10, 0, 0, "-", "utils"], [11, 0, 0, "-", "xforms"]], "compas_mrr.arbitrary_pts_localization": [[7, 1, 1, "", "arbitrary_pts_localization"]], "compas_mrr.measurement_point": [[8, 2, 1, "", "MeasurementPoint"]], "compas_mrr.measurement_point.MeasurementPoint": [[8, 3, 1, "", "__init__"], [8, 3, 1, "", "as_rgpoint"], [8, 4, 1, "", "idx"], [8, 4, 1, "", "prefix"]], "compas_mrr.three_pts_localization": [[9, 1, 1, "", "three_pts_localization"]], "compas_mrr.utils": [[10, 1, 1, "", "cgframe_to_rgplane"], [10, 1, 1, "", "cgpoint_to_rgpoint"], [10, 1, 1, "", "cgtransformation_to_rgtransform"], [10, 1, 1, "", "matrix_to_rgtransform"], [10, 1, 1, "", "rgpoint_to_cgpoint"], [10, 1, 1, "", "rgtransform_to_cgtransformation"], [10, 1, 1, "", "rgtransform_to_matrix"]], "compas_mrr.xforms": [[11, 1, 1, "", "worldxy_to_robot_base_xform"], [11, 1, 1, "", "xform_to_xyz_quaternion"]]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:method", "4": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "method", "Python method"], "4": ["py", "property", "Python property"]}, "titleterms": {"changelog": [0, 2], "1": [0, 2], "0": [0, 2], "7": [0, 2], "2021": [0, 2], "08": [0, 2], "25": [0, 2], "chang": [0, 2], "6": [0, 2], "03": [0, 2], "18": [0, 2], "5": [0, 2], "02": [0, 2], "09": [0, 2], "ad": [0, 2], "4": [0, 2], "3": [0, 2], "01": [0, 2], "2": [0, 2], "04": [0, 2], "2020": [0, 2], "12": [0, 2], "contribut": 1, "code": 1, "setup": 1, "make": 1, "pull": 1, "request": 1, "bug": 1, "report": 1, "featur": 1, "compa": 2, "mobil": 2, "robot": [2, 7], "reloc": [2, 7], "tabl": 2, "content": 2, "readm": 2, "sourc": 2, "cite": 2, "licens": [2, 4], "instal": 3, "updat": 3, "api": 5, "refer": 5, "compas_mrr": 6, "packag": 6, "submodul": 6, "arbitrari": 7, "point": 7, "method": 7, "usag": 12}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1, "sphinx": 58}, "alltitles": {"Changelog": [[0, "changelog"], [2, "changelog"]], "[1.0.7] - 2021-08-25": [[0, "id1"], [2, "id1"]], "Changed": [[0, "changed"], [0, "id3"], [0, "id5"], [0, "id7"], [0, "id9"], [2, "changed"], [2, "id3"], [2, "id5"], [2, "id7"], [2, "id9"]], "[1.0.6] - 2021-03-18": [[0, "id2"], [2, "id2"]], "[1.0.5] - 2021-02-09": [[0, "id4"], [2, "id4"]], "Added": [[0, "added"], [0, "id12"], [2, "added"], [2, "id12"]], "[1.0.4] - 2021-02-08": [[0, "id6"], [2, "id6"]], "[1.0.3] - 2021-02-01": [[0, "id8"], [2, "id8"]], "[1.0.2] - 2021-01-04": [[0, "id10"], [2, "id10"]], "[1.0.1] - 2020-12-18": [[0, "id11"], [2, "id11"]], "[1.0.0] - 2020-12-18": [[0, "id13"], [2, "id13"]], "Contributing": [[1, "contributing"]], "Code contributions": [[1, "code-contributions"]], "Setup": [[1, "setup"]], "Make a pull request": [[1, "make-a-pull-request"]], "Bug reports": [[1, "bug-reports"]], "Feature requests": [[1, "feature-requests"]], "COMPAS Mobile Robot Relocalization": [[2, "compas-mobile-robot-relocalization"]], "Table of contents": [[2, "table-of-contents"]], "README": [[2, "readme"]], "Sources": [[2, "sources"]], "Citing": [[2, "citing"]], "License": [[2, "license"], [4, "license"]], "Installation": [[3, "installation"]], "Install": [[3, "install"]], "Update": [[3, "update"]], "API reference": [[5, "api-reference"]], "compas_mrr package": [[6, "module-compas_mrr"]], "Submodules": [[6, "submodules"]], "Arbitrary points method for robot relocalization.": [[7, "arbitrary-points-method-for-robot-relocalization"]], "Usage": [[12, "usage"]]}, "indexentries": {"compas_mrr": [[6, "module-compas_mrr"]], "installable_rhino_packages() (in module compas_mrr)": [[6, "compas_mrr.installable_rhino_packages"]], "module": [[6, "module-compas_mrr"], [7, "module-compas_mrr.arbitrary_pts_localization"], [8, "module-compas_mrr.measurement_point"], [9, "module-compas_mrr.three_pts_localization"], [10, "module-compas_mrr.utils"], [11, "module-compas_mrr.xforms"]], "arbitrary_pts_localization() (in module compas_mrr.arbitrary_pts_localization)": [[7, "compas_mrr.arbitrary_pts_localization.arbitrary_pts_localization"]], "compas_mrr.arbitrary_pts_localization": [[7, "module-compas_mrr.arbitrary_pts_localization"]], "measurementpoint (class in compas_mrr.measurement_point)": [[8, "compas_mrr.measurement_point.MeasurementPoint"]], "__init__() (compas_mrr.measurement_point.measurementpoint method)": [[8, "compas_mrr.measurement_point.MeasurementPoint.__init__"]], "as_rgpoint() (compas_mrr.measurement_point.measurementpoint method)": [[8, "compas_mrr.measurement_point.MeasurementPoint.as_rgpoint"]], "compas_mrr.measurement_point": [[8, "module-compas_mrr.measurement_point"]], "idx (compas_mrr.measurement_point.measurementpoint property)": [[8, "compas_mrr.measurement_point.MeasurementPoint.idx"]], "prefix (compas_mrr.measurement_point.measurementpoint property)": [[8, "compas_mrr.measurement_point.MeasurementPoint.prefix"]], "compas_mrr.three_pts_localization": [[9, "module-compas_mrr.three_pts_localization"]], "three_pts_localization() (in module compas_mrr.three_pts_localization)": [[9, "compas_mrr.three_pts_localization.three_pts_localization"]], "cgframe_to_rgplane() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.cgframe_to_rgplane"]], "cgpoint_to_rgpoint() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.cgpoint_to_rgpoint"]], "cgtransformation_to_rgtransform() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.cgtransformation_to_rgtransform"]], "compas_mrr.utils": [[10, "module-compas_mrr.utils"]], "matrix_to_rgtransform() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.matrix_to_rgtransform"]], "rgpoint_to_cgpoint() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.rgpoint_to_cgpoint"]], "rgtransform_to_cgtransformation() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.rgtransform_to_cgtransformation"]], "rgtransform_to_matrix() (in module compas_mrr.utils)": [[10, "compas_mrr.utils.rgtransform_to_matrix"]], "compas_mrr.xforms": [[11, "module-compas_mrr.xforms"]], "worldxy_to_robot_base_xform() (in module compas_mrr.xforms)": [[11, "compas_mrr.xforms.worldxy_to_robot_base_xform"]], "xform_to_xyz_quaternion() (in module compas_mrr.xforms)": [[11, "compas_mrr.xforms.xform_to_xyz_quaternion"]]}}) \ No newline at end of file diff --git a/usage.html b/usage.html new file mode 100644 index 0000000..4fed8ca --- /dev/null +++ b/usage.html @@ -0,0 +1,285 @@ + + + + + + compas_mrr - Usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+

COMPAS

+

+ A computational framework for collaboration and research + in Architecture, Engineering, Fabrication, and Construction. +

+ +
+
+
+
+

Copyright © 2017-2021 compas-dev

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file