1
2
3
4
5
6
7 import Geometry
8 import Numeric
9 from Chem.FeatMaps import FeatMaps
10 from Chem.FeatMaps.FeatMapPoint import FeatMapPoint
11 import math,copy
12
14 WeightedAverage=0
15 """ Put the new point at the weighted average position of the two
16 fused points
17 """
18
19 Average=1
20 """ Put the new point at the un-weighted average position of the two
21 fused points
22 """
23
24 UseLarger=2
25 """ Put the new point at the position of the larger (by weight)
26 of the two points
27 """
28
30 NoMerge=0
31 """ Do not merge points """
32
33 Distance=1
34 """ merge two points if they come within a threshold distance """
35
36 Overlap=2
37 """ merge two points if their percent overlap exceeds a threshold """
38
40 NoMerge=0
41 """ Do not merge directions (i.e. keep all direction vectors) """
42
43 Sum=1
44 """ Sum direction vectors """
45
47 """ no user-serviceable parts inside """
48 for feat in fm1.getFeatures():
49 res.addFeatPoint(copy.deepcopy(feat))
50 for feat in fm2.getFeatures():
51 res.addFeatPoint(copy.deepcopy(feat))
52
53
90
93
94 -def feq(v1,v2,tol=1e-4):
96
101 """
102
103 NOTE that mergeTol is a max value for merging when using distance-based
104 merging and a min value when using score-based merging.
105
106 returns whether or not any points were actually merged
107
108 """
109 res=False
110 if mergeMetric==MergeMetric.NoMerge:
111 return res
112 dists = GetFeatFeatDistMatrix(fm,mergeMetric,mergeTol,dirMergeMode,compatFunc)
113 distOrders = [None]*len(dists)
114 for i in range(len(dists)):
115 distV = dists[i]
116 distOrders[i] = []
117 for j,dist in enumerate(distV):
118 if dist<mergeTol:
119 distOrders[i].append((dist,j))
120 distOrders[i].sort()
121
122
123
124
125
126
127
128
129
130 featsInPlay=range(fm.GetNumFeatures())
131 featsToRemove = []
132
133 while featsInPlay:
134
135 fipCopy=featsInPlay[:]
136 for fi in fipCopy:
137
138
139 mergeThem=False
140 if not distOrders[fi]:
141 featsInPlay.remove(fi)
142 continue
143 dist,nbr = distOrders[fi][0]
144 if nbr not in featsInPlay:
145 continue
146 if distOrders[nbr][0][1]==fi:
147
148 mergeThem=True
149 else:
150
151
152 if(feq(distOrders[nbr][0][0],dist)):
153 for distJ,nbrJ in distOrders[nbr][1:]:
154 if feq(dist,distJ):
155 if nbrJ==fi:
156
157 mergeThem=True
158 break
159 else:
160 break
161
162 if mergeThem: break
163 if mergeThem:
164 res=True
165 featI = fm.GetFeature(fi)
166 nbrFeat = fm.GetFeature(nbr)
167
168 if mergeMethod==MergeMethod.WeightedAverage:
169 newPos = featI.GetPos()*featI.weight+nbrFeat.GetPos()*nbrFeat.weight
170 newPos /= (featI.weight+nbrFeat.weight)
171 newWeight = (featI.weight+nbrFeat.weight)/2
172 elif mergeMethod==MergeMethod.Average:
173 newPos = featI.GetPos()+nbrFeat.GetPos()
174 newPos /= 2
175 newWeight = (featI.weight+nbrFeat.weight)/2
176 elif mergeMethod==MergeMethod.UseLarger:
177 if featI.weight>nbrFeat.weight:
178 newPos=featI.GetPos()
179 newWeight = featI.weight
180 else:
181 newPos=nbrFeat.GetPos()
182 newWeight = nbrFeat.weight
183 else:
184 raise ValueError,"bad mergeMethod"
185
186 featI.SetPos(newPos)
187 featI.weight = newWeight
188
189
190
191 featsToRemove.append(nbr)
192 featsInPlay.remove(fi)
193 featsInPlay.remove(nbr)
194 for nbrList in distOrders:
195 try:
196 nbrList.remove(fi)
197 except ValueError:
198 pass
199 try:
200 nbrList.remove(nbr)
201 except ValueError:
202 pass
203 else:
204
205 break
206 featsToRemove.sort()
207 for i,fIdx in enumerate(featsToRemove):
208 fm.DropFeature(fIdx-i)
209 return res
210
222
223
224
225
226
228 import doctest,sys
229 return doctest.testmod(sys.modules["__main__"])
230
231 if __name__ == '__main__':
232 import sys
233 failed,tried = _test()
234 sys.exit(failed)
235