/*************************************************************************** * Copyright (C) 2005 by Raphael Langerhorst * * raphael-langerhorst@gmx.at * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to * * the following conditions: * * * * The above copyright notice and this permission notice shall be * * included in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.* * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * * OTHER DEALINGS IN THE SOFTWARE. * ***************************************************************************/ #include "GweController.h" #include "GDataController.h" #include #include #include #include #include #include #include #include #include #include #include using namespace GCS; namespace GWE { //see GweController.h class QPtrListGElement : public QPtrList { public: virtual ~QPtrListGElement() {}; }; GweController::GweController(GDataController* data, QObject *parent, const char *name) : QObject(parent,name), Data(data) { } GweController::~GweController() { } GDataController* GweController::getDataController() { return this->Data; } const GDataController* GweController::getDataController() const { return this->Data; } void GweController::connectBasicElementSignals(const GCS::GElementID& id) { GElement* element = NULL; element = Data->getOpenElement(id); bool close_afterwards = false; if (element == NULL) { element = Data->open(id); close_afterwards = true; } if (element) { qDebug(QString("connecting signals and slots for element %1 !").arg(id.getID())); connect(element,SIGNAL(childElementCreated(GCS::GElement*)), Data,SLOT(add(GCS::GElement*))); connect(element,SIGNAL(radiateInfluence(const GCS::GElementInfluence&)), this,SLOT(radiateInfluence(const GCS::GElementInfluence& ))); connect(element,SIGNAL(sendInfluence(const GCS::GElementID&, const GCS::GElementInfluence& )), this,SLOT(routeInfluence(const GCS::GElementID&, const GCS::GElementInfluence& ))); connect(element,SIGNAL(formChanged(const GCS::GForm& )), this,SLOT(handleReparenting())); connect(element,SIGNAL(energyChanged(const GCS::GEnergy& )), this,SLOT(removeElementWithNoEnergyLeft(const GCS::GEnergy& ))); if (close_afterwards) Data->close(id); } else { qWarning(QString("could not connect element %1 !").arg(id.getID())); } } //@todo max_traverse_children and max_traverse_parents parameters not yet used!! QPtrListGElement GweController::findInRange(GElement* source, unsigned max_traverse_children, unsigned max_traverse_parents) { QPtrListGElement list; GDataController* data = this->getDataController(); Q_CHECK_PTR(source); if (source==NULL) { qWarning("source is NULL!!!"); return list; } const GObject* source_o = source->getObject(); bool close_parent_afterwards = false; const GElementID& parentID = source->getObject()->getParent(); GElement* parent = NULL; parent = data->getOpenElement(parentID); if (parent == NULL) { close_parent_afterwards = true; parent = data->open(parentID); } Q_CHECK_PTR(parent); //now, getParent()->children() to get a list of elements with the //same parent as source QValueList children; if (parent) { //parent is affected as well list.append(parent); //if the element is it's own parent we do not need to go through //it's children here, they will all be added later anyway if (parentID != source->getElementID().getID()) { children = parent->getObject()->getChildren(); bool has_form = source_o->hasForm() ? true : false; if (has_form) //if the source element has a form, we need to check if they touch each other { const GForm* source_f = source_o->getForm(); const GVector3& position = source_f->Position; const double range = source_f->getRadiusMax(); for (QValueListIterator childrenID = children.begin(); childrenID != children.end(); ++childrenID) { GElement* el = data->open(*childrenID); Q_CHECK_PTR(el); if (el) { const GObject* el_o= el->getObject(); if (el_o->hasForm()) { const GForm* f = el_o->getForm(); if ((f->Position - position).length() < (range + f->getRadiusMax())) list.append(el); else data->close(el_o->getID()); } else { //if something has no form it is everywhere list.append(el); } } } } else //if the source element has no form, it reaches everything anyway { for (QValueListIterator childrenID = children.begin(); childrenID != children.end(); ++childrenID) { GElement* el = data->open(*childrenID); Q_CHECK_PTR(el); if (el) { list.append(el); } } } } if (close_parent_afterwards) data->close(parentID); } else { qDebug("element with ID " + QString::number(source->getElementID().getID()) + " has no parent!"); //the element at least influences itself list.append(source); } //add own children - the element that radiates a certain influence DOES influence "itself" by this children = source->getObject()->getChildren(); for (QValueListIterator childrenID = children.begin(); childrenID != children.end(); ++childrenID) { GElement* el = data->open(*childrenID); Q_CHECK_PTR(el); if (el) { list.append(el); } } //this list contains: // * the parent // * all children of it's parent that touch the source's form (including itself) // * all own children // ALL elements are opened and should be closed when usage finished! return list; } void GweController::executeOpenElement(const GCS::GElementID& id) { GCS::GElement* element = this->Data->getOpenElement(id); if (element) { element->executeElement(); } else { qWarning(QString("Couldn't execute element with ID %1 because it couldn't be found").arg(id.getID())); } } void GweController::radiateInfluence(const GElementInfluence& influence) { GDataController* data = this->getDataController(); Q_CHECK_PTR(data); GElement* source_element = NULL; source_element = data->getOpenElement(influence.source()); if (source_element==NULL) source_element = data->open(influence.source()); if (source_element==NULL) { qWarning("Received influence to radiate from a source that does not exist!"); return; } Q_CHECK_PTR(source_element); // qDebug("got influence to radiate from " + QString::number(source_element->getElementID().getID())); QPtrList influenced_elements = this->findInRange(source_element); //for now provide a very simple mechanism for influence distribution: // energy amount of the influence is evenly distributed among its receivers unsigned dest_count = influenced_elements.count(); if (dest_count > 0) { double energy_level_original = influence.Energy.level(); double energy_amount_original = influence.Energy.amount(); double energy_sigma_original = influence.Energy.sigma(); double energy_amount_single_dest = energy_amount_original/dest_count; double energy_amount_left = 0; GCS::GElementInfluence influence_partial(influence.source(),GEnergy(energy_level_original,energy_amount_single_dest,energy_sigma_original)); GElement* e = influenced_elements.first(); while(e) { // qDebug(" sending to " + QString::number(e->getElementID().getID())); e->receiveInfluence(influence_partial); data->close(e->getElementID()); // energy_amount_left += influence.Energy.amount(); e = influenced_elements.next(); } //set the energy amount to what has been left by the receivers //the sender should put this energy back to it's own energy // influence.Energy.set(energy_level_original,energy_amount_left,energy_sigma_original); } else { qWarning("destination count for influence radiation is 0!"); } data->close(source_element->getElementID()); } void GweController::routeInfluence(const GElementID& destination, const GElementInfluence& influence) { // qDebug("got influence to route from " + QString::number(influence.source().getID())); GDataController* data = this->getDataController(); Q_CHECK_PTR(data); GElement* element = data->open(destination); Q_CHECK_PTR(element); if (element) { element->receiveInfluence(influence); data->close(element->getElementID()); } else { element = data->open(influence.source()); if (element==NULL) { Q_CHECK_PTR(element); qDebug("got influence from %lu, but this element is not stored?!",influence.source().getID()); } else { // qDebug(" sending to " + QString::number(element->getElementID().getID())); element->receiveInfluence(influence); } data->close(element->getElementID()); } } void GweController::handleReparenting() { // return; //not implemented yet const QObject* sender_generic = sender(); Q_ASSERT(sender_generic->inherits("GCS::GElement")); //sender MUST be a GElement; if (!sender_generic->inherits("GCS::GElement")) return; const GCS::GElement* const_element = (const GCS::GElement*)sender_generic; GCS::GElement* element = this->Data->getOpenElement(const_element->getElementID()); //element MUST be open Q_CHECK_PTR(element->getObject()); if (element->getObject() && element->getObject()->hasForm()) { const GCS::GForm* f = element->getObject()->getForm(); const GCS::GElementID& id = element->getElementID(); const GCS::GElementID& old_parent = element->getObject()->getParent(); if (old_parent.getID() == 0) return; if (old_parent == id) return; //we're our own parent, probably the universe element // if (old_parent.getID() == 0) // { // const GCS::GElementID& new_parent = const_old_parent_element->getObject()->getParent(); // if (new_parent == old_parent) // { // return; // } // qWarning("handling reparenting: old parent had ID 0, not notifying old parent"); // new_parent_element->addChildElement(id); // GCS::GElement* new_parent_element = this->Data->open(new_parent); // GCS::GMatrix44 m = GCS::GMatrix44::createScaleMatrix(f_old_parent->Ellipsoid); // m.multiply(GCS::GMatrix44::createRotationAroundX(f_old_parent->Rotation.x)); // m.multiply(GCS::GMatrix44::createRotationAroundY(f_old_parent->Rotation.y)); // m.multiply(GCS::GMatrix44::createRotationAroundZ(f_old_parent->Rotation.z)); // m.multiply(GCS::GMatrix44::createTranslationMatrix(f_old_parent->Position)); // qDebug(QString("reparenting element %1 from old parent %2 to new parent %3").arg(QString::number(id.getID()),QString::number(old_parent.getID()),QString::number(new_parent.getID()))); // element->reparent(old_parent,new_parent,m); // this->Data.close(new_parent); // return; // } const GCS::GElement* const_old_parent_element = this->Data->read(old_parent); Q_CHECK_PTR(const_old_parent_element); if (!const_old_parent_element) return; if (!const_old_parent_element->getObject()->hasForm()) return; //@todo: if parent has no form, traverse up until a parent with form is found const GCS::GForm* f_old_parent = const_old_parent_element->getObject()->getForm(); double old_parent_radius_min = f_old_parent->getRadiusMin(); double farthest_distance_current = f->Position.length() + f->getRadiusMax(); // qDebug(QString("reparenting, old parent radius min: %1, this max distance: %2").arg(QString::number(old_parent_radius_min),QString::number(farthest_distance_current))); if (f_old_parent->getRadiusMin() < f->Position.length() + f->getRadiusMax()) { const GCS::GElementID& new_parent = const_old_parent_element->getObject()->getParent(); if (new_parent != old_parent) { GCS::GMatrix44 m = GCS::GMatrix44::createScaleMatrix(f_old_parent->Ellipsoid); m.multiply(GCS::GMatrix44::createRotationAroundX(f_old_parent->Rotation.x)); m.multiply(GCS::GMatrix44::createRotationAroundY(f_old_parent->Rotation.y)); m.multiply(GCS::GMatrix44::createRotationAroundZ(f_old_parent->Rotation.z)); m.multiply(GCS::GMatrix44::createTranslationMatrix(f_old_parent->Position)); qDebug(QString("reparenting element %1 from old parent %2 to new parent %3").arg(QString::number(id.getID()),QString::number(old_parent.getID()),QString::number(new_parent.getID()))); element->reparent(old_parent,new_parent,m); } } //@todo IMPORTANT: check if element enters a sibling! } } void GweController::removeElementWithNoEnergyLeft(const GCS::GEnergy& changedEnergy) { if (changedEnergy.amount()>0) return; const QObject* sender_generic = sender(); Q_ASSERT(sender_generic->inherits("GCS::GElement")); //sender MUST be a GElement; if (!sender_generic->inherits("GCS::GElement")) return; const GCS::GElement* const_element = (const GCS::GElement*)sender_generic; Q_CHECK_PTR(const_element->getObject()); qDebug(QString("removing element %1 because energy amount is 0").arg(const_element->getElementID().getID())); Data->postDelete(const_element->getElementID()); } void GweController::shutdown() { qWarning("Shutting down world engine"); this->Data->shutdown(); QTimer::singleShot(2000,this,SIGNAL(quit())); } }