Old Project, New Version

Yes, I didnt make that clear that a position fix is when 3 circles intersect. Right now I’m revisiting Unfolding for Maps in processing-2.2.1 . This would allow to zoom in and see where the “fix” is on a Microsoft satellite map. The biggest limit on accuracy right now is how the variables like altitude are input - you can only get somewhat close with those sliders.

1 Like

I got this to work with Unfolding in processing-2.2.1. I used Interactive Computer Ephemeris from USNO to calculate for 39.21N, -77.21W and used Dubhe, Arcturus, Betelgeuse. I entered the GHA,dec,alt for each by writing it into the code instead of using the sliders, to see how well my code works with Unfolding and it works fairly nicely, except the more you zoom the points dont show well. When I use the sliders, there is mlles/kilometers of slop. Here’s a shot of a “fix” in Unfolding.

2 Likes

Looks great!!

Maybe use the sliders to update values in value boxes – but also allow the user to edit the values directly? Then you can either 1) type them in or 2) slide them, roughly, or 3) rough-them in with the sliders, then fine-tune by editing.

1 Like

Yeah, good idea about the input. I’ll need to research it because I really only know what others have already written, i.e., I can arrange but Im still lousy at original work. Anyway, changing the input method shuldnt be too hard, just need some time.

Im getting somewhere now. I need to figure out how to set a slider value based on text input and text based on slider value. I have no idea how to do that and suspect it might even discouraged. It would be cool though. The current layout for swing components is just to get them in and not optimal. I’ll have to rearrange them so GHA slider is near the GHA text input, etc.

Any chance that you can link or upload the “earthmap1.jpg” file?

I didnt link it because I couldnt remember where I found it, so I went searching and I got it by downloading JPARSEC from this site: http://conga.oan.es/~alonso/doku.php?id=jparsec To find the earthmap1.jpg file you have to look inside jprarsec.jar and look for textures.jar, it is inside that.

BTW, JPARSEC is very cool and is written in java. I’ve used some of it in a few sketches.

Here’s the link to jparsec/lib which contains textures.jar

http://conga.oan.es/~alonso/jparsec/lib/

1 Like

I found an example of java swing that combines text input with a slider. When you change the slider, the text changes and if you change the text directly, the slider updates. I was able to stick it directly into my code by adding a tab and then instantiating that class(I think that’s what its called when you use a class). There is one big problem though and that is that it only works with integers, but I have an idea. I found another example that also ties text/slider together and it uses Double.

Here’s the link to the integer example:

https://bitbucket.org/prubin/comboslider/src/master/src/comboslider/ComboSlider.java

1 Like

Not sure if it would be useful, but I recently saw a new Processing UI library you might take a look at:

1 Like

Odd, I don’t see any textures.jar inside that jparsec.jar download.

Sorry about the link, jparsec is cool but the site is a pain to read. I went to this link and textures.jar is listed.

http://conga.oan.es/~alonso/jparsec/lib/

1 Like
earthmap1.jpg

That looks good. It looks like its built on swing and sliders in swing use int, so I will be in the same spot trying to input text that represents a double and simultaneously update a slider that needs an int.

I modified that ComboSlider example so that it displays a double value, but when I try to edit the textfield it mixes the order of the numbers. That’s not useful. I mentioned a double slider example but it wont allow to edit the textfield either. I can change one digit after the decimal point but if I try to change more, it jumps to min or max.

1 Like

I reduced my sketch down to just a few swing inputs like one slider, one button, one textfield and gave it another try. I almost have it. I can move the slider and the textfield changes and shows a double. I can also edit the textfield. Edit: Whoops, now I can do both if I use a button to do it. Press the button after entering text and the slider updates.
Edit: Forgot to update the code. And, to use it, enter the text by typing and hitting enter. Then hit the GHA button. Or, move the slider and then hit enter in the textfield or it causes a nullpointer. Also, if you hit GHA and it prints a value in radians, then hit GHA again. Its not perfect, but it is a start.

Here’s the reduced code:

//Generated by GuiGenie - Copyright (c) 2004 Mario Awad.
//Home Page http://guigenie.cjb.net - Check often for new versions!
//import java.awt.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.text.DecimalFormat;

MyPanel controlPanel;
public String text;


double GHA = Math.toRadians(-51.16667f); //(-128.83333f);
double GHA1 = Math.toRadians(51.16667f);

//double alt = Math.toRadians(62.6f);

int timer=0;

boolean Star1;



public class MyPanel extends JPanel {
    private TextDemo jcomp1;
    private JLabel jcomp2;
    private JButton jcomp3;

    //private JButton jcomp9;
    private JButton jcomp4;
    private JSlider jcomp5;


    public MyPanel() {
        //construct components
        jcomp1 = new TextDemo(); //JTextArea (1, 16);
        jcomp2 = new JLabel ("GHA : DDD.MMSS");
        jcomp3 = new JButton ("GHA");
        jcomp4 = new JButton("Star1");
        jcomp5 = new JSlider(0,360,(int)(Math.toDegrees(-GHA)));  //,(int)Math.toDegrees(GHA));

        jcomp3.addActionListener(new Button1Click());
        jcomp4.addActionListener(new Button2Click());
        jcomp5.addChangeListener(new HSlider1Change());
        
        jcomp5.setOrientation (JSlider.HORIZONTAL);
        jcomp5.setMinorTickSpacing (10);
        jcomp5.setMajorTickSpacing (60);
        jcomp5.setPaintTicks (true);
        jcomp5.setPaintLabels (true);
               
        //adjust size and set layout
        setPreferredSize (new Dimension (544, 756));
        setLayout (null);

        //add components
        add (jcomp1);
        add (jcomp2);
        add (jcomp3);
        add (jcomp4);
        add (jcomp5);


        //set component bounds (only needed by Absolute Positioning)
        jcomp1.setBounds (70, 35, 205, 25);
        jcomp2.setBounds (285, 35, 175, 25);
        jcomp3.setBounds (70, 80, 100, 25);
        jcomp4.setBounds (70,320,100,25);
        jcomp5.setBounds(70,420,400,50);
        
 }
 
    
class Button1Click implements ActionListener
{
  public void actionPerformed(ActionEvent e)
  {
    JButton b = (JButton)e.getSource();
    GHA = Double.parseDouble(text);
            jcomp5.setValue((int)Double.parseDouble(text));
    jcomp1.textField.setText(text);

    println("GHA: " + GHA);
    timer=millis()+1000;

  }
}


class Button2Click implements ActionListener
{
  public void actionPerformed(ActionEvent e)
  {
    JButton b = (JButton)e.getSource();

    GHA1 = GHA;
    println("GHA1: " + GHA1); 
    //  dec1 = dec;
    //  alt1 = alt;
    // Globe = true;
    //  Map = false;
    Star1 = true;
    timer=millis()+1000;
  }
}


class HSlider1Change implements ChangeListener
{
          
  public void stateChanged(ChangeEvent e)
  {
    JSlider source = (JSlider)e.getSource();
     if (source.getValue() < 180){
        GHA = radians( (- source.getValue()));
        jcomp1.textField.setText(Double.toString(Math.toDegrees(-GHA))); 
     }
     if (source.getValue() > 180) {
        GHA = radians((360 - source.getValue())); 
        jcomp1.textField.setText(Double.toString(360-(Math.toDegrees(GHA))));
     }
     timer=millis()+1000; 
 
     println("slider: " + source.getValue() + " GHA: " + Math.toDegrees(GHA));
  }
}


}


void setup()
{

  JFrame frame =new JFrame("Controls");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  controlPanel = new MyPanel();
  controlPanel.setOpaque(true); //content panes must be opaque
  frame.setContentPane(controlPanel);
//frame.add(new TextDemo());
  //Display the window.
  frame.pack();
  frame.setVisible(true);
}




public class TextDemo extends JPanel implements ActionListener {
    protected JTextField textField;
    protected JTextArea textArea;
    private final static String newline = "\n";
 
    public TextDemo() {

        textField = new JTextField(20);
        textField.addActionListener(this);
        textField.setHorizontalAlignment(textField.CENTER);
        textArea = new JTextArea(2, 20);
        textArea.setEditable(false);

        add(textField);
        add(textArea);
    }
 
    public void actionPerformed(ActionEvent evt) {

        text = textField.getText();
        textArea.append(text + newline);
        textField.selectAll();
        GHA = Double.parseDouble(text);
        textField.setText(Double.toString(GHA));
        
        
        println(GHA);
 
        //Make sure the new text is visible, even if there
        //was a selection in the text area.

    }
}

1 Like

I tried to implement the changes I made in the stripped down GUI code. It worked mostly, except updating the slider caused some problems, so I commented that out. I kept the parts that updated the text and then calculated a fix using the Interactive Computer Ephemeris, and input the data by editing the text. I’m posting this shot because it shows good geometry. If I get the GUI straight, I want to use all the points to calculate an actual intersection. Its good that I can zoom in but the points get lost, the closer you zoom.

1 Like

I stumbled onto a nice feature of the points generating code. If you enter the declination as 90.00 degrees and the altitude as some latitude, then the points generated will draw a line of latitude. It makes sense. If polaris which is basically declination 90.00 degrees is observed at your latitude, the observed altitude of polaris will be your latitude.

I’ve been reading about the history of celestial navigation and got to the part about Sumner and lines of position and using the transit of a body across the local meridian as a way to check chronometers. So, I used ICE to calculate the transit of the sun. I then picked 1 hour before transit, time of transit and 1 hour after. I got three circles of position, with transit being the smallest. I thought it was interesting that it shows that the sun at local noon(transit)is at the highest altitude and the two circles preceding and following have equal altitudes and are bigger than transit because the alttiude is lower. It just illustrates what these circles are in a clear way.

Finally, just out of curiosity if I can draw a latitude line, can I also draw a longitude line. If I subtract my longitude from 90 degrees and set declination to 0 degrees and altitude also to 0 degrees, then yes.

1 Like

Alright, enough of that. Now I need to write an algorithm that uses the points generated to calculate an intersection. What I have now is 3600 points calculated for each circle, put into an array, then drawn on the map. It looks good, but the intersection is visual only.

It would be inefficient to do line-line on all points, as that is ~13 million checks to find the intersections between pairs of points, which may intersect 0, 1, or 2 times.

However, that will solve the problem simply.

Here is an example finding all intersections on two randomly generated lines:

/**
 * PointListIntersections
 * find any/all intersections on two random point lists
 * 2020-05-22 Jeremy Douglass Processing 3.5.4 
 * https://discourse.processing.org/t/old-project-new-version/20156/20
 *
 * This is checking *all* pairs, which is inefficient for ordered data.
 */
 
PVector[] as;
PVector[] bs;
int len = 100;  // how many points per line
int xstep = 5;  // x step on canvas between points

void settings() {
  size(len*xstep, len*xstep);
}

void setup() {
  as = new PVector[len];
  bs = new PVector[len];
  makePoints(xstep);
}
void draw() {
  background(255);

  // randomize the points again
  if(frameCount%120==0) {
    noiseSeed(frameCount);
    makePoints(xstep);
  }
  drawPoints(as, color(255,0,0));
  drawPoints(bs, color(0,0,255));

  drawLines(as, color(255,0,0));
  drawLines(bs, color(0,0,255));
  
  ArrayList<PVector> crosses = findCrosses(as, bs);
  for(PVector cross : crosses) {
    fill(0,255,0,128);
    ellipse(cross.x, cross.y, 10, 10);
  }
}
  
void drawPoints(PVector[] pts, color c) {
  for(int i=0; i<len; i++) {
    fill(c);
    ellipse(pts[i].x, pts[i].y, 3, 3);
  }
}

void drawLines(PVector[] pts, color c) {
  for(int i=1; i<len; i++) {
    stroke(c);
    line(pts[i-1].x, pts[i-1].y, pts[i].x, pts[i].y);
  }
}

void makePoints(int xstep) {
  for(int i=0; i<len; i++) {
    as[i] = new PVector(i*xstep, height * noise(i*0.02));
    bs[i] = new PVector(i*xstep, height - height * noise(i*0.05));
  }
}

ArrayList<PVector> findCrosses (PVector[] as, PVector[] bs) {
  ArrayList<PVector> crosses = new ArrayList<PVector>();
  for(int a=1; a < as.length; a++) {
    for(int b=1; b < bs.length; b++) {
      PVector cross = lineLine(as[a-1].x, as[a-1].y, as[a].x, as[a].y, bs[b-1].x, bs[b-1].y, bs[b].x, bs[b].y);
      if(cross!=null) crosses.add(cross);
    }
  }
  return crosses;
}

PVector lineLine(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
  float uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
  float uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
  if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) { // lines are colliding
    float x = x1 + (uA * (x2-x1));
    float y = y1 + (uA * (y2-y1));
    return new PVector(x, y);
  }
  return null;
}

1 Like

Yes sir, that’s quite good. I haven’t spent enough time with that yet, but one thing I noticed with my code is that the bigger the circle, the further the points are spaced as the number of points is fixed. So, I would zoom right into where the intersection should be and find multiple points for one circle and maybe one point for another. That made it trickier to visualize the intersection. When I started playing with drawing latitude and longitude lines, I noticed the point spacing was equal for a purely latitude or longitude line and sometimes a point might even land on the intersection.

I’ll be baaaack, thanks for the link.

1 Like

One thing bugging me and that is that I need to provide a link to navigationalalgorithms.com . That is where I got the basic point generator. I modified it but started with what Andres Ruiz wrote. Here is the link to the paper. http://www.mediafire.com/file/pp89of9q9fk4rbi/rotmatricesCoP.zip/file The title is “Use of Rotation Matrices to Plot a Circle of Equal Altitude” and is inside the zip file.

I’ve read some of his other papers too and I think there could be an efficient way to calculate an intersection using some of the functions I already have.