Spherical Coordinates and Angle back to Origin?

Alright, so I’ve been Googling for several days and cannot figure how to solve what I think is rather simple…? I’ve also searched the forum here and will list at the end some of the links I’ve explored.

Context: In 2D I can find the angle from one point to another using atan2 and create a line from one point in the direction of the other point with any desired length. I have some sample code below that has an origin at the center of the window and a secondary point that is essentially the mouseX and mouseY values. A line points from mouseX and mouseY towards the origin.x and origin.y.

Problem: My question is what is the equivalent to the above 2D solution in 3D? Create a line from one point with a given radius towards another in 3D space. From my searching I can place a point with x, y, and z values on the surface of a sphere given an origin, radius, theta, and phi. I believe this is called spherical to Cartesian coordinates. However, I cannot seem to be able to draw a line from a 3D point on the sphere surface back to the origin. I can seem to get theta and phi from a point on a sphere surface that when converted to Cartesian coordinates returns the origin point.

2D example:

PVector origin;      // center of window
PVector target;      // mouse position

void setup() {
  size(500, 500, P3D);
  origin = new PVector(width/2, height/2);
  target = new PVector();
}

void draw() {
  background(255);
  
  // set target to mouse position
  target.x = mouseX;
  target.y = mouseY;
  target.z = 100;
  
  // calculate angle from target/mouse to origin point
  float angle = atan2(origin.y - target.y, origin.x - target.x);
  float radius = 50;
  
  // caluclate new point form target towards origin with length radius
  float x = target.x + cos(angle) * radius;
  float y = target.y + sin(angle) * radius;
  
  // display origin and angle 
  fill(0);
  stroke(0);
  strokeWeight(10);
  point(origin.x, origin.y, origin.z); 
  strokeWeight(5);
  line(target.x, target.y, x, y);
  
  // what is the equivalent in 3D?
  // how can i draw a line with radius 50 from target pointing towards origin?
}

From my searching I’ve found the following:

float dx = origin.x - target.x;
float dy = origin.y - target.y;
float dz = origin.z - target.z;

float theta = atan2(dz, dx);
float phi = atan2(sqrt(sq(dz) + sq(dx)), dy)
// or:
float phi = atan2(sqrt(sq(dz) + sq(dx)), dy) * PI

// this can be converted to new points
// however this does not point back to origin
float x = target.x + radius * sin(phi) * cos(theta);
float y = target.y + radius * sin(phi) * sin(theta);
float z = target.z + radius * cos(phi);

I tried exploring the code from this question as well to no success:

Any tips or suggestions would be greatly appreciated.

1 Like

Hi @ASHER,

Welcome to the forum! :wink:

Thanks for the well written post!

First thing I would like to point out is that the 2D example can be simplified with vector math (without using atan2). In fact you can do the following:

(pseudocode below)

PVector mouseToCenter = center - mouse
PVector directionNormalized = mouseToCenter.normalize()
PVector lineEnd = center + directionNormalized * lineLength
float lineLength = 50;

void setup() {
  size(500, 500);
}

void draw() {
  background(255);
  
  PVector mouse = new PVector(mouseX, mouseY);
  PVector center = new PVector(width / 2, height / 2);
  
  PVector direction = PVector.sub(center, mouse).normalize();
  PVector lineEnd = PVector.add(mouse, PVector.mult(direction, lineLength));
  
  strokeWeight(5);
  line(mouse.x, mouse.y, lineEnd.x, lineEnd.y);
}

And in 3D this is the same computation but with one more dimension. Here with an animation around a sphere with a radius:

float lineLength = 50;
float time = 0;
float radius = 100;

void setup() {
  size(500, 500, P3D);
}

void draw() {
  background(255);
  
  translate(width / 2, height / 2);
  
  PVector lineOrigin = new PVector(cos(time) * radius, sin(time) * radius, cos(time / 2) * radius);
  PVector center = new PVector(0, 0, 0);
  
  PVector direction = PVector.sub(center, lineOrigin).normalize();
  PVector lineEnd = PVector.add(lineOrigin, PVector.mult(direction, lineLength));
  
  strokeWeight(5);
  line(lineOrigin.x, lineOrigin.y, lineOrigin.z, lineEnd.x, lineEnd.y, lineEnd.z);
  
  time += 0.1;
}

Of course you can still use spherical coordinates and convert it to cartesian but I find the above solution simpler :wink: (if it suits your needs)

3 Likes

Hello @ASHER ,

Some code I wrote to convert:

  • spherical to Cartesian
  • Cartesian to spherical < To compare to above!
// Spherical Coordinate System
// v1.0.0
// GLV 2022-11-19

// Reference:
// https://en.wikipedia.org/wiki/Spherical_coordinate_system

void setup()
  {
  size(500, 500, P3D);
  background(255);
  frameRate(60); //Default
  }

  float theta;
  float phi;
  
  
void draw()
  {
  //background(255);
  
  translate(width/2, height/2);
  
  //phi = random(0, TAU);
  phi = random(-TAU/2, TAU/2);
  theta = random(0, TAU/2);
  println( nf(degrees(phi), 3, 1), nf(degrees(theta), 3, 1) );
  //println(nf((degrees((phi + TAU)%TAU)), 3, 1), nf(degrees(theta), 3, 1)); // Converts to 0 to TAU
    
  float radius = 200;

  float x = radius * sin(theta) * cos(phi);
  float y = radius * sin(theta) * sin(phi);
  float z = radius * cos(theta);
  
  theta = acos(z/200);
  phi = atan2(y, x);
  
  // See atan2() reference
  // Values returned are PI to -PI
  println( nf(degrees(phi), 3, 1), nf(degrees(theta), 3, 1) );
  //println(nf((degrees((phi + TAU)%TAU)), 3, 1), nf(degrees(theta), 3, 1)); // Converts to 0 to TAU
  println();
  
  strokeWeight(1);
  stroke(128);
  line(0, 0, 0, x, y, z);
  
  strokeWeight(4);
  stroke(0, 255, 0);
  line(x, y, z, x-x/4, y-y/4, z-z/4);
  
  strokeWeight(10);
  stroke(255, 0, 0);
  point(x, y, z);
  
  strokeWeight(10);
  stroke(255, 0, 0);
  point(0, 0, 0);
  }

Also added some frills.

Base code above with some embellishments (not included here):

Reference:
https://en.wikipedia.org/wiki/Spherical_coordinate_system

:)

1 Like