Ignore:
Timestamp:
2011-10-11T22:52:35+02:00 (13 years ago)
Author:
zverik
Message:

Hurray, it 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/CreateMultipolygonAction.java

    r26816 r26834  
    408408    private boolean areAllOfThoseRings( Collection<Way> ways ) {
    409409        List<Way> rings = new ArrayList<Way>();
    410         List<Way> otherWays = new ArrayList<Way>();
    411410        for( Way way : ways ) {
    412411            if( way.isClosed() )
    413412                rings.add(way);
    414413            else
    415                 otherWays.add(way);
     414                return false;
    416415        }
    417416        if( rings.isEmpty() || ways.size() == 1 )
    418417            return false; // todo: for one ring, attach it to neares multipolygons
    419 
    420         // check that every segment touches just one ring
    421         for( Way segment : otherWays ) {
    422             boolean found = false;
    423             for( Way ring : rings ) {
    424                 if( ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode())
    425                         && !segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()) )
    426                     found = true;
    427             }
    428             if( !found )
    429                 return false;
    430         }
    431418
    432419        // check for non-containment of rings
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java

    r26832 r26834  
    22
    33import java.util.*;
     4import javax.swing.JOptionPane;
    45import org.openstreetmap.josm.Main;
    56import org.openstreetmap.josm.command.*;
     
    3031        boolean collideNoted = false;
    3132        for( int i = 0; i < segments.size(); i++ ) {
    32             if( !segments.get(i).isReference() ) {
     33            RingSegment segment1 = segments.get(i);
     34            if( !segment1.isReference() ) {
    3335                for( int j = 0; j < other.segments.size(); j++ ) {
    34                     if( !other.segments.get(j).isReference() ) {
    35                         RingSegment seg1 = segments.get(i);
    36                         RingSegment seg2 = other.segments.get(j);
    37                         boolean firstSegmentIsNotARing = !seg1.isRing() && segments.size() == 1;
    38                         if( !seg2.isRing() && other.segments.size() == 1 ) {
    39                             if( firstSegmentIsNotARing )
    40                                 break; // not doing two arcs collision
    41                             RingSegment tmp = seg1;
    42                             seg1 = seg2;
    43                             seg2 = tmp;
    44                             firstSegmentIsNotARing = true;
     36                    RingSegment segment2 = other.segments.get(j);
     37                    if( !segment2.isReference() ) {
     38                        List<Node> nodes1 = segment1.getNodes();
     39                        List<Node> nodes2 = segment2.getNodes();
     40                        boolean isRing1 = segment1.isRing();
     41                        boolean isRing2 = segment2.isRing();
     42
     43                        int pos = 0;
     44                        while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )
     45                            pos++;
     46                        boolean collideFound = pos == nodes1.size();
     47                        if( pos == 0 && isRing1 ) {
     48                            // rewind a bit
     49                            pos = nodes1.size() - 1;
     50                            while( pos > 0 && nodes2.contains(nodes1.get(pos)) ) pos--;
     51                            if( pos == 0 ) {
     52                                JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
     53                                return;
     54                            }
     55                            pos = pos == nodes1.size() ? 0 : pos + 1;
    4556                        }
    46                         if( firstSegmentIsNotARing ) {
    47                             if( seg2.getNodes().contains(seg1.getNodes().get(0)) && seg2.getNodes().contains(seg1.getNodes().get(seg1.getNodes().size()-2))) {
    48                                 // segment touches a ring
    49                            
     57                        System.out.println("Comparing " + segment1 + " and " + segment2);
     58                        int firstPos = isRing1 ? pos : nodes1.size();
     59                        while( !collideFound ) {
     60                            System.out.println("pos="+pos);
     61                            int start1 = pos;
     62                            int start2 = nodes2.indexOf(nodes1.get(start1));
     63                            int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
     64                            int last2 = start2;
     65                            int increment2 = 0;
     66                            if( last1 >= 0 ) {
     67                                last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
     68                                if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
     69                                    increment2 = -1;
     70                                else {
     71                                    last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
     72                                    if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
     73                                        increment2 = 1;
     74                                }
    5075                            }
    51                         } else {
    52                             // both are segments from rings, find intersection
    53                         }
    54                        
    55                        
    56                         Node[] intersection = getFirstIntersection(segments.get(i), other.segments.get(j));
    57                         if( intersection.length > 1 ) {
    58                             if( !collideNoted ) {
    59                                 System.out.println("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
    60                                 collideNoted = true;
    61                             }
    62                             // now split both ways at control points and remove duplicate parts
    63                             boolean[] isarc = new boolean[] {
    64                                 segments.size() == 1 && !segments.get(0).isRing(),
    65                                 other.segments.size() == 1 && !other.segments.get(0).isRing()
    66                             };
    67                             RingSegment segment = splitRingAt(i, intersection[0], intersection[1]);
    68                             RingSegment otherSegment = other.splitRingAt(j, intersection[0], intersection[1]);
    69                             if( !isarc[0] && !isarc[1] ) {
    70                                 if( segments.size() > 2 && other.segments.size() > 2 )
    71                                     segment.makeReference(otherSegment);
    72                                 else {
    73                                     System.out.println("Starting complex procedure. Rings: " + this + " and " + other);
    74                                     // this ring was a ring, and we're not sure "segment" is a correct segment
    75                                     // actually, we're not sure always
    76                                     if( segments.size() == 2 )
    77                                         segment = segments.get(0);
    78                                     if( other.segments.size() == 2 )
    79                                         otherSegment = other.segments.get(0);
    80                                     System.out.println("segment="+segment + ", otherSegment=" + otherSegment);
    81 
    82                                     if( areSegmentsEqual(segment, otherSegment) )
    83                                         segment.makeReference(otherSegment);
    84                                     else if( segments.size() == 2 && areSegmentsEqual(segments.get(1), otherSegment) )
    85                                         segments.get(1).makeReference(otherSegment);
    86                                     else if( areSegmentsEqual(segment, other.segments.get(1)) )
    87                                         segment.makeReference(other.segments.get(1));
    88                                     else
    89                                         segments.get(1).makeReference(other.segments.get(1));
     76                            System.out.println("last1="+last1+" last2="+last2+" increment2="+increment2);
     77                            if( increment2 != 0 ) {
     78                                if( !collideNoted ) {
     79                                    System.out.println("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
     80                                    collideNoted = true;
    9081                                }
    91                             } else {
    92                                 // 1. A ring is an arc. It should have only 2 segments after this
    93                                 // 2. But it has one, so add otherSegment as the second.
    94                                 // 3. determine which segment!
    95                                 if( isarc[0] ) {
    96                                     if( other.segments.size() > 2 )
    97                                         segments.add(new RingSegment(otherSegment));
     82                                // find the first nodes
     83                                boolean reachedEnd = false;
     84                                while( !reachedEnd ) {
     85                                    int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
     86                                    int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
     87                                    if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )
     88                                        reachedEnd = true;
    9889                                    else {
    99                                         // choose between 2 segments
    100                                         int segmentToAdd = whichSegmentIsCloser(segments.get(0), other.segments.get(0), other.segments.get(1));
    101                                         segments.add(new RingSegment(other.segments.get(segmentToAdd)));
    102                                     }
    103                                 } else {
    104                                     if( segments.size() > 2 )
    105                                         other.segments.add(new RingSegment(segment));
    106                                     else {
    107                                         // choose between 2 segments
    108                                         int segmentToAdd = whichSegmentIsCloser(other.segments.get(0), segments.get(0), segments.get(1));
    109                                         other.segments.add(new RingSegment(segments.get(segmentToAdd)));
     90                                        last1 = newLast1;
     91                                        last2 = newLast2;
    11092                                    }
    11193                                }
     94                                System.out.println("last1=" + last1 + " last2=" + last2);
     95                                if( increment2 < 0 ) {
     96                                    int tmp = start2;
     97                                    start2 = last2;
     98                                    last2 = tmp;
     99                                }
     100                                RingSegment segment = splitRingAt(i, nodes1.get(start1), nodes1.get(last1));
     101                                RingSegment otherSegment = other.splitRingAt(j, nodes2.get(start2), nodes2.get(last2));
     102                                if( !areSegmentsEqual(segment, otherSegment) )
     103                                    throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
     104                                segment.makeReference(otherSegment);
     105                                collideFound = true;
     106                            } else {
     107                                pos = last1;
     108                                while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )
     109                                    pos = incrementBy(pos, 1, nodes1.size(), isRing1);
     110                                if( pos < 0 || !nodes2.contains(nodes1.get(pos)) )
     111                                    collideFound = true;
    112112                            }
    113113                        }
    114114                    }
    115                     if( segments.get(i).isReference() )
     115                    if( segment1.isReference() )
    116116                        break;
    117117                }
     
    120120    }
    121121   
    122     private Node[] getFirstIntersection( RingSegment seg1, RingSegment seg2 ) {
    123         List<Node> intersectionNodes = new ArrayList<Node>();
    124         boolean colliding = false;
    125         List<Node> nodes1 = seg1.getNodes();
    126         List<Node> nodes2 = seg2.getNodes();
    127         for( int ni = 0; ni < nodes2.size(); ni++ ) {
    128             if( nodes1.contains(nodes2.get(ni)) != colliding ) {
    129                 intersectionNodes.add(nodes2.get(colliding ? ni - 1 : ni));
    130                 colliding = !colliding;
    131             }
    132         }
    133         if( colliding )
    134             intersectionNodes.add(nodes2.get(nodes2.size() - 1));
    135         // when an intersection of two rings spans a ring's beginning
    136         if( seg1.isRing() && seg2.isRing() && intersectionNodes.contains(nodes2.get(0)) && intersectionNodes.contains(nodes2.get(nodes2.size() - 1)) ) {
    137             intersectionNodes.remove(0);
    138             intersectionNodes.remove(intersectionNodes.size() - 1);
    139             intersectionNodes.add(intersectionNodes.get(0));
    140             intersectionNodes.remove(0);
    141         }
    142         System.out.print("Intersection nodes for segments " + seg1 + " and " + seg2 + ": ");
    143         for( Node inode : intersectionNodes )
    144             System.out.print(inode.getUniqueId() + ",");
    145         System.out.println();
    146         // unclosed ways produce duplicate nodes
    147         int ni = 1;
    148         while( ni < intersectionNodes.size() ) {
    149             if( intersectionNodes.get(ni - 1).equals(intersectionNodes.get(ni)) )
    150                 intersectionNodes.remove(ni - 1);
    151             else
    152                 ni++;
    153         }
    154         return intersectionNodes.toArray(new Node[2]);
    155     }
    156    
    157     private int whichSegmentIsCloser( RingSegment base, RingSegment test0, RingSegment test1 ) {
    158         List<Node> testRing = new ArrayList<Node>(base.getNodes());
    159         closePolygon(testRing, test1.getNodes());
    160         return segmentInsidePolygon(test1.getNodes().get(0), test1.getNodes().get(1), testRing) ? 1 : 0;
     122    private int incrementBy( int value, int increment, int limit1, boolean isRing ) {
     123        int result = value + increment;
     124        if( result < 0 )
     125            return isRing ? result + limit1 : -1;
     126        else if( result >= limit1 )
     127            return isRing ? result - limit1 : -1;
     128        else
     129            return result;
    161130    }
    162131   
     
    364333    }
    365334   
    366     /**
    367      * Copies segment from {@code ring} to close a multipolygon containing {@code segment}.
    368      * @param segment Unclosed segment.
    369      * @param ring Closed ring.
    370      * @return Missing way.
    371      */
    372     private Way makeIntersectionLine( Way segment, Way ring ) {
    373         List<Node> nodes = new ArrayList<Node>(ring.getNodes());
    374         nodes.remove(nodes.size() - 1);
    375         int index1 = nodes.indexOf(segment.firstNode());
    376         int index2 = nodes.indexOf(segment.lastNode());
    377         if( index1 == index2 || index1 < 0 || index2 < 0 )
    378             return null;
    379 
    380         // split ring
    381         List<List<Node>> chunks = new ArrayList<List<Node>>(2);
    382         chunks.add(new ArrayList<Node>());
    383         chunks.add(new ArrayList<Node>());
    384         int chunk = 0, i = index1;
    385         boolean madeCircle = false;
    386         while( i != index1 || !madeCircle ) {
    387             chunks.get(chunk).add(nodes.get(i));
    388             if( i == index2 ) {
    389                 chunk = 1 - chunk;
    390                 chunks.get(chunk).add(nodes.get(i));
    391             }
    392             if( ++i >= nodes.size() )
    393                 i = 0;
    394             madeCircle = true;
    395         }
    396         chunks.get(chunk).add(nodes.get(i));
    397 
    398         // check which segment to add
    399         List<Node> testRing = new ArrayList<Node>(segment.getNodes());
    400         closePolygon(testRing, chunks.get(0));
    401         chunk = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? 1 : 0;
    402 
    403         // create way
    404         Way w = new Way();
    405         w.setKeys(segment.getKeys());
    406         w.setNodes(chunks.get(chunk));
    407         return w;
    408     }
    409 
    410335    private static class RingSegment {
    411336        private List<Node> nodes;
Note: See TracChangeset for help on using the changeset viewer.