mathLab / PyGeM

Python Geometrical Morphing
http://mathlab.github.io/PyGeM/
Other
332 stars 116 forks source link

Points on bounding box not deforming #272

Open MarkoLeskovar opened 3 weeks ago

MarkoLeskovar commented 3 weeks ago

Dear PyGem Team.

Background I have the following problem. I have a bunch of meshes to which I want to apply some random deformations using the FFD transformer. Basically, I position the vertices of my surface mesh somewhere in space and initialize the FFD object such that the control points lie exactly on the bounding box of the object. In other words, control points are also the bounding box of my mesh.

Presumed bug I have noticed that points that lie exactly on plane of that bounding box do not deform as they should. The opposite, they do not deform at all. This creates weird looking deformation patterns, as shown in image below. point_deformation point_deformation_2

To Reproduce Here is a code to reproduce the similar error, but with random points instead. Points marked in orange are the ones that do not deform. `

Import modules

import numpy as np
import pyvista as pv
from pygem import FFD

# Define points
num_points = 1000
points = np.random.random(size=(num_points, 3)) * 100

# Get mesh bounding box
mesh_bbox = [
    (np.min(points[:, 0]), np.max(points[:, 0])),
    (np.min(points[:, 1]), np.max(points[:, 1])),
    (np.min(points[:, 2]), np.max(points[:, 2])),
]

mesh_bbox_length = np.asarray(mesh_bbox)[:, 1] - np.asarray(mesh_bbox)[:, 0]
mesh_bbox_origin = np.mean(np.asarray(mesh_bbox), axis=1)

# Control lattice
lattice = [2, 2, 2]

# Free-Form Deformation class
ffd_transformer = FFD(n_control_points=lattice)

# Print info
print(ffd_transformer)

# Center the control lattice
ffd_transformer.box_length = mesh_bbox_length
ffd_transformer.box_origin = mesh_bbox_origin - 0.5 * mesh_bbox_length

# Apply deformations (relative size to between 0-1 of the bbox)
ffd_transformer.array_mu_x[1, 1, 1] = 0.5
ffd_transformer.array_mu_y[1, 1, 1] = 0.5
ffd_transformer.array_mu_z[1, 1, 1] = 0.5

# Apply deformations
deformed_points = ffd_transformer(points)

# Differences
diff = deformed_points - points
zero_ids = np.where(np.linalg.norm(diff, axis=1) == 0)[0]

# Show the mesh
pl = pv.Plotter()
pl.add_points(points, render_points_as_spheres=True, color='blue', opacity=0.5, label='Original Mesh')
pl.add_points(deformed_points, render_points_as_spheres=True, color='red', opacity=0.5, label='Deformed Mesh')
pl.add_points(ffd_transformer.control_points(), render_points_as_spheres=True, color='green', point_size=20, label='Control Points')
# Plot error points
if len(zero_ids) != 0:
    pl.add_points(deformed_points[zero_ids, :], render_points_as_spheres=True, color='orange', point_size=20)
# Show everything
pl.add_legend()
pl.show()`

Expected behaviour I would expect all the points to deform according to some rules defined in the FFD. Am I understanding this wrong, of this this a bug in the code?

Best regards, Marko

guglielmopadula commented 3 days ago

Dear Marko Leskovar, I tried to run your code, and it seems to me that is working as it should. The only points that are not moved are on the boundary on the bounding box. Points on the boundary of the bounding box do not move because they correspond to the zeros of the Bernstein Polynomials. Furthermore the amount of deformation is continuous with respect to the distance from the control point that is moved. So to get meaningful deformations everywhere it is suggested to move more than one control point. I am available if you have further doubts. Best regards, Guglielmo