簡體   English   中英

如何在Processing中從一個點到另一個點繪制一條線

[英]How to draw a line from point to point in Processing

我正在嘗試生成一個圖形,繪制出貨路徑,從原點到目的地。 我已經將緯度和經度數據轉換為適合美國地圖的像素(1620,1080)。

它當前寫入的方式是按照在我的csv文件中排序的方式順序繪制的。 但是,我希望這些線從原點輻射到目的地。 現在我只能弄清楚如何放下已繪制的線條。

我認為代碼的相關部分在// Draw Lines

long current;

int x;
int y;
ArrayList loads;

void setup() {
  size(1620, 1080);
  background(55);
  smooth();
  frameRate(15);


// Draw US Map



String[] lines = loadStrings("Map2.csv");    // File containing coordinates to plot US Map
  stroke(55);
  strokeWeight(1);
  smooth();

  String[] pieces = split(lines[0], ',');

  for ( int i = 0; i < lines.length; i++) {

    fill(0);

    beginShape();
    current = int(pieces[0]);

    while ( current == int(pieces[0]) & i < lines.length) {

      x = int(pieces[2]);
      y = int(pieces[1]);
      vertex(x, y);
      i++;

      if ( i < lines.length) {
        pieces = split(lines[i], ',');
      }
    }
    endShape();
  }



// Add Lakes to Map




 String[] lines2 = loadStrings("Water.csv");    // File containing coordinates to plot great lakes
  smooth();

  fill(22, 25, 180);

  String[] pieces2 = split(lines2[0], ',');
  for (int i = 0; i < lines2.length; i++)
  {

    fill(110);
    beginShape();
    current =  int(pieces2[0]);

    while (current == int(pieces2[0]) & i < lines2.length) {

      x = int(pieces2[2]);
      y = int(pieces2[1]);
      vertex(x, y);
      i++;
      if (i < lines2.length) {
        pieces2 = split(lines2[i], ',');
      }
    }
    endShape();
  }


// Draw Lines



 loads = new ArrayList();

  String[] loadset = loadStrings("data1.csv");    
  for ( int i3 = 0; i3 < loadset.length; i3++) {
    String[] loads2 = split(loadset[i3], ',');
    loads.add( new Lane(int(loads2[0]), int(loads2[1]), int(loads2[2]), int(loads2[3])) );
  }
  }
     int i=1;
       int imax = 1;
       int incmult = 1;

    void draw() {
     if (i < loads.size()-imax){

      for(int iadd = 0; iadd < imax; iadd++)
      {
            Lane Lane = (Lane) loads.get(iadd);
            Lane.display();
            Lane = (Lane) loads.get(i+iadd);
            Lane.display();      
      }
          i +=imax;  
     }
      imax = imax + incmult;
    }

    class Lane {
        int x;
        int y;
        int x2;
        int y2;

        Lane( int tempX, int tempY, int tempX2, int tempY2) {
          x  = tempX;
          y  = tempY;
          x2 = tempX2;
          y2 = tempY2;
        }

        void display() {
          int r = 65;
          int g = 255;
          int b = 35;
          strokeWeight(1);
          stroke(r, g, b, 55);
          line(x, y, x2, y2);

          stroke(255, 255, 255);      // Origin
          fill(255, 255, 255, 55);
          ellipse(x, y, 3, 3);

          stroke(171, 62, 193);       // Destination
          fill(171, 62, 193);
          ellipse(x2, y2, 3, 3);
      }
      }

我的data1.csv文件包含四列x, y, x2, y2 ,其中(x, y)表示原點, (x2, y2)表示目標坐標。

//  data.csv 

data[0] data[1] data[2] data[3]
929     327      602      507
1335    458      1327     782
1422    325      848      744
1302    280      1118     458
1041    583      1193     666
1267    616      1058     394
1215    671      1351     857
1334    851      1410     946
1334    851      1409     916
828     761      861      653
1386    323      1203     594
1037    293      1013     522
908     869      958      532
1029    331      1053     409
906     357      828      761
.        .       .        .
.        .       .        .

更新我添加了我的數據的鏈接,因為我仍然在繪制圖像時遇到了一些困難,正如我所設想的那樣。

MAP2

data1 <“https://docs.google.com/spreadsheets/d/1QzbCGW8H6PZgLkmWN8OyplVNTJhp3tlPGxR_Zv6lttM/pub?output=csv”>

目前問題不是很清楚,所以這個答案的當前形式是不完整的。

以下是一些可能簡化代碼的建議,希望有助於實現最終目標:

  1. 使用loadTable()嘗試Processing的內置CSV解析器。 它支持選項卡支持和標題作為示例數據。 解析頭文件的好處是你可以使用列標簽來解析每個值,使用像getInt()這樣的函數。
  2. 嘗試使用PShape :您可以在設置中設置一次繪制命令,然后在一個命令中渲染最終形狀。 優點是,如果需要,您可以訪問以后使用的形狀和頂點。

這是使用此TSV的基本示例,基於上面保存為data.tsv的數據

Table data;
PShape dataPlot;

size(1620, 1080,P2D);
//create a group to store the lines from each row
dataPlot = createShape();
//load the data, specifying it has a header and it's tab separated
data = loadTable("data.tsv", "header, tsv");
//traverse each row
dataPlot.beginShape(LINES);
for(TableRow row : data.rows()){
  //extract each value
  int x1 = row.getInt("x1");
  int y1 = row.getInt("y1");
  int x2 = row.getInt("x2");
  int y2 = row.getInt("y2");
  //add the coordinates as lines to the group
  dataPlot.stroke(160);
  dataPlot.vertex(x1,y1);
  dataPlot.stroke(0);
  dataPlot.vertex(x2,y2);
}
dataPlot.endShape();
//render the plot
shape(dataPlot); 

使用暗到淺灰色顯示路徑的原點和目的地,這是使用部分樣本數據的結果:

數據圖1

如果在創建PShape實例后需要訪問每個頂點,可以使用getVertex() 它需要您可能想要檢索的頂點的索引。 例如, dataPlot.getVertex(0); dataPlot.getVertex(1); 將返回第一行的坐標dataPlot.getVertex(2); dataPlot.getVertex(2); 將返回第二行的坐標,依此類推。

如果管理類似層次結構的樹而不是頂點索引更容易,則可以創建PShape組。 唯一需要注意的是,創建的以下子PShape實例將使用前綴為set的函數繪制,而不是典型的stroke() / fill() / etc。 你已經習慣了: setStroke() / setFill() / setFill()

這是使用PShape組並將距離映射到線條顏色和粗細的代碼示例:

Table data;
PShape dataPlot;

size(1620, 1080, P2D);
//create a group to store the lines from each row
dataPlot = createShape(GROUP);
//load the data, specifying it has a header and it's tab separated
data = loadTable("data.tsv", "header, tsv");
//traverse each row
for (TableRow row : data.rows ()) {
  //extract each value
  int x1 = row.getInt("x1");
  int y1 = row.getInt("y1");
  int x2 = row.getInt("x2");
  int y2 = row.getInt("y2");
  //add the coordinates as lines to the group
  PShape line = createShape(LINE, x1, y1, x2, y2);
  float dist = dist(x1, y1, x2, y2);
  line.setStroke(color(map(dist, 0, height, 160, 0)));
  line.setStrokeWeight(map(dist, 0, height, 10.0, 1.0));
  dataPlot.addChild(line);
}
//render the plot
shape(dataPlot); 

情節2

在這種情況下,檢索第一行將如下所示:

PShape line0 = dataPlot.getChild(0);

你允許你訪問它的兩個頂點:

println(line0.getVertex(0));
println(line0.getVertex(1));

如果要為這些位置設置動畫,可以在單個值或PVector的lerp()方法(對於PVectors :)上輕松使用lerp() )。 此函數將期望一對開始/結束值和一個標准化值(介於0.0和1.0之間)並返回其間的值。 把它想象成你路徑上的一個百分比:

  • 傳遞0.0將是該行的開始
  • 通過0.5將是50%沿線
  • 傳遞1.0將是該行的結尾

這是在遍歷每一行時繪制橢圓的基本示例,它的顏色表示開始(黑色)或結束(白色)位置(拖動應允許手動控制將X​​軸映射到行遍歷):

Table data;
PShape plot;

void setup(){
  size(1620, 1080, P2D);
  //create a group to store the lines from each row
  plot = createShape(GROUP);
  //load the data, specifying it has a header and it's tab separated
  data = loadTable("data.tsv", "header, tsv");
  //traverse each row
  for (TableRow row : data.rows ()) {
    //extract each value
    int x1 = row.getInt("x1");
    int y1 = row.getInt("y1");
    int x2 = row.getInt("x2");
    int y2 = row.getInt("y2");
    //add the coordinates as lines to the group
    PShape line = createShape(LINE, x1, y1, x2, y2);
    float dist = dist(x1, y1, x2, y2);
    line.setStroke(color(map(dist, 0, height, 160, 0)));
    line.setStrokeWeight(map(dist, 0, height, 10.0, 1.0));
    plot.addChild(line);
  }
}
void draw(){
  background(255);
  //render the plot
  shape(plot);
  //animate the trajectories
  //use normalized (between 0.0 and 1.0) value to traverse the paths (think of it as 0 and 100%, 0 is at the start 100% is at the end)
  //if can be interactive
  float traversal;
  if(mousePressed) {
    traversal = map(mouseX,0,width,0.0,1.0);
  }else{//or time based, up to you :)
    traversal = map(sin(frameCount * 0.1),-1.0,1.0,0.0,1.0);
  } 
  //for each trajectory
  for(int i = 0 ; i < plot.getChildCount(); i++){
    PShape line = plot.getChild(i);
    //access each line's start and end points
    PVector start = line.getVertex(0);
    PVector end   = line.getVertex(1);
    //calculate the linearly interpolated point in between start end using the traversal value and lerp()
    PVector inbetween = PVector.lerp(start,end,traversal);
    //use the interpolated value to draw
    fill(traversal * 255);
    ellipse(inbetween.x,inbetween.y,15,15);
  }
}

這是一個非常類似的例子,只是淡化點:

Table data;
PShape plot;

void setup(){
  size(1620, 1080, P2D);
  //create a group to store the lines from each row
  plot = createShape(GROUP);
  //load the data, specifying it has a header and it's tab separated
  data = loadTable("data.tsv", "header, tsv");
  //traverse each row
  for (TableRow row : data.rows ()) {
    //extract each value
    int x1 = row.getInt("x1");
    int y1 = row.getInt("y1");
    int x2 = row.getInt("x2");
    int y2 = row.getInt("y2");
    //add the coordinates as lines to the group
    PShape line = createShape(LINE, x1, y1, x2, y2);
    float dist = dist(x1, y1, x2, y2);
    line.setStroke(color(map(dist, 0, height, 160, 0)));
    line.setStrokeWeight(map(dist, 0, height, 10.0, 1.0));
    plot.addChild(line);
  }
  //clear the background
  noStroke();
  shape(plot);//this needs to be drawn at least once it seems
  background(255);
}
void draw(){
  //hacky fade effect, change the alpha (16) transparency value to experiment with fade amount 
  fill(255,16);
  rect(0,0,width,height);
  //animate the trajectories
  //use normalized (between 0.0 and 1.0) value to traverse the paths (think of it as 0 and 100%, 0 is at the start 100% is at the end)
  //if can be interactive
  float traversal;
  if(mousePressed) {
    traversal = map(mouseX,0,width,0.0,1.0);
  }else{//or time based, up to you :)
    traversal = map(sin(frameCount * 0.01),-1.0,1.0,0.0,1.0);
  } 
  //for each trajectory
  for(int i = 0 ; i < plot.getChildCount(); i++){
    PShape line = plot.getChild(i);
    //access each line's start and end points
    PVector start = line.getVertex(0);
    PVector end   = line.getVertex(1);
    //calculate the linearly interpolated point in between start end using the traversal value and lerp()
    PVector inbetween = PVector.lerp(start,end,traversal);
    //use the interpolated value to draw
    fill(lerpColor(color(255,0,0),color(0,255,0),traversal));
    ellipse(inbetween.x,inbetween.y,15,15);
  }
}

褪色的小徑

這是另一個有趣的小變化:

Table data;
PShape plot;

void setup(){
  size(1620, 1080, P2D);
  smooth(8);
  //create a group to store the lines from each row
  plot = createShape(GROUP);
  //load the data, specifying it has a header and it's tab separated
  data = loadTable("data.tsv", "header, tsv");
  //traverse each row
  for (TableRow row : data.rows ()) {
    //extract each value
    int x1 = row.getInt("x1");
    int y1 = row.getInt("y1");
    int x2 = row.getInt("x2");
    int y2 = row.getInt("y2");
    //add the coordinates as lines to the group
    PShape line = createShape(LINE, x1, y1, x2, y2);
    plot.addChild(line);
  }
  shape(plot);
  strokeWeight(5.0);
}
void draw(){
  //hacky fade effect, change the alpha/transparency value to experiment with fade amount 
  background(255);
  //animate the trajectories
  //use normalized (between 0.0 and 1.0) value to traverse the paths (think of it as 0 and 100%, 0 is at the start 100% is at the end)
  //if can be interactive
  float traversal;
  if(mousePressed) {
    traversal = map(mouseX,0,width,0.0,1.0);
  }else{//or time based, up to you :)
    traversal = map(sin(frameCount * 0.01),-1.0,1.0,0.0,1.0);
  } 
  beginShape(LINES);
  //for each trajectory
  for(int i = 0 ; i < plot.getChildCount(); i++){
    PShape line = plot.getChild(i);
    //access each line's start and end points
    PVector start = line.getVertex(0);
    PVector end   = line.getVertex(1);
    //calculate the linearly interpolated point in between start end using the traversal value and lerp()
    PVector inbetween = PVector.lerp(start,end,traversal);
    //use the interpolated value to draw
    stroke(64);
    vertex(start.x,start.y);
    stroke(160);
    vertex(inbetween.x,inbetween.y);
  }
  endShape();
}

視頻演示在這里

如果線性插值不夠,您需要更多控制時序或插值類型,請查看BenediktGroß的Ani庫

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM