多个圆环组成的区域的合并

最近很忙,忙的连写日记的功夫都没有了。

有个项目的需求是需要把多个圆环的区域合并。得到包络线和内部空洞的线。

 

查了查google。类似的实现比较少见。简单的说说我的实现方法。

基本想法就是通过判断一段圆弧和圆环组的关系,来判断这段圆弧是否是属于合并后的包络线的一部分

 

如图,左边的圆盒右边的圆相交。则这两个圆就被分成了两段。

对外包络线,如上图。将所有圆环的外圆(粗线)相交。把每个圆都切成一段段的圆弧,如左边的黑色圆,则切成了黑色段和黑色+红色的两段。对每一段,我们测试这一段弧是否在其它圆环的大圆内部,如果这段圆弧不在其它的环的大圆内部(不包括内部小圆),则这段圆弧属于外包络线的一部分。否则不是。

 

内部透空的小圆的合并稍微麻烦一些。因为透空的部分,不光是小圆的弧,还会有大圆弧的参与。

考察小圆的圆弧,同样的,我们将小圆 和其它圆环的求交点,把小圆切成一段段的弧线(注意小圆和其它环求交的时候,就要跟这个环的大小圆都交一遍,而不光是小圆和小圆了)。如果这一段弧线不在这组圆环内(指的是环的内部,而不是大圆的内部),则表示这段弧是属于内包络线的一部分。

考察大圆的弧,大圆产生内包络线的原因主要是大圆会抵消一部分小圆的透空作用。所以同样的我们将大圆 和其它圆环的求交点,把小圆切成一段段的弧线--跟外包络不同,这次求交的时候,该大圆要和其它圆环的大小圆都求交,而不光是大圆对大圆。 对每一段圆弧,如果弧线不在环的内部,而且该段弧应该还需要位于某个环的小圆内部(看图就明白为什么了)。则该大圆弧也是内包络的一部分。

 

这里求圆弧在环的内部还是在大小圆内,有一个偷懒的方法。因为我们已经保证这段圆弧除了两个端点以外不和其它任何弧相交,所以只要用这段弧的中点来代替弧来作判断就好了。使得复杂性大大降低了。

以上是效果图,三个环合并成一个区域。

 

以下是主要代码

 

class CRingGroup
{
public:
    bool  load(const wchar_t* _ringGroupsFile)
    {
        xXmlDocument doc;
        if(doc.load(_ringGroupsFile) == false )
            return false;
       
        xXmlNode::XmlNodes ringNodes;
        doc.findAllNode(L"ring" , ringNodes);
        if(ringNodes.size() == 0)
            return false;

        for(size_t i = 0 ; i < ringNodes.size() ; i ++)
        {
            xXmlNode* pNode = ringNodes[i];
            xRing _ring;
            _ring.m_InnerR = pNode->float_value(L"r1");
            _ring.m_OutR   = pNode->float_value(L"r2");
            _ring.m_Center = pNode->get_value<float2>(L"center");
            m_vRings.push_back(_ring);
        }
    }

    void toSplineDrawer(CSplineDraw& drawer)
    {
        drawer.m_vArcs.clear();
        for(int i = 0 ; i < m_vRings.size() ; i ++)
        {
            std::vector<float> CutPoints;
            xRing& ring = m_vRings[i];
            ring.toArcs(CutPoints , true , drawer.m_vArcs);
        }
       
        for(int i = 0 ; i < m_vRings.size() ; i ++)
        {
            std::vector<float> CutPoints;
            xRing& ring = m_vRings[i];
            ring.toArcs(CutPoints , false , drawer.m_vArcs);
        }
    }
   
    void toInnerLine(std::vector<xArc>& vOut)
    {
        for(int i = 0 ; i < m_vRings.size() ; i ++)
        {
            std::vector<float> vCutPoints;
            std::vector<xArc>  vArcs;

            //先来切内圆
            xRing& _ring = m_vRings[i];
            for(int j = 0 ; j < m_vRings.size() ; j ++)
            {
                if(j == i) continue;
                xRing& _ring2 = m_vRings[j];
                _ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR   , vCutPoints , false );
                _ring.CutByCircle(_ring2.m_Center , _ring2.m_InnerR , vCutPoints , false);
            }
           
            _ring.toArcs(vCutPoints   , false  , vArcs);

            //内圆的弧,必须在所有的外圆的外部。
            for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
            {
                xArc& _arc = vArcs[iArc];
                bool bInRing = false;
                for(int k = 0 ; k < m_vRings.size() ; k ++)
                {
                    if( k == i ) continue;
                    xRing& _ring2 = m_vRings[k];
                    if( true == _ring2.IsInRing( _arc ) )
                    {
                        bInRing = true;
                    }
                }

                //
                if(bInRing == false)
                {
                    vOut.push_back(_arc);
                }
            }

            //内圆切完了。来切外圆套在其它内圆中的部分。
            vCutPoints.clear();
            vArcs.clear();
            for(int j = 0 ; j < m_vRings.size() ; j ++)
            {
                if(j == i) continue;
                xRing& _ring2 = m_vRings[j];
                _ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR   , vCutPoints , true );
                _ring.CutByCircle(_ring2.m_Center , _ring2.m_InnerR , vCutPoints , true);
            }

            _ring.toArcs(vCutPoints   , true  , vArcs);

            //内圆的弧,必须在所有的外圆的外部。
            for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
            {
                xArc& _arc = vArcs[iArc];
                bool bInRing      = false;
                bool bInSmallRing = false;
                for(int k = 0 ; k < m_vRings.size() ; k ++)
                {
                    if( k == i ) continue;
                    xRing& _ring2 = m_vRings[k];
                    if( true == _ring2.IsInRing( _arc ) )
                    {
                        bInRing = true;
                    }

                    if( true == _ring2.IsInSmallRing( _arc) )
                    {
                        bInSmallRing = true;
                    }
                }

                //
                if(bInRing == false && bInSmallRing == true)
                {
                    vOut.push_back(_arc);
                }
            }
        }
        return ;
    }

    void toOutLine(std::vector<xArc>& vOut)
    {
        //return ;
        for(int i = 0 ; i < m_vRings.size() ; i ++)
        {
            std::vector<float> vCutPoints;
            xRing& _ring = m_vRings[i];
            for(int j = 0 ; j < m_vRings.size() ; j ++)
            {
                if(j == i) continue;
                xRing& _ring2 = m_vRings[j];
                _ring.CutByCircle(_ring2.m_Center , _ring2.m_OutR , vCutPoints , true);

            }

            std::vector<xArc> vArcs;
            _ring.toArcs(vCutPoints , true , vArcs);

            //判断生成的圆弧是不是在内部。
            for(int iArc = 0 ; iArc < vArcs.size() ; iArc ++)
            {
                xArc& _arc = vArcs[iArc];
                bool bInRing = false;
                for(int k = 0 ; k < m_vRings.size() ; k ++)
                {
                    if( k == i ) continue;
                    xRing& _ring2 = m_vRings[k];
                    if( true == _ring2.IsInOutRing(_arc ) )
                    {
                        bInRing = true;
                    }
                }

                //
                if(bInRing == false)
                {
                    vOut.push_back(_arc);
                }
            }
        }
        return ;
    }
public:
    std::vector<xRing> m_vRings;
};

 

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值