Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java @ 5569:2a058dff9666
merge
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Fri, 05 Apr 2013 09:56:02 +0200 |
parents | 61f4d4164a30 |
children | 0cab1c884e72 |
line wrap: on
line source
package de.intevation.flys.artifacts.model; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.type.StandardBasicTypes; import org.w3c.dom.Document; import org.w3c.dom.Element; /** Generate Fixings Table chart. */ public class FixingsOverview implements Serializable { private static Logger log = Logger.getLogger(FixingsOverview.class); public static final double EPSILON = 1e-2; public static final String DATE_FORMAT = "dd.MM.yyyy"; public static final String SQL_RIVER_ID = "SELECT" + " id AS river_id," + " km_up " + "FROM rivers " + "WHERE" + " name = :name"; public static final String SQL_FIXINGS = "SELECT" + " id AS wst_id," + " description " + "FROM wsts " + "WHERE" + " river_id = :river_id AND kind = 2"; public static final String SQL_FIXING_COLUMNS = "SELECT" + " wc.id AS wst_column_id," + " ti.start_time AS start_time," + " wc.name AS name " + "FROM wst_columns wc" + " JOIN time_intervals ti ON wc.time_interval_id = ti.id " + "WHERE" + " wc.wst_id = :wst_id " + "ORDER BY position"; public static final String SQL_FIXING_COLUMN_Q_RANGES = "SELECT" + " wqr.q AS q," + " r.a AS start_km," + " r.b AS stop_km " + "FROM wst_column_q_ranges wcqr" + " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" + " JOIN ranges r ON wqr.range_id = r.id " + "WHERE" + " wcqr.wst_column_id = :column_id " + "ORDER BY r.a"; public static final String SQL_FIXING_COLUMN_KM_RANGE = "SELECT" + " MIN(position) AS start_km," + " MAX(position) AS stop_km " + "FROM" + " wst_column_values " + "WHERE" + " wst_column_id = :column_id"; public static class QRange extends Range { protected double q; public QRange() { } public QRange(double start, double end, double q) { super(start, end); this.q = q; } } // class QRange public static class SectorRange extends Range { protected int sector; public SectorRange() { } public SectorRange(SectorRange other) { start = other.start; end = other.end; sector = other.sector; } public SectorRange(Range range) { super(range); } public SectorRange(double start, double end, int sector) { super(start, end); this.sector = sector; } public int getSector() { return sector; } public void setSector(int sector) { this.sector = sector; } public boolean enlarge(SectorRange other) { if (sector == other.sector && Math.abs(end-other.start) < FixingsOverview.EPSILON) { end = other.end; return true; } return false; } } // class SectorRange public static class Fixing implements Serializable { public static final Comparator<Column> DATE_CMP = new Comparator<Column>() { @Override public int compare(Column a, Column b) { return a.startTime.compareTo(b.startTime); } }; public interface Filter { boolean accept(Column column); } // interface Filter public class Column extends Range { protected int columnId; protected Date startTime; protected String name; protected List<SectorRange> sectors; public Column() { } public Column(int columnId, Date startTime, String name) { this.columnId = columnId; this.startTime = startTime; this.name = name; sectors = new ArrayList<SectorRange>(); } public int getId() { return columnId; } public Fixing getFixing() { return Fixing.this; } public Date getStartTime() { return startTime; } public String getName() { return name; } public String getDescription() { return Fixing.this.description + "/" + name; } public List<SectorRange> getSectors() { return sectors; } public List<SectorRange> getSectors(Range range) { List<SectorRange> result = new ArrayList<SectorRange>(sectors.size()); for (SectorRange src: sectors) { SectorRange dst = new SectorRange(src); if (range == null || dst.clip(range)) { result.add(dst); } } return result; } public int findQSector(double km) { for (SectorRange sector: sectors) { if (sector.inside(km)) { return sector.getSector(); } } return -1; } public void buildSectors( GaugeFinder gaugeFinder, List<QRange> qRanges ) { for (QRange qRange: qRanges) { for (GaugeRange gRange: gaugeFinder.getGauges()) { SectorRange sector = new SectorRange(qRange); if (!sector.clip(gRange)) { continue; } sector.setSector(gRange.classify(qRange.q)); if (sectors.isEmpty() || !sectors.get(sectors.size()-1).enlarge(sector)) { sectors.add(sector); } } // for all gauges } // for all Q ranges } public void loadKmRange(SQLQuery query) { query.setInteger("column_id", columnId); List<Object []> kms = query.list(); if (kms.isEmpty()) { log.warn("No km range for column " + columnId + "."); } else { Object [] obj = kms.get(0); start = (Double)obj[0]; end = (Double)obj[1]; } } public void loadQRanges( SQLQuery query, GaugeFinder gaugeFinder ) { query.setInteger("column_id", columnId); List<Object []> list = query.list(); List<QRange> qRanges = new ArrayList<QRange>(list.size()); for (Object [] row: list) { double q = (Double)row[0]; double start = (Double)row[1]; double end = (Double)row[2]; QRange qRange = new QRange(start, end, q); if (qRange.clip(this)) { qRanges.add(qRange); } } buildSectors(gaugeFinder, qRanges); } } // class Column protected int wstId; protected String description; protected List<Column> columns; public Fixing() { } public int getId() { return wstId; } public String getDescription() { return description; } public Fixing(int wstId, String description) { this.wstId = wstId; this.description = description; columns = new ArrayList<Column>(); } public void loadColumns(SQLQuery query) { query.setInteger("wst_id", wstId); List<Object []> list = query.list(); for (Object [] row: list) { int columnId = (Integer)row[0]; Date startTime = (Date) row[1]; String name = (String) row[2]; columns.add(new Column(columnId, startTime, name)); } } public void loadColumnsKmRange(SQLQuery query) { for (Column column: columns) { column.loadKmRange(query); } } public void adjustExtent(Range extent) { for (Column column: columns) { extent.extend(column); } } public void loadColumnsQRanges( SQLQuery query, GaugeFinder gaugeFinder ) { for (Column column: columns) { column.loadQRanges(query, gaugeFinder); } } public void addAllColumns( List<Column> allColumns, Range range, Filter filter ) { for (Column column: columns) { if ((range == null || column.intersects(range)) && (filter == null || filter.accept(column))) { allColumns.add(column); } } } } // class Fixing protected String riverName; protected int riverId; protected boolean isKmUp; protected List<Fixing> fixings; protected Range extent; public FixingsOverview() { fixings = new ArrayList<Fixing>(); extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); } public FixingsOverview(String riverName) { this(); this.riverName = riverName; } protected boolean loadRiver(Session session) { SQLQuery query = session.createSQLQuery(SQL_RIVER_ID) .addScalar("river_id", StandardBasicTypes.INTEGER) .addScalar("km_up", StandardBasicTypes.BOOLEAN); query.setString("name", riverName); List<Object []> list = query.list(); if (list.isEmpty()) { log.warn("No river '" + riverName + "' found."); return false; } Object [] row = list.get(0); riverId = (Integer)row[0]; isKmUp = (Boolean)row[1]; return true; } protected void loadFixings(Session session) { SQLQuery query = session.createSQLQuery(SQL_FIXINGS) .addScalar("wst_id", StandardBasicTypes.INTEGER) .addScalar("description", StandardBasicTypes.STRING); query.setInteger("river_id", riverId); List<Object []> list = query.list(); if (list.isEmpty()) { log.warn("River " + riverId + " has no fixings."); // Its pretty fine to have no fixings. } for (Object [] row: list) { int wstId = (Integer)row[0]; String description = (String) row[1]; Fixing fixing = new Fixing(wstId, description); fixings.add(fixing); } } protected void loadFixingsColumns(Session session) { SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS) .addScalar("wst_column_id", StandardBasicTypes.INTEGER) .addScalar("start_time", StandardBasicTypes.DATE) .addScalar("name", StandardBasicTypes.STRING); for (Fixing fixing: fixings) { fixing.loadColumns(query); } } protected void loadFixingsColumnsKmRange(Session session) { SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE) .addScalar("start_km", StandardBasicTypes.DOUBLE) .addScalar("stop_km", StandardBasicTypes.DOUBLE); for (Fixing fixing: fixings) { fixing.loadColumnsKmRange(query); } } protected void loadFixingsColumnsQRanges( Session session, GaugeFinder gaugeFinder ) { SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES) .addScalar("q", StandardBasicTypes.DOUBLE) .addScalar("start_km", StandardBasicTypes.DOUBLE) .addScalar("stop_km", StandardBasicTypes.DOUBLE); for (Fixing fixing: fixings) { fixing.loadColumnsQRanges(query, gaugeFinder); } } protected void adjustExtent() { for (Fixing fixing: fixings) { fixing.adjustExtent(extent); } } public boolean load(Session session) { if (!loadRiver(session)) { return false; } GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); GaugeFinder gaugeFinder = gff.getGaugeFinder(riverId, isKmUp); if (gaugeFinder == null) { return false; } loadFixings(session); loadFixingsColumns(session); loadFixingsColumnsKmRange(session); adjustExtent(); loadFixingsColumnsQRanges(session, gaugeFinder); return true; } public static final Range FULL_EXTENT = new Range(-Double.MAX_VALUE, Double.MAX_VALUE); public static final Fixing.Filter ACCEPT = new Fixing.Filter() { @Override public boolean accept(Fixing.Column column) { return true; } }; public static class NotFilter implements Fixing.Filter { protected Fixing.Filter child; public NotFilter(Fixing.Filter child) { this.child = child; } @Override public boolean accept(Fixing.Column column) { return !child.accept(column); } } // class NotFilter public static abstract class ComponentFilter implements Fixing.Filter { protected List<Fixing.Filter> children; public ComponentFilter() { children = new ArrayList<Fixing.Filter>(); } public ComponentFilter(List<Fixing.Filter> children) { this.children = children; } public ComponentFilter add(Fixing.Filter filter) { children.add(filter); return this; } } // class ComponentFilter public static class OrFilter extends ComponentFilter { public OrFilter() { } public OrFilter(List<Fixing.Filter> children) { super(children); } @Override public boolean accept(Fixing.Column column) { for (Fixing.Filter child: children) { if (child.accept(column)) { return true; } } return false; } } // class OrFilter public static class AndFilter extends ComponentFilter { public AndFilter() { } public AndFilter(List<Fixing.Filter> children) { super(children); } @Override public boolean accept(Fixing.Column column) { for (Fixing.Filter child: children) { if (!child.accept(column)) { return false; } } return true; } } // class AndFilter public static class IdFilter implements Fixing.Filter { protected int columnId; public IdFilter(int columnId) { this.columnId = columnId; } @Override public boolean accept(Fixing.Column column) { return column.getId() == columnId; } } // class IdFilter public static class IdsFilter implements Fixing.Filter { protected int [] columnIds; public IdsFilter(int [] columnIds) { this.columnIds = columnIds; } @Override public boolean accept(Fixing.Column column) { int cid = column.getId(); for (int i = columnIds.length-1; i >= 0; --i) { if (columnIds[i] == cid) { return true; } } return false; } } // class IdFilter public static class DateFilter implements Fixing.Filter { protected Date date; public DateFilter(Date date) { this.date = date; } @Override public boolean accept(Fixing.Column column) { return date.equals(column.getStartTime()); } } // class DateFilter public static class DateRangeFilter implements Fixing.Filter { protected Date start; protected Date end; public DateRangeFilter(Date start, Date end) { this.start = start; this.end = end; } @Override public boolean accept(Fixing.Column column) { Date date = column.getStartTime(); return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; } } // class DateRangeFilter public static class SectorFilter implements Fixing.Filter { protected int sector; public SectorFilter(int sector) { this.sector = sector; } @Override public boolean accept(Fixing.Column column) { for (SectorRange s: column.getSectors()) { if (s.getSector() == sector) { return true; } } return false; } } // class SectorFilter public static class SectorRangeFilter implements Fixing.Filter { protected int min; protected int max; public SectorRangeFilter(int min, int max) { this.min = Math.min(min, max); this.max = Math.max(min, max); } @Override public boolean accept(Fixing.Column column) { for (SectorRange s: column.getSectors()) { int v = s.getSector(); if (v < min || v > max) { return false; } } return true; } } // class SectorRangeFilter public static class KmFilter implements Fixing.Filter { protected double km; public KmFilter(double km) { this.km = km; } @Override public boolean accept(Fixing.Column column) { for (SectorRange s: column.getSectors()) { if (s.inside(km)) { return true; } } return false; } } // class KmFilter public void generateOverview(Document document) { generateOverview(document, FULL_EXTENT, ACCEPT); } public List<Fixing.Column> filter(Range range, Fixing.Filter filter) { List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>(); for (Fixing fixing: fixings) { fixing.addAllColumns(allColumns, range, filter); } Collections.sort(allColumns, Fixing.DATE_CMP); return allColumns; } protected static Range realRange(List<Fixing.Column> columns) { Range range = null; for (Fixing.Column column: columns) { if (range == null) { range = new Range(column); } else { range.extend(column); } } return range; } protected Element intersectingGauges(Document document, Range range) { Element gauges = document.createElement("gauges"); if (range == null) { return gauges; } GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); GaugeFinder gf = gff.getGaugeFinder(riverId, isKmUp); if (gf == null) { return gauges; } for (GaugeRange gr: gf.getGauges()) { if (gr.intersects(range)) { Element gauge = document.createElement("gauge"); gauge.setAttribute("from", String.valueOf(gr.getStart())); gauge.setAttribute("to", String.valueOf(gr.getEnd())); gauge.setAttribute("name", gr.getName()); gauges.appendChild(gauge); } } return gauges; } /** Populate document with fixings, filtered by range and filter. */ public void generateOverview( Document document, Range range, Fixing.Filter filter ) { List<Fixing.Column> allColumns = filter(range, filter); Element fixingsElement = document.createElement("fixings"); Element riverElement = document.createElement("river"); riverElement.setAttribute("from", String.valueOf(extent.start)); riverElement.setAttribute("to", String.valueOf(extent.end)); riverElement.setAttribute("rid", String.valueOf(riverId)); riverElement.setAttribute("name", riverName); fixingsElement.appendChild(riverElement); fixingsElement.appendChild( intersectingGauges( document, realRange(allColumns))); SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); Element esE = document.createElement("events"); for (Fixing.Column column: allColumns) { List<SectorRange> sectors = column.getSectors(range); if (!sectors.isEmpty()) { Element eE = document.createElement("event"); eE.setAttribute("description", String.valueOf(column.getDescription())); eE.setAttribute("cid", String.valueOf(column.columnId)); eE.setAttribute("date", df.format(column.startTime)); for (SectorRange sector: sectors) { Element sE = document.createElement("sector"); sE.setAttribute("from", String.valueOf(sector.start)); sE.setAttribute("to", String.valueOf(sector.end)); sE.setAttribute("class", String.valueOf(sector.sector)); eE.appendChild(sE); } esE.appendChild(eE); } } fixingsElement.appendChild(esE); document.appendChild(fixingsElement); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :