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