如何在Processing中从一个点到另一个点绘制一条线

时间:2015-12-10 18:53:37

标签: java image-processing 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

Water

DATA1 &LT;&#34; HTTPS:?//docs.google.com/spreadsheets/d/1QzbCGW8H6PZgLkmWN8OyplVNTJhp3tlPGxR_Zv6lttM/pub输出= CSV&#34;&GT;

1 个答案:

答案 0 :(得分:2)

目前这个问题并不是很清楚,所以这个答案的当前形式是不完整的。

以下是一些可能简化代码的建议,希望有助于实现最终目标:

  1. 使用loadTable()尝试处理内置的CSV解析器。它支持选项卡支持和标题作为示例数据。解析头文件的好处是你可以使用列标签来解析每个值,使用像getInt()
  2. 这样的函数。
  3. 尝试使用PShape:您可以在设置中设置一次绘制命令,然后在一个命令中渲染最终形状。优点是,如果需要,您可以访问以后使用的形状和顶点。
  4. 以下是使用此TSV的基本示例,基于上面保存为data.tsv的数据

    157

    使用深灰色显示路径的原点和目的地,以下是使用部分样本数据的结果:

    Data Plot 1

    如果您需要在创建PShape实例后访问每个顶点,可以使用getVertex()。它需要您可能想要检索的顶点的索引。 例如,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); dataPlot.getVertex(0);将返回第一行的坐标,dataPlot.getVertex(1);dataPlot.getVertex(2);将返回第二行的坐标,依此类推。

    如果更容易管理类似层次结构的树而不是顶点索引,则可以创建PShape组。唯一需要注意的是,创建的以下子PShape实例将使用前缀为set的函数绘制,而不是典型的dataPlot.getVertex(2); / stroke() / etc。您已经习惯:fill() / setStroke() / etc。

    以下是使用PShape组并将距离映射到线条颜色和粗细的代码示例:

    setFill()

    plot 2

    在这种情况下,检索第一行将如下所示:

    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); 
    

    允许您访问它的两个顶点:

    PShape line0 = dataPlot.getChild(0);
    

    如果要为这些位置设置动画,可以轻松地对单个值使用lerp()PVector's lerp()方法(对于PVectors :))。此函数将期望一对开始/结束值和一个标准化值(介于0.0和1.0之间)并返回其间的值。把它想象成你的道路上的百分比:

    • 传递0.0将是该行的开头
    • 沿着
    • 线传递0.5将是50%
    • 传递1.0将是该行的结尾

    这里是一个基本示例,在遍历每条线时绘制一个椭圆,它的颜色表示开始(黑色)或结束(白色)位置(拖动应该允许手动控制将X​​轴映射到线遍历) :

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

    这是一个非常类似的例子,只是淡化点:

    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);
      }
    }
    

    fading trails

    这是另一个有趣的小变化:

    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);
      }
    }
    

    视频演示here

    如果线性插值不够,您需要更多控制时序或插值类型,请查看Benedikt Groß's Ani library