我正在Processing中编写一个程序来制作一个三维散点图,可以使用PeasyCam在空间中旋转。数据从文本文件读入PVectors的ArrayList。整个代码如下所示。我不明白的是,需要在draw()中调用(重复)importTextfile(),这会显着减慢速度。为什么我不能在setup()中调用它一次?使用draw()中的“println(pointsList)”,我可以看到如果pointList之前没有importTextFile(),则会更改。有谁能解释为什么?
(更新:从尝试构建一个最小工作示例,我现在看到问题是当我制作PVector V然后将其写入以将其映射到显示窗口时。我仍然会感谢关于良好工作的反馈,包括在setup()期间调用importTextFile()。我使用什么代替.get()所以我得到了Arraylist中的内容的副本,而不是指向ArrayList中实际值的指针?)
以下是代码:
import peasy.*;
PeasyCam cam;
ArrayList <PVector>pointList;
int maxX = 0;
int maxY = 0;
int maxZ = 0;
int minX = 10000;
int minY = 10000;
int minZ = 10000;
int range = 0;
void setup() {
size(500, 500, P3D);
cam = new PeasyCam(this, width/2, width/2, width/2, 800);
cam.setMinimumDistance(100);
cam.setMaximumDistance(2000);
pointList = new ArrayList();
importTextFile();
println(pointList);
//Determine min and max along each axis
for (int i=0; i < pointList.size(); i++) {
PVector R = pointList.get(i);
if (R.x > maxX) {
maxX = (int)R.x;
}
if (R.x < minX) {
minX = (int)R.x;
}
if (R.y > maxY) {
maxY = (int)R.y;
}
if (R.y < minY) {
minY = (int)R.y;
}
if (R.z > maxZ) {
maxZ = (int)R.z;
}
if (R.z < minZ) {
minZ = (int)R.z;
}
}
if (maxX - minX > range) {
range = maxX - minX;
}
if (maxY - minY > range) {
range = maxY - minY;
}
if (maxZ - minZ > range) {
range = maxZ - minZ;
}
println(pointList);
}
void draw() {
//importTextFile(); Uncomment to make run properly
println(pointList);
background(255);
stroke(0);
strokeWeight(2);
line(0, 0, 0, width, 0, 0);
line(0, 0, 0, 0, width, 0);
line(0, 0, 0, 0, 0, width);
stroke(150);
strokeWeight(1);
for (int i=1; i<6; i++) {
line(i*width/5, 0, 0, i*width/5, width, 0);
line(0, i*width/5, 0, width, i*width/5, 0);
}
lights();
noStroke();
fill(255, 0, 0);
sphereDetail(10);
//**The problem is here**
for (int i=0; i < pointList.size(); i++) {
PVector V = pointList.get(i);
V.x = map(V.x, minX-50, minX+range+50, 0, width);
V.y = map(V.y, minY-50, minY+range+50, 0, width);
V.z = map(V.z, minZ-50, minZ+range+50, 0, width);
pushMatrix();
translate(V.x, V.y, V.z);
sphere(4);
popMatrix();
}
}
void importTextFile() {
String[] strLines = loadStrings("positions.txt");
for (int i = 0; i < strLines.length; ++i) {
String[] arrTokens = split(strLines[i], ',');
float xx = float(arrTokens[2]);
float yy = float(arrTokens[1]);
float zz = float(arrTokens[0]);
pointList.add( new PVector(xx,zz,yy) );
}
}
答案 0 :(得分:2)
你可以继续重构,我不知道为什么他们在Processing文档中显示这种迭代ArrayLists的方法,但这里是重构它:
float calcV (float n) {
return map (n, minX-50, minX+range+50, 0, width);
}
for (PVector V: pointList) {
pushMatrix();
translate(calcV(V.x), calcV(V.y), calcV(V.z));
sphere(4);
popMatrix();
}
您可以考虑使用PVector作为字段或扩展PVector来创建新类。 Daniel Shiffman经常使用这种模式。创建一个类,其中PVector用于位置,另一个用于速度,一种方法用于计算每帧的新位置,另一种用于将其绘制到屏幕。这为您提供了很大的灵活性,而不必编写大量的循环,除了一个循环计算和显示ArrayList中的对象。
答案 1 :(得分:0)
我使用下面的代码解决了问题,但我仍然对其他方式感兴趣。
for (int i=0; i < pointList.size(); i++) {
PVector V = pointList.get(i);
PVector W = new PVector(0.0, 0.0, 0.0);
W.x = map(V.x, minX-50, minX+range+50, 0, width);
W.y = map(V.y, minY-50, minY+range+50, 0, width);
W.z = map(V.z, minZ-50, minZ+range+50, 0, width);
pushMatrix();
translate(W.x, W.y, W.z);
sphere(4);
popMatrix();
}
答案 2 :(得分:0)
由于PVector是一个对象,当你执行PVector V = pointList.get(i)
时,你将pointList中该特定元素的引用传递给V.它在内存中的地址。所以现在V和pointList.get(number)共享相同的内存地址。任何一个中的任何更改都会改变两者,因为它们是指向同一位置的两个不同指针。
但是,如果你这样做:
PVector V = new PVector(pointList.get(i).x, pointList.get(i).y, pointList.get(i).z);
V将是一个新对象,事情将按你的意愿工作,因为现在V拥有它自己的内存地址。并且poinList将保持不变。同样的事情也适用于其他对象,例如数组,试试看:
int[] one = new int[3];
int[] two = new int[3];
void setup(){
one[0] = 0;
one[1] = 1;
one[2] = 2;
print("one firstPrint -> \n");
println(one);
two = one;
print("two firstPrint -> \n");
println(two);
two[2] = 4;
// we didn't mean to change one, but...
print("one secondPrint -> \n");
println(one);
}