def _refresh(self): # get the positions of the centers of the head and tail circles direction = Vector([cos(self._rotation), sin(self._rotation), 0]) distance = (self._length - self._width) / 2 displacement = distance * direction self._head_center = self._position + displacement self._tail_center = self._position - displacement # get the positions of the corners of the bacilli box side = Vector([-sin(self._rotation), cos(self._rotation), 0]) radius = self._width / 2 self._head_right = self._head_center + radius * side self._head_left = self._head_center - radius * side self._tail_right = self._tail_center + radius * side self._tail_left = self._tail_center - radius * side # compute the region of interest self._region = Rectangle( floor(min(self._head_center.x, self._tail_center.x) - radius), #left floor(min(self._head_center.y, self._tail_center.y) - radius), #top ceil(max(self._head_center.x, self._tail_center.x) + radius) + 1, #right ceil(max(self._head_center.y, self._tail_center.y) + radius) + 1) #bottom self._needs_refresh = False
def split(self, alpha: float) -> (Cell, Cell): assert 0 < alpha < 1 direction = Vector([np.cos(self.rotation), np.sin(self.rotation), 0]) unit = self.dimensions.length * direction front = self.position + unit / 2 back = self.position - unit / 2 center = self.position + (1 / 2 - alpha) * unit position_1 = (front + center) / 2 position_2 = (center + back) / 2 cell_1 = Bacilli(self.name + '0', position_1.x, position_1.y, self.dimensions.width, alpha * self.dimensions.length, self.rotation, in_flux=True) cell_2 = Bacilli(self.name + '1', position_2.x, position_2.y, self.dimensions.width, (1 - alpha) * self.dimensions.length, self.rotation, in_flux=True) return cell_1, cell_2
def split(self, alpha): """Splits a cell into two cells with a ratio determined by alpha.""" if self._needs_refresh: self._refresh() direction = Vector([cos(self._rotation), sin(self._rotation), 0]) unit = self._length * direction front = self._position + unit / 2 back = self._position - unit / 2 center = self._position + (0.5 - float(alpha)) * unit position1 = (front + center) / 2 position2 = (center + back) / 2 cell1 = Bacilli(self._name + '0', position1.x, position1.y, self._width, self._length * float(alpha), self._rotation, alpha, self._opacity) cell2 = Bacilli(self._name + '1', position2.x, position2.y, self._width, self._length * (1 - float(alpha)), self._rotation, alpha, self._opacity) return cell1, cell2
def __init__(self, name, x, y, width, length, rotation): super().__init__(name) self._position = Vector([x, y, 0]) self._width = width self._length = length self._rotation = rotation self._needs_refresh = True
def __init__(self, name, x, y, width, length, rotation): #upper left corner is the origin #x,y are index of the array #x:column index y:row index super().__init__(name) self._position = Vector([x, y, 0]) self._width = width self._length = length self._rotation = rotation self._needs_refresh = True
def combine(self, cell): """Combines this cell with another cell.""" if self._needs_refresh: self._refresh() if cell._needs_refresh: cell._refresh() separation = self._position - cell._position direction = separation / sqrt(separation @ separation) # get combined front direction1 = Vector([cos(self._rotation), sin(self._rotation), 0]) distance1 = self._length - self._width if direction1 @ direction >= 0: head1 = self._position + distance1 * direction1 / 2 else: head1 = self._position - distance1 * direction1 / 2 extent1 = head1 + self._width * direction / 2 front = self._position + ( (extent1 - self._position) @ direction) * direction # get combined back direction2 = Vector([cos(cell._rotation), sin(cell._rotation), 0]) distance2 = cell._length - cell._width if direction2 @ direction >= 0: tail2 = cell._position - distance2 * direction2 / 2 else: tail2 = cell._position + distance2 * direction2 / 2 extent2 = tail2 - cell._width * direction / 2 back = cell._position + ( (extent2 - cell._position) @ direction) * direction # create new cell position = (front + back) / 2 rotation = atan2(direction.y, direction.x) width = (self._width + cell._width) / 2 length = sqrt((front - back) @ (front - back)) return Bacilli(self._name[:-1], position.x, position.y, width, length, rotation, "combined alpha unknown", (self._opacity + cell.opacity) / 2)
def __init__(self, name, x, y, width, length, rotation): super().__init__(name) self._position = Vector([x, y, 0]) self._width = width self._length = length self._rotation = rotation self._needs_refresh = True # diffraction constant, controlling how much does the pattern spread self._sigma = 3.0 # diffraction value, controlling how bright the diffraction pattern is self._diff_v = 0.5
def combine(self, cell_1: Cell, cell_2: Cell): separation = cell_1.position - cell_2.position direction = separation / np.sqrt(separation @ separation) # get combined front direction_1 = Vector( [np.cos(cell_1.rotation), np.sin(cell_1.rotation), 0]) distance_1 = cell_1.dimensions.length - cell_1.dimensions.width if direction_1 @ direction >= 0: head_1 = cell_1.position + distance_1 * direction_1 / 2 else: head_1 = cell_1.position - distance_1 * direction_1 / 2 extent_1 = head_1 + cell_1.dimensions.width * direction / 2 front = cell_1.position + ( (extent_1 - cell_1.position) @ direction) * direction # get combined back direction_2 = Vector( [np.cos(cell_2.rotation), np.sin(cell_2.rotation), 0]) distance_2 = cell_2.dimensions.length - cell_2.dimensions.width if direction_2 @ direction >= 0: tail_2 = cell_2.position - distance_2 * direction_2 / 2 else: tail_2 = cell_2.position + distance_2 * direction_2 / 2 extent_2 = tail_2 - cell_2.dimensions.width * direction / 2 back = cell_2.position + ( (extent_2 - cell_2.position) @ direction) * direction # update cell self.position = (front + back) / 2 self.rotation = np.arctan2(direction.y, direction.x) self.dimensions.width = (cell_1.dimensions.width + cell_2.dimensions.width) / 2 self.dimensions.length = np.sqrt((front - back) @ (front - back)) self._update()
def _update(self): # head and tail direction = Vector([np.cos(self.rotation), np.sin(self.rotation), 0]) distance = self.dimensions.length - self.dimensions.width self._head = self.position + distance * direction / 2 self._tail = self.position - distance * direction / 2 # body right = Vector([-np.sin(self.rotation), np.cos(self.rotation), 0]) radius = self.dimensions.width / 2 self._head_right = self._head + radius * right self._head_left = self._head - radius * right self._tail_right = self._tail + radius * right self._tail_left = self._tail - radius * right # region of interest self._region = Rectangle() self._region.left = min(self._head.x, self._tail.x) - radius self._region.right = max(self._head.x, self._tail.x) + radius self._region.top = min(self._head.y, self._tail.y) - radius self._region.bottom = max(self._head.y, self._tail.y) + radius
def update(self, position=None, rotation=None, dimensions=None): changes = False if position is not None: self.position = Vector(position) changes = True if rotation is not None: self.rotation = float(rotation) changes = True if dimensions is not None: self.dimensions = Dimensions(dimensions) changes = True if changes is not None: self._update()
def __init__(self, name, x, y, width, length, rotation, in_flux=False): super().__init__(name) self.position = Vector([x, y, 0]) self.dimensions = Dimensions([length, width]) self.rotation = float(rotation) self.in_flux = in_flux self._head = None self._tail = None self._head_left = None self._head_right = None self._tail_left = None self._tail_right = None self._region = None self._update()