C语言 如何在线性帧缓冲区上绘制二次贝塞尔曲线

6jjcrrmo  于 2022-12-11  发布在  其他
关注(0)|答案(1)|浏览(199)

正如标题所说,我想在线性帧缓冲区(又名绘制像素)上绘制二次贝塞尔曲线。
我已经有了一个函数,可以根据https://www.joshondesign.com/2018/07/11/bezier-curves绘制三次贝塞尔曲线(我把javascript翻译成C,如下所示https://gist.github.com/cheyao/a736a58c4cf683eabea2aa2a87718ef1#file-cubic-c),它工作得很好。
现在我试着把它转换成绘制一条二次贝塞尔曲线(比如下面的https://gist.github.com/cheyao/a736a58c4cf683eabea2aa2a87718ef1#file-flatness-c),这对我来说看起来不太好(也不像曲线)。
我也试过像这样野蛮地强迫它

void quadratic_bezier_curve(const Vector2 p[3], const color_t color) {
    for (double t = 0; t < 1; t += 0.001) {
        putPixel((uint32_t) ((1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x),
                 (uint32_t) ((1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y), color);
    }
}

这使得喜欢看大胆。
于是我的问题来了:有没有人知道一些更好的算法来绘制(二次)贝塞尔曲线?(我需要它的字体渲染。)

jyztefdp

jyztefdp1#

您的代码可以正常工作。发现一个错误,即对于平坦度,我们需要检查绝对值。还有一个打字错误,即p[1].y被使用了两次而不是一次。因此,它将如下所示:

static int32_t quadratic_flatness(const Vector2 p[3]) {
    return abs((int32_t) p[1].x - (((int32_t) p[0].x + (int32_t) p[2].x) / 2))
         + abs((int32_t) p[1].y - (((int32_t) p[0].y + (int32_t) p[2].y) / 2));
}

JS中的实时示例(单击“运行代码段”按钮,然后开始在画布上单击鼠标左键):

var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
document.body.style.margin = 0;
canvas.style.position = 'fixed';

// get canvas 2D context and set him correct size
var ctx = canvas.getContext('2d');
resize();

let points = [];

window.addEventListener('resize', resize);
document.addEventListener('mousedown', setPosition);

function quadratic_split_curve(p) { // out[2][3]
    const p12 = midpoint(p[0], p[1]);
    const p23 = midpoint(p[1], p[2]);
    const p123 = midpoint(p12, p23);
  return [
        [p[0], p12, p123],
        [p123, p23, p[2]]
  ];
}

function quadratic_flatness(p) {
    const result = Math.abs(p[1].x - (Math.floor( p[0].x + p[2].x) / 2)) +  Math.abs(p[1].y - (Math.floor( p[0].y +  p[2].y) / 2));
  return result;
}

function quadratic_bezier_curve(p, color) {
    if (quadratic_flatness(p) < 2) {
        line(p[0], p[2], color);
        return;
    } else {
        const split = quadratic_split_curve(p);
        quadratic_bezier_curve(split[0], color);
        quadratic_bezier_curve(split[1], color);
    }
}

function midpoint(a, b) {
    return {
    x: (a.x + b.x)/2,
    y: (a.y + b.y)/2
  }
}

// new position from mouse event
function setPosition(e) {
 if(points.length >= 3) {
        points = [];
  }
  points.push({ x: e.clientX, y: e.clientY });
  draw();
}

function resize() {
  ctx.canvas.width = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
}

function clear() {
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
}
function dot(point) {
    ctx.fillRect(point.x-1,point.y-1,3,3);
}
function line(a, b, color) {
    ctx.strokeStyle = color;
    ctx.beginPath(); 
    ctx.moveTo(a.x, a.y);
    ctx.lineTo(b.x, b.y); 
    ctx.stroke();
}
function draw() {
    clear();
  for(const point of points) {
    dot(point);
  }
  
  if(points.length == 3) {
    ctx.lineWidth = 1;
    quadratic_bezier_curve(points, '#c0392b');
  }
  
  if(points.length > 1) {
  
    ctx.lineWidth = 2;
    ctx.strokeStyle = '#3039cb77';
    ctx.beginPath(); 
    ctx.moveTo(points[0].x, points[0].y);
    
    for(i=1; i<points.length; i++) {

      ctx.lineTo(points[i].x, points[i].y); 
    }
    ctx.stroke();
  }
  
  return;
}

相关问题