compas-dev / compas

Core packages of the COMPAS framework.
https://compas.dev/compas/
MIT License
310 stars 105 forks source link

mesh_unify_cycles does not always work #16

Closed tomvanmele closed 6 years ago

tomvanmele commented 6 years ago
import random

from compas.geometry import distance_point_point
from compas.datastructures import Mesh
from compas.viewers import MeshViewer
from compas.topology import mesh_unify_cycles
from compas.geometry import convex_hull_numpy

radius = 5
origin = (0., 0., 0.)
count = 0
points = []

while count < 1000:
    x = (random.random() - 0.5) * radius * 2
    y = (random.random() - 0.5) * radius * 2
    z = (random.random() - 0.5) * radius * 2
    pt = x, y, z

    if distance_point_point(origin, pt) <= radius:
        points.append(pt)
        count += 1

vertices, faces = convex_hull_numpy(points)

i_index   = {i: index for index, i in enumerate(vertices)}
vertices = [points[index] for index in vertices]
faces     = [[i_index[i] for i in face] for face in faces]

mesh = Mesh.from_vertices_and_faces(vertices, faces)

mesh_unify_cycles(mesh)

viewer = MeshViewer(mesh)

viewer.axes_on = False
viewer.grid_on = False

viewer.setup()
viewer.show()

Displays a hull with variable colors for the faces, which means that some faces are seen from the back and others from the front.

tomvanmele commented 6 years ago

this is now solved. problem was result of transition from face cycles as dicts versus lists. the cases when half-edges were formed by vertices at the start and end of the vertex lists were not properly handled.

    def unify(node, nbr):
        # find the common edge
        for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
            if u in faces[node] and v in faces[node]:
                # node and nbr have edge u-v in common
                i = faces[node].index(u)
                j = faces[node].index(v)
                if i == j - 1:
                    # if the traversal of a neighbouring halfedge
                    # is in the same direction
                    # flip the neighbour
                    faces[nbr][:] = faces[nbr][::-1]
                    return

is now

    def unify(node, nbr):
        # find the common edge
        for u, v in pairwise(faces[nbr] + faces[nbr][0:1]):
            if u in faces[node] and v in faces[node]:
                # node and nbr have edge u-v in common
                i = faces[node].index(u)
                j = faces[node].index(v)
                if i == j - 1 or (j == 0 and u == faces[node][-1]):
                    # if the traversal of a neighbouring halfedge
                    # is in the same direction
                    # flip the neighbour
                    faces[nbr][:] = faces[nbr][::-1]
                    return

the snippet included in the original post works fine now...