1 // ELDVIEW_WCL.CPP
2 
3 // Copyright (C) 2005 Tommi Hassinen.
4 
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 /*################################################################################################*/
20 
21 #include "eldview_wcl.h"
22 
23 #include "custom_app.h"
24 
25 #include "local_i18n.h"
26 
27 #include <GL/gl.h>
28 #include <GL/glu.h>
29 
30 #include <sstream>
31 using namespace std;
32 
33 /*################################################################################################*/
34 
eldview_wcl(void)35 eldview_wcl::eldview_wcl(void) :
36 	pangofont_wcl(new ogl_camera(ogl_ol_static(), 1.0))
37 {
38 	cam->ortho = true;
39 
40 	cam->update_vdim = false;
41 	vdim[0] = 0.75;			// X-scaling
42 
43 	cam->GetLD()->crd[0] = 0.65;	// X-centering
44 
45 //const ogl_obj_loc_data * d = cam->GetSafeLD();
46 //cout << "cam crd = " << d->crd[0] << " " << d->crd[1] << " " << d->crd[2] << endl;
47 //cout << "cam zdir = { " << d->zdir << " }" << endl << "cam ydir = { " << d->ydir << " }" << endl;
48 
49 	reset_needed = true;
50 	SetCenterAndScale();
51 }
52 
~eldview_wcl(void)53 eldview_wcl::~eldview_wcl(void)
54 {
55 	// problem : lifetime of the camera object needs to be longer than
56 	// lifetime of this object since it is needed at the base class dtor.
57 	// solution : ask the base class to do the cleanup work for us...
58 
59 	delete_cam_plz = true;
60 }
61 
SetCenterAndScale(void)62 void eldview_wcl::SetCenterAndScale(void)
63 {
64 	project * prj = custom_app::GetAppC()->GetPrj();
65 	engine * eng = prj->GetCurrentSetup()->GetCurrentEngine();
66 
67 	setup1_qm * su1 = dynamic_cast<setup1_qm *>(prj->GetCurrentSetup());
68 	bool nonQM = (!su1);
69 
70 	if (!eng || nonQM)
71 	{
72 		cam->GetLD()->crd[1] = 0.0;			// center
73 		vdim[1] = 1.0;					// scale
74 
75 		reset_needed = true;		// failed...
76 	}
77 	else
78 	{
79 		f64 mine = eng->GetOrbitalEnergy(0);
80 		f64 maxe = eng->GetOrbitalEnergy(eng->GetOrbitalCount() - 1);
81 
82 // above we assumed that the first orbital has lowest and the last orbital has highest energy...
83 // above we assumed that the first orbital has lowest and the last orbital has highest energy...
84 // above we assumed that the first orbital has lowest and the last orbital has highest energy...
85 
86 		cam->GetLD()->crd[1] = (mine + maxe) / 2.0;	// center
87 		vdim[1] = (maxe - mine) * 0.75;			// scale
88 
89 		reset_needed = false;		// success!!!
90 	}
91 }
92 
ButtonEvent(int x,int y)93 void eldview_wcl::ButtonEvent(int x, int y)
94 {
95 	mouseinfo::latest_x = x;
96 	mouseinfo::latest_y = y;
97 }
98 
MotionEvent(int x,int y)99 void eldview_wcl::MotionEvent(int x, int y)
100 {
101 	int dy = mouseinfo::latest_y - y;
102 
103 	if (custom_app::GetCurrentMouseTool() == custom_app::mtZoom)
104 	{
105 		vdim[1] += mouseinfo::dist_sensitivity * vdim[1] * (float) dy / (float) GetWnd()->GetHeight();
106 		GetWnd()->RequestUpdate(false);
107 	}
108 
109 	if (custom_app::GetCurrentMouseTool() == custom_app::mtTranslateXY)
110 	{
111 		cam->GetLD()->crd[1] -= 2.0 * vdim[1] * (float) dy / (float) GetWnd()->GetHeight();
112 		GetWnd()->RequestUpdate(false);
113 	}
114 
115 	mouseinfo::latest_x = x;
116 	mouseinfo::latest_y = y;
117 }
118 
UpdateWnd(void)119 void eldview_wcl::UpdateWnd(void)
120 {
121 	base_wnd * wnd = GetWnd();
122 	if (!wnd || wnd->GetWidth() < 0 || !cam) return;
123 
124 	if (reset_needed) SetCenterAndScale();
125 
126 	wnd->SetCurrent();
127 	cam->RenderScene(wnd, false, false);
128 }
129 
InitGL(void)130 void eldview_wcl::InitGL(void)
131 {
132 	// all classes that inherit pangofont_wcl must call ogl_InitPangoFont()!!!
133 	// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
134 
135 	ogl_InitPangoFont("courier 12");
136 }
137 
RenderGL(rmode)138 void eldview_wcl::RenderGL(rmode)
139 {
140 	base_wnd * wnd = GetWnd();
141 	if (!wnd || wnd->GetWidth() < 0 || !cam) return;
142 
143 	const GLfloat label_color[3] = { 1.0, 1.0, 1.0 };
144 
145 	glInitNames();
146 
147 	project * prj = custom_app::GetAppC()->GetPrj();
148 	engine * eng = prj->GetCurrentSetup()->GetCurrentEngine();
149 
150 	setup1_qm * su1 = dynamic_cast<setup1_qm *>(prj->GetCurrentSetup());
151 	bool nonQM = (!su1);
152 
153 	if (!eng || nonQM)
154 	{
155 		reset_needed = true;
156 
157 		glColor3f(label_color[0], label_color[1], label_color[2]);
158 
159 		GLfloat xpos;
160 		GLfloat ypos;
161 
162 		const char * txt1 = _("No data available,");
163 		xpos = (wnd->GetWidth() - ogl_GetStringWidth(txt1)) / 2.0;
164 		ypos = (wnd->GetHeight() - 24) / 2.0 + 14;
165 		ogl_WriteString2D(txt1, xpos, ypos);
166 
167 		const char * txt2 = (nonQM ? _("must be a QM model!") : _("please calculate energy!"));
168 		xpos = (wnd->GetWidth() - ogl_GetStringWidth(txt2)) / 2.0;
169 		ypos = (wnd->GetHeight() - 24) / 2.0 - 14;
170 		ogl_WriteString2D(txt2, xpos, ypos);
171 	}
172 	else
173 	{
174 		const GLfloat fontsize = 10.0;
175 
176 		const GLfloat center = cam->GetLD()->crd[1];
177 		const GLfloat scale = vdim[1];
178 
179 		const GLfloat one_pixel_height = scale / (GLfloat) wnd->GetHeight();
180 
181 		const GLfloat diagram_line_thickness = 2.0;
182 		const GLfloat diagram_triangle_height = 45.0;
183 		const GLfloat diagram_triangle_width = 0.075;
184 
185 // the functions: GetOrbitalCount(), GetOrbitalEnergy(), need to separate between
186 // alpha and beta electrons. also a simple way to determine occupation (and whether
187 // is alpha/beta) is needed. THIS PLOT IS FOR RHF SYSTEMS ONLY!!!!!!!!!!!!!!!!!!!!
188 
189 		// gather the degenerate energy levels (del) into groups...
190 
191 		const GLfloat del_tolerance = 0.001;
192 		int * del_first = new int[eng->GetOrbitalCount()];
193 
194 		del_first[0] = 0; int dd = 1;
195 		while (dd < eng->GetOrbitalCount())
196 		{
197 			int ind_first = del_first[dd - 1];
198 
199 			GLfloat ene_first = eng->GetOrbitalEnergy(ind_first);
200 			GLfloat ene_current = eng->GetOrbitalEnergy(dd);
201 
202 			if (ene_current - ene_first < del_tolerance)
203 			{
204 				del_first[dd] = ind_first;	// belongs to the previous set.
205 			}
206 			else
207 			{
208 				del_first[dd] = dd;		// is the first of a new set.
209 			}
210 
211 			dd++;
212 		}
213 
214 		int * del_count = new int[eng->GetOrbitalCount()];
215 		for (dd = 0;dd < eng->GetOrbitalCount();dd++) del_count[dd] = 0;
216 
217 		dd = 0; int first = 0;
218 		while (dd < eng->GetOrbitalCount())	// calculate the group sizes...
219 		{
220 			if (del_first[dd] != del_first[first]) first = dd;
221 			del_count[first]++;
222 			dd++;
223 		}
224 
225 		dd = 0; first = 0;
226 		while (dd < eng->GetOrbitalCount())	// ...and copy them to all group members.
227 		{
228 			if (del_first[dd] != del_first[first]) first = dd;
229 			if (first != dd) del_count[dd] = del_count[first];
230 			dd++;
231 		}
232 
233 		// render...
234 
235 		for (int n1 = 0;n1 < eng->GetOrbitalCount();n1++)
236 		{
237 			GLfloat energy = eng->GetOrbitalEnergy(n1);
238 
239 			GLfloat width = 1.0 / (fGL) del_count[n1];
240 			GLfloat left = 0.0 + (fGL) (n1 - del_first[n1]) * width;
241 			GLfloat right = 0.0 + (fGL) (n1 - del_first[n1] + 1) * width;
242 
243 			// draw the line...
244 			// draw the line...
245 			// draw the line...
246 
247 			glColor3f(0.0, 1.0, 0.0);	// green
248 			glBegin(GL_QUADS);
249 
250 			glVertex3f(right - 0.05 * width, energy, 0.1);
251 			glVertex3f(left + 0.05 * width, energy, 0.1);
252 			glVertex3f(left + 0.05 * width, energy + one_pixel_height * diagram_line_thickness, 0.1);
253 			glVertex3f(right - 0.05 * width, energy + one_pixel_height * diagram_line_thickness, 0.1);
254 
255 			glEnd();
256 
257 			// draw the electrons...
258 			// draw the electrons...
259 			// draw the electrons...
260 
261 			if (n1 < eng->GetElectronCount() / 2)
262 			{
263 				glColor3f(1.0, 1.0, 0.0);	// yellow
264 				glBegin(GL_TRIANGLES);
265 
266 glVertex3f(left + 0.3 * width - diagram_triangle_width, energy - one_pixel_height * diagram_triangle_height / 3.0, 0.0);
267 glVertex3f(left + 0.3 * width, energy + one_pixel_height * diagram_triangle_height / 1.5, 0.0);
268 glVertex3f(left + 0.3 * width + diagram_triangle_width, energy - one_pixel_height * diagram_triangle_height / 3.0, 0.0);
269 
270 glVertex3f(right - 0.3 * width - diagram_triangle_width, energy + one_pixel_height * diagram_triangle_height / 3.0, 0.0);
271 glVertex3f(right - 0.3 * width, energy - one_pixel_height * diagram_triangle_height / 1.5, 0.0);
272 glVertex3f(right - 0.3 * width + diagram_triangle_width, energy + one_pixel_height * diagram_triangle_height / 3.0, 0.0);
273 
274 				glEnd();
275 			}
276 
277 			// print out the text...
278 			// print out the text...
279 			// print out the text...
280 
281 			glColor3f(label_color[0], label_color[1], label_color[2]);
282 
283 			GLfloat xpos;
284 			GLfloat ypos;
285 
286 			ostringstream str;
287 			str << "i = " << n1 << " e = " << energy << ends;
288 
289 			xpos = 10.0;
290 			ypos = (0.5 + (energy - center) / (scale * 2.0)) * wnd->GetHeight() - fontsize / 2.0;
291 			ypos += (fGL) (n1 - del_first[n1]) * fontsize;
292 
293 			ogl_WriteString2D(str.str().c_str(), xpos, ypos);
294 		}
295 
296 		delete[] del_first;
297 		delete[] del_count;
298 	}
299 }
300 
301 /*################################################################################################*/
302 
303 // eof
304