13
13
14
14
15
15
import numpy as np
16
+ import os .path as op
16
17
from scipy .spatial .distance import euclidean
17
18
18
19
from .. import logging
@@ -29,14 +30,19 @@ class P2PDistanceInputSpec(BaseInterfaceInputSpec):
29
30
surface2 = File (exists = True , mandatory = True ,
30
31
desc = ("Test surface (vtk format) from which compute "
31
32
"distance." ))
32
- weighting = traits .Enum ("none" , "surface" , usedefault = True ,
33
- desc = ('"none": no weighting is performed, '
34
- '"surface": edge distance is weighted by the '
35
- 'corresponding surface area' ))
33
+ 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' ))
38
+ out_file = File ('distance.npy' , usedefault = True ,
39
+ desc = 'numpy file keeping computed distances and weights' )
36
40
37
41
38
42
class P2PDistanceOutputSpec (TraitedSpec ):
39
43
distance = traits .Float (desc = "computed distance" )
44
+ out_file = File (exists = True ,
45
+ desc = 'numpy file keeping computed distances and weights' )
40
46
41
47
42
48
class P2PDistance (BaseInterface ):
@@ -78,6 +84,9 @@ def _run_interface(self, runtime):
78
84
except ImportError :
79
85
iflogger .warn (('ETS toolkit could not be imported' ))
80
86
pass
87
+ except ValueError :
88
+ iflogger .warn (('ETS toolkit is already set' ))
89
+ pass
81
90
82
91
r1 = tvtk .PolyDataReader (file_name = self .inputs .surface1 )
83
92
r2 = tvtk .PolyDataReader (file_name = self .inputs .surface2 )
@@ -86,32 +95,36 @@ def _run_interface(self, runtime):
86
95
r1 .update ()
87
96
r2 .update ()
88
97
assert (len (vtk1 .points ) == len (vtk2 .points ))
89
- d = 0.0
90
- totalWeight = 0.0
91
98
92
- points = vtk1 .points
93
- faces = vtk1 .polys .to_array ().reshape (- 1 , 4 ).astype (int )[:, 1 :]
99
+ points1 = np .array (vtk1 .points )
100
+ points2 = np .array (vtk2 .points )
101
+
102
+ diff = np .linalg .norm (points1 - points2 , axis = 1 )
103
+ weights = np .ones (len (diff ))
104
+
105
+ if (self .inputs .weighting == 'area' ):
106
+ faces = vtk1 .polys .to_array ().reshape (- 1 , 4 ).astype (int )[:, 1 :]
94
107
95
- for p1 , p2 in zip (points , vtk2 .points ):
96
- weight = 1.0
97
- if (self .inputs .weighting == 'surface' ):
108
+ for i , p1 in enumerate (points2 ):
98
109
# compute surfaces, set in weight
99
- weight = 0.0
100
- point_faces = faces [(faces [:, :] == 0 ).any (axis = 1 )]
110
+ w = 0.0
111
+ point_faces = faces [(faces [:, :] == i ).any (axis = 1 )]
101
112
102
113
for idset in point_faces :
103
- p1 = points [int (idset [0 ])]
104
- p2 = points [int (idset [1 ])]
105
- p3 = points [int (idset [2 ])]
106
- weight = weight + self ._triangle_area (p1 , p2 , p3 )
114
+ fp1 = points1 [int (idset [0 ])]
115
+ fp2 = points1 [int (idset [1 ])]
116
+ fp3 = points1 [int (idset [2 ])]
117
+ w += self ._triangle_area (fp1 , fp2 , fp3 )
118
+ weights [i ] = w
107
119
108
- d += weight * euclidean ( p1 , p2 )
109
- totalWeight = totalWeight + weight
120
+ result = np . vstack ([ diff , weights ] )
121
+ np . save ( op . abspath ( self . inputs . out_file ), result . transpose ())
110
122
111
- self ._distance = d / totalWeight
123
+ self ._distance = np . average ( diff , weights = weights )
112
124
return runtime
113
125
114
126
def _list_outputs (self ):
115
127
outputs = self ._outputs ().get ()
128
+ outputs ['out_file' ] = op .abspath (self .inputs .out_file )
116
129
outputs ['distance' ] = self ._distance
117
130
return outputs
0 commit comments