-1

キャンバス描画用の優れたJavaScriptライブラリまたはフレームワークを知っている人がいるかもしれません。

次の問題があります。

1)フリーハンドで線を引きます (ペイント/Photoshop の鉛筆など)。

2)線を「長方形のヘビ」に変換する必要があります(固定幅の長方形を使用して線を作成します)

スクリーンショットを見て ここに画像の説明を入力

この問題を解決するには、どのようなライブラリを使用するとよいでしょうか? ある種のライブラリにはすでにこの機能がありますか?

つまり、次の機能が必要です。

  • 直線近似

  • スプライン分離

  • 線を多角形/形状/オブジェクトに変換する

誰かが私を助けてくれれば素晴らしいことです。ありがとう!

4

1 に答える 1

3

質問で言うように、ポイントは一連の立方ベジエ曲線で構成されるスプラインに変換できます。ヒント:残りの (少ない) ポイントのスプラインを計算する前に、ポイント セットを単純化することができます。

立方ベジエ曲線に沿って一連の長方形っぽい多角形を計算する方法は次のとおりです。

補足: 曲線のパスに沿って側面が接続された一連の長方形を作成することはできないため、ポリゴンは長方形である必要があります。

ここに画像の説明を入力

  1. 曲線に沿って一連の点を計算します。
  2. #1 の点を使用して、各点の接線角度を計算します。
  3. ポイントと角度を使用して、各ポイントから両方向に外側に伸びる垂線を計算します。
  4. 垂線の端点を使用して、多角形のセットを構築します。新しいポリゴンはそれぞれ、以前および現在の垂直エンドポイントから構築されます。

注釈付きのコードとデモは次のとおりです。

// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

// variables defining a cubic bezier curve
var PI=Math.PI;
var PI2=PI*2;
var s={x:20,y:30};
var c1={x:300,y:40};
var c2={x:40,y:150};
var e={x:370,y:170};

// an array of points plotted along the bezier curve
var points=[];
// an array of polygons along the bezier curve
var polys=[];

// plot some points & tangent angles along the curve
for(var t=0;t<=100;t+=4){

  var T=t/100;

  // plot a point on the curve
  var pos=getCubicBezierXYatT(s,c1,c2,e,T);

  // calculate the tangent angle of the curve at that point
  var tx = bezierTangent(s.x,c1.x,c2.x,e.x,T);
  var ty = bezierTangent(s.y,c1.y,c2.y,e.y,T);
  var a = Math.atan2(ty, tx)-PI/2;

  // save the x/y position of the point and the tangent angle
  points.push({
    x:pos.x,
    y:pos.y,
    angle:a
  });         
}

// create polygons that extend on either side of the 
//     original points set
for(var i=1;i<points.length;i++){
  var p0=points[i-1];
  var p1=points[i];
  polys.push({
    x0:p0.x+20*Math.cos(p0.angle),
    y0:p0.y+20*Math.sin(p0.angle),
    x1:p1.x+20*Math.cos(p1.angle),
    y1:p1.y+20*Math.sin(p1.angle),
    x2:p1.x+20*Math.cos(p1.angle-PI),
    y2:p1.y+20*Math.sin(p1.angle-PI),                
    x3:p0.x+20*Math.cos(p0.angle-PI),
    y3:p0.y+20*Math.sin(p0.angle-PI),
  });
}

// draw the polygons
for(var i=0;i<polys.length;i++){
  var r=polys[i];
  ctx.beginPath();
  ctx.moveTo(r.x0,r.y0);
  ctx.lineTo(r.x1,r.y1);
  ctx.lineTo(r.x2,r.y2);
  ctx.lineTo(r.x3,r.y3);
  ctx.closePath();
  ctx.fillStyle=randomColor();
  ctx.fill();
  ctx.stroke();
}

// draw the bezier curve points
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
  ctx.lineTo(points[i].x,points[i].y);
}
ctx.lineWidth=3;
ctx.strokeStyle='red';
ctx.stroke();

function randomColor(){ 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
}


//////////////////////////////////////////
// helper functions
//////////////////////////////////////////

// calculate one XY point along Cubic Bezier at interval T
// (where T==0.00 at the start of the curve and T==1.00 at the end)
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
  var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
  var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
  return({x:x,y:y});
}

// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
  var t2 = T * T;
  var t3 = t2 * T;
  return a + (-a * 3 + T * (3 * a - a * T)) * T
  + (3 * b + T * (-6 * b + b * 3 * T)) * T
  + (c * 3 - c * 3 * T) * t2
  + d * t3;
}

// calculate the tangent angle at interval T on the curve
function bezierTangent(a, b, c, d, t) {
  return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
};
body{ background-color:white; padding:10px; }
#canvas{border:1px solid red; margin:0 auto; }
<h4>"Rectangular-ish" polygons along the red cubic bezier curve.</h4>
<canvas id="canvas" width=400 height=300></canvas>

均一幅のポリゴン:

繰り返しますが、それらは長方形っぽいポリゴンであるため、正確に均一な幅を取得することはできません. ほぼ均一な幅を取得するには:

  • 曲線に沿って多くの点を計算します (おそらく 1000 以上)。
  • 距離式を使用して、1000 以上のポイント セットを、曲線に沿って均一な距離を持つポイント セットに減らします。var distance=Math.sqrt( (pt1.x-pt0.x)*(pt1.x-pt0.x) + (pt1.y-pt0.y)*(pt1.y-pt0.y) )
于 2016-05-31T19:45:26.260 に答える