/src/openbabel/src/stereo/squareplanar.cpp
Line | Count | Source |
1 | | #include <openbabel/stereo/squareplanar.h> |
2 | | #include <openbabel/mol.h> |
3 | | #include <openbabel/oberror.h> |
4 | | #include <algorithm> // std::rotate |
5 | | #include <cassert> |
6 | | |
7 | | namespace OpenBabel { |
8 | | |
9 | | // |
10 | | // OBSquarePlanarStereo::Config struct |
11 | | // |
12 | | |
13 | | bool OBSquarePlanarStereo::Config::operator==(const Config &other) const |
14 | 0 | { |
15 | 0 | if (center != other.center) |
16 | 0 | return false; |
17 | 0 | if ((refs.size() != 4) || (other.refs.size() != 4)) |
18 | 0 | return false; |
19 | | |
20 | 0 | Config u1, u2; |
21 | 0 | if (!OBStereo::ContainsSameRefs(refs, other.refs)) { |
22 | | // find a ref that occurs in both |
23 | 0 | for (OBStereo::ConstRefIter i = refs.begin(); i != refs.end(); ++i) |
24 | 0 | if (OBStereo::ContainsRef(other.refs, *i)) { |
25 | 0 | u1 = OBTetraPlanarStereo::ToConfig(*this, *i, OBStereo::ShapeU); // refs[0] = u1.refs[0] |
26 | 0 | u2 = OBTetraPlanarStereo::ToConfig(other, *i, OBStereo::ShapeU); // refs[0] = u2.refs[0] |
27 | 0 | } |
28 | | |
29 | | // check if they actualy share an id... |
30 | 0 | if (u1.refs.empty()) |
31 | 0 | return false; |
32 | 0 | } else { |
33 | | // normalize the other Config struct |
34 | 0 | u1 = OBTetraPlanarStereo::ToConfig(*this, refs.at(0), OBStereo::ShapeU); // refs[0] = u1.refs[0] |
35 | 0 | u2 = OBTetraPlanarStereo::ToConfig(other, refs.at(0), OBStereo::ShapeU); // refs[0] = u2.refs[0] |
36 | | // both now start with the same ref |
37 | | // |
38 | | // 2 possiblilities: |
39 | | // |
40 | | // 1 2 3 4 1 2 3 4 |
41 | | // | | | | <- in any case, refs[0] & refs[2] remain unchanged |
42 | | // 1 2 3 4 1 4 3 2 |
43 | | // |
44 | 0 | return (u1.refs[2] == u2.refs[2]); |
45 | 0 | } |
46 | | |
47 | | // possibilities: |
48 | | // |
49 | | // 1 2 3 4 |
50 | | // | | <- refs[0] & refs[2] remain unchanged |
51 | | // 1 H 3 H |
52 | | // |
53 | | // 1 2 3 4 |
54 | | // | | <- refs[0] & refs[3] remain unchanged |
55 | | // 1 H H 4 |
56 | | // |
57 | | // 1 2 3 4 |
58 | | // | | <- refs[0] & refs[1] remain unchanged |
59 | | // 1 2 H H |
60 | 0 | if ((u1.refs[2] == OBStereo::ImplicitRef) || (u2.refs[2] == OBStereo::ImplicitRef)) { |
61 | | // 1 2 H 4 |
62 | 0 | if ((u1.refs[3] == OBStereo::ImplicitRef) || (u2.refs[3] == OBStereo::ImplicitRef)) { |
63 | 0 | return (u1.refs[1] == u2.refs[1]); // 1 2 H H |
64 | 0 | } else { |
65 | 0 | return (u1.refs[3] == u2.refs[3]); // 1 H H 4 |
66 | 0 | } |
67 | 0 | } else |
68 | 0 | return (u1.refs[2] == u2.refs[2]); // 1 2 3 4 & 1 H 3 4 & 1 2 3 H |
69 | | |
70 | 0 | return false; |
71 | 0 | } |
72 | | |
73 | | |
74 | | // |
75 | | // OBSquarePlanar class |
76 | | // |
77 | | |
78 | 0 | OBSquarePlanarStereo::OBSquarePlanarStereo(OBMol *mol) : OBTetraPlanarStereo(mol) |
79 | 0 | { |
80 | 0 | } |
81 | | |
82 | | OBSquarePlanarStereo::~OBSquarePlanarStereo() |
83 | 0 | { |
84 | 0 | } |
85 | | |
86 | | bool OBSquarePlanarStereo::IsValid() const |
87 | 0 | { |
88 | 0 | if (m_cfg.center == OBStereo::NoRef) |
89 | 0 | return false; |
90 | 0 | if (m_cfg.refs.size() != 4) |
91 | 0 | return false; |
92 | 0 | return true; |
93 | 0 | } |
94 | | |
95 | | void OBSquarePlanarStereo::SetConfig(const Config &config) |
96 | 0 | { |
97 | 0 | if (config.center == OBStereo::NoRef) { |
98 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
99 | 0 | "OBSquarePlanarStereo::SetConfig : center id is invalid.", obError); |
100 | 0 | m_cfg = Config(); |
101 | 0 | return; |
102 | 0 | } |
103 | 0 | if (config.refs.size() != 4) { |
104 | 0 | std::stringstream ss; |
105 | 0 | ss << "OBSquarePlanarStereo::SetConfig : found " << config.refs.size(); |
106 | 0 | ss << " reference ids, should be 4."; |
107 | 0 | obErrorLog.ThrowError(__FUNCTION__, ss.str(), obError); |
108 | 0 | m_cfg = Config(); |
109 | 0 | return; |
110 | 0 | } |
111 | | |
112 | | // store using U shape |
113 | 0 | m_cfg = OBTetraPlanarStereo::ToConfig(config, config.refs.at(0), OBStereo::ShapeU); |
114 | 0 | } |
115 | | |
116 | | OBSquarePlanarStereo::Config OBSquarePlanarStereo::GetConfig(OBStereo::Shape shape) const |
117 | 0 | { |
118 | 0 | if (!IsValid()) |
119 | 0 | return Config(); |
120 | | |
121 | 0 | return OBTetraPlanarStereo::ToConfig(m_cfg, m_cfg.refs.at(0), shape); |
122 | 0 | } |
123 | | |
124 | | OBSquarePlanarStereo::Config OBSquarePlanarStereo::GetConfig(unsigned long start, |
125 | | OBStereo::Shape shape) const |
126 | 0 | { |
127 | 0 | if (!IsValid()) |
128 | 0 | return Config(); |
129 | | |
130 | 0 | return OBTetraPlanarStereo::ToConfig(m_cfg, start, shape); |
131 | 0 | } |
132 | | |
133 | | bool OBSquarePlanarStereo::operator==(const OBSquarePlanarStereo &other) const |
134 | 0 | { |
135 | 0 | if (!IsValid() || !other.IsValid()) |
136 | 0 | return false; |
137 | | |
138 | 0 | Config u = OBTetraPlanarStereo::ToConfig(other.GetConfig(), |
139 | 0 | m_cfg.refs.at(0), OBStereo::ShapeU); |
140 | 0 | unsigned long a1 = u.refs.at(0); |
141 | 0 | unsigned long b1 = u.refs.at(2); |
142 | |
|
143 | 0 | if ((a1 == OBStereo::ImplicitRef) && (b1 == OBStereo::ImplicitRef)) { |
144 | 0 | a1 = u.refs.at(1); |
145 | 0 | b1 = u.refs.at(3); |
146 | 0 | } |
147 | |
|
148 | 0 | if (b1 != OBStereo::ImplicitRef) |
149 | 0 | if (a1 == GetTransRef(b1)) |
150 | 0 | return true; |
151 | 0 | if (a1 != OBStereo::ImplicitRef) |
152 | 0 | if (b1 == GetTransRef(a1)) |
153 | 0 | return true; |
154 | | |
155 | 0 | return false; |
156 | 0 | } |
157 | | |
158 | | bool OBSquarePlanarStereo::IsTrans(unsigned long id1, unsigned long id2) const |
159 | 0 | { |
160 | 0 | return (GetTransRef(id1) == id2); |
161 | 0 | } |
162 | | |
163 | | bool OBSquarePlanarStereo::IsCis(unsigned long id1, unsigned long id2) const |
164 | 0 | { |
165 | 0 | if (m_cfg.refs.size() != 4) |
166 | 0 | return false; |
167 | | |
168 | 0 | std::vector<unsigned long> cis = GetCisRefs(id1); |
169 | 0 | if (cis.size() != 2) |
170 | 0 | return false; |
171 | | |
172 | 0 | if ((cis.at(0) == id2) || (cis.at(1) == id2)) |
173 | 0 | return true; |
174 | | |
175 | 0 | return false; |
176 | 0 | } |
177 | | |
178 | | unsigned long OBSquarePlanarStereo::GetTransRef(unsigned long id) const |
179 | 0 | { |
180 | 0 | if (m_cfg.refs.size() != 4) |
181 | 0 | return false; |
182 | | |
183 | | // find id1 |
184 | 0 | for (int i = 0; i < 4; ++i) { |
185 | 0 | if (m_cfg.refs.at(i) == id) { |
186 | | // use it's index to compare id2 with the opposite reference id |
187 | 0 | int j = (i > 1) ? i - 2 : i + 2; |
188 | 0 | return m_cfg.refs.at(j); |
189 | 0 | } |
190 | 0 | } |
191 | | |
192 | | // id not found |
193 | 0 | return OBStereo::NoRef; |
194 | 0 | } |
195 | | |
196 | | std::vector<unsigned long> OBSquarePlanarStereo::GetCisRefs(unsigned long id) const |
197 | 0 | { |
198 | 0 | std::vector<unsigned long> refs; |
199 | 0 | if (m_cfg.refs.size() != 4) |
200 | 0 | return refs; |
201 | | |
202 | | // find id |
203 | 0 | for (int i = 0; i < 4; ++i) { |
204 | 0 | if (m_cfg.refs.at(i) == id) { |
205 | | // use it's index to get the left/right reference ids |
206 | 0 | int j = (i > 0) ? i - 1 : 3; |
207 | 0 | int k = (i < 3) ? i + 1 : 0; |
208 | 0 | refs.push_back(m_cfg.refs.at(j)); |
209 | 0 | refs.push_back(m_cfg.refs.at(k)); |
210 | 0 | return refs; |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | // id not found |
215 | 0 | return refs; |
216 | 0 | } |
217 | | |
218 | | OBGenericData* OBSquarePlanarStereo::Clone(OBBase *mol) const |
219 | 0 | { |
220 | 0 | OBSquarePlanarStereo *data = new OBSquarePlanarStereo(static_cast<OBMol*>(mol)); |
221 | 0 | data->SetConfig(m_cfg); |
222 | 0 | return data; |
223 | 0 | } |
224 | | |
225 | | } // namespace OpenBabel |
226 | | |
227 | | namespace std { |
228 | | |
229 | | ostream& operator<<(ostream &out, const OpenBabel::OBSquarePlanarStereo &ct) |
230 | 0 | { |
231 | 0 | OpenBabel::OBSquarePlanarStereo::Config cfg = ct.GetConfig(); |
232 | 0 | out << "OBSquarePlanarStereo(center = " << cfg.center; |
233 | |
|
234 | 0 | out << ", refs = "; |
235 | 0 | for (OpenBabel::OBStereo::Refs::iterator i = cfg.refs.begin(); i != cfg.refs.end(); ++i) |
236 | 0 | if (*i != OpenBabel::OBStereo::ImplicitRef) |
237 | 0 | out << *i << " "; |
238 | 0 | else |
239 | 0 | out << "H "; |
240 | |
|
241 | 0 | switch (cfg.shape) { |
242 | 0 | case OpenBabel::OBStereo::ShapeU: |
243 | 0 | out << ", shape = U)"; |
244 | 0 | break; |
245 | 0 | case OpenBabel::OBStereo::ShapeZ: |
246 | 0 | out << ", shape = Z)"; |
247 | 0 | break; |
248 | 0 | case OpenBabel::OBStereo::Shape4: |
249 | 0 | out << ", shape = 4)"; |
250 | 0 | break; |
251 | 0 | } |
252 | | |
253 | 0 | return out; |
254 | 0 | } |
255 | | |
256 | | ostream& operator<<(ostream &out, const OpenBabel::OBSquarePlanarStereo::Config &cfg) |
257 | 0 | { |
258 | 0 | out << "OBSquarePlanarStereo::Config(center = " << cfg.center; |
259 | |
|
260 | 0 | out << ", refs = "; |
261 | 0 | for (OpenBabel::OBStereo::Refs::const_iterator i = cfg.refs.begin(); i != cfg.refs.end(); ++i) |
262 | 0 | if (*i != OpenBabel::OBStereo::ImplicitRef) |
263 | 0 | out << *i << " "; |
264 | 0 | else |
265 | 0 | out << "H "; |
266 | |
|
267 | 0 | switch (cfg.shape) { |
268 | 0 | case OpenBabel::OBStereo::ShapeU: |
269 | 0 | out << ", shape = U)"; |
270 | 0 | break; |
271 | 0 | case OpenBabel::OBStereo::ShapeZ: |
272 | 0 | out << ", shape = Z)"; |
273 | 0 | break; |
274 | 0 | case OpenBabel::OBStereo::Shape4: |
275 | 0 | out << ", shape = 4)"; |
276 | 0 | break; |
277 | 0 | } |
278 | | |
279 | 0 | return out; |
280 | 0 | } |
281 | | |
282 | | } // namespace std |
283 | | |