Added hourly forecast

This commit is contained in:
Flare Microsystems
2024-03-08 21:31:49 -08:00
parent 107f83084e
commit 5628a5b76e
11 changed files with 358 additions and 57 deletions

Binary file not shown.

View File

@@ -1,4 +1,4 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Thu Mar 07 16:27:03 PST 2024 #Fri Mar 08 16:38:56 PST 2024
towns-by-code= towns-by-code=
towns-by-name-and-province=Vancouver,BC;Kamloops,BC;Kelowna,BC towns-by-name-and-province=Duncan,BC;Halifax,NS;Courtenay,BC;Comox,BC

Binary file not shown.

View File

@@ -29,6 +29,7 @@ import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.displays.BootupDisplay; import com.flaremicro.visualforecast.displays.BootupDisplay;
import com.flaremicro.visualforecast.displays.DayForecastDisplay; import com.flaremicro.visualforecast.displays.DayForecastDisplay;
import com.flaremicro.visualforecast.displays.Display; import com.flaremicro.visualforecast.displays.Display;
import com.flaremicro.visualforecast.displays.HourlyForecastDisplay;
import com.flaremicro.visualforecast.forecast.ForecastDetails; import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.graphics.DrawingUtil; import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager; import com.flaremicro.visualforecast.graphics.FontManager;
@@ -54,6 +55,8 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
private Rectangle exclusiveRedrawBound = null; private Rectangle exclusiveRedrawBound = null;
private Rectangle crawlBound = null; private Rectangle crawlBound = null;
private Rectangle currentBound = new Rectangle(0, 0, 0, 0);
private String currentTown = ""; private String currentTown = "";
private String currentForecast = ""; private String currentForecast = "";
@@ -109,30 +112,8 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
Graphics2D g2d = prepareFrameBuffer(); Graphics2D g2d = prepareFrameBuffer();
if(g.getClipBounds().equals(this.crawlBound))
{
g2d.setColor(BG_BLUE);
g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT);
g2d.setColor(Color.DARK_GRAY);
g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_OFFSET);
g2d.setColor(Color.WHITE);
g2d.drawLine(0, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET, W, H - INFOBAR_HEIGHT + STROKE_WIDTH + STROKE_OFFSET);
if (this.currentCrawlString != null)
{
g2d.setFont(font.deriveFont(26F));
DrawingUtil.drawOutlinedString(g2d, this.crawlPosition, H - INFOBAR_HEIGHT + 30, this.currentCrawlString, Color.WHITE, Color.BLACK, 2);
}
g2d.dispose();
g.drawImage(frameBuffer, 0, 0, getWidth(), getHeight(), this);
return;
}
drawMainRegion(g2d); drawMainRegion(g2d);
if (currentFlavour != null) if (currentFlavour != null)
{ {
if (this.getBounds().equals(g.getClipBounds())) if (this.getBounds().equals(g.getClipBounds()))
@@ -152,7 +133,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
g2d.setColor(BG_PURPLE); g2d.setColor(BG_PURPLE);
g2d.fillRect(0, 0, W, TOPBAR_HEIGHT); g2d.fillRect(0, 0, W, TOPBAR_HEIGHT);
g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_OORANGE, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE)); g2d.setPaint(new GradientPaint(0, HEADERBAR_Y, BG_ORANGE, 0, HEADERBAR_Y + (HEADERBAR_HEIGHT + 10), BG_PURPLE));
g2d.shear(HEADERBAR_SHEAR, 0); g2d.shear(HEADERBAR_SHEAR, 0);
g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT); g2d.fillRect(-HEADERBAR_OFFSET, HEADERBAR_Y, HEADERBAR_WIDTH, HEADERBAR_HEIGHT);
@@ -160,7 +141,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT); g2d.fillRect(W - TIMEBAR_WIDTH + TIMEBAR_OFFSET, TIMEBAR_Y, TIMEBAR_WIDTH, TIMEBAR_HEIGHT);
g2d.shear(-HEADERBAR_SHEAR, 0); g2d.shear(-HEADERBAR_SHEAR, 0);
g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, BG_PURPLE, 0, MAINBAR_HEIGHT, BG_OORANGE)); g2d.setPaint(new GradientPaint(0, TOPBAR_HEIGHT, BG_PURPLE, 0, MAINBAR_HEIGHT, BG_ORANGE));
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT); g2d.fillRect(0, TOPBAR_HEIGHT, W, MAINBAR_HEIGHT);
@@ -177,7 +158,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, W - sw - 60, TIMEBAR_Y + 36, timeString, Color.WHITE, Color.BLACK, 2);
g2d.setFont(font.deriveFont(36F)); g2d.setFont(font.deriveFont(36F));
DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, currentTown, Color.YELLOW, Color.BLACK, 2); DrawingUtil.drawOutlinedString(g2d, 60, HEADERBAR_Y + 52, currentTown, Color.YELLOW, Color.BLACK, 2);
g2d.setColor(BG_BLUE); g2d.setColor(BG_BLUE);
g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT); g2d.fillRect(0, H - INFOBAR_HEIGHT, W, INFOBAR_HEIGHT);
@@ -202,7 +183,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
//Clock and icon animations, should use repaint regions later //Clock and icon animations, should use repaint regions later
if (getWidth() > 0 && getHeight() > 0) if (getWidth() > 0 && getHeight() > 0)
{ {
repaint(this.redrawBound); requestRepaint(this.redrawBound);
} }
} }
if (this.currentFlavour != null) if (this.currentFlavour != null)
@@ -218,10 +199,37 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
this.currentCrawlStringWidth = g.getFontMetrics(font.deriveFont(26F)).stringWidth(currentCrawlString); this.currentCrawlStringWidth = g.getFontMetrics(font.deriveFont(26F)).stringWidth(currentCrawlString);
g.dispose(); g.dispose();
} }
else if (this.currentCrawlString != null) }
public void requestFullRepaint() {
currentBound = this.getBounds();
}
public void requestRepaint(Rectangle bound) {
if(currentBound.width == 0)
currentBound = new Rectangle(bound);
else currentBound.add(bound);
}
public void requestBoundedRepaint() {
requestRepaint(this.redrawBound);
}
public void requestExclusiveBoundedRepaint() {
requestRepaint(exclusiveRedrawBound);
}
public void performPaintIfNeeded() {
if (this.currentCrawlString != null)
{ {
this.crawlPosition-=2; this.crawlPosition -= 2;
repaint(0, this.crawlBound.x, this.crawlBound.y, this.crawlBound.width, this.crawlBound.height); requestRepaint(crawlBound);
}
if(this.currentBound.width != 0)
{
repaint(currentBound);
currentBound.width = 0;
} }
} }
@@ -293,7 +301,7 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
} }
public void nextDisplay() { public void nextDisplay() {
this.currentFlavour = new DayForecastDisplay(); this.currentFlavour = new HourlyForecastDisplay();
this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks); this.currentFlavour.initDisplay(this, forecastProvider, ticks, iconAnimationTicks);
this.loseRedrawRegion(); this.loseRedrawRegion();
this.requestFullRepaint(); this.requestFullRepaint();
@@ -307,18 +315,6 @@ public class RenderPanel extends JPanel implements Tickable, ComponentListener {
this.currentForecast = currentForecast; this.currentForecast = currentForecast;
} }
public void requestFullRepaint() {
repaint();
}
public void requestBoundedRepaint() {
repaint(redrawBound);
}
public void requestExclusiveBoundedRepaint() {
repaint(exclusiveRedrawBound);
}
private void loadCrawlStrings() { private void loadCrawlStrings() {
File crawl = new File("./crawl.txt"); File crawl = new File("./crawl.txt");
ArrayList<String> strings = new ArrayList<String>(); ArrayList<String> strings = new ArrayList<String>();

View File

@@ -2,6 +2,8 @@ package com.flaremicro.visualforecast;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.event.KeyListener;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
@@ -9,6 +11,7 @@ import java.awt.event.WindowListener;
import java.io.File; import java.io.File;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.Timer;
import com.flaremicro.visualforecast.api.ForecastProvider; import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.api.ForecastProviderManager; import com.flaremicro.visualforecast.api.ForecastProviderManager;
@@ -23,6 +26,8 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
private ForecastProviderManager forecastProviderManager; private ForecastProviderManager forecastProviderManager;
private Executor executor; private Executor executor;
private PropertyManager propertyManager = new PropertyManager(); private PropertyManager propertyManager = new PropertyManager();
private Timer timer;
private Timer timer2;
private boolean isFullscreen = false; private boolean isFullscreen = false;
/** /**
@@ -37,7 +42,7 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
frame.setVisible(true); frame.setVisible(true);
frame.init(); frame.init();
//GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[1].setFullScreenWindow(frame); //GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[1].setFullScreenWindow(frame);
frame.createBufferStrategy(2); //frame.createBufferStrategy(2);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -50,6 +55,10 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
public void end() { public void end() {
if (executor != null) if (executor != null)
executor.end(); executor.end();
if (timer != null)
{
timer.stop();
}
if (forecastProviderManager != null) if (forecastProviderManager != null)
forecastProviderManager.end(); forecastProviderManager.end();
propertyManager.store(); propertyManager.store();
@@ -58,6 +67,14 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
public void init() { public void init() {
executor = new Executor(this.renderPane, 30); executor = new Executor(this.renderPane, 30);
executor.begin(); executor.begin();
timer = new Timer(33, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
renderPane.performPaintIfNeeded();
}
});
timer.start();
new Thread() { new Thread() {
public void run() { public void run() {
@@ -67,6 +84,7 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
propertyManager.store(); propertyManager.store();
ForecastProvider provider = forecastProviderManager.loadProvider(new File(forecastProvider)); ForecastProvider provider = forecastProviderManager.loadProvider(new File(forecastProvider));
renderPane.setForecastProvider(provider); renderPane.setForecastProvider(provider);
} }
}.start(); }.start();
@@ -79,9 +97,9 @@ public class VisualForecastFrame extends JFrame implements WindowListener, KeyLi
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(100, 100, 640 * 2, 480 * 2); setBounds(100, 100, 640 * 2, 480 * 2);
renderPane = new RenderPanel(propertyManager); renderPane = new RenderPanel(propertyManager);
renderPane.setBorder(null); //renderPane.setBorder(null);
renderPane.setLayout(new BorderLayout(0, 0)); //renderPane.setLayout(new BorderLayout(0, 0));
setContentPane(renderPane); add(renderPane);
setUndecorated(true); setUndecorated(true);
addWindowListener(this); addWindowListener(this);
addKeyListener(this); addKeyListener(this);

View File

@@ -0,0 +1,252 @@
package com.flaremicro.visualforecast.displays;
import static com.flaremicro.visualforecast.graphics.RenderConstants.BG_BLUE;
import static com.flaremicro.visualforecast.graphics.RenderConstants.MAINBAR_HEIGHT;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import com.flaremicro.visualforecast.RenderPanel;
import com.flaremicro.visualforecast.api.ForecastProvider;
import com.flaremicro.visualforecast.forecast.DayForecast;
import com.flaremicro.visualforecast.forecast.ForecastDetails;
import com.flaremicro.visualforecast.forecast.HourlyForecast;
import com.flaremicro.visualforecast.forecast.TownForecast;
import com.flaremicro.visualforecast.forecast.ValueCheck;
import com.flaremicro.visualforecast.graphics.DrawingUtil;
import com.flaremicro.visualforecast.graphics.FontManager;
import com.flaremicro.visualforecast.graphics.RenderConstants;
import com.flaremicro.visualforecast.icons.IconProvider;
public class HourlyForecastDisplay implements Display {
private int dayOffset = 0;
private Font font;
private Font smallFont;
private ForecastDetails details;
private TownForecast currentTown = null;
private int townIndex;
private int ticksBeforeChange = 200;
private int animationTicks = -1;
DateFormat simpleDateFormat = new SimpleDateFormat("ha");
public HourlyForecastDisplay() {
font = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000.ttf"));
smallFont = FontManager.getInstance().getOrCreateFont(Font.TRUETYPE_FONT, this.getClass().getResource("/Star4000 Small.ttf"));
}
@Override
public void tick(RenderPanel renderer, long ticks, int iconTicks) {
}
@Override
public void initDisplay(RenderPanel renderer, ForecastProvider forecastProvider, long ticks, int iconTicks) {
this.details = forecastProvider != null ? forecastProvider.getForecast() : null;
renderer.setCurrentForecast("12 Hour Forecast");
if (details == null || details.getTownForecast() == null || details.getTownForecast().length <= 0)
this.details = null;
else
{
townIndex = 0;
currentTown = details.getTownForecast()[townIndex];
renderer.setCurrentTown(currentTown.getTownName());
}
redrawRegionlost(renderer);
}
@Override
public void drawDisplay(RenderPanel renderer, Graphics2D g2d, long ticks, int iconTicks) {
}
public int minTemp(HourlyForecast[] forecast) {
int min = Integer.MAX_VALUE;
for (int i = 0; i < forecast.length; i++)
{
int currMin;
if (ValueCheck.valueNoData(forecast[i].dewPoint) && ValueCheck.valueNoData(forecast[i].temp))
continue;
else if (ValueCheck.valueNoData(forecast[i].dewPoint))
currMin = forecast[i].temp;
else if (ValueCheck.valueNoData(forecast[i].temp))
currMin = forecast[i].dewPoint;
else currMin = Math.min(forecast[i].temp, forecast[i].dewPoint);
if (currMin < min)
min = currMin;
}
return min;
}
public int maxTemp(HourlyForecast[] forecast) {
int max = Integer.MIN_VALUE;
for (int i = 0; i < forecast.length; i++)
{
int currMax;
if (ValueCheck.valueNoData(forecast[i].dewPoint) && ValueCheck.valueNoData(forecast[i].temp))
continue;
else if (ValueCheck.valueNoData(forecast[i].dewPoint))
currMax = forecast[i].temp;
else if (ValueCheck.valueNoData(forecast[i].temp))
currMax = forecast[i].dewPoint;
else currMax = Math.max(forecast[i].temp, forecast[i].dewPoint);
if (currMax > max)
max = currMax;
}
return max;
}
@Override
public void drawBoundLimitedDisplay(RenderPanel renderer, Graphics2D g2d, Rectangle bounds, long ticks, int iconTicks) {
HourlyForecast[] forecast = currentTown.getHourlyForecast();
if(forecast == null)
return;
g2d.setColor(RenderConstants.BG_BLUE);
//g2d.fillRect(RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 20, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2, RenderConstants.MAINBAR_HEIGHT - 40);
DrawingUtil.drawGradientRect(g2d, RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 20, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2, RenderConstants.MAINBAR_HEIGHT - 40, 15, BG_BLUE.darker(), BG_BLUE.brighter());
int min = minTemp(forecast);
int max = maxTemp(forecast);
float range = Math.abs(min)+Math.abs(max);
g2d.setPaint(new GradientPaint(0, RenderConstants.TOPBAR_HEIGHT + 40, RenderConstants.BG_ORANGE, 0, RenderConstants.MAINBAR_HEIGHT, RenderConstants.BG_PURPLE));
g2d.fillRect(RenderConstants.SIDE_OFFSET + 40, RenderConstants.TOPBAR_HEIGHT + 40, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 60, RenderConstants.MAINBAR_HEIGHT - 124);
g2d.setColor(Color.BLACK);
g2d.drawRect(RenderConstants.SIDE_OFFSET, RenderConstants.TOPBAR_HEIGHT + 20, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2, RenderConstants.MAINBAR_HEIGHT - 40);
/*float lineHeight = (RenderConstants.MAINBAR_HEIGHT - 104) / 9F;
for(int i = 0; i < 10; i++)
{
g2d.drawLine(RenderConstants.SIDE_OFFSET + 36, (int)(RenderConstants.TOPBAR_HEIGHT + 40 + lineHeight * i), RenderConstants.W - RenderConstants.SIDE_OFFSET - 36, (int) (RenderConstants.TOPBAR_HEIGHT + 40 + lineHeight * i));
}*/
g2d.setFont(smallFont.deriveFont(20F));
FontMetrics fm = g2d.getFontMetrics();
DrawingUtil.drawOutlinedString(g2d, 100, RenderConstants.TOPBAR_HEIGHT + 35, "Temperature\u00B0c", Color.RED, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, 260, RenderConstants.TOPBAR_HEIGHT + 35, "Dew point\u00B0c", Color.WHITE, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, 410, RenderConstants.TOPBAR_HEIGHT + 35, "Precipitation%", Color.CYAN, Color.BLACK, 2);
String minText = min + "\u00B0";
String maxText = max + "\u00B0";
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET+40-fm.stringWidth(maxText), RenderConstants.TOPBAR_HEIGHT + 53, maxText, Color.YELLOW, Color.BLACK, 2);
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET+40-fm.stringWidth(minText), RenderConstants.TOPBAR_HEIGHT + MAINBAR_HEIGHT - 92, minText, Color.YELLOW, Color.BLACK, 2);
int slotWidth = (RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 60) / 12;
int lastDewpoint = 0;
int lastTemperature = 0;
int lastPercip = 0;
g2d.setColor(RenderConstants.BG_ORANGE.darker());
g2d.drawLine(RenderConstants.SIDE_OFFSET+40, (RenderConstants.TOPBAR_HEIGHT + 50), (RenderConstants.W - RenderConstants.SIDE_OFFSET - 20), (RenderConstants.TOPBAR_HEIGHT + 50));
g2d.setColor(RenderConstants.BG_PURPLE.brighter());
g2d.drawLine(RenderConstants.SIDE_OFFSET+40, RenderConstants.TOPBAR_HEIGHT + 50 + RenderConstants.MAINBAR_HEIGHT - 144, (RenderConstants.W - RenderConstants.SIDE_OFFSET - 20), RenderConstants.TOPBAR_HEIGHT + 50 + RenderConstants.MAINBAR_HEIGHT - 144);
//BlackLines
g2d.setClip(RenderConstants.SIDE_OFFSET + 40, RenderConstants.TOPBAR_HEIGHT + 40, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 60, RenderConstants.MAINBAR_HEIGHT - 124);
g2d.setStroke(new BasicStroke(2));
g2d.setColor(Color.BLACK);
for(int i = 0; i < Math.min(12, forecast.length); i++)
{
int nextDewpoint = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int)(((max-forecast[i].dewPoint)/range)*(RenderConstants.MAINBAR_HEIGHT - 144));
int nextTemperature = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int)(((max-forecast[i].temp)/range)*(RenderConstants.MAINBAR_HEIGHT - 144));
int nextPercip = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int) ((forecast[i].percip/100F)*(RenderConstants.MAINBAR_HEIGHT - 144));
if(i == 0)
{
lastDewpoint = nextDewpoint;
lastTemperature = nextTemperature;
lastPercip = nextPercip;
}
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1))+1, lastDewpoint+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i)+2, nextDewpoint+2);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1))+1, lastPercip+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i)+2, nextPercip+2);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1))+1, lastTemperature+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i)+2, nextTemperature+2);
if(i == Math.min(12, forecast.length)-1)
{
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextDewpoint+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+2)), nextDewpoint+2);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextPercip+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+2)), nextPercip+2);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextTemperature+2, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+2)), nextTemperature+2);
}
lastPercip = nextPercip;
lastTemperature = nextTemperature;
lastDewpoint = nextDewpoint;
}
g2d.setClip(null);
for(int i = 0; i < Math.min(12, forecast.length); i++)
{
g2d.setClip(RenderConstants.SIDE_OFFSET + 40, RenderConstants.TOPBAR_HEIGHT + 40, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 60, RenderConstants.MAINBAR_HEIGHT - 124);
int nextDewpoint = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int)(((max-forecast[i].dewPoint)/range)*(RenderConstants.MAINBAR_HEIGHT - 144));
int nextTemperature = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int)(((max-forecast[i].temp)/range)*(RenderConstants.MAINBAR_HEIGHT - 144));
int nextPercip = (RenderConstants.TOPBAR_HEIGHT + 50) + (RenderConstants.MAINBAR_HEIGHT - 144) - (int) ((forecast[i].percip/100F)*(RenderConstants.MAINBAR_HEIGHT - 144));
if(i == 0)
{
lastDewpoint = nextDewpoint;
lastTemperature = nextTemperature;
lastPercip = nextPercip;
}
g2d.setStroke(new BasicStroke(2));
g2d.setColor(Color.WHITE);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1)), lastDewpoint, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i), nextDewpoint);
g2d.setColor(Color.CYAN);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1)), lastPercip, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i), nextPercip);
g2d.setColor(Color.RED);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i-1)), lastTemperature, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i), nextTemperature);
if(i == Math.min(12, forecast.length)-1)
{
g2d.setColor(Color.WHITE);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextDewpoint, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+1)), nextDewpoint);
g2d.setColor(Color.CYAN);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextPercip, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+1)), nextPercip);
g2d.setColor(Color.RED);
g2d.drawLine(RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i)), nextTemperature, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*(i+1)), nextTemperature);
}
g2d.setClip(null);
lastPercip = nextPercip;
lastTemperature = nextTemperature;
lastDewpoint = nextDewpoint;
String timeString = simpleDateFormat.format(forecast[i].hour);
if((i % 2) == 0)
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i)-fm.stringWidth(timeString)/2, RenderConstants.TOPBAR_HEIGHT + MAINBAR_HEIGHT - 70, timeString, Color.YELLOW, Color.BLACK, 2);
else
DrawingUtil.drawOutlinedString(g2d, RenderConstants.SIDE_OFFSET+40+slotWidth/2+(slotWidth*i)-fm.stringWidth(timeString)/2, RenderConstants.TOPBAR_HEIGHT + MAINBAR_HEIGHT - 60, timeString, Color.YELLOW, Color.BLACK, 2);
IconProvider.drawIcon(g2d, IconProvider.INDEXED_ICONS[forecast[i].iconId], RenderConstants.SIDE_OFFSET + 45 + i * slotWidth , RenderConstants.TOPBAR_HEIGHT + MAINBAR_HEIGHT - 55, slotWidth - 10, iconTicks);
}
g2d.setStroke(new BasicStroke(2));
g2d.setColor(Color.BLACK);
g2d.drawRect(RenderConstants.SIDE_OFFSET + 40, RenderConstants.TOPBAR_HEIGHT + 40, RenderConstants.W - RenderConstants.SIDE_OFFSET * 2 - 60, RenderConstants.MAINBAR_HEIGHT - 124);
}
@Override
public void redrawRegionlost(RenderPanel renderer) {
renderer.addRedrawBound(0, RenderConstants.TOPBAR_HEIGHT, RenderConstants.W, RenderConstants.MAINBAR_HEIGHT);
}
@Override
public void notifyForecastProviderUpdate(RenderPanel renderer, ForecastProvider forecastProvider) {
}
}

View File

@@ -1,5 +1,7 @@
package com.flaremicro.visualforecast.forecast; package com.flaremicro.visualforecast.forecast;
import com.flaremicro.visualforecast.icons.IconProvider;
public class DayForecast { public class DayForecast {
public byte hiTemp; public byte hiTemp;
public byte loTemp; public byte loTemp;
@@ -11,7 +13,7 @@ public class DayForecast {
public DayForecast(byte hiTemp, byte loTemp, byte iconId, String weatherLine1, String weatherLine2, float percipPercent){ public DayForecast(byte hiTemp, byte loTemp, byte iconId, String weatherLine1, String weatherLine2, float percipPercent){
this.hiTemp = hiTemp; this.hiTemp = hiTemp;
this.loTemp = loTemp; this.loTemp = loTemp;
this.iconId = (byte)(iconId & 63); this.iconId = (byte)(iconId % IconProvider.INDEXED_ICONS.length);
this.weatherLine1 = weatherLine1; this.weatherLine1 = weatherLine1;
this.weatherLine2 = weatherLine2; this.weatherLine2 = weatherLine2;
this.percipPercent = percipPercent; this.percipPercent = percipPercent;

View File

@@ -0,0 +1,24 @@
package com.flaremicro.visualforecast.forecast;
import java.util.Date;
import com.flaremicro.visualforecast.icons.IconProvider;
public class HourlyForecast {
public final Date hour;
public final byte iconId;
public final byte temp;
public final short windSpeed;
public final float percip;
public final byte dewPoint;
public HourlyForecast(Date hour, byte iconId, byte temp, short windSpeed, float percip, byte dewPoint)
{
this.hour = hour;
this.iconId = (byte) (iconId % IconProvider.INDEXED_ICONS.length);
this.temp = temp;
this.windSpeed = windSpeed;
this.percip = percip;
this.dewPoint = dewPoint;
}
}

View File

@@ -1,18 +1,27 @@
package com.flaremicro.visualforecast.forecast; package com.flaremicro.visualforecast.forecast;
public class TownForecast { public class TownForecast {
public TownForecast(String townName, DayForecast[] dayForecast){ public TownForecast(String townName, DayForecast[] dayForecast) {
this.townName = townName; this.townName = townName;
this.dayForecast = dayForecast; this.dayForecast = dayForecast;
} }
private final String townName; private final String townName;
private final DayForecast[] dayForecast; private final DayForecast[] dayForecast;
private HourlyForecast[] hourlyForecast;
public void setHourlyForecast(HourlyForecast[] forecast) {
this.hourlyForecast = forecast;
}
public HourlyForecast[] getHourlyForecast() {
return this.hourlyForecast;
}
public DayForecast[] getDayForecast() { public DayForecast[] getDayForecast() {
return dayForecast; return dayForecast;
} }
public String getTownName() { public String getTownName() {
return townName; return townName;
} }

View File

@@ -31,6 +31,6 @@ public class RenderConstants {
public static final Color BG_PURPLE = new Color(0x2b29b3); public static final Color BG_PURPLE = new Color(0x2b29b3);
public static final Color BG_OORANGE = new Color(0xff8c00); public static final Color BG_ORANGE = new Color(0xff8c00);
public static final Color BG_BLUE = new Color(0x394aa8); public static final Color BG_BLUE = new Color(0x394aa8);
} }

View File

@@ -1,3 +1,3 @@
#VisualForecast 1000 Properties file. Functional provider must be set for successful boot! #VisualForecast 1000 Properties file. Functional provider must be set for successful boot!
#Thu Mar 07 16:27:03 PST 2024 #Fri Mar 08 21:30:25 PST 2024
forecast-provider-jar=CanadaDatamartProvider.jar forecast-provider-jar=MockForecastProvider.jar