"""mesh coordinate placeholders (X, Y, Z arrays)"""
import os
from typing import Union, Tuple, Any, BinaryIO
if os.environ.get('__USE_CUDA', '0') == '1':
import cupy as np
from cupy import ndarray, float64
else:
import numpy as np
from numpy import ndarray, float64
import struct
from g3d.defs import G3DEntity
from g3d.defs import FunctionByPass
[docs]
class Coordinates(G3DEntity):
def __init__(self, *args: Any, **kwargs: Any) -> None:
self._size = 0
self._X = np.zeros(self._size)
self._Y = np.zeros(self._size)
self._Z = np.zeros(self._size)
self.__n_bak = self._size
self.__X_bak = np.zeros(self.__n_bak)
self.__Y_bak = np.zeros(self.__n_bak)
self.__Z_bak = np.zeros(self.__n_bak)
super().__init__(*args, **kwargs)
def _set_from_args(self, *args: Any, **kwargs: Any) -> ndarray:
bps = self._get_function_evaluate_status(**kwargs)
if bps is FunctionByPass.SELF:
args_stat = np.ones(len(args))
else:
args_stat = super()._set_from_args(*args)
if bps in [FunctionByPass.EVALUATE, FunctionByPass.SELF]:
if np.sum(args_stat) == 1: # will only read args if number of remaining args is one
size_set = False
for i in range(len(args)):
if args_stat[i] == 1:
arg = args[i]
if type(arg) is Coordinates:
args_stat[i] = 0
self.copy(arg)
size_set = True
elif type(arg) in [int, np.int64, np.int32] and not size_set:
args_stat[i] = 0
if type(arg) in [np.int64, np.int32]:
self._size = arg.item()
else:
self._size = arg
size_set = True
self.allocate_XYZ()
return args_stat
[docs]
def set_from_key_value(self, key: str, value: Any) -> bool:
if super().set_from_key_value(key, value):
return True
elif key == 'size':
self._size = value
self.allocate_XYZ()
return True
return False
def _set_default(self) -> None:
super()._set_default()
self._tag = 'g3d_array_entity'
self.reset_XYZ()
@property
def size(self) -> int:
"""
:return:
"""
return self._size
@size.setter
def size(self, val: int) -> None:
self._size = val
self.allocate_XYZ()
@property
def X(self) -> ndarray:
"""
:return:
"""
return self._X
@property
def Y(self) -> ndarray:
"""
:return:
"""
return self._Y
@property
def Z(self) -> ndarray:
"""
:return:
"""
return self._Z
@property
def x_min(self) -> float64:
"""
:return:
"""
return np.min(self._X)
@property
def x_max(self) -> float64:
"""
:return:
"""
return np.max(self._X)
@property
def y_min(self) -> float64:
"""
:return:
"""
return np.min(self._Y)
@property
def y_max(self) -> float64:
"""
:return:
"""
return np.max(self._Y)
@property
def z_min(self) -> float64:
"""
:return:
"""
return np.min(self._Z)
@property
def z_max(self) -> float64:
"""
:return:
"""
return np.max(self._Z)
[docs]
def reset_XYZ(self) -> None:
"""
"""
self._size = 0
self.allocate_XYZ()
self.__reset_backup()
[docs]
def allocate_XYZ(self, N: int = None) -> None:
"""
:param N:
"""
if N is not None:
self._size = N
self._X = np.zeros(self._size)
self._Y = np.zeros(self._size)
self._Z = np.zeros(self._size)
[docs]
def backup(self) -> None:
"""
"""
self.__reset_backup()
self.__n_bak = self._size
if self.__n_bak > 0:
self.__X_bak = np.zeros(self.__n_bak)
self.__Y_bak = np.zeros(self.__n_bak)
self.__Z_bak = np.zeros(self.__n_bak)
self.__X_bak[:] = self._X[:]
self.__Y_bak[:] = self._Y[:]
self.__Z_bak[:] = self._Z[:]
[docs]
def get_from_backup(self, reset_bak: bool = False) -> None:
"""
:param reset_bak:
"""
if self.__n_bak > 0:
ll = np.arange(self.__n_bak)
self._X[ll] = self.__X_bak[ll]
self._Y[ll] = self.__Y_bak[ll]
self._Z[ll] = self.__Z_bak[ll]
if reset_bak:
self.__reset_backup()
def __reset_backup(self) -> None:
self.__n_bak = 0
self.__X_bak = np.zeros(self.__n_bak)
self.__Y_bak = np.zeros(self.__n_bak)
self.__Z_bak = np.zeros(self.__n_bak)
[docs]
def backup_is_allocated(self) -> bool:
"""
:return:
"""
return self.__n_bak > 0
def __calculate_extreme_values(self) -> None:
self.__x_min = np.min(self._X)
self.__x_max = np.max(self._X)
self.__y_min = np.min(self._Y)
self.__y_max = np.max(self._Y)
self.__z_min = np.min(self._Z)
self.__z_max = np.max(self._Z)
[docs]
def get_extreme_values(self) -> Tuple[float64, ...]:
"""
:return:
"""
self.__calculate_extreme_values()
return self.__x_min, self.__x_max, self.__y_min, self.__y_max, self.__z_min, self.__z_max
[docs]
def print_extreme_values(self) -> None:
"""
"""
if self._size > 0:
self.__calculate_extreme_values()
print(' x-coordinates: min=%12.5E, max=%12.5E' % (float(self.__x_min), float(self.__x_max)))
print(' y-coordinates: min=%12.5E, max=%12.5E' % (float(self.__y_min), float(self.__y_max)))
print(' z-coordinates: min=%12.5E, max=%12.5E' % (float(self.__z_min), float(self.__z_max)))
[docs]
def get_x_min_x_max(self) -> Tuple[float64, float64]:
"""
:return:
"""
self.__calculate_extreme_values()
return self.__x_min, self.__x_max
[docs]
def get_y_min_y_max(self) -> Tuple[float64, float64]:
"""
:return:
"""
self.__calculate_extreme_values()
return self.__y_min, self.__y_max
[docs]
def get_z_min_z_max(self) -> Tuple[float64, float64]:
"""
:return:
"""
self.__calculate_extreme_values()
return self.__z_min, self.__z_max
[docs]
def nullify(self) -> None:
"""
"""
if self._size:
self._X *= 0.
self._Y *= 0.
self._Z *= 0.
[docs]
def copy(self, e: 'Coordinates') -> None:
super().copy(e)
self.copy_XYZ(e)
[docs]
def copy_XYZ(self, *args: Any) -> None:
"""
:param args:
"""
if len(args) == 1: # copy from entity
e = args[0]
X, Y, Z = e.get_XYZ()
self._size = len(X)
self.allocate_XYZ()
if self._size > 0:
ll = np.arange(self._size)
self._X[ll] = X[ll]
self._Y[ll] = Y[ll]
self._Z[ll] = Z[ll]
elif len(args) == 2: # local copy from to
l_from = args[0]
l_to = args[1]
self._X[l_to] = self._X[l_from]
self._Y[l_to] = self._Y[l_from]
self._Z[l_to] = self._Z[l_from]
[docs]
def copy_X(self, *args: Any) -> None:
"""
:param args:
"""
if len(args) == 1: # copy from entity
e = args[0]
X = e.get_X()
ll = np.arange(self._size)
self._X[ll] = X[ll]
elif len(args) == 2: # local copy from to
l_from = args[0]
l_to = args[1]
self._X[l_to] = self._X[l_from]
[docs]
def copy_Y(self, *args: Any) -> None:
"""
:param args:
"""
if len(args) == 1: # copy from entity
e = args[0]
Y = e.get_Y()
ll = np.arange(self._size)
self._Y[ll] = Y[ll]
elif len(args) == 2: # local copy from to
l_from = args[0]
l_to = args[1]
self._Y[l_to] = self._Y[l_from]
[docs]
def copy_Z(self, *args: Any) -> None:
"""
:param args:
"""
if len(args) == 1: # copy from entity
e = args[0]
Z = e.get_Z()
ll = np.arange(self._size)
self._Z[ll] = Z[ll]
elif len(args) == 2: # local copy from to
l_from = args[0]
l_to = args[1]
self._Z[l_to] = self._Z[l_from]
[docs]
def get_XYZ(self, lp: Union[int, list[int], ndarray] = None) -> Union[Tuple[ndarray, ...], Tuple[float64, ...]]:
"""
:param lp:
:return:
"""
if lp is None:
return self._X, self._Y, self._Z
else:
if type(lp) is int:
return float64(self._X[lp]), float64(self._Y[lp]), float64(self._Z[lp])
else:
return self._X[lp], self._Y[lp], self._Z[lp]
[docs]
def get_X(self, lp: Union[int, list[int], ndarray] = None) -> Union[ndarray, float64]:
"""
:param lp:
:return:
"""
if lp is None:
return self._X
else:
if type(lp) is int:
return float64(self._X[lp])
else:
return self._X[lp]
[docs]
def get_Y(self, lp: Union[int, list[int], ndarray] = None) -> Union[ndarray, float64]:
"""
:param lp:
:return:
"""
if lp is None:
return self._Y
else:
if type(lp) is int:
return float64(self._Y[lp])
else:
return self._Y[lp]
[docs]
def get_Z(self, lp: Union[int, list[int], ndarray] = None) -> Union[ndarray, float64]:
"""
:param lp:
:return:
"""
if lp is None:
return self._Z
else:
if type(lp) is int:
return float64(self._Z[lp])
else:
return self._Z[lp]
[docs]
def set_XYZ(self, x: Union[float, ndarray], y: Union[float, ndarray], z: Union[float, ndarray],
lp: Union[int, list[int], ndarray] = None) -> None:
"""
:param x:
:param y:
:param z:
:param lp:
"""
if type(x) is float:
if lp is None:
self._X[:] = x
self._Y[:] = y
self._Z[:] = z
else:
self._X[lp] = x
self._Y[lp] = y
self._Z[lp] = z
else:
ll = np.arange(self._size)
self._X[ll] = x[ll]
self._Y[ll] = y[ll]
self._Z[ll] = z[ll]
[docs]
def set_X(self, x: Union[float, ndarray], lp: Union[int, list[int], ndarray] = None) -> None:
"""
:param x:
:param lp:
"""
if type(x) is float:
if lp is None:
self._X[:] = x
else:
self._X[lp] = x
else:
ll = np.arange(self._size)
self._X[ll] = x[ll]
[docs]
def set_Y(self, y: Union[float, ndarray], lp: Union[int, list[int], ndarray] = None) -> None:
"""
:param y:
:param lp:
"""
if type(y) is float:
if lp is None:
self._Y[:] = y
else:
self._Y[lp] = y
else:
ll = np.arange(self._size)
self._Y[ll] = y[ll]
[docs]
def set_Z(self, z: Union[float, ndarray], lp: Union[int, list[int], ndarray] = None) -> None:
"""
:param z:
:param lp:
"""
if type(z) is float:
if lp is None:
self._Z[:] = z
else:
self._Z[lp] = z
else:
ll = np.arange(self._size)
self._Z[ll] = z[ll]
[docs]
def scale(self, sf: float) -> None:
"""
:param sf:
"""
self._X *= sf
self._Y *= sf
self._Z *= sf
[docs]
def write_to_file(self, f: BinaryIO) -> None:
"""
:param f:
"""
f.write(bytes(self._X))
f.write(bytes(self._Y))
f.write(bytes(self._Z))
[docs]
def read_from_file(self, f: BinaryIO) -> None:
"""
:param f:
"""
N = self._size
self._X[:] = np.array(struct.unpack('d' * N, f.read(N * 8)))
self._Y[:] = np.array(struct.unpack('d' * N, f.read(N * 8)))
self._Z[:] = np.array(struct.unpack('d' * N, f.read(N * 8)))
[docs]
def scatter_XY(self, plt: Any, m: str = 'o') -> None:
"""
:param plt:
:param m:
"""
plt.scatter(self._X, self._Y, marker=m)
[docs]
def scatter_XZ(self, plt: Any, m: str = 'o') -> None:
"""
:param plt:
:param m:
"""
plt.scatter(self._X, self._Z, marker=m)
[docs]
def scatter_YZ(self, plt: Any, m: str = 'o') -> None:
"""
:param plt:
:param m:
"""
plt.scatter(self._Y, self._Z, marker=m)