最近遇到一个需求,画一个轮廓,然后外面画一个圆,圆外面再画个箭头表示方向,不能互相遮挡,所以轮廓要完全在圆内。
涉及一个子问题,先调研了一下:计算包含三角形的最小圆。后续根据这个一直迭代计算包含任意多边形的最小圆。
锐角三角形就是外接圆;钝角三角形要取最长边中点作为圆心,最长边长度作为直径;直角三角形可以并入其中任意一种情况。
参照了博客:https://blog.csdn.net/qq_17148595/article/details/122067966
效果如图
附上完整网页代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <style> 5 #main{ 6 height: 100%; 7 display: flex; 8 flex-direction: column; 9 } 10 #top{ 11 display: grid; 12 grid-template-rows: 50% 50%; 13 grid-template-columns: 33% 33% 33%; 14 } 15 input{ 16 width: 100px; 17 } 18 canvas{ 19 flex-grow: 1; 20 } 21 </style> 22 </head> 23 <body> 24 <div id="main"> 25 <div id="top"> 26 <div> 27 <span>A.x</span> 28 <input type="number" value="333" oninput="update()" /> 29 </div> 30 <div> 31 <span>B.x</span> 32 <input type="number" value="400" oninput="update()" /> 33 </div> 34 <div> 35 <span>C.x</span> 36 <input type="number" value="315" oninput="update()" /> 37 </div> 38 <div> 39 <span>A.y</span> 40 <input type="number" value="100" oninput="update()" /> 41 </div> 42 <div> 43 <span>B.y</span> 44 <input type="number" value="200" oninput="update()" /> 45 </div> 46 <div> 47 <span>C.y</span> 48 <input type="number" value="370" oninput="update()" /> 49 </div> 50 </div> 51 <canvas width="1000" height="800"></canvas> 52 </div> 53 </body> 54 <script> 55 function circleCenter(A, B, C) { 56 let yDelta_a = B.y - A.y; 57 let xDelta_a = B.x - A.x; 58 let yDelta_b = C.y - B.y; 59 let xDelta_b = C.x - B.x; 60 if(xDelta_a==0||xDelta_b==0||yDelta_a==0)//边界情况,把点换个位置 61 return circleCenter(B,C,A); 62 let center = {}; 63 let aSlope = yDelta_a/xDelta_a; 64 let bSlope = yDelta_b/xDelta_b; 65 center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x) 66 - aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) ); 67 center.y = -1*(center.x - (A.x+B.x)/2)/aSlope + (A.y+B.y)/2; 68 center.r=Math.sqrt((center.x-A.x)**2+(center.y-A.y)**2);//求出圆心之后随便跟一个点算距离就是半径 69 return center; 70 } 71 function update(){ 72 let c=document.getElementsByTagName('canvas')[0]; 73 let ctx=c.getContext('2d'); 74 c.width=c.width;//to clear 75 let a=Array.from(document.getElementsByTagName('input')).map(u=>parseInt(u.value)); 76 let l=[]; 77 for(let i=0;i<3;i++){ 78 l.push(Math.sqrt((a[(i+1)%3]-a[i])**2+(a[(i+1)%3+3]-a[i+3])**2)); 79 } 80 let max=0; 81 for(let i=1;i<3;i++) 82 if(l[i]>l[max]) 83 max=i;//找到最长边 84 if(l.reduce((a,b)=>a+b)-l[max]*2<0.01)//共线 85 return; 86 let sum=0; 87 for(let i=0;i<3;i++){ 88 if(i!=max) 89 sum+=l[i]**2; 90 } 91 let circle=circleCenter({x:a[0],y:a[3]}, {x:a[1],y:a[4]}, {x:a[2],y:a[5]}); 92 ctx.moveTo(a[0],a[3]); 93 ctx.lineTo(a[1],a[4]); 94 ctx.lineTo(a[2],a[5]); 95 ctx.closePath(); 96 ctx.stroke(); 97 ctx.strokeStyle='blue'; 98 ctx.beginPath(); 99 ctx.arc(circle.x,circle.y,circle.r,0,2*Math.PI); 100 ctx.stroke(); 101 if(l[max]**2>=sum){//不是锐角三角形 102 ctx.strokeStyle='red'; 103 ctx.beginPath(); 104 ctx.arc((a[max]+a[(max+1)%3])/2,(a[max+3]+a[(max+1)%3+3])/2,l[max]/2,0,2*Math.PI); 105 ctx.stroke(); 106 } 107 } 108 update(); 109 </script> 110 </html>