2016-05-31 12 views
-1

Может быть кто-то знает хорошо JavaScript библиотека или рамки для рисования холста.Преобразуйте строку в «прямоугольную змею». Холст. JavaScript

У меня следующий вопрос:

1) рисовать некоторые линии с помощью свободной руки (например, Paint/Photoshop карандашом)

2) нужно преобразовать строку в "прямоугольник змеи" (построить линии, используя прямоугольники с фиксированной шириной)

посмотреть на скриншоте enter image description here

Какой вид л Библиотека будет лучше использовать для этой проблемы? Может быть, какая-то библиотека alredy имеет эту функциональность?

Я имею в виду нужно следующие функциональные возможности:

  • линия приближения

  • разделение сплайн

  • линию многоугольников/формы преобразования/объекты

Будет здорово, если кто-то мне поможет. Благодаря!

+0

С фиксированной шириной, вы имеете в виду фиксированную длину замкнутого сегмента кривого? –

+0

Да, я имею в виду, что – archik

ответ

1

Как вы говорите в своем вопросе, ваши очки могут быть turned into a spline, состоящие из набора кубических кривых Безье. Подсказка: вы можете simplify the point-set перед вычислением сплайна оставшихся (меньше) точек.

Вот как вычислить набор прямоугольных многоугольников вдоль кубической кривой Безье.

Sidenote: Многоугольники должны быть прямоугольными, потому что невозможно создать набор прямоугольников с боковой связью вдоль изогнутого пути.

enter image description here

  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))