Source code for LRSplines.element

"""
This class represents a single mesh element (i.e., a rectangle), represented in terms
of its lower left and upper right corner.
"""
import typing

from LRSplines.b_spline import BSpline

BasisFunctions = typing.List[BSpline]


[docs]class Element(object): def __init__(self, u_min: float, v_min: float, u_max: float, v_max: float, level: int = 0) -> None: """ Initialize an Element (a rectangle) with lower left corner (u_min, v_min) and upper right corner (u_max, v_max) :param u_min: lower left u_component :param v_min: lower left v_component :param u_max: upper right u_component :param v_max: upper right v_component """ self.u_min = u_min self.v_min = v_min self.u_max = u_max self.v_max = v_max self.supported_b_splines: BasisFunctions = [] self.level = level
[docs] def fetch_neighbours(self): """ Returns a list of neighbouring elements based on supported B-splines. :return: """ pass
[docs] def contains(self, u: float, v: float) -> bool: """ Returns True if this element contains the point (u, v) :param u: u_component :param v: v_component :return: """ return self.u_min <= u <= self.u_max and self.v_min <= v <= self.v_max
[docs] def get_supported_b_spline(self, i: int): """ Returns the i-th supported B-spline. :param i: index of supported B-spline :return: b-spline i """ return self.supported_b_splines[i]
[docs] def add_supported_b_spline(self, b_spline): """ Adds a B-spline to the list of supported B-splines. :param b_spline: B-spline to add """ self.supported_b_splines.append(b_spline)
[docs] def remove_supported_b_spline(self, b_spline): """ Removes a B-spline from the list of supported B-splines. :param b_spline: B-spline to remove """ if self.has_supported_b_spline(b_spline): self.supported_b_splines.remove(b_spline) return True return False
[docs] def has_supported_b_spline(self, b_spline) -> bool: """ Returns True if given b_spline is among the list of supported b-splines. :param b_spline: B-spline to check :return: True or False """ return b_spline in self.supported_b_splines
[docs] def update_supported_basis(self, b_splines: BasisFunctions) -> None: """ Updates the list of supported basis functions. :param b_splines: list of BSpline functions """ raise NotImplementedError('Updating of supported basis functions is not implemented yet')
[docs] def split(self, axis: int, split_value: float) -> "Element": """ Splits the element into two, resizing into the left half, and returning the right half. :return: right half of element. """ # Create new element and resize old. new_element = None if axis == 0: # vertical split if not self.u_min < split_value < self.u_max: return None new_element = Element(split_value, self.v_min, self.u_max, self.v_max, level=self.level + 1) self.level += 1 self.u_max = split_value elif axis == 1: # horizontal split if not self.v_min < split_value < self.v_max: return None new_element = Element(self.u_min, split_value, self.u_max, self.v_max, level=self.level + 1) self.level += 1 self.v_max = split_value # Check all supported basis functions if their support has changed. supported_basis_to_remove = [] for basis in self.supported_b_splines: if basis.add_to_support_if_intersects(new_element): new_element.add_supported_b_spline(basis) if not basis.intersects(self): supported_basis_to_remove.append(basis) basis.remove_from_support(self) return new_element
@property def midpoint(self) -> typing.Tuple[float, float]: """ Returns the midpoint of the element. :return: midpoint of the element """ return (self.u_max - self.u_min) * 0.5 + self.u_min, (self.v_max - self.v_min) * 0.5 + self.v_min @property def area(self) -> float: """ Returns the area of the element. :return: area of the element """ return (self.u_max - self.u_min) * (self.v_max - self.v_min)
[docs] def intersects(self, other: 'Element') -> bool: """ Returns true if this element intersects the other element with *positive* area. :param other: the element to check intersection with. :return: true or false """ intersection_u = min(other.u_max, self.u_max) - max(other.u_min, self.u_min) intersection_v = min(other.v_max, self.v_max) - max(other.v_min, self.v_min) if intersection_u <= 0 or intersection_v <= 0: return False else: return True
def __eq__(self, other: 'Element') -> bool: """ Checks whether the two elements are equal within a tolerance. :param other: element to compare :return: true or false """ tol = 1.0e-14 return abs(self.u_min - other.u_min) < tol and abs(self.u_max - other.u_max) < tol and abs( self.v_min - other.v_min) < tol and abs(self.v_max - other.v_max) < tol def __repr__(self): return "Element({}, {}, {}, {})".format(self.u_min, self.v_min, self.u_max, self.v_max)
[docs] def is_overloaded(self) -> bool: """ Returns true if the number of supported B-splines on this element is greater than (d1 + 1)*(d2 + 1). :return: true if overloaded, false otherwise """ b = self.supported_b_splines[0] return len(self.supported_b_splines) > (b.degree_u + 1) * (b.degree_v + 1)
# TODO: Now that I think about it, this hash may change during the lifetime of the object, due to the # Element.split method. def __hash__(self): return hash(tuple([self.u_min, self.u_max, self.v_min, self.v_max]))
[docs] def evaluate_basis(self, u, v): """ Evaluates all the supported B-splines at the point u, v :param u: :param v: :return: """ values = np.zeros(len(self.supported_b_splines)) for i, b in enumerate(self.supported_b_splines): values[i] = b(u, v) return values