Trying Curve on a Sphere. Can't seem to get the rise and fall of the curve right

Was trying something like this:

But my curves were all wrong…And I ended up with something like this.

The code is inserted below:


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

Table Class:

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

Link to my data set:

And finally the link to the earth texture in sphere:

In the example image bezier curves are on a plane that can be set by earth center, start point and end point. To make bezier curves on that plane all points you give in the bezier(), function needs to be on that plane. Vectors from earth’s center (if it’s on the origo, ie. it’s coordinates are 0,0,0) to the start (let’s call this u) and the end point (let’s call this v) form that plane, and any point on that plane can be expressed as au + bv.
An easy way to get all those points on that plane and to create bezier curve is to add t*v to starting point and t*u to end point. Bezier curves height from surface of the earth depend on how big t is.

bezier

Math is pretty straight forward in the end. Starting point is x1, y1, z1 and vector u is then (x1,y1,z1). End point is x2, y2, z2 and vector u is then (x2,y2,z2). So function call would be bezier(x1, y1, z1, x1+t*x2, y1+t*y2, z1+t*z2, x2+t*x1, y2+t*y1, z2+t*z1, x2, y2, z2). Note! This works only if earth’s center is 0, 0, 0.

By the way, did you know that processing has a Table datastructure, that has one function to load data from tsv, or csv file? Check https://processing.org/reference/loadTable_.html for instance

Thank you for the reply man.
This was the result.

I think some sort of vector should be added to make them all fall into correct orientation. I found the one for sphere, where you would change its height tangent to the surface of the sphere.
The result was as following:

The code for the vector part was :

 float boxHeight = map(tripCountryOccurance, 1, 394, 5, 100);
    
    PVector pos = new PVector(x, y, z);
    PVector xaxis = new PVector(1, 0, 0);
    float angleb = PVector.angleBetween(xaxis, pos);
    PVector raxis = xaxis.cross(pos);
    
    pushMatrix();
    translate(x, y, z);
    rotate(angleb, raxis.x, raxis.y, raxis.z);
    box(boxHeight, 10, 10);
    popMatrix();

It also introduced a dynamic box height according to number of bookings in my data. Do you have any idea about the vector. I don’t know anything about them.

I created arcs as part of a project I did a few years back.

I drew them using vectors; you will get a sense of it seeing the different lines in the first image.
The green one was the first one and I had to improve on that!

I stepped through these in the demo I did to show I how built them:

The end result was quite nice:

:)

1 Like

To me curves look to be on the right plane, but their shape is funny. I would try to tune t value based on the distance of start and end point. Smaller distance and smaller value of t. I think then they would have more pleasing and also more uniform shapes.

I have to admit that vector code you included would require a bit more thinking than I can manage at 10PM Friday night.

Thanks for the input @SomeOne. It really helped me a lot.

1 Like