【问题标题】:Processing - lines get bigger progressively处理 - 生产线逐渐变大
【发布时间】:2017-07-08 05:20:05
【问题描述】:

所以我在一个文件中有坐标和我想让一条线逐渐变大的秒数。在文件中,我有 x1、x2(关于第一个点坐标)、x2、y2(第二个点坐标)以及我想在第二个点方向上开始增长线的时间(以秒为单位)。

这是我的代码:

//读取行

import processing.video.*;
Movie myMovie;
Table table;
float duration, time;

int row_no=1;
int clickcount = 0;

void setup() {
  size(640,480);
  myMovie = new Movie(this, "draft.mov");
  myMovie.loop();


  table = loadTable("data/new.csv");

}

void draw() {

duration = myMovie.duration();
time = myMovie.time();
image(myMovie, 0, 0);  

if(time>= table.getFloat(row_no, 4)){
strokeWeight(15);
stroke(255,14,255);

float a = table.getFloat(row_no, 0);
float b = table.getFloat(row_no,1);

line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b);

a = a + 2;
b = b + 2;
}



}
    // Called every time a new frame is available to read

void movieEvent(Movie m) {
  m.read();
} `

【问题讨论】:

  • Stack Overflow 并不是真正为一般的“我该怎么做”类型的问题而设计的。这是针对更具体的“我尝试了 X,预期 Y,但得到了 Z”类型的问题。你需要break your problem down。您所问的问题不清楚,因此请尝试编辑该问题,以便:询问您想做什么,展示您之前如何尝试但没有成功,并展示您尝试失败的结果。
  • 您能否将您的问题缩小到minimal reproducible example 而不是您的整个项目?你的问题与电影无关,是吗?所以从一个更基本的草图开始,它只显示线条的增长。我们也无权访问该文件,因此请改用硬编码数字。

标签: time processing lines


【解决方案1】:

正如 Niccolo 建议的那样,首先分解您的问题,取出您不需要的任何东西,然后一步一步走。

根据您对目标的描述,在术语或取出内容方面,听起来代码与播放电影没有任何关系,因此取出该代码以简化。 (我能想到使用电影的唯一原因是使用它的当前时间来控制线条,但除非你想要电影背景,否则你不应该需要它)

在 draw() 循环中有一些看起来很奇怪的东西:

  1. if(time>= table.getFloat(row_no, 4)){ 假设 .csv 文件中的第 5 列保存当前行的提示时间(以秒为单位),此条件可能仅触发一次,因为没有任何增量 row_no
  2. line(table.getFloat(row_no,0),table.getFloat(row_no, 1), a, b); 可能不是您想要的,并且可能是一个错字,因为 ab 已从相同的 .csv 列(0 和 1)中检索到,这意味着您是行的开始和结束位置在确切的位置(因此不渲染一条线)。也许你的意思是line(table.getFloat(row_no,2),table.getFloat(row_no, 3), a, b);
  3. a = a + 2;b = b + 2;:其中一个点的 x,y 位置可能会偏移 2,但在此点之后永远不会使用新位置。在下一次 draw() 迭代中,ab 被重新定义,因此偏移量丢失。

让我们来分解问题:

我在一个文件中有坐标和秒数,我想让一条线逐渐变大。在文件中,我有 x1、x2(关于第一个点坐标)、x2、y2(第二个点坐标)以及我想在第二个点方向上开始增长线的时间(以秒为单位)。

  1. 加载并解析数据(包含行坐标 (x1,y1,x2,y2) 和时间(以秒为单位)的行)
  2. “使线条逐渐变大” - 根据指定时间(以秒为单位)在当前行(.csv 行坐标)和下一行之间设置动画(插值)

更进一步,如果从头开始,更多的是“如何做”:

  1. 在一个值之间插入另一个值(暂时忽略时间,保持任务独立且尽可能简单)
  2. 跟踪时间作为值之间插值的参数
  3. 解析 .csv 行
  4. 在 4 个四个值之间进行插值
  5. 根据动画时间递增 .csv 行

幸运的是,Processing 提供了一个内置函数,用于在值之间进行线性插值lerp()(lerp = 简称线性插值)。 它需要三个参数:

  1. 从(开始)动画的值
  2. 动画到(停止)的值
  3. 一个插值量(介于 0.0 和 1.0 之间)

它返回一个值:开始值和停止值之间的值。 将插值量视为百分比(0 = 0%、0.5 = 50%、1.0 = 100%)。

这里有一个基本的草图来说明这个概念:

void draw(){
  background(255);
  //map time to an interpolation normalized value 
  float t = map(mouseX,0,width,0.0,1.0);
  //interpolate the values
  float size = lerp(10,90,constrain(t,0.0,1.0));
  ellipse(50,50,size,size);
}

你可以在下面运行 sn-p a p5.js 演示:

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

function draw(){
  background(255);
  //map time to an interpolation normalized value 
  var t = map(mouseX,0,width,0.0,1.0);
  //interpolate the values
  var size = lerp(10,90,constrain(t,0.0,1.0));
  ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>

如果您在 x 轴上移动鼠标,您会注意到大小在 10 到 90 像素之间,具体取决于鼠标位置。

第 1 步完成!

接下来,您可以使用millis() 来跟踪时间,只需在时间之间使用map()(以毫秒为单位)(将开始时间和结束时间之间的当前时间映射到 0.0 - 1.0 范围):

float seconds = 3.5;

//the time in millis since the last update
int previousMillis;
//the current time in millis 
int currentMillis;
//the time in millis until the next event
int nextMillis;



void setup(){

  previousMillis = millis();
  currentMillis = millis();

  nextMillis = currentMillis + (int)(seconds * 1000);

}

void draw(){
  background(255);
  //update the current timer continously
  currentMillis = millis();
  //map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
  float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);

  //interpolate the values
  float size = lerp(10,90,constrain(t,0.0,1.0));
  ellipse(50,50,size,size);
}

作为 p5.js 可运行演示:

var seconds = 3.5;

//the time in millis since the last update
var previousMillis;
//the current time in millis 
var currentMillis;
//the time in millis until the next event
var nextMillis;



function setup(){

  previousMillis = millis();
  currentMillis = millis();

  nextMillis = currentMillis + (int)(seconds * 1000);

}

function draw(){
  background(255);
  //update the current timer continously
  currentMillis = millis();
  //map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
  var t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);

  //interpolate the values
  var size = lerp(10,90,constrain(t,0.0,1.0));
  ellipse(50,50,size,size);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.min.js"></script>

第 2 步已完成,看起来您已经掌握了第 3 步(解析 .csv 值):)

一旦您了解了如何插入一个值,第 4 步应该是微不足道的:只需对不同的变量执行 4 次!

第 5 步很简单,您只需检查 row_no 是否超出表的行数。

row_no = row_no + 1;
if(row_no > table.getRowCount()) row_no = 0;

您可以做的一件巧妙的事情是使用modulo operator(%) 来做与数学表达式相同的事情:

row_no = (row_no + 1) % table.getRowCount();

总之,假设你的 .csv 文件看起来有点像这样:

x1,y1,x2,y2,seconds
5,5,95,5,4
95,5,95,95,3
95,95,5,95,2
5,95,5,5,1

将它们放在一起的一种方法是这样的:

Table table;
int row_no = 0;

//the time in millis since the last update
int previousMillis;
//the current time in millis 
int currentMillis;
//the time in millis until the next event
int nextMillis;

//where to animate the line from
float x1Start,y1Start,x2Start,y2Start;
//where to animate the line to 
float x1Stop,y1Stop,x2Stop,y2Stop;
//currently interpolated line positions
float x1Lerp,y1Lerp,x2Lerp,y2Lerp;

void setup(){
  size(100,100);
  strokeWeight(3);
  fill(0);

  table = loadTable("data/new.csv","header, csv");

  //printing the table in console, handy just for debugging/double checking values
  println("data");
  for(int i = 0 ; i <= table.getRowCount(); i++){
    print(table.getColumnTitle(i)+"\t");
  }
  println();
  for(int i = 0 ; i < table.getRowCount(); i++){
    TableRow row = table.getRow(i);
    for(int j = 0; j < row.getColumnCount(); j++){
      print(row.getFloat(j) + "\t");
    }
    println();
  } 
  //fetch lines and seconds from the current and next rows
  updateFromRow();
}

void updateFromRow(){
  //update times
  previousMillis = millis();
  currentMillis = millis();

  //get the current row and it's line coordinates
  TableRow currentRow = table.getRow(row_no);
  x1Start     = currentRow.getFloat("x1");
  y1Start     = currentRow.getFloat("y1");
  x2Start     = currentRow.getFloat("x2");
  y2Start     = currentRow.getFloat("y2");
  //get the next row and it's line coordinates - notice % module is used to easily loop back to 0 once row_no goes beyond the number of table rows 
  TableRow nextRow = table.getRow((row_no + 1) % table.getRowCount());
  x1Stop     = nextRow.getFloat("x1");
  y1Stop     = nextRow.getFloat("y1");
  x2Stop     = nextRow.getFloat("x2");
  y2Stop     = nextRow.getFloat("y2");
  //get the duration in seconds, convert it to millis( * 1000) and add it to the current millis
  nextMillis = currentMillis + (int)(currentRow.getFloat("seconds") * 1000);

  println("updated from row: " + row_no);
}

void draw(){
  background(255);
  //update the current timer continously
  currentMillis = millis();
  //map the current time from the previous to the next time as a normalized value (0,0 to 1.0) range
  float t = map(currentMillis,previousMillis,nextMillis,0.0,1.0);
  //if the current interpolation value is above 1.0 
  if(t > 1.0){
    t = 0;
    //increment the row
    row_no++;
    //if the current row counter is above the total number of rows, reset back 0
    if(row_no >= table.getRowCount()){
      row_no = 0;
    }
    //update values from incremented row (lines and their coordinates + time)
    updateFromRow();
  }
  text("t:"+t,15,20);

  //constrain interpolated value between 0.0 and 1.0
  float interpolationAmount = constrain(t,0.0,1.0);
  //linearly interpolate (lerp) between the current and next line coordinates
  x1Lerp = lerp(x1Start,x1Stop,interpolationAmount);
  y1Lerp = lerp(y1Start,y1Stop,interpolationAmount);
  x2Lerp = lerp(x2Start,x2Stop,interpolationAmount);
  y2Lerp = lerp(y2Start,y2Stop,interpolationAmount);

  //finally, render the interpolated line 
  line(x1Lerp,y1Lerp,x2Lerp,y2Lerp);
}

在跟踪数据方面,可以使用 PVector 实例存储线坐标(...来自 .csv 数据的 x,y 分量 set() 和线点可以通过 @ 成对插值987654327@)。 到目前为止,我们只使用线性插值,但您可能还想查看easingtweening

【讨论】:

    猜你喜欢
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 2021-08-31
    • 2018-11-21
    • 2010-12-17
    相关资源
    最近更新 更多