Java tutorial
/** * Copyright (C) 2012 * by 52 North Initiative for Geospatial Open Source Software GmbH * * Contact: Andreas Wytzisk * 52 North Initiative for Geospatial Open Source Software GmbH * Martin-Luther-King-Weg 24 * 48155 Muenster, Germany * info@52north.org * * This program is free software; you can redistribute and/or modify it under * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. * * This program is distributed WITHOUT ANY WARRANTY; even without the implied * WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program (see gnu-gpl v2.txt). If not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA or * visit the Free Software Foundation web page, http://www.fsf.org. */ package org.n52.oxf.render.sos; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickMarkPosition; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.Second; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.n52.oxf.adapter.ParameterContainer; import org.n52.oxf.adapter.ParameterShell; import org.n52.oxf.context.ContextBoundingBox; import org.n52.oxf.feature.OXFFeature; import org.n52.oxf.feature.OXFFeatureCollection; import org.n52.oxf.feature.sos.ObservationSeriesCollection; import org.n52.oxf.feature.sos.ObservedValueTuple; import org.n52.oxf.ows.capabilities.IBoundingBox; import org.n52.oxf.render.IFeatureDataRenderer; import org.n52.oxf.render.StaticVisualization; import org.n52.oxf.valueDomains.time.ITimePosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Point; /** * * @author <a href="mailto:broering@52north.org">Arne Broering</a> * */ public class TimeSeriesMapChartRenderer implements IFeatureDataRenderer { private static final Logger LOGGER = LoggerFactory.getLogger(TimeSeriesMapChartRenderer.class); protected static final float CHART_WIDTH = 150; protected static final float CHART_HEIGHT = 160; protected static final int X_SHIFT = -5; protected static final int Y_SHIFT = -10; private ObservationSeriesCollection obsValues4FOI = null; private Map<OXFFeature, Plot> chartCache; private Set<OXFFeature> selectedFeaturesCache = null; /** * * @param featuresWithCharts * the Features of Interest for which a chart shall be renderered. */ public TimeSeriesMapChartRenderer() { super(); chartCache = new HashMap<OXFFeature, Plot>(); } /** * @param observationCollection * @param screenW * @param screenH * @param bbox * @param selectedFeatures * the Features of Interest for which a chart shall be renderered. */ public StaticVisualization renderLayer(OXFFeatureCollection observationCollection, ParameterContainer paramCon, int screenW, int screenH, IBoundingBox bbox, Set<OXFFeature> selectedFeatures) { if (selectedFeaturesCache == null) { selectedFeaturesCache = selectedFeatures; } // before starting to render --> run garbageCollection Runtime.getRuntime().gc(); LOGGER.info("Garbage Collection done."); // -- String[] observedProperties; // which observedProperty has been used?: ParameterShell observedPropertyPS = paramCon.getParameterShellWithServiceSidedName("observedProperty"); if (observedPropertyPS.hasMultipleSpecifiedValues()) { observedProperties = observedPropertyPS.getSpecifiedTypedValueArray(String[].class); } else if (observedPropertyPS.hasSingleSpecifiedValue()) { observedProperties = new String[] { (String) observedPropertyPS.getSpecifiedValue() }; } else { throw new IllegalArgumentException("no observedProperties found."); } // find tuples: if (obsValues4FOI == null) { obsValues4FOI = new ObservationSeriesCollection(observationCollection, selectedFeaturesCache, observedProperties, true); } ContextBoundingBox contextBBox = new ContextBoundingBox(bbox); BufferedImage image = new BufferedImage(screenW, screenH, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); // draw white background: g.setColor(Color.WHITE); g.fillRect(0, 0, screenW, screenH); g.setColor(Color.BLACK); for (OXFFeature chartFeature : selectedFeaturesCache) { // // CACHING: create Plot for each "chart feature" and add it to the cache: // if (!chartCache.containsKey(chartFeature)) { Map<ITimePosition, ObservedValueTuple> timeMap = obsValues4FOI.getAllTuples(chartFeature); // draw a chart if there are tuples for the chartFeature available: if (timeMap != null) { XYPlot chart = drawChart4FOI(chartFeature.getID(), timeMap); chartCache.put(chartFeature, chart); } } // // draw the plots (which are in the cache): // Point pRealWorld = (Point) chartFeature.getGeometry(); java.awt.Point pScreen = ContextBoundingBox.realworld2Screen(contextBBox.getActualBBox(), screenW, screenH, new Point2D.Double(pRealWorld.getCoordinate().x, pRealWorld.getCoordinate().y)); XYPlot cachedPlot = (XYPlot) chartCache.get(chartFeature); // if there is a plot in the cache for the chartFeature -> draw it: if (cachedPlot != null) { cachedPlot.getRangeAxis().setRange((Double) obsValues4FOI.getMinimum(0), (Double) obsValues4FOI.getMaximum(0)); cachedPlot.draw(g, new Rectangle2D.Float(pScreen.x + X_SHIFT, pScreen.y + Y_SHIFT, CHART_WIDTH, CHART_HEIGHT), null, null, null); } else { g.drawString("No data available", pScreen.x + X_SHIFT, pScreen.y + Y_SHIFT); } // draw point of feature: g.fillOval(pScreen.x - (FeatureGeometryRenderer.DOT_SIZE_POINT / 2), pScreen.y - (FeatureGeometryRenderer.DOT_SIZE_POINT / 2), FeatureGeometryRenderer.DOT_SIZE_POINT, FeatureGeometryRenderer.DOT_SIZE_POINT); } return new StaticVisualization(image); } /** * The resulting chart consists a TimeSeries for each FeatureOfInterest contained in the * observationCollection. * * @param foiIdArray * the IDs of the FeaturesOfInterest whose Observations shall be rendered * @param observationCollection * @return */ protected XYPlot drawChart4FOI(String foiID, Map<ITimePosition, ObservedValueTuple> timeMap) { TimeSeriesCollection dataset = new TimeSeriesCollection(); TimeSeries timeSeries = new TimeSeries(foiID, Second.class); for (ITimePosition timePos : timeMap.keySet()) { Number value = (Number) timeMap.get(timePos).getValue(0); timeSeries.add( new Second(new Float(timePos.getSecond()).intValue(), timePos.getMinute(), timePos.getHour(), timePos.getDay(), timePos.getMonth(), new Long(timePos.getYear()).intValue()), value); } dataset.addSeries(timeSeries); dataset.setDomainIsPointsInTime(true); // // create Plot: // XYPlot plot = new XYPlot(); plot.setDataset(dataset); plot.setBackgroundPaint(Color.white); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(); renderer.setBaseShapesVisible(false); plot.setRenderer(renderer); DateAxis dateAxis = new DateAxis(); dateAxis.setTickMarkPosition(DateTickMarkPosition.START); dateAxis.setTickMarksVisible(true); dateAxis.setVerticalTickLabels(true); dateAxis.setDateFormatOverride(new SimpleDateFormat("dd'.'MM'.'")); plot.setDomainAxis(dateAxis); plot.setRangeAxis(new NumberAxis()); return plot; } /** * @return a plain text description of this Renderer. */ public String getDescription() { return "TimeSeriesMapChartRenderer - draws small time series charts into a map"; } public String toString() { return getDescription(); } /** * @return the type of the service whose data can be rendered with this ServiceRenderer. In this case * "OGC:SOS" will be returned. */ public String getServiceType() { return "OGC:SOS"; } /** * @return the versions of the services whose data can be rendered with this ServiceRenderer. In this case * {"1.0.0"} will be returned. */ public String[] getSupportedVersions() { return new String[] { "0.0.0" }; } }