连通不规则多边形算法

简介: 多边形连通和最小生成树本质上是一样的,问题在于确定权值。 下面算法由js实现,演示由svg提供。 let shown='hidden'; //核心算法 let caculatePath=function(){ ...

多边形连通和最小生成树本质上是一样的,问题在于确定权值。

下面算法由js实现,演示由svg提供。

<html>
<head>
    <script>
        let shown='hidden';
        //核心算法
        let caculatePath=function(){
            /*显示和隐藏,算法无关*/
            for(let i=0;i<panel.children.length;i++){
                panel.children[i].style.visibility=shown;
            }
            lineGroup.innerHTML=null;
            if(shown=='hidden'){
                shown='visible';
            }else{
                shown='hidden';
                return;
            }
            getEvent().target.style.visibility='visible';
            let gons=getPolygons(getEvent().target);
            let target=document.getElementById('target');
            /*----------END----------*/
            
            //closeList表示已经连通的图形,无需再连通
            let closeList=[];
            //未连通的图形
            let openList=[];
            
            //放入外框图形
            closeList.push(gons[0]);
            //放入其他图形
            for(let i=1;i<gons.length;i++){
                openList.push(gons[i]);
            }
            let cache={};
            while(openList.length>0){
                let min={dist:Number.MAX_SAFE_INTEGER};
                let imin,jmin;
                for(let i=0;i<openList.length;i++){
                    for(let j=0;j<closeList.length;j++){
                        //缓存之前的计算值,提高计算效率,这里应该利用最小堆,但是js没有默认实现,先不管
                        let cacheKey=openList[i].index+':'+closeList[j].index;
                        let d=cache[cacheKey];
                        if(!d){
                            d=polygon2Polygon(openList[i],closeList[j]);
                        }
                        cache[cacheKey]=d;
                        if(d.dist<min.dist){
                            min=d;
                            imin=i;
                            jmin=j;
                        }
                    }
                    
                }
                
                //构建父子级
                if(closeList[jmin].child==null){
                    closeList[jmin].child=[];
                }
                closeList[jmin].child.push(
                {
                    node:openList[imin],
                    target:min.target,
                    source:min.source,
                });
                
                closeList.push(openList[imin]);
                openList.splice(imin,1);
                
            }
            //测试
            collect(gons[0],getEvent().target);

            return gons[0]
        };

        /**
         * 返回{ dist:最小距离,source:parent链接点,target:child链接点}
         * @param poly1
         * @param poly2
         */
        let polygon2Polygon=function(poly1,poly2){
            let point,min={dist:Number.MAX_SAFE_INTEGER};
            for(let i=0;i<poly1.length;i++){
                point=poly1[i];
                let d=point2Polygon(point,poly2);
                if(d.dist<min.dist){
                    min=d;
                    min.target=point;
                    min.source=d.anchor;
                }
            }

            for(let i=0;i<poly2.length;i++){
                point=poly2[i];
                let d=point2Polygon(point,poly1);
                if(d.dist<min.dist){
                    min=d;
                    min.target=d.anchor;
                    min.source=point;
                }
            }

            return min;
        };

        //计算图形和点之间的最小距离,返回线,距离
        let point2Polygon=function(point,poly){
            let min=Number.MAX_SAFE_INTEGER;
            let anchor,d;
            for(let i=0;i<poly.length;i++){
                let p1=poly[i],p2;
                let i1;
                if(i==poly.length-1)
                    i1=0;
                else
                    i1=i+1;
                p2=poly[i1];
                
                d= distToSegment(point,p1,p2);
                if(min>d.dist){
                    min=d.dist;
                    anchor=d.p;
                }
                
            }
            return {
                dist:min,
                anchor:anchor,
            }
        };

        /*-------------点到线段距离------------*/
        function sqr(x) { return x * x }
        function dist2(v, w) { return sqr(v.x - w.x) + sqr(v.y - w.y) }

        //返回距离和连接点
        function distToSegment(p, v, w) {
            let l2 = dist2(v, w);
            if (l2 == 0) return dist2(p, v);
            let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;

            t = Math.max(0, Math.min(1, t));
            let w1={ x: v.x + t * (w.x - v.x),
                y: v.y + t * (w.y - v.y) };
            return {dist:Math.sqrt(dist2(p, w1)),
                p:w1};
        }
        /*-------------END---------------*/



        /*-------无关算法分界线--------*/

        //创建连线
        let createLineElement=function(){
            let line= document.createElementNS('http://www.w3.org/2000/svg','line');
            line.style.stroke='black';
            line.style['stroke-width']=2;
            line.setAttributeNS('','marker-end','url(#arrow)');
            return line;
        };


        let collect=function(p){
            if(p.child){
                for(let i=0;i<p.child.length;i++){

                    let np=createLineElement();
                    let s=p.child[i].source;
                    let t=p.child[i].target;


                    let x1,y1,x2,y2;
                    if(s instanceof Array){
                        x1=(s[0].x+s[1].x)/2;
                        y1=(s[0].y+s[1].y)/2;
                    }else{
                        x1=s.x;
                        y1=s.y;
                    }

                    if(t instanceof Array){
                        x2=(t[0].x+t[1].x)/2;
                        y2=(t[0].y+t[1].y)/2;
                    }else{
                        x2=t.x;
                        y2=t.y;
                    }


                    np.setAttribute('x1',x1);
                    np.setAttribute('y1',y1);

                    np.setAttribute('x2',x2);
                    np.setAttribute('y2',y2);
                    lineGroup.appendChild(np);

                    collect(p.child[i].node);
                }
            }
        };

        let getEvent = function(){
            return window.event || arguments.callee.caller.arguments[0];
        };

        let printChild=function(p){
            console.log('node:',p.index);
            if(p.child){
                console.log('{',p.index,'--child:');
                for(let i=0;i<p.child.length;i++){
                    console.log('source:',p.child[i].source);
                    console.log('target:',p.child[i].target);
                    printChild(p.child[i].node);
                }
                console.log('--',p.index,'}');
            }
        }
        //从path里获取所有的多边形
        let getPolygons=function(p){
            let d=p.getAttribute('d');
            if(d){
                let polygons=d.split('M');
                let result=[];
                for(let i=1;i<polygons.length;i++){
                    let seg = polygons[i];

                    let plist=[];
                    result.push(plist);
                    plist.index=i-1;
                    let status=0;
                    let np,pindex=0;
                    for(let j=0;j<seg.length;j++){
                        let c = seg.charAt(j);
                        if(status==0){
                            //初始化状态
                            if(c==' '||c=='L'||c=='Z'){

                            }else{
                                np={};
                                np.index=pindex++;
                                plist.push(np);
                                np.x=c;
                                np.y='';
                                status=1;
                            }
                        }else if(status == 1){
                            //开始写x
                            if(c==' '||c==','){
                                //开始写y
                                np.x=parseFloat(np.x);
                                status=2;
                            }else if(c=='L'){

                            }else{
                                np.x+=c;
                            }
                        }else if(status == 2){
                            if(c==' '||c=='Z'||c=='L'){
                                np.y=parseFloat(np.y);
                                status = 0;
                            }else{
                                np.y+=c;
                            }
                        }
                    }
                }
                return result;
            }
        }
        window.onload=function(){
            let panel=document.getElementById('panel');
            
            for(let i=0,len=panel.children.length;i<len;i++){
                panel.children[i].onclick=caculatePath;
            }
        }
    </script>
</head>
<body>
    <svg  width='100%' height='100%' style="border:1px solid">
        <defs>
            <marker id="arrow" markerWidth="5" markerHeight="5" refx="0" refy="3" orient="auto" markerUnits="strokeWidth">
                </marker>
        </defs>

        <g id="panel">
        <path  d="M20 90 L30 0 180 20 140 170Z M100 40 L60 20 40 60 Z M140 110 L140 60 100 60 80 100Z" fill="red" stroke="black" stroke-width="1"/>
        <path  d="M 240 110 200 110 210 130 230 130 Z M 20 10 140 160 270 10 270 190 20 190 Z M 40 130 80 130 70 110 50 110 Z" fill="blue" stroke="black" stroke-width="1"/>
        <path  d="M 190 60 160 40 40 40 40 160 160 160 190 140 190 110 150 110 150 150 50 150 50 50 150 50 150 90 190 90 Z M 130 70 70 70 90 100 70 130 130 130 110 100 Z M 20 10 210 10 240 190 30 190 Z" fill="green" stroke="black" stroke-width="1"/>
        <path  fill="yellow" d="M 515.176 32.5645 L 324.258 181.059 L 246.477 231.564 L 197.99 157.824 L 421.232 67.9199 L 362.645 39.6367 L 50.5078 55.7988 L 27.2734 217.422 L 118.188 327.529 L 518.207 326.52 L 604.07 184.088 L 515.176 32.5645 z M 312.137 61.8594 L 244.457 128.529 L 187.889 116.408 L 218.193 65.9004 L 312.137 61.8594 z M 177.787 76.002 L 170.717 209.342 L 254.557 269.951 L 427.295 148.732 L 446.486 226.514 L 253.547 305.307 L 131.32 241.666 L 75.7617 89.1328 L 177.787 76.002 z M 492.953 85.0938 L 522.248 90.1445 L 551.543 191.158 L 439.416 302.275 L 366.684 280.051 L 484.871 222.473 L 480.832 172.977 L 492.953 85.0938 z M 84.8535 185.098 L 123.238 263.889 L 169.705 281.062 L 156.574 305.307 L 95.9648 282.072 L 57.5781 226.514 L 54.5488 193.18 L 84.8535 185.098 z"></path>

        <path fill="pink" stroke="blue" d="M 0 300 L0 400 L150 400 L150 380 L250 380 L250 400 L400 400 L400 300Z M100 350 L300 350 L200 340Z M50 360 L350 360 L350 370 L50 370Z" ></path>

        <path fill="darkblue" d="M 76.0547,21.5254 L 75.4512,37.3594 L 58.9297,466.727 L 634.598,477.336 L 660.068,34.0449 Z M 131.348,54.9551 L 192.967,56.2754 L 186.355,98.2832 Z M 222.354,56.9062 L 266.256,57.8477 L 269.129,74.3066 L 225.398,109.703 L 214.082,109.459 Z M 389.65,60.4922 L 434.258,61.4492 L 440.795,117.586 L 350.936,135.99 L 362.236,97.3965 L 371.996,84.7891 L 381.024,72.2914 Z M 463.652,62.0781 L 548.537,63.8984 L 530.947,125.684 L 469.365,111.127 Z M 578.639,64.5449 L 625.961,65.5586 L 618.539,194.756 L 590.986,200.816 L 556.83,141.156 Z M 106.363,72.3535 L 169.805,122.324 L 102.598,170.236 Z M 289.045,95.6621 L 330.428,102.387 L 319.621,139.268 L 260.107,119.078 Z M 194,102 L214 132 L 190,122 Z M 225.17,138.832 L 227.857,138.891 L 315.775,168.713 L 325.164,218.836 L 318.633,224.689 L 262.492,206.191 L 234.553,159.479 Z M 467.902,140.713 L 531.643,155.779 L 556.002,198.344 L 467.482,158.762 Z M 194.078,140.803 L 206.014,167.082 L 185.609,228.994 L 159.529,242.369 L 114.529,197.502 Z M 438.604,147.764 L 438.248,163 L 402.289,209.734 L 386.125,213.602 L 353.268,210.686 L 345.074,166.912 Z M 457.236,186.09 L 537.91,222.158 L 493.592,228.064 L 455.502,230.307 L 432.676,218.002 Z M 225.48,201.053 L 238.491,213.006 L 220.955,214.807 Z M 100.504,224.646 L 142.338,266.361 L 112.168,311.863 L 103.346,314.174 L 98.252,283.168 Z M 616.805,224.961 L 612.346,302.57 L 581.812,274.451 L 579.367,249.936 L 577.547,235.974 L 574.516,230.923 L 589.637,230.941 Z M 253.117,233.77 L 303.359,250.32 L 295.482,272.451 L 286.461,288.41 L 227.938,301.764 L 180.045,264.582 L 203.475,252.564 Z M 408.684,238.146 L 439.324,254.684 L 447.172,292.891 L 425.367,291.783 L 406.387,238.701 Z M 345.99,239.283 L 376.639,242 L 398.215,302.361 L 327.033,270.68 L 334.547,249.529 Z M 536.516,251.73 L 501.43,277.691 L 506.85,255.68 Z M 483.356,253.262 L 477.721,274.616 L 459.165,257.925 Z M 552.703,275.986 L 553.08,279.773 L 543.338,309.279 L 520.807,299.586 Z M 162.859,288.115 L 207.246,322.566 L 193.545,361.557 L 181.705,383.217 L 167.805,382.314 L 138.123,325.424 Z M 314.955,297.188 L 387.291,329.379 L 382.189,358.236 L 378.357,363.965 L 373.125,364.098 L 339.242,351.496 L 312.578,301.389 Z M 574.629,307.426 L 610.186,340.182 L 604.191,444.537 L 587.582,444.23 L 551.996,400.861 L 566.256,332.762 Z M 288.344,317.85 L 311.229,360.85 L 301.432,371.266 L 226.195,356.479 L 235.533,329.904 Z M 492.541,319.135 L 535.49,337.611 L 527.479,375.805 L 489.086,326.139 L 488.297,321.459 Z M 421.859,320.766 L 458.963,322.641 L 459.02,322.98 L 414.891,340.57 L 417.344,326.707 Z M 113.695,341.566 L 138.027,388.199 L 93.6055,403.955 L 95.8223,346.34 L 96.3555,346.107 Z M 470.521,349.746 L 497.805,385.031 L 414.773,382.92 L 405.818,375.547 Z M 332.975,380.24 L 352.375,387.463 L 336.939,433.309 L 329.328,427.639 L 321.666,392.266 Z M 214.547,383.863 L 272.266,395.211 L 228.389,428.172 L 207.121,397.447 Z M 381.23,393.033 L 395.184,404.512 L 397,440.719 L 365.373,440.135 Z M 160.74,411.039 L 182.059,412.426 L 199.117,437.07 L 92.8984,435.113 Z M 424.732,412.316 L 524.307,414.842 L 526.926,416.221 L 549.33,443.525 L 426.184,441.256 Z M 296.465,413.465 L 299.07,425.506 L 270.42,433.027 Z"></path>

        </g>
        <g id="lineGroup"></g>
    </svg>
	
	<div style="position:fixed;right:10%;height:100px;width:200px;top:50px;background-color:#ccc;text-align:center;line-height:1.95">
	<div style="">点击左侧图形</div> <div>查看最小连通图</div></div>
</body>
</html>

  

目录
相关文章
|
2月前
|
算法 前端开发 机器人
一文了解分而治之和动态规则算法在前端中的应用
该文章详细介绍了分而治之策略和动态规划算法在前端开发中的应用,并通过具体的例子和LeetCode题目解析来说明这两种算法的特点及使用场景。
一文了解分而治之和动态规则算法在前端中的应用
|
3月前
|
数据可视化 算法 前端开发
基于python flask+pyecharts实现的中药数据可视化大屏,实现基于Apriori算法的药品功效关系的关联规则
本文介绍了一个基于Python Flask和Pyecharts实现的中药数据可视化大屏,该系统应用Apriori算法挖掘中药药材与功效之间的关联规则,为中医药学研究提供了数据支持和可视化分析工具。
130 2
|
4月前
|
数据采集 机器学习/深度学习 算法
Python基于Apriori关联规则算法实现商品零售购物篮分析
Python基于Apriori关联规则算法实现商品零售购物篮分析
262 0
|
5月前
|
存储 算法 Java
图像分析之连通组件标记算法
图像分析之连通组件标记算法
464 1
|
6月前
|
算法
多边形裁剪算法
多边形裁剪算法
多边形扫描转换-扫描线算法
多边形扫描转换-扫描线算法
|
5月前
|
机器学习/深度学习 算法 搜索推荐
【机器学习】Apriori算法在关联规则学习中的应用
【机器学习】Apriori算法在关联规则学习中的应用
95 0
|
6月前
|
机器学习/深度学习 算法
应用规则学习算法识别有毒的蘑菇
应用规则学习算法识别有毒的蘑菇
|
6月前
|
算法 数据可视化 数据挖掘
【视频】关联规则模型、Apriori算法及R语言挖掘商店交易数据与交互可视化|数据分享
【视频】关联规则模型、Apriori算法及R语言挖掘商店交易数据与交互可视化|数据分享
|
6月前
|
数据采集 机器学习/深度学习 算法
数据分享|WEKA关联规则挖掘Apriori算法在学生就业数据中的应用
数据分享|WEKA关联规则挖掘Apriori算法在学生就业数据中的应用