def chain_compose_after_inplace_chain_test(): a = PointCloud(np.random.random([10, 2])) b = PointCloud(np.random.random([10, 2])) t = Translation([3, 4]) s = Scale([4, 2]) chain_1 = TransformChain([t, s]) chain_2 = TransformChain([s.pseudoinverse(), t.pseudoinverse()]) chain_1.compose_before_inplace(chain_2) points = PointCloud(np.random.random([10, 2])) chain_res = chain_1.apply(points) assert(np.allclose(points.points, chain_res.points))
def model_to_clip_transform(points, xy_scale=0.9, z_scale=0.3): r""" Produces an Affine Transform which centres and scales 3D points to fit into the OpenGL clipping space ([-1, 1], [-1, 1], [1, 1-]). This can be used to construct an appropriate projection matrix for use in an orthographic Rasterizer. Note that the z-axis is flipped as is default in OpenGL - as a result this transform converts the right handed coordinate input into a left hand one. Parameters ---------- points: :map:`PointCloud` The points that should be adjusted. xy_scale: `float` 0-1, optional Amount by which the boundary is relaxed so the points are not right against the edge. A value of 1 means the extremities of the point cloud will be mapped onto [-1, 1] [-1, 1] exactly (no boarder) A value of 0.5 means the points will be mapped into the range [-0.5, 0.5]. Default: 0.9 (map to [-0.9, 0.9]) z_scale: float 0-1, optional Scale factor by which the z-dimension is squeezed. A value of 1 means the z-range of the points will be mapped to exactly fit in [1, -1]. A scale of 0.1 means the z-range is compressed to fit in the range [0.1, -0.1]. Returns ------- :map:`Affine` The affine transform that creates this mapping """ # 1. Centre the points on the origin center = Translation(points.centre_of_bounds()).pseudoinverse() # 2. Scale the points to exactly fit the boundaries scale = Scale(points.range() / 2.0) # 3. Apply the relaxations requested - note the flip in the z axis!! # This is because OpenGL by default evaluates depth as bigger number == # further away. Thus not only do we need to get to clip space [-1, 1] in # all dims) but we must invert the z axis so depth buffering is correctly # applied. b_scale = NonUniformScale([xy_scale, xy_scale, -z_scale]) return center.compose_before(scale.pseudoinverse()).compose_before(b_scale)