source: src/UIElements/Views/Qt4/Qt3D/GLWorldScene.cpp@ 426c84

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 426c84 was c48ac12, checked in by Frederik Heber <heber@…>, 11 years ago

FIX: GLWorldScene and GLWorldView have atomRemoved with id not atom ptr.

  • this is safer as we only need the id for looking up the internal "visual" instance of the atom. As Qt uses multiple threads, we cannot safely assume the atom to be still intact.
  • Property mode set to 100644
File size: 14.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * GLWorldScene.cpp
26 *
27 * This is based on the Qt3D example "teaservice", specifically parts of teaservice.cpp.
28 *
29 * Created on: Aug 17, 2011
30 * Author: heber
31 */
32
33// include config.h
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
37
38#include "GLWorldScene.hpp"
39#include <Qt3D/qglview.h>
40#include <Qt3D/qglbuilder.h>
41#include <Qt3D/qglscenenode.h>
42#include <Qt3D/qglsphere.h>
43#include <Qt3D/qglcylinder.h>
44
45#include "GLMoleculeObject.hpp"
46#include "GLMoleculeObject_atom.hpp"
47#include "GLMoleculeObject_bond.hpp"
48#include "GLMoleculeObject_molecule.hpp"
49#include "GLMoleculeObject_shape.hpp"
50
51#include "CodePatterns/MemDebug.hpp"
52
53#include "CodePatterns/Log.hpp"
54
55#include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp"
56#include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp"
57#include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp"
58#include "Actions/SelectionAction/Molecules/NotMoleculeByIdAction.hpp"
59#include "Atom/atom.hpp"
60#include "Bond/bond.hpp"
61#include "Descriptors/AtomIdDescriptor.hpp"
62#include "Helpers/helpers.hpp"
63#include "Shapes/ShapeRegistry.hpp"
64#include "molecule.hpp"
65#include "World.hpp"
66
67#include <iostream>
68
69using namespace MoleCuilder;
70
71std::ostream &operator<<(std::ostream &ost, const GLWorldScene::BondIds &t)
72{
73 ost << t.first << "," << t.second;
74 return ost;
75}
76
77GLWorldScene::GLWorldScene(QObject *parent)
78 : QObject(parent),
79 hoverAtom(NULL)
80{
81 int sphereDetails[] = {5, 3, 2, 0};
82 int cylinderDetails[] = {16, 8, 6, 3};
83 for (int i=0;i<GLMoleculeObject::DETAILTYPES_MAX;i++){
84 QGLBuilder emptyBuilder;
85 meshEmpty[i] = emptyBuilder.finalizedSceneNode();
86 QGLBuilder sphereBuilder;
87 sphereBuilder << QGLSphere(2.0, sphereDetails[i]);
88 meshSphere[i] = sphereBuilder.finalizedSceneNode();
89 meshSphere[i]->setOption(QGLSceneNode::CullBoundingBox, true);
90 QGLBuilder cylinderBuilder;
91 cylinderBuilder << QGLCylinder(.25,.25,1.0,cylinderDetails[i]);
92 meshCylinder[i] = cylinderBuilder.finalizedSceneNode();
93 meshCylinder[i]->setOption(QGLSceneNode::CullBoundingBox, true);
94 }
95
96 setSelectionMode(SelectAtom);
97
98 init();
99}
100
101GLWorldScene::~GLWorldScene()
102{
103 // remove all elements
104 GLMoleculeObject::cleanMaterialMap();
105}
106
107/** Initialise the WorldScene with molecules and atoms from World.
108 *
109 */
110void GLWorldScene::init()
111{
112 const std::vector<molecule*> &molecules = World::getInstance().getAllMolecules();
113
114 if (molecules.size() > 0) {
115 for (std::vector<molecule*>::const_iterator Runner = molecules.begin();
116 Runner != molecules.end();
117 Runner++) {
118
119 for (molecule::const_iterator atomiter = (*Runner)->begin();
120 atomiter != (*Runner)->end();
121 ++atomiter) {
122 // create atom objects in scene
123 atomInserted(*atomiter);
124
125 // create bond objects in scene
126 const BondList &bondlist = (*atomiter)->getListOfBonds();
127 for (BondList::const_iterator bonditer = bondlist.begin();
128 bonditer != bondlist.end();
129 ++bonditer) {
130 const bond::ptr _bond = *bonditer;
131 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == *atomiter) ?
132 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
133 bondInserted(_bond, side);
134 }
135 }
136 }
137 }
138}
139
140/** Adds an atom to the scene.
141 *
142 * @param _atom atom to add
143 */
144void GLWorldScene::atomInserted(const atom *_atom)
145{
146 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "+toString(_atom->getId())+".");
147 GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(meshSphere, this, _atom);
148 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atom->getId());
149 ASSERT(iter == AtomsinSceneMap.end(),
150 "GLWorldScene::atomAdded() - same atom "+_atom->getName()+" added again.");
151 AtomsinSceneMap.insert( make_pair(_atom->getId(), atomObject) );
152
153 qRegisterMetaType<atomId_t>("atomId_t");
154 qRegisterMetaType<bond::ptr>("bond::ptr");
155 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
156 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(atomClicked(atomId_t)));
157 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
158 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
159 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
160 connect (atomObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
161 connect (atomObject, SIGNAL(BondsInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)));
162 connect (atomObject, SIGNAL(indexChanged(GLMoleculeObject_atom*, int, int)), this, SLOT(changeAtomId(GLMoleculeObject_atom*, int, int)));
163 //bondsChanged(_atom);
164 emit changeOccured();
165}
166
167/** Removes an atom from the scene.
168 *
169 * We just the id as the atom might have already been destroyed.
170 *
171 * @param _id id of atom to remove
172 */
173void GLWorldScene::atomRemoved(const atomicNumber_t _id)
174{
175 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_id)+".");
176 // bonds are removed by signal coming from ~bond
177 // remove atoms
178 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
179 ASSERT(iter != AtomsinSceneMap.end(),
180 "GLWorldScene::atomRemoved() - atom "+toString(_id)+" not on display.");
181 GLMoleculeObject_atom *atomObject = iter->second;
182 atomObject->disconnect();
183 AtomsinSceneMap.erase(iter);
184 delete atomObject;
185 emit changeOccured();
186}
187
188/** ....
189 *
190 */
191void GLWorldScene::worldSelectionChanged()
192{
193 LOG(3, "INFO: GLWorldScene: Received signal selectionChanged.");
194
195 const std::vector<molecule*> &molecules = World::getInstance().getAllMolecules();
196
197 if (molecules.size() > 0) {
198 for (std::vector<molecule*>::const_iterator Runner = molecules.begin();
199 Runner != molecules.end();
200 Runner++) {
201
202 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find((*Runner)->getId());
203 bool isSelected = World::getInstance().isSelected(*Runner);
204
205 // molecule selected but not in scene?
206 if (isSelected && (iter == MoleculesinSceneMap.end())){
207 // -> create new mesh
208 GLMoleculeObject_molecule *molObject = new GLMoleculeObject_molecule(meshEmpty, this, *Runner);
209 MoleculesinSceneMap.insert( make_pair((*Runner)->getId(), molObject) );
210 connect (molObject, SIGNAL(changed()), this, SIGNAL(changed()));
211 connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
212 connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
213 emit changed();
214 emit changeOccured();
215 }
216
217 // molecule not selected but in scene?
218 if (!isSelected && (iter != MoleculesinSceneMap.end())){
219 // -> remove from scene
220 moleculeRemoved(*Runner);
221 }
222
223 }
224 }
225}
226
227/** Removes a molecule from the scene.
228 *
229 * @param _molecule molecule to remove
230 */
231void GLWorldScene::moleculeRemoved(const molecule *_molecule)
232{
233 LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molecule->getId())+".");
234 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molecule->getId());
235
236 // only remove if the molecule is in the scene
237 // (= is selected)
238 if (iter != MoleculesinSceneMap.end()){
239 GLMoleculeObject_molecule *molObject = iter->second;
240 molObject->disconnect();
241 MoleculesinSceneMap.erase(iter);
242 delete molObject;
243 emit changed();
244 emit changeOccured();
245 }
246}
247
248/** Adds a bond to the scene.
249 *
250 * @param _bond bond to add
251 * @param side which side of the bond (left or right)
252 */
253void GLWorldScene::bondInserted(const bond::ptr _bond, const enum GLMoleculeObject_bond::SideOfBond side)
254{
255 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");
256 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");
257
258 BondIds ids;
259 switch (side) {
260 case GLMoleculeObject_bond::left:
261 ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId());
262 break;
263 case GLMoleculeObject_bond::right:
264 ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId());
265 break;
266 }
267#ifndef NDEBUG
268 BondNodeMap::iterator iter = BondsinSceneMap.find(ids);
269 ASSERT(iter == BondsinSceneMap.end(),
270 "GLWorldScene::bondAdded() - same left-sided bond "+toString(*_bond)+" added again.");
271#endif
272 GLMoleculeObject_bond * bondObject =
273 new GLMoleculeObject_bond(meshCylinder, this, _bond, side);
274 connect (
275 bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)),
276 this, SLOT(bondRemoved(const atomId_t, const atomId_t)));
277 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
278 BondsinSceneMap.insert( make_pair(ids, bondObject) );
279// BondIdsinSceneMap.insert( Leftids );
280 emit changeOccured();
281}
282
283/** Removes a bond from the scene.
284 *
285 * @param _bond bond to remove
286 */
287void GLWorldScene::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
288{
289 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");
290 {
291 // left bond
292 const BondIds Leftids( make_pair(leftnr, rightnr) );
293 BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
294 ASSERT(leftiter != BondsinSceneMap.end(),
295 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
296 +toString(rightnr)+" not on display.");
297 //GLMoleculeObject_bond::ptr bondObject = leftiter->second;
298 BondsinSceneMap.erase(leftiter);
299 //delete bondObject; // is done by signal from bond itself
300 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");
301 }
302
303 emit changeOccured();
304}
305
306/** Adds a shape to the scene.
307 *
308 * uses ShapeRegistry::lastChanged()
309 *
310 */
311void GLWorldScene::addShape()
312{
313 Shape &shape = *ShapeRegistry::getInstance().lastChanged();
314 GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(shape, this);
315 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(shape.getName());
316 ASSERT(iter == ShapesinSceneMap.end(),
317 "GLWorldScene::addShape() - same shape "+shape.getName()+" added again.");
318 ShapesinSceneMap.insert( make_pair(shape.getName(), shapeObject) );
319}
320
321void GLWorldScene::removeShape()
322{
323 Shape &shape = *ShapeRegistry::getInstance().lastChanged();
324 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(shape.getName());
325 ASSERT(iter != ShapesinSceneMap.end(),
326 "GLWorldScene::removeShape() - shape "+shape.getName()+" not in scene.");
327 ShapesinSceneMap.erase(iter);
328 delete(iter->second);
329}
330
331void GLWorldScene::updateSelectedShapes()
332{
333 foreach (QObject *obj, children()) {
334 GLMoleculeObject_shape *shapeobj = qobject_cast<GLMoleculeObject_shape *>(obj);
335 if (shapeobj){
336 shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape()));
337 }
338 }
339}
340
341void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
342{
343 // Initialize all of the mesh objects that we have as children.
344 foreach (QObject *obj, children()) {
345 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
346 if (meshobj)
347 meshobj->initialize(view, painter);
348 }
349}
350
351void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const
352{
353 // Draw all of the mesh objects that we have as children.
354 foreach (QObject *obj, children()) {
355 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
356 if (meshobj)
357 meshobj->draw(painter, cameraPlane);
358 }
359}
360
361void GLWorldScene::atomClicked(atomId_t no)
362{
363 LOG(3, "INFO: GLWorldScene - atom " << no << " has been clicked.");
364 const atom *Walker = World::getInstance().getAtom(AtomById(no));
365 if (selectionMode == SelectAtom){
366 if (!World::getInstance().isSelected(Walker))
367 SelectionAtomById(std::vector<atomId_t>(1,no));
368 else
369 SelectionNotAtomById(std::vector<atomId_t>(1,no));
370 }else if (selectionMode == SelectMolecule){
371 const molecule *mol = Walker->getMolecule();
372 ASSERT(mol, "Atom without molecule has been clicked.");
373 if (!World::getInstance().isSelected(mol))
374 SelectionMoleculeById(mol->getId());
375 else
376 SelectionNotMoleculeById(mol->getId());
377 }
378 emit clicked(no);
379}
380
381void GLWorldScene::setSelectionMode(SelectionModeType mode)
382{
383 selectionMode = mode;
384 // TODO send update to toolbar
385}
386
387void GLWorldScene::setSelectionModeAtom()
388{
389 setSelectionMode(SelectAtom);
390}
391
392void GLWorldScene::setSelectionModeMolecule()
393{
394 setSelectionMode(SelectMolecule);
395}
396
397void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob)
398{
399 // Find the atom, ob corresponds to.
400 hoverAtom = NULL;
401 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
402 if (atomObject){
403 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
404 if (iter->second == atomObject)
405 hoverAtom = World::getInstance().getAtom(AtomById(iter->first));
406 }
407 }
408
409 // Propagate signal.
410 emit hoverChanged(hoverAtom);
411}
412
413void GLWorldScene::changeAtomId(GLMoleculeObject_atom *ob, int oldId, int newId)
414{
415 LOG(3, "INFO: GLWorldScene - change atom id " << oldId << " to " << newId << ".");
416 // Remove from map.
417 AtomNodeMap::iterator iter = AtomsinSceneMap.find(oldId);
418 ASSERT(iter != AtomsinSceneMap.end(),
419 "GLWorldScene::objectIdChangedSignalled() - atom with id "+toString(oldId)+" not on display.");
420 GLMoleculeObject_atom *atomObject = iter->second;
421 AtomsinSceneMap.erase(iter);
422
423 // Reinsert with new id.
424 AtomsinSceneMap.insert( make_pair(newId, atomObject) );
425}
426
Note: See TracBrowser for help on using the repository browser.