changeset 9706:299c1c61d8ef

zu 1.1. Sohlhöhen-Überlappung
author dnt_bjoernsen <d.tironi@bjoernsen.de>
date Fri, 22 Jan 2021 12:28:58 +0100
parents bfdf98529a66
children 23702537fb4f
files artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/DefaultBedHeights.java backend/src/main/java/org/dive4elements/river/model/BedHeight.java
diffstat 2 files changed, 438 insertions(+), 374 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/DefaultBedHeights.java	Thu Jan 21 15:05:24 2021 +0100
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/tkhstate/DefaultBedHeights.java	Fri Jan 22 12:28:58 2021 +0100
@@ -22,94 +22,131 @@
 import org.dive4elements.river.model.River;
 
 /**
- * This class knows how to find the default bed levels defined for tkh and other calculations
+ * This class knows how to find the default bed levels defined for tkh and other
+ * calculations
  *
  * @author Gernot Belger
  */
 public final class DefaultBedHeights {
 
-    private final River river;
-
-    public DefaultBedHeights(final River river) {
-        this.river = river;
-    }
-
-    public List<BedHeight> getBedHeights(final Calculation problems) {
-        final Collection<DefaultBedHeight> defaults = DefaultBedHeightsConfig.getDefaults(this.river, problems);
-
-        final List<BedHeight> defaultBedHeights = loadBedHeightsByName(this.river, defaults, problems);
-        if (defaultBedHeights.isEmpty()) {
-            problems.addProblem("sinfo.bedheightsfinder.nobedheightsforriver", this.river.getName());
-            return Collections.emptyList();
-        }
-
-        /* check for overlapping ranges, N2-search, but we expect only have small numbers of bed levels */
-        final List<BedHeight> result = new ArrayList<>(defaultBedHeights.size());
-
-        for (int i = 0; i < defaultBedHeights.size(); i++) {
-            final BedHeight bedHeight = defaultBedHeights.get(i);
-
-            final Range range = bedHeight.getRange();
-            final NumberRange bedRange = new NumberRange(range.getA(), range.getB());
-
-            if (overlapsRange(bedRange, defaultBedHeights, i + 1))
-                problems.addProblem("sinfo.bedheightsfinder.overlappingrange", bedHeight.getDescription());
-            else
-                result.add(bedHeight);
-        }
-
-        final List<BedHeight> validBedHeights = new ArrayList<>(defaultBedHeights.size());
-
-        // REMARK: check for bad ranges because db schema allow for incomplete ranges, and ignore if this is the case
-        for (final BedHeight bedHeight : defaultBedHeights) {
-
-            final Range range = bedHeight.getRange();
+	private final River river;
 
-            if (range.getA() == null || range.getB() == null)
-                problems.addProblem("sinfo.bedheightsfinder.badrange", bedHeight.getDescription());
-            else
-                validBedHeights.add(bedHeight);
-        }
-
-        return result;
-    }
-
-    private static List<BedHeight> loadBedHeightsByName(final River river, final Collection<DefaultBedHeight> defaults, final Calculation problems) {
-
-        final List<BedHeight> bedHeights = new ArrayList<>(defaults.size());
-
-        for (final DefaultBedHeight heightDefault : defaults) {
-
-            final String description = heightDefault.description;
-            try {
+	public DefaultBedHeights(final River river) {
+		this.river = river;
+	}
 
-                final BedHeight bedHeight = BedHeight.getBedHeightByDescription(river, description, heightDefault.startKm, heightDefault.endKm);
-                if (bedHeight == null)
-                    problems.addProblem("sinfo.bedheightsfinder.missingdescription", river.getName(), description);
-                else
-                    bedHeights.add(bedHeight);
-            }
-            catch (final Exception e) {
-                e.printStackTrace();
-                problems.addProblem("sinfo.bedheightsfinder.missingdescription", river.getName(), description);
-            }
-        }
-
-        return bedHeights;
-    }
+	public List<BedHeight> getBedHeights(final Calculation problems) {
+		final Collection<DefaultBedHeight> defaults = DefaultBedHeightsConfig.getDefaults(this.river, problems);
+		// check ob jede default-range irgendeine andere überlappt
 
-    private static boolean overlapsRange(final NumberRange bedRange, final List<BedHeight> result, final int startIndex) {
-
-        for (int i = startIndex; i < result.size(); i++) {
+		for (DefaultBedHeight check : defaults) {
+			double end = check.endKm > check.startKm ? check.endKm : check.startKm;
+			double start = check.startKm < check.endKm ? check.startKm : check.endKm;
 
-            final BedHeight compareBed = result.get(i);
-            final Range range = compareBed.getRange();
-            final NumberRange compareRange = new NumberRange(range.getA(), range.getB());
+			for (DefaultBedHeight checkInner : defaults) {
+				if (!checkInner.description.equals(check.description)
+						&& (checkInner.startKm < end && checkInner.endKm > start))
+					problems.addProblem("sinfo.bedheightsfinder.overlappingrange", check.description);
+			}
+		}
 
-            if (compareRange.overlapsRange(bedRange))
-                return true;
-        }
+		final List<BedHeight> defaultBedHeights = loadBedHeightsByName(this.river, defaults, problems);
+		if (defaultBedHeights.isEmpty()) {
+			problems.addProblem("sinfo.bedheightsfinder.nobedheightsforriver", this.river.getName());
+			return Collections.emptyList();
+		}
 
-        return false;
-    }
+		/*
+		 * check for overlapping ranges, N2-search, but we expect only have small
+		 * numbers of bed levels
+		 */
+		final List<BedHeight> result = new ArrayList<>(defaultBedHeights.size());
+
+		for (int i = 0; i < defaultBedHeights.size(); i++) {
+
+			final BedHeight bedHeight = defaultBedHeights.get(i);
+
+			DefaultBedHeight configuredBH = getConfiguredBedheightByDescription(problems, defaults,
+					bedHeight.getDescription());
+
+			final double startKm = configuredBH.startKm < configuredBH.endKm ? configuredBH.startKm
+					: configuredBH.endKm;
+			final double endKm = configuredBH.endKm > configuredBH.startKm ? configuredBH.endKm : configuredBH.startKm;
+			// final NumberRange bedRange = new NumberRange(range.getA(), range.getB());
+
+			// FIXME: optional: deckt die echte Range (Datenbank) die
+			// konfigurierte Range ab?
+
+			// copy bedheight and restrict to configured ranges
+			BedHeight rangedBedheight = BedHeight.copyPojoFrom(bedHeight, startKm, endKm);
+			result.add(rangedBedheight);
+		}
+
+		final List<BedHeight> validBedHeights = new ArrayList<>(defaultBedHeights.size());
+
+		// REMARK: check for bad ranges because db schema allow for incomplete ranges,
+		// and ignore if this is the case
+		for (final BedHeight bedHeight : defaultBedHeights) {
+
+			final Range range = bedHeight.getRange();
+
+			if (range.getA() == null || range.getB() == null)
+				problems.addProblem("sinfo.bedheightsfinder.badrange", bedHeight.getDescription());
+			else
+				validBedHeights.add(bedHeight);
+		}
+
+		return result;
+	}
+
+	private DefaultBedHeight getConfiguredBedheightByDescription(Calculation problems,
+			Collection<DefaultBedHeight> defaults, String description) {
+		for (DefaultBedHeight bh : defaults) {
+			if (bh.description.equals(description))
+				return bh;
+		}
+		problems.addProblem("could not find the configured bedheight, which is not possible", description);
+		return null;
+	}
+
+	private static List<BedHeight> loadBedHeightsByName(final River river, final Collection<DefaultBedHeight> defaults,
+			final Calculation problems) {
+
+		final List<BedHeight> bedHeights = new ArrayList<>(defaults.size());
+
+		for (final DefaultBedHeight heightDefault : defaults) {
+
+			final String description = heightDefault.description;
+			try {
+
+				final BedHeight bedHeight = BedHeight.getBedHeightByDescription(river, description,
+						heightDefault.startKm, heightDefault.endKm);
+				if (bedHeight == null)
+					problems.addProblem("sinfo.bedheightsfinder.missingdescription", river.getName(), description);
+				else
+					bedHeights.add(bedHeight);
+			} catch (final Exception e) {
+				e.printStackTrace();
+				problems.addProblem("sinfo.bedheightsfinder.missingdescription", river.getName(), description);
+			}
+		}
+
+		return bedHeights;
+	}
+
+	/*
+	 * this check is replaced by configRangeCheck private static boolean
+	 * overlapsRange(final NumberRange bedRange, final List<BedHeight> result, final
+	 * int startIndex) {
+	 * 
+	 * for (int i = startIndex; i < result.size(); i++) {
+	 * 
+	 * final BedHeight compareBed = result.get(i); final Range range =
+	 * compareBed.getRange(); final NumberRange compareRange = new
+	 * NumberRange(range.getA(), range.getB());
+	 * 
+	 * if (compareRange.overlapsRange(bedRange)) return true; }
+	 * 
+	 * return false; }
+	 */
 }
\ No newline at end of file
--- a/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Thu Jan 21 15:05:24 2021 +0100
+++ b/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Fri Jan 22 12:28:58 2021 +0100
@@ -27,310 +27,337 @@
 import org.hibernate.Query;
 import org.hibernate.Session;
 
+import com.vividsolutions.jts.util.Assert;
+
 @Entity
 @Table(name = "bed_height")
 public class BedHeight implements Serializable {
 
-    private Integer id;
-    private Integer year;
-
-    private String evaluationBy;
-    private String description;
-
-    private River river;
-
-    private BedHeightType type;
-
-    private LocationSystem locationSystem;
-
-    private ElevationModel curElevationModel;
-
-    private ElevationModel oldElevationModel;
-
-    private Range range;
-
-    private String sounding_width_info;
-    private String notes;
-
-    private List<BedHeightValue> values;
-
-    public BedHeight() {
-    }
-
-    public BedHeight(final River river, final Integer year, final BedHeightType type, final LocationSystem locationSystem,
-            final ElevationModel curElevationModel, final Range range) {
-        this(river, year, type, locationSystem, curElevationModel, null, range, null, null, null, null);
-    }
-
-    public BedHeight(final River river, final Integer year, final BedHeightType type, final LocationSystem locationSystem,
-            final ElevationModel curElevationModel, final ElevationModel oldElevationModel, final Range range, final String evaluationBy,
-            final String description, final String sounding_width_info, final String notes) {
-        this.river = river;
-        this.year = year;
-        this.type = type;
-        this.locationSystem = locationSystem;
-        this.curElevationModel = curElevationModel;
-        this.oldElevationModel = oldElevationModel;
-        this.range = range;
-        this.evaluationBy = evaluationBy;
-        this.description = description;
-        this.sounding_width_info = sounding_width_info;
-        this.notes = notes;
-    }
-
-    @Id
-    @SequenceGenerator(name = "SEQUENCE_BED_HEIGHT_ID_SEQ", sequenceName = "BED_HEIGHT_ID_SEQ", allocationSize = 1)
-    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_BED_HEIGHT_ID_SEQ")
-    @Column(name = "id")
-    public Integer getId() {
-        return this.id;
-    }
-
-    public void setId(final Integer id) {
-        this.id = id;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "river_id")
-    public River getRiver() {
-        return this.river;
-    }
-
-    public void setRiver(final River river) {
-        this.river = river;
-    }
-
-    @Column(name = "year")
-    public Integer getYear() {
-        return this.year;
-    }
-
-    public void setYear(final Integer year) {
-        this.year = year;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "type_id")
-    public BedHeightType getType() {
-        return this.type;
-    }
-
-    public void setType(final BedHeightType type) {
-        this.type = type;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "location_system_id")
-    public LocationSystem getLocationSystem() {
-        return this.locationSystem;
-    }
-
-    public void setLocationSystem(final LocationSystem locationSystem) {
-        this.locationSystem = locationSystem;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "cur_elevation_model_id")
-    public ElevationModel getCurElevationModel() {
-        return this.curElevationModel;
-    }
-
-    public void setCurElevationModel(final ElevationModel curElevationModel) {
-        this.curElevationModel = curElevationModel;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "old_elevation_model_id")
-    public ElevationModel getOldElevationModel() {
-        return this.oldElevationModel;
-    }
-
-    public void setOldElevationModel(final ElevationModel oldElevationModel) {
-        this.oldElevationModel = oldElevationModel;
-    }
-
-    @OneToOne
-    @JoinColumn(name = "range_id")
-    public Range getRange() {
-        return this.range;
-    }
-
-    public void setRange(final Range range) {
-        this.range = range;
-    }
-
-    @Column(name = "evaluation_by")
-    public String getEvaluationBy() {
-        return this.evaluationBy;
-    }
-
-    public void setEvaluationBy(final String evaluationBy) {
-        this.evaluationBy = evaluationBy;
-    }
-
-    @Column(name = "description")
-    public String getDescription() {
-        return this.description;
-    }
-
-    public void setDescription(final String description) {
-        this.description = description;
-    }
-
-    @Column(name = "sounding_width_info")
-    public String getSoundingWidthInfo() {
-        return this.sounding_width_info;
-    }
+	private Integer id;
+	private Integer year;
 
-    public void setSoundingWidthInfo(final String sounding_width_info) {
-        this.sounding_width_info = sounding_width_info;
-    }
-
-    @Column(name = "notes")
-    public String getNotes() {
-        return this.notes;
-    }
-
-    public void setNotes(final String notes) {
-        this.notes = notes;
-    }
-
-    @OneToMany
-    @JoinColumn(name = "bed_height_id")
-    public List<BedHeightValue> getValues() {
-        return this.values;
-    }
-
-    public void setValues(final List<BedHeightValue> values) {
-        this.values = values;
-    }
-
-    public static List<BedHeight> getBedHeights(final River river, final double kmLo, final double kmHi) {
-        return getBedHeights(river, kmLo, kmHi, false);
-    }
-
-    /**
-     * Fetch the soundings with values in a river km range, optionally only those that also have field 01 etc. values
-     */
-    public static List<BedHeight> getBedHeights(final River river, final double startKm, final double endKm, final boolean withHeightFieldsOnly) {
-
-        final Session session = SessionHolder.HOLDER.get();
-
-        final String fieldsClause = withHeightFieldsOnly ? " AND (height01 IS NOT NULL)" : "";
-        final Query query = session.createQuery("FROM BedHeight"
-                + " WHERE (river=:river)"
-                + " AND (id IN (SELECT bedHeight.id FROM BedHeightValue"
-                + " WHERE (station BETWEEN :kmfrom - 0.0001 AND :kmto + 0.0001)"
-                + fieldsClause
-                + " GROUP BY bed_height_id))");
-        query.setParameter("river", river);
-        query.setParameter("kmfrom", startKm);
-        query.setParameter("kmto", endKm);
-
-        final List<BedHeight> singles = query.list();
-
-        return ((singles != null) && !singles.isEmpty()) ? singles : null;
-    }
-
-    public static BedHeight getBedHeightById(final int id) {
-        final Session session = SessionHolder.HOLDER.get();
-
-        final Query query = session.createQuery("from BedHeight where id=:id");
-
-        query.setParameter("id", id);
-
-        final List<BedHeight> singles = query.list();
-
-        return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
-    }
-
-    public static BedHeight getBedHeightByDescription(final River river, final String description, final double startKm, final double endKm) {
-
-        final Session session = SessionHolder.HOLDER.get();
-
-        final Query query = session.createQuery("FROM BedHeight" + " WHERE (TRIM(description)=:description) AND river=:river"
-                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
-        query.setParameter("river", river);
-        query.setParameter("description", description);
-        query.setParameter("kmfrom", startKm);
-        query.setParameter("kmto", endKm);
-
-        final List<BedHeight> singles = query.list();
+	private String evaluationBy;
+	private String description;
 
-        return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
-    }
-
-    public static List<BedHeight> getBedHeightEpochs(final River river, final double startKm, final double endKm) {
-
-        final Session session = SessionHolder.HOLDER.get();
-        final String description = "epoch";
-        final Query query = session.createQuery("FROM BedHeight" + " WHERE lower(description) LIKE :description AND " + "river=:river"
-                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
-        query.setParameter("river", river);
-        query.setParameter("description", "%" + description + "%");
-        query.setParameter("kmfrom", startKm);
-        query.setParameter("kmto", endKm);
-
-        final List<BedHeight> singles = query.list();
-
-        return ((singles != null) && !singles.isEmpty()) ? singles : null;
-    }
-
-    public static List<BedHeight> getBedHeightYear(final River river, final double startKm, final double endKm) {
-
-        final Session session = SessionHolder.HOLDER.get();
-        final String description = "epoch";
-        final Query query = session.createQuery("FROM BedHeight" + " WHERE lower(description) NOT LIKE :description AND " + "river=:river"
-                + " AND id IN (SELECT bedHeight.id FROM BedHeightValue" + " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
-        query.setParameter("river", river);
-        query.setParameter("description", "%" + description + "%");
-        query.setParameter("kmfrom", startKm);
-        query.setParameter("kmto", endKm);
-
-        final List<BedHeight> singles = query.list();
-
-        return ((singles != null) && !singles.isEmpty()) ? singles : null;
-    }
-
-    public static Range getRangeFromBedHeights(final BedHeight bh) {
-        final List<Range> ranges = new ArrayList<>();
+	private River river;
 
-        final Session session = SessionHolder.HOLDER.get();
-
-        final Query query = session.createQuery("FROM Range" + " WHERE id=:range_id)");
-        query.setParameter("range_id", bh.getRange().getId());
-
-        final List<Range> singles = query.list();
-
-        return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
-    }
-
-    public static List<BedHeight> getBedHeightYearEpoch(final boolean isEpoch, final Integer year, final River river, final double lowerKm,
-            final double upperKm) {
-
-        final Session session = SessionHolder.HOLDER.get();
-        final String description = "epoch";
+	private BedHeightType type;
 
-        final StringBuilder builder = new StringBuilder();
-        builder.append("FROM BedHeight");
-        if (isEpoch) {
-            builder.append(" WHERE lower(description) LIKE :description ");
-        } else {
-            builder.append(" WHERE lower(description) NOT LIKE :description ");
-        }
-        builder.append(" AND year =:year");
+	private LocationSystem locationSystem;
 
-        builder.append(
-                " AND river=:river  AND id IN (SELECT bedHeight.id FROM BedHeightValue   WHERE station BETWEEN :kmfrom AND :kmto  GROUP BY bedHeight.id )");
-        final Query query = session.createQuery(builder.toString());
-        query.setParameter("river", river);
-        query.setParameter("year", year);
-        query.setParameter("description", "%" + description + "%");
-        query.setParameter("kmfrom", lowerKm);
-        query.setParameter("kmto", upperKm);
+	private ElevationModel curElevationModel;
 
-        final List<BedHeight> singles = query.list();
+	private ElevationModel oldElevationModel;
 
-        return ((singles != null) && !singles.isEmpty()) ? singles : null;
-    }
+	private Range range;
+
+	private String sounding_width_info;
+	private String notes;
+
+	private List<BedHeightValue> values;
+
+	public static BedHeight copyPojoFrom(BedHeight b, double from, double to) {
+		List<BedHeightValue> values2 = b.getValues();
+		List<BedHeightValue> copyValueList = new ArrayList<>();
+
+		BedHeight copy = new BedHeight(b.getRiver(), b.getYear(), b.getType(), b.getLocationSystem(),
+				b.getCurElevationModel(), b.getOldElevationModel(), new Range(from, to, b.getRange().getRiver()),
+				b.getEvaluationBy(), b.getDescription(), b.getSoundingWidthInfo(), b.getNotes());
+
+		for (BedHeightValue val : values2) {
+			Double station = val.getStation();
+			if (station >= from && station <= to)
+				copyValueList.add(val);
+		}
+
+		copy.setValues(copyValueList);
+		return copy;
+	}
+
+	public BedHeight() {
+	}
+
+	public BedHeight(final River river, final Integer year, final BedHeightType type,
+			final LocationSystem locationSystem, final ElevationModel curElevationModel, final Range range) {
+		this(river, year, type, locationSystem, curElevationModel, null, range, null, null, null, null);
+	}
+
+	public BedHeight(final River river, final Integer year, final BedHeightType type,
+			final LocationSystem locationSystem, final ElevationModel curElevationModel,
+			final ElevationModel oldElevationModel, final Range range, final String evaluationBy,
+			final String description, final String sounding_width_info, final String notes) {
+		this.river = river;
+		this.year = year;
+		this.type = type;
+		this.locationSystem = locationSystem;
+		this.curElevationModel = curElevationModel;
+		this.oldElevationModel = oldElevationModel;
+		this.range = range;
+		this.evaluationBy = evaluationBy;
+		this.description = description;
+		this.sounding_width_info = sounding_width_info;
+		this.notes = notes;
+	}
+
+	@Id
+	@SequenceGenerator(name = "SEQUENCE_BED_HEIGHT_ID_SEQ", sequenceName = "BED_HEIGHT_ID_SEQ", allocationSize = 1)
+	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_BED_HEIGHT_ID_SEQ")
+	@Column(name = "id")
+	public Integer getId() {
+		return this.id;
+	}
+
+	public void setId(final Integer id) {
+		this.id = id;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "river_id")
+	public River getRiver() {
+		return this.river;
+	}
+
+	public void setRiver(final River river) {
+		this.river = river;
+	}
+
+	@Column(name = "year")
+	public Integer getYear() {
+		return this.year;
+	}
+
+	public void setYear(final Integer year) {
+		this.year = year;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "type_id")
+	public BedHeightType getType() {
+		return this.type;
+	}
+
+	public void setType(final BedHeightType type) {
+		this.type = type;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "location_system_id")
+	public LocationSystem getLocationSystem() {
+		return this.locationSystem;
+	}
+
+	public void setLocationSystem(final LocationSystem locationSystem) {
+		this.locationSystem = locationSystem;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "cur_elevation_model_id")
+	public ElevationModel getCurElevationModel() {
+		return this.curElevationModel;
+	}
+
+	public void setCurElevationModel(final ElevationModel curElevationModel) {
+		this.curElevationModel = curElevationModel;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "old_elevation_model_id")
+	public ElevationModel getOldElevationModel() {
+		return this.oldElevationModel;
+	}
+
+	public void setOldElevationModel(final ElevationModel oldElevationModel) {
+		this.oldElevationModel = oldElevationModel;
+	}
+
+	@OneToOne
+	@JoinColumn(name = "range_id")
+	public Range getRange() {
+		return this.range;
+	}
+
+	public void setRange(final Range range) {
+		this.range = range;
+	}
+
+	@Column(name = "evaluation_by")
+	public String getEvaluationBy() {
+		return this.evaluationBy;
+	}
+
+	public void setEvaluationBy(final String evaluationBy) {
+		this.evaluationBy = evaluationBy;
+	}
+
+	@Column(name = "description")
+	public String getDescription() {
+		return this.description;
+	}
+
+	public void setDescription(final String description) {
+		this.description = description;
+	}
+
+	@Column(name = "sounding_width_info")
+	public String getSoundingWidthInfo() {
+		return this.sounding_width_info;
+	}
+
+	public void setSoundingWidthInfo(final String sounding_width_info) {
+		this.sounding_width_info = sounding_width_info;
+	}
+
+	@Column(name = "notes")
+	public String getNotes() {
+		return this.notes;
+	}
+
+	public void setNotes(final String notes) {
+		this.notes = notes;
+	}
+
+	@OneToMany
+	@JoinColumn(name = "bed_height_id")
+	public List<BedHeightValue> getValues() {
+		return this.values;
+	}
+
+	public void setValues(final List<BedHeightValue> values) {
+		this.values = values;
+	}
+
+	public static List<BedHeight> getBedHeights(final River river, final double kmLo, final double kmHi) {
+		return getBedHeights(river, kmLo, kmHi, false);
+	}
+
+	/**
+	 * Fetch the soundings with values in a river km range, optionally only those
+	 * that also have field 01 etc. values
+	 */
+	public static List<BedHeight> getBedHeights(final River river, final double startKm, final double endKm,
+			final boolean withHeightFieldsOnly) {
+
+		final Session session = SessionHolder.HOLDER.get();
+
+		final String fieldsClause = withHeightFieldsOnly ? " AND (height01 IS NOT NULL)" : "";
+		final Query query = session.createQuery(
+				"FROM BedHeight" + " WHERE (river=:river)" + " AND (id IN (SELECT bedHeight.id FROM BedHeightValue"
+						+ " WHERE (station BETWEEN :kmfrom - 0.0001 AND :kmto + 0.0001)" + fieldsClause
+						+ " GROUP BY bed_height_id))");
+		query.setParameter("river", river);
+		query.setParameter("kmfrom", startKm);
+		query.setParameter("kmto", endKm);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles : null;
+	}
+
+	public static BedHeight getBedHeightById(final int id) {
+		final Session session = SessionHolder.HOLDER.get();
+
+		final Query query = session.createQuery("from BedHeight where id=:id");
+
+		query.setParameter("id", id);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
+	}
+
+	public static BedHeight getBedHeightByDescription(final River river, final String description, final double startKm,
+			final double endKm) {
+
+		final Session session = SessionHolder.HOLDER.get();
+
+		final Query query = session
+				.createQuery("FROM BedHeight" + " WHERE (TRIM(description)=:description) AND river=:river"
+						+ " AND id IN (SELECT bedHeight.id FROM BedHeightValue"
+						+ " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
+		query.setParameter("river", river);
+		query.setParameter("description", description);
+		query.setParameter("kmfrom", startKm);
+		query.setParameter("kmto", endKm);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
+	}
+
+	public static List<BedHeight> getBedHeightEpochs(final River river, final double startKm, final double endKm) {
+
+		final Session session = SessionHolder.HOLDER.get();
+		final String description = "epoch";
+		final Query query = session.createQuery("FROM BedHeight" + " WHERE lower(description) LIKE :description AND "
+				+ "river=:river" + " AND id IN (SELECT bedHeight.id FROM BedHeightValue"
+				+ " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
+		query.setParameter("river", river);
+		query.setParameter("description", "%" + description + "%");
+		query.setParameter("kmfrom", startKm);
+		query.setParameter("kmto", endKm);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles : null;
+	}
+
+	public static List<BedHeight> getBedHeightYear(final River river, final double startKm, final double endKm) {
+
+		final Session session = SessionHolder.HOLDER.get();
+		final String description = "epoch";
+		final Query query = session
+				.createQuery("FROM BedHeight" + " WHERE lower(description) NOT LIKE :description AND " + "river=:river"
+						+ " AND id IN (SELECT bedHeight.id FROM BedHeightValue"
+						+ " WHERE station BETWEEN :kmfrom AND :kmto" + " GROUP BY bedHeight.id)");
+		query.setParameter("river", river);
+		query.setParameter("description", "%" + description + "%");
+		query.setParameter("kmfrom", startKm);
+		query.setParameter("kmto", endKm);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles : null;
+	}
+
+	public static Range getRangeFromBedHeights(final BedHeight bh) {
+		final List<Range> ranges = new ArrayList<>();
+
+		final Session session = SessionHolder.HOLDER.get();
+
+		final Query query = session.createQuery("FROM Range" + " WHERE id=:range_id)");
+		query.setParameter("range_id", bh.getRange().getId());
+
+		final List<Range> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles.get(0) : null;
+	}
+
+	public static List<BedHeight> getBedHeightYearEpoch(final boolean isEpoch, final Integer year, final River river,
+			final double lowerKm, final double upperKm) {
+
+		final Session session = SessionHolder.HOLDER.get();
+		final String description = "epoch";
+
+		final StringBuilder builder = new StringBuilder();
+		builder.append("FROM BedHeight");
+		if (isEpoch) {
+			builder.append(" WHERE lower(description) LIKE :description ");
+		} else {
+			builder.append(" WHERE lower(description) NOT LIKE :description ");
+		}
+		builder.append(" AND year =:year");
+
+		builder.append(
+				" AND river=:river  AND id IN (SELECT bedHeight.id FROM BedHeightValue   WHERE station BETWEEN :kmfrom AND :kmto  GROUP BY bedHeight.id )");
+		final Query query = session.createQuery(builder.toString());
+		query.setParameter("river", river);
+		query.setParameter("year", year);
+		query.setParameter("description", "%" + description + "%");
+		query.setParameter("kmfrom", lowerKm);
+		query.setParameter("kmto", upperKm);
+
+		final List<BedHeight> singles = query.list();
+
+		return ((singles != null) && !singles.isEmpty()) ? singles : null;
+	}
 }
\ No newline at end of file

http://dive4elements.wald.intevation.org