2

キャンバスに二次曲線を持つほぼ完全な円を構築しようとしています。円の周りにポイントを設定し、それらを二次曲線で接続するこの機能があります。

function calcPointsCircle(cx, cy, radius, dashLength) {
     var n = radius / dashLength,
         alpha = Math.PI * 2 / n,
         i = -1;
     while (i < n) {
         var theta = alpha * i,
             theta2 = alpha * (i + 1);
         points.push({
             x : (Math.cos(theta) * radius) + cx, 
             y : (Math.sin(theta) * radius) + cy, 
             ex : (Math.cos(theta2) * radius) + cx, 
             ey : (Math.sin(theta2) * radius) + cy,
             py : (Math.sin(theta) * radius) + cy
         });
         i+=2;
     }
}
for (i = 0; i < points.length; i++) {
    var p = points[i];
    ctx.strokeStyle = '#fff';
    ctx.quadraticCurveTo(p.x, p.py, p.x, p.y);
    ctx.stroke();
}

動作しますが、線は現在まっすぐです (コントロール ポイントに x 座標と y 座標のポイントを使用しているため、これは明らかです)。 ここに画像の説明を入力

円の半径とポイントの数に基づいてコントロール ポイントの位置を自動的に計算する方法を探しています...すべてのヘルプは大歓迎です

4

1 に答える 1

4

ここに画像の説明を入力ここに画像の説明を入力

正多角形に外接する円を近似する一連の二次曲線の制御点を計算する方法を次に示します。

与えられた:

中心点、半径、サイドカウント。

多角形の各辺について、次を計算します。

外接する円周上の 3 点を計算し、曲線がこれらの 3 点を通過する二次曲線の制御点を計算します。

  • ポリゴン側の 2 点は 3 点のうちの 2 点です

  • 側面の 2 点間のスイープ角度を計算します (var スイープ)

  • スイープ角度を二等分します (sweep/2)

  • 三角法を使用して、辺の 2 点の中間にある円周上の点を計算します。

  • 中央のコントロール ポイントを計算します。

    // calc middle control point
    var cpX=2*x1-x0/2-x2/2;
    var cpY=2*y1-y0/2-y2/2;
    

サンプルコードとデモ:

// change sideCount to the # of poly sides desired
//
var sideCount=5;


var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineWidth=2;
ctx.fillStyle=randomColor();

// save PI*2  
var PI2=Math.PI*2;

// functions to calc a point on circumference of circle
var xx=function(a){return(cx+radius*Math.cos(a));}
var yy=function(a){return(cy+radius*Math.sin(a));}

// general interpolation function
var lerp=function(a,b,x){ return(a+x*(b-a)); }

// define the regular polygon
var cx=150;
var cy=150;
var radius=100;

// calc qCurve controls points and put in sides[] array
var sides=[];
for(var i=0;i<sideCount;i++){
  sides.push(makeSide(i,sideCount));
}

// drawing and animating stuff
var percent=0;
var percentDirection=0.50;

$("#toShape").click(function(){
  percentDirection=-0.50;
})

$("#toCircle").click(function(){
  percentDirection=0.50;
})

animate();

// functions

function animate(){
  requestAnimationFrame(animate);
  drawSides(percent);
  percent+=percentDirection;
  if(percent>100){percent=100;}
  if(percent<0){percent=0;}
}


function drawSides(pct,color){
  ctx.clearRect(0,0,canvas.width,canvas.height);
  if(pct==100){
    ctx.beginPath();
    ctx.arc(cx,cy,radius,0,PI2);
    ctx.closePath();
    ctx.fill();
  }else{
    ctx.beginPath();
    ctx.moveTo(sides[0].x0,sides[0].y0);
    for(var i=0;i<sideCount;i++){
      var side=sides[i];
      var cpx=lerp(side.midX,side.cpX,pct/100);
      var cpy=lerp(side.midY,side.cpY,pct/100);        
      ctx.quadraticCurveTo(cpx,cpy,side.x2,side.y2);
    }
    ctx.fill();
  }
}

// given a side of a regular polygon,
// calc a qCurve that approximates a circle 
function makeSide(n,sideCount){

  // starting & ending angles vs centerpoint       
  var sweep=PI2/sideCount;
  var sAngle=sweep*(n-1);
  var eAngle=sweep*n;

  // given start & end points,
  // calc the point on circumference at middle of sweep angle
  var x0=xx(sAngle);
  var y0=yy(sAngle);
  var x1=xx((eAngle+sAngle)/2);
  var y1=yy((eAngle+sAngle)/2);
  var x2=xx(eAngle);
  var y2=yy(eAngle);

  // calc the control points to pass a qCurve 
  // through the 3 points
  var dx=x2-x1;
  var dy=y2-y1;
  var a=Math.atan2(dy,dx);
  var midX=lerp(x0,x2,0.50);
  var midY=lerp(y0,y2,0.50);

  // calc middle control point            
  var cpX=2*x1-x0/2-x2/2;
  var cpY=2*y1-y0/2-y2/2;

  return({
    x0:x0, y0:y0,
    x2:x2, y2:y2,
    midX:midX, midY:midY,
    cpX:cpX, cpY:cpY,
    color:randomColor()
  });
}

function randomColor(){ 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="toShape">Animate to Shape</button>
<button id="toCircle">Animate to Circle</button><br>
<canvas id="canvas" width=300 height=300></canvas>

于 2014-11-15T16:52:53.693 に答える