javascript - p5.j​​s 上每个点都有经典箭头的静态矢量场

标签 javascript p5.js

目标是用 p5.js 在 2D 或 3D 网格上的每个点上用箭头(即尖端带有人字形的线段)来说明矢量场。原因是我看到很多生成艺术都在使用它,而且流场(?)看起来很酷,所以为什么不使用它们来描绘有或没有运动的物理矢量场。

我对 p5.js 一无所知,但快速在线搜索告诉我,我可以生成从左上角开始的位置向量,以及将原点连接到它们的终点或从一个位置向量到另一个:

function setup() {
  createCanvas(500, 500);
}

function draw() {
  background(0);
  
  let vec1 = createVector(100,100);
  let vec2 = createVector(30,150);
  

    //First vector
      strokeWeight(10);
      stroke(250,250,250);
      line(0,0,vec1.x,vec1.y);
    
    //Second vector
      strokeWeight(10);
      stroke(250,0,250);
      line(0,0,vec2.x,vec2.y);
      
    //Difference vector
      strokeWeight(5);
      stroke(0,250,250);
      line(vec1.x,vec1.y,vec2.x,vec2.y);
    }

现在我想添加箭头并使它们更漂亮。理想的、长期的完美是 3Blue1Brown 中的 Material :

enter image description here

最佳答案

我找到了答案 here ,例如,它允许在两点(或两个位置向量的末端)之间绘制一个向量:

function setup() {
  createCanvas(500, 500);
}


function draw() {
  background(240);

  let v0 = createVector(250,250); //Beginning point at center canvas.
  let v1 = createVector(50,50);   //Ending point at the tip of this positional vec.

  drawArrow(v0, v1, 'red'); //Function that draws a red vector from vec0 to vec1.
}


// draw an arrow for a vector at a given base position
function drawArrow(base, vec, myColor) {
  stroke(myColor);
  strokeWeight(4);
  fill(myColor);
  translate(base.x, base.y); //Will transport the object line (below) to the tip of the positional vector v1
  line(0, 0, vec.x, vec.y);  //The line from the O to the tip of v1
  rotate(vec.heading()); //Rotates the following triangle the angle of v1
  let arrowSize = 7; // Determines size of the vector arrowhead (triangle).
  translate(vec.mag() - arrowSize, 0); //Will translate a triangle below by the modulus of v1
  triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
}

或者这里是从 Canvas 中心到鼠标尖端的矢量:

function setup() {
  createCanvas(500, 500);
}


function draw() {
  background(240);

  let v0 = createVector(250,250);
  let v1 = createVector(mouseX - 250, mouseY - 250);

  drawArrow(v0, v1, 'red');
}


// draw an arrow for a vector at a given base position
function drawArrow(base, vec, myColor) {
  stroke(myColor);
  strokeWeight(4);
  fill(myColor);
  translate(base.x, base.y);
  line(0, 0, vec.x, vec.y);
  rotate(vec.heading());
  let arrowSize = 7;
  translate(vec.mag() - arrowSize, 0);
  triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
}

这不仅仅是一个向量,而是一个实际的(随机)向量场,它是用上面的代码调整行 here 创建的丹尼尔希夫曼:

var inc = 0.1;
scl = 35;
var cols,rows;

function setup() {
  createCanvas(500,500);
  cols = floor(width/scl);
  rows = floor(height/scl);
  }



function draw() {
  background(255);
  var yoff = 0;
  loadPixels();
  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = (x + y * width)*4;
      var angle = noise(xoff,yoff) * TWO_PI;
      var v = p5.Vector.fromAngle(angle);
      xoff +- inc;
      fill('blue');
      stroke('blue');
      push();
      translate(x*scl,y*scl);
      rotate(v.heading());
      line(0,0,0.5*scl,0);
      let arrowSize = 7;
      translate(0.5*scl - arrowSize, 0);
      triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
      pop();
    }
    yoff += inc;
  }
}

enter image description here

不幸的是,左上角的原点使物理场在数学上的表达相当具有误导性,传达了场逆时针流动的直觉:

var inc = 0.1;
scl = 35;
var cols,rows;

function setup() {
  createCanvas(500,500);
  cols = floor(width/scl);
  rows = floor(height/scl);
  }



function draw() {
  background(255);
  var yoff = 0;
  loadPixels();
  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = (x + y * width)*4;
      var angle = noise(xoff,yoff) * TWO_PI;
      //var v = createVector(sin(x)+cos(y),sin(x)*cos(y));
      var v = createVector(y,-x);
      xoff +- inc;
      fill('blue');
      stroke('blue');
      push();
      translate(x*scl,y*scl);
      rotate(v.heading());
      line(0,0,0.5*scl,0);
      let arrowSize = 7;
      translate(0.5*scl - arrowSize, 0);
      triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
      pop();
    }
    yoff += inc;
  }
}

enter image description here

最常见的具有负值和正值以及四个象限的笛卡尔坐标将显示该场实际上是如何顺时针流动的:

enter image description here

但这似乎有一个几乎简单的修复方法,即通过将计数器重置为从减去行(和列)数到加上行(和列)数,而不是从零开始。另外,需要翻转y轴增加值的方向,原点需要平移到 Canvas 中间 (height/2,height/2) if square :

var inc = 0.1;
scl = 35;
var cols,rows;

function setup() {
  createCanvas(500,500);
  cols = floor(width/scl);
  rows = floor(height/scl);
  }



function draw() {
  translate(height/2, height/2);  //moves the origin to bottom left
  scale(1, -1);  //flips the y values so y increases "up"
  background(255);
  var yoff = 0;
  loadPixels();
  for (var y = -rows; y < rows; y++) {
    var xoff = 0;
    for (var x =- cols; x < cols; x++) {
      var index = (x + y * width)*4;
      var angle = noise(xoff,yoff) * TWO_PI;
      //var v = createVector(sin(x)+cos(y),sin(x)*cos(y));
      var v = createVector(y,-x);
      xoff +- inc;
      fill('blue');
      stroke('blue');
      push();
      translate(x*scl,y*scl);
      rotate(v.heading());
      line(0,0,0.5*scl,0);
      let arrowSize = 7;
      translate(0.5*scl - arrowSize, 0);
      triangle(0, arrowSize / 2, 0, -arrowSize / 2, arrowSize, 0);
      pop();
    }
    yoff += inc;
  }
}

enter image description here

关于javascript - p5.j​​s 上每个点都有经典箭头的静态矢量场,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70596353/

相关文章:

JavaScript/HTML 计算器

javascript - 编辑如何在循环中获取 localStorage 的 json 值

javascript - React Native中的函数调用

javascript - 从 JSON : P5. js 中提取信息

javascript - P5.Js - 如何在特定 x 值的 while 循环中更改 line() 颜色?

javascript - 单击 P5.JS 中的 Triangle 项目允许单击三 Angular 形修复之外

java - 将数据从 JSP 发送到 servlet

javascript - 覆盖 Tab 键行为,因此它不会转到下一个字段(只关注实际字段)

javascript - 为什么这不画轨道而只画椭圆?

p5.js - p5. 由于像素密度问题 p5js 来自 get() 的图像绘制模糊