00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "bondcentrictool.h"
00030 #include "quaternion.h"
00031
00032 #ifdef WIN32
00033 #include <float.h>
00034 #include <math.h>
00035 #define isnan(x) _isnan(x)
00036 #endif
00037
00038 #include <iostream>
00039
00040 #include <avogadro/navigate.h>
00041 #include <avogadro/primitive.h>
00042 #include <avogadro/color.h>
00043 #include <avogadro/glwidget.h>
00044 #include <avogadro/camera.h>
00045 #include <avogadro/toolgroup.h>
00046
00047 #include <openbabel/obiter.h>
00048 #include <openbabel/mol.h>
00049
00050 #include <QtPlugin>
00051 #include <QString>
00052
00053 #include <QDebug>
00054
00055 using namespace std;
00056 using namespace OpenBabel;
00057 using namespace Eigen;
00058
00059 namespace Avogadro {
00060
00061
00062
00063
00064
00065 BondCentricTool::BondCentricTool(QObject *parent) : Tool(parent),
00066 m_molecule(NULL),
00067 m_settingsWidget(NULL),
00068 m_clickedAtom(NULL),
00069 m_clickedBond(NULL),
00070 m_selectedBond(NULL),
00071 m_skeleton(NULL),
00072 m_referencePoint(NULL),
00073 m_currentReference(NULL),
00074 m_directionVector(NULL),
00075 m_snapped(false),
00076 m_toolGroup(NULL),
00077 m_leftButtonPressed(false),
00078 m_midButtonPressed(false),
00079 m_rightButtonPressed(false),
00080 m_movedSinceButtonPressed(false),
00081 m_showAngles(true),
00082 m_snapToEnabled(true),
00083 m_snapToAngle(10)
00084 {
00085 QAction *action = activateAction();
00086 action->setIcon(QIcon(QString::fromUtf8(":/bondcentric/bondcentric.png")));
00087 action->setToolTip(tr("Bond Centric Manipulation Tool\n\n"
00088 "Left Mouse: Click and drag to rotate the view\n"
00089 "Middle Mouse: Click and drag to zoom in or out\n"
00090 "Right Mouse: Click and drag to move the view\n\n"
00091 "Left Click & drag on a Bond to set the Manipulation Plane:\n"
00092 "- Left Click & Drag one of the Atoms in the Bond to change the angle\n"
00093 "- Right Click & Drag one of the Atoms in the Bond to change the length"));
00094
00095 connect(action,SIGNAL(toggled(bool)),this,SLOT(toolChanged(bool)));
00096 }
00097
00098
00099
00100 BondCentricTool::~BondCentricTool()
00101 {
00102 delete m_referencePoint;
00103 m_referencePoint = NULL;
00104 delete m_currentReference;
00105 m_currentReference = NULL;
00106 delete m_directionVector;
00107 m_directionVector = NULL;
00108
00109 if (m_settingsWidget)
00110 {
00111 m_snapToAngleLabel->deleteLater();
00112 m_spacer->deleteLater();
00113 m_showAnglesBox->deleteLater();
00114 m_snapToCheckBox->deleteLater();
00115 m_snapToAngleBox->deleteLater();
00116 m_layout->deleteLater();
00117
00118 m_settingsWidget->deleteLater();
00119 }
00120 }
00121
00122
00123
00124 void BondCentricTool::clearData()
00125 {
00126 m_clickedAtom = NULL;
00127 m_clickedBond = NULL;
00128 m_selectedBond = NULL;
00129 delete m_referencePoint;
00130 m_referencePoint = NULL;
00131 delete m_currentReference;
00132 m_currentReference = NULL;
00133 delete m_directionVector;
00134 m_directionVector = NULL;
00135 m_toolGroup = NULL;
00136 m_leftButtonPressed = false;
00137 m_midButtonPressed = false;
00138 m_rightButtonPressed = false;
00139 m_movedSinceButtonPressed = false;
00140 m_snapped = false;
00141 }
00142
00143
00144
00145 void BondCentricTool::setMolecule(Molecule* molecule)
00146 {
00147 if(m_molecule) {
00148 disconnect(m_molecule, 0 , this, 0);
00149 }
00150
00151 if (molecule) {
00152 m_molecule = molecule;
00153 connect(molecule, SIGNAL(primitiveRemoved(Primitive*)), this,
00154 SLOT(primitiveRemoved(Primitive*)));
00155 }
00156
00157 clearData();
00158 }
00159
00160
00161
00162 void BondCentricTool::primitiveRemoved(Primitive *primitive)
00163 {
00164 if (primitive == m_clickedAtom || primitive == m_clickedBond ||
00165 primitive == m_selectedBond) {
00166 clearData();
00167 }
00168 }
00169
00170
00171
00172 void BondCentricTool::toolChanged(bool checked)
00173 {
00174 if(!checked && m_molecule)
00175 {
00176 m_molecule->update();
00177 clearData();
00178 }
00179 }
00180
00181
00182
00183 int BondCentricTool::usefulness() const
00184 {
00185 return 2000000;
00186 }
00187
00188
00189
00190 QUndoCommand* BondCentricTool::mousePress(GLWidget *widget, const QMouseEvent *event)
00191 {
00192 m_undo = 0;
00193
00194 m_lastDraggingPosition = event->pos();
00195 m_movedSinceButtonPressed = false;
00196
00197 #ifdef Q_WS_MAC
00198 m_leftButtonPressed = (event->buttons() & Qt::LeftButton
00199 && event->modifiers() == Qt::NoModifier);
00200
00201
00202 m_midButtonPressed = ((event->buttons() & Qt::MidButton) ||
00203 (event->buttons() & Qt::LeftButton && event->modifiers()
00204 & Qt::ShiftModifier));
00205
00206 m_rightButtonPressed = ((event->buttons() & Qt::RightButton) ||
00207 (event->buttons() & Qt::LeftButton &&
00208 (event->modifiers() == Qt::ControlModifier ||
00209 event->modifiers() == Qt::MetaModifier)));
00210 #else
00211 m_leftButtonPressed = (event->buttons() & Qt::LeftButton);
00212 m_midButtonPressed = (event->buttons() & Qt::MidButton);
00213 m_rightButtonPressed = (event->buttons() & Qt::RightButton);
00214 #endif
00215
00216 m_clickedAtom = NULL;
00217 m_clickedBond = NULL;
00218
00219 int oldName = m_selectedBond ? m_selectedBond->GetIdx() : -1;
00220
00221
00222 Primitive *clickedPrim = widget->computeClickedPrimitive(event->pos());
00223
00224 if (clickedPrim && clickedPrim->type() == Primitive::AtomType)
00225 {
00226
00227 m_clickedAtom = (Atom*)clickedPrim;
00228
00229 if ((m_rightButtonPressed || m_leftButtonPressed) && isAtomInBond(m_clickedAtom, m_selectedBond))
00230 {
00231
00232 m_undo = new BondCentricMoveCommand(widget->molecule());
00233
00234
00235 m_skeleton = new SkeletonTree();
00236 m_skeleton->populate(m_clickedAtom, m_selectedBond, widget->molecule());
00237
00238 if (m_leftButtonPressed)
00239 {
00240
00241
00242
00243
00244 Atom *otherAtom;
00245 if (m_clickedAtom == static_cast<Atom*>(m_selectedBond->GetBeginAtom()))
00246 otherAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00247 else
00248 otherAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00249
00250 Vector3d centerProj = widget->camera()->project(otherAtom->pos());
00251 centerProj -= Vector3d(0,0,centerProj.z());
00252 Vector3d clickedProj = widget->camera()->project(m_clickedAtom->pos());
00253 clickedProj -= Vector3d(0,0,clickedProj.z());
00254
00255 if ((clickedProj - centerProj).norm() == 0)
00256 {
00257
00258 m_directionVector = new Vector3d(1, 0, 0);
00259 }
00260 else
00261 {
00262 m_directionVector = new Vector3d(clickedProj - centerProj);
00263 *m_directionVector = m_directionVector->normalized();
00264 }
00265 }
00266 }
00267 else if (m_selectedBond)
00268 {
00269
00270
00271
00272 Atom *dihedralRotCen = NULL;
00273 Bond *skeleBond = NULL;
00274
00275 Atom *beginAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00276 Atom *endAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00277
00278
00279
00280 if ((skeleBond = static_cast<Bond*>(m_clickedAtom->GetBond(beginAtom)))) {
00281 dihedralRotCen = beginAtom;
00282 }
00283 else if ((skeleBond = static_cast<Bond*>(m_clickedAtom->GetBond(endAtom)))) {
00284 dihedralRotCen = endAtom;
00285 }
00286
00287 bool skeletonSet = false;
00288 if (m_rightButtonPressed && skeleBond)
00289 {
00290
00291 m_undo = new BondCentricMoveCommand(widget->molecule());
00292
00293
00294
00295 m_skeleton = new SkeletonTree();
00296 m_skeleton->populate(m_clickedAtom, skeleBond, widget->molecule());
00297 skeletonSet = true;
00298 }
00299 else if (m_leftButtonPressed && dihedralRotCen)
00300 {
00301
00302 m_undo = new BondCentricMoveCommand(widget->molecule());
00303
00304
00305
00306
00307 m_skeleton = new SkeletonTree();
00308 m_skeleton->populate(dihedralRotCen, m_selectedBond, widget->molecule());
00309 skeletonSet = true;
00310 }
00311
00312 if (skeletonSet)
00313 {
00314
00315
00316
00317
00318 Vector3d centerProj = widget->camera()->project(dihedralRotCen->pos());
00319 centerProj -= Vector3d(0,0,centerProj.z());
00320 Vector3d clickedProj = widget->camera()->project(m_clickedAtom->pos());
00321 clickedProj -= Vector3d(0,0,clickedProj.z());
00322
00323 if ((clickedProj - centerProj).norm() == 0)
00324 {
00325
00326 m_directionVector = new Vector3d(1, 0, 0);
00327 }
00328 else
00329 {
00330 m_directionVector = new Vector3d(clickedProj - centerProj);
00331 *m_directionVector = m_directionVector->normalized();
00332 }
00333 }
00334 }
00335 }
00336 else if (clickedPrim && clickedPrim->type() == Primitive::BondType)
00337 {
00338
00339 m_clickedBond = (Bond*)clickedPrim;
00340
00341
00342
00343
00344 if (m_leftButtonPressed)
00345 {
00346 m_selectedBond = m_clickedBond;
00347
00348 if ((int)m_selectedBond->GetIdx() != oldName)
00349 {
00350 delete m_referencePoint;
00351 m_referencePoint = NULL;
00352
00353 delete m_currentReference;
00354 m_currentReference = NULL;
00355
00356 m_snapped = false;
00357
00358 Atom *leftAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00359 Atom *rightAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00360
00361 Vector3d left = leftAtom->pos();
00362 Vector3d right = rightAtom->pos();
00363 Vector3d leftToRight = right - left;
00364
00365 Vector3d x = Vector3d(1, 0, 0);
00366 Vector3d y = Vector3d(0, 1, 0);
00367
00368 Vector3d A = leftToRight.cross(x);
00369 Vector3d B = leftToRight.cross(y);
00370
00371 m_referencePoint = A.norm() >= B.norm() ? new Vector3d(A) : new Vector3d(B);
00372 *m_referencePoint = m_referencePoint->normalized();
00373
00374 Vector3d *reference = calculateSnapTo(m_selectedBond,
00375 m_referencePoint, m_snapToAngle);
00376
00377 if (reference && m_snapToEnabled)
00378 {
00379 m_snapped = true;
00380 m_currentReference = reference;
00381 *m_currentReference = m_currentReference->normalized();
00382 }
00383 else {
00384 m_currentReference = new Vector3d(*m_referencePoint);
00385 }
00386 }
00387 }
00388 }
00389
00390 widget->update();
00391 return 0;
00392 }
00393
00394
00395
00396 QUndoCommand* BondCentricTool::mouseRelease(GLWidget *widget, const QMouseEvent*)
00397 {
00398 delete m_directionVector;
00399 m_directionVector = NULL;
00400
00401 if (!m_clickedAtom && !m_clickedBond && !m_movedSinceButtonPressed)
00402 {
00403 delete m_referencePoint;
00404 m_referencePoint = NULL;
00405 delete m_currentReference;
00406 m_currentReference = NULL;
00407 m_snapped = false;
00408 m_selectedBond = NULL;
00409 }
00410 else if (!m_movedSinceButtonPressed) {
00411 m_undo = 0;
00412 }
00413
00414 if (m_skeleton)
00415 {
00416 delete m_skeleton;
00417 m_skeleton = NULL;
00418 }
00419
00420 m_leftButtonPressed = false;
00421 m_midButtonPressed = false;
00422 m_rightButtonPressed = false;
00423 m_clickedAtom = NULL;
00424 m_clickedBond = NULL;
00425
00426 widget->update();
00427 return m_undo;
00428 }
00429
00430
00431
00432 QUndoCommand* BondCentricTool::mouseMove(GLWidget *widget, const QMouseEvent *event)
00433 {
00434 if (!m_molecule) {
00435 return 0;
00436 }
00437
00438 QPoint deltaDragging = event->pos() - m_lastDraggingPosition;
00439
00440 if (deltaDragging.manhattanLength() > 2) {
00441 m_movedSinceButtonPressed = true;
00442 }
00443
00444
00445
00446
00447 #ifdef Q_WS_MAC
00448 if (event->buttons() & Qt::LeftButton && event->modifiers() == Qt::NoModifier)
00449 #else
00450 if (event->buttons() & Qt::LeftButton)
00451 #endif
00452 {
00453 if (m_clickedBond && m_selectedBond && m_referencePoint)
00454 {
00455 Atom *beginAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00456 Atom *endAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00457
00458 Vector3d rotationVector = endAtom->pos() - beginAtom->pos();
00459 rotationVector = rotationVector / rotationVector.norm();
00460
00461 Vector3d begin = widget->camera()->project(beginAtom->pos());
00462 Vector3d end = widget->camera()->project(endAtom->pos());
00463
00464 Vector3d zAxis = Vector3d(0, 0, 1);
00465 Vector3d beginToEnd = end - begin;
00466 beginToEnd -= Vector3d(0, 0, beginToEnd.z());
00467
00468 Vector3d direction = zAxis.cross(beginToEnd);
00469 direction = direction / direction.norm();
00470
00471 Vector3d mouseMoved = Vector3d(deltaDragging.x(), deltaDragging.y(), 0);
00472
00473 double magnitude = mouseMoved.dot(direction) / direction.norm();
00474
00475 *m_referencePoint = performRotation(magnitude * (M_PI / 180.0),
00476 rotationVector, Vector3d(0, 0, 0),
00477 *m_referencePoint);
00478
00479 Eigen::Vector3d *reference = calculateSnapTo(m_selectedBond,
00480 m_referencePoint, m_snapToAngle);
00481 if (reference && m_snapToEnabled)
00482 {
00483 m_snapped = true;
00484 delete m_currentReference;
00485 m_currentReference = reference;
00486 *m_currentReference = m_currentReference->normalized();
00487 }
00488 else
00489 {
00490 m_snapped = false;
00491 delete m_currentReference;
00492 m_currentReference = new Vector3d(*m_referencePoint);
00493 }
00494 }
00495 else if (isAtomInBond(m_clickedAtom, m_selectedBond))
00496 {
00497
00498 Atom *otherAtom;
00499
00500 if (m_clickedAtom == static_cast<Atom*>(m_selectedBond->GetBeginAtom()))
00501 otherAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00502 else
00503 otherAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00504
00505 Vector3d center = otherAtom->pos();
00506 Vector3d clicked = m_clickedAtom->pos();
00507
00508 Vector3d centerProj = widget->camera()->project(center);
00509 centerProj -= Vector3d(0,0,centerProj.z());
00510 Vector3d referenceProj = widget->camera()->project(*m_currentReference + center);
00511 referenceProj -= Vector3d(0,0,referenceProj.z());
00512
00513 Vector3d referenceVector = referenceProj - centerProj;
00514 referenceVector = referenceVector.normalized();
00515
00516 Vector3d rotationVector = referenceVector.cross(*m_directionVector);
00517 rotationVector = rotationVector.normalized();
00518
00519 Vector3d currMouseVector = Vector3d(event->pos().x(), event->pos().y(), 0)
00520 - centerProj;
00521 if(currMouseVector.norm() > 5)
00522 {
00523 currMouseVector = currMouseVector.normalized();
00524 double mouseAngle = acos(m_directionVector->dot(currMouseVector) /
00525 currMouseVector.norm2());
00526
00527 if(mouseAngle > 0)
00528 {
00529 Vector3d tester;
00530
00531 tester = performRotation(mouseAngle, rotationVector, Vector3d(0, 0, 0),
00532 *m_directionVector);
00533 double testAngle1 = acos(tester.dot(currMouseVector) /
00534 currMouseVector.norm2());
00535
00536 tester = performRotation(-mouseAngle, rotationVector, Vector3d(0, 0, 0),
00537 *m_directionVector);
00538 double testAngle2 = acos(tester.dot(currMouseVector) /
00539 currMouseVector.norm2());
00540
00541 if(testAngle1 > testAngle2 || isnan(testAngle2)) {
00542 mouseAngle = -mouseAngle;
00543 }
00544
00545 Vector3d direction = clicked - center;
00546 if (m_skeleton)
00547 {
00548 Vector3d currCrossDir = m_currentReference->cross(direction).normalized();
00549
00550 m_skeleton->skeletonRotate(mouseAngle, currCrossDir, center);
00551 *m_referencePoint = performRotation(mouseAngle, currCrossDir,
00552 Vector3d(0, 0, 0), *m_referencePoint);
00553 *m_currentReference = performRotation(mouseAngle, currCrossDir,
00554 Vector3d(0, 0, 0), *m_currentReference);
00555 *m_directionVector = performRotation(mouseAngle, rotationVector,
00556 Vector3d(0, 0, 0), *m_directionVector);
00557 }
00558 }
00559 }
00560 }
00561 else if (m_selectedBond && m_clickedAtom &&
00562 (m_clickedAtom->GetBond(m_selectedBond->GetBeginAtom()) ||
00563 m_clickedAtom->GetBond(m_selectedBond->GetEndAtom())))
00564 {
00565
00566
00567 Atom *beginAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00568 Atom *endAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00569
00570 Vector3d center;
00571 Vector3d other;
00572 if (m_clickedAtom->GetBond(beginAtom))
00573 {
00574 center = beginAtom->pos();
00575 other = endAtom->pos();
00576 }
00577 else {
00578 center = endAtom->pos();
00579 other = beginAtom->pos();
00580 }
00581
00582 Vector3d clicked = m_clickedAtom->pos();
00583
00584 Vector3d axis = Vector3d(0, 0, ((widget->camera()->modelview() * other).z() >=
00585 (widget->camera()->modelview() * center).z() ? -1 : 1));
00586
00587 Vector3d centerProj = widget->camera()->project(center);
00588 centerProj -= Vector3d(0,0,centerProj.z());
00589
00590 Vector3d currMouseVector = Vector3d(event->pos().x(), event->pos().y(), 0)
00591 - centerProj;
00592
00593 if(currMouseVector.norm() > 5)
00594 {
00595 currMouseVector = currMouseVector.normalized();
00596 double mouseAngle = acos(m_directionVector->dot(currMouseVector) /
00597 currMouseVector.norm2());
00598
00599 if(mouseAngle > 0)
00600 {
00601 Vector3d tester;
00602
00603 tester = performRotation(mouseAngle, axis, Vector3d(0, 0, 0), *m_directionVector);
00604 double testAngle1 = acos(tester.dot(currMouseVector) /
00605 currMouseVector.norm2());
00606
00607 tester = performRotation(-mouseAngle, axis, Vector3d(0, 0, 0), *m_directionVector);
00608 double testAngle2 = acos(tester.dot(currMouseVector) /
00609 currMouseVector.norm2());
00610
00611 if(testAngle1 > testAngle2 || isnan(testAngle2)) {
00612 mouseAngle = -mouseAngle;
00613 }
00614
00615 if (m_skeleton)
00616 {
00617 *m_directionVector = performRotation(mouseAngle, axis,
00618 Vector3d(0, 0, 0), *m_directionVector);
00619
00620 axis = (other - center).normalized();
00621 m_skeleton->skeletonRotate(mouseAngle, axis, center);
00622 }
00623 }
00624 }
00625 }
00626 else {
00627
00628 Navigate::rotate(widget, widget->center(), deltaDragging.x(), deltaDragging.y());
00629 }
00630 }
00631 #ifdef Q_WS_MAC
00632
00633
00634 else if ((event->buttons() & Qt::MidButton) || (event->buttons() &
00635 Qt::LeftButton && event->modifiers() & Qt::ShiftModifier))
00636 #else
00637 else if (event->buttons() & Qt::MidButton)
00638 #endif
00639 {
00640 if (m_clickedAtom)
00641 {
00642
00643 Navigate::tilt(widget, m_clickedAtom->pos(), deltaDragging.x());
00644
00645
00646 Navigate::zoom(widget, m_clickedAtom->pos(), deltaDragging.y());
00647 }
00648 else if (m_clickedBond)
00649 {
00650 Atom *begin = static_cast<Atom *>(m_clickedBond->GetBeginAtom());
00651 Atom *end = static_cast<Atom *>(m_clickedBond->GetEndAtom());
00652
00653 Vector3d btoe = end->pos() - begin->pos();
00654 double newLen = btoe.norm() / 2;
00655 btoe = btoe / btoe.norm();
00656
00657 Vector3d mid = begin->pos() + btoe * newLen;
00658
00659
00660 Navigate::tilt(widget, mid, deltaDragging.x());
00661
00662
00663 Navigate::zoom(widget, mid, deltaDragging.y());
00664 }
00665 else
00666 {
00667
00668 Navigate::tilt(widget, widget->center(), deltaDragging.x());
00669
00670
00671 Navigate::zoom(widget, widget->center(), deltaDragging.y());
00672 }
00673 }
00674 #ifdef Q_WS_MAC
00675
00676
00677 else if ((event->buttons() & Qt::RightButton) ||
00678 (event->buttons() & Qt::LeftButton &&
00679 (event->modifiers() == Qt::ControlModifier || event->modifiers() == Qt::MetaModifier)))
00680 #else
00681 else if (event->buttons() & Qt::RightButton)
00682 #endif
00683 {
00684 if (isAtomInBond(m_clickedAtom, m_selectedBond))
00685 {
00686
00687
00688 Atom *otherAtom;
00689
00690 if (m_clickedAtom == static_cast<Atom*>(m_selectedBond->GetBeginAtom()))
00691 otherAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00692 else
00693 otherAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00694
00695 Vector3d clicked = m_clickedAtom->pos();
00696 Vector3d other = otherAtom->pos();
00697 Vector3d direction = clicked - other;
00698
00699 Vector3d mouseLast = widget->camera()->unProject(m_lastDraggingPosition);
00700 Vector3d mouseCurr = widget->camera()->unProject(event->pos());
00701 Vector3d mouseDir = mouseCurr - mouseLast;
00702
00703 Vector3d component = mouseDir.dot(direction) / direction.norm2() * direction;
00704
00705 if (m_skeleton) {
00706 m_skeleton->skeletonTranslate(component.x(), component.y(), component.z());
00707 }
00708 }
00709 else if (m_selectedBond && m_clickedAtom &&
00710 (m_clickedAtom->GetBond(m_selectedBond->GetBeginAtom()) ||
00711 m_clickedAtom->GetBond(m_selectedBond->GetEndAtom())))
00712 {
00713
00714
00715 Atom *beginAtom = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00716 Atom *endAtom = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00717
00718 Vector3d center;
00719 Vector3d other;
00720 if (m_clickedAtom->GetBond(beginAtom))
00721 {
00722 center = beginAtom->pos();
00723 other = endAtom->pos();
00724 }
00725 else {
00726 center = endAtom->pos();
00727 other = beginAtom->pos();
00728 }
00729
00730 Vector3d clicked = m_clickedAtom->pos();
00731
00732 Vector3d axis = Vector3d(0, 0, ((widget->camera()->modelview() * other).z() >=
00733 (widget->camera()->modelview() * center).z() ? -1 : 1));
00734
00735 Vector3d centerProj = widget->camera()->project(center);
00736 centerProj -= Vector3d(0,0,centerProj.z());
00737
00738 Vector3d currMouseVector = Vector3d(event->pos().x(), event->pos().y(), 0)
00739 - centerProj;
00740
00741 if(currMouseVector.norm() > 5)
00742 {
00743 currMouseVector = currMouseVector.normalized();
00744 double mouseAngle = acos(m_directionVector->dot(currMouseVector) /
00745 currMouseVector.norm2());
00746
00747 if(mouseAngle > 0)
00748 {
00749 Vector3d tester;
00750
00751 tester = performRotation(mouseAngle, axis, Vector3d(0, 0, 0), *m_directionVector);
00752 double testAngle1 = acos(tester.dot(currMouseVector) /
00753 currMouseVector.norm2());
00754
00755 tester = performRotation(-mouseAngle, axis, Vector3d(0, 0, 0), *m_directionVector);
00756 double testAngle2 = acos(tester.dot(currMouseVector) /
00757 currMouseVector.norm2());
00758
00759 if(testAngle1 > testAngle2 || isnan(testAngle2)) {
00760 mouseAngle = -mouseAngle;
00761 }
00762
00763 if (m_skeleton)
00764 {
00765 *m_directionVector = performRotation(mouseAngle, axis,
00766 Vector3d(0, 0, 0), *m_directionVector);
00767
00768 axis = (other - center).normalized();
00769 m_skeleton->skeletonRotate(mouseAngle, axis, center);
00770 }
00771 }
00772 }
00773 }
00774 else {
00775
00776 Navigate::translate(widget, widget->center(), m_lastDraggingPosition, event->pos());
00777 }
00778 }
00779
00780 m_lastDraggingPosition = event->pos();
00781 widget->update();
00782
00783 return 0;
00784 }
00785
00786
00787
00788 QUndoCommand* BondCentricTool::wheel(GLWidget *widget, const QWheelEvent *event)
00789 {
00790 m_clickedAtom = NULL;
00791 m_clickedBond = NULL;
00792
00793 Primitive *clickedPrim = widget->computeClickedPrimitive(event->pos());
00794
00795 if (clickedPrim && clickedPrim->type() == Primitive::AtomType)
00796 {
00797 Atom *clickedAtom = (Atom*)clickedPrim;
00798
00799 Navigate::zoom(widget, clickedAtom->pos(), - MOUSE_WHEEL_SPEED * event->delta());
00800 }
00801 else if (clickedPrim && clickedPrim->type() == Primitive::BondType)
00802 {
00803 Bond *clickedBond = (Bond*)clickedPrim;
00804
00805 Atom *begin = static_cast<Atom *>(clickedBond->GetBeginAtom());
00806 Atom *end = static_cast<Atom *>(clickedBond->GetEndAtom());
00807
00808 Vector3d btoe = end->pos() - begin->pos();
00809 double newLen = btoe.norm() / 2;
00810 btoe = btoe / btoe.norm();
00811
00812 Vector3d mid = begin->pos() + btoe * newLen;
00813
00814
00815 Navigate::zoom(widget, mid, - MOUSE_WHEEL_SPEED * event->delta());
00816 }
00817 else {
00818
00819 Navigate::zoom(widget, widget->center(), - MOUSE_WHEEL_SPEED * event->delta());
00820 }
00821
00822 widget->update();
00823
00824 return 0;
00825 }
00826
00827
00828
00829 bool BondCentricTool::paint(GLWidget *widget)
00830 {
00831 if(widget->toolGroup()->activeTool() != this) {
00832 clearData();
00833 }
00834
00835 bool dihedralAtomClicked = false;
00836
00837
00838 if ((m_leftButtonPressed || m_rightButtonPressed) && m_clickedAtom &&
00839 m_selectedBond && !isAtomInBond(m_clickedAtom, m_selectedBond))
00840 {
00841 Atom *begin = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00842 Atom *end = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00843
00844 if (m_clickedAtom->GetBond(begin) || m_clickedAtom->GetBond(end))
00845 {
00846 dihedralAtomClicked = true;
00847
00848 if (m_rightButtonPressed) {
00849 drawSingleDihedralAngles(widget, m_clickedAtom, m_selectedBond);
00850 } else {
00851 drawDihedralAngles(widget, m_clickedAtom, m_selectedBond);
00852 }
00853 }
00854 }
00855
00856
00857 if (!dihedralAtomClicked &&
00858 ((m_leftButtonPressed && !m_clickedBond && !isAtomInBond(m_clickedAtom, m_selectedBond))
00859 || (m_midButtonPressed && !m_clickedBond && !m_clickedAtom)
00860 || (m_rightButtonPressed && !isAtomInBond(m_clickedAtom, m_selectedBond))))
00861 {
00862 drawSphere(widget, widget->center(), 0.10, 1.0);
00863 }
00864
00865
00866 if (!dihedralAtomClicked && m_leftButtonPressed && m_clickedAtom &&
00867 (!m_selectedBond || !isAtomInBond(m_clickedAtom, m_selectedBond)))
00868 {
00869 drawAtomAngles(widget, m_clickedAtom);
00870 }
00871
00872
00873 if (m_selectedBond && !dihedralAtomClicked)
00874 {
00875 Atom *begin = static_cast<Atom*>(m_selectedBond->GetBeginAtom());
00876 Atom *end = static_cast<Atom*>(m_selectedBond->GetEndAtom());
00877
00878 if (m_currentReference)
00879 {
00880
00881