2323iflogger = logging .getLogger ('interface' )
2424
2525
26- class P2PDistanceInputSpec (BaseInterfaceInputSpec ):
26+ class ComputeMeshWarpInputSpec (BaseInterfaceInputSpec ):
2727 surface1 = File (exists = True , mandatory = True ,
28- desc = (" Reference surface (vtk format) to which compute "
29- " distance." ))
28+ desc = (' Reference surface (vtk format) to which compute '
29+ ' distance.' ))
3030 surface2 = File (exists = True , mandatory = True ,
31- desc = ("Test surface (vtk format) from which compute "
32- "distance." ))
31+ desc = ('Test surface (vtk format) from which compute '
32+ 'distance.' ))
33+ metric = traits .Enum ('euclidean' , 'sqeuclidean' , usedefault = True ,
34+ desc = ('norm used to report distance' ))
3335 weighting = traits .Enum (
34- "none" , "area" , usedefault = True ,
35- desc = ('"none": no weighting is performed, "area": vertex distances are'
36- 'weighted by the total area of faces corresponding to the '
37- 'vertex' ))
36+ 'none' , 'area' , usedefault = True ,
37+ desc = ('"none": no weighting is performed, surface": edge distance is '
38+ 'weighted by the corresponding surface area' ))
39+ out_warp = File ('surfwarp.vtk' , usedefault = True ,
40+ desc = 'vtk file based on surface1 and warpings mapping it '
41+ 'to surface2' )
3842 out_file = File ('distance.npy' , usedefault = True ,
3943 desc = 'numpy file keeping computed distances and weights' )
4044
4145
42- class P2PDistanceOutputSpec (TraitedSpec ):
46+ class ComputeMeshWarpOutputSpec (TraitedSpec ):
4347 distance = traits .Float (desc = "computed distance" )
48+ out_warp = File (exists = True , desc = ('vtk file with the vertex-wise '
49+ 'mapping of surface1 to surface2' ))
4450 out_file = File (exists = True ,
4551 desc = 'numpy file keeping computed distances and weights' )
4652
4753
48- class P2PDistance (BaseInterface ):
54+ class ComputeMeshWarp (BaseInterface ):
4955
50- """Calculates a point-to-point (p2p) distance between two corresponding
51- VTK-readable meshes or contours.
56+ """
57+ Calculates a the vertex-wise warping to get surface2 from surface1.
58+ It also reports the average distance of vertices, using the norm specified
59+ as input.
60+
61+ .. warning:
62+
63+ A point-to-point correspondence between surfaces is required
5264
53- A point-to-point correspondence between nodes is required
5465
5566 Example
5667 -------
5768
5869 >>> import nipype.algorithms.mesh as mesh
59- >>> dist = mesh.P2PDistance ()
70+ >>> dist = mesh.ComputeMeshWarp ()
6071 >>> dist.inputs.surface1 = 'surf1.vtk'
6172 >>> dist.inputs.surface2 = 'surf2.vtk'
6273 >>> res = dist.run() # doctest: +SKIP
74+
6375 """
6476
65- input_spec = P2PDistanceInputSpec
66- output_spec = P2PDistanceOutputSpec
77+ input_spec = ComputeMeshWarpInputSpec
78+ output_spec = ComputeMeshWarpOutputSpec
6779
6880 def _triangle_area (self , A , B , C ):
6981 ABxAC = euclidean (A , B ) * euclidean (A , C )
@@ -73,10 +85,11 @@ def _triangle_area(self, A, B, C):
7385 return area
7486
7587 def _run_interface (self , runtime ):
88+ from numpy import linalg as nla
7689 try :
77- from tvtk .api import tvtk
90+ from tvtk .api import tvtk , write_data
7891 except ImportError :
79- raise ImportError ('Interface P2PDistance requires tvtk' )
92+ raise ImportError ('Interface ComputeMeshWarp requires tvtk' )
8093
8194 try :
8295 from enthought .etsconfig .api import ETSConfig
@@ -99,9 +112,13 @@ def _run_interface(self, runtime):
99112 points1 = np .array (vtk1 .points )
100113 points2 = np .array (vtk2 .points )
101114
102- diff = np . linalg . norm ( points1 - points2 , axis = 1 )
115+ diff = points2 - points1
103116 weights = np .ones (len (diff ))
104117
118+ errvector = nla .norm (diff , axis = 1 )
119+ if self .inputs .metric == 'sqeuclidean' :
120+ errvector = errvector ** 2
121+
105122 if (self .inputs .weighting == 'area' ):
106123 faces = vtk1 .polys .to_array ().reshape (- 1 , 4 ).astype (int )[:, 1 :]
107124
@@ -117,14 +134,40 @@ def _run_interface(self, runtime):
117134 w += self ._triangle_area (fp1 , fp2 , fp3 )
118135 weights [i ] = w
119136
120- result = np .vstack ([diff , weights ])
137+ result = np .vstack ([errvector , weights ])
121138 np .save (op .abspath (self .inputs .out_file ), result .transpose ())
122139
123- self ._distance = np .average (diff , weights = weights )
140+ out_mesh = tvtk .PolyData ()
141+ out_mesh .points = vtk1 .points
142+ out_mesh .polys = vtk1 .polys
143+ out_mesh .point_data .warpings = [tuple (d ) for d in diff ]
144+
145+ write_data (out_mesh , op .abspath (self .inputs .out_warp ))
146+
147+ self ._distance = np .average (errvector , weights = weights )
124148 return runtime
125149
126150 def _list_outputs (self ):
127151 outputs = self ._outputs ().get ()
128152 outputs ['out_file' ] = op .abspath (self .inputs .out_file )
129153 outputs ['distance' ] = self ._distance
130154 return outputs
155+
156+
157+ class P2PDistance (ComputeMeshWarp ):
158+
159+ """
160+ Calculates a point-to-point (p2p) distance between two corresponding
161+ VTK-readable meshes or contours.
162+
163+ A point-to-point correspondence between nodes is required
164+
165+ .. deprecated:: 1.0-dev
166+ Use :py:class:`ComputeMeshWarp` instead.
167+ """
168+
169+ def __init__ (self , ** inputs ):
170+ super (P2PDistance , self ).__init__ (** inputs )
171+ warnings .warn (("This interface has been deprecated since 1.0,"
172+ " please use nipype.algorithms.metrics.Distance" ),
173+ DeprecationWarning )
0 commit comments