Apply a Projection (Transformation) to a Mesh and Plot the Result (Image)

I’m trying to (quickly) explore various (orthographic and oblique) projection types.

I would therefore inquire about the suggested workflow in order to visualize projected images of a given object.

Starting with the tutorial things were rather easy:
Import an object: returns a Mesh Object.
Generate the desired projection: returns a Transformation (4 × 4 matrix).

point = [0, 0, 0]
normal = [0, 0, 1]
plane = (point, normal)
P = matrix_from_orthogonal_projection(plane)

But then I can’t find an example for the following steps:
Apply the projection on the object: returns a (2D) Mesh. (All the vertices should be in the same plane but is it the same plane which generated the Transformation matrix ?)
Plot the projected image/2D Mesh.

Thanks for any help!

P.S.

For the story, I already tried to implement a set of different parallel projections in Blender only by tweaking the camera parameters. Not everything was ‘perfectly’ possible (like the cavalier projection). Passing through the Transformation matrix rises my hopes to find a solution.

could you post an example snippet of what you are trying to accomplish with the 2 unchecked items?

something like this perhaps?

from compas.datastructures import Mesh
from compas.geometry import Projection

mesh = Mesh.from_polyhedron(8)
P = Projection.from_plane(([0, 0, 0], [0, 0, 1]))
mesh.transform(P)
z = mesh.vertices_attribute('z')
print(z)
# [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

also, we would be happy to hear about your feedback on the projection matrices. they are not being used very often so i can imagine there are some bugs and/or potential areas of improvement :slight_smile:

for visualising the result, you could do the following

from compas.datastructures import Mesh
from compas.geometry import Projection
from compas.geometry import Translation
from compas_viewers.objectviewer import ObjectViewer

mesh = Mesh.from_polyhedron(8)

z = mesh.vertices_attribute('z')
zmin = min(z)
zmax = max(z)
dz = zmax - zmin

T = Translation.from_vector([0, 0, 0.5 * dz])
mesh.transform(T)

P = Projection.from_plane(([0, 0, 0], [0, 0, 1]))
projected = mesh.transformed(P)

viewer = ObjectViewer()
viewer.view.use_shaders = True

viewer.add(mesh, settings={'color': '#ff0000', 'opacity': 0.7})
viewer.add(projected, settings={'color': '#00ff00', 'opacity': 0.7})

viewer.update()
viewer.show()

this should produce something like this

Thanks a lot. I’m now testing out the transformation matrices. The existing tools are very useful. Here my start to implement the axonometric projection.

I look also into defining a ProjectionPlane class, onto which the projected mesh would be translated onto; let’s say… like a window or a piece of paper in space. (Or the other way around, it would be nice if the ObjectViewer could be reduced to 2 dimensions).

# Axonometry Transformation Matrix

from compas.geometry import Projection
from compas.geometry._transformations import matrix_from_orthogonal_projection


class Axonometry(Projection):
    """ Axonometric projections are standardized parallel projections onto a plane.
    The position of the plane determines the type of axonometry:
    isometric, dimetric or trimetric."""

    def __init__(self, matrix=None):
        if matrix:
            _, _, _, _, perspective = decompose_matrix(matrix)
            check = matrix_from_perspective_entries(perspective)
            if not allclose(flatten(matrix), flatten(check)):
                raise ValueError(
                    'This is not a proper projection matrix.')
        super(Projection, self).__init__(matrix=matrix)

    @classmethod
    def isometric(cls):
        """Returns an orthogonal Projection onto a plane
        at angles 120, 120, 120; distrotion ratio 1, 1, 1."""
        P = cls()
        P.matrix = matrix_from_orthogonal_projection(
            ([0, 0, 0], [-1, -1, -1]))
        return P


# ==============================================================================
# Main
# ==============================================================================

if __name__ == "__main__":

    import doctest
    doctest.testmod(globs=globals())

    # ==============================================================================
    # Test
    # ==============================================================================
    from compas.datastructures import Mesh
    from compas_viewers.objectviewer import ObjectViewer

    mesh = Mesh.from_polyhedron(6)

    # apply projection to mesh
    P = Axonometry.isometric()
    projected = mesh.transformed(P)

    # print(projected_point)

    viewer = ObjectViewer()
    viewer.view.use_shaders = True

    # viewer.add(mesh, settings={'color': '#ff0000', 'opacity': 0.7})
    viewer.add(projected, settings={
               'color': '#00ff00', 'opacity': 0.7})

    viewer.update()
    viewer.show()

The axonometry class could also become a view selection button in the ObjectViewer… Where can I submit these proposals/requests ?

BTW, I just found something interesting: CARTESIO (made at the IUAV)
http://www.camillotrevisan.it/intern01.htm