我试图生成一个图形,用于绘制从发货地到目的地的货运路径。我已经将纬度和经度数据转换为适合美国地图的像素(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
. . . .
. . . .
更新 我已经添加了指向我数据的链接,因为我仍然在绘制图像时遇到了一些困难。
DATA1 &LT;&#34; HTTPS:?//docs.google.com/spreadsheets/d/1QzbCGW8H6PZgLkmWN8OyplVNTJhp3tlPGxR_Zv6lttM/pub输出= CSV&#34;&GT;
答案 0 :(得分:2)
目前这个问题并不是很清楚,所以这个答案的当前形式是不完整的。
以下是一些可能简化代码的建议,希望有助于实现最终目标:
以下是使用此TSV的基本示例,基于上面保存为data.tsv的数据
157
使用深灰色显示路径的原点和目的地,以下是使用部分样本数据的结果:
如果您需要在创建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()
在这种情况下,检索第一行将如下所示:
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之间)并返回其间的值。把它想象成你的道路上的百分比:
这里是一个基本示例,在遍历每条线时绘制一个椭圆,它的颜色表示开始(黑色)或结束(白色)位置(拖动应该允许手动控制将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);
}
}
这是另一个有趣的小变化:
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