view flys-backend/src/main/java/de/intevation/flys/model/River.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 8062b571884d
children
line wrap: on
line source
package de.intevation.flys.model;

import de.intevation.flys.backend.SessionHolder;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.Query;
import org.hibernate.Session;


@Entity
@Table(name = "rivers")
public class River
implements   Serializable
{
    public static final MathContext PRECISION = new MathContext(6);

    public static final double EPSILON = 1e-5;

    public static final Comparator<Double> KM_CMP = new Comparator<Double>() {
        @Override
        public int compare(Double a, Double b) {
            double diff = a - b;
            if (diff < -EPSILON) return -1;
            if (diff >  EPSILON) return +1;
            return 0;
        }
    };

    private Integer id;

    private Long    officialNumber;

    private String  name;

    private boolean kmUp;

    private List<Gauge> gauges;

    private List<MeasurementStation> measurementstations;

    private Unit wstUnit;

    @Id
    @SequenceGenerator(
        name           = "SEQUENCE_RIVERS_ID_SEQ",
        sequenceName   = "RIVERS_ID_SEQ",
        allocationSize = 1)
    @GeneratedValue(
        strategy  = GenerationType.SEQUENCE,
        generator = "SEQUENCE_RIVERS_ID_SEQ")
    @Column(name = "id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "official_number")
    public Long getOfficialNumber() {
        return officialNumber;
    }

    public void setOfficialNumber(Long officialNumber) {
        this.officialNumber = officialNumber;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "km_up")
    public boolean getKmUp() {
        return kmUp;
    }

    public void setKmUp(boolean kmUp) {
        this.kmUp = kmUp;
    }

    public River() {
    }

    public River(String name, Unit wstUnit) {
        this.name    = name;
        this.wstUnit = wstUnit;
    }

    @OneToMany
    @JoinColumn(name="river_id")
    public List<Gauge> getGauges() {
        return gauges;
    }

    public void setGauges(List<Gauge> gauges) {
        this.gauges = gauges;
    }


    @OneToMany
    @OrderBy("station")
    @JoinColumn(name="river_id")
    public List<MeasurementStation> getMeasurementStations() {
        return measurementstations;
    }

    public void setMeasurementStations(List<MeasurementStation> mstations) {
        this.measurementstations = mstations;
    }

    @OneToOne
    @JoinColumn(name = "wst_unit_id" )
    public Unit getWstUnit() {
        return wstUnit;
    }

    public void setWstUnit(Unit wstUnit) {
        this.wstUnit = wstUnit;
    }



    @Override
    public String toString() {
        return name != null ? name : "";
    }


    /**
     * This method returns the gauges that intersect with <i>a</i> and
     * <i>b</i>,
     *
     * @param a A start point.
     * @param b An end point.
     *
     * @return the intersecting gauges.
     */
    public List<Gauge> determineGauges(double a, double b) {
        Session session = SessionHolder.HOLDER.get();

        if (a > b) { double t = a; a = b; b = t; }

        Query query = session.createQuery(
            "from Gauge where river=:river " +
            "and not (range.a > :b or range.b < :a) order by a");
        query.setParameter("river", this);
        query.setParameter("a", new BigDecimal(a, PRECISION));
        query.setParameter("b", new BigDecimal(b, PRECISION));

        return query.list();
    }

    public Gauge maxOverlap(double a, double b) {
        List<Gauge> gauges = determineGauges(a, b);
        if (gauges == null) {
            return null;
        }

        if (a > b) { double t = a; a = b; b = t; }

        double max = -Double.MAX_VALUE;

        Gauge result = null;

        for (Gauge gauge: gauges) {
            Range  r = gauge.getRange();
            double c = r.getA().doubleValue();
            double d = r.getB().doubleValue();

            double start = c >= a ? c : a;
            double stop  = d <= b ? d : b;

            double length = stop - start;

            if (length > max) {
                max = length;
                result = gauge;
            }
        }

        return result;
    }

    public Gauge determineGaugeByName(String name) {
        Session session = SessionHolder.HOLDER.get();
        Query query = session.createQuery(
            "from Gauge where river=:river and name=:name");
        query.setParameter("river", this);
        query.setParameter("name", name);
        List<Gauge> gauges = query.list();
        return gauges.isEmpty() ? null : gauges.get(0);
    }

    public Gauge determineGaugeByPosition(double p) {
        Session session = SessionHolder.HOLDER.get();
        Query query = session.createQuery(
            "from Gauge g where river=:river "  +
            "and :p between g.range.a and g.range.b");
        query.setParameter("river", this);
        query.setParameter("p", new BigDecimal(p, PRECISION));
        List<Gauge> gauges = query.list();
        return gauges.isEmpty() ? null : gauges.get(0);
    }

    public Gauge determineGaugeByStation(double a, double b) {

        if (a > b) { double t = a; a = b; b = t; }

        Session session = SessionHolder.HOLDER.get();

        Query query = session.createQuery(
            "from Gauge where river.id=:river " +
            "and station between :a and :b");
        query.setParameter("river", getId());
        query.setParameter("a", new BigDecimal(a));
        query.setParameter("b", new BigDecimal(b));

        List<Gauge> gauges = query.list();
        return gauges.isEmpty() ? null : gauges.get(0);
    }

    public double[] determineMinMaxQ() {
        Session session = SessionHolder.HOLDER.get();

        Query query = session.createQuery(
            "select min(wqr.q) as min, max(wqr.q) as max " +
            "from Wst as w " +
            "join w.columns as wc " +
            "join wc.columnQRanges as wcqr " +
            "join wcqr.wstQRange as wqr " +
            "where w.kind = 0 and river_id = :river");

        query.setParameter("river", getId());

        double minmax[] = new double[] { Double.MAX_VALUE, Double.MIN_VALUE };

        List<Object> results = query.list();

        if (!results.isEmpty()) {
            Object[] arr = (Object[]) results.get(0);
            BigDecimal minq = (BigDecimal)arr[0];
            BigDecimal maxq = (BigDecimal)arr[1];
            minmax[0] = minq.doubleValue();
            minmax[1] = maxq.doubleValue();
        }

        return minmax;
    }


    /**
     * This method returns the first gauge that is intersected by <i>a</i> and
     * <i>b</i>,
     *
     * @param a A start point.
     * @param b An end point.
     *
     * @return the first intersecting gauge.
     */
    public Gauge determineGauge(double a, double b) {
        List<Gauge> gauges = determineGauges(a, b);

        int idx = a < b ? 0 : gauges.size() - 1;

        return gauges.isEmpty() ? null : gauges.get(idx);
    }

    /**
     * Returns the min and max distance of this river. The first position in the
     * resulting array contains the min distance, the second position the max
     * distance.
     *
     * @return the min and max distance of this river.
     */
    public double[] determineMinMaxDistance() {
        List<Gauge> gauges = getGauges();

        if (gauges == null || gauges.isEmpty()) {
            return null;
        }

        double minmax[] = new double[] { Double.MAX_VALUE, Double.MIN_VALUE };

        for (Gauge g: gauges) {
            Range r = g.getRange();

            if (r == null) {
                continue;
            }

            double a  = r.getA().doubleValue();
            minmax[0] = minmax[0] < a ? minmax[0] : a;

            BigDecimal bigB = r.getB();
            if (bigB != null) {
                double b  = bigB.doubleValue();
                minmax[1] = minmax[1] > b ? minmax[1] : b;
            }
        }

        return minmax;
    }

    public Map<Double, Double> queryGaugeDatumsKMs() {
        List<Gauge> gauges = getGauges();
        Map result = new TreeMap<Double, Double>(KM_CMP);

        for (Gauge gauge: gauges) {
            BigDecimal km    = gauge.getStation();
            BigDecimal datum = gauge.getDatum();
            if (km != null && datum != null) {
                result.put(km.doubleValue(), datum.doubleValue());
            }
        }

        return result;
    }

}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org