diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 288b5ef8088..00000000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,29 +0,0 @@ -[bumpversion] -current_version = 2.1.0 -message = Bump version to {new_version} -commit = True -tag = True - -[bumpversion:file:setup.py] -search = version="{current_version}" -replace = version="{new_version}" - -[bumpversion:file:src/compas/__init__.py] -search = __version__ = "{current_version}" -replace = __version__ = "{new_version}" - -[bumpversion:file:src/compas_blender/__init__.py] -search = __version__ = "{current_version}" -replace = __version__ = "{new_version}" - -[bumpversion:file:src/compas_ghpython/__init__.py] -search = __version__ = "{current_version}" -replace = __version__ = "{new_version}" - -[bumpversion:file:src/compas_rhino/__init__.py] -search = __version__ = "{current_version}" -replace = __version__ = "{new_version}" - -[bumpversion:file:CHANGELOG.md] -search = Unreleased -replace = [{new_version}] {now:%Y-%m-%d} diff --git a/.editorconfig b/.editorconfig index 4edb55d3deb..6a650d15256 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,7 +8,7 @@ insert_final_newline = true indent_style = space indent_size = 4 charset = utf-8 -max_line_length = 120 +max_line_length = 179 [*.{bat,cmd,ps1}] end_of_line = crlf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78564ace0e5..10e1fa60fdb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,10 +15,11 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python: ['3.8', '3.9', '3.10'] + python: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: compas-dev/compas-actions.build@v3 + - uses: compas-dev/compas-actions.build@v4 with: + invoke_lint: true + invoke_test: true python: ${{ matrix.python }} - invoke_lint: true \ No newline at end of file diff --git a/.github/workflows/ironpython.yml b/.github/workflows/ironpython.yml index e802f95eb94..472d4f91cfd 100644 --- a/.github/workflows/ironpython.yml +++ b/.github/workflows/ironpython.yml @@ -14,10 +14,10 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v2 - - name: "[RPC tests] Set up CPython 3.8" + - name: "[RPC tests] Set up CPython 3.9" uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.9 - name: "[RPC tests] Install CPython dependencies" run: | python -m pip install --upgrade pip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2cfac61a67b..57436e45b69 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,7 @@ on: push: tags: - - 'v*' + - "v*" name: Create Release @@ -11,20 +11,21 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python: ['3.8', '3.9', '3.10'] + python: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: compas-dev/compas-actions.build@v3 + - uses: compas-dev/compas-actions.build@v4 with: - python: ${{ matrix.python }} invoke_lint: true + invoke_test: true + python: ${{ matrix.python }} check_import: true publish: needs: build runs-on: windows-latest steps: - - uses: compas-dev/compas-actions.publish@v2 + - uses: compas-dev/compas-actions.publish@v3 with: pypi_token: ${{ secrets.PYPI }} github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 205fca16281..35cd39e7c63 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,5 @@ src/compas_blender/conversions/__temp/ docs/reference/__old/ scripts/ + +.ruff_cache \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cc09f2ba55c..c837680779b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,20 +9,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +* Added `compas.geometry.Line.point_from_start` and `compas.geometry.Line.point_from_end`. +* Added `compas.geometry.Line.flip` and `compas.geometry.Line.flipped`. +* Added an `compas.geometry.Frame.interpolate_frame(s)` method +* Added `compas.colors.Color.contrast`. +* Added `compas.geometry.Brep.from_plane`. +* Added `compas.tolerance.Tolerance.angulardeflection`. + ### Changed +* Changed and update the `compas_view2` examples into `compas_viewer`. * Changed and updated the `compas_view2` examples into `compas_viewer`. * Changed `compas.scene.Scene` to inherent from `compas.datastructrues.Tree`. * Changed `compas.scene.SceneObject` to inherent from `compas.datastructrues.TreeNode`. +* Changed `compas.geoemetry._core.predicates_3` bug fix in `is_coplanar` while loop when there are 4 points. +* Changed to implementation of `Mesh.unify_cycles` to use the corresponding function of `compas.topology.orientation`. +* Fixed bug in `compas.topology.orientation.unify_cycles`. +* Fixed bug in `Mesh.thickened`. +* Fixed various bugs in `compas.geometry.Quaternion`. +* Changed repo config to `pyproject.toml`. +* Fixed broken import in `copas.geometry.trimesh_smoothing_numpy`. +* Changed `RhinoBrep.trimmed` to return single result or raise `BrepTrimmingError` instead of returning a list. +* Changed order of imports according to `isort` and changed line length to `179`. +* Changed use of `compas.geometry.allclose` to `compas.tolerance.TOL.is_allclose`. +* Changed use of `compas.geometry.close` to `compas.tolerance.TOL.is_close`. +* Changed imports of itertools to `compas.itertools` instead of `compas.utilities`. * Changed `compas.datastructures.Tree.print_hierarchy` to `compas.datastructures.Tree.__str__`. ### Removed * Removed `compas.scene.SceneObjectNode`, functionalities merged into `compas.scene.SceneObject`. * Removed `compas.scene.SceneTree`, functionalities merged into `compas.scene.Scene`. +* Removed default implementation of `compas.geometry.trimesh_geodistance` since nonexistent. +* Removed `compas.utilities.geometric_key` and replaced it by `compas.tolerance.TOL.geometric_key`. +* Removed `compas.utilities.geometric_key_xy` and replaced it by `compas.tolerance.TOL.geometric_key_xy`. +* Removed indexed attribute access from all geometry classes except `Point`, `Vector`, `Line`, `Polygon`, `Polyline`. * Removed `compas.datastructures.Tree.print_hierarchy`. - ## [2.1.0] 2024-03-01 ### Added @@ -33,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `compas.datastructures.Tree.to_graph()`. ### Changed + * Changed `compas.datastructures.TreeNode` to skip serialising `attributes`, `name` and `children` if being empty. * Changed `compas.datastructures.TreeNode.__repr__` to omit `name` if `None`. * Fix bug in `compas_rhino.geometry.NurbsCurve.from_parameters` and `compas_rhino.geometry.NurbsCurve.from_points` related to the value of the parameter `degree`. @@ -43,7 +67,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - ## [2.0.4] 2024-02-12 ### Added @@ -54,7 +77,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - ## [2.0.3] 2024-02-09 ### Added diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 165e2d448ac..00000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,24 +0,0 @@ -graft src - -prune .github -prune docs -prune libs -prune samples -prune tests -prune temp - -include LICENSE -include README.md -include AUTHORS.md -include CHANGELOG.md -include requirements.txt -include conftest.py -include pyproject.toml - -exclude requirements-dev.txt -exclude pytest.ini .bumpversion.cfg .editorconfig -exclude tasks.py -exclude CONTRIBUTING.md -exclude .gitpod.yml - -global-exclude *.py[cod] __pycache__ *.dylib *.nb[ic] .DS_Store diff --git a/README.md b/README.md index ecb20d6ac8b..45ab7c06109 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ COMPAS has dedicated packages for working with Rhino, Grasshopper, and Blender, We are working on a new major release of the framework, COMPAS 2.0! Therefore, be aware that the current version of the repository already contains some changes that are incompatible with the version 1 releases. -The documentation of the latest stable version (COMPAS 1.17.6) [is available here](https://compas.dev/compas/1.17.6). +The documentation of the latest stable version (COMPAS 1.17.9) [is available here](https://compas.dev/compas/1.17.9). ## Installation @@ -29,21 +29,21 @@ The recommended way to install **COMPAS** is to use [Anaconda/conda](https://con ```bash conda config --add channels conda-forge -conda install COMPAS +conda install compas ``` -For other installation options, see +For other installation options, [see the user guide](https://compas.dev/compas/latest/userguide/installation.html) ## First Steps -* -* -* +* [First steps](https://compas.dev/compas/latest/userguide/firststeps.html) +* [Tutorials: geometry basics](https://compas.dev/compas/latest/userguide/basics.geometry.html) +* [Tutorials: datastructures](https://compas.dev/compas/latest/userguide/basics.datastructures.html) +* [API Reference](https://compas.dev/compas/latest/api/index.html) ## Questions and feedback -The **COMPAS** framework has a forum: -for questions and discussions. +The **COMPAS** framework has a [forum for questions and discussions](https://forum.compas-framework.org/). ## Issue tracker @@ -51,17 +51,17 @@ If you find a bug, please help us solve it by [filing a report](https://github.c ## Contributing -If you want to contribute, check out the [contribution guidelines](https://compas.dev/compas/latest/devguide.html). +If you want to contribute, check out the [contribution guidelines](https://compas.dev/compas/latest/devguide/index.html). ## Changelog -See changes between releases on the [changelog](https://compas.dev/compas/latest/changelog.html). +See changes between releases on the [changelog](https://github.com/compas-dev/compas/blob/main/CHANGELOG.md). ## License -The main library of **COMPAS** is [released under the MIT license](https://compas.dev/compas/latest/license.html). +The main library of **COMPAS** is [released under the MIT license](https://compas.dev/compas/latest/userguide/license.html). ## Credits COMPAS is developed by a small team of core developers (`compas-dev`) and with the support of contributers from the open source community. -See the [list of authors](AUTHORS.md) for a complete overview... +See the [list of authors](https://github.com/compas-dev/compas/blob/main/AUTHORS.md) for a complete overview... diff --git a/conftest.py b/conftest.py index 3e378e97e3e..88062fab2d3 100644 --- a/conftest.py +++ b/conftest.py @@ -1,8 +1,9 @@ -import pytest -import compas import math + import numpy +import pytest +import compas from compas.geometry import allclose @@ -16,9 +17,6 @@ def pytest_ignore_collect(path): if "ghpython" in str(path): return True - if "matlab" in str(path): - return True - if str(path).endswith("_cli.py"): return True diff --git a/docs/devguide/code.rst b/docs/devguide/code.rst index ce72b9caadb..8e182d8ca29 100644 --- a/docs/devguide/code.rst +++ b/docs/devguide/code.rst @@ -71,8 +71,7 @@ Naming conventions Line length ----------- -**COMPAS uses a line length of 120 characters**. While longer than the 80 characters recommended by ``PEP8``, it is in our opinion a more reasonable limit for modern displays. -This is enforced and can be automatically set using ``black -l 120``. +**COMPAS uses a line length of 180 characters**. While longer than the 80 characters recommended by ``PEP8``, it is in our opinion a more reasonable limit for modern displays. **Indentations are 4 spaces**. Tab to spaces setting can be set in ``.editorconfig`` which is respected by most editors. For more information see `EditorConfig `_. diff --git a/docs/devguide/workflow.rst b/docs/devguide/workflow.rst index f59b5a58b90..dc35ad28b81 100644 --- a/docs/devguide/workflow.rst +++ b/docs/devguide/workflow.rst @@ -22,7 +22,7 @@ To set up a developer environment .. code-block:: bash cd path/to/compas - pip install -r requirements-dev.txt + pip install -e ".[dev]" 4. Make sure all tests pass and the code is free of lint: diff --git a/pyproject.toml b/pyproject.toml index 91814cd4427..a1757ea043f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,26 +1,153 @@ -[tool.black] -line-length = 120 +[build-system] +requires = ["setuptools>=66.0"] +build-backend = "setuptools.build_meta" + +# ============================================================================ +# project info +# ============================================================================ + +[project] +name = "compas" +description = "The main COMPAS framework library." +keywords = ["architecture", "engineering", "fabrication", "construction"] +authors = [{ name = "tom van mele", email = "tom.v.mele@gmail.com" }] +license = { file = "LICENSE" } +readme = "README.md" +requires-python = ">=3.9" +dynamic = ['dependencies', 'optional-dependencies', 'version'] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Topic :: Scientific/Engineering", + "Operating System :: Unix", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +[project.urls] +Homepage = "https://compas-dev.github.io/compas" +Documentation = "https://compas-dev.github.io/compas" +Repository = "https://github.com/compas-dev/compas.git" +Changelog = "https://github.com/compas-dev/compas/blob/main/CHANGELOG.md" +Issues = "https://github.com/compas-dev/compas/issues" +Forum = "https://forum.compas-framework.org/" + +[project.scripts] +compas_rpc = "compas.rpc.__main__:main" + +# ============================================================================ +# setuptools config +# ============================================================================ + +[tool.setuptools] +package-dir = { "" = "src" } +include-package-data = true +zip-safe = false + +[tool.setuptools.dynamic] +version = { attr = "compas.__version__" } +dependencies = { file = "requirements.txt" } +optional-dependencies = { dev = { file = "requirements-dev.txt" } } + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +"compas.colors.cmcrameri" = ["*.txt"] +"compas.data.samples" = ["*.obj", "*.stl", "*.off", "*.ply", "*.json"] + +# ============================================================================ +# replace pytest.ini +# ============================================================================ [tool.pytest.ini_options] minversion = "6.0" -testpaths = ["tests"] -python_files = [ - "test_*.py", - "tests.py" +testpaths = ["tests", "src/compas"] +python_files = ["test_*.py", "*_test.py", "test.py"] +addopts = ["-ra", "--strict-markers", "--doctest-glob=*.rst", "--tb=short"] +doctest_optionflags = [ + "NORMALIZE_WHITESPACE", + "IGNORE_EXCEPTION_DETAIL", + "ALLOW_UNICODE", + "ALLOW_BYTES", + "NUMBER", +] + +# ============================================================================ +# replace bumpversion.cfg +# ============================================================================ + +[tool.bumpversion] +current_version = "2.1.0" +message = "Bump version to {new_version}" +commit = true +tag = true + +[[tool.bumpversion.files]] +filename = "src/compas/__init__.py" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "src/compas_blender/__init__.py" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "src/compas_ghpython/__init__.py" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "src/compas_rhino/__init__.py" +search = "{current_version}" +replace = "{new_version}" + +[[tool.bumpversion.files]] +filename = "CHANGELOG.md" +search = "Unreleased" +replace = "[{new_version}] {now:%Y-%m-%d}" + +# ============================================================================ +# replace setup.cfg +# ============================================================================ + +[tool.black] +line-length = 179 + +[tool.ruff] +line-length = 179 +indent-width = 4 +target-version = "py39" + +[tool.ruff.lint] +select = ["E", "F", "I"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["I001"] +"tests/*" = ["I001"] +"tasks.py" = ["I001"] + +[tool.ruff.lint.isort] +force-single-line = true +known-first-party = [ + "compas", + "compas_blender", + "compas_ghpython", + "compas_rhino", ] -addopts = "-ra --strict --doctest-modules --doctest-glob=*.rst --tb=short" -doctest_optionflags= "NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ALLOW_UNICODE ALLOW_BYTES NUMBER" -filterwarnings = "ignore::DeprecationWarning" - -[tool.isort] -line_length = 120 -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -force_single_line = true -ensure_newline_before_comments = true -known_first_party = "compas" -default_section = "THIRDPARTY" -forced_separate = "test_compas" -skip = ["__init__.py"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + +[tool.ruff.lint.pycodestyle] +max-doc-length = 179 + +[tool.ruff.format] +docstring-code-format = true +docstring-code-line-length = "dynamic" diff --git a/requirements-dev.txt b/requirements-dev.txt index def0bbb150b..a1579931b3b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,14 +1,9 @@ attrs >=17.4 -black -bump2version >=1.0.1 -check-manifest >=0.36 -compas_invocations -doc8 -flake8 -importlib_metadata <5.0 +black >=22.12.0 +bump-my-version +compas_invocations2 invoke >=0.14 -isort +ruff sphinx_compas2_theme twine wheel --e . diff --git a/requirements.txt b/requirements.txt index d7bf5d5b9ca..11f9a773638 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,5 +3,4 @@ jsonschema networkx >= 3.0 numpy >= 1.15.4 scipy >= 1.1 -typing_extensions watchdog; sys_platform != 'emscripten' diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e7f4c1234c9..00000000000 --- a/setup.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[bdist_wheel] -universal = 1 - -[flake8] -max-line-length = 120 -extend-ignore = - # See https://github.com/PyCQA/pycodestyle/issues/373 - E203, - # Only keep black line length check because flake8 forces it on comments as well - E501, - -[doc8] -max-line-length = 120 -ignore = D001 - -[pydocstyle] -convention = numpy diff --git a/setup.py b/setup.py deleted file mode 100644 index 2a2fbb3cc24..00000000000 --- a/setup.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: utf-8 -*- -# flake8: noqa -from __future__ import print_function - -import io -from os import path - -from setuptools import setup - - -here = path.abspath(path.dirname(__file__)) - - -def read(*names, **kwargs): - return io.open(path.join(here, *names), encoding=kwargs.get("encoding", "utf8")).read() - - -long_description = read("README.md") -requirements = [r for r in read("requirements.txt").split("\n") if r] -optional_requirements = {} - -setup( - name="COMPAS", - version="2.1.0", - description="The COMPAS framework", - long_description=long_description, - long_description_content_type="text/markdown", - url="http://compas.dev", - author="Tom Van Mele", - author_email="van.mele@arch.ethz.ch", - license="MIT", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "Topic :: Scientific/Engineering", - "License :: OSI Approved :: MIT License", - "Operating System :: Unix", - "Operating System :: POSIX", - "Operating System :: Microsoft :: Windows", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: Implementation :: CPython", - ], - keywords=["architecture", "engineering", "fabrication", "construction"], - project_urls={ - "Documentation": "http://compas.dev", - "Forum": "https://forum.compas-framework.org/", - "Repository": "https://github.com/compas-dev/compas", - "Issues": "https://github.com/compas-dev/compas/issues", - }, - packages=[ - "compas", - "compas_rhino", - "compas_blender", - "compas_ghpython", - ], - package_dir={"": "src"}, - package_data={"compas": ["data/schemas/*.json"]}, - data_files=[], - include_package_data=True, - zip_safe=False, - install_requires=requirements, - python_requires=">=2.7", - extras_require={"numba": ["numba"]}, - entry_points={"console_scripts": ["compas_rpc=compas.rpc.__main__:main"]}, - ext_modules=[], - cmdclass={}, -) diff --git a/src/compas/__init__.py b/src/compas/__init__.py index ad40d3d75cc..d5e2de51abe 100644 --- a/src/compas/__init__.py +++ b/src/compas/__init__.py @@ -1,7 +1,6 @@ from __future__ import print_function import os -from distutils.version import LooseVersion import compas._os from compas._os import ( @@ -23,8 +22,6 @@ __email__ = "tom.v.mele@gmail.com" __version__ = "2.1.0" -version = LooseVersion(compas.__version__) -versionstring = version.vstring.split("-")[0] HERE = compas._os.realpath(os.path.dirname(__file__)) """str: Path to the location of the compas package.""" diff --git a/src/compas/_iotools.py b/src/compas/_iotools.py index 98e278f8e46..e4bcc1d602d 100644 --- a/src/compas/_iotools.py +++ b/src/compas/_iotools.py @@ -1,7 +1,7 @@ """For the time being, these functions are only for internal use.""" -from contextlib import contextmanager import io +from contextlib import contextmanager try: from urllib.request import urlopen diff --git a/src/compas/_os.py b/src/compas/_os.py index a904aa8deb9..003df5fd975 100644 --- a/src/compas/_os.py +++ b/src/compas/_os.py @@ -677,7 +677,8 @@ def _get_win_folder_from_registry(csidl_name): def _get_win_folder_with_pywin32(csidl_name): - from win32com.shell import shellcon, shell + from win32com.shell import shell + from win32com.shell import shellcon dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) # Try to make this a unicode path because SHGetFolderPath does diff --git a/src/compas/colors/color.py b/src/compas/colors/color.py index 43255d6d920..61f82d713f0 100644 --- a/src/compas/colors/color.py +++ b/src/compas/colors/color.py @@ -90,6 +90,8 @@ class Color(Data): The perceived freedom of whiteness. is_light : bool If True, the color is considered light. + contrast : :class:`compas.colors.Color` + The contrasting color to the current color. Examples -------- @@ -311,6 +313,10 @@ def saturation(self): minval = min(self.r, self.g, self.b) return (maxval - minval) / maxval + @property + def contrast(self): + return self.darkened(25) if self.is_light else self.lightened(50) + # -------------------------------------------------------------------------- # Constructors # -------------------------------------------------------------------------- @@ -906,8 +912,8 @@ def lighten(self, factor=10): factor = 1.0 + factor / 100 - h, l, s = self.hls - r, g, b = colorsys.hls_to_rgb(h, min(1.0, l * factor), s) + hue, luminance, saturation = self.hls + r, g, b = colorsys.hls_to_rgb(hue, min(1.0, luminance * factor), saturation) self.r = r self.g = g self.b = b @@ -957,8 +963,8 @@ def darken(self, factor=10): factor = 1.0 - factor / 100 - h, l, s = self.hls - r, g, b = colorsys.hls_to_rgb(h, max(0.0, l * factor), s) + hue, luminance, saturation = self.hls + r, g, b = colorsys.hls_to_rgb(hue, max(0.0, luminance * factor), saturation) self.r = r self.g = g self.b = b @@ -1032,8 +1038,8 @@ def saturate(self, factor=10): factor = 1.0 + factor / 100 - h, l, s = self.hls - r, g, b = colorsys.hls_to_rgb(h, l, min(1.0, s * factor)) + hue, luminance, saturation = self.hls + r, g, b = colorsys.hls_to_rgb(hue, luminance, min(1.0, saturation * factor)) self.r = r self.g = g self.b = b @@ -1083,8 +1089,8 @@ def desaturate(self, factor=10): factor = 1.0 - factor / 100 - h, l, s = self.hls - r, g, b = colorsys.hls_to_rgb(h, l, max(0.0, s * factor)) + hue, luminance, saturation = self.hls + r, g, b = colorsys.hls_to_rgb(hue, luminance, max(0.0, saturation * factor)) self.r = r self.g = g self.b = b diff --git a/src/compas/colors/colordict.py b/src/compas/colors/colordict.py index c86d427b4b0..5a86b8fa46a 100644 --- a/src/compas/colors/colordict.py +++ b/src/compas/colors/colordict.py @@ -1,8 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.data import Data + from .color import Color diff --git a/src/compas/colors/colormap.py b/src/compas/colors/colormap.py index e61cb936ca9..fcdb9d3504d 100644 --- a/src/compas/colors/colormap.py +++ b/src/compas/colors/colormap.py @@ -7,8 +7,8 @@ from compas.itertools import linspace from .color import Color -from .mpl_colormap import _magma_data from .mpl_colormap import _inferno_data +from .mpl_colormap import _magma_data from .mpl_colormap import _plasma_data from .mpl_colormap import _viridis_data diff --git a/src/compas/data/coercion.py b/src/compas/data/coercion.py index f5e9680e0f8..25bba723d9a 100644 --- a/src/compas/data/coercion.py +++ b/src/compas/data/coercion.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from .validators import is_item_iterable diff --git a/src/compas/data/data.py b/src/compas/data/data.py index 7d22a29d151..d258287718e 100644 --- a/src/compas/data/data.py +++ b/src/compas/data/data.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function try: from typing import TypeVar # noqa: F401 @@ -10,13 +10,12 @@ pass import hashlib -from uuid import uuid4 -from uuid import UUID from copy import deepcopy +from uuid import UUID +from uuid import uuid4 import compas - # ============================================================================== # If you ever feel tempted to use ABCMeta in your code: don't, just DON'T. # Assigning __metaclass__ = ABCMeta to a class causes a severe memory leak/performance diff --git a/src/compas/data/encoders.py b/src/compas/data/encoders.py index 6e37f157c7e..04c93a8913b 100644 --- a/src/compas/data/encoders.py +++ b/src/compas/data/encoders.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function try: from typing import Type # noqa: F401 diff --git a/src/compas/data/schema.py b/src/compas/data/schema.py index a7a05965d87..dd051be09a4 100644 --- a/src/compas/data/schema.py +++ b/src/compas/data/schema.py @@ -2,8 +2,8 @@ from __future__ import division from __future__ import print_function -import os import json +import os def dataclass_dataschema(cls): # type: (...) -> dict @@ -119,10 +119,11 @@ def compas_dataclasses(): # type: (...) -> list """ from collections import deque - from compas.data import Data + import compas.colors # noqa: F401 import compas.datastructures # noqa: F401 import compas.geometry # noqa: F401 + from compas.data import Data tovisit = deque([Data]) dataclasses = [] diff --git a/src/compas/data/validators.py b/src/compas/data/validators.py index f7d37d5b9ea..716786acf30 100644 --- a/src/compas/data/validators.py +++ b/src/compas/data/validators.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function try: basestring # type: ignore diff --git a/src/compas/datastructures/assembly/assembly.py b/src/compas/datastructures/assembly/assembly.py index 0efed64080c..66a825cf5c9 100644 --- a/src/compas/datastructures/assembly/assembly.py +++ b/src/compas/datastructures/assembly/assembly.py @@ -1,9 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.datastructures import Datastructure from compas.datastructures import Graph + from .exceptions import AssemblyError diff --git a/src/compas/datastructures/assembly/part.py b/src/compas/datastructures/assembly/part.py index 32d41736894..d16cf250dfb 100644 --- a/src/compas/datastructures/assembly/part.py +++ b/src/compas/datastructures/assembly/part.py @@ -1,12 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.data import Data +from compas.datastructures import Datastructure +from compas.geometry import Brep from compas.geometry import Frame from compas.geometry import Polyhedron -from compas.geometry import Brep -from compas.datastructures import Datastructure -from compas.data import Data class Feature(Data): diff --git a/src/compas/datastructures/cell_network/cell_network.py b/src/compas/datastructures/cell_network/cell_network.py index 4c5b7f068b8..dd0cf8e2a5c 100644 --- a/src/compas/datastructures/cell_network/cell_network.py +++ b/src/compas/datastructures/cell_network/cell_network.py @@ -4,21 +4,22 @@ from random import sample -from compas.datastructures import Mesh from compas.datastructures import Graph -from compas.datastructures.datastructure import Datastructure -from compas.datastructures.attributes import VertexAttributeView +from compas.datastructures import Mesh +from compas.datastructures.attributes import CellAttributeView from compas.datastructures.attributes import EdgeAttributeView from compas.datastructures.attributes import FaceAttributeView -from compas.datastructures.attributes import CellAttributeView - +from compas.datastructures.attributes import VertexAttributeView +from compas.datastructures.datastructure import Datastructure from compas.files import OBJ - from compas.geometry import Line from compas.geometry import Point from compas.geometry import Polygon from compas.geometry import Polyhedron from compas.geometry import Vector +from compas.geometry import add_vectors +from compas.geometry import bestfit_plane +from compas.geometry import bounding_box from compas.geometry import centroid_points from compas.geometry import centroid_polygon from compas.geometry import centroid_polyhedron @@ -26,16 +27,11 @@ from compas.geometry import length_vector from compas.geometry import normal_polygon from compas.geometry import normalize_vector -from compas.geometry import volume_polyhedron -from compas.geometry import add_vectors -from compas.geometry import bestfit_plane from compas.geometry import project_point_plane from compas.geometry import scale_vector from compas.geometry import subtract_vectors -from compas.geometry import bounding_box - +from compas.geometry import volume_polyhedron from compas.itertools import pairwise - from compas.tolerance import TOL @@ -227,15 +223,7 @@ def __from_data__(cls, data): return cell_network - def __init__( - self, - default_vertex_attributes=None, - default_edge_attributes=None, - default_face_attributes=None, - default_cell_attributes=None, - name=None, - **kwargs - ): + def __init__(self, default_vertex_attributes=None, default_edge_attributes=None, default_face_attributes=None, default_cell_attributes=None, name=None, **kwargs): # fmt: skip super(CellNetwork, self).__init__(kwargs, name=name) self._max_vertex = -1 self._max_face = -1 diff --git a/src/compas/datastructures/graph/duality.py b/src/compas/datastructures/graph/duality.py index f81e359e2dc..89482267878 100644 --- a/src/compas/datastructures/graph/duality.py +++ b/src/compas/datastructures/graph/duality.py @@ -1,13 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import pi -from compas.itertools import pairwise from compas.geometry import angle_vectors from compas.geometry import is_ccw_xy - +from compas.itertools import pairwise PI2 = 2.0 * pi diff --git a/src/compas/datastructures/graph/graph.py b/src/compas/datastructures/graph/graph.py index bdae03b4f6c..469ff508e56 100644 --- a/src/compas/datastructures/graph/graph.py +++ b/src/compas/datastructures/graph/graph.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from random import sample from ast import literal_eval from itertools import combinations +from random import sample import compas @@ -13,42 +13,40 @@ else: from collections.abc import Mapping -from compas.tolerance import TOL +from compas.datastructures.attributes import EdgeAttributeView +from compas.datastructures.attributes import NodeAttributeView +from compas.datastructures.datastructure import Datastructure from compas.files import OBJ +from compas.geometry import Box +from compas.geometry import Line from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Line -from compas.geometry import Box +from compas.geometry import add_vectors +from compas.geometry import bounding_box from compas.geometry import centroid_points -from compas.geometry import subtract_vectors from compas.geometry import distance_point_point from compas.geometry import midpoint_line from compas.geometry import normalize_vector -from compas.geometry import add_vectors +from compas.geometry import oriented_bounding_box from compas.geometry import scale_vector +from compas.geometry import subtract_vectors from compas.geometry import transform_points -from compas.geometry import bounding_box -from compas.geometry import oriented_bounding_box +from compas.tolerance import TOL from compas.topology import astar_shortest_path from compas.topology import breadth_first_traverse from compas.topology import connected_components -from compas.datastructures.datastructure import Datastructure -from compas.datastructures.attributes import NodeAttributeView -from compas.datastructures.attributes import EdgeAttributeView - -from .operations.split import graph_split_edge +from .duality import graph_find_cycles from .operations.join import graph_join_edges - +from .operations.split import graph_split_edge +from .planarity import graph_count_crossings +from .planarity import graph_embed_in_plane +from .planarity import graph_find_crossings from .planarity import graph_is_crossed from .planarity import graph_is_planar from .planarity import graph_is_planar_embedding from .planarity import graph_is_xy -from .planarity import graph_count_crossings -from .planarity import graph_find_crossings -from .planarity import graph_embed_in_plane from .smoothing import graph_smooth_centroid -from .duality import graph_find_cycles class Graph(Datastructure): diff --git a/src/compas/datastructures/graph/operations/join.py b/src/compas/datastructures/graph/operations/join.py index 191eacbe4c1..3c9d4517218 100644 --- a/src/compas/datastructures/graph/operations/join.py +++ b/src/compas/datastructures/graph/operations/join.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.tolerance import TOL from compas.itertools import pairwise +from compas.tolerance import TOL def graph_join_edges(graph, key): @@ -104,15 +104,9 @@ def graph_polylines(graph, splits=None): # get adjacent edges until the polyline is closed... while polyline[0] != polyline[-1]: # ... or until both end are non-two-valent vertices - if ( - len(graph.neighbors(polyline[-1])) != 2 - or TOL.geometric_key(graph.node_coordinates(polyline[-1])) in stop_geom_keys - ): + if len(graph.neighbors(polyline[-1])) != 2 or TOL.geometric_key(graph.node_coordinates(polyline[-1])) in stop_geom_keys: polyline = list(reversed(polyline)) - if ( - len(graph.neighbors(polyline[-1])) != 2 - or TOL.geometric_key(graph.node_coordinates(polyline[-1])) in stop_geom_keys - ): + if len(graph.neighbors(polyline[-1])) != 2 or TOL.geometric_key(graph.node_coordinates(polyline[-1])) in stop_geom_keys: break # add next edge diff --git a/src/compas/datastructures/graph/operations/split.py b/src/compas/datastructures/graph/operations/split.py index 6e1c64e858d..1ba03018f2c 100644 --- a/src/compas/datastructures/graph/operations/split.py +++ b/src/compas/datastructures/graph/operations/split.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def graph_split_edge(graph, edge, t=0.5): diff --git a/src/compas/datastructures/graph/planarity.py b/src/compas/datastructures/graph/planarity.py index 35e0ae521ed..1e3802b1fc4 100644 --- a/src/compas/datastructures/graph/planarity.py +++ b/src/compas/datastructures/graph/planarity.py @@ -1,17 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from itertools import product from math import cos -from math import sin from math import pi - -from itertools import product +from math import sin from compas.geometry import angle_vectors_xy from compas.geometry import is_ccw_xy from compas.geometry import subtract_vectors_xy - from compas.geometry._core.predicates_2 import is_intersection_segment_segment_xy diff --git a/src/compas/datastructures/graph/smoothing.py b/src/compas/datastructures/graph/smoothing.py index c91349bfb85..457048eb48a 100644 --- a/src/compas/datastructures/graph/smoothing.py +++ b/src/compas/datastructures/graph/smoothing.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import centroid_points diff --git a/src/compas/datastructures/mesh/conway.py b/src/compas/datastructures/mesh/conway.py index 8b87ddaaad6..09b56a0f853 100644 --- a/src/compas/datastructures/mesh/conway.py +++ b/src/compas/datastructures/mesh/conway.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def mesh_conway_dual(mesh): @@ -185,11 +185,7 @@ def mesh_conway_kis(mesh): v = mesh.number_of_vertices() vkey_index = {vkey: i for i, vkey in enumerate(mesh.vertices())} fkey_index = {fkey: i + v for i, fkey in enumerate(mesh.faces())} - faces = [ - [vkey_index[u], vkey_index[v], fkey_index[mesh.halfedge[u][v]]] - for fkey in mesh.faces() - for u, v in mesh.face_halfedges(fkey) - ] + faces = [[vkey_index[u], vkey_index[v], fkey_index[mesh.halfedge[u][v]]] for fkey in mesh.faces() for u, v in mesh.face_halfedges(fkey)] return cls.from_vertices_and_faces(vertices, faces) @@ -427,9 +423,7 @@ def mesh_conway_gyro(mesh): F = mesh.number_of_faces() vkey_index = {vkey: i for i, vkey in enumerate(mesh.vertices())} fkey_index = {fkey: i + V for i, fkey in enumerate(mesh.faces())} - ekey_index = { - halfedge: i + V + F for i, halfedge in enumerate([(u, v) for u in mesh.vertices() for v in mesh.halfedge[u]]) - } + ekey_index = {halfedge: i + V + F for i, halfedge in enumerate([(u, v) for u in mesh.vertices() for v in mesh.halfedge[u]])} faces = [] for fkey in mesh.faces(): for u, v in mesh.face_halfedges(fkey): diff --git a/src/compas/datastructures/mesh/duality.py b/src/compas/datastructures/mesh/duality.py index c06bd172095..985aebda0bc 100644 --- a/src/compas/datastructures/mesh/duality.py +++ b/src/compas/datastructures/mesh/duality.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import pi -from compas.utilities import flatten +from compas.itertools import flatten PI2 = 2.0 * pi diff --git a/src/compas/datastructures/mesh/mesh.py b/src/compas/datastructures/mesh/mesh.py index 250e6a8dace..aa2641c817c 100644 --- a/src/compas/datastructures/mesh/mesh.py +++ b/src/compas/datastructures/mesh/mesh.py @@ -2,8 +2,8 @@ from __future__ import division from __future__ import print_function -from math import pi from itertools import product +from math import pi from random import sample import compas @@ -13,57 +13,53 @@ else: from collections.abc import Mapping -from compas.tolerance import TOL - +from compas.datastructures.attributes import EdgeAttributeView +from compas.datastructures.attributes import FaceAttributeView +from compas.datastructures.attributes import VertexAttributeView +from compas.datastructures.datastructure import Datastructure from compas.files import OBJ from compas.files import OFF from compas.files import PLY from compas.files import STL - -from compas.geometry import Point -from compas.geometry import Vector +from compas.geometry import Box +from compas.geometry import Circle +from compas.geometry import Frame from compas.geometry import Line from compas.geometry import Plane +from compas.geometry import Point from compas.geometry import Polygon -from compas.geometry import Circle -from compas.geometry import Frame from compas.geometry import Polyhedron -from compas.geometry import Box +from compas.geometry import Vector +from compas.geometry import add_vectors from compas.geometry import angle_points from compas.geometry import area_polygon from compas.geometry import bestfit_plane +from compas.geometry import bounding_box from compas.geometry import centroid_points from compas.geometry import centroid_polygon from compas.geometry import cross_vectors +from compas.geometry import distance_line_line from compas.geometry import distance_point_plane from compas.geometry import distance_point_point -from compas.geometry import distance_line_line from compas.geometry import length_vector +from compas.geometry import midpoint_line from compas.geometry import normal_polygon from compas.geometry import normalize_vector +from compas.geometry import oriented_bounding_box from compas.geometry import scale_vector -from compas.geometry import add_vectors from compas.geometry import subtract_vectors from compas.geometry import sum_vectors -from compas.geometry import midpoint_line -from compas.geometry import vector_average -from compas.geometry import bounding_box -from compas.geometry import oriented_bounding_box from compas.geometry import transform_points - +from compas.geometry import vector_average from compas.itertools import linspace from compas.itertools import pairwise -from compas.utilities import window - +from compas.itertools import window +from compas.tolerance import TOL from compas.topology import breadth_first_traverse -from compas.topology import face_adjacency from compas.topology import connected_components +from compas.topology import unify_cycles -from compas.datastructures.datastructure import Datastructure -from compas.datastructures.attributes import VertexAttributeView -from compas.datastructures.attributes import EdgeAttributeView -from compas.datastructures.attributes import FaceAttributeView - +from .duality import mesh_dual from .operations.collapse import mesh_collapse_edge from .operations.merge import mesh_merge_faces from .operations.split import mesh_split_edge @@ -71,13 +67,10 @@ from .operations.split import mesh_split_strip from .operations.weld import mesh_unweld_edges from .operations.weld import mesh_unweld_vertices - -from .subdivision import mesh_subdivide -from .duality import mesh_dual from .slice import mesh_slice_plane - -from .smoothing import mesh_smooth_centroid from .smoothing import mesh_smooth_area +from .smoothing import mesh_smooth_centroid +from .subdivision import mesh_subdivide class Mesh(Datastructure): @@ -235,14 +228,7 @@ def __from_data__(cls, data): return mesh - def __init__( - self, - default_vertex_attributes=None, - default_edge_attributes=None, - default_face_attributes=None, - name=None, - **kwargs - ): + def __init__(self, default_vertex_attributes=None, default_edge_attributes=None, default_face_attributes=None, name=None, **kwargs): # fmt: skip super(Mesh, self).__init__(kwargs, name=name) self._max_vertex = -1 self._max_face = -1 @@ -2953,42 +2939,25 @@ def unify_cycles(self, root=None): The mesh is modified in place. """ - - def unify(node, nbr): - # find the common edge - for u, v in self.face_halfedges(nbr): - if u in self.face[node] and v in self.face[node]: - # node and nbr have edge u-v in common - i = self.face[node].index(u) - j = self.face[node].index(v) - if i == j - 1 or (j == 0 and u == self.face[node][-1]): - # if the traversal of a neighboring halfedge - # is in the same direction - # flip the neighbor - self.face[nbr][:] = self.face[nbr][::-1] - return - - if root is None: - root = self.face_sample(size=1)[0] - + vertex_index = {} + index_vertex = {} + for index, vertex in enumerate(self.vertices()): + vertex_index[vertex] = index + index_vertex[index] = vertex index_face = {index: face for index, face in enumerate(self.faces())} - points = self.vertices_attributes("xyz") - faces = [self.face_vertices(face) for face in self.faces()] - - adj = face_adjacency(points, faces) - adjacency = {} - for face in adj: - adjacency[index_face[face]] = [index_face[nbr] for nbr in adj[face]] - visited = breadth_first_traverse(adjacency, root, unify) + vertices = self.vertices_attributes("xyz") + faces = [[vertex_index[vertex] for vertex in self.face_vertices(face)] for face in self.faces()] - if len(list(visited)) != self.number_of_faces(): - raise Exception("Not all faces were visited.") + unify_cycles(vertices, faces) self.halfedge = {key: {} for key in self.vertices()} - for fkey in self.faces(): - for u, v in self.face_halfedges(fkey): - self.halfedge[u][v] = fkey + for index, vertices in enumerate(faces): + face = index_face[index] + vertices = [index_vertex[vertex] for vertex in vertices] + self.face[face] = vertices + for u, v in pairwise(vertices + vertices[:1]): + self.halfedge[u][v] = face if u not in self.halfedge[v]: self.halfedge[v][u] = None @@ -4413,6 +4382,11 @@ def face_flatness(self, fkey, maxdev=0.02): float The flatness. + Raises + ------ + Exception + If the face has more than 4 vertices. + Notes ----- Flatness is computed as the ratio of the distance between the diagonals @@ -4426,6 +4400,12 @@ def face_flatness(self, fkey, maxdev=0.02): """ vertices = self.face_vertices(fkey) f = len(vertices) + + if f == 3: + return 0.0 + if f > 4: + raise Exception("Computing face flatness for faces with more than 4 vertices is not supported.") + points = self.vertices_attributes("xyz", keys=vertices) or [] lengths = [distance_point_point(a, b) for a, b in pairwise(points + points[:1])] length = sum(lengths) / f @@ -5075,8 +5055,8 @@ def thickened(self, thickness=1.0, both=True): raise ValueError("Thickness should be a positive number.") if both: - mesh_top = self.offset(+0.5 * thickness) - mesh_bottom = self.offset(-0.5 * thickness) + mesh_top = self.offset(+0.5 * thickness) # type: Mesh + mesh_bottom = self.offset(-0.5 * thickness) # type: Mesh else: mesh_top = self.offset(thickness) mesh_bottom = self.copy() @@ -5085,7 +5065,8 @@ def thickened(self, thickness=1.0, both=True): mesh_bottom.flip_cycles() # join parts - thickened_mesh = mesh_top.join(mesh_bottom) + thickened_mesh = mesh_top.copy() # type: Mesh + thickened_mesh.join(mesh_bottom) # close boundaries n = thickened_mesh.number_of_vertices() / 2 diff --git a/src/compas/datastructures/mesh/operations/collapse.py b/src/compas/datastructures/mesh/operations/collapse.py index d80a19f0913..8f5c688cb81 100644 --- a/src/compas/datastructures/mesh/operations/collapse.py +++ b/src/compas/datastructures/mesh/operations/collapse.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def is_collapse_legal(mesh, edge, allow_boundary=False): diff --git a/src/compas/datastructures/mesh/operations/insert.py b/src/compas/datastructures/mesh/operations/insert.py index f1a49ca00a2..0d68bf9dce0 100644 --- a/src/compas/datastructures/mesh/operations/insert.py +++ b/src/compas/datastructures/mesh/operations/insert.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def mesh_add_vertex_to_face_edge(mesh, key, fkey, v): diff --git a/src/compas/datastructures/mesh/operations/merge.py b/src/compas/datastructures/mesh/operations/merge.py index 9d8dbd636a4..dc873c7d2bd 100644 --- a/src/compas/datastructures/mesh/operations/merge.py +++ b/src/compas/datastructures/mesh/operations/merge.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def mesh_merge_faces(mesh, faces): diff --git a/src/compas/datastructures/mesh/operations/split.py b/src/compas/datastructures/mesh/operations/split.py index f947d1575ea..08e5e376b05 100644 --- a/src/compas/datastructures/mesh/operations/split.py +++ b/src/compas/datastructures/mesh/operations/split.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.itertools import pairwise diff --git a/src/compas/datastructures/mesh/operations/substitute.py b/src/compas/datastructures/mesh/operations/substitute.py index 5c351f9fc3b..571618645f0 100644 --- a/src/compas/datastructures/mesh/operations/substitute.py +++ b/src/compas/datastructures/mesh/operations/substitute.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def mesh_substitute_vertex_in_faces(mesh, old_vkey, new_vkey, fkeys=None): diff --git a/src/compas/datastructures/mesh/operations/swap.py b/src/compas/datastructures/mesh/operations/swap.py index adeac70e505..f36ef35ba5f 100644 --- a/src/compas/datastructures/mesh/operations/swap.py +++ b/src/compas/datastructures/mesh/operations/swap.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function def trimesh_swap_edge(mesh, edge, allow_boundary=True): diff --git a/src/compas/datastructures/mesh/operations/weld.py b/src/compas/datastructures/mesh/operations/weld.py index 54646726124..015a3c1cfab 100644 --- a/src/compas/datastructures/mesh/operations/weld.py +++ b/src/compas/datastructures/mesh/operations/weld.py @@ -1,11 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division - -from compas.topology import vertex_adjacency_from_edges -from compas.topology import connected_components +from __future__ import print_function from compas.itertools import pairwise +from compas.topology import connected_components +from compas.topology import vertex_adjacency_from_edges from .substitute import mesh_substitute_vertex_in_faces diff --git a/src/compas/datastructures/mesh/remesh.py b/src/compas/datastructures/mesh/remesh.py index c3992978b70..e47bf46b269 100644 --- a/src/compas/datastructures/mesh/remesh.py +++ b/src/compas/datastructures/mesh/remesh.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from .smoothing import mesh_smooth_area from .operations.collapse import trimesh_collapse_edge -from .operations.swap import trimesh_swap_edge from .operations.split import trimesh_split_edge +from .operations.swap import trimesh_swap_edge +from .smoothing import mesh_smooth_area def trimesh_remesh( diff --git a/src/compas/datastructures/mesh/slice.py b/src/compas/datastructures/mesh/slice.py index 0a98705d584..1059c5fdaa4 100644 --- a/src/compas/datastructures/mesh/slice.py +++ b/src/compas/datastructures/mesh/slice.py @@ -1,7 +1,7 @@ +from compas.geometry import dot_vectors from compas.geometry import intersection_segment_plane from compas.geometry import length_vector from compas.geometry import subtract_vectors -from compas.geometry import dot_vectors def mesh_slice_plane(mesh, plane): diff --git a/src/compas/datastructures/mesh/smoothing.py b/src/compas/datastructures/mesh/smoothing.py index 2a6925c05e7..ffe1f3151cb 100644 --- a/src/compas/datastructures/mesh/smoothing.py +++ b/src/compas/datastructures/mesh/smoothing.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import centroid_points from compas.geometry import centroid_polygon diff --git a/src/compas/datastructures/mesh/subdivision.py b/src/compas/datastructures/mesh/subdivision.py index 27fda25c806..190545a2a00 100644 --- a/src/compas/datastructures/mesh/subdivision.py +++ b/src/compas/datastructures/mesh/subdivision.py @@ -1,15 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from copy import deepcopy from math import cos from math import pi -from copy import deepcopy from compas.geometry import centroid_points from compas.geometry import offset_polygon - -from compas.utilities import iterable_like +from compas.itertools import iterable_like from compas.itertools import pairwise @@ -397,9 +396,7 @@ def mesh_subdivide_catmullclark(mesh, k=1, fixed=None): if C < 2: fnbrs = [mesh.face_centroid(fkey) for fkey in mesh.vertex_faces(key) if fkey is not None] - enbrs = [ - key_xyz[nbr] for nbr in subd.halfedge[key] - ] # this should be the location of the original neighbour + enbrs = [key_xyz[nbr] for nbr in subd.halfedge[key]] # this should be the location of the original neighbour n = len(enbrs) v = n - 3.0 F = centroid_points(fnbrs) @@ -673,9 +670,7 @@ def trimesh_subdivide_loop(mesh, k=1, fixed=None): for _ in range(k): key_xyz = {key: subd.vertex_coordinates(key) for key in subd.vertices()} fkey_vertices = {fkey: subd.face_vertices(fkey)[:] for fkey in subd.faces()} - uv_w = { - (u, v): subd.face_vertex_ancestor(fkey, u) for fkey in subd.faces() for u, v in subd.face_halfedges(fkey) - } + uv_w = {(u, v): subd.face_vertex_ancestor(fkey, u) for fkey in subd.faces() for u, v in subd.face_halfedges(fkey)} boundary = set(subd.vertices_on_boundary()) for key in subd.vertices(): diff --git a/src/compas/datastructures/tree/tree.py b/src/compas/datastructures/tree/tree.py index a72f140128a..4038f69d1c7 100644 --- a/src/compas/datastructures/tree/tree.py +++ b/src/compas/datastructures/tree/tree.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.datastructures import Datastructure from compas.data import Data +from compas.datastructures import Datastructure class TreeNode(Data): diff --git a/src/compas/datastructures/volmesh/volmesh.py b/src/compas/datastructures/volmesh/volmesh.py index 15e4b8c5405..f47d2643518 100644 --- a/src/compas/datastructures/volmesh/volmesh.py +++ b/src/compas/datastructures/volmesh/volmesh.py @@ -5,23 +5,22 @@ from itertools import product from random import sample -from compas.datastructures.datastructure import Datastructure -from compas.datastructures.attributes import VertexAttributeView +from compas.datastructures import Mesh +from compas.datastructures.attributes import CellAttributeView from compas.datastructures.attributes import EdgeAttributeView from compas.datastructures.attributes import FaceAttributeView -from compas.datastructures.attributes import CellAttributeView -from compas.datastructures import Mesh - +from compas.datastructures.attributes import VertexAttributeView +from compas.datastructures.datastructure import Datastructure from compas.files import OBJ - -from compas.geometry import Point -from compas.geometry import Vector +from compas.geometry import Box from compas.geometry import Line +from compas.geometry import Point from compas.geometry import Polygon from compas.geometry import Polyhedron -from compas.geometry import Box +from compas.geometry import Vector from compas.geometry import add_vectors from compas.geometry import bestfit_plane +from compas.geometry import bounding_box from compas.geometry import centroid_points from compas.geometry import centroid_polygon from compas.geometry import centroid_polyhedron @@ -29,16 +28,13 @@ from compas.geometry import length_vector from compas.geometry import normal_polygon from compas.geometry import normalize_vector +from compas.geometry import oriented_bounding_box from compas.geometry import project_point_plane from compas.geometry import scale_vector from compas.geometry import subtract_vectors -from compas.geometry import bounding_box from compas.geometry import transform_points -from compas.geometry import oriented_bounding_box - from compas.itertools import linspace from compas.itertools import pairwise - from compas.tolerance import TOL @@ -202,15 +198,7 @@ def __from_data__(cls, data): return volmesh - def __init__( - self, - default_vertex_attributes=None, - default_edge_attributes=None, - default_face_attributes=None, - default_cell_attributes=None, - name=None, - **kwargs - ): + def __init__(self, default_vertex_attributes=None, default_edge_attributes=None, default_face_attributes=None, default_cell_attributes=None, name=None, **kwargs): # fmt: skip super(VolMesh, self).__init__(kwargs, name=name) self._max_vertex = -1 self._max_face = -1 @@ -443,9 +431,7 @@ def to_vertices_and_cells(self): vertices = [self.vertex_coordinates(vertex) for vertex in self.vertices()] cells = [] for cell in self.cells(): - faces = [ - [vertex_index[vertex] for vertex in self.halfface_vertices(face)] for face in self.cell_faces(cell) - ] + faces = [[vertex_index[vertex] for vertex in self.halfface_vertices(face)] for face in self.cell_faces(cell)] cells.append(faces) return vertices, cells diff --git a/src/compas/files/_xml/xml_cli.py b/src/compas/files/_xml/xml_cli.py index c9094f58f6a..11c9898ae6f 100644 --- a/src/compas/files/_xml/xml_cli.py +++ b/src/compas/files/_xml/xml_cli.py @@ -41,11 +41,9 @@ from urllib import addinfourl import compas - from compas.files._xml.xml_shared import shared_xml_from_file from compas.files._xml.xml_shared import shared_xml_from_string - if compas.IPY: import clr diff --git a/src/compas/files/_xml/xml_pre_38.py b/src/compas/files/_xml/xml_pre_38.py index cd883fda75a..6771edef6b8 100644 --- a/src/compas/files/_xml/xml_pre_38.py +++ b/src/compas/files/_xml/xml_pre_38.py @@ -3,6 +3,7 @@ from __future__ import print_function import xml.etree.ElementTree as ET + from compas import _iotools from compas.files._xml.xml_cpython import prettify_string # noqa: F401 diff --git a/src/compas/files/gltf/constants.py b/src/compas/files/gltf/constants.py index 55d03c2590a..7ccefd4a3ad 100644 --- a/src/compas/files/gltf/constants.py +++ b/src/compas/files/gltf/constants.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function COMPONENT_TYPE_BYTE = 5120 COMPONENT_TYPE_UNSIGNED_BYTE = 5121 diff --git a/src/compas/files/gltf/data_classes.py b/src/compas/files/gltf/data_classes.py index 558fb6f644a..e7d4855a0db 100644 --- a/src/compas/files/gltf/data_classes.py +++ b/src/compas/files/gltf/data_classes.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function class AlphaMode(object): @@ -30,10 +30,7 @@ def add_extension(self, extension): def extensions_to_data(self, **kwargs): if not self.extensions: return None - return { - key: value.to_data(**kwargs) if hasattr(value, "to_data") else value - for key, value in self.extensions.items() - } + return {key: value.to_data(**kwargs) if hasattr(value, "to_data") else value for key, value in self.extensions.items()} @classmethod def extensions_from_data(cls, data): @@ -488,9 +485,7 @@ def __init__(self, channels, samplers_dict, name=None, extras=None, extensions=N self._sampler_index_by_key = None def to_data(self, samplers_list, node_index_by_key): - channels = [ - channel_data.to_data(node_index_by_key, self._sampler_index_by_key) for channel_data in self.channels - ] + channels = [channel_data.to_data(node_index_by_key, self._sampler_index_by_key) for channel_data in self.channels] animation_dict = { "channels": channels, "samplers": samplers_list, diff --git a/src/compas/files/gltf/extensions.py b/src/compas/files/gltf/extensions.py index 0064849f942..a53c25d6da1 100644 --- a/src/compas/files/gltf/extensions.py +++ b/src/compas/files/gltf/extensions.py @@ -1,6 +1,6 @@ from .data_classes import BaseGLTFDataClass -from .data_classes import TextureInfoData from .data_classes import NormalTextureInfoData +from .data_classes import TextureInfoData def create_if_data(cls, data, attr): diff --git a/src/compas/files/gltf/gltf.py b/src/compas/files/gltf/gltf.py index 4caec55fbec..5ca2c61331d 100644 --- a/src/compas/files/gltf/gltf.py +++ b/src/compas/files/gltf/gltf.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function from compas.files.gltf.gltf_exporter import GLTFExporter from compas.files.gltf.gltf_parser import GLTFParser diff --git a/src/compas/files/gltf/gltf_children.py b/src/compas/files/gltf/gltf_children.py index 90ffb63b2a9..32e3527a8a5 100644 --- a/src/compas/files/gltf/gltf_children.py +++ b/src/compas/files/gltf/gltf_children.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function class GLTFChildren(object): diff --git a/src/compas/files/gltf/gltf_content.py b/src/compas/files/gltf/gltf_content.py index 5da98eeab19..94b655b7acf 100644 --- a/src/compas/files/gltf/gltf_content.py +++ b/src/compas/files/gltf/gltf_content.py @@ -134,9 +134,7 @@ def visit_node(key): animation.channels.remove(channel) else: visited_sampler_keys.append(channel.sampler) - animation.samplers_dict = { - key: animation.samplers_dict[key] for key in animation.samplers_dict if key in visited_sampler_keys - } + animation.samplers_dict = {key: animation.samplers_dict[key] for key in animation.samplers_dict if key in visited_sampler_keys} if not animation.samplers_dict: del self.animations[animation_key] diff --git a/src/compas/files/gltf/gltf_exporter.py b/src/compas/files/gltf/gltf_exporter.py index 24b847f4256..ddf5c9f4997 100644 --- a/src/compas/files/gltf/gltf_exporter.py +++ b/src/compas/files/gltf/gltf_exporter.py @@ -1,13 +1,13 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function import array import base64 import json import os -import struct import shutil +import struct from compas.files.gltf.constants import COMPONENT_TYPE_ENUM from compas.files.gltf.constants import COMPONENT_TYPE_FLOAT @@ -21,7 +21,6 @@ from compas.files.gltf.constants import TYPE_VEC4 from compas.files.gltf.data_classes import BaseGLTFDataClass - # This fails on IronPython 2.7.8 (eg. Rhino 6 on Windows) # but works on IronPython 2.7.9 (Rhino 6 on Mac) try: @@ -179,9 +178,7 @@ def _add_extensions_recursively(self, item): self._add_extensions_recursively(getattr(item, a)) if item.extensions is not None: for ek, e in item.extensions.items(): - if ( - self._content.extensions_used is None - ): # attention: self._content.extension exists if we have general extensions. + if self._content.extensions_used is None: # attention: self._content.extension exists if we have general extensions. self._content.extensions_used = [] if ek not in self._content.extensions_used: self._content.extensions_used.append(ek) @@ -208,12 +205,7 @@ def _add_images(self): def _construct_image_data_uri(self, image_data): if image_data.data is None: return None - return ( - "data:" - + (image_data.mime_type if image_data.mime_type else "") - + ";base64," - + base64.b64encode(image_data.data).decode("ascii") - ) + return "data:" + (image_data.mime_type if image_data.mime_type else "") + ";base64," + base64.b64encode(image_data.data).decode("ascii") def _add_extensions(self): if not self._content.extensions_used: @@ -234,9 +226,7 @@ def _add_textures(self): return textures_list = [None] * len(self._content.textures) for key, texture_data in self._content.textures.items(): - textures_list[self._texture_index_by_key[key]] = texture_data.to_data( - self._sampler_index_by_key, self._image_index_by_key - ) + textures_list[self._texture_index_by_key[key]] = texture_data.to_data(self._sampler_index_by_key, self._image_index_by_key) self._add_extensions_recursively(texture_data) self._gltf_dict["textures"] = textures_list @@ -354,9 +344,7 @@ def _add_nodes(self): def _construct_primitives(self, mesh_data): primitives = [] for primitive_data in mesh_data.primitive_data_list: - indices_accessor = self._construct_accessor( - primitive_data.indices, COMPONENT_TYPE_UNSIGNED_SHORT, TYPE_SCALAR - ) + indices_accessor = self._construct_accessor(primitive_data.indices, COMPONENT_TYPE_UNSIGNED_SHORT, TYPE_SCALAR) attributes = {} for attr in primitive_data.attributes: @@ -366,9 +354,7 @@ def _construct_primitives(self, mesh_data): type_ = TYPE_VEC4 if len(primitive_data.attributes[attr][0]) == 2: type_ = TYPE_VEC2 - attributes[attr] = self._construct_accessor( - primitive_data.attributes[attr], component_type, type_, True - ) + attributes[attr] = self._construct_accessor(primitive_data.attributes[attr], component_type, type_, True) targets = [] for target in primitive_data.targets or []: diff --git a/src/compas/files/gltf/gltf_mesh.py b/src/compas/files/gltf/gltf_mesh.py index 1ec4619b0f2..9a1a2635d3b 100644 --- a/src/compas/files/gltf/gltf_mesh.py +++ b/src/compas/files/gltf/gltf_mesh.py @@ -1,14 +1,14 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function import itertools from compas.files.gltf.constants import VERTEX_COUNT_BY_MODE from compas.files.gltf.data_classes import PrimitiveData -from compas.files.gltf.helpers import get_weighted_mesh_vertices -from compas.files.gltf.helpers import get_unweighted_primitive_vertices from compas.files.gltf.helpers import get_mode +from compas.files.gltf.helpers import get_unweighted_primitive_vertices +from compas.files.gltf.helpers import get_weighted_mesh_vertices class GLTFMesh(object): diff --git a/src/compas/files/gltf/gltf_node.py b/src/compas/files/gltf/gltf_node.py index 13698f63990..78446abfbf7 100644 --- a/src/compas/files/gltf/gltf_node.py +++ b/src/compas/files/gltf/gltf_node.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function from math import fabs @@ -162,10 +162,7 @@ def rotation(self, value): if self._matrix: raise Exception("Cannot set rotation when matrix is set.") if not isinstance(value, list) or len(value) != 4 or fabs(sum([q**2 for q in value]) - 1) > 1e-03: - raise Exception( - "Invalid rotation. Rotations are expected to be given as " - "unit quaternions of the form [q1, q2, q3, q4]" - ) + raise Exception("Invalid rotation. Rotations are expected to be given as " "unit quaternions of the form [q1, q2, q3, q4]") self._rotation = value @property @@ -202,8 +199,7 @@ def matrix(self, value): raise Exception("Invalid matrix. A 4x4 matrix is expected.") if value[3] != [0, 0, 0, 1]: raise Exception( - "Invalid matrix. A matrix without shear or skew is expected. It must be of " - "the form TRS, where T is a translation, R is a rotation and S is a scaling." + "Invalid matrix. A matrix without shear or skew is expected. It must be of " "the form TRS, where T is a translation, R is a rotation and S is a scaling." ) self._matrix = value diff --git a/src/compas/files/gltf/gltf_parser.py b/src/compas/files/gltf/gltf_parser.py index e1b7fcde995..bb5881f148d 100644 --- a/src/compas/files/gltf/gltf_parser.py +++ b/src/compas/files/gltf/gltf_parser.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function from compas.files.gltf.data_classes import AnimationData from compas.files.gltf.data_classes import AnimationSamplerData @@ -42,26 +42,12 @@ def parse(self): self.content.extensions = self._get_extensions() self.content.images = {key: image_data for key, image_data in enumerate(self.reader.image_data)} - self.content.samplers = { - key: SamplerData.from_data(sampler) for key, sampler in enumerate(self.reader.json.get("samplers", [])) - } - self.content.textures = { - key: TextureData.from_data(texture) for key, texture in enumerate(self.reader.json.get("textures", [])) - } - self.content.materials = { - key: MaterialData.from_data(material) for key, material in enumerate(self.reader.json.get("materials", [])) - } - self.content.cameras = { - key: CameraData.from_data(camera) for key, camera in enumerate(self.reader.json.get("cameras", [])) - } - self.content.skins = { - key: SkinData.from_data(skin, self.reader.data[skin["inverseBindMatrices"]]) - for key, skin in enumerate(self.reader.json.get("skins", [])) - } - self.content.animations = { - key: self._get_animation_data(animation) - for key, animation in enumerate(self.reader.json.get("animations", [])) - } + self.content.samplers = {key: SamplerData.from_data(sampler) for key, sampler in enumerate(self.reader.json.get("samplers", []))} + self.content.textures = {key: TextureData.from_data(texture) for key, texture in enumerate(self.reader.json.get("textures", []))} + self.content.materials = {key: MaterialData.from_data(material) for key, material in enumerate(self.reader.json.get("materials", []))} + self.content.cameras = {key: CameraData.from_data(camera) for key, camera in enumerate(self.reader.json.get("cameras", []))} + self.content.skins = {key: SkinData.from_data(skin, self.reader.data[skin["inverseBindMatrices"]]) for key, skin in enumerate(self.reader.json.get("skins", []))} + self.content.animations = {key: self._get_animation_data(animation) for key, animation in enumerate(self.reader.json.get("animations", []))} for mesh in self.reader.json.get("meshes", []): self._add_gltf_mesh(mesh) diff --git a/src/compas/files/gltf/gltf_reader.py b/src/compas/files/gltf/gltf_reader.py index c05ecb833e5..6dd4a4a6ee2 100644 --- a/src/compas/files/gltf/gltf_reader.py +++ b/src/compas/files/gltf/gltf_reader.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function import base64 import json @@ -238,10 +238,7 @@ def _read_from_buffer_view(self, buffer_view_index, count, component_type, acces buffer_index = buffer_view["buffer"] buffer = self._get_buffer(buffer_index) - data = [ - unpack_from(buffer[i : i + byte_stride].tobytes()) - for i in range(offset, offset + count * byte_stride, byte_stride) - ] # noqa E203 + data = [unpack_from(buffer[i : i + byte_stride].tobytes()) for i in range(offset, offset + count * byte_stride, byte_stride)] # noqa E203 if num_components == 1: data = [item[0] for item in data] # unwrap scalars from tuple diff --git a/src/compas/files/gltf/gltf_scene.py b/src/compas/files/gltf/gltf_scene.py index 215baed5476..cd1556d8908 100644 --- a/src/compas/files/gltf/gltf_scene.py +++ b/src/compas/files/gltf/gltf_scene.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function from compas.files.gltf.gltf_children import GLTFChildren diff --git a/src/compas/files/gltf/helpers.py b/src/compas/files/gltf/helpers.py index 5acbb644fbe..399e923b838 100644 --- a/src/compas/files/gltf/helpers.py +++ b/src/compas/files/gltf/helpers.py @@ -1,6 +1,6 @@ -from __future__ import print_function -from __future__ import division from __future__ import absolute_import +from __future__ import division +from __future__ import print_function import itertools import math diff --git a/src/compas/files/off.py b/src/compas/files/off.py index 65a7e279010..96b457a433c 100644 --- a/src/compas/files/off.py +++ b/src/compas/files/off.py @@ -254,9 +254,7 @@ def __init__(self, filepath, mesh, author=None, email=None, date=None, precision self.email = email self.date = date self.precision = precision or compas.PRECISION - self.vertex_tpl = ( - "{0:." + self.precision + "}" + " {1:." + self.precision + "}" + " {2:." + self.precision + "}\n" - ) + self.vertex_tpl = "{0:." + self.precision + "}" + " {1:." + self.precision + "}" + " {2:." + self.precision + "}\n" self.v = mesh.number_of_vertices() self.f = mesh.number_of_faces() self.e = mesh.number_of_edges() diff --git a/src/compas/files/ply.py b/src/compas/files/ply.py index cc6a155eaf2..286d77d4135 100644 --- a/src/compas/files/ply.py +++ b/src/compas/files/ply.py @@ -648,9 +648,7 @@ def __init__(self, filepath, mesh, author=None, email=None, date=None, precision self.email = email self.date = date self.precision = precision or compas.PRECISION - self.vertex_tpl = ( - "{0:." + self.precision + "}" + " {1:." + self.precision + "}" + " {2:." + self.precision + "}\n" - ) + self.vertex_tpl = "{0:." + self.precision + "}" + " {1:." + self.precision + "}" + " {2:." + self.precision + "}\n" self.v = mesh.number_of_vertices() self.f = mesh.number_of_faces() self.e = mesh.number_of_edges() diff --git a/src/compas/files/stl.py b/src/compas/files/stl.py index 3f4d9658a6e..eaf2a4b88ee 100644 --- a/src/compas/files/stl.py +++ b/src/compas/files/stl.py @@ -3,6 +3,7 @@ from __future__ import print_function import struct + from compas import _iotools from compas.geometry import Translation from compas.tolerance import TOL diff --git a/src/compas/geometry/_core/_algebra.py b/src/compas/geometry/_core/_algebra.py index cf040bf6124..51bbeb87b38 100644 --- a/src/compas/geometry/_core/_algebra.py +++ b/src/compas/geometry/_core/_algebra.py @@ -1,11 +1,19 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from copy import deepcopy -from math import acos, atan2, asin, cos, fabs, pi, sin, sqrt, tan -from compas.tolerance import TOL +from math import acos +from math import asin +from math import atan2 +from math import cos +from math import fabs +from math import pi +from math import sin +from math import sqrt +from math import tan +from compas.tolerance import TOL _SPEC2TUPLE = { "sxyz": (0, 0, 0, 0), @@ -2033,10 +2041,7 @@ def axis_and_angle_from_matrix(M): eps2 = 0.1 # margin to distinguish between 0 and 180 degrees if all(fabs(M[i][j] - M[j][i]) < eps for i, j in [(0, 1), (0, 2), (1, 2)]): - if ( - all(fabs(M[i][j] - M[j][i]) < eps2 for i, j in [(0, 1), (0, 2), (1, 2)]) - and fabs(M[0][0] + M[1][1] + M[2][2] - 3) < eps2 - ): + if all(fabs(M[i][j] - M[j][i]) < eps2 for i, j in [(0, 1), (0, 2), (1, 2)]) and fabs(M[0][0] + M[1][1] + M[2][2] - 3) < eps2: return [0, 0, 0], 0 angle = pi @@ -2068,11 +2073,7 @@ def axis_and_angle_from_matrix(M): return axis, angle - s = sqrt( - (M[2][1] - M[1][2]) * (M[2][1] - M[1][2]) - + (M[0][2] - M[2][0]) * (M[0][2] - M[2][0]) - + (M[1][0] - M[0][1]) * (M[1][0] - M[0][1]) - ) + s = sqrt((M[2][1] - M[1][2]) * (M[2][1] - M[1][2]) + (M[0][2] - M[2][0]) * (M[0][2] - M[2][0]) + (M[1][0] - M[0][1]) * (M[1][0] - M[0][1])) # should this also be an eps? if fabs(s) < 0.001: @@ -2346,7 +2347,7 @@ def matrix_from_orthogonal_projection(plane): Parameters ---------- - plane : [point, normal] | :class:`compas.geometry.Plane` + plane : [point, normal] The plane to project onto. Returns @@ -2379,7 +2380,7 @@ def matrix_from_parallel_projection(plane, direction): Parameters ---------- - plane : [point, normal] | :class:`compas.geometry.Plane` + plane : [point, normal] The plane to project onto. direction : [float, float, float] | :class:`compas.geometry.Vector` Direction of the projection. @@ -2416,7 +2417,7 @@ def matrix_from_perspective_projection(plane, center_of_projection): Parameters ---------- - plane : [point, normal] | :class:`compas.geometry.Plane` + plane : [point, normal] The plane to project onto. center_of_projection : [float, float, float] | :class:`compas.geometry.Point` The camera view point. diff --git a/src/compas/geometry/_core/angles.py b/src/compas/geometry/_core/angles.py index 8479390634d..eba2084b892 100644 --- a/src/compas/geometry/_core/angles.py +++ b/src/compas/geometry/_core/angles.py @@ -1,20 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import pi -from math import degrees from math import acos +from math import degrees +from math import pi from compas.tolerance import TOL -from ._algebra import subtract_vectors -from ._algebra import subtract_vectors_xy +from ._algebra import cross_vectors from ._algebra import dot_vectors from ._algebra import dot_vectors_xy from ._algebra import length_vector from ._algebra import length_vector_xy -from ._algebra import cross_vectors +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy def angle_vectors(u, v, deg=False, tol=None): @@ -384,9 +384,9 @@ def angle_planes(a, b, deg=False): Parameters ---------- - a : [point, vector] | :class:`compas.geometry.Plane` + a : [point, vector] The first plane. - b : [point, vector] | :class:`compas.geometry.Plane` + b : [point, vector] The second plane. deg : bool, optional If True, returns the angle in degrees. diff --git a/src/compas/geometry/_core/centroids.py b/src/compas/geometry/_core/centroids.py index fee4229b2cb..41cf250ce20 100644 --- a/src/compas/geometry/_core/centroids.py +++ b/src/compas/geometry/_core/centroids.py @@ -7,14 +7,14 @@ from compas.itertools import pairwise from ._algebra import add_vectors -from ._algebra import subtract_vectors -from ._algebra import subtract_vectors_xy -from ._algebra import length_vector -from ._algebra import length_vector_xy -from ._algebra import dot_vectors from ._algebra import cross_vectors from ._algebra import cross_vectors_xy +from ._algebra import dot_vectors +from ._algebra import length_vector +from ._algebra import length_vector_xy from ._algebra import scale_vector +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy from ._algebra import sum_vectors diff --git a/src/compas/geometry/_core/distance.py b/src/compas/geometry/_core/distance.py index ac5fc5fab2e..6fa1a1e9bc8 100644 --- a/src/compas/geometry/_core/distance.py +++ b/src/compas/geometry/_core/distance.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import fabs from math import sqrt @@ -10,17 +10,17 @@ from ._algebra import add_vectors from ._algebra import add_vectors_xy -from ._algebra import subtract_vectors -from ._algebra import subtract_vectors_xy -from ._algebra import scale_vector -from ._algebra import normalize_vector -from ._algebra import length_vector -from ._algebra import length_vector_xy -from ._algebra import length_vector_sqrd -from ._algebra import length_vector_sqrd_xy from ._algebra import cross_vectors from ._algebra import cross_vectors_xy from ._algebra import dot_vectors +from ._algebra import length_vector +from ._algebra import length_vector_sqrd +from ._algebra import length_vector_sqrd_xy +from ._algebra import length_vector_xy +from ._algebra import normalize_vector +from ._algebra import scale_vector +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy from ._algebra import vector_component from ._algebra import vector_component_xy @@ -298,7 +298,7 @@ def distance_point_plane(point, plane): ---------- point : [float, float, float] | :class:`compas.geometry.Point` Point coordinates. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] A point and a vector defining a plane. Returns @@ -353,7 +353,7 @@ def distance_point_plane_signed(point, plane): ---------- point : [float, float, float] | :class:`compas.geometry.Point` Point coordinates. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] A point and a vector defining a plane. Returns @@ -592,9 +592,9 @@ def closest_points_in_cloud_numpy(points, cloud, threshold=10**7, distances=True True """ - from numpy import asarray from numpy import argmin from numpy import argpartition + from numpy import asarray from scipy.spatial import distance_matrix points = asarray(points).reshape((-1, 3)) @@ -838,7 +838,7 @@ def closest_point_on_plane(point, plane): ---------- point : [float, float, float] | :class:`compas.geometry.Point` XYZ coordinates of point. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] The base point and normal defining the plane. Returns diff --git a/src/compas/geometry/_core/normals.py b/src/compas/geometry/_core/normals.py index 961c0190b30..6c62f9d7894 100644 --- a/src/compas/geometry/_core/normals.py +++ b/src/compas/geometry/_core/normals.py @@ -1,14 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from ._algebra import subtract_vectors -from ._algebra import subtract_vectors_xy from ._algebra import cross_vectors from ._algebra import cross_vectors_xy from ._algebra import length_vector from ._algebra import normalize_vector - +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy from .centroids import centroid_points diff --git a/src/compas/geometry/_core/predicates_2.py b/src/compas/geometry/_core/predicates_2.py index 7cb346573f3..da834efc1b8 100644 --- a/src/compas/geometry/_core/predicates_2.py +++ b/src/compas/geometry/_core/predicates_2.py @@ -1,13 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.tolerance import TOL - -from compas.geometry import distance_point_point_xy -from compas.geometry import distance_point_line_xy from compas.geometry import closest_point_on_segment_xy - +from compas.geometry import distance_point_line_xy +from compas.geometry import distance_point_point_xy +from compas.tolerance import TOL # ============================================================================= # ============================================================================= @@ -453,7 +451,7 @@ def is_point_in_circle_xy(point, circle): ---------- point : [float, float, float] | :class:`compas.geometry.Point` XY(Z) coordinates of a point (Z will be ignored). - circle : [[point, vector], float] | :class:`compas.geometry.Circle` + circle : [[point, vector], float] Center and radius of the circle on the XY plane. Returns diff --git a/src/compas/geometry/_core/predicates_3.py b/src/compas/geometry/_core/predicates_3.py index b8722422deb..4e7eb851c5e 100644 --- a/src/compas/geometry/_core/predicates_3.py +++ b/src/compas/geometry/_core/predicates_3.py @@ -1,24 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.tolerance import TOL - -from compas.utilities import window - -from compas.geometry import subtract_vectors +from compas.geometry import area_triangle +from compas.geometry import centroid_points +from compas.geometry import closest_point_on_segment from compas.geometry import cross_vectors +from compas.geometry import distance_point_line +from compas.geometry import distance_point_plane +from compas.geometry import distance_point_point from compas.geometry import dot_vectors -from compas.geometry import centroid_points -from compas.geometry import normal_polygon -from compas.geometry import area_triangle from compas.geometry import length_vector - -from compas.geometry import distance_point_point -from compas.geometry import distance_point_plane -from compas.geometry import distance_point_line -from compas.geometry import closest_point_on_segment - +from compas.geometry import normal_polygon +from compas.geometry import subtract_vectors +from compas.itertools import window +from compas.tolerance import TOL # ============================================================================= # ============================================================================= @@ -130,7 +126,7 @@ def is_coplanar(points, tol=None): temp = points[:] - while True: + while len(temp) >= 3: a = temp.pop(0) b = temp.pop(0) c = temp.pop(0) @@ -241,9 +237,9 @@ def is_parallel_plane_plane(plane1, plane2, tol=None): Parameters ---------- - plane1 : [point, vector] | :class:`compas.geometry.Plane` + plane1 : [point, vector] Plane 1. - plane2 : [point, vector] | :class:`compas.geometry.Plane` + plane2 : [point, vector] Plane 2. tol : float, optional A tolerance for verifying parallelity of the plane normals. @@ -337,9 +333,9 @@ def is_perpendicular_plane_plane(plane1, plane2, tol=None): Parameters ---------- - plane1 : [point, vector] | :class:`compas.geometry.Plane` + plane1 : [point, vector] Plane 1. - plane2 : [point, vector] | :class:`compas.geometry.Plane` + plane2 : [point, vector] Plane 2. tol : float, optional A tolerance for verifying perpendicularity of the plane normals. @@ -429,7 +425,7 @@ def is_polyhedron_convex(polyhedron): Parameters ---------- - polyhedron : [sequence[point], sequence[sequence[int]]] | :class:`compas.geometry.Polyhedron` + polyhedron : [sequence[point], sequence[sequence[int]]] A polyhedron defined by a sequence of points and a sequence of faces, with each face defined as a sequence of indices into the sequence of points. @@ -484,7 +480,7 @@ def is_point_on_plane(point, plane, tol=None): ---------- point : [float, float, float] | :class:`compas.geometry.Point` A point. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] A plane. tol : float, optional Tolerance for comparing the distance between the point and the plane to zero. @@ -724,11 +720,7 @@ def is_on_same_side(p1, p2, segment): a, b, c = triangle if is_point_on_plane(point, (a, normal_polygon(triangle)), tol=tol): - if ( - is_on_same_side(point, a, (b, c)) - and is_on_same_side(point, b, (a, c)) - and is_on_same_side(point, c, (a, b)) - ): + if is_on_same_side(point, a, (b, c)) and is_on_same_side(point, b, (a, c)) and is_on_same_side(point, c, (a, b)): return True return False @@ -820,7 +812,7 @@ def is_point_in_polyhedron(point, polyhedron, tol=None): ---------- point : [float, float, float] | :class:`compas.geometry.Point` The test point. - polyhedron : [sequence[point], sequence[sequence[int]]] | :class:`compas.geometry.Polyhedron`. + polyhedron : [sequence[point], sequence[sequence[int]]] The polyhedron defined by a sequence of points and a sequence of faces, with each face defined as a sequence of indices into the sequence of points. @@ -844,7 +836,7 @@ def is_point_infrontof_plane(point, plane, tol=None): ---------- point : [float, float, float] | :class:`compas.geometry.Point` A point. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] A plane. tol : float, optional A tolerance for membership verification. @@ -866,7 +858,7 @@ def is_point_behind_plane(point, plane, tol=None): ---------- point : [float, float, float] | :class:`compas.geometry.Point` A point. - plane : [point, normal] | :class:`compas.geometry.Plane` + plane : [point, normal] A plane. tol : float, optional A tolerance for membership verification. @@ -1033,7 +1025,7 @@ def is_point_behind_plane(point, plane, tol=None): # ---------- # line : [point, point] | :class:`compas.geometry.Line` # A line. -# plane : [point, vector] | :class:`compas.geometry.Plane` +# plane : [point, vector] # A plane. # tol : float, optional # A tolerance for intersection verification. @@ -1064,7 +1056,7 @@ def is_point_behind_plane(point, plane, tol=None): # ---------- # segment : [point, point] | :class:`compas.geometry.Line` # A line segment. -# plane : [point, vector] | :class:`compas.geometry.Plane` +# plane : [point, vector] # A plane. # tol : float, optional # A tolerance for intersection verification. @@ -1099,9 +1091,9 @@ def is_point_behind_plane(point, plane, tol=None): # Parameters # ---------- -# plane1 : [point, vector] | :class:`compas.geometry.Plane` +# plane1 : [point, vector] # A plane. -# plane2 : [point, vector] | :class:`compas.geometry.Plane` +# plane2 : [point, vector] # A plane. # tol : float, optional # A tolerance for intersection verification. diff --git a/src/compas/geometry/_core/quaternions.py b/src/compas/geometry/_core/quaternions.py index 53e899f4a6c..8283bbac952 100644 --- a/src/compas/geometry/_core/quaternions.py +++ b/src/compas/geometry/_core/quaternions.py @@ -1,4 +1,5 @@ import math + from compas.tolerance import TOL diff --git a/src/compas/geometry/_core/size.py b/src/compas/geometry/_core/size.py index cd910c30d57..b7370590383 100644 --- a/src/compas/geometry/_core/size.py +++ b/src/compas/geometry/_core/size.py @@ -1,21 +1,19 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import fabs from compas.itertools import pairwise -from ._algebra import subtract_vectors -from ._algebra import subtract_vectors_xy -from ._algebra import length_vector from ._algebra import cross_vectors from ._algebra import cross_vectors_xy from ._algebra import dot_vectors - +from ._algebra import length_vector +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy from .centroids import centroid_points from .centroids import centroid_points_xy - from .normals import normal_triangle from .normals import normal_triangle_xy diff --git a/src/compas/geometry/_core/tangent.py b/src/compas/geometry/_core/tangent.py index 6db30a2cd3c..9e45db1f06f 100644 --- a/src/compas/geometry/_core/tangent.py +++ b/src/compas/geometry/_core/tangent.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import sqrt @@ -10,7 +10,7 @@ def tangent_points_to_circle_xy(circle, point): Parameters ---------- - circle : [plane, float] | :class:`compas.geometry.Circle` + circle : [plane, float] Plane and radius of the circle. point : [float, float] or [float, float, float] | :class:`compas.geometry.Point` XY(Z) coordinates of a point in the xy plane. @@ -22,13 +22,13 @@ def tangent_points_to_circle_xy(circle, point): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> circle = ((0, 0, 0), (0, 0, 1)), 1.0 >>> point = (2, 4, 0) >>> t1, t2 = tangent_points_to_circle_xy(circle, point) - >>> allclose(t1, [-0.772, 0.636, 0.000], 1e-3) + >>> TOL.is_allclose(t1, [-0.772, 0.636, 0.000], atol=1e-3) True - >>> allclose(t2, [0.972, -0.236, 0.000], 1e-3) + >>> TOL.is_allclose(t2, [0.972, -0.236, 0.000], atol=1e-3) True """ diff --git a/src/compas/geometry/_core/transformations.py b/src/compas/geometry/_core/transformations.py index 3c3308300ca..dc84673631a 100644 --- a/src/compas/geometry/_core/transformations.py +++ b/src/compas/geometry/_core/transformations.py @@ -1,32 +1,31 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import math -from ._algebra import scale_vector -from ._algebra import scale_vector_xy -from ._algebra import normalize_vector from ._algebra import add_vectors from ._algebra import add_vectors_xy +from ._algebra import cross_vectors +from ._algebra import dot_vectors +from ._algebra import matrix_from_axis_and_angle +from ._algebra import matrix_from_change_of_basis +from ._algebra import matrix_from_scale_factors +from ._algebra import multiply_matrices +from ._algebra import multiply_matrix_vector +from ._algebra import norm_vector +from ._algebra import normalize_vector +from ._algebra import scale_vector +from ._algebra import scale_vector_xy from ._algebra import subtract_vectors from ._algebra import subtract_vectors_xy -from ._algebra import dot_vectors -from ._algebra import cross_vectors +from ._algebra import transpose_matrix from ._algebra import vector_component from ._algebra import vector_component_xy -from ._algebra import multiply_matrix_vector -from ._algebra import multiply_matrices -from ._algebra import transpose_matrix -from ._algebra import norm_vector -from ._algebra import matrix_from_axis_and_angle -from ._algebra import matrix_from_scale_factors -from ._algebra import matrix_from_change_of_basis - from .angles import angle_vectors -from .distance import closest_point_on_plane from .distance import closest_point_on_line from .distance import closest_point_on_line_xy +from .distance import closest_point_on_plane # this function will not always work @@ -63,13 +62,13 @@ def orthonormalize_axes(xaxis, yaxis): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> xaxis = [1, 4, 5] >>> yaxis = [1, 0, -2] >>> xaxis, yaxis = orthonormalize_axes(xaxis, yaxis) - >>> allclose(xaxis, [0.1543, 0.6172, 0.7715], tol=0.001) + >>> TOL.is_allclose(xaxis, [0.1543, 0.6172, 0.7715], atol=0.001) True - >>> allclose(yaxis, [0.6929, 0.4891, -0.5298], tol=0.001) + >>> TOL.is_allclose(yaxis, [0.6929, 0.4891, -0.5298], atol=0.001) True """ @@ -140,7 +139,7 @@ def homogenize_and_flatten_frames(frames): Parameters ---------- - frames : sequence[[point, vector, vector] | :class:`compas.geometry.Frame`] + frames : sequence[[point, vector, vector]] Returns ------- @@ -246,7 +245,7 @@ def transform_frames(frames, T): Parameters ---------- - frames : sequence[[point, vector, vector] | :class:`compas.geometry.Frame`] + frames : sequence[[point, vector, vector]] A list of frames to be transformed. T : list[list[float]] | :class:`compas.geometry.Transformation` The transformation to apply on the frames. @@ -273,7 +272,7 @@ def world_to_local_coordinates(frame, xyz): Parameters ---------- - frame : [point, vector, vector] | :class:`compas.geometry.Frame` + frame : [point, vector, vector] The local coordinate system. xyz : array-like[[float, float, float] | :class:`compas.geometry.Point`] The global coordinates of the points to convert. @@ -303,7 +302,7 @@ def local_to_world_coordinates(frame, xyz): Parameters ---------- - frame : [point, vector, vector] | :class:`compas.geometry.Frame` + frame : [point, vector, vector] The local coordinate system. xyz : array-like[[float, float, float] | :class:`compas.geometry.Point`] The global coordinates of the points to convert. @@ -715,7 +714,7 @@ def mirror_point_plane(point, plane): ---------- point : list[float] XYZ coordinates of mirror point. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Base point and normal defining the mirror plane. Returns @@ -735,7 +734,7 @@ def mirror_points_plane(points, plane): ---------- points : sequence[[float, float, float] | :class:`compas.geometry.Point`] List of points to mirror. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Base point and normal defining the mirror plane. Returns @@ -761,7 +760,7 @@ def project_point_plane(point, plane): ---------- point : [float, float, float] | :class:`compas.geometry.Point` XYZ coordinates of the point. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Base point and normal vector defining the projection plane. Returns @@ -803,7 +802,7 @@ def project_points_plane(points, plane): ---------- points : sequence[[float, float, float] | :class:`compas.geometry.Point`] List of points. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Base point and normal vector defining the projection plane. Returns @@ -952,7 +951,7 @@ def reflect_line_plane(line, plane, tol=None): ---------- line : [point, point] | :class:`compas.geometry.Line` Two points defining the line. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Base point and normal vector of the plane. tol : float, optional A tolerance for finding the intersection between the line and the plane. @@ -1067,11 +1066,11 @@ def orient_points(points, reference_plane, target_plane): Parameters ---------- - points : sequence[[float, float, float] | :class:`compas.geometry.Point`]s + points : sequence[[float, float, float] | :class:`compas.geometry.Point`] XYZ coordinates of the points. - reference_plane : [point, vector] | :class:`compas.geometry.Plane` + reference_plane : [point, vector] Base point and normal defining a reference plane. - target_plane : [point, vector] | :class:`compas.geometry.Plane` + target_plane : [point, vector] Base point and normal defining a target plane. Returns diff --git a/src/compas/geometry/_core/transformations_numpy.py b/src/compas/geometry/_core/transformations_numpy.py index 972fd892d41..6d0813b5445 100644 --- a/src/compas/geometry/_core/transformations_numpy.py +++ b/src/compas/geometry/_core/transformations_numpy.py @@ -1,9 +1,8 @@ from numpy import asarray from numpy import hstack from numpy import ones -from numpy import vectorize from numpy import tile - +from numpy import vectorize from scipy.linalg import solve # type: ignore from ._algebra import cross_vectors @@ -70,7 +69,7 @@ def transform_frames_numpy(frames, T): Parameters ---------- - frames : sequence[[point, vector, vector] | :class:`compas.geometry.Frame`] + frames : sequence[[point, vector, vector]] A list of frames to be transformed. T : :class:`compas.geometry.Transformation` The transformation to apply on the frames. @@ -98,7 +97,7 @@ def world_to_local_coordinates_numpy(frame, xyz): Parameters ---------- - frame : [point, vector, vector] | :class:`compas.geometry.Frame` + frame : [point, vector, vector] The local coordinate system. xyz : array-like[[float, float, float] | :class:`compas.geometry.Point`] The global coordinates of the points to convert. @@ -131,7 +130,7 @@ def local_to_world_coordinates_numpy(frame, rst): Parameters ---------- - frame : [point, vector, vector] | :class:`compas.geometry.Frame` + frame : [point, vector, vector] The local coordinate system. rst : array-like[[float, float, float] | :class:`compas.geometry.Point`] The coordinates of the points wrt the local coordinate system. @@ -232,7 +231,7 @@ def homogenize_and_flatten_frames_numpy(frames): Parameters ---------- - frames : array_like[[point, vector, vector] | :class:`compas.geometry.Frame`] + frames : array_like[[point, vector, vector]] The input frames. Returns diff --git a/src/compas/geometry/bbox.py b/src/compas/geometry/bbox.py index b1ccc98813f..232f821176e 100644 --- a/src/compas/geometry/bbox.py +++ b/src/compas/geometry/bbox.py @@ -1,8 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from itertools import islice + from compas.plugins import pluggable diff --git a/src/compas/geometry/bbox_numpy.py b/src/compas/geometry/bbox_numpy.py index 7c45141d240..e95ed93e375 100644 --- a/src/compas/geometry/bbox_numpy.py +++ b/src/compas/geometry/bbox_numpy.py @@ -1,22 +1,20 @@ -from numpy import array -from numpy import asarray -from numpy import argmax -from numpy import argmin from numpy import amax from numpy import amin +from numpy import argmax +from numpy import argmin +from numpy import array +from numpy import asarray from numpy import dot from numpy import sum -from numpy import zeros from numpy import vstack - +from numpy import zeros from scipy.spatial import ConvexHull -from compas.tolerance import TOL - -from compas.geometry import pca_numpy from compas.geometry import local_axes -from compas.geometry import world_to_local_coordinates_numpy from compas.geometry import local_to_world_coordinates_numpy +from compas.geometry import pca_numpy +from compas.geometry import world_to_local_coordinates_numpy +from compas.tolerance import TOL from .bbox import bounding_box diff --git a/src/compas/geometry/bestfit.py b/src/compas/geometry/bestfit.py index 84e92a7e0a9..ba4a02c538c 100644 --- a/src/compas/geometry/bestfit.py +++ b/src/compas/geometry/bestfit.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import subtract_vectors -from compas.geometry import normalize_vector from compas.geometry import centroid_points +from compas.geometry import normalize_vector +from compas.geometry import subtract_vectors def bestfit_plane(points): diff --git a/src/compas/geometry/bestfit_numpy.py b/src/compas/geometry/bestfit_numpy.py index cb68064e84a..1317e4ccf4e 100644 --- a/src/compas/geometry/bestfit_numpy.py +++ b/src/compas/geometry/bestfit_numpy.py @@ -4,9 +4,9 @@ from numpy.linalg import lstsq from scipy.optimize import leastsq +from compas.geometry import local_to_world_coordinates_numpy from compas.geometry import pca_numpy from compas.geometry import world_to_local_coordinates_numpy -from compas.geometry import local_to_world_coordinates_numpy def bestfit_line_numpy(points): diff --git a/src/compas/geometry/booleans.py b/src/compas/geometry/booleans.py index 518a012d50d..0a220ddd7ec 100644 --- a/src/compas/geometry/booleans.py +++ b/src/compas/geometry/booleans.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.plugins import pluggable from compas.plugins import PluginNotInstalledError +from compas.plugins import pluggable @pluggable(category="booleans") @@ -57,9 +57,7 @@ def boolean_union_mesh_mesh(A, B): >>> union = Mesh.from_vertices_and_faces(V, F) # doctest: +SKIP """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_union_mesh_mesh pluggable. A plugin is available in compas_cgal..." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_union_mesh_mesh pluggable. A plugin is available in compas_cgal...") boolean_union_mesh_mesh.__pluggable__ = True @@ -94,9 +92,7 @@ def boolean_difference_mesh_mesh(A, B): One such plugin is available in ``compas_cgal``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_difference_mesh_mesh pluggable. A plugin is available in compas_cgal..." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_difference_mesh_mesh pluggable. A plugin is available in compas_cgal...") boolean_difference_mesh_mesh.__pluggable__ = True @@ -131,9 +127,7 @@ def boolean_intersection_mesh_mesh(A, B): One such plugin is available in ``compas_cgal``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_intersection_mesh_mesh pluggable. A plugin is available in compas_cgal..." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_intersection_mesh_mesh pluggable. A plugin is available in compas_cgal...") boolean_intersection_mesh_mesh.__pluggable__ = True @@ -174,9 +168,7 @@ def boolean_union_polygon_polygon(A, B): One such plugin is available through ``shapely``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_union_polygon_polygon pluggable. Installing Shapely should solve the problem." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_union_polygon_polygon pluggable. Installing Shapely should solve the problem.") boolean_union_polygon_polygon.__pluggable__ = True @@ -217,9 +209,7 @@ def boolean_difference_polygon_polygon(A, B): One such plugin is available through ``shapely``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_difference_polygon_polygon pluggable. Installing Shapely should solve the problem." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_difference_polygon_polygon pluggable. Installing Shapely should solve the problem.") boolean_difference_polygon_polygon.__pluggable__ = True @@ -260,9 +250,7 @@ def boolean_symmetric_difference_polygon_polygon(A, B): One such plugin is available through ``shapely``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_symmetric_difference_polygon_polygon pluggable. Installing Shapely should solve the problem." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_symmetric_difference_polygon_polygon pluggable. Installing Shapely should solve the problem.") boolean_symmetric_difference_polygon_polygon.__pluggable__ = True @@ -303,9 +291,7 @@ def boolean_intersection_polygon_polygon(A, B): One such plugin is available through ``shapely``. """ - raise PluginNotInstalledError( - "No plugin was found for the boolean_intersection_polygon_polygon pluggable. Installing Shapely should solve the problem." - ) + raise PluginNotInstalledError("No plugin was found for the boolean_intersection_polygon_polygon pluggable. Installing Shapely should solve the problem.") boolean_intersection_polygon_polygon.__pluggable__ = True diff --git a/src/compas/geometry/booleans_shapely.py b/src/compas/geometry/booleans_shapely.py index dbcd130a086..44d46619c6b 100644 --- a/src/compas/geometry/booleans_shapely.py +++ b/src/compas/geometry/booleans_shapely.py @@ -1,6 +1,7 @@ -from compas.plugins import plugin from shapely.geometry import Polygon +from compas.plugins import plugin + @plugin(category="booleans", requires=["shapely"]) def boolean_union_polygon_polygon(A, B): diff --git a/src/compas/geometry/brep/__init__.py b/src/compas/geometry/brep/__init__.py index 54185d363e2..5abec46e466 100644 --- a/src/compas/geometry/brep/__init__.py +++ b/src/compas/geometry/brep/__init__.py @@ -72,6 +72,11 @@ def from_pipe(*args, **kwargs): raise PluginNotInstalledError +@pluggable(category="factories") +def from_plane(*args, **kwargs): + raise PluginNotInstalledError + + @pluggable(category="factories") def from_planes(*args, **kwargs): raise PluginNotInstalledError diff --git a/src/compas/geometry/brep/brep.py b/src/compas/geometry/brep/brep.py index 5466895fd67..78028ef1236 100644 --- a/src/compas/geometry/brep/brep.py +++ b/src/compas/geometry/brep/brep.py @@ -1,29 +1,27 @@ from compas.geometry import Geometry -from . import new_brep -from . import from_brepfaces +from . import from_boolean_difference +from . import from_boolean_intersection +from . import from_boolean_union from . import from_box -from . import from_cylinder -from . import from_sphere -from . import from_mesh +from . import from_brepfaces from . import from_cone -from . import from_torus +from . import from_curves +from . import from_cylinder from . import from_extrusion from . import from_iges from . import from_loft -from . import from_boolean_difference -from . import from_boolean_intersection -from . import from_boolean_union -from . import from_curves +from . import from_mesh +from . import from_native from . import from_pipe +from . import from_plane from . import from_planes from . import from_polygons +from . import from_sphere from . import from_step from . import from_sweep -from . import from_native - - -LINEAR_DEFLECTION = 1e-3 +from . import from_torus +from . import new_brep class BrepType(object): @@ -489,6 +487,26 @@ def from_pipe(cls, curve, radius, thickness=None): """ return from_pipe(curve, radius, thickness=thickness) + @classmethod + def from_plane(cls, plane, domain_u=(-1, +1), domain_v=(-1, +1)): + """Construct a Brep from one plane and its u and v domains. + + Parameters + ---------- + plane : :class:`~compas.geometry.Plane` + A plane. + domain_u : tuple[float, float], optional + The surface domain in the u direction. + domain_v : tuple[float, float], optional + The surface domain in the v direction. + + Returns + ------- + :class:`compas.geometry.Brep` + + """ + return from_plane(plane, domain_u=domain_u, domain_v=domain_v) + @classmethod def from_planes(cls, planes): """Construct a Brep from a set of planes. @@ -768,7 +786,7 @@ def to_stl(self, filepath): """ raise NotImplementedError - def to_tesselation(self, linear_deflection=LINEAR_DEFLECTION): + def to_tesselation(self, linear_deflection=None): """Create a tesselation of the shape for visualisation. Parameters @@ -1093,7 +1111,7 @@ def split(self, cutter): """ raise NotImplementedError - def overlap(self, other, deflection=LINEAR_DEFLECTION, tolerance=0.0): + def overlap(self, other, deflection=None, tolerance=0.0): """Compute the overlap between this BRep and another. Parameters diff --git a/src/compas/geometry/brep/face.py b/src/compas/geometry/brep/face.py index b313fcb0219..ff9376eec86 100644 --- a/src/compas/geometry/brep/face.py +++ b/src/compas/geometry/brep/face.py @@ -1,5 +1,4 @@ from compas.data import Data - from compas.geometry import Polygon diff --git a/src/compas/geometry/contours.py b/src/compas/geometry/contours.py index 9ed3b1a8cec..2e272d3248c 100644 --- a/src/compas/geometry/contours.py +++ b/src/compas/geometry/contours.py @@ -1,5 +1,5 @@ -from compas.plugins import pluggable from compas.plugins import PluginNotInstalledError +from compas.plugins import pluggable @pluggable(category="contours") diff --git a/src/compas/geometry/curves/arc.py b/src/compas/geometry/curves/arc.py index c044bd324bd..9e61536bb8d 100644 --- a/src/compas/geometry/curves/arc.py +++ b/src/compas/geometry/curves/arc.py @@ -1,14 +1,17 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import pi, cos, sin +from math import cos +from math import pi +from math import sin -from compas.geometry import close +from compas.geometry import Circle +from compas.geometry import Frame from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Frame -from compas.geometry import Circle +from compas.tolerance import TOL + from .curve import Curve PI2 = 2.0 * pi @@ -171,12 +174,7 @@ def __repr__(self): def __eq__(self, other): try: - return ( - self.radius == other.radius - and self.start_angle == other.start - and self.end_angle == other.end - and self.frame == other.frame - ) + return self.radius == other.radius and self.start_angle == other.start and self.end_angle == other.end and self.frame == other.frame except Exception: return False @@ -246,7 +244,7 @@ def circumference(self): @property def is_circle(self): - return close(abs(abs(self.angle) - PI2), 0.0) + return TOL.is_close(abs(self.angle), PI2) @property def is_closed(self): diff --git a/src/compas/geometry/curves/bezier.py b/src/compas/geometry/curves/bezier.py index c06f1608cef..bf3d2e4f67f 100644 --- a/src/compas/geometry/curves/bezier.py +++ b/src/compas/geometry/curves/bezier.py @@ -1,12 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import factorial -from compas.geometry import Vector -from compas.geometry import Point from compas.geometry import Frame +from compas.geometry import Point +from compas.geometry import Vector from .curve import Curve diff --git a/src/compas/geometry/curves/circle.py b/src/compas/geometry/curves/circle.py index f6f8b61af7b..6e24392386b 100644 --- a/src/compas/geometry/curves/circle.py +++ b/src/compas/geometry/curves/circle.py @@ -1,13 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import pi, cos, sin +from math import cos +from math import pi +from math import sin -from compas.geometry import Point -from compas.geometry import Vector from compas.geometry import Frame from compas.geometry import Plane +from compas.geometry import Point +from compas.geometry import Vector + from .conic import Conic PI2 = 2 * pi diff --git a/src/compas/geometry/curves/conic.py b/src/compas/geometry/curves/conic.py index 0240e5bcd03..037cf28a2c8 100644 --- a/src/compas/geometry/curves/conic.py +++ b/src/compas/geometry/curves/conic.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from .curve import Curve diff --git a/src/compas/geometry/curves/curve.py b/src/compas/geometry/curves/curve.py index 3afcec270aa..f952a1bd8b8 100644 --- a/src/compas/geometry/curves/curve.py +++ b/src/compas/geometry/curves/curve.py @@ -1,13 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.plugins import pluggable +from compas.geometry import Frame from compas.geometry import Geometry -from compas.geometry import Transformation from compas.geometry import Plane -from compas.geometry import Frame +from compas.geometry import Transformation from compas.itertools import linspace +from compas.plugins import pluggable @pluggable(category="factories") diff --git a/src/compas/geometry/curves/ellipse.py b/src/compas/geometry/curves/ellipse.py index 6939def940b..554321940b0 100644 --- a/src/compas/geometry/curves/ellipse.py +++ b/src/compas/geometry/curves/ellipse.py @@ -1,12 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import sqrt, pi, cos, sin +from math import cos +from math import pi +from math import sin +from math import sqrt +from compas.geometry import Frame from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Frame + from .conic import Conic from .line import Line diff --git a/src/compas/geometry/curves/hyperbola.py b/src/compas/geometry/curves/hyperbola.py index 7d908f447d2..54f6120f918 100644 --- a/src/compas/geometry/curves/hyperbola.py +++ b/src/compas/geometry/curves/hyperbola.py @@ -1,12 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import cos, sin, sqrt +from math import cos from math import pi +from math import sin +from math import sqrt -from compas.geometry import Point from compas.geometry import Frame +from compas.geometry import Point + from .conic import Conic PI2 = 2 * pi diff --git a/src/compas/geometry/curves/line.py b/src/compas/geometry/curves/line.py index ce1d0875ea9..427d82511a3 100644 --- a/src/compas/geometry/curves/line.py +++ b/src/compas/geometry/curves/line.py @@ -1,11 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import add_vectors +from compas.geometry import Frame from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Frame +from compas.geometry import add_vectors + from .curve import Curve @@ -296,17 +297,19 @@ def transform(self, T): # ========================================================================== def point_at(self, t): - """Construct a point at a specific location along the line. + """Construct a point along the line at a fractional position. Parameters ---------- t : float - The location along the line. + The relative position along the line as a fraction of the length of the line. + 0.0 corresponds to the start point and 1.0 corresponds to the end point. + Numbers outside of this range are also valid and correspond to points beyond the start and end point. Returns ------- :class:`compas.geometry.Point` - The point at the specified location. + The point at the specified position. See Also -------- @@ -322,6 +325,44 @@ def point_at(self, t): point = self.point + self.vector * t return point + def point_from_start(self, distance): + """Construct a point along the line at a distance from the start point. + + Parameters + ---------- + distance : float + The distance along the line from the start point towards the end point. + If the distance is negative, the point is constructed in the opposite direction of the end point. + If the distance is larger than the length of the line, the point is constructed beyond the end point. + + Returns + ------- + :class:`compas.geometry.Point` + The point at the specified distance. + + """ + point = self.point + self.direction * distance + return point + + def point_from_end(self, distance): + """Construct a point along the line at a distance from the end point. + + Parameters + ---------- + distance : float + The distance along the line from the end point towards the start point. + If the distance is negative, the point is constructed in the opposite direction of the start point. + If the distance is larger than the length of the line, the point is constructed beyond the start point. + + Returns + ------- + :class:`compas.geometry.Point` + The point at the specified distance. + + """ + point = self.end - self.direction * distance + return point + def closest_point(self, point, return_parameter=False): """Compute the closest point on the line to a given point. @@ -348,3 +389,43 @@ def closest_point(self, point, return_parameter=False): if return_parameter: return closest, t return closest + + def flip(self): + """Flip the direction of the line. + + Returns + ------- + None + + Examples + -------- + >>> line = Line([0, 0, 0], [1, 2, 3]) + >>> line + Line(Point(x=0.0, y=0.0, z=0.0), Point(x=1.0, y=2.0, z=3.0)) + >>> line.flip() + >>> line + Line(Point(x=1.0, y=2.0, z=3.0), Point(x=0.0, y=0.0, z=0.0)) + + """ + new_vector = self.vector.inverted() + self.start = self.end + self.vector = new_vector + + def flipped(self): + """Return a new line with the direction flipped. + + Returns + ------- + :class:`Line` + A new line. + + Examples + -------- + >>> line = Line([0, 0, 0], [1, 2, 3]) + >>> line + Line(Point(x=0.0, y=0.0, z=0.0), Point(x=1.0, y=2.0, z=3.0)) + >>> line.flipped() + Line(Point(x=1.0, y=2.0, z=3.0), Point(x=0.0, y=0.0, z=0.0)) + + """ + return Line(self.end, self.start) diff --git a/src/compas/geometry/curves/nurbs.py b/src/compas/geometry/curves/nurbs.py index 1c0214d238b..ca4e741629c 100644 --- a/src/compas/geometry/curves/nurbs.py +++ b/src/compas/geometry/curves/nurbs.py @@ -1,13 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import sqrt -from compas.plugins import pluggable -from compas.plugins import PluginNotInstalledError -from compas.geometry import Point from compas.geometry import Frame +from compas.geometry import Point +from compas.plugins import PluginNotInstalledError +from compas.plugins import pluggable from .curve import Curve diff --git a/src/compas/geometry/curves/parabola.py b/src/compas/geometry/curves/parabola.py index 026a8ef4d44..d032e71dfed 100644 --- a/src/compas/geometry/curves/parabola.py +++ b/src/compas/geometry/curves/parabola.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import Vector -from compas.geometry import Point from compas.geometry import Frame -from .line import Line +from compas.geometry import Point +from compas.geometry import Vector + from .conic import Conic +from .line import Line class Parabola(Conic): diff --git a/src/compas/geometry/curves/polyline.py b/src/compas/geometry/curves/polyline.py index 0bec8e6ee78..00e65cea049 100644 --- a/src/compas/geometry/curves/polyline.py +++ b/src/compas/geometry/curves/polyline.py @@ -1,15 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.geometry import Frame +from compas.geometry import Line +from compas.geometry import Point +from compas.geometry import is_point_on_line +from compas.geometry import is_point_on_polyline +from compas.geometry import transform_points from compas.itertools import pairwise +from compas.tolerance import TOL -from compas.geometry import allclose -from compas.geometry import transform_points -from compas.geometry import is_point_on_line, is_point_on_polyline -from compas.geometry import Point -from compas.geometry import Line -from compas.geometry import Frame from .curve import Curve @@ -117,7 +118,7 @@ def __len__(self): def __eq__(self, other): if not hasattr(other, "__iter__") or not hasattr(other, "__len__") or len(self) != len(other): return False - return allclose(self, other) + return TOL.is_allclose(self, other) # ========================================================================== # properties diff --git a/src/compas/geometry/frame.py b/src/compas/geometry/frame.py index 4d60044f422..bc0b4034313 100644 --- a/src/compas/geometry/frame.py +++ b/src/compas/geometry/frame.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.tolerance import TOL - +from compas.geometry import Geometry +from compas.geometry import Transformation from compas.geometry import argmax from compas.geometry import axis_angle_vector_from_matrix from compas.geometry import basis_vectors_from_matrix @@ -16,13 +16,12 @@ from compas.geometry import matrix_from_quaternion from compas.geometry import quaternion_from_matrix from compas.geometry import subtract_vectors +from compas.itertools import linspace +from compas.tolerance import TOL -from compas.geometry import Geometry -from compas.geometry import Transformation - -from .vector import Vector from .point import Point from .quaternion import Quaternion +from .vector import Vector class Frame(Geometry): @@ -592,6 +591,65 @@ def to_transformation(self): # Methods # ========================================================================== + def interpolate_frame(self, other, t): + """Interpolates between two frames at a given parameter t in the range [0, 1] + + Parameters + ---------- + other : :class:`compas.geometry.Frame` + t : float + A parameter in the range [0-1]. + + Returns + ------- + :class:`compas.geometry.Frame` + A list of the interpolated :class:`compas.geometry.Frame` instances. + + Examples + -------- + >>> frame1 = Frame(Point(0, 0, 0), Vector(1, 0, 0), Vector(0, 1, 0)) + >>> frame2 = Frame(Point(1, 1, 1), Vector(0, 0, 1), Vector(0, 1, 0)) + >>> start_frame = frame1.interpolate_frame(frame2, 0) + >>> allclose(start_frame.point, frame1.point) and allclose(start_frame.quaternion, frame1.quaternion) + True + """ + quat1 = Quaternion.from_frame(self) + quat2 = Quaternion.from_frame(other) + + # Interpolate origin + origin_interpolated = (self.point * (1.0 - t)) + other.point * t + + rot_interpolated = quat1.slerp(quat2, t) + + # Create a new frame with the interpolated position and orientation + interpolated_frame = Frame.from_quaternion(rot_interpolated, point=origin_interpolated) + + return interpolated_frame + + def interpolate_frames(self, other, steps): + """Generates a specified number of interpolated frames between two given frames + + Parameters + ---------- + other : :class:`compas.geometry.Frame` + steps : int + The number of interpolated frames to return. + + Returns + ------- + list of :class:`compas.geometry.Frame` + + Examples + -------- + >>> frame1 = Frame(Point(0, 0, 0), Vector(1, 0, 0), Vector(0, 1, 0)) + >>> frame2 = Frame(Point(1, 1, 1), Vector(0, 0, 1), Vector(0, 1, 0)) + >>> steps = 5 + >>> frames = frame1.interpolate_frames(frame2, steps) + >>> assert len(frames) == steps + True + """ + return [self.interpolate_frame(other, t) for t in linspace(0, 1, steps)] + def euler_angles(self, static=True, axes="xyz"): """The Euler angles from the rotation given by the frame. diff --git a/src/compas/geometry/hull.py b/src/compas/geometry/hull.py index 28b22384431..37932239f4f 100644 --- a/src/compas/geometry/hull.py +++ b/src/compas/geometry/hull.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import cross_vectors -from compas.geometry import subtract_vectors -from compas.geometry import dot_vectors from compas.geometry import cross_vectors_xy +from compas.geometry import dot_vectors +from compas.geometry import subtract_vectors def convex_hull(points): diff --git a/src/compas/geometry/icp_numpy.py b/src/compas/geometry/icp_numpy.py index b3b79a49264..559b02f739a 100644 --- a/src/compas/geometry/icp_numpy.py +++ b/src/compas/geometry/icp_numpy.py @@ -1,15 +1,15 @@ import numpy as np -from numpy import asarray from numpy import argmin +from numpy import asarray from numpy.linalg import det -from scipy.spatial.distance import cdist -from scipy.linalg import svd from scipy.linalg import norm +from scipy.linalg import svd +from scipy.spatial.distance import cdist -from compas.tolerance import TOL from compas.geometry import pca_numpy from compas.geometry import transform_points_numpy from compas.linalg import normrow +from compas.tolerance import TOL def bestfit_transform(A, B): @@ -73,8 +73,8 @@ def icp_numpy(source, target, tol=None): The algorithm terminates when the alignment error is below a specified tolerance. """ - from compas.geometry import Transformation from compas.geometry import Frame + from compas.geometry import Transformation tol = tol or TOL.approximation diff --git a/src/compas/geometry/interpolation_barycentric.py b/src/compas/geometry/interpolation_barycentric.py index 229fa1afb6a..c6a2c64d8de 100644 --- a/src/compas/geometry/interpolation_barycentric.py +++ b/src/compas/geometry/interpolation_barycentric.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import subtract_vectors from compas.geometry import dot_vectors +from compas.geometry import subtract_vectors def barycentric_coordinates(point, triangle): diff --git a/src/compas/geometry/interpolation_coons.py b/src/compas/geometry/interpolation_coons.py index 6147781fc7a..3e69fab28f2 100644 --- a/src/compas/geometry/interpolation_coons.py +++ b/src/compas/geometry/interpolation_coons.py @@ -1,13 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import add_vectors from compas.geometry import scale_vector from compas.geometry import subtract_vectors from compas.geometry import sum_vectors - -from compas.utilities import normalize_values +from compas.itertools import normalize_values def discrete_coons_patch(ab, bc, dc, ad): diff --git a/src/compas/geometry/interpolation_tweening.py b/src/compas/geometry/interpolation_tweening.py index 0b05de764c6..47fbf3de076 100644 --- a/src/compas/geometry/interpolation_tweening.py +++ b/src/compas/geometry/interpolation_tweening.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import add_vectors -from compas.geometry import subtract_vectors -from compas.geometry import scale_vector from compas.geometry import distance_point_point +from compas.geometry import scale_vector +from compas.geometry import subtract_vectors def tween_points(points1, points2, num): diff --git a/src/compas/geometry/intersection.py b/src/compas/geometry/intersection.py index 3c54c5d618a..06aba837a4f 100644 --- a/src/compas/geometry/intersection.py +++ b/src/compas/geometry/intersection.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function # from compas.precision import Precision from compas.geometry import distance_point_point diff --git a/src/compas/geometry/intersections.py b/src/compas/geometry/intersections.py index de8528cbf15..7ddd03e805c 100644 --- a/src/compas/geometry/intersections.py +++ b/src/compas/geometry/intersections.py @@ -1,28 +1,26 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import fabs from math import sqrt -from compas.tolerance import TOL - -from compas.itertools import pairwise -from compas.plugins import pluggable -from compas.plugins import PluginNotInstalledError - from compas.geometry import add_vectors -from compas.geometry import subtract_vectors -from compas.geometry import scale_vector from compas.geometry import cross_vectors -from compas.geometry import dot_vectors -from compas.geometry import length_vector_xy -from compas.geometry import subtract_vectors_xy -from compas.geometry import normalize_vector from compas.geometry import distance_point_point +from compas.geometry import dot_vectors +from compas.geometry import is_point_in_triangle from compas.geometry import is_point_on_segment from compas.geometry import is_point_on_segment_xy -from compas.geometry import is_point_in_triangle +from compas.geometry import length_vector_xy +from compas.geometry import normalize_vector +from compas.geometry import scale_vector +from compas.geometry import subtract_vectors +from compas.geometry import subtract_vectors_xy +from compas.itertools import pairwise +from compas.plugins import PluginNotInstalledError +from compas.plugins import pluggable +from compas.tolerance import TOL def intersection_line_line(l1, l2, tol=None): @@ -207,7 +205,7 @@ def intersection_line_plane(line, plane, tol=None): ---------- line : [point, point] | :class:`compas.geometry.Line` Two points defining the line. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] The base point and normal defining the plane. tol : float, optional Tolerance for evaluating that the dot product of the line direction and the plane normal is zero. @@ -255,7 +253,7 @@ def intersection_segment_plane(segment, plane, tol=None): ---------- segment : [point, point] | :class:`compas.geometry.Line` Two points defining the line segment. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] The base point and normal defining the plane. tol : float, optional Tolerance for evaluating that the dot product of the line direction and the plane normal is zero. @@ -307,7 +305,7 @@ def intersection_polyline_plane(polyline, plane, expected_number_of_intersection ---------- polyline : sequence[point] | :class:`compas.geometry.Polyline` Polyline to test intersection. - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] Plane to compute intersection. expected_number_of_intersections : int, optional Number of useful or expected intersections. @@ -378,9 +376,9 @@ def intersection_plane_plane(plane1, plane2, tol=None): Parameters ---------- - plane1 : [point, vector] | :class:`compas.geometry.Plane` + plane1 : [point, vector] The base point and normal (normalized) defining the 1st plane. - plane2 : [point, vector] | :class:`compas.geometry.Plane` + plane2 : [point, vector] The base point and normal (normalized) defining the 2nd plane. tol : float, optional Tolerance for evaluating if the dot product of the plane normals is one. @@ -416,11 +414,11 @@ def intersection_plane_plane_plane(plane1, plane2, plane3, tol=None): Parameters ---------- - plane1 : [point, vector] | :class:`compas.geometry.Plane` + plane1 : [point, vector] The base point and normal (normalized) defining the 1st plane. - plane2 : [point, vector] | :class:`compas.geometry.Plane` + plane2 : [point, vector] The base point and normal (normalized) defining the 2nd plane. - plane3 : [point, vector] | :class:`compas.geometry.Plane` + plane3 : [point, vector] The base point and normal (normalized) defining the 3rd plane. tol : float, optional Tolerance for computing the intersection line between the first two planes, and between the intersection line and the third plane. @@ -452,9 +450,9 @@ def intersection_sphere_sphere(sphere1, sphere2): Parameters ---------- - sphere1 : [point, float] | :class:`compas.geometry.Sphere` + sphere1 : [point, float] A sphere defined by a point and radius. - sphere2 : [point, float] | :class:`compas.geometry.Sphere` + sphere2 : [point, float] A sphere defined by a point and radius. Returns @@ -591,7 +589,7 @@ def intersection_sphere_line(sphere, line): Parameters ---------- - sphere : [point, radius] | :class:`compas.geometry.Sphere` + sphere : [point, radius] A sphere defined by a point and a radius. line : [point, point] | :class:`compas.geometry.Line` A line defined by two points. @@ -611,15 +609,15 @@ def intersection_sphere_line(sphere, line): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> sphere = (3.0, 7.0, 4.0), 10.0 >>> line = (1.0, 0, 0.5), (2.0, 1.0, 0.5) >>> x1, x2 = intersection_sphere_line(sphere, line) - >>> allclose(x1, [11.634, 10.634, 0.500], 1e-3) + >>> TOL.is_allclose(x1, [11.634, 10.634, 0.500], atol=1e-3) True - >>> allclose(x2, [-0.634, -1.634, 0.50], 1e-3) + >>> TOL.is_allclose(x2, [-0.634, -1.634, 0.50], atol=1e-3) True """ @@ -627,20 +625,9 @@ def intersection_sphere_line(sphere, line): sp, radius = sphere a = (l2[0] - l1[0]) ** 2 + (l2[1] - l1[1]) ** 2 + (l2[2] - l1[2]) ** 2 - b = 2.0 * ( - (l2[0] - l1[0]) * (l1[0] - sp[0]) + (l2[1] - l1[1]) * (l1[1] - sp[1]) + (l2[2] - l1[2]) * (l1[2] - sp[2]) - ) - - c = ( - sp[0] ** 2 - + sp[1] ** 2 - + sp[2] ** 2 - + l1[0] ** 2 - + l1[1] ** 2 - + l1[2] ** 2 - - 2.0 * (sp[0] * l1[0] + sp[1] * l1[1] + sp[2] * l1[2]) - - radius**2 - ) + b = 2.0 * ((l2[0] - l1[0]) * (l1[0] - sp[0]) + (l2[1] - l1[1]) * (l1[1] - sp[1]) + (l2[2] - l1[2]) * (l1[2] - sp[2])) + + c = sp[0] ** 2 + sp[1] ** 2 + sp[2] ** 2 + l1[0] ** 2 + l1[1] ** 2 + l1[2] ** 2 - 2.0 * (sp[0] * l1[0] + sp[1] * l1[1] + sp[2] * l1[2]) - radius**2 i = b * b - 4.0 * a * c @@ -677,9 +664,9 @@ def intersection_plane_circle(plane, circle): Parameters ---------- - plane : [point, vector] | :class:`compas.geometry.Plane` + plane : [point, vector] A plane defined by a point and normal vector. - circle : [plane, float] | :class:`compas.geometry.Circle` + circle : [plane, float] A circle defined by a plane and radius. Returns @@ -954,9 +941,9 @@ def intersection_circle_circle_xy(circle1, circle2): Parameters ---------- - circle1 : [plane, float] | :class:`compas.geometry.Circle` + circle1 : [plane, float] Circle defined by a plane, with at least XY coordinates, and a radius. - circle2 : [plane, float] | :class:`compas.geometry.Circle` + circle2 : [plane, float] Circle defined by a plane, with at least XY coordinates, and a radius. Returns diff --git a/src/compas/geometry/kdtree.py b/src/compas/geometry/kdtree.py index e73761358a4..10457ba7804 100644 --- a/src/compas/geometry/kdtree.py +++ b/src/compas/geometry/kdtree.py @@ -1,12 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import collections from ._core.distance import distance_point_point_sqrd - Node = collections.namedtuple("Node", "point axis label left right") diff --git a/src/compas/geometry/offset.py b/src/compas/geometry/offset.py index d2cf4e80bde..2924dea68e6 100644 --- a/src/compas/geometry/offset.py +++ b/src/compas/geometry/offset.py @@ -1,20 +1,18 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import scale_vector -from compas.geometry import normalize_vector +from compas.data.validators import is_item_iterable from compas.geometry import add_vectors -from compas.geometry import subtract_vectors -from compas.geometry import cross_vectors from compas.geometry import centroid_points +from compas.geometry import cross_vectors from compas.geometry import intersection_line_line -from compas.geometry import normal_polygon from compas.geometry import is_colinear - -from compas.data.validators import is_item_iterable - -from compas.utilities import iterable_like +from compas.geometry import normal_polygon +from compas.geometry import normalize_vector +from compas.geometry import scale_vector +from compas.geometry import subtract_vectors +from compas.itertools import iterable_like from compas.itertools import pairwise diff --git a/src/compas/geometry/pca_numpy.py b/src/compas/geometry/pca_numpy.py index ad5c6f53dd5..9e2fcf13d3f 100644 --- a/src/compas/geometry/pca_numpy.py +++ b/src/compas/geometry/pca_numpy.py @@ -41,9 +41,7 @@ def pca_numpy(data): n, dim = X.shape if not n >= dim: - raise ValueError( - "The number of observations (n) should be higher than the number of measured variables (dimensions)." - ) + raise ValueError("The number of observations (n) should be higher than the number of measured variables (dimensions).") # the average of the observations for each of the variables # for example, if the data are 2D point coordinates, diff --git a/src/compas/geometry/plane.py b/src/compas/geometry/plane.py index b2cbe5cea15..2cebbafb943 100644 --- a/src/compas/geometry/plane.py +++ b/src/compas/geometry/plane.py @@ -4,13 +4,13 @@ from math import sqrt +from compas.geometry import Geometry +from compas.geometry import bestfit_plane +from compas.geometry import cross_vectors from compas.tolerance import TOL -from compas.geometry import cross_vectors -from compas.geometry import bestfit_plane -from compas.geometry import Geometry -from .vector import Vector from .point import Point +from .vector import Vector class Plane(Geometry): diff --git a/src/compas/geometry/pointcloud.py b/src/compas/geometry/pointcloud.py index cf26a73a84b..ed1a25c2f55 100644 --- a/src/compas/geometry/pointcloud.py +++ b/src/compas/geometry/pointcloud.py @@ -1,18 +1,17 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from random import uniform -from compas.tolerance import TOL - -from compas.geometry import KDTree from compas.geometry import Geometry +from compas.geometry import KDTree from compas.geometry import Point -from compas.geometry import transform_points -from compas.geometry import centroid_points from compas.geometry import bounding_box +from compas.geometry import centroid_points from compas.geometry import closest_point_in_cloud +from compas.geometry import transform_points +from compas.tolerance import TOL class Pointcloud(Geometry): diff --git a/src/compas/geometry/polygon.py b/src/compas/geometry/polygon.py index 2a38bdb2f22..893aa23d116 100644 --- a/src/compas/geometry/polygon.py +++ b/src/compas/geometry/polygon.py @@ -1,24 +1,24 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import math -from compas.itertools import pairwise -from compas.geometry import allclose +from compas.geometry import Frame +from compas.geometry import Geometry +from compas.geometry import Line +from compas.geometry import Plane +from compas.geometry import Point +from compas.geometry import Transformation from compas.geometry import area_polygon +from compas.geometry import bounding_box from compas.geometry import centroid_polygon +from compas.geometry import earclip_polygon from compas.geometry import is_coplanar from compas.geometry import is_polygon_convex from compas.geometry import transform_points -from compas.geometry import earclip_polygon -from compas.geometry import bounding_box -from compas.geometry import Geometry -from compas.geometry import Transformation -from compas.geometry import Point -from compas.geometry import Plane -from compas.geometry import Frame -from compas.geometry import Line +from compas.itertools import pairwise +from compas.tolerance import TOL class Polygon(Geometry): @@ -119,7 +119,7 @@ def __iter__(self): def __eq__(self, other): if not hasattr(other, "__iter__") or not hasattr(other, "__len__") or len(self) != len(other): return False - return allclose(self, other) + return TOL.is_allclose(self, other) # ========================================================================== # Properties diff --git a/src/compas/geometry/polyhedron.py b/src/compas/geometry/polyhedron.py index 39495041b5a..908bc65eea2 100644 --- a/src/compas/geometry/polyhedron.py +++ b/src/compas/geometry/polyhedron.py @@ -1,14 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import sqrt -from compas.itertools import pairwise -from compas.geometry import transform_points -from compas.geometry import Polygon -from compas.geometry import Point from compas.geometry import Line +from compas.geometry import Point +from compas.geometry import Polygon +from compas.geometry import transform_points +from compas.itertools import pairwise + from .geometry import Geometry @@ -414,10 +415,15 @@ def from_halfspaces(cls, halfspaces, interior_point): """ from itertools import combinations + from numpy import asarray - from scipy.spatial import HalfspaceIntersection, ConvexHull # type: ignore + from scipy.spatial import ConvexHull # type: ignore + from scipy.spatial import HalfspaceIntersection # type: ignore + from compas.datastructures import Mesh - from compas.geometry import length_vector, dot_vectors, cross_vectors + from compas.geometry import cross_vectors + from compas.geometry import dot_vectors + from compas.geometry import length_vector halfspaces = asarray(halfspaces, dtype=float) interior_point = asarray(interior_point, dtype=float) diff --git a/src/compas/geometry/projection.py b/src/compas/geometry/projection.py index c32f9189e88..d6a095b6ddd 100644 --- a/src/compas/geometry/projection.py +++ b/src/compas/geometry/projection.py @@ -11,14 +11,14 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import allclose +from compas.geometry import Transformation from compas.geometry import decompose_matrix from compas.geometry import matrix_from_orthogonal_projection from compas.geometry import matrix_from_parallel_projection -from compas.geometry import matrix_from_perspective_projection from compas.geometry import matrix_from_perspective_entries -from compas.geometry import Transformation +from compas.geometry import matrix_from_perspective_projection +from compas.itertools import flatten +from compas.tolerance import TOL class Projection(Transformation): @@ -47,7 +47,7 @@ class Projection(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: _, _, _, _, perspective = decompose_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_perspective_entries(perspective))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_perspective_entries(perspective))): raise ValueError("This is not a proper projection matrix.") super(Projection, self).__init__(matrix=matrix, name=name) diff --git a/src/compas/geometry/quadmesh_planarize.py b/src/compas/geometry/quadmesh_planarize.py index 5d1466816e3..5d2084762bc 100644 --- a/src/compas/geometry/quadmesh_planarize.py +++ b/src/compas/geometry/quadmesh_planarize.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.plugins import pluggable diff --git a/src/compas/geometry/quadmesh_planarize_none.py b/src/compas/geometry/quadmesh_planarize_none.py index 946f1eb6728..92487087aa3 100644 --- a/src/compas/geometry/quadmesh_planarize_none.py +++ b/src/compas/geometry/quadmesh_planarize_none.py @@ -1,16 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import project_points_plane +from compas.geometry import bestfit_plane from compas.geometry import centroid_points -from compas.geometry import midpoint_point_point -from compas.geometry import distance_point_point from compas.geometry import distance_line_line -from compas.geometry import bestfit_plane - -from compas.utilities import window +from compas.geometry import distance_point_point +from compas.geometry import midpoint_point_point +from compas.geometry import project_points_plane from compas.itertools import pairwise +from compas.itertools import window def mesh_flatness(mesh, maxdev=1.0): diff --git a/src/compas/geometry/quaternion.py b/src/compas/geometry/quaternion.py index 0dd0946099d..824ef80e238 100644 --- a/src/compas/geometry/quaternion.py +++ b/src/compas/geometry/quaternion.py @@ -1,17 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.tolerance import TOL +import math +from sys import float_info -from compas.geometry import quaternion_multiply -from compas.geometry import quaternion_conjugate -from compas.geometry import quaternion_unitize +from compas.geometry import Geometry +from compas.geometry import Rotation from compas.geometry import quaternion_canonize -from compas.geometry import quaternion_norm -from compas.geometry import quaternion_is_unit +from compas.geometry import quaternion_conjugate from compas.geometry import quaternion_from_matrix -from compas.geometry import Geometry +from compas.geometry import quaternion_is_unit +from compas.geometry import quaternion_multiply +from compas.geometry import quaternion_norm +from compas.geometry import quaternion_unitize +from compas.tolerance import TOL class Quaternion(Geometry): @@ -159,7 +162,7 @@ def __getitem__(self, key): return self.y if key == 3: return self.z - raise KeyError + raise KeyError(key) def __setitem__(self, key, value): if key == 0: @@ -170,9 +173,11 @@ def __setitem__(self, key, value): return if key == 2: self.y = value + return if key == 3: self.z = value - raise KeyError + return + raise KeyError(key) def __iter__(self): return iter(self.wxyz) @@ -287,12 +292,12 @@ def from_frame(cls, frame): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> from compas.geometry import Frame >>> q = [1., -2., 3., -4.] >>> F = Frame.from_quaternion(q) >>> Q = Quaternion.from_frame(F) - >>> allclose(Q.canonized(), quaternion_canonize(quaternion_unitize(q))) + >>> TOL.is_allclose(Q.canonized(), quaternion_canonize(quaternion_unitize(q))) True """ @@ -367,7 +372,7 @@ def unitize(self): True """ - qu = quaternion_unitize(self) + qu = quaternion_unitize(list(self)) self.w, self.x, self.y, self.z = qu def unitized(self): @@ -387,7 +392,7 @@ def unitized(self): True """ - qu = quaternion_unitize(self) + qu = quaternion_unitize(list(self)) return Quaternion(*qu) def canonize(self): @@ -408,7 +413,7 @@ def canonize(self): Quaternion(0.500, -0.500, -0.500, -0.500) """ - qc = quaternion_canonize(self) + qc = quaternion_canonize(list(self)) self.w, self.x, self.y, self.z = qc # type: ignore def canonized(self): @@ -430,7 +435,7 @@ def canonized(self): Quaternion(0.500, -0.500, -0.500, -0.500) """ - qc = quaternion_canonize(self) + qc = quaternion_canonize(list(self)) return Quaternion(*qc) # type: ignore def conjugate(self): @@ -448,7 +453,7 @@ def conjugate(self): Quaternion(1.000, -1.000, -1.000, -1.000) """ - qc = quaternion_conjugate(self) + qc = quaternion_conjugate(list(self)) self.w, self.x, self.y, self.z = qc def conjugated(self): @@ -469,5 +474,71 @@ def conjugated(self): Quaternion(1.000, -1.000, -1.000, -1.000) """ - qc = quaternion_conjugate(self) + qc = quaternion_conjugate(list(self)) return Quaternion(*qc) + + def dot(self, other): + """Computes the cosine of the angle between the two quaternions""" + return self.w * other.w + self.x * other.x + self.y * other.y + self.z * other.z + + def slerp(self, other, t): + """Slerp: spherical interpolation of two quaternions. + + Parameters + ---------- + other : :class:`compas.geometry.Quaternion` + The other quaternion to interpolate between. + t : float + A parameter in the range [0-1]. + + Returns + ------- + :class:`compas.geometry.Quaternion` + + Examples + -------- + >>> q1 = Quaternion(1, 0, 0, 0) + >>> q2 = Quaternion(0, 1, 0, 0) + >>> t = 0.5 + >>> interpolated_quaternion = Quaternion.slerp(q1, q2, t) + + """ + epsilon = float_info.epsilon + + q1 = self.unitized() + q2 = other.unitized() + + cosom = q1.dot(q2) + + interpolated = Rotation() + quat = list(interpolated.quaternion) + + # rotate around the shortest angle + if cosom < 0.0: + cosom = -cosom + quat[0] = -q1[0] + quat[1] = -q1[1] + quat[2] = -q1[2] + quat[3] = -q1[3] + + else: + quat[0] = q1[0] + quat[1] = q1[1] + quat[2] = q1[2] + quat[3] = q1[3] + + if (1.0 - cosom) > epsilon: + omega = math.acos(cosom) + sinom = math.sin(omega) + sc1 = math.sin((1.0 - t) * omega) / sinom + sc2 = math.sin(t * omega) / sinom + else: + sc1 = 1.0 - t + sc2 = t + + qw_interp = sc1 * quat[0] + sc2 * q2[0] + qx_interp = sc1 * quat[1] + sc2 * q2[1] + qy_interp = sc1 * quat[2] + sc2 * q2[2] + qz_interp = sc1 * quat[3] + sc2 * q2[3] + + return Quaternion(qw_interp, qx_interp, qy_interp, qz_interp) diff --git a/src/compas/geometry/reflection.py b/src/compas/geometry/reflection.py index cd6674db039..314ed8470bd 100644 --- a/src/compas/geometry/reflection.py +++ b/src/compas/geometry/reflection.py @@ -11,15 +11,15 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import allclose -from compas.geometry import dot_vectors +from compas.geometry import Transformation from compas.geometry import cross_vectors -from compas.geometry import normalize_vector from compas.geometry import decompose_matrix -from compas.geometry import matrix_from_perspective_entries +from compas.geometry import dot_vectors from compas.geometry import identity_matrix -from compas.geometry import Transformation +from compas.geometry import matrix_from_perspective_entries +from compas.geometry import normalize_vector +from compas.itertools import flatten +from compas.tolerance import TOL class Reflection(Transformation): @@ -50,7 +50,7 @@ class Reflection(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: _, _, _, _, perspective = decompose_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_perspective_entries(perspective))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_perspective_entries(perspective))): raise ValueError("This is not a proper reflection matrix.") super(Reflection, self).__init__(matrix=matrix, name=name) diff --git a/src/compas/geometry/rotation.py b/src/compas/geometry/rotation.py index 2f2c29e6a37..f9ecec4914a 100644 --- a/src/compas/geometry/rotation.py +++ b/src/compas/geometry/rotation.py @@ -11,20 +11,20 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import normalize_vector +from compas.geometry import Transformation +from compas.geometry import axis_and_angle_from_matrix +from compas.geometry import basis_vectors_from_matrix from compas.geometry import cross_vectors -from compas.geometry import length_vector -from compas.geometry import allclose from compas.geometry import decompose_matrix -from compas.geometry import matrix_from_euler_angles from compas.geometry import euler_angles_from_matrix +from compas.geometry import length_vector from compas.geometry import matrix_from_axis_and_angle -from compas.geometry import axis_and_angle_from_matrix -from compas.geometry import matrix_from_quaternion +from compas.geometry import matrix_from_euler_angles from compas.geometry import matrix_from_frame -from compas.geometry import basis_vectors_from_matrix -from compas.geometry import Transformation +from compas.geometry import matrix_from_quaternion +from compas.geometry import normalize_vector +from compas.itertools import flatten +from compas.tolerance import TOL class Rotation(Transformation): @@ -78,7 +78,7 @@ class Rotation(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: _, _, angles, _, _ = decompose_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_euler_angles(angles))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_euler_angles(angles))): raise ValueError("This is not a proper rotation matrix.") super(Rotation, self).__init__(matrix=matrix, name=name) @@ -230,11 +230,11 @@ def from_quaternion(cls, quaternion): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> q1 = [0.945, -0.021, -0.125, 0.303] >>> R = Rotation.from_quaternion(q1) >>> q2 = R.quaternion - >>> allclose(q1, q2) + >>> TOL.is_allclose(q1, q2) True """ @@ -258,11 +258,11 @@ def from_axis_angle_vector(cls, axis_angle_vector, point=[0, 0, 0]): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> aav1 = [-0.043, -0.254, 0.617] >>> R = Rotation.from_axis_angle_vector(aav1) >>> aav2 = R.axis_angle_vector - >>> allclose(aav1, aav2) + >>> TOL.is_allclose(aav1, aav2) True """ @@ -297,12 +297,12 @@ def from_euler_angles(cls, euler_angles, static=True, axes="xyz", **kwargs): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> ea1 = 1.4, 0.5, 2.3 >>> args = False, 'xyz' >>> R1 = Rotation.from_euler_angles(ea1, *args) >>> ea2 = R1.euler_angles(*args) - >>> allclose(ea1, ea2) + >>> TOL.is_allclose(ea1, ea2) True >>> alpha, beta, gamma = ea1 @@ -342,12 +342,12 @@ def euler_angles(self, static=True, axes="xyz"): Examples -------- - >>> from compas.geometry import allclose + >>> from compas.tolerance import TOL >>> ea1 = 1.4, 0.5, 2.3 >>> args = False, 'xyz' >>> R1 = Rotation.from_euler_angles(ea1, *args) >>> ea2 = R1.euler_angles(*args) - >>> allclose(ea1, ea2) + >>> TOL.is_allclose(ea1, ea2) True """ diff --git a/src/compas/geometry/scale.py b/src/compas/geometry/scale.py index 15f9ac3ee02..2ed8d7fdf8c 100644 --- a/src/compas/geometry/scale.py +++ b/src/compas/geometry/scale.py @@ -11,14 +11,14 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import allclose -from compas.geometry import multiply_matrices +from compas.geometry import Transformation from compas.geometry import decompose_matrix -from compas.geometry import matrix_from_scale_factors from compas.geometry import matrix_from_frame +from compas.geometry import matrix_from_scale_factors from compas.geometry import matrix_inverse -from compas.geometry import Transformation +from compas.geometry import multiply_matrices +from compas.itertools import flatten +from compas.tolerance import TOL class Scale(Transformation): @@ -61,7 +61,7 @@ class Scale(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: scale, _, _, _, _ = decompose_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_scale_factors(scale))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_scale_factors(scale))): raise ValueError("This is not a proper scale matrix.") super(Scale, self).__init__(matrix=matrix, name=name) diff --git a/src/compas/geometry/shapes/box.py b/src/compas/geometry/shapes/box.py index 199d18cfe23..45b95af4a45 100644 --- a/src/compas/geometry/shapes/box.py +++ b/src/compas/geometry/shapes/box.py @@ -2,12 +2,12 @@ from __future__ import division from __future__ import print_function -from compas.geometry import centroid_points -from compas.geometry import transform_points -from compas.geometry import Transformation from compas.geometry import Frame -from compas.geometry import Vector from compas.geometry import Line +from compas.geometry import Transformation +from compas.geometry import Vector +from compas.geometry import centroid_points +from compas.geometry import transform_points from .shape import Shape @@ -151,36 +151,6 @@ def __repr__(self): self.frame, ) - def __len__(self): - return 4 - - def __getitem__(self, key): - if key == 0: - return self.xsize - elif key == 1: - return self.ysize - elif key == 2: - return self.zsize - elif key == 3: - return self.frame - else: - raise KeyError - - def __setitem__(self, key, value): - if key == 0: - self.xsize = value - elif key == 1: - self.ysize = value - elif key == 2: - self.zsize = value - elif key == 3: - self.frame = value - else: - raise KeyError - - def __iter__(self): - return iter([self.xsize, self.ysize, self.zsize, self.frame]) - # ========================================================================== # Properties # ========================================================================== @@ -259,18 +229,8 @@ def height(self): @property def diagonal(self): - a = ( - self.frame.point - + self.frame.xaxis * -0.5 * self.xsize - + self.frame.yaxis * -0.5 * self.ysize - + self.frame.zaxis * -0.5 * self.zsize - ) - b = ( - self.frame.point - + self.frame.xaxis * 0.5 * self.xsize - + self.frame.yaxis * 0.5 * self.ysize - + self.frame.zaxis * 0.5 * self.zsize - ) + a = self.frame.point + self.frame.xaxis * -0.5 * self.xsize + self.frame.yaxis * -0.5 * self.ysize + self.frame.zaxis * -0.5 * self.zsize + b = self.frame.point + self.frame.xaxis * 0.5 * self.xsize + self.frame.yaxis * 0.5 * self.ysize + self.frame.zaxis * 0.5 * self.zsize return Line(a, b) @property diff --git a/src/compas/geometry/shapes/capsule.py b/src/compas/geometry/shapes/capsule.py index c576eaf4f69..4d97816b6ee 100644 --- a/src/compas/geometry/shapes/capsule.py +++ b/src/compas/geometry/shapes/capsule.py @@ -6,12 +6,12 @@ from math import pi from math import sin -from compas.geometry import transform_points +from compas.geometry import Circle from compas.geometry import Frame -from compas.geometry import Plane from compas.geometry import Line -from compas.geometry import Circle +from compas.geometry import Plane from compas.geometry import Transformation +from compas.geometry import transform_points from .shape import Shape diff --git a/src/compas/geometry/shapes/cone.py b/src/compas/geometry/shapes/cone.py index 2365a642d88..cc5b9d49925 100644 --- a/src/compas/geometry/shapes/cone.py +++ b/src/compas/geometry/shapes/cone.py @@ -7,12 +7,12 @@ from math import sin from math import sqrt -from compas.itertools import pairwise -from compas.geometry import transform_points from compas.geometry import Circle -from compas.geometry import Plane -from compas.geometry import Line from compas.geometry import Frame +from compas.geometry import Line +from compas.geometry import Plane +from compas.geometry import transform_points +from compas.itertools import pairwise from .shape import Shape diff --git a/src/compas/geometry/shapes/cylinder.py b/src/compas/geometry/shapes/cylinder.py index b1de3d8ab1b..cf1d8631b4c 100644 --- a/src/compas/geometry/shapes/cylinder.py +++ b/src/compas/geometry/shapes/cylinder.py @@ -6,11 +6,11 @@ from math import pi from math import sin -from compas.geometry import transform_points from compas.geometry import Circle -from compas.geometry import Plane from compas.geometry import Frame from compas.geometry import Line +from compas.geometry import Plane +from compas.geometry import transform_points from .shape import Shape diff --git a/src/compas/geometry/shapes/shape.py b/src/compas/geometry/shapes/shape.py index bee52da8c44..1969885b94f 100644 --- a/src/compas/geometry/shapes/shape.py +++ b/src/compas/geometry/shapes/shape.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.geometry import Geometry from compas.geometry import Frame -from compas.geometry import Transformation +from compas.geometry import Geometry from compas.geometry import Rotation +from compas.geometry import Transformation class Shape(Geometry): diff --git a/src/compas/geometry/shapes/sphere.py b/src/compas/geometry/shapes/sphere.py index 6a8db8e890a..b0046f02362 100644 --- a/src/compas/geometry/shapes/sphere.py +++ b/src/compas/geometry/shapes/sphere.py @@ -6,10 +6,11 @@ from math import pi from math import sin -from compas.geometry import transform_points +from compas.geometry import Circle from compas.geometry import Frame from compas.geometry import Line -from compas.geometry import Circle +from compas.geometry import transform_points + from .shape import Shape diff --git a/src/compas/geometry/shapes/torus.py b/src/compas/geometry/shapes/torus.py index 3a7b8707f3e..8b505c5d3a5 100644 --- a/src/compas/geometry/shapes/torus.py +++ b/src/compas/geometry/shapes/torus.py @@ -6,10 +6,10 @@ from math import pi from math import sin -from compas.geometry import matrix_from_frame -from compas.geometry import transform_points from compas.geometry import Frame from compas.geometry import Plane +from compas.geometry import matrix_from_frame +from compas.geometry import transform_points from .shape import Shape @@ -98,6 +98,13 @@ def __init__(self, radius_axis, radius_pipe, frame=None, name=None): self.radius_axis = radius_axis self.radius_pipe = radius_pipe + def __repr__(self): + return "Torus(frame={0!r}, radius_axis={1!r}, radius_pipe={2!r})".format( + self.frame, + self.radius_axis, + self.radius_pipe, + ) + # ========================================================================== # Properties # ========================================================================== @@ -142,41 +149,6 @@ def area(self): def volume(self): return (pi * self.radius_pipe**2) * (2 * pi * self.radius_axis) - # ========================================================================== - # Customisation - # ========================================================================== - - def __repr__(self): - return "Torus(frame={0!r}, radius_axis={1!r}, radius_pipe={2!r})".format( - self.frame, self.radius_axis, self.radius_pipe - ) - - def __len__(self): - return 3 - - def __getitem__(self, key): - if key == 0: - return self.frame - elif key == 1: - return self.radius_axis - elif key == 2: - return self.radius_pipe - else: - raise KeyError - - def __setitem__(self, key, value): - if key == 0: - self.frame = value - elif key == 1: - self.radius_axis = value - elif key == 2: - self.radius_pipe = value - else: - raise KeyError - - def __iter__(self): - return iter([self.frame, self.radius_axis, self.radius_pipe]) - # ========================================================================== # Constructors # ========================================================================== diff --git a/src/compas/geometry/shear.py b/src/compas/geometry/shear.py index 5d9b8ed3316..7de59bdc469 100644 --- a/src/compas/geometry/shear.py +++ b/src/compas/geometry/shear.py @@ -11,12 +11,12 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import allclose -from compas.geometry import matrix_from_shear_entries -from compas.geometry import matrix_from_shear -from compas.geometry import decompose_matrix from compas.geometry import Transformation +from compas.geometry import decompose_matrix +from compas.geometry import matrix_from_shear +from compas.geometry import matrix_from_shear_entries +from compas.itertools import flatten +from compas.tolerance import TOL class Shear(Transformation): @@ -50,7 +50,7 @@ class Shear(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: _, shear, _, _, _ = decompose_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_shear_entries(shear))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_shear_entries(shear))): raise ValueError("This is not a proper shear matrix.") super(Shear, self).__init__(matrix=matrix, name=name) diff --git a/src/compas/geometry/surfaces/conical.py b/src/compas/geometry/surfaces/conical.py index bb51b5b8ac2..d4c4ce41457 100644 --- a/src/compas/geometry/surfaces/conical.py +++ b/src/compas/geometry/surfaces/conical.py @@ -1,11 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import pi, cos, sin +from math import cos +from math import pi +from math import sin -from compas.geometry import Point from compas.geometry import Frame +from compas.geometry import Point + from .surface import Surface PI2 = 2 * pi diff --git a/src/compas/geometry/surfaces/cylindrical.py b/src/compas/geometry/surfaces/cylindrical.py index 9f146ff5082..0ed358a58c3 100644 --- a/src/compas/geometry/surfaces/cylindrical.py +++ b/src/compas/geometry/surfaces/cylindrical.py @@ -1,13 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import pi, cos, sin +from math import cos +from math import pi +from math import sin +from compas.geometry import Circle +from compas.geometry import Frame from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Frame -from compas.geometry import Circle + from .surface import Surface PI2 = 2 * pi diff --git a/src/compas/geometry/surfaces/nurbs.py b/src/compas/geometry/surfaces/nurbs.py index 862a0b034e3..23f7d9a8f86 100644 --- a/src/compas/geometry/surfaces/nurbs.py +++ b/src/compas/geometry/surfaces/nurbs.py @@ -1,12 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.plugins import pluggable -from compas.plugins import PluginNotInstalledError from compas.geometry import Point from compas.itertools import linspace -from compas.utilities import meshgrid +from compas.itertools import meshgrid +from compas.plugins import PluginNotInstalledError +from compas.plugins import pluggable from .surface import Surface diff --git a/src/compas/geometry/surfaces/planar.py b/src/compas/geometry/surfaces/planar.py index dde96172d76..66f636f1904 100644 --- a/src/compas/geometry/surfaces/planar.py +++ b/src/compas/geometry/surfaces/planar.py @@ -2,10 +2,11 @@ from __future__ import division from __future__ import print_function -from compas.geometry import Point -from compas.geometry import Vector from compas.geometry import Frame from compas.geometry import Plane +from compas.geometry import Point +from compas.geometry import Vector + from .surface import Surface diff --git a/src/compas/geometry/surfaces/spherical.py b/src/compas/geometry/surfaces/spherical.py index 16606c5ab24..555ee51031f 100644 --- a/src/compas/geometry/surfaces/spherical.py +++ b/src/compas/geometry/surfaces/spherical.py @@ -1,13 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import cos, sin, pi +from math import cos +from math import pi +from math import sin +from compas.geometry import Circle +from compas.geometry import Frame from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Frame -from compas.geometry import Circle + from .surface import Surface PI2 = 2 * pi diff --git a/src/compas/geometry/surfaces/surface.py b/src/compas/geometry/surfaces/surface.py index 4ddc9f828b6..4777705279b 100644 --- a/src/compas/geometry/surfaces/surface.py +++ b/src/compas/geometry/surfaces/surface.py @@ -1,15 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from itertools import product -from compas.geometry import Geometry from compas.geometry import Frame -from compas.geometry import Transformation +from compas.geometry import Geometry from compas.geometry import Point -from compas.plugins import pluggable +from compas.geometry import Transformation from compas.itertools import linspace +from compas.plugins import pluggable @pluggable(category="factories") diff --git a/src/compas/geometry/surfaces/toroidal.py b/src/compas/geometry/surfaces/toroidal.py index e236cd7a59f..f955c33b78a 100644 --- a/src/compas/geometry/surfaces/toroidal.py +++ b/src/compas/geometry/surfaces/toroidal.py @@ -1,11 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from math import cos, sin, pi +from math import cos +from math import pi +from math import sin -from compas.geometry import Point from compas.geometry import Frame +from compas.geometry import Point + from .surface import Surface PI2 = 2 * pi @@ -87,11 +90,7 @@ def __eq__(self, other): other_radius_pipe = other.radius_pipe except Exception: return False - return ( - self.radius_axis == other_radius_axis - and self.radius_pipe == other_radius_pipe - and self.frame == other_frame - ) + return self.radius_axis == other_radius_axis and self.radius_pipe == other_radius_pipe and self.frame == other_frame # ============================================================================= # Properties diff --git a/src/compas/geometry/transformation.py b/src/compas/geometry/transformation.py index 30731c21d09..dd57474b05e 100644 --- a/src/compas/geometry/transformation.py +++ b/src/compas/geometry/transformation.py @@ -12,11 +12,6 @@ """ from compas.data import Data - -from compas.tolerance import TOL - -from compas.geometry import multiply_matrices -from compas.geometry import transpose_matrix from compas.geometry import basis_vectors_from_matrix from compas.geometry import decompose_matrix from compas.geometry import identity_matrix @@ -25,7 +20,10 @@ from compas.geometry import matrix_from_frame from compas.geometry import matrix_from_translation from compas.geometry import matrix_inverse +from compas.geometry import multiply_matrices from compas.geometry import translation_from_matrix +from compas.geometry import transpose_matrix +from compas.tolerance import TOL class Transformation(Data): @@ -498,11 +496,11 @@ def decomposed(self): True """ + from compas.geometry import Projection + from compas.geometry import Rotation # noqa: F811 from compas.geometry import Scale # noqa: F811 from compas.geometry import Shear - from compas.geometry import Rotation # noqa: F811 from compas.geometry import Translation # noqa: F811 - from compas.geometry import Projection s, h, a, t, p = decompose_matrix(self.matrix) S = Scale.from_factors(s) diff --git a/src/compas/geometry/translation.py b/src/compas/geometry/translation.py index dd9fe6a637a..2b0d5a82009 100644 --- a/src/compas/geometry/translation.py +++ b/src/compas/geometry/translation.py @@ -11,11 +11,11 @@ Ippoliti for providing code and documentation. """ -from compas.utilities import flatten -from compas.geometry import allclose +from compas.geometry import Transformation from compas.geometry import matrix_from_translation from compas.geometry import translation_from_matrix -from compas.geometry import Transformation +from compas.itertools import flatten +from compas.tolerance import TOL class Translation(Transformation): @@ -72,7 +72,7 @@ class Translation(Transformation): def __init__(self, matrix=None, check=False, name=None): if matrix and check: translation = translation_from_matrix(matrix) - if not allclose(flatten(matrix), flatten(matrix_from_translation(translation))): + if not TOL.is_allclose(flatten(matrix), flatten(matrix_from_translation(translation))): raise ValueError("This is not a proper translation matrix.") super(Translation, self).__init__(matrix=matrix, name=name) diff --git a/src/compas/geometry/triangulation_delaunay.py b/src/compas/geometry/triangulation_delaunay.py index 2bf626bf6b5..5a547f555ed 100644 --- a/src/compas/geometry/triangulation_delaunay.py +++ b/src/compas/geometry/triangulation_delaunay.py @@ -1,7 +1,3 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from compas.plugins import pluggable diff --git a/src/compas/geometry/triangulation_earclip.py b/src/compas/geometry/triangulation_earclip.py index 5e58e4d984c..efc5788c527 100644 --- a/src/compas/geometry/triangulation_earclip.py +++ b/src/compas/geometry/triangulation_earclip.py @@ -84,9 +84,7 @@ def validate(self, points, indexes, ears): """ - not_ear_points = [ - points[i] for i in indexes if points[i] != self.coords and points[i] not in self.neighbour_coords - ] + not_ear_points = [points[i] for i in indexes if points[i] != self.coords and points[i] not in self.neighbour_coords] insides = [self.is_inside(p) for p in not_ear_points] if self.is_convex() and True not in insides: for e in ears: @@ -274,7 +272,9 @@ def earclip_polygon(polygon): """ # Orient the copy of polygon points to XY plane. - from compas.geometry import Plane, Frame, Transformation # Avoid circular import. + from compas.geometry import Frame # Avoid circular import. + from compas.geometry import Plane # Avoid circular import. + from compas.geometry import Transformation # Avoid circular import. frame = Frame.from_plane(Plane(polygon.points[0], polygon.normal)) xform = Transformation.from_frame_to_frame(frame, Frame.worldXY()) diff --git a/src/compas/geometry/trimesh_curvature.py b/src/compas/geometry/trimesh_curvature.py index 7d9347a23da..56a79ef3ef9 100644 --- a/src/compas/geometry/trimesh_curvature.py +++ b/src/compas/geometry/trimesh_curvature.py @@ -1,11 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from math import pi -from compas.plugins import pluggable + from compas.geometry import angle_points -from compas.utilities import window +from compas.itertools import window +from compas.plugins import pluggable @pluggable(category="trimesh") diff --git a/src/compas/geometry/trimesh_descent_numpy.py b/src/compas/geometry/trimesh_descent_numpy.py index 16a1bf9e35f..7c219efa44e 100644 --- a/src/compas/geometry/trimesh_descent_numpy.py +++ b/src/compas/geometry/trimesh_descent_numpy.py @@ -1,4 +1,5 @@ from numpy import asarray + from .trimesh_gradient_numpy import trimesh_gradient_numpy diff --git a/src/compas/geometry/trimesh_geodistance.py b/src/compas/geometry/trimesh_geodistance.py index d835f00648d..3c1862fe5ff 100644 --- a/src/compas/geometry/trimesh_geodistance.py +++ b/src/compas/geometry/trimesh_geodistance.py @@ -1,7 +1,3 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - from compas.plugins import pluggable @@ -33,12 +29,7 @@ def trimesh_geodistance(M, source, method="exact"): >>> """ - from .trimesh_geodistance_numpy import trimesh_geodesic_distances_numpy - - if method == "exact": - raise NotImplementedError - - return trimesh_geodesic_distances_numpy(M, [source]) + raise NotImplementedError trimesh_geodistance.__pluggable__ = True diff --git a/src/compas/geometry/trimesh_gradient_numpy.py b/src/compas/geometry/trimesh_gradient_numpy.py index d98ad783c80..7987686fa4e 100644 --- a/src/compas/geometry/trimesh_gradient_numpy.py +++ b/src/compas/geometry/trimesh_gradient_numpy.py @@ -1,8 +1,8 @@ import numpy as np from scipy.sparse import coo_matrix # type: ignore -from compas.linalg import normrow from compas.linalg import normalizerow +from compas.linalg import normrow from compas.linalg import rot90 diff --git a/src/compas/geometry/trimesh_isolines.py b/src/compas/geometry/trimesh_isolines.py index 96d315c53c9..0c8151e7001 100644 --- a/src/compas/geometry/trimesh_isolines.py +++ b/src/compas/geometry/trimesh_isolines.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.plugins import pluggable diff --git a/src/compas/geometry/trimesh_matrices.py b/src/compas/geometry/trimesh_matrices.py index 0e85b11734f..49413a1a388 100644 --- a/src/compas/geometry/trimesh_matrices.py +++ b/src/compas/geometry/trimesh_matrices.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.plugins import pluggable diff --git a/src/compas/geometry/trimesh_matrices_numpy.py b/src/compas/geometry/trimesh_matrices_numpy.py index 063ca58be31..d3a1f2186c5 100644 --- a/src/compas/geometry/trimesh_matrices_numpy.py +++ b/src/compas/geometry/trimesh_matrices_numpy.py @@ -1,13 +1,13 @@ from numpy import asarray -from numpy import zeros -from numpy import cross from numpy import bincount +from numpy import cross +from numpy import zeros from scipy.sparse import coo_matrix from scipy.sparse import spdiags +from compas.geometry import cross_vectors from compas.geometry import dot_vectors from compas.geometry import length_vector -from compas.geometry import cross_vectors from compas.linalg import normrow diff --git a/src/compas/geometry/trimesh_parametrisation.py b/src/compas/geometry/trimesh_parametrisation.py index 812c89d5a3b..336b5b622b6 100644 --- a/src/compas/geometry/trimesh_parametrisation.py +++ b/src/compas/geometry/trimesh_parametrisation.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.plugins import pluggable diff --git a/src/compas/geometry/trimesh_pull_points_numpy.py b/src/compas/geometry/trimesh_pull_points_numpy.py index 91f656a55e3..0b686339bab 100644 --- a/src/compas/geometry/trimesh_pull_points_numpy.py +++ b/src/compas/geometry/trimesh_pull_points_numpy.py @@ -61,9 +61,7 @@ def trimesh_pull_points_numpy(M, points): def _is_point_in_edgezone(p, p0, p1): n = cross_vectors(p1 - p0, [0, 0, 1.0]) - return ( - is_ccw_xy(p0 - p0, n, p - p0) and not is_ccw_xy(p0 - p0, p1 - p0, p - p0) and not is_ccw_xy(p1 - p1, n, p - p1) - ) + return is_ccw_xy(p0 - p0, n, p - p0) and not is_ccw_xy(p0 - p0, p1 - p0, p - p0) and not is_ccw_xy(p1 - p1, n, p - p1) def _compute_point_on_segment(p, p0, p1): diff --git a/src/compas/geometry/trimesh_remeshing.py b/src/compas/geometry/trimesh_remeshing.py index 78db7807f0c..9408afddfa6 100644 --- a/src/compas/geometry/trimesh_remeshing.py +++ b/src/compas/geometry/trimesh_remeshing.py @@ -1,7 +1,3 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - from compas.plugins import pluggable diff --git a/src/compas/geometry/trimesh_samplepoints_numpy.py b/src/compas/geometry/trimesh_samplepoints_numpy.py index ec2ffb69e0e..cfb92c8c6e0 100644 --- a/src/compas/geometry/trimesh_samplepoints_numpy.py +++ b/src/compas/geometry/trimesh_samplepoints_numpy.py @@ -1,12 +1,12 @@ from numpy import array -from numpy.random import choice -from numpy.random import rand -from numpy import sqrt -from numpy import float64 -from numpy import cross -from numpy.linalg import norm from numpy import clip +from numpy import cross from numpy import finfo +from numpy import float64 +from numpy import sqrt +from numpy.linalg import norm +from numpy.random import choice +from numpy.random import rand def trimesh_samplepoints_numpy(M, num_points=1000, return_normals=False): diff --git a/src/compas/geometry/trimesh_slicing.py b/src/compas/geometry/trimesh_slicing.py index 65ce832f04a..f1e9b114370 100644 --- a/src/compas/geometry/trimesh_slicing.py +++ b/src/compas/geometry/trimesh_slicing.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.plugins import pluggable diff --git a/src/compas/geometry/trimesh_smoothing_numpy.py b/src/compas/geometry/trimesh_smoothing_numpy.py index dcd7c61ac0b..702c0666083 100644 --- a/src/compas/geometry/trimesh_smoothing_numpy.py +++ b/src/compas/geometry/trimesh_smoothing_numpy.py @@ -1,6 +1,6 @@ from numpy import array -from ._algebra import trimesh_cotangent_laplacian_matrix +from .trimesh_matrices_numpy import trimesh_cotangent_laplacian_matrix def trimesh_smooth_laplacian_cotangent(trimesh, fixed, kmax=10): diff --git a/src/compas/itertools.py b/src/compas/itertools.py index abed217d78c..756764679b7 100644 --- a/src/compas/itertools.py +++ b/src/compas/itertools.py @@ -1,14 +1,14 @@ # recipes with itertools # see: https://docs.python.org/3.6/library/itertools.html -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from itertools import islice +from functools import reduce from itertools import chain +from itertools import islice from itertools import repeat from itertools import tee -from functools import reduce from operator import mul try: @@ -123,7 +123,7 @@ def meshgrid(x, y, indexing="xy"): Examples -------- - >>> from compas.utilities import linspace, meshgrid + >>> from compas.itertools import linspace, meshgrid >>> x = list(linspace(0, 1, 3)) >>> y = list(linspace(0, 1, 2)) @@ -181,7 +181,7 @@ def linspace(start, stop, num=50): Examples -------- - >>> from compas.utilities import linspace + >>> from compas.itertools import linspace >>> list(linspace(0, 1, 3)) [0.0, 0.5, 1.0] diff --git a/src/compas/linalg.py b/src/compas/linalg.py index 40cd9b33032..0b9f8967617 100644 --- a/src/compas/linalg.py +++ b/src/compas/linalg.py @@ -1,13 +1,14 @@ import sys from functools import wraps + +from numpy import absolute from numpy import array from numpy import asarray from numpy import atleast_2d +from numpy import cross from numpy import nan_to_num from numpy import nonzero from numpy import sum -from numpy import absolute -from numpy import cross from numpy.linalg import cond from scipy.linalg import cho_factor # type: ignore from scipy.linalg import cho_solve # type: ignore @@ -17,7 +18,6 @@ from scipy.sparse.linalg import factorized # type: ignore from scipy.sparse.linalg import spsolve # type: ignore - # ============================================================================== # Fundamentals # ============================================================================== diff --git a/src/compas/matrices.py b/src/compas/matrices.py index 9c957b675c2..1fe48bd6abd 100644 --- a/src/compas/matrices.py +++ b/src/compas/matrices.py @@ -2,7 +2,6 @@ from numpy import array from numpy import asarray from numpy import tile - from scipy.sparse import coo_matrix # type: ignore from scipy.sparse import csr_matrix # type: ignore from scipy.sparse import diags # type: ignore diff --git a/src/compas/plugins.py b/src/compas/plugins.py index d75050a2cf0..c33b7bd45d8 100644 --- a/src/compas/plugins.py +++ b/src/compas/plugins.py @@ -150,11 +150,7 @@ def load_plugins(self): with self._discovery_lock: count = 0 - modules = [ - module_name - for _importer, module_name, is_pkg in pkgutil.iter_modules() - if is_pkg and module_name.startswith("compas") - ] + modules = [module_name for _importer, module_name, is_pkg in pkgutil.iter_modules() if is_pkg and module_name.startswith("compas")] modules_to_inspect = dict() @@ -213,11 +209,7 @@ def register_module(self, plugin_module): plugins_list.sort(key=lambda p: p.key) if self.DEBUG: - print( - 'Registered plugin with ID "{}" for extension point: {}'.format( - plugin_impl.id, plugin_opts["extension_point_url"] - ) - ) + print('Registered plugin with ID "{}" for extension point: {}'.format(plugin_impl.id, plugin_opts["extension_point_url"])) count += 1 return count @@ -286,16 +278,10 @@ def wrapper(*args, **kwargs): try: return func(*args, **kwargs) except NotImplementedError: - raise PluginNotInstalledError( - "Plugin not found and no default implementation for extension point URL: {}".format( - extension_point_url - ) - ) + raise PluginNotInstalledError("Plugin not found and no default implementation for extension point URL: {}".format(extension_point_url)) except ImportError: raise PluginDefaultNotAvailableError( - "Plugin not found and the default implementation is not available in your environment for extension point URL: {}".format( - extension_point_url - ) + "Plugin not found and the default implementation is not available in your environment for extension point URL: {}".format(extension_point_url) ) # Invoke plugin diff --git a/src/compas/rpc/__init__.py b/src/compas/rpc/__init__.py index 5fb7058af67..c34107367d5 100644 --- a/src/compas/rpc/__init__.py +++ b/src/compas/rpc/__init__.py @@ -2,10 +2,11 @@ COMPAS runs in many different environments, but in some environments the availablity of libraries is limited. For example, when running COMPAS in an IronPython-based environment like Rhino/Grasshopper, plenty of CPython libraries such as `numpy` and `scipy` are not available. -To workaround this limitation, COMPAS provides a mechanisms to access the functionality of a CPython environment seemlessly from any other Python environment through a "Remote Procedure Call" or RPC. +To workaround this limitation, COMPAS provides a mechanisms to access the functionality of a CPython environment +seemlessly from any other Python environment through a "Remote Procedure Call" or RPC. Through RPC, COMPAS can be used as a server for remote clients, and as a client for remote servers. -A typical use case is to run algorithms that require packages like ``numpy`` or ``scipy`` on a remote server, when working in Rhino. -Or to use COMPAS in a browser application. +A typical use case is to run algorithms that require packages like ``numpy`` or ``scipy`` on a remote server, +when working in Rhino. Or to use COMPAS in a browser application. """ from __future__ import absolute_import diff --git a/src/compas/rpc/dispatcher.py b/src/compas/rpc/dispatcher.py index 85fd48bbcb7..82ec6bc8040 100644 --- a/src/compas/rpc/dispatcher.py +++ b/src/compas/rpc/dispatcher.py @@ -122,10 +122,7 @@ def _dispatch(self, name, args): try: idict = json.loads(args[0], cls=DataDecoder) except (IndexError, TypeError): - odict["error"] = ( - "API methods require a single JSON encoded dictionary as input.\n" - "For example: input = json.dumps({'param_1': 1, 'param_2': [2, 3]})" - ) + odict["error"] = "API methods require a single JSON encoded dictionary as input.\n" "For example: input = json.dumps({'param_1': 1, 'param_2': [2, 3]})" else: self._call(function, idict, odict) diff --git a/src/compas/rpc/errors.py b/src/compas/rpc/errors.py index 764fbb72fc6..89d37f6881b 100644 --- a/src/compas/rpc/errors.py +++ b/src/compas/rpc/errors.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function class RPCServerError(Exception): diff --git a/src/compas/rpc/proxy.py b/src/compas/rpc/proxy.py index 77fffa555bc..650c9f9efbf 100644 --- a/src/compas/rpc/proxy.py +++ b/src/compas/rpc/proxy.py @@ -7,9 +7,9 @@ import compas import compas._os -from compas.rpc import RPCServerError from compas.data import DataDecoder from compas.data import DataEncoder +from compas.rpc import RPCServerError try: from xmlrpclib import ServerProxy @@ -17,8 +17,8 @@ from xmlrpc.client import ServerProxy try: - from subprocess import Popen from subprocess import PIPE + from subprocess import Popen except ImportError: from System.Diagnostics import Process @@ -284,9 +284,7 @@ def start_server(self): self._process.StartInfo.RedirectStandardOutput = self.capture_output self._process.StartInfo.RedirectStandardError = self.capture_output self._process.StartInfo.FileName = self.python - self._process.StartInfo.Arguments = "-m {0} --port {1} --{2}autoreload".format( - self.service, self._port, "" if self.autoreload else "no-" - ) + self._process.StartInfo.Arguments = "-m {0} --port {1} --{2}autoreload".format(self.service, self._port, "" if self.autoreload else "no-") self._process.Start() else: args = [ diff --git a/src/compas/rpc/server.py b/src/compas/rpc/server.py index 92952a00279..c33a4665bcb 100644 --- a/src/compas/rpc/server.py +++ b/src/compas/rpc/server.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import threading diff --git a/src/compas/rpc/services/default.py b/src/compas/rpc/services/default.py index 3d1147071c6..33ef2dd751e 100644 --- a/src/compas/rpc/services/default.py +++ b/src/compas/rpc/services/default.py @@ -5,8 +5,8 @@ """ -from compas.rpc import Server from compas.rpc import Dispatcher +from compas.rpc import Server from .watcher import FileWatcherService diff --git a/src/compas/scene/assemblyobject.py b/src/compas/scene/assemblyobject.py index c8879b4b7c8..878841c1840 100644 --- a/src/compas/scene/assemblyobject.py +++ b/src/compas/scene/assemblyobject.py @@ -1,3 +1,3 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function diff --git a/src/compas/scene/context.py b/src/compas/scene/context.py index 872177dcb1d..d083023fa0f 100644 --- a/src/compas/scene/context.py +++ b/src/compas/scene/context.py @@ -137,9 +137,7 @@ def _get_sceneobject_cls(data, **kwargs): break if cls is None: - raise SceneObjectNotRegisteredError( - "No scene object is registered for this data type: {} in this context: {}".format(dtype, context_name) - ) + raise SceneObjectNotRegisteredError("No scene object is registered for this data type: {} in this context: {}".format(dtype, context_name)) return cls @@ -149,9 +147,7 @@ def get_sceneobject_cls(item, **kwargs): register_scene_objects() if item is None: - raise ValueError( - "Cannot create a scene object for None. Please ensure you pass a instance of a supported class." - ) + raise ValueError("Cannot create a scene object for None. Please ensure you pass a instance of a supported class.") cls = _get_sceneobject_cls(item, **kwargs) PluginValidator.ensure_implementations(cls) diff --git a/src/compas/scene/exceptions.py b/src/compas/scene/exceptions.py index 215f269a750..6b9882e324e 100644 --- a/src/compas/scene/exceptions.py +++ b/src/compas/scene/exceptions.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function class SceneObjectNotRegisteredError(Exception): diff --git a/src/compas/scene/geometryobject.py b/src/compas/scene/geometryobject.py index f1a060525aa..45ffbd8336e 100644 --- a/src/compas/scene/geometryobject.py +++ b/src/compas/scene/geometryobject.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from .sceneobject import SceneObject from .descriptors.color import ColorAttribute +from .sceneobject import SceneObject class GeometryObject(SceneObject): diff --git a/src/compas/scene/graphobject.py b/src/compas/scene/graphobject.py index f3c4736b054..bc1651dfc3d 100644 --- a/src/compas/scene/graphobject.py +++ b/src/compas/scene/graphobject.py @@ -1,10 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import transform_points -from .sceneobject import SceneObject + from .descriptors.colordict import ColorDictAttribute +from .sceneobject import SceneObject class GraphObject(SceneObject): diff --git a/src/compas/scene/meshobject.py b/src/compas/scene/meshobject.py index 1d665568b15..715e24477f8 100644 --- a/src/compas/scene/meshobject.py +++ b/src/compas/scene/meshobject.py @@ -1,10 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import transform_points -from .sceneobject import SceneObject + from .descriptors.colordict import ColorDictAttribute +from .sceneobject import SceneObject class MeshObject(SceneObject): diff --git a/src/compas/scene/scene.py b/src/compas/scene/scene.py index 93e2551e15c..b181691740d 100644 --- a/src/compas/scene/scene.py +++ b/src/compas/scene/scene.py @@ -3,9 +3,9 @@ from compas.datastructures import Tree from compas.datastructures import TreeNode -from .context import clear -from .context import before_draw from .context import after_draw +from .context import before_draw +from .context import clear from .context import detect_current_context from .sceneobject import SceneObject @@ -104,11 +104,7 @@ def add(self, item, parent=None, **kwargs): else: if "context" in kwargs: if kwargs["context"] != self.context: - raise Exception( - "Object context should be the same as scene context: {} != {}".format( - kwargs["context"], self.context - ) - ) + raise Exception("Object context should be the same as scene context: {} != {}".format(kwargs["context"], self.context)) del kwargs["context"] # otherwist the SceneObject receives "context" twice, which results in an error sceneobject = SceneObject(item, context=self.context, **kwargs) # type: ignore super(Scene, self).add(sceneobject, parent=parent) diff --git a/src/compas/scene/sceneobject.py b/src/compas/scene/sceneobject.py index 3c8607e36da..02ce2806e88 100644 --- a/src/compas/scene/sceneobject.py +++ b/src/compas/scene/sceneobject.py @@ -3,20 +3,20 @@ from __future__ import print_function from abc import abstractmethod -from .descriptors.protocol import DescriptorProtocol -from .descriptors.color import ColorAttribute -from .context import clear -from .context import get_sceneobject_cls +from functools import reduce +from operator import mul import compas.colors # noqa: F401 import compas.datastructures # noqa: F401 import compas.geometry # noqa: F401 - -from compas.datastructures import TreeNode from compas.colors import Color +from compas.datastructures import TreeNode from compas.geometry import Transformation -from functools import reduce -from operator import mul + +from .context import clear +from .context import get_sceneobject_cls +from .descriptors.color import ColorAttribute +from .descriptors.protocol import DescriptorProtocol class SceneObject(TreeNode): @@ -84,18 +84,8 @@ def __new__(cls, item, **kwargs): sceneobject_cls = get_sceneobject_cls(item, **kwargs) return super(SceneObject, cls).__new__(sceneobject_cls) - def __init__( - self, - item, # type: compas.geometry.Geometry | compas.datastructures.Datastructure - name=None, # type: str | None - color=None, # type: compas.colors.Color | None - opacity=1.0, # type: float - show=True, # type: bool - frame=None, # type: compas.geometry.Frame | None - transformation=None, # type: compas.geometry.Transformation | None - context=None, # type: str | None - **kwargs # type: dict - ): # type: (...) -> None + def __init__(self, item, name=None, color=None, opacity=1.0, show=True, frame=None, transformation=None, context=None, **kwargs): # fmt: skip + # type: (compas.geometry.Geometry | compas.datastructures.Datastructure, str | None, compas.colors.Color | None, float, bool, compas.geometry.Frame | None, compas.geometry.Transformation | None, str | None, dict) -> None name = name or item.name super(SceneObject, self).__init__(name=name, **kwargs) # the scene object needs to store the context @@ -238,11 +228,7 @@ def add(self, item, **kwargs): else: if "context" in kwargs: if kwargs["context"] != self.context: - raise Exception( - "Child context should be the same as parent context: {} != {}".format( - kwargs["context"], self.context - ) - ) + raise Exception("Child context should be the same as parent context: {} != {}".format(kwargs["context"], self.context)) del kwargs["context"] # otherwist the SceneObject receives "context" twice, which results in an error sceneobject = SceneObject(item, context=self.context, **kwargs) # type: ignore diff --git a/src/compas/scene/volmeshobject.py b/src/compas/scene/volmeshobject.py index 6c1b3761719..6ca1135b651 100644 --- a/src/compas/scene/volmeshobject.py +++ b/src/compas/scene/volmeshobject.py @@ -1,10 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import transform_points -from .sceneobject import SceneObject + from .descriptors.colordict import ColorDictAttribute +from .sceneobject import SceneObject class VolMeshObject(SceneObject): diff --git a/src/compas/tolerance.py b/src/compas/tolerance.py index 7e4a3bfbcaa..c3c8008008b 100644 --- a/src/compas/tolerance.py +++ b/src/compas/tolerance.py @@ -2,14 +2,14 @@ The tolerance module provides functionality to deal with tolerances consistently across all other COMPAS packages. """ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from compas.data import Data from decimal import Decimal import compas +from compas.data import Data __all__ = ["Tolerance", "TOL"] @@ -94,7 +94,14 @@ class Tolerance(Data): """ LINEARDEFLECTION = 1e-3 - """float: The maximum distance between a curve or surface and its polygonal approximation. + """float: The maximum "distance" deviation between a curve or surface and its polygonal approximation. + + This is used by the viewer to determine the mesh and polyline resolution of curves and surfaces for visualisation. + + """ + + ANGULARDEFLECTION = 1e-1 + """float: The maximum "curvature" deviation between a curve or surface and its polygonal approximation. This is used by the viewer to determine the mesh and polyline resolution of curves and surfaces for visualisation. @@ -115,6 +122,7 @@ def __data__(self): "approximation": self.approximation, "precision": self.precision, "lineardeflection": self.lineardeflection, + "angulardeflection": self.angulardeflection, } @classmethod @@ -127,6 +135,7 @@ def __from_data__(cls, data): tol.approximation = data["approximation"] tol.precision = data["precision"] tol.lineardeflection = data["lineardeflection"] + tol.angulardeflection = data["angulardeflection"] return tol def __init__( @@ -138,6 +147,7 @@ def __init__( approximation=None, precision=None, lineardflection=None, + angulardflection=None, name=None, ): super(Tolerance, self).__init__(name=name) @@ -148,6 +158,7 @@ def __init__( self._approximation = None self._precision = None self._lineardeflection = None + self._angulardeflection = None self.unit = unit self.absolute = absolute self.relative = relative @@ -155,11 +166,13 @@ def __init__( self.approximation = approximation self.precision = precision self.lineardeflection = lineardflection + self.angulardeflection = angulardflection # this can be autogenerated if we use slots # __repr__: return f"{__class__.__name__}({', '.join(f'{k}={v!r}' for k, v in self.__dict__.items())})}" + def __repr__(self): - return "Tolerance(unit='{}', absolute={}, relative={}, angular={}, approximation={}, precision={}, lineardeflection={})".format( + return "Tolerance(unit='{}', absolute={}, relative={}, angular={}, approximation={}, precision={}, lineardeflection={}, angulardeflection={})".format( self.unit, self.absolute, self.relative, @@ -167,6 +180,7 @@ def __repr__(self): self.approximation, self.precision, self.lineardeflection, + self.angulardeflection, ) def reset(self): @@ -177,6 +191,7 @@ def reset(self): self._approximation = None self._precision = None self._lineardeflection = None + self._angulardeflection = None @property def units(self): @@ -250,6 +265,16 @@ def lineardeflection(self): def lineardeflection(self, value): self._lineardeflection = value + @property + def angulardeflection(self): + if not self._angulardeflection: + return self.ANGULARDEFLECTION + return self._angulardeflection + + @angulardeflection.setter + def angulardeflection(self, value): + self._angulardeflection = value + def tolerance(self, truevalue, rtol, atol): """Compute the tolerance for a comparison. @@ -512,10 +537,7 @@ def is_allclose(self, A, B, rtol=None, atol=None): """ rtol = rtol or self.relative atol = atol or self.absolute - return all( - self.is_allclose(a, b, rtol, atol) if hasattr(a, "__iter__") else self.compare(a, b, rtol, atol) - for a, b in zip(A, B) - ) + return all(self.is_allclose(a, b, rtol, atol) if hasattr(a, "__iter__") else self.compare(a, b, rtol, atol) for a, b in zip(A, B)) def is_angle_zero(self, a, tol=None): """Check if an angle is close enough to zero to be considered zero. @@ -653,6 +675,81 @@ def geometric_key(self, xyz, precision=None, sanitize=True): return "{0:.{3}f},{1:.{3}f},{2:.{3}f}".format(x, y, z, precision) + def geometric_key_xy(self, xy, precision=None, sanitize=True): + """Compute the geometric key of a point in the XY plane. + + Parameters + ---------- + xy : list of float + The XY coordinates of the point. + precision : int, optional + The precision used when converting numbers to strings. + Default is ``None``, in which case ``self.precision`` is used. + sanitize : bool, optional + If ``True``, minus signs ("-") will be removed from values that are equal to zero up to the given precision. + + Returns + ------- + str + The geometric key in XY. + + Raises + ------ + ValueError + If the precision is zero. + + Examples + -------- + >>> tol = Tolerance() + >>> tol.geometric_key_xy([1.0, 2.0]) + '1.000,2.000' + + >>> tol = Tolerance() + >>> tol.geometric_key_xy([1.05725, 2.0195], precision=3) + '1.057,2.019' + + >>> tol = Tolerance() + >>> tol.geometric_key_xy([1.0, 2.0], precision=-1) + '1,2' + + >>> tol = Tolerance() + >>> tol.geometric_key_xy([1.0, 2.0], precision=-3) + '0,0' + + >>> tol = Tolerance() + >>> tol.geometric_key_xy([1103, 205], precision=-3) + '1100,200' + + """ + x = xy[0] + y = xy[1] + + if not precision: + precision = self.precision + + if precision == 0: + raise ValueError("Precision cannot be zero.") + + if precision == -1: + return "{:d},{:d}".format(int(x), int(y)) + + if precision < -1: + precision = -precision - 1 + factor = 10**precision + return "{:d},{:d}".format( + int(round(x / factor) * factor), + int(round(y / factor) * factor), + ) + + if sanitize: + minzero = "-{0:.{1}f}".format(0.0, precision) + if "{0:.{1}f}".format(x, precision) == minzero: + x = 0.0 + if "{0:.{1}f}".format(y, precision) == minzero: + y = 0.0 + + return "{0:.{2}f},{1:.{2}f}".format(x, y, precision) + def format_number(self, number, precision=None): """Format a number as a string. diff --git a/src/compas/topology/combinatorics.py b/src/compas/topology/combinatorics.py index a5d5e1d802b..30923d9a696 100644 --- a/src/compas/topology/combinatorics.py +++ b/src/compas/topology/combinatorics.py @@ -1,8 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from collections import deque + from compas.topology.traversal import breadth_first_traverse diff --git a/src/compas/topology/connectivity.py b/src/compas/topology/connectivity.py index 27c7c4ebee2..f271290c714 100644 --- a/src/compas/topology/connectivity.py +++ b/src/compas/topology/connectivity.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.itertools import pairwise diff --git a/src/compas/topology/orientation.py b/src/compas/topology/orientation.py index 4593a58e816..695e4750026 100644 --- a/src/compas/topology/orientation.py +++ b/src/compas/topology/orientation.py @@ -1,11 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import random -from compas.topology import breadth_first_traverse + from compas.geometry import centroid_points from compas.itertools import pairwise +from compas.topology import breadth_first_traverse def _closest_faces(vertices, faces, nmax=10, radius=10.0): @@ -24,9 +25,9 @@ def _closest_faces(vertices, faces, nmax=10, radius=10.0): except Exception: try: + from Rhino.Geometry import Point3d # type: ignore from Rhino.Geometry import RTree # type: ignore from Rhino.Geometry import Sphere # type: ignore - from Rhino.Geometry import Point3d # type: ignore except Exception: from compas.geometry import KDTree @@ -88,7 +89,7 @@ def _face_adjacency(vertices, faces, nmax=10, radius=10.0): found.add(nbr) break - adjacency[face] = nbrs + adjacency[index] = nbrs return adjacency @@ -98,8 +99,10 @@ def face_adjacency(points, faces): Parameters ---------- - mesh : :class:`compas.datastructures.Mesh` - A mesh object. + points : list[point] + The vertex locations of the faces. + faces : list[list[int]] + The faces defined as list of indices in the points list. Returns ------- diff --git a/src/compas/topology/traversal.py b/src/compas/topology/traversal.py index b577cd014d6..d185d430130 100644 --- a/src/compas/topology/traversal.py +++ b/src/compas/topology/traversal.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function try: from queue import PriorityQueue @@ -11,7 +11,6 @@ from compas.geometry import distance_point_point - # ============================================================================== # DFS # ============================================================================== diff --git a/src/compas/utilities/__init__.py b/src/compas/utilities/__init__.py index 5602a9ceb5b..2b926960a1a 100644 --- a/src/compas/utilities/__init__.py +++ b/src/compas/utilities/__init__.py @@ -9,19 +9,6 @@ print_profile, ) -from ..itertools import ( - flatten, - reshape, - grouper, - iterable_like, - linspace, - meshgrid, - normalize_values, - pairwise, - remap_values, - window, -) -from .maps import geometric_key, geometric_key_xy, reverse_geometric_key from .remote import download_file_from_remote from .ssh import SSH @@ -33,19 +20,6 @@ "abstractclassmethod", "memoize", "print_profile", - "normalize_values", - "remap_values", - "meshgrid", - "linspace", - "reshape", - "flatten", - "pairwise", - "window", - "iterable_like", - "grouper", - "geometric_key", - "reverse_geometric_key", - "geometric_key_xy", "download_file_from_remote", "SSH", ] diff --git a/src/compas/utilities/datetime.py b/src/compas/utilities/datetime.py index 6fd18ca91dd..b5d5611f670 100644 --- a/src/compas/utilities/datetime.py +++ b/src/compas/utilities/datetime.py @@ -1,9 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import time import datetime +import time def timestamp(): diff --git a/src/compas/utilities/decorators.py b/src/compas/utilities/decorators.py index c9ce27c0886..b39bf31df55 100644 --- a/src/compas/utilities/decorators.py +++ b/src/compas/utilities/decorators.py @@ -1,10 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import functools import pstats - from functools import wraps try: diff --git a/src/compas/utilities/maps.py b/src/compas/utilities/maps.py deleted file mode 100644 index c60e1607d91..00000000000 --- a/src/compas/utilities/maps.py +++ /dev/null @@ -1,127 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -import compas - - -def geometric_key(xyz, precision=None, sanitize=True): - """Convert XYZ coordinates to a string that can be used as a dict key. - - Parameters - ---------- - xyz : list[float] - The XYZ coordinates. - precision : str, optional - A formatting option that specifies the precision of the - individual numbers in the string. - Supported values are any float precision (e.g. ``'3f'``), or decimal integer (``'d'``). - Default is ``None``, in which case the global precision setting will be used (:attr:`compas.PRECISION`). - sanitize : bool, optional - If True, minus signs ("-") will be removed from values that are equal to zero up to the given precision. - - Returns - ------- - str - The string representation of the given coordinates. - - See also - -------- - geometric_key_xy - - Examples - -------- - >>> from math import pi - >>> geometric_key([pi, pi, pi]) - '3.142,3.142,3.142' - - """ - x, y, z = xyz - if not precision: - precision = compas.PRECISION - if precision == "d": - return "{0},{1},{2}".format(int(x), int(y), int(z)) - if sanitize: - minzero = "-{0:.{1}}".format(0.0, precision) - if "{0:.{1}}".format(x, precision) == minzero: - x = 0.0 - if "{0:.{1}}".format(y, precision) == minzero: - y = 0.0 - if "{0:.{1}}".format(z, precision) == minzero: - z = 0.0 - return "{0:.{3}},{1:.{3}},{2:.{3}}".format(x, y, z, precision) - - -def reverse_geometric_key(gkey): - """Reverse a geometric key string into xyz coordinates. - - Parameters - ---------- - gkey : str - A geometric key. - - Returns - ------- - list[float] - A list of XYZ coordinates. - - See Also - -------- - geometric_key - - Examples - -------- - >>> from math import pi - >>> xyz = [pi, pi, pi] - >>> gkey = geometric_key(xyz) - >>> reverse_geometric_key(gkey) - [3.142, 3.142, 3.142] - - """ - xyz = gkey.split(",") - return [float(i) for i in xyz] - - -def geometric_key_xy(xy, precision=None, sanitize=True): - """Convert XY coordinates to a string that can be used as a dict key. - - Parameters - ---------- - xy : list[float] - The XY(Z) coordinates. - precision : str, optional - A formatting option that specifies the precision of the - individual numbers in the string. - Supported values are any float precision (e.g. ``'3f'``), or decimal integer (``'d'``). - Default is ``None``, inwhich case the global precision setting will be used (``compas.PRECISION``). - sanitize : bool, optional - If True, minus signs ("-") will be removed from values that are equal to zero up to the given precision. - - Returns - ------- - str - The string representation of the given coordinates. - - See also - -------- - geometric_key - - Examples - -------- - >>> from math import pi - >>> geometric_key_xy([pi, pi, pi]) - '3.142,3.142' - - """ - x, y = xy[:2] - if not precision: - precision = compas.PRECISION - if precision == "d": - return "{0},{1}".format(int(x), int(y)) - if sanitize: - minzero = "-{0:.{1}}".format(0.0, precision) - if "{0:.{1}}".format(x, precision) == minzero: - x = 0.0 - if "{0:.{1}}".format(y, precision) == minzero: - y = 0.0 - return "{0:.{2}},{1:.{2}}".format(x, y, precision) diff --git a/src/compas/utilities/remote.py b/src/compas/utilities/remote.py index 464880169d4..6da13c40bd4 100644 --- a/src/compas/utilities/remote.py +++ b/src/compas/utilities/remote.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import os diff --git a/src/compas_blender/collections.py b/src/compas_blender/collections.py index dbe4558764d..98a590917e4 100644 --- a/src/compas_blender/collections.py +++ b/src/compas_blender/collections.py @@ -1,5 +1,7 @@ +from typing import List +from typing import Text + import bpy # type: ignore -from typing import List, Text from compas_blender.objects import delete_objects diff --git a/src/compas_blender/conversions/curves.py b/src/compas_blender/conversions/curves.py index b39b3d8298b..9d850feb036 100644 --- a/src/compas_blender/conversions/curves.py +++ b/src/compas_blender/conversions/curves.py @@ -4,9 +4,8 @@ from compas.geometry import Circle from compas.geometry import Line -from compas.geometry import Polyline from compas.geometry import NurbsCurve - +from compas.geometry import Polyline # ============================================================================= # To Blender diff --git a/src/compas_blender/conversions/geometry.py b/src/compas_blender/conversions/geometry.py index 25f2ff87c82..430e8af9898 100644 --- a/src/compas_blender/conversions/geometry.py +++ b/src/compas_blender/conversions/geometry.py @@ -2,14 +2,13 @@ import bpy # type: ignore +from compas.geometry import Cylinder + # import bmesh # type: ignore # import mathutils # type: ignore - from compas.geometry import Point from compas.geometry import Pointcloud from compas.geometry import Sphere -from compas.geometry import Cylinder - # ============================================================================= # To Blender @@ -33,9 +32,7 @@ def point_to_blender_sphere(point: Point) -> bpy.types.Object: raise NotImplementedError -def pointcloud_to_blender( - pointcloud: Pointcloud, radius: float = 0.05, u: int = 16, v: int = 16, name: Optional[str] = None -) -> bpy.types.Object: +def pointcloud_to_blender(pointcloud: Pointcloud, radius: float = 0.05, u: int = 16, v: int = 16, name: Optional[str] = None) -> bpy.types.Object: """Convert a COMPAS pointcloud to a Blender pointcloud. Parameters diff --git a/src/compas_blender/conversions/meshes.py b/src/compas_blender/conversions/meshes.py index a92483cb162..e81800e717b 100644 --- a/src/compas_blender/conversions/meshes.py +++ b/src/compas_blender/conversions/meshes.py @@ -1,10 +1,10 @@ from typing import Optional -import bpy # type: ignore import bmesh # type: ignore +import bpy # type: ignore -from compas.geometry import Translation from compas.datastructures import Mesh +from compas.geometry import Translation # To Do # ----- diff --git a/src/compas_blender/conversions/surfaces.py b/src/compas_blender/conversions/surfaces.py index ead438fbf3a..53343e5c796 100644 --- a/src/compas_blender/conversions/surfaces.py +++ b/src/compas_blender/conversions/surfaces.py @@ -1,6 +1,6 @@ import bpy # type: ignore -from compas.geometry import NurbsSurface +from compas.geometry import NurbsSurface # ============================================================================= # To Blender diff --git a/src/compas_blender/conversions/transformations.py b/src/compas_blender/conversions/transformations.py index 993452414db..20242080847 100644 --- a/src/compas_blender/conversions/transformations.py +++ b/src/compas_blender/conversions/transformations.py @@ -1,6 +1,6 @@ import mathutils # type: ignore -from compas.geometry import Transformation +from compas.geometry import Transformation # ============================================================================= # To Blender diff --git a/src/compas_blender/geometry/booleans.py b/src/compas_blender/geometry/booleans.py index b60c0f5b543..76d80b94603 100644 --- a/src/compas_blender/geometry/booleans.py +++ b/src/compas_blender/geometry/booleans.py @@ -1,4 +1,5 @@ import bpy # type: ignore + from compas.plugins import plugin @@ -78,9 +79,9 @@ def boolean_intersection_mesh_mesh(A, B, remesh=False): def _boolean_operation(A, B, method): - from compas_blender.utilities import draw_mesh from compas_blender.utilities import delete_object from compas_blender.utilities import delete_unused_data + from compas_blender.utilities import draw_mesh A = draw_mesh(*A) B = draw_mesh(*B) diff --git a/src/compas_blender/install.py b/src/compas_blender/install.py index 43e4c7480be..2a198c5e272 100644 --- a/src/compas_blender/install.py +++ b/src/compas_blender/install.py @@ -3,11 +3,9 @@ import os import sys -import compas_blender - import compas._os import compas.plugins - +import compas_blender INSTALLED_VERSION = None @@ -213,9 +211,7 @@ def _run_post_execution_steps(steps_generator): all_steps_succeeded = False print(" {} {}: {}".format(package.ljust(20), status, message)) except ValueError: - post_execution_errors.append( - ValueError("Step ran without errors but result is wrongly formatted: {}".format(str(item))) - ) + post_execution_errors.append(ValueError("Step ran without errors but result is wrongly formatted: {}".format(str(item)))) if post_execution_errors: print("\nOne or more errors occurred:\n") diff --git a/src/compas_blender/objects.py b/src/compas_blender/objects.py index b5e41a39c2c..0233f7b7129 100644 --- a/src/compas_blender/objects.py +++ b/src/compas_blender/objects.py @@ -1,9 +1,11 @@ +from typing import Iterable +from typing import List +from typing import Text + import bpy # type: ignore -from typing import List, Iterable, Text from compas_blender.data import delete_unused_data - # ============================================================================== # Delete # ============================================================================== diff --git a/src/compas_blender/print_python_path.py b/src/compas_blender/print_python_path.py index 57d20b01f0e..eee9622e009 100644 --- a/src/compas_blender/print_python_path.py +++ b/src/compas_blender/print_python_path.py @@ -1,6 +1,5 @@ import compas_blender - if __name__ == "__main__": import argparse diff --git a/src/compas_blender/scene/boxobject.py b/src/compas_blender/scene/boxobject.py index 43955336ec1..05f0da9b9fd 100644 --- a/src/compas_blender/scene/boxobject.py +++ b/src/compas_blender/scene/boxobject.py @@ -4,12 +4,11 @@ import bpy # type: ignore -from compas.geometry import Box from compas.colors import Color - +from compas.geometry import Box +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/capsuleobject.py b/src/compas_blender/scene/capsuleobject.py index 131c3948865..340c6d8cfef 100644 --- a/src/compas_blender/scene/capsuleobject.py +++ b/src/compas_blender/scene/capsuleobject.py @@ -3,12 +3,11 @@ import bpy # type: ignore -from compas.geometry import Capsule from compas.colors import Color - +from compas.geometry import Capsule +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/circleobject.py b/src/compas_blender/scene/circleobject.py index 5443966c5b8..3a5a15b18a0 100644 --- a/src/compas_blender/scene/circleobject.py +++ b/src/compas_blender/scene/circleobject.py @@ -3,10 +3,10 @@ import bpy # type: ignore -from compas.geometry import Circle from compas.colors import Color - +from compas.geometry import Circle from compas.scene import GeometryObject + from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/coneobject.py b/src/compas_blender/scene/coneobject.py index 23edebdafe5..b7b6ea7aeca 100644 --- a/src/compas_blender/scene/coneobject.py +++ b/src/compas_blender/scene/coneobject.py @@ -3,12 +3,11 @@ import bpy # type: ignore -from compas.geometry import Cone from compas.colors import Color - +from compas.geometry import Cone +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/curveobject.py b/src/compas_blender/scene/curveobject.py index 779f7cdaac4..39244369711 100644 --- a/src/compas_blender/scene/curveobject.py +++ b/src/compas_blender/scene/curveobject.py @@ -3,11 +3,11 @@ import bpy # type: ignore -from compas.geometry import Curve from compas.colors import Color +from compas.geometry import Curve +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/cylinderobject.py b/src/compas_blender/scene/cylinderobject.py index 86cff3c060a..ae7e198d3a9 100644 --- a/src/compas_blender/scene/cylinderobject.py +++ b/src/compas_blender/scene/cylinderobject.py @@ -3,12 +3,11 @@ import bpy # type: ignore -from compas.geometry import Cylinder from compas.colors import Color - +from compas.geometry import Cylinder +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/frameobject.py b/src/compas_blender/scene/frameobject.py index c7152a8c571..8c58e5d1fbb 100644 --- a/src/compas_blender/scene/frameobject.py +++ b/src/compas_blender/scene/frameobject.py @@ -3,15 +3,14 @@ import bpy # type: ignore +from compas.colors import Color from compas.geometry import Frame from compas.geometry import Line -from compas.colors import Color - from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class FrameObject(BlenderSceneObject, GeometryObject): """Scene object for drawing frames in Blender. diff --git a/src/compas_blender/scene/graphobject.py b/src/compas_blender/scene/graphobject.py index 4e8e8e1e031..f33a4145ab5 100644 --- a/src/compas_blender/scene/graphobject.py +++ b/src/compas_blender/scene/graphobject.py @@ -8,15 +8,14 @@ import bpy # type: ignore import compas_blender -from compas.datastructures import Graph from compas.colors import Color +from compas.datastructures import Graph from compas.geometry import Line - from compas.scene import GraphObject as BaseSceneObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class GraphObject(BlenderSceneObject, BaseSceneObject): """Scene object for drawing graph data structures in Blender. @@ -186,9 +185,7 @@ def draw_edges( for u, v in edges or self.graph.edges(): # type: ignore name = f"{self.graph.name}.edge.{u}-{v}" # type: ignore color = self.edgecolor[u, v] # type: ignore - curve = conversions.line_to_blender_curve( - Line(self.graph.nodes_attributes("xyz")[u], self.graph.nodes_attributes("xyz")[v]) - ) + curve = conversions.line_to_blender_curve(Line(self.graph.nodes_attributes("xyz")[u], self.graph.nodes_attributes("xyz")[v])) obj = self.create_object(curve, name=name) self.update_object(obj, color=color, collection=collection) diff --git a/src/compas_blender/scene/lineobject.py b/src/compas_blender/scene/lineobject.py index 98d49fa6f40..88cd3c96b9f 100644 --- a/src/compas_blender/scene/lineobject.py +++ b/src/compas_blender/scene/lineobject.py @@ -3,12 +3,11 @@ import bpy # type: ignore -from compas.geometry import Line from compas.colors import Color - +from compas.geometry import Line +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/meshobject.py b/src/compas_blender/scene/meshobject.py index ea809e503a0..22ba36beebd 100644 --- a/src/compas_blender/scene/meshobject.py +++ b/src/compas_blender/scene/meshobject.py @@ -8,20 +8,19 @@ import bpy # type: ignore import compas_blender +from compas.colors import Color from compas.datastructures import Mesh +from compas.geometry import Cylinder from compas.geometry import Line from compas.geometry import Sphere -from compas.geometry import Cylinder from compas.geometry import add_vectors from compas.geometry import centroid_points from compas.geometry import scale_vector -from compas.colors import Color - from compas.scene import MeshObject as BaseMeshObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class MeshObject(BlenderSceneObject, BaseMeshObject): """Scene object for drawing mesh data structures in Blender. @@ -80,9 +79,7 @@ def clear_faces(self): # draw # ========================================================================== - def draw( - self, color: Optional[Color] = None, collection: Optional[str] = None, show_wire: bool = True - ) -> list[bpy.types.Object]: + def draw(self, color: Optional[Color] = None, collection: Optional[str] = None, show_wire: bool = True) -> list[bpy.types.Object]: """Draw the mesh. Parameters diff --git a/src/compas_blender/scene/planeobject.py b/src/compas_blender/scene/planeobject.py index 57ba280e5f6..320692d2f90 100644 --- a/src/compas_blender/scene/planeobject.py +++ b/src/compas_blender/scene/planeobject.py @@ -3,16 +3,15 @@ import bpy # type: ignore -from compas.geometry import Plane -from compas.geometry import Line -from compas.geometry import Frame from compas.colors import Color - +from compas.geometry import Frame +from compas.geometry import Line +from compas.geometry import Plane from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class PlaneObject(BlenderSceneObject, GeometryObject): """Scene object for drawing planes in Blender. diff --git a/src/compas_blender/scene/pointcloudobject.py b/src/compas_blender/scene/pointcloudobject.py index 50eff35e243..26093a3e9bb 100644 --- a/src/compas_blender/scene/pointcloudobject.py +++ b/src/compas_blender/scene/pointcloudobject.py @@ -3,14 +3,13 @@ import bpy # type: ignore -from compas.geometry import Point from compas.colors import Color - +from compas.geometry import Point from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class PointcloudObject(BlenderSceneObject, GeometryObject): """Scene object for drawing pointclouds in Blender. diff --git a/src/compas_blender/scene/pointobject.py b/src/compas_blender/scene/pointobject.py index 997078cbfe8..3da3c63d083 100644 --- a/src/compas_blender/scene/pointobject.py +++ b/src/compas_blender/scene/pointobject.py @@ -3,10 +3,10 @@ import bpy # type: ignore -from compas.geometry import Point from compas.colors import Color - +from compas.geometry import Point from compas.scene import GeometryObject + from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/polygonobject.py b/src/compas_blender/scene/polygonobject.py index 8feabb6890d..2bbef35640d 100644 --- a/src/compas_blender/scene/polygonobject.py +++ b/src/compas_blender/scene/polygonobject.py @@ -3,12 +3,11 @@ import bpy # type: ignore -from compas.geometry import Polygon from compas.colors import Color - +from compas.geometry import Polygon +from compas.scene import GeometryObject from compas_blender import conversions -from compas.scene import GeometryObject from .sceneobject import BlenderSceneObject diff --git a/src/compas_blender/scene/polyhedronobject.py b/src/compas_blender/scene/polyhedronobject.py index d53868a6b1c..8e0384087cc 100644 --- a/src/compas_blender/scene/polyhedronobject.py +++ b/src/compas_blender/scene/polyhedronobject.py @@ -2,14 +2,14 @@ from typing import Optional import bpy # type: ignore -from compas.geometry import Polyhedron -from compas.colors import Color +from compas.colors import Color +from compas.geometry import Polyhedron from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class PolyhedronObject(BlenderSceneObject, GeometryObject): """Scene object for drawing polyhedron shapes in Blender. @@ -26,9 +26,7 @@ class PolyhedronObject(BlenderSceneObject, GeometryObject): def __init__(self, polyhedron: Polyhedron, **kwargs: Any): super().__init__(geometry=polyhedron, **kwargs) - def draw( - self, color: Optional[Color] = None, collection: Optional[str] = None, show_wire: bool = True - ) -> list[bpy.types.Object]: + def draw(self, color: Optional[Color] = None, collection: Optional[str] = None, show_wire: bool = True) -> list[bpy.types.Object]: """Draw the polyhedron associated with the scene object. Parameters diff --git a/src/compas_blender/scene/polylineobject.py b/src/compas_blender/scene/polylineobject.py index 61218cce996..51ec93c40d1 100644 --- a/src/compas_blender/scene/polylineobject.py +++ b/src/compas_blender/scene/polylineobject.py @@ -3,14 +3,13 @@ import bpy # type: ignore -from compas.geometry import Polyline from compas.colors import Color - +from compas.geometry import Polyline from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class PolylineObject(BlenderSceneObject, GeometryObject): """Scene object for drawing polylines in Blender. diff --git a/src/compas_blender/scene/sceneobject.py b/src/compas_blender/scene/sceneobject.py index 255d0b28999..6edf60dfe64 100644 --- a/src/compas_blender/scene/sceneobject.py +++ b/src/compas_blender/scene/sceneobject.py @@ -1,14 +1,13 @@ from typing import Any -from typing import Union from typing import Optional +from typing import Union import bpy # type: ignore -import compas_blender +import compas_blender from compas.colors import Color -from compas.scene import SceneObject from compas.geometry import Transformation - +from compas.scene import SceneObject from compas_blender import conversions @@ -40,9 +39,7 @@ def __init__(self, **kwargs: Any): # Objects # ============================================================================= - def create_object( - self, geometry: Union[bpy.types.Mesh, bpy.types.Curve], name: Optional[str] = None - ) -> bpy.types.Object: + def create_object(self, geometry: Union[bpy.types.Mesh, bpy.types.Curve], name: Optional[str] = None) -> bpy.types.Object: """Add an object to the Blender scene. Parameters @@ -105,9 +102,7 @@ def update_object( self.set_object_tranformation(obj, transformation) self.add_object_to_collection(obj, collection) - def add_object_to_collection( - self, obj: bpy.types.Object, name: Optional[str] = None, do_unlink: Optional[bool] = True - ) -> bpy.types.Collection: + def add_object_to_collection(self, obj: bpy.types.Object, name: Optional[str] = None, do_unlink: Optional[bool] = True) -> bpy.types.Collection: """Add an object to a collection. Parameters diff --git a/src/compas_blender/scene/sphereobject.py b/src/compas_blender/scene/sphereobject.py index dfe2eb43154..23faba0974f 100644 --- a/src/compas_blender/scene/sphereobject.py +++ b/src/compas_blender/scene/sphereobject.py @@ -1,16 +1,15 @@ -from typing import Optional from typing import Any +from typing import Optional import bpy # type: ignore -from compas.geometry import Sphere from compas.colors import Color - +from compas.geometry import Sphere from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class SphereObject(BlenderSceneObject, GeometryObject): """Scene object for drawing sphere shapes in Blender. diff --git a/src/compas_blender/scene/surfaceobject.py b/src/compas_blender/scene/surfaceobject.py index ce0c87602eb..94160250b9e 100644 --- a/src/compas_blender/scene/surfaceobject.py +++ b/src/compas_blender/scene/surfaceobject.py @@ -3,14 +3,13 @@ import bpy # type: ignore -from compas.geometry import Surface from compas.colors import Color - +from compas.geometry import Surface from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class SurfaceObject(BlenderSceneObject, GeometryObject): """Scene object for drawing surfaces in Blender. diff --git a/src/compas_blender/scene/torusobject.py b/src/compas_blender/scene/torusobject.py index 1fec886ef85..afffad83505 100644 --- a/src/compas_blender/scene/torusobject.py +++ b/src/compas_blender/scene/torusobject.py @@ -1,16 +1,15 @@ -from typing import Optional from typing import Any +from typing import Optional import bpy # type: ignore -from compas.geometry import Torus from compas.colors import Color - +from compas.geometry import Torus from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class TorusObject(BlenderSceneObject, GeometryObject): """Scene object for drawing torus shapes in Blender. diff --git a/src/compas_blender/scene/vectorobject.py b/src/compas_blender/scene/vectorobject.py index e16325855ca..599434f3d0a 100644 --- a/src/compas_blender/scene/vectorobject.py +++ b/src/compas_blender/scene/vectorobject.py @@ -3,16 +3,15 @@ import bpy # type: ignore +from compas.colors import Color +from compas.geometry import Line from compas.geometry import Point from compas.geometry import Vector -from compas.geometry import Line -from compas.colors import Color - from compas.scene import GeometryObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class VectorObject(BlenderSceneObject, GeometryObject): """Scene object for drawing vectors in Blender. diff --git a/src/compas_blender/scene/volmeshobject.py b/src/compas_blender/scene/volmeshobject.py index eab52c10b47..545a253c132 100644 --- a/src/compas_blender/scene/volmeshobject.py +++ b/src/compas_blender/scene/volmeshobject.py @@ -1,25 +1,23 @@ -from typing import Optional -from typing import Union from typing import Any -from typing import List from typing import Dict +from typing import List +from typing import Optional from typing import Tuple +from typing import Union import bpy # type: ignore import compas_blender - +from compas.colors import Color +from compas.geometry import Line from compas.geometry import add_vectors -from compas.geometry import scale_vector from compas.geometry import centroid_points -from compas.geometry import Line -from compas.colors import Color - +from compas.geometry import scale_vector from compas.scene import VolMeshObject as BaseVolMeshObject -from .sceneobject import BlenderSceneObject - from compas_blender import conversions +from .sceneobject import BlenderSceneObject + class VolMeshObject(BlenderSceneObject, BaseVolMeshObject): """A scene object for drawing volumetric mesh data structures in Blender. @@ -91,9 +89,7 @@ def clear_cells(self): # draw # ========================================================================== - def draw( - self, cells: Optional[List[int]] = None, color: Optional[Color] = None, collection: Optional[str] = None - ) -> list[bpy.types.Object]: + def draw(self, cells: Optional[List[int]] = None, color: Optional[Color] = None, collection: Optional[str] = None) -> list[bpy.types.Object]: """Draw a selection of cells. Parameters @@ -196,9 +192,7 @@ def draw_edges( for u, v in edges or self.volmesh.edges(): # type: ignore name = f"{self.volmesh.name}.edge.{u}-{v}" # type: ignore color = self.edgecolor[u, v] # type: ignore - curve = conversions.line_to_blender_curve( - Line(self.volmesh.vertices_attributes("xyz")[u], self.volmesh.vertices_attributes("xyz")[v]) - ) + curve = conversions.line_to_blender_curve(Line(self.volmesh.vertices_attributes("xyz")[u], self.volmesh.vertices_attributes("xyz")[v])) obj = self.create_object(curve, name=name) self.update_object(obj, color=color, collection=collection) # type: ignore diff --git a/src/compas_blender/utilities/drawing.py b/src/compas_blender/utilities/drawing.py index 3c893fe2929..4b88f823e2a 100644 --- a/src/compas_blender/utilities/drawing.py +++ b/src/compas_blender/utilities/drawing.py @@ -1,17 +1,15 @@ from typing import Dict from typing import List -from typing import Union -from typing import Tuple from typing import Text +from typing import Tuple +from typing import Union import bpy # type: ignore -from compas_blender.collections import create_collection - from compas.geometry import centroid_points from compas.geometry import distance_point_point from compas.geometry import subtract_vectors - +from compas_blender.collections import create_collection RGBColor = Union[Tuple[int, int, int], Tuple[float, float, float]] diff --git a/src/compas_ghpython/__init__.py b/src/compas_ghpython/__init__.py index b22a705d2df..9ba75898e75 100644 --- a/src/compas_ghpython/__init__.py +++ b/src/compas_ghpython/__init__.py @@ -78,9 +78,7 @@ def get_grasshopper_managedplugin_path(version): raise NotImplementedError if not os.path.exists(gh_managedplugin_path): - raise Exception( - "The Grasshopper (managed) Plug-in folder does not exist in this location: {}".format(gh_managedplugin_path) - ) + raise Exception("The Grasshopper (managed) Plug-in folder does not exist in this location: {}".format(gh_managedplugin_path)) return gh_managedplugin_path diff --git a/src/compas_ghpython/scene/boxobject.py b/src/compas_ghpython/scene/boxobject.py index 9b3938dc08b..5cc694f9b41 100644 --- a/src/compas_ghpython/scene/boxobject.py +++ b/src/compas_ghpython/scene/boxobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/brepobject.py b/src/compas_ghpython/scene/brepobject.py index c3b83dad4fb..939dd4e5bbf 100644 --- a/src/compas_ghpython/scene/brepobject.py +++ b/src/compas_ghpython/scene/brepobject.py @@ -2,9 +2,9 @@ from __future__ import division from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/capsuleobject.py b/src/compas_ghpython/scene/capsuleobject.py index 12b37b5d347..25518e63dcd 100644 --- a/src/compas_ghpython/scene/capsuleobject.py +++ b/src/compas_ghpython/scene/capsuleobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/circleobject.py b/src/compas_ghpython/scene/circleobject.py index 36e5363a57c..f74fb3e0dba 100644 --- a/src/compas_ghpython/scene/circleobject.py +++ b/src/compas_ghpython/scene/circleobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/coneobject.py b/src/compas_ghpython/scene/coneobject.py index bf66677ddd5..c19a318ac8a 100644 --- a/src/compas_ghpython/scene/coneobject.py +++ b/src/compas_ghpython/scene/coneobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/curveobject.py b/src/compas_ghpython/scene/curveobject.py index 48ff6b33681..ede00aaaaea 100644 --- a/src/compas_ghpython/scene/curveobject.py +++ b/src/compas_ghpython/scene/curveobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/cylinderobject.py b/src/compas_ghpython/scene/cylinderobject.py index ef859695392..19f26846682 100644 --- a/src/compas_ghpython/scene/cylinderobject.py +++ b/src/compas_ghpython/scene/cylinderobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/ellipseobject.py b/src/compas_ghpython/scene/ellipseobject.py index eb19f36c353..e32a4465305 100644 --- a/src/compas_ghpython/scene/ellipseobject.py +++ b/src/compas_ghpython/scene/ellipseobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/frameobject.py b/src/compas_ghpython/scene/frameobject.py index 7e89f84ec6e..26eaf85cbb6 100644 --- a/src/compas_ghpython/scene/frameobject.py +++ b/src/compas_ghpython/scene/frameobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/graphobject.py b/src/compas_ghpython/scene/graphobject.py index 9329b69204a..ac9396b651e 100644 --- a/src/compas_ghpython/scene/graphobject.py +++ b/src/compas_ghpython/scene/graphobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GraphObject as BaseGraphObject from compas_rhino import conversions -from compas.scene import GraphObject as BaseGraphObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/lineobject.py b/src/compas_ghpython/scene/lineobject.py index 58d539b76ce..ce838408a13 100644 --- a/src/compas_ghpython/scene/lineobject.py +++ b/src/compas_ghpython/scene/lineobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/meshobject.py b/src/compas_ghpython/scene/meshobject.py index 04c219996be..d4bcd6a0182 100644 --- a/src/compas_ghpython/scene/meshobject.py +++ b/src/compas_ghpython/scene/meshobject.py @@ -2,10 +2,11 @@ from __future__ import division from __future__ import print_function -from compas.scene import MeshObject as BaseMeshObject from compas.colors import Color +from compas.scene import MeshObject as BaseMeshObject from compas_rhino import conversions from compas_rhino.scene.helpers import ngon + from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/planeobject.py b/src/compas_ghpython/scene/planeobject.py index 123d0a7ee23..cd2472cf9a2 100644 --- a/src/compas_ghpython/scene/planeobject.py +++ b/src/compas_ghpython/scene/planeobject.py @@ -1,12 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.geometry import Frame +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject -from compas.geometry import Frame class PlaneObject(GHSceneObject, GeometryObject): @@ -42,9 +42,7 @@ def draw(self): List of created Rhino geometries. """ frame = Frame.from_plane(self._item) - normal = conversions.line_to_rhino( - [frame.to_world_coordinates([0, 0, 0]), frame.to_world_coordinates([0, 0, self.scale])] - ) + normal = conversions.line_to_rhino([frame.to_world_coordinates([0, 0, 0]), frame.to_world_coordinates([0, 0, self.scale])]) vertices = [ frame.to_world_coordinates([-self.scale, -self.scale, 0]), diff --git a/src/compas_ghpython/scene/pointobject.py b/src/compas_ghpython/scene/pointobject.py index 832274c1f0b..e16c3f6c438 100644 --- a/src/compas_ghpython/scene/pointobject.py +++ b/src/compas_ghpython/scene/pointobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/polygonobject.py b/src/compas_ghpython/scene/polygonobject.py index 4429c9be9b2..5ca5ab8c9ad 100644 --- a/src/compas_ghpython/scene/polygonobject.py +++ b/src/compas_ghpython/scene/polygonobject.py @@ -1,12 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.colors import Color - +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/polyhedronobject.py b/src/compas_ghpython/scene/polyhedronobject.py index f70a75a4622..1cf106f37e6 100644 --- a/src/compas_ghpython/scene/polyhedronobject.py +++ b/src/compas_ghpython/scene/polyhedronobject.py @@ -1,12 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.colors import Color - +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/polylineobject.py b/src/compas_ghpython/scene/polylineobject.py index 6d15b7fb0ba..86d50d7f9b1 100644 --- a/src/compas_ghpython/scene/polylineobject.py +++ b/src/compas_ghpython/scene/polylineobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/sceneobject.py b/src/compas_ghpython/scene/sceneobject.py index ef1b67a26e8..1fde7497460 100644 --- a/src/compas_ghpython/scene/sceneobject.py +++ b/src/compas_ghpython/scene/sceneobject.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.scene import SceneObject diff --git a/src/compas_ghpython/scene/sphereobject.py b/src/compas_ghpython/scene/sphereobject.py index ec5f099222c..702d39d1898 100644 --- a/src/compas_ghpython/scene/sphereobject.py +++ b/src/compas_ghpython/scene/sphereobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/surfaceobject.py b/src/compas_ghpython/scene/surfaceobject.py index c751376aea8..7d2cf3fd79f 100644 --- a/src/compas_ghpython/scene/surfaceobject.py +++ b/src/compas_ghpython/scene/surfaceobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/torusobject.py b/src/compas_ghpython/scene/torusobject.py index fb5101847dc..bbb48cd9c88 100644 --- a/src/compas_ghpython/scene/torusobject.py +++ b/src/compas_ghpython/scene/torusobject.py @@ -1,10 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import GeometryObject from compas_rhino import conversions -from compas.scene import GeometryObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/vectorobject.py b/src/compas_ghpython/scene/vectorobject.py index d5a242e2c88..aeeff71749b 100644 --- a/src/compas_ghpython/scene/vectorobject.py +++ b/src/compas_ghpython/scene/vectorobject.py @@ -2,10 +2,10 @@ from __future__ import division from __future__ import print_function -from compas_rhino import conversions - from compas.geometry import Point from compas.scene import GeometryObject +from compas_rhino import conversions + from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/scene/volmeshobject.py b/src/compas_ghpython/scene/volmeshobject.py index af7c1b739fa..adebfa1e8d1 100644 --- a/src/compas_ghpython/scene/volmeshobject.py +++ b/src/compas_ghpython/scene/volmeshobject.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function +from compas.scene import VolMeshObject as BaseVolMeshObject from compas_rhino import conversions from compas_rhino.scene.helpers import ngon -from compas.scene import VolMeshObject as BaseVolMeshObject from .sceneobject import GHSceneObject diff --git a/src/compas_ghpython/sets.py b/src/compas_ghpython/sets.py index 2b295edeff4..e0df9740b87 100644 --- a/src/compas_ghpython/sets.py +++ b/src/compas_ghpython/sets.py @@ -2,8 +2,8 @@ from __future__ import division from __future__ import print_function -import System # type: ignore import Grasshopper # type: ignore +import System # type: ignore def list_to_ghtree(items, none_and_holes=False, base_path=[0]): diff --git a/src/compas_rhino/conduits/base.py b/src/compas_rhino/conduits/base.py index d667eeaba89..e8a389f35a4 100644 --- a/src/compas_rhino/conduits/base.py +++ b/src/compas_rhino/conduits/base.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import time from contextlib import contextmanager diff --git a/src/compas_rhino/conduits/faces.py b/src/compas_rhino/conduits/faces.py index da5ee140876..238981a3971 100644 --- a/src/compas_rhino/conduits/faces.py +++ b/src/compas_rhino/conduits/faces.py @@ -1,11 +1,11 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from System.Drawing.Color import FromArgb from Rhino.Geometry import Point3d +from System.Drawing.Color import FromArgb -from compas.utilities import iterable_like +from compas.itertools import iterable_like from compas.utilities import is_sequence_of_iterable from .base import BaseConduit diff --git a/src/compas_rhino/conduits/labels.py b/src/compas_rhino/conduits/labels.py index c9fac7264e8..116d2187336 100644 --- a/src/compas_rhino/conduits/labels.py +++ b/src/compas_rhino/conduits/labels.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from System.Drawing.Color import FromArgb from Rhino.Geometry import Point3d +from System.Drawing.Color import FromArgb -from compas.utilities import iterable_like +from compas.itertools import iterable_like from compas.utilities import is_sequence_of_iterable + from .base import BaseConduit @@ -78,10 +79,7 @@ def color(self, color): # the first item in the list should be a tuple of colors # if not, wrap the tuple color = [color] - color = [ - (FromArgb(*bg), FromArgb(*text)) - for bg, text in iterable_like(self.labels, color, (self.default_color, self.default_textcolor)) - ] + color = [(FromArgb(*bg), FromArgb(*text)) for bg, text in iterable_like(self.labels, color, (self.default_color, self.default_textcolor))] self._color = color def DrawForeground(self, e): diff --git a/src/compas_rhino/conduits/lines.py b/src/compas_rhino/conduits/lines.py index 16f9a0fa4ab..57aca6f366b 100644 --- a/src/compas_rhino/conduits/lines.py +++ b/src/compas_rhino/conduits/lines.py @@ -1,13 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division - -from System.Drawing.Color import FromArgb +from __future__ import print_function from Rhino.Geometry import Point3d +from System.Drawing.Color import FromArgb +from compas.itertools import iterable_like from compas.utilities import is_sequence_of_iterable -from compas.utilities import iterable_like + from .base import BaseConduit diff --git a/src/compas_rhino/conduits/points.py b/src/compas_rhino/conduits/points.py index 7d677af9783..383a19266a1 100644 --- a/src/compas_rhino/conduits/points.py +++ b/src/compas_rhino/conduits/points.py @@ -1,15 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from System.Drawing.Color import FromArgb - -from Rhino.Geometry import Point3d from Rhino.Display.PointStyle import Simple +from Rhino.Geometry import Point3d +from System.Drawing.Color import FromArgb +from compas.itertools import iterable_like from compas.utilities import color_to_rgb -from compas.utilities import iterable_like from compas.utilities.coercing import is_sequence_of_iterable + from .base import BaseConduit diff --git a/src/compas_rhino/conversions/breps.py b/src/compas_rhino/conversions/breps.py index 9b42590edae..8d4c32affe7 100644 --- a/src/compas_rhino/conversions/breps.py +++ b/src/compas_rhino/conversions/breps.py @@ -5,12 +5,10 @@ import scriptcontext as sc # type: ignore from .exceptions import ConversionError - from .shapes import cone_to_compas from .shapes import cylinder_to_compas from .shapes import sphere_to_compas - # ============================================================================= # To Rhino # ============================================================================= diff --git a/src/compas_rhino/conversions/curves.py b/src/compas_rhino/conversions/curves.py index 3af65c86327..fc1335f5899 100644 --- a/src/compas_rhino/conversions/curves.py +++ b/src/compas_rhino/conversions/curves.py @@ -1,27 +1,24 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import scriptcontext as sc # type: ignore import Rhino # type: ignore +import scriptcontext as sc # type: ignore -from compas.geometry import Line +from compas.geometry import Arc from compas.geometry import Circle from compas.geometry import Ellipse -from compas.geometry import Polyline -from compas.geometry import Arc +from compas.geometry import Line from compas.geometry import NurbsCurve +from compas.geometry import Polyline from .exceptions import ConversionError - -from .geometry import point_to_rhino -from .geometry import plane_to_rhino from .geometry import frame_to_rhino_plane - -from .geometry import point_to_compas from .geometry import plane_to_compas from .geometry import plane_to_compas_frame - +from .geometry import plane_to_rhino +from .geometry import point_to_compas +from .geometry import point_to_rhino # ============================================================================= # To Rhino diff --git a/src/compas_rhino/conversions/exceptions.py b/src/compas_rhino/conversions/exceptions.py index 0c468546caf..00fe6125e09 100644 --- a/src/compas_rhino/conversions/exceptions.py +++ b/src/compas_rhino/conversions/exceptions.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function class ConversionError(Exception): diff --git a/src/compas_rhino/conversions/extrusions.py b/src/compas_rhino/conversions/extrusions.py index ba8b1003571..caf71dfb448 100644 --- a/src/compas_rhino/conversions/extrusions.py +++ b/src/compas_rhino/conversions/extrusions.py @@ -1,15 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import scriptcontext as sc # type: ignore import Rhino # type: ignore +import scriptcontext as sc # type: ignore from .shapes import box_to_compas from .shapes import cylinder_to_compas from .shapes import torus_to_compas - # ============================================================================= # To Rhino # ============================================================================= diff --git a/src/compas_rhino/conversions/geometry.py b/src/compas_rhino/conversions/geometry.py index 700c8368f91..118e4302e84 100644 --- a/src/compas_rhino/conversions/geometry.py +++ b/src/compas_rhino/conversions/geometry.py @@ -1,15 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import Rhino # type: ignore -from compas.geometry import Point -from compas.geometry import Vector -from compas.geometry import Plane from compas.geometry import Frame +from compas.geometry import Plane +from compas.geometry import Point from compas.geometry import Polygon - +from compas.geometry import Vector # ============================================================================= # To Rhino diff --git a/src/compas_rhino/conversions/meshes.py b/src/compas_rhino/conversions/meshes.py index cce023c3b43..bd9370cca57 100644 --- a/src/compas_rhino/conversions/meshes.py +++ b/src/compas_rhino/conversions/meshes.py @@ -14,6 +14,7 @@ from compas.datastructures import Mesh from compas.geometry import centroid_polygon from compas.itertools import pairwise + from .geometry import vector_to_compas diff --git a/src/compas_rhino/conversions/shapes.py b/src/compas_rhino/conversions/shapes.py index bcb088bf22a..955568fbf6c 100644 --- a/src/compas_rhino/conversions/shapes.py +++ b/src/compas_rhino/conversions/shapes.py @@ -1,30 +1,29 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import scriptcontext as sc # type: ignore import Rhino # type: ignore +import scriptcontext as sc # type: ignore -from compas.geometry import Plane -from compas.geometry import Circle from compas.geometry import Box -from compas.geometry import Sphere +from compas.geometry import Circle from compas.geometry import Cone from compas.geometry import Cylinder -from compas.geometry import Torus from compas.geometry import Frame +from compas.geometry import Plane +from compas.geometry import Sphere +from compas.geometry import Torus + +from .curves import circle_to_rhino +from .curves import line_to_rhino_curve # from .geometry import plane_to_rhino from .geometry import frame_to_rhino -from .geometry import point_to_rhino -from .geometry import plane_to_compas_frame from .geometry import plane_to_compas +from .geometry import plane_to_compas_frame from .geometry import point_to_compas +from .geometry import point_to_rhino from .geometry import vector_to_compas -from .curves import line_to_rhino_curve - -from .curves import circle_to_rhino - # ============================================================================= # To Rhino @@ -167,9 +166,7 @@ def capsule_to_rhino_brep(capsule): line = capsule.axis curve = line_to_rhino_curve(line) - return Rhino.Geometry.Brep.CreatePipe( - curve, radius, False, Rhino.Geometry.PipeCapMode.Round, False, abs_tol, ang_tol - ) + return Rhino.Geometry.Brep.CreatePipe(curve, radius, False, Rhino.Geometry.PipeCapMode.Round, False, abs_tol, ang_tol) def torus_to_rhino(torus): diff --git a/src/compas_rhino/conversions/surfaces.py b/src/compas_rhino/conversions/surfaces.py index 7e4cb282c2e..5843e3ab27f 100644 --- a/src/compas_rhino/conversions/surfaces.py +++ b/src/compas_rhino/conversions/surfaces.py @@ -1,21 +1,18 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import Rhino # type: ignore -from compas.tolerance import TOL - -from compas.geometry import Point -from compas.geometry import NurbsSurface from compas.datastructures import Mesh +from compas.geometry import NurbsSurface +from compas.geometry import Point +from compas.tolerance import TOL from compas.utilities import memoize from .exceptions import ConversionError - -from .geometry import point_to_rhino from .geometry import point_to_compas - +from .geometry import point_to_rhino # ============================================================================= # To Rhino diff --git a/src/compas_rhino/geometry/brep/brep.py b/src/compas_rhino/geometry/brep/brep.py index 3250b0aab83..1a7f8e589ce 100644 --- a/src/compas_rhino/geometry/brep/brep.py +++ b/src/compas_rhino/geometry/brep/brep.py @@ -4,32 +4,30 @@ import Rhino # type: ignore -from compas.geometry import Frame from compas.geometry import Brep -from compas.geometry import BrepTrimmingError from compas.geometry import BrepError +from compas.geometry import BrepTrimmingError +from compas.geometry import Frame from compas.geometry import Plane from compas.geometry import Point - +from compas.tolerance import TOL from compas_rhino.conversions import box_to_rhino -from compas_rhino.conversions import transformation_to_rhino -from compas_rhino.conversions import plane_to_rhino +from compas_rhino.conversions import curve_to_compas +from compas_rhino.conversions import curve_to_rhino from compas_rhino.conversions import cylinder_to_rhino -from compas_rhino.conversions import sphere_to_rhino from compas_rhino.conversions import mesh_to_compas from compas_rhino.conversions import mesh_to_rhino +from compas_rhino.conversions import plane_to_rhino from compas_rhino.conversions import point_to_rhino -from compas_rhino.conversions import curve_to_compas -from compas_rhino.conversions import curve_to_rhino +from compas_rhino.conversions import sphere_to_rhino +from compas_rhino.conversions import transformation_to_rhino from compas_rhino.conversions import vector_to_rhino from .builder import _RhinoBrepBuilder -from .face import RhinoBrepFace from .edge import RhinoBrepEdge -from .vertex import RhinoBrepVertex +from .face import RhinoBrepFace from .loop import RhinoBrepLoop - -TOLERANCE = 1e-6 +from .vertex import RhinoBrepVertex class RhinoBrep(Brep): @@ -242,7 +240,7 @@ def from_extrusion(cls, curve, vector, cap_ends=True): raise BrepError("Failed to create extrusion from curve: {} and vector: {}".format(curve, vector)) rhino_brep = extrusion.ToBrep() if cap_ends: - capped = rhino_brep.CapPlanarHoles(TOLERANCE) + capped = rhino_brep.CapPlanarHoles(TOL.absolute) if capped: rhino_brep = capped return cls.from_native(rhino_brep) @@ -327,7 +325,7 @@ def contains(self, object): raise BrepError("Cannot check for containment if brep is not manifold or is not closed") if isinstance(object, Point): - return self._brep.IsPointInside(point_to_rhino(object), TOLERANCE, False) + return self._brep.IsPointInside(point_to_rhino(object), TOL.absolute, False) else: raise NotImplementedError @@ -365,55 +363,78 @@ def transform(self, matrix): """ self._brep.Transform(transformation_to_rhino(matrix)) - def trim(self, plane, tolerance=TOLERANCE): + def trim(self, plane, tolerance=None): """Trim this brep by the given trimming plane. Parameters ---------- plane : :class:`compas.geometry.Frame` or :class:`compas.geometry.Plane` The frame or plane to use when trimming. The discarded bit is in the direction of the frame's normal. + tolerance : float, optional + The precision to use for the trimming operation. Defaults to `TOL.absolute`. - tolerance : float - The precision to use for the trimming operation. + Notes + ----- + Trimming operation may result in multiple results (breps). When trimming, only one is used. + The used bit is the one on the opposite side of the cutting plane's normal. Returns ------- None - """ - results = self.trimmed(plane, tolerance) - if not results: - raise BrepTrimmingError("Trim operation ended with no result") + Raises + ------ + BrepTrimmingError + If the trimming operation ended with no result. - self._brep = results[0].native_brep + See Also + -------- + :meth:`compas_rhino.geometry.RhinoBrep.trimmed` + + """ + result = self.trimmed(plane, tolerance) + self._brep = result.native_brep - def trimmed(self, plane, tolerance=TOLERANCE): + def trimmed(self, plane, tolerance=None): """Returns a trimmed copy of this brep by the given trimming plane. Parameters ---------- plane : :class:`compas.geometry.Frame` or :class:`compas.geometry.Plane` The frame or plane to use when trimming. The discarded bit is in the direction of the plane's normal. + tolerance : float, optional + The precision to use for the trimming operation. Defaults to `TOL.absolute`. - tolerance : float - The precision to use for the trimming operation. + Notes + ----- + Trimming operation may result in multiple results (breps). When trimming, only one is used. + The used bit is the one on the opposite side of the cutting plane's normal. Returns ------- :class:`~compas_rhino.geometry.RhinoBrep` + Raises + ------ + BrepTrimmingError + If the trimming operation ended with no result. + + See Also + -------- + :meth:`compas_rhino.geometry.RhinoBrep.trim` + """ + tolerance = tolerance or TOL.absolute if isinstance(plane, Frame): plane = Plane.from_frame(plane) results = self._brep.Trim(plane_to_rhino(plane), tolerance) - - breps = [] - for result in results: - capped = result.CapPlanarHoles(TOLERANCE) - if capped: - result = capped - breps.append(RhinoBrep.from_native(result)) - return breps + if not results: + raise BrepTrimmingError("Trim operation ended with no result") + result = results[0] + capped = result.CapPlanarHoles(tolerance) + if capped: + result = capped + return RhinoBrep.from_native(result) @classmethod def from_boolean_difference(cls, breps_a, breps_b): @@ -439,7 +460,7 @@ def from_boolean_difference(cls, breps_a, breps_b): resulting_breps = Rhino.Geometry.Brep.CreateBooleanDifference( [b.native_brep for b in breps_a], [b.native_brep for b in breps_b], - TOLERANCE, + TOL.absolute, ) return [RhinoBrep.from_native(brep) for brep in resulting_breps] @@ -465,7 +486,7 @@ def from_boolean_union(cls, breps_a, breps_b): if not isinstance(breps_b, list): breps_b = [breps_b] - resulting_breps = Rhino.Geometry.Brep.CreateBooleanUnion([b.native_brep for b in breps_a + breps_b], TOLERANCE) + resulting_breps = Rhino.Geometry.Brep.CreateBooleanUnion([b.native_brep for b in breps_a + breps_b], TOL.absolute) return [RhinoBrep.from_native(brep) for brep in resulting_breps] @classmethod @@ -492,7 +513,7 @@ def from_boolean_intersection(cls, breps_a, breps_b): resulting_breps = Rhino.Geometry.Brep.CreateBooleanIntersection( [b.native_brep for b in breps_a], [b.native_brep for b in breps_b], - TOLERANCE, + TOL.absolute, ) return [RhinoBrep.from_native(brep) for brep in resulting_breps] @@ -530,5 +551,5 @@ def split(self, cutter): list of zero or more resulting Breps. """ - resulting_breps = self._brep.Split(cutter.native_brep, TOLERANCE) + resulting_breps = self._brep.Split(cutter.native_brep, TOL.absolute) return [RhinoBrep.from_native(brep) for brep in resulting_breps] diff --git a/src/compas_rhino/geometry/brep/edge.py b/src/compas_rhino/geometry/brep/edge.py index d2f86101971..0e096b1437c 100644 --- a/src/compas_rhino/geometry/brep/edge.py +++ b/src/compas_rhino/geometry/brep/edge.py @@ -4,25 +4,24 @@ import Rhino # type: ignore +from compas.geometry import Arc from compas.geometry import BrepEdge -from compas.geometry import Line from compas.geometry import Circle from compas.geometry import Ellipse from compas.geometry import Frame -from compas.geometry import Arc - -from compas_rhino.geometry import RhinoNurbsCurve -from compas_rhino.conversions import curve_to_compas_line -from compas_rhino.conversions import plane_to_compas_frame +from compas.geometry import Line +from compas_rhino.conversions import arc_to_compas +from compas_rhino.conversions import arc_to_rhino from compas_rhino.conversions import circle_to_compas +from compas_rhino.conversions import circle_to_rhino +from compas_rhino.conversions import curve_to_compas_line from compas_rhino.conversions import ellipse_to_compas from compas_rhino.conversions import ellipse_to_rhino -from compas_rhino.conversions import circle_to_rhino from compas_rhino.conversions import frame_to_rhino_plane from compas_rhino.conversions import line_to_rhino -from compas_rhino.conversions import arc_to_compas -from compas_rhino.conversions import arc_to_rhino +from compas_rhino.conversions import plane_to_compas_frame from compas_rhino.conversions import point_to_compas +from compas_rhino.geometry import RhinoNurbsCurve from .vertex import RhinoBrepVertex diff --git a/src/compas_rhino/geometry/brep/face.py b/src/compas_rhino/geometry/brep/face.py index 5c82c7c0226..de9b3fe92b2 100644 --- a/src/compas_rhino/geometry/brep/face.py +++ b/src/compas_rhino/geometry/brep/face.py @@ -6,23 +6,21 @@ from compas.geometry import Brep from compas.geometry import BrepFace -from compas.geometry import Sphere from compas.geometry import Cylinder from compas.geometry import Frame +from compas.geometry import Sphere from compas.geometry import SurfaceType - - -from compas_rhino.geometry import RhinoNurbsSurface -from compas_rhino.geometry.surfaces import RhinoSurface -from compas_rhino.conversions import plane_to_compas_frame -from compas_rhino.conversions import sphere_to_compas from compas_rhino.conversions import cylinder_to_compas from compas_rhino.conversions import cylinder_to_rhino -from compas_rhino.conversions import sphere_to_rhino from compas_rhino.conversions import frame_to_rhino_plane +from compas_rhino.conversions import plane_to_compas_frame +from compas_rhino.conversions import sphere_to_compas +from compas_rhino.conversions import sphere_to_rhino +from compas_rhino.geometry import RhinoNurbsSurface +from compas_rhino.geometry.surfaces import RhinoSurface -from .loop import RhinoBrepLoop from .edge import RhinoBrepEdge +from .loop import RhinoBrepLoop class RhinoBrepFace(BrepFace): @@ -89,9 +87,7 @@ def __from_data__(cls, data, builder): """ instance = cls() - instance._surface = instance._make_surface__from_data__( - data["surface_type"], data["surface"], data["uv_domain"], data["frame"] - ) + instance._surface = instance._make_surface__from_data__(data["surface_type"], data["surface"], data["uv_domain"], data["frame"]) face_builder = builder.add_face(instance._surface) for loop_data in data["loops"]: RhinoBrepLoop.__from_data__(loop_data, face_builder) @@ -214,9 +210,7 @@ def _get_surface_geometry(surface): if success: return "cylinder", cylinder_to_compas(cast_surface), uv_domain, cast_surface.BasePlane success, cast_surface = surface.TryGetTorus() - raise NotImplementedError( - "Support for surface type: {} is not yet implemented.".format(surface.__class__.__name__) - ) + raise NotImplementedError("Support for surface type: {} is not yet implemented.".format(surface.__class__.__name__)) def _make_surface__from_data__(self, surface_type, surface_data, uv_domain, frame_data): u_domain, v_domain = uv_domain diff --git a/src/compas_rhino/geometry/brep/loop.py b/src/compas_rhino/geometry/brep/loop.py index 7e86d6145c9..65a9c35c8fc 100644 --- a/src/compas_rhino/geometry/brep/loop.py +++ b/src/compas_rhino/geometry/brep/loop.py @@ -6,8 +6,8 @@ from compas.geometry import BrepLoop -from .trim import RhinoBrepTrim from .edge import RhinoBrepEdge +from .trim import RhinoBrepTrim class LoopType(object): @@ -87,9 +87,7 @@ def __from_data__(cls, data, builder): """ instance = cls() - instance._type = ( - Rhino.Geometry.BrepLoopType.Outer if data["type"] == "Outer" else Rhino.Geometry.BrepLoopType.Inner - ) + instance._type = Rhino.Geometry.BrepLoopType.Outer if data["type"] == "Outer" else Rhino.Geometry.BrepLoopType.Inner loop_builder = builder.add_loop(instance._type) for trim_data in data["trims"]: RhinoBrepTrim.__from_data__(trim_data, loop_builder) diff --git a/src/compas_rhino/geometry/brep/vertex.py b/src/compas_rhino/geometry/brep/vertex.py index 6ebe8edc9c2..7ae9866efa2 100644 --- a/src/compas_rhino/geometry/brep/vertex.py +++ b/src/compas_rhino/geometry/brep/vertex.py @@ -2,8 +2,8 @@ from __future__ import division from __future__ import print_function -from compas.geometry import Point from compas.geometry import BrepVertex +from compas.geometry import Point from compas_rhino.conversions import point_to_compas diff --git a/src/compas_rhino/geometry/curves/curve.py b/src/compas_rhino/geometry/curves/curve.py index 6c4dd2d4b01..8ef652a8e23 100644 --- a/src/compas_rhino/geometry/curves/curve.py +++ b/src/compas_rhino/geometry/curves/curve.py @@ -1,17 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from compas.geometry import Curve from compas.geometry import Plane - -from compas_rhino.conversions import point_to_rhino -from compas_rhino.conversions import point_to_compas -from compas_rhino.conversions import vector_to_compas -from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import box_to_compas from compas_rhino.conversions import plane_to_compas_frame from compas_rhino.conversions import plane_to_rhino -from compas_rhino.conversions import box_to_compas +from compas_rhino.conversions import point_to_compas +from compas_rhino.conversions import point_to_rhino +from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import vector_to_compas class RhinoCurve(Curve): diff --git a/src/compas_rhino/geometry/curves/nurbs.py b/src/compas_rhino/geometry/curves/nurbs.py index b4a975e831a..f1e86b9466a 100644 --- a/src/compas_rhino/geometry/curves/nurbs.py +++ b/src/compas_rhino/geometry/curves/nurbs.py @@ -1,17 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from itertools import groupby import Rhino.Geometry # type: ignore -from compas.geometry import Point from compas.geometry import NurbsCurve - -from compas_rhino.conversions import point_to_rhino -from compas_rhino.conversions import point_to_compas +from compas.geometry import Point from compas_rhino.conversions import line_to_rhino +from compas_rhino.conversions import point_to_compas +from compas_rhino.conversions import point_to_rhino from .curve import RhinoCurve diff --git a/src/compas_rhino/geometry/surfaces/nurbs.py b/src/compas_rhino/geometry/surfaces/nurbs.py index c82b7ff273b..037263cff99 100644 --- a/src/compas_rhino/geometry/surfaces/nurbs.py +++ b/src/compas_rhino/geometry/surfaces/nurbs.py @@ -1,18 +1,17 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from itertools import groupby import Rhino.Geometry # type: ignore -from compas.geometry import Point from compas.geometry import NurbsSurface +from compas.geometry import Point from compas.geometry import knots_and_mults_to_knotvector -from compas.utilities import flatten - -from compas_rhino.conversions import point_to_rhino +from compas.itertools import flatten from compas_rhino.conversions import point_to_compas +from compas_rhino.conversions import point_to_rhino from .surface import RhinoSurface @@ -311,9 +310,7 @@ def from_parameters( """ surface = cls() - surface.rhino_surface = rhino_surface_from_parameters( - points, weights, knots_u, knots_v, mults_u, mults_v, degree_u, degree_v - ) + surface.rhino_surface = rhino_surface_from_parameters(points, weights, knots_u, knots_v, mults_u, mults_v, degree_u, degree_v) return surface @classmethod @@ -342,9 +339,7 @@ def from_points(cls, points, degree_u=3, degree_v=3): pointcount_v = len(points[0]) points[:] = [point_to_rhino(point) for row in points for point in row] surface = cls() - surface.rhino_surface = Rhino.Geometry.NurbsSurface.CreateFromPoints( - points, pointcount_u, pointcount_v, degree_u, degree_v - ) + surface.rhino_surface = Rhino.Geometry.NurbsSurface.CreateFromPoints(points, pointcount_u, pointcount_v, degree_u, degree_v) return surface @classmethod diff --git a/src/compas_rhino/geometry/surfaces/surface.py b/src/compas_rhino/geometry/surfaces/surface.py index 87bf92291fe..36fa127a0fa 100644 --- a/src/compas_rhino/geometry/surfaces/surface.py +++ b/src/compas_rhino/geometry/surfaces/surface.py @@ -1,22 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import Rhino.Geometry # type: ignore from compas.geometry import Surface - -from compas_rhino.conversions import point_to_rhino -from compas_rhino.conversions import point_to_compas -from compas_rhino.conversions import vector_to_compas -from compas_rhino.conversions import plane_to_compas_frame +from compas_rhino.conversions import box_to_compas +from compas_rhino.conversions import cylinder_to_rhino from compas_rhino.conversions import frame_to_rhino_plane +from compas_rhino.conversions import plane_to_compas_frame from compas_rhino.conversions import plane_to_rhino -from compas_rhino.conversions import box_to_compas -from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import point_to_compas +from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import sphere_to_rhino -from compas_rhino.conversions import cylinder_to_rhino - +from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import vector_to_compas from compas_rhino.geometry.curves import RhinoCurve @@ -400,9 +398,7 @@ def intersections_with_curve(self, curve, tolerance=1e-3, overlap=1e-3): list[:class:`compas.geometry.Point`] """ - intersections = Rhino.Geometry.Intersect.Intersection.CurveSurface( - curve.rhino_curve, self.rhino_surface, tolerance, overlap - ) + intersections = Rhino.Geometry.Intersect.Intersection.CurveSurface(curve.rhino_curve, self.rhino_surface, tolerance, overlap) points = [] for event in intersections: if event.IsPoint: diff --git a/src/compas_rhino/geometry/trimesh_curvature.py b/src/compas_rhino/geometry/trimesh_curvature.py index d2451e42e2c..e8a9465c94f 100644 --- a/src/compas_rhino/geometry/trimesh_curvature.py +++ b/src/compas_rhino/geometry/trimesh_curvature.py @@ -2,14 +2,14 @@ from __future__ import division from __future__ import print_function -import Rhino # type: ignore -import System # type: ignore -import clr # type: ignore -import scriptcontext # type: ignore - +from math import atan2 from math import pi from math import sqrt -from math import atan2 + +import clr # type: ignore +import Rhino # type: ignore +import scriptcontext # type: ignore +import System # type: ignore from compas.plugins import plugin @@ -81,9 +81,7 @@ def trimesh_gaussian_curvature(M): # (3) Main - loop every vertex for angle defect for i in range(mesh.Vertices.Count): - vert_neighbors_topo = mesh.TopologyVertices.ConnectedTopologyVertices( - mesh.TopologyVertices.TopologyVertexIndex(i), True - ) + vert_neighbors_topo = mesh.TopologyVertices.ConnectedTopologyVertices(mesh.TopologyVertices.TopologyVertexIndex(i), True) vert_neighbors = [] if vert_neighbors_topo is None: K.append(None) diff --git a/src/compas_rhino/install.py b/src/compas_rhino/install.py index 0fcf7a5f604..2c768ccbcdb 100644 --- a/src/compas_rhino/install.py +++ b/src/compas_rhino/install.py @@ -7,10 +7,9 @@ import os import sys -import compas_rhino - import compas._os import compas.plugins +import compas_rhino def install(version=None, packages=None, clean=False): @@ -242,9 +241,7 @@ def _run_post_execution_steps(steps_generator): all_steps_succeeded = False print(" {} {}: {}".format(package.ljust(20), status, message)) except ValueError: - post_execution_errors.append( - ValueError("Step ran without errors but result is wrongly formatted: {}".format(str(item))) - ) + post_execution_errors.append(ValueError("Step ran without errors but result is wrongly formatted: {}".format(str(item)))) if post_execution_errors: print("\nOne or more errors occurred:\n") diff --git a/src/compas_rhino/install_plugin.py b/src/compas_rhino/install_plugin.py index b793decd8e0..344269e948c 100644 --- a/src/compas_rhino/install_plugin.py +++ b/src/compas_rhino/install_plugin.py @@ -1,10 +1,10 @@ -import os import imp +import os import compas_rhino - from compas._os import create_symlinks from compas._os import remove_symlinks + from .install import install as install_packages diff --git a/src/compas_rhino/install_with_pip.py b/src/compas_rhino/install_with_pip.py index 453f6c8025d..fb1ae3b583e 100644 --- a/src/compas_rhino/install_with_pip.py +++ b/src/compas_rhino/install_with_pip.py @@ -1,4 +1,5 @@ import subprocess + import compas_rhino diff --git a/src/compas_rhino/layers.py b/src/compas_rhino/layers.py index b833ba6a96f..759a3ba8360 100644 --- a/src/compas_rhino/layers.py +++ b/src/compas_rhino/layers.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from collections import deque diff --git a/src/compas_rhino/objects.py b/src/compas_rhino/objects.py index 56c18a5152e..4bde93f6717 100644 --- a/src/compas_rhino/objects.py +++ b/src/compas_rhino/objects.py @@ -1,15 +1,15 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import json -import compas_rhino - -import System # type: ignore import Rhino # type: ignore import rhinoscriptsyntax as rs # type: ignore import scriptcontext as sc # type: ignore +import System # type: ignore + +import compas_rhino find_object = sc.doc.Objects.Find @@ -298,11 +298,7 @@ def set_object_attributes(guid, attr): try: u.Set(name, value) except Exception: - print( - "The following item cannot be stored in the user dictionary of this object: {0} => {1}".format( - name, value - ) - ) + print("The following item cannot be stored in the user dictionary of this object: {0} => {1}".format(name, value)) def get_object_attributes_from_name(guids, prefix=None): diff --git a/src/compas_rhino/print_python_path.py b/src/compas_rhino/print_python_path.py index c13fa987c5e..5422469b539 100644 --- a/src/compas_rhino/print_python_path.py +++ b/src/compas_rhino/print_python_path.py @@ -1,6 +1,5 @@ import compas_rhino - if __name__ == "__main__": import argparse diff --git a/src/compas_rhino/scene/boxobject.py b/src/compas_rhino/scene/boxobject.py index 9004674d1fa..b084630bfd1 100644 --- a/src/compas_rhino/scene/boxobject.py +++ b/src/compas_rhino/scene/boxobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import box_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/brepobject.py b/src/compas_rhino/scene/brepobject.py index e8bc376b971..24c4bbe9186 100644 --- a/src/compas_rhino/scene/brepobject.py +++ b/src/compas_rhino/scene/brepobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore +from compas.scene import GeometryObject from compas_rhino.conversions import brep_to_rhino from compas_rhino.conversions import transformation_to_rhino -from compas.scene import GeometryObject + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/capsuleobject.py b/src/compas_rhino/scene/capsuleobject.py index e39dd3b4887..52e59dc95ee 100644 --- a/src/compas_rhino/scene/capsuleobject.py +++ b/src/compas_rhino/scene/capsuleobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import capsule_to_rhino_brep from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/circleobject.py b/src/compas_rhino/scene/circleobject.py index 6374486b2fd..12067e24e45 100644 --- a/src/compas_rhino/scene/circleobject.py +++ b/src/compas_rhino/scene/circleobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import circle_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/coneobject.py b/src/compas_rhino/scene/coneobject.py index 0017dbc399f..2f578acff58 100644 --- a/src/compas_rhino/scene/coneobject.py +++ b/src/compas_rhino/scene/coneobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import cone_to_rhino_brep from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/curveobject.py b/src/compas_rhino/scene/curveobject.py index 33dda8fa3b1..a990c6f0cec 100644 --- a/src/compas_rhino/scene/curveobject.py +++ b/src/compas_rhino/scene/curveobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import curve_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/cylinderobject.py b/src/compas_rhino/scene/cylinderobject.py index 535879c92d7..d09115c38f7 100644 --- a/src/compas_rhino/scene/cylinderobject.py +++ b/src/compas_rhino/scene/cylinderobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import cylinder_to_rhino_brep from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/ellipseobject.py b/src/compas_rhino/scene/ellipseobject.py index 1cba81afbd3..154d4ffe9ec 100644 --- a/src/compas_rhino/scene/ellipseobject.py +++ b/src/compas_rhino/scene/ellipseobject.py @@ -1,13 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import ellipse_to_rhino - from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/frameobject.py b/src/compas_rhino/scene/frameobject.py index b1c3652e9e2..17168dc2eda 100644 --- a/src/compas_rhino/scene/frameobject.py +++ b/src/compas_rhino/scene/frameobject.py @@ -1,13 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore -from compas.scene import GeometryObject from compas.colors import Color +from compas.scene import GeometryObject from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/graphobject.py b/src/compas_rhino/scene/graphobject.py index 414548577be..b9a043b5dbc 100644 --- a/src/compas_rhino/scene/graphobject.py +++ b/src/compas_rhino/scene/graphobject.py @@ -1,19 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import Rhino # type: ignore import scriptcontext as sc # type: ignore import compas_rhino -from compas.geometry import Line from compas.geometry import Cylinder +from compas.geometry import Line from compas.geometry import Sphere from compas.scene import GraphObject -from compas_rhino.conversions import point_to_rhino +from compas_rhino.conversions import cylinder_to_rhino_brep from compas_rhino.conversions import line_to_rhino +from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import sphere_to_rhino -from compas_rhino.conversions import cylinder_to_rhino_brep + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/helpers.py b/src/compas_rhino/scene/helpers.py index acbc7af717f..6463acc3edf 100644 --- a/src/compas_rhino/scene/helpers.py +++ b/src/compas_rhino/scene/helpers.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import rhinoscriptsyntax as rs # type: ignore import scriptcontext as sc # type: ignore diff --git a/src/compas_rhino/scene/lineobject.py b/src/compas_rhino/scene/lineobject.py index 8d5d6ae34db..420cb2b71cc 100644 --- a/src/compas_rhino/scene/lineobject.py +++ b/src/compas_rhino/scene/lineobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import line_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/meshobject.py b/src/compas_rhino/scene/meshobject.py index b03961bb439..799eca74ed3 100644 --- a/src/compas_rhino/scene/meshobject.py +++ b/src/compas_rhino/scene/meshobject.py @@ -1,29 +1,28 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import scriptcontext as sc # type: ignore import Rhino # type: ignore +import scriptcontext as sc # type: ignore -from compas.geometry import centroid_points -from compas.geometry import Point -from compas.geometry import Line +import compas_rhino.objects +from compas.colors import Color from compas.geometry import Cylinder +from compas.geometry import Line +from compas.geometry import Point from compas.geometry import Sphere +from compas.geometry import centroid_points from compas.scene import MeshObject -from compas.colors import Color - -import compas_rhino.objects -from compas_rhino.conversions import vertices_and_faces_to_rhino +from compas_rhino.conversions import cylinder_to_rhino_brep +from compas_rhino.conversions import line_to_rhino from compas_rhino.conversions import mesh_to_rhino from compas_rhino.conversions import point_to_rhino -from compas_rhino.conversions import line_to_rhino -from compas_rhino.conversions import cylinder_to_rhino_brep from compas_rhino.conversions import sphere_to_rhino from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import vertices_and_faces_to_rhino -from .sceneobject import RhinoSceneObject from .helpers import ngon +from .sceneobject import RhinoSceneObject class RhinoMeshObject(RhinoSceneObject, MeshObject): diff --git a/src/compas_rhino/scene/planeobject.py b/src/compas_rhino/scene/planeobject.py index 209496fe87e..18b88259f10 100644 --- a/src/compas_rhino/scene/planeobject.py +++ b/src/compas_rhino/scene/planeobject.py @@ -1,15 +1,16 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore +from compas.geometry import Frame from compas.scene import GeometryObject -from .sceneobject import RhinoSceneObject from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import transformation_to_rhino from compas_rhino.conversions import vertices_and_faces_to_rhino -from compas.geometry import Frame + +from .sceneobject import RhinoSceneObject class RhinoPlaneObject(RhinoSceneObject, GeometryObject): diff --git a/src/compas_rhino/scene/pointobject.py b/src/compas_rhino/scene/pointobject.py index c4387d16732..0ee1014810c 100644 --- a/src/compas_rhino/scene/pointobject.py +++ b/src/compas_rhino/scene/pointobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/polygonobject.py b/src/compas_rhino/scene/polygonobject.py index fc219030e3b..35bc52773f0 100644 --- a/src/compas_rhino/scene/polygonobject.py +++ b/src/compas_rhino/scene/polygonobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject -from compas_rhino.conversions import vertices_and_faces_to_rhino from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import vertices_and_faces_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/polyhedronobject.py b/src/compas_rhino/scene/polyhedronobject.py index 97306d01085..ca6df3505d6 100644 --- a/src/compas_rhino/scene/polyhedronobject.py +++ b/src/compas_rhino/scene/polyhedronobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject -from compas_rhino.conversions import vertices_and_faces_to_rhino from compas_rhino.conversions import transformation_to_rhino +from compas_rhino.conversions import vertices_and_faces_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/polylineobject.py b/src/compas_rhino/scene/polylineobject.py index 1b36d1ac15c..ed98970b958 100644 --- a/src/compas_rhino/scene/polylineobject.py +++ b/src/compas_rhino/scene/polylineobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import polyline_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/sceneobject.py b/src/compas_rhino/scene/sceneobject.py index 50362eb70a7..2c2ecfcfadc 100644 --- a/src/compas_rhino/scene/sceneobject.py +++ b/src/compas_rhino/scene/sceneobject.py @@ -1,13 +1,14 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -import scriptcontext as sc # type: ignore import Rhino # type: ignore +import scriptcontext as sc # type: ignore import System # type: ignore import compas_rhino.layers from compas.scene import SceneObject + from .helpers import ensure_layer diff --git a/src/compas_rhino/scene/sphereobject.py b/src/compas_rhino/scene/sphereobject.py index 68ae60a1508..3d68d04ae72 100644 --- a/src/compas_rhino/scene/sphereobject.py +++ b/src/compas_rhino/scene/sphereobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import sphere_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/surfaceobject.py b/src/compas_rhino/scene/surfaceobject.py index f0a8b0b7c6a..7edfd3c7d0f 100644 --- a/src/compas_rhino/scene/surfaceobject.py +++ b/src/compas_rhino/scene/surfaceobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import surface_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/torusobject.py b/src/compas_rhino/scene/torusobject.py index 36d7cb3fefa..4fe21f9d18f 100644 --- a/src/compas_rhino/scene/torusobject.py +++ b/src/compas_rhino/scene/torusobject.py @@ -1,12 +1,13 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore from compas.scene import GeometryObject from compas_rhino.conversions import torus_to_rhino_brep from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/vectorobject.py b/src/compas_rhino/scene/vectorobject.py index 7b9946b9756..3c0f39739c0 100644 --- a/src/compas_rhino/scene/vectorobject.py +++ b/src/compas_rhino/scene/vectorobject.py @@ -1,6 +1,6 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import scriptcontext as sc # type: ignore @@ -8,6 +8,7 @@ from compas.scene import GeometryObject from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import transformation_to_rhino + from .sceneobject import RhinoSceneObject diff --git a/src/compas_rhino/scene/volmeshobject.py b/src/compas_rhino/scene/volmeshobject.py index 685d46c339f..3be88d5312c 100644 --- a/src/compas_rhino/scene/volmeshobject.py +++ b/src/compas_rhino/scene/volmeshobject.py @@ -1,21 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function -from Rhino.Geometry import TextDot # type: ignore import scriptcontext as sc # type: ignore +from Rhino.Geometry import TextDot # type: ignore -from compas.geometry import centroid_points +import compas_rhino.objects from compas.geometry import Line +from compas.geometry import centroid_points from compas.scene import VolMeshObject - -import compas_rhino.objects -from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import line_to_rhino +from compas_rhino.conversions import point_to_rhino from compas_rhino.conversions import vertices_and_faces_to_rhino -from .sceneobject import RhinoSceneObject from .helpers import ngon +from .sceneobject import RhinoSceneObject class RhinoVolMeshObject(RhinoSceneObject, VolMeshObject): diff --git a/src/compas_rhino/ui.py b/src/compas_rhino/ui.py index 7ccbff1fc3d..bdbd98eaebc 100644 --- a/src/compas_rhino/ui.py +++ b/src/compas_rhino/ui.py @@ -1,8 +1,9 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import os + import rhinoscriptsyntax as rs # type: ignore diff --git a/src/compas_rhino/uninstall_plugin.py b/src/compas_rhino/uninstall_plugin.py index 5bdfaa0e9f0..21c61566ac1 100644 --- a/src/compas_rhino/uninstall_plugin.py +++ b/src/compas_rhino/uninstall_plugin.py @@ -1,11 +1,10 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function import os import compas_rhino - from compas._os import remove_symlink diff --git a/src/compas_rhino/utilities/constructors.py b/src/compas_rhino/utilities/constructors.py index c58f7180f30..aa86af86ba5 100644 --- a/src/compas_rhino/utilities/constructors.py +++ b/src/compas_rhino/utilities/constructors.py @@ -1,12 +1,12 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division - -from compas.tolerance import TOL +from __future__ import print_function import Rhino # type: ignore import scriptcontext as sc # type: ignore +from compas.tolerance import TOL + def volmesh_from_polysurfaces(cls, guids, precision=None): """Construct a volumetric mesh from given polysurfaces. diff --git a/src/compas_rhino/utilities/drawing.py b/src/compas_rhino/utilities/drawing.py index a3f57fd6fe0..4df1f5bd687 100644 --- a/src/compas_rhino/utilities/drawing.py +++ b/src/compas_rhino/utilities/drawing.py @@ -1,21 +1,20 @@ -from __future__ import print_function from __future__ import absolute_import from __future__ import division +from __future__ import print_function from functools import wraps +import Rhino # type: ignore import rhinoscriptsyntax as rs # type: ignore import scriptcontext as sc # type: ignore import System # type: ignore -import Rhino # type: ignore import compas_rhino.objects -from compas_rhino.layers import create_layers_from_path -from compas_rhino.layers import clear_layer -from compas_rhino.layers import clear_current_layer -from compas_rhino.conversions import vertices_and_faces_to_rhino - from compas.geometry import centroid_polygon +from compas_rhino.conversions import vertices_and_faces_to_rhino +from compas_rhino.layers import clear_current_layer +from compas_rhino.layers import clear_layer +from compas_rhino.layers import create_layers_from_path find_object = sc.doc.Objects.Find add_point = sc.doc.Objects.AddPoint @@ -626,9 +625,7 @@ def draw_pipes(pipes, cap=2, fit=1.0, **kwargs): if type(radius) in (int, float): radius = [radius] * 2 radius = [float(r) for r in radius] - rail = Rhino.Geometry.Curve.CreateControlPointRhino.Geometry.Curve( - [Rhino.Geometry.Point3d(*xyz) for xyz in points] - ) + rail = Rhino.Geometry.Curve.CreateControlPointRhino.Geometry.Curve([Rhino.Geometry.Point3d(*xyz) for xyz in points]) breps = Rhino.Geometry.Brep.CreatePipe(rail, params, radius, 1, cap, fit, abs_tol, ang_tol) temp = [add_brep(brep) for brep in breps] for guid in temp: @@ -902,9 +899,7 @@ def draw_circles(circles, **kwargs): name = data.get("name", "") color = data.get("color") layer = data.get("layer") - circle = Rhino.Geometry.Circle( - Rhino.Geometry.Plane(Rhino.Geometry.Point3d(*point), Rhino.Geometry.Vector3d(*normal)), radius - ) + circle = Rhino.Geometry.Circle(Rhino.Geometry.Plane(Rhino.Geometry.Point3d(*point), Rhino.Geometry.Vector3d(*normal)), radius) guid = add_circle(circle) if not guid: continue diff --git a/tasks.py b/tasks.py index 9362999db4a..2313ff2f6af 100644 --- a/tasks.py +++ b/tasks.py @@ -2,10 +2,10 @@ import os -from compas_invocations import build -from compas_invocations import docs -from compas_invocations import style -from compas_invocations import tests +from compas_invocations2 import build +from compas_invocations2 import docs +from compas_invocations2 import style +from compas_invocations2 import tests from invoke import Collection ns = Collection( diff --git a/tests/compas/colors/test_color.py b/tests/compas/colors/test_color.py index 485ad498830..ff1ac36a275 100644 --- a/tests/compas/colors/test_color.py +++ b/tests/compas/colors/test_color.py @@ -4,7 +4,7 @@ from random import random from compas.colors import Color -from compas.geometry import allclose +from compas.tolerance import TOL @pytest.mark.parametrize( @@ -26,7 +26,7 @@ def test_color(color): assert c.b == color[2] assert c.a == color[3] if len(color) == 4 else 1.0 - assert allclose(eval(repr(c)), c, tol=1e-12) + assert TOL.is_allclose(eval(repr(c)), c) def test_color_data(): diff --git a/tests/compas/datastructures/test_mesh.py b/tests/compas/datastructures/test_mesh.py index 427412f244f..2d2f9764da3 100644 --- a/tests/compas/datastructures/test_mesh.py +++ b/tests/compas/datastructures/test_mesh.py @@ -10,7 +10,8 @@ from compas.geometry import Polygon from compas.geometry import Polyhedron from compas.geometry import Translation -from compas.geometry import allclose + +from compas.tolerance import TOL @pytest.fixture @@ -1018,7 +1019,7 @@ def test_area(): assert mesh.area() == 6 mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.area() == 22.802429316496635 + assert TOL.is_close(mesh.area(), 22.802429316496635) def test_centroid(): @@ -1029,7 +1030,7 @@ def test_centroid(): assert mesh.centroid() == [0.0, 0.0, 0.5] mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.centroid() == [2.508081952064351, 2.554046390557884, 1.2687133268242006] + assert TOL.is_allclose(mesh.centroid(), [2.508081952064351, 2.554046390557884, 1.2687133268242006]) def test_normal(): @@ -1040,11 +1041,14 @@ def test_normal(): assert mesh.normal() == [0.0, 0.0, 0.0] mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.normal() == [ - -2.380849234996509e-06, - 4.1056122145028854e-05, - 0.8077953732329284, - ] + assert TOL.is_allclose( + mesh.normal(), + [ + -2.380849234996509e-06, + 4.1056122145028854e-05, + 0.8077953732329284, + ], + ) # -------------------------------------------------------------------------- @@ -1078,22 +1082,28 @@ def test_vertex_neighborhood_centroid(): def test_vertex_normal(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.vertex_normal(0) == [ - -0.7875436283909406, - 0.07148692938164082, - 0.6120985642103861, - ] - assert mesh.vertex_normal(5) == [ - -0.482011312317331, - -0.32250183520381565, - 0.814651864963369, - ] + assert TOL.is_allclose( + mesh.vertex_normal(0), + [ + -0.7875436283909406, + 0.07148692938164082, + 0.6120985642103861, + ], + ) + assert TOL.is_allclose( + mesh.vertex_normal(5), + [ + -0.482011312317331, + -0.32250183520381565, + 0.814651864963369, + ], + ) def test_vertex_curvature(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.vertex_curvature(0) == 0.0029617825994936453 - assert mesh.vertex_curvature(5) == 0.036193074384009094 + assert TOL.is_close(mesh.vertex_curvature(0), 0.0029617825994936453) + assert TOL.is_close(mesh.vertex_curvature(5), 0.036193074384009094) def test_face_coordinates(): @@ -1114,39 +1124,44 @@ def test_face_coordinates(): def test_face_normal(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert allclose( + assert TOL.is_allclose( mesh.face_normal(0), [0.5435358481001584, -0.16248515023849733, 0.8235091728584537], - tol=1e-6, ) def test_face_centroid(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_centroid(0) == [ - 3.94185334444046, - 2.024157851934433, - 1.3333333134651184, - ] + assert TOL.is_allclose( + mesh.face_centroid(0), + [ + 3.94185334444046, + 2.024157851934433, + 1.3333333134651184, + ], + ) def test_face_center(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_center(0) == [ - 3.944329439044577, - 2.0258867968680776, - 1.332040166602369, - ] + assert TOL.is_allclose( + mesh.face_center(0), + [ + 3.944329439044577, + 2.0258867968680776, + 1.332040166602369, + ], + ) def test_face_area(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_area(0) == 0.3374168482414756 + assert TOL.is_close(mesh.face_area(0), 0.3374168482414756) def test_face_flatness(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_flatness(0) == 0.23896112582475654 + assert TOL.is_close(mesh.face_flatness(0), 0.23896112582475654) mesh = Mesh.from_obj(compas.get("faces.obj")) assert mesh.face_flatness(0) == 0 @@ -1154,7 +1169,7 @@ def test_face_flatness(): def test_face_aspect_ratio(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_aspect_ratio(0) == 1.2813792520925738 + assert TOL.is_close(mesh.face_aspect_ratio(0), 1.2813792520925738) mesh = Mesh.from_obj(compas.get("faces.obj")) assert mesh.face_aspect_ratio(0) == 1 @@ -1162,7 +1177,7 @@ def test_face_aspect_ratio(): def test_face_skewness(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_skewness(0) == 0.2432393485343291 + assert TOL.is_close(mesh.face_skewness(0), 0.2432393485343291) mesh = Mesh.from_obj(compas.get("faces.obj")) assert mesh.face_skewness(0) == 0 @@ -1170,7 +1185,7 @@ def test_face_skewness(): def test_face_curvature(): mesh = Mesh.from_obj(compas.get("quadmesh.obj")) - assert mesh.face_curvature(0) == 0.0035753184898039566 + assert TOL.is_close(mesh.face_curvature(0), 0.0035753184898039566) mesh = Mesh.from_obj(compas.get("faces.obj")) assert mesh.face_curvature(0) == 0 diff --git a/tests/compas/datastructures/test_mesh_subd.py b/tests/compas/datastructures/test_mesh_subd.py index d81c1c55ec8..2ee5947800b 100644 --- a/tests/compas/datastructures/test_mesh_subd.py +++ b/tests/compas/datastructures/test_mesh_subd.py @@ -19,17 +19,13 @@ def mesh_quads(): def test_quads_subdivide(mesh_quads): subd = mesh_quads.subdivided() assert subd.number_of_faces() == 4 * mesh_quads.number_of_faces() - assert subd.number_of_vertices() == ( - mesh_quads.number_of_vertices() + mesh_quads.number_of_edges() + mesh_quads.number_of_faces() - ) + assert subd.number_of_vertices() == (mesh_quads.number_of_vertices() + mesh_quads.number_of_edges() + mesh_quads.number_of_faces()) def test_tris_subdivide(mesh_tris): subd = mesh_tris.subdivided() assert subd.number_of_faces() == 3 * mesh_tris.number_of_faces() - assert subd.number_of_vertices() == ( - mesh_tris.number_of_vertices() + mesh_tris.number_of_edges() + mesh_tris.number_of_faces() - ) + assert subd.number_of_vertices() == (mesh_tris.number_of_vertices() + mesh_tris.number_of_edges() + mesh_tris.number_of_faces()) def test_quads_subdivide_tri(mesh_quads): @@ -47,14 +43,10 @@ def test_tris_subdivide_tri(mesh_tris): def test_quads_subdivide_quad(mesh_quads): subd = mesh_quads.subdivided(scheme="quad") assert subd.number_of_faces() == 4 * mesh_quads.number_of_faces() - assert subd.number_of_vertices() == ( - mesh_quads.number_of_vertices() + mesh_quads.number_of_edges() + mesh_quads.number_of_faces() - ) + assert subd.number_of_vertices() == (mesh_quads.number_of_vertices() + mesh_quads.number_of_edges() + mesh_quads.number_of_faces()) def test_tris_subdivide_quad(mesh_tris): subd = mesh_tris.subdivided(scheme="quad") assert subd.number_of_faces() == 3 * mesh_tris.number_of_faces() - assert subd.number_of_vertices() == ( - mesh_tris.number_of_vertices() + mesh_tris.number_of_edges() + mesh_tris.number_of_faces() - ) + assert subd.number_of_vertices() == (mesh_tris.number_of_vertices() + mesh_tris.number_of_edges() + mesh_tris.number_of_faces()) diff --git a/tests/compas/donttest_api_stability.py b/tests/compas/donttest_api_stability.py index d3db0a023d9..c305e5ec0ae 100644 --- a/tests/compas/donttest_api_stability.py +++ b/tests/compas/donttest_api_stability.py @@ -54,13 +54,7 @@ def get_names_in_module(module_name): exceptions = ["absolute_import", "division", "print_function"] module = importlib.import_module(module_name) all_names = module.__all__ if hasattr(module, "__all__") else dir(module) - return sorted( - [ - i - for i in all_names - if not i.startswith("_") and i not in exceptions and not inspect.ismodule(getattr(module, i)) - ] - ) + return sorted([i for i in all_names if not i.startswith("_") and i not in exceptions and not inspect.ismodule(getattr(module, i))]) if __name__ == "__main__": diff --git a/tests/compas/files/test_xml.py b/tests/compas/files/test_xml.py index 2e35b2c5c83..e092d5ef9d9 100644 --- a/tests/compas/files/test_xml.py +++ b/tests/compas/files/test_xml.py @@ -59,9 +59,7 @@ def test_xml_to_pretty_string(basic_xml): def test_namespaces_to_string(): - xml = XML.from_string( - """""" - ) + xml = XML.from_string("""""") xml_string = xml.to_string(prettify=True) assert b'xmlns:xacro="http://www.ros.org/wiki/xacro"' in xml_string assert b" line.length + + +@pytest.mark.parametrize( + "p1,p2", + [ + ([0, 0, 0], [1, 0, 0]), + ([0, 0, 0], [1, 2, 3]), + ([1, 2, 3], [-1, -2, -3]), + ([-11.1, 22.2, 33.3], [1.1, -2.2, -3.3]), + ], +) +def test_line_point_from_end(p1, p2): + distances = [0, 1, 4, -9, 3.3, 0.00001, -0.00001] + for distance in distances: + line = Line(p1, p2) + point = line.point_from_end(distance) + distance_to_start = distance_point_point(point, p1) + distance_to_end = distance_point_point(point, p2) + # Check that the distance is correct + assert TOL.is_close(distance_to_end, abs(distance)) + # Check that negative distance gives a point far away from start + if distance < 0: + assert distance_to_start > line.length + + +@pytest.mark.parametrize( + "p1,p2", + [ + ([0, 0, 0], [1, 0, 0]), + ([0, 0, 0], [1, 2, 3]), + ([1, 2, 3], [-1, -2, -3]), + ([-11.1, 22.2, 33.3], [1.1, -2.2, -3.3]), + ], +) +def test_line_flip(p1, p2): + line = Line(p1, p2) + line.flip() + assert TOL.is_zero(distance_point_point(line.start, p2)) + assert TOL.is_zero(distance_point_point(line.end, p1)) + flipped_line = Line(p1, p2).flipped() + assert TOL.is_zero(distance_point_point(flipped_line.start, p2)) + assert TOL.is_zero(distance_point_point(flipped_line.end, p1)) diff --git a/tests/compas/geometry/test_curves_parabola.py b/tests/compas/geometry/test_curves_parabola.py index d0b18ec741b..e2fe494a651 100644 --- a/tests/compas/geometry/test_curves_parabola.py +++ b/tests/compas/geometry/test_curves_parabola.py @@ -2,7 +2,7 @@ import json import compas -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import Frame from compas.geometry import Parabola @@ -13,9 +13,9 @@ def test_parabola_create(): assert parabola.focal == 1 assert parabola.frame == Frame.worldXY() - assert allclose(parabola.point_at(0.0), parabola.point_at(0.0, world=False), tol=1e-12) - assert allclose(parabola.point_at(0.5), parabola.point_at(0.5, world=False), tol=1e-12) - assert allclose(parabola.point_at(1.0), parabola.point_at(1.0, world=False), tol=1e-12) + assert TOL.is_allclose(parabola.point_at(0.0), parabola.point_at(0.0, world=False)) + assert TOL.is_allclose(parabola.point_at(0.5), parabola.point_at(0.5, world=False)) + assert TOL.is_allclose(parabola.point_at(1.0), parabola.point_at(1.0, world=False)) def test_parabola_create_with_frame(): @@ -25,24 +25,21 @@ def test_parabola_create_with_frame(): assert parabola.focal == 1 assert parabola.frame == frame - assert allclose(parabola.point_at(0.0), parabola.point_at(0.0, world=False), tol=1e-12) - assert not allclose(parabola.point_at(0.5), parabola.point_at(0.5, world=False), tol=1e-12) - assert not allclose(parabola.point_at(1.0), parabola.point_at(1.0, world=False), tol=1e-12) + assert TOL.is_allclose(parabola.point_at(0.0), parabola.point_at(0.0, world=False)) + assert not TOL.is_allclose(parabola.point_at(0.5), parabola.point_at(0.5, world=False)) + assert not TOL.is_allclose(parabola.point_at(1.0), parabola.point_at(1.0, world=False)) - assert allclose( + assert TOL.is_allclose( parabola.point_at(0.0), parabola.point_at(0.0, world=False).transformed(parabola.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( parabola.point_at(0.5), parabola.point_at(0.5, world=False).transformed(parabola.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( parabola.point_at(1.0), parabola.point_at(1.0, world=False).transformed(parabola.transformation), - tol=1e-12, ) @@ -57,8 +54,8 @@ def test_parabola_data(): assert parabola.focal == other.focal assert parabola.frame.point == other.frame.point - assert allclose(parabola.frame.xaxis, other.frame.xaxis, tol=1e-12) - assert allclose(parabola.frame.yaxis, other.frame.yaxis, tol=1e-12) + assert TOL.is_allclose(parabola.frame.xaxis, other.frame.xaxis) + assert TOL.is_allclose(parabola.frame.yaxis, other.frame.yaxis) if not compas.IPY: assert Parabola.validate_data(parabola.__data__) diff --git a/tests/compas/geometry/test_frame.py b/tests/compas/geometry/test_frame.py index b01cb17d0d5..8d67d6b4b84 100644 --- a/tests/compas/geometry/test_frame.py +++ b/tests/compas/geometry/test_frame.py @@ -1,10 +1,12 @@ from __future__ import division + +import math + import pytest import json import compas from random import random -from compas.geometry import allclose -from compas.geometry import close +from compas.tolerance import TOL from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Frame @@ -24,16 +26,16 @@ def test_frame(point, xaxis, yaxis): frame = Frame(point, xaxis, yaxis) assert frame.point == Point(*point) assert frame.xaxis == Vector(*xaxis).unitized() - assert close(frame.zaxis.dot(xaxis), 0, tol=1e-12) - assert close(frame.zaxis.dot(yaxis), 0, tol=1e-12) - assert close(frame.xaxis.length, 1, tol=1e-12) - assert close(frame.yaxis.length, 1, tol=1e-12) - assert close(frame.zaxis.length, 1, tol=1e-12) + assert TOL.is_close(frame.zaxis.dot(xaxis), 0) + assert TOL.is_close(frame.zaxis.dot(yaxis), 0) + assert TOL.is_close(frame.xaxis.length, 1) + assert TOL.is_close(frame.yaxis.length, 1) + assert TOL.is_close(frame.zaxis.length, 1) other = eval(repr(frame)) - assert allclose(frame.point, other.point, tol=1e-12) - assert allclose(frame.xaxis, other.xaxis, tol=1e-12) - assert allclose(frame.yaxis, other.yaxis, tol=1e-12) + assert TOL.is_allclose(frame.point, other.point) + assert TOL.is_allclose(frame.xaxis, other.xaxis) + assert TOL.is_allclose(frame.yaxis, other.yaxis) def test_frame_data(): @@ -43,9 +45,9 @@ def test_frame_data(): frame = Frame(point, xaxis, yaxis) other = Frame.__from_data__(json.loads(json.dumps(frame.__data__))) - assert allclose(frame.point, other.point, tol=1e-12) - assert allclose(frame.xaxis, other.xaxis, tol=1e-12) - assert allclose(frame.yaxis, other.yaxis, tol=1e-12) + assert TOL.is_allclose(frame.point, other.point) + assert TOL.is_allclose(frame.xaxis, other.xaxis) + assert TOL.is_allclose(frame.yaxis, other.yaxis) assert frame.guid != other.guid if not compas.IPY: @@ -68,3 +70,25 @@ def test_frame_predefined(): assert frame.point == Point(0, 0, 0) assert frame.xaxis == Vector(0, 0, 1) assert frame.yaxis == Vector(1, 0, 0) + + +def test_interpolate_frame_start_end(): + frame1 = Frame(Point(0, 0, 0), Vector(1, 0, 0), Vector(0, 1, 0)) + frame2 = Frame(Point(1, 1, 1), Vector(0, 0, 1), Vector(0, 1, 0)) + + # Test interpolation at the start + start_frame = frame1.interpolate_frame(frame2, 0) + assert start_frame.point == frame1.point and start_frame.xaxis == frame1.xaxis and start_frame.yaxis == frame1.yaxis, "Failed at t=0" + + # Test interpolation at the end + end_frame = frame1.interpolate_frame(frame2, 1) + assert end_frame.point == frame2.point and end_frame.xaxis == frame2.xaxis and end_frame.yaxis == frame2.yaxis, "Failed at t=1" + + quarter_frame = frame1.interpolate_frame(frame2, 0.25) + assert TOL.is_allclose([math.degrees(quarter_frame.axis_angle_vector.y)], [-22.5], atol=TOL.angular) + + half_frame = frame1.interpolate_frame(frame2, 0.5) + assert TOL.is_allclose([math.degrees(half_frame.axis_angle_vector.y)], [-45.0], atol=TOL.angular) + + three_quarter_frame = frame1.interpolate_frame(frame2, 0.75) + assert TOL.is_allclose([math.degrees(three_quarter_frame.axis_angle_vector.y)], [-67.5], atol=TOL.angular) diff --git a/tests/compas/geometry/test_intersections.py b/tests/compas/geometry/test_intersections.py index 9891936eb24..352eb50180f 100644 --- a/tests/compas/geometry/test_intersections.py +++ b/tests/compas/geometry/test_intersections.py @@ -1,4 +1,4 @@ -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import intersection_sphere_line from compas.geometry import intersection_plane_circle from compas.geometry import intersection_circle_circle_xy @@ -8,21 +8,21 @@ def test_intersection_sphere_line(): sphere = (3.0, 7.0, 4.0), 10.0 line = (1.0, 0, 0.5), (2.0, 1.0, 0.5) ipt1, ipt2 = intersection_sphere_line(sphere, line) - assert allclose(ipt1, (11.634, 10.634, 0.500), tol=1e-3) - assert allclose(ipt2, (-0.634, -1.634, 0.500), tol=1e-3) + assert TOL.is_allclose(ipt1, (11.634, 10.634, 0.500), atol=1e-3) + assert TOL.is_allclose(ipt2, (-0.634, -1.634, 0.500), atol=1e-3) def test_intersection_plane_circle(): plane = (0, 0, 0), (0, 0, 1) circle = ((3.0, 7.0, 4.0), (0, 1, 0)), 10.0 ipt1, ipt2 = intersection_plane_circle(plane, circle) - assert allclose(ipt1, (-6.165, 7.000, 0.000), tol=1e-3) - assert allclose(ipt2, (12.165, 7.000, 0.000), tol=1e-3) + assert TOL.is_allclose(ipt1, (-6.165, 7.000, 0.000), atol=1e-3) + assert TOL.is_allclose(ipt2, (12.165, 7.000, 0.000), atol=1e-3) def test_intersection_circle_circle_xy(): circle1 = ((0.0, 0.0, 0.0), (0, 0, 1)), 10.0 circle2 = ((3.0, 7.0, 0.0), (0, 0, 1)), 10.0 ipt1, ipt2 = intersection_circle_circle_xy(circle1, circle2) - assert allclose(ipt1, (9.999, -0.142, 0.000), tol=1e-3) - assert allclose(ipt2, (-6.999, 7.142, 0.000), tol=1e-3) + assert TOL.is_allclose(ipt1, (9.999, -0.142, 0.000), atol=1e-3) + assert TOL.is_allclose(ipt2, (-6.999, 7.142, 0.000), atol=1e-3) diff --git a/tests/compas/geometry/test_offset.py b/tests/compas/geometry/test_offset.py index 762b5ac7b36..ef3c0305131 100644 --- a/tests/compas/geometry/test_offset.py +++ b/tests/compas/geometry/test_offset.py @@ -1,6 +1,6 @@ import pytest -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import offset_line from compas.geometry import offset_polygon from compas.geometry import offset_polyline @@ -23,7 +23,7 @@ ) def test_offset_polygon(polygon, distance, tol, output_polygon): output_polygon = [v for v in output_polygon] - assert allclose(offset_polygon(polygon, distance, tol), output_polygon) + assert TOL.is_allclose(offset_polygon(polygon, distance, tol), output_polygon) @pytest.mark.parametrize( @@ -50,7 +50,7 @@ def test_offset_polygon(polygon, distance, tol, output_polygon): ], ) def test_offset_colinear_polygon(polygon, distance, tol, output_polygon): - assert allclose(offset_polygon(polygon, distance, tol), output_polygon) + assert TOL.is_allclose(offset_polygon(polygon, distance, tol), output_polygon) # ============================================================================== @@ -64,7 +64,7 @@ def test_offset_colinear_polygon(polygon, distance, tol, output_polygon): ) def test_offset_polyline_equals_offset_line(polyline, distance, normal, tol): output_line = [v for v in offset_line(polyline, distance, normal)] - assert allclose(offset_polyline(polyline, distance, normal, tol), output_line) + assert TOL.is_allclose(offset_polyline(polyline, distance, normal, tol), output_line) @pytest.mark.parametrize( @@ -81,7 +81,7 @@ def test_offset_polyline_equals_offset_line(polyline, distance, normal, tol): ) def test_variable_offset_on_colinear_polyline(polyline, distance, normal, tol, output_polyline): output_polyline = [v for v in output_polyline] - assert allclose(offset_polyline(polyline, distance, normal, tol), output_polyline) + assert TOL.is_allclose(offset_polyline(polyline, distance, normal, tol), output_polyline) # ============================================================================== @@ -95,4 +95,4 @@ def test_variable_offset_on_colinear_polyline(polyline, distance, normal, tol, o ) def test_offset_line_zero_length(line, distance, normal): output_line = offset_line(line, distance, normal) - assert allclose(line, output_line) + assert TOL.is_allclose(line, output_line) diff --git a/tests/compas/geometry/test_plane.py b/tests/compas/geometry/test_plane.py index 0c80a672fbc..bff62f5fcd1 100644 --- a/tests/compas/geometry/test_plane.py +++ b/tests/compas/geometry/test_plane.py @@ -2,8 +2,7 @@ import json import compas from random import random -from compas.geometry import close -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Plane @@ -25,11 +24,11 @@ def test_plane(point, vector): assert plane.normal == Vector(*vector).unitized() assert isinstance(plane.point, Point) assert isinstance(plane.normal, Vector) - assert close(plane.normal.length, 1.0, tol=1e-12) + assert TOL.is_close(plane.normal.length, 1.0) other = eval(repr(plane)) - assert allclose(other.point, plane.point, tol=1e-12) - assert allclose(other.normal, plane.normal, tol=1e-12) + assert TOL.is_allclose(other.point, plane.point) + assert TOL.is_allclose(other.normal, plane.normal) def test_plane_data(): @@ -38,8 +37,8 @@ def test_plane_data(): plane = Plane(point, vector) other = Plane.__from_data__(json.loads(json.dumps(plane.__data__))) - assert allclose(other.point, plane.point, tol=1e-12) - assert allclose(other.normal, plane.normal, tol=1e-12) + assert TOL.is_allclose(other.point, plane.point) + assert TOL.is_allclose(other.normal, plane.normal) assert plane.guid != other.guid if not compas.IPY: diff --git a/tests/compas/geometry/test_quaternion.py b/tests/compas/geometry/test_quaternion.py index ca76d7c40ec..8703e416e6a 100644 --- a/tests/compas/geometry/test_quaternion.py +++ b/tests/compas/geometry/test_quaternion.py @@ -4,7 +4,8 @@ from random import random from compas.geometry import Quaternion -from compas.geometry import close +from compas.tolerance import TOL +from compas.geometry import Frame @pytest.mark.parametrize( @@ -33,10 +34,10 @@ def test_quaternion(w, x, y, z): other = eval(repr(quaternion)) - assert close(quaternion.w, other.w, tol=1e-12) - assert close(quaternion.x, other.x, tol=1e-12) - assert close(quaternion.y, other.y, tol=1e-12) - assert close(quaternion.z, other.z, tol=1e-12) + assert TOL.is_close(quaternion.w, other.w) + assert TOL.is_close(quaternion.x, other.x) + assert TOL.is_close(quaternion.y, other.y) + assert TOL.is_close(quaternion.z, other.z) # ============================================================================= @@ -63,22 +64,89 @@ def test_quaternion_data(): assert Quaternion.validate_data(other.__data__) -# ============================================================================= -# Constructors -# ============================================================================= - # ============================================================================= # Properties and Geometry # ============================================================================= + +def test_quaternion_properties(): + w = 1.0 + x = 2.0 + y = 3.0 + z = 4.0 + + quaternion = Quaternion(w, x, y, z) + + assert quaternion.wxyz == [w, x, y, z] + assert quaternion.xyzw == [x, y, z, w] + assert TOL.is_close(quaternion.norm, 5.4772255) + assert quaternion.is_unit is False + + quaternion = Quaternion(0.0, 0.0, 0.0, 1.0) + assert quaternion.norm == 1.0 + + # ============================================================================= # Accessors # ============================================================================= + +def test_quaternion_accessors(): + w = 1.0 + x = 2.0 + y = 3.0 + z = 4.0 + + quaternion = Quaternion(w, x, y, z) + + assert quaternion[0] == w + assert quaternion[1] == x + assert quaternion[2] == y + assert quaternion[3] == z + + quaternion[0] = 5.0 + quaternion[1] = 6.0 + quaternion[2] = 7.0 + quaternion[3] = 8.0 + + assert quaternion.w == 5.0 + assert quaternion.x == 6.0 + assert quaternion.y == 7.0 + assert quaternion.z == 8.0 + + # ============================================================================= # Comparison # ============================================================================= + +def test_quaternion_comparison(): + quaternion1 = Quaternion(1.0, 2.0, 3.0, 4.0) + quaternion2 = Quaternion(1.0, 2.0, 3.0, 4.0) + quaternion3 = Quaternion(5.0, 6.0, 7.0, 8.0) + + assert quaternion1 == quaternion2 + assert quaternion1 != quaternion3 + + # ============================================================================= -# Other Methods +# Methods # ============================================================================= + + +def test_quaternion_other_methods(): + quaternion = Quaternion(1.0, 2.0, 3.0, 4.0) + + conjugate = quaternion.conjugated() + assert conjugate.w == 1.0 + assert conjugate.x == -2.0 + assert conjugate.y == -3.0 + assert conjugate.z == -4.0 + + unitized = quaternion.unitized() + assert unitized.is_unit + + quaternion = Quaternion.from_frame(Frame.worldZX()) + canonized = quaternion.canonized() + + assert str(canonized) == str("Quaternion(0.5, -0.5, -0.5, -0.5)") diff --git a/tests/compas/geometry/test_surfaces.py b/tests/compas/geometry/test_surfaces.py index 49f4d933ebc..bb2250f01c5 100644 --- a/tests/compas/geometry/test_surfaces.py +++ b/tests/compas/geometry/test_surfaces.py @@ -1,6 +1,6 @@ import pytest -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import Frame from compas.geometry import SphericalSurface from compas.geometry import CylindricalSurface @@ -20,50 +20,42 @@ ], ) def test_surface_geometry(surface): - assert allclose( + assert TOL.is_allclose( surface.point_at(0, 0), surface.point_at(0, 0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(0.5, 0), surface.point_at(0.5, 0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(1.0, 0), surface.point_at(1.0, 0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(1.0, 0.5), surface.point_at(1.0, 0.5, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(1.0, 1.0), surface.point_at(1.0, 1.0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(0.5, 1.0), surface.point_at(0.5, 1.0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(0, 1.0), surface.point_at(0, 1.0, world=False).transformed(surface.transformation), - tol=1e-12, ) - assert allclose( + assert TOL.is_allclose( surface.point_at(0, 0.5), surface.point_at(0, 0.5, world=False).transformed(surface.transformation), - tol=1e-12, ) diff --git a/tests/compas/geometry/test_surfaces_cone.py b/tests/compas/geometry/test_surfaces_cone.py index eba405be2c1..fbd9aa2aad7 100644 --- a/tests/compas/geometry/test_surfaces_cone.py +++ b/tests/compas/geometry/test_surfaces_cone.py @@ -7,7 +7,7 @@ from compas.geometry import Vector # noqa: F401 from compas.geometry import Frame from compas.geometry import ConicalSurface -from compas.geometry import close +from compas.tolerance import TOL from compas.itertools import linspace @@ -34,8 +34,8 @@ def test_cone(radius, height): other = eval(repr(cone)) - assert close(cone.radius, other.radius, tol=1e-12) - assert close(cone.height, other.height, tol=1e-12) + assert TOL.is_close(cone.radius, other.radius) + assert TOL.is_close(cone.height, other.height) assert cone.frame == other.frame @@ -62,8 +62,8 @@ def test_cone_frame(frame): other = eval(repr(cone)) - assert close(cone.radius, other.radius, tol=1e-12) - assert close(cone.height, other.height, tol=1e-12) + assert TOL.is_close(cone.radius, other.radius) + assert TOL.is_close(cone.height, other.height) assert cone.frame == other.frame diff --git a/tests/compas/geometry/test_surfaces_cylinder.py b/tests/compas/geometry/test_surfaces_cylinder.py index 1fec82fa590..5cf3bc5daf4 100644 --- a/tests/compas/geometry/test_surfaces_cylinder.py +++ b/tests/compas/geometry/test_surfaces_cylinder.py @@ -7,7 +7,7 @@ from compas.geometry import Vector # noqa: F401 from compas.geometry import Frame from compas.geometry import CylindricalSurface -from compas.geometry import close +from compas.tolerance import TOL from compas.itertools import linspace @@ -31,7 +31,7 @@ def test_cylinder(radius): for v in linspace(0.0, 1.0, num=100): assert cylinder.point_at(u, v) == cylinder.point_at(u, v, world=False) - assert close(cylinder.radius, other.radius, tol=1e-12) + assert TOL.is_close(cylinder.radius, other.radius) assert cylinder.frame == other.frame @@ -56,7 +56,7 @@ def test_cylinder_frame(frame): for v in linspace(0.0, 1.0, num=100): assert cylinder.point_at(u, v) == cylinder.point_at(u, v, world=False).transformed(cylinder.transformation) - assert close(cylinder.radius, other.radius, tol=1e-12) + assert TOL.is_close(cylinder.radius, other.radius) assert cylinder.frame == other.frame diff --git a/tests/compas/geometry/test_surfaces_plane.py b/tests/compas/geometry/test_surfaces_plane.py index ce8245b31c3..d219bec4288 100644 --- a/tests/compas/geometry/test_surfaces_plane.py +++ b/tests/compas/geometry/test_surfaces_plane.py @@ -7,7 +7,7 @@ from compas.geometry import Vector # noqa: F401 from compas.geometry import Frame from compas.geometry import PlanarSurface -from compas.geometry import close +from compas.tolerance import TOL from compas.itertools import linspace @@ -34,8 +34,8 @@ def test_plane(xsize, ysize): other = eval(repr(plane)) - assert close(plane.xsize, other.xsize, tol=1e-12) - assert close(plane.ysize, other.ysize, tol=1e-12) + assert TOL.is_close(plane.xsize, other.xsize) + assert TOL.is_close(plane.ysize, other.ysize) assert plane.frame == other.frame @@ -62,8 +62,8 @@ def test_plane_frame(frame): other = eval(repr(plane)) - assert close(plane.xsize, other.xsize, tol=1e-12) - assert close(plane.ysize, other.ysize, tol=1e-12) + assert TOL.is_close(plane.xsize, other.xsize) + assert TOL.is_close(plane.ysize, other.ysize) assert plane.frame == other.frame diff --git a/tests/compas/geometry/test_surfaces_sphere.py b/tests/compas/geometry/test_surfaces_sphere.py index 4a1864bef55..6fd1e94cc7d 100644 --- a/tests/compas/geometry/test_surfaces_sphere.py +++ b/tests/compas/geometry/test_surfaces_sphere.py @@ -8,7 +8,7 @@ from compas.geometry import Vector # noqa: F401 from compas.geometry import Frame from compas.geometry import SphericalSurface -from compas.geometry import close +from compas.tolerance import TOL @pytest.mark.parametrize( @@ -31,7 +31,7 @@ def test_spherical_surface(radius): other = eval(repr(surf)) - assert close(surf.radius, other.radius, tol=1e-12) + assert TOL.is_close(surf.radius, other.radius) assert surf.frame == other.frame @@ -55,7 +55,7 @@ def test_spherical_surface_with_frame(frame): other = eval(repr(surf)) - assert close(surf.radius, other.radius, tol=1e-12) + assert TOL.is_close(surf.radius, other.radius) assert surf.frame == other.frame diff --git a/tests/compas/geometry/test_surfaces_torus.py b/tests/compas/geometry/test_surfaces_torus.py index 3af4bfe662d..cf8b4739886 100644 --- a/tests/compas/geometry/test_surfaces_torus.py +++ b/tests/compas/geometry/test_surfaces_torus.py @@ -8,7 +8,7 @@ from compas.geometry import Vector # noqa: F401 from compas.geometry import Frame from compas.geometry import ToroidalSurface -from compas.geometry import close +from compas.tolerance import TOL @pytest.mark.parametrize( @@ -34,8 +34,8 @@ def test_torus(radius_axis, radius_pipe): other = eval(repr(torus)) - assert close(torus.radius_axis, other.radius_axis, tol=1e-12) - assert close(torus.radius_pipe, other.radius_pipe, tol=1e-12) + assert TOL.is_close(torus.radius_axis, other.radius_axis) + assert TOL.is_close(torus.radius_pipe, other.radius_pipe) assert torus.frame == other.frame @@ -60,8 +60,8 @@ def test_torus_with_frame(frame): other = eval(repr(torus)) - assert close(torus.radius_axis, other.radius_axis, tol=1e-12) - assert close(torus.radius_pipe, other.radius_pipe, tol=1e-12) + assert TOL.is_close(torus.radius_axis, other.radius_axis) + assert TOL.is_close(torus.radius_pipe, other.radius_pipe) assert torus.frame == other.frame diff --git a/tests/compas/geometry/test_transformations/test_matrices.py b/tests/compas/geometry/test_transformations/test_matrices.py index b55147fbdac..9d3d9cc0bec 100644 --- a/tests/compas/geometry/test_transformations/test_matrices.py +++ b/tests/compas/geometry/test_transformations/test_matrices.py @@ -5,7 +5,7 @@ from compas.geometry import Frame from compas.geometry import Rotation from compas.geometry import Translation -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import axis_and_angle_from_matrix from compas.geometry import axis_angle_from_quaternion from compas.geometry import axis_angle_vector_from_matrix @@ -55,7 +55,7 @@ def test_matrix_determinant(R, T): def test_matrix_inverse(R, T): - assert allclose( + assert TOL.is_allclose( matrix_inverse(R.matrix), [ [1.0, -0.0, 0.0, -0.0], @@ -64,7 +64,7 @@ def test_matrix_inverse(R, T): [-0.0, 0.0, -0.0, 1.0], ], ) - assert allclose( + assert TOL.is_allclose( matrix_inverse(T.matrix), [ [1.0, -0.0, 0.0, -1.0], @@ -135,7 +135,7 @@ def test_matrix_from_frame(): [0.2703110366411609, -0.14975955581430114, 0.9510541619236438, 1.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(T, t) + assert TOL.is_allclose(T, t) def test_matrix_from_euler_angles(): @@ -148,7 +148,7 @@ def test_matrix_from_euler_angles(): [-0.479425538604203, 0.8648134986574489, 0.14916020070358058, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R, r) + assert TOL.is_allclose(R, r) def test_euler_angles_from_matrix(): @@ -156,7 +156,7 @@ def test_euler_angles_from_matrix(): args = True, "xyz" R = matrix_from_euler_angles(ea1, *args) ea2 = euler_angles_from_matrix(R, *args) - assert allclose(ea1, ea2) + assert TOL.is_allclose(ea1, ea2) def test_matrix_from_axis_angle_vector(): @@ -169,7 +169,7 @@ def test_matrix_from_axis_angle_vector(): [0.037628871037522216, -0.008171760019527692, 0.9992583701939277, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R, r) + assert TOL.is_allclose(R, r) def test_matrix_from_basis_vectors(): @@ -182,7 +182,7 @@ def test_matrix_from_basis_vectors(): [0.2703110366411609, -0.14975954908850603, 0.9510541192112079, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R, r) + assert TOL.is_allclose(R, r) def test_matrix_from_translation(): @@ -193,7 +193,7 @@ def test_matrix_from_translation(): [0.0, 0.0, 1.0, 3.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(T, t) + assert TOL.is_allclose(T, t) def test_matrix_from_orthogonal_projection(): @@ -206,7 +206,7 @@ def test_matrix_from_orthogonal_projection(): [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(P, p) + assert TOL.is_allclose(P, p) def test_matrix_from_parallel_projection(): @@ -220,7 +220,7 @@ def test_matrix_from_parallel_projection(): [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(P, p) + assert TOL.is_allclose(P, p) def test_matrix_from_perspective_projection(): @@ -234,7 +234,7 @@ def test_matrix_from_perspective_projection(): [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0], ] - assert allclose(P, p) + assert TOL.is_allclose(P, p) def test_matrix_from_perspective_entries(): @@ -282,7 +282,7 @@ def test_matrix_from_shear(): ], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(S, s) + assert TOL.is_allclose(S, s) def test_matrix_from_scale_factors(): @@ -304,14 +304,14 @@ def test_matrix_from_quaternion(): [0.22332300929163754, -0.11533619742231993, 0.9678968927964832, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R, r) + assert TOL.is_allclose(R, r) def test_euler_angles_from_quaternion(): axis = [1.0, 0.0, 0.0] angle = math.pi / 2 q = quaternion_from_axis_angle(axis, angle) - assert allclose(euler_angles_from_quaternion(q), [math.pi / 2, 0, 0]) + assert TOL.is_allclose(euler_angles_from_quaternion(q), [math.pi / 2, 0, 0]) def test_axis_and_angle_from_matrix(): @@ -319,35 +319,35 @@ def test_axis_and_angle_from_matrix(): angle1 = 0.1 R = matrix_from_axis_and_angle(axis1, angle1) axis2, angle2 = axis_and_angle_from_matrix(R) - assert allclose(axis1, axis2) - assert allclose([angle1], [angle2]) + assert TOL.is_allclose(axis1, axis2) + assert TOL.is_allclose([angle1], [angle2]) def test_axis_angle_vector_from_matrix(): aav1 = [-0.043, -0.254, 0.617] R = matrix_from_axis_angle_vector(aav1) aav2 = axis_angle_vector_from_matrix(R) - assert allclose(aav1, aav2) + assert TOL.is_allclose(aav1, aav2) def test_axis_angle_from_quaternion(): q = [1.0, 1.0, 0.0, 0.0] axis, angle = axis_angle_from_quaternion(q) - assert allclose(axis, [1.0, 0.0, 0.0]) - assert allclose([angle], [math.pi / 2], 1e-6) + assert TOL.is_allclose(axis, [1.0, 0.0, 0.0]) + assert TOL.is_allclose([angle], [math.pi / 2]) def test_quaternion_from_matrix(): q1 = [0.945, -0.021, -0.125, 0.303] R = matrix_from_quaternion(q1) q2 = quaternion_from_matrix(R) - assert allclose(q1, q2, tol=1e-03) + assert TOL.is_allclose(q1, q2, atol=1e-03) def test_quaternion_from_euler_angles(): axis = [1.0, 0.0, 0.0] angle = math.pi / 2 - assert allclose( + assert TOL.is_allclose( quaternion_from_axis_angle(axis, angle), quaternion_from_euler_angles([math.pi / 2, 0, 0]), ) @@ -357,15 +357,15 @@ def test_quaternion_from_axis_angle(): axis = [1.0, 0.0, 0.0] angle = math.pi / 2 q = quaternion_from_axis_angle(axis, angle) - assert allclose(q, [math.sqrt(2) / 2, math.sqrt(2) / 2, 0, 0]) + assert TOL.is_allclose(q, [math.sqrt(2) / 2, math.sqrt(2) / 2, 0, 0]) def test_basis_vectors_from_matrix(): f = Frame([0, 0, 0], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) R = matrix_from_frame(f) xaxis, yaxis = basis_vectors_from_matrix(R) - assert allclose(xaxis, [0.6807833515407016, 0.6807833515407016, 0.2703110366411609]) - assert allclose(yaxis, [-0.6687681911461376, 0.7282315441900513, -0.14975955581430114]) + assert TOL.is_allclose(xaxis, [0.6807833515407016, 0.6807833515407016, 0.2703110366411609]) + assert TOL.is_allclose(yaxis, [-0.6687681911461376, 0.7282315441900513, -0.14975955581430114]) def test_translation_from_matrix(): diff --git a/tests/compas/geometry/test_transformations/test_rotation.py b/tests/compas/geometry/test_transformations/test_rotation.py index a173bb7a9a8..0cc80a0d04e 100644 --- a/tests/compas/geometry/test_transformations/test_rotation.py +++ b/tests/compas/geometry/test_transformations/test_rotation.py @@ -1,7 +1,7 @@ from compas.geometry import Frame from compas.geometry import Rotation from compas.geometry import Transformation -from compas.geometry import allclose +from compas.tolerance import TOL from compas.geometry import normalize_vector @@ -15,21 +15,21 @@ def test_from_basis_vectors(): [0.2703110366411609, -0.14975954908850603, 0.9510541192112079, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R.matrix, matrix) + assert TOL.is_allclose(R.matrix, matrix) def test_from_frame(): f1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(f1) f2 = Frame.from_transformation(T) - assert allclose(f1, f2) + assert TOL.is_allclose(f1, f2) def test_from_quaternion(): q1 = [0.945, -0.021, -0.125, 0.303] R = Rotation.from_quaternion(q1) q2 = R.quaternion - assert allclose(q1, q2, tol=1e-3) + assert TOL.is_allclose(q1, q2, atol=1e-3) def test_from_axis_angle_vector(): @@ -37,8 +37,8 @@ def test_from_axis_angle_vector(): angle1 = 0.1 R = Rotation.from_axis_and_angle(axis1, angle1) axis2, angle2 = R.axis_and_angle - assert allclose(axis1, axis2) - assert allclose([angle1], [angle2]) + assert TOL.is_allclose(axis1, axis2) + assert TOL.is_allclose([angle1], [angle2]) def test_from_euler_angles(): @@ -46,7 +46,7 @@ def test_from_euler_angles(): args = False, "xyz" R1 = Rotation.from_euler_angles(ea1, *args) ea2 = R1.euler_angles(*args) - assert allclose(ea1, ea2) + assert TOL.is_allclose(ea1, ea2) alpha, beta, gamma = ea1 xaxis, yaxis, zaxis = [1, 0, 0], [0, 1, 0], [0, 0, 1] @@ -54,14 +54,14 @@ def test_from_euler_angles(): Ry = Rotation.from_axis_and_angle(yaxis, beta) Rz = Rotation.from_axis_and_angle(zaxis, gamma) R2 = Rx * Ry * Rz - assert allclose(R1, R2) + assert TOL.is_allclose(R1, R2) def test_quaternion(): q1 = [0.945, -0.021, -0.125, 0.303] R = Rotation.from_quaternion(q1) q2 = R.quaternion - assert allclose(q1, q2, tol=1e-3) + assert TOL.is_allclose(q1, q2, atol=1e-3) def test_axis_and_angle(): @@ -69,15 +69,15 @@ def test_axis_and_angle(): angle1 = 0.1 R = Rotation.from_axis_and_angle(axis1, angle1) axis2, angle2 = R.axis_and_angle - assert allclose(axis1, axis2) - assert allclose([angle1], [angle2]) + assert TOL.is_allclose(axis1, axis2) + assert TOL.is_allclose([angle1], [angle2]) def test_axis_angle_vector(): aav1 = [-0.043, -0.254, 0.617] R = Rotation.from_axis_angle_vector(aav1) aav2 = R.axis_angle_vector - assert allclose(aav1, aav2) + assert TOL.is_allclose(aav1, aav2) def test_euler_angles(): @@ -85,7 +85,7 @@ def test_euler_angles(): args = False, "xyz" R1 = Rotation.from_euler_angles(ea1, *args) ea2 = R1.euler_angles(*args) - assert allclose(ea1, ea2) + assert TOL.is_allclose(ea1, ea2) def test_basis_vectors(): @@ -96,4 +96,4 @@ def test_basis_vectors(): [-0.5847122176808724, -0.18803656702967916, 0.789147560317086], [-0.6544178905170501, -0.4655532858863264, -0.5958165511058404], ] - assert allclose(R.basis_vectors, basis_vectors) + assert TOL.is_allclose(R.basis_vectors, basis_vectors) diff --git a/tests/compas/geometry/test_transformations/test_shear.py b/tests/compas/geometry/test_transformations/test_shear.py index d3e80382b96..17a4aeaf82a 100644 --- a/tests/compas/geometry/test_transformations/test_shear.py +++ b/tests/compas/geometry/test_transformations/test_shear.py @@ -1,5 +1,5 @@ from compas.geometry import Shear -from compas.geometry import allclose +from compas.tolerance import TOL def test_shear(): @@ -14,7 +14,7 @@ def test_shear(): [0.0, 0.0, 1.0, -0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(S.matrix, s) + assert TOL.is_allclose(S.matrix, s) def test_from_entries(): @@ -26,4 +26,4 @@ def test_from_entries(): [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(S.matrix, s) + assert TOL.is_allclose(S.matrix, s) diff --git a/tests/compas/geometry/test_transformations/test_transformation.py b/tests/compas/geometry/test_transformations/test_transformation.py index 2b91987aebf..edd5249b0ac 100644 --- a/tests/compas/geometry/test_transformations/test_transformation.py +++ b/tests/compas/geometry/test_transformations/test_transformation.py @@ -4,7 +4,7 @@ from compas.geometry import Transformation from compas.geometry import Translation from compas.geometry import Vector -from compas.geometry import allclose +from compas.tolerance import TOL def test_transformation(): @@ -48,7 +48,7 @@ def test_from_euler_angles(): [-0.9090506362335324, -0.35053715668381935, -0.22527903264048646, 0.25], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R.matrix, matrix) + assert TOL.is_allclose(R.matrix, matrix) def test_from_frame(): @@ -89,7 +89,7 @@ def test_rotation(): [-0.9090506362335324, -0.35053715668381935, -0.22527903264048646, 0.0], [0.0, 0.0, 0.0, 1.0], ] - assert allclose(R.matrix, matrix) + assert TOL.is_allclose(R.matrix, matrix) def test_rotation_property(): @@ -113,8 +113,8 @@ def test_basis_vectors(): S1 = Scale.from_factors(scale1) M = (T1 * R1) * S1 x, y = M.basis_vectors - assert allclose(x, Vector(0.41249169135312663, -0.05897071585157175, -0.9090506362335324)) - assert allclose(y, Vector(-0.8335562904208867, -0.4269749553355485, -0.35053715668381935)) + assert TOL.is_allclose(x, Vector(0.41249169135312663, -0.05897071585157175, -0.9090506362335324)) + assert TOL.is_allclose(y, Vector(-0.8335562904208867, -0.4269749553355485, -0.35053715668381935)) def test_list(): @@ -145,7 +145,7 @@ def test_concatenated(): T1 = Translation.from_vector(trans1) R1 = Rotation.from_euler_angles(angle1) M1 = T1.concatenated(R1) - assert allclose(M1, T1 * R1) + assert TOL.is_allclose(M1, T1 * R1) def test___repr__(): diff --git a/tests/compas/rpc/test_rpc.py b/tests/compas/rpc/test_rpc.py index a4cb0620b51..26e424f8d35 100644 --- a/tests/compas/rpc/test_rpc.py +++ b/tests/compas/rpc/test_rpc.py @@ -1,6 +1,6 @@ # import os -from compas.geometry import allclose +from compas.tolerance import TOL from compas.rpc import Proxy @@ -17,4 +17,4 @@ def test_switch_package(): proxy.package = "scipy.linalg" r = proxy.inv(A) - assert allclose(r, [[-2, 1], [1.5, -0.5]]) + assert TOL.is_allclose(r, [[-2, 1], [1.5, -0.5]]) diff --git a/tests/compas/test_iotools.py b/tests/compas/test_iotools.py index 59a03962074..2154559add3 100644 --- a/tests/compas/test_iotools.py +++ b/tests/compas/test_iotools.py @@ -56,7 +56,7 @@ def test_open_file_object_text(path_text): def test_open_file_memory_stream(): - text = b"All Gaul is divided into three parts, one of which the Belgae inhabit, the Aquitani another, those who in their own language are called Celts, in our Gauls, the third." + text = b"All Gaul is divided into three parts, one of which the Belgae inhabit, the Aquitani another, those who in their own language are called Celts, in our Gauls, the third." # noqa: E501 data = io.BytesIO(text) with _iotools.open_file(data, mode="rb") as f: assert f.read() == text diff --git a/tests/compas/utilities/test_itertools.py b/tests/compas/test_itertools.py similarity index 74% rename from tests/compas/utilities/test_itertools.py rename to tests/compas/test_itertools.py index 8c42a330f1c..844dac3a2ec 100644 --- a/tests/compas/utilities/test_itertools.py +++ b/tests/compas/test_itertools.py @@ -2,10 +2,10 @@ import pytest from compas.datastructures import Mesh -from compas.utilities import iterable_like -from compas.utilities import reshape -from compas.utilities import flatten -from compas.geometry import allclose +from compas.itertools import iterable_like +from compas.itertools import reshape +from compas.itertools import flatten +from compas.tolerance import TOL # ============================================================================== @@ -44,16 +44,16 @@ def test_iterable_cap_generator(mesh_a, mesh_b): def test_reshape(): a = [1, 2, 3, 4, 5, 6] - assert allclose(reshape(a, (2, 3)), [[1, 2, 3], [4, 5, 6]]) - assert allclose(reshape(a, (3, 2)), [[1, 2], [3, 4], [5, 6]]) + assert TOL.is_allclose(reshape(a, (2, 3)), [[1, 2, 3], [4, 5, 6]]) + assert TOL.is_allclose(reshape(a, (3, 2)), [[1, 2], [3, 4], [5, 6]]) a = [[1, 2], [3, 4], [5, 6]] - assert allclose(reshape(a, (2, 3)), [[1, 2, 3], [4, 5, 6]]) + assert TOL.is_allclose(reshape(a, (2, 3)), [[1, 2, 3], [4, 5, 6]]) a = [1, 2, 3, 4] - assert allclose(reshape(a, (4, 1)), [[1], [2], [3], [4]]) + assert TOL.is_allclose(reshape(a, (4, 1)), [[1], [2], [3], [4]]) def test_flatten(): a = [[1, 2, 3], [4, 5, 6]] - assert allclose(flatten(a), [1, 2, 3, 4, 5, 6]) + assert TOL.is_allclose(flatten(a), [1, 2, 3, 4, 5, 6]) a = [[1], [2], [3], [4]] - assert allclose(flatten(a), [1, 2, 3, 4]) + assert TOL.is_allclose(flatten(a), [1, 2, 3, 4]) diff --git a/tests/compas/utilities/test_async_.py b/tests/compas/utilities/test_async_.py deleted file mode 100644 index d4abfebcba4..00000000000 --- a/tests/compas/utilities/test_async_.py +++ /dev/null @@ -1,112 +0,0 @@ -from threading import Thread - -from compas.utilities import await_callback - -import pytest - - -def test_void_return_callback(): - def async_fn(callback): - def runner(cb): - cb() - - Thread(target=runner, args=(callback,)).start() - - result = await_callback(async_fn) - assert result is None - - -def test_single_positional_arg_callback(): - def async_fn(callback): - def runner(cb): - cb("only_return_value") - - Thread(target=runner, args=(callback,)).start() - - result = await_callback(async_fn) - assert result == "only_return_value" - - -def test_many_positional_args_callback(): - def async_fn(callback): - def runner(cb): - cb(1, 2) - - Thread(target=runner, args=(callback,)).start() - - result = await_callback(async_fn) - assert result == ( - 1, - 2, - ) - - -def test_kwargs_callback(): - def async_fn(callback): - def runner(cb): - cb(name="Austin", last_name="Powers") - - Thread(target=runner, args=(callback,)).start() - - result = await_callback(async_fn) - assert result["name"] == "Austin" - assert result["last_name"] == "Powers" - - -def test_one_positional_arg_and_kwargs_callback(): - def async_fn(callback): - def runner(cb): - cb(1, retries=5) - - Thread(target=runner, args=(callback,)).start() - - result, kwargs = await_callback(async_fn) - assert result == 1 - assert kwargs["retries"] == 5 - - -def test_many_positional_args_and_kwargs_callback(): - def async_fn(callback): - def runner(cb): - cb(4, 2, 3, retries=5) - - Thread(target=runner, args=(callback,)).start() - - a, b, c, kw = await_callback(async_fn) - assert a == 4 - assert b == 2 - assert c == 3 - assert kw["retries"] == 5 - - -def test_async_fn_with_more_params(): - def async_fn(values, other_stuff, callback): - def runner(cb): - cb(200) - - Thread(target=runner, args=(callback,)).start() - - result = await_callback(async_fn, values=[1, 2, 3], other_stuff=None) - assert result == 200 - - -def test_captured_exception_in_thread(): - def async_fn(callback): - def runner(cb): - raise ValueError("exception") - - Thread(target=runner, args=(callback,)).start() - - with pytest.raises(ValueError): - await_callback(async_fn) - - -def test_errback(): - def async_fn(callback, errback): - def runner(cb, eb): - eb(ValueError("exception via errback")) - - Thread(target=runner, args=(callback, errback)).start() - - with pytest.raises(ValueError): - await_callback(async_fn, errback_name="errback") diff --git a/tests/compas/utilities/test_itertools_.py b/tests/compas/utilities/test_itertools_.py deleted file mode 100644 index b5026a0d8ac..00000000000 --- a/tests/compas/utilities/test_itertools_.py +++ /dev/null @@ -1,39 +0,0 @@ -import compas -import pytest - -from compas.datastructures import Mesh -from compas.utilities import iterable_like - - -# ============================================================================== -# iterable_like -# ============================================================================== - - -@pytest.mark.parametrize(("target", "base", "fillvalue"), [("hello", [0.5], 0.5)]) -def test_iterable_like_string_and_float(target, base, fillvalue): - a = list(iterable_like(target, base, fillvalue)) - assert a == [0.5, 0.5, 0.5, 0.5, 0.5] - - -@pytest.mark.parametrize( - ("target", "base", "fillvalue"), - [(["foo", "bar", "baz"], {"key_1": "a", "key_2": "b"}, "key_3")], -) -def test_iterable_like_list_and_dict(target, base, fillvalue): - a = list(iterable_like(target, base, fillvalue)) - assert sorted(a) == ["key_1", "key_2", "key_3"] - - -@pytest.mark.parametrize(("target", "base", "fillvalue"), [(range(2), ["a", "b"], 0)]) -def test_iterable_like_generator_and_list(target, base, fillvalue): - a = list(iterable_like(target, base, fillvalue)) - assert a == ["a", "b"] - - -@pytest.mark.parametrize(("mesh_a", "mesh_b"), [("faces.obj", "hypar.obj"), ("hypar.obj", "faces.obj")]) -def test_iterable_cap_generator(mesh_a, mesh_b): - ma = Mesh.from_obj(compas.get(mesh_a)) - mb = Mesh.from_obj(compas.get(mesh_b)) - a = list(iterable_like(ma.faces(), mb.faces())) - assert len(a) == len(list(ma.faces()))