void LowStretchSphereParametrization::WrapComponents(const GfxTL::AABox< GfxTL::Vector2Df > &bbox,
	float epsilon, size_t uextent, size_t vextent,
	MiscLib::Vector< int > *componentImg,
	MiscLib::Vector< std::pair< int, size_t > > *labels) const
{
	// wraps are necessary only in v direction
	// relabel the components
	MiscLib::Vector< std::pair< int, size_t > > tempLabels(*labels);
	// wrap along v
	float vstartPrev, vendPrev, vstart = 0, vend = 0, vstartNext = 0, vendNext = 0;
	size_t vsPrev, vePrev, vs = 0, ve = 0, vsNext = 0, veNext = 0;
	float uangle = (bbox.Min()[0] + .5f * epsilon) / m_sphere->Radius();
	float radius = std::sin(uangle) * m_sphere->Radius();
	vstartNext = float(-M_PI) * radius;
	vendNext = float(M_PI) * radius;
	vsNext =  std::min(vextent - 1, (size_t)std::max((intptr_t)0,
		(intptr_t)((vstartNext - bbox.Min()[1]) / epsilon)));
	veNext = (size_t)std::max((intptr_t)0, std::min((intptr_t)vextent - 1,
		(intptr_t)((vendNext - bbox.Min()[1]) / epsilon)));
	for(size_t u = 0; u < uextent; ++u)
	{
		vstartPrev = vstart;		vstart = vstartNext;
		vendPrev = vend;			vend = vendNext;
		vsPrev = vs;				vs = vsNext;
		vePrev = ve;				ve = veNext;
		// determine starting position in the next column
		if(u < uextent - 1)
		{
			float uangleNext = ((u + 1.5f) * epsilon + bbox.Min()[0]) / m_sphere->Radius();
			float radiusNext = std::sin(uangle) * m_sphere->Radius();
			vstartNext = float(-M_PI) * radius;
			vendNext = float(M_PI) * radius;
			vsNext =  std::min(vextent - 1, (size_t)std::max((intptr_t)0,
				(intptr_t)((vstartNext - bbox.Min()[1]) / epsilon)));
			veNext = (size_t)std::max((intptr_t)0, std::min((intptr_t)vextent - 1,
				(intptr_t)((vendNext - bbox.Min()[1]) / epsilon)));
		}
		if(vstart <= bbox.Min()[1] - epsilon
			|| vend >= bbox.Max()[1] + epsilon
			|| !(*componentImg)[vs * uextent + u])
			continue;
		// check the three neighbors on the other side
		if((*componentImg)[ve * uextent + u])
			AssociateLabel((*componentImg)[vs * uextent + u],
				(*componentImg)[ve * uextent + u], &tempLabels);
		if(u > 0
			&& vstartPrev > bbox.Min()[1] - epsilon
			&& vendPrev < bbox.Min()[1] + epsilon
			&& (*componentImg)[vePrev * uextent + u - 1])
			AssociateLabel((*componentImg)[vs * uextent + u],
				(*componentImg)[vePrev * uextent + u - 1], &tempLabels);
		if(u < uextent - 1
			&& vstartNext > bbox.Min()[1] - epsilon
			&& vendNext < bbox.Min()[1] + epsilon
			&& (*componentImg)[veNext * uextent + u + 1])
			AssociateLabel((*componentImg)[vs * uextent + u],
				(*componentImg)[veNext * uextent + u + 1], &tempLabels);
	}

	// condense labels
	for(size_t i = tempLabels.size() - 1; i > 0; --i)
		tempLabels[i].first = ReduceLabel(i, tempLabels);
	MiscLib::Vector< int > condensed(tempLabels.size());
	labels->clear();
	labels->reserve(condensed.size());
	int count = 0;
    for(size_t i = 0; i < tempLabels.size(); ++i)
		if(i == tempLabels[i].first)
		{
			labels->push_back(std::make_pair(count, tempLabels[i].second));
			condensed[i] = count;
			++count;
		}
		else
			(*labels)[condensed[tempLabels[i].first]].second
				+= tempLabels[i].second;
	// set new component ids
	for(size_t i = 0; i < componentImg->size(); ++i)
		(*componentImg)[i] =
			condensed[tempLabels[(*componentImg)[i]].first];
}
void ConePrimitiveShape::WrapComponents(
	const GfxTL::AABox< GfxTL::Vector2Df > &bbox,
	float epsilon, size_t uextent, size_t vextent,
	MiscLib::Vector< int > *componentImg,
	MiscLib::Vector< std::pair< int, size_t > > *labels) const
{
	if(m_cone.Angle() >= float(M_PI / 4))
		return;
	// for wrapping we copy the first pixel to the last one in each v column
	for(size_t u = 0; u < uextent; ++u)
	{
		// determine the coordinates of the last pixel in the column
		// get the radius of the column
		float r = m_cone.RadiusAtLength(u * epsilon + bbox.Min()[0]);
		size_t v = std::floor((2 * float(M_PI) * r  - bbox.Min()[1]) / epsilon) + 1;
		if(v >= vextent)
			continue;
		if((*componentImg)[u])
			(*componentImg)[v * uextent + u] = (*componentImg)[u]; // do the wrap
	}
	// relabel the components
	MiscLib::Vector< std::pair< int, size_t > > tempLabels(*labels);
	int curLabel = tempLabels.size() - 1;
	for(size_t u = 0; u < uextent; ++u)
	{
		float r = m_cone.RadiusAtLength(u * epsilon + bbox.Min()[0]);
		size_t v = std::floor((2 * float(M_PI) * r  - bbox.Min()[1]) / epsilon) + 1;
		if(v >= vextent)
			continue;
		if(!(*componentImg)[v * uextent + u])
			continue;
		// get the neighbors
		int n[8];
		size_t i = 0;
		if(v >= 1)
		{
			size_t prevRow = (v - 1) * uextent;
			if(u >= 1)
				n[i++] = (*componentImg)[prevRow + u - 1];
			n[i++] = (*componentImg)[prevRow + u];
			if(u < uextent - 1)
				n[i++] = (*componentImg)[prevRow + u + 1];
		}
		size_t row = v * uextent;
		if(u >= 1)
			n[i++] = (*componentImg)[row + u - 1];
		if(u < uextent - 1)
			n[i++] = (*componentImg)[row + u + 1];
		if(v < vextent - 1)
		{
			size_t nextRow = (v + 1) * uextent;
			if(u >= 1)
				n[i++] = (*componentImg)[nextRow + u - 1];
			n[i++] = (*componentImg)[nextRow + u];
			if(u < uextent - 1)
				n[i++] = (*componentImg)[nextRow + u + 1];
		}
		// associate labels
		int l = (*componentImg)[v * uextent + u];
		for(size_t j = 0; j < i; ++j)
			if(n[j])
				AssociateLabel(l, n[j], &tempLabels);
	}
	// condense labels
	for(size_t i = tempLabels.size() - 1; i > 0; --i)
		tempLabels[i].first = ReduceLabel(i, tempLabels);
	MiscLib::Vector< int > condensed(tempLabels.size());
	labels->clear();
	labels->reserve(condensed.size());
	int count = 0;
    for(size_t i = 0; i < tempLabels.size(); ++i)
		if(i == tempLabels[i].first)
		{
			labels->push_back(std::make_pair(count, tempLabels[i].second));
			condensed[i] = count;
			++count;
		}
		else
			(*labels)[condensed[tempLabels[i].first]].second
				+= tempLabels[i].second;
	// set new component ids
	for(size_t i = 0; i < componentImg->size(); ++i)
		(*componentImg)[i] =
			condensed[tempLabels[(*componentImg)[i]].first];
}