Looks pretty cool with the isobars, wind arrows and a wind heat map.
The images below are showing a storm front (Xynthia) hitting Western Europe.











Comments are welcome!
openmap.components=... geonamessearcher
geonamessearcher.class=GeoNamesSearcher
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import net.miginfocom.swing.MigLayout;
import org.apache.log4j.Logger;
import org.geonames.Toponym;
import org.geonames.ToponymSearchCriteria;
import org.geonames.ToponymSearchResult;
import org.geonames.WebService;
import com.bbn.openmap.event.CenterListener;
import com.bbn.openmap.event.CenterSupport;
import com.bbn.openmap.gui.OMToolComponent;
public class GeoNamesSearcher extends OMToolComponent {
private static final Logger log = Logger.getLogger(GeoNamesSearcher.class
.getName());
private JComboBox searchBox;
private CenterSupport centerDelegate;
private DefaultComboBoxModel searchBoxModel = new DefaultComboBoxModel();
public GeoNamesSearcher() {
centerDelegate = new CenterSupport(this);
setLayout(new MigLayout());
searchBox = new JComboBox(searchBoxModel);
searchBox.setEditable(true);
searchBox.setMaximumRowCount(25);
searchBox
.setToolTipText("Enter part of location to search for (and center to).");
searchBox.setRenderer(new DefaultListCellRenderer() {
@Override
public JComponent getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
if (value instanceof Toponym) {
Toponym toponym = (Toponym) value;
setText(toponym.getName() + " " + toponym.getCountryCode());
}
return this;
}
});
searchBox.setEditor(new BasicComboBoxEditor() {
@Override
public void setItem(Object anObject) {
if (anObject != null) {
if (anObject instanceof Toponym) {
Toponym toponym = (Toponym) anObject;
editor.setText(toponym.getName() + " "
+ toponym.getCountryCode());
// oldValue = anObject;
} else {
super.setItem(anObject);
}
} else {
editor.setText("");
}
}
});
searchBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
JComboBox cb = (JComboBox) evt.getSource();
Object selectedItem = cb.getSelectedItem();
if ("comboBoxEdited".equals(evt.getActionCommand())) {
// User has typed in a string; only possible with an
// editable combobox
try {
searchBoxModel.removeAllElements();
ToponymSearchCriteria searchCriteria = new ToponymSearchCriteria();
// searchCriteria.setCountryCode("DK");
searchCriteria.setQ((String) selectedItem);
ToponymSearchResult searchResult = WebService
.search(searchCriteria);
for (Toponym toponym : searchResult.getToponyms()) {
searchBoxModel.addElement(toponym);
}
if (searchResult.getTotalResultsCount() == 1) {
Toponym t = searchResult.getToponyms().get(0);
centerDelegate.fireCenter(t.getLatitude(), t
.getLongitude());
} else if (searchResult.getTotalResultsCount() > 1) {
searchBox.showPopup();
}
} catch (Exception e) {
log.error("", e);
}
} else if ("comboBoxChanged".equals(evt.getActionCommand())) {
// User has selected an item; it may be the same item
if (cb.getSelectedItem() instanceof Toponym) {
Toponym newItem = (Toponym) cb.getSelectedItem();
centerDelegate.fireCenter(newItem.getLatitude(),
newItem.getLongitude());
}
}
}
});
add(searchBox);
}
public synchronized void addCenterListener(CenterListener listener) {
centerDelegate.add(listener);
}
/**
* Remove a CenterListener
*
* @param listener
* CenterListener
*/
public synchronized void removeCenterListener(CenterListener listener) {
centerDelegate.remove(listener);
}
@Override
public void findAndInit(Object obj) {
if (obj instanceof CenterListener) {
addCenterListener((CenterListener) obj);
}
}
@Override
public void findAndUndo(Object obj) {
if (obj instanceof CenterListener) {
removeCenterListener((CenterListener) obj);
}
}
}

public class GPSLayer extends OMGraphicHandlerLayer {
private static String GPSDATA = "gpsData";
private static final double KT2MPS = 1852.0 / 3600.0;
private static final double speedVectorLengthInMinutes = 6;
private String gpsDataPath = "";
private float latitude, longitude, speed, course;
private OMGraphicList graphics = new OMGraphicList();;
private OMRect gpsPosition = new OMRect(0, 0, 0, 0, 10, 10);
private OMLine speedVector;
private OMText gpsText = new OMText(10, 20, "GPS Data",
OMText.JUSTIFY_LEFT);
private Timer timer;
public GPSLayer() {
gpsText.setFillPaint(Color.WHITE);
gpsText.setTextMatteColor(new Color(182, 235, 219));
gpsPosition.setFillPaint(Color.pink);
}
@Override
public void setProperties(String prefix, Properties props) {
super.setProperties(prefix, props);
gpsDataPath = props.getProperty(prefix + "." + GPSDATA);
// redraw every 5 secs
timer = new Timer(5000, this);
timer.start();
// emulate reading GPS data (threading issue here access to members not
// protected!)
new Thread(new Runnable() {
public void run() {
try {
BufferedReader in = new BufferedReader(new FileReader(
gpsDataPath));
String str;
while ((str = in.readLine()) != null) {
Thread.sleep(100);
if (str.startsWith("$GPRMC")) {
String[] fields = str.split(",");
// utc_date = fields[1];
double lat = Double.parseDouble(fields[3]);
double degrees = Math.floor((lat / 100.0));
double minute = (lat / 100.0) - degrees;
lat = (degrees) + ((minute * 100.0) / 60);
if (fields[4].equals("S"))
lat = -lat;
latitude = (float) lat;
double lon = Double.parseDouble(fields[5]);
degrees = Math.floor((lon / 100.0));
minute = (lon / 100.0) - degrees;
lon = (degrees) + ((minute * 100.0) / 60);
if (fields[6].equals("W"))
lon = -lon;
longitude = (float) lon;
speed = (float) (Double.parseDouble(fields[7]) * KT2MPS);
if (!fields[8].equals("")) {
course = (float) Double.parseDouble(fields[8]);
}
// could parse date but to lazy
// date = fields[9];
}
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public synchronized OMGraphicList prepare() {
gpsPosition.setLocation(latitude, longitude, -5, -5, 5, 5);
// calc. speed vector length using OM GIS functions
LatLonPoint startPos = new LatLonPoint(latitude, longitude);
float length = (float) Length.KM.toRadians(speedVectorLengthInMinutes
* ((speed * 3.6) / 60.0));
LatLonPoint endPos = startPos.getPoint(length, (float) ProjMath
.degToRad(course));
speedVector = new OMLine(startPos.getLatitude(), startPos
.getLongitude(), endPos.getLatitude(), endPos.getLongitude(),
OMLine.LINETYPE_STRAIGHT);
// vec.addArrowHead(OMArrowHead.ARROWHEAD_DIRECTION_FORWARD, 100, 3, 1);
speedVector.setLinePaint(Color.DARK_GRAY);
graphics.clear();
// order of add determines what is rendered on top
graphics.add(speedVector);
graphics.add(gpsPosition);
gpsText.setData(String.format("GPS Data\n%4.2f Km/h",
(speed * 3.60)));
graphics.add(gpsText);
graphics.project(getProjection());
return graphics;
}
@Override
public void actionPerformed(ActionEvent ae) {
doPrepare();
}
}
uc = new URL(gpsDataPath).openConnection(); // gps.gpsData=http://localhost:2244
InputStreamReader icr = new InputStreamReader(uc.getInputStream());
in = new BufferedReader(icr);
openmap.layers=gps graticule shapePolitical
openmap.startUpLayers=gps graticule shapePolitical
gps.class=GPSLayer
gps.prettyName=GPS Position
gps.gpsData=/tmp/gpslog.txt
$GPRMC,143346,A,5616.9232,N,01008.2504,E,074.6,011.3,110105,000.9,E,A*13
$GPRMC,143347,A,5616.9435,N,01008.2571,E,074.5,010.4,110105,000.9,E,A*14
$GPRMC,143348,A,5616.9638,N,01008.2632,E,074.4,009.5,110105,000.9,E,A*18
$GPRMC,143349,A,5616.9842,N,01008.2686,E,074.3,008.4,110105,000.9,E,A*12
public class FontPanel extends OMComponentPanel {
public FontPanel() {
}
@Override
public void findAndInit(Object obj) {
if (obj instanceof InformationDelegator) {
InformationDelegator delgator = (InformationDelegator) obj;
GridBagConstraints c = new GridBagConstraints();
c.weightx = 1;
c.weighty = 1;
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.HORIZONTAL;
c.insets = new Insets(0, 0, 0, 4);
Component statusPanel = DialogUtils.getChildNamed(delgator,
StatusLightPanel.class);
delgator.remove(statusPanel);
delgator.add(FontSizePanel.getPanel(), c);
delgator.add(statusPanel);
}
}
}
-Dswing.defaultlaf=org.jvnet.substance.skin.SubstanceCremeLookAndFeelClick here to see how this looks.