Source code for pyhull.halfspace

"""
This module defines classes for computing halfspace intersections
"""

from __future__ import division

__author__ = "Will Richards"
__version__ = "2.0"
__maintainer__ = "Will Richards"
__email__ = "wrichard@mit.edu"
__date__ = "August 2, 2013"

from pyhull import qhalf

import numpy as np

[docs]class Halfspace(object): """ A halfspace defined by dot(normal, coords) + offset <= 0 """ def __init__(self, normal, offset): """ Initializes a Halfspace. Args: normal: vector normal to hyperplane offset: offset of hyperplane from origin """ self.normal = normal self.offset = offset def __str__(self): return "Halfspace, normal: {}, offset: {}".format(self.normal, self.offset) @staticmethod
[docs] def from_hyperplane(basis, origin, point, internal = True): """ Returns a Halfspace defined by a list of vectors parallel to the bounding hyperplane. Args: basis: basis for the hyperplane (array with vector rows) origin: point on the hyperplane point: point not on the hyperplane internal: whether point is inside the halfspace """ basis = np.array(basis) assert basis.shape[0] + 1 == basis.shape[1] big_basis = np.zeros((basis.shape[1], basis.shape[1])) big_basis[:basis.shape[0],:basis.shape[1]] = basis u, s, vh = np.linalg.svd(big_basis) null_mask = (s <= 1e-8) normal = np.compress(null_mask, vh, axis=0)[0] if np.inner(np.array(point)-np.array(origin), normal) > 0: if internal: normal *= -1 else: if not internal: normal *= -1 offset = -np.dot(origin, normal) return Halfspace(normal, offset)
[docs]class HalfspaceIntersection(object): """ Uses qhalf to calculate the vertex representation of the intersection of a set of halfspaces """ def __init__(self, halfspaces, interior_point): self.halfspaces = halfspaces self.interior_point = interior_point self._v_out = None self._fbv_out = None self._fbh_out = None @property def vertices(self): """ Returns the vertices of the halfspace intersection """ if self._v_out is None: output = qhalf('Fp', self.halfspaces, self.interior_point) pts = [] for l in output[2:]: pt = [] for c in l.split(): c = float(c) if c != 10.101 and c != -10.101: pt.append(c) else: pt.append(np.inf) pts.append(pt) self._v_out = np.array(pts) return self._v_out @property def facets_by_vertex(self): """ Returns a list of non-redundant halfspace indices for each vertex e.g: facets_by_vertex[0] is the list of indices of halfspaces incident to vertex 0 """ if self._fbv_out is None: output = qhalf('Fv', self.halfspaces, self.interior_point) facets = [] for l in output[1:]: facets.append([int(i) for i in l.split()[1:]]) self._fbv_out = facets return self._fbv_out @property def facets_by_halfspace(self): """ Returns a list of vertex indices for each halfspace e.g: facets_by_halfspace[0] is the list of indices ov vertices incident to halfspace 0 """ if self._fbh_out is None: output = qhalf('FN', self.halfspaces, self.interior_point) facets = [] for l in output[1:]: facets.append([int(i) for i in l.split()[1:]]) self._fbh_out = facets return self._fbh_out