Changeset 26816 in osm for applications/editors
- Timestamp:
- 2011-10-09T21:06:39+02:00 (13 years ago)
- Location:
- applications/editors/josm/plugins/reltoolbox/src/relcontext/actions
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java
r26815 r26816 14 14 import org.openstreetmap.josm.data.coor.EastNorth; 15 15 import org.openstreetmap.josm.data.osm.*; 16 import org.openstreetmap.josm.data.osm.MultipolygonCreate.JoinedPolygon;17 16 import org.openstreetmap.josm.gui.DefaultNameFormatter; 18 17 import org.openstreetmap.josm.tools.GBC; … … 423 422 boolean found = false; 424 423 for( Way ring : rings ) { 425 System.out.println("segment " + segment.getId() + ", ring " + ring.getId());426 System.out.println("ring.containsNode(segment.firstNode()) = " + ring.containsNode(segment.firstNode()));427 System.out.println("ring.containsNode(segment.lastNode() = " + ring.containsNode(segment.lastNode()));428 System.out.println("segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()) = " + segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()));429 424 if( ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode()) 430 425 && !segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()) ) … … 469 464 return relations; 470 465 } 471 472 /**473 * Creates ALOT of Multipolygons and pets him gently.474 * @return list of new relations.475 */476 private List<Relation> makeManySimpleMultipolygonsOld( Collection<Way> selection ) {477 List<Command> commands = new ArrayList<Command>();478 List<Way> ways = new ArrayList<Way>(selection.size());479 Map<Way, Way> wayDiff = new HashMap<Way, Way>(selection.size());480 List<Relation> relations = new ArrayList<Relation>(ways.size());481 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);482 for( Way w : selection ) {483 Way newWay = new Way(w);484 wayDiff.put(w, newWay);485 commands.add(new ChangeCommand(w, newWay));486 ways.add(newWay);487 Relation r = new Relation();488 r.put("type", "multipolygon");489 r.addMember(new RelationMember("outer", w));490 // move tags to relations491 for( String key : newWay.keySet() ) {492 if( !linearTags.contains(key) ) {493 r.put(key, newWay.get(key));494 newWay.remove(key);495 }496 }497 if( !w.isClosed() ) {498 Way ring = null;499 for( Way tring : selection )500 if( tring.containsNode(newWay.firstNode()) && tring.containsNode(newWay.lastNode())501 && !segmentInsidePolygon(newWay.getNode(0), newWay.getNode(1), tring.getNodes()) )502 ring = tring;503 Way intersection = makeIntersectionLine(newWay, ring);504 commands.add(new AddCommand(intersection));505 r.addMember(new RelationMember("outer", intersection));506 }507 relations.add(r);508 }509 510 for( int i = 0; i < relations.size() - 1; i++ )511 for( int j = i + 1; j < relations.size(); j++ )512 collideMultipolygons(relations.get(i), relations.get(j), commands, wayDiff);513 514 for( Relation r : relations )515 commands.add(new AddCommand(r));516 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands));517 return relations;518 }519 520 /**521 * Copies segment from {@code ring} to close a multipolygon containing {@code segment}.522 * @param segment Unclosed segment.523 * @param ring Closed ring.524 * @return Missing way.525 */526 private Way makeIntersectionLine( Way segment, Way ring ) {527 List<Node> nodes = new ArrayList<Node>(ring.getNodes());528 nodes.remove(nodes.size() - 1);529 int index1 = nodes.indexOf(segment.firstNode());530 int index2 = nodes.indexOf(segment.lastNode());531 if( index1 == index2 || index1 < 0 || index2 < 0 )532 return null;533 534 // split ring535 List<List<Node>> chunks = new ArrayList<List<Node>>(2);536 chunks.add(new ArrayList<Node>());537 chunks.add(new ArrayList<Node>());538 int chunk = 0, i = index1;539 boolean madeCircle = false;540 while( i != index1 || !madeCircle ) {541 chunks.get(chunk).add(nodes.get(i));542 if( i == index2 ) {543 chunk = 1 - chunk;544 chunks.get(chunk).add(nodes.get(i));545 }546 if( ++i >= nodes.size() )547 i = 0;548 madeCircle = true;549 }550 chunks.get(chunk).add(nodes.get(i));551 552 // check which segment to add553 List<Node> testRing = new ArrayList<Node>(segment.getNodes());554 closePolygon(testRing, chunks.get(0));555 chunk = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? 1 : 0;556 557 // create way558 Way w = new Way();559 w.setKeys(segment.getKeys());560 w.setNodes(chunks.get(chunk));561 return w;562 }563 466 564 467 /** … … 583 486 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0)); 584 487 return Geometry.nodeInsidePolygon(testNode, polygon); 585 }586 587 /**588 * Removes any intersections between multipolygons.589 * @param r1 First multipolygon.590 * @param r2 Second multipolygon.591 * @param commands List of commands. Only add way commands go there, also see wayDiff.592 * @param wayDiff The mapping old way to new Way: if there is no entry in this map, it is created, and593 * a ChangeCommand is issued.594 */595 private static void collideMultipolygons( Relation r1, Relation r2, List<Command> commands, Map<Way, Way> wayDiff ) {596 }597 598 /**599 * merges two ways from two multipolygons. The result is several new ways and changed old ones.600 * But it can also remove one old way — it is returned then.601 * @param w1602 * @param w2603 * @param commands604 */605 private static Way collideWays( Way w1, Way w2, List<Command> commands ) {606 return null;607 488 } 608 489 … … 771 652 772 653 /** 773 * Find a multipolygon at the tips of a segment, try to close the way.774 *775 * Note: this method is abandoned because of it's skyrocketing complexity. The only thing is776 * left to write is splitting and ordering ways (see below). But I doubt there is a point to it.777 */778 private Relation tryToCloseOneWayOld( Way segment ) {779 if( segment.isClosed() || segment.isIncomplete() )780 return null;781 782 // find relations that have ways from both arrays783 Set<Relation> relations1 = new HashSet<Relation>();784 for( Way way : OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class) )785 relations1.addAll(OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class));786 Set<Relation> relations2 = new HashSet<Relation>();787 for( Way way : OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class) )788 relations2.addAll(OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class));789 List<Relation> relations = intersection(relations1, relations2);790 for( Iterator<Relation> iter = relations.iterator(); iter.hasNext(); ) {791 Relation candidate = iter.next();792 if( !candidate.isMultipolygon() || candidate.isDeleted() || candidate.isIncomplete() )793 iter.remove();794 }795 if( relations.isEmpty() )796 return null;797 int i = 0;798 String error = "";799 MultipolygonCreate mpc = new MultipolygonCreate();800 JoinedPolygon poly = null;801 while( error != null && i < relations.size() ) {802 error = mpc.makeFromWays(OsmPrimitive.getFilteredSet(relations.get(i).getMemberPrimitives(), Way.class));803 if( error != null ) {804 for( JoinedPolygon p : mpc.outerWays ) {805 if( p.nodes.contains(segment.firstNode()) && p.nodes.contains(segment.lastNode()) ) {806 poly = p;807 break;808 }809 }810 }811 i++;812 }813 if( poly == null )814 return null; // no correct multipolygons with outer contour that segment touches815 Relation multipolygon = relations.get(i - 1);816 817 // time to create a new multipolygon relation and a command stack818 List<Command> commands = new ArrayList<Command>();819 Relation newRelation = new Relation();820 newRelation.put("type", "multipolygon");821 newRelation.addMember(new RelationMember("outer", segment));822 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);823 Way segmentCopy = new Way(segment);824 boolean changed = false;825 for( String key : segmentCopy.keySet() ) {826 if( !linearTags.contains(key) ) {827 newRelation.put(key, segmentCopy.get(key));828 segmentCopy.remove(key);829 changed = true;830 }831 }832 if( changed )833 commands.add(new ChangeCommand(segment, segmentCopy));834 835 // find a path from one point to another via found outer contour836 // but first, determine in which order to traverse nodes837 int index1 = poly.nodes.indexOf(segment.firstNode());838 int index2 = poly.nodes.indexOf(segment.lastNode());839 840 List<List<Node>> chunks = new ArrayList<List<Node>>(2);841 chunks.add(new ArrayList<Node>());842 chunks.add(new ArrayList<Node>());843 int chunk = 0;844 i = index1;845 boolean madeCircle = false;846 while( i != index1 || !madeCircle ) {847 chunks.get(chunk).add(poly.nodes.get(i));848 if( i == index2 ) {849 chunk = 1 - chunk;850 chunks.get(chunk).add(poly.nodes.get(i));851 }852 if( ++i >= poly.nodes.size() )853 i = 0;854 madeCircle = true;855 }856 chunks.get(chunk).add(poly.nodes.get(i));857 858 // check which segment to add859 List<Node> testRing = new ArrayList<Node>(segment.getNodes());860 closePolygon(testRing, chunks.get(0));861 // Node startNode = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? segment.lastNode() : segment.firstNode();862 // Node endNode = startNode.equals(segment.firstNode()) ? segment.lastNode() : segment.firstNode();863 int startIndex = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? index2 : index1;864 int endIndex = startIndex == index2 ? index1 : index2;865 Node startNode = poly.nodes.get(startIndex);866 Node endNode = poly.nodes.get(endIndex);867 868 // add ways containing nodes from startNode to endNode869 // note: they are in order!870 i = 0;871 while( i < poly.ways.size() && !poly.ways.get(i).containsNode(startNode) )872 i++;873 int startNodeIndex = poly.ways.get(i).getNodes().indexOf(startNode);874 if( startNodeIndex == 0 || startNodeIndex == poly.ways.get(i).getNodesCount() - 1 )875 i++; // if it's the last node, take next way876 877 if( poly.ways.get(i).containsNode(endNode) ) {878 // ok, both nodes are in the same way879 // split it, return the new part880 List<Way> newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);881 // find which of the parts we need (in case of closed way)882 Node testNode = poly.nodes.get((index1 + 1) % poly.nodes.size());883 } else {884 // so, let's take ways one by one885 // todo: split way 1 and add relevant part886 List<Way> newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);887 i++;888 while( !poly.ways.get(i).containsNode(endNode) ) {889 newRelation.addMember(new RelationMember("outer", poly.ways.get(i)));890 i++;891 }892 // todo: split way 2 and add relevant part893 newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);894 }895 896 commands.add(new AddCommand(newRelation));897 Main.main.undoRedo.add(new SequenceCommand(tr("Complete multipolygon for way {0}",898 DefaultNameFormatter.getInstance().format(segment)), commands));899 return newRelation;900 }901 902 /**903 654 * Returns all elements from {@code list1} that are in {@code list2}. 904 655 */ … … 910 661 return result; 911 662 } 912 913 public static class TheRing {914 private Way source;915 private List<RingSegment> segments;916 private Relation relation = null;917 918 public TheRing( Way source ) {919 this.source = source;920 segments = new ArrayList<RingSegment>(1);921 segments.add(new RingSegment(source));922 }923 924 public void collide( TheRing other ) {925 List<Node> intersectionNodes = new ArrayList<Node>();926 List<RingSegment> segmentsList1 = new ArrayList<RingSegment>(segments);927 List<RingSegment> segmentsList2 = new ArrayList<RingSegment>(other.segments);928 boolean collideNoted = false;929 for( int i = 0; i < segmentsList1.size(); i++ ) {930 if( !segmentsList1.get(i).isReference() )931 for( int j = 0; j < segmentsList2.size(); j++ ) {932 // not colliding referencing nodes: they've already collided, and933 // there should be no more than two ways passing through two points.934 if( !segmentsList1.get(i).isReference() ) {935 intersectionNodes.clear();936 boolean colliding = false;937 List<Node> nodes1 = segmentsList1.get(i).getNodes();938 List<Node> nodes2 = segmentsList2.get(j).getNodes();939 for( int ni = 0; ni < nodes2.size(); ni++ ) {940 if( nodes1.contains(nodes2.get(ni)) != colliding ) {941 intersectionNodes.add(nodes2.get(colliding ? ni-1 : ni));942 colliding = !colliding;943 }944 }945 if( colliding )946 intersectionNodes.add(nodes2.get(nodes2.size()-1));947 // when an intersection of two rings spans a ring's beginning948 if( segmentsList1.get(i).isRing() && segmentsList2.get(j).isRing() && intersectionNodes.contains(nodes2.get(0)) && intersectionNodes.contains(nodes2.get(nodes2.size()-1)) ) {949 intersectionNodes.remove(0);950 intersectionNodes.remove(intersectionNodes.size()-1);951 intersectionNodes.add(intersectionNodes.get(0));952 intersectionNodes.remove(0);953 }954 if( !collideNoted && !intersectionNodes.isEmpty() ) {955 System.out.println("Rings " + this + " and " + other + " collide.");956 collideNoted = true;957 }958 System.out.print("Intersection nodes for segments " + segmentsList1.get(i) + " and " + segmentsList2.get(j) + ": ");959 for( Node inode : intersectionNodes )960 System.out.print(inode.getUniqueId() + ",");961 System.out.println();962 // unclosed ways produce duplicate nodes963 int ni = 1;964 while( ni < intersectionNodes.size() ) {965 if( intersectionNodes.get(ni-1).equals(intersectionNodes.get(ni)) )966 intersectionNodes.remove(ni-1);967 else968 ni++;969 }970 // boolean thisWayIsReversed = !intersectionNodes.isEmpty() && nodes1.indexOf(intersectionNodes.get(0)) > nodes1.indexOf(intersectionNodes.get(1));971 // now split both ways at control points and remove duplicate parts972 ni = 0;973 while( ni+1 < intersectionNodes.size() ) {974 if( !segmentsList1.get(i).isReferencingEqual(segmentsList2.get(j)) ) {975 boolean[] isarc = new boolean[] {976 segments.size() == 1 && !segments.get(0).isRing(),977 other.segments.size() == 1 && !other.segments.get(0).isRing()978 };979 RingSegment segment = splitRingAt(i, intersectionNodes.get(ni), intersectionNodes.get(ni+1));980 RingSegment otherSegment = other.splitRingAt(j, intersectionNodes.get(ni), intersectionNodes.get(ni+1));981 if( !isarc[0] && !isarc[1] ) {982 if( segments.size() > 2 )983 segment.makeReference(otherSegment);984 else {985 // this ring was a ring, and we're not sure "segment" is a correct segment986 if( segments.get(0).getNodes().size() == otherSegment.getNodes().size() &&987 (segments.get(0).getNodes().get(1).equals(otherSegment.getNodes().get(1))) ||988 (segments.get(0).getNodes().get(segments.get(0).getNodes().size()-2).equals(otherSegment.getNodes().get(1))))989 segments.get(0).makeReference(otherSegment);990 else991 segments.get(1).makeReference(otherSegment);992 }993 } else {994 // 1. A ring is an arc. It should have only 2 segments after this995 // 2. But it has one, so add otherSegment as the second.996 // 3. determine which segment!997 if( isarc[0] ) {998 if( other.segments.size() > 2 )999 segments.add(new RingSegment(otherSegment));1000 else {1001 // choose between 2 segments1002 List<Node> testRing = new ArrayList<Node>(segments.get(0).getNodes());1003 closePolygon(testRing, other.segments.get(0).getNodes());1004 int segmentToAdd = segmentInsidePolygon(other.segments.get(1).getNodes().get(0),1005 other.segments.get(1).getNodes().get(1), testRing) ? 1 : 0;1006 segments.add(new RingSegment(other.segments.get(segmentToAdd)));1007 }1008 } else1009 if( segments.size() > 2 )1010 other.segments.add(new RingSegment(segment));1011 else {1012 // choose between 2 segments1013 List<Node> testRing = new ArrayList<Node>(other.segments.get(0).getNodes());1014 closePolygon(testRing, segments.get(0).getNodes());1015 int segmentToAdd = segmentInsidePolygon(segments.get(1).getNodes().get(0),1016 segments.get(1).getNodes().get(1), testRing) ? 1 : 0;1017 other.segments.add(new RingSegment(segments.get(segmentToAdd)));1018 }1019 }1020 }1021 ni += 2;1022 }1023 }1024 }1025 }1026 }1027 1028 /**1029 * Split the segment in this ring at those nodes.1030 * @return The segment between nodes.1031 */1032 private RingSegment splitRingAt( int segmentIndex, Node n1, Node n2 ) {1033 if( n1.equals(n2) )1034 throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());1035 RingSegment segment = segments.get(segmentIndex);1036 boolean isRing = segment.isRing();1037 System.out.println("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());1038 boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);1039 if( reversed && !isRing ) {1040 // order nodes1041 Node tmp = n1;1042 n1 = n2;1043 n2 = tmp;1044 }1045 RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1);1046 // if secondPart == null, then n1 == firstNode1047 RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);1048 // if secondPart == null, then thirdPart is between n1 and n21049 // otherwise, thirdPart is between n2 and lastNode1050 // if thirdPart == null, then n2 == lastNode1051 int pos = segmentIndex + 1;1052 if( secondPart != null )1053 segments.add(pos++, secondPart);1054 if( thirdPart != null )1055 segments.add(pos++, thirdPart);1056 RingSegment result = isRing || secondPart == null ? segment : secondPart;1057 System.out.println("Returning segment " + result);1058 return result;1059 }1060 1061 /**1062 * Tries to arrange segments in order for each ring to have at least one.1063 * Also, sets source way for all rings.1064 *1065 * This method should be called, even if there is just one ring.1066 */1067 public static void redistributeSegments( List<TheRing> rings ) {1068 // build segments map1069 Map<RingSegment, TheRing> segmentMap = new HashMap<RingSegment, TheRing>();1070 for( TheRing ring : rings )1071 for( RingSegment seg : ring.segments )1072 if( !seg.isReference())1073 segmentMap.put(seg, ring);1074 1075 // rearrange references1076 for( int i = 0; i < rings.size(); i++) {1077 TheRing ring = rings.get(i);1078 if( ring.countNonReferenceSegments() == 0 ) {1079 // need to find one non-reference segment1080 for( RingSegment seg : ring.segments ) {1081 TheRing otherRing = segmentMap.get(seg.references);1082 if( otherRing.countNonReferenceSegments() > 1 ) {1083 // we could check for >0, but it is prone to deadlocking1084 seg.swapReference();1085 }1086 }1087 }1088 }1089 1090 // initializing source way for each ring1091 for( TheRing ring : rings )1092 ring.putSourceWayFirst();1093 }1094 1095 private int countNonReferenceSegments() {1096 int count = 0;1097 for( RingSegment seg : segments )1098 if( !seg.isReference() )1099 count++;1100 return count;1101 }1102 1103 private void putSourceWayFirst() {1104 for( RingSegment seg : segments ) {1105 if( !seg.isReference() ) {1106 seg.overrideWay(source);1107 return;1108 }1109 }1110 }1111 1112 /**1113 * Returns a list of commands to make a new relation and all newly created ways.1114 * The first way is copied from the source one, ChangeCommand is issued in this case.1115 */1116 public List<Command> getCommands() {1117 System.out.println("Making ring " + this);1118 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);1119 relation = new Relation();1120 relation.put("type", "multipolygon");1121 Way sourceCopy = new Way(source);1122 for( String key : sourceCopy.keySet() ) {1123 if( !linearTags.contains(key) ) {1124 relation.put(key, sourceCopy.get(key));1125 sourceCopy.remove(key);1126 }1127 }1128 1129 // build a map of referencing relations1130 Map<Relation, Integer> referencingRelations = new HashMap<Relation, Integer>();1131 List<Command> relationCommands = new ArrayList<Command>();1132 for( OsmPrimitive p : source.getReferrers() ) {1133 if( p instanceof Relation ) {1134 Relation rel = new Relation((Relation)p);1135 relationCommands.add(new ChangeCommand((Relation)p, rel));1136 for( int i = 0; i < rel.getMembersCount(); i++ )1137 if( rel.getMember(i).getMember().equals(source) )1138 referencingRelations.put(rel, Integer.valueOf(i));1139 }1140 }1141 1142 List<Command> commands = new ArrayList<Command>();1143 boolean foundOwnWay = false;1144 for( RingSegment seg : segments ) {1145 boolean needAdding = !seg.isWayConstructed();1146 Way w = seg.constructWay(seg.isReference() ? null : sourceCopy);1147 if( needAdding )1148 commands.add(new AddCommand(w));1149 if( w.equals(source) ) {1150 if( segments.size() == 1 ) {1151 // one segment means that it is a ring1152 List<Node> segnodes = seg.getNodes();1153 segnodes.add(segnodes.get(0));1154 sourceCopy.setNodes(segnodes);1155 } else1156 sourceCopy.setNodes(seg.getNodes());1157 commands.add(new ChangeCommand(source, sourceCopy));1158 foundOwnWay = true;1159 } else {1160 for( Relation rel : referencingRelations.keySet() ) {1161 int relIndex = referencingRelations.get(rel);1162 rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w));1163 }1164 }1165 relation.addMember(new RelationMember("outer", w));1166 }1167 if( !foundOwnWay )1168 commands.add(new DeleteCommand(source));1169 commands.addAll(relationCommands);1170 commands.add(new AddCommand(relation));1171 return commands;1172 }1173 1174 /**1175 * Returns the relation created in {@link #getCommands()}.1176 */1177 public Relation getRelation() {1178 return relation;1179 }1180 1181 @Override1182 public String toString() {1183 StringBuilder sb = new StringBuilder("TheRing@");1184 sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: ");1185 if( segments.isEmpty() )1186 sb.append("empty");1187 else {1188 sb.append(segments.get(0));1189 for( int i = 1; i < segments.size(); i++ )1190 sb.append(", ").append(segments.get(i));1191 }1192 return sb.append(']').toString();1193 }1194 }1195 1196 private static class RingSegment {1197 private List<Node> nodes;1198 private RingSegment references;1199 private Way resultingWay = null;1200 private boolean wasTemplateApplied = false;1201 private boolean isRing;1202 1203 private RingSegment() {}1204 1205 public RingSegment( Way w ) {1206 this(w.getNodes());1207 }1208 1209 public RingSegment( List<Node> nodes ) {1210 this.nodes = nodes;1211 isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size()-1));1212 if( isRing )1213 nodes.remove(nodes.size()-1);1214 references = null;1215 }1216 1217 public RingSegment( RingSegment ref ) {1218 this.nodes = null;1219 this.references = ref;1220 }1221 1222 /**1223 * Splits this segment at node n. Retains nodes 0..n and moves1224 * nodes n..N to a separate segment that is returned.1225 * @param n node at which to split.1226 * @return new segment, {@code null} if splitting is unnecessary.1227 */1228 public RingSegment split( Node n ) {1229 if( nodes == null )1230 throw new IllegalArgumentException("Cannot split segment: it is a reference");1231 int pos = nodes.indexOf(n);1232 if( pos <= 0 || pos >= nodes.size()-1 )1233 return null;1234 List<Node> newNodes = new ArrayList<Node>(nodes.subList(pos, nodes.size()));1235 nodes.subList(pos+1, nodes.size()).clear();1236 return new RingSegment(newNodes);1237 }1238 1239 /**1240 * Split this segment as a way at two nodes. If one of them is null or at the end,1241 * split as an arc. Note: order of nodes is important.1242 * @return A new segment from n2 to n1.1243 */1244 public RingSegment split( Node n1, Node n2 ) {1245 if( nodes == null )1246 throw new IllegalArgumentException("Cannot split segment: it is a reference");1247 if( !isRing ) {1248 if( n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size()-1).equals(n1) )1249 return split(n2);1250 if( n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size()-1).equals(n2) )1251 return split(n1);1252 throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this);1253 }1254 int pos1 = nodes.indexOf(n1);1255 int pos2 = nodes.indexOf(n2);1256 if( pos1 == pos2 )1257 return null;1258 1259 List<Node> newNodes = new ArrayList<Node>();1260 if( pos2 > pos1 ) {1261 newNodes.addAll(nodes.subList(pos2, nodes.size()));1262 newNodes.addAll(nodes.subList(0, pos1 + 1));1263 if( pos2+1 < nodes.size() )1264 nodes.subList(pos2+1, nodes.size()).clear();1265 if( pos1 > 0 )1266 nodes.subList(0, pos1).clear();1267 } else {1268 newNodes.addAll(nodes.subList(pos2, pos1+1));1269 nodes.addAll(new ArrayList<Node>(nodes.subList(0, pos2+1)));1270 nodes.subList(0, pos1).clear();1271 }1272 isRing = false;1273 return new RingSegment(newNodes);1274 }1275 1276 public List<Node> getNodes() {1277 return nodes == null ? references.nodes : nodes;1278 }1279 1280 public boolean isReference() {1281 return nodes == null;1282 }1283 1284 public boolean isRing() {1285 return isRing;1286 }1287 1288 public void makeReference( RingSegment segment ) {1289 this.nodes = null;1290 this.references = segment;1291 }1292 1293 public void swapReference() {1294 this.nodes = references.nodes;1295 references.nodes = null;1296 references.references = this;1297 this.references = null;1298 }1299 1300 public boolean isWayConstructed() {1301 return isReference() ? references.isWayConstructed() : resultingWay != null;1302 }1303 1304 public Way constructWay( Way template ) {1305 if( isReference() )1306 return references.constructWay(template);1307 if( resultingWay == null ) {1308 resultingWay = new Way();1309 resultingWay.setNodes(nodes);1310 }1311 if( template != null && !wasTemplateApplied ) {1312 resultingWay.setKeys(template.getKeys());1313 wasTemplateApplied = true;1314 }1315 return resultingWay;1316 }1317 1318 public void overrideWay( Way source ) {1319 if( isReference() )1320 references.overrideWay(source);1321 else {1322 resultingWay = source;1323 wasTemplateApplied = true;1324 }1325 }1326 1327 /**1328 * Compares two segments with respect to referencing.1329 * @return true if ways are equals, or one references another.1330 */1331 public boolean isReferencingEqual( RingSegment other ) {1332 return this.equals(other) || (other.isReference() && other.references == this ) || (isReference() && references == other);1333 }1334 1335 @Override1336 public String toString() {1337 StringBuilder sb = new StringBuilder("RingSegment@");1338 sb.append(this.hashCode()).append('[');1339 if( isReference() )1340 sb.append("references ").append(references.hashCode());1341 else if( nodes.isEmpty() )1342 sb.append("empty");1343 else {1344 if( isRing )1345 sb.append("ring:");1346 sb.append(nodes.get(0).getUniqueId());1347 for( int i = 1; i < nodes.size(); i++ )1348 sb.append(',').append(nodes.get(i).getUniqueId());1349 }1350 return sb.append(']').toString();1351 }1352 }1353 663 }
Note:
See TracChangeset
for help on using the changeset viewer.