Example #1
0
void DESPOT::Update(VNode* vnode) {
	if (vnode->IsLeaf()) {
		return;
	}

	double lower = vnode->default_move().value;
	double upper = vnode->default_move().value;
	double utility_upper = Globals::NEG_INFTY;

	for (int action = 0; action < vnode->children().size(); action++) {
		QNode* qnode = vnode->Child(action);

		lower = max(lower, qnode->lower_bound());
		upper = max(upper, qnode->upper_bound());
		utility_upper = max(utility_upper, qnode->utility_upper_bound);
	}

	if (lower > vnode->lower_bound()) {
		vnode->lower_bound(lower);
	}
	if (upper < vnode->upper_bound()) {
		vnode->upper_bound(upper);
	}
	if (utility_upper < vnode->utility_upper_bound) {
		vnode->utility_upper_bound = utility_upper;
	}
}
Example #2
0
File: qnode.cpp Project: RSATom/Qt
void QNodePrivate::propertyChanged(int propertyIndex)
{
    // Bail out early if we can to avoid the cost below
    if (m_blockNotifications)
        return;

    Q_Q(QNode);

    const QMetaProperty property = q->metaObject()->property(propertyIndex);

    const QVariant data = property.read(q);
    if (data.canConvert<QNode*>()) {
        QNode *node = data.value<QNode*>();

        // Ensure the node has issued a node creation change. We can end
        // up here if a newly created node with a parent is immediately set
        // as a property on another node. In this case the deferred call to
        // _q_postConstructorInit() will not have happened yet as the event
        // loop will still be blocked. So force it here and we catch this
        // eventuality in the _q_postConstructorInit() function so that we
        // do not repeat the creation and new child scene change events.
        if (node)
            QNodePrivate::get(node)->_q_postConstructorInit();

        const QNodeId id = node ? node->id() : QNodeId();
        notifyPropertyChange(property.name(), QVariant::fromValue(id));
    } else {
        notifyPropertyChange(property.name(), data);
    }
}
Example #3
0
int main(int argc, char *argv[]){
    
    int numThreads = atoi(argv[1]);
    threshold = atoi(argv[2]);
    int levels = atoi(argv[3]);
    int * participantsAtLevel = (int * ) malloc(levels);
    for (int i = 0; i < levels; i++) {
        participantsAtLevel[i] = atoi(argv[4 + i]);
    }
    
    omp_set_num_threads(numThreads);
    
    int numIter = 144 * (0x4ffff) / numThreads;

        //int levels = 4;
        //int participantsAtLevel[] = {2, 4, 8, 16};
        //omp_set_num_threads(16);
        //int levels = 2;
        //int participantsAtLevel[] = {12, 36};
        //omp_set_num_threads(36);
    
    //int levels = 2;
    //int participantsAtLevel[] = {2, 4};
    //omp_set_num_threads(4);
    
    struct timeval start;
    struct timeval end;
    uint64_t elapsed;
    
#pragma omp parallel
    {
        int tid = omp_get_thread_num();
        int size = omp_get_num_threads();
        HMCS * hmcs = LockInit(tid, size, levels, participantsAtLevel);
        
        if(tid == 0)
            gettimeofday(&start, 0);
        
        QNode me;
        for(int i = 0; i < numIter; i++) {
            me.Reuse();
            Acquire(hmcs, &me);
            //printf("Acquired %d!\n", tid);
//#define VALIDATE
#ifdef VALIDATE
            int lvar = var;
            var ++;
            assert(var == lvar + 1);
#endif
            Release(hmcs, &me);
            
        }
    }
    gettimeofday(&end, 0);
    elapsed = TIME_SPENT(start, end);
    double throughPut = (numIter * numThreads * 144 * 0x4ffffL) * 100000.0 / elapsed;
    std::cout<<"\n Throughput = " << throughPut;
    return 0;
}
Example #4
0
ValuedAction DESPOT::Evaluate(VNode* root, vector<State*>& particles,
	RandomStreams& streams, POMCPPrior* prior, const DSPOMDP* model) {
	double value = 0;

	for (int i = 0; i < particles.size(); i++) {
		particles[i]->scenario_id = i;
	}

	for (int i = 0; i < particles.size(); i++) {
		State* particle = particles[i];
		VNode* cur = root;
		State* copy = model->Copy(particle);
		double discount = 1.0;
		double val = 0;
		int steps = 0;

		while (!streams.Exhausted()) {
			int action =
				(cur != NULL) ?
					OptimalAction(cur).action : prior->GetAction(*copy);

			assert(action != -1);

			double reward;
			OBS_TYPE obs;
			bool terminal = model->Step(*copy, streams.Entry(copy->scenario_id),
				action, reward, obs);

			val += discount * reward;
			discount *= Discount();

			if (!terminal) {
				prior->Add(action, obs);
				streams.Advance();
				steps++;

				if (cur != NULL && !cur->IsLeaf()) {
					QNode* qnode = cur->Child(action);
					map<OBS_TYPE, VNode*>& vnodes = qnode->children();
					cur = vnodes.find(obs) != vnodes.end() ? vnodes[obs] : NULL;
				}
			} else {
				break;
			}
		}

		for (int i = 0; i < steps; i++) {
			streams.Back();
			prior->PopLast();
		}

		model->Free(copy);

		value += val;
	}

	return ValuedAction(OptimalAction(root).action, value / particles.size());
}
Example #5
0
// Main Thread
void QPostman::notifyFrontendNode(const QSceneChangePtr &e)
{
    Q_D(QPostman);
    if (!e.isNull() && d->m_scene != nullptr) {
        QNode *n = d->m_scene->lookupNode(e->subjectId());
        if (n != nullptr)
            n->sceneChangeEvent(e);
    }
}
Example #6
0
double AEMS::AEMS2Likelihood(QNode* qnode) {
	VNode* vnode = qnode->parent();
	QNode* qstar = NULL;
	for (int action = 0; action < vnode->children().size(); action++) {
		QNode* child = vnode->Child(action);

		if (qstar == NULL || child->upper_bound() > qstar->upper_bound())
			qstar = child;
	}

	return qstar == qnode;
}
Example #7
0
Queue::~Queue()
{
  if (!first) return;

  QNode *ce = first;
  while (ce->has_next()) {
    QNode *tmp = ce;
    ce = ce->next();
    delete tmp;
  }
  delete ce;
}
Example #8
0
int VNode::PolicyTreeSize() const {
	if (children_.size() == 0)
		return 0;

	QNode* best = NULL;
	for (int a = 0; a < children_.size(); a++) {
		QNode* child = children_[a];
		if (best == NULL || child->lower_bound() > best->lower_bound())
			best = child;
	}
	return best->PolicyTreeSize();
}
Example #9
0
/*!
    Returns a pointer to the parent.
 */
QFrameGraphNode *QFrameGraphNode::parentFrameGraphNode() const
{
    QFrameGraphNode *parentFGNode = nullptr;
    QNode *parentN = parentNode();

    while (parentN) {
        if ((parentFGNode = qobject_cast<QFrameGraphNode *>(parentN)) != nullptr)
            break;
        parentN = parentN->parentNode();
    }
    return parentFGNode;
}
void QuadTreeObject::upDateQuadTree(RECT screen)
{
	//this->upDateQNode(this->root);

	//duyet listObjectInMap. Nhung Object nao ko ton tai thi xoa di
	std::hash_map< int, ObjectGame*>::iterator it = this->mapObject.listObjectInMap.begin();
	ObjectGame* obj = NULL;
	while (it != this->mapObject.listObjectInMap.end())
	{
		obj = it->second;
		if (!obj->_isALive)
		{
			//xoa object ra khoi quadtree
			this->eraseObject(it->first);

			//xoa khoi listObj
			it = this->mapObject.listObjectInMap.erase(it);
			//xoa IDHashMap cua Object ra khoi Quadtree
			//it++;
		
		}else
		{
			//neu van thuoc trong man hinh ma la enemy thi kiem tra no con va cham voi node chua no ko
			if (obj->className() == TagClassName::getInstance()->tagEnemy)
			{
				//tim nhung node co chua no
				QNode* node = NULL;
				//duyet tat ca node. 
				for (std::hash_map< int, QNode*>::iterator itNode = this->listQNode.begin(); itNode != listQNode.end();)
				{
					node = itNode->second;
					int ID_HashMapOfObj = it->first;
					if (node->findIDObj(it->first))
					{
						//neu node co chua enemy thi kiem tra enemy co con nam trong do ko? neu ko thi xoa va add vao lai
						if (!QNode::isBound(node->rect, obj->getRect()))
						{
							//neu node ko con chua obj nua
							this->eraseObject(it->first);
							
							//sau do add vao lai node root
							this->addObjectToNode(this->root, obj, it->first);
						}
					}
					itNode++;
				}
			}

			it ++;
		}

	}
}
Example #11
0
VNode* DESPOT::Trial(VNode* root, RandomStreams& streams,
	ScenarioLowerBound* lower_bound, ScenarioUpperBound* upper_bound,
	const DSPOMDP* model, History& history, SearchStatistics* statistics) {
	VNode* cur = root;

	int hist_size = history.Size();

	do {
		if (statistics != NULL
			&& cur->depth() > statistics->longest_trial_length) {
			statistics->longest_trial_length = cur->depth();
		}

		ExploitBlockers(cur);

		if (Gap(cur) == 0) {
			break;
		}

		if (cur->IsLeaf()) {
			double start = clock();
			Expand(cur, lower_bound, upper_bound, model, streams, history);

			if (statistics != NULL) {
				statistics->time_node_expansion += (double) (clock() - start)
					/ CLOCKS_PER_SEC;
				statistics->num_expanded_nodes++;
				statistics->num_tree_particles += cur->particles().size();
			}
		}

		double start = clock();
		QNode* qstar = SelectBestUpperBoundNode(cur);
		VNode* next = SelectBestWEUNode(qstar);

		if (statistics != NULL) {
			statistics->time_path += (clock() - start) / CLOCKS_PER_SEC;
		}

		if (next == NULL) {
			break;
		}

		cur = next;
		history.Add(qstar->edge(), cur->edge());
	} while (cur->depth() < Globals::config.search_depth && WEU(cur) > 0);

	history.Truncate(hist_size);

	return cur;
}
Example #12
0
void VNode::Free(const DSPOMDP& model) {
	for (int i = 0; i < particles_.size(); i++) {
		model.Free(particles_[i]);
	}

	for (int a = 0; a < children().size(); a++) {
		QNode* qnode = Child(a);
		map<OBS_TYPE, VNode*>& children = qnode->children();
		for (map<OBS_TYPE, VNode*>::iterator it = children.begin();
			it != children.end(); it++) {
			it->second->Free(model);
		}
	}
}
Example #13
0
QNode* DESPOT::SelectBestUpperBoundNode(VNode* vnode) {
	int astar = -1;
	double upperstar = Globals::NEG_INFTY;
	for (int action = 0; action < vnode->children().size(); action++) {
		QNode* qnode = vnode->Child(action);

		if (qnode->upper_bound() > upperstar) {
			upperstar = qnode->upper_bound();
			astar = action;
		}
	}
	assert(astar >= 0);
	return vnode->Child(astar);
}
Example #14
0
ValuedAction DESPOT::OptimalAction(VNode* vnode) {
	ValuedAction astar(-1, Globals::NEG_INFTY);
	for (int action = 0; action < vnode->children().size(); action++) {
		QNode* qnode = vnode->Child(action);
		if (qnode->lower_bound() > astar.value) {
			astar = ValuedAction(action, qnode->lower_bound());
		}
	}

	if (vnode->default_move().value > astar.value) {
		astar = vnode->default_move();
	}

	return astar;
}
const char *QTextContainer::getText(QAbstractPlayer *ctx) {
	// Need to deal with locales
	if (!subnodes) return NULL;

	for (int i=0;i<subnodeCount;i++) {
		QNode *n = subnodes[i];
		if (n->getType() == NODETYPE_TEXT) {
			QText *t = (QText*)n;
			const char *str = t->getText();
			return ctx ? ctx->replaceVariables(str) : str;
		}
	}
	
	return NULL;
}
Example #16
0
Word* Queue::pop()
{
  if (first != NULL) {
    QNode *tmp = first;
    if (first->has_next()) {
      first = first->next();
    } else {
      first = NULL;
      last = NULL;
    }
    var_size--;
    return tmp->get_word();
  } else {
    return NULL;
  }
}
Example #17
0
void QVisualBinding::Draw()
{
      if ( dflags&bDrawNodes ) {
	QNode *n;
	for (n=doc->nodes; n; n=n->next)
		n->draw();
      }
      if ( dflags&bDrawComps ) {
	QComponent *c;
	for (c=doc->comps; c; c=c->next) {
	  c->draw();
	  if (c==selectc) // Dibujar seleccion
	    gui_drawrect( c->r, EGA_RED );
	}
      }
}
void QTransferFunction::AddNode(const QNode& Node)
{
	// Add the node to the list
	m_Nodes.append(Node);

	// Cache node
	QNode& CacheNode = m_Nodes.back();

	// Sort the transfer function nodes based on intensity
	qSort(m_Nodes.begin(), m_Nodes.end(), CompareNodes);

	// Update ID's
	for (int i = 0; i < m_Nodes.size(); i++)
		m_Nodes[i].m_ID = i;

	// Update ranges
	UpdateNodeRanges();

	// Notify us when the node changes
	connect(&CacheNode, SIGNAL(NodeChanged(QNode*)), this, SLOT(OnNodeChanged(QNode*)));

	for (int i = 0; i < m_Nodes.size(); i++)
	{
		if (Node.GetIntensity() == m_Nodes[i].GetIntensity())
			SetSelectedNode(&m_Nodes[i]);
	}

	// Inform others that the transfer function has changed
	emit Changed();

	if (!signalsBlocked())
		Log("Inserted node", "layer-select-point");
}
//处理客户离开事件,是要首先计算该客户在银行逗留的时间,然后从队列中删除该客户之后查看队列是否为空,若不为空则设定一个新的对头客户离开事件
void customer_departure()
{
	cout << "======================一位客户离开======================" << endl;
	//处理客户离开事件,就是Ntype > 0
	int i = en.getNType();	//得到事件的类型
	q[i]->deQueue();	//吧排头删除,表示排头客户离开
	TotalTime += en.getOccurTime() - customer.getArrivalTime();	//这个是客户逗留事件,不包含处理业务的时间,这个计算的也就是客户等待时间
	//如果走了这个客户,队列不是空,则设定一个新的排头客户
	if (q[i]->length() != 0)
	{
		Event e;
		customer = q[i]->getHead(); //得到排头的客户
		e.setOccurTime(en.getOccurTime() + customer.getDuration()); //客户开始办理业务时间+客户使用时间,也就是到了客户离开时间
		e.setNType(i);	//那个窗口的
		ev.insert(e);
	}
}
void QuadTreeObject::eraseObject(int IDinMap)
{
	QNode* node = NULL;
	//duyet tat ca node. 
	for (std::hash_map< int, QNode*>::iterator it = this->listQNode.begin(); it != listQNode.end();)
	{
		node = it->second;
		if (node->eraseIDObj(IDinMap))
		{
			//xoa thanh cong
		}
		it ++;
	}
	
	//xoa trong list Object
	//this->mapObject.eraseObject(IDinMap);
}
Example #21
0
void VNode::PrintPolicyTree(int depth, ostream& os) {
	if (depth != -1 && this->depth() > depth)
		return;

	vector<QNode*>& qnodes = children();
	if (qnodes.size() == 0) {
		int astar = this->default_move().action;
		os << this << "-a=" << astar << endl;
	} else {
		QNode* qstar = NULL;
		for (int a = 0; a < qnodes.size(); a++) {
			QNode* qnode = qnodes[a];
			if (qstar == NULL || qnode->lower_bound() > qstar->lower_bound()) {
				qstar = qnode;
			}
		}

		os << this << "-a=" << qstar->edge() << endl;

		vector<OBS_TYPE> labels;
		map<OBS_TYPE, VNode*>& vnodes = qstar->children();
		for (map<OBS_TYPE, VNode*>::iterator it = vnodes.begin();
			it != vnodes.end(); it++) {
			labels.push_back(it->first);
		}

		for (int i = 0; i < labels.size(); i++) {
			if (depth == -1 || this->depth() + 1 <= depth) {
				os << repeat("|   ", this->depth()) << "| o=" << labels[i]
					<< ": ";
				qstar->Child(labels[i])->PrintPolicyTree(depth, os);
			}
		}
	}
}
Example #22
0
VNode* DESPOT::Prune(VNode* vnode, int& pruned_action, double& pruned_value) {
	vector<State*> empty;
	VNode* pruned_v = new VNode(empty, vnode->depth(), NULL,
		vnode->edge());

	vector<QNode*>& children = vnode->children();
	int astar = -1;
	double nustar = Globals::NEG_INFTY;
	QNode* qstar = NULL;
	for (int i = 0; i < children.size(); i++) {
		QNode* qnode = children[i];
		double nu;
		QNode* pruned_q = Prune(qnode, nu);

		if (nu > nustar) {
			nustar = nu;
			astar = qnode->edge();

			if (qstar != NULL) {
				delete qstar;
			}

			qstar = pruned_q;
		} else {
			delete pruned_q;
		}
	}

	if (nustar < vnode->default_move().value) {
		nustar = vnode->default_move().value;
		astar = vnode->default_move().action;
		delete qstar;
	} else {
		pruned_v->children().push_back(qstar);
		qstar->parent(pruned_v);
	}

	pruned_v->lower_bound(vnode->lower_bound()); // for debugging
	pruned_v->upper_bound(vnode->upper_bound());

	pruned_action = astar;
	pruned_value = nustar;

	return pruned_v;
}
Example #23
0
bool Queue::add(Word in, int place) 
{
  QNode *node = new QNode(new Word(in));
  
  if (size() < place || place < 0) {
    return false;
  }
 
  if (place == 0) {
    if (first != NULL){
      node->set_next(first);
      first = node;
    } 
    if (first == NULL) {
      first = node;
      last = first;
    }
    var_size++;
    return true;
  }
  
  QNode *current = first;
  
  for(; place > 1; place--) {
    current = current->next();
  }
  
  node->set_next(current->next());
  current->set_next(node);
  var_size++;
  
  return true;
}
Example #24
0
/** Carga el componente. El parser llama a esta funcion una vez de
 * haver leido el token "comp" y su nombre
 * Formato de texto plano:
comp "nombre" [x] [y] [w] [h]
...parametros de los derivados... (o nada)
pin "nombre" in/out [idn] [idm]
...
endcomo
 */
bool QComponent::load( FILE *f )
{
  if ( fscanf( f, "%d%d%d%d", &r.a.x, &r.a.y, &r.b.x, &r.b.y ) != 4 )
    return false;
  r.b.x += r.a.x;
  r.b.y += r.a.y;

  if ( !extraLoad( f ) )
    return false;

  char b[32];
  while ( !feof( f ) ) {
    char pinName[32];
    int pio, idn, idm;
    bool pointIsNiple;
    if ( fscanf( f, "%s", b ) != 1 )
      return false;
    if ( strcmp( b, "pin" ) == 0 ) {
      if ( !getString( f, pinName ) )
	return false;
      if ( fscanf( f, "%s%d%d", b, &idn, &idm ) != 3 )
	return false;

      if ( strcmp( b, "in" ) == 0 )
	pio = pinIn;
      else if ( strcmp( b, "out" ) == 0 )
	pio = pinOut;
      else
	return false;

      QNode *pn = doc->getNode( idn );
      if ( !pn )
	return false;
      QNodePoint *pm = pn->getPoint( idm );
      if ( !pm )
	return false;
      insertPin( new QPin( pio, pn, pm, pinName ) );
    } else if ( strcmp( b, "endcomp" ) == 0 )
      return true;
    else
      return false;
  }
  return false; // Unexpected EOF
}
Example #25
0
void AEMS::Update(VNode* vnode) {
	if (vnode->IsLeaf())
		return;

	double lower = Globals::NEG_INFTY;
	double upper = Globals::NEG_INFTY;

	for (int action = 0; action < vnode->children().size(); action++) {
		QNode* qnode = vnode->Child(action);

		lower = max(lower, qnode->lower_bound());
		upper = max(upper, qnode->upper_bound());
	}

	if (lower > vnode->lower_bound())
		vnode->lower_bound(lower);
	if (upper < vnode->upper_bound())
		vnode->upper_bound(upper);
}
void customer_arrived()
{
	cout << "======================一位客户到达======================" << endl;
	//处理客户到达事件,en.NType=0
	QNode *qe = new QNode();	//客户到达时间,处理业务所需要的时间,指向下一个对象
	int durtime, intertime;	//一个是处理业务所需要的时间,一个是下一个客户到达的所需时间

	++CustomerNum;	//人数++

	//参数两个随机数,代表处理业务需要的时间,下一个客户到达的时间
	durtime = rand() % (MAX_TIME + 1);	//这个额是[0 ~ MAX_TIME(30)]
	intertime = rand() % (INTERVAL + 1);	//这个是下一个客户进入银行要等待的时间[0~INTERVAL(5)]

	//如果银行没有关门,我们要产生下一个事件到达
	int t = en.getOccurTime() + intertime;
	if (t < closeTime)
	{
		//插入事件表下一个事件
		Event ei;
		ei.setOccurTime(t);
		ei.setNType(0);
		ev.insert(ei);
	}

	int i = min_queue(q);	//求得最短的队列,注意我们有1到4队列,没有0队列
	//吧事件插入到最短的队列中
	//首先我们的事件发生时间(事件到达时间)和执行时间
	qe->setArrivalTime(en.getOccurTime());
	qe->setDuration(durtime);	//时间的执行时间
	q[i]->enQueue(qe);	//吧qe插入到链表中

	//判断我们插入的队列是不是长度是1,如果是代表在插入之前这个窗口是空的,这个的作用
	//客户离开事件,是要首先计算该客户在银行逗留的时间,然后从队列中删除该客户之后查看队列是否为空,若不为空则设定一个新的对头客户离开事件
	en.setOccurTime(en.getOccurTime() + durtime);	//设置新的时间到达事件
	en.setNType(i);	//0代表新的客户到达,1是1号窗口客户离开,2是2号窗口客户离开,3是3号窗口客户离开,4是。。。,这里是客户到达事件,所以是0
	if (q[i]->length() == 1)
	{
		//吧第i个队列的离开事件插入事件表,等会用来计算窗口的客户总时间
		ev.insert(en);
	}

}//customer_arrived()
Example #27
0
void AEMS::Backup(VNode* vnode) {
	int iter = 0;
	logd << "- Backup " << vnode << " at depth " << vnode->depth() << endl;
	while (true) {
		logd << " Iter " << (iter++) << " " << vnode << endl;

		Update(vnode);
		logd << " Updated vnode " << vnode << endl;

		QNode* parentq = vnode->parent();
		if (parentq == NULL)
			break;

		Update(parentq);
		logd << " Updated Q-node to (" << parentq->lower_bound() << ", "
			<< parentq->upper_bound() << ")" << endl;

		vnode = parentq->parent();
	}
	logd << "* Backup complete!" << endl;
}
//------------------------------------------------------------------------------
// QContactListener
//------------------------------------------------------------------------------
void QContactListener::BeginContact(b2Contact* pContact)
{
    QNode* pNodeA = (QNode*)pContact->GetFixtureA()->GetBody()->GetUserData();
    QNode* pNodeB = (QNode*)pContact->GetFixtureB()->GetBody()->GetUserData();

    lua_gettop(g_L);

    LUA_EVENT_PREPARE("collision"); // On stack: event
    LUA_EVENT_SET_STRING("phase", "began");
    LUA_EVENT_SET_TOLUA_PTR("nodeA", (void*)pNodeA, pNodeA->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("nodeB", (void*)pNodeB, pNodeB->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("target", (void*)pNodeA, pNodeA->_getToLuaClassName());

    // World point of collision... is this correct?
    b2WorldManifold wm;
    pContact->GetWorldManifold(&wm);
    float dx = g_Sim->scaleP2D(wm.points[0].x);
    float dy = g_Sim->scaleP2D(wm.points[0].y);
    LUA_EVENT_SET_NUMBER("x", dx);
    LUA_EVENT_SET_NUMBER("y", dy);

    lua_getfield(g_L, LUA_GLOBALSINDEX, "handleNodeEvent");
	lua_pushvalue(g_L, -2); // On stack: handleNodeEvent(event)
    tolua_pushusertype(g_L, (void*)pNodeA, pNodeA->_getToLuaClassName()); // On stack: handleNodeEvent(event, node)

    lua_gettop(g_L);
    int s = lua_pcall(g_L, 2, 1, 0);
    lua_gettop(g_L);
    LUA_REPORT_ERRORS(g_L, s);
    lua_gettop(g_L);
    lua_pop(g_L, 3);
    lua_gettop(g_L);
}
//------------------------------------------------------------------------------
void QContactListener::PostSolve(b2Contact* pContact, const b2ContactImpulse* pImpulse)
{
    QNode* pNodeA = (QNode*)pContact->GetFixtureA()->GetBody()->GetUserData();
    QNode* pNodeB = (QNode*)pContact->GetFixtureB()->GetBody()->GetUserData();

    LUA_EVENT_PREPARE("collisionPostSolve"); // On stack: event
    LUA_EVENT_SET_STRING("phase", "ended");
    LUA_EVENT_SET_TOLUA_PTR("nodeA", (void*)pNodeA, pNodeA->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("nodeB", (void*)pNodeB, pNodeB->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("target", (void*)pNodeA, pNodeA->_getToLuaClassName());
    QContact con(pContact);
    LUA_EVENT_SET_TOLUA_PTR("contact", (void*)&con, "quick::QPhysics::Contact");

    // Force (impulse)
    float f = g_Sim->scaleP2D(pImpulse->normalImpulses[0]);
    LUA_EVENT_SET_NUMBER("impulse", f);

    lua_getfield(g_L, LUA_GLOBALSINDEX, "handleNodeEvent");
	lua_pushvalue(g_L, -2); // On stack: handleNodeEvent(event)
    tolua_pushusertype(g_L, (void*)pNodeA, pNodeA->_getToLuaClassName()); // On stack: handleNodeEvent(event, node)

    int s = lua_pcall(g_L, 2, 1, 0);
    LUA_REPORT_ERRORS(g_L, s);
    lua_pop(g_L, 2);

    lua_gettop(g_L);
}
//------------------------------------------------------------------------------
void QContactListener::EndContact(b2Contact* pContact)
{
    QNode* pNodeA = (QNode*)pContact->GetFixtureA()->GetBody()->GetUserData();
    QNode* pNodeB = (QNode*)pContact->GetFixtureB()->GetBody()->GetUserData();

    lua_gettop(g_L);

    LUA_EVENT_PREPARE("collision"); // On stack: event
    LUA_EVENT_SET_STRING("phase", "ended");
    LUA_EVENT_SET_TOLUA_PTR("nodeA", (void*)pNodeA, pNodeA->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("nodeB", (void*)pNodeB, pNodeB->_getToLuaClassName());
    LUA_EVENT_SET_TOLUA_PTR("target", (void*)pNodeA, pNodeA->_getToLuaClassName());

    lua_getfield(g_L, LUA_GLOBALSINDEX, "handleNodeEvent");
	lua_pushvalue(g_L, -2); // On stack: handleNodeEvent(event)
    tolua_pushusertype(g_L, (void*)pNodeA, pNodeA->_getToLuaClassName()); // On stack: handleNodeEvent(event, node)

    lua_gettop(g_L);
    int s = lua_pcall(g_L, 2, 1, 0);
    lua_gettop(g_L);
    LUA_REPORT_ERRORS(g_L, s);
    lua_gettop(g_L);
    lua_pop(g_L, 3);
    lua_gettop(g_L);
}