diff --git a/pygem/ffd.py b/pygem/ffd.py index ab98870..9b40ead 100644 --- a/pygem/ffd.py +++ b/pygem/ffd.py @@ -235,6 +235,26 @@ def reset_weights(self): self.array_mu_x.fill(0.0) self.array_mu_y.fill(0.0) self.array_mu_z.fill(0.0) + + def fit_to_points(self, points, padding_factor=0.05): + """ + Automatically set the FFD box_origin and box_length based on the input points. + + The method computes the axis-aligned bounding box of the input points, adds a small padding, and sets the FFD lattice to exactly + enclose the points. This provides a convenient default for the morphing setup. + + :param numpy.ndarray points: The original mesh points (N x 3). + :param float padding_factor: Additional space around the object as a fraction of its size. Default is 0.05 (5%). + """ + points = np.asarray(points) + min_coords = np.min(points, axis=0) + max_coords = np.max(points, axis=0) + + side_lengths = max_coords - min_coords + padding = side_lengths * padding_factor + self.box_length = side_lengths + 2 * padding + self.box_origin = min_coords - padding + def read_parameters(self, filename='parameters.prm'): """ diff --git a/tests/test_ffd.py b/tests/test_ffd.py index 11702a5..5148fe4 100644 --- a/tests/test_ffd.py +++ b/tests/test_ffd.py @@ -382,3 +382,39 @@ def test_ffd_sphere_mod(self): 'tests/test_datasets/meshpoints_sphere_mod.npy') mesh_points_test = ffd(mesh_points) np.testing.assert_array_almost_equal(mesh_points_test, mesh_points_ref) + + def test_fit_to_points_default_padding(self): + params = FFD() + points = np.array([[0., 0., 0.], [10., 10., 10.]]) + params.fit_to_points(points) + + expected_length = np.array([11., 11., 11.]) + expected_origin = np.array([-0.5, -0.5, -0.5]) + + np.testing.assert_array_almost_equal(params.box_length, expected_length) + np.testing.assert_array_almost_equal(params.box_origin, expected_origin) + + def test_fit_to_points_custom_padding(self): + params = FFD() + points = np.array([[-5., 2., 0.], [5., 6., 10.]]) + # Test with 10% padding + params.fit_to_points(points, padding_factor=0.1) + + expected_length = np.array([12., 4.8, 12.]) + expected_origin = np.array([-6., 1.6, -1.]) + + np.testing.assert_array_almost_equal(params.box_length, expected_length) + np.testing.assert_array_almost_equal(params.box_origin, expected_origin) + + def test_fit_to_points_zero_padding(self): + params = FFD() + points = np.array([[1., 1., 1.], [3., 4., 5.]]) + + # Test with exactly bounding the points (0% padding) + params.fit_to_points(points, padding_factor=0.0) + + expected_length = np.array([2., 3., 4.]) + expected_origin = np.array([1., 1., 1.]) + + np.testing.assert_array_almost_equal(params.box_length, expected_length) + np.testing.assert_array_almost_equal(params.box_origin, expected_origin)