Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java @ 5240:9c024718bffb
WaterlevelParser: Use Wst-structures directly (instead of Waterlevel*).
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Tue, 12 Mar 2013 10:55:14 +0100 |
parents | f2e7f07f608d |
children |
line wrap: on
line source
package de.intevation.flys.artifacts; import java.util.ArrayList; import java.util.List; import java.util.NavigableMap; import org.apache.log4j.Logger; import org.w3c.dom.Document; import de.intevation.artifacts.Artifact; import de.intevation.artifacts.ArtifactFactory; import de.intevation.artifacts.CallMeta; import de.intevation.flys.artifacts.access.RangeAccess; import de.intevation.flys.artifacts.model.CrossSectionFacet; import de.intevation.flys.artifacts.model.FastCrossSectionLineFactory; import de.intevation.flys.model.FastCrossSectionLine; import de.intevation.flys.model.CrossSection; import de.intevation.flys.model.CrossSectionLine; import de.intevation.flys.artifacts.model.CrossSectionFactory; import de.intevation.flys.artifacts.states.StaticState; import de.intevation.artifactdatabase.state.Facet; import de.intevation.artifactdatabase.state.FacetActivity; import de.intevation.artifactdatabase.state.State; import de.intevation.flys.artifacts.services.CrossSectionKMService; /** * Artifact describing a cross-section. */ public class CrossSectionArtifact extends StaticFLYSArtifact { /** Name of Artifact. */ public static final String CS_ARTIFACT_NAME = "cross_section"; /** Name of state. */ public static final String STATIC_STATE_NAME = "state.cross_section"; /** Name of data item keeping the position. */ public static final String DATA_KM = "cross_section.km"; /** Name of data item keeping the database id of this c.s.. */ public static final String DATA_DBID = "cross_section.dbid"; /** Name of data item flagging whether we think that we are master. */ public static final String DATA_IS_MASTER = "cross_section.master?"; /** Name of data item flagging whether we are the newest. */ public static final String DATA_IS_NEWEST = "cross_section.newest?"; /** Name of data item storing the previous possible km. */ public static final String DATA_PREV_KM = "cross_section.km.previous"; /** Name of data item storing the next possible km. */ public static final String DATA_NEXT_KM = "cross_section.km.next"; /** Own logger. */ private static final Logger logger = Logger.getLogger(CrossSectionArtifact.class); static { // TODO: Move to configuration. FacetActivity.Registry.getInstance().register( CS_ARTIFACT_NAME, new FacetActivity() { @Override public Boolean isInitialActive( Artifact artifact, Facet facet, String outputName ) { if (artifact instanceof FLYSArtifact) { FLYSArtifact flys = (FLYSArtifact)artifact; String data = flys.getDataAsString(DATA_IS_NEWEST); return data != null && data.equals("1"); } return null; } }); } /** Return given name. */ @Override public String getName() { return CS_ARTIFACT_NAME; } /** Store ids, create a CrossSectionFacet. */ @Override public void setup( String identifier, ArtifactFactory factory, Object context, CallMeta callMeta, Document data) { logger.info("CrossSectionArtifact.setup"); super.setup(identifier, factory, context, callMeta, data); String ids = getDatacageIDValue(data); if (ids != null && ids.length() > 0) { addStringData(DATA_DBID, ids); logger.debug("CrossSectionArtifacts db-id: " + ids); } else { throw new IllegalArgumentException("No attribute 'ids' found!"); } List<Facet> fs = new ArrayList<Facet>(); CrossSection cs = CrossSectionFactory.getCrossSection( Integer.parseInt(ids)); List<CrossSectionLine> csls = cs.getLines(); if (!csls.isEmpty()) { CrossSectionLine csl = csls.get(0); // Find min-km of cross sections, // then set DATA_KM to min(DATA_KM, minCross). double dataKm = Double.valueOf(getDataAsString(DATA_KM)); if (dataKm < csl.getKm().doubleValue()) { addStringData(DATA_KM, csl.getKm().toString()); } } fs.add(new CrossSectionFacet(0, cs.getDescription())); // Find out if we are newest and become master if so. boolean isNewest = CrossSectionFactory.isNewest(cs); String newString = (isNewest) ? "1" : "0"; addStringData(DATA_IS_NEWEST, newString); addStringData(DATA_IS_MASTER, newString); StaticState state = (StaticState) getCurrentState(context); if (!fs.isEmpty()) { addFacets(getCurrentStateId(), fs); } } /** Copy km where master-artifact "starts". */ @Override protected void initialize( Artifact artifact, Object context, CallMeta callMeta) { FLYSArtifact flys = (FLYSArtifact) artifact; RangeAccess rangeAccess = new RangeAccess(flys, null); double[] range = rangeAccess.getKmRange(); double min = 0.0f; if (range != null && range.length > 0) { min = range[0]; } this.addStringData(DATA_KM, Double.toString(min)); } /** Returns next possible km for a cross-section. */ public Double getNextKm() { return getDataAsDouble(DATA_NEXT_KM); } /** Returns previous possible km for a cross-section. */ public Double getPrevKm() { return getDataAsDouble(DATA_PREV_KM); } /** * Create and return a new StaticState with charting output. */ @Override public State getCurrentState(Object cc) { final List<Facet> fs = getFacets(getCurrentStateId()); StaticState state = new StaticState(STATIC_STATE_NAME) { @Override public Object staticCompute(List<Facet> facets) { if (facets != null) { facets.addAll(fs); } return null; } }; state.addDefaultChartOutput("cross_section", fs); return state; } /** * Get a list containing the one and only State. * @param context ignored. * @return list with one and only state. */ @Override protected List<State> getStates(Object context) { ArrayList<State> states = new ArrayList<State>(); states.add(getCurrentState(context)); return states; } // TODO all data access needs proper caching. /** * Get a DataItem casted to int (0 if fails). */ public int getDataAsIntNull(String dataName) { String val = getDataAsString(dataName); try { return Integer.parseInt(val); } catch (NumberFormatException e) { logger.warn("Could not get data " + dataName + " as int", e); return 0; } } /** Returns database-id of cross-section (from data). */ protected int getDBID() { return getDataAsIntNull(DATA_DBID); } /** * Return position (km) from data, 0 if not found. */ protected double getKm() { String val = getDataAsString(DATA_KM); try { return Double.valueOf(val); } catch (NumberFormatException e) { logger.warn("Could not get data " + DATA_KM + " as double", e); return 0; } } /** Returns true if artifact is set to be a "master" (other facets will * refer to this). */ public boolean isMaster() { return !getDataAsString(DATA_IS_MASTER).equals("0"); } /** * Get points of Profile of cross section at given kilometer. * * @return an array holding coordinates of points of profile ( * in the form {{x1, x2} {y1, y2}} ). */ public double [][] getCrossSectionData() { logger.info("getCrossSectionData() for cross_section.km " + getDataAsString(DATA_KM)); FastCrossSectionLine line = searchCrossSectionLine(); return line != null ? line.fetchCrossSectionProfile() : null; } /** * Get CrossSectionLine spatially closest to what is specified in the data * "cross_section.km", null if considered too far. * * It also adds DataItems to store the next and previous (numerically) * values at which cross-section data was recorded. * * @return CrossSectionLine closest to "cross_section.km", might be null * if considered too far. */ public FastCrossSectionLine searchCrossSectionLine() { double TOO_FAR = 1d; CrossSection crossSection = CrossSectionFactory .getCrossSection(getDBID()); if (logger.isDebugEnabled()) { logger.debug("dbid " + getDBID() + " : " + crossSection); } NavigableMap<Double, Integer> kms = CrossSectionKMService .getKms(crossSection.getId()); Double wishKM = getKm(); Double floor = kms.floorKey(wishKM); Double ceil = kms.ceilingKey(wishKM); Double nextKm; Double prevKm; double floorD = floor != null ? Math.abs(floor - wishKM) : Double.MAX_VALUE; double ceilD = ceil != null ? Math.abs(ceil - wishKM) : Double.MAX_VALUE; double km; if (floorD < ceilD) { km = floor; } else { km = ceil; } // If we are too far from the wished km, return null. if (Math.abs(km - wishKM) > TOO_FAR) { return null; } // Store next and previous km. nextKm = kms.higherKey(km); prevKm = kms.lowerKey(km); if (prevKm == null) { prevKm = -1d; } if (nextKm == null) { nextKm = -1d; } addStringData(DATA_PREV_KM, prevKm.toString()); addStringData(DATA_NEXT_KM, nextKm.toString()); return FastCrossSectionLineFactory .getCrossSectionLine(crossSection, km); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :