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