void FPSDeclarativeView::drawForeground(QPainter *p, const QRectF &rect)
{
    QDeclarativeView::drawForeground(p, rect);
    if (m_showFPS) {
        QFont npf("Nokia Pure");
        npf.setPointSize(18);
        p->setPen(Qt::red);
        p->setFont(npf);
        p->drawText(m_fpsRect, Qt::AlignRight, m_fpsMeasured ? "FPS: " + QString::number(m_fps) : "FPS: n/a");
    }
}
void NodeColorSampler::operator()(LidarProcessOctree::Node& node,unsigned int nodeLevel)
	{
	if(node.isLeaf())
		{
		if(node.getNumPoints()>0)
			{
			/* Find all images whose bounding boxes overlap this node: */
			std::vector<Image2D*> nodeImages;
			for(std::vector<Image2D*>::const_iterator iIt=images.begin();iIt!=images.end();++iIt)
				{
				const Image2D::Box& box=(*iIt)->getWorldBox();
				if(box.min[0]-lpo.getOffset()[0]<node.getDomain().getMax()[0]&&box.max[0]-lpo.getOffset()[0]>node.getDomain().getMin()[0]
		  		 &&box.min[1]-lpo.getOffset()[1]<node.getDomain().getMax()[1]&&box.max[1]-lpo.getOffset()[1]>node.getDomain().getMin()[1])
					nodeImages.push_back(*iIt);
				}
			
			/* Page in all found images: */
			imageCacher.requestImages(nodeImages);
			
			/* Assign a color to each LiDAR point in this node: */
			for(unsigned int i=0;i<node.getNumPoints();++i)
				{
				/* Copy the point's original color: */
				colorBuffer[i]=node[i].value;
				
				/* Lookup the point in all images overlapping this node: */
				Geometry::Point<double,3> pos;
				for(int j=0;j<3;++j)
					pos[j]=double(node[i][j]+lpo.getOffset()[j]);
				for(std::vector<Image2D*>::iterator iIt=nodeImages.begin();iIt!=nodeImages.end();++iIt)
					{
					Image2D::SampleResult sr=(*iIt)->getColor(Image2D::Point(pos.getComponents()));
					if(sr.first)
						{
						/* Copy the sample result: */
						for(int j=0;j<3;++j)
							colorBuffer[i][j]=sr.second[j];
						colorBuffer[i][3]=Color::Scalar(255);
						
						++numAssignedColors;
						
						/* Bail out: */
						break;
						}
					}
				}
			}
		}
	else
		{
		/* Get pointers to the node's children and load their color arrays: */
		colorFile.flush();
		for(int childIndex=0;childIndex<8;++childIndex)
			{
			LidarProcessOctree::Node* child=lpo.getChild(&node,childIndex);
			if(child->getNumPoints()>0)
				{
				colorFile.setReadPosAbs(LidarDataFileHeader::getFileSize()+colorDataSize*child->getDataOffset());
				colorFile.read(childColorBuffers[childIndex],child->getNumPoints());
				}
			}
		
		/* Find the direct ancestors of all LiDAR points in this node and copy their color values from the child arrays: */
		for(unsigned int i=0;i<node.getNumPoints();++i)
			{
			/* Find the child node containing this point's ancestor: */
			int pointChildIndex=node.getDomain().findChild(node[i]);
			LidarProcessOctree::Node* pointChild=lpo.getChild(&node,pointChildIndex);
			
			/* Find the point's ancestor: */
			NodePointFinder npf(node[i]);
			lpo.processNodePointsDirected(pointChild,npf);
			if(npf.getFoundPoint()==0)
				{
				/* This is an internal corruption in the octree file. Print a helpful and non-offensive error message: */
				Misc::throwStdErr("Fatal error: Octree file corrupted around position (%f, %f, %f)",node[i][0],node[i][1],node[i][2]);
				}
			
			/* Retrieve the ancestor's color: */
			colorBuffer[i]=childColorBuffers[pointChildIndex][npf.getFoundPoint()-pointChild->getPoints()];
			}
		}
	
	/* Write the node's colors to the color file: */
	colorFile.setWritePosAbs(LidarDataFileHeader::getFileSize()+colorDataSize*node.getDataOffset());
	colorFile.write(colorBuffer,node.getNumPoints());
	
	/* Update the progress counter: */
	++numProcessedNodes;
	if(numProcessedNodes>=nextProgressUpdate)
		{
		int percent=int((numProcessedNodes*100+lpo.getNumNodes()/2)/lpo.getNumNodes());
		std::cout<<"\rAssigning colors... "<<std::setw(3)<<percent<<"%"<<std::flush;
		nextProgressUpdate=((percent+1)*lpo.getNumNodes()-lpo.getNumNodes()/2+99)/100;
		}
	}