Mapping

../_images/example_mapping_patterns.png
from compas.colors import Color
from compas.datastructures import Mesh
from compas_viewer import Viewer
from compas_viewer.config import Config
from tessagon.adaptors.list_adaptor import ListAdaptor
from tessagon.types.brick_tessagon import BrickTessagon
from tessagon.types.dissected_hex_quad_tessagon import DissectedHexQuadTessagon
from tessagon.types.dissected_hex_tri_tessagon import DissectedHexTriTessagon
from tessagon.types.dissected_square_tessagon import DissectedSquareTessagon
from tessagon.types.dissected_triangle_tessagon import DissectedTriangleTessagon
from tessagon.types.dodeca_tessagon import DodecaTessagon
from tessagon.types.floret_tessagon import FloretTessagon
from tessagon.types.hex_big_tri_tessagon import HexBigTriTessagon

from tessagon.types.hex_tessagon import HexTessagon
from tessagon.types.hex_tri_tessagon import HexTriTessagon
from tessagon.types.octo_tessagon import OctoTessagon
from tessagon.types.pythagorean_tessagon import PythagoreanTessagon
from tessagon.types.rhombus_tessagon import RhombusTessagon
from tessagon.types.square_tessagon import SquareTessagon
from tessagon.types.square_tri_tessagon import SquareTriTessagon
from tessagon.types.tri_tessagon import TriTessagon
from tessagon.types.weave_tessagon import WeaveTessagon
from tessagon.types.zig_zag_tessagon import ZigZagTessagon

import compas_libigl as igl

TESSAGON_TYPES = {
    1: ("Hex", HexTessagon),
    2: ("Tri", TriTessagon),
    3: ("Octo", OctoTessagon),
    4: ("Square", SquareTessagon),
    5: ("Rhombus", RhombusTessagon),
    6: ("HexTri", HexTriTessagon),
    7: ("DissectedSquare", DissectedSquareTessagon),
    8: ("DissectedTriangle", DissectedTriangleTessagon),
    9: ("DissectedHexQuad", DissectedHexQuadTessagon),
    10: ("DissectedHexTri", DissectedHexTriTessagon),
    11: ("Floret", FloretTessagon),
    12: ("Pythagorean", PythagoreanTessagon),
    13: ("Brick", BrickTessagon),
    14: ("Weave", WeaveTessagon),
    15: ("ZigZag", ZigZagTessagon),
    16: ("HexBigTri", HexBigTriTessagon),
    17: ("Dodeca", DodecaTessagon),
    18: ("SquareTri", SquareTriTessagon),
}

# Pattern selection - change this value to use a different pattern
PATTERN_TYPE = 15

# ==============================================================================
# Input geometry: 3D Mesh
# ==============================================================================

mesh = Mesh.from_obj("data/minimal_surface.obj")
for key, attr in mesh.vertices(True):
    y = attr["y"]
    attr["y"] = -attr["z"]
    attr["z"] = y
mesh.translate([2, 2, 0.5])

v, f = mesh.to_vertices_and_faces()


# ==============================================================================
# Input geometry: 2D Pattern creation using Tessagon library, can be other mesh.
# ==============================================================================

options = {
    "function": lambda u, v: [u, v, 0],
    "u_range": [-0.25, 1.25],
    "v_range": [-0.25, 1.25],
    "u_num": 20,
    "v_num": 20,
    "u_cyclic": False,
    "v_cyclic": False,
    "adaptor_class": ListAdaptor,
}

# Get pattern name and class based on selected pattern type
pattern_name, pattern_class = TESSAGON_TYPES[PATTERN_TYPE]

# Create the selected tessagon pattern
tessagon = pattern_class(**options)
tessagon_mesh = tessagon.create_mesh()
pv = tessagon_mesh["vert_list"]
pf = tessagon_mesh["face_list"]

# ==============================================================================
# Mapping: 3D Mesh, 2D Pattern, UV
# ==============================================================================

mv, mf = igl.map_mesh((v, f), (pv, pf))
mesh_mapped = Mesh.from_vertices_and_faces(mv, mf)

# ==============================================================================
# Viewer
# ==============================================================================

config = Config()
config.camera.target = [2, 2, 0.25]
config.camera.position = [5, 2, 1.5]

viewer = Viewer(config=config)
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
viewer.scene.add(Mesh.from_vertices_and_faces(pv, pf), name="pattern2d")
viewer.scene.add(mesh_mapped, name="mesh_mapped", facecolor=Color.red())

# To see where the pattern is mapped:
uv = igl.trimesh_lsc_mapping((v, f))
mesh_flattened = mesh.copy()
for i in range(mesh.number_of_vertices()):
    mesh_flattened.vertex_attributes(i, "xyz", [uv[i][0], uv[i][1], 0])

viewer.scene.add(mesh_flattened, name="mesh_flattened")
viewer.show()
../_images/example_mapping.png
from compas.colors import Color
from compas.datastructures import Mesh
from compas_viewer import Viewer
from compas_viewer.config import Config
from tessagon.adaptors.list_adaptor import ListAdaptor
from tessagon.types.hex_tessagon import HexTessagon

import compas_libigl as igl

# ==============================================================================
# Input geometry: 3D Mesh
# ==============================================================================

mesh = Mesh.from_obj("data/minimal_surface.obj")
for key, attr in mesh.vertices(True):
    y = attr["y"]
    attr["y"] = -attr["z"]
    attr["z"] = y
mesh.translate([2, 2, 0.5])

v, f = mesh.to_vertices_and_faces()


# ==============================================================================
# Input geometry: 2D Pattern creation using Tessagon library, can be other mesh.
# ==============================================================================

options = {
    "function": lambda u, v: [u, v, 0],
    "u_range": [-0.255, 1.33],
    "v_range": [-0.34, 1.33],
    "u_num": 16,
    "v_num": 10,
    "u_cyclic": False,
    "v_cyclic": False,
    "adaptor_class": ListAdaptor,
}
tessagon = HexTessagon(**options)
tessagon_mesh = tessagon.create_mesh()
pv = tessagon_mesh["vert_list"]
pf = tessagon_mesh["face_list"]

# ==============================================================================
# Mapping: 3D Mesh, 2D Pattern, UV
# ==============================================================================

mv, mf = igl.map_mesh((v, f), (pv, pf))
mesh_mapped = Mesh.from_vertices_and_faces(mv, mf)

# ==============================================================================
# Viewer
# ==============================================================================

config = Config()
config.camera.target = [2, 2, 0.25]
config.camera.position = [5, 2, 1.5]

viewer = Viewer(config=config)
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
viewer.scene.add(Mesh.from_vertices_and_faces(pv, pf), name="pattern2d")
viewer.scene.add(mesh_mapped, name="mesh_mapped", facecolor=Color.red())

# To see where the pattern is mapped:
uv = igl.trimesh_lsc_mapping((v, f))
mesh_flattened = mesh.copy()
for i in range(mesh.number_of_vertices()):
    mesh_flattened.vertex_attributes(i, "xyz", [uv[i][0], uv[i][1], 0])

viewer.scene.add(mesh_flattened, name="mesh_flattened")
viewer.show()
../_images/example_mapping_boundaries.png
from math import pi

from compas.colors import Color
from compas.datastructures import Mesh
from compas.geometry import Polygon
from compas_viewer import Viewer
from compas_viewer.config import Config
from tessagon.adaptors.list_adaptor import ListAdaptor
from tessagon.types.hex_tessagon import HexTessagon

import compas_libigl as igl

# ==============================================================================
# Input geometry: 3D Mesh
# ==============================================================================

mesh = Mesh.from_obj("data/minimal_surface.obj")
for key, attr in mesh.vertices(True):
    y = attr["y"]
    attr["y"] = -attr["z"]
    attr["z"] = y
mesh.translate([2, 2, 0.5])

v, f = mesh.to_vertices_and_faces()

# ==============================================================================
# Flattening
# ==============================================================================

# To see where the pattern is mapped:
uv = igl.trimesh_lsc_mapping((v, f))
mesh_flattened = mesh.copy()
for i in range(mesh.number_of_vertices()):
    mesh_flattened.vertex_attributes(i, "xyz", [uv[i][0], uv[i][1], 0])


# ==============================================================================
# Input geometry: 2D Pattern creation using Tessagon library, can be other mesh.
# ==============================================================================

options = {
    "function": lambda u, v: [u, v, 0],
    "u_range": [-0.255, 1.33],
    "v_range": [-0.34, 1.33],
    "u_num": 16,
    "v_num": 10,
    "u_cyclic": False,
    "v_cyclic": False,
    "adaptor_class": ListAdaptor,
}
tessagon = HexTessagon(**options)
tessagon_mesh = tessagon.create_mesh()
pv = tessagon_mesh["vert_list"]
pf = tessagon_mesh["face_list"]

# rotate the pattern
rotated_mesh = Mesh.from_vertices_and_faces(pv, pf)
rotated_mesh.rotate(0 * pi / 180, [0, 0, 1])

pv, pf = rotated_mesh.to_vertices_and_faces()

# ==============================================================================
# Boundaries
# ==============================================================================

boundaries = igl.trimesh_boundaries(mesh_flattened.to_vertices_and_faces())

polygons = []
for vertices in boundaries:
    vertices = list(vertices)
    vertices.pop()
    vertices.append(vertices[0])
    points = mesh_flattened.vertices_attributes("xyz", keys=vertices)
    polygons.append(Polygon(points))

# ==============================================================================
# 2D Boolean Intersection using Shapely
# ==============================================================================

polygons_cut = []
for face in pf:
    points = []
    for vertex in face:
        points.append(pv[vertex])
    polygon_cut = Polygon(points)
    if len(points) > 2:
        polygons_cut.append(polygon_cut)


# Polygon.boolean_intersection
intersections = []
for polygon_cut in polygons_cut:
    for polygon in polygons:
        from compas.geometry import boolean_intersection_polygon_polygon

        coords = boolean_intersection_polygon_polygon(polygon, polygon_cut)
        if len(coords) > 0:
            intersection = Polygon([[x, y, 0] for x, y in coords])  # type: ignore
            intersections.append(intersection)

mesh_cropped = Mesh.from_polygons(intersections)
pv, pf = mesh_cropped.to_vertices_and_faces()


# ==============================================================================
# Place the pattern mesh at the bottom left corner of the meshpattern_uv
# ==============================================================================

mv, mf = igl.map_mesh((v, f), (pv, pf))
mesh_mapped = Mesh.from_vertices_and_faces(mv, mf)

# ==============================================================================
# Viewer
# ==============================================================================

config = Config()
config.camera.target = [2, 2, 0.25]
config.camera.position = [5, 2, 1.5]

viewer = Viewer(config=config)
viewer.scene.add(mesh, name="mesh", show_faces=False, linecolor=Color.grey(), opacity=0.2)
viewer.scene.add(mesh_mapped, name="mesh_mapped", facecolor=Color.red())
viewer.scene.add(rotated_mesh, linecolor=Color.red(), linewidth=3)
viewer.scene.add(intersections, linecolor=Color.red(), linewidth=3)
viewer.scene.add(mesh_flattened, name="mesh_flattened0")
viewer.show()