@@ -215,7 +215,7 @@ public class SoundingFrame extends JFrame {
215215
216216 private HazType [] hazType = new HazType [3 ];
217217
218- private SoundingGraphics g ;
218+ private SoundingGraphics sg ;
219219 private MapInset mapInset ;
220220
221221 private static HashMap <PrecipitationType , String > ptypeNames = new HashMap <>();
@@ -268,7 +268,8 @@ public class SoundingFrame extends JFrame {
268268 }
269269
270270 public SoundingFrame (String soundingSource , Sounding sounding0 , DateTime time0 , Sounding soundingM , DateTime timeM ,
271- Sounding sounding1 , DateTime time1 , double lat , double lon , double windOffsetAngle , MapInset mapInset ) {
271+ Sounding sounding1 , DateTime time1 , double lat , double lon , double windOffsetAngle , MapInset mapInset ,
272+ JFrame parentFrame ) {
272273 this .soundingSource = soundingSource ;
273274
274275 this .lat = lat ;
@@ -280,15 +281,15 @@ public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0,
280281 this .windOffsetAngle = windOffsetAngle ;
281282
282283 this .setSize (1750 , 900 );
283- this .setLocationRelativeTo (null );
284+ this .setLocationRelativeTo (parentFrame );
284285 this .setDefaultCloseOperation (JFrame .DISPOSE_ON_CLOSE );
285286
286287 this .setTitle (generateTitle (this .timeM ));
287288
288289 this .setDefaultCloseOperation (JFrame .DISPOSE_ON_CLOSE );
289290
290- g = new SoundingGraphics ();
291- this .add (g );
291+ sg = new SoundingGraphics ();
292+ this .add (sg );
292293
293294 this .addKeyListener (new SoundingKeyListener ());
294295
@@ -645,10 +646,48 @@ public SoundingFrame(String soundingSource, Sounding sounding0, DateTime time0,
645646 hazType [1 ] = determineHazType ();
646647 }
647648
649+ public SoundingFrame (Sounding soundingM , JFrame parentFrame ) {
650+ this ("" , soundingM , null , -1024.0 , -1024.0 , 0 , null , parentFrame );
651+ }
652+
653+ public SoundingFrame (Sounding soundingM , DateTime d , JFrame parentFrame ) {
654+ this ("" , soundingM , d , -1024.0 , -1024.0 , 0 , null , parentFrame );
655+ }
656+
657+ public SoundingFrame (Sounding soundingM , DateTime timeM , double lat , double lon , JFrame parentFrame ) {
658+ this ("" , soundingM , timeM , lat , lon , 0 , null , parentFrame );
659+ }
660+
661+ public SoundingFrame (String soundingSource , Sounding soundingM , JFrame parentFrame ) {
662+ this (soundingSource , soundingM , null , -1024.0 , -1024.0 , 0 , null , parentFrame );
663+ }
664+
665+ public SoundingFrame (String soundingSource , Sounding soundingM , DateTime timeM , double lat , double lon , JFrame parentFrame ) {
666+ this (soundingSource , soundingM , timeM , lat , lon , 0 , null , parentFrame );
667+ }
668+
669+ public SoundingFrame (String soundingSource , Sounding soundingM , DateTime timeM , double lat , double lon ,
670+ MapInset mapInset , JFrame parentFrame ) {
671+ this (soundingSource , soundingM , timeM , lat , lon , 0 , mapInset , parentFrame );
672+ }
673+
674+ public SoundingFrame (String soundingSource , Sounding soundingM , DateTime timeM , double lat , double lon ,
675+ double windOffsetAngle , MapInset mapInset , JFrame parentFrame ) {
676+ this (soundingSource , null , null , soundingM , timeM , null , null , lat , lon , windOffsetAngle , mapInset , parentFrame );
677+ }
678+
679+ public SoundingFrame (String soundingSource , Sounding sounding0 , DateTime time0 , Sounding soundingM , DateTime timeM ,
680+ Sounding sounding1 , DateTime time1 , double lat , double lon , double windOffsetAngle , MapInset mapInset ) {
681+ }
682+
648683 public SoundingFrame (Sounding soundingM ) {
649684 this ("" , soundingM , null , -1024.0 , -1024.0 , 0 , null );
650685 }
651686
687+ public SoundingFrame (Sounding soundingM , DateTime d ) {
688+ this ("" , soundingM , d , -1024.0 , -1024.0 , 0 , null );
689+ }
690+
652691 public SoundingFrame (Sounding soundingM , DateTime timeM , double lat , double lon ) {
653692 this ("" , soundingM , timeM , lat , lon , 0 , null );
654693 }
@@ -658,7 +697,10 @@ public SoundingFrame(String soundingSource, Sounding soundingM) {
658697 }
659698
660699 public SoundingFrame (String soundingSource , Sounding soundingM , DateTime timeM , double lat , double lon ) {
661- this (soundingSource , soundingM , timeM , lat , lon , 0 , null );
700+ // String soundingSource, Sounding sounding0, DateTime time0, Sounding soundingM, DateTime timeM,
701+ // Sounding sounding1, DateTime time1, double lat, double lon, double windOffsetAngle, MapInset mapInset,
702+ // JFrame parentFrame
703+ this (soundingSource , soundingM , timeM , lat , lon , 0 , null , null );
662704 }
663705
664706 public SoundingFrame (String soundingSource , Sounding soundingM , DateTime timeM , double lat , double lon ,
@@ -675,6 +717,27 @@ public SoundingFrame(String soundingSource, Sounding soundingM, DateTime timeM,
675717 private int activeReadoutSet = 1 ;
676718
677719 private int stormMotionVector = 2 ; // 0 = LM, 1 = MW, 2 = RM
720+
721+ public BufferedImage printChart (int width , int height , String text ) {
722+ System .out .println (sg );
723+ BufferedImage chart = sg .drawSoundingChart (width , height );
724+
725+ BufferedImage bg = new BufferedImage (width , height , BufferedImage .TYPE_3BYTE_BGR );
726+ Graphics g = bg .createGraphics ();
727+
728+ g .setColor (Color .BLACK );
729+ g .fillRect (0 , 0 , width , height );
730+
731+ g .drawImage (chart , 0 , 0 , null );
732+
733+ g .setFont (new Font (Font .MONOSPACED , Font .BOLD , 24 ));
734+
735+ g .setColor (Color .WHITE );
736+ drawCenteredString (text , (Graphics2D ) g , width /2 , 20 );
737+
738+ g .dispose ();
739+ return bg ;
740+ }
678741
679742 private class SoundingGraphics extends JComponent {
680743 private static final long serialVersionUID = 1649550301315411744L ;
@@ -700,12 +763,12 @@ public void paintComponent(Graphics g) {
700763 private static final String AUTHOR_MESSAGE = "MADE BY AMELIA URQUHART | PRESS 'C' FOR CONTROLS" ;
701764
702765 private BufferedImage drawSoundingChart (int width , int height ) {
703- double scaleW = width / 1750 .0 ;
766+ double scaleW = width / 1850 .0 ;
704767 double scaleH = height / 900.0 ;
705768
706769 double scale = Double .min (scaleW , scaleH );
707770
708- BufferedImage chart = new BufferedImage ((int ) (1750 * scale ), (int ) (900 * scale ),
771+ BufferedImage chart = new BufferedImage ((int ) (1850 * scale ), (int ) (900 * scale ),
709772 BufferedImage .TYPE_4BYTE_ABGR );
710773 Graphics2D g = chart .createGraphics ();
711774 g .setStroke (thickStroke );
@@ -717,59 +780,66 @@ private BufferedImage drawSoundingChart(int width, int height) {
717780 g .drawImage (skewT , (int ) (50 * scale ), (int ) (50 * scale ), (int ) (850 * scale ), (int ) (850 * scale ), 0 , 0 ,
718781 skewT .getWidth (), skewT .getHeight (), null );
719782
783+ BufferedImage tempAdvection = drawTemperatureAdvection (scale );
784+ g .drawImage (tempAdvection , (int ) (875 * scale ), (int ) (50 * scale ), (int ) (950 * scale ), (int ) (850 * scale ),
785+ 0 , 0 , tempAdvection .getWidth (), tempAdvection .getHeight (), null );
786+
720787 BufferedImage hodograph = drawHodograph (scale );
721- g .drawImage (hodograph , (int ) (875 * scale ), (int ) (50 * scale ), (int ) (1275 * scale ), (int ) (450 * scale ),
788+ g .drawImage (hodograph , (int ) (975 * scale ), (int ) (50 * scale ), (int ) (1375 * scale ), (int ) (450 * scale ),
722789 0 , 0 , hodograph .getWidth (), hodograph .getHeight (), null );
723790
724791 if (mapInset != null ) {
725792 BufferedImage mapInsetImg = mapInset .drawMapInset (lat , lon , 1 , (int ) (400 * scale ));
726- g .drawImage (mapInsetImg , (int ) (1300 * scale ), (int ) (50 * scale ), (int ) (1700 * scale ),
793+ g .drawImage (mapInsetImg , (int ) (1400 * scale ), (int ) (50 * scale ), (int ) (1800 * scale ),
727794 (int ) (450 * scale ), 0 , 0 , mapInsetImg .getWidth (), mapInsetImg .getHeight (), null );
728795 }
729796
730797 BufferedImage stormSlinky = drawStormSlinky (scale );
731- g .drawImage (stormSlinky , (int ) (875 * scale ), (int ) (475 * scale ), (int ) (1062 .5 * scale ),
798+ g .drawImage (stormSlinky , (int ) (975 * scale ), (int ) (475 * scale ), (int ) (1162 .5 * scale ),
732799 (int ) (650 * scale ), 0 , 0 , stormSlinky .getWidth (), stormSlinky .getHeight (), null );
733800
734801 BufferedImage streamwiseVorticity = drawVorticityPlot (scale );
735- g .drawImage (streamwiseVorticity , (int ) (875 * scale ), (int ) (675 * scale ), (int ) (1062 .5 * scale ),
802+ g .drawImage (streamwiseVorticity , (int ) (975 * scale ), (int ) (675 * scale ), (int ) (1162 .5 * scale ),
736803 (int ) (850 * scale ), 0 , 0 , streamwiseVorticity .getWidth (), streamwiseVorticity .getHeight (), null );
737804
738805 BufferedImage severeReadouts = drawSevereReadouts (scale );
739- g .drawImage (severeReadouts , (int ) (1087 .5 * scale ), (int ) (475 * scale ), (int ) (1487 .5 * scale ),
806+ g .drawImage (severeReadouts , (int ) (1187 .5 * scale ), (int ) (475 * scale ), (int ) (1587 .5 * scale ),
740807 (int ) (850 * scale ), 0 , 0 , severeReadouts .getWidth (), severeReadouts .getHeight (), null );
741808
742809 BufferedImage winterReadouts = drawWinterReadouts (scale );
743- g .drawImage (winterReadouts , (int ) (1512 .5 * scale ), (int ) (475 * scale ), (int ) (1700 * scale ),
810+ g .drawImage (winterReadouts , (int ) (1612 .5 * scale ), (int ) (475 * scale ), (int ) (1800 * scale ),
744811 (int ) (650 * scale ), 0 , 0 , winterReadouts .getWidth (), winterReadouts .getHeight (), null );
745812
746813 BufferedImage hazardType = drawHazardType (scale );
747- g .drawImage (hazardType , (int ) (1512 .5 * scale ), (int ) (675 * scale ), (int ) (1700 * scale ),
814+ g .drawImage (hazardType , (int ) (1612 .5 * scale ), (int ) (675 * scale ), (int ) (1800 * scale ),
748815 (int ) (850 * scale ), 0 , 0 , hazardType .getWidth (), hazardType .getHeight (), null );
749816
750817 // skew-t frame
751818 g .drawRect ((int ) (50 * scale ), (int ) (50 * scale ), (int ) (800 * scale ), (int ) (800 * scale ));
819+
820+ // temperature advection frame
821+ g .drawRect ((int ) (875 * scale ), (int ) (50 * scale ), (int ) (75 * scale ), (int ) (800 * scale ));
752822
753823 // hodograph frame
754- g .drawRect ((int ) (875 * scale ), (int ) (50 * scale ), (int ) (400 * scale ), (int ) (400 * scale ));
824+ g .drawRect ((int ) (975 * scale ), (int ) (50 * scale ), (int ) (400 * scale ), (int ) (400 * scale ));
755825
756826 // map inset frame
757- g .drawRect ((int ) (1300 * scale ), (int ) (50 * scale ), (int ) (400 * scale ), (int ) (400 * scale ));
827+ g .drawRect ((int ) (1400 * scale ), (int ) (50 * scale ), (int ) (400 * scale ), (int ) (400 * scale ));
758828
759829 // storm slinky frame
760- g .drawRect ((int ) (875 * scale ), (int ) (475 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
830+ g .drawRect ((int ) (975 * scale ), (int ) (475 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
761831
762832 // streamwise vorticity frame
763- g .drawRect ((int ) (875 * scale ), (int ) (675 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
833+ g .drawRect ((int ) (975 * scale ), (int ) (675 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
764834
765835 // severe readout frame
766- g .drawRect ((int ) (1087 .5 * scale ), (int ) (475 * scale ), (int ) (400 * scale ), (int ) (375 * scale ));
836+ g .drawRect ((int ) (1187 .5 * scale ), (int ) (475 * scale ), (int ) (400 * scale ), (int ) (375 * scale ));
767837
768838 // winter readout frame
769- g .drawRect ((int ) (1512 .5 * scale ), (int ) (475 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
839+ g .drawRect ((int ) (1612 .5 * scale ), (int ) (475 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
770840
771841 // haz type frame
772- g .drawRect ((int ) (1512 .5 * scale ), (int ) (675 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
842+ g .drawRect ((int ) (1612 .5 * scale ), (int ) (675 * scale ), (int ) (187.5 * scale ), (int ) (175 * scale ));
773843
774844 // skew-t labels
775845 if (scale > 0.693 ) {
@@ -783,9 +853,12 @@ private BufferedImage drawSoundingChart(int width, int height) {
783853 drawCenteredString (i + "C" , g , x , (int ) (860 * scale ));
784854 }
785855 }
856+
857+ // temp advection label
858+ drawCenteredString ("K hr^-1" , g , (int ) (912.5 * scale ), (int ) (860 * scale ));
786859
787860 // hodograph label
788- drawCenteredString ("1 RING = 10 KT" , g , (int ) (1075 * scale ), (int ) (460 * scale ));
861+ drawCenteredString ("1 RING = 10 KT" , g , (int ) (1175 * scale ), (int ) (460 * scale ));
789862
790863 // time labels
791864 g .setColor (Color .WHITE );
@@ -1259,6 +1332,82 @@ private BufferedImage drawSkewT(double scale, ParcelPath pathType) {
12591332 return skewT ;
12601333 }
12611334
1335+ private static final double THERMAL_WIND_DP = 5000 ;
1336+ private BufferedImage drawTemperatureAdvection (double scale ) {
1337+ BufferedImage advection = new BufferedImage ((int ) (75 * scale ), (int ) (800 * scale ),
1338+ BufferedImage .TYPE_4BYTE_ABGR );
1339+ Graphics2D g = advection .createGraphics ();
1340+ g .setStroke (thickStroke );
1341+ g .setFont (CAPTION_FONT );
1342+
1343+ double [] pressure = activeSounding .getPressureLevels ();
1344+ double [] height = activeSounding .getHeight ();
1345+ double [] uWind = activeSounding .getUWind ();
1346+ double [] vWind = activeSounding .getVWind ();
1347+
1348+ double surfacePressure = pressure [pressure .length - 1 ];
1349+
1350+ ArrayList <Double > temperatureAdvection = new ArrayList <>();
1351+ ArrayList <Double > lowerLimits = new ArrayList <>();
1352+ ArrayList <Double > upperLimits = new ArrayList <>();
1353+
1354+ double tempAdvMax = 0.0 ;
1355+
1356+ for (double i = 10000 ; i < 100000 ; i += THERMAL_WIND_DP ) {
1357+ double upperLimitPres = i ;
1358+ double lowerLimitPres = i + THERMAL_WIND_DP ;
1359+
1360+ if (upperLimitPres > surfacePressure ) {
1361+ break ;
1362+ }
1363+
1364+ if (lowerLimitPres > surfacePressure ) {
1365+ lowerLimitPres = surfacePressure ;
1366+ }
1367+
1368+ // System.out.println(upperLimitPres);
1369+ // System.out.println(lowerLimitPres);
1370+
1371+ double tempAdv = WeatherUtils .inferredTemperatureAdvection (pressure , height , uWind , vWind , lat , upperLimitPres , lowerLimitPres );
1372+
1373+ temperatureAdvection .add (tempAdv * 3600 );
1374+ lowerLimits .add (lowerLimitPres );
1375+ upperLimits .add (upperLimitPres );
1376+
1377+ tempAdvMax = Double .max (Math .abs (tempAdvMax ), Math .abs (tempAdv * 3600 ));
1378+ }
1379+
1380+ // System.out.println(tempAdvMax);
1381+
1382+ g .setColor (Color .GRAY );
1383+ g .drawLine ((int ) (37.5 * scale ), (int ) (0 * scale ), (int ) (37.5 * scale ), (int ) (800 * scale ));
1384+
1385+ double tempAdvScaleMax = Double .max (1.2 * tempAdvMax , 3 );
1386+ for (int i = 0 ; i < temperatureAdvection .size (); i ++) {
1387+ double y1 = linScale (Math .log (10000 ), Math .log (110000 ), 0 , 800 , Math .log (upperLimits .get (i )));
1388+ double y2 = linScale (Math .log (10000 ), Math .log (110000 ), 0 , 800 , Math .log (lowerLimits .get (i )));
1389+
1390+ // System.out.printf("%5.2fK hr^-1 %6.1f mb %6.1f mb\n", temperatureAdvection.get(i), upperLimits.get(i)/100.0, lowerLimits.get(i)/100.0);
1391+
1392+ double x1 = 37.5 ;
1393+ double x2 = linScale (-tempAdvScaleMax , tempAdvScaleMax , 0 , 75 , temperatureAdvection .get (i ));
1394+
1395+ if (x2 < x1 ) {
1396+ g .setColor (new Color (64 , 64 , 255 ));
1397+ g .drawRect ((int ) (x2 * scale ), (int ) (y1 * scale ), (int ) ((x1 - x2 ) * scale ), (int ) ((y2 - y1 ) * scale ));
1398+ drawCenteredString (String .format ("%3.1f" , temperatureAdvection .get (i )), g , (int ) (scale *23 *x1 /16.0 ), (int ) (scale *(y1 +y2 )/2.0 ));
1399+ } else {
1400+ g .setColor (new Color (255 , 0 , 0 ));
1401+ g .drawRect ((int ) (x1 * scale ), (int ) (y1 * scale ), (int ) ((x2 - x1 ) * scale ), (int ) ((y2 - y1 ) * scale ));
1402+ drawCenteredString (String .format ("%3.1f" , temperatureAdvection .get (i )), g , (int ) (scale * x1 /2.0 ), (int ) (scale *(y1 +y2 )/2.0 ));
1403+ }
1404+ }
1405+
1406+ g .dispose ();
1407+
1408+ return advection ;
1409+ }
1410+
12621411 private BufferedImage drawHodograph (double scale ) {
12631412 BufferedImage hodograph = new BufferedImage ((int ) (400 * scale ), (int ) (400 * scale ),
12641413 BufferedImage .TYPE_4BYTE_ABGR );
@@ -2387,10 +2536,15 @@ private BufferedImage drawStormSlinky(double scale) {
23872536 drawLeftCenterAlignedString ((int ) (xArr .size () * dT ) + " s" , g , (int ) (5 * scale ), (int ) (8 * scale ));
23882537
23892538 // updraft tilt
2390- double updraftHeight = zArr .get (zArr .size () - 1 ) - zArr .get (0 );
2391-
2392- double deltaX = xArr .get (xArr .size () - 1 ) - xArr .get (0 );
2393- double deltaY = yArr .get (yArr .size () - 1 ) - yArr .get (0 );
2539+ double updraftHeight = 0 ;
2540+ double deltaX = 0 ;
2541+ double deltaY = 0 ;
2542+ if (zArr .size () > 0 ) {
2543+ updraftHeight = zArr .get (zArr .size () - 1 ) - zArr .get (0 );
2544+ deltaX = xArr .get (xArr .size () - 1 ) - xArr .get (0 );
2545+ deltaY = yArr .get (yArr .size () - 1 ) - yArr .get (0 );
2546+ }
2547+
23942548 double updraftTopOffset = Math .hypot (deltaX , deltaY );
23952549
23962550 double updraftTilt = Math .toDegrees (Math .atan2 (updraftTopOffset , updraftHeight ));
@@ -2545,7 +2699,7 @@ public void keyPressed(KeyEvent e) {
25452699
25462700 setTitle (generateTitle (time0 ));
25472701
2548- g .repaint ();
2702+ sg .repaint ();
25492703 }
25502704 break ;
25512705 case KeyEvent .VK_2 :
@@ -2555,7 +2709,7 @@ public void keyPressed(KeyEvent e) {
25552709
25562710 setTitle (generateTitle (timeM ));
25572711
2558- g .repaint ();
2712+ sg .repaint ();
25592713 }
25602714 break ;
25612715 case KeyEvent .VK_3 :
@@ -2565,23 +2719,23 @@ public void keyPressed(KeyEvent e) {
25652719
25662720 setTitle (generateTitle (time1 ));
25672721
2568- g .repaint ();
2722+ sg .repaint ();
25692723 }
25702724 break ;
25712725 case KeyEvent .VK_C :
25722726 openControlsPage ();
25732727 break ;
25742728 case KeyEvent .VK_E :
25752729 showEntrainment = !showEntrainment ;
2576- g .repaint ();
2730+ sg .repaint ();
25772731 break ;
25782732 case KeyEvent .VK_P :
25792733 selectParcelPathType ();
2580- g .repaint ();
2734+ sg .repaint ();
25812735 break ;
25822736 case KeyEvent .VK_S :
25832737 selectStormMotionVector ();
2584- g .repaint ();
2738+ sg .repaint ();
25852739 break ;
25862740 }
25872741 }
0 commit comments