Changeset 3636 in josm


Ignore:
Timestamp:
Oct 24, 2010 10:25:12 AM (3 years ago)
Author:
bastiK
Message:

see #5577 (patch by extropy) - Move some methods and make them public static

Location:
trunk/src/org/openstreetmap/josm
Files:
2 added
1 edited

Legend:

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

    r3595 r3636  
    22package org.openstreetmap.josm.actions; 
    33 
    4 import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.combineTigerTags; 
    5 import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.completeTagCollectionForEditing; 
    6 import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing; 
    74import static org.openstreetmap.josm.tools.I18n.marktr; 
    85import static org.openstreetmap.josm.tools.I18n.tr; 
     
    129import java.awt.event.KeyEvent; 
    1310import java.awt.geom.Area; 
    14 import java.awt.geom.Line2D; 
    1511import java.util.ArrayList; 
    1612import java.util.Collection; 
    1713import java.util.Collections; 
    18 import java.util.Comparator; 
    1914import java.util.HashMap; 
    2015import java.util.HashSet; 
     
    3934import org.openstreetmap.josm.data.UndoRedoHandler; 
    4035import org.openstreetmap.josm.data.coor.EastNorth; 
    41 import org.openstreetmap.josm.data.coor.LatLon; 
    4236import org.openstreetmap.josm.data.osm.DataSet; 
    4337import org.openstreetmap.josm.data.osm.Node; 
     38import org.openstreetmap.josm.data.osm.NodePositionComparator; 
    4439import org.openstreetmap.josm.data.osm.OsmPrimitive; 
    4540import org.openstreetmap.josm.data.osm.Relation; 
     
    4843import org.openstreetmap.josm.data.osm.Way; 
    4944import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog; 
     45import org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil; 
     46import org.openstreetmap.josm.tools.Geometry; 
    5047import org.openstreetmap.josm.tools.Pair; 
    5148import org.openstreetmap.josm.tools.Shortcut; 
    5249 
     50/** 
     51 * Join Areas (i.e. closed ways and multipolygons) 
     52 */ 
    5353public class JoinAreasAction extends JosmAction { 
    5454    // This will be used to commit commands and unite them into one large command sequence at the end 
     
    110110    //saves a way and the "inside" side 
    111111    // insideToTheLeft: if true left side is "in", false -right side is "in". Left and right are determined along the orientation of way. 
    112     private static class WayInPolygon { 
     112    public static class WayInPolygon { 
    113113        public final Way way; 
    114114        public boolean insideToTheRight; 
     
    137137     * 
    138138     */ 
    139     private static class AssembledPolygon { 
     139    public static class AssembledPolygon { 
    140140        public List<WayInPolygon> ways; 
    141141 
     
    164164    } 
    165165 
    166  
    167166    public static class AssembledMultipolygon { 
    168167        public AssembledPolygon outerWay; 
     
    209208 
    210209        public WayInPolygon startNewWay() { 
    211             if (availableWays.size() == 0) { 
     210            if (availableWays.isEmpty()) { 
    212211                lastWay = null; 
    213212            } else { 
     
    247246                        //this is the path we came from - ignore it. 
    248247                    } 
    249                     else if (bestWay == null || (isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode) == rightmost)) { 
     248                    else if (bestWay == null || (Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode) == rightmost)) { 
    250249                        //the new way is better 
    251250                        bestWay = way; 
     
    262261                        //this is the path we came from - ignore it. 
    263262                    } 
    264                     else if (bestWay == null || (isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode) == rightmost)) { 
     263                    else if (bestWay == null || (Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode) == rightmost)) { 
    265264                        //the new way is better 
    266265                        bestWay = way; 
     
    291290 
    292291    /** 
    293      * Provides some node order , based on coordinates, nodes with equal coordinates are equal. 
    294      * @author viesturs 
    295      * 
    296      */ 
    297     private class NodePositionComparator implements Comparator<Node> { 
    298  
    299         @Override 
    300         public int compare(Node n1, Node n2) { 
    301  
    302             double dLat = n1.getCoor().lat() - n2.getCoor().lat(); 
    303             double dLon = n1.getCoor().lon() - n2.getCoor().lon(); 
    304  
    305             if (dLat > 0) 
    306                 return 1; 
    307             else if (dLat < 0) 
    308                 return -1; 
    309             else if (dLon == 0) //dlat is 0 here 
    310                 return 0; 
    311             else 
    312                 return dLon > 0 ? 1 : -1; 
    313         } 
    314     } 
    315  
    316  
    317     /** 
    318292     * Helper storage class for finding findOuterWays 
    319293     * @author viesturs 
     
    328302        } 
    329303    } 
    330  
    331304 
    332305    // Adds the menu entry, Shortcuts, etc. 
     
    415388    } 
    416389 
    417  
    418390    /** 
    419391     * Tests if the areas have some intersections to join. 
     
    430402 
    431403        //find intersection points 
    432         ArrayList<Node> nodes = addIntersections(allStartingWays, true); 
     404        ArrayList<Node> nodes = Geometry.addIntersections(allStartingWays, true, cmds); 
    433405        return nodes.size() > 0; 
    434406    } 
     
    466438 
    467439        //find intersection points 
    468         ArrayList<Node> nodes = addIntersections(allStartingWays, false); 
     440        ArrayList<Node> nodes = Geometry.addIntersections(allStartingWays, false, cmds); 
    469441 
    470442        //no intersections, return. 
    471         if (nodes.size() == 0) return result; 
     443        if (nodes.isEmpty()) 
     444            return result; 
    472445        commitCommands(marktr("Added node on all intersections")); 
    473446 
     
    529502        } 
    530503 
    531  
    532504        makeCommitsOneAction(marktr("Joined overlapping areas")); 
    533505 
     
    563535        TagCollection wayTags = TagCollection.unionOfAllPrimitives(ways); 
    564536        TagCollection completeWayTags = new TagCollection(wayTags); 
    565         combineTigerTags(completeWayTags); 
    566         normalizeTagCollectionBeforeEditing(completeWayTags, ways); 
     537        TagConflictResolutionUtil.combineTigerTags(completeWayTags); 
     538        TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing(completeWayTags, ways); 
    567539        TagCollection tagsToEdit = new TagCollection(completeWayTags); 
    568         completeTagCollectionForEditing(tagsToEdit); 
     540        TagConflictResolutionUtil.completeTagCollectionForEditing(tagsToEdit); 
    569541 
    570542        CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance(); 
     
    596568    } 
    597569 
    598  
    599570    /** 
    600571     * This method removes duplicate points (if any) from the input way. 
     
    659630        return totalNodesRemoved > 0; 
    660631    } 
    661  
    662  
    663  
    664     /** 
    665      * Will find all intersection and add nodes there for list of given ways. Handles self-intersections too. 
    666      * And make commands to add the intersection points to ways. 
    667      * @param List<Way> - a list of ways to test 
    668      * @return ArrayList<Node> List of new nodes 
    669      * Prerequisite: no two nodes have the same coordinates. 
    670      */ 
    671     private ArrayList<Node> addIntersections(List<Way> ways, boolean test) { 
    672         //TODO: this is a bit slow - O( (number of nodes)^2 + numberOfIntersections * numberOfNodes ) 
    673  
    674         //stupid java, cannot instantiate array of generic classes.. 
    675         @SuppressWarnings("unchecked") 
    676         ArrayList<Node>[] newNodes = new ArrayList[ways.size()]; 
    677         boolean[] changedWays = new boolean[ways.size()]; 
    678  
    679         Set<Node> intersectionNodes = new LinkedHashSet<Node>(); 
    680  
    681         for (int pos = 0; pos < ways.size(); pos ++) { 
    682             newNodes[pos] = new ArrayList<Node>(ways.get(pos).getNodes()); 
    683             changedWays[pos] = false; 
    684         } 
    685  
    686         //iterate over all segment pairs and introduce the intersections 
    687  
    688         Comparator<Node> coordsComparator = new NodePositionComparator(); 
    689  
    690         int seg1Way = 0; 
    691         int seg1Pos = -1; 
    692  
    693         while (true) { 
    694             //advance to next segment 
    695             seg1Pos++; 
    696             if (seg1Pos > newNodes[seg1Way].size() - 2) { 
    697                 seg1Way++; 
    698                 seg1Pos = 0; 
    699  
    700                 if (seg1Way == ways.size()) { //finished 
    701                     break; 
    702                 } 
    703             } 
    704  
    705  
    706             //iterate over secondary segment 
    707  
    708             int seg2Way = seg1Way; 
    709             int seg2Pos = seg1Pos + 1;//skip the adjacent segment 
    710  
    711             while (true) { 
    712  
    713                 //advance to next segment 
    714                 seg2Pos++; 
    715                 if (seg2Pos > newNodes[seg2Way].size() - 2) { 
    716                     seg2Way++; 
    717                     seg2Pos = 0; 
    718  
    719                     if (seg2Way == ways.size()) { //finished 
    720                         break; 
    721                     } 
    722                 } 
    723  
    724                 //need to get them again every time, because other segments may be changed 
    725                 Node seg1Node1 = newNodes[seg1Way].get(seg1Pos); 
    726                 Node seg1Node2 = newNodes[seg1Way].get(seg1Pos + 1); 
    727                 Node seg2Node1 = newNodes[seg2Way].get(seg2Pos); 
    728                 Node seg2Node2 = newNodes[seg2Way].get(seg2Pos + 1); 
    729  
    730                 int commonCount = 0; 
    731                 //test if we have common nodes to add. 
    732                 if (seg1Node1 == seg2Node1 || seg1Node1 == seg2Node2) { 
    733                     commonCount ++; 
    734  
    735                     if (seg1Way == seg2Way && 
    736                             seg1Pos == 0 && 
    737                             seg2Pos == newNodes[seg2Way].size() -2) { 
    738                         //do not add - this is first and last segment of the same way. 
    739                     } else { 
    740                         intersectionNodes.add(seg1Node1); 
    741                     } 
    742                 } 
    743  
    744                 if (seg1Node2 == seg2Node1 || seg1Node2 == seg2Node2) { 
    745                     commonCount ++; 
    746  
    747                     intersectionNodes.add(seg1Node2); 
    748                 } 
    749  
    750                 //no common nodes - find intersection 
    751                 if (commonCount == 0) { 
    752                     LatLon intersection = getLineLineIntersection( 
    753                             seg1Node1.getEastNorth().east(), seg1Node1.getEastNorth().north(), 
    754                             seg1Node2.getEastNorth().east(), seg1Node2.getEastNorth().north(), 
    755                             seg2Node1.getEastNorth().east(), seg2Node1.getEastNorth().north(), 
    756                             seg2Node2.getEastNorth().east(), seg2Node2.getEastNorth().north()); 
    757  
    758                     if (intersection != null) { 
    759                         if (test) { 
    760                             intersectionNodes.add(seg2Node1); 
    761                             return new ArrayList<Node>(intersectionNodes); 
    762                         } 
    763  
    764                         Node newNode = new Node(intersection); 
    765                         Node intNode = newNode; 
    766                         boolean insertInSeg1 = false; 
    767                         boolean insertInSeg2 = false; 
    768  
    769                         //find if the intersection point is at end point of one of the segments, if so use that point 
    770  
    771                         //segment 1 
    772                         if (coordsComparator.compare(newNode, seg1Node1) == 0) { 
    773                             intNode = seg1Node1; 
    774                         } else if (coordsComparator.compare(newNode, seg1Node2) == 0) { 
    775                             intNode = seg1Node2; 
    776                         } else { 
    777                             insertInSeg1 = true; 
    778                         } 
    779  
    780                         //segment 2 
    781                         if (coordsComparator.compare(newNode, seg2Node1) == 0) { 
    782                             intNode = seg2Node1; 
    783                         } else if (coordsComparator.compare(newNode, seg2Node2) == 0) { 
    784                             intNode = seg2Node2; 
    785                         } else { 
    786                             insertInSeg2 = true; 
    787                         } 
    788  
    789                         if (insertInSeg1) { 
    790                             newNodes[seg1Way].add(seg1Pos +1, intNode); 
    791                             changedWays[seg1Way] = true; 
    792  
    793                             //fix seg2 position, as indexes have changed, seg2Pos is always bigger than seg1Pos on the same segment. 
    794                             if (seg2Way == seg1Way) { 
    795                                 seg2Pos ++; 
    796                             } 
    797                         } 
    798  
    799                         if (insertInSeg2) { 
    800                             newNodes[seg2Way].add(seg2Pos +1, intNode); 
    801                             changedWays[seg2Way] = true; 
    802  
    803                             //Do not need to compare again to already split segment 
    804                             seg2Pos ++; 
    805                         } 
    806  
    807                         intersectionNodes.add(intNode); 
    808  
    809                         if (intNode == newNode) { 
    810                             cmds.add(new AddCommand(intNode)); 
    811                         } 
    812                     } 
    813                 } 
    814                 else if (test && intersectionNodes.size() > 0) 
    815                     return new ArrayList<Node>(intersectionNodes); 
    816             } 
    817         } 
    818  
    819         for (int pos = 0; pos < ways.size(); pos ++) { 
    820             if (changedWays[pos] == false) { 
    821                 continue; 
    822             } 
    823  
    824             Way way = ways.get(pos); 
    825             Way newWay = new Way(way); 
    826             newWay.setNodes(newNodes[pos]); 
    827  
    828             cmds.add(new ChangeCommand(way, newWay)); 
    829         } 
    830  
    831         return new ArrayList<Node>(intersectionNodes); 
    832     } 
    833  
    834     /** 
    835      * Finds the intersection of two lines 
    836      * @return LatLon null if no intersection was found, the LatLon coordinates of the intersection otherwise 
    837      */ 
    838     static private LatLon getLineLineIntersection( 
    839             double x1, double y1, double x2, double y2, 
    840             double x3, double y3, double x4, double y4) { 
    841  
    842         if (!Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) return null; 
    843  
    844         // Convert line from (point, point) form to ax+by=c 
    845         double a1 = y2 - y1; 
    846         double b1 = x1 - x2; 
    847         double c1 = x2*y1 - x1*y2; 
    848  
    849         double a2 = y4 - y3; 
    850         double b2 = x3 - x4; 
    851         double c2 = x4*y3 - x3*y4; 
    852  
    853         // Solve the equations 
    854         double det = a1*b2 - a2*b1; 
    855         if (det == 0) return null; // Lines are parallel 
    856  
    857         return Main.proj.eastNorth2latlon(new EastNorth( 
    858                 (b1*c2 - b2*c1)/det, 
    859                 (a2*c1 -a1*c2)/det 
    860         )); 
    861     } 
    862  
    863  
    864632 
    865633    /** 
     
    884652    } 
    885653 
    886  
    887654    /** 
    888655     * This method analyzes the way and assigns each part what direction polygon "inside" is. 
     
    950717                    Node nextNode = way.getNode(1); 
    951718 
    952                     if (topWay == null || !isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) { 
     719                    if (topWay == null || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) { 
    953720                        //the new way is better 
    954721                        topWay = way; 
     
    962729                    Node nextNode = way.getNode(way.getNodesCount() - 2); 
    963730 
    964                     if (topWay == null || !isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) { 
     731                    if (topWay == null || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) { 
    965732                        //the new way is better 
    966733                        topWay = way; 
     
    976743 
    977744            //there will be no parallel segments in the middle of way, so all fine. 
    978             wayClockwise = angleIsClockwise(prev, topNode, next); 
     745            wayClockwise = Geometry.angleIsClockwise(prev, topNode, next); 
    979746        } 
    980747 
     
    999766                break; 
    1000767            } 
    1001  
    1002768 
    1003769            //find intersecting segments 
     
    1037803                    Node wayBNode = wayB.getNode(1); 
    1038804 
    1039                     boolean wayAToTheRight = isToTheRightSideOfLine(prevNode, headNode, nextNode, wayANode); 
    1040                     boolean wayBToTheRight = isToTheRightSideOfLine(prevNode, headNode, nextNode, wayBNode); 
     805                    boolean wayAToTheRight = Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayANode); 
     806                    boolean wayBToTheRight = Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayBNode); 
    1041807 
    1042808                    if (wayAToTheRight != wayBToTheRight) { 
     
    1084850    } 
    1085851 
    1086  
    1087     /** 
    1088      * Simple chunking version. Does not care about circular ways and result being proper, we will glue it all back together later on. 
     852    /** 
     853     * Simple chunking version. Does not care about circular ways and result being 
     854     * proper, we will glue it all back together later on. 
    1089855     * @param way the way to chunk 
    1090856     * @param splitNodes the places where to cut. 
     
    1185951        return result; 
    1186952    } 
    1187  
    1188  
    1189953 
    1190954    /** 
     
    12851049    } 
    12861050 
    1287  
    12881051    /** 
    12891052     * This method checks if polygons have several touching parts and splits them in several polygons. 
     
    13231086        return newPolygons; 
    13241087    } 
    1325  
    1326  
    1327     /** 
    1328      * Tests if given point is to the right side of path consisting of 3 points. 
    1329      * @param lineP1 first point in path 
    1330      * @param lineP2 second point in path 
    1331      * @param lineP3 third point in path 
    1332      * @param testPoint 
    1333      * @return true if to the right side, false otherwise 
    1334      */ 
    1335     public static boolean isToTheRightSideOfLine(Node lineP1, Node lineP2, Node lineP3, Node testPoint) { 
    1336         boolean pathBendToRight = angleIsClockwise(lineP1, lineP2, lineP3); 
    1337         boolean rightOfSeg1 = angleIsClockwise(lineP1, lineP2, testPoint); 
    1338         boolean rightOfSeg2 = angleIsClockwise(lineP2, lineP3, testPoint); 
    1339  
    1340         if (pathBendToRight) 
    1341             return rightOfSeg1 && rightOfSeg2; 
    1342         else 
    1343             return !(!rightOfSeg1 && !rightOfSeg2); 
    1344     } 
    1345  
    1346     /** 
    1347      * This method tests if secondNode is clockwise to first node. 
    1348      * @param commonNode starting point for both vectors 
    1349      * @param firstNode first vector end node 
    1350      * @param secondNode second vector end node 
    1351      * @return true if first vector is clockwise before second vector. 
    1352      */ 
    1353  
    1354     public static boolean angleIsClockwise(Node commonNode, Node firstNode, Node secondNode) { 
    1355         double dy1 = (firstNode.getEastNorth().getY() - commonNode.getEastNorth().getY()); 
    1356         double dy2 = (secondNode.getEastNorth().getY() - commonNode.getEastNorth().getY()); 
    1357         double dx1 = (firstNode.getEastNorth().getX() - commonNode.getEastNorth().getX()); 
    1358         double dx2 = (secondNode.getEastNorth().getX() - commonNode.getEastNorth().getX()); 
    1359  
    1360         return dy1 * dx2 - dx1 * dy2 > 0; 
    1361     } 
    1362  
    13631088 
    13641089    /** 
     
    13751100            if (!outsideNodes.contains(insideNode)) 
    13761101                //simply test the one node 
    1377                 return nodeInsidePolygon(insideNode, outside.getNodes()); 
     1102                return Geometry.nodeInsidePolygon(insideNode, outside.getNodes()); 
    13781103        } 
    13791104 
     
    13811106        return false; 
    13821107    } 
    1383  
    1384     /** 
    1385      * Tests if point is inside a polygon. The polygon can be self-intersecting. In such case the contains function works in xor-like manner. 
    1386      * @param polygonNodes list of nodes from polygon path. 
    1387      * @param point the point to test 
    1388      * @return true if the point is inside polygon. 
    1389      * FIXME: this should probably be moved to tools.. 
    1390      */ 
    1391     public static boolean nodeInsidePolygon(Node point, List<Node> polygonNodes) { 
    1392         if (polygonNodes.size() < 3) 
    1393             return false; 
    1394  
    1395         boolean inside = false; 
    1396         Node p1, p2; 
    1397  
    1398         //iterate each side of the polygon, start with the last segment 
    1399         Node oldPoint = polygonNodes.get(polygonNodes.size() - 1); 
    1400  
    1401         for (Node newPoint : polygonNodes) { 
    1402             //skip duplicate points 
    1403             if (newPoint.equals(oldPoint)) { 
    1404                 continue; 
    1405             } 
    1406  
    1407             //order points so p1.lat <= p2.lat; 
    1408             if (newPoint.getEastNorth().getY() > oldPoint.getEastNorth().getY()) { 
    1409                 p1 = oldPoint; 
    1410                 p2 = newPoint; 
    1411             } else { 
    1412                 p1 = newPoint; 
    1413                 p2 = oldPoint; 
    1414             } 
    1415  
    1416             //test if the line is crossed and if so invert the inside flag. 
    1417             if ((newPoint.getEastNorth().getY() < point.getEastNorth().getY()) == (point.getEastNorth().getY() <= oldPoint.getEastNorth().getY()) 
    1418                     && (point.getEastNorth().getX() - p1.getEastNorth().getX()) * (p2.getEastNorth().getY() - p1.getEastNorth().getY()) 
    1419                     < (p2.getEastNorth().getX() - p1.getEastNorth().getX()) * (point.getEastNorth().getY() - p1.getEastNorth().getY())) 
    1420             { 
    1421                 inside = !inside; 
    1422             } 
    1423  
    1424             oldPoint = newPoint; 
    1425         } 
    1426  
    1427         return inside; 
    1428     } 
    1429  
    14301108 
    14311109    /** 
     
    14431121        return result; 
    14441122    } 
    1445  
    14461123 
    14471124    /** 
     
    14731150    } 
    14741151 
    1475  
    14761152    /** 
    14771153     * Joins a list of ways (using CombineWayAction and ReverseWayAction as specified in WayInPath) 
     
    15061182        return result.a; 
    15071183    } 
    1508  
    15091184 
    15101185    /** 
     
    16041279    } 
    16051280 
    1606  
    16071281    /** 
    16081282     * This method filters the list of relations that form the multipolygons. 
     
    16271301        return result; 
    16281302    } 
    1629  
    16301303 
    16311304    /** 
     
    16501323    } 
    16511324 
    1652  
    16531325    /** 
    16541326     * Removes a given OsmPrimitive from all relations 
     
    16851357        return result; 
    16861358    } 
    1687  
    16881359 
    16891360    /** 
Note: See TracChangeset for help on using the changeset viewer.