Source code for ixpeobssim.core.geometry

#!/usr/bin/env python
#
# Copyright (C) 2020, the ixpeobssim team.
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

"""Geometry module.
"""

from __future__ import print_function, division

import numpy


[docs] class xPoint: """Class representing a point in the three-dimensional space. """ def __init__(self, x, y, z): """Constructor. """ self.x = x self.y = y self.z = z
[docs] def norm(self): """Return the norm of the three-dimensional vector corresponding to the point. """ return numpy.sqrt(self.x**2. + self.y**2. + self.z**2.)
[docs] def distance_to(self, other): """Return the distance to another point. """ return (self - other).norm()
[docs] def move(self, length, ray): """Move the point by a given length along a given ray. """ x = self.x + length * ray.xdir y = self.y + length * ray.ydir z = self.z + length * ray.zdir return self.__class__(x, y, z)
[docs] @classmethod def unphysical_point(cls): """Return an unphysical point. """ return cls(numpy.nan, numpy.nan, numpy.nan)
[docs] def unphysical(self): """Return True if the point is unphysical. """ return numpy.nan in [self.x, self.y, self.z]
def __add__(self, other): """Operator overload. """ return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z) def __sub__(self, other): """Operator overload. """ return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z) def __eq__(self, other): """Operator overload. """ return self.x == other.x and self.y == other.y and self.z == other.z def __str__(self): """String formatting. """ args = self.__class__.__name__, self.x, self.y, self.z return '%s(%.6f, %.6f, %.6f)' % args
[docs] class xLine: """Class representing a line. """ def __init__(self, begin, end): """Constructor. """ self.begin = begin self.end = end
[docs] def length(self): """Return the length of the line. """ return (self.end - self.begin).norm()
def __str__(self): """String formatting. """ return '%s--%s' % (self.begin, self.end)
[docs] class xRay: """Class representing a ray in the three-dimensional space. """ def __init__(self, origin, theta, phi): """Constructor. """ self.origin = origin self.theta = theta self.phi = phi # Calculate and cache the cosine directors for later use. st = numpy.sin(numpy.radians(self.theta)) ct = numpy.cos(numpy.radians(self.theta)) sp = numpy.sin(numpy.radians(self.phi)) cp = numpy.cos(numpy.radians(self.phi)) self.xdir = st * cp self.ydir = st * sp self.zdir = ct
[docs] def xintersect(self, x): """Return the point where the ray intersects the plane at a given x. """ if x == self.origin.x: return self.origin if self.xdir == 0.: return xPoint.unphysical_point() dx = (x - self.origin.x) / self.xdir return xPoint(x, self.origin.y + dx * self.ydir, self.origin.z + dx * self.zdir)
[docs] def yintersect(self, y): """Return the point where the ray intersects the plane at a given y. """ if y == self.origin.y: return self.origin if self.ydir == 0.: return xPoint.unphysical_point() dy = (y - self.origin.y) / self.ydir return xPoint(self.origin.x + dy * self.xdir, y, self.origin.z + dy * self.zdir)
[docs] def zintersect(self, z): """Return the point where the ray intersects the plane at a given z. """ if z == self.origin.z: return self.origin if self.zdir == 0.: return xPoint.unphysical_point() dz = (z - self.origin.z) / self.zdir return xPoint(self.origin.x + dz * self.xdir, self.origin.y + dz * self.ydir, z)
def __str__(self): """String formatting. """ args = self.__class__.__name__, self.origin, self.theta, self.phi return '%s: %s -> (%.3f deg, %.3f deg)' % args