From d75e8b9046295051c91696461e8d5f59c8260ccc Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 17:02:18 -0700 Subject: altosuilib: Show raw tick values in graph and info table Not terribly useful, but did help validate firmware handling of tick wrapping, so we'll keep it. Signed-off-by: Keith Packard --- altosuilib/AltosGraph.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'altosuilib/AltosGraph.java') diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java index 31042abb..5df95233 100644 --- a/altosuilib/AltosGraph.java +++ b/altosuilib/AltosGraph.java @@ -80,6 +80,7 @@ public class AltosGraph extends AltosUIGraph { static final private Color orient_color = new Color(31, 31, 31); static AltosUnits dop_units = null; + static AltosUnits tick_units = null; AltosUIFlightSeries flight_series; @@ -89,7 +90,7 @@ public class AltosGraph extends AltosUIGraph { AltosUIAxis height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis; AltosUIAxis distance_axis, pressure_axis, thrust_axis; AltosUIAxis gyro_axis, orient_axis, mag_axis; - AltosUIAxis course_axis, dop_axis; + AltosUIAxis course_axis, dop_axis, tick_axis; if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight)); @@ -98,6 +99,7 @@ public class AltosGraph extends AltosUIGraph { pressure_axis = newAxis("Pressure", AltosConvert.pressure, pressure_color, 0); speed_axis = newAxis("Speed", AltosConvert.speed, speed_color); thrust_axis = newAxis("Thrust", AltosConvert.force, thrust_color); + tick_axis = newAxis("Tick", tick_units, accel_color, 0); accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color); voltage_axis = newAxis("Voltage", AltosConvert.voltage, voltage_color); temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0); @@ -129,6 +131,11 @@ public class AltosGraph extends AltosUIGraph { plot, false); + flight_series.register_axis(AltosUIFlightSeries.tick_name, + accel_color, + false, + tick_axis); + flight_series.register_axis(AltosUIFlightSeries.accel_name, accel_color, true, @@ -320,6 +327,12 @@ public class AltosGraph extends AltosUIGraph { return flight_series.series(cal_data); } + public void set_filter(double filter) { + System.out.printf("filter set to %f\n", filter); + flight_series.set_filter(filter, filter); + units_changed(false); + } + public void set_data(AltosFlightStats stats, AltosUIFlightSeries flight_series) { set_series(setup(stats, flight_series)); } @@ -330,6 +343,7 @@ public class AltosGraph extends AltosUIGraph { public AltosGraph(AltosUIEnable enable, AltosFlightStats stats, AltosUIFlightSeries flight_series) { this(enable); + this.flight_series = flight_series; set_series(setup(stats, flight_series)); } } -- cgit v1.2.3 From 98dc29a7a964f8d653b73989c6751695d168844c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 2 Oct 2017 19:33:37 -0700 Subject: altoslib: Add user-selectable filter width for data smoothing Also switch smoothing window to Kaiser and change default accel filter width to 1 second instead of 4 seconds. Now users can play with the filter and see what it does. Signed-off-by: Keith Packard --- altoslib/AltosFlightSeries.java | 90 +++++++++++++++++++++++++---------- altoslib/AltosTimeSeries.java | 42 ++++++++++++++-- altoslib/Makefile.am | 1 + altosui/AltosGraphUI.java | 23 +++++++-- altosuilib/AltosFlightStatsTable.java | 84 ++++++++++++++++++++++++-------- altosuilib/AltosGraph.java | 8 +--- altosuilib/AltosUIEnable.java | 82 ++++++++++++++++++++++++++++++- altosuilib/AltosUIGraph.java | 4 ++ altosuilib/AltosUITimeSeries.java | 3 +- micropeak/MicroPeak.java | 23 ++++++++- telegps/TeleGPSGraphUI.java | 26 ++++++++-- 11 files changed, 320 insertions(+), 66 deletions(-) (limited to 'altosuilib/AltosGraph.java') diff --git a/altoslib/AltosFlightSeries.java b/altoslib/AltosFlightSeries.java index ab7943b3..02bf64ff 100644 --- a/altoslib/AltosFlightSeries.java +++ b/altoslib/AltosFlightSeries.java @@ -21,7 +21,7 @@ public class AltosFlightSeries extends AltosDataListener { public ArrayList series = new ArrayList(); public double speed_filter_width = 4.0; - public double accel_filter_width = 4.0; + public double accel_filter_width = 1.0; public int[] indices() { int[] indices = new int[series.size()]; @@ -160,6 +160,7 @@ public class AltosFlightSeries extends AltosDataListener { } public AltosTimeSeries accel_series; + public boolean accel_computed; public static final String accel_name = "Accel"; @@ -174,17 +175,44 @@ public class AltosFlightSeries extends AltosDataListener { accel_series = add_series(accel_name, AltosConvert.accel); accel_series.add(time(), acceleration); + accel_computed = false; } - private void compute_accel() { - if (accel_series != null) - return; + private AltosTimeSeries compute_accel() { + AltosTimeSeries new_accel_series = null; if (speed_series != null) { - AltosTimeSeries temp_series = make_series(speed_name, AltosConvert.speed); - speed_series.filter(temp_series, accel_filter_width); - accel_series = add_series(accel_name, AltosConvert.accel); - temp_series.differentiate(accel_series); + AltosTimeSeries temp_series; + if (accel_filter_width > 0) { + temp_series = make_series(speed_name, AltosConvert.speed); + speed_series.filter(temp_series, accel_filter_width); + } else + temp_series = speed_series; + + new_accel_series = make_series(accel_name, AltosConvert.accel); + temp_series.differentiate(new_accel_series); + } + return new_accel_series; + } + + public void set_filter(double speed_filter, double accel_filter) { + this.speed_filter_width = speed_filter; + this.accel_filter_width = accel_filter; + + AltosTimeSeries new_speed_series = compute_speed(); + + if (new_speed_series != null) { + speed_series.erase_values(); + for (AltosTimeValue tv : new_speed_series) + speed_series.add(tv); + } + if (accel_computed) { + AltosTimeSeries new_accel_series = compute_accel(); + if (new_accel_series != null) { + accel_series.erase_values(); + for (AltosTimeValue tv : new_accel_series) + accel_series.add(tv); + } } } @@ -268,21 +296,24 @@ public class AltosFlightSeries extends AltosDataListener { public static final String speed_name = "Speed"; - private void compute_speed() { - if (speed_series != null) - return; - + private AltosTimeSeries compute_speed() { + AltosTimeSeries new_speed_series = null; AltosTimeSeries alt_speed_series = null; AltosTimeSeries accel_speed_series = null; if (altitude_series != null) { - AltosTimeSeries temp_series = make_series(altitude_name, AltosConvert.height); - altitude_series.filter(temp_series, speed_filter_width); + AltosTimeSeries temp_series; + + if (speed_filter_width > 0) { + temp_series = make_series(speed_name, AltosConvert.height); + altitude_series.filter(temp_series, speed_filter_width); + } else + temp_series = altitude_series; alt_speed_series = make_series(speed_name, AltosConvert.speed); temp_series.differentiate(alt_speed_series); } - if (accel_series != null) { + if (accel_series != null && !accel_computed) { if (orient_series != null) { vert_accel_series = add_series(vert_accel_name, AltosConvert.accel); @@ -318,26 +349,25 @@ public class AltosFlightSeries extends AltosDataListener { } } if (apogee_time == AltosLib.MISSING) { - speed_series = alt_speed_series; + new_speed_series = alt_speed_series; } else { - speed_series = make_series(speed_name, AltosConvert.speed); + new_speed_series = make_series(speed_name, AltosConvert.speed); for (AltosTimeValue d : accel_speed_series) { if (d.time <= apogee_time) - speed_series.add(d); + new_speed_series.add(d); } for (AltosTimeValue d : alt_speed_series) { if (d.time > apogee_time) - speed_series.add(d); + new_speed_series.add(d); } } } else if (alt_speed_series != null) { - speed_series = alt_speed_series; + new_speed_series = alt_speed_series; } else if (accel_speed_series != null) { - speed_series = accel_speed_series; + new_speed_series = accel_speed_series; } - if (speed_series != null) - add_series(speed_series); + return new_speed_series; } public AltosTimeSeries orient_series; @@ -690,8 +720,18 @@ public class AltosFlightSeries extends AltosDataListener { public void finish() { compute_orient(); - compute_speed(); - compute_accel(); + if (speed_series == null) { + speed_series = compute_speed(); + if (speed_series != null) + add_series(speed_series); + } + if (accel_series == null) { + accel_series = compute_accel(); + if (accel_series != null) { + add_series(accel_series); + accel_computed = true; + } + } compute_height(); } diff --git a/altoslib/AltosTimeSeries.java b/altoslib/AltosTimeSeries.java index 9f3b4d80..7208c176 100644 --- a/altoslib/AltosTimeSeries.java +++ b/altoslib/AltosTimeSeries.java @@ -20,15 +20,30 @@ public class AltosTimeSeries implements Iterable, Comparable values; + boolean data_changed; public int compareTo(AltosTimeSeries other) { return label.compareTo(other.label); } public void add(AltosTimeValue tv) { + data_changed = true; values.add(tv); } + public void erase_values() { + data_changed = true; + this.values = new ArrayList(); + } + + public void clear_changed() { + data_changed = false; + } + +// public boolean changed() { +// return data_changed; +// } + public void add(double time, double value) { add(new AltosTimeValue(time, value)); } @@ -264,14 +279,35 @@ public class AltosTimeSeries implements Iterable, Comparable 0); + return s; + } + + private static double kaiser(double n, double m, double beta) { + double alpha = m / 2; + double t = (n - alpha) / alpha; + + if (t > 1) + t = 1; + double k = i0 (beta * Math.sqrt (1 - t*t)) / i0(beta); + return k; + } + + private double filter_coeff(double dist, double width) { + return kaiser(dist + width/2.0, width, 2 * Math.PI); } public AltosTimeSeries filter(AltosTimeSeries f, double width) { + double half_width = width/2; + int half_point = values.size() / 2; for (int i = 0; i < values.size(); i++) { double center_time = values.get(i).time; double left_time = center_time - half_width; diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 08af9496..2a1cb8e4 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -55,6 +55,7 @@ altoslib_JAVA = \ AltosEepromList.java \ AltosEepromLog.java \ AltosFile.java \ + AltosFilterListener.java \ AltosFlash.java \ AltosFlashListener.java \ AltosDataListener.java \ diff --git a/altosui/AltosGraphUI.java b/altosui/AltosGraphUI.java index 042f9277..f387ed9b 100644 --- a/altosui/AltosGraphUI.java +++ b/altosui/AltosGraphUI.java @@ -31,7 +31,7 @@ import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.ui.RefineryUtilities; -public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener +public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener { JTabbedPane pane; AltosGraph graph; @@ -82,6 +82,23 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt enable.units_changed(imperial_units); } + AltosUIFlightSeries flight_series; + + public void filter_changed(double speed_filter, double accel_filter) { + flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + stats = new AltosFlightStats(flight_series); + statsTable.filter_changed(stats); + } + + public double speed_filter() { + return flight_series.speed_filter_width; + } + + public double accel_filter() { + return flight_series.accel_filter_width; + } + AltosGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException { super(file.getName()); AltosCalData cal_data = set.cal_data(); @@ -89,9 +106,9 @@ public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, Alt pane = new JTabbedPane(); - enable = new AltosUIEnable(); + flight_series = new AltosUIFlightSeries(cal_data); - AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data); + enable = new AltosUIEnable(this); set.capture_series(flight_series); diff --git a/altosuilib/AltosFlightStatsTable.java b/altosuilib/AltosFlightStatsTable.java index 415c0244..8f7e9bff 100644 --- a/altosuilib/AltosFlightStatsTable.java +++ b/altosuilib/AltosFlightStatsTable.java @@ -38,6 +38,11 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen value[i].setFont(AltosUILib.value_font); } + public void set(String ... values) { + for (int j = 0; j < values.length; j++) + value[j].setText(values[j]); + } + public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) { GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad); @@ -87,6 +92,43 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen return String.format("%s %4d° %9.6f'", h, deg, min); } + private FlightStat max_height_stat; + private FlightStat max_speed_stat; + private FlightStat max_accel_stat; + private FlightStat boost_accel_stat; + private FlightStat drogue_descent_stat; + private FlightStat main_descent_stat; + + public void set_values(AltosFlightStats stats) { + if (max_height_stat != null && stats.max_height != AltosLib.MISSING) { + max_height_stat.set(String.format("%6.1f m", stats.max_height), + String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); + } + if (max_speed_stat != null && stats.max_speed != AltosLib.MISSING) { + max_speed_stat.set(String.format("%6.1f m/s", stats.max_speed), + String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), + String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); + } + if (max_accel_stat != null && stats.max_acceleration != AltosLib.MISSING) { + max_accel_stat.set(String.format("%6.1f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); + } + if (boost_accel_stat != null && stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) { + boost_accel_stat.set(String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); + } + if (drogue_descent_stat != null && stats.state_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING) { + drogue_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue]))); + } + if (main_descent_stat != null && stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) { + main_descent_stat.set(String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); + } + } + public void set_stats(AltosFlightStats stats) { int y = 0; if (stats.serial != AltosLib.MISSING) { @@ -113,9 +155,9 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second)); } if (stats.max_height != AltosLib.MISSING) { - new FlightStat(layout, y++, "Maximum height", - String.format("%6.1f m", stats.max_height), - String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); + max_height_stat = new FlightStat(layout, y++, "Maximum height", + String.format("%6.1f m", stats.max_height), + String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height))); } if (stats.max_gps_height != AltosLib.MISSING) { new FlightStat(layout, y++, "Maximum GPS height", @@ -123,21 +165,21 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height))); } if (stats.max_speed != AltosLib.MISSING) { - new FlightStat(layout, y++, "Maximum speed", - String.format("%6.1f m/s", stats.max_speed), - String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), - String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); + max_speed_stat = new FlightStat(layout, y++, "Maximum speed", + String.format("%6.1f m/s", stats.max_speed), + String.format("%5.0f fps", AltosConvert.mps_to_fps(stats.max_speed)), + String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed))); } if (stats.max_acceleration != AltosLib.MISSING) - new FlightStat(layout, y++, "Maximum boost acceleration", - String.format("%6.1f m/s²", stats.max_acceleration), - String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), - String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); + max_accel_stat = new FlightStat(layout, y++, "Maximum boost acceleration", + String.format("%6.1f m/s²", stats.max_acceleration), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.max_acceleration))); if (stats.state_accel[AltosLib.ao_flight_boost] != AltosLib.MISSING) - new FlightStat(layout, y++, "Average boost acceleration", - String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), - String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), - String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); + boost_accel_stat = new FlightStat(layout, y++, "Average boost acceleration", + String.format("%6.1f m/s²", stats.state_accel[AltosLib.ao_flight_boost]), + String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])), + String.format("%6.2f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost]))); if (stats.state_time[AltosLib.ao_flight_boost] != 0 || stats.state_time[AltosLib.ao_flight_fast] != 0 || stats.state_time[AltosLib.ao_flight_coast] != 0) { double boost_time = stats.state_time[AltosLib.ao_flight_boost]; @@ -167,14 +209,14 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen label = "Descent rate"; else label = "Drogue descent rate"; - new FlightStat(layout, y++, label, + drogue_descent_stat = new FlightStat(layout, y++, label, String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_drogue]), String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue]))); } if (stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING) - new FlightStat(layout, y++, "Main descent rate", - String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), - String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); + main_descent_stat = new FlightStat(layout, y++, "Main descent rate", + String.format("%6.1f m/s", -stats.state_speed[AltosLib.ao_flight_main]), + String.format("%5.0f ft/s", -AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main]))); if (stats.state_time[AltosLib.ao_flight_drogue] != 0 || stats.state_time[AltosLib.ao_flight_main] != 0) { double drogue_duration = stats.state_time[AltosLib.ao_flight_drogue]; double main_duration = stats.state_time[AltosLib.ao_flight_main]; @@ -210,6 +252,10 @@ public class AltosFlightStatsTable extends JComponent implements AltosFontListen AltosUIPreferences.unregister_font_listener(this); } + public void filter_changed(AltosFlightStats stats) { + set_values(stats); + } + public AltosFlightStatsTable() { layout = new GridBagLayout(); diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java index 5df95233..3f610285 100644 --- a/altosuilib/AltosGraph.java +++ b/altosuilib/AltosGraph.java @@ -92,7 +92,7 @@ public class AltosGraph extends AltosUIGraph { AltosUIAxis gyro_axis, orient_axis, mag_axis; AltosUIAxis course_axis, dop_axis, tick_axis; - if (stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) + if (stats != null && stats.serial != AltosLib.MISSING && stats.product != null && stats.flight != AltosLib.MISSING) setName(String.format("%s %d flight %d\n", stats.product, stats.serial, stats.flight)); height_axis = newAxis("Height", AltosConvert.height, height_color); @@ -327,12 +327,6 @@ public class AltosGraph extends AltosUIGraph { return flight_series.series(cal_data); } - public void set_filter(double filter) { - System.out.printf("filter set to %f\n", filter); - flight_series.set_filter(filter, filter); - units_changed(false); - } - public void set_data(AltosFlightStats stats, AltosUIFlightSeries flight_series) { set_series(setup(stats, flight_series)); } diff --git a/altosuilib/AltosUIEnable.java b/altosuilib/AltosUIEnable.java index 0c23fa8d..4bd07c52 100644 --- a/altosuilib/AltosUIEnable.java +++ b/altosuilib/AltosUIEnable.java @@ -21,6 +21,7 @@ package org.altusmetrum.altosuilib_12; import java.awt.*; import java.awt.event.*; import javax.swing.*; +import javax.swing.event.*; import java.io.*; import java.util.concurrent.*; import java.util.*; @@ -36,12 +37,17 @@ import org.jfree.chart.labels.*; import org.jfree.data.xy.*; import org.jfree.data.*; -public class AltosUIEnable extends Container { +public class AltosUIEnable extends Container implements ChangeListener { Insets il, ir; int y; int x; JCheckBox imperial_units; + JLabel speed_filter_label; + JSlider speed_filter; + JLabel accel_filter_label; + JSlider accel_filter; + AltosFilterListener filter_listener; static final int max_rows = 14; @@ -69,11 +75,15 @@ public class AltosUIEnable extends Container { } } + LinkedList elements = new LinkedList(); + public void add(String name, AltosUIGrapher grapher, boolean enabled) { GraphElement e = new GraphElement(name, grapher, enabled); GridBagConstraints c = new GridBagConstraints(); + elements.add(e); + /* Add element */ c = new GridBagConstraints(); c.gridx = x; c.gridy = y; @@ -90,6 +100,17 @@ public class AltosUIEnable extends Container { } } + public void stateChanged(ChangeEvent e) { + JSlider filter = (JSlider) e.getSource(); + if (!filter.getValueIsAdjusting()) { + double speed_value = (int) speed_filter.getValue() / 1000.0; + double accel_value = (int) accel_filter.getValue() / 1000.0; + if (filter_listener != null) { + filter_listener.filter_changed(speed_value, accel_value); + } + } + } + public void add_units() { /* Imperial units setting */ @@ -109,9 +130,66 @@ public class AltosUIEnable extends Container { c.anchor = GridBagConstraints.LINE_START; c.insets = il; add(imperial_units, c); + + speed_filter_label = new JLabel("Speed Filter(ms)"); + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1001; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(speed_filter_label, c); + + speed_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.speed_filter() * 1000.0)); + Hashtable label_table = new Hashtable(); + for (int i = 0; i <= 10000; i += 5000) { + label_table.put(new Integer(i), new JLabel(String.format("%d", i))); + } + speed_filter.setPaintTicks(true); + speed_filter.setMajorTickSpacing(1000); + speed_filter.setMinorTickSpacing(250); + speed_filter.setLabelTable(label_table); + speed_filter.setPaintTrack(false); + speed_filter.setSnapToTicks(true); + speed_filter.setPaintLabels(true); + speed_filter.addChangeListener(this); + + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 1001; + c.gridwidth = 1000; c.gridheight = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(speed_filter, c); + + accel_filter_label = new JLabel("Acceleration Filter(ms)"); + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1002; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(accel_filter_label, c); + + accel_filter = new JSlider(JSlider.HORIZONTAL, 0, 10000, (int) (filter_listener.accel_filter() * 1000.0)); + accel_filter.setPaintTicks(true); + accel_filter.setMajorTickSpacing(1000); + accel_filter.setMinorTickSpacing(250); + accel_filter.setLabelTable(label_table); + accel_filter.setPaintTrack(false); + accel_filter.setSnapToTicks(true); + accel_filter.setPaintLabels(true); + accel_filter.addChangeListener(this); + + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 1002; + c.gridwidth = 1000; c.gridheight = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(accel_filter, c); } - public AltosUIEnable() { + public AltosUIEnable(AltosFilterListener filter_listener) { + this.filter_listener = filter_listener; il = new Insets(4,4,4,4); ir = new Insets(4,4,4,4); x = 0; diff --git a/altosuilib/AltosUIGraph.java b/altosuilib/AltosUIGraph.java index 0caabcfa..efc3d493 100644 --- a/altosuilib/AltosUIGraph.java +++ b/altosuilib/AltosUIGraph.java @@ -95,6 +95,10 @@ public class AltosUIGraph implements AltosUnitsListener { s.set_units(); } + public void filter_changed() { + units_changed(false); + } + public void setName (String name) { chart.setTitle(name); } diff --git a/altosuilib/AltosUITimeSeries.java b/altosuilib/AltosUITimeSeries.java index 08f95ca7..71166064 100644 --- a/altosuilib/AltosUITimeSeries.java +++ b/altosuilib/AltosUITimeSeries.java @@ -89,7 +89,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher public void fireSeriesChanged() { } - void set_data() { + public void set_data() { if (marker) { if (markers != null) { for (ValueMarker marker : markers) @@ -124,6 +124,7 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher } xy_series.setNotify(true); } + clear_changed(); } public void set_units() { diff --git a/micropeak/MicroPeak.java b/micropeak/MicroPeak.java index 749d0f64..c6a2a3c9 100644 --- a/micropeak/MicroPeak.java +++ b/micropeak/MicroPeak.java @@ -27,7 +27,7 @@ import java.util.*; import org.altusmetrum.altoslib_12.*; import org.altusmetrum.altosuilib_12.*; -public class MicroPeak extends MicroFrame implements ActionListener, ItemListener { +public class MicroPeak extends MicroFrame implements ActionListener, ItemListener, AltosFilterListener { File filename; AltosGraph graph; @@ -206,6 +206,25 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene Preferences(); } + public void filter_changed(double speed_filter, double accel_filter) { + data.flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + data.flight_stats = new AltosFlightStats(data.flight_series); + statsTable.filter_changed(data.flight_stats); + } + + public double speed_filter() { + if (data != null && data.flight_series != null) + return data.flight_series.speed_filter_width; + return 4.0; + } + + public double accel_filter() { + if (data != null && data.flight_series != null) + return data.flight_series.accel_filter_width; + return 1.0; + } + public MicroPeak() { ++number_of_windows; @@ -267,7 +286,7 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene } }); - enable = new AltosUIEnable(); + enable = new AltosUIEnable(this); graph = new AltosGraph(enable); statsTable = new AltosFlightStatsTable(); diff --git a/telegps/TeleGPSGraphUI.java b/telegps/TeleGPSGraphUI.java index 9d8c6bf5..c68f2bad 100644 --- a/telegps/TeleGPSGraphUI.java +++ b/telegps/TeleGPSGraphUI.java @@ -34,7 +34,7 @@ import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.ui.RefineryUtilities; -public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener +public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener { JTabbedPane pane; AltosGraph graph; @@ -92,20 +92,38 @@ public class TeleGPSGraphUI extends AltosUIFrame implements AltosFontListener, A enable.units_changed(imperial_units); } + AltosUIFlightSeries flight_series; + + public void filter_changed(double speed_filter, double accel_filter) { + flight_series.set_filter(speed_filter, accel_filter); + graph.filter_changed(); + stats = new AltosFlightStats(flight_series); + statsTable.filter_changed(stats); + } + + public double speed_filter() { + return flight_series.speed_filter_width; + } + + public double accel_filter() { + return flight_series.accel_filter_width; + } + TeleGPSGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException { super(file.getName()); AltosCalData cal_data = set.cal_data(); - AltosUIFlightSeries flight_series = new AltosUIFlightSeries(cal_data); + flight_series = new AltosUIFlightSeries(cal_data); set.capture_series(flight_series); flight_series.finish(); pane = new JTabbedPane(); - enable = new AltosUIEnable(); + graph = new AltosGraph(enable, stats, flight_series); + stats = new AltosFlightStats(flight_series); - graph = new AltosGraph(enable, stats, flight_series); + enable = new AltosUIEnable(this); statsTable = new AltosFlightStatsTable(stats); -- cgit v1.2.3 From 5b6805d1a6a91a26a1892f414a99f0184871ac1a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 11 Nov 2017 16:08:32 -0800 Subject: altosuilib: New line styles and colors for graphs. Selectable line width Improve the readability of graphs by offering a better selection of colors and adding line styles. Let the user configure the line width as desired. Signed-off-by: Keith Packard --- altosuilib/AltosEepromGrapher.java | 22 +++++++ altosuilib/AltosGraph.java | 116 ++++++++++++++++++++---------------- altosuilib/AltosShapeListener.java | 1 + altosuilib/AltosUIAxis.java | 23 +++---- altosuilib/AltosUIEnable.java | 36 ++++++++++- altosuilib/AltosUIFlightSeries.java | 52 +++++++++------- altosuilib/AltosUIGraph.java | 13 ++-- altosuilib/AltosUILineStyle.java | 84 ++++++++++++++++++++++++++ altosuilib/AltosUITimeSeries.java | 54 +++++++++++------ altosuilib/Makefile.am | 2 + 10 files changed, 297 insertions(+), 106 deletions(-) create mode 100644 altosuilib/AltosEepromGrapher.java create mode 100644 altosuilib/AltosUILineStyle.java (limited to 'altosuilib/AltosGraph.java') diff --git a/altosuilib/AltosEepromGrapher.java b/altosuilib/AltosEepromGrapher.java new file mode 100644 index 00000000..a29f64ea --- /dev/null +++ b/altosuilib/AltosEepromGrapher.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2017 Keith Packard + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +package org.altusmetrum.altosuilib_12; + +import org.altusmetrum.altoslib_12.*; + +public interface AltosEepromGrapher { + + public void graph_flights(AltosEepromList list); +} diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java index 3f610285..a758bcde 100644 --- a/altosuilib/AltosGraph.java +++ b/altosuilib/AltosGraph.java @@ -37,47 +37,53 @@ import org.jfree.data.*; public class AltosGraph extends AltosUIGraph { - static final private Color height_color = new Color(194,31,31); - static final private Color kalman_height_color = new Color(255,0,0); - static final private Color gps_height_color = new Color(150,31,31); - static final private Color pressure_color = new Color (225,31,31); - static final private Color range_color = new Color(100, 31, 31); - static final private Color distance_color = new Color(100, 31, 194); - static final private Color speed_color = new Color(31,194,31); - static final private Color kalman_speed_color = new Color(0,255,0); - static final private Color thrust_color = new Color(31,194,31); - static final private Color accel_color = new Color(31,31,194); - static final private Color vert_accel_color = new Color(64,164,164); - static final private Color kalman_accel_color = new Color(0,0,255); - static final private Color voltage_color = new Color(194, 194, 31); - static final private Color battery_voltage_color = new Color(194, 194, 31); - static final private Color drogue_voltage_color = new Color(150, 150, 31); - static final private Color main_voltage_color = new Color(100, 100, 31); - static final private Color igniter_voltage_color = new Color(80, 80, 31); - static final private Color igniter_marker_color = new Color(255, 0, 0); - static final private Color gps_nsat_color = new Color (194, 31, 194); - static final private Color gps_nsat_solution_color = new Color (194, 31, 194); - static final private Color gps_nsat_view_color = new Color (150, 31, 150); - static final private Color gps_course_color = new Color (100, 31, 112); - static final private Color gps_ground_speed_color = new Color (31, 112, 100); - static final private Color gps_speed_color = new Color (31, 112, 100); - static final private Color gps_climb_rate_color = new Color (31, 31, 112); - static final private Color gps_pdop_color = new Color(50, 194, 0); - static final private Color gps_hdop_color = new Color(50, 0, 194); - static final private Color gps_vdop_color = new Color(194, 0, 50); - static final private Color temperature_color = new Color (31, 194, 194); - static final private Color dbm_color = new Color(31, 100, 100); - static final private Color state_color = new Color(0,0,0); - static final private Color accel_along_color = new Color(255, 0, 0); - static final private Color accel_across_color = new Color(0, 255, 0); - static final private Color accel_through_color = new Color(0, 0, 255); - static final private Color gyro_roll_color = new Color(192, 0, 0); - static final private Color gyro_pitch_color = new Color(0, 192, 0); - static final private Color gyro_yaw_color = new Color(0, 0, 192); - static final private Color mag_along_color = new Color(128, 0, 0); - static final private Color mag_across_color = new Color(0, 128, 0); - static final private Color mag_through_color = new Color(0, 0, 128); - static final private Color orient_color = new Color(31, 31, 31); + /* These are in 'priority' order so that earlier ones get simpler line styles, + * then they are grouped so that adjacent ones get sequential colors + */ + static final private AltosUILineStyle height_color = new AltosUILineStyle(); + static final private AltosUILineStyle speed_color = new AltosUILineStyle(); + static final private AltosUILineStyle accel_color = new AltosUILineStyle(); + static final private AltosUILineStyle vert_accel_color = new AltosUILineStyle(); + static final private AltosUILineStyle orient_color = new AltosUILineStyle(); + + static final private AltosUILineStyle gps_height_color = new AltosUILineStyle(); + static final private AltosUILineStyle altitude_color = new AltosUILineStyle(); + + static final private AltosUILineStyle battery_voltage_color = new AltosUILineStyle(); + static final private AltosUILineStyle pyro_voltage_color = new AltosUILineStyle(); + static final private AltosUILineStyle drogue_voltage_color = new AltosUILineStyle(); + static final private AltosUILineStyle main_voltage_color = new AltosUILineStyle(); + static final private AltosUILineStyle igniter_marker_color = new AltosUILineStyle(1); + + static final private AltosUILineStyle kalman_height_color = new AltosUILineStyle(); + static final private AltosUILineStyle kalman_speed_color = new AltosUILineStyle(); + static final private AltosUILineStyle kalman_accel_color = new AltosUILineStyle(); + + static final private AltosUILineStyle gps_nsat_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_nsat_solution_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_nsat_view_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_course_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_ground_speed_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_speed_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_climb_rate_color = new AltosUILineStyle (); + static final private AltosUILineStyle gps_pdop_color = new AltosUILineStyle(); + static final private AltosUILineStyle gps_hdop_color = new AltosUILineStyle(); + static final private AltosUILineStyle gps_vdop_color = new AltosUILineStyle(); + + static final private AltosUILineStyle temperature_color = new AltosUILineStyle (); + static final private AltosUILineStyle dbm_color = new AltosUILineStyle(); + static final private AltosUILineStyle pressure_color = new AltosUILineStyle (); + + static final private AltosUILineStyle state_color = new AltosUILineStyle(0); + static final private AltosUILineStyle accel_along_color = new AltosUILineStyle(); + static final private AltosUILineStyle accel_across_color = new AltosUILineStyle(); + static final private AltosUILineStyle accel_through_color = new AltosUILineStyle(); + static final private AltosUILineStyle gyro_roll_color = new AltosUILineStyle(); + static final private AltosUILineStyle gyro_pitch_color = new AltosUILineStyle(); + static final private AltosUILineStyle gyro_yaw_color = new AltosUILineStyle(); + static final private AltosUILineStyle mag_along_color = new AltosUILineStyle(); + static final private AltosUILineStyle mag_across_color = new AltosUILineStyle(); + static final private AltosUILineStyle mag_through_color = new AltosUILineStyle(); static AltosUnits dop_units = null; static AltosUnits tick_units = null; @@ -88,7 +94,7 @@ public class AltosGraph extends AltosUIGraph { AltosCalData cal_data = flight_series.cal_data(); AltosUIAxis height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis; - AltosUIAxis distance_axis, pressure_axis, thrust_axis; + AltosUIAxis pressure_axis, thrust_axis; AltosUIAxis gyro_axis, orient_axis, mag_axis; AltosUIAxis course_axis, dop_axis, tick_axis; @@ -98,15 +104,14 @@ public class AltosGraph extends AltosUIGraph { height_axis = newAxis("Height", AltosConvert.height, height_color); pressure_axis = newAxis("Pressure", AltosConvert.pressure, pressure_color, 0); speed_axis = newAxis("Speed", AltosConvert.speed, speed_color); - thrust_axis = newAxis("Thrust", AltosConvert.force, thrust_color); + thrust_axis = newAxis("Thrust", AltosConvert.force, accel_color); tick_axis = newAxis("Tick", tick_units, accel_color, 0); accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color); - voltage_axis = newAxis("Voltage", AltosConvert.voltage, voltage_color); + voltage_axis = newAxis("Voltage", AltosConvert.voltage, battery_voltage_color); temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0); nsat_axis = newAxis("Satellites", null, gps_nsat_color, AltosUIAxis.axis_include_zero | AltosUIAxis.axis_integer); dbm_axis = newAxis("Signal Strength", null, dbm_color, 0); - distance_axis = newAxis("Distance", AltosConvert.distance, range_color); gyro_axis = newAxis("Rotation Rate", AltosConvert.rotation_rate, gyro_roll_color, 0); orient_axis = newAxis("Tilt Angle", AltosConvert.orient, orient_color, 0); @@ -177,7 +182,7 @@ public class AltosGraph extends AltosUIGraph { height_axis); flight_series.register_axis(AltosUIFlightSeries.altitude_name, - height_color, + altitude_color, false, height_axis); @@ -197,6 +202,11 @@ public class AltosGraph extends AltosUIGraph { false, voltage_axis); + flight_series.register_axis(AltosUIFlightSeries.pyro_voltage_name, + pyro_voltage_color, + false, + voltage_axis); + flight_series.register_axis(AltosUIFlightSeries.apogee_voltage_name, drogue_voltage_color, false, @@ -312,17 +322,19 @@ public class AltosGraph extends AltosUIGraph { false, orient_axis); - for (int channel = 0; channel < 26; channel++) { + flight_series.register_axis(AltosUIFlightSeries.thrust_name, + accel_color, + true, + thrust_axis); + + for (int channel = 0; channel < 8; channel++) { flight_series.register_axis(flight_series.igniter_voltage_name(channel), - igniter_voltage_color, + new AltosUILineStyle(), false, voltage_axis); } - flight_series.register_axis(AltosUIFlightSeries.thrust_name, - thrust_color, - true, - thrust_axis); + flight_series.check_axes(); return flight_series.series(cal_data); } diff --git a/altosuilib/AltosShapeListener.java b/altosuilib/AltosShapeListener.java index 082b6135..6bf52fd4 100644 --- a/altosuilib/AltosShapeListener.java +++ b/altosuilib/AltosShapeListener.java @@ -16,4 +16,5 @@ package org.altusmetrum.altosuilib_12; public interface AltosShapeListener { void set_shapes_visible(boolean visible); + void set_line_width(float width); } diff --git a/altosuilib/AltosUIAxis.java b/altosuilib/AltosUIAxis.java index fe94f161..52873363 100644 --- a/altosuilib/AltosUIAxis.java +++ b/altosuilib/AltosUIAxis.java @@ -36,12 +36,12 @@ import org.jfree.data.xy.*; import org.jfree.data.*; public class AltosUIAxis extends NumberAxis { - String label; - AltosUnits units; - Color color; - int ref; - int visible; - int index; + String label; + AltosUnits units; + AltosUILineStyle line_style; + int ref; + int visible; + int index; public final static int axis_integer = 1; public final static int axis_include_zero = 2; @@ -82,21 +82,22 @@ public class AltosUIAxis extends NumberAxis { } } - public AltosUIAxis(String label, AltosUnits units, Color color, int index, int flags) { + public AltosUIAxis(String label, AltosUnits units, AltosUILineStyle line_style, int index, int flags) { this.label = label; this.units = units; + this.line_style = line_style; this.index = index; this.visible = 0; this.ref = 0; - setLabelPaint(color); - setTickLabelPaint(color); + setLabelPaint(line_style.color); + setTickLabelPaint(line_style.color); setVisible(false); if ((flags & axis_integer) != 0) setStandardTickUnits(NumberAxis.createIntegerTickUnits()); setAutoRangeIncludesZero((flags & axis_include_zero) != 0); } - public AltosUIAxis(String label, AltosUnits units, Color color, int index) { - this(label, units, color, index, axis_default); + public AltosUIAxis(String label, AltosUnits units, AltosUILineStyle line_style, int index) { + this(label, units, line_style, index, axis_default); } } diff --git a/altosuilib/AltosUIEnable.java b/altosuilib/AltosUIEnable.java index ed1e6c53..851e831f 100644 --- a/altosuilib/AltosUIEnable.java +++ b/altosuilib/AltosUIEnable.java @@ -44,6 +44,8 @@ public class AltosUIEnable extends Container implements ChangeListener { int x; JCheckBox imperial_units; JCheckBox show_shapes; + JLabel line_width_label; + JSpinner line_width; JLabel speed_filter_label; JSlider speed_filter; JLabel accel_filter_label; @@ -114,11 +116,15 @@ public class AltosUIEnable extends Container implements ChangeListener { } public void set_shapes_visible(boolean visible) { - System.out.printf("set shapes %b\n", visible); if (shape_listener != null) shape_listener.set_shapes_visible(visible); } + public void set_line_width(float width) { + if (shape_listener != null) + shape_listener.set_line_width(width); + } + public void register_shape_listener(AltosShapeListener shape_listener) { this.shape_listener = shape_listener; } @@ -160,6 +166,34 @@ public class AltosUIEnable extends Container implements ChangeListener { add(show_shapes, c); + line_width_label = new JLabel("Line Width"); + c = new GridBagConstraints(); + c.gridx = 1; c.gridy = 1001; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(line_width_label, c); + + line_width = new JSpinner(); + line_width.setValue(new Integer(1)); + line_width.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + int w = (Integer) line_width.getValue(); + if (w < 1) { + w = 1; + line_width.setValue(new Integer(w)); + } + System.out.printf("line width set to %d\n", w); + set_line_width(w); + } + }); + c = new GridBagConstraints(); + c.gridx = 2; c.gridy = 1001; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.insets = il; + add(line_width, c); + speed_filter_label = new JLabel("Speed Filter(ms)"); c = new GridBagConstraints(); c.gridx = 0; c.gridy = 1002; diff --git a/altosuilib/AltosUIFlightSeries.java b/altosuilib/AltosUIFlightSeries.java index 19bed609..407e5ab4 100644 --- a/altosuilib/AltosUIFlightSeries.java +++ b/altosuilib/AltosUIFlightSeries.java @@ -30,15 +30,16 @@ import org.jfree.data.xy.*; import org.jfree.data.*; class AltosUITimeSeriesAxis { - Color color; - boolean enabled; - boolean marker; - boolean marker_top; - AltosUIAxis axis; - XYPlot plot; - - public AltosUITimeSeriesAxis(Color color, boolean enabled, AltosUIAxis axis, XYPlot plot, boolean marker, boolean marker_top) { - this.color = color; + AltosUILineStyle line_style; + boolean enabled; + boolean marker; + boolean marker_top; + AltosUIAxis axis; + XYPlot plot; + + public AltosUITimeSeriesAxis(AltosUILineStyle line_style, boolean enabled, + AltosUIAxis axis, XYPlot plot, boolean marker, boolean marker_top) { + this.line_style = line_style; this.enabled = enabled; this.axis = axis; this.plot = plot; @@ -51,26 +52,34 @@ public class AltosUIFlightSeries extends AltosFlightSeries { Hashtable axes; - AltosUIFlightSeries flight_series; - void fill_axes(String label, AltosUITimeSeriesAxis axis) { for (AltosTimeSeries ts : series) { AltosUITimeSeries uts = (AltosUITimeSeries) ts; - if (label.equals(ts.label) || (label.equals("default") && uts.color == null)) { + if (label.equals(ts.label) || (label.equals("default") && uts.line_style == null)) { + uts.custom_axis_set = true; if (axis.marker) - uts.set_marker(axis.color, axis.enabled, axis.plot, axis.marker_top); + uts.set_marker(axis.line_style, axis.enabled, axis.plot, axis.marker_top); else - uts.set_axis(axis.color, axis.enabled, axis.axis); + uts.set_axis(axis.line_style, axis.enabled, axis.axis); } } } + void check_axes() { + for (AltosTimeSeries ts : series) { + AltosUITimeSeries uts = (AltosUITimeSeries) ts; + + if (!uts.custom_axis_set) + System.out.printf("%s using default axis\n", ts.label); + } + } + public void register_axis(String label, - Color color, + AltosUILineStyle line_style, boolean enabled, AltosUIAxis axis) { - AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(color, + AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(line_style, enabled, axis, null, @@ -81,11 +90,11 @@ public class AltosUIFlightSeries extends AltosFlightSeries { } public void register_marker(String label, - Color color, + AltosUILineStyle line_style, boolean enabled, XYPlot plot, boolean marker_top) { - AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(color, + AltosUITimeSeriesAxis tsa = new AltosUITimeSeriesAxis(line_style, enabled, null, plot, @@ -97,17 +106,18 @@ public class AltosUIFlightSeries extends AltosFlightSeries { public AltosTimeSeries make_series(String label, AltosUnits units) { - AltosUITimeSeries time_series = new AltosUITimeSeries(label, units); AltosUITimeSeriesAxis tsa = axes.get(label); if (tsa == null) tsa = axes.get("default"); + else + time_series.custom_axis_set = true; if (tsa != null) { if (tsa.marker) - time_series.set_marker(tsa.color, tsa.enabled, tsa.plot, tsa.marker_top); + time_series.set_marker(tsa.line_style, tsa.enabled, tsa.plot, tsa.marker_top); else - time_series.set_axis(tsa.color, tsa.enabled, tsa.axis); + time_series.set_axis(tsa.line_style, tsa.enabled, tsa.axis); } return time_series; } diff --git a/altosuilib/AltosUIGraph.java b/altosuilib/AltosUIGraph.java index 6328d40a..40f415f1 100644 --- a/altosuilib/AltosUIGraph.java +++ b/altosuilib/AltosUIGraph.java @@ -56,14 +56,14 @@ public class AltosUIGraph implements AltosUnitsListener, AltosShapeListener { return panel; } - public AltosUIAxis newAxis(String label, AltosUnits units, Color color, int flags) { - AltosUIAxis axis = new AltosUIAxis(label, units, color, axis_index++, flags); + public AltosUIAxis newAxis(String label, AltosUnits units, AltosUILineStyle line_style, int flags) { + AltosUIAxis axis = new AltosUIAxis(label, units, line_style, axis_index++, flags); plot.setRangeAxis(axis.index, axis); return axis; } - public AltosUIAxis newAxis(String label, AltosUnits units, Color color) { - return newAxis(label, units, color, AltosUIAxis.axis_default); + public AltosUIAxis newAxis(String label, AltosUnits units, AltosUILineStyle line_style) { + return newAxis(label, units, line_style, AltosUIAxis.axis_default); } void addAxis(AltosUIAxis axis) { @@ -104,6 +104,11 @@ public class AltosUIGraph implements AltosUnitsListener, AltosShapeListener { s.set_shapes_visible(visible); } + public void set_line_width(float width) { + for (AltosUITimeSeries s : series) + s.set_line_width(width); + } + public void setName (String name) { chart.setTitle(name); } diff --git a/altosuilib/AltosUILineStyle.java b/altosuilib/AltosUILineStyle.java new file mode 100644 index 00000000..387281a3 --- /dev/null +++ b/altosuilib/AltosUILineStyle.java @@ -0,0 +1,84 @@ +/* + * Copyright © 2017 Keith Packard + * + * 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, either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +package org.altusmetrum.altosuilib_12; + +import java.io.*; +import java.util.ArrayList; + +import java.awt.*; +import javax.swing.*; +import org.altusmetrum.altoslib_12.*; + +import org.jfree.ui.*; +import org.jfree.chart.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.renderer.*; +import org.jfree.chart.renderer.xy.*; +import org.jfree.chart.labels.*; +import org.jfree.data.xy.*; +import org.jfree.data.*; + +public class AltosUILineStyle { + public Color color; + public float[] dash; + + static private Color color(int r, int g, int b) { + return new Color(r,g,b); + } + + static final private Color[] colors = { + new Color(0,0,0), + new Color(230,0,0), // red + new Color(216,103,0), // orange + new Color(200,200,0), // yellow + new Color(0,180,0), // green + new Color(0,140,140), // cyan + new Color(130,0,0), // dark red + new Color(0,100,0), // dark green + new Color(0,0,255), // blue + new Color(140,0,140), // magenta + new Color(150,150,150), // gray + }; + + static final private float[][] dashes = { + { 0 }, + { 2, 4 }, + { 4, 4 }, + { 6, 4 }, + { 6, 4, 2, 4 } + }; + + static int color_index, dash_index; + + public AltosUILineStyle () { + color = colors[color_index]; + dash = dashes[dash_index]; + color_index = (color_index + 1) % colors.length; + if (color_index == 0) { + dash_index = (dash_index + 1) % dashes.length; + if (dash_index == 0) + System.out.printf("too many line styles\n"); + } + } + + public AltosUILineStyle(int index) { + index = index % (colors.length * dashes.length); + int c = index % colors.length; + int d = index / colors.length; + color = colors[c]; + dash = dashes[d]; + } +} diff --git a/altosuilib/AltosUITimeSeries.java b/altosuilib/AltosUITimeSeries.java index b98c8376..e85e3c17 100644 --- a/altosuilib/AltosUITimeSeries.java +++ b/altosuilib/AltosUITimeSeries.java @@ -61,16 +61,17 @@ class AltosXYSeries extends XYSeries { } public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher { - Color color; - boolean enable; - AltosUIAxis axis; - boolean marker; - boolean marker_top; + AltosUILineStyle line_style; + boolean enable; + boolean custom_axis_set; + AltosUIAxis axis; + boolean marker; + boolean marker_top; XYLineAndShapeRenderer renderer; - XYPlot plot; - AltosXYSeries xy_series; + XYPlot plot; + AltosXYSeries xy_series; ArrayList markers; - + float width; /* AltosUIGrapher interface */ public boolean need_reset() { @@ -107,7 +108,8 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher marker.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT); marker.setLabelTextAnchor(TextAnchor.BOTTOM_LEFT); } - marker.setPaint(color); + marker.setPaint(line_style.color); + marker.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); if (enable) plot.addDomainMarker(marker); markers.add(marker); @@ -165,23 +167,41 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher } } - public void set_axis(Color color, boolean enable, AltosUIAxis axis) { - this.color = color; + // public BasicStroke(float width, int cap, int join, float miterlimit, + // float dash[], float dash_phase) + + public void set_line_width(float width) { + this.width = width; + if (markers != null) { + for (ValueMarker marker : markers) { + marker.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + } + } else { + if (line_style.dash[0] == 0.0) + renderer.setSeriesStroke(0, new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + else + renderer.setSeriesStroke(0, new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, line_style.dash, 0.0f)); + } + } + + public void set_axis(AltosUILineStyle line_style, boolean enable, AltosUIAxis axis) { + this.line_style = line_style; this.enable = enable; this.axis = axis; this.marker = false; + this.width = 1.0f; axis.ref(this.enable); renderer = new XYLineAndShapeRenderer(true, false); - renderer.setSeriesPaint(0, color); - renderer.setSeriesStroke(0, new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + renderer.setSeriesPaint(0, line_style.color); + set_line_width(this.width); renderer.setSeriesVisible(0, enable); xy_series = new AltosXYSeries(label); } - public void set_marker(Color color, boolean enable, XYPlot plot, boolean marker_top) { - this.color = color; + public void set_marker(AltosUILineStyle line_style, boolean enable, XYPlot plot, boolean marker_top) { + this.line_style = line_style; this.enable = enable; this.marker = true; this.plot = plot; @@ -197,9 +217,9 @@ public class AltosUITimeSeries extends AltosTimeSeries implements AltosUIGrapher } public AltosUITimeSeries(String label, AltosUnits units, - Color color, boolean enable, + AltosUILineStyle line_style, boolean enable, AltosUIAxis axis) { this(label, units); - set_axis(color, enable, axis); + set_axis(line_style, enable, axis); } } diff --git a/altosuilib/Makefile.am b/altosuilib/Makefile.am index 0f606225..c65a3d15 100644 --- a/altosuilib/Makefile.am +++ b/altosuilib/Makefile.am @@ -41,6 +41,7 @@ altosuilib_JAVA = \ AltosConfigFreqUI.java \ AltosScanUI.java \ AltosEepromDelete.java \ + AltosEepromGrapher.java \ AltosEepromManage.java \ AltosEepromMonitorUI.java \ AltosEepromSelect.java \ @@ -57,6 +58,7 @@ altosuilib_JAVA = \ AltosBTDeviceIterator.java \ AltosBTManage.java \ AltosBTKnown.java \ + AltosUILineStyle.java \ AltosUIMap.java \ AltosUIMapPreload.java \ AltosUIFlightTab.java \ -- cgit v1.2.3