Ignore:
Timestamp:
2010-05-11T08:41:44+02:00 (14 years ago)
Author:
stoecker
Message:

fix #4995 - improve area joinging reliability

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java

    r3083 r3230  
    184184        boolean hadChanges = false;
    185185        if(!same) {
     186            int i = 0;
    186187            if(checkForTagConflicts(a, b)) return true; // User aborted, so don't warn again
    187             hadChanges = joinAreas(a, a);
    188             hadChanges = joinAreas(b, b) || hadChanges;
     188            if(joinAreas(a, a))
     189                ++i;
     190            if(joinAreas(b, b))
     191                ++i;
     192            hadChanges = i > 0;
     193            cmdsCount = i;
    189194        }
    190195
     
    212217
    213218        // Fix Multipolygons if there are any
    214         Collection<Way> newInnerWays = fixMultigons(innerWays, outerWay);
     219        Collection<Way> newInnerWays = fixMultipolygons(innerWays, outerWay, same);
    215220
    216221        // Delete the remaining inner ways
     
    251256
    252257        // FIXME: This is mostly copied and pasted from CombineWayAction.java and one day should be moved into tools
     258        // We have TagCollection handling for that now - use it here as well
    253259        Map<String, Set<String>> props = new TreeMap<String, Set<String>>();
    254260        for (Way w : ways) {
     
    274280                if("created_by".equals(e.getKey()))
    275281                {
    276                     ax.put("created_by", "JOSM");
    277                     bx.put("created_by", "JOSM");
     282                    ax.remove("created_by");
     283                    bx.remove("created_by");
    278284                } else {
    279285                    JComboBox c = new JComboBox(e.getValue().toArray());
     
    409415     */
    410416    private void addNodesToWay(Way a, ArrayList<NodeToSegs> nodes) {
     417        if(nodes.size() == 0)
     418            return;
    411419        Way ax=new Way(a);
    412420        Collections.sort(nodes);
     
    640648            a = b;
    641649        }
    642         Main.main.getCurrentDataSet().setSelected(ways);
    643         // TODO: It might be possible that a confirmation dialog is presented even after reversing (for
    644         // "strange" ways). If the user cancels this, makeCommitsOneAction will wrongly consume a previous
    645         // action. Make CombineWayAction either silent or expose its combining capabilities.
    646         new CombineWayAction().actionPerformed(null);
    647         cmdsCount++;
    648         return (Way)(Main.main.getCurrentDataSet().getSelectedWays().toArray())[0];
     650        if((a = new CombineWayAction().combineWays(ways)) != null)
     651            cmdsCount++;
     652        return a;
    649653    }
    650654
     
    656660     * @return ArrayList<Way> The List of newly created inner ways
    657661     */
    658     private ArrayList<Way> fixMultigons(Collection<Way> uninterestingWays, Way outerWay) {
     662    private ArrayList<Way> fixMultipolygons(Collection<Way> uninterestingWays, Way outerWay, boolean selfintersect) {
    659663        Collection<Node> innerNodes = getNodesFromWays(uninterestingWays);
    660664        Collection<Node> outerNodes = outerWay.getNodes();
     
    672676            for(Node n : w.getNodes()) {
    673677                if(outerNodes.contains(n)) {
    674                     continue wayIterator;
    675                 }
    676                 if(!hasInnerNodes && innerNodes.contains(n)) {
     678                    if(!selfintersect) // allow outer point for self intersection
     679                        continue wayIterator;
     680                }
     681                else if(!hasInnerNodes && innerNodes.contains(n)) {
    677682                    hasInnerNodes = true;
    678683                }
     
    686691        // This removes unnecessary ways that might have been added.
    687692        removeAlmostAlikeWays(possibleWays);
    688         removePartlyUnconnectedWays(possibleWays);
    689 
    690         // Join all ways that have one start/ending node in common
    691         Way joined = null;
    692         outerIterator: do {
    693             joined = null;
    694             for(Way w1 : possibleWays) {
    695                 if(w1.isClosed()) {
    696                     if(!wayIsCollapsed(w1)) {
    697                         uninterestingWays.remove(w1);
    698                         newInnerWays.add(w1);
     693
     694        // loop twice
     695        // in k == 0 prefer ways which allow no Y-joining (i.e. which have only 1 solution)
     696        for(int k = 0; k < 2; ++k)
     697        {
     698            // Join all ways that have one start/ending node in common
     699            Way joined = null;
     700            outerIterator: do {
     701                removePartlyUnconnectedWays(possibleWays);
     702                joined = null;
     703                for(Way w1 : possibleWays) {
     704                    if(w1.isClosed()) {
     705                        if(!wayIsCollapsed(w1)) {
     706                            uninterestingWays.remove(w1);
     707                            newInnerWays.add(w1);
     708                        }
     709                        joined = w1;
     710                        possibleWays.remove(w1);
     711                        continue outerIterator;
    699712                    }
    700                     joined = w1;
    701                     possibleWays.remove(w1);
    702                     continue outerIterator;
    703                 }
    704                 for(Way w2 : possibleWays) {
    705                     // w2 cannot be closed, otherwise it would have been removed above
    706                     if(!waysCanBeCombined(w1, w2)) {
    707                         continue;
     713                    ArrayList<Way> secondary = new ArrayList<Way>();
     714                    for(Way w2 : possibleWays) {
     715                        int i = 0;
     716                        // w2 cannot be closed, otherwise it would have been removed above
     717                        if(w1.equals(w2))
     718                            continue;
     719                        if(w2.isFirstLastNode(w1.firstNode()))
     720                            ++i;
     721                        if(w2.isFirstLastNode(w1.lastNode()))
     722                            ++i;
     723                        if(i == 2) // this way closes w1 - take it!
     724                        {
     725                            if(secondary.size() > 0)
     726                                secondary.clear();
     727                            secondary.add(w2);
     728                            break;
     729                        }
     730                        else if(i > 0)
     731                            secondary.add(w2);
    708732                    }
    709 
    710                     ArrayList<Way> joinThem = new ArrayList<Way>();
    711                     joinThem.add(w1);
    712                     joinThem.add(w2);
    713                     uninterestingWays.removeAll(joinThem);
    714                     possibleWays.removeAll(joinThem);
    715 
    716                     // Although we joined the ways, we cannot simply assume that they are closed
    717                     joined = joinWays(joinThem);
    718                     uninterestingWays.add(joined);
    719                     possibleWays.add(joined);
    720                     continue outerIterator;
    721                 }
    722             }
    723         } while(joined != null);
     733                    if(k == 0 ? secondary.size() == 1 : secondary.size() > 0)
     734                    {
     735                        ArrayList<Way> joinThem = new ArrayList<Way>();
     736                        joinThem.add(w1);
     737                        joinThem.add(secondary.get(0));
     738                        // Although we joined the ways, we cannot simply assume that they are closed
     739                        if((joined = joinWays(joinThem)) != null)
     740                        {
     741                            uninterestingWays.removeAll(joinThem);
     742                            possibleWays.removeAll(joinThem);
     743
     744                            List<Node> nodes = joined.getNodes();
     745                            // check if we added too much
     746                            /*for(int i = 1; i < nodes.size()-2; ++i)
     747                            {
     748                                if(nodes.get(i) == nodes.get(nodes.size()-1))
     749                                    System.out.println("Joining of ways produced unexpecteded result\n");
     750                            }*/
     751                            uninterestingWays.add(joined);
     752                            possibleWays.add(joined);
     753                            continue outerIterator;
     754                        }
     755                    }
     756                }
     757            } while(joined != null);
     758        }
    724759        return newInnerWays;
    725760    }
     
    795830            if(count == 2) return true;
    796831        }
    797         return false;
    798     }
    799 
    800     /**
    801      * Checks if two ways share one starting/ending node
    802      * @param Way first way
    803      * @param Way second way
    804      * @return boolean Wheter the ways share a starting/ending node or not
    805      */
    806     private boolean waysCanBeCombined(Way w1, Way w2) {
    807         if(w1.equals(w2)) return false;
    808 
    809         if(w1.getNode(0).equals(w2.getNode(0))) return true;
    810         if(w1.getNode(0).equals(w2.getNode(w2.getNodesCount()-1))) return true;
    811 
    812         if(w1.getNode(w1.getNodesCount()-1).equals(w2.getNode(0))) return true;
    813         if(w1.getNode(w1.getNodesCount()-1).equals(w2.getNode(w2.getNodesCount()-1))) return true;
    814 
    815832        return false;
    816833    }
Note: See TracChangeset for help on using the changeset viewer.