def world_to_local_coords(frame, xyz): """Convert global coordinates to local coordinates. Parameters ---------- frame : :class:`Frame` or [point, xaxis, yaxis] The local coordinate system. xyz : array-like The global coordinates of the points to convert. Returns ------- list of list of float The coordinates of the given points in the local coordinate system. Examples -------- >>> import numpy as np >>> f = Frame([0, 1, 0], [3, 4, 1], [1, 5, 9]) >>> xyz = [Point(2, 3, 5)] >>> Point(*world_to_local_coords(f, xyz)[0]) Point(3.726, 4.088, 1.550) """ from compas.geometry.primitives import Frame T = matrix_change_basis(Frame.worldXY(), frame) return transform_points(xyz, T)
def local_to_world_coords(frame, xyz): """Convert local coordinates to global coordinates. Parameters ---------- frame : :class:`Frame` or [point, xaxis, yaxis] The local coordinate system. xyz : list of `Points` or list of list of float The global coordinates of the points to convert. Returns ------- list of list of float The coordinates of the given points in the local coordinate system. Examples -------- >>> import numpy as np >>> f = Frame([0, 1, 0], [3, 4, 1], [1, 5, 9]) >>> xyz = [Point(3.726, 4.088, 1.550)] >>> Point(*local_to_world_coords(f, xyz)[0]) Point(2.000, 3.000, 5.000) """ from compas.geometry.primitives import Frame # noqa: F811 T = matrix_change_basis(frame, Frame.worldXY()) return transform_points(xyz, T)
def to_vertices_and_faces(self, **kwargs): if 'u' in kwargs: u = kwargs['u'] else: u = 10 vertices = [] a = 2 * pi / u for i in range(u): x = self.circle.radius * cos(i * a) y = self.circle.radius * sin(i * a) z = self.height / 2 vertices.append([x, y, z]) vertices.append([x, y, -z]) # transform vertices to cylinder's plane frame = Frame.from_plane(self.circle.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] for i in range(0, u*2, 2): faces.append([i, i+1, (i+3)%(u*2), (i+2)%(u*2)]) faces.append([i for i in range(0, u*2, 2)]) faces.append([i for i in range(1, u*2, 2)]) faces[-1].reverse() return vertices, faces
def to_vertices_and_faces(self, **kwargs): """Returns a list of vertices and faces, called by `Mesh.from_shape()`.""" if 'u' in kwargs: u = kwargs['u'] else: u = 10 vertices = [] a = 2 * pi / u for i in range(u): x = self.circle.radius * cos(i * a) y = self.circle.radius * sin(i * a) vertices.append([x, y, 0]) vertices.append([0, 0, self.height]) # transform vertices to cylinder's plane frame = Frame.from_plane(self.circle.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] last = len(vertices) - 1 for i in range(u): faces.append([i, (i + 1) % u, last]) faces.append([i for i in range(u)]) faces[-1].reverse() return vertices, faces
def to_vertices_and_faces(self, **kwargs): """Returns a list of vertices and faces""" u = kwargs.get('u') or 10 if u < 3: raise ValueError('The value for u should be u > 3.') vertices = [] a = 2 * pi / u for i in range(u): x = self.circle.radius * cos(i * a) y = self.circle.radius * sin(i * a) z = self.height / 2 vertices.append([x, y, z]) vertices.append([x, y, -z]) # transform vertices to cylinder's plane frame = Frame.from_plane(self.circle.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] for i in range(0, u * 2, 2): faces.append([i, i + 1, (i + 3) % (u * 2), (i + 2) % (u * 2)]) faces.append([i for i in range(0, u * 2, 2)]) faces.append([i for i in range(1, u * 2, 2)]) faces[-1].reverse() return vertices, faces
def test_basis_vectors_from_matrix(): f = Frame([0, 0, 0], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) R = matrix_from_frame(f) xaxis, yaxis = basis_vectors_from_matrix(R) assert np.allclose( xaxis, [0.6807833515407016, 0.6807833515407016, 0.2703110366411609]) assert np.allclose( yaxis, [-0.6687681911461376, 0.7282315441900513, -0.14975955581430114])
def test_matrix_from_frame(): f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = matrix_from_frame(f) t = [[0.6807833515407016, -0.6687681911461376, -0.29880283595731283, 1.0], [0.6807833515407016, 0.7282315441900513, -0.0788216106888398, 1.0], [0.2703110366411609, -0.14975955581430114, 0.9510541619236438, 1.0], [0.0, 0.0, 0.0, 1.0]] assert np.allclose(T, t)
def test_reflection_from_frame(): point = [1, 1, 1] x = [1, 0, 0] y = [0, 1, 0] f = Frame(point, x, y) R1 = Reflection.from_frame(f) R2 = Transformation.from_matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 2], [0, 0, 0, 1]]) assert R1 == R2
def from_bounding_box(cls, bbox): a = bbox[0] b = bbox[1] d = bbox[3] e = bbox[4] xaxis = Vector(*subtract_vectors(d, a)) yaxis = Vector(*subtract_vectors(b, a)) zaxis = Vector(*subtract_vectors(e, a)) xsize = xaxis.length ysize = yaxis.length zsize = zaxis.length frame = Frame(a, xaxis, yaxis) return cls(frame, xsize, ysize, zsize)
def from_bounding_box(cls, bbox): # this should put the frame at the centroid of the box # not at the bottom left corner a = bbox[0] b = bbox[1] d = bbox[3] e = bbox[4] xaxis = Vector(*subtract_vectors(d, a)) yaxis = Vector(*subtract_vectors(b, a)) zaxis = Vector(*subtract_vectors(e, a)) xsize = xaxis.length ysize = yaxis.length zsize = zaxis.length frame = Frame(a, xaxis, yaxis) frame.point += frame.xaxis * 0.5 * xsize + frame.yaxis * 0.5 * ysize + frame.zaxis * 0.5 * zsize return cls(frame, xsize, ysize, zsize)
def from_width_height_depth(cls, width, height, depth): """Construct a box from its width, height and depth. Parameters ---------- width : float Width of the box. height : float Height of the box. depth : float Depth of the box. Returns ------- Box The resulting box. Notes ----- The bottom left corner of the box is positioned at the origin of the coordinates system. The box is axis-aligned. Examples -------- >>> from compas.geometry import Box >>> box = Box.from_width_height_depth(1.0, 2.0, 3.0) """ width = float(width) height = float(height) depth = float(depth) if width == 0.0: raise Exception('Width cannot be zero.') if height == 0.0: raise Exception('Height cannot be zero.') if depth == 0.0: raise Exception('Depth cannot be zero.') return cls(Frame.worldXY(), width, depth, height)
def from_corner_corner_height(cls, corner1, corner2, height): """Construct a box from the opposite corners of its base and its height. Parameters ---------- corner1 : point The XYZ coordinates of the bottom left corner of the base of the box. corner2 : point The XYZ coordinates of the top right corner of the base of the box. height : float The height of the box. Returns ------- Box The resulting box. Examples -------- >>> box = Box.from_corner_corner_height([0.0, 0.0, 0.0], [1.0, 1.0, 0.0], 1.0) """ # this should put the frame at the centroid of the box # not at the bottom left corner if height == 0: raise Exception('The box should have a height.') x1, y1, z1 = corner1 x2, y2, z2 = corner2 xaxis = Vector(x2 - x1, 0, 0) yaxis = Vector(0, y2 - y1, 0) width = xaxis.length depth = yaxis.length if z1 != z2: raise Exception('Corners should be in the same horizontal plane.') frame = Frame(corner1, xaxis, yaxis) frame.point += frame.xaxis * 0.5 * width + frame.yaxis * 0.5 * depth + frame.zaxis * 0.5 * height return cls(frame, width, depth, height)
def from_data(cls, data): """Construct a box from its data representation. Parameters ---------- data : :obj:`dict` The data dictionary. Returns ------- Box The constructed box. Examples -------- >>> data = {'frame': Frame.worldXY().data, 'xsize': 1.0, 'ysize': 1.0, 'zsize': 1.0} >>> box = Box.from_data(data) """ box = cls(Frame.worldXY(), 1, 1, 1) box.data = data return box
def from_diagonal(cls, diagonal): """Construct a box from its main diagonal. Parameters ---------- diagonal : segment The diagonal of the box, represented by a pair of points in space. Returns ------- Box The resulting box. Examples -------- >>> diagonal = [0.0, 0.0, 0.0], [1.0, 1.0, 1.0] >>> box = Box.from_diagonal(diagonal) """ # this should put the frame at the centroid of the box # not at the bottom left corner d1, d2 = diagonal x1, y1, z1 = d1 x2, y2, z2 = d2 if z1 == z2: raise Exception('The box has no height.') xaxis = Vector(x2 - x1, 0, 0) yaxis = Vector(0, y2 - y1, 0) zaxis = Vector(0, 0, z2 - z1) width = xaxis.length depth = yaxis.length height = zaxis.length frame = Frame(d1, xaxis, yaxis) frame.point += frame.xaxis * 0.5 * width + frame.yaxis * 0.5 * depth + frame.zaxis * 0.5 * height return cls(frame, width, depth, height)
def to_vertices_and_faces(self, **kwargs): """Returns a list of vertices and faces""" u = kwargs.get('u') or 10 v = kwargs.get('v') or 10 if u < 3: raise ValueError('The value for u should be u > 3.') if v < 3: raise ValueError('The value for v should be v > 3.') theta = pi * 2 / u phi = pi * 2 / v vertices = [] for i in range(u): for j in range(v): x = cos(i * theta) * (self.radius_axis + self.radius_pipe * cos(j * phi)) y = sin(i * theta) * (self.radius_axis + self.radius_pipe * cos(j * phi)) z = self.radius_pipe * sin(j * phi) vertices.append([x, y, z]) # transform vertices to torus' plane frame = Frame.from_plane(self.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] for i in range(u): ii = (i + 1) % u for j in range(v): jj = (j + 1) % v a = i * v + j b = ii * v + j c = ii * v + jj d = i * v + jj faces.append([a, b, c, d]) return vertices, faces
def from_diagonal(cls, diagonal): """Construct a box from its main diagonal. Parameters ---------- diagonal : segment The diagonal of the box, represented by a pair of points in space. Returns ------- Box The resulting box. Examples -------- >>> from compas.geometry import Box >>> diagonal = [0.0, 0.0, 0.0], [1.0, 1.0, 1.0] >>> box = Box.from_diagonal(diagonal) """ d1, d2 = diagonal x1, y1, z1 = d1 x2, y2, z2 = d2 if z1 == z2: raise Exception('The box has no height.') xaxis = Vector(x2 - x1, 0, 0) yaxis = Vector(0, y2 - y1, 0) zaxis = Vector(0, 0, z2 - z1) width = xaxis.length depth = yaxis.length height = zaxis.length frame = Frame(d1, xaxis, yaxis) return cls(frame, width, depth, height)
def to_vertices_and_faces(self, **kwargs): """Returns a list of vertices and faces, called by `Mesh.from_shape()`.""" if 'u' in kwargs: u = kwargs['u'] else: u = 10 if 'v' in kwargs: v = kwargs['v'] else: v = 10 theta = pi*2 / u phi = pi*2 / v vertices = [] for i in range(u): for j in range(v): x = cos(i * theta) * (self.radius_axis + self.radius_pipe * cos(j * phi)) y = sin(i * theta) * (self.radius_axis + self.radius_pipe * cos(j * phi)) z = self.radius_pipe * sin(j * phi) vertices.append([x, y, z]) # transform vertices to torus' plane frame = Frame.from_plane(self.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] for i in range(u): ii = (i + 1) % u for j in range(v): jj = (j + 1) % v a = i * v + j b = ii * v + j c = ii * v + jj d = i * v + jj faces.append([a, b, c, d]) return vertices, faces
def to_vertices_and_faces(self, **kwargs): """Returns a list of vertices and faces""" u = kwargs.get('u') or 10 if u < 3: raise ValueError('The value for u should be u > 3.') vertices = [] a = 2 * pi / u z = self.height / 2 for i in range(u): x = self.circle.radius * cos(i * a) y = self.circle.radius * sin(i * a) vertices.append([x, y, z]) vertices.append([x, y, -z]) # add v in bottom and top's circle center vertices.append([0, 0, z]) vertices.append([0, 0, -z]) # transform vertices to cylinder's plane frame = Frame.from_plane(self.circle.plane) M = matrix_from_frame(frame) vertices = transform_points(vertices, M) faces = [] # side faces for i in range(0, u * 2, 2): faces.append([i, i + 1, (i + 3) % (u * 2), (i + 2) % (u * 2)]) # top and bottom circle faces for i in range(0, u * 2, 2): top = [i, (i + 2) % (u * 2), len(vertices) - 2] bottom = [i + 1, (i + 3) % (u * 2), len(vertices) - 1] faces.append(top) faces.append(bottom[::-1]) return vertices, faces
>>> T = Transformation.from_frame(frame) >>> circle_transformed = cylinder.transformed(T) """ cylinder = self.copy() cylinder.transform(transformation) return cylinder # ============================================================================== # Main # ============================================================================== if __name__ == "__main__": from compas.geometry import Transformation cylinder = Cylinder(Circle(Plane.worldXY(), 5), 7) frame = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) print(frame.normal) T = Transformation.from_frame(frame) cylinder.transform(T) print(cylinder) print(Plane.worldXY().data) data = {'circle': Circle(Plane.worldXY(), 5).data, 'height': 7.} cylinder = Cylinder.from_data(data) print(cylinder) import doctest doctest.testmod()
def frame(self, frame): self._frame = Frame(frame[0], frame[1], frame[2])
def data(self, data): self.frame = Frame.from_data(data['frame']) self.xsize = data['xsize'] self.ysize = data['ysize'] self.zsize = data['zsize']
def test_inverse(): f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(f) assert Transformation() == T * T.inverse()
>>> torus = Torus(Plane.worldXY(), 5, 2) >>> frame = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) >>> T = Transformation.from_frame(frame) >>> torus_transformed = torus.transformed(T) """ torus = self.copy() torus.transform(transformation) return torus if __name__ == '__main__': from compas.geometry import Frame from compas.geometry import Plane from compas.geometry import Transformation torus = Torus(Plane.worldXY(), 5, 2) frame = Frame([5, 0, 0], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(frame) torus.transform(T) print(torus) torus = Torus(Plane.worldXY(), 5, 2) print(torus.data) print(torus) torus = Torus.from_data(torus.data) print(torus) import doctest doctest.testmod()
def test_from_frame(): f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26]) f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame_to_frame(f1, f2) f1.transform(T) assert f1 == f2