static std::vector<unsigned> calculateActiveGroup(const Cell_handle &cell,
		unsigned iNearest,
		const std::vector<SupportItem> &items)
{
	DEBUG_START;
	Vector_3 xOld = cell->info().point - CGAL::Origin();
	std::vector<unsigned> activeGroup;
	unsigned numUnresolvedCurrent = 0;
	bool nearestFound = false;
	for (unsigned iPlane : cell->info().associations)
	{
		const SupportItem &item = items[iPlane];
		double delta = item.direction * xOld - item.value;
		std::cout << "  delta for plane #" << iPlane << "= " << delta
			<< "; resolved: " << item.resolved << std::endl;
		if (!item.resolved)
		{
			++numUnresolvedCurrent;
			if (iPlane == iNearest)
			{
				activeGroup.push_back(iPlane);
				nearestFound = true;
			}
		}
		else
			activeGroup.push_back(iPlane);
	}
	std::cout << "  Number of current unresolved items: "
		<< numUnresolvedCurrent << std::endl;
	if (numUnresolvedCurrent == 0)
	{
		DEBUG_END;
		return std::vector<unsigned>();
	}
	ASSERT(numUnresolvedCurrent > 0 && "Nothing to be resolved");
	ASSERT(nearestFound && "Failed to find nearest point inside given "
			"cell");
	ASSERT(activeGroup.size() > NUM_FACET_VERTICES && "Not enough planes");

	DEBUG_END;
	return activeGroup;
}
/**
 * Gets the material for the given point
 * @param p The point to get the material for
 * @return The material at the given point
 */
Contents StoneWeatherer::getContents( const Point & p ) const {

	// Get a handle to the cell that contains the given point
	Cell_handle ch = newDT->locate( p );

	if ( newDT->is_infinite( ch ) ) {

		return AIR;
	}
	else {

		return ch->info();
	}
}
static unsigned getNearestOuterItemID(const Cell_handle &cell,
		const std::vector<SupportItem> &items,
		const Vertex_handle &infinity)
{
	DEBUG_START;
	Plane_3 plane = getOppositeFacetPlane(cell, infinity);
	Point_3 point = dual(plane);
	cell->info().point = point;
	
	double distanceMin = MINIMIZATION_STARTING_VALUE;
	unsigned iNearest = 0;
	const auto &associations = cell->info().associations;
	unsigned numUnresolved = 0;
	for (unsigned iPlane : associations)
	{
		SupportItem item = items[iPlane];
		Vector_3 u = item.direction;
		double value = item.value;
		double distance = value - u * (point - CGAL::Origin());
		if (!item.resolved)
		{
			ASSERT(distance > 0. && "Incorrect resolved flag");
			if (distance < distanceMin)
			{
				iNearest = iPlane;
				distanceMin = distance;
			}
			++numUnresolved;
		}
	}
	if (numUnresolved > 0)
		ASSERT(distanceMin < MINIMIZATION_STARTING_VALUE
				&& "Failed to find");
	cell->info().distance = distanceMin;
	DEBUG_END;
	return iNearest;
}
void DualPolyhedron_3::associateVertex(const Vertex_handle &vertex)
{
	DEBUG_START;
	int iPlane = vertex->info();
	if (isOuterVertex(vertex))
	{
		Cell_handle cell;
		int iVertex, iInfinity;
		bool result = is_edge(vertex, infinite_vertex(), cell,
				iVertex, iInfinity);
		ASSERT(result && "Wrong set");
		
		TDelaunay_3::Edge edge(cell, iVertex, iInfinity);
		auto circulator = incident_cells(edge);
		auto end = circulator;
		do
		{
			Cell_handle currentCell = circulator;
			ASSERT(currentCell->has_vertex(vertex));
			ASSERT(currentCell->has_vertex(infinite_vertex()));
			currentCell->info().associations.insert(iPlane);
			items[iPlane].associations.insert(currentCell);
			items[iPlane].resolved = true;
			++circulator;
		} while (circulator != end);
	}
	else
	{
		Vector_3 direction = items[iPlane].direction;
		Cell_handle bestCell = findBestCell(direction,
				infinite_vertex(), infinite_cell());
		bestCell->info().associations.insert(iPlane);
		/* FIXME: Maybe the association for a plane is singular? */
		items[iPlane].associations.insert(bestCell);
	}
	DEBUG_END;
}
/**
 * Finds a circumcenter in the grid and labels its associated cell
 * @param point The location of the circumcenter
 * @param cell The cell to label
 * @param midpoint Stores the weighted midpoint of non-air cells
 * @param volume Accumulates the volume of non-air cells
 */
void UniformGrid::locateAndLabel( const Point & point, Cell_handle & cell, double * midpoint, double & volume ) const {

	Point3D p( point.x(), point.y(), point.z() );
	unsigned int x = ( unsigned int ) ( ( p.x - xmin ) * inv_Xsize );
	unsigned int y = ( unsigned int ) ( ( p.y - ymin ) * inv_Ysize );
	unsigned int z = ( unsigned int ) ( ( p.z - zmin ) * inv_Zsize );

	unsigned int i = ( ( ( My * z ) + y ) * Mx ) + x;
	unsigned int start = grid[ i ];
	unsigned int end = grid[ i + 1 ];
	double tetrahedronVolume = 0.0;

	for ( i = start; i < end; ++i ) {

		if ( tetrahedrons[ L[ i ] ]->contains( p ) ) {

			cell->info() = tetrahedrons[ L[ i ] ]->cell->info();

			if ( cell->info() > AIR ) {

				tetrahedronVolume = Tetrahedron::volume( cell );
				
				#pragma omp critical(updateVolume)
				{
					volume += tetrahedronVolume;
					midpoint[ 0 ] += p.x * tetrahedronVolume;
					midpoint[ 1 ] += p.y * tetrahedronVolume;
					midpoint[ 2 ] += p.z * tetrahedronVolume;
				}
			}

			return;
		}
	}

	cell->info() = AIR;
}
bool DualPolyhedron_3::lift(Cell_handle cell, unsigned iNearest)
{
	DEBUG_START;
	Vector_3 xOld = cell->info().point - CGAL::Origin();
	std::cout << "Old tangient point: " << xOld << std::endl;
	const auto activeGroup = calculateActiveGroup(cell, iNearest, items);
	if (activeGroup.empty())
	{
		DEBUG_END;
		return false;
	}

	Vector_3 xNew = leastSquaresPoint(activeGroup, items);
	std::cout << "New tangient point: " << xNew << std::endl;

	ASSERT(cell->has_vertex(infinite_vertex()));
	unsigned infinityIndex = cell->index(infinite_vertex());
	std::vector<Vertex_handle> vertices;
	Vertex_handle dominator;
	double alphaMax = 0.;
	double alphaMax2 = 0.;
	for (unsigned i = 0; i < NUM_CELL_VERTICES; ++i)
	{
		if (i == infinityIndex)
			continue;

		vertices.push_back(cell->vertex(i));

		Vertex_handle vertex = mirror_vertex(cell, i);
		Plane_3 plane = ::dual(vertex->point());
		double alpha;
	        bool succeeded;
		std::tie(succeeded, alpha) = calculateAlpha(xOld, xNew, plane);
		if (!succeeded)
			return false;
		std::cout << "Alpha #" << i << ": " << alpha << std::endl;
		ASSERT(alpha <= 1. && "Wrongly computed alpha");
		if (alpha > alphaMax)
		{
			alphaMax2 = alphaMax;
			alphaMax = alpha;
			dominator = vertex;
		}
	}
	
	std::cout << "Maximal alpha: " << alphaMax << std::endl;
	std::cout << "Maximal alpha 2nd: " << alphaMax2 << std::endl;
	ASSERT(alphaMax < 1. && "What to do then?");
	if (alphaMax > 0.)
	{
		std::cout << "Full move is impossible, performing partial move"
			<< std::endl;
		partiallyMove(xOld, xNew, vertices, dominator, alphaMax,
				alphaMax2);
	}
	else
	{
		std::cout << "Performing full move" << std::endl;
		if (!fullyMove(vertices, xNew, activeGroup))
		{
			DEBUG_END;
			return false;
		}
	}
	DEBUG_END;
	return true;
}