Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java @ 5818:a4ff4167be1e
Request feature info on all layers and show it as html if
the server does not return valid gml.
Non queryable layers produce an error message when the request
fails. This is good enough
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Wed, 24 Apr 2013 17:33:27 +0200 |
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 :