proteindf_bridge.position のソースコード

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (C) 2014 The ProteinDF development team.
# see also AUTHORS and README if provided.
#
# This file is a part of the ProteinDF software package.
#
# The ProteinDF is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# The ProteinDF is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ProteinDF.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import annotations

import math
import numpy
from typing import Union, Sequence, List, Optional, Any

from .vector import Vector
from .error import BrInputError, BrValueError

import logging
logger = logging.getLogger(__name__)


[ドキュメント] class Position(object): """ >>> p = Position([5.0, 3.0, -1.2]) >>> p.x 5.0 >>> p.y 3.0 >>> p.z -1.2 >>> p.x = 0.0 >>> p.y = 1.0 >>> p.z = 2.0 >>> p == Position([0, 1, 2]) True >>> abs(abs(p) - 2.23606) < 1.0E-5 True >>> _ = p.norm() >>> p == Position([0, 1/math.sqrt(5), 2/math.sqrt(5)]) True >>> p.move_to([3, 4, 5]) >>> p == Position([3.0, 4.0, 5.0]) True >>> tmp = p * 2.0 >>> tmp == Position([6.0, 8.0, 10.0]) True >>> tmp = (-1.0 * p) >>> tmp == Position([-3.0, -4.0, -5.0]) True >>> a = Position([1, 2, 3]) >>> b = Position([2, 3, 4]) >>> a * b 20.0 >>> p = a + b >>> p == Position([3, 5, 7]) True >>> a += b >>> a == Position([3, 5, 7]) True >>> p = a - b >>> p == Position([1, 2, 3]) True >>> a -= b >>> a == Position([1, 2, 3]) True >>> a.dot(b) 20.0 >>> n = a.cross(b) >>> n == Position([-1, 2, -1]) True """ def __init__(self, *args, **kwds): self._initialize() len_args = len(args) if len_args > 0: if len_args == 3: self._position[0] = float(args[0]) self._position[1] = float(args[1]) self._position[2] = float(args[2]) elif len_args == 1: if isinstance(args[0], Position): self._position[0] = args[0]._position[0] self._position[1] = args[0]._position[1] self._position[2] = args[0]._position[2] elif (isinstance(args[0], (list, tuple, numpy.ndarray, Vector)) and len(args[0]) == 3): self._position[0] = float(args[0][0]) self._position[1] = float(args[0][1]) self._position[2] = float(args[0][2]) elif isinstance(args[0], str): line = args[0] line = line.replace(",", " ") inputs = line.split() self._position[0] = float(inputs.pop(0).rstrip( ",")) if (len(inputs) > 0) else 0.0 self._position[1] = float(inputs.pop(0).rstrip( ",")) if (len(inputs) > 0) else 0.0 self._position[2] = float(inputs.pop(0).rstrip( ",")) if (len(inputs) > 0) else 0.0 else: raise BrInputError("position::__init__", "illegal input") def _initialize(self): self.epsilon = 1.0E-5 self._position = [0.0, 0.0, 0.0] # -------------------------------------------------------------------------- @property def xyz(self): return self._position def __get_x(self): return self._position[0] def __set_x(self, new_x): self._position[0] = float(new_x) x = property(__get_x, __set_x) def __get_y(self): return self._position[1] def __set_y(self, new_y): self._position[1] = float(new_y) y = property(__get_y, __set_y) def __get_z(self): return self._position[2] def __set_z(self, new_z): self._position[2] = float(new_z) z = property(__get_z, __set_z) # --------------------------------------------------------------------------
[ドキュメント] def get_raw_data(self) -> List[float]: return self._position
[ドキュメント] def move_to(self, position: Union[Position, Sequence[float], str]) -> None: tmp = Position(position) self._position = tmp._position
[ドキュメント] def square_distance_from(self, other: Optional[Union[Position, Sequence[float]]] = None) -> float: if other is None: other = Position() other = Position(other) d2 = 0.0 for i in range(3): tmp = self._position[i] - other._position[i] d2 += tmp * tmp return d2
[ドキュメント] def distance_from(self, other: Optional[Union[Position, Sequence[float]]] = None) -> float: d2 = self.square_distance_from(other) return math.sqrt(d2)
[ドキュメント] def norm(self) -> Position: n = self.__abs__() if n < 1.0e-15: raise BrValueError("Position.norm()", "cannot normalize zero vector") self._position = [x / n for x in self._position] return self
[ドキュメント] def rotate(self, mat: Any) -> None: assert mat.rows == 3 assert mat.cols == 3 v1 = Vector(self._position) v2 = mat * v1 self._position = v2.to_list()
[ドキュメント] def dot(self, rhs): """ Compute the dot product. """ return float(numpy.dot(self._position, rhs._position))
[ドキュメント] def cross(self, rhs): """ Compute the cross product. """ n = numpy.cross(self._position, rhs._position) answer = Position(n) return answer
def __str__(self): return f"({self.x: 10.6f}, {self.y: 10.6f}, {self.z: 10.6f})" def __eq__(self, rhs): answer = False if isinstance(rhs, Position): if (self.distance_from(rhs) < self.epsilon): answer = True return answer def __ne__(self, rhs): return not(self.__eq__(rhs)) def __neg__(self): return Position([-x for x in self._position]) def __abs__(self): return math.sqrt(sum([x * x for x in self._position])) def __add__(self, rhs): if isinstance(rhs, Position): return Position([x + y for x, y in zip(self._position, rhs._position)]) else: raise BrInputError("position.__add__", "illegal input: Position is required.") def __sub__(self, rhs): return self.__add__(-rhs) def __mul__(self, rhs2): rhs1 = Position(self) if isinstance(rhs2, Position): return sum([x * y for x, y in zip(rhs1._position, rhs2._position)]) elif isinstance(rhs2, float): rhs1._position = [x * rhs2 for x in rhs1._position] return rhs1 else: raise BrInputError("position.__add__", "illegal input: Position is required.") __rmul__ = __mul__ def __imul__(self, rhs): v = float(rhs) self._position[0] *= v self._position[1] *= v self._position[2] *= v return self def __truediv__(self, rhs): v = float(rhs) return Position([x / v for x in self._position]) def __itruediv__(self, rhs): return self.__imul__(1.0 / float(rhs)) def __getitem__(self, i): i = int(i) assert(0 <= i and i < 3) return self._position[i] def __setitem__(self, i, v): i = int(i) assert(0 <= i and i < 3) self._position[i] = v # ------------------------------------------------------------------ # serialize # ------------------------------------------------------------------ def __getstate__(self): return self.get_raw_data() def __setstate__(self, state): assert isinstance(state, (list, tuple)) assert len(state) == 3 self._initialize() self._position[0] = float(state[0]) self._position[1] = float(state[1]) self._position[2] = float(state[2])
if __name__ == "__main__": import doctest doctest.testmod()