/***************************************************************************
* Copyright (C) 2003-2004 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 "GElement.h"
#include "GElementID.h"
#include "GObject.h"
#include "GElementInfluence.h"
#include "GAgent.h"
#include "GEnergy.h"
#include "GForm.h"
#include "GVector3.h"
#include "GMatrix44.h"
#include <qmutex.h>
#include <exception>
using namespace std;
namespace GCS
{
// ###################### PUBLIC ##################
GElement::GElement(GObject* object, const QDateTime& park_time)
: Object(object),
ParkTime(park_time)
{
}
GElement::~GElement()
{
//stop all running agents
emit park();
QValueList<GAgent*>::iterator it;
for (it = Agents.begin(); it != Agents.end(); ++it)
{
(*it)->wait(); //wait until thread is stopped before deleting
(*it)->deleteLater(); //post a delete event (the event loop will delete it)
}
Q_CHECK_PTR(Object);
if (Object)
delete Object;
}
const GElementID& GElement::getElementID() const
{
Q_CHECK_PTR(Object);
if (Object)
return Object->getID();
else
throw exception();
}
QDateTime GElement::getParkTime() const
{
return this->ParkTime;
}
bool GElement::isParked()
{
//check all agents
QValueList<GAgent*>::iterator it;
for (it = this->Agents.begin(); it != this->Agents.end(); ++it)
{
if ((*it)->running()) //directly accesses the QThread method
return false;
}
return true; //when no running agent was found
}
QValueList<const GAgent*> GElement::getAgents() const
{
QValueList<const GAgent*> list;
QValueList<GAgent*>::const_iterator it;
for (it = this->Agents.begin(); it != this->Agents.end(); ++it)
{
list.append(*it);
}
return list;
}
const GObject* GElement::getObject() const
{
Q_CHECK_PTR(Object);
if (Object)
return Object;
else
throw exception();
}
// ################# PUBLIC SLOTS ####################
void GElement::receiveInfluence(const GCS::GElementInfluence& influence)
{
QTime t(QTime::currentTime());
emit forwardInfluenceInternal(influence);
//add the energy of the influence to own energy
if (Object)
{
if (Object->hasEnergy())
{
GEnergy* e = Object->getEnergy();
QMutexLocker m(e);
e->put(influence.Energy);
}
}
if (t.elapsed() > 100)
{
qWarning("Internal influence processing time longer than 100 milliseconds, this is bad agent design!!!");
}
emit influenceReceived(influence);
if (t.elapsed() > 100)
{
qWarning("External influence processing time longer than 100 milliseconds, this is bad agent design!!!");
}
}
void GElement::reparent(const GCS::GElementID& old_parent, const GCS::GElementID& new_parent, const GCS::GMatrix44& transformation)
{
if (Object)
{
if (old_parent != Object->getParent())
qWarning(QString("INCONSISTENCY DETECTED: Reparenting element %1, but old parent doesn't apply!").arg(old_parent.getID()));
Object->reparent(new_parent);
emit this->notifyReparentingInternal(old_parent,new_parent,transformation);
if (this->Object->hasForm())
{
GCS::GForm* f = Object->getForm();
QMutexLocker lock(f);
f->Position = transformation.transform(f->Position);
f->Rotation = transformation.transform(f->Rotation);
}
emit this->parentChanged(this,old_parent,new_parent,transformation);
}
}
void GElement::addAgent(GCS::GAgent* agent)
{
agent->Object = this->Object;
agent->Agents = &this->Agents;
//connect signals from agent
connect(agent,SIGNAL(
sendInfluence(const GCS::GElementID&, const GCS::GElementInfluence&)),
this,SIGNAL(
sendInfluence(const GCS::GElementID&, const GCS::GElementInfluence&)));
connect(agent,SIGNAL(radiateInfluence(const GCS::GElementInfluence&)),
this,SIGNAL(radiateInfluence(const GCS::GElementInfluence&)));
//connect slots from agent
connect(this,SIGNAL(forwardInfluenceInternal(const GCS::GElementInfluence&)),
agent,SLOT(receiveInfluence(const GCS::GElementInfluence&)));
// control stuff (parking, executing)
connect(this,SIGNAL(park()),
agent,SLOT(beginPark()));
// execute is used for "resuming" AND for starting the first time(!)
connect(this,SIGNAL(execute(double)),
agent,SLOT(threadStart(double)));
// data change stuff
connect(this,SIGNAL(notifyReparentingInternal(const GCS::GElementID&, const GCS::GElementID&, const GCS::GMatrix44& )),
agent,SLOT(reparented(const GCS::GElementID&, const GCS::GElementID&, const GCS::GMatrix44& )));
connect(agent,SIGNAL(agentChanged(const GCS::GAgent& )),
this,SIGNAL(agentChanged(const GCS::GAgent& )));
connect(agent,SIGNAL(energyChanged(const GCS::GEnergy& )),
this,SIGNAL(energyChanged(const GCS::GEnergy& )));
connect(agent,SIGNAL(formChanged(const GCS::GForm& )),
this,SIGNAL(formChanged(const GCS::GForm& )));
connect(agent,SIGNAL(childElementCreated(GCS::GElement* )),
this,SIGNAL(childElementCreated(GCS::GElement* )));
connect(agent,SIGNAL(childElementRemoved(const GCS::GElementID& )),
this,SIGNAL(childElementRemoved(const GCS::GElementID& )));
this->Agents.append(agent);
}
void GElement::removeAgent(GCS::GAgent* agent, bool del)
{
//park the agent
agent->beginPark();
//wait until the agent is parked (the agent thread stops)
agent->wait();
agent->Object = NULL;
agent->Agents = NULL;
//disconnect agent
agent->disconnect(this);
this->disconnect(agent);
this->Agents.remove(agent);
if (del)
delete agent;
}
void GElement::parkElement()
{
// qDebug("Parking element " + QString::number(getElementID().getID()));
emit park();
this->ParkTime = QDateTime::currentDateTime();
}
void GElement::executeElement(double seconds_delta_t_offset)
{
// qDebug("Executing element " + QString::number(getElementID().getID()));
QDateTime current = QDateTime::currentDateTime();
double delta_t = (double)(this->ParkTime.secsTo(current)) + seconds_delta_t_offset;
emit execute(delta_t);
}
}
syntax highlighted by Code2HTML, v. 0.9.1