def from_three_points(cls, a, b, c): """Construct a plane from three points in three-dimensional space. Parameters ---------- a : [float, float, float] | :class:`compas.geometry.Point` The first point. b : [float, float, float] | :class:`compas.geometry.Point` The second point. c : [float, float, float] | :class:`compas.geometry.Point` The second point. Returns ------- :class:`compas.geometry.Plane` A plane with base point `a` and normal vector defined as the unitized cross product of the vectors `ab` and `ac`. Examples -------- >>> plane = Plane.from_three_points([0.0, 0.0, 0.0], [2.0, 1.0, 0.0], [0.0, 3.0, 0.0]) >>> plane.point Point(0.000, 0.000, 0.000) >>> plane.normal Vector(0.000, 0.000, 1.000) """ a = Point(*a) b = Point(*b) c = Point(*c) normal = Vector.cross(b - a, c - a) return cls(a, normal)
def represent_point_in_global_coordinates(self, point): """Represents a point from local coordinates in the world coordinate system. Parameters ---------- point : :obj:`list` of :obj:`float` or :class:`Point` A point in local coordinates. Returns ------- :class:`Point` A point in the world coordinate system. Examples -------- >>> from compas.geometry import Frame >>> f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> pw1 = [2, 2, 2] >>> pf = f.represent_point_in_local_coordinates(pw1) >>> pw2 = f.represent_point_in_global_coordinates(pf) >>> allclose(pw1, pw2) True """ T = matrix_from_frame(self) pt = Point(*point) pt.transform(T) return pt
def transform_collection(collection, X): """Transform a collection of Line objects. Parameters ---------- collection : list[[point, point] | :class:`compas.geometry.Line`] The collection of lines. Returns ------- None The lines are modified in-place. Examples -------- >>> from math import radians >>> from compas.geometry import Point >>> from compas.geometry import Vector >>> from compas.geometry import Rotation >>> R = Rotation.from_axis_and_angle(Vector.Zaxis(), radians(90)) >>> a = Line(Point(0.0, 0.0, 0.0), Point(1.0, 0.0, 0.0)) >>> lines = [a] >>> Line.transform_collection(lines, R) >>> b = lines[0] >>> b.end Point(0.000, 1.000, 0.000) >>> a is b True """ points = [line.start for line in collection] + [line.end for line in collection] Point.transform_collection(points, X)
def represent_point_in_local_coordinates(self, point): """Represents a point in the frame's local coordinate system. Parameters ---------- point : :obj:`list` of :obj:`float` or :class:`Point` A point in world XY. Returns ------- :class:`Point` A point in the local coordinate system of the frame. Examples -------- >>> from compas.geometry import Frame >>> f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> pw1 = [2, 2, 2] >>> pf = f.represent_point_in_local_coordinates(pw1) >>> pw2 = f.represent_point_in_global_coordinates(pf) >>> allclose(pw1, pw2) True """ pt = Point(*subtract_vectors(point, self.point)) T = inverse(matrix_from_basis_vectors(self.xaxis, self.yaxis)) pt.transform(T) return pt
def from_plane(cls, plane): """Constructs a frame from a plane. Xaxis and yaxis are arbitrarily selected based on the plane's normal. Parameters ---------- plane : :class:`compas.geometry.Plane` A plane. Returns ------- :class:`compas.geometry.Frame` The constructed frame. Examples -------- >>> plane = Plane([0,0,0], [0,0,1]) >>> frame = Frame.from_plane(plane) >>> allclose(frame.normal, plane.normal) True """ # plane equation: a*x + b*y + c*z = d d = Vector(*plane.point).dot(plane.normal) # select 2 arbitrary points in the plane from which we create the xaxis coeffs = list(plane.normal) # a, b, c # select a coeff with a value != 0 coeffs_abs = [math.fabs(x) for x in coeffs] idx = coeffs_abs.index(max(coeffs_abs)) # first point coords = [0, 0, 0] # x, y, z # z = (d - a*0 + b*0)/c, if idx == 2 v = d / coeffs[idx] coords[idx] = v pt1_in_plane = Point(*coords) # second point coords = [1, 1, 1] # x, y, z coords[idx] = 0 # z = (d - a*1 + b*1)/c, if idx == 2 v = (d - sum([a * x for a, x in zip(coeffs, coords)])) / coeffs[idx] coords[idx] = v pt2_in_plane = Point(*coords) xaxis = pt2_in_plane - pt1_in_plane yaxis = plane.normal.cross(xaxis) return cls(plane.point, xaxis, yaxis)
def from_data(cls, data): """Construct a frame from a data dict. Parameters ---------- data : dict The data dictionary. Examples -------- >>> line = Line.from_data({'start': [0.0, 0.0, 0.0], 'end': [1.0, 0.0, 0.0]}) >>> line.end Point(1.000, 0.000, 0.000) """ return cls(Point.from_data(data['start']), Point.from_data(data['end']))
def to_local_coords(self, object_in_wcf): """Returns the object's coordinates in the local coordinate system of the frame. Parameters ---------- object_in_wcf : :class:`Point` or :class:`Vector` or :class:`Frame` or list of float An object in the world coordinate frame. Returns ------- :class:`Point` or :class:`Vector` or :class:`Frame` The object in the local coordinate system of the frame. Notes ----- If you pass a list of float, it is assumed to represent a point. Examples -------- >>> from compas.geometry import Point, Frame >>> frame = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> pw = Point(2, 2, 2) # point in wcf >>> pl = frame.to_local_coords(pw) # point in frame >>> frame.to_world_coords(pl) Point(2.000, 2.000, 2.000) """ T = Transformation.change_basis(Frame.worldXY(), self) if isinstance(object_in_wcf, list): return Point(*object_in_wcf).transformed(T) else: return object_in_wcf.transformed(T)
def from_data(cls, data): """Construct a frame from its data representation. Parameters ---------- data : dict The data dictionary. Returns ------- :class:`compas.geometry.Frame` The constructed frame. Examples -------- >>> data = {'point': [0.0, 0.0, 0.0], 'xaxis': [1.0, 0.0, 0.0], 'yaxis': [0.0, 1.0, 0.0]} >>> frame = Frame.from_data(data) >>> frame.point Point(0.000, 0.000, 0.000) >>> frame.xaxis Vector(1.000, 0.000, 0.000) >>> frame.yaxis Vector(0.000, 1.000, 0.000) """ frame = cls(Point.from_data(data['point']), Vector.from_data(data['xaxis']), Vector.from_data(data['yaxis'])) return frame
def points(self, points): self._points = [Point(*xyz) for xyz in points] self._lines = [ Line(self._points[i], self._points[i + 1]) for i in range(0, len(self._points) - 1) ]
def to_world_coordinates(self, object_in_lcf): """Returns the object's coordinates in the global coordinate frame. Parameters ---------- object_in_lcf : :class:`compas.geometry.Point` or :class:`compas.geometry.Vector` or :class:`compas.geometry.Frame` or list of float An object in local coordinate system of the frame. Returns ------- :class:`compas.geometry.Point` or :class:`compas.geometry.Vector` or :class:`compas.geometry.Frame` The object in the world coordinate frame. Notes ----- If you pass a list of float, it is assumed to represent a point. Examples -------- >>> from compas.geometry import Point >>> frame = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> pl = Point(1.632, -0.090, 0.573) # point in frame >>> pw = frame.to_world_coordinates(pl) # point in wcf >>> frame.to_local_coordinates(pw) Point(1.632, -0.090, 0.573) """ T = Transformation.from_change_of_basis(self, Frame.worldXY()) if isinstance(object_in_lcf, list): return Point(*object_in_lcf).transformed(T) else: return object_in_lcf.transformed(T)
def local_to_local_coordinates(frame1, frame2, object_in_frame1): """Returns the object's coordinates in frame1 in the local coordinates of frame2. Parameters ---------- frame1 : :class:`compas.geometry.Frame` A frame representing one local coordinate system. frame2 : :class:`compas.geometry.Frame` A frame representing another local coordinate system. object_in_frame1 : :class:`compas.geometry.Point` or :class:`compas.geometry.Vector` or :class:`compas.geometry.Frame` or list of float An object in the coordinate frame1. If you pass a list of float, it is assumed to represent a point. Returns ------- :class:`compas.geometry.Point` or :class:`compas.geometry.Vector` or :class:`compas.geometry.Frame` The object in the local coordinate system of frame2. Examples -------- >>> from compas.geometry import Point >>> frame1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> frame2 = Frame([2, 1, 3], [1., 0., 0.], [0., 1., 0.]) >>> p1 = Point(2, 2, 2) # point in frame1 >>> p2 = Frame.local_to_local_coordinates(frame1, frame2, p1) # point in frame2 >>> Frame.local_to_local_coordinates(frame2, frame1, p2) Point(2.000, 2.000, 2.000) """ T = Transformation.from_change_of_basis(frame1, frame2) if isinstance(object_in_frame1, list): return Point(*object_in_frame1).transformed(T) return object_in_frame1.transformed(T)
def point(self, t): """Compute a point on the curve. Parameters ---------- t : float The value of the curve parameter. Must be between 0 and 1. Returns ------- Point the corresponding point on the curve. Examples -------- >>> curve = Bezier([[0.0, 0.0, 0.0], [0.5, 1.0, 0.0], [1.0, 0.0, 0.0]]) >>> curve.point(0.0) Point(0.000, 0.000, 0.000) >>> curve.point(1.0) Point(1.000, 0.000, 0.000) """ n = self.degree point = Point(0, 0, 0) for i, p in enumerate(self.points): b = bernstein(n, i, t) point += p * b return point
def points(self, points): if points[-1] == points[0]: del points[-1] self._points = [Point(*xyz) for xyz in points] self._lines = [ Line(self.points[i], self.points[i + 1]) for i in range(-1, len(points) - 1) ]
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)
def from_data(cls, data): """Construct a polyline from a data dict. Parameters ---------- data : dict The data dictionary. Returns ------- :class:`compas.geometry.Polyline` The constructed polyline. Examples -------- >>> Polyline.from_data({'points': [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]]}) Polyline([Point(0.000, 0.000, 0.000), Point(1.000, 0.000, 0.000), Point(1.000, 1.000, 0.000)]) """ return cls([Point.from_data(point) for point in data['points']])
def compute_point(self, t): """Compute a point on the curve. Parameters ---------- t : float The value of the curve parameter. Must be between 0 and 1. Returns ------- Point the corresponding point on the curve. """ n = self.degree point = Point(0, 0, 0) for i, p in enumerate(self.points): b = bernstein(n, i, t) point += p * b return point
def from_data(cls, data): """Construct a polygon from its data representation. Parameters ---------- data : dict The data dictionary. Returns ------- :class:`compas.geometry.Polygon` The constructed polygon. Examples -------- >>> polygon = Polygon.from_data({'points': [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 1.0]]}) >>> polygon.points[0] Point(0.000, 0.000, 0.000) """ return cls([Point.from_data(point) for point in data['points']])
def from_data(cls, data): """Construct a plane from its data representation. Parameters ---------- data : dict The data dictionary. Returns ------- :class:`compas.geometry.Plane` The constructed plane. Examples -------- >>> plane = Plane.from_data({'point': [0.0, 0.0, 0.0], 'normal': [0.0, 0.0, 1.0]}) >>> plane.point Point(0.000, 0.000, 0.000) >>> plane.normal Vector(0.000, 0.000, 1.000) """ return cls(Point.from_data(data['point']), Vector.from_data(data['normal']))
def points(self, points): if points[-1] == points[0]: del points[-1] self._points = [Point(*xyz) for xyz in points] self._lines = None
def data(self, data): self.start = Point.from_data(data['start']) self.end = Point.from_data(data['end'])
def end(self, point): self._end = Point(*point)
def start(self, point): self._start = Point(*point)
def point(self, point): self._point = Point(*point)
def points(self, points): if points: self._points = [Point(*point) for point in points]
def data(self, data): self.point = Point.from_data(data['point']) self.normal = Vector.from_data(data['normal'])
def centroid(self): """int : The centroid of the polygon.""" point = centroid_polygon(self.points) return Point(*point)
def __setitem__(self, key, value): self.points[key] = Point(*value) self._lines = None
""" plane = self.copy() plane.transform(transformation) return plane # ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.geometry import Frame from compas.geometry import Transformation base = Point(0.0, 0.0, 0.0) normal = Vector(1.0, 0.0, 0.0) plane = Plane(base, normal) print(plane) print(plane.d) a, b, c = normal p = [1.0, 0.0, 1.0] d = a * p[0] + b * p[1] + c * p[2] print(d) print(d <= plane.d)
def data(self, data): self.points = [Point.from_data(point) for point in data['points']]
def points(self, points): self._points = [Point(*xyz) for xyz in points] self._lines = None