Add option to mark max, average
authorBill Kuker <bkuker@billkuker.com>
Thu, 4 Nov 2010 23:27:11 +0000 (23:27 +0000)
committerBill Kuker <bkuker@billkuker.com>
Thu, 4 Nov 2010 23:27:11 +0000 (23:27 +0000)
gui/com/billkuker/rocketry/motorsim/visual/Chart.java

index ffaf72e3d7a2c651686c9a437ea3413d4c07dc17..b39ab15fb946b4de26afb38cbeb3cc4fe9236d67 100644 (file)
@@ -1,8 +1,10 @@
 package com.billkuker.rocketry.motorsim.visual;\r
 \r
+import java.awt.BasicStroke;\r
 import java.awt.BorderLayout;\r
 import java.awt.Color;\r
 import java.awt.Font;\r
+import java.awt.Stroke;\r
 import java.lang.reflect.InvocationTargetException;\r
 import java.lang.reflect.Method;\r
 import java.util.Collection;\r
@@ -30,17 +32,19 @@ import org.jfree.chart.plot.PlotOrientation;
 import org.jfree.chart.plot.ValueMarker;\r
 import org.jfree.data.xy.XYSeries;\r
 import org.jfree.data.xy.XYSeriesCollection;\r
+import org.jfree.ui.RectangleAnchor;\r
 import org.jfree.ui.RectangleInsets;\r
 import org.jfree.ui.TextAnchor;\r
 import org.jscience.physics.amount.Amount;\r
 \r
-import com.billkuker.rocketry.motorsim.Burn;\r
 import com.billkuker.rocketry.motorsim.RocketScience;\r
 import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
 \r
 public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {\r
        private static final long serialVersionUID = 1L;\r
-       private static Logger log = Logger.getLogger(Burn.class);\r
+       private static Logger log = Logger.getLogger(Chart.class);\r
+       \r
+       private final Stroke dashed =new BasicStroke(1, 1, 1, 1, new float[]{2,4}, 0);\r
 \r
        private static ThreadFactory tf = new ThreadFactory() {\r
                public Thread newThread(Runnable r) {\r
@@ -51,7 +55,7 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
        };\r
        private static ExecutorService fast = Executors.newFixedThreadPool(2, tf);\r
        private static ExecutorService slow = Executors.newFixedThreadPool(2, tf);\r
-       private volatile boolean stop = false;\r
+\r
 \r
        public class IntervalDomain implements Iterable<Amount<X>> {\r
 \r
@@ -129,25 +133,89 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                add(new ChartPanel(chart));\r
        }\r
 \r
-       private Marker marker;\r
+       public void showMax(){\r
+               markMax = true;\r
+       }\r
+       \r
+       public void showAverage(){\r
+               markAverage = true;\r
+       }\r
+       private boolean markMax = false, markAverage = false;\r
+       private Marker focusMarkerX, focusMarkerY;\r
+       private void markMax(){\r
+               if ( !markMax && !markAverage )\r
+                       return;\r
+               if ( dataset.getSeriesCount() != 1 ){\r
+                       return;\r
+               }\r
+               final XYSeries s = dataset.getSeries(0);\r
+\r
+               double max = 0;\r
+               double accum = 0;\r
+               for ( int i = 0; i < s.getItemCount(); i++){\r
+                       if ( s.getY(i).doubleValue() > max ){\r
+                               max = s.getY(i).doubleValue();\r
+                       }\r
+                       if ( i > 0 ){\r
+                               double dx = s.getX(i).doubleValue() - s.getX(i-1).doubleValue();\r
+                               accum += s.getY(i).doubleValue() * dx;\r
+                       }\r
+               }\r
+               double average = accum / (s.getX(s.getItemCount()-1).doubleValue() - s.getX(0).doubleValue());\r
+               \r
+               if (markMax) {\r
+                       Marker marker = new ValueMarker(average);\r
+                       marker.setStroke(dashed);\r
+                       marker.setPaint(Color.BLACK);\r
+                       marker.setLabelFont(new Font(Font.DIALOG, Font.BOLD, 10));\r
+                       marker.setLabel("Average: "\r
+                                       + RocketScience.ammountToRoundedString(Amount.valueOf(\r
+                                                       average, yUnit)));\r
+                       marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);\r
+                       marker.setLabelOffset(new RectangleInsets(0, 5, 0, 0));\r
+                       chart.getXYPlot().addRangeMarker(marker);\r
+               }\r
+\r
+               if (markAverage) {\r
+                       Marker marker = new ValueMarker(max);\r
+                       marker.setStroke(dashed);\r
+                       marker.setPaint(Color.BLACK);\r
+                       marker.setLabelFont(new Font(Font.DIALOG, Font.BOLD, 10));\r
+                       marker.setLabel("Max: "\r
+                                       + RocketScience.ammountToRoundedString(Amount.valueOf(max,\r
+                                                       yUnit)));\r
+                       marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);\r
+                       marker.setLabelOffset(new RectangleInsets(0, 5, 0, 0));\r
+                       chart.getXYPlot().addRangeMarker(marker);\r
+               }\r
+\r
+       }\r
 \r
        public void mark(Amount<X> m) {\r
-               if (marker != null)\r
-                       chart.getXYPlot().removeDomainMarker(marker);\r
+               if (focusMarkerX != null)\r
+                       chart.getXYPlot().removeDomainMarker(focusMarkerX);\r
+               if (focusMarkerY != null)\r
+                       chart.getXYPlot().removeRangeMarker(focusMarkerY);\r
+               \r
                if (m != null) {\r
-                       marker = new ValueMarker(m.doubleValue(xUnit));\r
-                       marker.setPaint(Color.blue);\r
-                       marker.setAlpha(0.8f);\r
+                       focusMarkerX = new ValueMarker(m.doubleValue(xUnit));\r
+                       focusMarkerX.setPaint(Color.blue);\r
+                       focusMarkerX.setAlpha(0.8f);\r
                        \r
-                       Amount<Y> val = getNear(m);\r
-                       if ( val != null )\r
-                               marker.setLabel(RocketScience.ammountToRoundedString(val));\r
-                       \r
-                       marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);\r
-                       marker.setLabelOffset(new RectangleInsets(0,-5,0,0));\r
+                       chart.getXYPlot().addDomainMarker(focusMarkerX);\r
                        \r
-                       marker.setLabelFont(new Font(Font.DIALOG, Font.BOLD, 12));\r
-                       chart.getXYPlot().addDomainMarker(marker);\r
+                       Amount<Y> val = getNear(m);\r
+                       if ( val != null ){\r
+                               focusMarkerY = new ValueMarker(val.doubleValue(yUnit));\r
+                               focusMarkerY.setPaint(Color.BLUE);\r
+                               focusMarkerY.setLabelAnchor(RectangleAnchor.TOP_RIGHT);\r
+                               focusMarkerY.setLabelTextAnchor(TextAnchor.TOP_RIGHT);\r
+                               focusMarkerY.setLabelPaint(Color.BLUE);\r
+                               focusMarkerY.setLabelFont(new Font(Font.DIALOG, Font.BOLD, 10));\r
+                               focusMarkerY.setLabelOffset(new RectangleInsets(0,5,0,0));\r
+                               chart.getXYPlot().addRangeMarker(focusMarkerY);\r
+                               focusMarkerY.setLabel(RocketScience.ammountToRoundedString(val));\r
+                       }\r
                }\r
        }\r
        \r
@@ -188,8 +256,17 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                        }\r
                }\r
        }\r
+       \r
+       private void drawDone(){\r
+               markMax();\r
+       }\r
 \r
+       private volatile boolean stop = false;\r
+       private volatile int lastSkipStepShown;\r
        public void setDomain(final Iterable<Amount<X>> d) {\r
+               chart.getXYPlot().clearDomainMarkers();\r
+               chart.getXYPlot().clearRangeMarkers();\r
+               lastSkipStepShown = Integer.MAX_VALUE;\r
                stop = true;\r
                fill(d, 100);\r
                fast.submit(new Thread() {\r
@@ -198,8 +275,9 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                                        fill(d, 10);\r
                                slow.submit(new Thread() {\r
                                        public void run() {\r
-                                               if (!stop)\r
+                                               if (!stop){\r
                                                        fill(d, 1);\r
+                                               }\r
                                        }\r
                                });\r
                        }\r
@@ -207,15 +285,16 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
        }\r
 \r
        @SuppressWarnings("unchecked")\r
-       private synchronized void fill(Iterable<Amount<X>> d, int skip) {\r
-               log.debug(f.getName() + " " + skip + " Start");\r
+       private synchronized void fill(Iterable<Amount<X>> d, final int requestedSkip) {\r
+               log.debug(f.getName() + " " + requestedSkip + " Start");\r
                stop = false;\r
                int sz = 0;\r
+               int calculatedSkip = requestedSkip;\r
                if (d instanceof Collection) {\r
                        sz = ((Collection<Amount<X>>) d).size();\r
                        int sk2 = sz / 200;\r
-                       if (skip < sk2)\r
-                               skip = sk2;\r
+                       if (calculatedSkip < sk2)\r
+                               calculatedSkip = sk2;\r
                }\r
                // series.clear();\r
                int cnt = 0;\r
@@ -225,11 +304,11 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                        Amount<X> last = null;\r
                        for (Amount<X> ax : d) {\r
                                if (stop) {\r
-                                       log.debug(f.getName() + " " + skip + " Abort");\r
+                                       log.debug(f.getName() + " " + calculatedSkip + " Abort");\r
                                        return;\r
                                }\r
                                last = ax;\r
-                               if (cnt % skip == 0) {\r
+                               if (cnt % calculatedSkip == 0) {\r
                                        Amount<Y> y = (Amount<Y>) f.invoke(source, ax);\r
                                        newSeries.add(ax.doubleValue(xUnit), y.doubleValue(yUnit));\r
                                }\r
@@ -240,9 +319,15 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                        SwingUtilities.invokeLater(new Thread() {\r
                                @Override\r
                                public void run() {\r
-                                       dataset.removeAllSeries();\r
-                                       dataset.addSeries(newSeries);\r
-                                       log.debug(f.getName() + " Replaced");\r
+                                       if ( requestedSkip < lastSkipStepShown ){\r
+                                               lastSkipStepShown = requestedSkip;\r
+                                               dataset.removeAllSeries();\r
+                                               dataset.addSeries(newSeries);\r
+                                               log.debug(f.getName() + " Replaced with " + requestedSkip);\r
+                                       }\r
+                                       if ( requestedSkip == 1 ){\r
+                                               drawDone();\r
+                                       }\r
                                }\r
                        });\r
                } catch (IllegalArgumentException e) {\r
@@ -255,7 +340,7 @@ public class Chart<X extends Quantity, Y extends Quantity> extends JPanel {
                        // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
                }\r
-               log.debug(f.getName() + " " + skip + " Done");\r
+               log.debug(f.getName() + " " + calculatedSkip + " Done");\r
        }\r
 \r
        public void show() {\r