我正在尝试生成一个图形,该图形使用一条从起点到目的地的线来绘制 cargo 路径。我已将纬度和经度数据转换为适合美国 map 的像素(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
. . . .
. . . .
更新 我已经添加了指向我的数据的链接,因为我在按照我的设想绘制图像时仍然遇到一些困难。
数据1 <“https://docs.google.com/spreadsheets/d/1QzbCGW8H6PZgLkmWN8OyplVNTJhp3tlPGxR_Zv6lttM/pub?output=csv”>
最佳答案
目前问题还不是很清楚,所以当前形式的答案是不完整的。
以下是一些可以简化代码并希望有助于实现最终目标的建议:
- 尝试使用 Processing 的内置 CSV 解析器 loadTable() .它支持选项卡支持和标题作为示例数据。解析 header 的好处在于,您可以使用列标签来使用现成可用的函数(例如 getInt())来解析每个值。
- 尝试使用 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);
使用深灰色到浅灰色显示路径的起点和终点,这是使用部分示例数据的结果:
如果您需要在创建 PShape 实例后访问每个顶点,您可以使用 getVertex() .它需要您可能想要检索的顶点的索引。
例如,dataPlot.getVertex(0);
和 dataPlot.getVertex(1);
将返回第一行的坐标,dataPlot.getVertex(2) ;
和 dataPlot.getVertex(2);
将返回第二条线的坐标,依此类推。
如果管理树状层次结构而不是顶点索引更容易,您可以创建 PShape 组。唯一需要注意的是,创建的以下子 PShape 实例将使用以 set 为前缀的函数绘制,而不是典型的 stroke()
/fill()
/etc。你已经习惯了:setStroke()
/setFill()
/etc.
下面是一个使用 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);
在这种情况下,检索第一行将如下所示:
PShape line0 = dataPlot.getChild(0);
你允许你访问它的两个顶点:
println(line0.getVertex(0));
println(line0.getVertex(1));
如果你想为这些位置设置动画,你可以很容易地使用 lerp()单个值或 PVector's lerp()方法(对于 PVectors :))。此函数需要一对开始/结束值和一个标准化值(介于 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();
}
视频演示 here
如果线性插值还不够并且您需要更多地控制时间或插值类型,请查看 Benedikt Groß's Ani library
关于java - 如何在 Processing 中点对点画线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34209539/