HRESULT CIsochartMesh::MergeAdjacentChart()

in UVAtlas/isochart/mergecharts.cpp [305:482]


HRESULT CIsochartMesh::MergeAdjacentChart(
    ISOCHARTMESH_ARRAY& children,
    uint32_t dwMainChartID,
    size_t dwTotalFaceNumber,
    bool* pbMergeFlag,
    XMFLOAT3* pChartNormal,
    bool& bMerged)
{
    HRESULT hr = S_OK;
    bMerged = false;

    CIsochartMesh* pMainChart = children[dwMainChartID];

    auto& adjacentChartList = pMainChart->m_adjacentChart;
    size_t dwAdjacentChartNumber = adjacentChartList.size();
    if (dwAdjacentChartNumber == 0)
    {
        return hr;
    }

    // 1. Sort adjacent sub-charts according to the average normal 
    // alwasy try to merge charts having approximate normals firstly
    for (size_t i = 0; i < dwAdjacentChartNumber - 1; i++)
    {
        if (!children[adjacentChartList[i]])
        {
            continue;
        }
        for (size_t j = i + 1; j < dwAdjacentChartNumber; j++)
        {
            if (!children[adjacentChartList[j]])
            {
                continue;
            }

            float fTemp1, fTemp2;
            fTemp1 = XMVectorGetX(XMVector3Dot(
                XMLoadFloat3(pChartNormal + dwMainChartID), XMLoadFloat3(pChartNormal + adjacentChartList[i])));

            fTemp2 = XMVectorGetX(XMVector3Dot(
                XMLoadFloat3(pChartNormal + dwMainChartID), XMLoadFloat3(pChartNormal + adjacentChartList[j])));

            if (fTemp1 < fTemp2)
            {
                uint32_t dwTemp = adjacentChartList[i];
                adjacentChartList[i] = adjacentChartList[j];
                adjacentChartList[j] = dwTemp;
            }
        }
    }

    // 2 . Try to merge current chart to its adjacent charts.
    uint32_t dwAdditionalChartID = INVALID_INDEX;

    CIsochartMesh* pMergedChart = nullptr;
    CIsochartMesh* pAddjacentChart = nullptr;
    size_t dwMaxFaceNumAfterMerging
        = std::max<size_t>(size_t(float(dwTotalFaceNumber) * MAX_MERGE_RATIO),
            size_t(MAX_MERGE_FACE_NUMBER));

    for (size_t i = 0; i < dwAdjacentChartNumber; i++)
    {
        uint32_t dwAdjacentChartID = adjacentChartList[i];

        // 2.1. Don't try merage this chart, if its has failed to merage other charts
        if (!pbMergeFlag[dwAdjacentChartID])
        {
            continue;
        }

        pAddjacentChart = children[dwAdjacentChartID];
        if (!pAddjacentChart)
        {
            continue;
        }
        if (0 == pAddjacentChart->GetChart3DArea())
        {
            continue;
        }

        // 2.2. Don't try to get a very large chart
        size_t dwMergedFaceNumber = pMainChart->GetFaceNumber() + pAddjacentChart->GetFaceNumber();
        if (dwMergedFaceNumber > dwMaxFaceNumAfterMerging)
        {
            continue;
        }

        // 2.3.  try to merge.
        FAILURE_RETURN(
            TryMergeChart(children, pMainChart, pAddjacentChart, &pMergedChart));
        if (!pMergedChart)
        {
            continue;
        }

        // 2.4 try to get right initial parameterization
        bool bParameterSucceed = false;
        if (FAILED(hr = pMergedChart->TryParameterize(bParameterSucceed)))
        {
            delete pMergedChart;
            pMergedChart = nullptr;
            return hr;
        }
        if (!bParameterSucceed)
        {
            delete pMergedChart;
            pMergedChart = nullptr;
            continue;
        }

        // 2.5 Check if the meraged chart also satisfied the stretch
        bool bCanMerge = true;
        if (FAILED(hr = CheckMergeResult(
            children,
            pMainChart,
            pAddjacentChart,
            pMergedChart,
            bCanMerge)))
        {
            delete pMergedChart;
            pMergedChart = nullptr;
            continue;
        }
        if (bCanMerge)
        {
            dwAdditionalChartID = dwAdjacentChartID;
            break;
        }
        else
        {
            delete pMergedChart;
            pMergedChart = nullptr;
        }
    }

    if (!pMergedChart)
    {
        pbMergeFlag[dwMainChartID] = false;
        bMerged = false;
        return S_OK;
    }

    // 3. Adjust the adjacence of merged charts and other charts
    for (size_t i = 0; i < pMergedChart->m_adjacentChart.size(); i++)
    {
        pAddjacentChart = children[pMergedChart->m_adjacentChart[i]];
        if (!pAddjacentChart)
        {
            continue;
        }
        removeItem(pAddjacentChart->m_adjacentChart, dwAdditionalChartID);
        if (!addNoduplicateItem(pAddjacentChart->m_adjacentChart,
            dwMainChartID))
        {
            delete pMergedChart;
            return E_OUTOFMEMORY;
        }
    }

    // Delete the two sub-charts that joined the merging.
    if (children[dwAdditionalChartID]->m_bIsInitChart)
        children[dwAdditionalChartID] = nullptr;
    else
    {
        delete children[dwAdditionalChartID];
        children[dwAdditionalChartID] = nullptr;
    }

    if (!pMainChart->m_bIsInitChart)
        delete pMainChart;

    // Assign merged chart to main chart, caculate the normal of the new chart.
    children[dwMainChartID] = pMergedChart;
    pMergedChart->CalculateAveragNormal(pChartNormal + dwMainChartID);
    bMerged = true;

    return hr;
}