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