capytaine 2.3.1__cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capytaine/__about__.py +16 -0
- capytaine/__init__.py +36 -0
- capytaine/bem/__init__.py +0 -0
- capytaine/bem/airy_waves.py +111 -0
- capytaine/bem/engines.py +441 -0
- capytaine/bem/problems_and_results.py +600 -0
- capytaine/bem/solver.py +594 -0
- capytaine/bodies/__init__.py +4 -0
- capytaine/bodies/bodies.py +1221 -0
- capytaine/bodies/dofs.py +19 -0
- capytaine/bodies/predefined/__init__.py +6 -0
- capytaine/bodies/predefined/cylinders.py +151 -0
- capytaine/bodies/predefined/rectangles.py +111 -0
- capytaine/bodies/predefined/spheres.py +70 -0
- capytaine/green_functions/FinGreen3D/.gitignore +1 -0
- capytaine/green_functions/FinGreen3D/FinGreen3D.f90 +3589 -0
- capytaine/green_functions/FinGreen3D/LICENSE +165 -0
- capytaine/green_functions/FinGreen3D/Makefile +16 -0
- capytaine/green_functions/FinGreen3D/README.md +24 -0
- capytaine/green_functions/FinGreen3D/test_program.f90 +39 -0
- capytaine/green_functions/LiangWuNoblesse/.gitignore +1 -0
- capytaine/green_functions/LiangWuNoblesse/LICENSE +504 -0
- capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90 +751 -0
- capytaine/green_functions/LiangWuNoblesse/Makefile +16 -0
- capytaine/green_functions/LiangWuNoblesse/README.md +2 -0
- capytaine/green_functions/LiangWuNoblesse/test_program.f90 +28 -0
- capytaine/green_functions/__init__.py +2 -0
- capytaine/green_functions/abstract_green_function.py +64 -0
- capytaine/green_functions/delhommeau.py +507 -0
- capytaine/green_functions/hams.py +204 -0
- capytaine/green_functions/libs/Delhommeau_float32.cpython-38-x86_64-linux-gnu.so +0 -0
- capytaine/green_functions/libs/Delhommeau_float64.cpython-38-x86_64-linux-gnu.so +0 -0
- capytaine/green_functions/libs/__init__.py +0 -0
- capytaine/io/__init__.py +0 -0
- capytaine/io/bemio.py +153 -0
- capytaine/io/legacy.py +328 -0
- capytaine/io/mesh_loaders.py +1086 -0
- capytaine/io/mesh_writers.py +692 -0
- capytaine/io/meshio.py +38 -0
- capytaine/io/wamit.py +479 -0
- capytaine/io/xarray.py +668 -0
- capytaine/matrices/__init__.py +16 -0
- capytaine/matrices/block.py +592 -0
- capytaine/matrices/block_toeplitz.py +325 -0
- capytaine/matrices/builders.py +89 -0
- capytaine/matrices/linear_solvers.py +232 -0
- capytaine/matrices/low_rank.py +395 -0
- capytaine/meshes/__init__.py +6 -0
- capytaine/meshes/clipper.py +465 -0
- capytaine/meshes/collections.py +342 -0
- capytaine/meshes/geometry.py +409 -0
- capytaine/meshes/mesh_like_protocol.py +37 -0
- capytaine/meshes/meshes.py +890 -0
- capytaine/meshes/predefined/__init__.py +6 -0
- capytaine/meshes/predefined/cylinders.py +314 -0
- capytaine/meshes/predefined/rectangles.py +261 -0
- capytaine/meshes/predefined/spheres.py +62 -0
- capytaine/meshes/properties.py +276 -0
- capytaine/meshes/quadratures.py +80 -0
- capytaine/meshes/quality.py +448 -0
- capytaine/meshes/surface_integrals.py +63 -0
- capytaine/meshes/symmetric.py +462 -0
- capytaine/post_pro/__init__.py +6 -0
- capytaine/post_pro/free_surfaces.py +88 -0
- capytaine/post_pro/impedance.py +92 -0
- capytaine/post_pro/kochin.py +54 -0
- capytaine/post_pro/rao.py +60 -0
- capytaine/tools/__init__.py +0 -0
- capytaine/tools/cache_on_disk.py +26 -0
- capytaine/tools/deprecation_handling.py +18 -0
- capytaine/tools/lists_of_points.py +52 -0
- capytaine/tools/lru_cache.py +49 -0
- capytaine/tools/optional_imports.py +27 -0
- capytaine/tools/prony_decomposition.py +150 -0
- capytaine/tools/symbolic_multiplication.py +149 -0
- capytaine/tools/timer.py +66 -0
- capytaine/ui/__init__.py +0 -0
- capytaine/ui/cli.py +28 -0
- capytaine/ui/rich.py +5 -0
- capytaine/ui/vtk/__init__.py +3 -0
- capytaine/ui/vtk/animation.py +329 -0
- capytaine/ui/vtk/body_viewer.py +28 -0
- capytaine/ui/vtk/helpers.py +82 -0
- capytaine/ui/vtk/mesh_viewer.py +461 -0
- capytaine-2.3.1.dist-info/LICENSE +674 -0
- capytaine-2.3.1.dist-info/METADATA +750 -0
- capytaine-2.3.1.dist-info/RECORD +93 -0
- capytaine-2.3.1.dist-info/WHEEL +6 -0
- capytaine-2.3.1.dist-info/entry_points.txt +3 -0
- capytaine.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
- capytaine.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
- capytaine.libs/libmvec-2-583a17db.28.so +0 -0
- capytaine.libs/libquadmath-2284e583.so.0.0.0 +0 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"""Tools to describe geometric objects in 3D.
|
|
2
|
+
Based on meshmagick <https://github.com/LHEEA/meshmagick> by François Rongère.
|
|
3
|
+
"""
|
|
4
|
+
# Copyright (C) 2017-2019 Matthieu Ancellin, based on the work of François Rongère
|
|
5
|
+
# See LICENSE file at <https://github.com/mancellin/capytaine>
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from capytaine.tools.deprecation_handling import _get_water_depth
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
e_x = np.array((1, 0, 0))
|
|
13
|
+
e_y = np.array((0, 1, 0))
|
|
14
|
+
e_z = np.array((0, 0, 1))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
###########################################
|
|
18
|
+
# DECORATOR FOR INPLACE TRANSFORMATIONS #
|
|
19
|
+
###########################################
|
|
20
|
+
|
|
21
|
+
def inplace_transformation(inplace_function):
|
|
22
|
+
"""Decorator for methods transforming 3D objects:
|
|
23
|
+
* Add the optional argument `inplace` to return a new object instead of doing the transformation in place.
|
|
24
|
+
* If the object has properties cached in an "__internals__" dict, they are deleted.
|
|
25
|
+
"""
|
|
26
|
+
def enhanced_inplace_function(self, *args, inplace=True, name=None, **kwargs):
|
|
27
|
+
if not inplace:
|
|
28
|
+
object3d = self.copy(name=name)
|
|
29
|
+
else:
|
|
30
|
+
object3d = self
|
|
31
|
+
inplace_function(object3d, *args, **kwargs)
|
|
32
|
+
if hasattr(object3d, '__internals__'):
|
|
33
|
+
object3d.__internals__.clear()
|
|
34
|
+
return object3d
|
|
35
|
+
return enhanced_inplace_function
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
##############################
|
|
39
|
+
# ABSTRACT 3D OBJECT CLASS #
|
|
40
|
+
##############################
|
|
41
|
+
|
|
42
|
+
class Abstract3DObject(ABC):
|
|
43
|
+
"""Abstract class for 3d objects that can be transformed in 3d.
|
|
44
|
+
The child classes have to define `mirror`, `rotate` and `translate`,
|
|
45
|
+
then more routines such as `translate_x` and `translated` are automatically available."""
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def translate(self, vector):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def rotate(self, axis, angle):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def mirror(self, plane):
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
@inplace_transformation
|
|
60
|
+
def translate_x(self, tx):
|
|
61
|
+
return self.translate((tx, 0., 0.))
|
|
62
|
+
|
|
63
|
+
@inplace_transformation
|
|
64
|
+
def translate_y(self, ty):
|
|
65
|
+
return self.translate((0., ty, 0.))
|
|
66
|
+
|
|
67
|
+
@inplace_transformation
|
|
68
|
+
def translate_z(self, tz):
|
|
69
|
+
return self.translate((0., 0., tz))
|
|
70
|
+
|
|
71
|
+
@inplace_transformation
|
|
72
|
+
def translate_point_to_point(self, point_a, point_b):
|
|
73
|
+
return self.translate(np.asarray(point_b) - np.asarray(point_a))
|
|
74
|
+
|
|
75
|
+
@inplace_transformation
|
|
76
|
+
def rotate_x(self, thetax):
|
|
77
|
+
return self.rotate(Ox_axis, thetax)
|
|
78
|
+
|
|
79
|
+
@inplace_transformation
|
|
80
|
+
def rotate_y(self, thetay):
|
|
81
|
+
return self.rotate(Oy_axis, thetay)
|
|
82
|
+
|
|
83
|
+
@inplace_transformation
|
|
84
|
+
def rotate_z(self, thetaz):
|
|
85
|
+
return self.rotate(Oz_axis, thetaz)
|
|
86
|
+
|
|
87
|
+
@inplace_transformation
|
|
88
|
+
def rotate_around_center_to_align_vectors(self, center, vec1, vec2):
|
|
89
|
+
"""Rotate self such that if vec1 is in self, then it will point in the same direction as vec2."""
|
|
90
|
+
vec1 = np.asarray(vec1)
|
|
91
|
+
vec2 = np.asarray(vec2)
|
|
92
|
+
if parallel_vectors_with_same_direction(vec1, vec2):
|
|
93
|
+
return self
|
|
94
|
+
else:
|
|
95
|
+
if parallel_vectors(vec1, vec2):
|
|
96
|
+
if parallel_vectors(vec1, e_x):
|
|
97
|
+
axis = Axis(vector=np.cross(vec1, e_y), point=center)
|
|
98
|
+
else:
|
|
99
|
+
axis = Axis(vector=np.cross(vec1, e_x), point=center)
|
|
100
|
+
return self.rotate(axis, np.pi)
|
|
101
|
+
else:
|
|
102
|
+
axis = Axis(vector=np.cross(vec1, vec2), point=center)
|
|
103
|
+
return self.rotate(axis, np.arccos(np.dot(vec1, vec2)))
|
|
104
|
+
|
|
105
|
+
def translated(self, *args, **kwargs):
|
|
106
|
+
return self.translate(*args, inplace=False, **kwargs)
|
|
107
|
+
|
|
108
|
+
def rotated(self, *args, **kwargs):
|
|
109
|
+
return self.rotate(*args, inplace=False, **kwargs)
|
|
110
|
+
|
|
111
|
+
def mirrored(self, *args, **kwargs):
|
|
112
|
+
return self.mirror(*args, inplace=False, **kwargs)
|
|
113
|
+
|
|
114
|
+
def translated_x(self, *args, **kwargs):
|
|
115
|
+
return self.translate_x(*args, inplace=False, **kwargs)
|
|
116
|
+
|
|
117
|
+
def translated_y(self, *args, **kwargs):
|
|
118
|
+
return self.translate_y(*args, inplace=False, **kwargs)
|
|
119
|
+
|
|
120
|
+
def translated_z(self, *args, **kwargs):
|
|
121
|
+
return self.translate_z(*args, inplace=False, **kwargs)
|
|
122
|
+
|
|
123
|
+
def translated_point_to_point(self, *args, **kwargs):
|
|
124
|
+
return self.translate_point_to_point(*args, inplace=False, **kwargs)
|
|
125
|
+
|
|
126
|
+
def rotated_x(self, *args, **kwargs):
|
|
127
|
+
return self.rotate_x(*args, inplace=False, **kwargs)
|
|
128
|
+
|
|
129
|
+
def rotated_y(self, *args, **kwargs):
|
|
130
|
+
return self.rotate_y(*args, inplace=False, **kwargs)
|
|
131
|
+
|
|
132
|
+
def rotated_z(self, *args, **kwargs):
|
|
133
|
+
return self.rotate_z(*args, inplace=False, **kwargs)
|
|
134
|
+
|
|
135
|
+
def rotated_around_center_to_align_vectors(self, *args, **kwargs):
|
|
136
|
+
return self.rotate_around_center_to_align_vectors(*args, inplace=False, **kwargs)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class ClippableMixin(ABC):
|
|
140
|
+
"""Abstract base class for object that can be clipped.
|
|
141
|
+
The child classes should implement a `clip` method, then this abstract
|
|
142
|
+
class will append the new methods `clipped`, `keep_immersed_part` and
|
|
143
|
+
`immersed_part`, all based on `clip`.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
@abstractmethod
|
|
147
|
+
def clip(self, plane):
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
def clipped(self, plane, **kwargs):
|
|
151
|
+
# Same API as for the other transformations
|
|
152
|
+
return self.clip(plane, inplace=False, **kwargs)
|
|
153
|
+
|
|
154
|
+
@inplace_transformation
|
|
155
|
+
def keep_immersed_part(self, free_surface=0.0, *, sea_bottom=None, water_depth=None):
|
|
156
|
+
self.clip(Plane(normal=(0, 0, 1), point=(0, 0, free_surface)))
|
|
157
|
+
water_depth = _get_water_depth(free_surface, water_depth, sea_bottom,
|
|
158
|
+
default_water_depth=np.inf)
|
|
159
|
+
if water_depth < np.inf:
|
|
160
|
+
self.clip(Plane(normal=(0, 0, -1), point=(0, 0, free_surface-water_depth)))
|
|
161
|
+
return self
|
|
162
|
+
|
|
163
|
+
def immersed_part(self, free_surface=0.0, *, sea_bottom=None, water_depth=None):
|
|
164
|
+
return self.keep_immersed_part(free_surface, inplace=False, name=self.name,
|
|
165
|
+
sea_bottom=sea_bottom, water_depth=water_depth)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
######################
|
|
169
|
+
# HELPER FUNCTIONS #
|
|
170
|
+
######################
|
|
171
|
+
|
|
172
|
+
def orthogonal_vectors(vec1, vec2) -> bool:
|
|
173
|
+
return np.linalg.norm(vec1 @ vec2) < 1e-6
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def parallel_vectors(vec1, vec2) -> bool:
|
|
177
|
+
return np.linalg.norm(np.cross(vec1, vec2)) < 1e-6
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def parallel_vectors_with_same_direction(vec1, vec2) -> bool:
|
|
181
|
+
return parallel_vectors(vec1, vec2) and np.dot(vec1, vec2) > 0
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
################
|
|
185
|
+
# AXIS CLASS #
|
|
186
|
+
################
|
|
187
|
+
|
|
188
|
+
class Axis(Abstract3DObject):
|
|
189
|
+
def __init__(self, vector=(1, 0, 0), point=(0, 0, 0)):
|
|
190
|
+
assert len(vector) == 3, "Vector of an axis should be given as a 3-ple of values."
|
|
191
|
+
assert len(point) == 3, "Point of an axis should be given as a 3-ple of values."
|
|
192
|
+
vector = np.array(vector, float)
|
|
193
|
+
self.vector = vector / np.linalg.norm(vector)
|
|
194
|
+
self.point = np.array(point, float)
|
|
195
|
+
|
|
196
|
+
def __repr__(self):
|
|
197
|
+
return f"Axis(vector={self.vector}, point={self.point})"
|
|
198
|
+
|
|
199
|
+
def __contains__(self, other_point):
|
|
200
|
+
if len(other_point) == 3:
|
|
201
|
+
other_point = np.asarray(other_point, dtype=float)
|
|
202
|
+
return parallel_vectors(other_point - self.point, self.vector)
|
|
203
|
+
else:
|
|
204
|
+
raise NotImplementedError
|
|
205
|
+
|
|
206
|
+
def __eq__(self, other):
|
|
207
|
+
if isinstance(self, Axis):
|
|
208
|
+
return (self is other) or (self.point in other and parallel_vectors(self.vector, other.vector))
|
|
209
|
+
else:
|
|
210
|
+
return NotImplemented
|
|
211
|
+
|
|
212
|
+
def is_orthogonal_to(self, other):
|
|
213
|
+
if isinstance(other, Plane):
|
|
214
|
+
return parallel_vectors(self.vector, other.normal)
|
|
215
|
+
elif len(other) == 3: # The other is supposed to be a vector given as a 3-ple
|
|
216
|
+
return orthogonal_vectors(self.vector, other)
|
|
217
|
+
else:
|
|
218
|
+
raise NotImplementedError
|
|
219
|
+
|
|
220
|
+
def is_parallel_to(self, other):
|
|
221
|
+
if isinstance(other, Plane):
|
|
222
|
+
return orthogonal_vectors(self.vector, other.normal)
|
|
223
|
+
elif isinstance(other, Axis):
|
|
224
|
+
return parallel_vectors(self.vector, other.vector)
|
|
225
|
+
elif len(other) == 3: # The other is supposed to be a vector given as a 3-ple
|
|
226
|
+
return parallel_vectors(self.vector, other)
|
|
227
|
+
else:
|
|
228
|
+
raise NotImplementedError
|
|
229
|
+
|
|
230
|
+
def angle_with_respect_to(self, other_axis: 'Axis') -> float:
|
|
231
|
+
"""Angle between two axes."""
|
|
232
|
+
return np.arccos(np.dot(self.vector, other_axis.vector))
|
|
233
|
+
|
|
234
|
+
################################
|
|
235
|
+
# Transformation of the axis #
|
|
236
|
+
################################
|
|
237
|
+
|
|
238
|
+
def copy(self, name=None):
|
|
239
|
+
return Axis(vector=self.vector.copy(), point=self.point.copy())
|
|
240
|
+
|
|
241
|
+
@inplace_transformation
|
|
242
|
+
def translate(self, vector):
|
|
243
|
+
self.point += vector
|
|
244
|
+
return self
|
|
245
|
+
|
|
246
|
+
@inplace_transformation
|
|
247
|
+
def rotate(self, axis, angle):
|
|
248
|
+
rot_matrix = axis.rotation_matrix(angle)
|
|
249
|
+
self.point = rot_matrix @ (self.point - axis.point) + axis.point
|
|
250
|
+
self.vector = rot_matrix @ self.vector
|
|
251
|
+
return self
|
|
252
|
+
|
|
253
|
+
@inplace_transformation
|
|
254
|
+
def mirror(self, plane):
|
|
255
|
+
self.point -= 2 * (self.point @ plane.normal - plane.c) * plane.normal
|
|
256
|
+
self.vector -= 2 * (self.vector @ plane.normal) * plane.normal
|
|
257
|
+
return self
|
|
258
|
+
|
|
259
|
+
###########
|
|
260
|
+
# Other #
|
|
261
|
+
###########
|
|
262
|
+
|
|
263
|
+
def rotation_matrix(self, theta):
|
|
264
|
+
"""Rotation matrix around the vector according to Rodrigues' formula."""
|
|
265
|
+
ux, uy, uz = self.vector
|
|
266
|
+
W = np.array([[0, -uz, uy],
|
|
267
|
+
[uz, 0, -ux],
|
|
268
|
+
[-uy, ux, 0]])
|
|
269
|
+
return np.identity(3) + np.sin(theta)*W + 2*np.sin(theta/2)**2 * (W @ W)
|
|
270
|
+
|
|
271
|
+
def rotate_vectors(self, vectors, angle):
|
|
272
|
+
vectors = np.asarray(vectors)
|
|
273
|
+
return (self.rotation_matrix(angle) @ vectors.T).T
|
|
274
|
+
|
|
275
|
+
def rotate_points(self, points, angle):
|
|
276
|
+
points = np.asarray(points)
|
|
277
|
+
return self.rotate_vectors(points - self.point, angle) + self.point
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
Ox_axis = Axis(vector=e_x, point=(0, 0, 0))
|
|
281
|
+
Oy_axis = Axis(vector=e_y, point=(0, 0, 0))
|
|
282
|
+
Oz_axis = Axis(vector=e_z, point=(0, 0, 0))
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
#################
|
|
286
|
+
# PLANE CLASS #
|
|
287
|
+
#################
|
|
288
|
+
|
|
289
|
+
class Plane(Abstract3DObject):
|
|
290
|
+
"""3D plane, oriented by the direction of their normal."""
|
|
291
|
+
def __init__(self, normal=(0.0, 0.0, 1.0), point=(0.0, 0.0, 0.0)):
|
|
292
|
+
normal = np.asarray(normal, dtype=float)
|
|
293
|
+
self.normal = normal / np.linalg.norm(normal)
|
|
294
|
+
self.point = np.asarray(point, dtype=float)
|
|
295
|
+
|
|
296
|
+
def __repr__(self):
|
|
297
|
+
return f"Plane(normal={self.normal}, point={self.point})"
|
|
298
|
+
|
|
299
|
+
def __contains__(self, other):
|
|
300
|
+
if isinstance(other, Axis):
|
|
301
|
+
return other.point in self and orthogonal_vectors(self.normal, other.vector)
|
|
302
|
+
elif len(other) == 3:
|
|
303
|
+
return orthogonal_vectors(other - self.point, self.normal)
|
|
304
|
+
else:
|
|
305
|
+
raise NotImplementedError
|
|
306
|
+
|
|
307
|
+
def __eq__(self, other):
|
|
308
|
+
"""Plane are considered equal only when their normal are pointing in the same direction."""
|
|
309
|
+
if isinstance(other, Plane):
|
|
310
|
+
return ((self is other) or
|
|
311
|
+
(other.point in self and parallel_vectors_with_same_direction(self.normal, other.normal)))
|
|
312
|
+
else:
|
|
313
|
+
return NotImplemented
|
|
314
|
+
|
|
315
|
+
def is_orthogonal_to(self, other):
|
|
316
|
+
if isinstance(other, Axis):
|
|
317
|
+
return parallel_vectors(self.normal, other.vector)
|
|
318
|
+
elif isinstance(other, Plane):
|
|
319
|
+
return orthogonal_vectors(self.normal, other.normal)
|
|
320
|
+
elif len(other) == 3: # The other is supposed to be a vector given as a 3-ple
|
|
321
|
+
return parallel_vectors(self.normal, other)
|
|
322
|
+
else:
|
|
323
|
+
raise NotImplementedError
|
|
324
|
+
|
|
325
|
+
@property
|
|
326
|
+
def c(self):
|
|
327
|
+
"""Distance from plane to origin."""
|
|
328
|
+
return np.linalg.norm(self.normal @ self.point)
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def s(self):
|
|
332
|
+
"""Distance from origin to plane along the normal"""
|
|
333
|
+
return np.dot(self.normal, self.point)
|
|
334
|
+
|
|
335
|
+
#################################
|
|
336
|
+
# Transformation of the plane #
|
|
337
|
+
#################################
|
|
338
|
+
|
|
339
|
+
def copy(self, name=None):
|
|
340
|
+
return Plane(normal=self.normal.copy(), point=self.point.copy())
|
|
341
|
+
|
|
342
|
+
@inplace_transformation
|
|
343
|
+
def translate(self, vector):
|
|
344
|
+
self.point = self.point + np.asarray(vector)
|
|
345
|
+
return self
|
|
346
|
+
|
|
347
|
+
@inplace_transformation
|
|
348
|
+
def rotate(self, axis, angle):
|
|
349
|
+
rot_matrix = axis.rotation_matrix(angle)
|
|
350
|
+
self.point = rot_matrix @ self.point
|
|
351
|
+
self.normal = rot_matrix @ self.normal
|
|
352
|
+
return self
|
|
353
|
+
|
|
354
|
+
@inplace_transformation
|
|
355
|
+
def mirror(self, plane):
|
|
356
|
+
self.point -= 2 * (self.point @ plane.normal - plane.c) * plane.normal
|
|
357
|
+
self.normal -= 2 * (self.normal @ plane.normal) * plane.normal
|
|
358
|
+
return self
|
|
359
|
+
|
|
360
|
+
###########
|
|
361
|
+
# Other #
|
|
362
|
+
###########
|
|
363
|
+
|
|
364
|
+
def distance_to_point(self, points):
|
|
365
|
+
"""
|
|
366
|
+
Return the orthogonal distance of points with respect to the plane.
|
|
367
|
+
The distance is counted positively on one side of the plane and negatively on the other.
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
points : ndarray
|
|
372
|
+
Array of points coordinates
|
|
373
|
+
|
|
374
|
+
Returns
|
|
375
|
+
-------
|
|
376
|
+
dist : ndarray
|
|
377
|
+
Array of distances of points with respect to the plane
|
|
378
|
+
"""
|
|
379
|
+
return np.dot(points, self.normal) - np.dot(self.point, self.normal)
|
|
380
|
+
|
|
381
|
+
def get_edge_intersection(self, p0, p1):
|
|
382
|
+
"""
|
|
383
|
+
Returns the coordinates of the intersection point between the plane and the edge P0P1.
|
|
384
|
+
|
|
385
|
+
Parameters
|
|
386
|
+
----------
|
|
387
|
+
p0 : ndarray
|
|
388
|
+
Coordinates of point p0
|
|
389
|
+
p1 : ndarray
|
|
390
|
+
Coordinates of point P1
|
|
391
|
+
|
|
392
|
+
Returns
|
|
393
|
+
-------
|
|
394
|
+
I : ndarray
|
|
395
|
+
Coordinates of intersection point
|
|
396
|
+
"""
|
|
397
|
+
assert len(p0) == 3 and len(p1) == 3
|
|
398
|
+
|
|
399
|
+
p0n = np.dot(p0, self.normal)
|
|
400
|
+
p1n = np.dot(p1, self.normal)
|
|
401
|
+
t = (p0n - self.s) / (p0n - p1n)
|
|
402
|
+
if t < 0. or t > 1.:
|
|
403
|
+
raise RuntimeError('Intersection is outside the edge')
|
|
404
|
+
return (1-t) * p0 + t * p1
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
yOz_Plane = Plane(normal=e_x, point=(0, 0, 0))
|
|
408
|
+
xOz_Plane = Plane(normal=e_y, point=(0, 0, 0))
|
|
409
|
+
xOy_Plane = Plane(normal=e_z, point=(0, 0, 0))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Tuple, Protocol, runtime_checkable
|
|
2
|
+
from numpy.typing import ArrayLike
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@runtime_checkable
|
|
6
|
+
class MeshLike(Protocol):
|
|
7
|
+
"""Minimal API that a class describing a mesh should implement to be
|
|
8
|
+
usable with the rest of Capytaine.
|
|
9
|
+
|
|
10
|
+
The goal is two-fold:
|
|
11
|
+
1. Use at runtime to identify a mesh for functions that behaves
|
|
12
|
+
differently depending on the type of the input (e.g. Delhommeau().evaluate).
|
|
13
|
+
2. Use as documentation for third-party mesh implementation.
|
|
14
|
+
|
|
15
|
+
In the future, it could also be used for static typing.
|
|
16
|
+
"""
|
|
17
|
+
vertices: ArrayLike
|
|
18
|
+
faces: ArrayLike
|
|
19
|
+
nb_vertices: int
|
|
20
|
+
nb_faces: int
|
|
21
|
+
faces_centers: ArrayLike
|
|
22
|
+
faces_normals: ArrayLike
|
|
23
|
+
faces_areas: ArrayLike
|
|
24
|
+
faces_radiuses: ArrayLike
|
|
25
|
+
quadrature_points: Tuple[ArrayLike, ArrayLike]
|
|
26
|
+
|
|
27
|
+
def __short_str__(self) -> str:
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
def extract_faces(self, faces_id):
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def join_meshes(*meshes, return_mask):
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def with_normal_vector_going_down(self, **kwargs):
|
|
37
|
+
...
|