/* * Copyright (C) 2015 Alec Dhuse * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package co.foldingmap.actions; import co.foldingmap.map.vector.VectorLayer; import co.foldingmap.map.vector.CoordinateList; import co.foldingmap.map.vector.CoordinateMath; import co.foldingmap.map.vector.VectorObject; import co.foldingmap.map.vector.VectorObjectList; import co.foldingmap.map.vector.Coordinate; import co.foldingmap.map.vector.MapPoint; import co.foldingmap.map.vector.LineString; import co.foldingmap.map.vector.Polygon; import co.foldingmap.GUISupport.Updateable; import co.foldingmap.Logger; import co.foldingmap.map.DigitalMap; import co.foldingmap.map.Layer; import java.util.ArrayList; /** * Takes a list of MapObjects and creates a new object form one or more parts * of the given list. * * @author Alec */ public class TraceMerge extends Action { private final ArrayList<Updateable> updateables; private final CoordinateList<Coordinate> coordinatesToMerge; private DigitalMap mapData; private VectorObject newObject; private final VectorObjectList<VectorObject> objectsToMerge; public TraceMerge(DigitalMap mapData, VectorObjectList<VectorObject> objectsToMerge, CoordinateList<Coordinate> coordinatesToMerge, ArrayList<Updateable> updateables) { this.commandDescription = "Trace Merge"; this.coordinatesToMerge = coordinatesToMerge.clone(); this.mapData = mapData; this.objectsToMerge = objectsToMerge; this.updateables = updateables; } /** * Returns if this Action can be undone. * * @return */ @Override public boolean canUndo() { return true; } @Override public void execute() { VectorLayer parentLayer; try { newObject = null; parentLayer = null; if (coordinatesToMerge.size() == 1) { //create point newObject = new MapPoint("New Point", "(Unspecified Point)", "", coordinatesToMerge.get(0)); } else if (coordinatesToMerge.size() > 1) { if (coordinatesToMerge.lastCoordinate().equals(coordinatesToMerge.get(0))) { //make a Polygon coordinatesToMerge.remove(coordinatesToMerge.lastCoordinate()); newObject = new co.foldingmap.map.vector.Polygon("New Polygon", "(Unspecified Polygon)", coordinatesToMerge); } else { //make a LineString newObject = new co.foldingmap.map.vector.LineString("New LineString", "(Unspecified Linestring)", coordinatesToMerge); } } if (newObject != null) { for (Coordinate c: coordinatesToMerge) { c.addParent(newObject); c.incrementPullCount(); } /* * Run a check to see if all the objects points, if they are * remove the points. */ if (objectsToMerge.getMapPoints().size() == objectsToMerge.size()) { for (VectorObject vo: objectsToMerge) { parentLayer = (VectorLayer) vo.getParentLayer(); parentLayer.removeObject(vo); vo.getCoordinateList().removeParentObject(vo); } } if (mapData.getSelectedLayer() instanceof VectorLayer) { parentLayer = (VectorLayer) mapData.getSelectedLayer(); } else { for (Layer l: mapData.getLayers()) { if (l instanceof VectorLayer) parentLayer = (VectorLayer) l; break; } } if (parentLayer == null) { parentLayer = new VectorLayer("New Layer"); mapData.addLayer(parentLayer); } parentLayer.addObject(newObject); newObject.setHighlighted(true); mapData.getSelectedObjects().add(newObject); } for (Updateable u: updateables) u.update(); } catch (Exception e) { Logger.log(Logger.ERR, "Error in TraceMerge.execute() - " + e); } } private void generalMerge() { VectorObject currentObject; VectorLayer parentLayer; //If objects are MapPoints, remove them for (int i = 0; i < objectsToMerge.size(); i++) { currentObject = objectsToMerge.get(i); if (currentObject instanceof MapPoint) { parentLayer = (VectorLayer) currentObject.getParentLayer(); parentLayer.removeObject(currentObject); } } // end for loop if (coordinatesToMerge.get(0) == coordinatesToMerge.lastCoordinate()) { //polygon coordinatesToMerge.remove(coordinatesToMerge.size() - 1); newObject = new Polygon("New Polgon", "(Unspecified Polygon)", coordinatesToMerge); } else { if (objectsToMerge.get(0) == objectsToMerge.lastElement() && objectsToMerge.get(0) instanceof LineString) { /** The first and last object is the same LineString * Create a Polygon using the coordinates in between the * the two coordinates selected. */ LineString tempLine = (LineString) objectsToMerge.get(0); CoordinateList<Coordinate> tempLineCoordinatesToUse = tempLine.getCoordinateList().getCoordinatesBetween( coordinatesToMerge.get(0), coordinatesToMerge.lastCoordinate()); //remove the first and last coordinate coordinatesToMerge.remove(coordinatesToMerge.get(0)); coordinatesToMerge.remove(coordinatesToMerge.lastCoordinate()); //add in the coordinates from the LineStirng tempLineCoordinatesToUse.reverse(); coordinatesToMerge.addAll(tempLineCoordinatesToUse); //create the polygon newObject = new Polygon("New Polgon", "(Unspecified Polygon)", coordinatesToMerge); } else { //lineString newObject = new LineString("New Line", "(Unspecified Linestring)", coordinatesToMerge); } } //Get the parent layer of the first object, that is where the new object will go. parentLayer = (VectorLayer) objectsToMerge.get(0).getParentLayer(); parentLayer.addObject(newObject); mapData.deselectObjects(); mapData.setSelected(newObject); } private void lineStringMerge() { CoordinateList line1Coordinates, line2Coordinates, newLineCoordinates; double firstFirst, firstLast; double lastFirst, lastLast; LineString line1, line2; VectorObject currentObject; VectorLayer parentLayer; line1 = (LineString) objectsToMerge.get(0); line2 = (LineString) objectsToMerge.get(1); line1Coordinates = line1.getCoordinateList(); line2Coordinates = line2.getCoordinateList(); newLineCoordinates = new CoordinateList(); if ((line1.isEndPoint(coordinatesToMerge.get(0)) && line2.isEndPoint(coordinatesToMerge.get(1))) || (line1.isEndPoint(coordinatesToMerge.get(1)) && line2.isEndPoint(coordinatesToMerge.get(0)))) { firstFirst = CoordinateMath.getDistance(line1.firstCoordinate(), line2.firstCoordinate()); firstLast = CoordinateMath.getDistance(line1.firstCoordinate(), line2.lastCoordinate()); lastFirst = CoordinateMath.getDistance(line1.lastCoordinate(), line2.firstCoordinate()); lastLast = CoordinateMath.getDistance(line1.lastCoordinate(), line2.lastCoordinate()); if ((firstFirst < firstLast) && (firstFirst < lastFirst) && (firstFirst < lastLast)) { newLineCoordinates = line2Coordinates.clone(); newLineCoordinates.reverse(); newLineCoordinates.addAll(line1Coordinates); } else if ((firstLast < firstFirst) && (firstLast < lastFirst) && (firstLast < lastLast)) { newLineCoordinates = line2Coordinates.clone(); newLineCoordinates.addAll(line1Coordinates); } else if ((lastFirst < firstFirst) && (lastFirst < firstLast) && (lastFirst < lastLast)) { newLineCoordinates = line1Coordinates.clone(); newLineCoordinates.addAll(line2Coordinates); } else if ((lastLast < firstFirst) && (lastLast < firstLast) && (lastLast < lastFirst)) { newLineCoordinates = line1Coordinates.clone(); newLineCoordinates.reverse(); newLineCoordinates.addAll(line2Coordinates); } for (int i = 0; i < objectsToMerge.size(); i++) { currentObject = objectsToMerge.get(i); parentLayer = (VectorLayer) currentObject.getParentLayer(); parentLayer.removeObject(currentObject); } currentObject = line1.copy(); parentLayer = (VectorLayer) line1.getParentLayer(); currentObject.setCoordinateList(newLineCoordinates); parentLayer.addObject(currentObject); } else { //connect aka join if (line1.getCoordinateList().lastCoordinate().equals(coordinatesToMerge.get(1))) { //the coordinate to extend from is the last coordinate, just add on line1.getCoordinateList().add(coordinatesToMerge.get(1)); } else { //coordinate to extend from is first, we must prepend line1.prependCoordinate(coordinatesToMerge.get(1)); } } } @Override public void undo() { VectorObject currentObject; VectorLayer parentLayer; parentLayer = (VectorLayer) newObject.getParentLayer(); parentLayer.removeObject(newObject); for (int i = 0; i < objectsToMerge.size(); i++) { currentObject = objectsToMerge.get(i); if (currentObject instanceof MapPoint) { parentLayer = (VectorLayer) currentObject.getParentLayer(); parentLayer.addObject(currentObject); } } parentLayer = (VectorLayer) newObject.getParentLayer(); parentLayer.removeObject(newObject); for (Updateable u: updateables) u.update(); } }