HRESULT CIsochartMesh::ProcessPlaneLikeShape()

in UVAtlas/isochart/meshpartitionchart.cpp [1295:1557]


HRESULT CIsochartMesh::ProcessPlaneLikeShape(
    size_t dwCalculatedDimension,
    size_t dwPrimaryEigenDimension,
    bool& bPlaneLikeShape)
{
    HRESULT hr = S_OK;

    bPlaneLikeShape = false;

#if USING_COMBINED_DISTANCE_TO_PARAMETERIZE
    if (IsIMTSpecified())
    {
        return hr;
    }
#endif

    // When processing sub-chart, only process the chart which is exactly isomorphic
    // to a plane. Otherwise, self overlapping can be easily generated.
    if (m_bIsSubChart && dwCalculatedDimension > 2)
    {
        return hr;
    }

    // Only used to expand charts whose energy centralizes into one plane.
    if (dwPrimaryEigenDimension > 2)
    {
        return hr;
    }

    // Find one face as the standard face to expand all other faces
    uint32_t dwStandardFaceID = INVALID_FACE_ID;
    for (uint32_t i = 0; i < m_dwFaceNumber; i++)
    {
        if (m_baseInfo.pfFaceAreaArray[m_pFaces[i].dwIDInRootMesh]
    > ISOCHART_ZERO_EPS
            && INVALID_FACE_ID == dwStandardFaceID)
        {
            dwStandardFaceID = i;
            break;
        }
    }
    if (INVALID_FACE_ID == dwStandardFaceID)
    {
        return hr;
    }

    XMVECTOR axisX, axisY, axisZ;
    XMVECTOR normalDelta;
    XMFLOAT3 v1, v2;
    XMVECTOR temp[3];

    std::queue<uint32_t> faceQueue;

    std::unique_ptr<bool[]> rgbVertProcessed(new (std::nothrow) bool[m_dwVertNumber]);
    std::unique_ptr<bool[]> rgbFaceAdded(new (std::nothrow) bool[m_dwFaceNumber]);
    if (!rgbVertProcessed || !rgbFaceAdded)
    {
        return E_OUTOFMEMORY;
    }

    memset(rgbFaceAdded.get(), 0, sizeof(bool) * m_dwFaceNumber);
    memset(rgbVertProcessed.get(), 0, sizeof(bool) * m_dwVertNumber);

    // Parameterize the standard face to UV plane
    XMVECTOR vV[3];
    ISOCHARTFACE& face = m_pFaces[dwStandardFaceID];
    for (size_t i = 0; i < 3; i++)
    {
        ISOCHARTVERTEX& v = m_pVerts[face.dwVertexID[i]];
        vV[i] = XMLoadFloat3(m_baseInfo.pVertPosition + v.dwIDInRootMesh);
    }

    float fMinDot = FLT_MAX;
    uint32_t dwOrgIndex = INVALID_INDEX;
    // Find a vertex whose adjacent 2 edges has angle closest to PI/4
    for (uint32_t i = 0; i < 3; i++)
    {
        axisX = XMVectorSubtract(vV[(i + 1) % 3], vV[i]);
        axisY = XMVectorSubtract(vV[(i + 2) % 3], vV[i]);

        axisX = XMVector3Normalize(axisX);
        axisY = XMVector3Normalize(axisY);

        float fDot = fabsf(XMVectorGetX(XMVector3Dot(axisX, axisY)));
        if (fMinDot > fDot)
        {
            fMinDot = fDot;
            dwOrgIndex = i;
        }
    }

    _Analysis_assume_(dwOrgIndex < 3);

    axisX = XMVectorSubtract(vV[(dwOrgIndex + 1) % 3], vV[dwOrgIndex]);
    axisY = XMVectorSubtract(vV[(dwOrgIndex + 2) % 3], vV[dwOrgIndex]);


    axisZ = XMVector3Cross(axisX, axisY);
    axisY = XMVector3Cross(axisZ, axisX);

    axisX = XMVector3Normalize(axisX);
    axisY = XMVector3Normalize(axisY);
    axisZ = XMVector3Normalize(axisZ);

    for (size_t i = 0; i < 3; i++)
    {
        normalDelta = XMVectorSubtract(vV[(dwOrgIndex + i) % 3], vV[dwOrgIndex]);

        m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.x =
            XMVectorGetX(XMVector3Dot(normalDelta, axisX));

        m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.y =
            XMVectorGetX(XMVector3Dot(normalDelta, axisY));

        temp[(dwOrgIndex + i) % 3] = XMVectorSet(
            m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.x,
            m_pVerts[face.dwVertexID[(dwOrgIndex + i) % 3]].uv.y,
            0, 0);

        rgbVertProcessed[face.dwVertexID[(dwOrgIndex + i) % 3]] = true;
    }

    XMStoreFloat3(&v1, XMVectorSubtract(temp[1], temp[0]));
    XMStoreFloat3(&v2, XMVectorSubtract(temp[2], temp[0]));
    bool bPositive = (CalculateZOfVec3Cross(&v1, &v2) >= 0);

    // From iteratively lay faces adjacent to the parameterized faces onto UV plane.
    try
    {
        faceQueue.push(dwStandardFaceID);

        rgbFaceAdded[dwStandardFaceID] = true;
        while (!faceQueue.empty())
        {
            uint32_t dwFaceID = faceQueue.front();
            faceQueue.pop();
            ISOCHARTFACE& curFace = m_pFaces[dwFaceID];
            for (size_t i = 0; i < 3; i++)
            {
                if (!rgbVertProcessed[curFace.dwVertexID[i]])
                {
                    uint32_t vId0 = curFace.dwVertexID[(i + 1) % 3];
                    uint32_t vId1 = curFace.dwVertexID[(i + 2) % 3];
                    assert(rgbVertProcessed[vId0]);
                    assert(rgbVertProcessed[vId1]);

                    uint32_t vId2 = curFace.dwVertexID[i];

                    vV[0] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId0].dwIDInRootMesh);
                    vV[1] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId1].dwIDInRootMesh);
                    vV[2] = XMLoadFloat3(m_baseInfo.pVertPosition + m_pVerts[vId2].dwIDInRootMesh);

                    XMVECTOR vv1 = XMVectorSubtract(vV[1], vV[0]);
                    XMVECTOR vv2 = XMVectorSubtract(vV[2], vV[0]);

                    float fLen1 = XMVectorGetX(XMVector3Length(vv1));
                    float fLen2 = XMVectorGetX(XMVector3Length(vv2));

                    if (IsInZeroRange(fLen1))
                    {
                        return S_OK;
                    }
                    if (IsInZeroRange(fLen2))
                    {
                        m_pVerts[vId2].uv = m_pVerts[vId0].uv;
                        rgbVertProcessed[vId2] = true;
                        break;
                    }

                    float cosB = XMVectorGetX(XMVector3Dot(vv1, vv2)) / (fLen1 * fLen2);
                    if (cosB < -1.0f)
                    {
                        cosB = -1.0f;
                    }
                    if (cosB > 1.0f)
                    {
                        cosB = 1.0f;
                    }

                    float sinB = IsochartSqrtf(1.0f - cosB * cosB);

                    XMFLOAT2 v2D;
                    XMStoreFloat2(&v2D, XMVector2Normalize(
                        XMVectorSubtract(XMLoadFloat2(&m_pVerts[vId1].uv), XMLoadFloat2(&m_pVerts[vId0].uv))));

                    float x = v2D.x * cosB - v2D.y * sinB;
                    float y = v2D.y * cosB + v2D.x * sinB;

                    temp[i] = XMVectorSet(x, y, 0, 0);
                    temp[(i + 1) % 3] = XMVectorSet(0, 0, 0, 0);
                    temp[(i + 2) % 3] = XMVectorSet(v2D.x, v2D.y, 0, 0);


                    XMStoreFloat3(&v1, XMVectorSubtract(temp[1], temp[0]));
                    XMStoreFloat3(&v2, XMVectorSubtract(temp[2], temp[0]));

                    bool bPositive1 = (CalculateZOfVec3Cross(&v1, &v2) >= 0);

                    if ((bPositive && !bPositive1)
                        || (!bPositive && bPositive1))
                    {
                        sinB = -sinB;
                        x = v2D.x * cosB - v2D.y * sinB;
                        y = v2D.y * cosB + v2D.x * sinB;
                    }

                    m_pVerts[vId2].uv.x = fLen2 * x + m_pVerts[vId0].uv.x;
                    m_pVerts[vId2].uv.y = fLen2 * y + m_pVerts[vId0].uv.y;

                    assert(std::isfinite(double(m_pVerts[vId2].uv.x)) &&
                        std::isfinite(double(m_pVerts[vId2].uv.y)));

                    if (!std::isfinite(double(m_pVerts[vId2].uv.x)) ||
                        !std::isfinite(double(m_pVerts[vId2].uv.y)))
                    {
                        DPF(0, "ProcessPlaneLikeShape failed due to INFs");
                        return E_FAIL;
                    }

                    rgbVertProcessed[vId2] = true;
                    break;
                }
            }

            for (size_t i = 0; i < 3; i++)
            {
                ISOCHARTEDGE& edge = m_edges[curFace.dwEdgeID[i]];
                uint32_t dwAdjacent = edge.dwFaceID[0];
                if (dwAdjacent == curFace.dwID)
                {
                    dwAdjacent = edge.dwFaceID[1];
                }
                if (dwAdjacent != INVALID_FACE_ID &&
                    !rgbFaceAdded[dwAdjacent])
                {
                    faceQueue.push(dwAdjacent);
                    rgbFaceAdded[dwAdjacent] = true;
                }
            }
        }
    }
    catch (std::bad_alloc&)
    {
        return E_OUTOFMEMORY;
    }

#if CHECK_OVER_LAPPING_BEFORE_OPT_INFINIT
    bool bIsOverlapping = false;

    bIsOverlapping = IsSelfOverlapping(this);
    if (bIsOverlapping)
    {
        DPF(1, "Generate self overlapping chart when processing plane-like chart");
        return S_OK;
    }
#endif

    hr = OptimizeGeoLnInfiniteStretch(bPlaneLikeShape);
    m_bIsParameterized = bPlaneLikeShape;
    m_fParamStretchL2 = m_fBaseL2Stretch;

    return hr;
}