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

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 f3b597 was f3b597, checked in by Frederik Heber <heber@…>, 9 years ago

FIX: GLMoleculeObject_molecule() may overlap with atomInserted() signal.

  • this is because GLMoleculeObject_molecule takes some time till init() is called and its runs in a separate thread (hence, further atoms may be loaded into the just created atoms). As we first signOn() and then call init(), we may end up initializing atoms whose atomInserted signal then also comes in but lateron. This causes the AtomsInSceneMap to have double entries and the assertion to fail. We now keep book of all atomic ids inserted during init() and these are ok to appear doubly and their signal is skipped.
  • Property mode set to 100644
File size: 16.7 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 "Descriptors/MoleculeIdDescriptor.hpp"
63#include "Helpers/helpers.hpp"
64#include "Shapes/ShapeRegistry.hpp"
65#include "molecule.hpp"
66#include "World.hpp"
67
68#include <iostream>
69
70using namespace MoleCuilder;
71
72GLWorldScene::GLWorldScene(QObject *parent)
73 : QObject(parent)
74{
75 int sphereDetails[] = {5, 3, 2, 0};
76 int cylinderDetails[] = {16, 8, 6, 3};
77 for (int i=0;i<GLMoleculeObject::DETAILTYPES_MAX;i++){
78 QGLBuilder emptyBuilder;
79 GLMoleculeObject::meshEmpty[i] = emptyBuilder.finalizedSceneNode();
80 QGLBuilder sphereBuilder;
81 sphereBuilder << QGLSphere(2.0, sphereDetails[i]);
82 GLMoleculeObject::meshSphere[i] = sphereBuilder.finalizedSceneNode();
83 GLMoleculeObject::meshSphere[i]->setOption(QGLSceneNode::CullBoundingBox, true);
84 QGLBuilder cylinderBuilder;
85 cylinderBuilder << QGLCylinder(.25,.25,1.0,cylinderDetails[i]);
86 GLMoleculeObject::meshCylinder[i] = cylinderBuilder.finalizedSceneNode();
87 GLMoleculeObject::meshCylinder[i]->setOption(QGLSceneNode::CullBoundingBox, true);
88 }
89
90 connect(this, SIGNAL(updated()), this, SLOT(update()));
91
92
93 setSelectionMode(SelectAtom);
94
95 init();
96}
97
98GLWorldScene::~GLWorldScene()
99{
100 // remove all elements
101 GLMoleculeObject::cleanMaterialMap();
102}
103
104/** Initialise the WorldScene with molecules and atoms from World.
105 *
106 */
107void GLWorldScene::init()
108{
109 const std::vector<const molecule *> &molecules =
110 const_cast<const World &>(World::getInstance()).getAllMolecules();
111
112 for (std::vector<const molecule*>::const_iterator moliter = molecules.begin();
113 moliter != molecules.end();
114 moliter++) {
115 // create molecule objects in scene
116 moleculeInserted((*moliter)->getId());
117 }
118}
119
120/** Update the WorldScene with molecules and atoms from World.
121 *
122 * This function should be called after e.g. WorldTime::TimeChanged was
123 * received or after another molecule has been loaded.
124 *
125 */
126void GLWorldScene::update()
127{
128 const std::vector<const molecule *> &molecules =
129 const_cast<const World &>(World::getInstance()).getAllMolecules();
130
131 for (std::vector<const molecule*>::const_iterator moliter = molecules.begin();
132 moliter != molecules.end();
133 moliter++) {
134 // check whether molecule already exists
135 const moleculeId_t molid = (*moliter)->getId();
136 const bool mol_present = MoleculesinSceneMap.count(molid);
137 if (!mol_present)
138 moleculeInserted((*moliter)->getId());
139 }
140}
141
142void GLWorldScene::atomClicked(atomId_t no)
143{
144 LOG(3, "INFO: GLMoleculeObject_molecule - atom " << no << " has been clicked.");
145 const atom * const Walker = const_cast<const World &>(World::getInstance()).
146 getAtom(AtomById(no));
147 if (selectionMode == SelectAtom){
148 if (!World::getInstance().isSelected(Walker))
149 SelectionAtomById(std::vector<atomId_t>(1,no));
150 else
151 SelectionNotAtomById(std::vector<atomId_t>(1,no));
152 }else if (selectionMode == SelectMolecule){
153 const molecule *mol = Walker->getMolecule();
154 ASSERT(mol, "Atom without molecule has been clicked.");
155 molids_t ids(1, mol->getId());
156 if (!World::getInstance().isSelected(mol))
157 SelectionMoleculeById(ids);
158 else
159 SelectionNotMoleculeById(ids);
160 }
161 emit clicked(no);
162}
163
164void GLWorldScene::moleculeClicked(moleculeId_t no)
165{
166 LOG(3, "INFO: GLMoleculeObject_molecule - mol " << no << " has been clicked.");
167 const molecule * const mol= const_cast<const World &>(World::getInstance()).
168 getMolecule(MoleculeById(no));
169 ASSERT(mol, "Atom without molecule has been clicked.");
170 molids_t ids(1, mol->getId());
171 if (!World::getInstance().isSelected(mol))
172 SelectionMoleculeById(ids);
173 else
174 SelectionNotMoleculeById(ids);
175 emit clicked(no);
176}
177
178
179/** Adds an atom to the scene.
180 *
181 * @param _atom atom to add
182 */
183void GLWorldScene::atomInserted(const atomId_t _id)
184{
185 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "+toString(_id)+".");
186 // find associated molecule
187 const atom * const _atom = const_cast<const World &>(World::getInstance()).
188 getAtom(AtomById(_id));
189 if (_atom != NULL) {
190 const moleculeId_t molid = _atom->getMolecule()->getId();
191 MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(molid );
192 ASSERT(moliter != MoleculesinSceneMap.end(),
193 "GLWorldScene::atomAdded() - molecule with id of "+toString(molid)
194 +" atom with id "+toString(_id)+" is unknown.");
195 GLMoleculeObject_molecule *molObject = moliter->second;
196
197 // add atom to internal list
198#ifndef NDEBUG
199 AtomMoleculeMap::const_iterator atomiter = AtomsinSceneMap.find(_id);
200 ASSERT(atomiter == AtomsinSceneMap.end(),
201 "GLWorldScene::atomRemoved() - atom "+toString(_id)+" already known.");
202#endif
203 AtomsinSceneMap.insert( std::make_pair( _id, molObject ));
204
205 // inform its GlMoleculeObject_molecule.
206 molObject->atomInserted(_id);
207
208 // emit change
209 emit changeOccured();
210 } else {
211 ELOG(1, "GLWorldScene::atomInserted() - added NULL molobject to AtomsinSceneMap for id " << _id);
212 GLMoleculeObject_molecule *molObject = NULL;
213 AtomsinSceneMap.insert( std::make_pair( _id, molObject ));
214 }
215}
216
217/** Removes an atom from the scene.
218 *
219 * We just the id as the atom might have already been destroyed.
220 *
221 * @param _id id of atom to remove
222 */
223void GLWorldScene::atomRemoved(const atomId_t _id)
224{
225 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_id)+".");
226 // find associated molecule
227 AtomMoleculeMap::iterator iter = AtomsinSceneMap.find(_id);
228 ASSERT(iter != AtomsinSceneMap.end(),
229 "GLWorldScene::atomRemoved() - atom "+toString(_id)+" not on display.");
230 GLMoleculeObject_molecule *molObject = iter->second;
231
232 // remove from internal list
233 AtomsinSceneMap.erase(iter);
234
235 // inform its GlMoleculeObject_molecule.
236 molObject->atomRemoved(_id);
237
238 // emit change
239 emit changeOccured();
240}
241
242/** ....
243 *
244 */
245void GLWorldScene::worldSelectionChanged()
246{
247 LOG(3, "INFO: GLWorldScene: Received signal selectionChanged.");
248
249 const std::vector<const molecule*> &molecules =
250 const_cast<const World &>(World::getInstance()).getAllMolecules();
251
252 if (molecules.size() > 0) {
253 for (std::vector<const molecule*>::const_iterator Runner = molecules.begin();
254 Runner != molecules.end();
255 Runner++) {
256
257 // molecule selected but not in scene?
258 const bool isSelected =
259 const_cast<const World &>(World::getInstance()).isSelected(*Runner);
260 if (isSelected){
261 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find((*Runner)->getId());
262 ASSERT( iter != MoleculesinSceneMap.end(),
263 "GLWorldScene::worldSelectionChanged() - selected molecule is unknown.");
264 GLMoleculeObject_molecule *molObject = iter->second;
265 // inform molecule object
266 molObject->selected(isSelected);
267 }
268 }
269 }
270}
271
272/** Inserts a molecule into the scene.
273 *
274 * @param _mol molecule to insert
275 */
276void GLWorldScene::moleculeInserted(const moleculeId_t _id)
277{
278 LOG(3, "INFO: GLWorldScene: Received signal moleculeInserted for molecule "+toString(_id)+".");
279 MoleculeNodeMap::const_iterator iter = MoleculesinSceneMap.find(_id);
280 ASSERT( iter == MoleculesinSceneMap.end(),
281 "GLWorldScene::moleculeInserted() - molecule's id "+toString(_id)+" already present.");
282
283 // add new object
284 GLMoleculeObject_molecule *molObject = new GLMoleculeObject_molecule(GLMoleculeObject::meshEmpty, this, _id);
285 ASSERT( molObject != NULL,
286 "GLWorldScene::moleculeInserted - could not create molecule object for "+toString(_id));
287 MoleculesinSceneMap.insert( make_pair(_id, molObject) );
288 connect (molObject, SIGNAL(changed()), this, SIGNAL(changed()));
289 connect (molObject, SIGNAL(changeOccured()), this, SIGNAL(changeOccured()));
290 connect (molObject, SIGNAL(atomClicked(atomId_t)), this, SLOT(atomClicked(atomId_t)));
291 connect (molObject, SIGNAL(moleculeClicked(moleculeId_t)), this, SLOT(moleculeClicked(moleculeId_t)));
292 connect (molObject, SIGNAL(changeAtomId(GLMoleculeObject_atom *, int, int)), this, SLOT(changeAtomId(GLMoleculeObject_atom *, int, int)));
293 connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
294 connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
295 connect (molObject, SIGNAL(hoverChanged(const atomId_t)), this, SIGNAL(hoverChanged(const atomId_t)));
296 connect (molObject, SIGNAL(hoverChanged(const moleculeId_t, int)), this, SIGNAL(hoverChanged(const moleculeId_t, int)));
297 emit changed();
298 emit changeOccured();
299}
300
301/** Removes a molecule from the scene.
302 *
303 * @param _id id of molecule to remove
304 */
305void GLWorldScene::moleculeRemoved(const moleculeId_t _id)
306{
307 LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_id)+".");
308 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id);
309 ASSERT( iter != MoleculesinSceneMap.end(),
310 "GLWorldScene::moleculeInserted() - molecule's id "+toString(_id)+" is unknown.");
311
312 GLMoleculeObject_molecule *molObject = iter->second;
313 molObject->disconnect();
314 MoleculesinSceneMap.erase(iter);
315 delete molObject;
316 emit changed();
317 emit changeOccured();
318}
319
320void GLWorldScene::moleculesVisibilityChanged(const moleculeId_t _id, bool _visible)
321{
322 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id);
323 ASSERT( iter != MoleculesinSceneMap.end(),
324 "GLWorldScene::moleculeInserted() - molecule's id "+toString(_id)+" is unknown.");
325
326 GLMoleculeObject_molecule *molObject = iter->second;
327 molObject->setVisible(_visible);
328
329 emit changed();
330 emit changeOccured();
331}
332
333/** Adds a bond to the scene.
334 *
335 * @param _bond bond to add
336 * @param side which side of the bond (left or right)
337 */
338void GLWorldScene::bondInserted(const bond::ptr _bond, const enum GLMoleculeObject_bond::SideOfBond _side)
339{
340 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");
341 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");
342 // bond partners must both belong to same atom
343 ASSERT( _bond->leftatom->getMolecule() == _bond->rightatom->getMolecule(),
344 "GLWorldScene::bondInserted() - bond partners do not belong to same molecule.");
345
346 // find associated molecule object
347 const moleculeId_t molid = _bond->leftatom->getMolecule()->getId();
348 MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(molid );
349 ASSERT(moliter != MoleculesinSceneMap.end(),
350 "GLWorldScene::bondInserted() - molecule with id of "+toString(molid)
351 +" atom with id "+toString(_bond->leftatom->getId())+" is unknown.");
352 GLMoleculeObject_molecule *molObject = moliter->second;
353
354 // add to internal list
355 const GLMoleculeObject_molecule::BondIds ids =
356 GLMoleculeObject_molecule::getBondIds(_bond, _side);
357 BondMoleculeMap::const_iterator iter = BondsinSceneMap.find(ids);
358 ASSERT(iter == BondsinSceneMap.end(),
359 "GLWorldScene::bondInserted() - bond with ids "+toString(ids.first)
360 +","+toString(ids.second)+" already present.");
361 BondsinSceneMap.insert( std::make_pair( ids, molObject ));
362
363 // inform its GlMoleculeObject_molecule.
364 molObject->bondInserted(_bond, _side);
365
366 // emit change
367 emit changeOccured();
368}
369
370/** Removes a bond from the scene.
371 *
372 * @param _bond bond to remove
373 */
374void GLWorldScene::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
375{
376 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");
377 {
378 // left bond
379 const GLMoleculeObject_molecule::BondIds Leftids( make_pair(leftnr, rightnr) );
380 BondMoleculeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
381 ASSERT(leftiter != BondsinSceneMap.end(),
382 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
383 +toString(rightnr)+" not on display.");
384 GLMoleculeObject_molecule *molObject = leftiter->second;
385
386 // remove from internal list
387 BondsinSceneMap.erase(leftiter);
388
389 // inform its GlMoleculeObject_molecule.
390 molObject->bondRemoved( leftnr, rightnr );
391 }
392
393 // emit change
394 emit changeOccured();
395}
396
397/** Adds a shape to the scene.
398 *
399 * uses ShapeRegistry::lastChanged()
400 *
401 */
402void GLWorldScene::addShape()
403{
404 Shape &shape = *ShapeRegistry::getInstance().lastChanged();
405 GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(shape, this);
406 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(shape.getName());
407 ASSERT(iter == ShapesinSceneMap.end(),
408 "GLWorldScene::addShape() - same shape "+shape.getName()+" added again.");
409 ShapesinSceneMap.insert( make_pair(shape.getName(), shapeObject) );
410}
411
412void GLWorldScene::removeShape()
413{
414 Shape &shape = *ShapeRegistry::getInstance().lastChanged();
415 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(shape.getName());
416 ASSERT(iter != ShapesinSceneMap.end(),
417 "GLWorldScene::removeShape() - shape "+shape.getName()+" not in scene.");
418 ShapesinSceneMap.erase(iter);
419 delete(iter->second);
420}
421
422void GLWorldScene::updateSelectedShapes()
423{
424 foreach (QObject *obj, children()) {
425 GLMoleculeObject_shape *shapeobj = qobject_cast<GLMoleculeObject_shape *>(obj);
426 if (shapeobj){
427 shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape()));
428 }
429 }
430}
431
432void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
433{
434 // Initialize all of the mesh objects that we have as children.
435 foreach (QObject *obj, children()) {
436 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
437 if (meshobj)
438 meshobj->initialize(view, painter);
439 }
440}
441
442void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const
443{
444 // Draw all of the mesh objects that we have as children.
445 foreach (QObject *obj, children()) {
446 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
447 if (meshobj)
448 meshobj->draw(painter, cameraPlane);
449 }
450}
451
452void GLWorldScene::setSelectionMode(SelectionModeType mode)
453{
454 selectionMode = mode;
455 // TODO send update to toolbar
456}
457
458void GLWorldScene::setSelectionModeAtom()
459{
460 setSelectionMode(SelectAtom);
461}
462
463void GLWorldScene::setSelectionModeMolecule()
464{
465 setSelectionMode(SelectMolecule);
466}
467
468void GLWorldScene::changeAtomId(GLMoleculeObject_atom *ob, int oldId, int newId)
469{
470 LOG(3, "INFO: GLWorldScene - change atom id " << oldId << " to " << newId << ".");
471 // Remove from map.
472 AtomMoleculeMap::iterator iter = AtomsinSceneMap.find(oldId);
473 ASSERT(iter != AtomsinSceneMap.end(),
474 "GLWorldScene::changeAtomId() - atom with old id "+toString(oldId)+" not on display.");
475 GLMoleculeObject_molecule *molObject = iter->second;
476
477 // erase by signalling removal
478 molObject->atomRemoved(oldId);
479
480 // remove from internal list
481 AtomsinSceneMap.erase(iter);
482
483 // Reinsert with new id.
484 {
485 AtomMoleculeMap::iterator iter = AtomsinSceneMap.find(newId);
486 ASSERT(iter == AtomsinSceneMap.end(),
487 "GLWorldScene::changeAtomId() - atom with new id "+toString(newId)+" already known.");
488 }
489 AtomsinSceneMap.insert( make_pair(newId, molObject) );
490
491 // inform molecule object
492 molObject->atomInserted(newId);
493}
Note: See TracBrowser for help on using the repository browser.