altosui: Add KML file export.
authorKeith Packard <keithp@keithp.com>
Wed, 29 Sep 2010 00:56:49 +0000 (17:56 -0700)
committerKeith Packard <keithp@keithp.com>
Wed, 29 Sep 2010 00:56:49 +0000 (17:56 -0700)
Command line has switches now, --kml and --csv
Export save dialog has combo box to select kml or csv result.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-tools/altosui/Altos.java
ao-tools/altosui/AltosCSV.java
ao-tools/altosui/AltosCSVUI.java
ao-tools/altosui/AltosKML.java [new file with mode: 0644]
ao-tools/altosui/AltosUI.java
ao-tools/altosui/AltosWriter.java [new file with mode: 0644]
ao-tools/altosui/Makefile.am

index 07bd01a..997550e 100644 (file)
@@ -200,4 +200,11 @@ public class Altos {
                }
                return v * sign;
        }
+
+       static String replace_extension(String input, String extension) {
+               int dot = input.lastIndexOf(".");
+               if (dot > 0)
+                       input = input.substring(0,dot);
+               return input.concat(extension);
+       }
 }
index 3a9e48f..df98b2b 100644 (file)
@@ -22,9 +22,7 @@ import java.io.*;
 import java.text.*;
 import java.util.*;
 
-import altosui.AltosRecord;
-
-public class AltosCSV {
+public class AltosCSV implements AltosWriter {
        File                    name;
        PrintStream             out;
        boolean                 header_written;
@@ -33,9 +31,9 @@ public class AltosCSV {
        LinkedList<AltosRecord> pad_records;
        AltosState              state;
 
-       static final int ALTOS_CSV_VERSION = 1;
+       static final int ALTOS_CSV_VERSION = 2;
 
-       /* Version 1 format:
+       /* Version 2 format:
         *
         * General info
         *      version number
@@ -91,7 +89,7 @@ public class AltosCSV {
 
        void write_general(AltosRecord record) {
                out.printf("%s, %d, %d, %s, %8.2f, %4d, %3d",
-                          record.version, record.serial, record.flight, record.callsign,
+                          ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign,
                           (double) record.time,
                           record.rssi,
                           record.status & 0x7f);
index 4eb72de..eb620ba 100644 (file)
@@ -38,7 +38,25 @@ public class AltosCSVUI
        JFrame                  frame;
        Thread                  thread;
        AltosRecordIterable     iterable;
-       AltosCSV                writer;
+       AltosWriter             writer;
+       JFileChooser            csv_chooser;
+       JComboBox               combo_box;
+
+       static String[]         combo_box_items = { "CSV", "KML" };
+
+       void set_default_file() {
+               File    current = csv_chooser.getSelectedFile();
+               String  current_name = current.getName();
+               String  new_name = null;
+               String  selected = (String) combo_box.getSelectedItem();
+
+               if (selected.equals("CSV"))
+                       new_name = Altos.replace_extension(current_name, ".csv");
+               else if (selected.equals("KML"))
+                       new_name = Altos.replace_extension(current_name, ".kml");
+               if (new_name != null)
+                       csv_chooser.setSelectedFile(new File(new_name));
+       }
 
        public void run() {
                AltosLogfileChooser     chooser;
@@ -47,20 +65,22 @@ public class AltosCSVUI
                iterable = chooser.runDialog();
                if (iterable == null)
                        return;
-               JFileChooser    csv_chooser;
 
-               File file = chooser.file();
-               String path = file.getPath();
-               int dot = path.lastIndexOf(".");
-               if (dot >= 0)
-                       path = path.substring(0,dot);
-               path = path.concat(".csv");
-               csv_chooser = new JFileChooser(path);
-               csv_chooser.setSelectedFile(new File(path));
+               csv_chooser = new JFileChooser(chooser.file());
+               combo_box = new JComboBox(combo_box_items);
+               combo_box.addActionListener(this);
+               csv_chooser.setAccessory(combo_box);
+               csv_chooser.setSelectedFile(chooser.file());
+               set_default_file();
                int ret = csv_chooser.showSaveDialog(frame);
                if (ret == JFileChooser.APPROVE_OPTION) {
+                       File    file = csv_chooser.getSelectedFile();
+                       String  type = (String) combo_box.getSelectedItem();
                        try {
-                               writer = new AltosCSV(csv_chooser.getSelectedFile());
+                               if (type.equals("CSV"))
+                                       writer = new AltosCSV(file);
+                               else
+                                       writer = new AltosKML(file);
                        } catch (FileNotFoundException ee) {
                                JOptionPane.showMessageDialog(frame,
                                                              file.getName(),
@@ -73,6 +93,9 @@ public class AltosCSVUI
        }
 
        public void actionPerformed(ActionEvent e) {
+               System.out.printf("command %s param %s\n", e.getActionCommand(), e.paramString());
+               if (e.getActionCommand().equals("comboBoxChanged"))
+                       set_default_file();
        }
 
        public AltosCSVUI(JFrame in_frame) {
diff --git a/ao-tools/altosui/AltosKML.java b/ao-tools/altosui/AltosKML.java
new file mode 100644 (file)
index 0000000..d586033
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.lang.*;
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+public class AltosKML implements AltosWriter {
+
+       File                    name;
+       PrintStream             out;
+       int                     state = -1;
+       AltosRecord             prev = null;
+
+       static final String[] kml_state_colors = {
+               "FF000000",
+               "FF000000",
+               "FF000000",
+               "FF0000FF",
+               "FF4080FF",
+               "FF00FFFF",
+               "FFFF0000",
+               "FF00FF00",
+               "FF000000",
+               "FFFFFFFF"
+       };
+
+       static final String kml_header_start =
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+               "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
+               "<Document>\n" +
+               "  <name>AO Flight#%d S/N: %03d</name>\n" +
+               "  <description>\n";
+       static final String kml_header_end =
+               "  </description>\n" +
+               "  <open>0</open>\n";
+
+       static final String kml_style_start =
+               "  <Style id=\"ao-flightstate-%s\">\n" +
+               "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
+               "    <BalloonStyle>\n" +
+               "      <text>\n";
+
+       static final String kml_style_end =
+               "      </text>\n" +
+               "    </BalloonStyle>\n" +
+               "  </Style>\n";
+
+       static final String kml_placemark_start =
+               "  <Placemark>\n" +
+               "    <name>%s</name>\n" +
+               "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
+               "    <LineString>\n" +
+               "      <tessellate>1</tessellate>\n" +
+               "      <altitudeMode>absolute</altitudeMode>\n" +
+               "      <coordinates>\n";
+
+       static final String kml_coord_fmt =
+       "        %12.7f, %12.7f, %12.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+
+       static final String kml_placemark_end =
+               "      </coordinates>\n" +
+               "    </LineString>\n" +
+               "  </Placemark>\n";
+
+       static final String kml_footer =
+               "</Document>\n" +
+               "</kml>\n";
+
+       void start (AltosRecord record) {
+               out.printf(kml_header_start, record.flight, record.serial);
+               out.printf("Date:   %04d-%02d-%02d\n",
+                          record.gps.year, record.gps.month, record.gps.day);
+               out.printf("Time:     %2d:%02d:%02d\n",
+                          record.gps.hour, record.gps.minute, record.gps.second);
+               out.printf("%s", kml_header_end);
+       }
+
+       boolean started = false;
+
+       void state_start(AltosRecord record) {
+               String  state_name = Altos.state_name(record.state);
+               out.printf(kml_style_start, state_name, kml_state_colors[record.state]);
+               out.printf("\tState: %s\n", state_name);
+               out.printf("%s", kml_style_end);
+               out.printf(kml_placemark_start, state_name, state_name);
+       }
+
+       void state_end(AltosRecord record) {
+               out.printf("%s", kml_placemark_end);
+       }
+
+       void coord(AltosRecord record) {
+               AltosGPS        gps = record.gps;
+               out.printf(kml_coord_fmt,
+                          gps.lon, gps.lat,
+                          record.filtered_altitude(), (double) gps.alt,
+                          record.time, gps.nsat);
+       }
+
+       void end() {
+               out.printf("%s", kml_footer);
+       }
+
+       public void close() {
+               if (prev != null) {
+                       state_end(prev);
+                       end();
+                       prev = null;
+               }
+       }
+
+       public void write(AltosRecord record) {
+               AltosGPS        gps = record.gps;
+
+               if (gps == null)
+                       return;
+               if (!started) {
+                       start(record);
+                       started = true;
+               }
+               if (prev != null &&
+                   prev.gps.second == record.gps.second &&
+                   prev.gps.minute == record.gps.minute &&
+                   prev.gps.hour == record.gps.hour)
+                       return;
+               if (record.state != state) {
+                       state = record.state;
+                       if (prev != null) {
+                               coord(record);
+                               state_end(prev);
+                       }
+                       state_start(record);
+               }
+               coord(record);
+               prev = record;
+       }
+
+       public void write(AltosRecordIterable iterable) {
+               for (AltosRecord record : iterable)
+                       write(record);
+       }
+
+       public AltosKML(File in_name) throws FileNotFoundException {
+               name = in_name;
+               out = new PrintStream(name);
+       }
+
+       public AltosKML(String in_string) throws FileNotFoundException {
+               this(new File(in_string));
+       }
+}
index de0673a..7148151 100644 (file)
@@ -426,13 +426,6 @@ public class AltosUI extends JFrame {
 
        }
 
-       static String replace_extension(String input, String extension) {
-               int dot = input.lastIndexOf(".");
-               if (dot > 0)
-                       input = input.substring(0,dot);
-               return input.concat(extension);
-       }
-
        static AltosRecordIterable open_logfile(String filename) {
                File file = new File (filename);
                try {
@@ -449,7 +442,7 @@ public class AltosUI extends JFrame {
                }
        }
 
-       static AltosCSV open_csv(String filename) {
+       static AltosWriter open_csv(String filename) {
                File file = new File (filename);
                try {
                        return new AltosCSV(file);
@@ -459,29 +452,65 @@ public class AltosUI extends JFrame {
                }
        }
 
-       static void process_file(String input) {
-               String output = replace_extension(input,".csv");
-               if (input.equals(output)) {
-                       System.out.printf("Not processing '%s'\n", input);
-                       return;
+       static AltosWriter open_kml(String filename) {
+               File file = new File (filename);
+               try {
+                       return new AltosKML(file);
+               } catch (FileNotFoundException fe) {
+                       System.out.printf("Cannot open '%s'\n", filename);
+                       return null;
                }
-               System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+       }
+
+       static final int process_csv = 1;
+       static final int process_kml = 2;
+
+       static void process_file(String input, int process) {
                AltosRecordIterable iterable = open_logfile(input);
                if (iterable == null)
                        return;
-               AltosCSV writer = open_csv(output);
-               if (writer == null)
-                       return;
-               writer.write(iterable);
-               writer.close();
+               if (process == 0)
+                       process = process_csv;
+               if ((process & process_csv) != 0) {
+                       String output = Altos.replace_extension(input,".csv");
+                       System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+                       if (input.equals(output)) {
+                               System.out.printf("Not processing '%s'\n", input);
+                       } else {
+                               AltosWriter writer = open_csv(output);
+                               if (writer != null) {
+                                       writer.write(iterable);
+                                       writer.close();
+                               }
+                       }
+               }
+               if ((process & process_kml) != 0) {
+                       String output = Altos.replace_extension(input,".kml");
+                       System.out.printf("Processing \"%s\" to \"%s\"\n", input, output);
+                       if (input.equals(output)) {
+                               System.out.printf("Not processing '%s'\n", input);
+                       } else {
+                               AltosWriter writer = open_kml(output);
+                               if (writer == null)
+                                       return;
+                               writer.write(iterable);
+                               writer.close();
+                       }
+               }
        }
 
        public static void main(final String[] args) {
-
+               int     process = 0;
                /* Handle batch-mode */
                if (args.length > 0) {
-                       for (int i = 0; i < args.length; i++)
-                               process_file(args[i]);
+                       for (int i = 0; i < args.length; i++) {
+                               if (args[i].equals("--kml"))
+                                       process |= process_kml;
+                               else if (args[i].equals("--csv"))
+                                       process |= process_csv;
+                               else
+                                       process_file(args[i], process);
+                       }
                } else {
                        AltosUI altosui = new AltosUI();
                        altosui.setVisible(true);
diff --git a/ao-tools/altosui/AltosWriter.java b/ao-tools/altosui/AltosWriter.java
new file mode 100644 (file)
index 0000000..a172dff
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+package altosui;
+
+import java.lang.*;
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+public interface AltosWriter {
+
+       public void write(AltosRecord record);
+
+       public void write(AltosRecordIterable iterable);
+
+       public void close();
+}
index 7510c88..4e2a502 100644 (file)
@@ -35,6 +35,7 @@ altosui_JAVA = \
        AltosHexfile.java \
        Altos.java \
        AltosInfoTable.java \
+       AltosKML.java \
        AltosLine.java \
        AltosLogfileChooser.java \
        AltosLog.java \
@@ -53,13 +54,14 @@ altosui_JAVA = \
        AltosTelemetry.java \
        AltosTelemetryIterable.java \
        AltosUI.java \
-    AltosDataPointReader.java \
-    AltosCsvReader.java \
-    AltosDataPoint.java \
-    AltosGraph.java \
-    AltosGraphTime.java \
-    AltosGraphUI.java \
-    AltosGraphDataChooser.java \
+       AltosWriter.java \
+       AltosDataPointReader.java \
+       AltosCsvReader.java \
+       AltosDataPoint.java \
+       AltosGraph.java \
+       AltosGraphTime.java \
+       AltosGraphUI.java \
+       AltosGraphDataChooser.java \
        AltosVoice.java
 
 JFREECHART_CLASS= \
@@ -109,13 +111,13 @@ MACOSX_EXTRA=$(FIRMWARE)
 
 WINDOWS_FILES=$(FAT_FILES) altos.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
 
-all-local: classes/altosui $(JAR) altosui altosui-test
+all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb
 
 clean-local:
        -rm -rf classes $(JAR) $(FATJAR) \
                $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(FREETTS_CLASS) \
                $(JFREECHART_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log \
-               altosui altosui-test macosx linux
+               altosui altosui-test altosui-jdb macosx linux
 
 if FATINSTALL
 
@@ -185,6 +187,11 @@ altosui-test: Makefile
        echo 'exec java -cp "$(FREETTS)/*" -Djava.library.path="../libaltos/.libs" -jar altosui.jar "$$@"' >> $@
        chmod +x $@
 
+altosui-jdb: Makefile
+       echo "#!/bin/sh" > $@
+       echo 'exec jdb -classpath "classes:../libaltos:$(FREETTS)/*" -Djava.library.path="../libaltos/.libs" altosui/AltosUI "$$@"' >> $@
+       chmod +x $@
+
 libaltos.so:
        -rm -f "$@"
        $(LN_S) ../libaltos/.libs/"$@" .