static bool ComputeCellStats(	CCLib::ReferenceCloud* subset,
								CCVector3& N,
								CCVector3& C,
								ScalarType& error,
								CCLib::DistanceComputationTools::ERROR_MEASURES errorMeasure)
{
	error = 0;

	if (!subset || subset->size() == 0)
		return false;

	//we compute the gravity center
	CCLib::Neighbourhood Yk(subset);
	C = *Yk.getGravityCenter();

	//we compute the (least square) best fit plane
	const PointCoordinateType* planeEquation = Yk.getLSPlane();
	if (planeEquation)
	{
		N = CCVector3(planeEquation); //normal = first 3 components
		error = CCLib::DistanceComputationTools::ComputeCloud2PlaneDistance(subset, planeEquation, errorMeasure);
	}
	else
	{
		//not enough points?
		N = CCVector3(0,0,0);
	}

	return true;
}
ScalarType FastMarchingForFacetExtraction::addCellToCurrentFacet(unsigned index)
{
	if (!m_currentFacetPoints || !m_initialized || !m_octree || m_gridLevel > CCLib::DgmOctree::MAX_OCTREE_LEVEL)
		return -1;

	PlanarCell* cell = static_cast<PlanarCell*>(m_theGrid[index]);
	if (!cell)
		return -1;

	CCLib::ReferenceCloud Yk(m_octree->associatedCloud());
	if (!m_octree->getPointsInCell(cell->cellCode,m_gridLevel,&Yk,true))
		return -1;

	if (!m_currentFacetPoints->add(Yk))
	{
		//not enough memory?
		return -1;
	}

	//update error
	CCVector3 N,C;
	ScalarType error;
	ComputeCellStats(m_currentFacetPoints,N,C,error,m_errorMeasure);

	return error;
}
unsigned FastMarchingForFacetExtraction::updateFlagsTable(	ccGenericPointCloud* theCloud,
																GenericChunkedArray<1,unsigned char> &flags,
																unsigned facetIndex)
{
	if (!m_initialized || !m_currentFacetPoints)
		return 0;

	unsigned pointCount = m_currentFacetPoints->size();
	for (unsigned k=0; k<pointCount; ++k)
	{
		unsigned index = m_currentFacetPoints->getPointGlobalIndex(k);
		flags.setValue(index,1);

		theCloud->setPointScalarValue(index,static_cast<ScalarType>(facetIndex));
	}

	if (m_currentFacetPoints)
		m_currentFacetPoints->clear(false);

	/*for (size_t i=0; i<m_activeCells.size(); ++i)
	{
		//we remove the processed cell so as to be sure not to consider them again!
		CCLib::FastMarching::Cell* cell = m_theGrid[m_activeCells[i]];
		m_theGrid[m_activeCells[i]] = 0;
		if (cell)
			delete cell;
	}
	//*/
	
	//unsigned pointCount = 0;
	CCLib::ReferenceCloud Yk(m_octree->associatedCloud());
	for (size_t i=0; i<m_activeCells.size(); ++i)
	{
		PlanarCell* aCell = static_cast<PlanarCell*>(m_theGrid[m_activeCells[i]]);
		if (!m_octree->getPointsInCell(aCell->cellCode,m_gridLevel,&Yk,true))
			continue;

		for (unsigned k=0; k<Yk.size(); ++k)
		{
			unsigned index = Yk.getPointGlobalIndex(k);
			assert(flags.getValue(index) == 1);
			//flags.setValue(index,1);			
			//++pointCount;
		}

		m_theGrid[m_activeCells[i]] = 0;
		delete aCell;
	}

	return pointCount;
}
int ccFastMarchingForNormsDirection::init(	ccGenericPointCloud* cloud,
											NormsIndexesTableType* theNorms,
											ccOctree* theOctree,
											unsigned char level)
{
	int result = initGridWithOctree(theOctree, level);
	if (result < 0)
		return result;

	//fill the grid with the octree
	CCLib::DgmOctree::cellCodesContainer cellCodes;
	theOctree->getCellCodes(level,cellCodes,true);

	CCLib::ReferenceCloud Yk(theOctree->associatedCloud());

	while (!cellCodes.empty())
	{
		if (!theOctree->getPointsInCell(cellCodes.back(),level,&Yk,true))
		{
			//not enough memory
			return -1;
		}
		
		//convert the octree cell code to grid position
		Tuple3i cellPos;
		theOctree->getCellPos(cellCodes.back(),level,cellPos,true);

		//convert it to FM cell pos index
		unsigned gridPos = pos2index(cellPos);

		//create corresponding cell
		DirectionCell* aCell = new DirectionCell;
		{
			//aCell->signConfidence = 1;
			aCell->cellCode = cellCodes.back();
			aCell->N = ComputeRobustAverageNorm(&Yk,cloud);
			aCell->C = *CCLib::Neighbourhood(&Yk).getGravityCenter();
		}

		m_theGrid[gridPos] = aCell;

		cellCodes.pop_back();
	}

	m_initialized = true;

	return 0;
}
unsigned ccFastMarchingForNormsDirection::updateResolvedTable(	ccGenericPointCloud* cloud,
																GenericChunkedArray<1,unsigned char> &resolved,
																NormsIndexesTableType* theNorms)
{
	if (!m_initialized || !m_octree || m_gridLevel > CCLib::DgmOctree::MAX_OCTREE_LEVEL)
		return 0;

	CCLib::ReferenceCloud Yk(m_octree->associatedCloud());

	unsigned count = 0;
	for (size_t i=0; i<m_activeCells.size(); ++i)
	{
		DirectionCell* aCell = static_cast<DirectionCell*>(m_theGrid[m_activeCells[i]]);
		if (!m_octree->getPointsInCell(aCell->cellCode,m_gridLevel,&Yk,true))
		{
			//not enough memory
			return 0;
		}

		for (unsigned k=0; k<Yk.size(); ++k)
		{
			unsigned index = Yk.getPointGlobalIndex(k);
			resolved.setValue(index,1);

			const CompressedNormType& norm = theNorms->getValue(index);
			const CCVector3& N = ccNormalVectors::GetNormal(norm);

			//inverse point normal if necessary
			if (N.dot(aCell->N) < 0)
			{
				theNorms->setValue(index,ccNormalVectors::GetNormIndex(-N));
			}

#ifdef QT_DEBUG
			cloud->setPointScalarValue(index,aCell->T);
			//cloud->setPointScalarValue(index,aCell->signConfidence);
			//cloud->setPointScalarValue(index,aCell->scalar);
#endif
			
			++count;
		}
	}

	return count;
}
float FastMarchingForFacetExtraction::computeTCoefApprox(CCLib::FastMarching::Cell* originCell, CCLib::FastMarching::Cell* destCell) const
{
	PlanarCell* oCell = static_cast<PlanarCell*>(originCell);
	PlanarCell* dCell = static_cast<PlanarCell*>(destCell);

	//compute the 'confidence' relatively to the neighbor cell
	//1) it depends on the angle between the current cell's orientation
	//	and its neighbor's orientation (symmetric)
	//2) it depends on whether the neighbor's relative position is
	//	compatible with the current cell orientation (symmetric)
	float orientationConfidence = 0;
	{
		CCVector3 AB = dCell->C - oCell->C;
		AB.normalize();

		float psOri = fabs(static_cast<float>(AB.dot(oCell->N))); //ideal: 90 degrees
		float psDest = fabs(static_cast<float>(AB.dot(dCell->N))); //ideal: 90 degrees
		orientationConfidence = (psOri + psDest)/2; //between 0 and 1 (ideal: 0)
	}

	//add reprojection error into balance
	if (m_useRetroProjectionError && m_octree && oCell->N.norm2() != 0)
	{
		PointCoordinateType theLSQPlaneEquation[4];
		theLSQPlaneEquation[0] = oCell->N.x;
		theLSQPlaneEquation[1] = oCell->N.y;
		theLSQPlaneEquation[2] = oCell->N.z;
		theLSQPlaneEquation[3] = oCell->C.dot(oCell->N);

		CCLib::ReferenceCloud Yk(m_octree->associatedCloud());
		if (m_octree->getPointsInCell(oCell->cellCode,m_gridLevel,&Yk,true))
		{
			ScalarType reprojError = CCLib::DistanceComputationTools::ComputeCloud2PlaneDistance(&Yk,theLSQPlaneEquation,m_errorMeasure);
			if (reprojError >= 0)
				return (1.0f-orientationConfidence) * static_cast<float>(reprojError);
		}
	}

	return (1.0f-orientationConfidence) /** oCell->planarError*/;
}
Exemplo n.º 7
0
int R() {
int SG;
int tu;
int b;
int cbnn;
int fJA;
int Ywh;
int Sd3i;
int U;
int FTe;
;
if (AgC9 > + (Y0V(UnE, 791438648 + cK(517618502, + N_ != Ed() != - (Yk(((883538282)), nBa)), sdDM(kC, (1604897559), ! ! 528836364 / (1815076270) / 1477268768), n), psl, - 126855483))) while (om(AZ)) {
int xF;
int yd;
int xEmV;
int vc;
int m9;
while (2044928990) while (- 644557172 + 1573824677 + 1727264726 < TvAP(1980609521, Jy47, C, 953854953, - WyD(RlhU(LY0), + ipA(G, (Vg((1882502790), (1790689388) == 711715734 / (_) != + ! (134548752)))), nk1(((2078180300)) - + - 1230367323 - gD13, pK38 / 1377998756, m4G(1127784867) > u, (QSs()), 1389625403), 929895424, 895835811 < dW) * - 1339857856) / 2045295101) while (pLb) while (+ 1321345616) return ! 708468611;
(J);
return eUY;
continue;
(bRvz = 1838176344);
r(F + ! 196992386, Gg);
if (1419330106) ! (- (uG)) <= ! 996971325;
 else T((- ! 2092297653 <= AA >= ! 1494541558 == o((! + v7nD))), 1818433226);
}
 else break;
;
;
if (! (! cQ63(1853496451, i(DW9, 988295904 > _Gv, Wlbr, b) / ! ((O(xl))) - - O(+ a_O > 318640956, 1005354893, 167517361) / If, GDD, u, B) * B) + 443946612 + (dN(BFD3(mg <= 1303591176 + hFH2, x) % hch > 1053610009 / RaZ0(ZC7O((720576768)), 124325761, K(! C, 1901412912 * 1202992483, + (+ + e * 389490648), + 1244843051 < (sm = dH), W9(1583501857)), - ! sIs, 1297610228)))) lYAi(1443174874, U8R, + 925787186);
 else continue;
continue;
if (+ ! 329152016 + K2()) continue;
 else ;
continue;
continue;
}
Exemplo n.º 8
0
ccPlane* ccGenericPointCloud::fitPlane(double* rms /*= 0*/)
{
	//number of points
	unsigned count = size();
	if (count<3)
		return 0;

	CCLib::Neighbourhood Yk(this);

	//we determine plane normal by computing the smallest eigen value of M = 1/n * S[(p-µ)*(p-µ)']
	CCLib::SquareMatrixd eig = Yk.computeCovarianceMatrix().computeJacobianEigenValuesAndVectors();

	//invalid matrix?
	if (!eig.isValid())
	{
		//ccConsole::Warning("[ccPointCloud::fitPlane] Failed to compute plane/normal for cloud '%s'",getName());
		return 0;
	}
	eig.sortEigenValuesAndVectors();

	//plane equation
	PointCoordinateType theLSQPlane[4];

	//the smallest eigen vector corresponds to the "least square best fitting plane" normal
	double vec[3];
	eig.getEigenValueAndVector(2,vec);
	//PointCoordinateType sign = (vec[2] < 0.0 ? -1.0 : 1.0);  //plane normal (always with a positive 'Z' by default)
	for (unsigned i=0;i<3;++i)
		theLSQPlane[i]=/*sign*/(PointCoordinateType)vec[i];
	CCVector3 N(theLSQPlane);

	//we also get centroid
	const CCVector3* G = Yk.getGravityCenter();
	assert(G);

	//eventually we just have to compute 'constant' coefficient a3
	//we use the fact that the plane pass through the centroid --> GM.N = 0 (scalar prod)
	//i.e. a0*G[0]+a1*G[1]+a2*G[2]=a3
	theLSQPlane[3] =  G->dot(N);

	//least-square fitting RMS
	if (rms)
	{
		placeIteratorAtBegining();
		*rms = 0.0;
		for (unsigned k=0;k<count;++k)
		{
			double d = (double)CCLib::DistanceComputationTools::computePoint2PlaneDistance(getNextPoint(),theLSQPlane);
			*rms += d*d;
		}
		*rms = sqrt(*rms)/(double)count;
	}

	//we has a plane primitive to the cloud
	eig.getEigenValueAndVector(0,vec); //main direction
	CCVector3 X(vec[0],vec[1],vec[2]); //plane normal
	//eig.getEigenValueAndVector(1,vec); //intermediate direction
	//CCVector3 Y(vec[0],vec[1],vec[2]); //plane normal
	CCVector3 Y = N * X;

	//we eventually check for plane extents
	PointCoordinateType minX=0.0,maxX=0.0,minY=0.0,maxY=0.0;
	placeIteratorAtBegining();
	for (unsigned k=0;k<count;++k)
	{
		//projetion into local 2D plane ref.
		CCVector3 P = *getNextPoint() - *G;
		PointCoordinateType x2D = P.dot(X);
		PointCoordinateType y2D = P.dot(Y);

		if (k!=0)
		{
			if (minX<x2D)
				minX=x2D;
			else if (maxX>x2D)
				maxX=x2D;
			if (minY<y2D)
				minY=y2D;
			else if (maxY>y2D)
				maxY=y2D;
		}
		else
		{
			minX=maxX=x2D;
			minY=maxY=y2D;
		}
	}

	//we recenter plane (as it is not always the case!)
	float dX = maxX-minX;
	float dY = maxY-minY;
	CCVector3 Gt = *G + X * (minX+dX*0.5);
	Gt += Y * (minY+dY*0.5);
	ccGLMatrix glMat(X,Y,N,Gt);

	return new ccPlane(dX,dY,&glMat);
}
Exemplo n.º 9
0
ccPlane* ccPlane::Fit(CCLib::GenericIndexedCloudPersist *cloud, double* rms/*=0*/)
{
    //number of points
    unsigned count = cloud->size();
    if (count < 3)
    {
        ccLog::Warning("[ccPlane::fitTo] Not enough points in input cloud to fit a plane!");
        return 0;
    }

    CCLib::Neighbourhood Yk(cloud);

    //plane equation
    const PointCoordinateType* theLSQPlane = Yk.getLSQPlane();
    if (!theLSQPlane)
    {
        ccLog::Warning("[ccGenericPointCloud::fitPlane] Not enough points to fit a plane!");
        return 0;
    }

    //compute least-square fitting RMS if requested
    if (rms)
    {
        *rms = CCLib::DistanceComputationTools::computeCloud2PlaneDistanceRMS(cloud, theLSQPlane);
    }

    //get the centroid
    const CCVector3* G = Yk.getGravityCenter();
    assert(G);

    //and a local base
    CCVector3 N(theLSQPlane);
    const CCVector3* X = Yk.getLSQPlaneX(); //main direction
    assert(X);
    CCVector3 Y = N * (*X);

    PointCoordinateType minX=0,maxX=0,minY=0,maxY=0;
    cloud->placeIteratorAtBegining();
    for (unsigned k=0; k<count; ++k)
    {
        //projetion into local 2D plane ref.
        CCVector3 P = *(cloud->getNextPoint()) - *G;
        
		PointCoordinateType x2D = P.dot(*X);
        PointCoordinateType y2D = P.dot(Y);

        if (k!=0)
        {
            if (minX < x2D)
                minX = x2D;
            else if (maxX > x2D)
                maxX = x2D;
            if (minY < y2D)
                minY = y2D;
            else if (maxY > y2D)
                maxY = y2D;
        }
        else
        {
            minX = maxX = x2D;
            minY = maxY = y2D;
        }
    }

    //we recenter the plane
    PointCoordinateType dX = maxX-minX;
    PointCoordinateType dY = maxY-minY;
    CCVector3 Gt = *G + *X * (minX + dX*static_cast<PointCoordinateType>(0.5));
    Gt += Y * (minY + dY*static_cast<PointCoordinateType>(0.5));
    ccGLMatrix glMat(*X,Y,N,Gt);

    ccPlane* plane = new ccPlane(dX, dY, &glMat);

    return plane;
}
Exemplo n.º 10
0
void qHPR::doAction()
{
	assert(m_app);
	if (!m_app)
		return;

	const ccHObject::Container& selectedEntities = m_app->getSelectedEntities();
	size_t selNum = selectedEntities.size();
	if (	selNum != 1
		||	!selectedEntities.front()->isA(CC_TYPES::POINT_CLOUD))
	{
		m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}

	ccPointCloud* cloud = static_cast<ccPointCloud*>(selectedEntities[0]);

	ccGLWindow* win = m_app->getActiveGLWindow();
	if (!win)
	{
		m_app->dispToConsole("No active window!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}

	//display parameters
	const ccViewportParameters& params =  win->getViewportParameters();
	if (!params.perspectiveView)
	{
		m_app->dispToConsole("Perspective mode only!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}

	ccHprDlg dlg(m_app->getMainWindow());
	if (!dlg.exec())
		return;

	//progress dialog
	ccProgressDialog progressCb(false,m_app->getMainWindow());

	//unique parameter: the octree subdivision level
	int octreeLevel = dlg.octreeLevelSpinBox->value();
	assert(octreeLevel >= 0 && octreeLevel <= CCLib::DgmOctree::MAX_OCTREE_LEVEL);

	//compute octree if cloud hasn't any
	ccOctree::Shared theOctree = cloud->getOctree();
	if (!theOctree)
	{
		theOctree = cloud->computeOctree(&progressCb);
		if (theOctree && cloud->getParent())
		{
			m_app->addToDB(cloud->getOctreeProxy());
		}
	}

	if (!theOctree)
	{
		m_app->dispToConsole("Couldn't compute octree!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		return;
	}

	CCVector3d viewPoint = params.cameraCenter;
	if (params.objectCenteredView)
	{
		CCVector3d PC = params.cameraCenter - params.pivotPoint;
		params.viewMat.inverse().apply(PC);
		viewPoint = params.pivotPoint + PC;
	}

	//HPR
	CCLib::ReferenceCloud* visibleCells = 0;
	{
		QElapsedTimer eTimer;
		eTimer.start();

		CCLib::ReferenceCloud* theCellCenters = CCLib::CloudSamplingTools::subsampleCloudWithOctreeAtLevel(	cloud,
																											static_cast<unsigned char>(octreeLevel),
																											CCLib::CloudSamplingTools::NEAREST_POINT_TO_CELL_CENTER,
																											&progressCb,
																											theOctree.data());
		if (!theCellCenters)
		{
			m_app->dispToConsole("Error while simplifying point cloud with octree!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
			return;
		}

		visibleCells = removeHiddenPoints(theCellCenters,viewPoint,3.5);
	
		m_app->dispToConsole(QString("[HPR] Cells: %1 - Time: %2 s").arg(theCellCenters->size()).arg(eTimer.elapsed()/1.0e3));

		//warning: after this, visibleCells can't be used anymore as a
		//normal cloud (as it's 'associated cloud' has been deleted).
		//Only its indexes are valid! (they are corresponding to octree cells)
		delete theCellCenters;
		theCellCenters = 0;
	}

	if (visibleCells)
	{
		//DGM: we generate a new cloud now, instead of playing with the points visiblity! (too confusing for the user)
		/*if (!cloud->isVisibilityTableInstantiated() && !cloud->resetVisibilityArray())
		{
			m_app->dispToConsole("Visibility array allocation failed! (Not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
			return;
		}

		ccPointCloud::VisibilityTableType* pointsVisibility = cloud->getTheVisibilityArray();
		assert(pointsVisibility);
		pointsVisibility->fill(POINT_HIDDEN);
		//*/

		CCLib::ReferenceCloud visiblePoints(theOctree->associatedCloud());

		unsigned visiblePointCount = 0;
		unsigned visibleCellsCount = visibleCells->size();

		CCLib::DgmOctree::cellIndexesContainer cellIndexes;
		if (!theOctree->getCellIndexes(static_cast<unsigned char>(octreeLevel), cellIndexes))
		{
			m_app->dispToConsole("Couldn't fetch the list of octree cell indexes! (Not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
			delete visibleCells;
			return;
		}

		for (unsigned i=0; i<visibleCellsCount; ++i)
		{
			//cell index
			unsigned index = visibleCells->getPointGlobalIndex(i);

			//points in this cell...
			CCLib::ReferenceCloud Yk(theOctree->associatedCloud());
			theOctree->getPointsInCellByCellIndex(&Yk,cellIndexes[index],static_cast<unsigned char>(octreeLevel));
			//...are all visible
			/*unsigned count = Yk.size();
			for (unsigned j=0;j<count;++j)
				pointsVisibility->setValue(Yk.getPointGlobalIndex(j),POINT_VISIBLE);
			visiblePointCount += count;
			//*/
			if (!visiblePoints.add(Yk))
			{
				m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
				delete visibleCells;
				return;
			}
		}

		delete visibleCells;
		visibleCells = 0;

		m_app->dispToConsole(QString("[HPR] Visible points: %1").arg(visiblePointCount));

		if (visiblePoints.size() == cloud->size())
		{
			m_app->dispToConsole("No points were removed!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
		}
		else
		{
			//create cloud from visibility selection
			ccPointCloud* newCloud = cloud->partialClone(&visiblePoints);
			if (newCloud)
			{			
				newCloud->setDisplay(newCloud->getDisplay());
				newCloud->setVisible(true);
				newCloud->setName(cloud->getName()+QString(".visible_points"));
				cloud->setEnabled(false);

				//add associated viewport object
				cc2DViewportObject* viewportObject = new cc2DViewportObject(QString("Viewport"));
				viewportObject->setParameters(params);
				newCloud->addChild(viewportObject);

				m_app->addToDB(newCloud);
				newCloud->redrawDisplay();
			}
			else
			{
				m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE);
			}
		}
	}

	//currently selected entities appearance may have changed!
	m_app->refreshAll();
}
Exemplo n.º 11
0
ccQuadric* ccQuadric::Fit(CCLib::GenericIndexedCloudPersist *cloud, double* rms/*=0*/)
{
	//number of points
	unsigned count = cloud->size();
	if (count < CC_LOCAL_MODEL_MIN_SIZE[HF])
	{
		ccLog::Warning(QString("[ccQuadric::fitTo] Not enough points in input cloud to fit a quadric! (%1 at the very least are required)").arg(CC_LOCAL_MODEL_MIN_SIZE[HF]));
		return 0;
	}

	//project the points on a 2D plane
	CCVector3 G, X, Y, N;
	{
		CCLib::Neighbourhood Yk(cloud);
		
		//plane equation
		const PointCoordinateType* theLSQPlane = Yk.getLSQPlane();
		if (!theLSQPlane)
		{
			ccLog::Warning("[ccQuadric::Fit] Not enough points to fit a quadric!");
			return 0;
		}

		assert(Yk.getGravityCenter());
		G = *Yk.getGravityCenter();

		//local base
		N = CCVector3(theLSQPlane);
		assert(Yk.getLSQPlaneX() && Yk.getLSQPlaneY());
		X = *Yk.getLSQPlaneX(); //main direction
		Y = *Yk.getLSQPlaneY(); //secondary direction
	}

	//project the points in a temporary cloud
	ccPointCloud tempCloud("temporary");
	if (!tempCloud.reserve(count))
	{
		ccLog::Warning("[ccQuadric::Fit] Not enough memory!");
		return 0;
	}

	cloud->placeIteratorAtBegining();
	for (unsigned k=0; k<count; ++k)
	{
		//projection into local 2D plane ref.
		CCVector3 P = *(cloud->getNextPoint()) - G;

		tempCloud.addPoint(CCVector3(P.dot(X),P.dot(Y),P.dot(N)));
	}

	CCLib::Neighbourhood Zk(&tempCloud);
	{
		//set exact values for gravity center and plane equation
		//(just to be sure and to avoid re-computing them)
		Zk.setGravityCenter(CCVector3(0,0,0));
		PointCoordinateType perfectEq[4] = { 0, 0, 1, 0 };
		Zk.setLSQPlane(	perfectEq,
						CCVector3(1,0,0),
						CCVector3(0,1,0),
						CCVector3(0,0,1));
	}

	uchar hfdims[3];
	const PointCoordinateType* eq = Zk.getHeightFunction(hfdims);
	if (!eq)
	{
		ccLog::Warning("[ccQuadric::Fit] Failed to fit a quadric!");
		return 0;
	}

	//we recenter the quadric object
	ccGLMatrix glMat(X,Y,N,G);

	ccBBox bb = tempCloud.getBB();
	CCVector2 minXY(bb.minCorner().x,bb.minCorner().y);
	CCVector2 maxXY(bb.maxCorner().x,bb.maxCorner().y);

	ccQuadric* quadric = new ccQuadric(minXY, maxXY, eq, hfdims, &glMat);

	quadric->setMetaData(QString("Equation"),QVariant(quadric->getEquationString()));

	//compute rms if necessary
	if (rms)
	{
		const uchar& dX = hfdims[0];
		const uchar& dY = hfdims[1];
		const uchar& dZ = hfdims[2];

		*rms = 0;

		for (unsigned k=0; k<count; ++k)
		{
			//projection into local 2D plane ref.
			const CCVector3* P = tempCloud.getPoint(k);

			PointCoordinateType z = eq[0] + eq[1]*P->u[dX] + eq[2]*P->u[dY] + eq[3]*P->u[dX]*P->u[dX] + eq[4]*P->u[dX]*P->u[dY] + eq[5]*P->u[dY]*P->u[dY];
			*rms += (z-P->z)*(z-P->z);
		}

		if (count)
		{
			*rms = sqrt(*rms / count);
			quadric->setMetaData(QString("RMS"),QVariant(*rms));
		}
	}
	
	return quadric;
}
Exemplo n.º 12
0
ccPolyline* ccContourExtractor::ExtractFlatContour(	CCLib::GenericIndexedCloudPersist* points,
													bool allowMultiPass,
													PointCoordinateType maxEdgeLength/*=0*/,
													const PointCoordinateType* preferredNormDim/*=0*/,
													const PointCoordinateType* preferredUpDir/*=0*/,
													ContourType contourType/*=FULL*/,
													std::vector<unsigned>* originalPointIndexes/*=0*/,
													bool enableVisualDebugMode/*=false*/,
													double maxAngleDeg/*=0.0*/)
{
	assert(points);
	if (!points)
		return 0;
	unsigned ptsCount = points->size();
	if (ptsCount < 3)
		return 0;

	CCLib::Neighbourhood Yk(points);
	CCVector3 O,X,Y; //local base
	bool useOXYasBase = false;

	//we project the input points on a plane
	std::vector<Vertex2D> points2D;
	PointCoordinateType* planeEq = 0;
	//if the user has specified a default direction, we'll use it as 'projecting plane'
	PointCoordinateType preferredPlaneEq[4] = {0, 0, 0, 0};
	if (preferredNormDim != 0)
	{
		const CCVector3* G = points->getPoint(0); //any point through which the point passes is ok
		preferredPlaneEq[0] = preferredNormDim[0];
		preferredPlaneEq[1] = preferredNormDim[1];
		preferredPlaneEq[2] = preferredNormDim[2];
		CCVector3::vnormalize(preferredPlaneEq);
		preferredPlaneEq[3] = CCVector3::vdot(G->u, preferredPlaneEq);
		planeEq = preferredPlaneEq;

		if (preferredUpDir != 0)
		{
			O = *G;
			Y = CCVector3(preferredUpDir);
			X = Y.cross(CCVector3(preferredNormDim));
			useOXYasBase = true;
		}
	}

	if (!Yk.projectPointsOn2DPlane<Vertex2D>(points2D, planeEq, &O, &X, &Y, useOXYasBase))
	{
		ccLog::Warning("[ExtractFlatContour] Failed to project the points on the LS plane (not enough memory?)!");
		return 0;
	}

	//update the points indexes (not done by Neighbourhood::projectPointsOn2DPlane)
	{
		for (unsigned i = 0; i < ptsCount; ++i)
			points2D[i].index = i;
	}

	//try to get the points on the convex/concave hull to build the contour and the polygon
	Hull2D hullPoints;
	if (!ExtractConcaveHull2D(	points2D,
								hullPoints,
								contourType,
								allowMultiPass,
								maxEdgeLength*maxEdgeLength,
								enableVisualDebugMode,
								maxAngleDeg))
	{
		ccLog::Warning("[ExtractFlatContour] Failed to compute the convex hull of the input points!");
		return 0;
	}

	if (originalPointIndexes)
	{
		try
		{
			originalPointIndexes->resize(hullPoints.size(), 0);
		}
		catch (const std::bad_alloc&)
		{
			//not enough memory
			ccLog::Error("[ExtractFlatContour] Not enough memory!");
			return 0;
		}

		unsigned i=0;
		for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it, ++i)
			(*originalPointIndexes)[i] = (*it)->index;
	}

	unsigned hullPtsCount = static_cast<unsigned>(hullPoints.size());

	//create vertices
	ccPointCloud* contourVertices = new ccPointCloud();
	{
		if (!contourVertices->reserve(hullPtsCount))
		{
			delete contourVertices;
			contourVertices = 0;
			ccLog::Error("[ExtractFlatContour] Not enough memory!");
			return 0;
		}

		//projection on the LS plane (in 3D)
		for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it)
			contourVertices->addPoint(O + X*(*it)->x + Y*(*it)->y);
		contourVertices->setName("vertices");
		contourVertices->setEnabled(false);
	}

	//we create the corresponding (3D) polyline
	ccPolyline* contourPolyline = new ccPolyline(contourVertices);
	if (contourPolyline->reserve(hullPtsCount))
	{
		contourPolyline->addPointIndex(0, hullPtsCount);
		contourPolyline->setClosed(contourType == FULL);
		contourPolyline->setVisible(true);
		contourPolyline->setName("contour");
		contourPolyline->addChild(contourVertices);
	}
	else
	{
		delete contourPolyline;
		contourPolyline = 0;
		ccLog::Warning("[ExtractFlatContour] Not enough memory to create the contour polyline!");
	}

	return contourPolyline;
}
Exemplo n.º 13
0
ccPolyline* ccPolyline::ExtractFlatContour(	CCLib::GenericIndexedCloudPersist* points,
											PointCoordinateType maxEdgelLength/*=0*/,
											const PointCoordinateType* preferredNormDim/*=0*/,
											const PointCoordinateType* preferredUpDir/*=0*/,
											ContourType contourType/*=FULL*/,
											std::vector<unsigned>* originalPointIndexes/*=0*/)
{
	assert(points);
	if (!points)
		return 0;
	unsigned ptsCount = points->size();
	if (ptsCount < 3)
		return 0;

	CCLib::Neighbourhood Yk(points);
	CCVector3 O,X,Y; //local base
	bool useOXYasBase = false;

	//we project the input points on a plane
	std::vector<CCLib::PointProjectionTools::IndexedCCVector2> points2D;
	PointCoordinateType* planeEq = 0;
	//if the user has specified a default direction, we'll use it as 'projecting plane'
	PointCoordinateType preferredPlaneEq[4] = {0, 0, 0, 0};
	if (preferredNormDim != 0)
	{
		const CCVector3* G = points->getPoint(0); //any point through which the point passes is ok
		preferredPlaneEq[0] = preferredNormDim[0];
		preferredPlaneEq[1] = preferredNormDim[1];
		preferredPlaneEq[2] = preferredNormDim[2];
		CCVector3::vnormalize(preferredPlaneEq);
		preferredPlaneEq[3] = CCVector3::vdot(G->u,preferredPlaneEq);
		planeEq = preferredPlaneEq;

		if (preferredUpDir != 0)
		{
			O = *G;
			Y = CCVector3(preferredUpDir);
			X = Y.cross(CCVector3(preferredNormDim));
			useOXYasBase = true;
		}
	}

	if (!Yk.projectPointsOn2DPlane<CCLib::PointProjectionTools::IndexedCCVector2>(points2D,planeEq,&O,&X,&Y,useOXYasBase))
	{
		ccLog::Warning("[ccPolyline::ExtractFlatContour] Failed to project the points on the LS plane (not enough memory?)!");
		return 0;
	}

	//update the points indexes (not done by Neighbourhood::projectPointsOn2DPlane)
	{
		for (unsigned i=0; i<ptsCount; ++i)
			points2D[i].index = i;
	}

	//try to get the points on the convex/concave hull to build the contour and the polygon
	Hull2D hullPoints;
	if (!CCLib::PointProjectionTools::extractConcaveHull2D(	points2D,
															hullPoints,
															maxEdgelLength*maxEdgelLength) )
	{
		ccLog::Warning("[ccPolyline::ExtractFlatContour] Failed to compute the convex hull of the input points!");
		return 0;
	}

	bool isClosed = true;
	if (contourType != FULL)
	{
		//look for the min and max 'X' coordinates (preferredNormDim and preferredUpDir should have been defined ;)
		PointCoordinateType xMin = 0, xMax = 0;
		{
			unsigned i=0;
			for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it, ++i)
			{
				const CCLib::PointProjectionTools::IndexedCCVector2* P = *it;
				if (i != 0)
				{
					if (P->x < xMin)
						xMin = P->x;
					else if (P->x > xMax)
						xMax = P->x;
				}
				else
				{
					xMin = xMax = P->x;
				}
			}
		}

		if (xMin != xMax)
		{
			//now identify the 'min' vertex
			Hull2D::const_iterator firstIt = hullPoints.end();
			{
				for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it)
				{
					const CCLib::PointProjectionTools::IndexedCCVector2* P = *it;
					if (P->x == xMin)
					{
						if (	firstIt == hullPoints.end()
							//we take the lowest (resp highest) if multiple points with x == xMin
							||	(contourType == LOWER && (*firstIt)->y > P->y)
							||	(contourType == UPPER && (*firstIt)->y < P->y) )
						{
							firstIt = it;
						}
					}
				}
			}
			assert(firstIt != hullPoints.end());

			//now we are going to keep only the right part
			try
			{
				//determine the right way
				Hull2D::const_iterator prevIt = (firstIt != hullPoints.begin() ? firstIt : hullPoints.end()); --prevIt;
				Hull2D::const_iterator nextIt = firstIt; ++nextIt; if (nextIt == hullPoints.end()) nextIt = hullPoints.begin();
				bool forward = (	(contourType == LOWER && (*nextIt)->y < (*prevIt)->y)
								||	(contourType == UPPER && (*nextIt)->y > (*prevIt)->y) );
				if (!forward)
					std::swap(prevIt,nextIt);
				
				Hull2D hullPart;
				hullPart.push_back(*firstIt);

				nextIt = firstIt;
				while ((*nextIt)->x != xMax)
				{
					if (forward)
					{
						++nextIt;
						if (nextIt == hullPoints.end())
							nextIt = hullPoints.begin();
					}
					else
					{
						if (nextIt == hullPoints.begin())
							nextIt = hullPoints.end();
						--nextIt;
					}
					hullPart.push_back(*nextIt);
				}

				hullPoints = hullPart;
				isClosed = false;
			}
			catch(std::bad_alloc)
			{
				ccLog::Error("[ccPolyline::ExtractFlatContour] Not enough memory!");
				return 0;
			}
		}
		else //xMin == xMax
		{
			//flat contour?!
		}
	}

	if (originalPointIndexes)
	{
		try
		{
			originalPointIndexes->resize(hullPoints.size(),0);
		}
		catch(std::bad_alloc)
		{
			//not enough memory
			ccLog::Error("[ccPolyline::ExtractFlatContour] Not enough memory!");
			return 0;
		}

		unsigned i=0;
		for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it, ++i)
			(*originalPointIndexes)[i] = (*it)->index;
	}

	unsigned hullPtsCount = static_cast<unsigned>(hullPoints.size());

	//create vertices
	ccPointCloud* contourVertices = new ccPointCloud();
	{
		if (!contourVertices->reserve(hullPtsCount))
		{
			delete contourVertices;
			contourVertices = 0;
			ccLog::Error("[ccPolyline::ExtractFlatContour] Not enough memory!");
			return 0;
		}

		//projection on the LS plane (in 3D)
		for (Hull2D::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it)
			contourVertices->addPoint(O + X*(*it)->x + Y*(*it)->y);
		contourVertices->setName("vertices");
		contourVertices->setEnabled(false);
	}

	//we create the corresponding (3D) polyline
	ccPolyline* contourPolyline = new ccPolyline(contourVertices);
	if (contourPolyline->reserve(hullPtsCount))
	{
		contourPolyline->addPointIndex(0,hullPtsCount);
		contourPolyline->setClosed(isClosed);
		contourPolyline->setVisible(true);
		contourPolyline->setName("contour");
		contourPolyline->addChild(contourVertices);
	}
	else
	{
		delete contourPolyline;
		contourPolyline = 0;
		ccLog::Warning("[ccPolyline::ExtractFlatContour] Not enough memory to create the contour polyline!");
	}

	return contourPolyline;
}
Exemplo n.º 14
0
ccPlane* ccPlane::Fit(CCLib::GenericIndexedCloudPersist *cloud, double* rms/*=0*/)
{
    //number of points
    unsigned count = cloud->size();
    if (count < 3)
    {
        ccLog::Warning("[ccPlane::Fit] Not enough points in input cloud to fit a plane!");
        return 0;
    }

    CCLib::Neighbourhood Yk(cloud);

    //plane equation
    const PointCoordinateType* theLSPlane = Yk.getLSPlane();
    if (!theLSPlane)
    {
        ccLog::Warning("[ccPlane::Fit] Not enough points to fit a plane!");
        return 0;
    }

    //get the centroid
    const CCVector3* G = Yk.getGravityCenter();
    assert(G);

    //and a local base
    CCVector3 N(theLSPlane);
    const CCVector3* X = Yk.getLSPlaneX(); //main direction
    assert(X);
    CCVector3 Y = N * (*X);

    //compute bounding box in 2D plane
    CCVector2 minXY(0,0), maxXY(0,0);
    cloud->placeIteratorAtBegining();
    for (unsigned k=0; k<count; ++k)
    {
        //projection into local 2D plane ref.
        CCVector3 P = *(cloud->getNextPoint()) - *G;

        CCVector2 P2D( P.dot(*X), P.dot(Y) );

        if (k != 0)
        {
            if (minXY.x > P2D.x)
                minXY.x = P2D.x;
            else if (maxXY.x < P2D.x)
                maxXY.x = P2D.x;
            if (minXY.y > P2D.y)
                minXY.y = P2D.y;
            else if (maxXY.y < P2D.y)
                maxXY.y = P2D.y;
        }
        else
        {
            minXY = maxXY = P2D;
        }
    }

    //we recenter the plane
    PointCoordinateType dX = maxXY.x-minXY.x;
    PointCoordinateType dY = maxXY.y-minXY.y;
    CCVector3 Gt = *G + *X * (minXY.x + dX / 2) + Y * (minXY.y + dY / 2);
    ccGLMatrix glMat(*X,Y,N,Gt);

    ccPlane* plane = new ccPlane(dX, dY, &glMat);

    //compute least-square fitting RMS if requested
    if (rms)
    {
        *rms = CCLib::DistanceComputationTools::computeCloud2PlaneDistanceRMS(cloud, theLSPlane);
        plane->setMetaData(QString("RMS"),QVariant(*rms));
    }


    return plane;
}
Exemplo n.º 15
0
bool ccFacet::createInternalRepresentation(	CCLib::GenericIndexedCloudPersist* points,
											const PointCoordinateType* planeEquation/*=0*/)
{
	assert(points);
	if (!points)
		return false;
	unsigned ptsCount = points->size();
	if (ptsCount < 3)
		return false;

	CCLib::Neighbourhood Yk(points);

	//get corresponding plane
	if (!planeEquation)
	{
		planeEquation = Yk.getLSPlane();
		if (!planeEquation)
		{
			ccLog::Warning("[ccFacet::createInternalRepresentation] Failed to compute the LS plane passing through the input points!");
			return false;
		}
	}
	memcpy(m_planeEquation, planeEquation, sizeof(PointCoordinateType) * 4);

	//we project the input points on a plane
	std::vector<CCLib::PointProjectionTools::IndexedCCVector2> points2D;
	CCVector3 X, Y; //local base
	if (!Yk.projectPointsOn2DPlane<CCLib::PointProjectionTools::IndexedCCVector2>(points2D, nullptr, &m_center, &X, &Y))
	{
		ccLog::Error("[ccFacet::createInternalRepresentation] Not enough memory!");
		return false;
	}

	//compute resulting RMS
	m_rms = CCLib::DistanceComputationTools::computeCloud2PlaneDistanceRMS(points, m_planeEquation);
	
	//update the points indexes (not done by Neighbourhood::projectPointsOn2DPlane)
	{
		for (unsigned i = 0; i < ptsCount; ++i)
		{
			points2D[i].index = i;
		}
	}

	//try to get the points on the convex/concave hull to build the contour and the polygon
	{
		std::list<CCLib::PointProjectionTools::IndexedCCVector2*> hullPoints;
		if (!CCLib::PointProjectionTools::extractConcaveHull2D(	points2D,
																hullPoints,
																m_maxEdgeLength*m_maxEdgeLength))
		{
			ccLog::Error("[ccFacet::createInternalRepresentation] Failed to compute the convex hull of the input points!");
		}

		unsigned hullPtsCount = static_cast<unsigned>(hullPoints.size());

		//create vertices
		m_contourVertices = new ccPointCloud();
		{
			if (!m_contourVertices->reserve(hullPtsCount))
			{
				delete m_contourVertices;
				m_contourVertices = nullptr;
				ccLog::Error("[ccFacet::createInternalRepresentation] Not enough memory!");
				return false;
			}
			
			//projection on the LS plane (in 3D)
			for (std::list<CCLib::PointProjectionTools::IndexedCCVector2*>::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it)
			{
				m_contourVertices->addPoint(m_center + X*(*it)->x + Y*(*it)->y);
			}
			m_contourVertices->setName(DEFAULT_CONTOUR_POINTS_NAME);
			m_contourVertices->setLocked(true);
			m_contourVertices->setEnabled(false);
			addChild(m_contourVertices);
		}

		//we create the corresponding (3D) polyline
		{
			m_contourPolyline = new ccPolyline(m_contourVertices);
			if (m_contourPolyline->reserve(hullPtsCount))
			{
				m_contourPolyline->addPointIndex(0, hullPtsCount);
				m_contourPolyline->setClosed(true);
				m_contourPolyline->setVisible(true);
				m_contourPolyline->setLocked(true);
				m_contourPolyline->setName(DEFAULT_CONTOUR_NAME);
				m_contourVertices->addChild(m_contourPolyline);
				m_contourVertices->setEnabled(true);
				m_contourVertices->setVisible(false);
			}
			else
			{
				delete m_contourPolyline;
				m_contourPolyline = nullptr;
				ccLog::Warning("[ccFacet::createInternalRepresentation] Not enough memory to create the contour polyline!");
			}
		}

		//we create the corresponding (2D) mesh
		std::vector<CCVector2> hullPointsVector;
		try
		{
			hullPointsVector.reserve(hullPoints.size());
			for (std::list<CCLib::PointProjectionTools::IndexedCCVector2*>::const_iterator it = hullPoints.begin(); it != hullPoints.end(); ++it)
			{
				hullPointsVector.push_back(**it);
			}
		}
		catch (...)
		{
			ccLog::Warning("[ccFacet::createInternalRepresentation] Not enough memory to create the contour mesh!");
		}

		//if we have computed a concave hull, we must remove triangles falling outside!
		bool removePointsOutsideHull = (m_maxEdgeLength > 0);

		if (!hullPointsVector.empty() && CCLib::Delaunay2dMesh::Available())
		{
			//compute the facet surface
			CCLib::Delaunay2dMesh dm;
			char errorStr[1024];
			if (dm.buildMesh(hullPointsVector, 0, errorStr))
			{
				if (removePointsOutsideHull)
					dm.removeOuterTriangles(hullPointsVector, hullPointsVector);
				unsigned triCount = dm.size();
				assert(triCount != 0);

				m_polygonMesh = new ccMesh(m_contourVertices);
				if (m_polygonMesh->reserve(triCount))
				{
					//import faces
					for (unsigned i = 0; i < triCount; ++i)
					{
						const CCLib::VerticesIndexes* tsi = dm.getTriangleVertIndexes(i);
						m_polygonMesh->addTriangle(tsi->i1, tsi->i2, tsi->i3);
					}
					m_polygonMesh->setVisible(true);
					m_polygonMesh->enableStippling(true);

					//unique normal for facets
					if (m_polygonMesh->reservePerTriangleNormalIndexes())
					{
						NormsIndexesTableType* normsTable = new NormsIndexesTableType();
						normsTable->reserve(1);
						CCVector3 N(m_planeEquation);
						normsTable->addElement(ccNormalVectors::GetNormIndex(N.u));
						m_polygonMesh->setTriNormsTable(normsTable);
						for (unsigned i = 0; i < triCount; ++i)
							m_polygonMesh->addTriangleNormalIndexes(0, 0, 0); //all triangles will have the same normal!
						m_polygonMesh->showNormals(true);
						m_polygonMesh->setLocked(true);
						m_polygonMesh->setName(DEFAULT_POLYGON_MESH_NAME);
						m_contourVertices->addChild(m_polygonMesh);
						m_contourVertices->setEnabled(true);
						m_contourVertices->setVisible(false);
					}
					else
					{
						ccLog::Warning("[ccFacet::createInternalRepresentation] Not enough memory to create the polygon mesh's normals!");
					}

					//update facet surface
					m_surface = CCLib::MeshSamplingTools::computeMeshArea(m_polygonMesh);
				}
				else
				{
					delete m_polygonMesh;
					m_polygonMesh = nullptr;
					ccLog::Warning("[ccFacet::createInternalRepresentation] Not enough memory to create the polygon mesh!");
				}
			}
			else
			{
				ccLog::Warning(QString("[ccFacet::createInternalRepresentation] Failed to create the polygon mesh (third party lib. said '%1'").arg(errorStr));
			}
		}
	}

	return true;
}
int FastMarchingForFacetExtraction::init(	ccGenericPointCloud* cloud,
											CCLib::DgmOctree* theOctree,
											unsigned char level,
											ScalarType maxError,
											CCLib::DistanceComputationTools::ERROR_MEASURES errorMeasure,
											bool useRetroProjectionError,
											CCLib::GenericProgressCallback* progressCb/*=0*/)
{
	m_maxError = maxError;
	m_errorMeasure = errorMeasure;
	m_useRetroProjectionError = useRetroProjectionError;

	if (progressCb)
	{
		if (progressCb->textCanBeEdited())
		{
			progressCb->setMethodTitle("Fast Marching grid initialization");
			progressCb->setInfo(qPrintable(QString("Level: %1").arg(level)));
		}
		progressCb->update(0);
		progressCb->start();
	}

	int result = initGridWithOctree(theOctree, level);
	if (result < 0)
		return result;

	//fill the grid with the octree
	CCLib::DgmOctree::cellCodesContainer cellCodes;
	theOctree->getCellCodes(level,cellCodes,true);
	size_t cellCount = cellCodes.size();

	CCLib::NormalizedProgress nProgress(progressCb, static_cast<unsigned>(cellCount));
	if (progressCb)
	{
		progressCb->setInfo(qPrintable(QString("Level: %1\nCells: %2").arg(level).arg(cellCount)));
	}

	CCLib::ReferenceCloud Yk(theOctree->associatedCloud());
	while (!cellCodes.empty())
	{
		if (theOctree->getPointsInCell(cellCodes.back(),level,&Yk,true))
		{
			//convert the octree cell code to grid position
			Tuple3i cellPos;
			theOctree->getCellPos(cellCodes.back(),level,cellPos,true);

			CCVector3 N,C;
			ScalarType error;
			if (ComputeCellStats(&Yk,N,C,error,m_errorMeasure))
			{
				//convert octree cell pos to FM cell pos index
				unsigned gridPos = pos2index(cellPos);

				//create corresponding cell
				PlanarCell* aCell = new PlanarCell;
				aCell->cellCode = cellCodes.back();
				aCell->N = N;
				aCell->C = C;
				aCell->planarError = error;
				m_theGrid[gridPos] = aCell;
			}
			else
			{
				//an error occurred?!
				return -10;
			}
		}

		cellCodes.pop_back();

		if (progressCb && !nProgress.oneStep())
		{
			//process cancelled by user
			progressCb->stop();
			return -1;
		}
	}

	if (progressCb)
	{
		progressCb->stop();
	}
		
	m_initialized = true;

	return 0;
}