in UVAtlas/isochart/meshoptimizestretch.cpp [1800:2019]
bool CIsochartMesh::OptimizeVertexStretchAroundCenter(
CHARTOPTIMIZEINFO& optimizeInfo,
VERTOPTIMIZEINFO& vertInfo)
{
ISOCHARTVERTEX* pOptimizeVertex = vertInfo.pOptimizeVertex;
float fOriginalStartStretch = vertInfo.fStartStretch;
XMFLOAT2 originalEnd = vertInfo.end;
float fOriginalEndStretch = vertInfo.fEndStretch;
float fToleranceLength
= optimizeInfo.fAverageEdgeLength * optimizeInfo.fAverageEdgeLength
* optimizeInfo.fTolerance * optimizeInfo.fTolerance;
float fTempStretch = 0;
XMFLOAT2 middle;
// As the decription in [SSGH01], randomly moving vertex will have more
// chance to find the optimal position. To make consistent results, srand
// with a specified value 2
srand(2);
size_t iteration = 0;
while (iteration < optimizeInfo.dwRandOptOneVertTimes)
{
// 1. Get a new random position in the optimizing circle range
float fAngle = m_IsochartEngine.UniformRand(2.f * XM_PI);
vertInfo.end.x =
vertInfo.center.x + vertInfo.fRadius * cosf(fAngle);
vertInfo.end.y =
vertInfo.center.y + vertInfo.fRadius * sinf(fAngle);
// 2. When optimizing an boundary vertex during sigal-specified
// parameterizing, must gurantee the vertex didn't move outside
// of chart bounding box.
if (pOptimizeVertex->bIsBoundary && optimizeInfo.bUseBoundingBox)
{
LimitVertexToBoundingBox(
vertInfo.end,
optimizeInfo.minBound,
optimizeInfo.maxBound,
vertInfo.end);
}
// 3. Move vertex to the new position, and caculate new vertex stretch
TryAdjustVertexParamStretch(
pOptimizeVertex,
optimizeInfo.bOptLn,
optimizeInfo.bOptSignal,
optimizeInfo.fStretchScale,
vertInfo.end,
vertInfo.fEndStretch,
vertInfo.pfEndFaceStretch);
float fDiffernece =
CaculateUVDistanceSquare(vertInfo.start, vertInfo.end);
// 4. Bisearch the position along the segment between center and end.
// get the position with smallest vertex stretch
float fPrevDiff = fDiffernece;
while (fDiffernece > fToleranceLength)
{
middle.x = (vertInfo.start.x + vertInfo.end.x) / 2;
middle.y = (vertInfo.start.y + vertInfo.end.y) / 2;
TryAdjustVertexParamStretch(
pOptimizeVertex,
optimizeInfo.bOptLn,
optimizeInfo.bOptSignal,
optimizeInfo.fStretchScale,
middle,
fTempStretch,
vertInfo.pfWorkStretch);
// When Optimize bounday vertex signal stretch, if the L2 squared Stretch is 0,
// this mean's no signal change on faces around the vertex, we can decrease their
// 2D area.
if (vertInfo.fStartStretch == vertInfo.fEndStretch &&
pOptimizeVertex->bIsBoundary &&
optimizeInfo.bOptSignal &&
IsInZeroRange(vertInfo.fEndStretch))
{
float fStatArea = GetFaceAreaAroundVertex(
pOptimizeVertex, vertInfo.start);
float fEndArea = GetFaceAreaAroundVertex(
pOptimizeVertex, vertInfo.end);
if (fStatArea < fEndArea)
{
vertInfo.fEndStretch = fTempStretch;
vertInfo.end = middle;
}
else
{
vertInfo.fStartStretch = fTempStretch;
vertInfo.start = middle;
}
}
else if (vertInfo.fStartStretch < vertInfo.fEndStretch)
{
vertInfo.fEndStretch = fTempStretch;
vertInfo.end = middle;
}
else
{
vertInfo.fStartStretch = fTempStretch;
vertInfo.start = middle;
}
fDiffernece =
CaculateUVDistanceSquare(vertInfo.start, vertInfo.end);
if (IsInZeroRange2(fPrevDiff - fDiffernece) || fPrevDiff < fDiffernece)
{
break;
}
fPrevDiff = fDiffernece;
}
if (vertInfo.fStartStretch == vertInfo.fEndStretch &&
pOptimizeVertex->bIsBoundary &&
optimizeInfo.bOptSignal &&
IsInZeroRange(vertInfo.fEndStretch))
{
float fStatArea = GetFaceAreaAroundVertex(
pOptimizeVertex, vertInfo.start);
float fEndArea = GetFaceAreaAroundVertex(
pOptimizeVertex, vertInfo.end);
if (fStatArea > fEndArea)
{
vertInfo.start = vertInfo.end;
vertInfo.fStartStretch = vertInfo.fEndStretch;
}
}
else if (vertInfo.fStartStretch > vertInfo.fEndStretch)
{
vertInfo.start = vertInfo.end;
vertInfo.fStartStretch = vertInfo.fEndStretch;
}
else {}
iteration++;
}
if (vertInfo.fStartStretch == vertInfo.fEndStretch &&
pOptimizeVertex->bIsBoundary &&
optimizeInfo.bOptSignal &&
IsInZeroRange(vertInfo.fEndStretch))
{
vertInfo.fEndStretch = vertInfo.fStartStretch;
vertInfo.end = vertInfo.start;
float fOldArea = GetFaceAreaAroundVertex(
pOptimizeVertex, pOptimizeVertex->uv);
float fNewArea = GetFaceAreaAroundVertex(
pOptimizeVertex, vertInfo.end);
if (fOldArea > fNewArea)
{
TryAdjustVertexParamStretch(
pOptimizeVertex,
optimizeInfo.bOptLn,
optimizeInfo.bOptSignal,
optimizeInfo.fStretchScale,
vertInfo.end,
vertInfo.fEndStretch,
vertInfo.pfEndFaceStretch);
UpdateOptimizeResult(
optimizeInfo,
pOptimizeVertex,
vertInfo.end,
vertInfo.fEndStretch,
vertInfo.pfEndFaceStretch);
return true;
}
else
{
return false;
}
}
// If Precomputed candidate position is better, use precomputed one.
if (vertInfo.fStartStretch >= fOriginalEndStretch)
{
vertInfo.fEndStretch = fOriginalEndStretch;
vertInfo.end = originalEnd;
}
else
{
vertInfo.fEndStretch = vertInfo.fStartStretch;
vertInfo.end = vertInfo.start;
}
// Update vertex adjacent faces' stretch
if (vertInfo.fEndStretch < INFINITE_STRETCH &&
vertInfo.fEndStretch < fOriginalStartStretch)
{
TryAdjustVertexParamStretch(
pOptimizeVertex,
optimizeInfo.bOptLn,
optimizeInfo.bOptSignal,
optimizeInfo.fStretchScale,
vertInfo.end,
vertInfo.fEndStretch,
vertInfo.pfEndFaceStretch);
UpdateOptimizeResult(
optimizeInfo,
pOptimizeVertex,
vertInfo.end,
vertInfo.fEndStretch,
vertInfo.pfEndFaceStretch);
return true;
}
else
{
return false;
}
}