OpenStreetMapで天気予報地図
天気予報RSSとOpenStreetMapを利用して、天気予報地図を作ってみた。
処理の流れとしては、
1)WaypointPainterクラスのレンダラーにURLImageIconWaypointRenderクラスを設定する。
2)天気予報RSSを取得し、各地点の予報アイコンのURLを取得する。
3)URLImageIconWaypointクラスを生成し、WaypointPainterのSet
天気予報地点の緯度経度は、2009-05-23のGeocodingで取得したものをcitydata.xmlとしてまとめて使用した。
また、以下のライブラリが必要となる。
・SwingX、SwingX-WS、Informa
■ソースコード
ソースコードは、以下のとおり。なお、OpenStreetTileInfo.javaは、2009-06-02のものを使用している。
・OsmTest.java
package test; import java.awt.BorderLayout; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.WindowConstants; import org.jdesktop.swingx.JXMapKit; import org.jdesktop.swingx.mapviewer.DefaultTileFactory; import org.jdesktop.swingx.mapviewer.GeoPosition; public class OsmTest { private JFrame frame; private JXMapKit kit; public OsmTest(){ frame=new JFrame(); initFrame(); initMap(); Runnable r=new Runnable(){ public void run(){ WeatherChecker wc=new WeatherChecker( kit,getClass().getResource("citydata.xml")); wc.updateWeatherForcastRssList(); } }; new Thread(r).start(); } private void initFrame(){ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { int id=JOptionPane.showConfirmDialog( frame, "終了しますか?", "Info", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); if(id==JOptionPane.YES_OPTION){ frame.setVisible(false); System.exit(0); } } }); frame.getContentPane().setLayout(new BorderLayout()); frame.setTitle("OSM"); frame.setSize(640,480); } private void initMap(){ OpenStreetTileInfo info=new OpenStreetTileInfo(1,17,17,256,true,true, "http://tile.openstreetmap.org", "x", "y", "zoom"); DefaultTileFactory tile=new DefaultTileFactory(info); kit=new JXMapKit(); kit.setDefaultProvider(JXMapKit.DefaultProviders.OpenStreetMaps); kit.setDataProviderCreditShown(false); kit.setTileFactory(tile); kit.setAddressLocationShown(false); kit.setZoom(9); kit.setAddressLocation(new GeoPosition(34.6833,135.5)); kit.getMainMap().setRestrictOutsidePanning(true); kit.getMainMap().setHorizontalWrapped(false); kit.getMainMap().setDrawTileBorders(false); frame.getContentPane().add(kit.getMainMap(),BorderLayout.CENTER); } public static void main(String[] args){ OsmTest app=new OsmTest(); app.frame.setVisible(true); } }
・URLImageIconWaypoint.java
package test; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import javax.imageio.ImageIO; import org.jdesktop.swingx.mapviewer.GeoPosition; import org.jdesktop.swingx.mapviewer.Waypoint; public class URLImageIconWaypoint extends Waypoint { private BufferedImage img; public URLImageIconWaypoint(double latitude, double longitude,URL url) throws IOException{ super(latitude, longitude); img=ImageIO.read(url); } public URLImageIconWaypoint(GeoPosition coord,URL url) throws IOException{ super(coord); img=ImageIO.read(url); } public BufferedImage getImage(){ return img; } }
・URLImageIconWaypointRender.java
package test; import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import org.jdesktop.swingx.JXMapViewer; import org.jdesktop.swingx.mapviewer.Waypoint; import org.jdesktop.swingx.mapviewer.WaypointRenderer; public class URLImageIconWaypointRender implements WaypointRenderer { private static final AlphaComposite alpha= AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); @Override public boolean paintWaypoint(Graphics2D arg0, JXMapViewer arg1,Waypoint arg2) { if(arg2 instanceof URLImageIconWaypoint){ arg0.setComposite(alpha); URLImageIconWaypoint wp=(URLImageIconWaypoint)arg2; BufferedImage img=wp.getImage(); if(img==null)return false; int width=img.getWidth(); int height=img.getHeight(); arg0.drawImage(img, -width/2,-height/2,width, height, arg1); return true; }else{ return false; } } }
・WeatherChecker.java
package test; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.jdesktop.swingx.JXMapKit; import org.jdesktop.swingx.JXMapViewer; import org.jdesktop.swingx.mapviewer.Waypoint; import org.jdesktop.swingx.mapviewer.WaypointPainter; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import de.nava.informa.core.ChannelIF; import de.nava.informa.core.ItemIF; import de.nava.informa.impl.basic.ChannelBuilder; import de.nava.informa.parsers.FeedParser; public class WeatherChecker{ private Set<Waypoint> waypoints; private Map<String,double[]> latlng; private JXMapKit kit; public WeatherChecker(JXMapKit kit,URL url){ this.kit=kit; latlng=new HashMap<String,double[]>(); waypoints=new HashSet<Waypoint>(); WaypointPainter<JXMapViewer> wp=new WaypointPainter<JXMapViewer>(); wp.setWaypoints(waypoints); wp.setRenderer(new URLImageIconWaypointRender()); kit.getMainMap().setOverlayPainter(wp); buildMap(url); } private void buildMap(URL url){ try{ URLConnection conn= (URLConnection)url.openConnection(); conn.setRequestProperty("Accept-Language", "ja;q=0.7,en;q=0.3"); conn.connect(); DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); DocumentBuilder db=dbf.newDocumentBuilder(); Document doc=db.parse(conn.getInputStream()); NodeList list=doc.getChildNodes(); for(int i=0;i<list.getLength();i++){ Node node=list.item(i); parseNode(node); } }catch(MalformedURLException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); }catch(ParserConfigurationException e){ e.printStackTrace(); }catch(SAXException e){ e.printStackTrace(); } } private void parseNode(Node n){ if(n.getNodeName().equals("city")){ String[] val=n.getTextContent().split(","); latlng.put(val[0],new double[]{ Double.parseDouble(val[2]), Double.parseDouble(val[1])}); }else{ NodeList list=n.getChildNodes(); for(int i=0;i<list.getLength();i++){ Node node=list.item(i); parseNode(node); } } } public void updateWeatherForcastRssList(){ try{ DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); DocumentBuilder db=dbf.newDocumentBuilder(); URL url = new URL("http://weather.livedoor.com/forecast/rss/forecastmap.xml"); Document doc=db.parse(url.openStream()); NodeList list=doc.getChildNodes(); Node n=list.item(0); parse(n); }catch(Exception e){ e.printStackTrace(); } } private void parse(Node n){ NodeList list=n.getChildNodes(); for(int i=0;i<list.getLength();i++){ Node tmp=list.item(i); if(tmp.getNodeType()==3)continue; if(tmp.getNodeName().equals("city")){ NamedNodeMap map=tmp.getAttributes(); double[] pos=latlng.get( map.getNamedItem("title").getNodeValue()); String img=null; try{ URL url= new URL(map.getNamedItem("source").getNodeValue()); ChannelIF channel = FeedParser.parse(new ChannelBuilder(), url); Set<ItemIF> tv=channel.getItems(); for(ItemIF item : tv){ if(item.getTitle().contains("PR"))continue; img= item.getElementValues("image", new String[]{"url"})[0]; } if(img!=null){ final URLImageIconWaypoint wp =new URLImageIconWaypoint( pos[0],pos[1],new URL(img)); Runnable r=new Runnable(){ public void run(){ waypoints.add(wp); } }; javax.swing.SwingUtilities.invokeLater(r); } kit.getMainMap().repaint(); }catch(Exception e){ e.printStackTrace(); } } if(tmp.hasChildNodes()){ parse(tmp); } } } }
■実行結果
実行結果は、以下のとおり。