teichmann@5844: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5844: * Software engineering by Intevation GmbH teichmann@5844: * teichmann@5992: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5844: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5992: * documentation coming with Dive4Elements River for details. teichmann@5844: */ teichmann@5844: teichmann@5829: package org.dive4elements.river.model; sascha@167: teichmann@5829: import org.dive4elements.river.backend.SessionHolder; christian@4809: sascha@167: import java.io.Serializable; ingo@465: import java.math.BigDecimal; sascha@768: import java.math.MathContext; christian@4809: import java.util.Comparator; christian@4809: import java.util.List; christian@4809: import java.util.Map; christian@4809: import java.util.TreeMap; ingo@465: christian@4809: import javax.persistence.Column; sascha@168: import javax.persistence.Entity; christian@4809: import javax.persistence.GeneratedValue; christian@4809: import javax.persistence.GenerationType; sascha@168: import javax.persistence.Id; christian@4809: import javax.persistence.JoinColumn; sascha@174: import javax.persistence.OneToMany; ingo@2347: import javax.persistence.OneToOne; bjoern@4262: import javax.persistence.OrderBy; christian@4809: import javax.persistence.SequenceGenerator; christian@4809: import javax.persistence.Table; sascha@168: christian@4809: import org.hibernate.Query; ingo@472: import org.hibernate.Session; ingo@472: ingo@472: sascha@168: @Entity sascha@168: @Table(name = "rivers") sascha@167: public class River sascha@167: implements Serializable sascha@167: { sascha@768: public static final MathContext PRECISION = new MathContext(6); sascha@768: sascha@2383: public static final double EPSILON = 1e-5; sascha@2383: christian@4809: public static final Comparator KM_CMP = new Comparator() { sascha@2383: @Override sascha@2383: public int compare(Double a, Double b) { sascha@2383: double diff = a - b; sascha@2383: if (diff < -EPSILON) return -1; sascha@2383: if (diff > EPSILON) return +1; sascha@2383: return 0; sascha@2383: } sascha@2383: }; sascha@2383: sascha@168: private Integer id; sascha@167: sascha@3946: private Long officialNumber; sascha@3946: sascha@168: private String name; sascha@167: sascha@505: private boolean kmUp; sascha@505: sascha@174: private List gauges; sascha@174: bjoern@4245: private List measurementstations; bjoern@4245: ingo@2347: private Unit wstUnit; ingo@2347: sascha@168: @Id sascha@168: @SequenceGenerator( sascha@171: name = "SEQUENCE_RIVERS_ID_SEQ", sascha@169: sequenceName = "RIVERS_ID_SEQ", sascha@169: allocationSize = 1) sascha@168: @GeneratedValue( sascha@168: strategy = GenerationType.SEQUENCE, sascha@171: generator = "SEQUENCE_RIVERS_ID_SEQ") sascha@168: @Column(name = "id") sascha@168: public Integer getId() { sascha@168: return id; sascha@168: } sascha@168: sascha@168: public void setId(Integer id) { sascha@167: this.id = id; sascha@167: } sascha@167: sascha@3946: @Column(name = "official_number") sascha@3946: public Long getOfficialNumber() { sascha@3946: return officialNumber; sascha@3946: } sascha@3946: sascha@3946: public void setOfficialNumber(Long officialNumber) { sascha@3946: this.officialNumber = officialNumber; sascha@3946: } sascha@3946: sascha@168: @Column(name = "name") sascha@168: public String getName() { sascha@168: return name; sascha@167: } sascha@167: sascha@167: public void setName(String name) { sascha@167: this.name = name; sascha@167: } sascha@167: sascha@505: @Column(name = "km_up") sascha@505: public boolean getKmUp() { sascha@505: return kmUp; sascha@505: } sascha@505: sascha@505: public void setKmUp(boolean kmUp) { sascha@505: this.kmUp = kmUp; sascha@505: } sascha@505: sascha@167: public River() { sascha@167: } sascha@169: ingo@2347: public River(String name, Unit wstUnit) { ingo@2347: this.name = name; ingo@2347: this.wstUnit = wstUnit; sascha@169: } sascha@174: sascha@174: @OneToMany sascha@174: @JoinColumn(name="river_id") sascha@174: public List getGauges() { sascha@174: return gauges; sascha@174: } sascha@174: sascha@174: public void setGauges(List gauges) { sascha@174: this.gauges = gauges; sascha@174: } sascha@188: ingo@2347: bjoern@4245: @OneToMany bjoern@4262: @OrderBy("station") bjoern@4245: @JoinColumn(name="river_id") bjoern@4245: public List getMeasurementStations() { bjoern@4245: return measurementstations; bjoern@4245: } bjoern@4245: bjoern@4245: public void setMeasurementStations(List mstations) { bjoern@4245: this.measurementstations = mstations; bjoern@4245: } bjoern@4245: ingo@2347: @OneToOne ingo@2347: @JoinColumn(name = "wst_unit_id" ) ingo@2347: public Unit getWstUnit() { ingo@2347: return wstUnit; ingo@2347: } ingo@2347: ingo@2347: public void setWstUnit(Unit wstUnit) { ingo@2347: this.wstUnit = wstUnit; ingo@2347: } ingo@2347: ingo@2347: ingo@2347: christian@4809: @Override sascha@188: public String toString() { sascha@188: return name != null ? name : ""; sascha@188: } ingo@465: ingo@472: ingo@472: /** ingo@488: * This method returns the gauges that intersect with a and ingo@488: * b, ingo@488: * ingo@488: * @param a A start point. ingo@488: * @param b An end point. ingo@488: * ingo@488: * @return the intersecting gauges. ingo@488: */ ingo@488: public List determineGauges(double a, double b) { ingo@488: Session session = SessionHolder.HOLDER.get(); ingo@488: sascha@756: if (a > b) { double t = a; a = b; b = t; } sascha@756: ingo@488: Query query = session.createQuery( ingo@488: "from Gauge where river=:river " + teichmann@5992: "and not " + teichmann@5880: "((:b < least(range.a, range.b)) or" + teichmann@5992: " (:a > greatest(range.a, range.b)))" + teichmann@5880: "order by a"); ingo@488: query.setParameter("river", this); sascha@769: query.setParameter("a", new BigDecimal(a, PRECISION)); sascha@769: query.setParameter("b", new BigDecimal(b, PRECISION)); ingo@488: ingo@488: return query.list(); ingo@488: } ingo@488: sascha@769: public Gauge maxOverlap(double a, double b) { sascha@769: List gauges = determineGauges(a, b); sascha@769: if (gauges == null) { sascha@769: return null; sascha@769: } sascha@769: sascha@769: if (a > b) { double t = a; a = b; b = t; } sascha@769: sascha@769: double max = -Double.MAX_VALUE; sascha@769: sascha@769: Gauge result = null; sascha@769: sascha@769: for (Gauge gauge: gauges) { sascha@769: Range r = gauge.getRange(); sascha@769: double c = r.getA().doubleValue(); sascha@769: double d = r.getB().doubleValue(); sascha@769: teichmann@5878: if (c > d) { double t = c; c = d; d = t; } teichmann@5878: sascha@769: double start = c >= a ? c : a; sascha@769: double stop = d <= b ? d : b; sascha@769: sascha@769: double length = stop - start; sascha@769: sascha@769: if (length > max) { sascha@769: max = length; sascha@769: result = gauge; sascha@769: } sascha@769: } sascha@769: sascha@769: return result; sascha@769: } sascha@769: sascha@767: public Gauge determineGaugeByName(String name) { sascha@767: Session session = SessionHolder.HOLDER.get(); sascha@767: Query query = session.createQuery( sascha@767: "from Gauge where river=:river and name=:name"); sascha@767: query.setParameter("river", this); sascha@767: query.setParameter("name", name); sascha@767: List gauges = query.list(); sascha@767: return gauges.isEmpty() ? null : gauges.get(0); sascha@767: } sascha@767: sascha@764: public Gauge determineGaugeByPosition(double p) { sascha@764: Session session = SessionHolder.HOLDER.get(); sascha@764: Query query = session.createQuery( sascha@768: "from Gauge g where river=:river " + teichmann@5992: "and :p between " + teichmann@5878: "least(g.range.a, g.range.b) and " + teichmann@5878: "greatest(g.range.a, g.range.b)"); sascha@764: query.setParameter("river", this); sascha@768: query.setParameter("p", new BigDecimal(p, PRECISION)); sascha@764: List gauges = query.list(); sascha@764: return gauges.isEmpty() ? null : gauges.get(0); sascha@764: } sascha@764: sascha@757: public Gauge determineGaugeByStation(double a, double b) { sascha@757: sascha@757: if (a > b) { double t = a; a = b; b = t; } sascha@757: sascha@757: Session session = SessionHolder.HOLDER.get(); sascha@757: sascha@757: Query query = session.createQuery( sascha@757: "from Gauge where river.id=:river " + sascha@757: "and station between :a and :b"); sascha@757: query.setParameter("river", getId()); sascha@757: query.setParameter("a", new BigDecimal(a)); sascha@757: query.setParameter("b", new BigDecimal(b)); sascha@757: sascha@757: List gauges = query.list(); sascha@757: return gauges.isEmpty() ? null : gauges.get(0); sascha@757: } sascha@757: bjoern@3794: public double[] determineMinMaxQ() { bjoern@3794: Session session = SessionHolder.HOLDER.get(); bjoern@3794: bjoern@3794: Query query = session.createQuery( bjoern@3795: "select min(wqr.q) as min, max(wqr.q) as max " + bjoern@3795: "from Wst as w " + bjoern@3795: "join w.columns as wc " + bjoern@3795: "join wc.columnQRanges as wcqr " + bjoern@3795: "join wcqr.wstQRange as wqr " + bjoern@3795: "where w.kind = 0 and river_id = :river"); bjoern@3794: bjoern@3794: query.setParameter("river", getId()); bjoern@3794: teichmann@5878: double minmax[] = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE }; bjoern@3794: bjoern@3794: List results = query.list(); bjoern@3794: bjoern@3794: if (!results.isEmpty()) { bjoern@3794: Object[] arr = (Object[]) results.get(0); bjoern@3794: BigDecimal minq = (BigDecimal)arr[0]; bjoern@3794: BigDecimal maxq = (BigDecimal)arr[1]; bjoern@3794: minmax[0] = minq.doubleValue(); bjoern@3794: minmax[1] = maxq.doubleValue(); bjoern@3794: } bjoern@3794: bjoern@3794: return minmax; bjoern@3794: } bjoern@3794: ingo@488: ingo@488: /** ingo@472: * This method returns the first gauge that is intersected by a and aheinecke@6106: * b, but which possibly does not ends with a or starts with b. ingo@472: * ingo@472: * @param a A start point. ingo@472: * @param b An end point. ingo@472: * aheinecke@6106: * @return the first intersecting gauge that does not border with a or b, aheinecke@6106: * the first intersecting gauge if that is impossible. ingo@472: */ ingo@472: public Gauge determineGauge(double a, double b) { ingo@488: List gauges = determineGauges(a, b); ingo@472: aheinecke@6106: if (a > b) { aheinecke@6106: for (int i = gauges.size() - 1; i >= 0; i--) { aheinecke@6106: Gauge g = gauges.get(i); aheinecke@6229: if (KM_CMP.compare(g.getRange().getA().doubleValue(), a) == 0) aheinecke@6106: continue; aheinecke@6106: return g; aheinecke@6106: } aheinecke@6106: } aheinecke@6106: aheinecke@6106: for (Gauge g: gauges) { aheinecke@6229: if (KM_CMP.compare(g.getRange().getB().doubleValue(), a) == 0) { aheinecke@6106: continue; aheinecke@6106: } aheinecke@6106: return g; aheinecke@6106: } aheinecke@6106: aheinecke@6106: return null; ingo@472: } ingo@472: ingo@465: /** ingo@465: * Returns the min and max distance of this river. The first position in the ingo@465: * resulting array contains the min distance, the second position the max ingo@465: * distance. ingo@465: * ingo@465: * @return the min and max distance of this river. ingo@465: */ ingo@465: public double[] determineMinMaxDistance() { sascha@2373: List gauges = getGauges(); sascha@2373: sascha@2373: if (gauges == null || gauges.isEmpty()) { ingo@465: return null; ingo@465: } ingo@465: teichmann@5878: double minmax[] = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE }; ingo@465: ingo@465: for (Gauge g: gauges) { ingo@465: Range r = g.getRange(); ingo@465: sascha@2373: if (r == null) { sascha@2373: continue; sascha@2373: } sascha@2373: teichmann@5878: double a = r.getA().doubleValue(); teichmann@5878: if (a < minmax[0]) { teichmann@5878: minmax[0] = a; teichmann@5878: } teichmann@5878: if (a > minmax[1]) { teichmann@5878: minmax[1] = a; teichmann@5878: } ingo@465: ingo@465: BigDecimal bigB = r.getB(); ingo@465: if (bigB != null) { teichmann@5878: double b = bigB.doubleValue(); teichmann@5878: if (b < minmax[0]) { teichmann@5878: minmax[0] = b; teichmann@5878: } teichmann@5878: if (b > minmax[1]) { teichmann@5878: minmax[1] = b; teichmann@5878: } ingo@465: } ingo@465: } ingo@465: ingo@465: return minmax; ingo@465: } sascha@2383: felix@2384: public Map queryGaugeDatumsKMs() { sascha@2383: List gauges = getGauges(); teichmann@5878: Map result = new TreeMap(KM_CMP); sascha@2383: sascha@2383: for (Gauge gauge: gauges) { sascha@2383: BigDecimal km = gauge.getStation(); sascha@2383: BigDecimal datum = gauge.getDatum(); sascha@2383: if (km != null && datum != null) { sascha@2383: result.put(km.doubleValue(), datum.doubleValue()); sascha@2383: } sascha@2383: } sascha@2383: sascha@2383: return result; sascha@2383: } bjoern@3944: sascha@167: } sascha@167: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :