Java tutorial
/*---------------- 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.model.wspm.ui.profil.wizard.createDivider; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import org.apache.commons.lang3.ArrayUtils; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.kalypso.commons.command.ICommand; import org.kalypso.commons.java.lang.Objects; import org.kalypso.contribs.eclipse.core.runtime.StatusUtilities; import org.kalypso.contribs.eclipse.jface.operation.ICoreRunnableWithProgress; import org.kalypso.contribs.eclipse.ui.progress.ProgressUtilities; import org.kalypso.gmlschema.property.IPropertyType; import org.kalypso.model.wspm.core.KalypsoModelWspmCoreExtensions; import org.kalypso.model.wspm.core.gml.IProfileFeature; import org.kalypso.model.wspm.core.profil.IProfile; import org.kalypso.model.wspm.core.profil.IProfilePointMarker; import org.kalypso.model.wspm.core.profil.IProfilePointPropertyProvider; import org.kalypso.model.wspm.core.profil.util.ProfileUtil; import org.kalypso.model.wspm.core.profil.visitors.ProfileVisitors; import org.kalypso.model.wspm.core.profil.wrappers.IProfileRecord; import org.kalypso.model.wspm.core.util.WspmProfileHelper; import org.kalypso.model.wspm.ui.KalypsoModelWspmUIPlugin; import org.kalypso.model.wspm.ui.i18n.Messages; import org.kalypso.observation.result.IComponent; import org.kalypso.observation.result.IRecord; import org.kalypso.ogc.gml.IKalypsoFeatureTheme; import org.kalypso.ogc.gml.command.ChangeFeaturesCommand; import org.kalypso.ogc.gml.command.FeatureChange; import org.kalypsodeegree.KalypsoDeegreePlugin; import org.kalypsodeegree.model.feature.Feature; import org.kalypsodeegree.model.feature.FeatureList; import org.kalypsodeegree.model.feature.GMLWorkspace; import org.kalypsodeegree.model.geometry.GM_Curve; import org.kalypsodeegree.model.geometry.GM_Envelope; import org.kalypsodeegree.model.geometry.GM_Exception; import org.kalypsodeegree.model.geometry.GM_Object; import org.kalypsodeegree.model.geometry.GM_Point; import org.kalypsodeegree_impl.model.geometry.JTSAdapter; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.MultiPoint; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; /** * @author Gernot Belger */ public class CreateDividerOperation implements ICoreRunnableWithProgress { private final List<FeatureChange> m_changes = new ArrayList<>(); private final Object[] m_profileFeatures; private final FeatureList m_lineFeatures; private final IPropertyType m_lineGeomProperty; private final IComponent m_deviderType; private final boolean m_useExisting; private final IKalypsoFeatureTheme m_commandTarget; public CreateDividerOperation(final Object[] choosen, final FeatureList lineFeatures, final IPropertyType lineGeomProperty, final IComponent deviderType, final boolean useExisting, final IKalypsoFeatureTheme commandTarget) { m_profileFeatures = choosen; m_lineFeatures = lineFeatures; m_lineGeomProperty = lineGeomProperty; m_deviderType = deviderType; m_useExisting = useExisting; m_commandTarget = commandTarget; } @Override public IStatus execute(final IProgressMonitor monitor) throws InvocationTargetException { try { createDevider(monitor); final FeatureChange[] changes = m_changes.toArray(new FeatureChange[m_changes.size()]); if (changes.length > 0) { final GMLWorkspace gmlworkspace = changes[0].getFeature().getWorkspace(); final ICommand command = new ChangeFeaturesCommand(gmlworkspace, changes); m_commandTarget.postCommand(command, null); } } catch (final Exception e) { throw new InvocationTargetException(e); } return Status.OK_STATUS; } protected void createDevider(final IProgressMonitor monitor) { monitor.beginTask(Messages.getString("org.kalypso.model.wspm.ui.wizard.CreateProfileDeviderWizard.6"), //$NON-NLS-1$ m_profileFeatures.length); for (final Object object : m_profileFeatures) { try { final IProfileFeature profile = (IProfileFeature) object; monitor.subTask(String.format("%s (km %s)", profile.getName(), profile.getBigStation())); //$NON-NLS-1$ final IProfile profil = profile.getProfile(); // create marker for each point final Integer[] newMarkerPoints = findNewMarkerPoints(profile); createNewDevider(profil, newMarkerPoints); } catch (final GM_Exception e) { final IStatus status = StatusUtilities.statusFromThrowable(e); KalypsoModelWspmUIPlugin.getDefault().getLog().log(status); } ProgressUtilities.worked(monitor, 1); } } private Integer[] findNewMarkerPoints(final IProfileFeature profile) throws GM_Exception { final Point[] intersectionPoints = findNewMarkerLocations(profile); final IProfile profil = profile.getProfile(); final double[] intersectionWidths = getIntersectionWidths(profil, intersectionPoints); final Integer[] nearestPointIndices = ProfileUtil.findNearestPointIndices(profil, intersectionWidths); final Integer[] bestMarkers = findBestMarkers(profil, nearestPointIndices); final Integer[] cleanMarkers = cleanupMarkers(profil, bestMarkers); return cleanMarkers; } /** * Makes sure we always have exactly two markers.<br> * If we have too many, we take the outermost markers.<br> * If we have too less, we add markers at profile end or beginning. */ private Integer[] cleanupMarkers(final IProfile profil, final Integer[] bestMarkers) { final IRecord[] points = profil.getPoints(); if (points.length < 2) return new Integer[0]; final int first = 0; final int last = points.length - 1; switch (bestMarkers.length) { case 0: return new Integer[] { first, last }; case 1: { final Integer oneIndex = bestMarkers[0]; final IProfileRecord lowestPoint = ProfileVisitors.findLowestPoint(profil); if (Objects.isNull(lowestPoint)) return new Integer[] { oneIndex }; if (oneIndex < lowestPoint.getIndex()) return new Integer[] { oneIndex, last }; else return new Integer[] { first, oneIndex }; } case 2: return bestMarkers; // > 2 default: return findOutermost(bestMarkers); } } private Integer[] findBestMarkers(final IProfile profil, final Integer[] nearestPointIndices) { /* Clear points that are contained multiple times */ final Set<Integer> nearestPointSet = new HashSet<>(Arrays.asList(nearestPointIndices)); nearestPointSet.remove(null); final Integer[] uniqueIntersectionPoints = nearestPointSet.toArray(new Integer[nearestPointSet.size()]); if (m_useExisting) return findBestMarkersAndKeepExisting(profil, uniqueIntersectionPoints); else return findBestMarkersAndDeleteExisting(uniqueIntersectionPoints); } private Integer[] findBestMarkersAndDeleteExisting(final Integer[] intersectionPoints) { switch (intersectionPoints.length) { case 0: return new Integer[0]; case 1: case 2: return intersectionPoints; default: return findOutermost(intersectionPoints); } } private Integer[] findBestMarkersAndKeepExisting(final IProfile profil, final Integer[] intersectionPoints) { switch (intersectionPoints.length) { case 0: return existingMarkersAsIndices(profil); case 1: return mixExistingWithIntersectionPoint(profil, intersectionPoints[0]); case 2: return intersectionPoints; default: return findOutermost(intersectionPoints); } } private Integer[] findOutermost(final Integer[] intersectionPoints) { Assert.isTrue(intersectionPoints.length > 1); final Integer[] result = new Integer[2]; final SortedSet<Integer> markerIndices = new TreeSet<>(Arrays.asList(intersectionPoints)); result[0] = markerIndices.first(); result[1] = markerIndices.last(); return result; } private Integer[] mixExistingWithIntersectionPoint(final IProfile profil, final Integer intersectionIndex) { final Integer[] markerPoints = existingMarkersAsIndices(profil); final SortedSet<Integer> markerIndices = new TreeSet<>(Arrays.asList(markerPoints)); // depends on the side of the profile! final IProfileRecord lowestPoint = ProfileVisitors.findLowestPoint(profil); if (Objects.isNull(lowestPoint)) return new Integer[] { intersectionIndex }; final Collection<Integer> result = new ArrayList<>(2); result.add(intersectionIndex); if (intersectionIndex > lowestPoint.getIndex()) { // use leftmost of all left markers final SortedSet<Integer> leftSet = markerIndices.headSet(lowestPoint.getIndex()); if (!leftSet.isEmpty()) { result.add(leftSet.first()); } } else { // use leftmost of all left markers final SortedSet<Integer> rightSet = markerIndices.tailSet(lowestPoint.getIndex()); if (!rightSet.isEmpty()) { result.add(rightSet.last()); } } return result.toArray(new Integer[result.size()]); } private Integer[] existingMarkersAsIndices(final IProfile profil) { final IProfilePointMarker[] existingMarkers = profil.getPointMarkerFor(m_deviderType); final Integer[] asPoints = new Integer[existingMarkers.length]; for (int i = 0; i < asPoints.length; i++) { final IProfileRecord markerPoint = existingMarkers[i].getPoint(); asPoints[i] = markerPoint.getIndex(); } return asPoints; } private Point[] findNewMarkerLocations(final IProfileFeature profile) throws GM_Exception { final GM_Curve curve = profile.getLine(); if (curve == null) return new Point[0]; final LineString profileLine = (LineString) JTSAdapter.export(curve); // find intersectors with curve final GM_Envelope curveEnvelope = curve.getEnvelope(); @SuppressWarnings("unchecked") final List<?> lineIntersectors = m_lineFeatures.query(curveEnvelope, null); final List<Point> pointList = new ArrayList<>(); for (final Object lineF : lineIntersectors) { final Feature lineFeature = (Feature) lineF; final Geometry line = getAsLine(lineFeature); if (line == null) { continue; } // find intersecting points final Geometry intersection = profileLine.intersection(line); final Point[] points = getPointFromGeometry(intersection); Collections.addAll(pointList, points); } return pointList.toArray(new Point[pointList.size()]); } private Geometry getAsLine(final Feature lineFeature) throws GM_Exception { final GM_Object lineGeom = (GM_Object) lineFeature.getProperty(m_lineGeomProperty); if (lineGeom == null) return null; final Geometry lineGeometry = JTSAdapter.export(lineGeom); if (lineGeometry instanceof Polygon || lineGeometry instanceof MultiPolygon) return lineGeometry.getBoundary(); return lineGeometry; } private static Point[] getPointFromGeometry(final Geometry points) { if (points instanceof Point) return new Point[] { (Point) points }; if (points instanceof MultiPoint) { final MultiPoint mp = (MultiPoint) points; final Point[] result = new Point[mp.getNumGeometries()]; for (int i = 0; i < result.length; i++) { result[i] = (Point) mp.getGeometryN(i); } return result; } return new Point[] {}; } /** * At the moment, only existing points are taken */ private boolean createNewDevider(final IProfile profil, final Integer[] newMarkerPoints) { /** Clear existing points */ final IProfilePointMarker[] existingMarkers = profil.getPointMarkerFor(m_deviderType); for (final IProfilePointMarker marker : existingMarkers) { profil.removePointMarker(marker); } /** Add new Points */ final IProfilePointPropertyProvider provider = KalypsoModelWspmCoreExtensions .getPointPropertyProviders(profil.getType()); final String id = m_deviderType.getId(); boolean markerHasBeenAdded = false; for (final Integer markerIndex : newMarkerPoints) { if (markerIndex != null) { final IProfileRecord markerPoint = profil.getPoint(markerIndex); final IProfilePointMarker marker = profil.createPointMarker(id, markerPoint); final Object defaultValue = provider.getDefaultValue(id); marker.setValue(defaultValue); markerHasBeenAdded = true; } } return markerHasBeenAdded; } private double[] getIntersectionWidths(final IProfile profil, final Point[] intersectionPoints) { final Collection<Double> widthList = new ArrayList<>(intersectionPoints.length); for (final Point point : intersectionPoints) { try { final GM_Point p = (GM_Point) JTSAdapter.wrap(point, KalypsoDeegreePlugin.getDefault().getCoordinateSystem()); final Double width = WspmProfileHelper.getWidthPosition(p, profil); if (width != null) { widthList.add(width); } } catch (final Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } final Double[] widths = widthList.toArray(new Double[widthList.size()]); return ArrayUtils.toPrimitive(widths); } }