1 /*
2 ----------------------------------------------------------------------------
3 "THE BEER-WARE LICENSE" (Revision 42):
4 <dkratzert@gmx.de> wrote this file. As long as you retain
5 this notice you can do whatever you want with this stuff. If we meet some day,
6 and you think this stuff is worth it, you can buy me a beer in return.
7 Daniel Kratzert
8 ----------------------------------------------------------------------------
9 */
10
11 #include "dsrglwindow.h"
12 #include "molecule.h"
13 #include "chgl.h"
14 #include "dsrgui.h"
15
16
DSRGlWindow(QWidget * parent,Molecule * m,DSRMol header,QString fragment)17 DSRGlWindow::DSRGlWindow(QWidget *parent, Molecule *m,
18 DSRMol header, QString fragment) {
19 this->setParent(parent);
20 m_molecule=m;
21 showFit=nullptr;
22 showFitLabel=nullptr;
23 mole.cell.symmops.clear();
24 mole.cell.trans.clear();
25 mole.asymm.clear();
26 mole.sdm.clear();
27 mole.showbonds.clear();
28 mole.showatoms.clear();
29 mole.selectedatoms.clear();
30 mole.envi_sdm.clear();
31 mole.contact.clear();
32 mole.envi_sdm.clear();
33 mole.contact.clear();
34 mole.symmopsEQIV.clear();
35 mole.labelEQIV.clear();
36 mole.transEQIV.clear();
37 mole.freeatoms.clear();
38 mole.bindatoms.clear();
39 mole.selectedatoms.clear();
40 mole.showatoms.clear();
41 dsrLabelColor = QColor("white");
42 V3 nl(0,0,0);
43 mole.cell.trans.append(nl);
44 mole.cell.symmops.append(Matrix(1,0,0, 0,1,0, 0,0,1));
45 mole.pmin=10000;
46 mole.pmax=-10000;
47 mole.LOD=3;
48 // initial zoom level:
49 // The Zom will later be adapted to fragment size.
50 L=50.0;
51 mole.transEQIV.clear();
52 mole.symmopsEQIV.clear();
53 mole.labelEQIV.clear();
54 mole.freeatoms.clear();
55 mole.bindatoms.clear();
56 mole.envi_sdm.clear();
57 if (fragment.size() > 0) {
58 display_fragment(header);
59 }
60 }
61
~DSRGlWindow()62 DSRGlWindow::~DSRGlWindow() {
63 }
64
transform_point(GLdouble out[4],const GLdouble m[16],const GLdouble in[4])65 static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4]) {
66 #define M(row,col) m[col*4+row]
67 out[0] =
68 M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
69 out[1] =
70 M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
71 out[2] =
72 M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
73 out[3] =
74 M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
75 #undef M
76 }
77
posTo2D(V3 obj,const GLdouble model[16],const GLdouble proj[16],const GLint viewport[4],GLdouble * winx,GLdouble * winy)78 static inline bool posTo2D(V3 obj,
79 const GLdouble model[16], const GLdouble proj[16],
80 const GLint viewport[4],
81 GLdouble * winx, GLdouble * winy) {
82 GLdouble in[4], out[4];
83
84 in[0] = obj.x;
85 in[1] = obj.y;
86 in[2] = obj.z;
87 in[3] = 1.0;
88 transform_point(out, model, in);
89 transform_point(in, proj, out);
90
91 if (in[3] == 0.0) return false;
92
93 in[0] /= in[3];
94 in[1] /= in[3];
95 in[2] /= in[3];
96
97 *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
98 *winy = viewport[1] + (1 - in[1]) * viewport[3] / 2;
99 return true;
100 }
101
102
draw()103 void DSRGlWindow::draw(){
104 /*const GLfloat OBJ_SPE[] = { 0.8, 0.8, 0.8, 1.0 };
105 const GLfloat OBJ_SHIN = 127.0;
106 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, OBJ_SPE );
107 glEnable ( GL_COLOR_MATERIAL ) ;
108 glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
109 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, OBJ_SHIN );
110 */
111 mole.dratom = 0;
112 glPushMatrix();
113 glScaled( L, L, L );
114 GLdouble model[16];
115 GLdouble proj[16];
116 GLint viewport[4];
117 glGetIntegerv(GL_VIEWPORT, viewport);
118 #if defined Q_OS_MAC && (QT_VERSION >= 0x050000)
119 viewport[2]/=2;
120 viewport[3]/=2;
121 #endif
122 // printf("%d %d %d %d\n",viewport[0],viewport[1],viewport[2],viewport[3]);
123 glGetDoublev( GL_PROJECTION_MATRIX, (double*)proj );
124 glGetDoublev( GL_MODELVIEW_MATRIX, (double*)model );
125 mole.adp = 0;
126 mole.intern = 0;
127 mole.tubes = 0;
128 glDisable(GL_BLEND);
129 mole.atoms(xd, 50);
130 mole.bonds(bonds);
131 glEnable(GL_COLOR_MATERIAL);
132 qglColor(dsrLabelColor); // The fragment label color
133 glClear( GL_DEPTH_BUFFER_BIT);
134 for (int i=0; i<xd.size(); i++){
135 GLdouble in[4], out[4];
136 in[0] = xd.at(i).pos.x;
137 in[1] = xd.at(i).pos.y;
138 in[2] = xd.at(i).pos.z;
139 in[3] = 1.0;
140 transform_point(out, model, in);
141 posTo2D(xd.at(i).pos,model,proj,viewport, &xd[i].screenX, &xd[i].screenY);
142 bool issel=false;
143 for (int j=0; j<selFragAt.size(); j++) {
144 if ((showFitLabel!=nullptr)
145 && (!showFitLabel->isChecked())
146 && (j<m_molecule->selectedatoms.size())
147 && (xd.at(i).Label==selFragAt.at(j).Label)) {
148 issel=true;
149 renderText( xd.at(i).pos.x, xd.at(i).pos.y, xd.at(i).pos.z,
150 xd.at(i).Label+"->"+m_molecule->selectedatoms.at(j).Label, myFont);
151 }
152 }
153 if (!issel) {
154 renderText( xd.at(i).pos.x, xd.at(i).pos.y, xd.at(i).pos.z,
155 xd.at(i).Label, myFont);
156 }
157 }
158 glPopMatrix();
159 if (!selFragAt.isEmpty()){
160 glPushMatrix();{
161 glScaled( L, L, L );
162 mole.tubes=0;
163 mole.intern=1;
164 mole.adp=0;
165 mole.dratom=1;
166 mole.atoms(selFragAt);
167 mole.dratom=0;
168 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
169 }glPopMatrix();
170 }
171 if ((showFit!=nullptr)&&(!fita.isEmpty())&&(showFit->isChecked())){
172 glPushMatrix();{
173 glEnable(GL_BLEND);
174 glScaled( L, L, L );
175 mole.tubes=0;
176 mole.intern=0;
177 mole.adp=0;
178 mole.dratom=5;
179 mole.atoms(fita);
180 mole.dbond(fitabonds);
181 mole.lbond();
182 if (showFitLabel->isChecked()){
183 qglColor(QColor(0, 0, 175)); // The surrounding atoms label color
184 for (int i=0; i<fita.size(); i++){
185 renderText( fita.at(i).pos.x, fita.at(i).pos.y, fita.at(i).pos.z, fita.at(i).Label, myFont);
186 }
187 }
188 }glPopMatrix();
189 }
190 }
191
initializeGL()192 void DSRGlWindow::initializeGL(){
193 glEnable(GL_LINE_SMOOTH);
194 glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
195 //glEnable(GL_POLYGON_SMOOTH);
196 myFont = QFont("Arial", 12, -1, false); // the initial label font size
197 const GLfloat position[] = {100.0f, 100.0f,100.0f,0.0f};
198 const GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
199 const GLfloat specular[] = { 1.0f, 0.9f, 0.9f, 1.0f };
200 const GLfloat ambient[] = { 0.4f, 0.4f, 0.4f, 1.0f };
201 glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, 1 );
202 glLightfv( GL_LIGHT0, GL_POSITION, position );
203 glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
204 glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
205 glLightfv( GL_LIGHT0, GL_SPECULAR, specular );
206 glLightfv( GL_LIGHT1, GL_POSITION, position );
207 glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse );
208 glLightfv( GL_LIGHT1, GL_AMBIENT, ambient );
209 glLightfv( GL_LIGHT2, GL_DIFFUSE, diffuse );
210 glEnable( GL_LIGHTING );
211 glEnable( GL_LIGHT0 );
212 // glEnable( GL_BLEND);
213 glDisable(GL_BLEND);
214 glAlphaFunc ( GL_GREATER, 0.01f ) ;
215 //glEnable(GL_ALPHA_TEST);
216 glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
217 const GLfloat OBJ_SPE[] = { 1.0, 1.0, 1.0, 1.0 };
218 const GLfloat OBJ_SHIN = 127.0;
219 glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, OBJ_SPE );
220 glEnable ( GL_COLOR_MATERIAL ) ;
221 glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
222 glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, OBJ_SHIN );
223 glShadeModel( GL_SMOOTH );
224 glEnable(GL_NORMALIZE);
225 glClearColor(0.6f,0.6f,0.6f,1.0f);
226 glEnable(GL_DEPTH_TEST );
227 glDepthFunc(GL_LEQUAL);
228 gluLookAt_(0.0, 200, 50 , 0.0, 0.0, 0.0, 0.0, -100, 400 );
229 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
230 }
231
resizeGL(int width,int height)232 void DSRGlWindow::resizeGL(int width, int height){
233 #if defined Q_OS_MAC && (QT_VERSION >= 0x050000)
234 glViewport(0, 0, width*2,height*2);
235 #else
236 glViewport(0, 0, width, height);
237 #endif
238 glGetIntegerv(GL_VIEWPORT, vp);
239 glMatrixMode(GL_PROJECTION);
240 glLoadIdentity();
241 gluPerspective_( 29.0, (double)width/height, 5.0, 8000.0 );
242 }
243
minimumSizeHint() const244 QSize DSRGlWindow::minimumSizeHint() const
245 {
246 return QSize(250, 250);
247 }
248
sizeHint() const249 QSize DSRGlWindow::sizeHint() const
250 {
251 return QSize(400, 400);
252 }
253
paintGL()254 void DSRGlWindow::paintGL(){
255 glClearColor(0.6f,0.6f,0.6f,1.0f); // The background color
256 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
257 #if defined Q_OS_MAC && (QT_VERSION >= 0x050000)
258 glViewport(0, 0, QGLWidget::width()*2, QGLWidget::height()*2);
259 #else
260 glViewport(0, 0, QGLWidget::width(), QGLWidget::height());
261 #endif
262 glGetIntegerv(GL_VIEWPORT, vp);
263 glMatrixMode(GL_PROJECTION);
264 glLoadIdentity();
265 gluPerspective_( 29.0, (double)QGLWidget::width()/QGLWidget::height(), 5.0, 8000.0 );
266 glMatrixMode(GL_MODELVIEW);
267 glPushMatrix();
268 draw();
269 glPopMatrix();
270 }
271
clear_molecule()272 void DSRGlWindow::clear_molecule()
273 { // clear the 3D view
274 xd.clear();
275 bonds.clear();
276 fita.clear();
277 fitabonds.clear();
278 selFragAt.clear();
279 source_atoms.clear();
280 updateGL();
281 }
282
display_fragment(DSRMol frag,bool clear_sel)283 void DSRGlWindow::display_fragment(DSRMol frag, bool clear_sel)
284 { //! uses a QStringlist of atoms from DSR and fills
285 //! them into a MyAtom. MyAtom is then drawn in OpenGL
286 //! @param The fragment from DSR
287 //! @param clear_sel if enabled, the selected atoms are cleared
288 //! before drawing the molecule
289 V3 mid = V3(0,0,0);
290 MyAtom newAtom;
291 newAtom.part = 0;
292 newAtom.resiNr = 0;
293 newAtom.hidden = 0;
294 newAtom.symmGroup = 0;
295 newAtom.afix = 0;
296 xd.clear();
297 bonds.clear();
298 fita.clear();
299 fitabonds.clear();
300 // Do not clear the selection during invert:
301 if (clear_sel) {
302 selFragAt.clear();
303 }
304 if (frag.atoms.isEmpty()) {
305 return;
306 }
307 foreach (QStringList atom, frag.atoms) {
308 if (atom.length() < 4) continue; // Do not crash on empty string
309 newAtom.Label = atom.at(0);
310 newAtom.an = abs(atom.at(1).toInt())-1;
311 newAtom.pos.x = atom.at(2).toDouble();
312 newAtom.pos.y = atom.at(3).toDouble();
313 newAtom.pos.z = atom.at(4).toDouble();
314 mid += newAtom.pos;
315 //qDebug()<< newAtom.Label << newAtom.an << newAtom.pos.x << newAtom.pos.y << newAtom.pos.z;
316 xd.append(newAtom);
317 }
318 mid *= -1.0/xd.size();
319 for (int i=0; i<xd.size(); i++){
320 xd[i].pos += mid;
321 }
322 L = 90.0/mole.dimension(xd); // Zoom level of the molecule inside the widget
323 bonds=mole.connecting(xd,true);
324 updateGL();
325 }
326
327
set_label_color()328 void DSRGlWindow::set_label_color() {
329 //! Sets the label color. The default color was not visible
330 //! for white or yellow atoms.
331 QColor lc= QColorDialog::getColor(QColor(6, 167, 222), this);
332 if (lc.isValid()) {
333 dsrLabelColor=lc;
334 } else {
335 dsrLabelColor = QColor("white");
336 }
337 updateGL();
338 }
339
340
mousePressEvent(QMouseEvent * event)341 void DSRGlWindow::mousePressEvent(QMouseEvent *event){
342 //! Handles the mousePressEvents in the 3D view.
343 //! Atoms are selectable if showFit is not nullptr.
344 //! New atoms will be selected if the mousePressEvent is inside the
345 //! size of the respective atom and less than three atoms.
346 //! With more than three atoms, the first selection will be removed.
347 moux=event->pos().x();
348 mouy=event->pos().y();
349 if((event->buttons() == Qt::RightButton && event->modifiers() == Qt::ControlModifier)){
350 QMenu *menu = new QMenu("");
351 menu->addAction(QString("Set label color"), this, SLOT(set_label_color()));
352 menu->exec(QCursor::pos());
353 }
354 if (event->buttons() == Qt::LeftButton) {
355 // Has to be after moux/mouy, otherwise zoom is strange:
356 if (showFit == nullptr) return; // <-prevents selection of atoms in edit window
357 double nahda=200.0, da=0;
358 int nahdai=-1;
359 for (int j=0; j<xd.size();j++){
360 if (xd.at(j).hidden) continue;
361 da=(((xd.at(j).screenX-event->x())*( xd.at(j).screenX-event->x()))+
362 ((xd.at(j).screenY-event->y())*( xd.at(j).screenY-event->y())));
363 nahdai=(da<nahda)?j:nahdai;
364 nahda=qMin(nahda,da);
365 }
366 if ((nahdai >- 1) && (nahdai < xd.size())){
367 // This might be a good idea in the first place, but results in wired behavior:
368 //if (selFragAt.contains(xd[nahdai])) {
369 // return;
370 //}
371 selFragAt.append(xd[nahdai]);
372 if (selFragAt.size() > 3) selFragAt.removeFirst();
373 updateGL();
374 if (selFragAt.size() == 3) {
375 source_atoms = QString("%1 %2 %3")
376 .arg(selFragAt.at(0).Label)
377 .arg(selFragAt.at(1).Label)
378 .arg(selFragAt.at(2).Label);
379 emit sourceStringChanged();
380 }
381 }
382 makeInfo();
383 }
384 }
385
makeInfo()386 void DSRGlWindow::makeInfo(){
387 //! makes an info box that shows the fragment fit distances
388 double f12dis=0, f13dis=0, t12dis=0, t13dis=0;
389 if (selFragAt.size()>1) f12dis=sqrt(Distance(selFragAt.at(0).pos,selFragAt.at(1).pos));
390 if (selFragAt.size()>2) f13dis=sqrt(Distance(selFragAt.at(0).pos,selFragAt.at(2).pos));
391 if (m_molecule->selectedatoms.size()>1) t12dis=sqrt(Distance(m_molecule->selectedatoms.at(0).pos,m_molecule->selectedatoms.at(1).pos));
392 if (m_molecule->selectedatoms.size()>2) t13dis=sqrt(Distance(m_molecule->selectedatoms.at(0).pos,m_molecule->selectedatoms.at(2).pos));
393 emit updateInfo(QString(
394 "<table>"
395 "<tr><th colspan=\"2\" align=\"left\">fragment: </th>"
396 "<th><th>"
397 " <th colspan=\"2\" align=\"left\">target:</th>"
398 "</tr>"
399 "<tr><td colspan=\"2\"><font color=blue>%1</font></td>"
400 "<td><td>"
401 " <td colspan=\"2\"><font color=blue>%2</font></td>"
402 "</tr>"
403 "<tr><td align=\"left\"><font color=blue>%3</font></td> "
404 " <td align=\"left\">1,2: <b>%7 Å</b></td>"
405 "<td><td>"
406 " <td align=\"left\"><font color=blue>%4 </font></td>"
407 " <td align=\"right\">1,2: <b>%9 Å</b></td>"
408 "</tr>"
409 "<tr><td align=\"left\"><font color=blue>%5</font></td>"
410 " <td align=\"left\">1,3: <b>%8 Å</b></td>"
411 "<td><td>"
412 " <td align=\"right\"><font color=blue>%6 </font></td>"
413 " <td align=\"right\">1,3: <b>%10 Å<b></td>"
414 "</tr>"
415 "</table>")
416 .arg((selFragAt.size()>0)?selFragAt.at(0).Label:"")
417 .arg((m_molecule->selectedatoms.size()>0)?m_molecule->selectedatoms.at(0).Label:"")
418 .arg((selFragAt.size()>1)?selFragAt.at(1).Label:"")
419 .arg((m_molecule->selectedatoms.size()>1)?m_molecule->selectedatoms.at(1).Label:"")
420 .arg((selFragAt.size()>2)?selFragAt.at(2).Label:"")
421 .arg((m_molecule->selectedatoms.size()>2)?m_molecule->selectedatoms.at(2).Label:"")
422 .arg(f12dis, 4, 'f', 2)
423 .arg(f13dis, 4, 'f', 2)
424 .arg(t12dis, 4, 'f', 2)
425 .arg(t13dis, 4, 'f', 2)
426 );
427 tryfit();
428 }
429
430 //void glRotateL(double ang, double x, double y, double z);
__RotateCS(double c,double s,double & X,double & Y)431 inline void DSRGlWindow::__RotateCS( double c, double s, double& X, double& Y ) {
432 double T = X;
433 X = c*X - s*Y;
434 Y = s*T + c*Y;
435 }
436
glTranslateL(const double dx,const double dy,const double dz)437 void DSRGlWindow::glTranslateL( const double dx, const double dy, const double dz ) {
438 double mat[4][4];
439
440 glGetDoublev( GL_MODELVIEW_MATRIX, (double*)mat );
441 mat[3][0] += dx; mat[3][1] += dy; mat[3][2] += dz;
442 glLoadMatrixd((double*)mat);
443 }
glRotateL(const double dang,const double x,const double y,const double z)444 void DSRGlWindow::glRotateL( const double dang, const double x, const double y, const double z ) {
445 double mat[4][4];
446 #ifndef M_PI
447 #define M_PI 3.14159265358979323846 /* pi */
448 #endif
449
450 double s = z;
451 s = sin(dang*M_PI/180);
452 const double c = cos(dang*M_PI/180);
453 glGetDoublev( GL_MODELVIEW_MATRIX, (double*)mat );
454 // glGetDoublev( GL_PROJECTION_MATRIX, (double*)mat );
455 if( x!=0.0 ){
456 __RotateCS( c, s, mat[0][1], mat[0][2] );
457 __RotateCS( c, s, mat[1][1], mat[1][2] );
458 __RotateCS( c, s, mat[2][1], mat[2][2] );
459 // printf("x\n");
460 }else if( y!=0.0 ){
461 __RotateCS( c, s, mat[0][2], mat[0][0] );
462 __RotateCS( c, s, mat[1][2], mat[1][0] );
463 __RotateCS( c, s, mat[2][2], mat[2][0] );
464 // printf("y\n");
465 }else{
466 __RotateCS( c, s, mat[0][0], mat[0][1] );
467 __RotateCS( c, s, mat[1][0], mat[1][1] );
468 __RotateCS( c, s, mat[2][0], mat[2][1] );
469 // printf("z\n");
470 }
471 glLoadMatrixd((double*)mat);
472 }
473
474
475
mouseMoveEvent(QMouseEvent * event)476 void DSRGlWindow::mouseMoveEvent(QMouseEvent *event){
477 //! Either rotates (left mouse button) the molecule
478 //! or zooms the molecule (right mouse button).
479 double x = event->pos().x();
480 double y = event->pos().y();
481 GLfloat dx = GLfloat( event->x() - moux) / width();
482 GLfloat dy = GLfloat( event->y() - mouy) / height();
483 if((event->buttons() & Qt::RightButton)){
484 glScaled(1.0-dy,1.0-dy,1.0-dy);
485 }else if((event->buttons() && Qt::LeftButton)){
486 glRotateL(dy*360.0,1.0,0.0,0.0);
487 glRotateL(dx*360.0,0.0,1.0,0.0);
488 }
489 moux=x;
490 mouy=y;
491 updateGL();
492 }
493
wheelEvent(QWheelEvent * event)494 void DSRGlWindow::wheelEvent(QWheelEvent *event){
495 /*
496 modifiers:
497 Qt::NoModifier 0x00000000 No modifier key is pressed.
498 Qt::ShiftModifier 0x02000000 A Shift key on the keyboard is pressed.
499 Qt::ControlModifier 0x04000000 A Ctrl key on the keyboard is pressed.
500 Qt::AltModifier 0x08000000 An Alt key on the keyboard is pressed.
501 Qt::MetaModifier 0x10000000 A Meta key on the keyboard is pressed.
502 Qt::KeypadModifier 0x20000000 A keypad button is pressed.
503 Qt::GroupSwitchModifier 0x40000000 X11 only. A Mode_switch key on the keyboard is pressed.
504 */
505 int numDegrees = event->delta() / 8;
506 int numSteps = numDegrees / 15;
507 if (event->modifiers()==Qt::NoModifier){
508 int d = myFont.pointSize();
509 d = (d+numSteps>4)?d+numSteps:d;
510 d = qMax(d,7);
511 myFont.setPointSize(d);
512 updateGL();
513 }
514
515 }
516
tryfit()517 void DSRGlWindow::tryfit(){
518 if (showFit==nullptr) return;
519 fita.clear();
520 fitabonds.clear();
521 if ((selFragAt.size()!=3)||(m_molecule->selectedatoms.size()!=3)) {updateGL();return;}
522
523 //tree orthogonal vectors of unit size form a rotation matrix
524 //the transponse of the latter is its inverse
525 V3 a1,a2,a3;
526 a1=Normalize(m_molecule->selectedatoms.at(0).pos-m_molecule->selectedatoms.at(1).pos);//a1=(A-B)/|A-B|
527 a2=Normalize(m_molecule->selectedatoms.at(0).pos-m_molecule->selectedatoms.at(2).pos);//a2=(A-C)/|A-B|
528 a3=Normalize(a1%a2);//a3=(a1 x a2)/(a1 x a2)
529 a2=a3%a1;//a2 = a3 x a1
530 Matrix amat=Matrix(a1,a2,a3);
531
532 V3 b1,b2,b3;
533 b1=Normalize(selFragAt.at(0).pos-selFragAt.at(1).pos);
534 b2=Normalize(selFragAt.at(0).pos-selFragAt.at(2).pos);
535 b3=Normalize(b1%b2);
536 b2=b3%b1;
537 Matrix bmat=transponse(Matrix(b1,b2,b3));
538 if ( (a1*(a2%a3)<0.9) || (b1*(b2%b3)<0.9) ) { //linear dependence id determinant is 0
539 updateGL();
540 return;
541 }
542 // m_molecule->showatoms was m_molecule->asymm before, but showatoms is needed for disorder
543 // around special positions:
544 for (int i=0; i<m_molecule->showatoms.size(); i++) {
545 fita.append(m_molecule->showatoms[i]);
546 fita.last().pos+=-1.0*(m_molecule->selectedatoms.at(0).pos);
547 fita.last().pos=fita.last().pos*amat;
548 fita.last().pos=fita.last().pos*bmat;
549 fita.last().pos+=selFragAt.at(0).pos;
550 fita.last().part=1;
551 if (Norm (fita.last().pos) > 12) { // 4 Angstroem cut-off (3*4=12)
552 fita.removeLast();
553 }
554 }
555 fitabonds=mole.connecting(fita,true);
556 updateGL();
557 printf("FIT:\n================================================================================\n");
558 for (int i=0; i<xd.size(); i++){
559 int imin=0;
560 double dmin=10.0;
561 for (int j=0; j<m_molecule->showatoms.size(); j++){
562 V3 ort=m_molecule->showatoms.at(j).pos;
563 ort+=-1.0*(m_molecule->selectedatoms.at(0).pos);
564 ort=ort*amat;
565 ort=ort*bmat;
566 ort+=selFragAt.at(0).pos;
567
568 double d=Distance(ort,xd.at(i).pos);
569 if (d<dmin) imin=j;
570 dmin=(d<dmin)?d:dmin;
571 }
572 printf("%-8s <==> %-8s %f\n", xd.at(i).Label.toStdString().c_str(),
573 m_molecule->showatoms.at(imin).Label.toStdString().c_str(), sqrt(dmin));
574 }
575 }
576