/src/openbabel/src/stereo/tetrahedral.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | tetrahedral.h - OBTetrahedralStereo |
3 | | |
4 | | Copyright (C) 2009 by Tim Vandermeersch |
5 | | |
6 | | This file is part of the Open Babel project. |
7 | | For more information, see <http://openbabel.org/> |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 2 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program; if not, write to the Free Software |
21 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
22 | | 02110-1301, USA. |
23 | | **********************************************************************/ |
24 | | #include <openbabel/stereo/tetrahedral.h> |
25 | | #include <openbabel/mol.h> |
26 | | |
27 | | namespace OpenBabel { |
28 | | |
29 | | // |
30 | | // OBTetrahedralStereo::Config struct |
31 | | // |
32 | | |
33 | | bool OBTetrahedralStereo::Config::operator==(const OBTetrahedralStereo::Config &other) const |
34 | 0 | { |
35 | 0 | if (center != other.center) |
36 | 0 | return false; |
37 | 0 | if ((refs.size() != 3) || (other.refs.size() != 3)) |
38 | 0 | return false; |
39 | | // return true if either is unspecified (i.e. accidental) |
40 | 0 | if (!specified || !other.specified) |
41 | 0 | return true; |
42 | | |
43 | | // Convert both Config's refs to same from, winding and view while |
44 | | // avoiding having an ImplicitRef in the 'from' position of either |
45 | 0 | Config thisConfig, otherConfig; |
46 | 0 | if (from == OBStereo::ImplicitRef) { |
47 | 0 | thisConfig = OBTetraNonPlanarStereo::ToConfig(*this, refs[0], winding, view); |
48 | 0 | otherConfig = OBTetraNonPlanarStereo::ToConfig(other, thisConfig.from, winding, view); |
49 | 0 | } |
50 | 0 | else if (other.from == OBStereo::ImplicitRef) { |
51 | 0 | otherConfig = OBTetraNonPlanarStereo::ToConfig(other, other.refs[0], winding, view); |
52 | 0 | thisConfig = OBTetraNonPlanarStereo::ToConfig(*this, otherConfig.from, winding, view); |
53 | 0 | } |
54 | 0 | else { |
55 | 0 | thisConfig = *this; |
56 | 0 | otherConfig = OBTetraNonPlanarStereo::ToConfig(other, thisConfig.from, winding, view); |
57 | 0 | } |
58 | |
|
59 | 0 | if (!OBStereo::ContainsSameRefs(thisConfig.refs, otherConfig.refs)) { |
60 | 0 | if (OBStereo::ContainsRef(thisConfig.refs, OBStereo::ImplicitRef)) { |
61 | | // if both refs already contain ImplicitRef, return false |
62 | 0 | if (OBStereo::ContainsRef(otherConfig.refs, OBStereo::ImplicitRef)) |
63 | 0 | return false; |
64 | | |
65 | | // example: *this = 23H |
66 | | // otherConfig = 234 --> 23H |
67 | | |
68 | | // for each ref in otherConfig |
69 | 0 | for (unsigned int i = 0; i < otherConfig.refs.size(); ++i) { |
70 | 0 | bool found = false; |
71 | 0 | for (OBStereo::RefIter j = thisConfig.refs.begin(); j != thisConfig.refs.end(); ++j) |
72 | 0 | if (otherConfig.refs.at(i) == *j) |
73 | 0 | found = true; |
74 | |
|
75 | 0 | if (!found) { |
76 | | // the ref from otherConfig is not found in this config |
77 | 0 | otherConfig.refs[i] = OBStereo::ImplicitRef; |
78 | 0 | break; |
79 | 0 | } |
80 | 0 | } |
81 | 0 | } else |
82 | 0 | if (OBStereo::ContainsRef(otherConfig.refs, OBStereo::ImplicitRef)) { |
83 | | // if both refs already contain ImplicitRef, return false |
84 | 0 | if (OBStereo::ContainsRef(thisConfig.refs, OBStereo::ImplicitRef)) |
85 | 0 | return false; |
86 | | |
87 | | // example: *this = 234 |
88 | | // otherConfig = 23H --> 234 |
89 | | |
90 | | // for each ref in *this |
91 | 0 | for (unsigned int i = 0; i < thisConfig.refs.size(); ++i) { |
92 | 0 | bool found = false; |
93 | | // for each refs in otherConfig |
94 | 0 | for (OBStereo::RefIter j = otherConfig.refs.begin(); j != otherConfig.refs.end(); ++j) |
95 | 0 | if (thisConfig.refs.at(i) == *j) |
96 | 0 | found = true; |
97 | |
|
98 | 0 | if (!found) { |
99 | 0 | for (OBStereo::RefIter j = otherConfig.refs.begin(); j != otherConfig.refs.end(); ++j) |
100 | 0 | if (*j == OBStereo::ImplicitRef) |
101 | 0 | *j = thisConfig.refs.at(i); |
102 | 0 | break; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | 0 | int Ni1 = OBStereo::NumInversions(thisConfig.refs); |
109 | 0 | int Ni2 = OBStereo::NumInversions(otherConfig.refs); |
110 | 0 | return ((Ni1 + Ni2) % 2 == 0); |
111 | 0 | } |
112 | | |
113 | | // |
114 | | // OBTetrahedralStereo class |
115 | | // |
116 | | |
117 | | OBTetrahedralStereo::OBTetrahedralStereo(OBMol *mol) : |
118 | 0 | OBTetraNonPlanarStereo(mol), m_cfg(Config()) |
119 | 0 | { |
120 | 0 | } |
121 | | |
122 | | OBTetrahedralStereo::~OBTetrahedralStereo() |
123 | 0 | { |
124 | 0 | } |
125 | | |
126 | | bool OBTetrahedralStereo::IsValid() const |
127 | 0 | { |
128 | 0 | if (m_cfg.center == OBStereo::NoRef) |
129 | 0 | return false; |
130 | 0 | if (m_cfg.from == OBStereo::NoRef) |
131 | 0 | return false; |
132 | 0 | if (m_cfg.refs.size() != 3) |
133 | 0 | return false; |
134 | 0 | return true; |
135 | 0 | } |
136 | | |
137 | | void OBTetrahedralStereo::SetConfig(const Config &config) |
138 | 0 | { |
139 | 0 | if (config.center == OBStereo::NoRef) { |
140 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
141 | 0 | "OBTetrahedralStereo::SetConfig : center atom id is invalid.", obError); |
142 | 0 | m_cfg = Config(); |
143 | 0 | return; |
144 | 0 | } |
145 | 0 | if (config.from == OBStereo::NoRef) { |
146 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
147 | 0 | "OBTetrahedralStereo::SetConfig : from/towards atom id is invalid.", obError); |
148 | 0 | m_cfg = Config(); |
149 | 0 | return; |
150 | 0 | } |
151 | 0 | if (config.refs.size() != 3) { |
152 | 0 | std::stringstream ss; |
153 | 0 | ss << "OBTetrahedralStereo::SetConfig : found " << config.refs.size(); |
154 | 0 | ss << " reference ids, should be 3."; |
155 | 0 | obErrorLog.ThrowError(__FUNCTION__, ss.str(), obError); |
156 | 0 | m_cfg = Config(); |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | 0 | m_cfg = config; |
161 | 0 | } |
162 | | |
163 | | OBTetrahedralStereo::Config OBTetrahedralStereo::GetConfig( |
164 | | OBStereo::Winding winding, OBStereo::View view) const |
165 | 0 | { |
166 | 0 | if (!IsValid()) |
167 | 0 | return Config(); |
168 | | |
169 | 0 | if (m_cfg.winding != OBStereo::UnknownWinding) |
170 | 0 | return OBTetraNonPlanarStereo::ToConfig(m_cfg, m_cfg.from, winding, view); |
171 | 0 | else |
172 | 0 | return OBTetraNonPlanarStereo::ToConfig(m_cfg, m_cfg.from, OBStereo::UnknownWinding, view); |
173 | 0 | } |
174 | | |
175 | | OBTetrahedralStereo::Config OBTetrahedralStereo::GetConfig(unsigned long from_or_towards, |
176 | | OBStereo::Winding winding, OBStereo::View view) const |
177 | 0 | { |
178 | 0 | if (!IsValid()) |
179 | 0 | return Config(); |
180 | | |
181 | 0 | if (m_cfg.winding != OBStereo::UnknownWinding) |
182 | 0 | return OBTetraNonPlanarStereo::ToConfig(m_cfg, from_or_towards, winding, view); |
183 | 0 | else |
184 | 0 | return OBTetraNonPlanarStereo::ToConfig(m_cfg, from_or_towards, OBStereo::UnknownWinding, view); |
185 | 0 | } |
186 | | |
187 | | bool OBTetrahedralStereo::operator==(const OBTetrahedralStereo &other) const |
188 | 0 | { |
189 | 0 | if (!IsValid() || !other.IsValid()) |
190 | 0 | return false; |
191 | | |
192 | 0 | if (m_cfg == other.GetConfig()) |
193 | 0 | return true; |
194 | | |
195 | 0 | return false; |
196 | 0 | } |
197 | | |
198 | | OBGenericData* OBTetrahedralStereo::Clone(OBBase *mol) const |
199 | 0 | { |
200 | 0 | OBTetrahedralStereo *data = new OBTetrahedralStereo(static_cast<OBMol*>(mol)); |
201 | 0 | data->SetConfig(m_cfg); |
202 | 0 | return data; |
203 | 0 | } |
204 | | |
205 | | } // namespace OpenBabel |
206 | | |
207 | | namespace std { |
208 | | |
209 | | using namespace OpenBabel; |
210 | | |
211 | | ostream& operator<<(ostream &out, const OBTetrahedralStereo &ts) |
212 | 0 | { |
213 | 0 | OBTetrahedralStereo::Config cfg = ts.GetConfig(); |
214 | 0 | out << "OBTetrahedralStereo(center = " << cfg.center; |
215 | 0 | if (cfg.view == OBStereo::ViewFrom) |
216 | 0 | out << ", viewFrom = "; |
217 | 0 | else |
218 | 0 | out << ", viewTowards = "; |
219 | |
|
220 | 0 | if (cfg.from == OBStereo::ImplicitRef) |
221 | 0 | out << "H"; |
222 | 0 | else |
223 | 0 | out << cfg.from; |
224 | |
|
225 | 0 | out << ", refs = "; |
226 | 0 | for (OBStereo::Refs::iterator i = cfg.refs.begin(); i != cfg.refs.end(); ++i) |
227 | 0 | if (*i != OBStereo::ImplicitRef) |
228 | 0 | out << *i << " "; |
229 | 0 | else |
230 | 0 | out << "H "; |
231 | |
|
232 | 0 | if (!cfg.specified) |
233 | 0 | out << ", unspecified)"; |
234 | 0 | else { |
235 | 0 | if (cfg.winding == OBStereo::Clockwise) |
236 | 0 | out << ", clockwise)"; |
237 | 0 | else |
238 | 0 | out << ", anti-clockwise)"; |
239 | 0 | } |
240 | |
|
241 | 0 | return out; |
242 | 0 | } |
243 | | |
244 | | ostream& operator<<(ostream &out, const OBTetrahedralStereo::Config &cfg) |
245 | 0 | { |
246 | 0 | out << "OBTetrahedralStereo::Config(center = " << cfg.center; |
247 | 0 | if (cfg.view == OBStereo::ViewFrom) |
248 | 0 | out << ", viewFrom = "; |
249 | 0 | else |
250 | 0 | out << ", viewTowards = "; |
251 | |
|
252 | 0 | if (cfg.from == OBStereo::ImplicitRef) |
253 | 0 | out << "H"; |
254 | 0 | else |
255 | 0 | out << cfg.from; |
256 | |
|
257 | 0 | out << ", refs = "; |
258 | 0 | for (OBStereo::Refs::const_iterator i = cfg.refs.begin(); i != cfg.refs.end(); ++i) |
259 | 0 | if (*i != OBStereo::ImplicitRef) |
260 | 0 | out << *i << " "; |
261 | 0 | else |
262 | 0 | out << "H "; |
263 | |
|
264 | 0 | if (!cfg.specified) |
265 | 0 | out << ", unspecified)"; |
266 | 0 | else { |
267 | 0 | if (cfg.winding == OBStereo::Clockwise) |
268 | 0 | out << ", clockwise)"; |
269 | 0 | else |
270 | 0 | out << ", anti-clockwise)"; |
271 | 0 | } |
272 | |
|
273 | 0 | return out; |
274 | 0 | } |
275 | | |
276 | | } // namespace std |
277 | | |