0

我想使用Processing重新创建抛物线三角形: 抛物线三角形.gif

我认为我已经弄清楚了“基本”代码。我现在需要的是循环浏览我的代码以获得正确数量的三角形/线。

n用来确定应该绘制多少个三角形,如您所见,当改变 n 时,线的位置是正确的。我只需要制作一个循环,以便绘制正确数量的三角形。

这是我的代码:

float x1, y1, x2, y2, x3, y3;
float b, a;

float a1, b1, a2, b2, a3, b3, a4, b4, a5, b5, a6, b6, a7, b7, a8, b8, a9, b9;

void setup () {
  size(600, 600);
  background(255);

  x2=50;
  y2=height-50;

  x3=width-50;
  y3=y2;

  b=x3-x2;
  a=b*sqrt(3)/2;

  x1=x2+b/2;
  y1=y2-a;

  stroke(255, 0, 153);
  line(x1, y1, x2, y2);
  stroke(0, 255, 253);
  line(x2, y2, x3, y3);
  stroke(79, 144, 252);
  line(x3, y3, x1, y1);
}
void draw() {
  float n=4;
  float div=(1/n);

  a1=lerp(x1, x2, div);
  b1=lerp(y1, y2, div);
  a2=lerp(x2, x3, div);
  b2=lerp(y2, y3, div);
  a3=lerp(x3, x1, div);
  b3=lerp(y3, y1, div);

  a4=lerp(x1, x2, div+div);
  b4=lerp(y1, y2, div+div);
  a5=lerp(x2, x3, div+div);
  b5=lerp(y2, y3, div+div);
  a6=lerp(x3, x1, div+div);
  b6=lerp(y3, y1, div+div);

  a7=lerp(x1, x2, div+div+div);
  b7=lerp(y1, y2, div+div+div);
  a8=lerp(x2, x3, div+div+div);
  b8=lerp(y2, y3, div+div+div);
  a9=lerp(x3, x1, div+div+div);
  b9=lerp(y3, y1, div+div+div);

  line(a1, b1, a2, b2);
  line(a2, b2, a3, b3);
  line(a3, b3, a1, b1);

  line(a4, b4, a5, b5);
  line(a5, b5, a6, b6);
  line(a6, b6, a4, b4);

  line(a7, b7, a8, b8);
  line(a8, b8, a9, b9);
  line(a9, b9, a7, b7);
}
4

1 回答 1

0

正如前面在评论中提到的,有几件事需要注意:

  1. 插值超过必要
  2. 正确映射 lerpt参数以进行插值(div在您的代码中)

关于插值,您的代码当前包含以下部分:

  a1=lerp(x1, x2, div);
  b1=lerp(y1, y2, div);
  a2=lerp(x2, x3, div);
  b2=lerp(y2, y3, div);
  a3=lerp(x3, x1, div);
  b3=lerp(y3, y1, div);

  a4=lerp(x1, x2, div+div);
  b4=lerp(y1, y2, div+div);
  a5=lerp(x2, x3, div+div);
  b5=lerp(y2, y3, div+div);
  a6=lerp(x3, x1, div+div);
  b6=lerp(y3, y1, div+div);

  a7=lerp(x1, x2, div+div+div);
  b7=lerp(y1, y2, div+div+div);
  a8=lerp(x2, x3, div+div+div);
  b8=lerp(y2, y3, div+div+div);
  a9=lerp(x3, x1, div+div+div);
  b9=lerp(y3, y1, div+div+div);

  line(a1, b1, a2, b2);
  line(a2, b2, a3, b3);
  line(a3, b3, a1, b1);

  line(a4, b4, a5, b5);
  line(a5, b5, a6, b6);
  line(a6, b6, a4, b4);

  line(a7, b7, a8, b8);
  line(a8, b8, a9, b9);
  line(a9, b9, a7, b7);

前 6 个插值(在三角形的 3 个点之间)处理一个细分级别。使用渲染线a1,a2,a3,b1,b2,b3,c1,c2,c3应该可以解决问题。其余的插值似乎是在另一个细分级别手动插值。这是您希望通过for循环避免和改进的位复制/粘贴手工劳动。

关于插值参数,如果您知道细分的总数,您可以t手动(使用除法)或使用map()函数将其映射到参数

这是您的代码的修改版本,以说明这些要点:

float x1, y1, x2, y2, x3, y3;
float b, a;

float a1, b1, a2, b2, a3, b3;

void setup () {
  frameRate(10);
  size(600, 600);
  background(255);

  x2=50;
  y2=height-50;

  x3=width-50;
  y3=y2;

  b=x3-x2;
  a=b*sqrt(3)/2;

  x1=x2+b/2;
  y1=y2-a;
}

void draw() {
  background(255);
  int subdivisions = frameCount % 300;
  for(float n = 1; n < subdivisions; n++){
    float div= n / (subdivisions - 1);
  
    a1=lerp(x1, x2, div);//x1x2
    b1=lerp(y1, y2, div);//y1y2
    a2=lerp(x2, x3, div);//x2x3
    b2=lerp(y2, y3, div);//y2y3
    a3=lerp(x3, x1, div);//x3x1
    b3=lerp(y3, y1, div);//y3y1
    
    stroke(255, 0, 153);
    line(a1, b1, a2, b2);//x1x2,y1y2,x2x3,y2y3
    stroke(0, 255, 253);
    line(a3, b3, a1, b1);//x3x1,y3y1,x1x2,y1y2
    stroke(79, 144, 252);
    line(a2, b2, a3, b3);//x2x3,y2y3,x3x1,y3y1
  }
}

抛物线三角形最小码

就我个人而言,我会将它全部封装在一个可重用的函数中(这将使其更容易在其他草图中重用)。这是一个示例,其中我还将所有线条图一次分组,以反对多次line()调用。这主要是一个偏好问题,应该稍微加快速度,但是你不应该轻易牺牲可读性/灵活性。

float x1, y1, x2, y2, x3, y3;
float b, a;

color c1 = color(255, 0, 153);
color c2 = color(0, 255, 253);
color c3 = color(79, 144, 252);

void setup () {
  size(600, 600);
  background(255);

  x2 = 50;
  y2 = height - 50;

  x3 = width - 50;
  y3 = y2;

  b = x3 - x2;
  a = b * sqrt(3) / 2;

  x1 = x2 + b / 2;
  y1 = y2 - a;
}

void drawSubdivisions(int div, float x1, float y1,
                               float x2, float y2,
                               float x3, float y3,
                               color c1, color c2, color c3){
  
  // alternative rendering option: render the lines in a batch
  beginShape(LINES);
    
  // for each subdivision level
  for(int i = 0; i < div; i++){
    // map the subdivision level to the t interpolation parameter
    float t = map(i, 0, div - 1, 0.0, 1.0);
    // interpolate each coordinate 
    // connecting the current triangle vertex to the next 
    float x1x2 = lerp(x1, x2, t);
    float y1y2 = lerp(y1, y2, t);
    
    float x2x3 = lerp(x2, x3, t);
    float y2y3 = lerp(y2, y3, t);
    // ... and last vertex to first vertex
    float x3x1 = lerp(x3, x1, t);
    float y3y1 = lerp(y3, y1, t);
    
    // render lines for th interpolated shape
    
    stroke(c1);
    vertex(x1x2, y1y2); 
    vertex(x2x3, y2y3);
    
    stroke(c2);
    vertex(x2x3, y2y3); 
    vertex(x3x1, y3y1);
    
    stroke(c3);
    vertex(x3x1, y3y1);
    vertex(x1x2, y1y2);
  } 
  
  endShape();
}

void draw() {
  // map the number of subdivisions
  int subdivisions = round(map(mouseX, 0, width, 2, 90));
  
  background(0);
  drawSubdivisions(subdivisions, x1, y1, x2, y2, x3, y3, c1, c2, c3);
  text("move mouse on X axis to control subdivisions: " + subdivisions, 10, 15);
}

抛物线三角形封装

为了完整起见,这里有一个用 p5.js 编写的示例,您可以在下面运行它。我将等边三角形推广到正多边形并使用颜色映射:

function setup() {
  createCanvas(900, 900);
  colorMode(HSB, 360, 100, 100);
}

function draw() {
  background(0, 0, 100);
  // map the number of points to Y axis
  let numPoints = round(map(mouseY, 0, height, 3, 6));
  // map the number of subdivisions to the X axis 
  let subdivisions = round(map(mouseX, 0, width, 1, 300));
  // compute regular polygon points
  let regularPolygonPoints = getRegularPolygonPoints(width * 0.5, height * 0.5, numPoints, 300);
  // optional: render regular polygon points
  if(mouseIsPressed) drawPoints(regularPolygonPoints);
  // compute and render interpolation lines between pairs of points
  drawLinearInterpolation(regularPolygonPoints, subdivisions);
  // instructions:
  text(`mouseY -> numPoints:${numPoints}\nmouseX -> subdivisions: ${subdivisions}`, 10, 15);
}

// make a list of points (p5.Vector with x, y properties and conveniently lerp) 
function getRegularPolygonPoints(x, y, sides, radius){
  // output list
  let points = [];
  // calculate the angle per polygon side (same as 360 degrees / sides)
  let angleIncrement = TWO_PI / sides;
  // for each side
  for(let i = 0 ; i < sides; i++){
    // increment the angle (and offset by 90 degrees to point up)
    let angle = (angleIncrement * i) - HALF_PI; 
    // insert the points into the list
    // p5.Vector.fromAngle converts and angle radius to an x and y position (polar to cartesian)
    // we offset(add) by x, y (transalation from 0,0 to center)  
    points.push(p5.Vector.fromAngle(angle, radius).add(x, y));
  }
  // return result
  return points;
}

// draw lines between interpolated pairs of points in sequental side order
function drawLinearInterpolation(points, subdivisions){
  // make strokes thinner the more subdivisions there are
  strokeWeight((300 - subdivisions) / 600);
  let numPoints = points.length;
  beginShape(LINES);
  // for each subdivision
  for(let i = 0; i < subdivisions; i++){
    let amount    = map(i, 0, subdivisions - 1, 0.0, 1.0);
    // for each point index from first to last (and back to first)
    for(let j = 0; j <= numPoints; j++){
      // array access current, previous and next points
      let current   = points[j % numPoints];
      let previous  = points[(j-1) < 0 ? numPoints - 1 : j - 1];
      let next      = points[(j+1) % numPoints];
      // interpolate between pairs of points: previous to current, current to next
      let previousToCurrent = p5.Vector.lerp(previous, current, amount);
      let currentToNext     = p5.Vector.lerp(current, next, amount);
      // play with stroke colour mapping
      stroke((mouseIsPressed ? (i + j) : (i * j)) % 360, 85, 100);
      // pass the point coordinates for shape rendering
      vertex(previousToCurrent.x, previousToCurrent.y);
      vertex(currentToNext.x, currentToNext.y);
    }
  }
  endShape();
}

// render a list of points
function drawPoints(points){
  strokeWeight(9);
  stroke(0, 100, 0);
  let numPoints = points.length;
  beginShape(POINTS);
  for(let i = 0 ; i < numPoints; i++){
    let point = points[i];
    vertex(point.x, point.y);
  }
  endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>

抛物线正多边形(在 p5.js 中)

您可以选择使用不同的颜色映射。lerpColor()类似和colorMode()可能有用的函数。玩得开心!

于 2021-06-12T14:05:56.387 回答