Ignore:
Timestamp:
2016-06-24T09:10:57+02:00 (9 years ago)
Author:
donvip
Message:

checkstyle, update to JOSM 10279

File:
1 edited

Legend:

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

    r30738 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    2526 * One ring that contains segments forming an outer way of multipolygon.
    2627 * This class is used in {@link CreateMultipolygonAction#makeManySimpleMultipolygons(java.util.Collection)}.
    27  * 
     28 *
    2829 * @author Zverik
    2930 */
     
    3536    private Relation relation = null;
    3637
    37     public TheRing( Way source ) {
    38     this.source = source;
    39     segments = new ArrayList<>(1);
    40     segments.add(new RingSegment(source));
    41     }
    42    
    43     public static boolean areAllOfThoseRings( Collection<Way> ways ) {
    44     List<Way> rings = new ArrayList<>();
    45     for( Way way : ways ) {
    46         if( way.isClosed() )
    47         rings.add(way);
    48         else
    49         return false;
    50     }
    51     if( rings.isEmpty() || ways.size() == 1 )
    52         return false;
    53 
    54     // check for non-containment of rings
    55     for( int i = 0; i < rings.size() - 1; i++ ) {
    56         for( int j = i + 1; j < rings.size(); j++ ) {
    57         PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
    58         if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
     38    public TheRing(Way source) {
     39        this.source = source;
     40        segments = new ArrayList<>(1);
     41        segments.add(new RingSegment(source));
     42    }
     43
     44    public static boolean areAllOfThoseRings(Collection<Way> ways) {
     45        List<Way> rings = new ArrayList<>();
     46        for (Way way : ways) {
     47            if (way.isClosed() ) {
     48                rings.add(way);
     49            } else
     50                return false;
     51        }
     52        if (rings.isEmpty() || ways.size() == 1 )
    5953            return false;
    60         }
    61     }
    62 
    63     return true;
     54
     55        // check for non-containment of rings
     56        for (int i = 0; i < rings.size() - 1; i++) {
     57            for (int j = i + 1; j < rings.size(); j++) {
     58                PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
     59                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
     60                    return false;
     61            }
     62        }
     63
     64        return true;
    6465    }
    6566
     
    6869     * @return list of new relations.
    6970     */
    70     public static List<Relation> makeManySimpleMultipolygons( Collection<Way> selection, List<Command> commands ) {
    71     log("---------------------------------------");
    72     List<TheRing> rings = new ArrayList<>(selection.size());
    73     for( Way w : selection )
    74         rings.add(new TheRing(w));
    75     for( int i = 0; i < rings.size() - 1; i++ )
    76         for( int j = i + 1; j < rings.size(); j++ )
    77         rings.get(i).collide(rings.get(j));
    78     redistributeSegments(rings);
    79     List<Relation> relations = new ArrayList<>();
    80     Map<Relation, Relation> relationCache = new HashMap<>();
    81     for( TheRing r : rings ) {
    82         commands.addAll(r.getCommands(relationCache));
    83         relations.add(r.getRelation());
    84     }
    85     updateCommandsWithRelations(commands, relationCache);
    86     return relations;
    87     }
    88 
    89     public void collide( TheRing other ) {
    90     boolean collideNoted = false;
    91     for( int i = 0; i < segments.size(); i++ ) {
    92         RingSegment segment1 = segments.get(i);
    93         if( !segment1.isReference() ) {
    94         for( int j = 0; j < other.segments.size(); j++ ) {
    95             RingSegment segment2 = other.segments.get(j);
    96             if( !segment2.isReference() ) {
    97             log("Comparing " + segment1 + " and " + segment2);
    98             Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());
    99             if( split != null ) {
    100                 if( !collideNoted ) {
    101                 log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
    102                 collideNoted = true;
    103                 }
    104                 RingSegment segment = splitRingAt(i, split[0], split[1]);
    105                 RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);
    106                 if( !areSegmentsEqual(segment, otherSegment) )
    107                 throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
    108                 segment.makeReference(otherSegment);
    109             }
    110             }
    111             if( segment1.isReference() )
    112             break;
    113         }
    114         }
    115     }
    116     }
    117    
     71    public static List<Relation> makeManySimpleMultipolygons(Collection<Way> selection, List<Command> commands) {
     72        log("---------------------------------------");
     73        List<TheRing> rings = new ArrayList<>(selection.size());
     74        for (Way w : selection ) {
     75            rings.add(new TheRing(w));
     76        }
     77        for (int i = 0; i < rings.size() - 1; i++ ) {
     78            for (int j = i + 1; j < rings.size(); j++ ) {
     79                rings.get(i).collide(rings.get(j));
     80            }
     81        }
     82        redistributeSegments(rings);
     83        List<Relation> relations = new ArrayList<>();
     84        Map<Relation, Relation> relationCache = new HashMap<>();
     85        for (TheRing r : rings) {
     86            commands.addAll(r.getCommands(relationCache));
     87            relations.add(r.getRelation());
     88        }
     89        updateCommandsWithRelations(commands, relationCache);
     90        return relations;
     91    }
     92
     93    public void collide(TheRing other) {
     94        boolean collideNoted = false;
     95        for (int i = 0; i < segments.size(); i++) {
     96            RingSegment segment1 = segments.get(i);
     97            if (!segment1.isReference()) {
     98                for (int j = 0; j < other.segments.size(); j++) {
     99                    RingSegment segment2 = other.segments.get(j);
     100                    if (!segment2.isReference()) {
     101                        log("Comparing " + segment1 + " and " + segment2);
     102                        Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());
     103                        if (split != null) {
     104                            if (!collideNoted) {
     105                                log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
     106                                collideNoted = true;
     107                            }
     108                            RingSegment segment = splitRingAt(i, split[0], split[1]);
     109                            RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);
     110                            if (!areSegmentsEqual(segment, otherSegment) )
     111                                throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
     112                            segment.makeReference(otherSegment);
     113                        }
     114                    }
     115                    if (segment1.isReference() ) {
     116                        break;
     117                    }
     118                }
     119            }
     120        }
     121    }
     122
    118123    /**
    119124     * Returns array of {start1, last1, start2, last2} or null if there is no common nodes.
    120125     */
    121     public static Node[] getSplitNodes( List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2 ) {
    122     int pos = 0;
    123     while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )
    124         pos++;
    125     boolean collideFound = pos == nodes1.size();
    126     if( pos == 0 && isRing1 ) {
    127         // rewind a bit
    128         pos = nodes1.size() - 1;
    129         while( pos > 0 && nodes2.contains(nodes1.get(pos)) )
    130         pos--;
    131         if( pos == 0 && nodes1.size() == nodes2.size() ) {
    132         JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
     126    public static Node[] getSplitNodes(List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2) {
     127        int pos = 0;
     128        while(pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) ) {
     129            pos++;
     130        }
     131        boolean collideFound = pos == nodes1.size();
     132        if (pos == 0 && isRing1) {
     133            // rewind a bit
     134            pos = nodes1.size() - 1;
     135            while(pos > 0 && nodes2.contains(nodes1.get(pos)) ) {
     136                pos--;
     137            }
     138            if (pos == 0 && nodes1.size() == nodes2.size()) {
     139                JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
     140                return null;
     141            }
     142            pos = pos == nodes1.size() - 1 ? 0 : pos + 1;
     143        }
     144        int firstPos = isRing1 ? pos : nodes1.size();
     145        while(!collideFound) {
     146            log("pos=" + pos);
     147            int start1 = pos;
     148            int start2 = nodes2.indexOf(nodes1.get(start1));
     149            int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
     150            int last2 = start2;
     151            int increment2 = 0;
     152            if (last1 >= 0) {
     153                last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
     154                if (last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) {
     155                    increment2 = -1;
     156                } else {
     157                    last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
     158                    if (last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) {
     159                        increment2 = 1;
     160                    }
     161                }
     162            }
     163            log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);
     164            if (increment2 != 0) {
     165                // find the first nodes
     166                boolean reachedEnd = false;
     167                while(!reachedEnd) {
     168                    int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
     169                    int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
     170                    if (newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) ) {
     171                        reachedEnd = true;
     172                    } else {
     173                        last1 = newLast1;
     174                        last2 = newLast2;
     175                    }
     176                }
     177                log("last1=" + last1 + " last2=" + last2);
     178                if (increment2 < 0) {
     179                    int tmp = start2;
     180                    start2 = last2;
     181                    last2 = tmp;
     182                }
     183                return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};
     184            } else {
     185                pos = last1;
     186                while(pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) ) {
     187                    pos = incrementBy(pos, 1, nodes1.size(), isRing1);
     188                }
     189                if (pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) ) {
     190                    collideFound = true;
     191                }
     192            }
     193        }
    133194        return null;
    134         }
    135         pos = pos == nodes1.size() - 1 ? 0 : pos + 1;
    136     }
    137     int firstPos = isRing1 ? pos : nodes1.size();
    138     while( !collideFound ) {
    139         log("pos=" + pos);
    140         int start1 = pos;
    141         int start2 = nodes2.indexOf(nodes1.get(start1));
    142         int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
    143         int last2 = start2;
    144         int increment2 = 0;
    145         if( last1 >= 0 ) {
    146         last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
    147         if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    148             increment2 = -1;
    149         else {
    150             last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
    151             if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    152             increment2 = 1;
    153         }
    154         }
    155         log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);
    156         if( increment2 != 0 ) {
    157         // find the first nodes
    158         boolean reachedEnd = false;
    159         while( !reachedEnd ) {
    160             int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
    161             int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
    162             if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )
    163             reachedEnd = true;
    164             else {
    165             last1 = newLast1;
    166             last2 = newLast2;
    167             }
    168         }
    169         log("last1=" + last1 + " last2=" + last2);
    170         if( increment2 < 0 ) {
    171             int tmp = start2;
    172             start2 = last2;
    173             last2 = tmp;
    174         }
    175         return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};
    176         } else {
    177         pos = last1;
    178         while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )
    179             pos = incrementBy(pos, 1, nodes1.size(), isRing1);
    180         if( pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) )
    181             collideFound = true;
    182         }
    183     }
    184     return null;
    185     }
    186    
    187     private static int incrementBy( int value, int increment, int limit1, boolean isRing ) {
    188     int result = value + increment;
    189     if( result < 0 )
    190         return isRing ? result + limit1 : -1;
    191     else if( result >= limit1 )
    192         return isRing ? result - limit1 : -1;
    193     else
    194         return result;
    195     }
    196    
    197     private boolean areSegmentsEqual( RingSegment seg1, RingSegment seg2 ) {
    198     List<Node> nodes1 = seg1.getNodes();
    199     List<Node> nodes2 = seg2.getNodes();
    200     int size = nodes1.size();
    201     if( size != nodes2.size() )
    202         return false;
    203     boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0));
    204     for( int i = 0; i < size; i++ )
    205         if( !nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) )
    206         return false;
    207     return true;
     195    }
     196
     197    private static int incrementBy(int value, int increment, int limit1, boolean isRing) {
     198        int result = value + increment;
     199        if (result < 0 )
     200            return isRing ? result + limit1 : -1;
     201        else if (result >= limit1 )
     202            return isRing ? result - limit1 : -1;
     203        else
     204            return result;
     205    }
     206
     207    private boolean areSegmentsEqual(RingSegment seg1, RingSegment seg2) {
     208        List<Node> nodes1 = seg1.getNodes();
     209        List<Node> nodes2 = seg2.getNodes();
     210        int size = nodes1.size();
     211        if (size != nodes2.size() )
     212            return false;
     213        boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0));
     214        for (int i = 0; i < size; i++ )
     215            if (!nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) )
     216                return false;
     217        return true;
    208218    }
    209219
     
    212222     * @return The segment between nodes.
    213223     */
    214     private RingSegment splitRingAt( int segmentIndex, Node n1, Node n2 ) {
    215     if( n1.equals(n2) )
    216         throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());
    217     RingSegment segment = segments.get(segmentIndex);
    218     boolean isRing = segment.isRing();
    219     log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());
    220     boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);
    221     if( reversed && !isRing ) {
    222         // order nodes
    223         Node tmp = n1;
    224         n1 = n2;
    225         n2 = tmp;
    226     }
    227     RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1);
    228     // if secondPart == null, then n1 == firstNode
    229     RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);
    230     // if secondPart == null, then thirdPart is between n1 and n2
    231     // otherwise, thirdPart is between n2 and lastNode
    232     // if thirdPart == null, then n2 == lastNode
    233     int pos = segmentIndex + 1;
    234     if( secondPart != null )
    235         segments.add(pos++, secondPart);
    236     if( thirdPart != null )
    237         segments.add(pos++, thirdPart);
    238     return isRing || secondPart == null ? segment : secondPart;
     224    private RingSegment splitRingAt(int segmentIndex, Node n1, Node n2) {
     225        if (n1.equals(n2) )
     226            throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());
     227        RingSegment segment = segments.get(segmentIndex);
     228        boolean isRing = segment.isRing();
     229        log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());
     230        boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);
     231        if (reversed && !isRing) {
     232            // order nodes
     233            Node tmp = n1;
     234            n1 = n2;
     235            n2 = tmp;
     236        }
     237        RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1);
     238        // if secondPart == null, then n1 == firstNode
     239        RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);
     240        // if secondPart == null, then thirdPart is between n1 and n2
     241        // otherwise, thirdPart is between n2 and lastNode
     242        // if thirdPart == null, then n2 == lastNode
     243        int pos = segmentIndex + 1;
     244        if (secondPart != null ) {
     245            segments.add(pos++, secondPart);
     246        }
     247        if (thirdPart != null ) {
     248            segments.add(pos++, thirdPart);
     249        }
     250        return isRing || secondPart == null ? segment : secondPart;
    239251    }
    240252
     
    242254     * Tries to arrange segments in order for each ring to have at least one.
    243255     * Also, sets source way for all rings.
    244      * 
     256     *
    245257     * If this method is not called, do not forget to call {@link #putSourceWayFirst()} for all rings.
    246258     */
    247     public static void redistributeSegments( List<TheRing> rings ) {
    248     // build segments map
    249     Map<RingSegment, TheRing> segmentMap = new HashMap<>();
    250     for( TheRing ring : rings )
    251         for( RingSegment seg : ring.segments )
    252         if( !seg.isReference() )
    253             segmentMap.put(seg, ring);
    254 
    255     // rearrange references
    256     for( int i = 0; i < rings.size(); i++ ) {
    257         TheRing ring = rings.get(i);
    258         if( ring.countNonReferenceSegments() == 0 ) {
    259         // need to find one non-reference segment
    260         for( RingSegment seg : ring.segments ) {
    261             TheRing otherRing = segmentMap.get(seg.references);
    262             if( otherRing.countNonReferenceSegments() > 1 ) {
    263             // we could check for >0, but it is prone to deadlocking
    264             seg.swapReference();
    265             }
    266         }
    267         }
    268     }
    269 
    270     // initializing source way for each ring
    271     for( TheRing ring : rings )
    272         ring.putSourceWayFirst();
     259    public static void redistributeSegments(List<TheRing> rings) {
     260        // build segments map
     261        Map<RingSegment, TheRing> segmentMap = new HashMap<>();
     262        for (TheRing ring : rings ) {
     263            for (RingSegment seg : ring.segments )
     264                if (!seg.isReference() ) {
     265                    segmentMap.put(seg, ring);
     266                }
     267        }
     268
     269        // rearrange references
     270        for (int i = 0; i < rings.size(); i++) {
     271            TheRing ring = rings.get(i);
     272            if (ring.countNonReferenceSegments() == 0) {
     273                // need to find one non-reference segment
     274                for (RingSegment seg : ring.segments) {
     275                    TheRing otherRing = segmentMap.get(seg.references);
     276                    if (otherRing.countNonReferenceSegments() > 1) {
     277                        // we could check for >0, but it is prone to deadlocking
     278                        seg.swapReference();
     279                    }
     280                }
     281            }
     282        }
     283
     284        // initializing source way for each ring
     285        for (TheRing ring : rings ) {
     286            ring.putSourceWayFirst();
     287        }
    273288    }
    274289
    275290    private int countNonReferenceSegments() {
    276     int count = 0;
    277     for( RingSegment seg : segments )
    278         if( !seg.isReference() )
    279         count++;
    280     return count;
     291        int count = 0;
     292        for (RingSegment seg : segments )
     293            if (!seg.isReference() ) {
     294                count++;
     295            }
     296        return count;
    281297    }
    282298
    283299    public void putSourceWayFirst() {
    284     for( RingSegment seg : segments ) {
    285         if( !seg.isReference() ) {
    286         seg.overrideWay(source);
    287         return;
    288         }
    289     }
    290     }
    291    
     300        for (RingSegment seg : segments) {
     301            if (!seg.isReference()) {
     302                seg.overrideWay(source);
     303                return;
     304            }
     305        }
     306    }
     307
    292308    public List<Command> getCommands() {
    293     return getCommands(true, null);
    294     }
    295    
    296     public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) {
    297     return getCommands(true, relationChangeMap);
    298     }
    299    
     309        return getCommands(true, null);
     310    }
     311
     312    public List<Command> getCommands(Map<Relation, Relation> relationChangeMap) {
     313        return getCommands(true, relationChangeMap);
     314    }
     315
    300316    /**
    301317     * Returns a list of commands to make a new relation and all newly created ways.
    302318     * The first way is copied from the source one, ChangeCommand is issued in this case.
    303319     */
    304     public List<Command> getCommands( boolean createMultipolygon, Map<Relation, Relation> relationChangeMap ) {
    305     Way sourceCopy = new Way(source);
    306     if( createMultipolygon ) {
    307         Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
    308         relation = new Relation();
    309         relation.put("type", "multipolygon");
    310         for( String key : sourceCopy.keySet() ) {
    311                 if( linearTags.contains(key) ) continue;
    312                 if( key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) continue;
     320    public List<Command> getCommands(boolean createMultipolygon, Map<Relation, Relation> relationChangeMap) {
     321        Way sourceCopy = new Way(source);
     322        if (createMultipolygon) {
     323            Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
     324            relation = new Relation();
     325            relation.put("type", "multipolygon");
     326            for (String key : sourceCopy.keySet()) {
     327                if (linearTags.contains(key) ) {
     328                    continue;
     329                }
     330                if (key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) {
     331                    continue;
     332                }
    313333                relation.put(key, sourceCopy.get(key));
    314334                sourceCopy.remove(key);
    315         }
    316     }
    317 
    318     // build a map of referencing relations
    319     Map<Relation, Integer> referencingRelations = new HashMap<>();
    320     List<Command> relationCommands = new ArrayList<>();
    321     for( OsmPrimitive p : source.getReferrers() ) {
    322         if( p instanceof Relation ) {
    323         Relation rel = null;
    324         if( relationChangeMap != null ) {
    325             if( relationChangeMap.containsKey((Relation)p) )
    326             rel = relationChangeMap.get((Relation)p);
    327             else {
    328             rel = new Relation((Relation)p);
    329             relationChangeMap.put((Relation)p, rel);
    330             }
    331         } else {           
    332             rel = new Relation((Relation)p);
    333             relationCommands.add(new ChangeCommand((Relation)p, rel));
    334         }
    335         for( int i = 0; i < rel.getMembersCount(); i++ )
    336             if( rel.getMember(i).getMember().equals(source) )
    337             referencingRelations.put(rel, Integer.valueOf(i));
    338         }
    339     }
    340     // todo: когда два кольца менÑ�ÑŽÑ‚ одно и то же отношение, в Ñ�пиÑ�ок команд добавлÑ�етÑ�Ñ�
    341     // изменение базового отношениÑ� на новое, а не предыдущего
    342     // поÑ�тому Ñ�охранÑ�етÑ�Ñ� только первое изменение
    343 
    344     List<Command> commands = new ArrayList<>();
    345     boolean foundOwnWay = false;
    346     for( RingSegment seg : segments ) {
    347         boolean needAdding = !seg.isWayConstructed();
    348         Way w = seg.constructWay(seg.isReference() ? null : sourceCopy);
    349         if( needAdding )
    350         commands.add(new AddCommand(w));
    351         if( w.equals(source) ) {
    352         if( createMultipolygon || !seg.getWayNodes().equals(source.getNodes()) ) {
    353             sourceCopy.setNodes(seg.getWayNodes());
    354             commands.add(new ChangeCommand(source, sourceCopy));
    355         }
    356         foundOwnWay = true;
    357         } else {
    358         for( Relation rel : referencingRelations.keySet() ) {
    359             int relIndex = referencingRelations.get(rel);
    360             rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w));
    361         }
    362         }
    363         if( createMultipolygon )
    364         relation.addMember(new RelationMember("outer", w));
    365     }
    366     if( !foundOwnWay )
    367         commands.add(new DeleteCommand(source));
    368     commands.addAll(relationCommands);
    369     if( createMultipolygon )
    370         commands.add(new AddCommand(relation));
    371     return commands;
    372     }
    373    
    374     public static void updateCommandsWithRelations( List<Command> commands, Map<Relation, Relation> relationCache ) {
    375     for( Relation src : relationCache.keySet() )
    376         commands.add(new ChangeCommand(src, relationCache.get(src)));
     335            }
     336        }
     337
     338        // build a map of referencing relations
     339        Map<Relation, Integer> referencingRelations = new HashMap<>();
     340        List<Command> relationCommands = new ArrayList<>();
     341        for (OsmPrimitive p : source.getReferrers()) {
     342            if (p instanceof Relation) {
     343                Relation rel = null;
     344                if (relationChangeMap != null) {
     345                    if (relationChangeMap.containsKey(p) ) {
     346                        rel = relationChangeMap.get(p);
     347                    } else {
     348                        rel = new Relation((Relation)p);
     349                        relationChangeMap.put((Relation)p, rel);
     350                    }
     351                } else {
     352                    rel = new Relation((Relation)p);
     353                    relationCommands.add(new ChangeCommand(p, rel));
     354                }
     355                for (int i = 0; i < rel.getMembersCount(); i++ )
     356                    if (rel.getMember(i).getMember().equals(source) ) {
     357                        referencingRelations.put(rel, Integer.valueOf(i));
     358                    }
     359            }
     360        }
     361        // todo: когда два кольца менÑ�ÑŽÑ‚ одно и то же отношение, в Ñ�пиÑ�ок команд добавлÑ�етÑ�Ñ�
     362        // изменение базового отношениÑ� на новое, а не предыдущего
     363        // поÑ�тому Ñ�охранÑ�етÑ�Ñ� только первое изменение
     364
     365        List<Command> commands = new ArrayList<>();
     366        boolean foundOwnWay = false;
     367        for (RingSegment seg : segments) {
     368            boolean needAdding = !seg.isWayConstructed();
     369            Way w = seg.constructWay(seg.isReference() ? null : sourceCopy);
     370            if (needAdding ) {
     371                commands.add(new AddCommand(w));
     372            }
     373            if (w.equals(source)) {
     374                if (createMultipolygon || !seg.getWayNodes().equals(source.getNodes())) {
     375                    sourceCopy.setNodes(seg.getWayNodes());
     376                    commands.add(new ChangeCommand(source, sourceCopy));
     377                }
     378                foundOwnWay = true;
     379            } else {
     380                for (Relation rel : referencingRelations.keySet()) {
     381                    int relIndex = referencingRelations.get(rel);
     382                    rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w));
     383                }
     384            }
     385            if (createMultipolygon ) {
     386                relation.addMember(new RelationMember("outer", w));
     387            }
     388        }
     389        if (!foundOwnWay ) {
     390            commands.add(new DeleteCommand(source));
     391        }
     392        commands.addAll(relationCommands);
     393        if (createMultipolygon ) {
     394            commands.add(new AddCommand(relation));
     395        }
     396        return commands;
     397    }
     398
     399    public static void updateCommandsWithRelations(List<Command> commands, Map<Relation, Relation> relationCache) {
     400        for (Relation src : relationCache.keySet() ) {
     401            commands.add(new ChangeCommand(src, relationCache.get(src)));
     402        }
    377403    }
    378404
     
    381407     */
    382408    public Relation getRelation() {
    383     return relation;
     409        return relation;
    384410    }
    385411
    386412    @Override
    387413    public String toString() {
    388     StringBuilder sb = new StringBuilder("TheRing@");
    389     sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: ");
    390     if( segments.isEmpty() )
    391         sb.append("empty");
    392     else {
    393         sb.append(segments.get(0));
    394         for( int i = 1; i < segments.size(); i++ )
    395         sb.append(", ").append(segments.get(i));
    396     }
    397     return sb.append(']').toString();
     414        StringBuilder sb = new StringBuilder("TheRing@");
     415        sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: ");
     416        if (segments.isEmpty() ) {
     417            sb.append("empty");
     418        } else {
     419            sb.append(segments.get(0));
     420            for (int i = 1; i < segments.size(); i++ ) {
     421                sb.append(", ").append(segments.get(i));
     422            }
     423        }
     424        return sb.append(']').toString();
    398425    }
    399426
     
    401428     * Appends "append" to "base" so the closed polygon forms.
    402429     */
    403     /*private static void closePolygon( List<Node> base, List<Node> append ) {
    404     if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {
     430    /*private static void closePolygon(List<Node> base, List<Node> append) {
     431    if (append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1))) {
    405432        List<Node> ap2 = new ArrayList<Node>(append);
    406433        Collections.reverse(ap2);
     
    414441     * Checks if a middle point between two nodes is inside a polygon. Useful to check if the way is inside.
    415442     */
    416     /*private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) {
     443    /*private static boolean segmentInsidePolygon(Node n1, Node n2, List<Node> polygon) {
    417444    EastNorth en1 = n1.getEastNorth();
    418445    EastNorth en2 = n2.getEastNorth();
     
    420447    return Geometry.nodeInsidePolygon(testNode, polygon);
    421448    }*/
    422    
    423     private static void log( String s ) {
    424 //    System.out.println(s);
    425     }
    426    
     449
     450    private static void log(String s) {
     451        //    System.out.println(s);
     452    }
     453
    427454    private static class RingSegment {
    428     private List<Node> nodes;
    429     private RingSegment references;
    430     private Way resultingWay = null;
    431     private boolean wasTemplateApplied = false;
    432     private boolean isRing;
    433 
    434     /*private RingSegment() {
     455        private List<Node> nodes;
     456        private RingSegment references;
     457        private Way resultingWay = null;
     458        private boolean wasTemplateApplied = false;
     459        private boolean isRing;
     460
     461        /*private RingSegment() {
    435462    }*/
    436463
    437     public RingSegment( Way w ) {
    438         this(w.getNodes());
    439     }
    440 
    441     public RingSegment( List<Node> nodes ) {
    442         this.nodes = nodes;
    443         isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size() - 1));
    444         if( isRing )
    445         nodes.remove(nodes.size() - 1);
    446         references = null;
    447     }
    448 
    449     /*public RingSegment( RingSegment ref ) {
     464        public RingSegment(Way w) {
     465            this(w.getNodes());
     466        }
     467
     468        public RingSegment(List<Node> nodes) {
     469            this.nodes = nodes;
     470            isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size() - 1));
     471            if (isRing ) {
     472                nodes.remove(nodes.size() - 1);
     473            }
     474            references = null;
     475        }
     476
     477        /*public RingSegment(RingSegment ref) {
    450478        this.nodes = null;
    451479        this.references = ref;
    452480    }*/
    453481
    454     /**
    455      * Splits this segment at node n. Retains nodes 0..n and moves
    456      * nodes n..N to a separate segment that is returned.
    457      * @param n node at which to split.
    458      * @return new segment, {@code null} if splitting is unnecessary.
    459      */
    460     public RingSegment split( Node n ) {
    461         if( nodes == null )
    462         throw new IllegalArgumentException("Cannot split segment: it is a reference");
    463         int pos = nodes.indexOf(n);
    464         if( pos <= 0 || pos >= nodes.size() - 1 )
    465         return null;
    466         List<Node> newNodes = new ArrayList<>(nodes.subList(pos, nodes.size()));
    467         nodes.subList(pos + 1, nodes.size()).clear();
    468         return new RingSegment(newNodes);
    469     }
    470 
    471     /**
    472      * Split this segment as a way at two nodes. If one of them is null or at the end,
    473      * split as an arc. Note: order of nodes is important.
    474      * @return A new segment from n2 to n1.
    475      */
    476     public RingSegment split( Node n1, Node n2 ) {
    477         if( nodes == null )
    478         throw new IllegalArgumentException("Cannot split segment: it is a reference");
    479         if( !isRing ) {
    480         if( n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size() - 1).equals(n1) )
    481             return split(n2);
    482         if( n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size() - 1).equals(n2) )
    483             return split(n1);
    484         throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this);
    485         }
    486         int pos1 = nodes.indexOf(n1);
    487         int pos2 = nodes.indexOf(n2);
    488         if( pos1 == pos2 )
    489         return null;
    490 
    491         List<Node> newNodes = new ArrayList<>();
    492         if( pos2 > pos1 ) {
    493         newNodes.addAll(nodes.subList(pos2, nodes.size()));
    494         newNodes.addAll(nodes.subList(0, pos1 + 1));
    495         if( pos2 + 1 < nodes.size() )
    496             nodes.subList(pos2 + 1, nodes.size()).clear();
    497         if( pos1 > 0 )
    498             nodes.subList(0, pos1).clear();
    499         } else {
    500         newNodes.addAll(nodes.subList(pos2, pos1 + 1));
    501         nodes.addAll(new ArrayList<>(nodes.subList(0, pos2 + 1)));
    502         nodes.subList(0, pos1).clear();
    503         }
    504         isRing = false;
    505         return new RingSegment(newNodes);
    506     }
    507 
    508     public List<Node> getNodes() {
    509         return nodes == null ? references.nodes : nodes;
    510     }
    511 
    512     public List<Node> getWayNodes() {
    513         if( nodes == null )
    514         throw new IllegalArgumentException("Won't give you wayNodes: it is a reference");
    515         List<Node> wayNodes = new ArrayList<>(nodes);
    516         if( isRing )
    517         wayNodes.add(wayNodes.get(0));
    518         return wayNodes;
    519     }
    520 
    521     public boolean isReference() {
    522         return nodes == null;
    523     }
    524 
    525     public boolean isRing() {
    526         return isRing;
    527     }
    528 
    529     public void makeReference( RingSegment segment ) {
    530         log(this + " was made a reference to " + segment);
    531         this.nodes = null;
    532         this.references = segment;
    533     }
    534 
    535     public void swapReference() {
    536         this.nodes = references.nodes;
    537         references.nodes = null;
    538         references.references = this;
    539         this.references = null;
    540     }
    541 
    542     public boolean isWayConstructed() {
    543         return isReference() ? references.isWayConstructed() : resultingWay != null;
    544     }
    545 
    546     public Way constructWay( Way template ) {
    547         if( isReference() )
    548         return references.constructWay(template);
    549         if( resultingWay == null ) {
    550         resultingWay = new Way();
    551         resultingWay.setNodes(getWayNodes());
    552         }
    553         if( template != null && !wasTemplateApplied ) {
    554         resultingWay.setKeys(template.getKeys());
    555         wasTemplateApplied = true;
    556         }
    557         return resultingWay;
    558     }
    559 
    560     public void overrideWay( Way source ) {
    561         if( isReference() )
    562         references.overrideWay(source);
    563         else {
    564         resultingWay = source;
    565         wasTemplateApplied = true;
    566         }
    567     }
    568 
    569     /**
    570      * Compares two segments with respect to referencing.
    571      * @return true if ways are equals, or one references another.
    572      */
    573     /*public boolean isReferencingEqual( RingSegment other ) {
     482        /**
     483         * Splits this segment at node n. Retains nodes 0..n and moves
     484         * nodes n..N to a separate segment that is returned.
     485         * @param n node at which to split.
     486         * @return new segment, {@code null} if splitting is unnecessary.
     487         */
     488        public RingSegment split(Node n) {
     489            if (nodes == null )
     490                throw new IllegalArgumentException("Cannot split segment: it is a reference");
     491            int pos = nodes.indexOf(n);
     492            if (pos <= 0 || pos >= nodes.size() - 1 )
     493                return null;
     494            List<Node> newNodes = new ArrayList<>(nodes.subList(pos, nodes.size()));
     495            nodes.subList(pos + 1, nodes.size()).clear();
     496            return new RingSegment(newNodes);
     497        }
     498
     499        /**
     500         * Split this segment as a way at two nodes. If one of them is null or at the end,
     501         * split as an arc. Note: order of nodes is important.
     502         * @return A new segment from n2 to n1.
     503         */
     504        public RingSegment split(Node n1, Node n2) {
     505            if (nodes == null )
     506                throw new IllegalArgumentException("Cannot split segment: it is a reference");
     507            if (!isRing) {
     508                if (n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size() - 1).equals(n1) )
     509                    return split(n2);
     510                if (n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size() - 1).equals(n2) )
     511                    return split(n1);
     512                throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this);
     513            }
     514            int pos1 = nodes.indexOf(n1);
     515            int pos2 = nodes.indexOf(n2);
     516            if (pos1 == pos2 )
     517                return null;
     518
     519            List<Node> newNodes = new ArrayList<>();
     520            if (pos2 > pos1) {
     521                newNodes.addAll(nodes.subList(pos2, nodes.size()));
     522                newNodes.addAll(nodes.subList(0, pos1 + 1));
     523                if (pos2 + 1 < nodes.size() ) {
     524                    nodes.subList(pos2 + 1, nodes.size()).clear();
     525                }
     526                if (pos1 > 0 ) {
     527                    nodes.subList(0, pos1).clear();
     528                }
     529            } else {
     530                newNodes.addAll(nodes.subList(pos2, pos1 + 1));
     531                nodes.addAll(new ArrayList<>(nodes.subList(0, pos2 + 1)));
     532                nodes.subList(0, pos1).clear();
     533            }
     534            isRing = false;
     535            return new RingSegment(newNodes);
     536        }
     537
     538        public List<Node> getNodes() {
     539            return nodes == null ? references.nodes : nodes;
     540        }
     541
     542        public List<Node> getWayNodes() {
     543            if (nodes == null )
     544                throw new IllegalArgumentException("Won't give you wayNodes: it is a reference");
     545            List<Node> wayNodes = new ArrayList<>(nodes);
     546            if (isRing ) {
     547                wayNodes.add(wayNodes.get(0));
     548            }
     549            return wayNodes;
     550        }
     551
     552        public boolean isReference() {
     553            return nodes == null;
     554        }
     555
     556        public boolean isRing() {
     557            return isRing;
     558        }
     559
     560        public void makeReference(RingSegment segment) {
     561            log(this + " was made a reference to " + segment);
     562            this.nodes = null;
     563            this.references = segment;
     564        }
     565
     566        public void swapReference() {
     567            this.nodes = references.nodes;
     568            references.nodes = null;
     569            references.references = this;
     570            this.references = null;
     571        }
     572
     573        public boolean isWayConstructed() {
     574            return isReference() ? references.isWayConstructed() : resultingWay != null;
     575        }
     576
     577        public Way constructWay(Way template) {
     578            if (isReference() )
     579                return references.constructWay(template);
     580            if (resultingWay == null) {
     581                resultingWay = new Way();
     582                resultingWay.setNodes(getWayNodes());
     583            }
     584            if (template != null && !wasTemplateApplied) {
     585                resultingWay.setKeys(template.getKeys());
     586                wasTemplateApplied = true;
     587            }
     588            return resultingWay;
     589        }
     590
     591        public void overrideWay(Way source) {
     592            if (isReference() ) {
     593                references.overrideWay(source);
     594            } else {
     595                resultingWay = source;
     596                wasTemplateApplied = true;
     597            }
     598        }
     599
     600        /**
     601         * Compares two segments with respect to referencing.
     602         * @return true if ways are equals, or one references another.
     603         */
     604        /*public boolean isReferencingEqual(RingSegment other) {
    574605        return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other);
    575606    }*/
    576607
    577     @Override
    578     public String toString() {
    579         StringBuilder sb = new StringBuilder("RingSegment@");
    580         sb.append(this.hashCode()).append('[');
    581         if( isReference() )
    582         sb.append("references ").append(references.hashCode());
    583         else if( nodes.isEmpty() )
    584         sb.append("empty");
    585         else {
    586         if( isRing )
    587             sb.append("ring:");
    588         sb.append(nodes.get(0).getUniqueId());
    589         for( int i = 1; i < nodes.size(); i++ )
    590             sb.append(',').append(nodes.get(i).getUniqueId());
    591         }
    592         return sb.append(']').toString();
    593     }
     608        @Override
     609        public String toString() {
     610            StringBuilder sb = new StringBuilder("RingSegment@");
     611            sb.append(this.hashCode()).append('[');
     612            if (isReference() ) {
     613                sb.append("references ").append(references.hashCode());
     614            } else if (nodes.isEmpty() ) {
     615                sb.append("empty");
     616            } else {
     617                if (isRing ) {
     618                    sb.append("ring:");
     619                }
     620                sb.append(nodes.get(0).getUniqueId());
     621                for (int i = 1; i < nodes.size(); i++ ) {
     622                    sb.append(',').append(nodes.get(i).getUniqueId());
     623                }
     624            }
     625            return sb.append(']').toString();
     626        }
    594627    }
    595628}
Note: See TracChangeset for help on using the changeset viewer.