如何在p5.js中使用鼠标绘制平滑曲线。

3

我正在尝试在p5js中绘制平滑曲线,而不是普通的直线连接点,使用当前和上一个鼠标位置(如果需要,我可以保留过去点的列表)。

我已经尝试将this answer适应到p5中,但由于某些原因它并不起作用。试图为p5.js重新编写它只会得到直线而不是曲线。

let history = []
let value = 0
var p = 10
window.setup = setup;
window.draw = draw;
window.keyPressed = keyPressed;

function setup() {
  createCanvas(window.innerWidth, window.innerHeight);
}

function drawLine(x1, y1, x2, y2, width, color) {
  strokeWeight(p)
  line(x1, y1, x2, y2);
}

async function keyPressed() {
  if (key === " ") {
    background(255)
    for (let i = 0; i < history.length - 1; i++) {
      window.setTimeout(function() {
        drawLine(history[i][0], history[i][1], history[i + 1][0], history[i + 1][1])
      }, await sleep(1))
      // sleep(1000)
    }
    // drawing = 0
  }
}

function draw() {
  if (mouseIsPressed === true) {
    stroke(0)
    drawLine(mouseX, mouseY, pmouseX, pmouseY)
    history.push([pmouseX, pmouseY], [mouseX, mouseY])
    history = history.slice(history.length - 1000, history.length)
  }
}

function mouseReleased() {
  beginShape()
  noFill()
  stroke('red')
  strokeWeight(2)
  vertex(history[0][0], history[0][1]);
  for (i = 1; i < history.length - 1; i++) {
    var xc = (history[i][0] + history[i + 1][0]) / 2;
    var yc = (history[i][1] + history[i + 1][1]) / 2;
    quadraticVertex(xc, yc, history[i][0], history[i][1]);
  }
  vertex(history[history.length-1][0], history[history.length-1][1])
  endShape()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js" integrity="sha512-DWtDo/6AXxH1t9p7GCWqmC4XTVK/eje94XTV6QYB39rGllLN8Tr3izDf6lkmebgqRnYh4wtSFm4CvBoA9SrdpA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

我该如何绘制曲线并正确地将原始的HTML5画布代码转换为p5?


如何使用JavaScript HTML5画布通过N个点绘制平滑曲线? - ggorlen
@ggorlen使用HTML5画布,我不太确定如何将其修改为p5js。 - Labbo Lab
2
这个回答解决了您的问题吗?如何使用JavaScript HTML5画布通过N个点绘制平滑曲线? - Rabbid76
@ggorlen 好的,我的代码有些杂乱,提前道歉哈哈。 - Labbo Lab
1
好的@ggorlen,我已经更新了帖子并添加了代码片段,希望这可以帮到你。 - Labbo Lab
显示剩余5条评论
1个回答

3

你已经很接近了。问题与算法无关,而是与构建点有关。你可以通过 print(history) 检测到这一点,或者通过 最小化代码 来删除鼠标并使用硬编码的点列表,然后你会发现它可以工作。

当你在 draw 中测试 mousePressed 时,实际上会添加许多相同的点,因为一个鼠标按下可以跨越多个帧,但是点需要分散开来才能使曲线效果正常工作。

这里是一个鼠标按下多次触发的示例:

function draw() {
  if (mouseIsPressed) {
    print(`mouse pressed at ${mouseX}, ${mouseY}`);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

一个解决方案可能是仅在释放时推送新的点:

const history = [];

function setup() {
  createCanvas(window.innerWidth, window.innerHeight);
  noFill();
  stroke("red");
  strokeWeight(2);
}

function mouseReleased() {
  clear();
  history.push({x: mouseX, y: mouseY});
  history.forEach(({x, y}) => ellipse(x, y, 5, 5));

  if (history.length < 2) {
    return;
  }

  beginShape();
  vertex(history[0].x, history[0].y);

  for (let i = 1; i < history.length - 2; i++) {
    const xc = (history[i].x + history[i + 1].x) / 2;
    const yc = (history[i].y + history[i + 1].y) / 2;
    quadraticVertex(history[i].x, history[i].y, xc, yc);
  }

  quadraticVertex(
    history.at(-2).x,
    history.at(-2).y,
    history.at(-1).x,
    history.at(-1).y
  );
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

通过一些尝试,你会发现之前绘制的曲线可能会改变,这在绘图应用中似乎不太真实。为了解决这个问题,你可能需要绕过它或者从规范线程中尝试另一个算法,如果这个算法不符合你的需求。

这个非常好用,非常感谢!(我会查看链接的线程,如果我成功了,我应该自己回答吗?(同时分离曲线)) - Labbo Lab
请这样做,那将是很棒的!感谢您的回复并耐心更新帖子以解决反馈。我认为这个主题将是一个很好的资源。 - ggorlen
当然!非常感谢您的帮助,我在SO上的经历有好有坏,所以能有一个看起来想要帮助我的人真是太好了。 - Labbo Lab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接