processing - 在球体上尝试曲线。似乎无法正确理解曲线的上升和下降
问题描述
代码插入如下:
float angle;
float r = 200;
Table table;
PImage earth;
PShape globe;
int rowCount;
void setup() {
background(51);
size(600, 600, P3D);
table = new Table("From_USA_Coordinates.tsv");
rowCount = table.getRowCount();
earth = loadImage("world.topo.bathy.200406.3x5400x2700.jpg");
noStroke();
globe = createShape(SPHERE, r);
globe.setTexture(earth);
}
void draw() {
background(51);
text("From USA to other Parts of the World", width/2, 50);
textAlign(CENTER);
translate(width/2, height/2);
//rotateY(angle);
//angle += 0.005;
//lights();
noStroke();
shape(globe);
for(int row = 0; row < rowCount; row++){
float USALatitude = table.getFloat(row, 3);
float USALongitude = table.getFloat(row, 4);
float tripCountryLatitude = table.getFloat(row, 5);
float tripCountryLongitude = table.getFloat(row, 6);
int tripCountryOccurance = table.getInt(row, 2);
float tripTheta = radians(tripCountryLatitude);
float tripPhi = radians(tripCountryLongitude) + PI;
float USATheta = radians(USALatitude);
float USAPhi = radians(USALongitude);
float x1 = r * cos(USATheta) * cos(USAPhi);
float y1 = -r * sin(USATheta);
float z1 = -r * cos(USATheta) * sin(USAPhi);
float x2 = r * cos(tripTheta) * cos(tripPhi);
float y2 = -r * sin(tripTheta);
float z2 = -r * cos(tripTheta) * sin(tripPhi);
pushMatrix();
noFill();
stroke(255);
bezier(x1, y1, z1, x1+150, y1+240, z1+150, x2-300, y2-150, z2-190, x2, y2, z2);
popMatrix();
}
noLoop();
}
表类:
class Table {
int rowCount;
String[][] data;
Table(String filename) {
String[] rows = loadStrings(filename);
data = new String[rows.length][];
for (int i = 0; i < rows.length; i++) {
if (trim(rows[i]).length() == 0) {
continue; // skip empty rows
}
if (rows[i].startsWith("#")) {
continue; // skip comment lines
}
// split the row on the tabs
String[] pieces = split(rows[i], TAB);
// copy to the table array
data[rowCount] = pieces;
rowCount++;
// this could be done in one fell swoop via:
//data[rowCount++] = split(rows[i], TAB);
}
// resize the 'data' array as necessary
data = (String[][]) subset(data, 0, rowCount);
}
int getRowCount() {
return rowCount;
}
// find a row by its name, returns -1 if no row found
int getRowIndex(String name) {
for (int i = 0; i < rowCount; i++) {
if (data[i][0].equals(name)) {
return i;
}
}
println("No row named '" + name + "' was found");
return -1;
}
String getRowName(int row) {
return getString(row, 0);
}
String getString(int rowIndex, int column) {
return data[rowIndex][column];
}
String getString(String rowName, int column) {
return getString(getRowIndex(rowName), column);
}
int getInt(String rowName, int column) {
return parseInt(getString(rowName, column));
}
int getInt(int rowIndex, int column) {
return parseInt(getString(rowIndex, column));
}
float getFloat(String rowName, int column) {
return parseFloat(getString(rowName, column));
}
float getFloat(int rowIndex, int column) {
return parseFloat(getString(rowIndex, column));
}
void setRowName(int row, String what) {
data[row][0] = what;
}
void setString(int rowIndex, int column, String what) {
data[rowIndex][column] = what;
}
void setString(String rowName, int column, String what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = what;
}
void setInt(int rowIndex, int column, int what) {
data[rowIndex][column] = str(what);
}
void setInt(String rowName, int column, int what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = str(what);
}
void setFloat(int rowIndex, int column, float what) {
data[rowIndex][column] = str(what);
}
void setFloat(String rowName, int column, float what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = str(what);
}
}
链接到我的数据集: https ://drive.google.com/file/d/1W169RaiqqvHiDAJvMGnAztjjqkTFCCRH/view?usp=sharing
最后是球体中地球纹理的链接: https ://drive.google.com/file/d/1qQx5CGwqPFufdOIBbKiBivos_hxd7AJq/view?usp=sharing
解决方案
我用注释对代码进行了一些更改。给定球体表面上的两个点,我计算了指向向外的点的法线。然后,我添加了法线并将结果归一化以获得贝塞尔曲线应该倾斜的平均方向。将此值乘以一个因子(凸起),可以控制曲线的高度。(使用较小的值可能会导致曲线与地球相交)。我根据点之间的距离分配了膨胀系数。这是代码:
float angle = 0;
float r = 200f;
Table table;
PImage earth;
PShape globe;
int rowCount;
void setup() {
size(600, 600, P3D);
table = new Table("From_USA_Coordinates.tsv");
rowCount = table.getRowCount();
earth = loadImage("world.topo.bathy.200406.3x5400x2700.jpg");
globe = createShape(SPHERE, r);
globe.beginShape(SPHERE);
globe.noStroke();
globe.endShape();
globe.setTexture(earth);
}
void draw() {
background(51);
text("From USA to other Parts of the World", width/2, 50);
textAlign(CENTER);
translate(width/2f, height/2f);
ambientLight(180, 180, 180);
rotateY(angle);
angle += 0.005f;
shape(globe);
for(int row = 0; row < rowCount; row++) {
float USALatitude = radians(table.getFloat(row, 3));
float USALongitude = radians(table.getFloat(row, 4));
float tripCountryLatitude = radians(table.getFloat(row, 5));
float tripCountryLongitude = radians(table.getFloat(row, 6));
int tripCountryOccurance = table.getInt(row, 2);
// Corrected calculations based on Processing environment. (Y points down).
float x1 = -r * cos(USALatitude) * cos(USALongitude);
float y1 = -r * sin(USALatitude);
float z1 = r * cos(USALatitude) * sin(USALongitude);
float x2 = -r * cos(tripCountryLatitude) * cos(tripCountryLongitude);
float y2 = -r * sin(tripCountryLatitude);
float z2 = r * cos(tripCountryLatitude) * sin(tripCountryLongitude);
pushMatrix();
// Calculate normal to the first point on the sphere surface
PVector norm1 = calculateNormal(new PVector(x1, y1, z1), new PVector(0,0,0));
// Do the same for second point
PVector norm2 = calculateNormal(new PVector(x2, y2, z2), new PVector(0,0,0));
// Calculate dir. This is the sum of two normals and gives an average direction towards which, the intermediate bezier points should point.
// It theoritically bisects the two normal vectors.
PVector dir = norm1.add(norm2).normalize();
// Calculate distance between the points based on which, the bulge factor will apply.
float d = dist(x1, y1, z1, x2, y2, z2);
// Lower bulge might result into intersection of curve with earth.
float bulge = 2*d / 3f;
// Amplify the dir with bulge factor
dir.mult(bulge);
bezierDetail(120);
noFill();
stroke(255, 120);
strokeWeight(2);
bezier(x1, y1, z1, // First point
x1 + dir.x, y1 + dir.y, z1 + dir.z, // First intermediate point
x2 + dir.x, y2 + dir.y, z2 + dir.z, // Second intermediate point
x2, y2, z2); // Final point
popMatrix();
}
}
// Returns normalized vector perpendicular to the point p on the surface of a sphere with the given center
PVector calculateNormal(PVector p, PVector center) {
return p.sub(center).normalize();
}
忽略结果中的工件。我必须高度压缩 gif 才能在此处发布。
希望这可以帮助!
推荐阅读
- google-apps-script - 谷歌表格 dd/mm/yyyy 到 mm/dd/yyyy 日期格式
- neural-network - Inception-v1 与 Inception-Resnet-V1
- shell - 如何用户期望并发送请求和睡眠
- leaflet - 如何将多边形坐标添加到现有的 geoJSON 文件?
- cassandra - Opscenter.rollup_state 表的卡住压缩
- go - 从 redis 获取结构数组时解组错误
- excel - 在给定范围内查找 Length=2 单元格
- ubuntu - 是否可以从我不是管理员的系统上的容器中构建容器?
- angular - 从一个window.addEventListener(MessageEvent)中取出一个值event.data来执行一个新的函数
- python - split() 缺少 1 个必需的位置参数:'y'