Ignore:
Timestamp:
2011-10-12T23:23:14+02:00 (13 years ago)
Author:
zverik
Message:

Almost works

Location:
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SplittingMultipolygons.java

    r26837 r26844  
    5555   
    5656    public static List<Relation> process( Collection<Way> selectedWays, List<Command> commands ) {
     57        System.out.println("---------------------------------------");
    5758        List<Relation> result = new ArrayList<Relation>();
    5859        List<Way> rings = new ArrayList<Way>();
     
    279280   
    280281    /**
    281      * Find a way the tips of a segment, ensure it's in a multipolygon and try to close the relation.
    282      */
    283     public static Relation attachRingToNeighbours( Way segment, List<Command> resultingCommands ) {
    284         if( !segment.isClosed() || segment.isIncomplete() )
     282     * Make a multipolygon out of the ring, but split it to attach to neighboring multipolygons.
     283     */
     284    public static Relation attachRingToNeighbours( Way ring, List<Command> resultingCommands ) {
     285        if( !ring.isClosed() || ring.isIncomplete() )
    285286            return null;
    286        
    287         return null; // todo
     287        Map<Way, Boolean> touchingWays = new HashMap<Way, Boolean>();
     288        for( Node n : ring.getNodes() ) {
     289            for( OsmPrimitive p : n.getReferrers() ) {
     290                if( p instanceof Way && !p.equals(ring) ) {
     291                    for( OsmPrimitive r : p.getReferrers() ) {
     292                        if( r instanceof Relation && ((Relation)r).hasKey("type") && ((Relation)r).get("type").equals("multipolygon") ) {
     293                            if( touchingWays.containsKey((Way)p) )
     294                                touchingWays.put((Way)p, Boolean.TRUE);
     295                            else
     296                                touchingWays.put((Way)p, Boolean.FALSE);
     297                            break;
     298                        }
     299                    }
     300                }
     301            }
     302        }
     303       
     304        List<TheRing> otherWays = new ArrayList<TheRing>();
     305        for( Way w : touchingWays.keySet() )
     306            if( touchingWays.get(w) ) {
     307                otherWays.add(new TheRing(w));
     308                System.out.println("Touching ring: " + otherWays.get(otherWays.size()-1));
     309            }
     310       
     311//      for( Iterator<Way> keys = touchingWays.keySet().iterator(); keys.hasNext(); ) {
     312//          if( !touchingWays.get(keys.next()) )
     313//              keys.remove();
     314//      }
     315       
     316        // now touchingWays has only ways that touch the ring twice
     317        List<Command> commands = new ArrayList<Command>();
     318        TheRing theRing = new TheRing(ring); // this is actually useful
     319       
     320        for( TheRing otherRing : otherWays )
     321            theRing.collide(otherRing);
     322       
     323        theRing.putSourceWayFirst();
     324        for( TheRing otherRing : otherWays )
     325            otherRing.putSourceWayFirst();
     326       
     327        for( TheRing otherRing : otherWays )
     328            commands.addAll(otherRing.getCommands(false));
     329        commands.addAll(theRing.getCommands());
     330        resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}",
     331                DefaultNameFormatter.getInstance().format(ring)), commands));
     332        return theRing.getRelation();
    288333    }
    289334}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java

    r26837 r26844  
    8181                    RingSegment segment2 = other.segments.get(j);
    8282                    if( !segment2.isReference() ) {
    83                         List<Node> nodes1 = segment1.getNodes();
    84                         List<Node> nodes2 = segment2.getNodes();
    85                         boolean isRing1 = segment1.isRing();
    86                         boolean isRing2 = segment2.isRing();
    87 
    88                         int pos = 0;
    89                         while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )
    90                             pos++;
    91                         boolean collideFound = pos == nodes1.size();
    92                         if( pos == 0 && isRing1 ) {
    93                             // rewind a bit
    94                             pos = nodes1.size() - 1;
    95                             while( pos > 0 && nodes2.contains(nodes1.get(pos)) ) pos--;
    96                             if( pos == 0 ) {
    97                                 JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
    98                                 return;
     83                        System.out.println("Comparing " + segment1 + " and " + segment2);
     84                        Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());
     85                        if( split != null ) {
     86                            if( !collideNoted ) {
     87                                System.out.println("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
     88                                collideNoted = true;
    9989                            }
    100                             pos = pos == nodes1.size() ? 0 : pos + 1;
    101                         }
    102                         System.out.println("Comparing " + segment1 + " and " + segment2);
    103                         int firstPos = isRing1 ? pos : nodes1.size();
    104                         while( !collideFound ) {
    105                             System.out.println("pos="+pos);
    106                             int start1 = pos;
    107                             int start2 = nodes2.indexOf(nodes1.get(start1));
    108                             int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
    109                             int last2 = start2;
    110                             int increment2 = 0;
    111                             if( last1 >= 0 ) {
    112                                 last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
    113                                 if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    114                                     increment2 = -1;
    115                                 else {
    116                                     last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
    117                                     if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    118                                         increment2 = 1;
    119                                 }
    120                             }
    121                             System.out.println("last1="+last1+" last2="+last2+" increment2="+increment2);
    122                             if( increment2 != 0 ) {
    123                                 if( !collideNoted ) {
    124                                     System.out.println("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
    125                                     collideNoted = true;
    126                                 }
    127                                 // find the first nodes
    128                                 boolean reachedEnd = false;
    129                                 while( !reachedEnd ) {
    130                                     int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
    131                                     int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
    132                                     if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )
    133                                         reachedEnd = true;
    134                                     else {
    135                                         last1 = newLast1;
    136                                         last2 = newLast2;
    137                                     }
    138                                 }
    139                                 System.out.println("last1=" + last1 + " last2=" + last2);
    140                                 if( increment2 < 0 ) {
    141                                     int tmp = start2;
    142                                     start2 = last2;
    143                                     last2 = tmp;
    144                                 }
    145                                 RingSegment segment = splitRingAt(i, nodes1.get(start1), nodes1.get(last1));
    146                                 RingSegment otherSegment = other.splitRingAt(j, nodes2.get(start2), nodes2.get(last2));
    147                                 if( !areSegmentsEqual(segment, otherSegment) )
    148                                     throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
    149                                 segment.makeReference(otherSegment);
    150                                 collideFound = true;
    151                             } else {
    152                                 pos = last1;
    153                                 while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )
    154                                     pos = incrementBy(pos, 1, nodes1.size(), isRing1);
    155                                 if( pos < 0 || !nodes2.contains(nodes1.get(pos)) )
    156                                     collideFound = true;
    157                             }
     90                            RingSegment segment = splitRingAt(i, split[0], split[1]);
     91                            RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);
     92                            if( !areSegmentsEqual(segment, otherSegment) )
     93                                throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
     94                            segment.makeReference(otherSegment);
    15895                        }
    15996                    }
     
    165102    }
    166103   
    167     private int incrementBy( int value, int increment, int limit1, boolean isRing ) {
     104    /**
     105     * Returns array of {start1, last1, start2, last2} or null if there is no common nodes.
     106     */
     107    public static Node[] getSplitNodes( List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2 ) {
     108        int pos = 0;
     109        while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )
     110            pos++;
     111        boolean collideFound = pos == nodes1.size();
     112        if( pos == 0 && isRing1 ) {
     113            // rewind a bit
     114            pos = nodes1.size() - 1;
     115            while( pos > 0 && nodes2.contains(nodes1.get(pos)) )
     116                pos--;
     117            if( pos == 0 ) {
     118                JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
     119                return null;
     120            }
     121            pos = pos == nodes1.size() - 1 ? 0 : pos + 1;
     122        }
     123        int firstPos = isRing1 ? pos : nodes1.size();
     124        while( !collideFound ) {
     125            System.out.println("pos=" + pos);
     126            int start1 = pos;
     127            int start2 = nodes2.indexOf(nodes1.get(start1));
     128            int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
     129            int last2 = start2;
     130            int increment2 = 0;
     131            if( last1 >= 0 ) {
     132                last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
     133                if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
     134                    increment2 = -1;
     135                else {
     136                    last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
     137                    if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
     138                        increment2 = 1;
     139                }
     140            }
     141            System.out.println("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);
     142            if( increment2 != 0 ) {
     143                // find the first nodes
     144                boolean reachedEnd = false;
     145                while( !reachedEnd ) {
     146                    int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
     147                    int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
     148                    if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )
     149                        reachedEnd = true;
     150                    else {
     151                        last1 = newLast1;
     152                        last2 = newLast2;
     153                    }
     154                }
     155                System.out.println("last1=" + last1 + " last2=" + last2);
     156                if( increment2 < 0 ) {
     157                    int tmp = start2;
     158                    start2 = last2;
     159                    last2 = tmp;
     160                }
     161                return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};
     162            } else {
     163                pos = last1;
     164                while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )
     165                    pos = incrementBy(pos, 1, nodes1.size(), isRing1);
     166                if( pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) )
     167                    collideFound = true;
     168            }
     169        }
     170        return null;
     171    }
     172   
     173    private static int incrementBy( int value, int increment, int limit1, boolean isRing ) {
    168174        int result = value + increment;
    169175        if( result < 0 )
     
    216222        if( thirdPart != null )
    217223            segments.add(pos++, thirdPart);
    218         RingSegment result = isRing || secondPart == null ? segment : secondPart;
    219 //      System.out.println("Returning segment " + result);
    220         return result;
     224        return isRing || secondPart == null ? segment : secondPart;
    221225    }
    222226
     
    225229     * Also, sets source way for all rings.
    226230     *
    227      * This method should be called, even if there is just one ring.
     231     * If this method is not called, do not forget to call {@link #putSourceWayFirst()} for all rings.
    228232     */
    229233    public static void redistributeSegments( List<TheRing> rings ) {
     
    263267    }
    264268
    265     private void putSourceWayFirst() {
     269    public void putSourceWayFirst() {
    266270        for( RingSegment seg : segments ) {
    267271            if( !seg.isReference() ) {
     
    271275        }
    272276    }
    273 
     277   
     278    public List<Command> getCommands() {
     279        return getCommands(true);
     280    }
     281   
    274282    /**
    275283     * Returns a list of commands to make a new relation and all newly created ways.
    276284     * The first way is copied from the source one, ChangeCommand is issued in this case.
    277285     */
    278     public List<Command> getCommands() {
    279         System.out.println("Making ring " + this);
    280         Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
    281         relation = new Relation();
    282         relation.put("type", "multipolygon");
     286    public List<Command> getCommands( boolean createMultipolygon ) {
    283287        Way sourceCopy = new Way(source);
    284         for( String key : sourceCopy.keySet() ) {
    285             if( !linearTags.contains(key) ) {
    286                 relation.put(key, sourceCopy.get(key));
    287                 sourceCopy.remove(key);
     288        if( createMultipolygon ) {
     289            Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
     290            relation = new Relation();
     291            relation.put("type", "multipolygon");
     292            for( String key : sourceCopy.keySet() ) {
     293                if( !linearTags.contains(key) ) {
     294                    relation.put(key, sourceCopy.get(key));
     295                    sourceCopy.remove(key);
     296                }
    288297            }
    289298        }
     
    310319                commands.add(new AddCommand(w));
    311320            if( w.equals(source) ) {
    312                 if( segments.size() == 1 ) {
    313                     // one segment means that it is a ring
    314                     List<Node> segnodes = seg.getNodes();
    315                     segnodes.add(segnodes.get(0));
    316                     sourceCopy.setNodes(segnodes);
    317                 } else
    318                     sourceCopy.setNodes(seg.getNodes());
    319                 commands.add(new ChangeCommand(source, sourceCopy));
     321                if( createMultipolygon || !seg.getWayNodes().equals(source.getNodes()) ) {
     322                    sourceCopy.setNodes(seg.getWayNodes());
     323                    commands.add(new ChangeCommand(source, sourceCopy));
     324                }
    320325                foundOwnWay = true;
    321326            } else {
     
    325330                }
    326331            }
    327             relation.addMember(new RelationMember("outer", w));
     332            if( createMultipolygon )
     333                relation.addMember(new RelationMember("outer", w));
    328334        }
    329335        if( !foundOwnWay )
    330336            commands.add(new DeleteCommand(source));
    331337        commands.addAll(relationCommands);
    332         commands.add(new AddCommand(relation));
     338        if( createMultipolygon )
     339            commands.add(new AddCommand(relation));
    333340        return commands;
    334341    }
     
    463470        }
    464471
     472        public List<Node> getWayNodes() {
     473            if( nodes == null )
     474                throw new IllegalArgumentException("Won't give you wayNodes: it is a reference");
     475            List<Node> wayNodes = new ArrayList<Node>(nodes);
     476            if( isRing )
     477                wayNodes.add(wayNodes.get(0));
     478            return wayNodes;
     479        }
     480
    465481        public boolean isReference() {
    466482            return nodes == null;
     
    493509            if( resultingWay == null ) {
    494510                resultingWay = new Way();
    495                 resultingWay.setNodes(nodes);
     511                resultingWay.setNodes(getWayNodes());
    496512            }
    497513            if( template != null && !wasTemplateApplied ) {
Note: See TracChangeset for help on using the changeset viewer.