HRESULT CIsochartMesh::IsomapParameterlization()

in UVAtlas/isochart/isochartmesh.cpp [1184:1363]


HRESULT CIsochartMesh::IsomapParameterlization(
    bool& bIsLikePlane,
    size_t& dwPrimaryEigenDimension,
    size_t& dwMaxEigenDimension,
    float** ppfVertGeodesicDistance,
    float** ppfVertCombineDistance,
    float** ppfVertMappingCoord)
{
    assert(ppfVertGeodesicDistance != nullptr);
    assert(ppfVertCombineDistance != nullptr);
    assert(ppfVertMappingCoord != nullptr);

    HRESULT hr = S_OK;
    bIsLikePlane = false;

    bool bIsSignalSpecialized = IsIMTSpecified();
    float* pfVertGeodesicDistance = nullptr;
    float* pfVertCombinedDistance = nullptr;
    float* pfGeodesicMatrix = nullptr;
    float* pfVertMappingCoord = nullptr;
    size_t dwLandmarkNumber = 0;
    size_t dwCalculatedDimension = 0;

    // 1. Calculate the landmark vertices
    if (FAILED(hr = CalculateLandmarkVertices(
        MIN_LANDMARK_NUMBER,
        dwLandmarkNumber)))
    {
        goto LEnd;
    }

    // 2. Calculate the geodesic distance matrix of landmark vertices
    pfVertGeodesicDistance = new (std::nothrow) float[dwLandmarkNumber * m_dwVertNumber];

    if (bIsSignalSpecialized)
    {
        pfVertCombinedDistance = new (std::nothrow) float[dwLandmarkNumber * m_dwVertNumber];
    }
    else
    {
        pfVertCombinedDistance = pfVertGeodesicDistance;
    }
    pfGeodesicMatrix = new (std::nothrow) float[dwLandmarkNumber * dwLandmarkNumber];
    if (!pfVertGeodesicDistance || !pfGeodesicMatrix || !pfVertCombinedDistance)
    {
        hr = E_OUTOFMEMORY;
        goto LEnd;
    }

    if (FAILED(hr = CalculateGeodesicDistance(
        m_landmarkVerts,
        pfVertCombinedDistance,
        pfVertGeodesicDistance)))
    {
        goto LEnd;
    }

#if USING_COMBINED_DISTANCE_TO_PARAMETERIZE
    CalculateGeodesicMatrix(
        m_landmarkVerts,
        pfVertCombinedDistance,
        pfGeodesicMatrix);

#else
    CalculateGeodesicMatrix(
        m_landmarkVerts,
        pfVertGeodesicDistance,
        pfGeodesicMatrix);
#endif

    // 4. Perform Isomap to do surface spectral analysis
    if (m_bIsSubChart)
    {
        dwMaxEigenDimension = std::min(SUB_CHART_EIGEN_DIMENSION, dwLandmarkNumber);
    }
    else
    {
        dwMaxEigenDimension = std::min(ORIGINAL_CHART_EIGEN_DIMENSION, dwLandmarkNumber);
    }
    if (FAILED(hr = m_isoMap.Init(
        dwLandmarkNumber,
        pfGeodesicMatrix)))
    {
        goto LEnd;
    }

    if (FAILED(hr = m_isoMap.ComputeLargestEigen(
        dwMaxEigenDimension,
        dwCalculatedDimension)))
    {
        goto LEnd;
    }
    SAFE_DELETE_ARRAY(pfGeodesicMatrix)

        assert(dwMaxEigenDimension >= dwCalculatedDimension);

    dwMaxEigenDimension = dwCalculatedDimension;
    dwPrimaryEigenDimension = 0;
    if (FAILED(hr = m_isoMap.GetPrimaryEnergyDimension(
        PRIMARY_EIGEN_ENERGY_PERCENT,
        dwPrimaryEigenDimension)))
    {
        goto LEnd;
    }

    // If current chart degenerated to a point, dwPrimaryEigenDimension
    // will equal to 0
    if (0 == dwPrimaryEigenDimension)
    {
        goto LEnd;
    }

    if (FAILED(hr = ProcessPlaneLikeShape(
        dwCalculatedDimension,
        dwPrimaryEigenDimension,
        bIsLikePlane)) || bIsLikePlane)
    {
        goto LEnd;
    }

    // if CIsomap::GetPrimaryEnergyDimension discard too many vector
    // demensions which are needed by special-shape detecting, just
    // set it back to DIMENSION_TO_CHECK_SPECIAL_SHAPE
    if (dwPrimaryEigenDimension < DIMENSION_TO_CHECK_SPECIAL_SHAPE
        && dwCalculatedDimension >= DIMENSION_TO_CHECK_SPECIAL_SHAPE)
    {
        dwPrimaryEigenDimension = DIMENSION_TO_CHECK_SPECIAL_SHAPE;
    }

    //5. Compute n-dimensional embedding coordinates of each vertex
    //   here, n = dwPrimaryEigenDimension
    pfVertMappingCoord = new (std::nothrow) float[m_dwVertNumber * dwPrimaryEigenDimension];
    if (!pfVertMappingCoord)
    {
        hr = E_OUTOFMEMORY;
        goto LEnd;
    }

#if USING_COMBINED_DISTANCE_TO_PARAMETERIZE
    if (FAILED(hr = CalculateVertMappingCoord(
        pfVertCombinedDistance,
        dwLandmarkNumber,
        dwPrimaryEigenDimension,
        pfVertMappingCoord)))
    {
        goto LEnd;
    }
#else
    if (FAILED(hr = CalculateVertMappingCoord(
        pfVertGeodesicDistance,
        dwLandmarkNumber,
        dwPrimaryEigenDimension,
        pfVertMappingCoord)))
    {
        goto LEnd;
    }

#endif

    m_bIsParameterized = true;
LEnd:
    SAFE_DELETE_ARRAY(pfGeodesicMatrix)
        if (FAILED(hr))
        {
            SAFE_DELETE_ARRAY(pfVertGeodesicDistance)
                if (bIsSignalSpecialized)
                {
                    SAFE_DELETE_ARRAY(pfVertCombinedDistance)
                }
            SAFE_DELETE_ARRAY(pfVertMappingCoord)
        }
        else
        {
            *ppfVertCombineDistance = pfVertCombinedDistance;
            *ppfVertGeodesicDistance = pfVertGeodesicDistance;
            *ppfVertMappingCoord = pfVertMappingCoord;
        }

    return hr;
}