/** * Tests if the areas have some intersections to join. * * @param areas Areas to test * @return @{code true} if areas are joinable */ private boolean testJoin(List<Multipolygon> areas) { List<Way> allStartingWays = new ArrayList<Way>(); for (Multipolygon area : areas) { allStartingWays.add(area.outerWay); allStartingWays.addAll(area.innerWays); } // find intersection points Set<Node> nodes = Geometry.addIntersections(allStartingWays, true, cmds); return !nodes.isEmpty(); }
/** * Will join two or more overlapping areas * * @param areas list of areas to join * @return new area formed. */ private JoinAreasResult joinAreas(List<Multipolygon> areas) throws UserCancelException { JoinAreasResult result = new JoinAreasResult(); result.hasChanges = false; List<Way> allStartingWays = new ArrayList<Way>(); List<Way> innerStartingWays = new ArrayList<Way>(); List<Way> outerStartingWays = new ArrayList<Way>(); for (Multipolygon area : areas) { outerStartingWays.add(area.outerWay); innerStartingWays.addAll(area.innerWays); } allStartingWays.addAll(innerStartingWays); allStartingWays.addAll(outerStartingWays); // first remove nodes in the same coordinate boolean removedDuplicates = false; removedDuplicates |= removeDuplicateNodes(allStartingWays); if (removedDuplicates) { result.hasChanges = true; commitCommands(marktr("Removed duplicate nodes")); } // find intersection points Set<Node> nodes = Geometry.addIntersections(allStartingWays, false, cmds); // no intersections, return. if (nodes.isEmpty()) return result; commitCommands(marktr("Added node on all intersections")); List<RelationRole> relations = new ArrayList<RelationRole>(); // Remove ways from all relations so ways can be combined/split quietly for (Way way : allStartingWays) { relations.addAll(removeFromAllRelations(way)); } // Don't warn now, because it will really look corrupted boolean warnAboutRelations = !relations.isEmpty() && allStartingWays.size() > 1; List<WayInPolygon> preparedWays = new ArrayList<WayInPolygon>(); for (Way way : outerStartingWays) { List<Way> splitWays = splitWayOnNodes(way, nodes); preparedWays.addAll(markWayInsideSide(splitWays, false)); } for (Way way : innerStartingWays) { List<Way> splitWays = splitWayOnNodes(way, nodes); preparedWays.addAll(markWayInsideSide(splitWays, true)); } // Find boundary ways List<Way> discardedWays = new ArrayList<Way>(); List<AssembledPolygon> bounadries = findBoundaryPolygons(preparedWays, discardedWays); // find polygons List<AssembledMultipolygon> preparedPolygons = findPolygons(bounadries); // assemble final polygons List<Multipolygon> polygons = new ArrayList<Multipolygon>(); Set<Relation> relationsToDelete = new LinkedHashSet<Relation>(); for (AssembledMultipolygon pol : preparedPolygons) { // create the new ways Multipolygon resultPol = joinPolygon(pol); // create multipolygon relation, if necessary. RelationRole ownMultipolygonRelation = addOwnMultigonRelation(resultPol.innerWays, resultPol.outerWay); // add back the original relations, merged with our new multipolygon relation fixRelations(relations, resultPol.outerWay, ownMultipolygonRelation, relationsToDelete); // strip tags from inner ways // TODO: preserve tags on existing inner ways stripTags(resultPol.innerWays); polygons.add(resultPol); } commitCommands(marktr("Assemble new polygons")); for (Relation rel : relationsToDelete) { cmds.add(new DeleteCommand(rel)); } commitCommands(marktr("Delete relations")); // Delete the discarded inner ways if (!discardedWays.isEmpty()) { Command deleteCmd = DeleteCommand.delete(Main.main.getEditLayer(), discardedWays, true); if (deleteCmd != null) { cmds.add(deleteCmd); commitCommands(marktr("Delete Ways that are not part of an inner multipolygon")); } } makeCommitsOneAction(marktr("Joined overlapping areas")); if (warnAboutRelations) { new Notification( tr( "Some of the ways were part of relations that have been modified.<br>Please verify no errors have been introduced.")) .setIcon(JOptionPane.INFORMATION_MESSAGE) .setDuration(Notification.TIME_LONG) .show(); } result.hasChanges = true; result.polygons = polygons; return result; }