What's possible with ellipse()?


#1

I play around with celestial navigation and processing to visualize things, some involve lots of trig. What I’ve used so far is shapes3d to build spheres, as in celestial sphere or earth sphere, then plot points for stars or observer location. This is great and looks cool, but… It has limitations that I’m trying to overcome, the biggest is my understanding of things…

Its certainly been a good trip and also led me to this site:

https://en.wikipedia.org/wiki/Circle_of_equal_altitude

And to this site for algorithms:

https://sites.google.com/site/navigationalalgorithms/papersnavigation

Sometimes a circle of equal altitude looks egg shaped on a map or oval or even will look like a sine wave and not a closed circle. That’s what I wonder if ellipse() function can be used to draw these circles. Ive tried it with just using a straight up circle, but that’s not correct.

Here are two images, the first shows how circles look on a flat map. The second image shows how these identical points look on a sphere. .

What I wonder is it possible to get the same oblong, egg, quasi rectangular, sine waveish type “circles” by using the processing ellipse() function?


#2

It is possible to use ellipse() to put a ring around a sphere. But I don’t think it is the right function for doing it on the distorted flat map. I honestly doubt it is even possible.

Instead, I would suggest you look into using this:

https://processing.org/reference/bezierVertex_.html


#3

I wasn’t totally clear how I am doing it right now. I’m using the algorithm from the link. Its kind of messy and so I wondered if processing had something better but accomplishes the same thing.

I’ll look at your Bezier hint and see if that has the flexibility. Thanks.


#4

What makes me wonder about PShapes like ellipse and Bezier is they are very good at drawing, compared to the algorithm I’m using which is very good at calculating and transforming.

When I use ellipse to draw angle data coming in real time over USB in android, it works smoothly.

Could I extend PShapes to use this CoP algorithm?


#5

Hi HackinHarry,

One way to go would be to subdivide your circle in x points.
Then you apply the transformation to each one of those points in order to know their position in the flat model.
Finally, you use curveVertex to link all your points together.
You should get a pretty good approximation of your curves :slight_smile:

Using curveVertex allow you to draw Catmull-Rom splines. The big advantages you have compare to bezier curves is that the spline go through all of your points.


#6

Yes, the aha moment. I see it. I gotta google Catmull-Rom splines, big Thanks.


#7

That worked!! I’ll post some code soon. I tried to control it with mouseY and it worked a few times and then locked up. The “approximation” is as good as any.


#8

Here’s the code using the @jb4x suggestion,Thanks It works now. It was locking up trying to println.



 float[] x = new float[3600];
 float[] y = new float[3600];

  // double GHA = Math.toRadians(162.3366651);
      double GHA = Math.toRadians(-38.6552);
// double dec = Math.toRadians(42); 
    double dec = Math.toRadians(62);
 //    double dec = mouseY;
  double Be = Math.toRadians(35.4000);
  double Le = Math.toRadians(26.452837); 

 double[]vv = new double[3]; //, vy[3], vyz[3];
 double[]vy = new double[3];
 double[]vyz = new double[3];
 double[]wpt = new double[3600];
 float[]WPT = new float[3600];

 double[][]My = new double[3][3];

 double[][]Mz = new double[3][3];


void setup() {
 size(400, 300, P3D); 
 smooth();
  noFill();   
 
}

void draw() {    
  background(0);   
  pushMatrix(); 
  dec = map(mouseY,height-height,height,90,-90);
  println(dec);
  x = new float[3600];
  y = new float[3600];


//  noLoop();
   getPoints();
  popMatrix();
  

}

void getPoints(){
     
  Mz = Rz(Math.toRadians(360.0) - GHA, Mz);
 
// println(Mz[0][0] + " " + Mz[0][1] + " " + Mz[0][2]);
// println(Mz[1][0] + " " + Mz[1][1] + " " + Mz[1][2]);
// println(Mz[2][0] + " " + Mz[2][1] + " " + Mz[2][2]);
 
  My =  Ry(Math.toRadians(90.0) - dec, My);
 
//  println(My[0][0] + " " + My[0][1] + " " + My[0][2]);
// println(My[1][0] + " " + My[1][1] + " " + My[1][2]);
// println(My[2][0] + " " + My[2][1] + " " + My[2][2]);

 int w = 0;

  for( double L0 = -180.0; L0 <= 180.0; L0 += .1 )
    {
//float alt = map(mouseX,width-width,width,0,90);
    vv =  VectorSpherical2Cartesian(Math.toRadians(62.5),Math.toRadians(L0) ); 
// vv =  VectorSpherical2Cartesian(alt,Math.toRadians(L0) );
     
    vy =  MatrixVecProd( My, vv, vy );

    vyz =  MatrixVecProd( Mz, vy, vyz );



    wpt[w] = C2ELat( vyz[0], vyz[1], vyz[2]);
    wpt[w+1] = C2ELon( vyz[0], vyz[1], vyz[2]);

    WPT = toFloatArray(wpt);

    x[w] = map(WPT[w+1],radians(-180) ,radians(180),width, width - width);
    y[w] = map(WPT[w],radians(-90),(radians(90)),height,height - height);
    point(x[w],y[w]);
    noFill();
    stroke(0,255,0);
    strokeWeight(2);
    beginShape();
    curveVertex(x[w],y[w]);
    curveVertex(x[w],y[w]);
    endShape();
  }
}


//Funcition to convert double[] to float[]
float[] toFloatArray(double[] arr) {
  if (arr == null) return null;
  int n = arr.length;
  float[] ret = new float[n];
  for (int i = 0; i < n; i++) {
    ret[i] = (float)arr[i];
  }
  return ret;
}
// end of function to convert double[] to float[]

 double[] VectorSpherical2Cartesian(double B, double L){
  
   double v[] = new double[3];
   v[0] = Math.cos(B) * Math.cos(L);
   v[1] = Math.cos(B) * Math.sin(L);
   v[2] = Math.sin(B);
//   println(B);
//   println(L);
   return(v);
   
 }

public double C2ELat( double x, double y, double z )
{
  double[]res = new double[3];
res[0] = Math.sqrt( x*x+y*y+z*z);  //R
//*B = ASIN(z/(*R));
res[1] = Math.atan2( z, Math.sqrt(x*x+y*y) ); //B
res[2] = Math.atan2( y, x ); //L

//println("R:  " + (res[0]) + "  B: " + Math.toDegrees(res[1]) + "  L: " + Math.toDegrees(res[2]));

return (res[1]);
//println(R);
}

public double C2ELon( double x, double y, double z )
{
  double[]res = new double[3];
res[0] = Math.sqrt( x*x+y*y+z*z);  //R
//*B = ASIN(z/(*R));
res[1] = Math.atan2( z, Math.sqrt(x*x+y*y) ); //B
res[2] = Math.atan2( y, x ); //L

//println("R:  " + (res[0]) + "  B: " + Math.toDegrees(res[1]) + "  L: " + Math.toDegrees(res[2]));

return (res[2]);
//println(R);
}
 
//public double[] E2C( double B, double L, double R, double x, double y, double z )
 
public double[] E2C( double B, double L, double R )
{
  double[]res = new double[3];
  
 res[0] = R*Math.cos((B))*Math.cos((L));
 res[1] = R*Math.cos((B))*Math.sin((L));
 res[2] = R*Math.sin((B));
 
// println(res[0] + " " + res[1] + " " + res[0]);
 
 return(res);
}
 
 public double[][] Rx( double a, double[][] M ){

  M[0][0] = 1.0;
  M[1][0] = 0.0;
  M[2][0] = 0.0;
  M[0][1] = 0.0;
  M[1][1] = Math.cos(a); //Math.cos(Math.toRadians(a));
  M[2][1] = Math.sin(a); //Math.sin(Math.toRadians(a));
  M[0][2] = 0.0;
  M[1][2] = -Math.sin(a); //-Math.sin(Math.toRadians(a));
  M[2][2] = Math.cos(a); //Math.cos(Math.toRadians(a));
  
  return(M);
}

public double[][] Ry( double a, double[][] M ){

  M[0][0] = Math.cos(a);
  M[1][0] = 0.0;
  M[2][0] = -Math.sin(a);
  M[0][1] = 0.0;
  M[1][1] = 1.0;
  M[2][1] = 0.0;
  M[0][2] = Math.sin(a);
  M[1][2] = 0.0; 
  M[2][2] = Math.cos(a);
  
  return(M);
}

public double[][] Rz( double a, double[][] M ){

  M[0][0] = Math.cos(a); //Math.cos(a);
  M[1][0] = Math.sin(a);
  M[2][0] = 0.0;
  M[0][1] = -Math.sin(a);
  M[1][1] = Math.cos(a);
  M[2][1] = 0.0;
  M[0][2] = 0.0; 
  M[1][2] = 0.0; 
  M[2][2] = 1.0;
  
  return(M);
}
 
public double[] MatrixVecProd( double[][] A, double[] v, double[] res ) {

  int i,j;
  int n = 3;

  for( i=0; i<n; i++ ) {
    res[i] = 0.0;
    for( j=0; j<n; j++ ) {
    res[i] += A[i][j]*v[j];
   
  }
}

return (res);
}

#9

If you go to the getPoints() function and uncomment float alt and swap comments on vv, And set the GHA to 0 in the variable area before setup(), it looks very good and symmetrical. This allows mouseX and mouseY to control the GHA and Altitude and you can see how it changes the shape of the circle. Another thing to do is change the dimensions of the size() and see how the shapes change.

I’m currently trying to use textureSphere and mouseX and mouseY to show how the circle will move around the globe. OneDrive screwed up my preferences.txt file, so I’m trying to fix that so it will see my libraries.


#10

Hi HackinHarry,

It seems that the mouse movement is too sensible, so the movements of your lines are not really smooth.


#11

Where I use map() to map the mouse to the angles needed, I reduced the range of angles that get mapped to a smaller range 15 to -15 and it is smoother. Thanks @ jb4x

  dec = map(mouseY,height-height,height,15,-15);

  float alt = map(mouseX,width-width,width,0,30);

#12

I see that this topic got moved to project guidance for good reason as this is part of a project I’ve been working on for some time. The project is to use an IMU connected by USB to android and use the pitch and yaw as inputs for GHA and altitude… It’s current state is it can read USB, use the data as input to calculate the circle of equal altitude, display those circles on a sphere. 3 of those circles intersecting is a position fix. It now does that.

Where it needs to go is allow selection of a navigational star with an altitude some nice angle… This would be preferred as the IMU is most accurate below about 80 degrees in pitch. Above that and it wants to gimbal lock and get all goofy.

Another feature that would be great is to switch between sphere display and map and zoom to see where the fix is.

As a related side note, way back when celestial navigation was new, accurate chronometers were new, somebody had the idea to use a really big globe and mark the observations and circles of equal altitude on that globe. That’s a good idea but accuracy required a ginormous globe. With a computer its now possible to realistically deploy that concept…