org.kalypso.kalypsomodel1d2d.ui.map.channeledit.editdata.BanklineIntersector.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.kalypsomodel1d2d.ui.map.channeledit.editdata.BanklineIntersector.java

Source

/*----------------    FILE HEADER KALYPSO ------------------------------------------
 *
 *  This file is part of kalypso.
 *  Copyright (C) 2004 by:
 *
 *  Technical University Hamburg-Harburg (TUHH)
 *  Institute of River and coastal engineering
 *  Denickestrae 22
 *  21073 Hamburg, Germany
 *  http://www.tuhh.de/wb
 *
 *  and
 *
 *  Bjoernsen Consulting Engineers (BCE)
 *  Maria Trost 3
 *  56070 Koblenz, Germany
 *  http://www.bjoernsen.de
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *  Contact:
 *
 *  E-Mail:
 *  belger@bjoernsen.de
 *  schlienger@bjoernsen.de
 *  v.doemming@tuhh.de
 *
 *  ---------------------------------------------------------------------------*/
package org.kalypso.kalypsomodel1d2d.ui.map.channeledit.editdata;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.tuple.Pair;
import org.kalypso.commons.java.lang.Doubles;
import org.kalypso.jts.JTSUtilities;
import org.kalypso.kalypsomodel1d2d.ui.map.channeledit.ChannelEditData.SIDE;
import org.kalypso.kalypsomodel1d2d.ui.map.channeledit.ChannelEditUtil;
import org.kalypso.model.wspm.core.profil.IProfile;
import org.kalypso.model.wspm.core.util.WspmProfileHelper;
import org.kalypso.transformation.transformer.GeoTransformerException;
import org.kalypsodeegree.model.geometry.GM_Curve;
import org.kalypsodeegree.model.geometry.GM_Exception;
import org.kalypsodeegree_impl.model.geometry.JTSAdapter;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.linearref.LengthIndexedLine;

/**
 * Intersects profiles with banklines and creates the segmented bank line.
 * 
 * @author Gernot Belger
 */
class BanklineIntersector {
    private final Map<GM_Curve, SIDE> m_banks;

    private final SIDE m_side;

    private final BankData m_bankData;

    private final int m_numberOfBankPoints;

    private final ISegmentData m_segment;

    public BanklineIntersector(final ISegmentData segment, final Map<GM_Curve, SIDE> banks, final SIDE side,
            final int numberOfBankPoints) {
        m_segment = segment;
        m_banks = banks;
        m_side = side;
        m_numberOfBankPoints = numberOfBankPoints;

        m_bankData = calculateBanklines();
    }

    /**
     * Intersects the selected bank lines with the two profiles of the segment. This method will be called at the very
     * beginning. Here, the four intersection points will be initialized.
     */
    private BankData calculateBanklines() {
        try {
            final IProfileData downProfile = m_segment.getProfileDown();
            final IProfileData upProfile = m_segment.getProfileUp();

            return intersectBankline(downProfile, upProfile);
        } catch (final GM_Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private BankData intersectBankline(final IProfileData downProfile, final IProfileData upProfile)
            throws GM_Exception {
        final LineString upProfileLine = convertProfilesToLineStrings(upProfile);
        final LineString downProfileLine = convertProfilesToLineStrings(downProfile);

        final Pair<LineString, Pair<Point, Point>> intersection = findBankForProfiles(downProfileLine,
                upProfileLine);

        if (intersection == null)
            return null;

        final Pair<Point, Point> points = intersection.getValue();

        final Point downPoint = points.getLeft();
        final Point upPoint = points.getRight();

        final LineString bankLine = intersection.getKey();

        /* extract line between start end end intersection */
        final LineString croppedBankLine = (LineString) JTSUtilities.extractLineString(bankLine, downPoint,
                upPoint);

        /* handle z values of start a<nd end point */
        final double downZ = findIntersectionZ(downProfile, croppedBankLine.getStartPoint(), bankLine);
        final double upZ = findIntersectionZ(upProfile, croppedBankLine.getEndPoint(), bankLine);

        /* cropped line has z if bankLine has z; addionally, we want to force the profile height onto the endpoints */
        final LineString croppedBankLineWithZEndPoints = replaceEndpointZ(croppedBankLine, downZ, upZ);

        /* now make sure, we have z everywhere */
        final LineString croppedBankLineWithZ = JTSUtilities.interpolateMissingZ(croppedBankLineWithZEndPoints);

        final LineString segmentedGeometry = ChannelEditUtil.intersectLineString(croppedBankLineWithZ,
                m_numberOfBankPoints);

        return new BankData(m_segment, bankLine, croppedBankLine, segmentedGeometry, false);
    }

    /**
     * converts a WSPM profile into an linestring
     * 
     * @param profile
     *          Input profile to be converted.
     */
    private static LineString convertProfilesToLineStrings(final IProfileData upProfile) throws GM_Exception {
        final GM_Curve profCurve = upProfile.getOriginalProfileGeometry();
        return (LineString) JTSAdapter.export(profCurve);
    }

    private LineString replaceEndpointZ(final LineString bankLine, final double startZ, final double endZ) {
        final Point startPoint = bankLine.getStartPoint();
        final Point endPoint = bankLine.getEndPoint();

        final Coordinate[] coordinates = bankLine.getCoordinates();
        final Coordinate[] newCoordinates = new Coordinate[coordinates.length];

        newCoordinates[0] = new Coordinate(startPoint.getX(), startPoint.getY(), startZ);
        System.arraycopy(coordinates, 1, newCoordinates, 1, coordinates.length - 2);
        newCoordinates[coordinates.length - 1] = new Coordinate(endPoint.getX(), endPoint.getY(), endZ);

        return bankLine.getFactory().createLineString(newCoordinates);
    }

    // TODO: fetch heights from profile at this points
    // - either from bankline, if bankline has z
    // -or from profile
    private double findIntersectionZ(final IProfileData profileData, final Point intersection,
            final LineString bankLine) {
        try {
            /* original height from where ??? */
            final double intersectionZ = intersection.getCoordinate().z;

            if (!Double.isNaN(intersectionZ))
                return intersectionZ;

            final IProfile profilOrg = profileData.getOriginalProfile();

            final LengthIndexedLine bankIndex = new LengthIndexedLine(bankLine);
            final double indexOnBankLine = bankIndex.project(intersection.getCoordinate());
            final Coordinate bankPoint = bankIndex.extractPoint(indexOnBankLine);

            final Double width = WspmProfileHelper.getWidthPosition(intersection, profilOrg);
            if (Doubles.isNaN(width))
                return Double.NaN;

            final Double profileHeight = WspmProfileHelper.getHeightByWidth(width, profilOrg);

            // TODO: if both abk point and profile have height's: compute difference and show if too big

            return profileHeight;
        } catch (GM_Exception | GeoTransformerException e) {
            e.printStackTrace();
            return Double.NaN;
        }
    }

    /**
     * Find a bank line that intersect both profiles in exactly one point.
     */
    private Pair<LineString, Pair<Point, Point>> findBankForProfiles(final LineString downProfile,
            final LineString upProfile) {
        for (final Entry<GM_Curve, SIDE> bankEntry : m_banks.entrySet()) {
            if (m_side == bankEntry.getValue()) {
                try {
                    /* convert current bankLine in Curve */
                    final GM_Curve bankCurve = bankEntry.getKey();
                    final LineString bankLine = (LineString) JTSAdapter.export(bankCurve);

                    if (bankLine != null) {
                        final Geometry upIntersection = bankLine.intersection(upProfile);
                        final Geometry downIntersection = bankLine.intersection(downProfile);

                        /* intersect it with the first (previous) profile of this segment */
                        if (upIntersection instanceof Point && downIntersection instanceof Point) {
                            final Pair<Point, Point> points = Pair.of((Point) upIntersection,
                                    (Point) downIntersection);
                            return Pair.of(bankLine, points);
                        }
                    }
                } catch (final GM_Exception e) {
                    // TODO: error handling?

                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    public BankData getBankline() {
        return m_bankData;
    }
}