Commit 8b71fffa authored by Daniel Böckenhoff (Laptop)'s avatar Daniel Böckenhoff (Laptop)
Browse files

triangles neat, mesh3D messy

parent 64f4270c
...@@ -7,17 +7,17 @@ Mail: daniel.boeckenhoff@ipp.mpg.de ...@@ -7,17 +7,17 @@ Mail: daniel.boeckenhoff@ipp.mpg.de
core of tfields library core of tfields library
contains numpy ndarray derived bases of the tfields package contains numpy ndarray derived bases of the tfields package
""" """
import tfields.bases import warnings
import numpy as np import os
import pathlib
from six import string_types
from contextlib import contextmanager from contextlib import contextmanager
from collections import Counter from collections import Counter
import numpy as np
import sympy import sympy
import scipy as sp import scipy as sp
import scipy.spatial # NOQA: F401 import tfields.bases
import os
from six import string_types
import pathlib
import warnings
np.seterr(all='warn', over='raise') np.seterr(all='warn', over='raise')
...@@ -356,19 +356,23 @@ class Tensors(AbstractNdarray): ...@@ -356,19 +356,23 @@ class Tensors(AbstractNdarray):
__slot_setters__ = [tfields.bases.get_coord_system_name] __slot_setters__ = [tfields.bases.get_coord_system_name]
def __new__(cls, tensors, **kwargs): def __new__(cls, tensors, **kwargs):
dtype = kwargs.pop('dtype', np.float64) dtype = kwargs.pop('dtype', None)
order = kwargs.pop('order', None) order = kwargs.pop('order', None)
dim = kwargs.pop('dim', None) dim = kwargs.pop('dim', None)
''' copy constructor extracts the kwargs from tensors''' ''' copy constructor extracts the kwargs from tensors'''
if issubclass(type(tensors), Tensors): if issubclass(type(tensors), Tensors):
dtype = tensors.dtype
if dim is not None: if dim is not None:
dim = tensors.dim dim = tensors.dim
coordSys = kwargs.pop('coordSys', tensors.coordSys) coordSys = kwargs.pop('coordSys', tensors.coordSys)
tensors = tensors.copy() tensors = tensors.copy()
tensors.transform(coordSys) tensors.transform(coordSys)
kwargs['coordSys'] = coordSys kwargs['coordSys'] = coordSys
if dtype is None:
dtype = tensors.dtype
else:
if dtype is None:
dtype = np.float64
''' demand iterable structure ''' ''' demand iterable structure '''
try: try:
...@@ -443,7 +447,7 @@ class Tensors(AbstractNdarray): ...@@ -443,7 +447,7 @@ class Tensors(AbstractNdarray):
Merge also shifts the maps to still refer to the same tensors Merge also shifts the maps to still refer to the same tensors
>>> tm_a = tfields.TensorMaps(merge, maps=[[[0, 1, 2]]]) >>> tm_a = tfields.TensorMaps(merge, maps=[[[0, 1, 2]]])
>>> tm_b = tm_a.copy() >>> tm_b = tm_a.copy()
>>> tm_a.coordSys >>> assert tm_a.coordSys == 'cylinder'
>>> tm_merge = tfields.TensorMaps.merged(tm_a, tm_b) >>> tm_merge = tfields.TensorMaps.merged(tm_a, tm_b)
>>> assert tm_merge.coordSys == 'cylinder' >>> assert tm_merge.coordSys == 'cylinder'
>>> assert tm_merge.maps[0].equal([[0, 1, 2], >>> assert tm_merge.maps[0].equal([[0, 1, 2],
...@@ -853,11 +857,14 @@ class Tensors(AbstractNdarray): ...@@ -853,11 +857,14 @@ class Tensors(AbstractNdarray):
>>> import numpy >>> import numpy
>>> import sympy >>> import sympy
>>> x, y, z = sympy.symbols('x y z') >>> x, y, z = sympy.symbols('x y z')
>>> p = tfields.Points3D([[1., 2., 3.], [4., 5., 6.], [1, 2, -6], >>> p = tfields.Tensors([[1., 2., 3.], [4., 5., 6.], [1, 2, -6],
... [-5, -5, -5], [1,0,-1], [0,1,-1]]) ... [-5, -5, -5], [1,0,-1], [0,1,-1]])
>>> np.array_equal(p.evalf(x > 0), >>> np.array_equal(p.evalf(x > 0),
... [True, True, True, False, True, False]) ... [True, True, True, False, True, False])
True True
>>> np.array_equal(p.evalf(x >= 0),
... [True, True, True, False, True, True])
True
And combination And combination
>>> np.array_equal(p.evalf((x > 0) & (y < 3)), >>> np.array_equal(p.evalf((x > 0) & (y < 3)),
...@@ -1181,14 +1188,18 @@ class TensorFields(Tensors): ...@@ -1181,14 +1188,18 @@ class TensorFields(Tensors):
""" """
item = super(TensorFields, self).__getitem__(index) item = super(TensorFields, self).__getitem__(index)
if issubclass(type(item), TensorFields): try:
if isinstance(index, slice): if issubclass(type(item), TensorFields):
item.fields = [field.__getitem__(index) for field in item.fields] if isinstance(index, tuple):
elif isinstance(index, tuple): index = index[0]
item.fields = [field.__getitem__(index[0]) for field in item.fields] if isinstance(index, slice):
else:
if item.fields:
item.fields = [field.__getitem__(index) for field in item.fields] item.fields = [field.__getitem__(index) for field in item.fields]
else:
if item.fields:
item.fields = [field.__getitem__(index) for field in item.fields]
except IndexError as err:
warnings.warn("Index error occured for field.__getitem__. Error "
"message: {err}".format(**locals()))
return item return item
...@@ -1527,8 +1538,8 @@ class TensorMaps(TensorFields): ...@@ -1527,8 +1538,8 @@ class TensorMaps(TensorFields):
if __name__ == '__main__': # pragma: no cover if __name__ == '__main__': # pragma: no cover
import doctest import doctest
# doctest.testmod() doctest.testmod()
doctest.run_docstring_examples(TensorMaps, globals()) # doctest.run_docstring_examples(TensorMaps, globals())
# doctest.run_docstring_examples(TensorFields, globals()) # doctest.run_docstring_examples(TensorFields, globals())
# doctest.run_docstring_examples(AbstractNdarray.copy, globals()) # doctest.run_docstring_examples(AbstractNdarray.copy, globals())
# doctest.run_docstring_examples(TensorMaps.equal, globals()) # doctest.run_docstring_examples(TensorMaps.equal, globals())
...@@ -42,9 +42,13 @@ def evalf(array, cutExpression=None, coords=None): ...@@ -42,9 +42,13 @@ def evalf(array, cutExpression=None, coords=None):
If array of other shape than (?, 3) is given, the coords need to be specified If array of other shape than (?, 3) is given, the coords need to be specified
>>> a0, a1 = sympy.symbols('a0 a1') >>> a0, a1 = sympy.symbols('a0 a1')
>>> assert np.array_equal(tfields.evalf([[0., 1.], [-1, 3]], a1 > 2, >>> assert np.array_equal(tfields.evalf([[0., 1.], [-1, 3]], a1 > 2,
... coords=[a0, a1]), ... coords=[a0, a1]),
... np.array([False, True], dtype=bool)) ... np.array([False, True], dtype=bool))
>= is taken care of
>>> assert np.array_equal(tfields.evalf(a, x >= 0),
... np.array([ True, True, True, False, True, True]))
""" """
if isinstance(array, list): if isinstance(array, list):
array = np.array(array) array = np.array(array)
...@@ -57,7 +61,6 @@ def evalf(array, cutExpression=None, coords=None): ...@@ -57,7 +61,6 @@ def evalf(array, cutExpression=None, coords=None):
coords = sympy.symbols('x y z') coords = sympy.symbols('x y z')
else: else:
raise ValueError("coords are None and shape is not (?, 3)") raise ValueError("coords are None and shape is not (?, 3)")
elif len(coords) != array.shape[1]: elif len(coords) != array.shape[1]:
raise ValueError("Length of coords is not {0} but {1}".format(array.shape[1], len(coords))) raise ValueError("Length of coords is not {0} but {1}".format(array.shape[1], len(coords)))
...@@ -65,7 +68,7 @@ def evalf(array, cutExpression=None, coords=None): ...@@ -65,7 +68,7 @@ def evalf(array, cutExpression=None, coords=None):
cutExpression, cutExpression,
modules={'&': np.logical_and, '|': np.logical_or}) modules={'&': np.logical_and, '|': np.logical_or})
mask = np.array([preMask(*x) for x in array], dtype=bool) mask = np.array([preMask(*vals) for vals in array], dtype=bool)
return mask return mask
......
This diff is collapsed.
...@@ -39,6 +39,67 @@ class Triangles3D(tfields.TensorFields): ...@@ -39,6 +39,67 @@ class Triangles3D(tfields.TensorFields):
.format(len(obj))) .format(len(obj)))
return obj return obj
def ntriangles(self):
"""
Returns:
int: number of triangles
"""
return len(self) // 3
def _to_triangles_mask(self, mask):
mask = np.array(mask)
mask = mask.reshape((self.ntriangles(), 3))
mask = mask.all(axis=1)
return mask
def __getitem__(self, index):
"""
In addition to the usual, also slice fields
Examples:
>>> import tfields
>>> import numpy as np
>>> vectors = tfields.Tensors(np.array([range(30)] * 3).T)
>>> triangles = tfields.Triangles3D(vectors, range(10))
>>> assert np.array_equal(triangles[3:6],
... [[3] * 3,
... [4] * 3,
... [5] * 3])
>>> assert triangles[3:6].fields[0][0] == 1
"""
item = super(tfields.TensorFields, self).__getitem__(index)
try: # __iter__ will try except __getitem__(i) until IndexError
if issubclass(type(item), Triangles3D): # block int, float, ...
if len(item) % 3 != 0:
item = tfields.Tensors(item)
elif item.fields:
# build triangle index / indices / mask when possible
tri_index = None
if isinstance(index, tuple):
index = index[0]
if isinstance(index, int):
pass
elif isinstance(index, slice):
start = index.start or 0
stop = index.stop or len(self)
step = index.step
if start % 3 == 0 and (stop - start) % 3 == 0 and step is None:
tri_index = slice(start // 3, stop // 3)
else:
tri_index = self._to_triangles_mask(index)
# apply triangle index to fields
if not tri_index is None:
item.fields = [field.__getitem__(tri_index)
for field in item.fields]
else:
item = tfields.Tensors(item)
except IndexError as err:
warnings.warn("Index error occured for field.__getitem__. Error "
"message: {err}".format(**locals()))
return item
@classmethod @classmethod
def merged(cls, *objects, **kwargs): def merged(cls, *objects, **kwargs):
with warnings.catch_warnings(): with warnings.catch_warnings():
...@@ -61,20 +122,25 @@ class Triangles3D(tfields.TensorFields): ...@@ -61,20 +122,25 @@ class Triangles3D(tfields.TensorFields):
def triangleScalars(self, scalars): def triangleScalars(self, scalars):
self.fields = tfields.scalars_to_fields(scalars) self.fields = tfields.scalars_to_fields(scalars)
def get_ntriangles(self):
"""
Returns:
int: number of triangles
"""
return len(self) // 3
def evalf(self, expression=None, coordSys=None): def evalf(self, expression=None, coordSys=None):
""" """
Triangle3D implementation Triangle3D implementation
Examples:
>>> from sympy.abc import x
>>> t = tfields.Triangles3D([[1., 2., 3.], [-4., 5., 6.], [1, 2, -6],
... [5, -5, -5], [1,0,-1], [0,1,-1],
... [-5, -5, -5], [1,0,-1], [0,1,-1]])
>>> mask = t.evalf(x >= 0)
>>> assert np.array_equal(t[mask],
... tfields.Triangles3D([[ 5., -5., -5.],
... [ 1., 0., -1.],
... [ 0., 1., -1.]]))
Returns:
np.array: mask which is True, where expression evaluates True
""" """
mask = super(Triangles3D, self).evalf(expression, coordSys=coordSys) mask = super(Triangles3D, self).evalf(expression, coordSys=coordSys)
mask = mask.reshape((self.get_ntriangles(), 3)) mask = self._to_triangles_mask(mask)
mask = mask.all(axis=1)
mask = np.array([mask] * 3).T.reshape((len(self))) mask = np.array([mask] * 3).T.reshape((len(self)))
return mask return mask
...@@ -86,25 +152,23 @@ class Triangles3D(tfields.TensorFields): ...@@ -86,25 +152,23 @@ class Triangles3D(tfields.TensorFields):
>>> import tfields >>> import tfields
>>> x, y, z = sympy.symbols('x y z') >>> x, y, z = sympy.symbols('x y z')
>>> t = tfields.Triangles3D([[1., 2., 3.], [-4., 5., 6.], [1, 2, -6], >>> t = tfields.Triangles3D([[1., 2., 3.], [-4., 5., 6.], [1, 2, -6],
... [5, -5, -5], [1,0,-1], [0,1,-1], [-5, -5, -5], ... [5, -5, -5], [1, 0, -1], [0, 1, -1],
... [1,0,-1], [0,1,-1]]) ... [-5, -5, -5], [1, 0, -1], [0, 1, -1]])
>>> tc = t.cut(x >= 0) >>> tc = t.cut(x >= 0)
>>> tc >>> assert tc.equal(tfields.Triangles3D([[ 5., -5., -5.],
Triangles3D([[ 5., -5., -5.], ... [ 1., 0., -1.],
[ 1., 0., -1.], ... [ 0., 1., -1.]]))
[ 0., 1., -1.]]) >>> assert np.array_equal(tc.triangleScalars, [])
>>> tc.triangleScalars >>> t.fields.append(tfields.Tensors([1,2,3]))
array([], shape=(1, 0), dtype=float64)
>>> t.appendScalars([1,2,3])
>>> tc2 = t.cut(x >= 0) >>> tc2 = t.cut(x >= 0)
>>> tc2.triangleScalars >>> assert np.array_equal(tc2.triangleScalars, np.array([[2.]]))
array([[ 2.]])
""" """
mask = self.evalf(expression, coordSys=coordSys) mask = self.evalf(expression, coordSys=coordSys)
inst = self[mask].copy() inst = self[mask].copy()
inst.triangleScalars = inst.triangleScalars[mask.reshape((self.get_ntriangles(), 3)).T[0]] # inst.triangleScalars =
# inst.triangleScalars[mask.reshape((self.ntriangles(), 3)).T[0]]
return inst return inst
...@@ -113,7 +177,7 @@ class Triangles3D(tfields.TensorFields): ...@@ -113,7 +177,7 @@ class Triangles3D(tfields.TensorFields):
""" """
Cached method to retrieve areas of triangles Cached method to retrieve areas of triangles
""" """
transform = np.eye() transform = np.eye(3)
return self.areas(transform=transform) return self.areas(transform=transform)
def areas(self, transform=None): def areas(self, transform=None):
...@@ -124,31 +188,30 @@ class Triangles3D(tfields.TensorFields): ...@@ -124,31 +188,30 @@ class Triangles3D(tfields.TensorFields):
The triangle points are transformed with transform if given The triangle points are transformed with transform if given
before calclulating the area before calclulating the area
Examples: Examples:
>>> m = tfields.Mesh3D([[1,0,0], [0,0,1], [0,0,0]], [[0, 1, 2]]); >>> m = tfields.Mesh3D([[1,0,0], [0,0,1], [0,0,0]],
>>> m.triangles.areas() ... faces=[[0, 1, 2]])
array([ 0.5]) >>> assert np.allclose(m.triangles.areas(), np.array([0.5]))
>>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0], [0,0,1]], [[0, 1, 2], [1, 2, 3]]); >>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0], [0,0,1]],
>>> m.triangles.areas() ... faces=[[0, 1, 2], [1, 2, 3]])
array([ 0.5, 0.5]) >>> assert np.allclose(m.triangles.areas(), np.array([0.5, 0.5]))
>>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [1,1,0], [0,0,1], [1,0,1]], >>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [1,1,0], [0,0,1], [1,0,1]],
... [[0, 1, 2], [0, 3, 4]]); ... faces=[[0, 1, 2], [0, 3, 4]])
>>> m.triangles.areas() >>> assert np.allclose(m.triangles.areas(), np.array([0.5, 0.5]))
array([ 0.5, 0.5])
""" """
if transform is None: if transform is None:
return self._areas return self._areas
else: else:
indices = range(self.get_ntriangles()) indices = range(self.ntriangles())
aIndices = [i * 3 for i in indices] aIndices = [i * 3 for i in indices]
bIndices = [i * 3 + 1 for i in indices] bIndices = [i * 3 + 1 for i in indices]
cIndices = [i * 3 + 2 for i in indices] cIndices = [i * 3 + 2 for i in indices]
# define 3 vectors building the triangle, transform it back and take their norm # define 3 vectors building the triangle, transform it back and take their norm
if not np.array_equal(transform, np.eye): if not np.array_equal(transform, np.eye(3)):
a = np.linalg.norm(np.linalg.solve(transform.T, a = np.linalg.norm(np.linalg.solve(transform.T,
(self[aIndices, :] - self[bIndices, :]).T), (self[aIndices, :] - self[bIndices, :]).T),
axis=0) axis=0)
...@@ -175,7 +238,7 @@ class Triangles3D(tfields.TensorFields): ...@@ -175,7 +238,7 @@ class Triangles3D(tfields.TensorFields):
Returns: Returns:
three np.arrays with corner points of triangles three np.arrays with corner points of triangles
""" """
indices = range(self.get_ntriangles()) indices = range(self.ntriangles())
aIndices = [i * 3 for i in indices] aIndices = [i * 3 for i in indices]
bIndices = [i * 3 + 1 for i in indices] bIndices = [i * 3 + 1 for i in indices]
cIndices = [i * 3 + 2 for i in indices] cIndices = [i * 3 + 2 for i in indices]
...@@ -191,12 +254,13 @@ class Triangles3D(tfields.TensorFields): ...@@ -191,12 +254,13 @@ class Triangles3D(tfields.TensorFields):
Examples: Examples:
>>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]], >>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]],
... [[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]); ... faces=[[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]);
>>> m.triangles.circumcenters() >>> assert np.allclose(
Points3D([[ 5.00000000e-01, 5.00000000e-01, 0.00000000e+00], ... m.triangles.circumcenters(),
[ -5.00000000e-01, 5.00000000e-01, 0.00000000e+00], ... [[0.5, 0.5, 0.0],
[ 0.00000000e+00, 0.00000000e+00, 2.22044605e-16], ... [-0.5, 0.5, 0.0],
[ 3.33333333e-01, 3.33333333e-01, 3.33333333e-01]]) ... [0.0, 0.0, 0.0],
... [1.0 / 3, 1.0 / 3, 1.0 / 3]])
""" """
pointA, pointB, pointC = self.corners() pointA, pointB, pointC = self.corners()
...@@ -221,7 +285,7 @@ class Triangles3D(tfields.TensorFields): ...@@ -221,7 +285,7 @@ class Triangles3D(tfields.TensorFields):
this version is faster but takes much more ram also. this version is faster but takes much more ram also.
So much that i get memory error with a 32 GB RAM So much that i get memory error with a 32 GB RAM
""" """
nT = self.get_ntriangles() nT = self.ntriangles()
mat = np.ones((1, 3)) / 3.0 mat = np.ones((1, 3)) / 3.0
# matrix product calculatesq center of all triangles # matrix product calculatesq center of all triangles
return tfields.Points3D(np.dot(mat, self.reshape(nT, 3, 3))[0], coordSys=self.coordSys) return tfields.Points3D(np.dot(mat, self.reshape(nT, 3, 3))[0], coordSys=self.coordSys)
...@@ -239,7 +303,7 @@ class Triangles3D(tfields.TensorFields): ...@@ -239,7 +303,7 @@ class Triangles3D(tfields.TensorFields):
""" """
Examples: Examples:
>>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]], >>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]],
... [[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]); ... faces=[[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]);
>>> m.triangles.centroids() >>> m.triangles.centroids()
Points3D([[ 0.33333333, 0.33333333, 0. ], Points3D([[ 0.33333333, 0.33333333, 0. ],
[-0.33333333, 0.33333333, 0. ], [-0.33333333, 0.33333333, 0. ],
...@@ -267,12 +331,13 @@ class Triangles3D(tfields.TensorFields): ...@@ -267,12 +331,13 @@ class Triangles3D(tfields.TensorFields):
""" """
Examples: Examples:
>>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]], >>> m = tfields.Mesh3D([[0,0,0], [1,0,0], [-1,0,0], [0,1,0], [0,0,1]],
... [[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]); ... faces=[[0, 1, 3],[0, 2, 3],[1,2,4], [1, 3, 4]]);
>>> m.triangles.norms() >>> assert np.allclose(m.triangles.norms(),
array([[ 0. , 0. , 1. ], ... [[0.0, 0.0, 1.0],
[ 0. , 0. , -1. ], ... [0.0, 0.0, -1.0],
[ 0. , 1. , 0. ], ... [0.0, 1.0, 0.0],
[ 0.57735027, 0.57735027, 0.57735027]]) ... [0.57735027] * 3],
... atol=1e-8)
""" """
ab, ac = self.edges() ab, ac = self.edges()
...@@ -303,21 +368,25 @@ class Triangles3D(tfields.TensorFields): ...@@ -303,21 +368,25 @@ class Triangles3D(tfields.TensorFields):
... [0.1, 0.0, 0.1]]) ... [0.1, 0.0, 0.1]])
if point lies in the plane, return np.nan, else inf for w if delta is exactly 0. if point lies in the plane, return np.nan, else inf for w if delta is exactly 0.
>>> assert np.array_equal(m2.triangles._baricentric(np.array([0.2, 0.2, 0]), >>> baric = m2.triangles._baricentric(np.array([0.2, 0.2, 0]),
... delta=0.), ... delta=0.),
... [[0.1, 0.1, np.nan], >>> baric_expected = np.array([[0.1, 0.1, np.nan],
... [0.1, 0.0, np.inf]]) ... [0.1, 0.0, np.inf]])
>>> assert ((baric == baric_expected) | (np.isnan(baric) &
... np.isnan(baric_expected))).all()
If you define triangles that have colinear side vectors or in general lead to If you define triangles that have colinear side vectors or in general lead to
not invertable matrices [ab, ac, ab x ac] the values will be nan not invertable matrices [ab, ac, ab x ac] the values will be nan
>>> m3 = tfields.Mesh3D([[0,0,0], [2,0,0], [4,0,0], [0,1,0]], [[0, 1, 2], [0, 1, 3]]); >>> m3 = tfields.Mesh3D([[0,0,0], [2,0,0], [4,0,0], [0,1,0]], faces=[[0, 1, 2], [0, 1, 3]]);
>>> bc = m3.triangles._baricentric(np.array([0.2, 0.2, 0]), delta=0.3) >>> bc = m3.triangles._baricentric(np.array([0.2, 0.2, 0]), delta=0.3)
>>> assert np.array_equal(bc, [[ np.nan, np.nan, np.nan], [ 0.1, 0.2, 0. ]]) >>> bc_exp = np.array([[ np.nan, np.nan, np.nan], [ 0.1, 0.2, 0. ]])
>>> assert ((bc == bc_exp) | (np.isnan(bc) &
... np.isnan(bc_exp))).all()
Returns: Returns:
np.ndarray: barycentric coordinates u, v, w of point with respect to each triangle np.ndarray: barycentric coordinates u, v, w of point with respect to each triangle
""" """
if self.get_ntriangles() == 0: if self.ntriangles() == 0:
return np.array([]) return np.array([])
a, _, _ = self.corners() a, _, _ = self.corners()
...@@ -375,9 +444,10 @@ class Triangles3D(tfields.TensorFields): ...@@ -375,9 +444,10 @@ class Triangles3D(tfields.TensorFields):
Returns: Returns:
np.array: boolean mask, True where point in a triangle within delta np.array: boolean mask, True where point in a triangle within delta
Examples: Examples:
>>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0]], [[0, 1, 2]]); >>> m = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0]], faces=[[0, 1, 2]]);
>>> m.triangles._in_triangles(tfields.Points3D([[0.2, 0.2, 0]])) >>> assert np.array_equal(
array([ True], dtype=bool) ... m.triangles._in_triangles(tfields.Points3D([[0.2, 0.2, 0]])),
... np.array([True], dtype=bool))
wrong format of point will raise a ValueError wrong format of point will raise a ValueError
>>> m.triangles._in_triangles(tfields.Points3D([[0.2, 0.2, 0], [0.2, 0.2, 0]])) >>> m.triangles._in_triangles(tfields.Points3D([[0.2, 0.2, 0], [0.2, 0.2, 0]]))
...@@ -387,32 +457,44 @@ class Triangles3D(tfields.TensorFields): ...@@ -387,32 +457,44 @@ class Triangles3D(tfields.TensorFields):
All Triangles are tested All Triangles are tested
>>> m2 = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0], [4,0,0], [4, 4, 0], [8, 0, 0]], >>> m2 = tfields.Mesh3D([[1,0,0], [0,1,0], [0,0,0], [4,0,0], [4, 4, 0], [8, 0, 0]],
... [[0, 1, 2], [3, 4, 5]]); ... faces=[[0, 1, 2], [3, 4, 5]]);
>>> m2.triangles._in_triangles(np.array([0.2, 0.2, 0])) >>> assert np.array_equal(
array([ True, False], dtype=bool) ... m2.triangles._in_triangles(np.array([0.2, 0.2, 0])),
>>> m2.triangles._in_triangles(np.array([5, 2, 0])) ... np.array([True, False], dtype=bool))
array([False, True], dtype=bool) >>> assert np.array_equal(
... m2.triangles._in_triangles(np.array([5, 2, 0])),
... np.array([False, True], dtype=bool))
delta allows to accept points that lie within delta orthogonal to the tringle plain delta allows to accept points that lie within delta orthogonal to the tringle plain
>>> m2.triangles._in_triangles(np.array([0.2, 0.2, 9000]), 0.0) >>> assert np.array_equal(
array([False, False], dtype=bool) ... m2.triangles._in_triangles(np.array([0.2, 0.2, 9000]), 0.0),
>>> m2.triangles._in_triangles(np.array([0.2, 0.2, 0.1]), 0.2) ... np.array([False, False], dtype=bool))
array([ True, False], dtype=bool) >>> assert np.array_equal(
... m2.triangles._in_triangles(np.array([0.2, 0.2, 0.1]), 0.2),
... np.array([ True, False], dtype=bool))
If you define triangles that have colinear side vectors or in general lead to If you define triangles that have colinear side vectors or in general lead to
not invertable matrices the you will always get False not invertable matrices the you will always get False
>>> m3 = tfields.Mesh3D([[0,0,0], [2,0,0], [4,0,0], [0,1,0]], [[0, 1, 2], [0, 1, 3]]); >>> m3 = tfields.Mesh3D([[0,0,0], [2,0,0], [4,0,0], [0,1,0]],
... faces=[[0, 1, 2], [0, 1, 3]]);
>>> import pytest >>> import pytest
>>> with pytest.warns(UserWarning) as record: >>> mask = m3.triangles._in_triangles(np.array([0.2, 0.2, 0]), delta=0.3)
... mask = m3.triangles._in_triangles(np.array([0.2, 0.2, 0]), delta=0.3) >>> assert np.array_equal(mask,
>>> mask ... np.array([False, True], dtype=bool))
array([False, True], dtype=bool)