def basis_vectors(self): """Returns the basis vectors from the ``Rotation`` component of the ``Transformation``. """ sc, sh, a, t, p = decompose_matrix(self.matrix) R = matrix_from_euler_angles(a, static=True, axes='xyz') xv, yv = basis_vectors_from_matrix(R) return Vector(*xv), Vector(*yv)
def from_point_and_two_vectors(cls, point, v1, v2): v1 = Vector(*v1) v2 = Vector(*v2) n = Vector.cross(v1, v2) n.unitize() plane = cls() plane.point = Point(*point) plane.normal = n return plane
def frame(self): """The local coordinate frame.""" o = self.center w = self.normal p = self.points[0] u = Vector.from_start_end(o, p) u.unitize() v = Vector.cross(w, u) return o, u, v, w
def basis(self): a, b, c = self.normal u = 1.0, 0.0, -a / c v = 0.0, 1.0, -b / c return [ Vector(*vector, unitize=True) for vector in orthonormalise_vectors([u, v]) ]
def from_three_points(cls, p1, p2, p3): p1 = Point(*p1) p2 = Point(*p2) p3 = Point(*p3) v1 = p2 - p1 v2 = p3 - p1 plane = cls() plane.point = p1 plane.normal = Vector.cross(v1, v2) plane.normal.unitize() return plane
def __sub__(self, other): """Create a vector from other to self. Parameters: other (sequence, Point): The point to subtract. Returns: Vector: A vector from other to self """ x = self.x - other[0] y = self.y - other[1] z = self.z - other[2] return Vector(x, y, z)
def normal(self): """Vector: The (average) normal of the polygon.""" o = self.center points = self.points a2 = 0 normals = [] for i in range(-1, len(points) - 1): p1 = points[i] p2 = points[i + 1] u = [p1[_] - o[_] for _ in range(3)] v = [p2[_] - o[_] for _ in range(3)] w = cross_vectors(u, v) a2 += sum(w[_] ** 2 for _ in range(3)) ** 0.5 normals.append(w) n = [sum(axis) / a2 for axis in zip(*normals)] n = Vector(* n) return n
def __sub__(self, other): """Return a ``Vector`` that is the the difference between this ``Point`` and another point. Parameters ---------- other : point The point to subtract. Returns ------- Vector A vector from other to self. """ x = self.x - other[0] y = self.y - other[1] z = self.z - other[2] return Vector(x, y, z)
def from_point_and_two_vectors(cls, point, u, v): """Construct a plane from a base point and two vectors. Parameters ---------- point : point The base point. u : vector The first vector. v : vector The second vector. Returns ------- Plane A plane with base point ``point`` and normal vector defined as the unitized cross product of vectors ``u`` and ``v``. """ normal = Vector.cross(u, v) return cls(point, normal)
def from_three_points(cls, a, b, c): """Construct a plane from three points in three-dimensional space. Parameters ---------- a : point The first point. b : point The second point. c : point The second point. Returns ------- Plane A plane with base point ``a`` and normal vector defined as the unitized cross product of the vectors ``ab`` and ``ac``. """ a = Point(*a) b = Point(*b) c = Point(*c) normal = Vector.cross(b - a, c - a) return cls(a, normal)
# transformations # ========================================================================== # ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.viewers import Viewer from compas.viewers import xdraw_points from compas.viewers import xdraw_lines base = Point(1.0, 0.0, 0.0) normal = Vector(1.0, 1.0, 1.0) plane = Plane.from_point_and_normal(base, normal) points = [{'pos': base, 'color': (1.0, 0.0, 0.0), 'size': 10.0}] lines = [] for vector in plane.basis + [plane.normal]: lines.append({ 'start': base, 'end': base + vector, 'color': (0.0, 0.0, 0.0), 'width': 3.0 }) def draw_plane():
# ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Plane from compas.geometry import Line from compas.geometry import Polygon from compas.geometry import projection_matrix point = Point(0.0, 0.0, 0.0) normal = Vector(0.0, 0.0, 1.0) plane = Plane.from_point_and_normal(point, normal) line = Line([0.0, 0.0, 0.0], [1.0, 0.0, 0.0]) triangle = Polygon([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]]) polygon = Polygon([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]) p = Point(1.0, 1.0, 1.0) print(repr(p)) print(p.distance_to_point(point)) print(p.distance_to_line(line)) print(p.distance_to_plane(plane)) print(p.in_triangle(triangle))
def yaxis(self, vector): yaxis = Vector(*vector) yaxis.unitize() zaxis = Vector.cross(self.xaxis, yaxis) self._yaxis = Vector.cross(zaxis, self.xaxis)
def normal(self): """:class:`Vector` : The frame's normal (z-axis).""" return Vector(*cross_vectors(self.xaxis, self.yaxis))
def normal(self, vector): self._normal = Vector(*vector) self._normal.unitize()
def from_point_and_normal(cls, point, normal): plane = cls() plane.point = Point(*point) plane.normal = Vector(*normal) plane.normal.unitize() return plane
def xaxis(self, vector): xaxis = Vector(*vector) xaxis.unitize() self._xaxis = xaxis
class Plane(object): """A plane is defined by a base point and a normal vector. Parameters ---------- point : point The base point of the plane. normal : vector The normal vector of the plane. Examples -------- >>> Notes ----- For more info on lines and linear equations, see [1]_. References ---------- .. [1] Wikipedia. *Plane (geometry)*. Available at: https://en.wikipedia.org/wiki/Plane_(geometry). """ __slots__ = ['_point', '_normal'] def __init__(self, point, normal): self._point = None self._normal = None self.point = point self.normal = normal # ========================================================================== # factory # ========================================================================== @classmethod def from_three_points(cls, a, b, c): """Construct a plane from three points in three-dimensional space. Parameters ---------- a : point The first point. b : point The second point. c : point The second point. Returns ------- Plane A plane with base point ``a`` and normal vector defined as the unitized cross product of the vectors ``ab`` and ``ac``. """ a = Point(*a) b = Point(*b) c = Point(*c) normal = Vector.cross(b - a, c - a) return cls(a, normal) @classmethod def from_point_and_two_vectors(cls, point, u, v): """Construct a plane from a base point and two vectors. Parameters ---------- point : point The base point. u : vector The first vector. v : vector The second vector. Returns ------- Plane A plane with base point ``point`` and normal vector defined as the unitized cross product of vectors ``u`` and ``v``. """ normal = Vector.cross(u, v) return cls(point, normal) @classmethod def from_points(cls, points): """Construct the *best-fit* plane through more than three (non-coplanar) points. Parameters ---------- points : list of point List of points. Returns ------- Plane A plane that minimizes the distance to each point in the list. """ raise NotImplementedError # ========================================================================== # descriptors # ========================================================================== @property def point(self): """Point: The base point of the plane.""" return self._point @point.setter def point(self, point): self._point = Point(*point) @property def normal(self): """Vector: The normal vector of the plane.""" return self._normal @normal.setter def normal(self, vector): self._normal = Vector(*vector) self._normal.unitize() @property def d(self): """:obj:`float`: The *d* parameter of the linear equation describing the plane.""" a, b, c = self.normal x, y, z = self.point return - a * x - b * y - c * z # @property # def frame(self): # """Frame: The frame that forms a basis for the local coordinates of all # points in the half-spaces defined by the plane. # """ # a, b, c = self.normal # u = 1.0, 0.0, - a / c # v = 0.0, 1.0, - b / c # u, v = orthonormalize_vectors([u, v]) # u = Vector(*u) # v = Vector(*v) # u.unitize() # v.unitize() # return self.point, u, v # ========================================================================== # representation # ========================================================================== def __repr__(self): return 'Plane({0}, {1})'.format(self.point, self.normal) def __len__(self): return 2 # ========================================================================== # access # ========================================================================== def __getitem__(self, key): if key == 0: return self.point if key == 1: return self.normal raise KeyError def __setitem__(self, key, value): if key == 0: self.point = value return if key == 1: self.normal = value return raise KeyError def __iter__(self): return iter([self.point, self.normal]) # ========================================================================== # comparison # ========================================================================== def __eq__(self, other): raise NotImplementedError # ========================================================================== # operators # ========================================================================== # ========================================================================== # inplace operators # ========================================================================== # ========================================================================== # helpers # ========================================================================== def copy(self): """Make a copy of this ``Plane``. Returns ------- Plane The copy. """ cls = type(self) return cls(self.point.copy(), self.normal.copy()) # ========================================================================== # methods # ========================================================================== # ========================================================================== # transformations # ========================================================================== def transform(self, matrix): """Transform this ``Plane`` using a given transformation matrix. Parameters ---------- matrix : list of list The transformation matrix. """ point = transform_points([self.point], matrix) normal = transform_vectors([self.normal], matrix) self.point.x = point[0] self.point.y = point[1] self.point.z = point[2] self.normal.x = normal[0] self.normal.y = normal[1] self.normal.z = normal[2]