bool CIsochartMesh::OptimizeVertexStretchAroundCenter()

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;
    }
}