Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}