From 2ba853321ada7044c5cae88c2da8fb2f4582bf28 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Mon, 26 Jul 2021 18:46:29 +0200 Subject: [PATCH 001/150] Adding reshape and unflatten to compas.utilities --- CHANGELOG.md | 1 + src/compas/utilities/__init__.py | 2 + src/compas/utilities/itertools.py | 75 ++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9d0ec25919..bfab7d3e0ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `compas.data.is_sequence_of_uint`. * Added general plotter for geometry objects and data structures based on the artist registration mechanism. * Added support for multimesh files to OBJ reader/writer. +* Added `reshape` and `unflatten` in `compas.utilities` ### Changed diff --git a/src/compas/utilities/__init__.py b/src/compas/utilities/__init__.py index b6eae6dadeb..937bde67caf 100644 --- a/src/compas/utilities/__init__.py +++ b/src/compas/utilities/__init__.py @@ -53,6 +53,8 @@ :nosignatures: flatten + unflatten + reshape linspace meshgrid pairwise diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index 451844c1bad..13afe6be151 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -8,6 +8,8 @@ from itertools import chain from itertools import repeat from itertools import tee +from functools import reduce +from operator import mul try: from itertools import zip_longest @@ -21,6 +23,8 @@ 'meshgrid', 'linspace', 'flatten', + 'unflatten', + 'reshape', 'pairwise', 'window', 'iterable_like', @@ -185,10 +189,79 @@ def linspace(start, stop, num=50): def flatten(list_of_lists): - """Flatten one level of nesting""" + """Flatten one level of nesting. + + Examples + -------- + >>> a = [[1, 2, 3], [4, 5, 6]] + >>> list(flatten(a)) + [1, 2, 3, 4, 5, 6] + """ return chain.from_iterable(list_of_lists) +def unflatten(lst, num): + """Returns a nested list. + + Parameters + ---------- + lst : list + A list of items. + num : int + The length of the sub-list. + + Raises + ------ + ValueError + If the length of the list is not a factor of num. + + + Examples + -------- + >>> a = [1, 2, 3, 4, 5, 6] + >>> unflatten(a, 3) + [[1, 2, 3], [4, 5, 6]] + """ + if len(lst) % num: + raise ValueError("The length of the array must be a factor of n: %d %% %d == 0" % (len(lst), num)) + return [lst[i:i + num] for i in range(0, len(lst), num)] + + +def reshape(lst, shape): + """Gives a new shape to an array without changing its data. + + This function mimicks the functionality of ``numpy.reshape`` [1]_, but in a simpler form. + + Parameters + ---------- + lst : list + A list of items. + shape : int or tuple of ints + The new shape of the list + + + Examples + -------- + >>> a = [1, 2, 3, 4, 5, 6] + >>> reshape(a, (2, 3)) + [[1, 2, 3], [4, 5, 6]] + >>> reshape(a, (3, 2)) + [[1, 2], [3, 4], [5, 6]] + + + References + ---------- + .. [1] ``numpy.reshape`` Available at https://numpy.org/doc/stable/reference/generated/numpy.reshape.html + + """ + if len(shape) == 1: + return lst + if len(lst) != reduce(lambda x, y: x * y, shape): + raise ValueError("ValueError: cannot reshape array of size %d into shape %s" % (len(lst), shape)) + n = reduce(mul, shape[1:]) + return [reshape(lst[i * n:(i + 1) * n], shape[1:]) for i in range(len(lst) // n)] + + def pairwise(iterable): """Returns a sliding window of size 2 over the data of the iterable. From ed2229b2fdfb9703a2013b96cb3ac6142db60bcd Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Mon, 26 Jul 2021 18:49:38 +0200 Subject: [PATCH 002/150] small function add to glft --- CHANGELOG.md | 1 + src/compas/files/gltf/gltf_content.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfab7d3e0ce..363280acffd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added general plotter for geometry objects and data structures based on the artist registration mechanism. * Added support for multimesh files to OBJ reader/writer. * Added `reshape` and `unflatten` in `compas.utilities` +* Adding `get_node_by_name` to `compas.files.gltf.GLTFContent` ### Changed diff --git a/src/compas/files/gltf/gltf_content.py b/src/compas/files/gltf/gltf_content.py index 149cf7e9116..db0eba8fe6c 100644 --- a/src/compas/files/gltf/gltf_content.py +++ b/src/compas/files/gltf/gltf_content.py @@ -43,6 +43,7 @@ class GLTFContent(object): extensions : object """ + def __init__(self): self.scenes = {} self.default_scene_key = None @@ -398,6 +399,23 @@ def visit(node, key): return positions_dict, edges_list + def get_node_by_name(self, name): + """Returns the node with a specific name. + + Parameters + ---------- + name : str + The name of the node + + Returns + ------- + node : :class:`compas.files.GLTFNode` or `None` + """ + for key in self.nodes: + if self.nodes[key].name == name: + return self.nodes[key] + return None + # ============================================================================== # Main @@ -426,6 +444,7 @@ def visit(node, key): node_2 = node_1.add_child(child_name='Node2') node_2.translation = [0, 0, 5] node_2.add_mesh(mesh_data.key) + assert(node_1 == cnt.get_node_by_name('Node1')) gltf = GLTF(gltf_filepath) gltf.content = cnt From a10d0ad2edd99289d944f1eceaea04221269bf99 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Wed, 28 Jul 2021 18:51:00 +0200 Subject: [PATCH 003/150] Revert "small function add to glft" This reverts commit ed2229b2fdfb9703a2013b96cb3ac6142db60bcd. --- CHANGELOG.md | 1 - src/compas/files/gltf/gltf_content.py | 19 ------------------- 2 files changed, 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 363280acffd..bfab7d3e0ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added general plotter for geometry objects and data structures based on the artist registration mechanism. * Added support for multimesh files to OBJ reader/writer. * Added `reshape` and `unflatten` in `compas.utilities` -* Adding `get_node_by_name` to `compas.files.gltf.GLTFContent` ### Changed diff --git a/src/compas/files/gltf/gltf_content.py b/src/compas/files/gltf/gltf_content.py index db0eba8fe6c..149cf7e9116 100644 --- a/src/compas/files/gltf/gltf_content.py +++ b/src/compas/files/gltf/gltf_content.py @@ -43,7 +43,6 @@ class GLTFContent(object): extensions : object """ - def __init__(self): self.scenes = {} self.default_scene_key = None @@ -399,23 +398,6 @@ def visit(node, key): return positions_dict, edges_list - def get_node_by_name(self, name): - """Returns the node with a specific name. - - Parameters - ---------- - name : str - The name of the node - - Returns - ------- - node : :class:`compas.files.GLTFNode` or `None` - """ - for key in self.nodes: - if self.nodes[key].name == name: - return self.nodes[key] - return None - # ============================================================================== # Main @@ -444,7 +426,6 @@ def get_node_by_name(self, name): node_2 = node_1.add_child(child_name='Node2') node_2.translation = [0, 0, 5] node_2.add_mesh(mesh_data.key) - assert(node_1 == cnt.get_node_by_name('Node1')) gltf = GLTF(gltf_filepath) gltf.content = cnt From 99ec0cb882f0e48ee37b5cae8fc8d28436259d52 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Wed, 28 Jul 2021 18:58:40 +0200 Subject: [PATCH 004/150] Update __init__.py --- src/compas/utilities/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compas/utilities/__init__.py b/src/compas/utilities/__init__.py index 937bde67caf..754bafe38e0 100644 --- a/src/compas/utilities/__init__.py +++ b/src/compas/utilities/__init__.py @@ -137,6 +137,8 @@ from .images import gif_from_images from .itertools import ( flatten, + unflatten, + reshape, grouper, iterable_like, linspace, @@ -205,6 +207,8 @@ 'meshgrid', 'linspace', 'flatten', + 'unflatten', + 'rehape', 'pairwise', 'window', 'iterable_like', From 1fe82a01b431b61421aa9c94d2ae4ff00f1ab0a6 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Wed, 28 Jul 2021 19:01:29 +0200 Subject: [PATCH 005/150] Update __init__.py --- src/compas/utilities/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compas/utilities/__init__.py b/src/compas/utilities/__init__.py index 754bafe38e0..69c3e2c52b1 100644 --- a/src/compas/utilities/__init__.py +++ b/src/compas/utilities/__init__.py @@ -208,7 +208,7 @@ 'linspace', 'flatten', 'unflatten', - 'rehape', + 'reshape', 'pairwise', 'window', 'iterable_like', From 4dc265edf48748b42366abd653a7ebb15d69c367 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 30 Jul 2021 23:39:34 +0200 Subject: [PATCH 006/150] Update src/compas/utilities/itertools.py Co-authored-by: beverlylytle <57254617+beverlylytle@users.noreply.github.com> --- src/compas/utilities/itertools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index 13afe6be151..7efeed30e3d 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -230,7 +230,7 @@ def unflatten(lst, num): def reshape(lst, shape): """Gives a new shape to an array without changing its data. - This function mimicks the functionality of ``numpy.reshape`` [1]_, but in a simpler form. + This function mimics the functionality of ``numpy.reshape`` [1]_, but in a simpler form. Parameters ---------- From 95c1e5943e279fd4b2ea12c9812d5dd1c5f92e66 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 30 Jul 2021 23:42:10 +0200 Subject: [PATCH 007/150] removing unflatten --- src/compas/utilities/itertools.py | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index 7efeed30e3d..5cdddb5cd2c 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -200,33 +200,6 @@ def flatten(list_of_lists): return chain.from_iterable(list_of_lists) -def unflatten(lst, num): - """Returns a nested list. - - Parameters - ---------- - lst : list - A list of items. - num : int - The length of the sub-list. - - Raises - ------ - ValueError - If the length of the list is not a factor of num. - - - Examples - -------- - >>> a = [1, 2, 3, 4, 5, 6] - >>> unflatten(a, 3) - [[1, 2, 3], [4, 5, 6]] - """ - if len(lst) % num: - raise ValueError("The length of the array must be a factor of n: %d %% %d == 0" % (len(lst), num)) - return [lst[i:i + num] for i in range(0, len(lst), num)] - - def reshape(lst, shape): """Gives a new shape to an array without changing its data. From 55f2921e878450123b77202bf04fc2165e89c21e Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Sat, 31 Jul 2021 11:35:31 +0200 Subject: [PATCH 008/150] adding tests --- tests/compas/utilities/test_itertools.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/compas/utilities/test_itertools.py b/tests/compas/utilities/test_itertools.py index ba09e99fae5..1a1ae1ad734 100644 --- a/tests/compas/utilities/test_itertools.py +++ b/tests/compas/utilities/test_itertools.py @@ -3,6 +3,9 @@ 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 # ============================================================================== @@ -15,6 +18,7 @@ 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): @@ -37,3 +41,20 @@ def test_iterable_cap_generator(mesh_a, mesh_b): mb = Mesh.from_obj(compas.get(mesh_b)) a = list(iterable_like(ma.faces(), mb.faces())) assert len(a) == len(list(ma.faces())) + + +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]])) + a = [[1, 2], [3, 4], [5, 6]] + assert(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]])) + + +def test_flatten(): + a = [[1, 2, 3], [4, 5, 6]] + assert(allclose(flatten(a), [1, 2, 3, 4, 5, 6])) + a = [[1], [2], [3], [4]] + assert(allclose(flatten(a), [1, 2, 3, 4])) From 2d569b6b4ec8508507b7195daa8cc0bdf27b6430 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Sat, 31 Jul 2021 11:35:46 +0200 Subject: [PATCH 009/150] remove unflatten from init --- src/compas/utilities/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/compas/utilities/__init__.py b/src/compas/utilities/__init__.py index 69c3e2c52b1..7587011433c 100644 --- a/src/compas/utilities/__init__.py +++ b/src/compas/utilities/__init__.py @@ -53,7 +53,6 @@ :nosignatures: flatten - unflatten reshape linspace meshgrid @@ -137,7 +136,6 @@ from .images import gif_from_images from .itertools import ( flatten, - unflatten, reshape, grouper, iterable_like, @@ -207,7 +205,6 @@ 'meshgrid', 'linspace', 'flatten', - 'unflatten', 'reshape', 'pairwise', 'window', From 40accd62eed0f45dd1d4c934d78399a840a8a380 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Sat, 31 Jul 2021 11:39:23 +0200 Subject: [PATCH 010/150] update flatten and reduce --- src/compas/utilities/itertools.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index 5cdddb5cd2c..c5d68d97b75 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -23,7 +23,6 @@ 'meshgrid', 'linspace', 'flatten', - 'unflatten', 'reshape', 'pairwise', 'window', @@ -194,10 +193,12 @@ def flatten(list_of_lists): Examples -------- >>> a = [[1, 2, 3], [4, 5, 6]] - >>> list(flatten(a)) + >>> flatten(a) [1, 2, 3, 4, 5, 6] """ - return chain.from_iterable(list_of_lists) + if not hasattr(list_of_lists[0], '__len__'): + return list_of_lists + return flatten(list(chain(*list_of_lists))) def reshape(lst, shape): @@ -220,6 +221,9 @@ def reshape(lst, shape): [[1, 2, 3], [4, 5, 6]] >>> reshape(a, (3, 2)) [[1, 2], [3, 4], [5, 6]] + >>> a = [[1, 2], [3, 4], [5, 6]] + >>> reshape(a, (2, 3)) + [[1, 2, 3], [4, 5, 6]] References @@ -227,12 +231,20 @@ def reshape(lst, shape): .. [1] ``numpy.reshape`` Available at https://numpy.org/doc/stable/reference/generated/numpy.reshape.html """ - if len(shape) == 1: - return lst - if len(lst) != reduce(lambda x, y: x * y, shape): + def helper(l, shape): # noqa E741 + if len(shape) == 1: + if len(l) % shape[0] != 0: + raise ValueError("ValueError: cannot reshape array of size %d into shape %s" % (len(lst), shape)) + return l + else: + n = reduce(mul, shape[1:]) + return [helper(l[i * n:(i + 1) * n], shape[1:]) for i in range(len(l) // n)] + + shape = (shape,) if isinstance(shape, int) else shape + flattened_list = flatten(lst) + if len(flattened_list) != reduce(lambda x, y: x * y, shape): raise ValueError("ValueError: cannot reshape array of size %d into shape %s" % (len(lst), shape)) - n = reduce(mul, shape[1:]) - return [reshape(lst[i * n:(i + 1) * n], shape[1:]) for i in range(len(lst) // n)] + return helper(flattened_list, shape) def pairwise(iterable): From cd8e8e278f932beb782537c45177aab6c5ed72c1 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Sat, 31 Jul 2021 11:48:04 +0200 Subject: [PATCH 011/150] update flatten docstr --- src/compas/utilities/itertools.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index c5d68d97b75..c1a197e17c6 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -188,7 +188,11 @@ def linspace(start, stop, num=50): def flatten(list_of_lists): - """Flatten one level of nesting. + """Flattens a multi-dimensional list. + + Notes + ----- + It does only work if the nested sequences have the same lengths or shapes. Examples -------- From 0f5a7f97b1245aeaa07bf529b0c9c0647f8ceeca Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Mon, 2 Aug 2021 09:22:06 +0200 Subject: [PATCH 012/150] Update CHANGELOG.md Co-authored-by: beverlylytle <57254617+beverlylytle@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfab7d3e0ce..16cf77f0efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `compas.data.is_sequence_of_uint`. * Added general plotter for geometry objects and data structures based on the artist registration mechanism. * Added support for multimesh files to OBJ reader/writer. -* Added `reshape` and `unflatten` in `compas.utilities` +* Added `reshape` and generalized `flatten` in `compas.utilities`. ### Changed From d2afaf554de034c5787f2ad24fa271ba4183b6de Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 28 Oct 2022 08:32:42 +0200 Subject: [PATCH 013/150] small fix --- src/compas/files/gltf/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compas/files/gltf/extensions.py b/src/compas/files/gltf/extensions.py index 9c21932765f..0064849f942 100644 --- a/src/compas/files/gltf/extensions.py +++ b/src/compas/files/gltf/extensions.py @@ -4,7 +4,7 @@ def create_if_data(cls, data, attr): - return cls.from_data(data.get(attr)) if attr in data and len(data[attr]) else None + return cls.from_data(data.get(attr)) if attr in data and data[attr] is not None else None class KHR_materials_transmission(BaseGLTFDataClass): From bf59b3736b7230dfe05e636a4e5b37d95a95091c Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 28 Oct 2022 08:33:51 +0200 Subject: [PATCH 014/150] add texture, normals and vertex color support if data available --- src/compas/files/gltf/gltf_mesh.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/compas/files/gltf/gltf_mesh.py b/src/compas/files/gltf/gltf_mesh.py index 2f7d3ddf937..9b78d46d3d8 100644 --- a/src/compas/files/gltf/gltf_mesh.py +++ b/src/compas/files/gltf/gltf_mesh.py @@ -202,7 +202,22 @@ def from_mesh(cls, context, mesh): :class:`~compas.files.GLTFMesh` """ vertices, faces = mesh.to_vertices_and_faces() - return cls.from_vertices_and_faces(context, vertices, faces) + texture_coordinates = mesh.vertices_attribute("texture_coordinate") + vertex_normals = mesh.vertices_attribute("vertex_normal") + vertex_colors = mesh.vertices_attribute("vertex_color") + + print("GLTFMesh.from_mesh : texture_coordinate", texture_coordinates[0]) # TODO: in ipy this is None + print("GLTFMesh.from_mesh : vertex_normals", vertex_normals[0]) # TODO: in ipy this is None + + mesh_data = cls.from_vertices_and_faces(context, vertices, faces) + pd = mesh_data.primitive_data_list[0] + if texture_coordinates[0] is not None: + pd.attributes["TEXCOORD_0"] = texture_coordinates + if vertex_normals[0] is not None: + pd.attributes["NORMAL"] = vertex_normals + if vertex_colors[0] is not None: + pd.attributes["COLOR_0"] = vertex_colors + return mesh_data def to_data(self, primitives): """Returns a JSONable dictionary object in accordance with glTF specifications. From 2572319c6052d3a797a95a6578a1b6fcfbd3de52 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 28 Oct 2022 08:34:10 +0200 Subject: [PATCH 015/150] remove note --- src/compas/files/gltf/gltf_mesh.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/compas/files/gltf/gltf_mesh.py b/src/compas/files/gltf/gltf_mesh.py index 9b78d46d3d8..186c8171e0a 100644 --- a/src/compas/files/gltf/gltf_mesh.py +++ b/src/compas/files/gltf/gltf_mesh.py @@ -206,9 +206,6 @@ def from_mesh(cls, context, mesh): vertex_normals = mesh.vertices_attribute("vertex_normal") vertex_colors = mesh.vertices_attribute("vertex_color") - print("GLTFMesh.from_mesh : texture_coordinate", texture_coordinates[0]) # TODO: in ipy this is None - print("GLTFMesh.from_mesh : vertex_normals", vertex_normals[0]) # TODO: in ipy this is None - mesh_data = cls.from_vertices_and_faces(context, vertices, faces) pd = mesh_data.primitive_data_list[0] if texture_coordinates[0] is not None: From 15a2be9088f6aea9d5afec36c6b83d189bc808e6 Mon Sep 17 00:00:00 2001 From: Romana Rust Date: Fri, 28 Oct 2022 08:54:52 +0200 Subject: [PATCH 016/150] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3f8b61b2b..cd5d7f5f168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +* Changed `GLTFMesh.from_mesh` to read texture coordinates, vertex normals and colors if available and add to `GLTFMesh` + ### Removed From 6433bb7cbad4c55aea1f5dd9a4c022f7bdff5c6d Mon Sep 17 00:00:00 2001 From: Katerina <78984454+katarametin@users.noreply.github.com> Date: Wed, 1 Mar 2023 23:43:44 +0100 Subject: [PATCH 017/150] Fixed unbound method usage of `.cross()` --- CHANGELOG.md | 1 + src/compas/geometry/primitives/frame.py | 4 ++-- src/compas/geometry/primitives/plane.py | 12 +++++++----- src/compas/geometry/primitives/vector.py | 3 ++- tests/compas/geometry/test_frame.py | 10 ++++++++++ tests/compas/geometry/test_plane.py | 19 +++++++++++++++++++ tests/compas/geometry/test_vector.py | 18 ++++++++++++++++++ 7 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/compas/geometry/test_frame.py create mode 100644 tests/compas/geometry/test_plane.py create mode 100644 tests/compas/geometry/test_vector.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3235516f870..63068aeb260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Fixed bug that caused a new-line at the end of the `compas.HERE` constant in IronPython for Mac. +* Fixed unbound method usage of `.cross()` on `Plane`, `Vector` and `Frame`. ### Removed diff --git a/src/compas/geometry/primitives/frame.py b/src/compas/geometry/primitives/frame.py index d6b427f7d73..16ea2d09c5e 100644 --- a/src/compas/geometry/primitives/frame.py +++ b/src/compas/geometry/primitives/frame.py @@ -175,9 +175,9 @@ def yaxis(self): def yaxis(self, vector): yaxis = Vector(*vector) yaxis.unitize() - zaxis = Vector.cross(self.xaxis, yaxis) + zaxis = Vector(*cross_vectors(self.xaxis, yaxis)) zaxis.unitize() - self._yaxis = Vector.cross(zaxis, self.xaxis) + self._yaxis = Vector(*cross_vectors(zaxis, self.xaxis)) @property def normal(self): diff --git a/src/compas/geometry/primitives/plane.py b/src/compas/geometry/primitives/plane.py index 84988b9e0d3..597326ec664 100644 --- a/src/compas/geometry/primitives/plane.py +++ b/src/compas/geometry/primitives/plane.py @@ -1,11 +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.geometry import cross_vectors +from compas.geometry.primitives import Point from compas.geometry.primitives import Primitive from compas.geometry.primitives import Vector -from compas.geometry.primitives import Point class Plane(Primitive): @@ -204,7 +206,7 @@ def from_three_points(cls, a, b, c): a = Point(*a) b = Point(*b) c = Point(*c) - normal = Vector.cross(b - a, c - a) + normal = Vector(*cross_vectors(b - a, c - a)) return cls(a, normal) @classmethod @@ -228,14 +230,14 @@ def from_point_and_two_vectors(cls, point, u, v): Examples -------- - >>> plane = Plane.from_three_points([0.0, 0.0, 0.0], [2.0, 1.0, 0.0], [0.0, 3.0, 0.0]) + >>> plane = Plane.from_point_and_two_vectors([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]) >>> plane.point Point(0.000, 0.000, 0.000) >>> plane.normal Vector(0.000, 0.000, 1.000) """ - normal = Vector.cross(u, v) + normal = Vector(*cross_vectors(u, v)) return cls(point, normal) def from_abcd(cls, abcd): diff --git a/src/compas/geometry/primitives/vector.py b/src/compas/geometry/primitives/vector.py index f7ca259941c..d8dcb7c5a63 100644 --- a/src/compas/geometry/primitives/vector.py +++ b/src/compas/geometry/primitives/vector.py @@ -628,7 +628,8 @@ def cross_vectors(left, right): [Vector(0.000, 0.000, 1.000), Vector(0.000, -4.000, 0.000)] """ - return [Vector.cross(u, v) for u, v in zip(left, right)] + # cross_vectors(u,v) from src\compas\geometry\_core\_algebra.py + return [Vector(*cross_vectors(u, v)) for u, v in zip(left, right)] @staticmethod def angles_vectors(left, right): diff --git a/tests/compas/geometry/test_frame.py b/tests/compas/geometry/test_frame.py new file mode 100644 index 00000000000..77d96adf2df --- /dev/null +++ b/tests/compas/geometry/test_frame.py @@ -0,0 +1,10 @@ +from compas.geometry import Frame + + +def test_axes_are_orthonormal(): + pt = [1, 2, 3] + vec1 = [1, 0, 0] + vec2 = [0, 0.9, 0] + + frame = Frame(pt, vec1, vec2) + assert frame == [[1, 2, 3], [1, 0, 0], [0, 1, 0]] diff --git a/tests/compas/geometry/test_plane.py b/tests/compas/geometry/test_plane.py new file mode 100644 index 00000000000..ec84e9bbf08 --- /dev/null +++ b/tests/compas/geometry/test_plane.py @@ -0,0 +1,19 @@ +from compas.geometry import Plane + + +def test_from_point_and_two_vectors(): + pt = [1, 2, 3] + vec1 = [1, 0, 0] + vec2 = [0, 1, 0] + + result = Plane.from_point_and_two_vectors(pt, vec1, vec2) + assert result == [[1, 2, 3], [0, 0, 1]] + + +def test_from_three_points(): + pt1 = [0, 0, 0] + pt2 = [1, 0, 0] + pt3 = [0, 1, 0] + + result = Plane.from_three_points(pt1, pt2, pt3) + assert result == ([0, 0, 0], [0, 0, 1]) diff --git a/tests/compas/geometry/test_vector.py b/tests/compas/geometry/test_vector.py new file mode 100644 index 00000000000..e617a7500db --- /dev/null +++ b/tests/compas/geometry/test_vector.py @@ -0,0 +1,18 @@ +from compas.geometry import Vector + + +def test_cross_vectors(): + vec_list1 = [[1, 2, 3], [7, 8, 9]] + vec_list2 = [[2, 3, 4], [5, 6, 7]] + + result = Vector.cross_vectors(vec_list1, vec_list2) + assert result == [[-1, 2, -1], [2, -4, 2]] + + +def test_cross(): + vec1 = Vector(1, 2, 3) + vec2 = [5, 6, 7] + + result = vec1.cross(vec2) + assert result == (-4, 8, -4) + assert result == Vector(-4, 8, -4) From fabde09c4a7bbbb7d95b68f0b55947c05ed7b5ef Mon Sep 17 00:00:00 2001 From: baehrjo Date: Thu, 23 Mar 2023 12:25:33 +0100 Subject: [PATCH 018/150] bug fix on `is_polygon_in_polygon_xy` --- AUTHORS.md | 1 + CHANGELOG.md | 1 + src/compas/geometry/predicates/predicates_2.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index f4619ba3c96..9ac52a0af55 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -36,3 +36,4 @@ - Chen Kasirer <> [@chenkasirer](https://github.com/chenkasirer) - Nickolas Maslarinos <> [@nmaslarinos](https://github.com/nmaslarinos) - Katerina Toumpektsi <> [@katarametin](https://github.com/katarametin) +- Joelle Baehr-Bruyere <> [@baehrjo](https://github.com/baehrjo) diff --git a/CHANGELOG.md b/CHANGELOG.md index 687a8035231..71489dc48e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed bug that caused a new-line at the end of the `compas.HERE` constant in IronPython for Mac. * Fixed Grasshopper `draw_polylines` method to return `PolylineCurve` instead of `Polyline` because the latter shows as only points. +* Fixed bug in the `is_polygon_in_polygon_xy` that was not correctly generating all the edges of the second polygon before checking for intersections. ### Removed diff --git a/src/compas/geometry/predicates/predicates_2.py b/src/compas/geometry/predicates/predicates_2.py index 85e23410461..55f4c461e8b 100644 --- a/src/compas/geometry/predicates/predicates_2.py +++ b/src/compas/geometry/predicates/predicates_2.py @@ -383,7 +383,7 @@ def is_polygon_in_polygon_xy(polygon1, polygon2): for i in range(len(polygon1)): line = [polygon1[-i], polygon1[-i - 1]] for j in range(len(polygon2)): - line_ = [polygon2[-j], polygon2[j - 1]] + line_ = [polygon2[-j], polygon2[-j - 1]] if is_intersection_segment_segment_xy(line, line_): return False for pt in polygon2: From 8226ba7ba1296a0080fc2ead2ee92f2b1e82dbb5 Mon Sep 17 00:00:00 2001 From: baehrjo Date: Thu, 23 Mar 2023 16:27:31 +0100 Subject: [PATCH 019/150] add test to is_polygon_in_polygon_xy fix report --- .../geometry/predicates/test_predicates_2.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/compas/geometry/predicates/test_predicates_2.py b/tests/compas/geometry/predicates/test_predicates_2.py index 310a1a0f617..50cafdba3c9 100644 --- a/tests/compas/geometry/predicates/test_predicates_2.py +++ b/tests/compas/geometry/predicates/test_predicates_2.py @@ -1,8 +1,9 @@ from compas.geometry import Circle from compas.geometry import Plane from compas.geometry import Point +from compas.geometry import Polygon from compas.geometry import Vector -from compas.geometry import is_point_in_circle_xy +from compas.geometry import is_point_in_circle_xy, is_polygon_in_polygon_xy def test_is_point_in_circle_xy(): @@ -24,3 +25,16 @@ def test_is_point_in_circle_xy_class_input(): pt_outside = Point(15, 15, 0) assert is_point_in_circle_xy(pt_outside, circle) is False + + +def test_is_polygon_in_polygon_xy(): + polygon_contour = Polygon([(0, 0, 0), (4, 2, 0), (10, 0, 0), (11, 10, 0), (8, 12, 0), (0, 10, 0)]) + polygon_inside = Polygon([(5, 5, 0), (10, 5, 0), (10, 10 ,0), (5, 10, 0)]) + assert is_polygon_in_polygon_xy(polygon_contour, polygon_inside) is True + + polygon_outside = Polygon([(15, 5, 0), (20, 5, 0), (20, 10 ,0), (15, 10, 0)]) + assert is_polygon_in_polygon_xy(polygon_contour, polygon_outside) is False + + polygon_intersecting = Polygon([(10, 5, 0), (15, 5, 0), (15, 10 ,0), (10, 10, 0)]) + assert is_polygon_in_polygon_xy(polygon_contour, polygon_intersecting) is False + From b1d3ddff0734441a7fffec732df5f1da499271ca Mon Sep 17 00:00:00 2001 From: Li Date: Sat, 25 Mar 2023 11:38:59 +0100 Subject: [PATCH 020/150] Update release.yml Fix release name --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d11e657aa26..2cfac61a67b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,4 +30,5 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} build_ghpython_components: true gh_source: src/compas_ghpython/components - gh_target: src/compas_ghpython/components/ghuser \ No newline at end of file + gh_target: src/compas_ghpython/components/ghuser + release_name_prefix: COMPAS From 6b7c3e823d306d85c340d68145b3e87de51dcc1b Mon Sep 17 00:00:00 2001 From: baehrjo Date: Tue, 28 Mar 2023 18:13:31 +0200 Subject: [PATCH 021/150] comment test method --- tests/compas/geometry/predicates/test_predicates_2.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/compas/geometry/predicates/test_predicates_2.py b/tests/compas/geometry/predicates/test_predicates_2.py index 50cafdba3c9..0690de4b35b 100644 --- a/tests/compas/geometry/predicates/test_predicates_2.py +++ b/tests/compas/geometry/predicates/test_predicates_2.py @@ -35,6 +35,9 @@ def test_is_polygon_in_polygon_xy(): polygon_outside = Polygon([(15, 5, 0), (20, 5, 0), (20, 10 ,0), (15, 10, 0)]) assert is_polygon_in_polygon_xy(polygon_contour, polygon_outside) is False - polygon_intersecting = Polygon([(10, 5, 0), (15, 5, 0), (15, 10 ,0), (10, 10, 0)]) + polygon_intersecting = Polygon([(10, 10, 0), (10, 5, 0), (15, 5, 0), (15, 10 ,0)]) assert is_polygon_in_polygon_xy(polygon_contour, polygon_intersecting) is False - + + # shifting the vertices list of the same polygon shouldn't affect the containment check output anymore + polygon_intersecting_shifted = Polygon(polygon_intersecting[1:] + polygon_intersecting[:1]) + assert is_polygon_in_polygon_xy(polygon_contour, polygon_intersecting_shifted) is False \ No newline at end of file From 05499b17935a335ce504acaead756e9d3e870380 Mon Sep 17 00:00:00 2001 From: brgcode Date: Sat, 6 May 2023 12:00:21 +0200 Subject: [PATCH 022/150] up to numerical --- src/compas/datastructures/__init__.py | 213 ++++---- .../datastructures/assembly/__init__.py | 22 - .../datastructures/assembly/assembly.py | 4 +- src/compas/datastructures/graph/__init__.py | 1 - .../datastructures/halfedge/__init__.py | 1 - .../datastructures/halfface/__init__.py | 1 - src/compas/datastructures/mesh/__init__.py | 47 -- src/compas/datastructures/mesh/bbox.py | 7 - src/compas/datastructures/mesh/bbox_numpy.py | 7 - src/compas/datastructures/mesh/clean.py | 3 - .../datastructures/mesh/combinatorics.py | 3 - .../datastructures/mesh/contours_numpy.py | 6 - src/compas/datastructures/mesh/conway.py | 17 - src/compas/datastructures/mesh/curvature.py | 3 - .../datastructures/mesh/descent_numpy.py | 3 - src/compas/datastructures/mesh/duality.py | 2 - src/compas/datastructures/mesh/explode.py | 6 - .../datastructures/mesh/geodesics_numpy.py | 3 - src/compas/datastructures/mesh/geometry.py | 2 - src/compas/datastructures/mesh/join.py | 2 - src/compas/datastructures/mesh/matrices.py | 11 - src/compas/datastructures/mesh/mesh.py | 10 +- src/compas/datastructures/mesh/offset.py | 2 - .../mesh/operations/__init__.py | 14 - .../mesh/operations/collapse.py | 6 - .../datastructures/mesh/operations/insert.py | 3 - .../datastructures/mesh/operations/merge.py | 3 - .../datastructures/mesh/operations/split.py | 8 - .../mesh/operations/substitute.py | 2 - .../datastructures/mesh/operations/swap.py | 3 - .../datastructures/mesh/operations/weld.py | 3 - src/compas/datastructures/mesh/orientation.py | 7 - .../datastructures/mesh/planarisation.py | 6 - src/compas/datastructures/mesh/pull_numpy.py | 3 - src/compas/datastructures/mesh/remesh.py | 11 +- src/compas/datastructures/mesh/slice.py | 3 - src/compas/datastructures/mesh/smoothing.py | 7 - .../datastructures/mesh/smoothing_numpy.py | 3 - src/compas/datastructures/mesh/subdivision.py | 12 - .../datastructures/mesh/transformations.py | 6 - .../mesh/transformations_numpy.py | 6 - .../datastructures/mesh/triangulation.py | 7 +- .../mesh/trimesh_samplepoints_numpy.py | 5 - src/compas/datastructures/mesh/trimming.py | 3 - src/compas/datastructures/network/__init__.py | 24 - .../datastructures/network/combinatorics.py | 3 - .../datastructures/network/complementarity.py | 3 - src/compas/datastructures/network/duality.py | 5 - src/compas/datastructures/network/explode.py | 6 - src/compas/datastructures/network/matrices.py | 8 - src/compas/datastructures/network/network.py | 2 +- .../network/operations/__init__.py | 8 - .../datastructures/network/operations/join.py | 2 - .../network/operations/split.py | 5 - .../datastructures/network/planarity.py | 12 - .../datastructures/network/smoothing.py | 5 - .../datastructures/network/transformations.py | 6 - .../datastructures/network/traversal.py | 3 - src/compas/datastructures/volmesh/__init__.py | 13 - src/compas/files/__init__.py | 7 +- src/compas/files/gltf/__init__.py | 19 - src/compas/geometry/__init__.py | 506 +++++++++--------- src/compas/geometry/_core/__init__.py | 19 - src/compas/geometry/_core/_algebra.py | 49 -- src/compas/geometry/_core/analytical.py | 8 - src/compas/geometry/_core/angles.py | 30 +- src/compas/geometry/_core/centroids.py | 38 +- src/compas/geometry/_core/constructors.py | 22 +- src/compas/geometry/_core/distance.py | 55 +- src/compas/geometry/_core/kdtree.py | 5 +- src/compas/geometry/_core/normals.py | 23 +- src/compas/geometry/_core/quaternions.py | 11 +- src/compas/geometry/_core/size.py | 33 +- src/compas/geometry/_core/tangent.py | 3 - src/compas/geometry/bbox/__init__.py | 13 - src/compas/geometry/bbox/bbox.py | 6 - src/compas/geometry/bbox/bbox_numpy.py | 20 +- src/compas/geometry/bestfit/__init__.py | 13 - src/compas/geometry/bestfit/bestfit.py | 3 - src/compas/geometry/bestfit/bestfit_numpy.py | 10 +- src/compas/geometry/booleans/__init__.py | 6 - src/compas/geometry/brep/__init__.py | 27 - src/compas/geometry/curves/__init__.py | 4 - src/compas/geometry/hull/__init__.py | 13 - src/compas/geometry/hull/hull.py | 6 - src/compas/geometry/hull/hull_numpy.py | 6 - src/compas/geometry/icp/__init__.py | 11 - src/compas/geometry/icp/icp_numpy.py | 8 +- src/compas/geometry/interpolation/__init__.py | 10 - .../geometry/interpolation/barycentric.py | 3 - src/compas/geometry/interpolation/coons.py | 5 - src/compas/geometry/interpolation/tweening.py | 3 - src/compas/geometry/intersections/__init__.py | 4 - .../geometry/intersections/intersections.py | 24 - src/compas/geometry/offset/__init__.py | 9 - src/compas/geometry/offset/offset.py | 7 - src/compas/geometry/pointclouds/__init__.py | 7 - src/compas/geometry/pointclouds/pointcloud.py | 3 - src/compas/geometry/predicates/__init__.py | 8 - .../geometry/predicates/predicates_2.py | 23 +- .../geometry/predicates/predicates_3.py | 52 +- src/compas/geometry/primitives/__init__.py | 21 - src/compas/geometry/primitives/_primitive.py | 2 +- src/compas/geometry/primitives/arc.py | 5 +- src/compas/geometry/primitives/circle.py | 4 +- src/compas/geometry/primitives/curve.py | 6 +- src/compas/geometry/primitives/ellipse.py | 4 +- src/compas/geometry/primitives/frame.py | 9 +- src/compas/geometry/primitives/line.py | 4 +- src/compas/geometry/primitives/plane.py | 6 +- src/compas/geometry/primitives/point.py | 6 +- src/compas/geometry/primitives/polygon.py | 10 +- src/compas/geometry/primitives/polyline.py | 11 +- src/compas/geometry/primitives/quaternion.py | 2 +- src/compas/geometry/primitives/vector.py | 2 +- src/compas/geometry/quadmesh/__init__.py | 8 - src/compas/geometry/quadmesh/planarization.py | 3 - src/compas/geometry/shapes/__init__.py | 13 - src/compas/geometry/shapes/_shape.py | 2 +- src/compas/geometry/surfaces/__init__.py | 4 - .../geometry/transformations/__init__.py | 21 - .../geometry/transformations/matrices.py | 35 -- .../geometry/transformations/projection.py | 13 +- .../geometry/transformations/reflection.py | 4 +- .../geometry/transformations/rotation.py | 19 +- src/compas/geometry/transformations/scale.py | 12 +- src/compas/geometry/transformations/shear.py | 10 +- .../transformations/transformation.py | 18 +- .../transformations/transformations.py | 47 +- .../transformations/transformations_numpy.py | 12 - .../geometry/transformations/translation.py | 8 +- src/compas/geometry/triangulation/__init__.py | 9 - src/compas/geometry/triangulation/delaunay.py | 5 - .../geometry/triangulation/delaunay_numpy.py | 6 - src/compas/geometry/trimesh/__init__.py | 14 - src/compas/geometry/trimesh/curvature.py | 7 - src/compas/geometry/trimesh/geodistance.py | 3 - src/compas/geometry/trimesh/isolines.py | 3 - src/compas/geometry/trimesh/matrices.py | 3 - .../geometry/trimesh/parametrisation.py | 3 - src/compas/geometry/trimesh/remesh.py | 7 - src/compas/geometry/trimesh/slicing.py | 3 - src/compas/numerical/__init__.py | 22 +- src/compas/numerical/descent/__init__.py | 11 - src/compas/numerical/descent/descent_numpy.py | 4 - src/compas/numerical/devo/__init__.py | 11 - src/compas/numerical/devo/devo_numpy.py | 3 - src/compas/numerical/dr/__init__.py | 13 - src/compas/numerical/dr/dr_numpy.py | 3 - src/compas/numerical/fd/__init__.py | 11 - src/compas/numerical/fd/fd_numpy.py | 3 - src/compas/numerical/ga/__init__.py | 10 - src/compas/numerical/ga/ga.py | 4 - src/compas/numerical/ga/moga.py | 3 - src/compas/numerical/isolines/__init__.py | 11 - .../numerical/isolines/isolines_numpy.py | 5 - src/compas/numerical/lma/__init__.py | 11 - src/compas/numerical/mma/__init__.py | 11 - src/compas/numerical/mma/mma_numpy.py | 3 - src/compas/numerical/pca/__init__.py | 11 - src/compas/numerical/pca/pca_numpy.py | 3 - src/compas/numerical/topop/__init__.py | 11 - src/compas/numerical/topop/topop_numpy.py | 9 - tests/gen.py | 23 - 164 files changed, 574 insertions(+), 1740 deletions(-) delete mode 100644 tests/gen.py diff --git a/src/compas/datastructures/__init__.py b/src/compas/datastructures/__init__.py index 085a6f0b7ce..f6631e80f94 100644 --- a/src/compas/datastructures/__init__.py +++ b/src/compas/datastructures/__init__.py @@ -201,39 +201,63 @@ from .datastructure import Datastructure -from .graph import Graph -from .network import ( - Network, - network_complement, +# ============================================================================= +# Graphs +# ============================================================================= + +# ============================================================================= +# Networks +# ============================================================================= + +from .network.operations.join import network_join_edges, network_polylines +from .network.operations.split import network_split_edge + +from .network.combinatorics import network_is_connected +from .network.complementarity import network_complement +from .network.duality import network_find_cycles +from .network.explode import network_disconnected_edges, network_disconnected_nodes, network_explode +from .network.planarity import ( network_count_crossings, - network_disconnected_edges, - network_disconnected_nodes, - network_embed_in_plane_proxy, network_embed_in_plane, - network_explode, + network_embed_in_plane_proxy, network_find_crossings, - network_find_cycles, - network_is_connected, network_is_crossed, - network_is_planar_embedding, network_is_planar, + network_is_planar_embedding, network_is_xy, - network_join_edges, - network_polylines, - network_shortest_path, - network_smooth_centroid, - network_split_edge, - network_transform, - network_transformed, ) -from .halfedge import HalfEdge -from .mesh import ( - Mesh, - mesh_add_vertex_to_face_edge, - mesh_bounding_box_xy, - mesh_bounding_box, - mesh_collapse_edge, - mesh_connected_components, +from .network.smoothing import network_smooth_centroid +from .network.transformations import network_transform, network_transformed +from .network.traversal import network_shortest_path + +if not compas.IPY: + from .network.matrices import ( + network_adjacency_matrix, + network_connectivity_matrix, + network_degree_matrix, + network_laplacian_matrix, + ) + +# ============================================================================= +# Halfedges +# ============================================================================= + +# ============================================================================= +# Meshes +# ============================================================================= + +from .mesh.operations.collapse import mesh_collapse_edge, trimesh_collapse_edge +from .mesh.operations.insert import mesh_add_vertex_to_face_edge, mesh_insert_vertex_on_edge +from .mesh.operations.merge import mesh_merge_faces +from .mesh.operations.split import mesh_split_edge, mesh_split_face, mesh_split_strip, trimesh_split_edge +from .mesh.operations.substitute import mesh_substitute_vertex_in_faces +from .mesh.operations.swap import trimesh_swap_edge +from .mesh.operations.weld import mesh_unweld_edges, mesh_unweld_vertices + +from .mesh.bbox import mesh_bounding_box, mesh_bounding_box_xy # this needs to be moved to geometry +from .mesh.clean import mesh_delete_duplicate_vertices +from .mesh.combinatorics import mesh_connected_components, mesh_is_connected +from .mesh.conway import ( mesh_conway_ambo, mesh_conway_bevel, mesh_conway_dual, @@ -247,98 +271,89 @@ mesh_conway_snub, mesh_conway_truncate, mesh_conway_zip, - mesh_delete_duplicate_vertices, - mesh_disconnected_faces, - mesh_disconnected_vertices, - mesh_dual, - mesh_explode, - mesh_face_adjacency, - mesh_flatness, - mesh_flip_cycles, - mesh_insert_vertex_on_edge, - mesh_is_connected, - mesh_merge_faces, - mesh_offset, - mesh_planarize_faces, - mesh_quads_to_triangles, - mesh_slice_plane, - mesh_smooth_area, - mesh_smooth_centerofmass, - mesh_smooth_centroid, - mesh_split_edge, - mesh_split_face, - mesh_split_strip, +) +from .mesh.curvature import trimesh_gaussian_curvature, trimesh_mean_curvature # this needs to be moved to geometry +from .mesh.duality import mesh_dual +from .mesh.explode import mesh_disconnected_faces, mesh_disconnected_vertices, mesh_explode +from .mesh.geometry import trimesh_face_circle # this needs to be moved to geometry +from .mesh.join import mesh_weld, meshes_join, meshes_join_and_weld # used by offset +from .mesh.orientation import mesh_face_adjacency, mesh_flip_cycles, mesh_unify_cycles # used by offset +from .mesh.offset import mesh_offset, mesh_thicken +from .mesh.planarisation import mesh_flatness, mesh_planarize_faces # this needs to be moved to geometry +from .mesh.remesh import trimesh_remesh +from .mesh.slice import mesh_slice_plane +from .mesh.smoothing import mesh_smooth_area, mesh_smooth_centerofmass, mesh_smooth_centroid +from .mesh.subdivision import ( + mesh_subdivide, mesh_subdivide_catmullclark, mesh_subdivide_corner, mesh_subdivide_doosabin, mesh_subdivide_frames, mesh_subdivide_quad, mesh_subdivide_tri, - mesh_subdivide, - mesh_substitute_vertex_in_faces, - mesh_thicken, - mesh_transform, - mesh_transformed, - mesh_unify_cycles, - mesh_unweld_edges, - mesh_unweld_vertices, - mesh_weld, - meshes_join_and_weld, - meshes_join, - trimesh_collapse_edge, - trimesh_face_circle, - trimesh_gaussian_curvature, - trimesh_mean_curvature, - trimesh_remesh, - trimesh_split_edge, trimesh_subdivide_loop, - trimesh_swap_edge, -) -from .halfface import HalfFace -from .volmesh import ( - VolMesh, - volmesh_bounding_box, - volmesh_transform, - volmesh_transformed, -) - -from .assembly import ( - Assembly, - Part, - AssemblyError, - FeatureError, - Feature, - GeometricFeature, - ParametricFeature, ) +from .mesh.transformations import mesh_transform, mesh_transformed # this needs to be moved to geometry +from .mesh.triangulation import mesh_quads_to_triangles if not compas.IPY: - from .network import ( - network_adjacency_matrix, - network_connectivity_matrix, - network_degree_matrix, - network_laplacian_matrix, - ) - from .mesh import ( + + from .mesh.matrices import ( mesh_adjacency_matrix, mesh_connectivity_matrix, - mesh_contours_numpy, mesh_degree_matrix, mesh_face_matrix, - mesh_geodesic_distances_numpy, - mesh_isolines_numpy, mesh_laplacian_matrix, + trimesh_cotangent_laplacian_matrix, + trimesh_vertexarea_matrix, + ) + + from .mesh.bbox_numpy import ( mesh_oriented_bounding_box_numpy, mesh_oriented_bounding_box_xy_numpy, + ) # this needs to be moved to geometry + from .mesh.contours_numpy import mesh_isolines_numpy, mesh_contours_numpy # this needs to be moved to geometry + from .mesh.descent_numpy import trimesh_descent # this needs to be moved to geometry + from .mesh.geodesics_numpy import mesh_geodesic_distances_numpy + from .mesh.pull_numpy import trimesh_pull_points_numpy # this needs to be moved to geometry + from .mesh.smoothing_numpy import trimesh_smooth_laplacian_cotangent + from .mesh.transformations_numpy import ( mesh_transform_numpy, mesh_transformed_numpy, - trimesh_cotangent_laplacian_matrix, - trimesh_descent, - trimesh_pull_points_numpy, - trimesh_samplepoints_numpy, - trimesh_smooth_laplacian_cotangent, - trimesh_vertexarea_matrix, - ) + ) # this needs to be moved to geometry + from .mesh.trimesh_samplepoints_numpy import trimesh_samplepoints_numpy + +# ============================================================================= +# Halffaces +# ============================================================================= + +# ============================================================================= +# Volmeshes +# ============================================================================= + +from .volmesh.bbox import volmesh_bounding_box # this needs to be moved to geometry +from .volmesh.transformations import volmesh_transform, volmesh_transformed # this needs to be moved to geometry + +# ============================================================================= +# Volmeshes +# ============================================================================= + +# ============================================================================= +# Class APIs +# ============================================================================= + +from .graph.graph import Graph +from .network.network import Network + +from .halfedge.halfedge import HalfEdge +from .mesh.mesh import Mesh + +from .halfface.halfface import HalfFace +from .volmesh.volmesh import VolMesh + +from .assembly.exceptions import AssemblyError, FeatureError +from .assembly.assembly import Assembly +from .assembly.part import Feature, GeometricFeature, ParametricFeature, Part BaseNetwork = Network BaseMesh = Mesh diff --git a/src/compas/datastructures/assembly/__init__.py b/src/compas/datastructures/assembly/__init__.py index 3b79b6cdcf7..e69de29bb2d 100644 --- a/src/compas/datastructures/assembly/__init__.py +++ b/src/compas/datastructures/assembly/__init__.py @@ -1,22 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .exceptions import AssemblyError -from .exceptions import FeatureError -from .assembly import Assembly -from .part import Part -from .part import Feature -from .part import GeometricFeature -from .part import ParametricFeature - - -__all__ = [ - "AssemblyError", - "FeatureError", - "Assembly", - "Part", - "Feature", - "GeometricFeature", - "ParametricFeature", -] diff --git a/src/compas/datastructures/assembly/assembly.py b/src/compas/datastructures/assembly/assembly.py index 1d4b2a48db1..274909fd90f 100644 --- a/src/compas/datastructures/assembly/assembly.py +++ b/src/compas/datastructures/assembly/assembly.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from __future__ import division -from ..datastructure import Datastructure -from ..graph import Graph +from compas.datastructures import Datastructure +from compas.datastructures import Graph from .exceptions import AssemblyError diff --git a/src/compas/datastructures/graph/__init__.py b/src/compas/datastructures/graph/__init__.py index b040d910420..e69de29bb2d 100644 --- a/src/compas/datastructures/graph/__init__.py +++ b/src/compas/datastructures/graph/__init__.py @@ -1 +0,0 @@ -from .graph import Graph # noqa: F401 diff --git a/src/compas/datastructures/halfedge/__init__.py b/src/compas/datastructures/halfedge/__init__.py index be40e19a910..e69de29bb2d 100644 --- a/src/compas/datastructures/halfedge/__init__.py +++ b/src/compas/datastructures/halfedge/__init__.py @@ -1 +0,0 @@ -from .halfedge import HalfEdge # noqa: F401 diff --git a/src/compas/datastructures/halfface/__init__.py b/src/compas/datastructures/halfface/__init__.py index 8fea78fb4a7..e69de29bb2d 100644 --- a/src/compas/datastructures/halfface/__init__.py +++ b/src/compas/datastructures/halfface/__init__.py @@ -1 +0,0 @@ -from .halfface import HalfFace # noqa: F401 diff --git a/src/compas/datastructures/mesh/__init__.py b/src/compas/datastructures/mesh/__init__.py index 8f660e54fe3..e69de29bb2d 100644 --- a/src/compas/datastructures/mesh/__init__.py +++ b/src/compas/datastructures/mesh/__init__.py @@ -1,47 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from compas import IPY - -if not IPY: - from .matrices import * # noqa: F401 F403 - -from .operations import * # noqa: F401 F403 -from .clean import * # noqa: F401 F403 - -from .bbox import * # noqa: F401 F403 -from .combinatorics import * # noqa: F401 F403 -from .conway import * # noqa: F401 F403 -from .curvature import * # noqa: F401 F403 -from .duality import * # noqa: F401 F403 -from .explode import * # noqa: F401 F403 -from .geometry import * # noqa: F401 F403 -from .join import * # noqa: F401 F403 -from .offset import * # noqa: F401 F403 -from .orientation import * # noqa: F401 F403 -from .planarisation import * # noqa: F401 F403 -from .slice import * # noqa: F401 F403 - -# has to be imported before remeshing -from .smoothing import * # noqa: F401 F403 -from .remesh import * # noqa: F401 F403 -from .subdivision import * # noqa: F401 F403 -from .transformations import * # noqa: F401 F403 -from .triangulation import * # noqa: F401 F403 -from .trimming import * # noqa: F401 F403 - -if not IPY: - from .bbox_numpy import * # noqa: F401 F403 - from .contours_numpy import * # noqa: F401 F403 - from .descent_numpy import * # noqa: F401 F403 - from .geodesics_numpy import * # noqa: F401 F403 - from .pull_numpy import * # noqa: F401 F403 - from .smoothing_numpy import * # noqa: F401 F403 - from .transformations_numpy import * # noqa: F401 F403 - from .trimesh_samplepoints_numpy import * # noqa: F401 F403 - -from .mesh import Mesh # noqa: F401 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/datastructures/mesh/bbox.py b/src/compas/datastructures/mesh/bbox.py index 73ff7718fbd..523b0a678f4 100644 --- a/src/compas/datastructures/mesh/bbox.py +++ b/src/compas/datastructures/mesh/bbox.py @@ -2,17 +2,10 @@ from __future__ import division from __future__ import print_function - from compas.geometry import bounding_box from compas.geometry import bounding_box_xy -__all__ = [ - "mesh_bounding_box", - "mesh_bounding_box_xy", -] - - def mesh_bounding_box(mesh): """Compute the (axis aligned) bounding box of a mesh. diff --git a/src/compas/datastructures/mesh/bbox_numpy.py b/src/compas/datastructures/mesh/bbox_numpy.py index 8bc05144ef8..6d592bc2870 100644 --- a/src/compas/datastructures/mesh/bbox_numpy.py +++ b/src/compas/datastructures/mesh/bbox_numpy.py @@ -2,17 +2,10 @@ from __future__ import division from __future__ import print_function - from compas.geometry import oriented_bounding_box_numpy from compas.geometry import oriented_bounding_box_xy_numpy -__all__ = [ - "mesh_oriented_bounding_box_numpy", - "mesh_oriented_bounding_box_xy_numpy", -] - - def mesh_oriented_bounding_box_numpy(mesh): """Compute the (axis aligned) bounding box of a mesh. diff --git a/src/compas/datastructures/mesh/clean.py b/src/compas/datastructures/mesh/clean.py index 4e47478ae86..f09c43322e7 100644 --- a/src/compas/datastructures/mesh/clean.py +++ b/src/compas/datastructures/mesh/clean.py @@ -5,9 +5,6 @@ from compas.utilities import geometric_key -__all__ = ["mesh_delete_duplicate_vertices"] - - def mesh_delete_duplicate_vertices(mesh, precision=None): """Cull all duplicate vertices of a mesh and sanitize affected faces. diff --git a/src/compas/datastructures/mesh/combinatorics.py b/src/compas/datastructures/mesh/combinatorics.py index 04d1cea8a92..a8e117b6fdc 100644 --- a/src/compas/datastructures/mesh/combinatorics.py +++ b/src/compas/datastructures/mesh/combinatorics.py @@ -6,9 +6,6 @@ from compas.topology import connected_components -__all__ = ["mesh_is_connected", "mesh_connected_components"] - - def mesh_is_connected(mesh): """Verify that the mesh is connected. diff --git a/src/compas/datastructures/mesh/contours_numpy.py b/src/compas/datastructures/mesh/contours_numpy.py index c1feb571e9a..4b8648d1e9f 100644 --- a/src/compas/datastructures/mesh/contours_numpy.py +++ b/src/compas/datastructures/mesh/contours_numpy.py @@ -15,12 +15,6 @@ from compas.numerical import scalarfield_contours_numpy -__all__ = [ - "mesh_isolines_numpy", - "mesh_contours_numpy", -] - - def mesh_isolines_numpy(mesh, attr_name, N=50): """Compute the isolines of a specified attribute of the vertices of a mesh. diff --git a/src/compas/datastructures/mesh/conway.py b/src/compas/datastructures/mesh/conway.py index 9b72c3912ff..042e7616373 100644 --- a/src/compas/datastructures/mesh/conway.py +++ b/src/compas/datastructures/mesh/conway.py @@ -3,23 +3,6 @@ from __future__ import division -__all__ = [ - "mesh_conway_dual", - "mesh_conway_join", - "mesh_conway_ambo", - "mesh_conway_kis", - "mesh_conway_needle", - "mesh_conway_zip", - "mesh_conway_truncate", - "mesh_conway_ortho", - "mesh_conway_expand", - "mesh_conway_gyro", - "mesh_conway_snub", - "mesh_conway_meta", - "mesh_conway_bevel", -] - - def mesh_conway_dual(mesh): """Generates the dual mesh from a seed mesh. diff --git a/src/compas/datastructures/mesh/curvature.py b/src/compas/datastructures/mesh/curvature.py index fbac4cb695e..20c3160f11b 100644 --- a/src/compas/datastructures/mesh/curvature.py +++ b/src/compas/datastructures/mesh/curvature.py @@ -7,9 +7,6 @@ from compas.geometry import angle_points -__all__ = ["trimesh_mean_curvature", "trimesh_gaussian_curvature"] - - def trimesh_mean_curvature(mesh): pass diff --git a/src/compas/datastructures/mesh/descent_numpy.py b/src/compas/datastructures/mesh/descent_numpy.py index e96f39d8766..c73b6697dd1 100644 --- a/src/compas/datastructures/mesh/descent_numpy.py +++ b/src/compas/datastructures/mesh/descent_numpy.py @@ -6,9 +6,6 @@ from compas.numerical import grad -__all__ = ["trimesh_descent"] - - def trimesh_descent(trimesh): """Compute the gradient per face of the heightfield of the vertices of the mesh. diff --git a/src/compas/datastructures/mesh/duality.py b/src/compas/datastructures/mesh/duality.py index f57959ac928..f64565d309a 100644 --- a/src/compas/datastructures/mesh/duality.py +++ b/src/compas/datastructures/mesh/duality.py @@ -5,8 +5,6 @@ from math import pi from compas.utilities import flatten -__all__ = ["mesh_dual"] - PI2 = 2.0 * pi diff --git a/src/compas/datastructures/mesh/explode.py b/src/compas/datastructures/mesh/explode.py index 9d4f584daad..3a17d0ea90c 100644 --- a/src/compas/datastructures/mesh/explode.py +++ b/src/compas/datastructures/mesh/explode.py @@ -4,12 +4,6 @@ from compas.topology import connected_components -__all__ = [ - "mesh_disconnected_vertices", - "mesh_disconnected_faces", - "mesh_explode", -] - def mesh_disconnected_vertices(mesh): """Get the disconnected vertex groups in a mesh. diff --git a/src/compas/datastructures/mesh/geodesics_numpy.py b/src/compas/datastructures/mesh/geodesics_numpy.py index a88daf7c86b..141c462e069 100644 --- a/src/compas/datastructures/mesh/geodesics_numpy.py +++ b/src/compas/datastructures/mesh/geodesics_numpy.py @@ -20,9 +20,6 @@ from .matrices import trimesh_cotangent_laplacian_matrix -__all__ = ["mesh_geodesic_distances_numpy"] - - def mesh_geodesic_distances_numpy(mesh, sources, m=1.0): """Compute geodesic from the vertices of a mesh to given source vertices. diff --git a/src/compas/datastructures/mesh/geometry.py b/src/compas/datastructures/mesh/geometry.py index c14fa9b7246..28a915abac4 100644 --- a/src/compas/datastructures/mesh/geometry.py +++ b/src/compas/datastructures/mesh/geometry.py @@ -4,8 +4,6 @@ from compas.geometry import circle_from_points -__all__ = ["trimesh_face_circle"] - def trimesh_face_circle(mesh, fkey): """Get data on circumcentre of triangular face. diff --git a/src/compas/datastructures/mesh/join.py b/src/compas/datastructures/mesh/join.py index 107b1822adb..613d6d8ac24 100644 --- a/src/compas/datastructures/mesh/join.py +++ b/src/compas/datastructures/mesh/join.py @@ -5,8 +5,6 @@ from compas.utilities import pairwise from compas.utilities import geometric_key -__all__ = ["mesh_weld", "meshes_join", "meshes_join_and_weld"] - def mesh_weld(mesh, precision=None, cls=None): """Weld vertices of a mesh within some precision distance. diff --git a/src/compas/datastructures/mesh/matrices.py b/src/compas/datastructures/mesh/matrices.py index de5f2a3336c..4f4b67396dc 100644 --- a/src/compas/datastructures/mesh/matrices.py +++ b/src/compas/datastructures/mesh/matrices.py @@ -21,17 +21,6 @@ from compas.numerical import face_matrix -__all__ = [ - "mesh_adjacency_matrix", - "mesh_connectivity_matrix", - "mesh_degree_matrix", - "mesh_face_matrix", - "mesh_laplacian_matrix", - "trimesh_cotangent_laplacian_matrix", - "trimesh_vertexarea_matrix", -] - - def mesh_adjacency_matrix(mesh, rtype="array"): """Creates a vertex adjacency matrix from a Mesh datastructure. diff --git a/src/compas/datastructures/mesh/mesh.py b/src/compas/datastructures/mesh/mesh.py index b863b893c48..e7a15922df7 100644 --- a/src/compas/datastructures/mesh/mesh.py +++ b/src/compas/datastructures/mesh/mesh.py @@ -45,11 +45,11 @@ from compas.datastructures import HalfEdge -from .operations import mesh_collapse_edge -from .operations import mesh_split_edge -from .operations import mesh_split_face -from .operations import mesh_split_strip -from .operations import mesh_merge_faces +from .operations.collapse import mesh_collapse_edge +from .operations.split import mesh_split_edge +from .operations.split import mesh_split_face +from .operations.split import mesh_split_strip +from .operations.merge import mesh_merge_faces from .bbox import mesh_bounding_box from .bbox import mesh_bounding_box_xy diff --git a/src/compas/datastructures/mesh/offset.py b/src/compas/datastructures/mesh/offset.py index 3b1ba93562d..e06f5979efa 100644 --- a/src/compas/datastructures/mesh/offset.py +++ b/src/compas/datastructures/mesh/offset.py @@ -8,8 +8,6 @@ from .orientation import mesh_flip_cycles from .join import meshes_join -__all__ = ["mesh_offset", "mesh_thicken"] - def mesh_offset(mesh, distance=1.0): """Offset a mesh. diff --git a/src/compas/datastructures/mesh/operations/__init__.py b/src/compas/datastructures/mesh/operations/__init__.py index 85c06d7a76b..e69de29bb2d 100644 --- a/src/compas/datastructures/mesh/operations/__init__.py +++ b/src/compas/datastructures/mesh/operations/__init__.py @@ -1,14 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .collapse import * # noqa: F401 F403 -from .insert import * # noqa: F401 F403 -from .merge import * # noqa: F401 F403 -from .split import * # noqa: F401 F403 -from .substitute import * # noqa: F401 F403 -from .swap import * # noqa: F401 F403 -from .weld import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/datastructures/mesh/operations/collapse.py b/src/compas/datastructures/mesh/operations/collapse.py index bd3aa966129..c600295e1f5 100644 --- a/src/compas/datastructures/mesh/operations/collapse.py +++ b/src/compas/datastructures/mesh/operations/collapse.py @@ -3,12 +3,6 @@ from __future__ import division -__all__ = [ - "mesh_collapse_edge", - "trimesh_collapse_edge", -] - - def is_collapse_legal(mesh, u, v, allow_boundary=False): """Verify if the requested collapse is legal for a triangle mesh. diff --git a/src/compas/datastructures/mesh/operations/insert.py b/src/compas/datastructures/mesh/operations/insert.py index d1d03ee5805..a147d3c22fa 100644 --- a/src/compas/datastructures/mesh/operations/insert.py +++ b/src/compas/datastructures/mesh/operations/insert.py @@ -3,9 +3,6 @@ from __future__ import division -__all__ = ["mesh_add_vertex_to_face_edge", "mesh_insert_vertex_on_edge"] - - def mesh_add_vertex_to_face_edge(mesh, key, fkey, v): """Add an existing vertex of the mesh to an existing face. diff --git a/src/compas/datastructures/mesh/operations/merge.py b/src/compas/datastructures/mesh/operations/merge.py index bd811aa7b32..e670c38687b 100644 --- a/src/compas/datastructures/mesh/operations/merge.py +++ b/src/compas/datastructures/mesh/operations/merge.py @@ -3,9 +3,6 @@ from __future__ import division -__all__ = ["mesh_merge_faces"] - - def mesh_merge_faces(mesh, faces): """Merge two faces of a mesh over their shared edge. diff --git a/src/compas/datastructures/mesh/operations/split.py b/src/compas/datastructures/mesh/operations/split.py index 56a380271f3..48630861dc7 100644 --- a/src/compas/datastructures/mesh/operations/split.py +++ b/src/compas/datastructures/mesh/operations/split.py @@ -5,14 +5,6 @@ from compas.utilities import pairwise -__all__ = [ - "mesh_split_edge", - "mesh_split_face", - "mesh_split_strip", - "trimesh_split_edge", -] - - def mesh_split_edge(mesh, u, v, t=0.5, allow_boundary=False): """Split and edge by inserting a vertex along its length. diff --git a/src/compas/datastructures/mesh/operations/substitute.py b/src/compas/datastructures/mesh/operations/substitute.py index 850e3c9ec89..5c351f9fc3b 100644 --- a/src/compas/datastructures/mesh/operations/substitute.py +++ b/src/compas/datastructures/mesh/operations/substitute.py @@ -2,8 +2,6 @@ from __future__ import absolute_import from __future__ import division -__all__ = ["mesh_substitute_vertex_in_faces"] - def mesh_substitute_vertex_in_faces(mesh, old_vkey, new_vkey, fkeys=None): """Substitute in a mesh a vertex by another one. diff --git a/src/compas/datastructures/mesh/operations/swap.py b/src/compas/datastructures/mesh/operations/swap.py index a786806e018..ec72b8a790a 100644 --- a/src/compas/datastructures/mesh/operations/swap.py +++ b/src/compas/datastructures/mesh/operations/swap.py @@ -3,9 +3,6 @@ from __future__ import division -__all__ = ["trimesh_swap_edge"] - - def trimesh_swap_edge(mesh, u, v, allow_boundary=True): """Replace an edge of the mesh by an edge connecting the opposite vertices of the adjacent faces. diff --git a/src/compas/datastructures/mesh/operations/weld.py b/src/compas/datastructures/mesh/operations/weld.py index 28d915164f6..1672f508a03 100644 --- a/src/compas/datastructures/mesh/operations/weld.py +++ b/src/compas/datastructures/mesh/operations/weld.py @@ -10,9 +10,6 @@ from .substitute import mesh_substitute_vertex_in_faces -__all__ = ["mesh_unweld_vertices", "mesh_unweld_edges"] - - def mesh_unweld_vertices(mesh, fkey, where=None): """Unweld a face of the mesh. diff --git a/src/compas/datastructures/mesh/orientation.py b/src/compas/datastructures/mesh/orientation.py index 87d514cd75a..d83dba4228f 100644 --- a/src/compas/datastructures/mesh/orientation.py +++ b/src/compas/datastructures/mesh/orientation.py @@ -5,13 +5,6 @@ from compas.topology import breadth_first_traverse -__all__ = [ - "mesh_face_adjacency", - "mesh_unify_cycles", - "mesh_flip_cycles", -] - - def _mesh_face_adjacency(mesh, nmax=10, radius=10.0): fkey_index = {fkey: index for index, fkey in enumerate(mesh.faces())} index_fkey = {index: fkey for index, fkey in enumerate(mesh.faces())} diff --git a/src/compas/datastructures/mesh/planarisation.py b/src/compas/datastructures/mesh/planarisation.py index 53810dd95e7..9cda441f14e 100644 --- a/src/compas/datastructures/mesh/planarisation.py +++ b/src/compas/datastructures/mesh/planarisation.py @@ -13,12 +13,6 @@ from compas.utilities import pairwise -__all__ = [ - "mesh_flatness", - "mesh_planarize_faces", -] - - def mesh_flatness(mesh, maxdev=1.0): """Compute mesh flatness per face. diff --git a/src/compas/datastructures/mesh/pull_numpy.py b/src/compas/datastructures/mesh/pull_numpy.py index 894ed7b0603..a5c8d881a80 100644 --- a/src/compas/datastructures/mesh/pull_numpy.py +++ b/src/compas/datastructures/mesh/pull_numpy.py @@ -18,9 +18,6 @@ from compas.geometry import is_point_in_triangle -__all__ = ["trimesh_pull_points_numpy"] - - def trimesh_pull_points_numpy(mesh, points): """Pull points onto a mesh by computing the closest point on the mesh for each of the points. diff --git a/src/compas/datastructures/mesh/remesh.py b/src/compas/datastructures/mesh/remesh.py index 583d26cd584..1689b237829 100644 --- a/src/compas/datastructures/mesh/remesh.py +++ b/src/compas/datastructures/mesh/remesh.py @@ -3,14 +3,9 @@ from __future__ import division from .smoothing import mesh_smooth_area -from .operations import trimesh_collapse_edge -from .operations import trimesh_swap_edge -from .operations import trimesh_split_edge - - -__all__ = [ - "trimesh_remesh", -] +from .operations.collapse import trimesh_collapse_edge +from .operations.swap import trimesh_swap_edge +from .operations.split import trimesh_split_edge def trimesh_remesh( diff --git a/src/compas/datastructures/mesh/slice.py b/src/compas/datastructures/mesh/slice.py index d7b6d510063..6c713456385 100644 --- a/src/compas/datastructures/mesh/slice.py +++ b/src/compas/datastructures/mesh/slice.py @@ -4,9 +4,6 @@ from compas.geometry import dot_vectors -__all__ = ["mesh_slice_plane"] - - def mesh_slice_plane(mesh, plane): """Slice a mesh with a plane and construct the resulting submeshes. diff --git a/src/compas/datastructures/mesh/smoothing.py b/src/compas/datastructures/mesh/smoothing.py index fbcd4163086..c8098937cd6 100644 --- a/src/compas/datastructures/mesh/smoothing.py +++ b/src/compas/datastructures/mesh/smoothing.py @@ -6,13 +6,6 @@ from compas.geometry import centroid_polygon -__all__ = [ - "mesh_smooth_centroid", - "mesh_smooth_centerofmass", - "mesh_smooth_area", -] - - def mesh_smooth_centroid(mesh, fixed=None, kmax=100, damping=0.5, callback=None, callback_args=None): """Smooth a mesh by moving every free vertex to the centroid of its neighbors. diff --git a/src/compas/datastructures/mesh/smoothing_numpy.py b/src/compas/datastructures/mesh/smoothing_numpy.py index bd842bd203f..d03d2512e47 100644 --- a/src/compas/datastructures/mesh/smoothing_numpy.py +++ b/src/compas/datastructures/mesh/smoothing_numpy.py @@ -3,9 +3,6 @@ from .matrices import trimesh_cotangent_laplacian_matrix -__all__ = ["trimesh_smooth_laplacian_cotangent"] - - def trimesh_smooth_laplacian_cotangent(trimesh, fixed, kmax=10): """Smooth a triangle mesh using a laplacian matrix with cotangent weights. diff --git a/src/compas/datastructures/mesh/subdivision.py b/src/compas/datastructures/mesh/subdivision.py index 376b43eef13..b0993ec1ae9 100644 --- a/src/compas/datastructures/mesh/subdivision.py +++ b/src/compas/datastructures/mesh/subdivision.py @@ -13,18 +13,6 @@ from compas.utilities import pairwise -__all__ = [ - "mesh_subdivide", - "mesh_subdivide_tri", - "mesh_subdivide_corner", - "mesh_subdivide_quad", - "mesh_subdivide_catmullclark", - "mesh_subdivide_doosabin", - "mesh_subdivide_frames", - "trimesh_subdivide_loop", -] - - def subd_factory(cls): class SubdMesh(cls): diff --git a/src/compas/datastructures/mesh/transformations.py b/src/compas/datastructures/mesh/transformations.py index e9a5d14f250..232663a8c98 100644 --- a/src/compas/datastructures/mesh/transformations.py +++ b/src/compas/datastructures/mesh/transformations.py @@ -5,12 +5,6 @@ from compas.geometry import transform_points -__all__ = [ - "mesh_transform", - "mesh_transformed", -] - - def mesh_transform(mesh, transformation): """Transform a mesh. diff --git a/src/compas/datastructures/mesh/transformations_numpy.py b/src/compas/datastructures/mesh/transformations_numpy.py index 94a2cb49388..6b2cf9bf9fd 100644 --- a/src/compas/datastructures/mesh/transformations_numpy.py +++ b/src/compas/datastructures/mesh/transformations_numpy.py @@ -5,12 +5,6 @@ from compas.geometry import transform_points_numpy -__all__ = [ - "mesh_transform_numpy", - "mesh_transformed_numpy", -] - - def mesh_transform_numpy(mesh, transformation): """Transform a mesh. diff --git a/src/compas/datastructures/mesh/triangulation.py b/src/compas/datastructures/mesh/triangulation.py index 631a6e15597..19298855060 100644 --- a/src/compas/datastructures/mesh/triangulation.py +++ b/src/compas/datastructures/mesh/triangulation.py @@ -3,12 +3,7 @@ from __future__ import division -from .operations import mesh_split_face - - -__all__ = [ - "mesh_quads_to_triangles", -] +from .operations.split import mesh_split_face def mesh_quads_to_triangles(mesh, check_angles=False): diff --git a/src/compas/datastructures/mesh/trimesh_samplepoints_numpy.py b/src/compas/datastructures/mesh/trimesh_samplepoints_numpy.py index 0edbaae9cba..62d35388e0c 100644 --- a/src/compas/datastructures/mesh/trimesh_samplepoints_numpy.py +++ b/src/compas/datastructures/mesh/trimesh_samplepoints_numpy.py @@ -9,11 +9,6 @@ from numpy import finfo -__all__ = [ - "trimesh_samplepoints_numpy", -] - - def trimesh_samplepoints_numpy(mesh, num_points=1000, return_normals=False): """Compute sample points on a triangle mesh surface. diff --git a/src/compas/datastructures/mesh/trimming.py b/src/compas/datastructures/mesh/trimming.py index d1f61ba81eb..39e279b5bc4 100644 --- a/src/compas/datastructures/mesh/trimming.py +++ b/src/compas/datastructures/mesh/trimming.py @@ -3,8 +3,5 @@ from __future__ import division -__all__ = [] - - def mesh_trim(mesh): pass diff --git a/src/compas/datastructures/network/__init__.py b/src/compas/datastructures/network/__init__.py index 4ad486ba3c5..e69de29bb2d 100644 --- a/src/compas/datastructures/network/__init__.py +++ b/src/compas/datastructures/network/__init__.py @@ -1,24 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -from .operations import * # noqa: F401 F403 - -if not compas.IPY: - from .matrices import * # noqa: F401 F403 - -from .network import * # noqa: F401 F403 - -from .combinatorics import * # noqa: F401 F403 -from .complementarity import * # noqa: F401 F403 -from .duality import * # noqa: F401 F403 -from .explode import * # noqa: F401 F403 -from .planarity import * # noqa: F401 F403 -from .smoothing import * # noqa: F401 F403 -from .transformations import * # noqa: F401 F403 -from .traversal import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/datastructures/network/combinatorics.py b/src/compas/datastructures/network/combinatorics.py index 8cca0778a9e..0a5f75809d5 100644 --- a/src/compas/datastructures/network/combinatorics.py +++ b/src/compas/datastructures/network/combinatorics.py @@ -5,9 +5,6 @@ from compas.topology import breadth_first_traverse -__all__ = ["network_is_connected"] - - def network_is_connected(network): """Verify that the network is connected. diff --git a/src/compas/datastructures/network/complementarity.py b/src/compas/datastructures/network/complementarity.py index a770a300e08..f2fae7dbade 100644 --- a/src/compas/datastructures/network/complementarity.py +++ b/src/compas/datastructures/network/complementarity.py @@ -5,9 +5,6 @@ from itertools import combinations -__all__ = ["network_complement"] - - def network_complement(network, cls=None): """Generate the complement network of a network. diff --git a/src/compas/datastructures/network/duality.py b/src/compas/datastructures/network/duality.py index bcd7610b435..5e1d55497d8 100644 --- a/src/compas/datastructures/network/duality.py +++ b/src/compas/datastructures/network/duality.py @@ -9,11 +9,6 @@ from compas.geometry import is_ccw_xy -__all__ = [ - "network_find_cycles", -] - - PI2 = 2.0 * pi diff --git a/src/compas/datastructures/network/explode.py b/src/compas/datastructures/network/explode.py index aeb88e93318..1750a479168 100644 --- a/src/compas/datastructures/network/explode.py +++ b/src/compas/datastructures/network/explode.py @@ -4,12 +4,6 @@ from compas.topology import connected_components -__all__ = [ - "network_disconnected_nodes", - "network_disconnected_edges", - "network_explode", -] - def network_disconnected_nodes(network): """Get the disconnected node groups in a network. diff --git a/src/compas/datastructures/network/matrices.py b/src/compas/datastructures/network/matrices.py index ef113f53f43..343e8873de3 100644 --- a/src/compas/datastructures/network/matrices.py +++ b/src/compas/datastructures/network/matrices.py @@ -8,14 +8,6 @@ from compas.numerical import laplacian_matrix -__all__ = [ - "network_adjacency_matrix", - "network_degree_matrix", - "network_connectivity_matrix", - "network_laplacian_matrix", -] - - def _return_matrix(M, rtype): if rtype == "list": return M.toarray().tolist() diff --git a/src/compas/datastructures/network/network.py b/src/compas/datastructures/network/network.py index ee359c654ff..a47de7e6b36 100644 --- a/src/compas/datastructures/network/network.py +++ b/src/compas/datastructures/network/network.py @@ -22,7 +22,7 @@ from compas.datastructures import Graph -from .operations import network_split_edge +from .operations.split import network_split_edge from .combinatorics import network_is_connected from .complementarity import network_complement diff --git a/src/compas/datastructures/network/operations/__init__.py b/src/compas/datastructures/network/operations/__init__.py index 7a9198e29be..e69de29bb2d 100644 --- a/src/compas/datastructures/network/operations/__init__.py +++ b/src/compas/datastructures/network/operations/__init__.py @@ -1,8 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .split import * # noqa: F401 F403 -from .join import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/datastructures/network/operations/join.py b/src/compas/datastructures/network/operations/join.py index 7d2f3f818fd..4ecbaf03514 100644 --- a/src/compas/datastructures/network/operations/join.py +++ b/src/compas/datastructures/network/operations/join.py @@ -5,8 +5,6 @@ from compas.utilities import pairwise from compas.utilities import geometric_key -__all__ = ["network_join_edges", "network_polylines"] - def network_join_edges(network, key): """Join the edges incidental on the given node, if there are exactly two incident edges. diff --git a/src/compas/datastructures/network/operations/split.py b/src/compas/datastructures/network/operations/split.py index 04fb9a20944..bf282462862 100644 --- a/src/compas/datastructures/network/operations/split.py +++ b/src/compas/datastructures/network/operations/split.py @@ -3,11 +3,6 @@ from __future__ import division -__all__ = [ - "network_split_edge", -] - - def network_split_edge(network, u, v, t=0.5): """Split and edge by inserting a node along its length. diff --git a/src/compas/datastructures/network/planarity.py b/src/compas/datastructures/network/planarity.py index 95243a1f6ed..506a31ce3f2 100644 --- a/src/compas/datastructures/network/planarity.py +++ b/src/compas/datastructures/network/planarity.py @@ -14,18 +14,6 @@ from compas.geometry import subtract_vectors_xy -__all__ = [ - "network_is_crossed", - "network_count_crossings", - "network_find_crossings", - "network_is_xy", - "network_is_planar", - "network_is_planar_embedding", - "network_embed_in_plane", - "network_embed_in_plane_proxy", -] - - def network_embed_in_plane_proxy(data, fixed=None, straightline=True): from compas.datastructures import Network diff --git a/src/compas/datastructures/network/smoothing.py b/src/compas/datastructures/network/smoothing.py index ccb708ff3b0..271fd53d282 100644 --- a/src/compas/datastructures/network/smoothing.py +++ b/src/compas/datastructures/network/smoothing.py @@ -5,11 +5,6 @@ from compas.geometry import centroid_points -__all__ = [ - "network_smooth_centroid", -] - - def network_smooth_centroid(network, fixed=None, kmax=100, damping=0.5, callback=None, callback_args=None): """Smooth a network by moving every free node to the centroid of its neighbors. diff --git a/src/compas/datastructures/network/transformations.py b/src/compas/datastructures/network/transformations.py index bc403eec24d..8dd228a0256 100644 --- a/src/compas/datastructures/network/transformations.py +++ b/src/compas/datastructures/network/transformations.py @@ -6,12 +6,6 @@ from compas.geometry import transform_points -__all__ = [ - "network_transform", - "network_transformed", -] - - def network_transform(network, transformation): """Transform a network. diff --git a/src/compas/datastructures/network/traversal.py b/src/compas/datastructures/network/traversal.py index fe7cda4edc3..eeba6b1565b 100644 --- a/src/compas/datastructures/network/traversal.py +++ b/src/compas/datastructures/network/traversal.py @@ -5,9 +5,6 @@ from compas.topology import shortest_path -__all__ = ["network_shortest_path"] - - def network_shortest_path(network, start, end): """Find the shortest path between two nodes of the network. diff --git a/src/compas/datastructures/volmesh/__init__.py b/src/compas/datastructures/volmesh/__init__.py index 6dac31a42eb..e69de29bb2d 100644 --- a/src/compas/datastructures/volmesh/__init__.py +++ b/src/compas/datastructures/volmesh/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .operations import * # noqa: F401 F403 - -from .bbox import * # noqa: F401 F403 -from .transformations import * # noqa: F401 F403 - -from .volmesh import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/files/__init__.py b/src/compas/files/__init__.py index 6e7d1b19ae9..9ac69482b61 100644 --- a/src/compas/files/__init__.py +++ b/src/compas/files/__init__.py @@ -132,7 +132,12 @@ from __future__ import absolute_import from .dxf import DXF, DXFParser, DXFReader -from .gltf import GLTF, GLTFContent, GLTFExporter, GLTFMesh, GLTFParser, GLTFReader +from .gltf.gltf import GLTF +from .gltf.gltf_content import GLTFContent +from .gltf.gltf_exporter import GLTFExporter +from .gltf.gltf_mesh import GLTFMesh +from .gltf.gltf_parser import GLTFParser +from .gltf.gltf_reader import GLTFReader from .las import LAS, LASParser, LASReader from .obj import OBJ, OBJParser, OBJReader, OBJWriter from .off import OFF, OFFReader, OFFWriter diff --git a/src/compas/files/gltf/__init__.py b/src/compas/files/gltf/__init__.py index 7e7503c1bf4..e69de29bb2d 100644 --- a/src/compas/files/gltf/__init__.py +++ b/src/compas/files/gltf/__init__.py @@ -1,19 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .gltf import GLTF -from .gltf_content import GLTFContent -from .gltf_exporter import GLTFExporter -from .gltf_mesh import GLTFMesh -from .gltf_parser import GLTFParser -from .gltf_reader import GLTFReader - -__all__ = [ - "GLTF", - "GLTFContent", - "GLTFMesh", - "GLTFReader", - "GLTFParser", - "GLTFExporter", -] diff --git a/src/compas/geometry/__init__.py b/src/compas/geometry/__init__.py index 07c281e4232..42cdf27e75d 100644 --- a/src/compas/geometry/__init__.py +++ b/src/compas/geometry/__init__.py @@ -540,39 +540,27 @@ from __future__ import absolute_import import compas -from ._core import ( - close, - allclose, - argmin, - argmax, - add_vectors, - add_vectors_xy, - sum_vectors, - cross_vectors, - cross_vectors_xy, - divide_vectors, - divide_vectors_xy, - dot_vectors, - dot_vectors_xy, - length_vector, - length_vector_xy, - length_vector_sqrd, - length_vector_sqrd_xy, - multiply_matrices, - multiply_matrix_vector, - multiply_vectors, - multiply_vectors_xy, +# ============================================================================= +# Core +# ============================================================================= + +from ._core._algebra import add_vectors, add_vectors_xy, allclose, argmax, argmin +from ._core._algebra import close, cross_vectors, cross_vectors_xy +from ._core._algebra import dehomogenize_vectors, divide_vectors, divide_vectors_xy, dot_vectors, dot_vectors_xy +from ._core._algebra import homogenize_vectors +from ._core._algebra import length_vector, length_vector_sqrd, length_vector_sqrd_xy, length_vector_xy +from ._core._algebra import multiply_matrices, multiply_matrix_vector, multiply_vectors, multiply_vectors_xy +from ._core._algebra import ( norm_vector, norm_vectors, normalize_vector, normalize_vector_xy, normalize_vectors, normalize_vectors_xy, - homogenize_vectors, - dehomogenize_vectors, - orthonormalize_vectors, - power_vector, - power_vectors, +) +from ._core._algebra import orthonormalize_vectors +from ._core._algebra import power_vector, power_vectors +from ._core._algebra import ( scale_vector, scale_vector_xy, scale_vectors, @@ -581,82 +569,180 @@ square_vectors, subtract_vectors, subtract_vectors_xy, - transpose_matrix, + sum_vectors, +) +from ._core._algebra import transpose_matrix +from ._core._algebra import ( + vector_average, vector_component, vector_component_xy, - vector_average, - vector_variance, vector_standard_deviation, + vector_variance, +) + +from ._core.analytical import ( + archimedean_spiral_evaluate, circle_evaluate, ellipse_evaluate, - archimedean_spiral_evaluate, - logarithmic_spiral_evaluate, helix_evaluate, - angles_vectors, - angles_vectors_xy, - angles_points, - angles_points_xy, + logarithmic_spiral_evaluate, +) +from ._core.angles import ( + angle_planes, + angle_points, + angle_points_xy, angle_vectors, angle_vectors_signed, angle_vectors_xy, - angle_points, - angle_points_xy, - angle_planes, - midpoint_point_point, - midpoint_point_point_xy, - midpoint_line, - midpoint_line_xy, + angles_points, + angles_points_xy, + angles_vectors, + angles_vectors_xy, +) +from ._core.centroids import ( centroid_points, centroid_points_weighted, centroid_points_xy, centroid_polygon, - centroid_polygon_xy, - centroid_polygon_vertices, - centroid_polygon_vertices_xy, centroid_polygon_edges, centroid_polygon_edges_xy, + centroid_polygon_vertices, + centroid_polygon_vertices_xy, + centroid_polygon_xy, centroid_polyhedron, - circle_from_points, - circle_from_points_xy, - distance_point_point, - distance_point_point_xy, - distance_point_point_sqrd, - distance_point_point_sqrd_xy, - distance_point_line, - distance_point_line_xy, - distance_point_line_sqrd, - distance_point_line_sqrd_xy, - distance_point_plane, - distance_point_plane_signed, - distance_line_line, + midpoint_line, + midpoint_line_xy, + midpoint_point_point, + midpoint_point_point_xy, +) +from ._core.constructors import circle_from_points, circle_from_points_xy +from ._core.distance import ( + closest_line_to_point, closest_point_in_cloud, closest_point_in_cloud_xy, closest_point_on_line, closest_point_on_line_xy, - closest_point_on_segment, - closest_point_on_segment_xy, + closest_point_on_plane, + # closest_point_on_polygon_xy, closest_point_on_polyline, closest_point_on_polyline_xy, - closest_point_on_plane, - closest_line_to_point, - KDTree, - normal_polygon, - normal_triangle, - normal_triangle_xy, - quaternion_norm, - quaternion_unitize, - quaternion_is_unit, - quaternion_multiply, + closest_point_on_segment, + closest_point_on_segment_xy, + # closest_points_in_cloud_numpy, + distance_line_line, + distance_point_line, + distance_point_line_sqrd, + distance_point_line_sqrd_xy, + distance_point_line_xy, + distance_point_plane, + distance_point_plane_signed, + distance_point_point, + distance_point_point_sqrd, + distance_point_point_sqrd_xy, + distance_point_point_xy, +) +from ._core.normals import normal_polygon, normal_triangle, normal_triangle_xy +from ._core.quaternions import ( quaternion_canonize, quaternion_conjugate, - area_polygon, - area_polygon_xy, - area_triangle, - area_triangle_xy, - volume_polyhedron, - tangent_points_to_circle_xy, + quaternion_is_unit, + quaternion_multiply, + quaternion_norm, + quaternion_unitize, ) -from .predicates import ( +from ._core.size import area_polygon, area_polygon_xy, area_triangle, area_triangle_xy, volume_polyhedron +from ._core.tangent import tangent_points_to_circle_xy + +from ._core.kdtree import KDTree + +# ============================================================================= +# Transformations +# ============================================================================= + +from .transformations.matrices import ( + axis_and_angle_from_matrix, + axis_angle_from_quaternion, + axis_angle_vector_from_matrix, + basis_vectors_from_matrix, + compose_matrix, + decompose_matrix, + euler_angles_from_matrix, + euler_angles_from_quaternion, + identity_matrix, + matrix_determinant, + matrix_from_axis_and_angle, + matrix_from_axis_angle_vector, + matrix_from_basis_vectors, + matrix_from_change_of_basis, + matrix_from_euler_angles, + matrix_from_frame, + matrix_from_frame_to_frame, + matrix_from_orthogonal_projection, + matrix_from_parallel_projection, + matrix_from_perspective_entries, + matrix_from_perspective_projection, + matrix_from_quaternion, + matrix_from_scale_factors, + matrix_from_shear, + matrix_from_shear_entries, + matrix_from_translation, + matrix_inverse, + quaternion_from_axis_angle, + quaternion_from_euler_angles, + quaternion_from_matrix, + translation_from_matrix, +) + +from .transformations.transformations import local_axes, local_to_world_coordinates +from .transformations.transformations import ( + # mirror_point_line, + # mirror_point_line_xy, + mirror_point_plane, + # mirror_point_point, + # mirror_point_point_xy, + mirror_points_line, + mirror_points_line_xy, + mirror_points_point, + mirror_points_plane, + mirror_points_point_xy, + mirror_vector_vector, +) +from .transformations.transformations import orient_points, orthonormalize_axes +from .transformations.transformations import ( + project_point_line, + project_point_line_xy, + project_point_plane, + project_points_line, + project_points_line_xy, + project_points_plane, +) +from .transformations.transformations import reflect_line_plane, reflect_line_triangle, rotate_points, rotate_points_xy +from .transformations.transformations import scale_points, scale_points_xy +from .transformations.transformations import ( + transform_frames, + transform_points, + transform_vectors, + translate_points_xy, + translate_points, +) +from .transformations.transformations import world_to_local_coordinates + +if not compas.IPY: + from .transformations.transformations_numpy import dehomogenize_and_unflatten_frames_numpy, dehomogenize_numpy + from .transformations.transformations_numpy import homogenize_and_flatten_frames_numpy, homogenize_numpy + from .transformations.transformations_numpy import local_to_world_coordinates_numpy + from .transformations.transformations_numpy import ( + # transform_frames_numpy, + transform_points_numpy, + transform_vectors_numpy, + ) + from .transformations.transformations_numpy import world_to_local_coordinates_numpy + +# ============================================================================= +# Predicates +# ============================================================================= + +from .predicates.predicates_2 import ( is_ccw_xy, is_colinear_xy, is_polygon_convex_xy, @@ -670,6 +756,8 @@ is_polygon_in_polygon_xy, is_intersection_line_line_xy, is_intersection_segment_segment_xy, +) +from .predicates.predicates_3 import ( is_colinear, is_colinear_line_line, is_coplanar, @@ -691,7 +779,24 @@ is_intersection_segment_plane, is_intersection_plane_plane, ) -from .intersections import ( + +# ============================================================================= +# Other +# ============================================================================= + +from .bbox.bbox import bounding_box, bounding_box_xy +from .bestfit.bestfit import bestfit_plane +from .booleans import ( + boolean_union_mesh_mesh, + boolean_difference_mesh_mesh, + boolean_intersection_mesh_mesh, +) +from .hull.hull import convex_hull, convex_hull_xy +from .interpolation.barycentric import barycentric_coordinates +from .interpolation.coons import discrete_coons_patch +from .interpolation.tweening import tween_points, tween_points_distance +from .intersections import intersection_mesh_mesh, intersection_ray_mesh +from .intersections.intersections import ( intersection_circle_circle_xy, intersection_ellipse_line_xy, intersection_line_box_xy, @@ -701,12 +806,10 @@ intersection_line_segment_xy, intersection_line_segment, intersection_line_triangle, - intersection_mesh_mesh, intersection_plane_circle, intersection_plane_plane_plane, intersection_plane_plane, intersection_polyline_plane, - intersection_ray_mesh, intersection_segment_plane, intersection_segment_polyline_xy, intersection_segment_polyline, @@ -715,196 +818,97 @@ intersection_sphere_line, intersection_sphere_sphere, ) -from .transformations import ( - matrix_determinant, - matrix_inverse, - decompose_matrix, - compose_matrix, - identity_matrix, - matrix_from_frame, - matrix_from_frame_to_frame, - matrix_from_change_of_basis, - matrix_from_euler_angles, - matrix_from_axis_and_angle, - matrix_from_axis_angle_vector, - matrix_from_basis_vectors, - matrix_from_translation, - matrix_from_orthogonal_projection, - matrix_from_parallel_projection, - matrix_from_perspective_projection, - matrix_from_perspective_entries, - matrix_from_shear_entries, - matrix_from_shear, - matrix_from_scale_factors, - matrix_from_quaternion, - euler_angles_from_matrix, - euler_angles_from_quaternion, - axis_and_angle_from_matrix, - axis_angle_vector_from_matrix, - axis_angle_from_quaternion, - quaternion_from_matrix, - quaternion_from_euler_angles, - quaternion_from_axis_angle, - basis_vectors_from_matrix, - translation_from_matrix, - local_axes, - orthonormalize_axes, - transform_points, - transform_vectors, - transform_frames, - local_to_world_coordinates, - world_to_local_coordinates, - translate_points, - translate_points_xy, - scale_points, - scale_points_xy, - rotate_points, - rotate_points_xy, - mirror_vector_vector, - mirror_points_point, - mirror_points_point_xy, - mirror_points_line, - mirror_points_line_xy, - mirror_point_plane, - mirror_points_plane, - project_point_plane, - project_points_plane, - project_point_line, - project_point_line_xy, - project_points_line, - project_points_line_xy, - reflect_line_plane, - reflect_line_triangle, - orient_points, - Projection, - Reflection, - Rotation, - Scale, - Shear, - Transformation, - Translation, -) +from .offset.offset import offset_line, offset_polyline, offset_polygon +from .quadmesh.planarization import quadmesh_planarize +from .triangulation import conforming_delaunay_triangulation, constrained_delaunay_triangulation, delaunay_triangulation +from .triangulation.delaunay import delaunay_from_points +from .trimesh.curvature import trimesh_mean_curvature, trimesh_gaussian_curvature, trimesh_principal_curvature +from .trimesh.geodistance import trimesh_geodistance +from .trimesh.isolines import trimesh_isolines +from .trimesh.matrices import trimesh_massmatrix +from .trimesh.parametrisation import trimesh_harmonic, trimesh_lscm +from .trimesh.remesh import trimesh_remesh, trimesh_remesh_along_isoline, trimesh_remesh_constrained +from .trimesh.slicing import trimesh_slice if not compas.IPY: - from .transformations import ( - transform_points_numpy, - transform_vectors_numpy, - homogenize_numpy, - dehomogenize_numpy, - homogenize_and_flatten_frames_numpy, - dehomogenize_and_unflatten_frames_numpy, - world_to_local_coordinates_numpy, - local_to_world_coordinates_numpy, - ) - -from .geometry import Geometry - -from .primitives import ( # noqa: E402 - Primitive, - Bezier, - Circle, - Ellipse, - Frame, - Line, - Plane, - Point, - Polygon, - Polyline, - Quaternion, - Vector, - Arc, -) -from .shapes import ( # noqa: E402 - Shape, - Box, - Capsule, - Cone, - Cylinder, - Polyhedron, - Sphere, - Torus, -) -from .bbox import bounding_box, bounding_box_xy # noqa: E402 - -if not compas.IPY: - from .bbox import ( + from .bbox.bbox_numpy import ( oriented_bounding_box_numpy, oriented_bounding_box_xy_numpy, oabb_numpy, ) -from .bestfit import bestfit_plane # noqa: E402 - -if not compas.IPY: - from .bestfit import ( + from .bestfit.bestfit_numpy import ( bestfit_plane_numpy, bestfit_frame_numpy, bestfit_circle_numpy, bestfit_sphere_numpy, ) -from .booleans import ( # noqa: E402 - boolean_union_mesh_mesh, - boolean_difference_mesh_mesh, - boolean_intersection_mesh_mesh, -) -from .hull import convex_hull, convex_hull_xy # noqa: E402 - -if not compas.IPY: - from .hull import convex_hull_numpy, convex_hull_xy_numpy -from .interpolation import ( # noqa: E402 - barycentric_coordinates, - discrete_coons_patch, - tween_points, - tween_points_distance, -) -from .offset import offset_line, offset_polyline, offset_polygon # noqa: E402 -from .pointclouds import Pointcloud # noqa: E402 -from .quadmesh import quadmesh_planarize # noqa: E402 -from .triangulation import ( # noqa: E402 - conforming_delaunay_triangulation, - constrained_delaunay_triangulation, - delaunay_from_points, - delaunay_triangulation, -) - -if not compas.IPY: - from .triangulation import delaunay_from_points_numpy, voronoi_from_points_numpy -from .trimesh import ( # noqa: E402 - trimesh_mean_curvature, - trimesh_gaussian_curvature, - trimesh_principal_curvature, - trimesh_geodistance, - trimesh_isolines, - trimesh_massmatrix, - trimesh_harmonic, - trimesh_lscm, - trimesh_remesh, - trimesh_remesh_constrained, - trimesh_remesh_along_isoline, - trimesh_slice, -) - -if not compas.IPY: - from .icp import icp_numpy + from .hull.hull_numpy import convex_hull_numpy, convex_hull_xy_numpy + from .icp.icp_numpy import icp_numpy + from .triangulation.delaunay_numpy import delaunay_from_points_numpy, voronoi_from_points_numpy -from .curves import Curve, NurbsCurve +# ============================================================================= +# Class APIs +# ============================================================================= -from .surfaces import Surface, NurbsSurface +from .geometry import Geometry +from .transformations.transformation import Transformation + +from .transformations.projection import Projection +from .transformations.reflection import Reflection +from .transformations.rotation import Rotation +from .transformations.scale import Scale +from .transformations.shear import Shear +from .transformations.translation import Translation + +from .primitives._primitive import Primitive +from .primitives.vector import Vector +from .primitives.point import Point +from .primitives.line import Line +from .primitives.plane import Plane +from .primitives.quaternion import Quaternion +from .primitives.frame import Frame + +from .primitives.arc import Arc +from .primitives.circle import Circle +from .primitives.curve import Bezier +from .primitives.ellipse import Ellipse +from .primitives.polygon import Polygon +from .primitives.polyline import Polyline + +from .curves.curve import Curve +from .curves.nurbs import NurbsCurve + +from .surfaces.surface import Surface +from .surfaces.nurbs import NurbsSurface + +from .shapes._shape import Shape +from .shapes.box import Box +from .shapes.capsule import Capsule +from .shapes.cone import Cone +from .shapes.cylinder import Cylinder +from .shapes.polyhedron import Polyhedron +from .shapes.sphere import Sphere +from .shapes.torus import Torus + +from .pointclouds.pointcloud import Pointcloud from .brep import ( - Brep, - BrepVertex, - BrepFace, - BrepLoop, - BrepEdge, - BrepTrim, - BrepTrimIsoStatus, - BrepType, - BrepOrientation, BrepError, BrepInvalidError, BrepTrimmingError, ) +from .brep.brep import Brep +from .brep.brep import BrepOrientation +from .brep.brep import BrepType +from .brep.edge import BrepEdge +from .brep.loop import BrepLoop +from .brep.face import BrepFace +from .brep.vertex import BrepVertex +from .brep.trim import BrepTrim +from .brep.trim import BrepTrimIsoStatus + + __all__ = [ "close", "allclose", diff --git a/src/compas/geometry/_core/__init__.py b/src/compas/geometry/_core/__init__.py index c19989b1a0e..e69de29bb2d 100644 --- a/src/compas/geometry/_core/__init__.py +++ b/src/compas/geometry/_core/__init__.py @@ -1,19 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -from ._algebra import * # noqa: F401 F403 - -from .constructors import * # noqa: F401 F403 -from .analytical import * # noqa: F401 F403 -from .distance import * # noqa: F401 F403 -from .angles import * # noqa: F401 F403 -from .centroids import * # noqa: F401 F403 -from .normals import * # noqa: F401 F403 -from .size import * # noqa: F401 F403 -from .quaternions import * # noqa: F401 F403 -from .tangent import * # noqa: F401 F403 -from .kdtree import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/_core/_algebra.py b/src/compas/geometry/_core/_algebra.py index 921435eb4df..31ca4303fd8 100644 --- a/src/compas/geometry/_core/_algebra.py +++ b/src/compas/geometry/_core/_algebra.py @@ -5,55 +5,6 @@ from math import sqrt from math import fabs -__all__ = [ - "close", - "allclose", - "argmin", - "argmax", - "add_vectors", - "add_vectors_xy", - "sum_vectors", - "cross_vectors", - "cross_vectors_xy", - "divide_vectors", - "divide_vectors_xy", - "dot_vectors", - "dot_vectors_xy", - "length_vector", - "length_vector_xy", - "length_vector_sqrd", - "length_vector_sqrd_xy", - "multiply_matrices", - "multiply_matrix_vector", - "multiply_vectors", - "multiply_vectors_xy", - "norm_vector", - "norm_vectors", - "normalize_vector", - "normalize_vector_xy", - "normalize_vectors", - "normalize_vectors_xy", - "homogenize_vectors", - "dehomogenize_vectors", - "orthonormalize_vectors", - "power_vector", - "power_vectors", - "scale_vector", - "scale_vector_xy", - "scale_vectors", - "scale_vectors_xy", - "square_vector", - "square_vectors", - "subtract_vectors", - "subtract_vectors_xy", - "transpose_matrix", - "vector_component", - "vector_component_xy", - "vector_average", - "vector_variance", - "vector_standard_deviation", -] - def vector_average(vector): """Average of a vector. diff --git a/src/compas/geometry/_core/analytical.py b/src/compas/geometry/_core/analytical.py index 9dfb90d9eff..13a40b13403 100644 --- a/src/compas/geometry/_core/analytical.py +++ b/src/compas/geometry/_core/analytical.py @@ -6,14 +6,6 @@ from math import cos from math import sin -__all__ = [ - "circle_evaluate", - "ellipse_evaluate", - "archimedean_spiral_evaluate", - "logarithmic_spiral_evaluate", - "helix_evaluate", -] - def circle_evaluate(t, r, z=0): """Evalutes a circle at a parameter. diff --git a/src/compas/geometry/_core/angles.py b/src/compas/geometry/_core/angles.py index 3fc88425be1..aa5901e0805 100644 --- a/src/compas/geometry/_core/angles.py +++ b/src/compas/geometry/_core/angles.py @@ -6,29 +6,13 @@ from math import degrees from math import acos -from compas.geometry._core import subtract_vectors -from compas.geometry._core import subtract_vectors_xy -from compas.geometry._core import dot_vectors -from compas.geometry._core import dot_vectors_xy -from compas.geometry._core import length_vector -from compas.geometry._core import length_vector_xy -from compas.geometry._core import cross_vectors - - -__all__ = [ - "angles_vectors", - "angles_vectors_xy", - "angles_vectors", - "angles_vectors_xy", - "angles_points", - "angles_points_xy", - "angle_vectors", - "angle_vectors_signed", - "angle_vectors_xy", - "angle_points", - "angle_points_xy", - "angle_planes", -] +from ._algebra import subtract_vectors +from ._algebra import subtract_vectors_xy +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 def angle_vectors(u, v, deg=False, tol=0.0): diff --git a/src/compas/geometry/_core/centroids.py b/src/compas/geometry/_core/centroids.py index 4b5a17ff2cc..63777dc524f 100644 --- a/src/compas/geometry/_core/centroids.py +++ b/src/compas/geometry/_core/centroids.py @@ -6,34 +6,16 @@ from compas.utilities import pairwise -from compas.geometry._core import add_vectors -from compas.geometry._core import subtract_vectors -from compas.geometry._core import subtract_vectors_xy -from compas.geometry._core import length_vector -from compas.geometry._core import length_vector_xy -from compas.geometry._core import dot_vectors -from compas.geometry._core import cross_vectors -from compas.geometry._core import cross_vectors_xy -from compas.geometry._core import scale_vector -from compas.geometry._core import sum_vectors - - -__all__ = [ - "midpoint_point_point", - "midpoint_point_point_xy", - "midpoint_line", - "midpoint_line_xy", - "centroid_points", - "centroid_points_weighted", - "centroid_points_xy", - "centroid_polygon", - "centroid_polygon_xy", - "centroid_polygon_vertices", - "centroid_polygon_vertices_xy", - "centroid_polygon_edges", - "centroid_polygon_edges_xy", - "centroid_polyhedron", -] +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 scale_vector +from ._algebra import sum_vectors def midpoint_point_point(a, b): diff --git a/src/compas/geometry/_core/constructors.py b/src/compas/geometry/_core/constructors.py index 9c14a8153bd..5a31dadb826 100644 --- a/src/compas/geometry/_core/constructors.py +++ b/src/compas/geometry/_core/constructors.py @@ -4,20 +4,14 @@ from math import sqrt -from compas.geometry._core import subtract_vectors -from compas.geometry._core import sum_vectors -from compas.geometry._core import cross_vectors -from compas.geometry._core import dot_vectors -from compas.geometry._core import scale_vector -from compas.geometry._core import normalize_vector -from compas.geometry._core import length_vector -from compas.geometry._core import length_vector_sqrd - - -__all__ = [ - "circle_from_points", - "circle_from_points_xy", -] +from ._algebra import subtract_vectors +from ._algebra import sum_vectors +from ._algebra import cross_vectors +from ._algebra import dot_vectors +from ._algebra import scale_vector +from ._algebra import normalize_vector +from ._algebra import length_vector +from ._algebra import length_vector_sqrd def circle_from_points(a, b, c): diff --git a/src/compas/geometry/_core/distance.py b/src/compas/geometry/_core/distance.py index 899f7992e78..decbbe7636e 100644 --- a/src/compas/geometry/_core/distance.py +++ b/src/compas/geometry/_core/distance.py @@ -7,46 +7,21 @@ from compas.utilities import pairwise -from compas.geometry._core import add_vectors -from compas.geometry._core import add_vectors_xy -from compas.geometry._core import subtract_vectors -from compas.geometry._core import subtract_vectors_xy -from compas.geometry._core import scale_vector -from compas.geometry._core import normalize_vector -from compas.geometry._core import length_vector -from compas.geometry._core import length_vector_xy -from compas.geometry._core import length_vector_sqrd -from compas.geometry._core import length_vector_sqrd_xy -from compas.geometry._core import cross_vectors -from compas.geometry._core import cross_vectors_xy -from compas.geometry._core import dot_vectors -from compas.geometry._core import vector_component -from compas.geometry._core import vector_component_xy - - -__all__ = [ - "distance_point_point", - "distance_point_point_xy", - "distance_point_point_sqrd", - "distance_point_point_sqrd_xy", - "distance_point_line", - "distance_point_line_xy", - "distance_point_line_sqrd", - "distance_point_line_sqrd_xy", - "distance_point_plane", - "distance_point_plane_signed", - "distance_line_line", - "closest_point_in_cloud", - "closest_point_in_cloud_xy", - "closest_point_on_line", - "closest_point_on_line_xy", - "closest_point_on_segment", - "closest_point_on_segment_xy", - "closest_point_on_polyline", - "closest_point_on_polyline_xy", - "closest_point_on_plane", - "closest_line_to_point", -] +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 vector_component +from ._algebra import vector_component_xy def distance_point_point(a, b): diff --git a/src/compas/geometry/_core/kdtree.py b/src/compas/geometry/_core/kdtree.py index 874ffee9eaa..bd9587f2ea4 100644 --- a/src/compas/geometry/_core/kdtree.py +++ b/src/compas/geometry/_core/kdtree.py @@ -4,10 +4,7 @@ import collections -from compas.geometry._core import distance_point_point_sqrd - - -__all__ = ["KDTree"] +from .distance import distance_point_point_sqrd Node = collections.namedtuple("Node", "point axis label left right") diff --git a/src/compas/geometry/_core/normals.py b/src/compas/geometry/_core/normals.py index 85db0701dff..c7f9d066716 100644 --- a/src/compas/geometry/_core/normals.py +++ b/src/compas/geometry/_core/normals.py @@ -2,21 +2,14 @@ from __future__ import absolute_import from __future__ import division -from compas.geometry._core import subtract_vectors -from compas.geometry._core import subtract_vectors_xy -from compas.geometry._core import cross_vectors -from compas.geometry._core import cross_vectors_xy -from compas.geometry._core import length_vector -from compas.geometry._core import normalize_vector - -from compas.geometry._core import centroid_points - - -__all__ = [ - "normal_polygon", - "normal_triangle", - "normal_triangle_xy", -] +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 .centroids import centroid_points def normal_polygon(polygon, unitized=True): diff --git a/src/compas/geometry/_core/quaternions.py b/src/compas/geometry/_core/quaternions.py index 0fc76490892..7cfb6b5bcca 100644 --- a/src/compas/geometry/_core/quaternions.py +++ b/src/compas/geometry/_core/quaternions.py @@ -49,18 +49,9 @@ """ import math -from compas.geometry._core import allclose +from ._algebra import allclose -__all__ = [ - "quaternion_norm", - "quaternion_unitize", - "quaternion_is_unit", - "quaternion_multiply", - "quaternion_canonize", - "quaternion_conjugate", -] - ATOL = 1e-6 # absolute tolerance diff --git a/src/compas/geometry/_core/size.py b/src/compas/geometry/_core/size.py index c79a69e74a0..7536a8e985c 100644 --- a/src/compas/geometry/_core/size.py +++ b/src/compas/geometry/_core/size.py @@ -6,27 +6,18 @@ from compas.utilities import pairwise -from compas.geometry._core import subtract_vectors -from compas.geometry._core import subtract_vectors_xy -from compas.geometry._core import length_vector -from compas.geometry._core import cross_vectors -from compas.geometry._core import cross_vectors_xy -from compas.geometry._core import dot_vectors - -from compas.geometry._core import centroid_points -from compas.geometry._core import centroid_points_xy - -from compas.geometry._core import normal_triangle -from compas.geometry._core import normal_triangle_xy - - -__all__ = [ - "area_polygon", - "area_polygon_xy", - "area_triangle", - "area_triangle_xy", - "volume_polyhedron", -] +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 .centroids import centroid_points +from .centroids import centroid_points_xy + +from .normals import normal_triangle +from .normals import normal_triangle_xy def area_polygon(polygon): diff --git a/src/compas/geometry/_core/tangent.py b/src/compas/geometry/_core/tangent.py index 3f5f5be786b..32da71412a5 100644 --- a/src/compas/geometry/_core/tangent.py +++ b/src/compas/geometry/_core/tangent.py @@ -5,9 +5,6 @@ from math import sqrt -__all__ = ["tangent_points_to_circle_xy"] - - def tangent_points_to_circle_xy(circle, point): """Calculates the tangent points on a circle in the XY plane. diff --git a/src/compas/geometry/bbox/__init__.py b/src/compas/geometry/bbox/__init__.py index 57c9d4303da..e69de29bb2d 100644 --- a/src/compas/geometry/bbox/__init__.py +++ b/src/compas/geometry/bbox/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -from .bbox import * # noqa: F401 F403 - -if not compas.IPY: - from .bbox_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/bbox/bbox.py b/src/compas/geometry/bbox/bbox.py index 44b731060b6..79e7b8a1c63 100644 --- a/src/compas/geometry/bbox/bbox.py +++ b/src/compas/geometry/bbox/bbox.py @@ -5,12 +5,6 @@ from itertools import islice -__all__ = [ - "bounding_box", - "bounding_box_xy", -] - - def bounding_box(points): """Computes the axis-aligned minimum bounding box of a list of points. diff --git a/src/compas/geometry/bbox/bbox_numpy.py b/src/compas/geometry/bbox/bbox_numpy.py index a078d7a7636..7986db0e290 100644 --- a/src/compas/geometry/bbox/bbox_numpy.py +++ b/src/compas/geometry/bbox/bbox_numpy.py @@ -9,30 +9,17 @@ from numpy import amax from numpy import amin from numpy import dot - -# from numpy import ptp from numpy import sum from scipy.spatial import ConvexHull -# from scipy.spatial import QhullError - +from compas.numerical 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 transform_points_numpy -from compas.geometry import Frame -from compas.geometry import Transformation -from compas.numerical import pca_numpy -from compas.geometry.bbox.bbox import bounding_box - - -__all__ = [ - "oriented_bounding_box_numpy", - "oriented_bounding_box_xy_numpy", - "oabb_numpy", -] +from .bbox import bounding_box # make alternative implementation using PCA @@ -264,6 +251,9 @@ def oabb_numpy(points): XYZ coordinates of 8 points defining a box. """ + from compas.geometry import Frame + from compas.geometry import Transformation + origin, (xaxis, yaxis, zaxis), values = pca_numpy(points) frame = Frame(origin, xaxis, yaxis) world = Frame.worldXY() diff --git a/src/compas/geometry/bestfit/__init__.py b/src/compas/geometry/bestfit/__init__.py index 7886571d90f..e69de29bb2d 100644 --- a/src/compas/geometry/bestfit/__init__.py +++ b/src/compas/geometry/bestfit/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -from .bestfit import * # noqa: F401 F403 - -if not compas.IPY: - from .bestfit_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/bestfit/bestfit.py b/src/compas/geometry/bestfit/bestfit.py index 8219816fd43..e8a8a5c509d 100644 --- a/src/compas/geometry/bestfit/bestfit.py +++ b/src/compas/geometry/bestfit/bestfit.py @@ -7,9 +7,6 @@ from compas.geometry import centroid_points -__all__ = ["bestfit_plane"] - - def bestfit_plane(points): """Fit a plane to a list of (more than three) points. diff --git a/src/compas/geometry/bestfit/bestfit_numpy.py b/src/compas/geometry/bestfit/bestfit_numpy.py index 29cc3161f92..c8eaf27f782 100644 --- a/src/compas/geometry/bestfit/bestfit_numpy.py +++ b/src/compas/geometry/bestfit/bestfit_numpy.py @@ -8,17 +8,9 @@ from numpy.linalg import lstsq from scipy.optimize import leastsq +from compas.numerical import pca_numpy from compas.geometry import world_to_local_coordinates_numpy from compas.geometry import local_to_world_coordinates_numpy -from compas.numerical import pca_numpy - - -__all__ = [ - "bestfit_plane_numpy", - "bestfit_frame_numpy", - "bestfit_circle_numpy", - "bestfit_sphere_numpy", -] def bestfit_plane_numpy(points): diff --git a/src/compas/geometry/booleans/__init__.py b/src/compas/geometry/booleans/__init__.py index a256b292bfd..042a3bbc51f 100644 --- a/src/compas/geometry/booleans/__init__.py +++ b/src/compas/geometry/booleans/__init__.py @@ -4,12 +4,6 @@ from compas.plugins import pluggable -__all__ = [ - "boolean_union_mesh_mesh", - "boolean_difference_mesh_mesh", - "boolean_intersection_mesh_mesh", -] - @pluggable(category="booleans") def boolean_union_mesh_mesh(A, B): diff --git a/src/compas/geometry/brep/__init__.py b/src/compas/geometry/brep/__init__.py index 63c4272235f..c5474b87b5f 100644 --- a/src/compas/geometry/brep/__init__.py +++ b/src/compas/geometry/brep/__init__.py @@ -1,14 +1,3 @@ -from .brep import Brep -from .brep import BrepOrientation -from .brep import BrepType -from .edge import BrepEdge -from .loop import BrepLoop -from .face import BrepFace -from .vertex import BrepVertex -from .trim import BrepTrim -from .trim import BrepTrimIsoStatus - - class BrepError(Exception): """Represents a generic error in the Brep context""" @@ -25,19 +14,3 @@ class BrepTrimmingError(BrepError): """Raised when a trimming operation has failed or had not result""" pass - - -__all__ = [ - "Brep", - "BrepEdge", - "BrepLoop", - "BrepFace", - "BrepVertex", - "BrepTrim", - "BrepTrimIsoStatus", - "BrepOrientation", - "BrepType", - "BrepError", - "BrepInvalidError", - "BrepTrimmingError", -] diff --git a/src/compas/geometry/curves/__init__.py b/src/compas/geometry/curves/__init__.py index 1a958bd18a2..e69de29bb2d 100644 --- a/src/compas/geometry/curves/__init__.py +++ b/src/compas/geometry/curves/__init__.py @@ -1,4 +0,0 @@ -from __future__ import absolute_import - -from .curve import Curve # noqa: F401 -from .nurbs import NurbsCurve # noqa: F401 diff --git a/src/compas/geometry/hull/__init__.py b/src/compas/geometry/hull/__init__.py index a997d8aa5cb..e69de29bb2d 100644 --- a/src/compas/geometry/hull/__init__.py +++ b/src/compas/geometry/hull/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -from .hull import * # noqa: F401 F403 - -if not compas.IPY: - from .hull_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/hull/hull.py b/src/compas/geometry/hull/hull.py index 9004464c42b..547019b8a73 100644 --- a/src/compas/geometry/hull/hull.py +++ b/src/compas/geometry/hull/hull.py @@ -8,12 +8,6 @@ from compas.geometry import cross_vectors_xy -__all__ = [ - "convex_hull", - "convex_hull_xy", -] - - def convex_hull(points): """Construct convex hull for a set of points. diff --git a/src/compas/geometry/hull/hull_numpy.py b/src/compas/geometry/hull/hull_numpy.py index 7c9b099b754..d1119502db8 100644 --- a/src/compas/geometry/hull/hull_numpy.py +++ b/src/compas/geometry/hull/hull_numpy.py @@ -6,12 +6,6 @@ from scipy.spatial import ConvexHull -__all__ = [ - "convex_hull_numpy", - "convex_hull_xy_numpy", -] - - def convex_hull_numpy(points): """Compute the convex hull of a set of points. diff --git a/src/compas/geometry/icp/__init__.py b/src/compas/geometry/icp/__init__.py index 5731f4e56dc..e69de29bb2d 100644 --- a/src/compas/geometry/icp/__init__.py +++ b/src/compas/geometry/icp/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .icp_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/icp/icp_numpy.py b/src/compas/geometry/icp/icp_numpy.py index 09cf50963ed..cd7534912b8 100644 --- a/src/compas/geometry/icp/icp_numpy.py +++ b/src/compas/geometry/icp/icp_numpy.py @@ -12,14 +12,9 @@ from compas.numerical import pca_numpy from compas.numerical import normrow -from compas.geometry import Transformation -from compas.geometry import Frame from compas.geometry import transform_points_numpy -__all__ = ["icp_numpy"] - - def bestfit_transform(A, B): n, m = A.shape Am = np.mean(A, axis=0) @@ -84,6 +79,9 @@ def icp_numpy(source, target, tol=1e-3): >>> """ + from compas.geometry import Transformation + from compas.geometry import Frame + A = asarray(source) B = asarray(target) diff --git a/src/compas/geometry/interpolation/__init__.py b/src/compas/geometry/interpolation/__init__.py index 13901f7a3cc..e69de29bb2d 100644 --- a/src/compas/geometry/interpolation/__init__.py +++ b/src/compas/geometry/interpolation/__init__.py @@ -1,10 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .barycentric import * # noqa: F401 F403 -from .coons import * # noqa: F401 F403 -from .tweening import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/interpolation/barycentric.py b/src/compas/geometry/interpolation/barycentric.py index 25e85fe2d3f..7a5663b0439 100644 --- a/src/compas/geometry/interpolation/barycentric.py +++ b/src/compas/geometry/interpolation/barycentric.py @@ -6,9 +6,6 @@ from compas.geometry import dot_vectors -__all__ = ["barycentric_coordinates"] - - def barycentric_coordinates(point, triangle): """Compute the barycentric coordinates of a point wrt to a triangle. diff --git a/src/compas/geometry/interpolation/coons.py b/src/compas/geometry/interpolation/coons.py index 8b28675adc3..868ba0cef40 100644 --- a/src/compas/geometry/interpolation/coons.py +++ b/src/compas/geometry/interpolation/coons.py @@ -10,11 +10,6 @@ from compas.utilities import normalize_values -__all__ = [ - "discrete_coons_patch", -] - - def discrete_coons_patch(ab, bc, dc, ad): """Creates a coons patch from a set of four or three boundary polylines (ab, bc, dc, ad). diff --git a/src/compas/geometry/interpolation/tweening.py b/src/compas/geometry/interpolation/tweening.py index 19ee6d478ea..8b8862d9914 100644 --- a/src/compas/geometry/interpolation/tweening.py +++ b/src/compas/geometry/interpolation/tweening.py @@ -8,9 +8,6 @@ from compas.geometry import distance_point_point -__all__ = ["tween_points", "tween_points_distance"] - - def tween_points(points1, points2, num): """Compute the interpolated points between two sets of points. diff --git a/src/compas/geometry/intersections/__init__.py b/src/compas/geometry/intersections/__init__.py index ac06df4fcfb..f6fa9ec7bd7 100644 --- a/src/compas/geometry/intersections/__init__.py +++ b/src/compas/geometry/intersections/__init__.py @@ -3,7 +3,6 @@ from __future__ import print_function from compas.plugins import pluggable -from .intersections import * # noqa: F401 F403 @pluggable(category="intersections") @@ -53,6 +52,3 @@ def intersection_ray_mesh(ray, mesh): """ raise NotImplementedError - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/intersections/intersections.py b/src/compas/geometry/intersections/intersections.py index 40484290c55..0da81dd9480 100644 --- a/src/compas/geometry/intersections/intersections.py +++ b/src/compas/geometry/intersections/intersections.py @@ -25,30 +25,6 @@ from compas.geometry import is_point_in_triangle -__all__ = [ - "intersection_line_line", - "intersection_segment_segment", - "intersection_line_segment", - "intersection_line_plane", - "intersection_polyline_plane", - "intersection_line_triangle", - "intersection_segment_plane", - "intersection_plane_circle", - "intersection_plane_plane", - "intersection_plane_plane_plane", - "intersection_sphere_line", - "intersection_sphere_sphere", - "intersection_segment_polyline", - "intersection_line_line_xy", - "intersection_segment_segment_xy", - "intersection_line_segment_xy", - "intersection_line_box_xy", - "intersection_circle_circle_xy", - "intersection_ellipse_line_xy", - "intersection_segment_polyline_xy", -] - - def intersection_line_line(l1, l2, tol=1e-6): """Computes the intersection of two lines. diff --git a/src/compas/geometry/offset/__init__.py b/src/compas/geometry/offset/__init__.py index 123b83f6242..e69de29bb2d 100644 --- a/src/compas/geometry/offset/__init__.py +++ b/src/compas/geometry/offset/__init__.py @@ -1,9 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -from .offset import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/offset/offset.py b/src/compas/geometry/offset/offset.py index 77a2e0cb06a..95039d1afaf 100644 --- a/src/compas/geometry/offset/offset.py +++ b/src/compas/geometry/offset/offset.py @@ -17,13 +17,6 @@ from compas.utilities import is_item_iterable -__all__ = [ - "offset_line", - "offset_polyline", - "offset_polygon", -] - - def intersect_lines(l1, l2, tol): x1, x2 = intersection_line_line(l1, l2, tol) if x1 and x2: diff --git a/src/compas/geometry/pointclouds/__init__.py b/src/compas/geometry/pointclouds/__init__.py index baf8688eb3c..e69de29bb2d 100644 --- a/src/compas/geometry/pointclouds/__init__.py +++ b/src/compas/geometry/pointclouds/__init__.py @@ -1,7 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -from .pointcloud import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/pointclouds/pointcloud.py b/src/compas/geometry/pointclouds/pointcloud.py index 7f8daf97f8e..a01e2256544 100644 --- a/src/compas/geometry/pointclouds/pointcloud.py +++ b/src/compas/geometry/pointclouds/pointcloud.py @@ -10,9 +10,6 @@ from compas.geometry import Point -__all__ = ["Pointcloud"] - - class Pointcloud(Primitive): """Class for working with pointclouds. diff --git a/src/compas/geometry/predicates/__init__.py b/src/compas/geometry/predicates/__init__.py index 1de2646dfe9..e69de29bb2d 100644 --- a/src/compas/geometry/predicates/__init__.py +++ b/src/compas/geometry/predicates/__init__.py @@ -1,8 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .predicates_2 import * # noqa: F401 F403 -from .predicates_3 import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/predicates/predicates_2.py b/src/compas/geometry/predicates/predicates_2.py index 85e23410461..143a08ed52f 100644 --- a/src/compas/geometry/predicates/predicates_2.py +++ b/src/compas/geometry/predicates/predicates_2.py @@ -2,26 +2,9 @@ from __future__ import absolute_import from __future__ import division -from compas.geometry._core import distance_point_point_xy -from compas.geometry._core import distance_point_line_xy -from compas.geometry._core import closest_point_on_segment_xy - - -__all__ = [ - "is_ccw_xy", - "is_colinear_xy", - "is_polygon_convex_xy", - "is_point_on_line_xy", - "is_point_on_segment_xy", - "is_point_on_polyline_xy", - "is_point_in_triangle_xy", - "is_point_in_polygon_xy", - "is_point_in_convex_polygon_xy", - "is_point_in_circle_xy", - "is_polygon_in_polygon_xy", - "is_intersection_line_line_xy", - "is_intersection_segment_segment_xy", -] +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 def is_ccw_xy(a, b, c, colinear=False): diff --git a/src/compas/geometry/predicates/predicates_3.py b/src/compas/geometry/predicates/predicates_3.py index 52e138ddf5d..6ba43fc544f 100644 --- a/src/compas/geometry/predicates/predicates_3.py +++ b/src/compas/geometry/predicates/predicates_3.py @@ -6,44 +6,20 @@ from compas.utilities import window -from compas.geometry._core import subtract_vectors -from compas.geometry._core import cross_vectors -from compas.geometry._core import dot_vectors -from compas.geometry._core import normalize_vector -from compas.geometry._core import centroid_points -from compas.geometry._core import normal_polygon -from compas.geometry._core import length_vector_sqrd - -from compas.geometry._core import distance_point_point -from compas.geometry._core import distance_point_plane -from compas.geometry._core import distance_point_line -from compas.geometry._core import closest_point_on_segment - -from compas.geometry._core import area_triangle - - -__all__ = [ - "is_colinear", - "is_colinear_line_line", - "is_coplanar", - "is_polygon_convex", - "is_point_on_plane", - "is_point_infront_plane", - "is_point_behind_plane", - "is_point_in_halfspace", - "is_point_on_line", - "is_point_on_segment", - "is_point_on_polyline", - "is_point_in_triangle", - "is_point_in_circle", - "is_point_in_polyhedron", - "is_intersection_line_line", - "is_intersection_segment_segment", - "is_intersection_line_triangle", - "is_intersection_line_plane", - "is_intersection_segment_plane", - "is_intersection_plane_plane", -] +from compas.geometry import subtract_vectors +from compas.geometry import cross_vectors +from compas.geometry import dot_vectors +from compas.geometry import normalize_vector +from compas.geometry import centroid_points +from compas.geometry import normal_polygon +from compas.geometry import length_vector_sqrd + +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 area_triangle def is_colinear(a, b, c, tol=1e-6): diff --git a/src/compas/geometry/primitives/__init__.py b/src/compas/geometry/primitives/__init__.py index 77a4d64e85d..e69de29bb2d 100644 --- a/src/compas/geometry/primitives/__init__.py +++ b/src/compas/geometry/primitives/__init__.py @@ -1,21 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from ._primitive import Primitive # noqa: F401 - -from .vector import Vector # noqa: F401 -from .point import Point # noqa: F401 -from .line import Line # noqa: F401 -from .plane import Plane # noqa: F401 -from .quaternion import Quaternion # noqa: F401 -from .frame import Frame # noqa: F401 -from .polyline import Polyline # noqa: F401 -from .polygon import Polygon # noqa: F401 -from .circle import Circle # noqa: F401 -from .ellipse import Ellipse # noqa: F401 -from .curve import Bezier # noqa: F401 -from .arc import Arc # noqa: F401 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/primitives/_primitive.py b/src/compas/geometry/primitives/_primitive.py index 1c837d98071..d57289b5e74 100644 --- a/src/compas/geometry/primitives/_primitive.py +++ b/src/compas/geometry/primitives/_primitive.py @@ -2,7 +2,7 @@ from __future__ import division from __future__ import print_function -from ..geometry import Geometry +from compas.geometry import Geometry class Primitive(Geometry): diff --git a/src/compas/geometry/primitives/arc.py b/src/compas/geometry/primitives/arc.py index bf31845690d..e4253320a0a 100644 --- a/src/compas/geometry/primitives/arc.py +++ b/src/compas/geometry/primitives/arc.py @@ -1,8 +1,9 @@ import math from compas.geometry import close -from compas.geometry.primitives import Frame -from compas.geometry.primitives import Primitive + +from ._primitive import Primitive +from .frame import Frame class Arc(Primitive): diff --git a/src/compas/geometry/primitives/circle.py b/src/compas/geometry/primitives/circle.py index 6d22d342c16..50a670615b4 100644 --- a/src/compas/geometry/primitives/circle.py +++ b/src/compas/geometry/primitives/circle.py @@ -4,8 +4,8 @@ from math import pi -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Plane +from ._primitive import Primitive +from .plane import Plane class Circle(Primitive): diff --git a/src/compas/geometry/primitives/curve.py b/src/compas/geometry/primitives/curve.py index b3edf43d9f5..5934eb258a4 100644 --- a/src/compas/geometry/primitives/curve.py +++ b/src/compas/geometry/primitives/curve.py @@ -4,9 +4,9 @@ from math import factorial -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Point -from compas.geometry.primitives import Vector +from ._primitive import Primitive +from .vector import Vector +from .point import Point def binomial_coefficient(n, k): diff --git a/src/compas/geometry/primitives/ellipse.py b/src/compas/geometry/primitives/ellipse.py index a350953fabd..106f322fb31 100644 --- a/src/compas/geometry/primitives/ellipse.py +++ b/src/compas/geometry/primitives/ellipse.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from __future__ import division -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Plane +from ._primitive import Primitive +from .plane import Plane class Ellipse(Primitive): diff --git a/src/compas/geometry/primitives/frame.py b/src/compas/geometry/primitives/frame.py index d6b427f7d73..725ae008497 100644 --- a/src/compas/geometry/primitives/frame.py +++ b/src/compas/geometry/primitives/frame.py @@ -15,12 +15,13 @@ from compas.geometry import matrix_from_quaternion from compas.geometry import quaternion_from_matrix from compas.geometry import subtract_vectors + from compas.geometry import Transformation -from compas.geometry.primitives import Point -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Quaternion -from compas.geometry.primitives import Vector +from ._primitive import Primitive +from .vector import Vector +from .point import Point +from .quaternion import Quaternion class Frame(Primitive): diff --git a/src/compas/geometry/primitives/line.py b/src/compas/geometry/primitives/line.py index 798ee4a3f5b..a3c9c9913a0 100644 --- a/src/compas/geometry/primitives/line.py +++ b/src/compas/geometry/primitives/line.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from __future__ import division -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Point +from ._primitive import Primitive +from .point import Point class Line(Primitive): diff --git a/src/compas/geometry/primitives/plane.py b/src/compas/geometry/primitives/plane.py index 84988b9e0d3..17871cc491f 100644 --- a/src/compas/geometry/primitives/plane.py +++ b/src/compas/geometry/primitives/plane.py @@ -3,9 +3,9 @@ from __future__ import division from math import sqrt -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Vector -from compas.geometry.primitives import Point +from ._primitive import Primitive +from .vector import Vector +from .point import Point class Plane(Primitive): diff --git a/src/compas/geometry/primitives/point.py b/src/compas/geometry/primitives/point.py index 4fd46d91b3d..d64b588502e 100644 --- a/src/compas/geometry/primitives/point.py +++ b/src/compas/geometry/primitives/point.py @@ -6,7 +6,6 @@ from compas.geometry import centroid_points from compas.geometry import normal_polygon - from compas.geometry import distance_point_point from compas.geometry import distance_point_line from compas.geometry import distance_point_plane @@ -19,11 +18,10 @@ from compas.geometry import is_point_in_polygon_xy from compas.geometry import is_point_in_convex_polygon_xy from compas.geometry import is_point_behind_plane - from compas.geometry import transform_points -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Vector +from ._primitive import Primitive +from .vector import Vector class Point(Primitive): diff --git a/src/compas/geometry/primitives/polygon.py b/src/compas/geometry/primitives/polygon.py index 79e163668fe..95f38e74ad6 100644 --- a/src/compas/geometry/primitives/polygon.py +++ b/src/compas/geometry/primitives/polygon.py @@ -12,13 +12,13 @@ from compas.geometry import is_polygon_convex from compas.geometry import transform_points -from compas.geometry.primitives import Line -from compas.geometry.primitives import Point -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Vector - from compas.utilities import pairwise +from ._primitive import Primitive +from .line import Line +from .point import Point +from .vector import Vector + class Polygon(Primitive): """A polygon is defined by a sequence of points forming a closed loop. diff --git a/src/compas/geometry/primitives/polyline.py b/src/compas/geometry/primitives/polyline.py index 96b71eb7603..2e61eb77e27 100644 --- a/src/compas/geometry/primitives/polyline.py +++ b/src/compas/geometry/primitives/polyline.py @@ -4,14 +4,13 @@ from compas.geometry import allclose from compas.geometry import transform_points - -from compas.geometry.predicates import is_point_on_line -from compas.geometry.primitives import Line -from compas.geometry.primitives import Primitive -from compas.geometry.primitives import Point - +from compas.geometry import is_point_on_line from compas.utilities import pairwise +from ._primitive import Primitive +from .point import Point +from .line import Line + class Polyline(Primitive): """A polyline is defined by a sequence of points connected by line segments. diff --git a/src/compas/geometry/primitives/quaternion.py b/src/compas/geometry/primitives/quaternion.py index d9b14e5dbcc..264256230fa 100644 --- a/src/compas/geometry/primitives/quaternion.py +++ b/src/compas/geometry/primitives/quaternion.py @@ -12,7 +12,7 @@ from compas.geometry import quaternion_is_unit from compas.geometry import quaternion_from_matrix -from compas.geometry.primitives import Primitive +from ._primitive import Primitive class Quaternion(Primitive): diff --git a/src/compas/geometry/primitives/vector.py b/src/compas/geometry/primitives/vector.py index f7ca259941c..07b79fa9248 100644 --- a/src/compas/geometry/primitives/vector.py +++ b/src/compas/geometry/primitives/vector.py @@ -13,7 +13,7 @@ from compas.geometry import angles_vectors from compas.geometry import transform_vectors -from compas.geometry.primitives import Primitive +from ._primitive import Primitive class Vector(Primitive): diff --git a/src/compas/geometry/quadmesh/__init__.py b/src/compas/geometry/quadmesh/__init__.py index 7b91d26504b..e69de29bb2d 100644 --- a/src/compas/geometry/quadmesh/__init__.py +++ b/src/compas/geometry/quadmesh/__init__.py @@ -1,8 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -from .planarization import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/quadmesh/planarization.py b/src/compas/geometry/quadmesh/planarization.py index 526a8cdc021..85d904db9a8 100644 --- a/src/compas/geometry/quadmesh/planarization.py +++ b/src/compas/geometry/quadmesh/planarization.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["quadmesh_planarize"] - - @pluggable(category="quadmesh") def quadmesh_planarize(M, kmax=500, maxdev=0.005): """Planarize the faces of a quad mesh. diff --git a/src/compas/geometry/shapes/__init__.py b/src/compas/geometry/shapes/__init__.py index 6b393c2f096..e69de29bb2d 100644 --- a/src/compas/geometry/shapes/__init__.py +++ b/src/compas/geometry/shapes/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from ._shape import Shape # noqa: F401 - -from .box import Box # noqa: F401 -from .capsule import Capsule # noqa: F401 -from .cone import Cone # noqa: F401 -from .cylinder import Cylinder # noqa: F401 -from .polyhedron import Polyhedron # noqa: F401 -from .sphere import Sphere # noqa: F401 -from .torus import Torus # noqa: F401 diff --git a/src/compas/geometry/shapes/_shape.py b/src/compas/geometry/shapes/_shape.py index 10006e02e86..a00e454e068 100644 --- a/src/compas/geometry/shapes/_shape.py +++ b/src/compas/geometry/shapes/_shape.py @@ -3,7 +3,7 @@ from __future__ import division import abc -from ..geometry import Geometry +from compas.geometry import Geometry class Shape(Geometry): diff --git a/src/compas/geometry/surfaces/__init__.py b/src/compas/geometry/surfaces/__init__.py index fd13c21f91a..e69de29bb2d 100644 --- a/src/compas/geometry/surfaces/__init__.py +++ b/src/compas/geometry/surfaces/__init__.py @@ -1,4 +0,0 @@ -from __future__ import absolute_import - -from .surface import Surface # noqa F401 -from .nurbs import NurbsSurface # noqa: F401 diff --git a/src/compas/geometry/transformations/__init__.py b/src/compas/geometry/transformations/__init__.py index e73756c33b0..e69de29bb2d 100644 --- a/src/compas/geometry/transformations/__init__.py +++ b/src/compas/geometry/transformations/__init__.py @@ -1,21 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas # noqa: F402 - -from .matrices import * # noqa: F401 F403 - -from .transformation import Transformation # noqa: F401 F402 -from .translation import Translation # noqa: F401 F402 -from .shear import Shear # noqa: F401 F402 -from .scale import Scale # noqa: F401 F402 -from .rotation import Rotation # noqa: F401 F402 -from .reflection import Reflection # noqa: F401 F402 -from .projection import Projection # noqa: F401 F402 -from .transformations import * # noqa: F401 F403 - -if not compas.IPY: - from .transformations_numpy import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/transformations/matrices.py b/src/compas/geometry/transformations/matrices.py index 9b1d3ea5756..58efd51acf4 100644 --- a/src/compas/geometry/transformations/matrices.py +++ b/src/compas/geometry/transformations/matrices.py @@ -53,41 +53,6 @@ _NEXT_SPEC = [1, 2, 0, 1] -__all__ = [ - "matrix_determinant", - "matrix_inverse", - "decompose_matrix", - "compose_matrix", - "identity_matrix", - "matrix_from_frame", - "matrix_from_frame_to_frame", - "matrix_from_change_of_basis", - "matrix_from_euler_angles", - "matrix_from_axis_and_angle", - "matrix_from_axis_angle_vector", - "matrix_from_basis_vectors", - "matrix_from_translation", - "matrix_from_orthogonal_projection", - "matrix_from_parallel_projection", - "matrix_from_perspective_projection", - "matrix_from_perspective_entries", - "matrix_from_shear_entries", - "matrix_from_shear", - "matrix_from_scale_factors", - "matrix_from_quaternion", - "euler_angles_from_matrix", - "euler_angles_from_quaternion", - "axis_and_angle_from_matrix", - "axis_angle_vector_from_matrix", - "axis_angle_from_quaternion", - "quaternion_from_matrix", - "quaternion_from_euler_angles", - "quaternion_from_axis_angle", - "basis_vectors_from_matrix", - "translation_from_matrix", -] - - def is_matrix_square(M): """Verify that a matrix is square. diff --git a/src/compas/geometry/transformations/projection.py b/src/compas/geometry/transformations/projection.py index 96b627f3398..534f85f00f5 100644 --- a/src/compas/geometry/transformations/projection.py +++ b/src/compas/geometry/transformations/projection.py @@ -12,12 +12,13 @@ """ from compas.utilities import flatten from compas.geometry import allclose -from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import matrix_from_orthogonal_projection -from compas.geometry.transformations import matrix_from_parallel_projection -from compas.geometry.transformations import matrix_from_perspective_projection -from compas.geometry.transformations import matrix_from_perspective_entries -from compas.geometry.transformations import Transformation +from .matrices import decompose_matrix +from .matrices import matrix_from_orthogonal_projection +from .matrices import matrix_from_parallel_projection +from .matrices import matrix_from_perspective_projection +from .matrices import matrix_from_perspective_entries + +from .transformation import Transformation class Projection(Transformation): diff --git a/src/compas/geometry/transformations/reflection.py b/src/compas/geometry/transformations/reflection.py index f803cacdbd8..43faf06308c 100644 --- a/src/compas/geometry/transformations/reflection.py +++ b/src/compas/geometry/transformations/reflection.py @@ -15,8 +15,8 @@ from compas.geometry import cross_vectors from compas.geometry import normalize_vector -from compas.geometry.transformations import identity_matrix -from compas.geometry.transformations import Transformation +from .matrices import identity_matrix +from .transformation import Transformation class Reflection(Transformation): diff --git a/src/compas/geometry/transformations/rotation.py b/src/compas/geometry/transformations/rotation.py index 623d95c9ad5..27374922531 100644 --- a/src/compas/geometry/transformations/rotation.py +++ b/src/compas/geometry/transformations/rotation.py @@ -17,15 +17,16 @@ from compas.geometry import length_vector from compas.geometry import allclose -from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import matrix_from_euler_angles -from compas.geometry.transformations import euler_angles_from_matrix -from compas.geometry.transformations import matrix_from_axis_and_angle -from compas.geometry.transformations import axis_and_angle_from_matrix -from compas.geometry.transformations import matrix_from_quaternion -from compas.geometry.transformations import matrix_from_frame -from compas.geometry.transformations import basis_vectors_from_matrix -from compas.geometry.transformations import Transformation +from .matrices import decompose_matrix +from .matrices import matrix_from_euler_angles +from .matrices import euler_angles_from_matrix +from .matrices import matrix_from_axis_and_angle +from .matrices import axis_and_angle_from_matrix +from .matrices import matrix_from_quaternion +from .matrices import matrix_from_frame +from .matrices import basis_vectors_from_matrix + +from .transformation import Transformation class Rotation(Transformation): diff --git a/src/compas/geometry/transformations/scale.py b/src/compas/geometry/transformations/scale.py index 61900860daf..ba902fc4eb2 100644 --- a/src/compas/geometry/transformations/scale.py +++ b/src/compas/geometry/transformations/scale.py @@ -13,11 +13,13 @@ from compas.utilities import flatten from compas.geometry import allclose from compas.geometry import multiply_matrices -from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import matrix_from_scale_factors -from compas.geometry.transformations import matrix_from_frame -from compas.geometry.transformations import matrix_inverse -from compas.geometry.transformations import Transformation + +from .matrices import decompose_matrix +from .matrices import matrix_from_scale_factors +from .matrices import matrix_from_frame +from .matrices import matrix_inverse + +from .transformation import Transformation class Scale(Transformation): diff --git a/src/compas/geometry/transformations/shear.py b/src/compas/geometry/transformations/shear.py index 9d7a2d2adee..a81595e3d0e 100644 --- a/src/compas/geometry/transformations/shear.py +++ b/src/compas/geometry/transformations/shear.py @@ -10,12 +10,10 @@ Many thanks to Christoph Gohlke, Martin John Baker, Sachin Joglekar and Andrew Ippoliti for providing code and documentation. """ -# from compas.utilities import flatten -# from compas.geometry import allclose -# from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import matrix_from_shear_entries -from compas.geometry.transformations import matrix_from_shear -from compas.geometry.transformations import Transformation +from .matrices import matrix_from_shear_entries +from .matrices import matrix_from_shear + +from .transformation import Transformation class Shear(Transformation): diff --git a/src/compas/geometry/transformations/transformation.py b/src/compas/geometry/transformations/transformation.py index 25d1229eac5..f778cd3fe82 100644 --- a/src/compas/geometry/transformations/transformation.py +++ b/src/compas/geometry/transformations/transformation.py @@ -17,15 +17,15 @@ from compas.geometry import multiply_matrices from compas.geometry import transpose_matrix -from compas.geometry.transformations import basis_vectors_from_matrix -from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import identity_matrix -from compas.geometry.transformations import matrix_determinant -from compas.geometry.transformations import matrix_from_euler_angles -from compas.geometry.transformations import matrix_from_frame -from compas.geometry.transformations import matrix_from_translation -from compas.geometry.transformations import matrix_inverse -from compas.geometry.transformations import translation_from_matrix +from .matrices import basis_vectors_from_matrix +from .matrices import decompose_matrix +from .matrices import identity_matrix +from .matrices import matrix_determinant +from .matrices import matrix_from_euler_angles +from .matrices import matrix_from_frame +from .matrices import matrix_from_translation +from .matrices import matrix_inverse +from .matrices import translation_from_matrix class Transformation(Data): diff --git a/src/compas/geometry/transformations/transformations.py b/src/compas/geometry/transformations/transformations.py index 3a06358f87c..f232303257f 100644 --- a/src/compas/geometry/transformations/transformations.py +++ b/src/compas/geometry/transformations/transformations.py @@ -23,45 +23,10 @@ from compas.geometry import closest_point_on_plane from compas.geometry import closest_point_on_line from compas.geometry import closest_point_on_line_xy -from compas.geometry import intersection_line_plane -from compas.geometry import intersection_line_triangle - -from compas.geometry.transformations import matrix_from_axis_and_angle -from compas.geometry.transformations import matrix_from_scale_factors -from compas.geometry.transformations import matrix_from_change_of_basis - - -__all__ = [ - "local_axes", - "orthonormalize_axes", - "transform_points", - "transform_vectors", - "transform_frames", - "local_to_world_coordinates", - "world_to_local_coordinates", - "translate_points", - "translate_points_xy", - "scale_points", - "scale_points_xy", - "rotate_points", - "rotate_points_xy", - "mirror_vector_vector", - "mirror_points_point", - "mirror_points_point_xy", - "mirror_points_line", - "mirror_points_line_xy", - "mirror_point_plane", - "mirror_points_plane", - "project_point_plane", - "project_points_plane", - "project_point_line", - "project_point_line_xy", - "project_points_line", - "project_points_line_xy", - "reflect_line_plane", - "reflect_line_triangle", - "orient_points", -] + +from .matrices import matrix_from_axis_and_angle +from .matrices import matrix_from_scale_factors +from .matrices import matrix_from_change_of_basis # this function will not always work @@ -1014,6 +979,8 @@ def reflect_line_plane(line, plane, tol=1e-6): ([0.0, 0.0, 0.0], [1.0, 1.0, 0.0]) """ + from compas.geometry import intersection_line_plane + x = intersection_line_plane(line, plane, tol=tol) if not x: return @@ -1064,6 +1031,8 @@ def reflect_line_triangle(line, triangle, tol=1e-6): ([0.0, 0.0, 0.0], [1.0, 1.0, 0.0]) """ + from compas.geometry import intersection_line_triangle + x = intersection_line_triangle(line, triangle, tol=tol) if not x: return diff --git a/src/compas/geometry/transformations/transformations_numpy.py b/src/compas/geometry/transformations/transformations_numpy.py index fd8b863e2c6..0d8b3190120 100644 --- a/src/compas/geometry/transformations/transformations_numpy.py +++ b/src/compas/geometry/transformations/transformations_numpy.py @@ -13,18 +13,6 @@ from compas.geometry import cross_vectors -__all__ = [ - "transform_points_numpy", - "transform_vectors_numpy", - "homogenize_numpy", - "dehomogenize_numpy", - "homogenize_and_flatten_frames_numpy", - "dehomogenize_and_unflatten_frames_numpy", - "world_to_local_coordinates_numpy", - "local_to_world_coordinates_numpy", -] - - def transform_points_numpy(points, T): """Transform multiple points with one Transformation using numpy. diff --git a/src/compas/geometry/transformations/translation.py b/src/compas/geometry/transformations/translation.py index 655115f68b0..a46a784a988 100644 --- a/src/compas/geometry/transformations/translation.py +++ b/src/compas/geometry/transformations/translation.py @@ -12,9 +12,11 @@ """ from compas.utilities import flatten from compas.geometry import allclose -from compas.geometry.transformations import decompose_matrix -from compas.geometry.transformations import matrix_from_translation -from compas.geometry.transformations import Transformation + +from .matrices import decompose_matrix +from .matrices import matrix_from_translation + +from .transformation import Transformation class Translation(Transformation): diff --git a/src/compas/geometry/triangulation/__init__.py b/src/compas/geometry/triangulation/__init__.py index ce563753ccd..87b98b9116d 100644 --- a/src/compas/geometry/triangulation/__init__.py +++ b/src/compas/geometry/triangulation/__init__.py @@ -2,14 +2,8 @@ from __future__ import division from __future__ import print_function -import compas from compas.plugins import pluggable -from .delaunay import * # noqa: F401 F403 - -if not compas.IPY: - from .delaunay_numpy import * # noqa: F401 F403 - @pluggable(category="triangulation") def delaunay_triangulation(points): @@ -96,6 +90,3 @@ def conforming_delaunay_triangulation(boundary, polylines=None, polygons=None, a """ raise NotImplementedError - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/triangulation/delaunay.py b/src/compas/geometry/triangulation/delaunay.py index 4b0f8eb7105..c1286118c4b 100644 --- a/src/compas/geometry/triangulation/delaunay.py +++ b/src/compas/geometry/triangulation/delaunay.py @@ -16,11 +16,6 @@ from compas.geometry import circle_from_points_xy -__all__ = [ - "delaunay_from_points", -] - - def delaunay_from_points(points, boundary=None, holes=None, tiny=1e-12): """Computes the delaunay triangulation for a list of points. diff --git a/src/compas/geometry/triangulation/delaunay_numpy.py b/src/compas/geometry/triangulation/delaunay_numpy.py index 6dbb7cce1bb..d9eef25ccad 100644 --- a/src/compas/geometry/triangulation/delaunay_numpy.py +++ b/src/compas/geometry/triangulation/delaunay_numpy.py @@ -7,12 +7,6 @@ from scipy.spatial import Delaunay -__all__ = [ - "delaunay_from_points_numpy", - "voronoi_from_points_numpy", -] - - def delaunay_from_points_numpy(points): """Computes the delaunay triangulation for a list of points using Numpy. diff --git a/src/compas/geometry/trimesh/__init__.py b/src/compas/geometry/trimesh/__init__.py index 566670e59d5..e69de29bb2d 100644 --- a/src/compas/geometry/trimesh/__init__.py +++ b/src/compas/geometry/trimesh/__init__.py @@ -1,14 +0,0 @@ -from __future__ import print_function -from __future__ import absolute_import -from __future__ import division - -from .curvature import * # noqa: F401 F403 -from .geodistance import * # noqa: F401 F403 -from .isolines import * # noqa: F401 F403 -from .matrices import * # noqa: F401 F403 -from .parametrisation import * # noqa: F401 F403 -from .remesh import * # noqa: F401 F403 -from .slicing import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/geometry/trimesh/curvature.py b/src/compas/geometry/trimesh/curvature.py index 925bb9ce2db..1e0f688a055 100644 --- a/src/compas/geometry/trimesh/curvature.py +++ b/src/compas/geometry/trimesh/curvature.py @@ -5,13 +5,6 @@ from compas.plugins import pluggable -__all__ = [ - "trimesh_gaussian_curvature", - "trimesh_mean_curvature", - "trimesh_principal_curvature", -] - - @pluggable(category="trimesh") def trimesh_gaussian_curvature(M): """Compute the discrete gaussian curvature of a triangle mesh. diff --git a/src/compas/geometry/trimesh/geodistance.py b/src/compas/geometry/trimesh/geodistance.py index 0880852da8e..513aab0c516 100644 --- a/src/compas/geometry/trimesh/geodistance.py +++ b/src/compas/geometry/trimesh/geodistance.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["trimesh_geodistance"] - - @pluggable(category="trimesh") def trimesh_geodistance(M, source, method="exact"): """Compute the geodesic distance from every vertex of the mesh to a source vertex. diff --git a/src/compas/geometry/trimesh/isolines.py b/src/compas/geometry/trimesh/isolines.py index 12317874937..4b0ecb0a3c4 100644 --- a/src/compas/geometry/trimesh/isolines.py +++ b/src/compas/geometry/trimesh/isolines.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["trimesh_isolines"] - - @pluggable(category="trimesh") def trimesh_isolines(M, S, N=50): """Compute isolines on a triangle mesh using a scalarfield of data points diff --git a/src/compas/geometry/trimesh/matrices.py b/src/compas/geometry/trimesh/matrices.py index 9e37f98480e..d1aa7cc1501 100644 --- a/src/compas/geometry/trimesh/matrices.py +++ b/src/compas/geometry/trimesh/matrices.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["trimesh_massmatrix"] - - @pluggable(category="trimesh") def trimesh_massmatrix(M): """Compute massmatrix on a triangle mesh using a scalarfield of data points diff --git a/src/compas/geometry/trimesh/parametrisation.py b/src/compas/geometry/trimesh/parametrisation.py index 8c4d139bab5..fd62c4c0c56 100644 --- a/src/compas/geometry/trimesh/parametrisation.py +++ b/src/compas/geometry/trimesh/parametrisation.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["trimesh_harmonic", "trimesh_lscm"] - - @pluggable(category="trimesh") def trimesh_harmonic(M): """Compute the harmonic parametrisation of a triangle mesh within a fixed circular boundary. diff --git a/src/compas/geometry/trimesh/remesh.py b/src/compas/geometry/trimesh/remesh.py index 635b7b8528d..1879adf518c 100644 --- a/src/compas/geometry/trimesh/remesh.py +++ b/src/compas/geometry/trimesh/remesh.py @@ -5,13 +5,6 @@ from compas.plugins import pluggable -__all__ = [ - "trimesh_remesh", - "trimesh_remesh_constrained", - "trimesh_remesh_along_isoline", -] - - @pluggable(category="trimesh") def trimesh_remesh(mesh, target_edge_length, number_of_iterations=10, do_project=True): """Remeshing of a triangle mesh. diff --git a/src/compas/geometry/trimesh/slicing.py b/src/compas/geometry/trimesh/slicing.py index 0de83ee4033..635f430a000 100644 --- a/src/compas/geometry/trimesh/slicing.py +++ b/src/compas/geometry/trimesh/slicing.py @@ -5,9 +5,6 @@ from compas.plugins import pluggable -__all__ = ["trimesh_slice"] - - @pluggable(category="trimesh") def trimesh_slice(mesh, planes): """Slice a mesh by a list of planes. diff --git a/src/compas/numerical/__init__.py b/src/compas/numerical/__init__.py index c8465fd85b1..fa1bf596f23 100644 --- a/src/compas/numerical/__init__.py +++ b/src/compas/numerical/__init__.py @@ -141,17 +141,17 @@ unset_array_print_precision, ) -if not compas.IPY: - from .descent import descent_numpy - from .topop import topop_numpy - from .pca import pca_numpy - from .fd import fd_numpy - from .dr import dr_numpy - from .devo import devo_numpy - from .isolines import scalarfield_contours_numpy - -from .dr import dr # noqa: E402 -from .ga import ga, moga # noqa: E402 + from .descent.descent_numpy import descent_numpy + from .topop.topop_numpy import topop_numpy + from .pca.pca_numpy import pca_numpy + from .fd.fd_numpy import fd_numpy + from .dr.dr_numpy import dr_numpy + from .devo.devo_numpy import devo_numpy + from .isolines.isolines_numpy import scalarfield_contours_numpy + +from .dr.dr import dr +from .ga.ga import ga +from .ga.moga import moga __all__ = [ "dr", diff --git a/src/compas/numerical/descent/__init__.py b/src/compas/numerical/descent/__init__.py index 9865acec0e0..e69de29bb2d 100644 --- a/src/compas/numerical/descent/__init__.py +++ b/src/compas/numerical/descent/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .descent_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/descent/descent_numpy.py b/src/compas/numerical/descent/descent_numpy.py index 937c81acf9c..3a79da3d1c4 100644 --- a/src/compas/numerical/descent/descent_numpy.py +++ b/src/compas/numerical/descent/descent_numpy.py @@ -19,9 +19,6 @@ e = sqrt(eps) -__all__ = ["descent_numpy"] - - def descent_numpy(x0, fn, iterations=1000, gtol=10 ** (-6), bounds=None, limit=0, args=()): """A gradient descent optimisation solver. @@ -75,7 +72,6 @@ def phi(x, mu, *args): mu = 1 while i < iterations: - p0 = phi(x0, mu, *args) for j in range(n): diff --git a/src/compas/numerical/devo/__init__.py b/src/compas/numerical/devo/__init__.py index 251c10ed5d7..e69de29bb2d 100644 --- a/src/compas/numerical/devo/__init__.py +++ b/src/compas/numerical/devo/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .devo_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/devo/devo_numpy.py b/src/compas/numerical/devo/devo_numpy.py index 64613546149..d3a010f4da6 100644 --- a/src/compas/numerical/devo/devo_numpy.py +++ b/src/compas/numerical/devo/devo_numpy.py @@ -24,9 +24,6 @@ from time import time -__all__ = ["devo_numpy"] - - def devo_numpy( fn, bounds, diff --git a/src/compas/numerical/dr/__init__.py b/src/compas/numerical/dr/__init__.py index 40a05fc13ec..e69de29bb2d 100644 --- a/src/compas/numerical/dr/__init__.py +++ b/src/compas/numerical/dr/__init__.py @@ -1,13 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -from .dr import * # noqa: F401 F403 - -if not compas.IPY: - from .dr_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/dr/dr_numpy.py b/src/compas/numerical/dr/dr_numpy.py index 89bb1091eda..762f0fddee8 100644 --- a/src/compas/numerical/dr/dr_numpy.py +++ b/src/compas/numerical/dr/dr_numpy.py @@ -14,9 +14,6 @@ from compas.numerical import normrow -__all__ = ["dr_numpy"] - - K = [ [0.0], [0.5, 0.5], diff --git a/src/compas/numerical/fd/__init__.py b/src/compas/numerical/fd/__init__.py index 30ab16da816..e69de29bb2d 100644 --- a/src/compas/numerical/fd/__init__.py +++ b/src/compas/numerical/fd/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .fd_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/fd/fd_numpy.py b/src/compas/numerical/fd/fd_numpy.py index a4a222db9c1..78ec138441c 100644 --- a/src/compas/numerical/fd/fd_numpy.py +++ b/src/compas/numerical/fd/fd_numpy.py @@ -10,9 +10,6 @@ from compas.numerical import normrow -__all__ = ["fd_numpy"] - - def fd_numpy(vertices, edges, fixed, q, loads, **kwargs): """Implementation of the force density method to compute equilibrium of axial force networks. diff --git a/src/compas/numerical/ga/__init__.py b/src/compas/numerical/ga/__init__.py index b813f940aa2..e69de29bb2d 100644 --- a/src/compas/numerical/ga/__init__.py +++ b/src/compas/numerical/ga/__init__.py @@ -1,10 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - - -from .ga import * # noqa: F401 F403 -from .moga import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/ga/ga.py b/src/compas/numerical/ga/ga.py index 80b45de9aa4..a9b597c5042 100644 --- a/src/compas/numerical/ga/ga.py +++ b/src/compas/numerical/ga/ga.py @@ -8,9 +8,6 @@ import copy -__all__ = ["ga"] - - TPL = """ GA summary ========== @@ -298,7 +295,6 @@ def ga_optimize(self): start_gen_number = 0 for generation in range(start_gen_number, self.num_gen): - self.current_pop["decoded"] = self.decode_binary_pop(self.current_pop["binary"]) self.current_pop["scaled"] = self.scale_population(self.current_pop["decoded"]) diff --git a/src/compas/numerical/ga/moga.py b/src/compas/numerical/ga/moga.py index 8453378e2f9..06b83d618bd 100644 --- a/src/compas/numerical/ga/moga.py +++ b/src/compas/numerical/ga/moga.py @@ -7,9 +7,6 @@ import json -__all__ = ["moga"] - - TPL = """ ================================================================================ MOGA summary diff --git a/src/compas/numerical/isolines/__init__.py b/src/compas/numerical/isolines/__init__.py index 49b1fca4287..e69de29bb2d 100644 --- a/src/compas/numerical/isolines/__init__.py +++ b/src/compas/numerical/isolines/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .isolines_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/isolines/isolines_numpy.py b/src/compas/numerical/isolines/isolines_numpy.py index 12f002da960..567e6a44c63 100644 --- a/src/compas/numerical/isolines/isolines_numpy.py +++ b/src/compas/numerical/isolines/isolines_numpy.py @@ -11,11 +11,6 @@ import matplotlib.pyplot as plt -__all__ = [ - "scalarfield_contours_numpy", -] - - # def trimesh_descent(trimesh): # """""" # vertices, faces = trimesh.to_vertices_and_faces() diff --git a/src/compas/numerical/lma/__init__.py b/src/compas/numerical/lma/__init__.py index 9dbd96b5920..e69de29bb2d 100644 --- a/src/compas/numerical/lma/__init__.py +++ b/src/compas/numerical/lma/__init__.py @@ -1,11 +0,0 @@ -# from __future__ import absolute_import -# from __future__ import division -# from __future__ import print_function - -# import compas - -# if not compas.IPY: -# from .lma_numpy import * # noqa: F401 F403 - - -# __all__ = [name for name in dir() if not name.startswith('_')] diff --git a/src/compas/numerical/mma/__init__.py b/src/compas/numerical/mma/__init__.py index e526048917b..e69de29bb2d 100644 --- a/src/compas/numerical/mma/__init__.py +++ b/src/compas/numerical/mma/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .mma_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/mma/mma_numpy.py b/src/compas/numerical/mma/mma_numpy.py index fed322f869d..7b5f2f9ace2 100644 --- a/src/compas/numerical/mma/mma_numpy.py +++ b/src/compas/numerical/mma/mma_numpy.py @@ -3,8 +3,5 @@ from __future__ import print_function -__all__ = ["mma_numpy"] - - def mma_numpy(): raise NotImplementedError diff --git a/src/compas/numerical/pca/__init__.py b/src/compas/numerical/pca/__init__.py index 4ab1b16da3e..e69de29bb2d 100644 --- a/src/compas/numerical/pca/__init__.py +++ b/src/compas/numerical/pca/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .pca_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/pca/pca_numpy.py b/src/compas/numerical/pca/pca_numpy.py index efcf64173e0..9ba2856b562 100644 --- a/src/compas/numerical/pca/pca_numpy.py +++ b/src/compas/numerical/pca/pca_numpy.py @@ -6,9 +6,6 @@ from scipy.linalg import svd -__all__ = ["pca_numpy"] - - def pca_numpy(data): """Compute the principle components of a set of data points. diff --git a/src/compas/numerical/topop/__init__.py b/src/compas/numerical/topop/__init__.py index 1e5640eef51..e69de29bb2d 100644 --- a/src/compas/numerical/topop/__init__.py +++ b/src/compas/numerical/topop/__init__.py @@ -1,11 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .topop_numpy import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/numerical/topop/topop_numpy.py b/src/compas/numerical/topop/topop_numpy.py index 0a63adbd3b0..76a3d0026a5 100644 --- a/src/compas/numerical/topop/topop_numpy.py +++ b/src/compas/numerical/topop/topop_numpy.py @@ -29,9 +29,6 @@ from scipy.sparse.linalg import spsolve -__all__ = ["topop_numpy"] - - def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, callback=None): """Topology optimisation in 2D. @@ -104,7 +101,6 @@ def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, cal fixed = [] for support, B in supports.items(): - jb, ib = [int(i) for i in support.split("-")] Bx, By = B node = int(jb * ny + ib) @@ -123,7 +119,6 @@ def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, cal cols = [] for load, P in loads.items(): - jp, ip = [int(i) for i in load.split("-")] Px, Py = P node = int(jp * ny + ip) @@ -143,12 +138,10 @@ def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, cal k = 0 for i1 in range(nelx): - max_i = int(max([i1 - (ceil(rmin) - 1), 0])) min_i = int(min([i1 + (ceil(rmin) - 1), nelx - 1])) for j1 in range(nely): - max_j = int(max([j1 - (ceil(rmin) - 1), 0])) min_j = int(min([j1 + (ceil(rmin) - 1), nely - 1])) @@ -176,7 +169,6 @@ def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, cal nones = ones((ne)) * 0.001 while change > 0.1: - # FE xrav = ravel(xP, order="F").transpose() @@ -203,7 +195,6 @@ def topop_numpy(nelx, nely, loads, supports, volfrac=0.5, penal=3, rmin=1.5, cal l2 = 10**9 while (l2 - l1) / (l1 + l2) > 0.001: - lmid = 0.5 * (l2 + l1) sdv = sqrt(-dc / dv / lmid) min1 = minimum(x + move, x * sdv) diff --git a/tests/gen.py b/tests/gen.py deleted file mode 100644 index 7c38b0de3cd..00000000000 --- a/tests/gen.py +++ /dev/null @@ -1,23 +0,0 @@ -from compas.geometry.transformations import ( - transformations as src, -) # change this line to different modules - - -temp = "" -print(src.__all__) - -for func in src.__all__: - temp += "from compas.geometry.transformations import {}\n".format(func) - -temp += "\n\n" - -for func in src.__all__: - temp += """ -def test_{}(): - pass - -""".format( - func - ) - -print(temp) From 5c3811839be8d66f26053445c0236ecb2e62afdf Mon Sep 17 00:00:00 2001 From: brgcode Date: Wed, 10 May 2023 22:06:57 +0200 Subject: [PATCH 023/150] all done --- src/compas/robots/__init__.py | 49 +++++------------------- src/compas/robots/configuration.py | 5 --- src/compas/robots/model/__init__.py | 12 ------ src/compas/robots/model/base.py | 9 +---- src/compas/robots/model/geometry.py | 25 ++++-------- src/compas/robots/model/joint.py | 22 +++-------- src/compas/robots/model/link.py | 30 +++++++-------- src/compas/robots/model/robot.py | 34 ++++++++-------- src/compas/robots/model/tool.py | 3 +- src/compas/robots/resources/__init__.py | 8 ---- src/compas/robots/resources/basic.py | 6 +-- src/compas/robots/resources/github.py | 8 ++-- src/compas/topology/combinatorics.py | 2 +- src/compas/topology/orientation.py | 2 +- src/compas/topology/orientation_numpy.py | 2 +- src/compas/topology/orientation_rhino.py | 2 +- src/compas/utilities/azync.py | 3 -- src/compas/utilities/coercing.py | 13 ------- src/compas/utilities/datetime.py | 3 -- src/compas/utilities/decorators.py | 8 ---- src/compas/utilities/descriptors.py | 6 --- src/compas/utilities/encoders.py | 1 - src/compas/utilities/images.py | 3 -- src/compas/utilities/itertools.py | 13 ------- src/compas/utilities/maps.py | 7 ---- src/compas/utilities/remote.py | 3 -- src/compas/utilities/ssh.py | 3 -- src/compas/utilities/xfunc.py | 3 -- 28 files changed, 67 insertions(+), 218 deletions(-) diff --git a/src/compas/robots/__init__.py b/src/compas/robots/__init__.py index 67a3e78d409..162301387aa 100644 --- a/src/compas/robots/__init__.py +++ b/src/compas/robots/__init__.py @@ -115,45 +115,16 @@ from __future__ import absolute_import from .configuration import Configuration -from .model import ( - Axis, - Calibration, - ChildLink, - Collision, - Color, - Dynamics, - Geometry, - Inertia, - Inertial, - Joint, - Limit, - Link, - Mass, - Material, - MeshDescriptor, - Mimic, - ParentLink, - RobotModel, - SafetyController, - Texture, - ToolModel, - Visual, -) -from .resources import ( - AbstractMeshLoader, - DefaultMeshLoader, - GithubPackageMeshLoader, - LocalPackageMeshLoader, -) - -# Deprecated aliases -from .model import ( - Origin, - Box, - Capsule, - Cylinder, - Sphere, -) + +from .resources.basic import AbstractMeshLoader, DefaultMeshLoader, LocalPackageMeshLoader +from .resources.github import GithubPackageMeshLoader + +# from .model.base import FrameProxy, ProxyObject +from .model.geometry import Box, Capsule, Color, Cylinder, Geometry, Material, MeshDescriptor, Origin, Sphere, Texture +from .model.joint import Axis, Calibration, ChildLink, Dynamics, Joint, Limit, Mimic, ParentLink, SafetyController +from .model.link import Collision, Inertia, Inertial, Link, Mass, Visual +from .model.robot import RobotModel +from .model.tool import ToolModel __all__ = [ "Geometry", diff --git a/src/compas/robots/configuration.py b/src/compas/robots/configuration.py index 4f100d9f229..64915a8c644 100644 --- a/src/compas/robots/configuration.py +++ b/src/compas/robots/configuration.py @@ -7,11 +7,6 @@ from compas.data import Data -__all__ = [ - "Configuration", - "FixedLengthList", -] - # These joint types known to configuration are a match # to the ones defined in `Joint` class, but we redefine here # to avoid a circular dependency diff --git a/src/compas/robots/model/__init__.py b/src/compas/robots/model/__init__.py index 622c4b19953..e69de29bb2d 100644 --- a/src/compas/robots/model/__init__.py +++ b/src/compas/robots/model/__init__.py @@ -1,12 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .base import * # noqa: F401 F403 -from .geometry import * # noqa: F401 F403 -from .joint import * # noqa: F401 F403 -from .link import * # noqa: F401 F403 -from .robot import * # noqa: F401 F403 -from .tool import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/robots/model/base.py b/src/compas/robots/model/base.py index 3f7fba88b41..4381acd225e 100644 --- a/src/compas/robots/model/base.py +++ b/src/compas/robots/model/base.py @@ -2,15 +2,10 @@ from __future__ import division from __future__ import print_function -from compas.files.urdf import URDFElement -from compas.files.urdf import URDFGenericElement +from compas.files import URDFElement +from compas.files import URDFGenericElement from compas.geometry import Frame -__all__ = [ - "FrameProxy", - "ProxyObject", -] - def _parse_floats(values): return [float(i) for i in values.split()] diff --git a/src/compas/robots/model/geometry.py b/src/compas/robots/model/geometry.py index c2daa2a1291..e0e91225b55 100644 --- a/src/compas/robots/model/geometry.py +++ b/src/compas/robots/model/geometry.py @@ -5,27 +5,16 @@ import compas import compas.colors import compas.geometry + from compas.data import Data from compas.datastructures import Mesh -from compas.files.urdf import URDFElement +from compas.files import URDFElement from compas.geometry import Frame -from compas.robots.model.base import ProxyObject -from compas.robots.model.base import _attr_from_data -from compas.robots.model.base import _attr_to_data -from compas.robots.model.base import _parse_floats - -__all__ = [ - "Geometry", - "MeshDescriptor", - "Color", - "Texture", - "Material", - "Origin", - "Cylinder", - "Box", - "Sphere", - "Capsule", -] + +from .base import ProxyObject +from .base import _attr_from_data +from .base import _attr_to_data +from .base import _parse_floats class BoxProxy(ProxyObject): diff --git a/src/compas/robots/model/joint.py b/src/compas/robots/model/joint.py index 267c020c3bf..16d6f02fa6a 100644 --- a/src/compas/robots/model/joint.py +++ b/src/compas/robots/model/joint.py @@ -11,22 +11,11 @@ from compas.geometry import Translation from compas.geometry import Vector from compas.geometry import transform_vectors -from compas.robots.model.base import FrameProxy -from compas.robots.model.base import _attr_from_data -from compas.robots.model.base import _attr_to_data -from compas.robots.model.base import _parse_floats - -__all__ = [ - "Joint", - "ParentLink", - "ChildLink", - "Calibration", - "Dynamics", - "Limit", - "Axis", - "Mimic", - "SafetyController", -] + +from .base import FrameProxy +from .base import _attr_from_data +from .base import _attr_to_data +from .base import _parse_floats class ParentLink(Data): @@ -489,7 +478,6 @@ def __init__( mimic=None, **kwargs ): - type_idx = type if isinstance(type_idx, str) and type_idx in Joint.SUPPORTED_TYPES: diff --git a/src/compas/robots/model/link.py b/src/compas/robots/model/link.py index 2017a131a27..2c5c2f5b36e 100644 --- a/src/compas/robots/model/link.py +++ b/src/compas/robots/model/link.py @@ -11,20 +11,20 @@ from compas.geometry import Frame from compas.geometry import Sphere from compas.geometry import Transformation -from compas.robots.model.base import FrameProxy -from compas.robots.model.base import _attr_from_data -from compas.robots.model.base import _attr_to_data -from compas.robots.model.geometry import BoxProxy -from compas.robots.model.geometry import CapsuleProxy -from compas.robots.model.geometry import Color -from compas.robots.model.geometry import CylinderProxy -from compas.robots.model.geometry import Geometry -from compas.robots.model.geometry import Material -from compas.robots.model.geometry import MeshDescriptor -from compas.robots.model.geometry import SphereProxy -from compas.robots.model.geometry import Texture - -__all__ = ["Link", "Inertial", "Visual", "Collision", "Mass", "Inertia"] + +from .base import FrameProxy +from .base import _attr_from_data +from .base import _attr_to_data + +from .geometry import BoxProxy +from .geometry import CapsuleProxy +from .geometry import Color +from .geometry import CylinderProxy +from .geometry import Geometry +from .geometry import Material +from .geometry import MeshDescriptor +from .geometry import SphereProxy +from .geometry import Texture class Mass(Data): @@ -444,7 +444,7 @@ def data(self): @data.setter def data(self, data): - from compas.robots.model.joint import Joint + from .joint import Joint self.name = data["name"] self.type = data["type"] diff --git a/src/compas/robots/model/robot.py b/src/compas/robots/model/robot.py index aea4a8efbc9..b7a7617a477 100644 --- a/src/compas/robots/model/robot.py +++ b/src/compas/robots/model/robot.py @@ -13,25 +13,25 @@ from compas.files import URDFParser from compas.geometry import Frame from compas.geometry import Transformation -from compas.robots import Configuration -from compas.robots.model.base import _attr_from_data -from compas.robots.model.base import _attr_to_data -from compas.robots.model.geometry import Color -from compas.robots.model.geometry import Geometry -from compas.robots.model.geometry import Material -from compas.robots.model.geometry import MeshDescriptor -from compas.robots.model.geometry import Texture -from compas.robots.model.joint import Axis -from compas.robots.model.joint import Joint -from compas.robots.model.joint import Limit -from compas.robots.model.link import Collision -from compas.robots.model.link import Link -from compas.robots.model.link import Visual -from compas.robots.resources import DefaultMeshLoader -from compas.robots.resources import LocalPackageMeshLoader from compas.topology import shortest_path -__all__ = ["RobotModel"] +from compas.robots import Configuration +from compas.robots import DefaultMeshLoader +from compas.robots import LocalPackageMeshLoader + +from .base import _attr_from_data +from .base import _attr_to_data +from .geometry import Color +from .geometry import Geometry +from .geometry import Material +from .geometry import MeshDescriptor +from .geometry import Texture +from .joint import Axis +from .joint import Joint +from .joint import Limit +from .link import Collision +from .link import Link +from .link import Visual class RobotModel(Data): diff --git a/src/compas/robots/model/tool.py b/src/compas/robots/model/tool.py index 31c75e1d4ae..47969ea89d0 100644 --- a/src/compas/robots/model/tool.py +++ b/src/compas/robots/model/tool.py @@ -4,7 +4,8 @@ from compas.geometry import Frame from compas.geometry import Transformation -from compas.robots.model.robot import RobotModel + +from .robot import RobotModel class ToolModel(RobotModel): diff --git a/src/compas/robots/resources/__init__.py b/src/compas/robots/resources/__init__.py index 34d26f4d592..e69de29bb2d 100644 --- a/src/compas/robots/resources/__init__.py +++ b/src/compas/robots/resources/__init__.py @@ -1,8 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from .basic import * # noqa: F401 F403 -from .github import * # noqa: F401 F403 - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas/robots/resources/basic.py b/src/compas/robots/resources/basic.py index 940080dc2dc..24da80cb33b 100644 --- a/src/compas/robots/resources/basic.py +++ b/src/compas/robots/resources/basic.py @@ -4,15 +4,13 @@ import os -from compas.datastructures import Mesh - -__all__ = ["AbstractMeshLoader", "DefaultMeshLoader", "LocalPackageMeshLoader"] - try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse +from compas.datastructures import Mesh + SUPPORTED_FORMATS = ("obj", "stl", "ply") diff --git a/src/compas/robots/resources/github.py b/src/compas/robots/resources/github.py index 2dfd7490943..0d7d5e979fb 100644 --- a/src/compas/robots/resources/github.py +++ b/src/compas/robots/resources/github.py @@ -2,16 +2,14 @@ from __future__ import division from __future__ import print_function -from compas.robots.resources.basic import AbstractMeshLoader -from compas.robots.resources.basic import _mesh_import - -__all__ = ["GithubPackageMeshLoader"] - try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen +from .basic import AbstractMeshLoader +from .basic import _mesh_import + class GithubPackageMeshLoader(AbstractMeshLoader): """Loads resources stored in Github. diff --git a/src/compas/topology/combinatorics.py b/src/compas/topology/combinatorics.py index 725bc2722ee..eb7e6808669 100644 --- a/src/compas/topology/combinatorics.py +++ b/src/compas/topology/combinatorics.py @@ -3,7 +3,7 @@ from __future__ import division from collections import deque -from compas.topology import breadth_first_traverse +from compas.topology.traversal import breadth_first_traverse def vertex_coloring(adjacency): diff --git a/src/compas/topology/orientation.py b/src/compas/topology/orientation.py index 194c146b791..4e46d4cb62f 100644 --- a/src/compas/topology/orientation.py +++ b/src/compas/topology/orientation.py @@ -6,7 +6,7 @@ from compas.utilities import pairwise from compas.geometry import centroid_points -from compas.topology import breadth_first_traverse +from compas.topology.traversal import breadth_first_traverse def unify_cycles(vertices, faces, root=0): diff --git a/src/compas/topology/orientation_numpy.py b/src/compas/topology/orientation_numpy.py index 283f2b79e3e..13655f1c5b6 100644 --- a/src/compas/topology/orientation_numpy.py +++ b/src/compas/topology/orientation_numpy.py @@ -6,7 +6,7 @@ from compas.utilities import pairwise from compas.geometry import centroid_points -from compas.topology import breadth_first_traverse +from compas.topology.traversal import breadth_first_traverse def unify_cycles_numpy(vertices, faces, root=0): diff --git a/src/compas/topology/orientation_rhino.py b/src/compas/topology/orientation_rhino.py index fb4435c639e..a6755875258 100644 --- a/src/compas/topology/orientation_rhino.py +++ b/src/compas/topology/orientation_rhino.py @@ -8,7 +8,7 @@ from compas.utilities import pairwise from compas.geometry import centroid_points -from compas.topology import breadth_first_traverse +from compas.topology.traversal import breadth_first_traverse def unify_cycles_rhino(vertices, faces, root=0): diff --git a/src/compas/utilities/azync.py b/src/compas/utilities/azync.py index b45251774fe..8845e7f1e8b 100644 --- a/src/compas/utilities/azync.py +++ b/src/compas/utilities/azync.py @@ -6,9 +6,6 @@ import threading -__all__ = ["await_callback"] - - class ThreadExceptHookHandler(object): """Workaround to deal with a bug in the Python interpreter (!). diff --git a/src/compas/utilities/coercing.py b/src/compas/utilities/coercing.py index 90a98ef9665..a7a4dd2e3de 100644 --- a/src/compas/utilities/coercing.py +++ b/src/compas/utilities/coercing.py @@ -16,19 +16,6 @@ from compas.data.validators import is_item_iterable -__all__ = [ - "is_sequence_of_str", - "is_sequence_of_int", - "is_sequence_of_float", - "is_sequence_of_tuple", - "is_sequence_of_list", - "is_sequence_of_dict", - "is_sequence_of_iterable", - "is_item_iterable", - "coerce_sequence_of_tuple", - "coerce_sequence_of_list", -] - warnings.warn( "The coercing module in utilities is deprecated. Use the data module instead", DeprecationWarning, diff --git a/src/compas/utilities/datetime.py b/src/compas/utilities/datetime.py index 6895cf347d5..6fd18ca91dd 100644 --- a/src/compas/utilities/datetime.py +++ b/src/compas/utilities/datetime.py @@ -6,9 +6,6 @@ import datetime -__all__ = ["timestamp", "now"] - - def timestamp(): """Generate a timestamp using the current date and time. diff --git a/src/compas/utilities/decorators.py b/src/compas/utilities/decorators.py index d2c3d6cf159..c9ce27c0886 100644 --- a/src/compas/utilities/decorators.py +++ b/src/compas/utilities/decorators.py @@ -21,14 +21,6 @@ import profile as Profile -__all__ = [ - "abstractstaticmethod", - "abstractclassmethod", - "memoize", - "print_profile", -] - - class abstractstaticmethod(staticmethod): """Decorator for declaring a static method abstract. diff --git a/src/compas/utilities/descriptors.py b/src/compas/utilities/descriptors.py index 44656dfbc79..51415e4c307 100644 --- a/src/compas/utilities/descriptors.py +++ b/src/compas/utilities/descriptors.py @@ -5,12 +5,6 @@ import warnings -__all__ = [ - "Float", - "RGBColour", -] - - class Float(object): def __init__(self): warnings.warn("This class will be removed.", DeprecationWarning) diff --git a/src/compas/utilities/encoders.py b/src/compas/utilities/encoders.py index ea1f21dbb12..0d560cc9919 100644 --- a/src/compas/utilities/encoders.py +++ b/src/compas/utilities/encoders.py @@ -7,7 +7,6 @@ from compas.data import DataEncoder from compas.data import DataDecoder -__all__ = ["DataEncoder", "DataDecoder"] warnings.warn( "The encoders module in utilities is deprecated. Use the encoders module from data instead", diff --git a/src/compas/utilities/images.py b/src/compas/utilities/images.py index d191712e15b..b3cb30e3f0b 100644 --- a/src/compas/utilities/images.py +++ b/src/compas/utilities/images.py @@ -9,9 +9,6 @@ import imageio -__all__ = ["gif_from_images"] - - def gif_from_images( files, gif_path, diff --git a/src/compas/utilities/itertools.py b/src/compas/utilities/itertools.py index a776c9ec951..89419f5a0ac 100644 --- a/src/compas/utilities/itertools.py +++ b/src/compas/utilities/itertools.py @@ -15,19 +15,6 @@ from itertools import izip_longest as zip_longest -__all__ = [ - "normalize_values", - "remap_values", - "meshgrid", - "linspace", - "flatten", - "pairwise", - "window", - "iterable_like", - "grouper", -] - - def normalize_values(values, new_min=0.0, new_max=1.0): """Normalize a list of numbers to the range between new_min and new_max. diff --git a/src/compas/utilities/maps.py b/src/compas/utilities/maps.py index 9e6c25f6807..c60e1607d91 100644 --- a/src/compas/utilities/maps.py +++ b/src/compas/utilities/maps.py @@ -5,13 +5,6 @@ import compas -__all__ = [ - "geometric_key", - "reverse_geometric_key", - "geometric_key_xy", -] - - def geometric_key(xyz, precision=None, sanitize=True): """Convert XYZ coordinates to a string that can be used as a dict key. diff --git a/src/compas/utilities/remote.py b/src/compas/utilities/remote.py index 07b8dafa58b..2845f1be701 100644 --- a/src/compas/utilities/remote.py +++ b/src/compas/utilities/remote.py @@ -24,9 +24,6 @@ # raise -__all__ = ["download_file_from_remote"] - - def download_file_from_remote(source, target, overwrite=True): """Download a file from a remote source and save it to a local destination. diff --git a/src/compas/utilities/ssh.py b/src/compas/utilities/ssh.py index e926c72450c..8ae61721185 100644 --- a/src/compas/utilities/ssh.py +++ b/src/compas/utilities/ssh.py @@ -11,9 +11,6 @@ import os -__all__ = ["SSH"] - - class SSH(object): """Initialse an SSH object. diff --git a/src/compas/utilities/xfunc.py b/src/compas/utilities/xfunc.py index 023e5a091dd..938941f523c 100644 --- a/src/compas/utilities/xfunc.py +++ b/src/compas/utilities/xfunc.py @@ -27,9 +27,6 @@ compas.raise_if_ironpython() -__all__ = ["XFunc"] - - WRAPPER = """ import os import sys From bc3714fccd9a77ad729831c89b2b211b203306f0 Mon Sep 17 00:00:00 2001 From: brgcode Date: Sat, 20 May 2023 10:23:22 +0200 Subject: [PATCH 024/150] blender and rhino --- src/compas_blender/utilities/collections.py | 10 ------ src/compas_blender/utilities/data.py | 5 --- src/compas_blender/utilities/drawing.py | 18 ---------- src/compas_blender/utilities/misc.py | 5 --- src/compas_blender/utilities/objects.py | 11 ------- src/compas_rhino/forms/__init__.py | 8 ++--- src/compas_rhino/forms/etoforms/__init__.py | 33 ------------------- src/compas_rhino/forms/etoforms/image.py | 3 -- .../forms/etoforms/propertylist.py | 3 -- src/compas_rhino/forms/etoforms/settings.py | 3 -- src/compas_rhino/forms/etoforms/text.py | 3 -- src/compas_rhino/geometry/__init__.py | 18 +++++----- .../geometry/booleans/__init__.py | 7 ---- src/compas_rhino/geometry/brep/__init__.py | 20 ----------- src/compas_rhino/geometry/trimesh/__init__.py | 7 ++-- .../geometry/trimesh/curvature.py | 8 ----- src/compas_rhino/geometry/trimesh/slice.py | 5 --- 17 files changed, 17 insertions(+), 150 deletions(-) diff --git a/src/compas_blender/utilities/collections.py b/src/compas_blender/utilities/collections.py index f01c69c9baa..4c2725e7861 100644 --- a/src/compas_blender/utilities/collections.py +++ b/src/compas_blender/utilities/collections.py @@ -4,15 +4,6 @@ from compas_blender.utilities import delete_objects -__all__ = [ - "create_collection", - "create_collections", - "create_collections_from_path", - "clear_collection", - "clear_collections", -] - - def collection_path(collection, names=[]): for parent in bpy.data.collections: if collection.name in parent.children: @@ -40,7 +31,6 @@ def create_collection(name: Text, parent: bpy.types.Collection = None) -> bpy.ty return if not parent: - if name in bpy.data.collections: count = 1 newname = f"{name}.{count:04}" diff --git a/src/compas_blender/utilities/data.py b/src/compas_blender/utilities/data.py index 8ce1b865dd4..d03750cac21 100644 --- a/src/compas_blender/utilities/data.py +++ b/src/compas_blender/utilities/data.py @@ -1,11 +1,6 @@ import bpy -__all__ = [ - "delete_unused_data", -] - - def delete_unused_data(): """Delete all collections, mesh and curve objects, meshes, curves, materials. diff --git a/src/compas_blender/utilities/drawing.py b/src/compas_blender/utilities/drawing.py index b7e54f6d33c..27872124ab7 100644 --- a/src/compas_blender/utilities/drawing.py +++ b/src/compas_blender/utilities/drawing.py @@ -13,24 +13,6 @@ from compas.geometry import subtract_vectors -__all__ = [ - "draw_circles", - "draw_cylinders", - "draw_cubes", - "draw_faces", - "draw_lines", - "draw_mesh", - "draw_pipes", - "draw_planes", - "draw_pointcloud", - "draw_points", - "draw_polylines", - "draw_spheres", - "draw_texts", - "RGBColor", -] - - RGBColor = Union[Tuple[int, int, int], Tuple[float, float, float]] diff --git a/src/compas_blender/utilities/misc.py b/src/compas_blender/utilities/misc.py index 4bff1a15b84..acf68c61c3a 100644 --- a/src/compas_blender/utilities/misc.py +++ b/src/compas_blender/utilities/misc.py @@ -1,11 +1,6 @@ import sys -__all__ = [ - "unload_modules", -] - - def unload_modules(top_level_module_name): """Unloads all modules named starting with the specified string. diff --git a/src/compas_blender/utilities/objects.py b/src/compas_blender/utilities/objects.py index 61813490998..05c40e6939c 100644 --- a/src/compas_blender/utilities/objects.py +++ b/src/compas_blender/utilities/objects.py @@ -4,17 +4,6 @@ from compas_blender.utilities.data import delete_unused_data -__all__ = [ - "delete_object", - "delete_objects", - "delete_all_objects", - "delete_object_by_name", - "delete_objects_by_names", - "get_object_by_name", - "get_objects_by_names", -] - - # ============================================================================== # Delete # ============================================================================== diff --git a/src/compas_rhino/forms/__init__.py b/src/compas_rhino/forms/__init__.py index b0930dc52f7..103314bcccd 100644 --- a/src/compas_rhino/forms/__init__.py +++ b/src/compas_rhino/forms/__init__.py @@ -40,8 +40,8 @@ from .slider import SliderForm try: - from .etoforms import ImageForm - from .etoforms import TextForm + from .etoforms.image import ImageForm + from .etoforms.text import TextForm except Exception: from .image import ImageForm from .text import TextForm @@ -57,8 +57,8 @@ ] try: - from .etoforms import PropertyListForm - from .etoforms import SettingsForm + from .etoforms.propertylist import PropertyListForm + from .etoforms.settings import SettingsForm except Exception: pass else: diff --git a/src/compas_rhino/forms/etoforms/__init__.py b/src/compas_rhino/forms/etoforms/__init__.py index bee4c5b146f..e69de29bb2d 100644 --- a/src/compas_rhino/forms/etoforms/__init__.py +++ b/src/compas_rhino/forms/etoforms/__init__.py @@ -1,33 +0,0 @@ -""" -******************************************************************************** -etoforms -******************************************************************************** - -.. currentmodule:: compas_rhino.etoforms - -.. note:: - - In the future, Eto forms will be merged into the normal forms package. - -Classes -======= - -.. autosummary:: - :toctree: generated/ - :nosignatures: - - ImageForm - PropertyListForm - SettingsForm - TextForm - -""" -from __future__ import absolute_import - -from .image import * # noqa: F401 F403 -from .propertylist import * # noqa: F401 F403 -from .settings import * # noqa: F401 F403 -from .text import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith("_")] diff --git a/src/compas_rhino/forms/etoforms/image.py b/src/compas_rhino/forms/etoforms/image.py index 4ded51bf862..a1d1e30c9f4 100644 --- a/src/compas_rhino/forms/etoforms/image.py +++ b/src/compas_rhino/forms/etoforms/image.py @@ -22,9 +22,6 @@ import Eto.Forms # noqa: E402 -__all__ = ["ImageForm"] - - def image_from_remote(source): """Construct an image from a remote source. diff --git a/src/compas_rhino/forms/etoforms/propertylist.py b/src/compas_rhino/forms/etoforms/propertylist.py index bbb7b8bd908..2d36ad5875c 100644 --- a/src/compas_rhino/forms/etoforms/propertylist.py +++ b/src/compas_rhino/forms/etoforms/propertylist.py @@ -13,9 +13,6 @@ import Eto.Forms # noqa: E402 -__all__ = ["PropertyListForm"] - - class PropertyListForm(Eto.Forms.Dialog[bool]): def __init__(self, names, values, title="Properties", width=400, height=600): self.names = names diff --git a/src/compas_rhino/forms/etoforms/settings.py b/src/compas_rhino/forms/etoforms/settings.py index ebeb5af7651..a36cadb2ff5 100644 --- a/src/compas_rhino/forms/etoforms/settings.py +++ b/src/compas_rhino/forms/etoforms/settings.py @@ -15,9 +15,6 @@ import Eto.Forms # noqa: E402 -__all__ = ["SettingsForm"] - - class SettingsForm(Eto.Forms.Dialog[bool]): def __init__(self, settings, title="Settings"): # super(SettingsForm, self).__init__() diff --git a/src/compas_rhino/forms/etoforms/text.py b/src/compas_rhino/forms/etoforms/text.py index 49e966d70c0..6164144b163 100644 --- a/src/compas_rhino/forms/etoforms/text.py +++ b/src/compas_rhino/forms/etoforms/text.py @@ -13,9 +13,6 @@ import Eto.Forms # noqa: E402 -__all__ = ["TextForm"] - - class TextForm(Eto.Forms.Dialog[bool]): def __init__(self, text, title="Message"): self.text = text diff --git a/src/compas_rhino/geometry/__init__.py b/src/compas_rhino/geometry/__init__.py index 3d8e135d3d5..adbb0d3da95 100644 --- a/src/compas_rhino/geometry/__init__.py +++ b/src/compas_rhino/geometry/__init__.py @@ -83,15 +83,15 @@ from compas_rhino.conversions import RhinoSurface from compas_rhino.conversions import RhinoVector -from .curves import RhinoNurbsCurve -from .surfaces import RhinoNurbsSurface - -from .brep import RhinoBrep -from .brep import RhinoBrepLoop -from .brep import RhinoBrepVertex -from .brep import RhinoBrepFace -from .brep import RhinoBrepEdge -from .brep import RhinoBrepTrim +from .curves.nurbs import RhinoNurbsCurve +from .surfaces.nurbs import RhinoNurbsSurface + +from .brep.brep import RhinoBrep +from .brep.loop import RhinoBrepLoop +from .brep.vertex import RhinoBrepVertex +from .brep.face import RhinoBrepFace +from .brep.edge import RhinoBrepEdge +from .brep.trim import RhinoBrepTrim __all__ = [ "RhinoGeometry", diff --git a/src/compas_rhino/geometry/booleans/__init__.py b/src/compas_rhino/geometry/booleans/__init__.py index 4645c4b6c0a..969457eb117 100644 --- a/src/compas_rhino/geometry/booleans/__init__.py +++ b/src/compas_rhino/geometry/booleans/__init__.py @@ -7,13 +7,6 @@ from compas.plugins import plugin -__all__ = [ - "boolean_union_mesh_mesh", - "boolean_difference_mesh_mesh", - "boolean_intersection_mesh_mesh", -] - - @plugin(category="booleans", requires=["Rhino"]) def boolean_union_mesh_mesh(A, B, remesh=False): """Compute the boolean union of two triangle meshes. diff --git a/src/compas_rhino/geometry/brep/__init__.py b/src/compas_rhino/geometry/brep/__init__.py index 349bdcf26f1..6f9619a09f4 100644 --- a/src/compas_rhino/geometry/brep/__init__.py +++ b/src/compas_rhino/geometry/brep/__init__.py @@ -1,28 +1,8 @@ from compas.plugins import plugin - from .brep import RhinoBrep -from .face import RhinoBrepFace -from .edge import RhinoBrepEdge -from .vertex import RhinoBrepVertex -from .loop import RhinoBrepLoop -from .trim import RhinoBrepTrim - import Rhino -__all__ = [ - "RhinoBrep", - "RhinoBrepVertex", - "RhinoBrepEdge", - "RhinoBrepLoop", - "RhinoBrepFace", - "RhinoBrepTrim", - "new_brep", - "from_native", - "from_box", -] - - @plugin(category="factories", requires=["Rhino"]) def new_brep(*args, **kwargs): # Note: this is called inside Brep.__new__, thus Brep.__init__ will be ran by the interpreter diff --git a/src/compas_rhino/geometry/trimesh/__init__.py b/src/compas_rhino/geometry/trimesh/__init__.py index d459b9f5d16..9bc476dcc20 100644 --- a/src/compas_rhino/geometry/trimesh/__init__.py +++ b/src/compas_rhino/geometry/trimesh/__init__.py @@ -1,6 +1,7 @@ from __future__ import absolute_import -from .curvature import * # noqa : F401 F403 -from .slice import * # noqa : F401 F403 +from .curvature import trimesh_gaussian_curvature # noqa: F401 +from .curvature import trimesh_mean_curvature # noqa: F401 +from .curvature import trimesh_principal_curvature # noqa: F401 -__all__ = [name for name in dir() if not name.startswith("_")] +from .slice import trimesh_slice # noqa: F401 diff --git a/src/compas_rhino/geometry/trimesh/curvature.py b/src/compas_rhino/geometry/trimesh/curvature.py index f76e008a67f..5767eb3c2d6 100644 --- a/src/compas_rhino/geometry/trimesh/curvature.py +++ b/src/compas_rhino/geometry/trimesh/curvature.py @@ -17,16 +17,8 @@ from compas.plugins import plugin -__all__ = [ - "trimesh_gaussian_curvature", - "trimesh_mean_curvature", - "trimesh_principal_curvature", -] - - @plugin(category="trimesh", requires=["Rhino"]) def trimesh_gaussian_curvature(M): - r"""Compute the discrete Gaussian curvature of a triangle mesh. Parameters diff --git a/src/compas_rhino/geometry/trimesh/slice.py b/src/compas_rhino/geometry/trimesh/slice.py index adbe7682bab..f02f7cd25ba 100644 --- a/src/compas_rhino/geometry/trimesh/slice.py +++ b/src/compas_rhino/geometry/trimesh/slice.py @@ -9,11 +9,6 @@ from compas.plugins import plugin -__all__ = [ - "trimesh_slice", -] - - @plugin(category="trimesh", requires=["Rhino"]) def trimesh_slice(mesh, planes): """Slice a mesh by a list of planes. From ebecc85b3dd1d2e9acba8f9b0795a007d9bf46d4 Mon Sep 17 00:00:00 2001 From: brgcode Date: Thu, 25 May 2023 16:42:31 +0200 Subject: [PATCH 025/150] plotters --- src/compas_plotters/core/drawing.py | 16 ---------------- src/compas_plotters/core/helpers.py | 11 ----------- src/compas_plotters/core/utilities.py | 8 -------- 3 files changed, 35 deletions(-) diff --git a/src/compas_plotters/core/drawing.py b/src/compas_plotters/core/drawing.py index 14a37a8b644..ee20b494a87 100644 --- a/src/compas_plotters/core/drawing.py +++ b/src/compas_plotters/core/drawing.py @@ -16,22 +16,6 @@ from compas.utilities import color_to_rgb -__all__ = [ - "create_axes_xy", - "create_axes_3d", - "draw_points_xy", - "draw_xpoints_xy", - "draw_points_3d", - "draw_lines_xy", - "draw_xlines_xy", - "draw_lines_3d", - "draw_xarrows_xy", - "draw_xlabels_xy", - "draw_xpolygons_xy", - "draw_xpolylines_xy", -] - - ZORDER_POLYGONS = 1000 ZORDER_LINES = 2000 ZORDER_POINTS = 3000 diff --git a/src/compas_plotters/core/helpers.py b/src/compas_plotters/core/helpers.py index 6650d446674..64717bf2235 100644 --- a/src/compas_plotters/core/helpers.py +++ b/src/compas_plotters/core/helpers.py @@ -8,17 +8,6 @@ from compas_plotters.core.utilities import assert_axes_dimension -__all__ = [ - "Axes2D", - "Axes3D", - "Bounds", - "Box", - "Cloud2D", - "Cloud3D", - "Hull", -] - - class Axes2D(object): """Definition of a 2D Axes object. diff --git a/src/compas_plotters/core/utilities.py b/src/compas_plotters/core/utilities.py index 48a9b56ae78..eef1399ecc6 100644 --- a/src/compas_plotters/core/utilities.py +++ b/src/compas_plotters/core/utilities.py @@ -1,11 +1,3 @@ -__all__ = [ - "get_axes_dimension", - "assert_axes_dimension", - "width_to_dict", - "size_to_sizedict", -] - - def get_axes_dimension(axes): """Returns the number of dimensions of a matplotlib axes object. From fcd00515545bcac9cdd990e26b0f0d2d702100de Mon Sep 17 00:00:00 2001 From: brgcode Date: Thu, 25 May 2023 20:26:02 +0200 Subject: [PATCH 026/150] lint --- src/compas/utilities/coercing.py | 20 ++++++++++---------- src/compas/utilities/encoders.py | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/compas/utilities/coercing.py b/src/compas/utilities/coercing.py index a7a4dd2e3de..d77ca5f5091 100644 --- a/src/compas/utilities/coercing.py +++ b/src/compas/utilities/coercing.py @@ -4,16 +4,16 @@ import warnings -from compas.data.coercion import coerce_sequence_of_list -from compas.data.coercion import coerce_sequence_of_tuple -from compas.data.validators import is_sequence_of_str -from compas.data.validators import is_sequence_of_int -from compas.data.validators import is_sequence_of_float -from compas.data.validators import is_sequence_of_tuple -from compas.data.validators import is_sequence_of_list -from compas.data.validators import is_sequence_of_dict -from compas.data.validators import is_sequence_of_iterable -from compas.data.validators import is_item_iterable +from compas.data.coercion import coerce_sequence_of_list # noqa: F401 +from compas.data.coercion import coerce_sequence_of_tuple # noqa: F401 +from compas.data.validators import is_sequence_of_str # noqa: F401 +from compas.data.validators import is_sequence_of_int # noqa: F401 +from compas.data.validators import is_sequence_of_float # noqa: F401 +from compas.data.validators import is_sequence_of_tuple # noqa: F401 +from compas.data.validators import is_sequence_of_list # noqa: F401 +from compas.data.validators import is_sequence_of_dict # noqa: F401 +from compas.data.validators import is_sequence_of_iterable # noqa: F401 +from compas.data.validators import is_item_iterable # noqa: F401 warnings.warn( diff --git a/src/compas/utilities/encoders.py b/src/compas/utilities/encoders.py index 0d560cc9919..799f191e33b 100644 --- a/src/compas/utilities/encoders.py +++ b/src/compas/utilities/encoders.py @@ -4,8 +4,8 @@ import warnings -from compas.data import DataEncoder -from compas.data import DataDecoder +from compas.data import DataEncoder # noqa: F401 +from compas.data import DataDecoder # noqa: F401 warnings.warn( From 31fce1b03b307c85446e31b215ae4801a9404255 Mon Sep 17 00:00:00 2001 From: brgcode Date: Thu, 25 May 2023 20:29:57 +0200 Subject: [PATCH 027/150] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e23aca6e7..4000bb4112e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +* All `__all__` beyond second level package. + ## [1.17.5] 2023-02-16 From 338400b29c9a7af463c52966ed7494585046ce49 Mon Sep 17 00:00:00 2001 From: brgcode Date: Thu, 25 May 2023 22:02:46 +0200 Subject: [PATCH 028/150] working config without api --- docs/conf.py | 48 ++++++++++++++++++--------------- docs/gettingstarted/blender.rst | 6 ++--- docs/index.rst | 2 -- docs/tutorial/robots.rst | 3 +-- src/compas/geometry/__init__.py | 2 +- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 3efdfd20811..6e3a2f609e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,32 +9,33 @@ import os import inspect import importlib -import m2r2 -import sphinx_compas_theme +# import m2r2 + +# import sphinx_compas_theme from sphinx.ext.napoleon.docstring import NumpyDocstring sys.path.append(os.path.join(os.path.dirname(__file__), "_ext")) # patches -current_m2r2_setup = m2r2.setup +# current_m2r2_setup = m2r2.setup -def patched_m2r2_setup(app): - try: - return current_m2r2_setup(app) - except (AttributeError): - app.add_source_suffix(".md", "markdown") - app.add_source_parser(m2r2.M2RParser) - return dict( - version=m2r2.__version__, - parallel_read_safe=True, - parallel_write_safe=True, - ) +# def patched_m2r2_setup(app): +# try: +# return current_m2r2_setup(app) +# except AttributeError: +# app.add_source_suffix(".md", "markdown") +# app.add_source_parser(m2r2.M2RParser) +# return dict( +# version=m2r2.__version__, +# parallel_read_safe=True, +# parallel_write_safe=True, +# ) -m2r2.setup = patched_m2r2_setup +# m2r2.setup = patched_m2r2_setup # -- General configuration ------------------------------------------------ @@ -50,13 +51,13 @@ def patched_m2r2_setup(app): ".rst": "restructuredtext", ".md": "markdown", } -templates_path = sphinx_compas_theme.get_autosummary_templates_path() +# templates_path = sphinx_compas_theme.get_autosummary_templates_path() exclude_patterns = ["_build", "**.ipynb_checkpoints", "_notebooks", "**/__temp"] pygments_style = "sphinx" show_authors = True add_module_names = True -language = None +language = "en" # -- Extension configuration ------------------------------------------------ @@ -75,10 +76,12 @@ def patched_m2r2_setup(app): "sphinx.ext.inheritance_diagram", "sphinx.ext.graphviz", "matplotlib.sphinxext.plot_directive", - "m2r2", + # "m2r2", # "nbsphinx", "sphinx.ext.autodoc.typehints", - "tabs", + # "tabs", + "sphinx_inline_tabs", + "sphinx_design", ] # autodoc options @@ -288,8 +291,8 @@ def linkcode_resolve(domain, info): # -- Options for HTML output ---------------------------------------------- -html_theme = "compas" -html_theme_path = sphinx_compas_theme.get_html_theme_path() +html_theme = "furo" +# html_theme_path = sphinx_compas_theme.get_html_theme_path() html_theme_options = { "navbar_active": "compas", "package_version": release, @@ -297,7 +300,8 @@ def linkcode_resolve(domain, info): "package_old_versions_txt": "https://compas.dev/compas/doc_versions.txt", } html_context = {} -html_static_path = sphinx_compas_theme.get_html_static_path() +# html_static_path = sphinx_compas_theme.get_html_static_path() +html_static_path = ["_static"] html_extra_path = [] html_last_updated_fmt = "" html_copy_source = False diff --git a/docs/gettingstarted/blender.rst b/docs/gettingstarted/blender.rst index 2030af134e3..e97ef94dc61 100644 --- a/docs/gettingstarted/blender.rst +++ b/docs/gettingstarted/blender.rst @@ -30,10 +30,9 @@ If you don't have an environment yet with Python 3.9 and COMPAS you can create o Configuring Blender to use the newly installed environment is slightly different per OS. -.. tabs:: +.. tab-set:: .. tab-item:: Windows - :active: .. code-block:: bash @@ -132,10 +131,9 @@ On Mac or Linux, you should start Blender from the command line. By adding the Blender executable to the ``PATH`` variable this is really simple. Just add the following to your ``.bash_profile`` or ``.bashrc``. -.. tabs:: +.. tab-set:: .. tab-item:: OSX - :active: .. code-block:: bash diff --git a/docs/index.rst b/docs/index.rst index 92de8449381..0c2264865cb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,10 +36,8 @@ Table of Contents installation gettingstarted tutorial - api plugins devguide - changelog releases license citing diff --git a/docs/tutorial/robots.rst b/docs/tutorial/robots.rst index fd642b0c2cb..1a23ad19e70 100644 --- a/docs/tutorial/robots.rst +++ b/docs/tutorial/robots.rst @@ -151,10 +151,9 @@ artists. The basic procedure is the same in any of the CAD software (aside from the import statement). Below you can find an example code for both Rhino and Blender. -.. tabs:: +.. tab-set:: .. tab-item:: Rhino - :active: Be sure to first install COMPAS for Rhino. While the following code is incomplete, it can be used as a scaffolding for code to be run in a Python script editor within Rhino. diff --git a/src/compas/geometry/__init__.py b/src/compas/geometry/__init__.py index 42cdf27e75d..636f8f9e599 100644 --- a/src/compas/geometry/__init__.py +++ b/src/compas/geometry/__init__.py @@ -532,7 +532,7 @@ archimedean_spiral_evaluate circle_evaluate - ellipse_evaluate, + ellipse_evaluate helix_evaluate logarithmic_spiral_evaluate From 53c9b4e1cc3b42047bc9a8f1152563a00e8aa90a Mon Sep 17 00:00:00 2001 From: brgcode Date: Mon, 29 May 2023 11:01:33 +0200 Subject: [PATCH 029/150] book theme and furo --- docs/_static/compas.css | 7 + docs/_static/images/compas.ico | Bin 0 -> 5148 bytes docs/_static/images/compas_icon.png | Bin 0 -> 2780 bytes docs/_static/images/compas_icon_white.png | Bin 0 -> 5093 bytes docs/_static/images/compas_icon_white_48.png | Bin 0 -> 25528 bytes docs/_static/images/compas_icon_white_96.png | Bin 0 -> 52767 bytes docs/_static/images/compas_white.ico | Bin 0 -> 4856 bytes docs/_static/versions.json | 15 + docs/_templates/framework-logo.html | 3 + docs/_templates/framework-nav.html | 23 + docs/api.rst | 18 +- docs/api/compas.artists.rst | 54 +- docs/api/compas.colors.rst | 21 +- docs/api/compas.data.rst | 62 +- docs/api/compas.datastructures.rst | 195 ++++++- docs/api/compas.files.rst | 129 ++++- docs/api/compas.geometry.rst | 537 ++++++++++++++++- docs/api/compas.numerical.rst | 99 +++- docs/api/compas.plugins.rst | 39 +- docs/api/compas.robots.rst | 111 +++- docs/api/compas.rpc.rst | 38 +- docs/api/compas.rst | 24 +- docs/api/compas.topology.rst | 64 ++- docs/api/compas.utilities.rst | 80 ++- docs/api/compas_blender.artists.rst | 2 - docs/api/compas_blender.conversions.rst | 2 - docs/api/compas_blender.geometry.rst | 2 - docs/api/compas_blender.rst | 17 +- docs/api/compas_blender.ui.rst | 2 - docs/api/compas_blender.utilities.rst | 2 - docs/api/compas_ghpython.artists.rst | 2 - docs/api/compas_ghpython.rst | 15 +- docs/api/compas_ghpython.utilities.rst | 2 - docs/api/compas_plotters.artists.rst | 2 - docs/api/compas_plotters.plotter.rst | 2 - docs/api/compas_plotters.rst | 2 - docs/api/compas_rhino.artists.rst | 2 - docs/api/compas_rhino.conduits.rst | 2 - docs/api/compas_rhino.conversions.rst | 2 - docs/api/compas_rhino.forms.rst | 2 - docs/api/compas_rhino.geometry.rst | 2 - docs/api/compas_rhino.rst | 18 +- docs/api/compas_rhino.utilities.rst | 2 - docs/conf_booktheme.py | 290 ++++++++++ docs/conf_furo.py | 243 ++++++++ .../{gettingstarted.rst => configuration.rst} | 12 +- .../blender.rst | 0 .../freecad.rst | 0 .../grasshopper.rst | 0 .../rhino.rst | 0 .../rhino5.rst | 0 .../vscode.rst | 0 docs/index.rst | 61 +- docs/tutorial.rst | 30 +- src/compas/__init__.py | 28 - src/compas/artists/__init__.py | 56 -- src/compas/artists/robotmodelartist.py | 8 +- src/compas/colors/__init__.py | 24 - src/compas/colors/color.py | 27 +- src/compas/data/__init__.py | 64 --- src/compas/datastructures/__init__.py | 198 ------- .../datastructures/halfedge/halfedge.py | 7 +- .../datastructures/halfface/halfface.py | 6 +- src/compas/datastructures/volmesh/volmesh.py | 4 +- src/compas/files/__init__.py | 131 ----- src/compas/geometry/__init__.py | 539 ------------------ .../geometry/predicates/predicates_2.py | 2 +- .../geometry/predicates/predicates_3.py | 4 +- src/compas/geometry/primitives/polyline.py | 16 +- src/compas/geometry/primitives/quaternion.py | 8 +- src/compas/numerical/__init__.py | 103 ---- src/compas/plugins.py | 40 -- src/compas/robots/__init__.py | 114 ---- src/compas/robots/configuration.py | 14 +- src/compas/robots/model/link.py | 4 +- src/compas/robots/model/robot.py | 4 +- src/compas/rpc/__init__.py | 40 -- src/compas/topology/__init__.py | 66 --- src/compas/utilities/__init__.py | 82 --- src/compas_ghpython/utilities/__init__.py | 2 +- src/compas_rhino/utilities/objects.py | 2 +- 81 files changed, 2197 insertions(+), 1633 deletions(-) create mode 100644 docs/_static/compas.css create mode 100644 docs/_static/images/compas.ico create mode 100644 docs/_static/images/compas_icon.png create mode 100644 docs/_static/images/compas_icon_white.png create mode 100644 docs/_static/images/compas_icon_white_48.png create mode 100644 docs/_static/images/compas_icon_white_96.png create mode 100644 docs/_static/images/compas_white.ico create mode 100644 docs/_static/versions.json create mode 100644 docs/_templates/framework-logo.html create mode 100644 docs/_templates/framework-nav.html delete mode 100644 docs/api/compas_blender.artists.rst delete mode 100644 docs/api/compas_blender.conversions.rst delete mode 100644 docs/api/compas_blender.geometry.rst delete mode 100644 docs/api/compas_blender.ui.rst delete mode 100644 docs/api/compas_blender.utilities.rst delete mode 100644 docs/api/compas_ghpython.artists.rst delete mode 100644 docs/api/compas_ghpython.utilities.rst delete mode 100644 docs/api/compas_plotters.artists.rst delete mode 100644 docs/api/compas_plotters.plotter.rst delete mode 100644 docs/api/compas_plotters.rst delete mode 100644 docs/api/compas_rhino.artists.rst delete mode 100644 docs/api/compas_rhino.conduits.rst delete mode 100644 docs/api/compas_rhino.conversions.rst delete mode 100644 docs/api/compas_rhino.forms.rst delete mode 100644 docs/api/compas_rhino.geometry.rst delete mode 100644 docs/api/compas_rhino.utilities.rst create mode 100644 docs/conf_booktheme.py create mode 100644 docs/conf_furo.py rename docs/{gettingstarted.rst => configuration.rst} (71%) rename docs/{gettingstarted => configuration}/blender.rst (100%) rename docs/{gettingstarted => configuration}/freecad.rst (100%) rename docs/{gettingstarted => configuration}/grasshopper.rst (100%) rename docs/{gettingstarted => configuration}/rhino.rst (100%) rename docs/{gettingstarted => configuration}/rhino5.rst (100%) rename docs/{gettingstarted => configuration}/vscode.rst (100%) diff --git a/docs/_static/compas.css b/docs/_static/compas.css new file mode 100644 index 00000000000..1e91153164e --- /dev/null +++ b/docs/_static/compas.css @@ -0,0 +1,7 @@ +i.fa-square-github { + color: #0092d2; +} + +.bd-header { + background-color: #0092d2 !important; +} \ No newline at end of file diff --git a/docs/_static/images/compas.ico b/docs/_static/images/compas.ico new file mode 100644 index 0000000000000000000000000000000000000000..ec6b1f27be96714c38db632032fd76439528a1a6 GIT binary patch literal 5148 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 KMNUMnLSTa8^2MeA literal 0 HcmV?d00001 diff --git a/docs/_static/images/compas_icon.png b/docs/_static/images/compas_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f112c7b3c69bcdb0100652d1883dff848e77289b GIT binary patch literal 2780 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 literal 0 HcmV?d00001 diff --git a/docs/_static/images/compas_icon_white_48.png b/docs/_static/images/compas_icon_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..f685a045350a0709a004cd1f823773df57990007 GIT binary patch literal 25528 zcmeIaby!y2(m1^7?(UoJZUkv5L8K9+Z&JEJrBe_PP(Y+bL`p(H1nDl3kdOxH6p_+z zZ`9}b#ChVp?|c2eKhAiq9V=$d%$hZ8W;VA`ni@(tn3R|R0N|)7D`(XS zqX_U>!cWJ*L(AM7=HljTZFd6>^YC?n!{9!4)&Sr$@i=`o`H^^B-q*L$1ISx<#El0i z@Y+v(gI}dydsgT0Qsfv=|#2|DaZ~W`wSL*%DucsZgIu%h*ho{_LoRS&cXxLY* z+J1fetB1(6^mf49KI50Op2NOFJjoeM>5GQ@ANEaWyk|sx0z4a3rQa9y58$_{+l01NpHm&Kz&`E*r&E`%rP#B+H7|MY|P<<6Pq)sxrlR5bPWr|S{7 z4U@M^r)FL|-!?5?k*33Vt?u^a%Sq{sD9_oakexH?ultFXXE&Du&c0yWekFSB`03yz zU3Y*+Fn5JtaO6m^pfr1`^fR?+l%I$2t7|X9W}=LePM+;Pvlt=LHt?EgDqT(6=NfZ; z!#(!i_2i4x`$dx6nf403>66u#Gi&%}TBhte*+CDDsT>xk&ZyfoJgzC=^_{vnN3XP# z%I?Gm3%S#-f*s6Xj~^UWlch82yY!E4*Us0!8nfD`ye59u)nP#3eK9d@3pwEI_)NOk z!3-tQ+K^``<=w6m|GkqSh60#{@AovZ-28osnkfUNo6SQ zx!JTrM>H8X0_tX!^^2F}^?Di()>J!W_dYNuj@}S2Cg&ut-e0XLtrGlFT%flVQ00{0 zYC78Y^=nD`o1wFw)AvtD-o%ZW;p(|3I~4Evr` zjdIcNAUQ{MR4I~C-hScD#buKz!%hB>9DNosruVJryDrfllesT0X3dO!3#wZhqK65! z)PCy5wd{nwosYaKFUHJy*|OxV4LLP08(b5E$Gr846SC|-y-+Q9ZTzHiOTLf3=1pJ} ziU2EO%iW&Ii>e~51Egh9dJ#B|q+8wg#R&q{RWhHaC0}(h-I%#1KTETcDplKORmMPN zkrWeNev7tiQoCoxRU^EZInvnh4|uaGtY@pbzkilg6CiVY)5;%8^h`ELZ4yc z{T5by{HeQu38N61*?XI=z<$v3&ZRc&Mk~N0(nc%B>l)#PVc)A9A5rc%sSd zGh_MI_~IM5bH~6TsxNLt;+AKcWw4af0_j%{^-_IFtXHV!zDET6{q8+18yhUTsco$h z2&i?ci-~Y%QMEnCJlgf9A)j%AL|&VSe|TAYmEqn8 za{2_P=rq896VEp26!EpIWquG+-3aO@5sTUSLc?iU#B1|?ETg*Rc&`qO$wl4_TE;z2 zkMD627PS1_NAcmB1RZsqg)97J#oV~hSxiY!17+l^owX^hYVRt34(vPd2tK=0|6TFh zAr7a~5vGZvC7k++jm>=Wx8Df_+MJkX^`H3L+()_6$7x3Sia%G#K}p{LI|E(CTe#NX z$^LVE{N>bHyNf*ASIz3YEE6$0*Z2i$G}no1Wa7024s7*qaP*neq72U4WshORJhSa0{dSb|TC}vpM&atcmuf3kg9mmkkNw{S^aJ0u-AT zJuYi4PBqm^!qkdJDHHQDdz0!AY>MgUWfm@$xpq6rv})C7iy4yP(m=dO6E=fV)3pr- z!s2-IPbt9gz{3738_OIk8Nl7ZpG}gsr$bdm1V2E-I>Ym%cB}+JXv;sHjchz6iybBA z4l`GiP}~Q1%frLk_Hu>$0Zvy(V!8}3Cm795nUU>J47og`v!15TmzbNzAd(It5x;JZ zaPa(d$JAc+3dV+a!IKIx8hH+qa9tZZ{J_{Vrklk*@mHm5d>;+8CRU9cKfW(}um zQi@Sn-kcUTzl+5h5Q~;8qv;PE;={S>-U@UQeo|@kdM9E)BdUixL1gdy_)<(Gy$c^o z(o4pW6ij8LO2H#wo^`h=ysK0k!&a<-jD(%aBu8`Q(k73rnpRZGg8yXOkkdAty;FgR znx_bpgYs~KV@LJyxYB;?)uF@S^1npNLq3mzV@AVmxsSQ!Qfm#(9cJMa0CPSG5?Sl47j42=RZ! zVtX(3xhU-}R^oN`=z*CQLKTB5Y)TmkzYqeZJGo}KgQgFqEW&k%1RN#^nJi=3CBr0D z!h`n|E+hIN-`f%HbV!7Mz8HY*(v06|@H$l5_w_D80(s_evU|f>^aIq!%X}FZKLr)y zSB~|TjpDzZ^BwHrNl#_CK7T||fN>e?lC>`?^#W64zEbXqZ$^fJLDQ2xKHVJ(5o|NA z8&vYa+Rra`N^T(*qk2$!v~lB`KNqRL6mo(*7{yLdk%*NkrQh@}GSyXP_r#4HF9rwK zKPA);l*N2VVOM#6rkb&T1gJI(X;@GlrE7r;~xtVn%rq4Df%>7YXb+ISp z*l44oqkFx~`Kp1QO?xZR2!#EpWf+H-l~Gv|#X{bGe0U9?U`9ADP(vx9juW$0kld_C{3Sc`sR4j+e(S@)wCiiB<02eu5_tsIqPys^yGdcBMk^dU6k zNi>P-9mJMZaH*CACBCT;6wiNU@NSR|%%{GIv zIrN5;<3FgIN|KmY8(Uf!c$IZq_S0%4A^6E;%a$dOn0*W$QnsEuv>a{3qR-O|3T1DR zM5X>>j5|h;ZfABSF=CsT9$S3{YvsDW%3IkF+>*-F9l85)Vt3i1-=v+~W_n3vg>YT& zM%a$$lWf8cT4STKb-YSalt3k5K#&}d5q{*tQugf0yqtN0>szZ-RyjIeRweVR{Xrj? z(lPSU_amHhmQOF6B(=c+vt0rN?Hh)@Zma@~nWOPo%{q((Xqw35PG3m8&;iHi@_eoI zK0&I)v_8n4?#v#JS>wzOTGft-kspfg;Twetanb0-0UNHmc<&Y6x)P478B?9F$T{TX zy4dgT1Q(IX8V>S4dxtHJWT5S>DE{`v`*46^FWW_i_IRLC%}miXM>MG*Vu)YPI)KE$ z4sjFBN+~e9|z4SyuOM_szW4L^U9krunZm0@iChWw> z9&3>kg*K|@4D)Z1wCYitJU5luWTxCqHsw>|Tgy#j+W@y}v+tb%6e z4%lB(DJu;rxd%-v4-6no^D_<8bVgF`qa(Wu8}2lz$pX1bB0N`$d@R-;H-u`-yi;J@ zwNAmmET1a%nX6J0Ie;z9dWZie&JYtdLBNtpv-1+!gGw z`d+z6iJCjIQ?wY>ohUF{-O1p_nU%L1rYn#v8&L<}_gid3bFp5BilALmwo${dj++i@meXg`_b!_imp?-G zr9dZe^$e+5Hp!?hDyLbvvPsSddsGZ-<~cKY-mtoeSK6C52p(YSd-T#-BzF2qPyzgMD@J&k7nrHDQ&M zB|s;udb(kS72miYV|826*;)}NUtWbHtc{6k+i|YEyP5Ckgfqq9;Vd`488*5Ak5+OK z#Wj)F_ZMx;>0Ws?JJ?dar9-?)OgYwwoJ1nl)66!`SB~j}7RP8`Y-=WsZC4g^+UbuL z8|Z=f345kV^nr_x$J3V29KHA}E@Tq+WF(h&h=iI1uD2I3g*Q@&203B&4_?Bi9KSn8 zFBGLc-IC~n&lp@sNR})*Q zQ0P$Yfjrkc53Vv3sVUM}p$STNb60EAm;-i(=BOkgy;D_$bSWn}H<@KeU{80B_6*>j z#`<#(t#sS^FK+;RLHe8aRK0jkg^yW@1LKSZF2r2exQETc-T$=lgMa{~`y@`_IzF+k z|4ULb&r|>FW|bdx$&_p6gnZb7aMcKE-*-z1s0p@b5}L~&ZRdB7_SHVi2#Sv;7_jU@ zT2XWfeC|k+yVF4!sl;JIG!F~D9LpSy63LzJ&V$&Pocu+}p6$LB!KA>6WfI*Tc`IWD zR#tseH(R8Kc9zX=2wmnrn>0})B^ig?hIDE~SH`xQ+Lf zB*#cIG7UN%SuXD^POGd%p#3`veq335)NTZ^+~Qrt9IF-8ef?_Nr z>K1OpNw;9P#~MWfNl_B=?-yvYFlL+XV20*cBXb8oqS>9+RY%NB)RYRUWDwj_uu!}j z(|SGWP^oO+Q(m1tEXIN0&9S1BKfAly)6{gIhuN)sMA6s;JX2!5{&Qc%f~-ZyQSACG zF2oa~Y?|afO+=)J^^E^pOx%T_4&aB~ce&7?#=4 z-0IynDTS~L>wI^*EtKB};g$7ZtW?CC9b%#t$I(2cb6hZ{F2 zp2~#XDjm8euFZ=XuRZeM18n<9~z7I`hDd=0LQ-LBhC2-TPw7nE5KQSP{Rn7*`|} zwq6x+TzX?-)GPgrkA4X7BwBt{WHtrj<-6gP)zNaNf=a9IT!Q84_I`m8EqfANh@4o> ztQJ1Hn^}*@C=k;kV0V_B22~XCNFCC)@X@svX5T51jD%EhRGT>SP+8-Nhc^&qIrmc9 zx`Zbhw78QP%H2<)w$OytGD>+Bon(I);!yIw53HCA^&?`?IMX(Ln98jyvmj-TYC zFB;wdLiV5)L+6EFHe2^t8KCLpkB>R&h{@qe(0r zr%j>+@l`$DFlRZ`rKYeM+UABgyUDYe;cK@-Y4r9Hb*|Fh4z^0Uu37J%g-u>QK{Hsr zlz2JVQ{wVS;s9Xo1+N--1v>cVN_14Au3Tb|}6uH+&hi_OKhKq*=&G8MQ z+&$AVxyfOp0(biq4e?FW0xn5_%B3qXc z|IyWCD_cb3=s;5s0x=y*>~a~Q9I46e#ZCVbZooM1#c)$)grFH? zeLRVYmqV3N6klE=w6b{u$MRVB z9PRs^h0nMYY-36B8JlqL`FZ;3y02~OAxw{{_sg!7cN0f^HW`e6_h?VVgb@Fl2ha#F2$ST<)G@Nlw#9bNUsGy>KXFk9Z|ln*0Y2oIvc9fZ71qbeS^ zE~$z-M&=ISyvQA>38Iuhs(j7i*psQ+xFdivfK?J1O9}J|e+CvbXB7$@iv=h4rxaMJ zkC(*P?+7Q@+3ZRrQ1@Y9H#QNbwUBP!4w+SXU#*x#Ku?)KxEA>Wy=QLLwu3N=<|9(c z0y?@+EK`S@fV60z(>2$5(rB`|5aj8@a7x;01-~4HNo-a4aSb}j0bCj#(c4_-2BIAH zWdWNuGr0%(>4EadP4!F^O@NN}wtXpeG^t{+A>tQQZZ{e6jQ?S1zVTjYt}4jCQ%k5sAf+9>ZNugJ4804$(P!w{APy z8vAx#xX!~n2-g5>|M8@Hj9_h8u0liiq{K6Fff1d?>lj6}YFaJaoJhrLisL(|TJH4t zrNHN*Q2B!*i&@OI*1%QZa%(2}Zu9)Ms=gVe^ z$^u!NlwK1_N-lvF^OzqG+mf^IEd>>E`P^nH5ll35tTJ2R8o6j;mPFe+hjdJ}-D8ht zA{up>D@baV_nqpa-WbBSKHhazYGt3tq94|pHeP3?MLqzqAKRcZry<^t<=HwlE6H+&i zNiH>hJj)ULr+Zm-{A-e6GJ>@8ljZ;b!(yr;;}S9Fox)_iW#;d)zkPF&jCS*m!} z07H>Vd(otNl?sf)hhiejS{ky41xx^1LSW(MkfoDkUh=5^*bZXfe+#_-A%p0qViNo}255EVmfi?>jrtq_B@fqU@mKf5=zFpS2fK9|Twy+6Uq@ z?B&dHn6IK#fD@v8D+PzWO-%{?E}KQCeNkz5 zMuuYTGyDfH*~qBb@lTX+)++qb!#nH74d@MeI5KMA*^izodKx~v6ipOgD5 zGc!h2am#x~?L zhpW_VMs-NOYs)bq4__WUd8cS)){BCj%b|;_(wf?@uD>vUcU*0){*$%{&f|d;iWg_Z zwL9&z-sobQs%?*ajYf3>!igvbxOznBU;GhP}o4H=&>l5u|0 z?OT)5xpVAMe%bTj)>8^o=N=;W7D_>s9Gm6bAo`629|o$9yR)I=4n&O49(U_#21Ezw zs%}yg3>6L?=^hb034LsMQ66vjzVQ0`&b`2Oqu9#$7(`dRSCVTl1xHeANhHnFVR!`i z9pQd4uVVM+I1mcu7awCN>}uA;5X*ZJc`Jt58igcs={^92Rxw?Y@sbAL$Lk_-^-L?G zJzVtAuC@vCW24G4CRJ;DxHG$6!7TH-;r$qU5`Vrx_|<1{-F0FI;}kE?pqooEBUU52 zVYqw=MH6ZAaRs(sOQNrt=ag)?kd>b>DP&fE^fL+*@#&p)S`sRL*xKjBR;Qu~bl7(` zhn=o`)nzQ85{y>um05V%#ntQ`5!EVVR!-8KF6)1A&?4{iIJ%lnpU*tT53ll~uH~A)>4Kluq z%cURW%t+4?=E7f;h{9*UkNR}$9hU<)K-;VGbnhYgn*EY0jLsnM1&ljpBI=dIMI42( zqa=Q1ec|n5LFy91603u};z^Dr1I-b118w9B&drzv=qWOd&D*_H?4<@u`n7uF#|2)o zEM5^E!((HNsZU0GO{C#|uSuQ4=5oDEjW_cnX$nZQF81t`q*uNUru)2T5;StFpuFYz z1zT?u!AmWL!=t!ld`EM!??gX}y}x88Ry`zGIJUzZzFQTW6OiTVt0Q$dG4suQzt_4gE!RmB?DF6YtWt(d2tI7+_l+nO$#an9ehZ9XC+ z^qo45q)gw2Ux!yC$>4164ZR&+t-B!g8EvKR(@z1mK(2rAal*e}Nm1HCq=-q!mQZl#DCHsi0 z;&uk|-HjR_sTcyc@~Gz%k2RCuTS)O&%*KIqZAYfg$N0nWMvGS>tq(W8amk2b4<~!`P6YM+ zn-{dq!X^@7xRmI%sr-aRmEzXr`H>XDq|S?dqt>z(0S;L^Ooap6`5XiRDW^jh^Cn+l z_cmD6>&Xh!4608uG}V<9`*u~0ZVa61Y>l#=I#SU$I?0K5u5Z^9B5I&4JXqC_aCJd{ z=6PA$n@Pd!QXCNah5ajjM$U)sP*mTjF*`MywFhk;lf@bcN8a)+Wg@-{dW;#H#f$yS zr5VbCLTy~n?XOIbc>903qbjlfqO7o*z6rS!BP$Y5&nEwPtx{SBsc0f^Rp;`yDm%As z5F@s{xQ?fr4hdWG+F(f^H}_*pfs#F;by5h?CneW3a2~m575Ng`I_WIbzfx3?Sn_WOs;8r0*B+fu*>4sn z!1MU!6OqE?tjpbvXGX8vW0Aia6W&P+dmynhr@Te_LKje6&a*lm>(J8MyAk3XPoA_Y zTk&$>i2;j`+-)iodgrSuM~2z)sdPm+PXs4a;7fN8hOU?Z-K9KOjyg`QI|IcHnPYit zX7<`RHKHdGHJPJRJ;}@%Yh!vdpIEo`A38sux|=hrNb^-fW)YUr2lQ>@o%R3~JuVEJ zayrk|a6HH{$=wd`XDd2AOcS3-dnzTag{0l*M6)XKa*RcQJjD%DXn`Uwf;W|*zOtZxOst}f1#aAFe`^$*G+r5Ug2^zvdwpENg&kXS3dr7f)NoqT(9 zSkJq#u!2k{3WvK%FhZhE%?24?QZl1y&PE=NqQXG@#xa_SFeOgza$4xib_01yM+<#K z4$roE>LMhUh1}zs_OZprKht)cg1g? zc4zRzKg5VUy5$KxgGmO;d)F^jiokF8O1Qqmz1qLKisBLQ5ixBNTe+aQa%BJ0>ivYv zHbNRyM9DFRguNv+RbvI|q68vrxwnTW%BOh7^Qipv^;v|~#5pFzKf3aTx%nSP9r&*z z2Ts;)dl+MT>uxvXqurj+eBHwKi1c3mshp`UR+27O&*t=N-MFVQpH{?Q+fNoho3S_A zEu9EImRNQ=yjJ#g(p9^%PPomVHptI9h@|~pqp#$&95Vw}>9yof-efrgQF@QoizrA-emSe#;?ij;#Fs`auSMtQ+p)L9Q?pjp%uFR@yG5e8QSE=lckVVN zU-oGHWPdC5Q(0pwPJHkWkE&l}`guwRJRBe^iEX&Zp7HQSOhH^+ek$)9j6;Ge6xF0a z>_p4zy#bWvYR-$94?I^eom@)ksl&J@M-ZgCM=TQp$CfgAlkGjC>aA8^cRrc!IIUT6 z9!q)6Y_6ymt-EX)?y(u*jzRG8tVlE zWFHGnHl2*PL}K%vtD}VEI!bq6ilMpQZY1)Qk%eo?zgRw52^mC9pwjt3kyu9e+4YTv z*1^G3o{|vh{7;NeCTEI5pZG7aT(`P-0fnI4!1m?^lw0M75mQ!=qlQ^ZD)7U*Q5@x) zs+f-|c;7s$;Bhd`A((l4_xhu3Byk5L|LgdK5|`=OEL)I$4J`u~s)k1FM{_?h-jOUk zG%m(vq&n~;5q|36EO&gPXt*Di|JA8Thxg#+k>QCKowqOye}&LFo%v&3cQgzCbA`7a z)oyxAno^yk8&VA6BdVW<#IuPJ>S~Hj@RW}x0yE>h^T9uQ({XfJm3DL?=%JL)9lOtz zEGK2Y1s7{1elQ#{6KTeAVs}V7q#WTE_`rGF$vEIfZN_?lNe91a81>VjeLVe@8yT4; zwPb-wTLo*z!+IKG%_G($CjA2_D&r)ZV>L$k6F6$*omVgP`zzPk=0u#{j6I?=9(G#Q zZbPV?YqzB;T2N7$ek^ThciV1vaE=pmmArH!O}8kxGIsuo$>C*GYtuR>Pm6H(EDXXZ zlp?MySD!k)oo5l^OApxeQm!b_SX>B?WasBCVT`{DKM`9QCF%X5_mY5pqCU-Ia5iRP z>*b?~)WUh(V{$a{3pC* zF*guA9ow+$w4)!4Hxp}ma+905bh;0tecAZ=@aFxA91pRp+97u*jY2Jss|OmSXR2!1 z*WLxUhpGp07wi;hi@q=~lcc}od9&eG(+UH{PPx9tx-z+oTSr|N*-(Wc@%VsLYF?+S zbNk!V7I8#LwYrq+$JA!9Xk@Ee@c;T?IlsLn8BQ79U{*pdwSGML@Bv9AvjcG zeXuPzKJPnd#UlcziQIoNQkPIghmR^f74dagEwD9U!bQ|PZG`SC)`<#B2##$@G^70j zxdFPxX3wppAZ5N_gp!TAnZdD}aZNkXVSsT2gF`{?h1J_k*vGomFP#tWq#ISfD7&qj z9E`g(%Tvf`O(UFVrJQUWKUY{ykS1~mA*>4I8tdTR8g{j&Cq>i?BCk!|jv4F0ONdLk zZf?<+1sDs6mU+A?r%QvEaem#q4u=O!mZ=zmabMbCh6L!mPOY+RHc@n zly(HN&hTyHd5VCJ=xR(bo#t*tZj0m&;e!xJ7s=@M^Af%jLf@ADPtnK5FYG!CPd{(*@Z{7@#TCXWMfd$b+`cB$4fA(yXA|O zLbTGpSkRtDOBZHfMHS$A$IlRK^$Ux}x8{;q-j=P&Pus>H;k9 zU3NfnuLG>i2mYaNQ~ml{CVI8s^D(@tJeF9k`w#W%oRde0kX(utYjj?Pw?+)lhX!xF znw#{?L1MR-@io|d;kM-{`Rpiz^=fh|8fxeRiKombC0^V@Ru~NG7#Km41|qFu!^Egj zitKiH3t=JYJ6K;mmG9g_W0RS~zaNU}7}*!eTw+j^raNF~D*-Ef;Xj?Yhl)Tn)=rPM zSi(2_Mk)^1f2fPkcy>x^H}5^s;~F}`dD@!6dR%#rd%3NT@~@dr+N{@f74zJm>?^$0 zWvXz}@djg?9DDx?tMQS5ZimFolN*l@CAO1_>&zvp{JZr=muKYzi|qG^SY}lGjlwZq zDv~VL*N(?DTJu;$Bz0^W3qrm=#284gdNY)VRWvafn71|&>mPnRL=$~Kd2E_5RO*;T z*D1>}H|w>=rJM9J^jz34Yl_#3iX1^lwA3U`x8o@uTu0aWK=dYUlNa8J?c&~<0?Sf@Sv1k=})Y>y6ZPtyvY>R4(=Ngfg zm%Bd&a!OeDGq##3@vj5oY#EUoHMP3W!cXrdp-EkZb>d@SON@yM?SG=SMImlTD&_6Q zdM58@EMAx)!{UrPeE8^V*rTGz!4l!M&MChq(*T~mQcuO&2Hq9?k8XCJb;*%0LoMFt z9?f1+G^%#ZFLv4PBC`UZ#yn+J1_sCso%Q{XXHyUy>Ge z&jyXqsnUb?<5wgntQq2E1IKCrKnS&ym)BI0m;doA0`Rv3>9-Q3lv`w|+f0qr6t79V zlO3j)_bi8T%opgg$%SchR<4=3t&$1ZDQg*1ql^WI(B08RBeS_qV~irZgVZ|Grt(Hn z_0&|$mSCaDReJip|5QEFX&;AnUxus92p40bDrW6zA-zwKoFIBoX(a%C*H6% z2U>?<8{f~`Lxq>d`YyQIpR!G z(Ar9Hzm?x2d$`SwtfD-d@Crc(iEi%AfPQ$`KB-OBHJeTUJ+g4DiEe>0J6y&vMK0M; zfWlKpGb{|bn3A1EpfdC04xYsA1Y?0(4zooA85|C#4!kdDuj_>GBoaAkiD4j{-Z-&D zM&Cp%4tETooAg>oMwdj=zt&;ufGC)mCn|C66g|=jiENBUeHw|!J1~g#x&V_B=HN%N zJB=q4x3pHIFFB`3;3%K0FadSaWS`afP26!;5K$nQViR5uNh!= zR#FW5!s>kLF7j|&J7qsNxVE2$j-{W2rMMM?^hHcb9|;hFBizFr=Hqz7$z8%nis2lu z1o#Y9^D@BByLdQAF&L<8!sMOZ;4mQ`As#+%MISpa0fvj1FiAHnYY8odOW#p|Z&D1l z9v&_dyu9At-aOudJkD-5y!_(g;=FtUyaEE;U=MD0UndW9A8sdiMhL|>913uEOE)_g z4?AZk7=+W@!r9Y9ih%)ahy9?>(M4VT7xYf<-=zS`gV)F0g_oa)kJr(W_vaDr9*SNd zlJ5ll;Rtsf@W(N{T5xw~Pd7`rq8HrBgYjn+R+hhvcky()an6pFB`^F2+!5^R4$jK| zt0|RK)HQz@0g1rI&e7$36e#Rp_4Kf_{+Fm`>WnRct7t9_EJ}u zP;j>Ngve7-kYa%5m#}iSw6l^pe-yS5<`?I)wBWXY^P6)EiHiwyTkwkta$8tf@L330 zh**nQ3;l#j#mU{n+{qFSp#qWf*nxP2#jP!^`OQVRMJ+6ZxP=7xEx5(Sti`#lg!#;^ ztt_pqg{*~tLUF~-4%ABX8$VM8p|S!|Sy;fuMEQh7xCKSUEVzXP1mmVi14`B$QdAJZ`3R6133)fTxreixjclD`9T=Z4!5LFSynDMBun@O_sLiPBw6GgMZhkAN6*Buv+GV zB5-qa3rlWMK?^}{A#+PBZgD|z5pH2Y0bvnAOCfPSQPE#xcXzh-@HTgY%i4gPg4}=_ zbj}To?VBvwf8E{N77huDPe72HPncUkREJ+wLO?`9P?VETK!T5tf%iMdywJY>!LlUp z?}Q?G-r*-h0FL`s2O1dAUh)27u)YfolH>m&d|!IQsgP8^j<17T)iL9=wx-btEF zk%nL~0Sg0IP|m>1=dS=jhmHhLq9FkUC?JU-?45iCmX6MVna`&HI{1$CZPrupaRn^7 zV98r_lY|)i$MBCC010OTX9)(223W9=5fA_YTvR}rkpSSL#slbyu>dSIWB>^X5kN-# zhW_l!SK##Q3vhID225`p023effa<9&plACCI0V~3I08#8SZ<>tAPh~rUO2CW8vY9Y zHUl(wTQNbb0U$yLuwW5_(!Ie=3dpdM0CXhS04hlEKLLpD`OS|&`_u-IG_VRRfU5%n z#7G`kyulTLRPHa~Z!rK$T^Pjl2rS&F;Q9v&QUEHvlmIa{+FwracRK7Go&b#_D?m`! z60mU$DIzcr7Hg0RXjT3c{*nQZ`0F5s6mX|u>QdtXZgPwO4G|XbR|5yNL78uDMOO8dkbVEAGZ_@>_9=uMS{0jhjd-(LRYdI}Dzeft6MYnlbN z&b~r>As(F36SP+6OY_^I|CXBX#0O&|As}a{Fag)ZVSkJGFW{VoLo2@`9-1_^XBmKq z`zwGpz8a{Wc~{v15=dVGzy)0WJG6IO|B%){to*JvK_Kx+IqIx{6btEJs>~0Cmmi3j9fVFQT1+2bIPHuc{Q_!UOTRDvBIK^qp*c}Y<6{}do4 z*#-|S2%zh^aRl$j;5qOW{P$0RlNuk0mW2TzP2he8Qb8tuMbxht0MQ44ow!Bu(Etqr z>c6cvKNIzSZ6AnvyLL|MU2$q4TY&+Z97ub=0}RY={oM6$Kg+O@0aq!pq5c$LiKUDC z*M9hg0gyB3goO?%pljy{@G2b!2Ise-*S`(WCQWUbJ>RTSgy`o&kmDc&^l5MaWDrYS z%iQ^C{I?N;9Vb`!ft%$cK*{pQAHxhl%PjWeU^y$IM1VUs)R38CyV07aUH~`s%G`0tPE*)M22oSyi zbl?GohWrz%?--%m!Oabf$NV4ffn$PIt7{gExZCH+r4`PV1W}^ zNzj3(?l z#nR&{S=>kb9*i(RE-~a){s2gTT%ZX{)aL;*FEIeDSSaUB5bMQ@`#}BZ>bZ(RYw@^i z9$Hp_2?H505TX5n;&=B;AY+h)gIwrG?ephShdOnF9%;t=Z2;x_qLG4oCs~>f$iBu0 z2s03Y@x%89urCE31|Us-zE$zTR|!akphyY@^5_4^C5GzcIVphR>-<27Fa>}O`a&>t zWI#`p_FN)k%e%nc;q`M}br+)sB?bMTX@3mRruM!FJ3kxp!IfyATtDv!nQU>8F=)?t za+3fxCj93X4C?M zj1OXZegEh@N`p(n04S2{1kam_!KL$VyrA#HO!n8rL!HTS(LqP=-2QMwS9&Ohg*Mqg zf&I@XKuqiWxqXH+5dea)Z~jkF_dFo^_zm!=={>M@a188&kyb(193YoF2xPR*fL`iX z00!nAcq2QD2DwfP(HW}y!m(xV1ahd6toi1 zK3m-S1jG!k0tn!W2KBE1N?HAYYIZ;1*}e!IfTsA~_~v;$3~fm*L27^o+)E2!1opUd z?w?Ezpn@w+0~!nn&Z&m72R{Pvzk>-P^bROF2>gX80oV`q11VFZ!ajH6ptco|xYxO<)8x&3_lbqXq!I<@4_UOzhwg$feH(%_elXabThV z>OVzU)C8D7m?jrcqQMIA;QY%PF@TbOti%W;>hYZG`42)bf(GFt=rbLGX7zsS8~_=G ze+uUeKzSSJB>X!tw6G1_f46xqWgjV803T%HXMk1`+T_mSG{00k@sR>@9OS=?=+Hq` z@R4IU$5jqGYfa;8zl`~_2Z+*>@4*qoz$TP*g7P+h1>el(H+|Ir50gKO7rrgq|5X7}F0DIrkE8hnGo9hv{`t#t44FSZ!6qGT8l1_gGFF}8&5_HJEfYjZP zf`OaqA8X+6ra%H$%pCMqp#ySg{}?Fi`@Ns^+d;=5t>Xvh46H#Ej6&%?C}Z~T0P^#} z--iQnor~wD&jkz_A<6w2u#jN`nR2l6!b|&2!vC&64Ivib!~g9NybD^d*^Q5Xx*v8v z9sh9lMj%@>2zh)^x=-W};@>XNPs#3C1YUw}HMDe)*)$USW;XvFK~Oy%G4^@+vpzrC zAa%PcL=9w)tOM^st0kBJ7EmBU2XuMK0R_;F`N%rV)KIPx21@P+)Pf%8&%{IZ!+S@7LeAjtr1E3T z|Ktw2<39ru_)-Vb@G}F@>E8S;yxa$yn~|aXJQ$JXf-bIa`{c&282B04&(Ax*nds-X z|H(6?7T+}EXDq+2=>x;oCGda*Yb(Lr>Glr?C=VRsmN2k_2BrV-!DWL$ft?h%^JeWA zn+w&cf#x$|@C$q3Dm(|@ zH4?$YNmJYI`UB226TJM^ z8vJPgqx<`{kHFCPv%@4^q8@$-C;n{EQeT<H6lc1!N>(8n7Ul@Rh{r*|U3amVZ^7C&& z$L;?$%z!KDS~~@Rp9-Lj>k861^)pSsVgPCYJJf+UKj`CvY56z+1?~T@0188$%ijSD z-*QCvLE18YOUv&VfI5H&NGy1ZUq3$kYE(J~jQm3#{_Q0H$vY%@+u{*m06aKBCLdQUXJeU7D zK&NfT+t2czOzNm;ux?`+!O?zw=@D z@aL}o=oxa->OeKUmfL@R+I}a#5=0{ScZi23gU+kJ4bWE-P*~81h9I!WfCU*$&!6Wl zq0}FgJ%bWZP}J54#=3A&1tEwPr35rY=m03Hf&vrBw};$g$iw{Zq(Lh^0G3;zL|^`F z^P%y72LFhGABdn24PY=T2)={b4?voa5AH)SX$+ia&!7Yp^s)O57%oDPNs#NQb0vfL!m^@EcpKeV>#CJ literal 0 HcmV?d00001 diff --git a/docs/_static/images/compas_icon_white_96.png b/docs/_static/images/compas_icon_white_96.png new file mode 100644 index 0000000000000000000000000000000000000000..157f04c867819afe1097d726548362f8d15aad34 GIT binary patch literal 52767 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 Avj6}9 literal 0 HcmV?d00001 diff --git a/docs/_static/images/compas_white.ico b/docs/_static/images/compas_white.ico new file mode 100644 index 0000000000000000000000000000000000000000..381bd9414fc39233e98365aa1149bccf33b64f23 GIT binary patch literal 4856 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