@@ -25,27 +25,14 @@ class FFDParameters(object):
2525 :param list n_control_points: number of control points in the x, y, and z
2626 direction. If not provided it is set to [2, 2, 2].
2727
28- :cvar float length_box_x: length of the FFD bounding box in the x direction
29- (local coordinate system).
30- :cvar float length_box_y: length of the FFD bounding box in the y direction
31- (local coordinate system).
32- :cvar float length_box_z: length of the FFD bounding box in the z direction
33- (local coordinate system).
34-
35- :cvar numpy.ndarray origin_box: a 3-by-1 vector of float numbers
36- representing the x, y and z coordinates of the origin of the FFD
37- bounding box.
38-
39- :cvar float rot_angle_x: rotation angle around x axis of the FFD bounding
40- box.
41- :cvar float rot_angle_y: rotation angle around y axis of the FFD bounding
42- box.
43- :cvar float rot_angle_z: rotation angle around z axis of the FFD bounding
44- box.
45-
46- :cvar list n_control_points: list of 3 int representing the number of
47- control points in the x, y, and z direction.
48-
28+ :cvar numpy.ndarray length_box: dimension of the FFD bounding box, in the
29+ x, y and z direction (local coordinate system).
30+ :cvar numpy.ndarray origin_box: the x, y and z coordinates of the origin of
31+ the FFD bounding box.
32+ :cvar numpy.ndarray rot_angle: rotation angle around x, y and z axis of the
33+ FFD bounding box.
34+ :cvar numpy.ndarray n_control_points: the number of control points in the
35+ x, y, and z direction.
4936 :cvar numpy.ndarray array_mu_x: collects the displacements (weights) along
5037 x, normalized with the box lenght x.
5138 :cvar numpy.ndarray array_mu_y: collects the displacements (weights) along
@@ -73,16 +60,18 @@ class FFDParameters(object):
7360 :Example: from file
7461
7562 >>> import pygem.params as ffdp
76-
63+ >>>
7764 >>> # Reading an existing file
7865 >>> params1 = ffdp.FFDParameters()
79- >>> params1.read_parameters(filename='tests/test_datasets/parameters_test_ffd_identity.prm')
80-
81- >>> # Creating a default parameters file with the right dimensions (if the file does not exists
82- >>> # it is created with that name). So it is possible to manually edit it and read it again.
66+ >>> params1.read_parameters(
67+ >>> filename='tests/test_datasets/parameters_test_ffd_identity.prm')
68+ >>>
69+ >>> # Creating a default parameters file with the right dimensions (if the
70+ >>> # file does not exists it is created with that name). So it is possible
71+ >>> # to manually edit it and read it again.
8372 >>> params2 = ffdp.FFDParameters(n_control_points=[2, 3, 2])
8473 >>> params2.read_parameters(filename='parameters_test.prm')
85-
74+ >>>
8675 >>> # Creating bounding box of the given shape
8776 >>> from OCC.IGESControl import IGESControl_Reader
8877 >>> params3 = ffdp.FFDParameters()
@@ -115,15 +104,42 @@ def __init__(self, n_control_points=None):
115104 self .array_mu_y = np .zeros (self .n_control_points )
116105 self .array_mu_z = np .zeros (self .n_control_points )
117106
118- self .psi_mapping = np .diag (1. / self .lenght_box )
119- self .inv_psi_mapping = np .diag (self .lenght_box )
120-
121- self .rotation_matrix = np .eye (3 )
122107 self .position_vertex_0 = self .origin_box
123108 self .position_vertex_1 = np .array ([1. , 0. , 0. ])
124109 self .position_vertex_2 = np .array ([0. , 1. , 0. ])
125110 self .position_vertex_3 = np .array ([0. , 0. , 1. ])
126111
112+ @property
113+ def psi_mapping (self ):
114+ """
115+ Map from the physical domain to the reference domain.
116+
117+ :return: map from the pysical domain to the reference domain.
118+ :rtype: numpy.ndarray
119+ """
120+ return np .diag (np .reciprocal (self .lenght_box ))
121+
122+ @property
123+ def inv_psi_mapping (self ):
124+ """
125+ Map from the reference domain to the physical domain.
126+
127+ :return: map from the reference domain to domain.
128+ :rtype: numpy.ndarray
129+ """
130+ return np .diag (self .lenght_box )
131+
132+ @property
133+ def rotation_matrix (self ):
134+ """
135+ :cvar numpy.ndarray rotation_matrix: rotation matrix (according to
136+ rot_angle_x, rot_angle_y, rot_angle_z).
137+ """
138+ return at .angles2matrix (
139+ radians (self .rot_angle [2 ]), radians (self .rot_angle [1 ]),
140+ radians (self .rot_angle [0 ]))
141+
142+
127143 def read_parameters (self , filename = 'parameters.prm' ):
128144 """
129145 Reads in the parameters file and fill the self structure.
@@ -181,10 +197,6 @@ def read_parameters(self, filename='parameters.prm'):
181197 values = line .split ()
182198 self .array_mu_z [tuple (map (int , values [0 :3 ]))] = float (values [3 ])
183199
184- self .rotation_matrix = at .angles2matrix (
185- radians (self .rot_angle [2 ]), radians (self .rot_angle [1 ]),
186- radians (self .rot_angle [0 ]))
187-
188200 self .position_vertex_0 = self .origin_box
189201 self .position_vertex_1 = self .position_vertex_0 + \
190202 np .dot (self .rotation_matrix , [self .lenght_box [0 ], 0 , 0 ])
@@ -193,9 +205,6 @@ def read_parameters(self, filename='parameters.prm'):
193205 self .position_vertex_3 = self .position_vertex_0 + \
194206 np .dot (self .rotation_matrix , [0 , 0 , self .lenght_box [2 ]])
195207
196- self .psi_mapping = np .diag (1. / self .lenght_box )
197- self .inv_psi_mapping = np .diag (self .lenght_box )
198-
199208 def write_parameters (self , filename = 'parameters.prm' ):
200209 """
201210 This method writes a parameters file (.prm) called `filename` and fills
@@ -343,24 +352,10 @@ def build_bounding_box(self,
343352 min_xyz , max_xyz = self ._calculate_bb_dimension (shape , tol , triangulate ,
344353 triangulate_tol )
345354 self .origin_box = min_xyz
346- self ._set_box_dimensions ( min_xyz , max_xyz )
355+ self .lenght_box = max_xyz - min_xyz
347356 self ._set_position_of_vertices ()
348- self ._set_mapping ()
349357 self ._set_transformation_params_to_zero ()
350358
351- def _set_box_dimensions (self , min_xyz , max_xyz ):
352- """
353- Dimensions of the cage are set as distance from the origin (minimum) of
354- the cage to the maximal point in each dimension.
355-
356- :param iterable min_xyz: three values representing the minimal values of
357- the bounding box in XYZ respectively
358- :param iterable max_xyz: three values representing the maximal values of
359- the bounding box in XYZ respectively
360- """
361- dims = [max_xyz [i ] - min_xyz [i ] for i in range (3 )]
362- self .lenght_box = np .asarray (dims )
363-
364359 def _set_position_of_vertices (self ):
365360 """
366361 Vertices of the control box around the object are set in this method.
@@ -376,24 +371,15 @@ def _set_position_of_vertices(self):
376371 self .position_vertex_3 = self .origin_box + np .array (
377372 [.0 , .0 , self .lenght_box [2 ]])
378373
379- def _set_mapping (self ):
380- """
381- This method sets mapping from physcial domain to the reference domain
382- (``psi_mapping``) as well as inverse mapping (``inv_psi_mapping``).
383- """
384- self .psi_mapping = np .diag ([1. / self .lenght_box [i ] for i in range (3 )])
385- self .inv_psi_mapping = np .diag (self .lenght_box )
386-
387374 def _set_transformation_params_to_zero (self ):
388375 """
389376 Sets transfomration parameters (``array_mu_x, array_mu_y, array_mu_z``)
390377 to arrays of zeros (``numpy.zeros``). The shape of arrays corresponds to
391378 the number of control points in each dimension.
392379 """
393- ctrl_pnts = self .n_control_points
394- self .array_mu_x = np .zeros (ctrl_pnts )
395- self .array_mu_y = np .zeros (ctrl_pnts )
396- self .array_mu_z = np .zeros (ctrl_pnts )
380+ self .array_mu_x .fill (0.0 )
381+ self .array_mu_y .fill (0.0 )
382+ self .array_mu_z .fill (0.0 )
397383
398384 @staticmethod
399385 def _calculate_bb_dimension (shape ,
@@ -428,170 +414,3 @@ def _calculate_bb_dimension(shape,
428414 xyz_min = np .array ([xmin , ymin , zmin ])
429415 xyz_max = np .array ([xmax , ymax , zmax ])
430416 return xyz_min , xyz_max
431-
432-
433- class RBFParameters (object ):
434- """
435- Class that handles the Radial Basis Functions parameters in terms of RBF
436- control points and basis functions.
437-
438- :cvar string basis: name of the basis functions to use in the
439- transformation. The functions implemented so far are: gaussian spline,
440- multi quadratic biharmonic spline, inv multi quadratic biharmonic
441- spline, thin plate spline, beckert wendland c2 basis, polyharmonic
442- splines. For a comprehensive list with details see the class
443- :class:`~pygem.radialbasis.RBF`. The default value is None.
444- :cvar float radius: is the scaling parameter r that affects the shape of the
445- basis functions. For details see the class
446- :class:`~pygem.radialbasis.RBF`. The default value is None.
447- :cvar int n_control_points: total number of control points.
448- :cvar numpy.ndarray original_control_points: it is an
449- `n_control_points`-by-3 array with the coordinates of the original
450- interpolation control points before the deformation. The default value
451- is None.
452- :cvar numpy.ndarray deformed_control_points: it is an
453- `n_control_points`-by-3 array with the coordinates of the
454- interpolation control points after the deformation. The default value is
455- None.
456- """
457-
458- def __init__ (self ):
459- self .basis = None
460- self .radius = None
461- self .power = 2
462- self .n_control_points = None
463- self .original_control_points = None
464- self .deformed_control_points = None
465-
466- def read_parameters (self , filename = 'parameters_rbf.prm' ):
467- """
468- Reads in the parameters file and fill the self structure.
469-
470- :param string filename: parameters file to be read in. Default value is
471- parameters_rbf.prm.
472- """
473- if not isinstance (filename , str ):
474- raise TypeError ('filename must be a string' )
475-
476- # Checks if the parameters file exists. If not it writes the default
477- # class into filename. It consists in the vetices of a cube of side one
478- # with a vertex in (0, 0, 0) and opposite one in (1, 1, 1).
479- if not os .path .isfile (filename ):
480- self .basis = 'gaussian_spline'
481- self .radius = 0.5
482- self .n_control_points = 8
483- self .original_control_points = np .array ([0. , 0. , 0. , 0. , 0. , 1. , 0. , 1. , 0. , 1. , 0. , 0. , \
484- 0. , 1. , 1. , 1. , 0. , 1. , 1. , 1. , 0. , 1. , 1. , 1. ]).reshape ((8 , 3 ))
485- self .deformed_control_points = np .array ([0. , 0. , 0. , 0. , 0. , 1. , 0. , 1. , 0. , 1. , 0. , 0. , \
486- 0. , 1. , 1. , 1. , 0. , 1. , 1. , 1. , 0. , 1. , 1. , 1. ]).reshape ((8 , 3 ))
487- self .write_parameters (filename )
488- return
489-
490- config = configparser .RawConfigParser ()
491- config .read (filename )
492-
493- self .basis = config .get ('Radial Basis Functions' , 'basis function' )
494- self .radius = config .getfloat ('Radial Basis Functions' , 'radius' )
495- self .power = config .getint ('Radial Basis Functions' , 'power' )
496-
497- ctrl_points = config .get ('Control points' , 'original control points' )
498- lines = ctrl_points .split ('\n ' )
499- self .n_control_points = len (lines )
500- self .original_control_points = np .zeros ((self .n_control_points , 3 ))
501- for line , i in zip (lines , list (range (0 , self .n_control_points ))):
502- values = line .split ()
503- self .original_control_points [i ] = np .array (
504- [float (values [0 ]),
505- float (values [1 ]),
506- float (values [2 ])])
507-
508- mod_points = config .get ('Control points' , 'deformed control points' )
509- lines = mod_points .split ('\n ' )
510-
511- if len (lines ) != self .n_control_points :
512- raise TypeError ("The number of control points must be equal both in the 'original control points'" + \
513- " and in the 'deformed control points' section of the parameters file ({0!s})" .format (filename ))
514-
515- self .deformed_control_points = np .zeros ((self .n_control_points , 3 ))
516- for line , i in zip (lines , list (range (0 , self .n_control_points ))):
517- values = line .split ()
518- self .deformed_control_points [i ] = np .array (
519- [float (values [0 ]),
520- float (values [1 ]),
521- float (values [2 ])])
522-
523- def write_parameters (self , filename = 'parameters_rbf.prm' ):
524- """
525- This method writes a parameters file (.prm) called `filename` and fills
526- it with all the parameters class members. Default value is
527- parameters_rbf.prm.
528-
529- :param string filename: parameters file to be written out.
530- """
531- if not isinstance (filename , str ):
532- raise TypeError ("filename must be a string" )
533-
534- with open (filename , 'w' ) as output_file :
535- output_file .write ('\n [Radial Basis Functions]\n ' )
536- output_file .write (
537- '# This section describes the radial basis functions shape.\n ' )
538-
539- output_file .write ('\n # basis funtion is the name of the basis functions to use in the transformation. ' + \
540- 'The functions\n ' )
541- output_file .write (
542- '# implemented so far are: gaussian_spline, multi_quadratic_biharmonic_spline,\n '
543- )
544- output_file .write (
545- '# inv_multi_quadratic_biharmonic_spline, thin_plate_spline, beckert_wendland_c2_basis, polyharmonic_spline.\n '
546- )
547- output_file .write (
548- '# For a comprehensive list with details see the class RBF.\n ' )
549- output_file .write ('basis function: ' + str (self .basis ) + '\n ' )
550-
551- output_file .write ('\n # radius is the scaling parameter r that affects the shape of the basis functions. ' + \
552- 'See the documentation\n ' )
553- output_file .write ('# of the class RBF for details.\n ' )
554- output_file .write ('radius: ' + str (self .radius ) + '\n ' )
555- output_file .write (
556- '\n # The power parameter k for polyharmonic spline' )
557- output_file .write ('\n # See the documentation for details\n ' )
558- output_file .write ('power: ' + str (self .power ) + '\n ' )
559-
560- output_file .write ('\n \n [Control points]\n ' )
561- output_file .write (
562- '# This section describes the RBF control points.\n ' )
563-
564- output_file .write ('\n # original control points collects the coordinates of the interpolation ' + \
565- 'control points before the deformation.\n ' )
566- output_file .write ('original control points:' )
567- offset = 1
568- for i in range (0 , self .n_control_points ):
569- output_file .write (offset * ' ' + str (self .original_control_points [i ][0 ]) + ' ' + \
570- str (self .original_control_points [i ][1 ]) + ' ' + \
571- str (self .original_control_points [i ][2 ]) + '\n ' )
572- offset = 25
573-
574- output_file .write ('\n # deformed control points collects the coordinates of the interpolation ' + \
575- 'control points after the deformation.\n ' )
576- output_file .write ('deformed control points:' )
577- offset = 1
578- for i in range (0 , self .n_control_points ):
579- output_file .write (offset * ' ' + str (self .deformed_control_points [i ][0 ]) + ' ' + \
580- str (self .deformed_control_points [i ][1 ]) + ' ' + \
581- str (self .deformed_control_points [i ][2 ]) + '\n ' )
582- offset = 25
583-
584- def __str__ (self ):
585- """
586- This method prints all the RBF parameters on the screen. Its purpose is
587- for debugging.
588- """
589- string = ''
590- string += 'basis function = {}\n ' .format (self .basis )
591- string += 'radius = {}\n ' .format (self .radius )
592- string += 'power = {}\n ' .format (self .power )
593- string += '\n original control points =\n '
594- string += '{}\n ' .format (self .original_control_points )
595- string += '\n deformed control points =\n '
596- string += '{}\n ' .format (self .deformed_control_points )
597- return string
0 commit comments