inline static HRESULT MergeBorders()

in UVAtlas/isochart/packingcharts.cpp [1713:1945]


    inline static HRESULT MergeBorders(
        PackingDirection direction,
        VERTEX_ARRAY& atlasBorder,
        VERTEX_ARRAY& chartBorder)
    {
        Axis TangentAxis = XAxis;
        Axis RadialAxis = XAxis;

        // If a vertex on one border is on the discardLocation
        // side of another border, don't add it to the updated
        // border
        // For example, when updating left border, vertex A on
        // border 1 is on the right side of border 2, A will be
        // discarded
        VertexLocation discardLocation = NotDefined;
        bool bPackingFromLowerPlace = false;

        switch (direction)
        {
        case FromRight:
        {
            discardLocation = LeftToBorder;
            TangentAxis = YAxis; // y
            RadialAxis = XAxis; // x
            bPackingFromLowerPlace = false;
            break;
        }
        case FromLeft:
        {
            discardLocation = RightToBorder;
            TangentAxis = YAxis; // y
            RadialAxis = XAxis; // x
            bPackingFromLowerPlace = true;
            break;
        }
        case FromTop:
        {
            discardLocation = BelowBorder;
            TangentAxis = XAxis; // x
            RadialAxis = YAxis; // y
            bPackingFromLowerPlace = false;
            break;
        }
        case FromBottom:
        {
            discardLocation = AboveBorder;
            TangentAxis = XAxis; // x
            RadialAxis = YAxis; // y
            bPackingFromLowerPlace = true;
            break;
        }
        default:
            assert(false);
            break;
        }

        size_t dwAtlasBorderSize = atlasBorder.size();
        size_t dwChartBorderSize = chartBorder.size();

        VertexLocation location;
        float fDistance;

        VERTEX_ARRAY tempBorder;

        try
        {
            // 1. Before merge chart border and atlas border, find the
            // correspond segments on each border. This operation is just
            // used to decrease useless computation
            size_t dwAtlasBorderStart, dwAtlasBorderEnd;
            size_t dwChartBorderStart, dwChartBorderEnd;

            if (!FindCorrespondSegmentsOfBorders(
                atlasBorder,
                chartBorder,
                dwAtlasBorderStart,
                dwAtlasBorderEnd,
                dwChartBorderStart,
                dwChartBorderEnd,
                TangentAxis))
            {
                // if 2 borders have no correspond segments, just merge them according to
                // the increasing order of coordinate in tangent direction
                if (VECTOR_ITEM(&atlasBorder[dwAtlasBorderSize - 1]->uv, TangentAxis) <
                    VECTOR_ITEM(&chartBorder[0]->uv, TangentAxis))
                {
                    atlasBorder.insert(atlasBorder.end(), chartBorder.cbegin(), chartBorder.cend());
                }
                else if (VECTOR_ITEM(&atlasBorder[0]->uv, TangentAxis) >
                    VECTOR_ITEM(&chartBorder[dwChartBorderSize - 1]->uv, TangentAxis))
                {
                    tempBorder.insert(tempBorder.end(), atlasBorder.cbegin(), atlasBorder.cend());
                    atlasBorder.clear();

                    atlasBorder.insert(atlasBorder.end(), chartBorder.cbegin(), chartBorder.cend());

                    atlasBorder.insert(atlasBorder.end(), tempBorder.cbegin(), tempBorder.cend());
                }
                else
                {
                    assert(false);
                }
                return S_OK;
            }

            // 2. Add vertices before correspond segments into new border
            for (size_t i = 0; i < dwAtlasBorderStart; i++)
            {
                tempBorder.push_back(atlasBorder[i]);
            }
            for (size_t i = 0; i < dwChartBorderStart; i++)
            {
                tempBorder.push_back(chartBorder[i]);
            }

            // 3. Merge the correspond segments

            size_t ii = dwAtlasBorderStart;
            size_t jj = dwChartBorderStart;
            while (ii <= dwAtlasBorderEnd && jj <= dwChartBorderEnd)
            {
                float tangent1 = VECTOR_ITEM(&atlasBorder[ii]->uv, TangentAxis);
                float tangent2 = VECTOR_ITEM(&chartBorder[jj]->uv, TangentAxis);

                // 3.1 Check if current vertex on old atlas border can be a vertex
                // on new atlas border
                if (tangent1 < tangent2)
                {
                    location = CalculateVertexLocationToBorder(
                        chartBorder,
                        dwChartBorderStart,
                        dwChartBorderEnd,
                        atlasBorder[ii]->uv,
                        0,
                        fDistance,
                        TangentAxis);


                    if (location != discardLocation)
                    {
                        tempBorder.push_back(atlasBorder[ii]);
                    }
                    dwAtlasBorderStart = ii;
                    ii++;
                }
                // 3.2 Check if current vertex on chart border can be a vertex
                // on new atlas border
                else if (tangent1 > tangent2)
                {
                    location = CalculateVertexLocationToBorder(
                        atlasBorder,
                        dwAtlasBorderStart,
                        dwAtlasBorderEnd,
                        chartBorder[jj]->uv,
                        0,
                        fDistance,
                        TangentAxis);

                    if (location != discardLocation)
                    {
                        tempBorder.push_back(chartBorder[jj]);
                    }
                    dwChartBorderStart = jj;
                    jj++;
                }
                // 3.3 compare 2 vertices on different borders, and add
                // one into new atlas border.
                else
                {
                    float fRadia1 = VECTOR_ITEM(&atlasBorder[ii]->uv, RadialAxis);
                    float fRadia2 = VECTOR_ITEM(&chartBorder[jj]->uv, RadialAxis);

                    if (bPackingFromLowerPlace)
                    {
                        if (fRadia1 < fRadia2)
                        {
                            tempBorder.push_back(atlasBorder[ii]);
                        }
                        else if (fRadia1 > fRadia2)
                        {
                            tempBorder.push_back(chartBorder[jj]);
                        }
                        else
                        {
                            tempBorder.push_back(chartBorder[jj]);
                            //assert(fRadia1 != fRadia2);
                        }
                    }
                    else
                    {
                        if (fRadia1 > fRadia2)
                        {
                            tempBorder.push_back(atlasBorder[ii]);
                        }
                        else if (fRadia1 < fRadia2)
                        {
                            tempBorder.push_back(chartBorder[jj]);
                        }
                        else
                        {
                            tempBorder.push_back(chartBorder[jj]);
                            //assert(fRadia1 != fRadia2);
                        }
                    }
                    dwAtlasBorderStart = ii;
                    dwChartBorderStart = jj;
                    ii++;
                    jj++;
                }
            }
            // 4. Add vertices after correspond segments into new border
            for (size_t i = ii; i < dwAtlasBorderSize; i++)
            {
                tempBorder.push_back(atlasBorder[i]);
            }
            for (size_t i = jj; i < dwChartBorderSize; i++)
            {
                tempBorder.push_back(chartBorder[i]);
            }

            // 6. Update atlas border.
            atlasBorder.clear();

            atlasBorder.insert(atlasBorder.end(), tempBorder.cbegin(), tempBorder.cend());

        }
        catch (std::bad_alloc&)
        {
            return E_OUTOFMEMORY;
        }

        return S_OK;
    }