1 // -*- C++ -*-
2
3 /*
4 * Gnome Chemistry Utils
5 * bond.cc
6 *
7 * Copyright (C) 2001-2011 Jean Bréfort <jean.brefort@normalesup.org>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 3 of the
12 * License, or (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 St, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 */
24
25 #include "config.h"
26 #include "bond.h"
27 #include "atom.h"
28 #include "objprops.h"
29 #include "document.h"
30 #include "molecule.h"
31 #include <glib/gi18n-lib.h>
32 #include <cmath>
33 #include <sstream>
34
35 using namespace std;
36
37 namespace gcu
38 {
39
Bond()40 Bond::Bond(): Object(BondType)
41 {
42 SetId ("b1");
43 m_Begin = NULL;
44 m_End = NULL;
45 m_order = 0;
46 }
47
Bond(Atom * first,Atom * last,unsigned char order)48 Bond::Bond(Atom* first, Atom* last, unsigned char order): Object(BondType)
49 {
50 SetId ("b1");
51 m_Begin = first;
52 m_End = last;
53 m_order = order;
54 first->AddBond(this);
55 last->AddBond(this);
56 }
57
~Bond()58 Bond::~Bond()
59 {
60 Molecule *mol = static_cast < Molecule * > (GetMolecule ());
61 if (mol)
62 mol->Remove (this);
63 }
64
GetAtom(int which) const65 Atom* Bond::GetAtom(int which) const
66 {
67 switch (which)
68 {
69 case 0: return m_Begin;
70 case 1: return m_End;
71 default: return NULL;
72 }
73 }
74
GetAtom(Atom * pAtom,G_GNUC_UNUSED int which) const75 Atom* Bond::GetAtom(Atom* pAtom, G_GNUC_UNUSED int which) const
76 {
77 return (pAtom == m_Begin)? m_End: (pAtom == m_End)? m_Begin: NULL;
78 }
79
GetAtom(Atom const * pAtom,G_GNUC_UNUSED int which) const80 Atom const * Bond::GetAtom (Atom const * pAtom, G_GNUC_UNUSED int which) const
81 {
82 return (pAtom == m_Begin)? m_End: (pAtom == m_End)? m_Begin: NULL;
83 }
84
GetOrder() const85 unsigned char Bond::GetOrder() const
86 {
87 return m_order;
88 }
89
SetOrder(unsigned char Order)90 void Bond::SetOrder(unsigned char Order)
91 {
92 m_order = Order;
93 }
94
Save(xmlDocPtr xml) const95 xmlNodePtr Bond::Save(xmlDocPtr xml) const
96 {
97 xmlNodePtr parent;
98 gchar buf[16];
99 parent = xmlNewDocNode(xml, NULL, (xmlChar*)"bond", NULL);
100 if (!parent) return NULL;
101
102 SaveId(parent);
103
104 buf[0] = m_order + '0';
105 buf[1] = 0;
106 xmlNewProp(parent, (xmlChar*)"order", (xmlChar*)buf);
107
108 if (m_Begin)
109 xmlNewProp (parent, (xmlChar*) "begin", (xmlChar*) m_Begin->GetId ());
110
111
112 if (m_End)
113 xmlNewProp (parent, (xmlChar*) "end", (xmlChar*) m_End->GetId ());
114
115 if (!SaveNode(xml, parent)) {xmlFreeNode(parent); return NULL;}
116 return parent;
117 }
118
Load(xmlNodePtr node)119 bool Bond::Load (xmlNodePtr node)
120 {
121 char* tmp;
122 xmlNodePtr child;
123 Document *doc = GetDocument ();
124 tmp = (char*) xmlGetProp (node, (xmlChar*) "id");
125 if (tmp) {
126 SetId (tmp);
127 xmlFree (tmp);
128 }
129 tmp = (char*) xmlGetProp (node, (xmlChar*) "order");
130 if (!tmp) m_order = 1;
131 else {
132 m_order = *tmp - '0';
133 xmlFree (tmp);
134 }
135 if (m_order > 4)
136 return false;
137 tmp = (char*) xmlGetProp (node, (xmlChar*) "begin");
138 if (!tmp) {
139 child = GetNodeByName(node, "begin");
140 tmp = (char*) xmlNodeGetContent(child); //necessary to read version 0.1.0 files
141 if (!tmp)
142 return false;
143 }
144 doc->SetTarget (tmp, reinterpret_cast <Object **> (&m_Begin), GetParent (), this, ActionDelete);
145 xmlFree (tmp);
146 tmp = (char*) xmlGetProp (node, (xmlChar*) "end");
147 if (!tmp) {
148 child = GetNodeByName (node, "end");
149 tmp = (char*) xmlNodeGetContent (child); //necessary to read version 0.1.0 files
150 if (!tmp)
151 return false;
152 }
153 if (doc->SetTarget (tmp, reinterpret_cast <Object **> (&m_End), GetParent (), this, ActionDelete))
154 m_End->AddBond (this);
155 xmlFree (tmp);
156 bool result = LoadNode (node);
157 doc->ObjectLoaded (this);
158 OnLoaded ();
159 return result;
160 }
161
LoadNode(xmlNodePtr)162 bool Bond::LoadNode(xmlNodePtr)
163 {
164 return true;
165 }
166
SaveNode(xmlDocPtr,xmlNodePtr) const167 bool Bond::SaveNode(xmlDocPtr, xmlNodePtr) const
168 {
169 return true;
170 }
171
IncOrder(int n)172 void Bond::IncOrder(int n)
173 {
174 m_order += n;
175 if (m_order > 4) m_order %= 4;
176 }
177
Move(G_GNUC_UNUSED double x,G_GNUC_UNUSED double y,G_GNUC_UNUSED double z)178 void Bond::Move(G_GNUC_UNUSED double x, G_GNUC_UNUSED double y, G_GNUC_UNUSED double z)
179 {
180 }
181
Transform2D(G_GNUC_UNUSED Matrix2D & m,G_GNUC_UNUSED double x,G_GNUC_UNUSED double y)182 void Bond::Transform2D(G_GNUC_UNUSED Matrix2D& m, G_GNUC_UNUSED double x, G_GNUC_UNUSED double y)
183 {
184 }
185
SetProperty(unsigned property,char const * value)186 bool Bond::SetProperty (unsigned property, char const *value)
187 {
188 switch (property) {
189 case GCU_PROP_ID: {
190 char *Id = (*value == 'b')? g_strdup (value): g_strdup_printf ("b%s", value);
191 SetId (Id);
192 break;
193 }
194 case GCU_PROP_BOND_BEGIN: {
195 char *tmp = (*value == 'a')? g_strdup (value): g_strdup_printf ("a%s", value);
196 if (!GetDocument ()->SetTarget (tmp, reinterpret_cast <Object **> (&m_Begin), GetParent (), this))
197 return false;
198 g_free (tmp);
199 if (m_End) {
200 m_Begin->AddBond (this);
201 m_End->AddBond (this);
202 }
203 break;
204 }
205 case GCU_PROP_BOND_END: {
206 char *tmp = (*value == 'a')? g_strdup (value): g_strdup_printf ("a%s", value);
207 if (!GetDocument ()->SetTarget (tmp, reinterpret_cast <Object **> (&m_End), GetParent (), this))
208 return false;
209 g_free (tmp);
210 if (m_Begin) {
211 m_Begin->AddBond (this);
212 m_End->AddBond (this);
213 }
214 break;
215 }
216 case GCU_PROP_BOND_ORDER:
217 m_order = atoi (value);
218 if (m_Begin && m_End) {
219 m_Begin->AddBond (this);
220 m_End->AddBond (this);
221 }
222 break;
223 }
224 return true;
225 }
226
GetProperty(unsigned property) const227 string Bond::GetProperty (unsigned property) const
228 {
229 ostringstream res;
230 switch (property) {
231 case GCU_PROP_BOND_BEGIN:
232 res << m_Begin->GetId ();
233 break;
234 case GCU_PROP_BOND_END:
235 res << m_End->GetId ();
236 break;
237 case GCU_PROP_BOND_ORDER:
238 res << static_cast <unsigned> (m_order);
239 break;
240 default:
241 return Object::GetProperty (property);
242 }
243 return res.str ();
244 }
245
AddCycle(Cycle * pCycle)246 void Bond::AddCycle (Cycle* pCycle)
247 {
248 m_Cycles.push_back (pCycle);
249 }
250
RemoveCycle(Cycle * pCycle)251 void Bond::RemoveCycle (Cycle* pCycle)
252 {
253 m_Cycles.remove (pCycle);
254 }
255
RemoveAllCycles()256 void Bond::RemoveAllCycles ()
257 {
258 m_Cycles.clear ();
259 }
260
GetFirstCycle(std::list<Cycle * >::iterator & i,Cycle * pCycle)261 Cycle* Bond::GetFirstCycle (std::list<Cycle*>::iterator& i, Cycle * pCycle)
262 {
263 i = m_Cycles.begin ();
264 return GetNextCycle (i, pCycle);
265 }
266
GetNextCycle(std::list<Cycle * >::iterator & i,Cycle * pCycle)267 Cycle* Bond::GetNextCycle (std::list<Cycle*>::iterator& i, Cycle * pCycle)
268 {
269 if (*i == pCycle)
270 i++;
271 if (i == m_Cycles.end ())
272 return NULL;
273 pCycle = *i;
274 i++;
275 return pCycle;
276 }
277
IsInCycle(Cycle * pCycle)278 bool Bond::IsInCycle (Cycle* pCycle)
279 {
280 std::list<Cycle*>::iterator i, end = m_Cycles.end ();
281 for (i = m_Cycles.begin (); i != end; i++)
282 if ((*i) == pCycle)
283 return true;
284 return false;
285 }
286
Get2DLength()287 double Bond::Get2DLength ()
288 {
289 double x1, y1, x2, y2;
290 m_Begin->GetCoords (&x1, &y1);
291 m_End->GetCoords (&x2, &y2);
292 return sqrt (square (x1 - x2) + square (y1 - y2));
293 }
294
GetAngle2DRad(Atom * pAtom)295 double Bond::GetAngle2DRad (Atom* pAtom)
296 {
297 double x1, y1, x2, y2;
298 if (m_Begin == NULL || m_End == NULL)
299 return HUGE_VAL;
300 m_Begin->GetCoords (&x1, &y1);
301 m_End->GetCoords (&x2, &y2);
302 x2 -= x1;
303 y2 -= y1;
304 double length = square (x2) + square (y2);
305 if (length == 0.0)
306 return HUGE_VAL;
307 if (pAtom == m_Begin)
308 return atan2 (-y2, x2);
309 else if (pAtom == m_End)
310 return atan2 (y2, -x2);
311 return HUGE_VAL;
312 }
313
ReplaceAtom(Atom * oldAtom,Atom * newAtom)314 bool Bond::ReplaceAtom (Atom* oldAtom, Atom* newAtom)
315 {
316 if (oldAtom == m_Begin) {
317 if (m_End)
318 m_End->RemoveBond (this);
319 m_Begin = newAtom;
320 if (m_Begin && m_End)
321 m_End->AddBond (this);
322 } else if (oldAtom == m_End) {
323 if (m_Begin)
324 m_Begin->RemoveBond (this);
325 m_End = newAtom;
326 if (m_Begin && m_End)
327 m_Begin->AddBond (this);
328 }
329 return true;
330 }
331
OnLoaded()332 void Bond::OnLoaded ()
333 {
334 if (m_Begin && m_End) {
335 m_Begin->AddBond (this);
336 m_End->AddBond (this);
337 }
338 }
339
Name()340 std::string Bond::Name ()
341 {
342 return _("Bond");
343 }
344
345 } // namespace gcu
346