与绳索样式的二次曲线 [英] Quadratic Curve with Rope pattern

查看:183
本文介绍了与绳索样式的二次曲线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在布料中创建绳子。一切工作正常,当它是一个直的绳子,但如果我让它曲线一点点,它变成这样





是的,但它相当复杂,曲线必须相对温和(没有急转弯)。



您在问题中使用的曲线会正常工作。



您将必须在原生html5画布上绘制弯曲的绳子,然后在FabricJS上显示该原生画布。



查看此链接,了解如何在曲线上绘制渐变:



沿画布中的曲线的渐变描边



然后逐渐沿曲线绘制绳索图像,而不是渐变:


  1. 开始使用水平绳图像

  2. 您要将其垂直切成1px长度,

  3. 每个切片的曲线与曲线上每个新点处的曲线角度相切。

您可以使用转换完成#3:


  1. 将画布起点重置为曲线上的某一点: context.translate(curveX,curveY)

  2. 旋转画布由曲线的切线角度: context.rotate(tangentAngle)。

  3. 绘制图像的下一个切片使用剪切版本 drawImage

      drawImage(ropeImg,sliceX, 0,1,ropeImg.height,0,0,1,ropeImg.height); 


  4. 通过撤销转换清除: context.setTransform ,0,0,1,0,0);


  5. 在曲线上的下一个点重复#1,

在这一点上,在原生html5画布上有一条弯曲的绳子。



使用 nativeCanvas.toDataURL()创建一个新的FabricJS图像作为其图像源。



示例代码和演示



  var canvas = document.getElementById(canvas); var ctx = canvas.getContext(2d); var cw = canvas.width; var ch = canvas.height; //定义立方贝塞尔曲线的变量PI2 = Math.PI * 2; var s = {x:20,y:50}; var c1 = {x:200,y:70}; var c2 = {x: y:230}; var e = {x:270,y:250}; //沿着贝塞尔曲线点绘制的点数组= []; //我们经常使用PI, PI; //沿着曲线绘制400个点//并计算曲线在该点的角度//注意:您可能需要调整点数(这里为== 100)//如果曲线短得多(var t = 0; t <= 100; t + = 0.25){var T = t / 100; //绘制曲线上的点var pos = getCubicBezierXYatT(s,c1,c2,e,T); //计算曲线在该点的切线角度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; //保存点的x / y位置和切线角度//在点数组中points.push({x:pos.x,y:pos.y,angle:a});} var img = new Image (); img.onload = function(){slicer();}; img.src ='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png'; function slicer注意:如果//渐变有明显的间隙,则增加lineWidth ctx.lineWidth = 2; ctx.strokeStyle ='skyblue'; var sliceCount = 0; //绘制与曲线上的每个点相切的渐变描边线(var i = 0; i  

  body {background-color:ivory; } #canvas {border:1px solid red; margin:0 auto; }  

 < h4>来源水平绳图像< / h4> ;< img src ='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png'>< h4>在切割绳索并沿曲线绘制之后< / h4>< canvas id = canvaswidth = 300 height = 300>< / canvas>  


Im trying to create a rope in Fabric. Everything worked fine when it was a straight rope, but if i make it curves a little bit, it becomes like this

http://i.stack.imgur.com/EZeSb.png

i lost a part of my rope pattern when it curved.

So i tried to split it to multiple small rectangles, and add the pattern to all of those, but it doesnt look natural, all the rectangles in a messy coordinate system.

So is there anyway to create a normal curve rope ? thank you!

解决方案

Yes you can, but its quite complicated and the curve must be relatively "gentle" (no sharp turns).

The curve you use in your question would work fine.

You will have to draw the curved rope on a native html5 canvas and then display that native canvas on FabricJS.

See this link on how to draw a gradient across a curve:

Gradient Stroke Along Curve in Canvas.

Then incrementally draw the rope image along the curve instead of the gradient:

  1. Start with a horizontal rope image,
  2. You're going to slice it vertically into 1px lengths, and
  3. Incrementally draw the rope-slices along the curve with each slice tangent to the curve's angle at each new point on the curve.

You can accomplish #3 by using transformations:

  1. Reset the canvas origin to the a point on the curve: context.translate(curveX,curveY)
  2. Rotate the canvas by the angle tangent to the curve: context.rotate(tangentAngle).
  3. Draw the next slice of the image using the clipping version of drawImage:

    drawImage(ropeImg,sliceX,0,1,ropeImg.height,0,0,1,ropeImg.height);
    

  4. Clean up by undoing the transformations: context.setTransform(1,0,0,1,0,0);

  5. Repeat #1 with the next point on the curve and with the next slice of the rope.
  6. Continue for all the points on the curve.

At this point you have a curved rope on a native html5 canvas.

Create a new FabricJS image using nativeCanvas.toDataURL() as its image source.

Example code and a Demo

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

// variables defining a cubic bezier curve
var PI2=Math.PI*2;
var s={x:20,y:50};
var c1={x:200,y:70};
var c2={x:40,y:230};
var e={x:270,y:250};

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

// we use PI often so put it in a variable
var PI=Math.PI;

// plot 400 points along the curve
// and also calculate the angle of the curve at that point
// NOTE: You may need to adjust the point count (==100 here)
//      if the curve is much shorter or longer than this demo's curve
for(var t=0;t<=100;t+=0.25){

  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
  // in the points array
  points.push({
    x:pos.x,
    y:pos.y,
    angle:a
  });

}

var img=new Image();
img.onload=function(){
  slicer();
};
img.src='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png';


function slicer(){

  // Note: increase the lineWidth if 
  // the gradient has noticable gaps 
  ctx.lineWidth=2;

  ctx.strokeStyle='skyblue';

  var sliceCount=0;

  // draw a gradient-stroked line tangent to each point on the curve
  for(var i=0;i<points.length;i++){
    var p=points[i];
    ctx.translate(p.x,p.y);
    ctx.rotate(p.angle-PI/2);
    // draw multiple times to fill gaps on outside of rope slices
    ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
    ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
    ctx.drawImage(img,sliceCount,0,1,img.height,0,0,1,img.height);
    ctx.setTransform(1,0,0,1,0,0);
    ++sliceCount;
    if(sliceCount>(img.width-1)){sliceCount=0;}
  }

}


//////////////////////////////////////////
// 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: ivory; }
#canvas{border:1px solid red; margin:0 auto; }

<h4>Source horizontal rope image</h4>
<img src='https://dl.dropboxusercontent.com/u/139992952/multple/rope.png'>
<h4>After slicing rope and drawing it along curve</h4>
<canvas id="canvas" width=300 height=300></canvas>

这篇关于与绳索样式的二次曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆