Java tutorial
/* * Copyright (C) 2007-2012 GeoSolutions S.A.S. * http://www.geo-solutions.it * * GPLv3 + Classpath exception * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even 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. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.geobatch.destination.vulnerability; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.stats.Statistics; import it.geosolutions.jaiext.zonal.ZoneGeometry; import java.awt.image.RenderedImage; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections.ListUtils; import org.apache.commons.collections.MapUtils; import org.geotools.coverage.grid.GridGeometry2D; import org.jaitools.media.jai.zonalstats.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is responsible for managing the different types of Target (Human - NotHuman - GroundCoverage ) * providing a single API. * The abstraction is implemented by the 3 inner class that are instantiated with the getInstance method. * * @author DamianoG * */ public abstract class TargetManager { public static class TargetInfo { public TargetInfo(String id, GridGeometry2D gg2d, Double nodata, RenderedImage raster, TargetType type, Map vulnerabilityCfg, int pixelArea) { this.gg2d = gg2d; this.nodata = nodata; this.raster = raster; this.id = id; manager = TargetManager.createManager(id, type, vulnerabilityCfg, pixelArea); } public Double getNodata() { return nodata; } public RenderedImage getRaster() { return raster; } public TargetManager getManager() { return manager; } public GridGeometry2D getGG2D() { return gg2d; } public String getId() { return id; } GridGeometry2D gg2d; Double nodata; RenderedImage raster; String id; TargetManager manager; TargetInfo mergeWith(TargetInfo other) { if (manager instanceof GroundCoverageTarget && other.manager instanceof GroundCoverageTarget) { manager.pixelValues.putAll(other.manager.pixelValues); return this; } return null; } } private final static Logger LOGGER = LoggerFactory.getLogger(TargetManager.class); protected static Map<String, Double[]> allDistances; protected static List<Integer> copSuoloValues; static { /*allDistances = TargetPropertiesLoader.loadDistances(); TargetPropertiesLoader tpl = new TargetPropertiesLoader(); copSuoloValues = tpl.getAllCopSuoloValues();*/ } /** * Boolean indicating if the target is human or not */ protected boolean humanTarget; /** * The resolutions of the pixels */ protected int pixelArea; /** * The accepted distances for this Target. The initTargets() method is responsible for init it. */ protected Double[] distances; /** * The id of the target as specified in the properties file */ protected String targetID; /** * The value of copSuolo pixels. This is initialized (with the static list) just if the concrete class is of type GroundCoverage. * Otherwise it must be null. */ protected Map<Integer, String> pixelValues; private TargetManager(String targetID, Double[] distances, int pixelArea) { this.targetID = targetID; this.pixelArea = pixelArea <= 0 ? 100 : pixelArea; this.distances = distances; } /** * Handle the results and add them to the resultStatsMap provided as input. The band parameter is used for selecting the statistic associated with * the related target. * * @param results * @param statsMap * @param forceToZero * @param band */ public abstract void handleResults(List<Result> results, ResultStatsMap statsMap, boolean forceToZero); /** * Handle the results and add them to the resultStatsMap provided as input. The band parameter is used for selecting the statistic associated with * the related target. * * @param results * @param statsMap * @param forceToZero * @param band */ public abstract void handleResults(ZoneGeometry result, ResultStatsMap statsMap, boolean forceToZero, int band); /** * Check if the Target is Human or Not */ public boolean isHumanTarget() { return humanTarget; } /** * Check if the provided input distance is accepted by this target * * @param distance * @return */ public boolean isDistanceRelatedToTarget(Double distance) { return Arrays.asList(distances).contains(distance); } public Map<Integer, String> getPixelValues() { if (pixelValues == null) { return null; } return MapUtils.unmodifiableMap(pixelValues); } public List<Double> getDistances() { if (distances == null) { return null; } return ListUtils.unmodifiableList(Arrays.asList(distances)); } //************************************** // Concrete Targets Implementation //************************************** /** * In The rasters of Human Targets each pixel contains the number of the humans present in that area. * So basically we have to take the result of the stat SUM and store it in the result Map * * @author DamianoG * */ private static class HumanTarget extends TargetManager { /** * @param pixelArea */ public HumanTarget(String targetID, Double[] distances, int pixelArea) { super(targetID, distances, pixelArea); humanTarget = true; } @Override public void handleResults(List<Result> results, ResultStatsMap statsMap, boolean forceToZero) { for (Result el3 : results) { Double resSimple = (el3.getValue().equals(Double.NaN) ? 0d : el3.getValue()); // Long countSimple = el3.getNumOffered(); statsMap.addResult(targetID, resSimple, forceToZero); } } public void handleResults(List<ZoneGeometry> results, ResultStatsMap statsMap, boolean forceToZero, int band) { // Default class value int classId = 0; int zones = results.size(); for (int i = 0; i < zones; i++) { ZoneGeometry geometry = results.get(i); // Total statistics Map<Integer, Map<Integer, Map<Range, Statistics[]>>> totalStatistics = geometry.getTotalStats(); // Statistics associates to the selected band and the class Map<Range, Statistics[]> resultsPerRange = totalStatistics.get(band).get(classId); // Set of Ranges(if not used, it is only one object) Set<Range> ranges = resultsPerRange.keySet(); for (Range r : ranges) { // Selection of the statistic Statistics stat = resultsPerRange.get(r)[0]; // Sum of the values Double resSimple = (Double) (stat.getResult().equals(Double.NaN) ? 0d : stat.getResult()); // Addition of the result statsMap.addResult(targetID, resSimple, forceToZero); } } } @Override public void handleResults(ZoneGeometry result, ResultStatsMap statsMap, boolean forceToZero, int band) { // Default class value int classId = 0; // Total statistics Map<Integer, Map<Integer, Map<Range, Statistics[]>>> totalStatistics = result.getTotalStats(); // Statistics associates to the selected band and the class Map<Range, Statistics[]> resultsPerRange = totalStatistics.get(band).get(classId); // Set of Ranges(if not used, it is only one object) Set<Range> ranges = resultsPerRange.keySet(); for (Range r : ranges) { // Selection of the statistic Statistics stat = resultsPerRange.get(r)[0]; // Sum of the values Double resSimple = (Double) (stat.getResult().equals(Double.NaN) ? 0d : stat.getResult()); // Addition of the result statsMap.addResult(targetID, resSimple, forceToZero); } } } /** * In The rasters of NotHuman Targets each pixel that is different to NODATA represent a snippet of the area of that target * We want calculate the mq2 present inside a given ROI so we have to count the pixel used for calculate the stat sum and multiply that value for the resolution of the pixel * So basically we have to take the result of the stat SUM and store it in the result Map * * @author DamianoG * */ private static class NotHumanTarget extends TargetManager { /** * @param pixelArea */ public NotHumanTarget(String targetID, Double[] distances, int pixelArea) { super(targetID, distances, pixelArea); humanTarget = false; } @Override public void handleResults(List<Result> results, ResultStatsMap statsMap, boolean forceToZero) { for (Result el3 : results) { // Double resSimple = (el3.getValue().equals(Double.NaN)?0d:el3.getValue()); // TODO check if must be used numOffered or numAccepted for retrieve the number of valid (without NODATA) pixels used for the stats Long countSimple = el3.getNumAccepted(); statsMap.addResult(targetID, Double.valueOf(countSimple) * pixelArea, forceToZero); } } public void handleResults(List<ZoneGeometry> results, ResultStatsMap statsMap, boolean forceToZero, int band) { // Default class value int classId = 0; for (ZoneGeometry geometry : results) { // Total statistics Map<Integer, Map<Integer, Map<Range, Statistics[]>>> totalStatistics = geometry.getTotalStats(); // Statistics associates to the selected band and the class Map<Range, Statistics[]> resultsPerRange = totalStatistics.get(band).get(classId); // Set of Ranges(if not used, it is only one object) Set<Range> ranges = resultsPerRange.keySet(); for (Range r : ranges) { // Selection of the statistic Statistics stat = resultsPerRange.get(r)[0]; // Number of elements Long countSimple = stat.getNumSamples(); // Addition of the result statsMap.addResult(targetID, Double.valueOf(countSimple) * pixelArea, forceToZero); } } } @Override public void handleResults(ZoneGeometry result, ResultStatsMap statsMap, boolean forceToZero, int band) { // Default class value int classId = 0; // Total statistics Map<Integer, Map<Integer, Map<Range, Statistics[]>>> totalStatistics = result.getTotalStats(); // Statistics associates to the selected band and the class Map<Range, Statistics[]> resultsPerRange = totalStatistics.get(band).get(classId); // Set of Ranges(if not used, it is only one object) Set<Range> ranges = resultsPerRange.keySet(); for (Range r : ranges) { // Selection of the statistic Statistics stat = resultsPerRange.get(r)[0]; // Number of elements Long countSimple = stat.getNumSamples(); // Addition of the result statsMap.addResult(targetID, Double.valueOf(countSimple) * pixelArea, forceToZero); } } } /** * The GroundCoverageTarget is a special case of NotHumanTarget. * Basically in a single raster is stored more than one NotHuman target. * Depending on the value of the pixel it could refers to a target or another. * So before count the pixel we have to clusterize the results by the different pixel values * * @author DamianoG * */ private static class GroundCoverageTarget extends TargetManager { /** * @param pixelArea */ public GroundCoverageTarget(String targetID, Double[] distances, int pixelArea, Map targetCfg) { super(targetID, distances, pixelArea); pixelValues = new HashMap<Integer, String>(); pixelValues.put((Integer) targetCfg.get("GROUPVALUE"), targetID); humanTarget = false; } @Override public void handleResults(List<Result> results, ResultStatsMap statsMap, boolean forceToZero) { for (Result el3 : results) { Double resSimple = (el3.getValue().equals(Double.NaN) ? 0d : el3.getValue()); // Long countSimple = el3.getNumOffered(); Iterator rangeIter = el3.getRanges().iterator(); while (rangeIter.hasNext()) { Range range = (Range) rangeIter.next(); Number value = range.getMax(); if (resSimple != 0 && resSimple != Double.NaN) { statsMap.addResult(pixelValues.get(value.intValue()), Double.valueOf(resSimple / value.doubleValue()) * pixelArea, forceToZero); } else { statsMap.addResult(pixelValues.get(value.intValue()), 0d, true); } } } } @Override public void handleResults(ZoneGeometry result, ResultStatsMap statsMap, boolean forceToZero, int band) { return; } } /** * This method instantiate a concrete implementation of TargetManager parsing * the provided Target name and init the targetID. * * @param targetName * @param pixelArea if < 0 the default value is 100 * * @return a concrete implementation of TargetManager */ public static TargetManager createManager(String targetId, TargetType type, Map vulnerabilityCfg, int pixelArea) { if (targetId == null) { throw new IllegalArgumentException("targetId is null..."); } TargetManager manager = null; if (allDistances == null) { allDistances = VulnerabilityUtils.loadDistances(vulnerabilityCfg); } if (copSuoloValues == null) { copSuoloValues = VulnerabilityUtils.loadGroupValues(0, vulnerabilityCfg); } if (type == TargetType.COMPUTEPIXEL) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("HumanTarget Instantiated..."); } manager = new HumanTarget(targetId, allDistances.get(targetId), pixelArea); } else if (type == TargetType.GROUPED) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("GroundCoverage Instantiated..."); } manager = new GroundCoverageTarget(targetId, allDistances.get(targetId), pixelArea, (Map) vulnerabilityCfg.get(Integer.parseInt(targetId))); } else if (type == TargetType.COMPUTEAREA) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("NotHumanTarget Instantiated..."); } manager = new NotHumanTarget(targetId, allDistances.get(targetId), pixelArea); } else { throw new IllegalArgumentException( targetId + " is not a supported target, check the properties file..."); } return manager; } }