Changeset 30738 in osm for applications/editors/josm/plugins/reltoolbox
- Timestamp:
- 2014-10-19T01:27:04+02:00 (11 years ago)
- Location:
- applications/editors/josm/plugins/reltoolbox/src/relcontext
- Files:
-
- 15 edited
-
ChosenRelation.java (modified) (1 diff)
-
ChosenRelationListener.java (modified) (1 diff)
-
ExtraNameFormatHook.java (modified) (1 diff)
-
RelContextDialog.java (modified) (20 diffs)
-
RelContextPlugin.java (modified) (1 diff)
-
actions/CreateMultipolygonAction.java (modified) (5 diffs)
-
actions/ReconstructPolygonAction.java (modified) (2 diffs)
-
actions/SortAndFixAction.java (modified) (2 diffs)
-
actions/SplittingMultipolygons.java (modified) (7 diffs)
-
actions/TheRing.java (modified) (9 diffs)
-
relationfix/AssociatedStreetFixer.java (modified) (1 diff)
-
relationfix/BoundaryFixer.java (modified) (2 diffs)
-
relationfix/MultipolygonFixer.java (modified) (1 diff)
-
relationfix/NothingFixer.java (modified) (1 diff)
-
relationfix/RelationFixer.java (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelation.java
r30737 r30738 150 150 } 151 151 } else if( element.getType() == OsmPrimitiveType.RELATION ) { 152 Color oldColor = g.getColor();153 g.setColor(Color.magenta);152 Color oldColor = g.getColor(); 153 g.setColor(Color.magenta); 154 154 drawRelations(g, mv, bbox, (Relation)element); 155 155 g.setColor(oldColor); -
applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelationListener.java
r25649 r30738 9 9 */ 10 10 public interface ChosenRelationListener { 11 void chosenRelationChanged( Relation oldRelation, Relation newRelation );11 void chosenRelationChanged( Relation oldRelation, Relation newRelation ); 12 12 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/ExtraNameFormatHook.java
r26802 r30738 14 14 15 15 public String checkRelationTypeName( IRelation relation, String defaultName ) { 16 return null;16 return null; 17 17 } 18 18 19 19 public String checkFormat( INode node, String defaultName ) { 20 return null;20 return null; 21 21 } 22 22 23 23 public String checkFormat( IWay way, String defaultName ) { 24 if( way.get("place") != null && way.get("name") == null && way.get("place_name") != null )25 return way.get("place_name") + " " + defaultName;26 return null;24 if( way.get("place") != null && way.get("name") == null && way.get("place_name") != null ) 25 return way.get("place_name") + " " + defaultName; 26 return null; 27 27 } 28 28 29 29 public String checkFormat( IRelation relation, String defaultName ) { 30 String type = relation.get("type");31 if( type != null ) {32 String name = relation.get("destination");33 if( type.equals("destination_sign") && name != null ) {34 if( relation.get("distance") != null )35 name += " " + relation.get("distance");36 if( defaultName.indexOf('"') < 0 )37 return '"' + name + "\" " + defaultName;38 else39 return defaultName.replaceFirst("\".?+\"", '"'+name+'"');40 }41 }42 return null;30 String type = relation.get("type"); 31 if( type != null ) { 32 String name = relation.get("destination"); 33 if( type.equals("destination_sign") && name != null ) { 34 if( relation.get("distance") != null ) 35 name += " " + relation.get("distance"); 36 if( defaultName.indexOf('"') < 0 ) 37 return '"' + name + "\" " + defaultName; 38 else 39 return defaultName.replaceFirst("\".?+\"", '"'+name+'"'); 40 } 41 } 42 return null; 43 43 } 44 44 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java
r30737 r30738 97 97 /** 98 98 * The new, advanced relation editing panel. 99 * 99 * 100 100 * @author Zverik 101 101 */ … … 103 103 104 104 public final static String PREF_PREFIX = "reltoolbox"; 105 105 106 106 private final DefaultTableModel relationsData; 107 107 private ChosenRelation chosenRelation; … … 142 142 roleBox.addMouseListener(relationMouseAdapter); 143 143 roleBox.addItemListener(new ItemListener() { 144 @Override 144 145 public void itemStateChanged( ItemEvent e ) { 145 146 if( e.getStateChange() == ItemEvent.DESELECTED ) return; … … 174 175 175 176 roleBox.addPropertyChangeListener("enabled", new PropertyChangeListener() { 177 @Override 176 178 public void propertyChange( PropertyChangeEvent evt ) { 177 179 boolean showRoleBox = roleBox.isEnabled(); … … 182 184 183 185 sortAndFixAction.addPropertyChangeListener(new PropertyChangeListener() { 186 @Override 184 187 public void propertyChange( PropertyChangeEvent evt ) { 185 188 sortAndFixButton.setVisible(sortAndFixAction.isEnabled()); … … 189 192 190 193 downloadChosenRelationAction.addPropertyChangeListener(new PropertyChangeListener() { 194 @Override 191 195 public void propertyChange( PropertyChangeEvent evt ) { 192 196 downloadButton.setVisible(downloadChosenRelationAction.isEnabled()); … … 304 308 columns.getColumn(0).setPreferredWidth(220); 305 309 relationsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 310 @Override 306 311 public void valueChanged( ListSelectionEvent e ) { 307 312 int selectedRow = relationsTable.getSelectedRow(); … … 339 344 } 340 345 346 @Override 341 347 public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) { 342 348 if( chosenRelationPanel != null && Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false) ) … … 348 354 } 349 355 356 @Override 350 357 public void selectionChanged( Collection<? extends OsmPrimitive> newSelection ) { 351 358 if( !isVisible() || relationsData == null ) … … 397 404 } 398 405 406 @Override 399 407 public void editLayerChanged( OsmDataLayer oldLayer, OsmDataLayer newLayer ) { 400 408 updateSelection(); … … 410 418 super.destroy(); 411 419 } 412 420 413 421 private static final String POSSIBLE_ROLES_FILE = "relcontext/possible_roles.txt"; 414 422 private static final Map<String, List<String>> possibleRoles = loadRoles(); … … 416 424 private static Map<String, List<String>> loadRoles() { 417 425 Map<String, List<String>> result = new HashMap<>(); 418 try {419 ClassLoader classLoader = RelContextDialog.class.getClassLoader();420 finalInputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE);426 ClassLoader classLoader = RelContextDialog.class.getClassLoader(); 427 try ( 428 InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE); 421 429 BufferedReader r = new BufferedReader(new InputStreamReader(possibleRolesStream)); 430 ) { 422 431 while( r.ready() ) { 423 432 String line = r.readLine(); … … 431 440 } 432 441 } 433 r.close();434 442 } catch( Exception e ) { 435 System.err.println("[RelToolbox] Error reading possible roles file.");436 e.printStackTrace();443 Main.error("[RelToolbox] Error reading possible roles file."); 444 Main.error(e); 437 445 } 438 446 return result; … … 466 474 467 475 role.getEditor().addActionListener(new ActionListener() { 476 @Override 468 477 public void actionPerformed( ActionEvent e ) { 469 478 dlg.setVisible(false); … … 589 598 } 590 599 600 @Override 591 601 public void actionPerformed( ActionEvent e ) { 592 602 String property = e.getActionCommand(); … … 609 619 } 610 620 621 @Override 611 622 public void actionPerformed( ActionEvent e ) { 612 623 if( roleBoxModel.membersRole != null ) { … … 617 628 } 618 629 630 @Override 619 631 public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) { 620 632 setEnabled(newRelation != null); 621 633 } 622 634 } 623 635 624 636 private class RoleComboBoxModel extends AbstractListModel<String> implements ComboBoxModel<String> { 625 637 private List<String> roles = new ArrayList<>(); … … 704 716 } 705 717 718 @Override 706 719 public int getSize() { 707 720 return roles.size(); 708 721 } 709 722 723 @Override 710 724 public String getElementAt( int index ) { 711 725 return getRole(index); … … 716 730 } 717 731 732 @Override 718 733 public void setSelectedItem( Object anItem ) { 719 734 int newIndex = anItem == null ? -1 : roles.indexOf(anItem); … … 724 739 } 725 740 741 @Override 726 742 public Object getSelectedItem() { 727 743 return selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex); -
applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextPlugin.java
r29535 r30738 11 11 public RelContextPlugin( PluginInformation info ) { 12 12 super(info); 13 DefaultNameFormatter.registerFormatHook(new ExtraNameFormatHook());13 DefaultNameFormatter.registerFormatHook(new ExtraNameFormatHook()); 14 14 } 15 15 -
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java
r30737 r30738 28 28 29 29 public CreateMultipolygonAction( ChosenRelation chRel ) { 30 super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"),31 Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")),32 KeyEvent.VK_A, Shortcut.ALT_CTRL), false);33 this.chRel = chRel;34 updateEnabledState();30 super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"), 31 Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")), 32 KeyEvent.VK_A, Shortcut.ALT_CTRL), false); 33 this.chRel = chRel; 34 updateEnabledState(); 35 35 } 36 36 37 37 public CreateMultipolygonAction() { 38 this(null);38 this(null); 39 39 } 40 40 41 41 public static boolean getDefaultPropertyValue( String property ) { 42 if( property.equals("boundary") )43 return false;44 else if( property.equals("boundaryways") )45 return true;46 else if( property.equals("tags") )47 return true;48 else if( property.equals("alltags") )49 return false;50 else if( property.equals("single") )51 return true;52 else if( property.equals("allowsplit") )53 return false;54 throw new IllegalArgumentException(property);42 if( property.equals("boundary") ) 43 return false; 44 else if( property.equals("boundaryways") ) 45 return true; 46 else if( property.equals("tags") ) 47 return true; 48 else if( property.equals("alltags") ) 49 return false; 50 else if( property.equals("single") ) 51 return true; 52 else if( property.equals("allowsplit") ) 53 return false; 54 throw new IllegalArgumentException(property); 55 55 } 56 56 57 57 private boolean getPref( String property ) { 58 return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));58 return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property)); 59 59 } 60 60 61 61 public void actionPerformed( ActionEvent e ) { 62 boolean isBoundary = getPref("boundary");63 Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();64 if( !isBoundary && getPref("tags") ) {65 List<Relation> rels = null;66 if( getPref("allowsplit") || selectedWays.size() == 1 ) {67 if( SplittingMultipolygons.canProcess(selectedWays) )68 rels = SplittingMultipolygons.process(getCurrentDataSet().getSelectedWays());69 } else {70 if( TheRing.areAllOfThoseRings(selectedWays) ) {71 List<Command> commands = new ArrayList<>();72 rels = TheRing.makeManySimpleMultipolygons(getCurrentDataSet().getSelectedWays(), commands);73 if( !commands.isEmpty() )74 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands));75 }76 }77 if( rels != null && !rels.isEmpty() ) {78 if( chRel != null )79 chRel.set(rels.size() == 1 ? rels.get(0) : null);80 if( rels.size() == 1 )81 getCurrentDataSet().setSelected(rels);82 else83 getCurrentDataSet().clearSelection();84 return;85 }86 }87 88 // for now, just copying standard action89 MultipolygonBuilder mpc = new MultipolygonBuilder();90 String error = mpc.makeFromWays(getCurrentDataSet().getSelectedWays());91 if( error != null ) {92 JOptionPane.showMessageDialog(Main.parent, error);93 return;94 }95 Relation rel = new Relation();96 if( isBoundary ) {97 rel.put("type", "boundary");98 rel.put("boundary", "administrative");99 } else100 rel.put("type", "multipolygon");101 for( MultipolygonBuilder.JoinedPolygon poly : mpc.outerWays )102 for( Way w : poly.ways )103 rel.addMember(new RelationMember("outer", w));104 for( MultipolygonBuilder.JoinedPolygon poly : mpc.innerWays )105 for( Way w : poly.ways )106 rel.addMember(new RelationMember("inner", w));107 List<Command> list = removeTagsFromInnerWays(rel);108 if( !list.isEmpty() && isBoundary ) {109 Main.main.undoRedo.add(new SequenceCommand(tr("Move tags from ways to relation"), list));110 list = new ArrayList<>();111 }112 if( isBoundary ) {113 if( !askForAdminLevelAndName(rel) )114 return;115 addBoundaryMembers(rel);116 if( getPref("boundaryways") )117 list.addAll(fixWayTagsForBoundary(rel));118 }119 list.add(new AddCommand(rel));120 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));121 122 if( chRel != null )123 chRel.set(rel);124 125 getCurrentDataSet().setSelected(rel);62 boolean isBoundary = getPref("boundary"); 63 Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays(); 64 if( !isBoundary && getPref("tags") ) { 65 List<Relation> rels = null; 66 if( getPref("allowsplit") || selectedWays.size() == 1 ) { 67 if( SplittingMultipolygons.canProcess(selectedWays) ) 68 rels = SplittingMultipolygons.process(getCurrentDataSet().getSelectedWays()); 69 } else { 70 if( TheRing.areAllOfThoseRings(selectedWays) ) { 71 List<Command> commands = new ArrayList<>(); 72 rels = TheRing.makeManySimpleMultipolygons(getCurrentDataSet().getSelectedWays(), commands); 73 if( !commands.isEmpty() ) 74 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands)); 75 } 76 } 77 if( rels != null && !rels.isEmpty() ) { 78 if( chRel != null ) 79 chRel.set(rels.size() == 1 ? rels.get(0) : null); 80 if( rels.size() == 1 ) 81 getCurrentDataSet().setSelected(rels); 82 else 83 getCurrentDataSet().clearSelection(); 84 return; 85 } 86 } 87 88 // for now, just copying standard action 89 MultipolygonBuilder mpc = new MultipolygonBuilder(); 90 String error = mpc.makeFromWays(getCurrentDataSet().getSelectedWays()); 91 if( error != null ) { 92 JOptionPane.showMessageDialog(Main.parent, error); 93 return; 94 } 95 Relation rel = new Relation(); 96 if( isBoundary ) { 97 rel.put("type", "boundary"); 98 rel.put("boundary", "administrative"); 99 } else 100 rel.put("type", "multipolygon"); 101 for( MultipolygonBuilder.JoinedPolygon poly : mpc.outerWays ) 102 for( Way w : poly.ways ) 103 rel.addMember(new RelationMember("outer", w)); 104 for( MultipolygonBuilder.JoinedPolygon poly : mpc.innerWays ) 105 for( Way w : poly.ways ) 106 rel.addMember(new RelationMember("inner", w)); 107 List<Command> list = removeTagsFromInnerWays(rel); 108 if( !list.isEmpty() && isBoundary ) { 109 Main.main.undoRedo.add(new SequenceCommand(tr("Move tags from ways to relation"), list)); 110 list = new ArrayList<>(); 111 } 112 if( isBoundary ) { 113 if( !askForAdminLevelAndName(rel) ) 114 return; 115 addBoundaryMembers(rel); 116 if( getPref("boundaryways") ) 117 list.addAll(fixWayTagsForBoundary(rel)); 118 } 119 list.add(new AddCommand(rel)); 120 Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list)); 121 122 if( chRel != null ) 123 chRel.set(rel); 124 125 getCurrentDataSet().setSelected(rel); 126 126 } 127 127 128 128 @Override 129 129 protected void updateEnabledState() { 130 if( getCurrentDataSet() == null ) {131 setEnabled(false);132 } else {133 updateEnabledState(getCurrentDataSet().getSelected());134 }130 if( getCurrentDataSet() == null ) { 131 setEnabled(false); 132 } else { 133 updateEnabledState(getCurrentDataSet().getSelected()); 134 } 135 135 } 136 136 137 137 @Override 138 138 protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) { 139 boolean isEnabled = true;140 if( selection == null || selection.isEmpty() )141 isEnabled = false;142 else {143 if( !getPref("boundary") ) {144 for( OsmPrimitive p : selection ) {145 if( !(p instanceof Way) ) {146 isEnabled = false;147 break;148 }149 }150 }151 }152 setEnabled(isEnabled);139 boolean isEnabled = true; 140 if( selection == null || selection.isEmpty() ) 141 isEnabled = false; 142 else { 143 if( !getPref("boundary") ) { 144 for( OsmPrimitive p : selection ) { 145 if( !(p instanceof Way) ) { 146 isEnabled = false; 147 break; 148 } 149 } 150 } 151 } 152 setEnabled(isEnabled); 153 153 } 154 154 … … 157 157 */ 158 158 private void addBoundaryMembers( Relation rel ) { 159 for( OsmPrimitive p : getCurrentDataSet().getSelected() ) {160 String role = null;161 if( p.getType().equals(OsmPrimitiveType.RELATION) ) {162 role = "subarea";163 } else if( p.getType().equals(OsmPrimitiveType.NODE) ) {164 Node n = (Node)p;165 if( !n.isIncomplete() ) {166 if( n.hasKey("place") )167 role = "admin_centre";168 else169 role = "label";170 }171 }172 if( role != null )173 rel.addMember(new RelationMember(role, p));174 }159 for( OsmPrimitive p : getCurrentDataSet().getSelected() ) { 160 String role = null; 161 if( p.getType().equals(OsmPrimitiveType.RELATION) ) { 162 role = "subarea"; 163 } else if( p.getType().equals(OsmPrimitiveType.NODE) ) { 164 Node n = (Node)p; 165 if( !n.isIncomplete() ) { 166 if( n.hasKey("place") ) 167 role = "admin_centre"; 168 else 169 role = "label"; 170 } 171 } 172 if( role != null ) 173 rel.addMember(new RelationMember(role, p)); 174 } 175 175 } 176 176 … … 179 179 */ 180 180 private List<Command> fixWayTagsForBoundary( Relation rel ) { 181 List<Command> commands = new ArrayList<>();182 if( !rel.hasKey("boundary") || !rel.hasKey("admin_level") )183 return commands;184 String adminLevelStr = rel.get("admin_level");185 int adminLevel = 0;186 try {187 adminLevel = Integer.parseInt(adminLevelStr);188 } catch( NumberFormatException e ) {189 return commands;190 }191 Set<OsmPrimitive> waysBoundary = new HashSet<>();192 Set<OsmPrimitive> waysAdminLevel = new HashSet<>();193 for( OsmPrimitive p : rel.getMemberPrimitives() ) {194 if( p instanceof Way ) {195 int count = 0;196 if( p.hasKey("boundary") && p.get("boundary").equals("administrative") )197 count++;198 if( p.hasKey("admin_level") )199 count++;200 if( p.keySet().size() - count == 0 ) {201 if( !p.hasKey("boundary") )202 waysBoundary.add(p);203 if( !p.hasKey("admin_level") ) {204 waysAdminLevel.add(p);205 } else {206 try {207 int oldAdminLevel = Integer.parseInt(p.get("admin_level"));208 if( oldAdminLevel > adminLevel )209 waysAdminLevel.add(p);210 } catch( NumberFormatException e ) {211 waysAdminLevel.add(p); // some garbage, replace it212 }213 }214 }215 }216 }217 if( !waysBoundary.isEmpty() )218 commands.add(new ChangePropertyCommand(waysBoundary, "boundary", "administrative"));219 if( !waysAdminLevel.isEmpty() )220 commands.add(new ChangePropertyCommand(waysAdminLevel, "admin_level", adminLevelStr));221 return commands;181 List<Command> commands = new ArrayList<>(); 182 if( !rel.hasKey("boundary") || !rel.hasKey("admin_level") ) 183 return commands; 184 String adminLevelStr = rel.get("admin_level"); 185 int adminLevel = 0; 186 try { 187 adminLevel = Integer.parseInt(adminLevelStr); 188 } catch( NumberFormatException e ) { 189 return commands; 190 } 191 Set<OsmPrimitive> waysBoundary = new HashSet<>(); 192 Set<OsmPrimitive> waysAdminLevel = new HashSet<>(); 193 for( OsmPrimitive p : rel.getMemberPrimitives() ) { 194 if( p instanceof Way ) { 195 int count = 0; 196 if( p.hasKey("boundary") && p.get("boundary").equals("administrative") ) 197 count++; 198 if( p.hasKey("admin_level") ) 199 count++; 200 if( p.keySet().size() - count == 0 ) { 201 if( !p.hasKey("boundary") ) 202 waysBoundary.add(p); 203 if( !p.hasKey("admin_level") ) { 204 waysAdminLevel.add(p); 205 } else { 206 try { 207 int oldAdminLevel = Integer.parseInt(p.get("admin_level")); 208 if( oldAdminLevel > adminLevel ) 209 waysAdminLevel.add(p); 210 } catch( NumberFormatException e ) { 211 waysAdminLevel.add(p); // some garbage, replace it 212 } 213 } 214 } 215 } 216 } 217 if( !waysBoundary.isEmpty() ) 218 commands.add(new ChangePropertyCommand(waysBoundary, "boundary", "administrative")); 219 if( !waysAdminLevel.isEmpty() ) 220 commands.add(new ChangePropertyCommand(waysAdminLevel, "admin_level", adminLevelStr)); 221 return commands; 222 222 } 223 223 static public final List<String> DEFAULT_LINEAR_TAGS = Arrays.asList(new String[] {"barrier", "source"}); 224 224 private static final Set<String> REMOVE_FROM_BOUNDARY_TAGS = new TreeSet<>(Arrays.asList(new String[] { 225 "boundary", "boundary_type", "type", "admin_level"226 }));225 "boundary", "boundary_type", "type", "admin_level" 226 })); 227 227 228 228 /** … … 232 232 */ 233 233 private List<Command> removeTagsFromInnerWays( Relation relation ) { 234 Map<String, String> values = new HashMap<>();235 236 if( relation.hasKeys() ) {237 for( String key : relation.keySet() ) {238 values.put(key, relation.get(key));239 }240 }241 242 List<Way> innerWays = new ArrayList<>();243 List<Way> outerWays = new ArrayList<>();244 245 Set<String> conflictingKeys = new TreeSet<>();246 247 for( RelationMember m : relation.getMembers() ) {248 249 if( m.hasRole() && "inner".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {250 innerWays.add(m.getWay());251 }252 253 if( m.hasRole() && "outer".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {254 Way way = m.getWay();255 outerWays.add(way);256 for( String key : way.keySet() ) {257 if( !values.containsKey(key) ) { //relation values take precedence258 values.put(key, way.get(key));259 } else if( !relation.hasKey(key) && !values.get(key).equals(way.get(key)) ) {260 conflictingKeys.add(key);261 }262 }263 }264 }265 266 // filter out empty key conflicts - we need second iteration267 boolean isBoundary = getPref("boundary");268 if( isBoundary || !getPref("alltags") )269 for( RelationMember m : relation.getMembers() )270 if( m.hasRole() && m.getRole().equals("outer") && m.isWay() )271 for( String key : values.keySet() )272 if( !m.getWay().hasKey(key) && !relation.hasKey(key) )273 conflictingKeys.add(key);274 275 for( String key : conflictingKeys )276 values.remove(key);277 278 for( String linearTag : Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS) )279 values.remove(linearTag);280 281 if( values.containsKey("natural") && values.get("natural").equals("coastline") )282 values.remove("natural");283 284 String name = values.get("name");285 if( isBoundary ) {286 Set<String> keySet = new TreeSet<>(values.keySet());287 for( String key : keySet )288 if( !REMOVE_FROM_BOUNDARY_TAGS.contains(key) )289 values.remove(key);290 }291 292 values.put("area", "yes");293 294 List<Command> commands = new ArrayList<>();295 boolean moveTags = getPref("tags");296 297 for( String key : values.keySet() ) {298 List<OsmPrimitive> affectedWays = new ArrayList<>();299 String value = values.get(key);300 301 for( Way way : innerWays ) {302 if( way.hasKey(key) && (isBoundary || value.equals(way.get(key))) ) {303 affectedWays.add(way);304 }305 }306 307 if( moveTags ) {308 // remove duplicated tags from outer ways309 for( Way way : outerWays ) {310 if( way.hasKey(key) ) {311 affectedWays.add(way);312 }313 }314 }315 316 if( affectedWays.size() > 0 ) {317 commands.add(new ChangePropertyCommand(affectedWays, key, null));318 }319 }320 321 if( moveTags ) {322 // add those tag values to the relation323 if( isBoundary )324 values.put("name", name);325 boolean fixed = false;326 Relation r2 = new Relation(relation);327 for( String key : values.keySet() ) {328 if( !r2.hasKey(key) && !key.equals("area")329 && (!isBoundary || key.equals("admin_level") || key.equals("name")) ) {330 if( relation.isNew() )331 relation.put(key, values.get(key));332 else333 r2.put(key, values.get(key));334 fixed = true;335 }336 }337 if( fixed && !relation.isNew() )338 commands.add(new ChangeCommand(relation, r2));339 }340 341 return commands;234 Map<String, String> values = new HashMap<>(); 235 236 if( relation.hasKeys() ) { 237 for( String key : relation.keySet() ) { 238 values.put(key, relation.get(key)); 239 } 240 } 241 242 List<Way> innerWays = new ArrayList<>(); 243 List<Way> outerWays = new ArrayList<>(); 244 245 Set<String> conflictingKeys = new TreeSet<>(); 246 247 for( RelationMember m : relation.getMembers() ) { 248 249 if( m.hasRole() && "inner".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) { 250 innerWays.add(m.getWay()); 251 } 252 253 if( m.hasRole() && "outer".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) { 254 Way way = m.getWay(); 255 outerWays.add(way); 256 for( String key : way.keySet() ) { 257 if( !values.containsKey(key) ) { //relation values take precedence 258 values.put(key, way.get(key)); 259 } else if( !relation.hasKey(key) && !values.get(key).equals(way.get(key)) ) { 260 conflictingKeys.add(key); 261 } 262 } 263 } 264 } 265 266 // filter out empty key conflicts - we need second iteration 267 boolean isBoundary = getPref("boundary"); 268 if( isBoundary || !getPref("alltags") ) 269 for( RelationMember m : relation.getMembers() ) 270 if( m.hasRole() && m.getRole().equals("outer") && m.isWay() ) 271 for( String key : values.keySet() ) 272 if( !m.getWay().hasKey(key) && !relation.hasKey(key) ) 273 conflictingKeys.add(key); 274 275 for( String key : conflictingKeys ) 276 values.remove(key); 277 278 for( String linearTag : Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS) ) 279 values.remove(linearTag); 280 281 if( values.containsKey("natural") && values.get("natural").equals("coastline") ) 282 values.remove("natural"); 283 284 String name = values.get("name"); 285 if( isBoundary ) { 286 Set<String> keySet = new TreeSet<>(values.keySet()); 287 for( String key : keySet ) 288 if( !REMOVE_FROM_BOUNDARY_TAGS.contains(key) ) 289 values.remove(key); 290 } 291 292 values.put("area", "yes"); 293 294 List<Command> commands = new ArrayList<>(); 295 boolean moveTags = getPref("tags"); 296 297 for( String key : values.keySet() ) { 298 List<OsmPrimitive> affectedWays = new ArrayList<>(); 299 String value = values.get(key); 300 301 for( Way way : innerWays ) { 302 if( way.hasKey(key) && (isBoundary || value.equals(way.get(key))) ) { 303 affectedWays.add(way); 304 } 305 } 306 307 if( moveTags ) { 308 // remove duplicated tags from outer ways 309 for( Way way : outerWays ) { 310 if( way.hasKey(key) ) { 311 affectedWays.add(way); 312 } 313 } 314 } 315 316 if( affectedWays.size() > 0 ) { 317 commands.add(new ChangePropertyCommand(affectedWays, key, null)); 318 } 319 } 320 321 if( moveTags ) { 322 // add those tag values to the relation 323 if( isBoundary ) 324 values.put("name", name); 325 boolean fixed = false; 326 Relation r2 = new Relation(relation); 327 for( String key : values.keySet() ) { 328 if( !r2.hasKey(key) && !key.equals("area") 329 && (!isBoundary || key.equals("admin_level") || key.equals("name")) ) { 330 if( relation.isNew() ) 331 relation.put(key, values.get(key)); 332 else 333 r2.put(key, values.get(key)); 334 fixed = true; 335 } 336 } 337 if( fixed && !relation.isNew() ) 338 commands.add(new ChangeCommand(relation, r2)); 339 } 340 341 return commands; 342 342 } 343 343 … … 348 348 */ 349 349 private boolean askForAdminLevelAndName( Relation rel ) { 350 String relAL = rel.get("admin_level");351 String relName = rel.get("name");352 if( relAL != null && relName != null )353 return true;354 355 JPanel panel = new JPanel(new GridBagLayout());356 panel.add(new JLabel(tr("Enter admin level and name for the border relation:")), GBC.eol().insets(0, 0, 0, 5));357 358 final JTextField admin = new JTextField();359 admin.setText(relAL != null ? relAL : Main.pref.get(PREF_MULTIPOLY + "lastadmin", ""));360 panel.add(new JLabel(tr("Admin level")), GBC.std());361 panel.add(Box.createHorizontalStrut(10), GBC.std());362 panel.add(admin, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5));363 364 final JTextField name = new JTextField();365 if( relName != null )366 name.setText(relName);367 panel.add(new JLabel(tr("Name")), GBC.std());368 panel.add(Box.createHorizontalStrut(10), GBC.std());369 panel.add(name, GBC.eol().fill(GBC.HORIZONTAL));370 371 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {372 @Override373 public void selectInitialValue() {374 admin.requestFocusInWindow();375 admin.selectAll();376 }377 };378 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Create a new relation"));379 dlg.setModalityType(ModalityType.DOCUMENT_MODAL);380 381 name.addActionListener(new ActionListener() {382 public void actionPerformed( ActionEvent e ) {383 dlg.setVisible(false);384 optionPane.setValue(JOptionPane.OK_OPTION);385 }386 });387 388 dlg.setVisible(true);389 390 Object answer = optionPane.getValue();391 if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE392 || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) {393 return false;394 }395 396 String admin_level = admin.getText().trim();397 String new_name = name.getText().trim();398 if( admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0))) ) {399 rel.put("admin_level", admin_level);400 Main.pref.put(PREF_MULTIPOLY + "lastadmin", admin_level);401 }402 if( new_name.length() > 0 )403 rel.put("name", new_name);404 return true;350 String relAL = rel.get("admin_level"); 351 String relName = rel.get("name"); 352 if( relAL != null && relName != null ) 353 return true; 354 355 JPanel panel = new JPanel(new GridBagLayout()); 356 panel.add(new JLabel(tr("Enter admin level and name for the border relation:")), GBC.eol().insets(0, 0, 0, 5)); 357 358 final JTextField admin = new JTextField(); 359 admin.setText(relAL != null ? relAL : Main.pref.get(PREF_MULTIPOLY + "lastadmin", "")); 360 panel.add(new JLabel(tr("Admin level")), GBC.std()); 361 panel.add(Box.createHorizontalStrut(10), GBC.std()); 362 panel.add(admin, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5)); 363 364 final JTextField name = new JTextField(); 365 if( relName != null ) 366 name.setText(relName); 367 panel.add(new JLabel(tr("Name")), GBC.std()); 368 panel.add(Box.createHorizontalStrut(10), GBC.std()); 369 panel.add(name, GBC.eol().fill(GBC.HORIZONTAL)); 370 371 final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) { 372 @Override 373 public void selectInitialValue() { 374 admin.requestFocusInWindow(); 375 admin.selectAll(); 376 } 377 }; 378 final JDialog dlg = optionPane.createDialog(Main.parent, tr("Create a new relation")); 379 dlg.setModalityType(ModalityType.DOCUMENT_MODAL); 380 381 name.addActionListener(new ActionListener() { 382 public void actionPerformed( ActionEvent e ) { 383 dlg.setVisible(false); 384 optionPane.setValue(JOptionPane.OK_OPTION); 385 } 386 }); 387 388 dlg.setVisible(true); 389 390 Object answer = optionPane.getValue(); 391 if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE 392 || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) { 393 return false; 394 } 395 396 String admin_level = admin.getText().trim(); 397 String new_name = name.getText().trim(); 398 if( admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0))) ) { 399 rel.put("admin_level", admin_level); 400 Main.pref.put(PREF_MULTIPOLY + "lastadmin", admin_level); 401 } 402 if( new_name.length() > 0 ) 403 rel.put("name", new_name); 404 return true; 405 405 } 406 406 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructPolygonAction.java
r30737 r30738 42 42 43 43 private static final List<String> IRRELEVANT_KEYS = Arrays.asList(new String[] { 44 "source", "created_by", "note"});44 "source", "created_by", "note"}); 45 45 46 46 public ReconstructPolygonAction( ChosenRelation rel ) { 47 47 super(tr("Reconstruct polygon")); 48 48 putValue(SMALL_ICON, ImageProvider.get("dialogs", "filter")); 49 putValue(LONG_DESCRIPTION, "Reconstruct polygon from multipolygon relation");49 putValue(LONG_DESCRIPTION, "Reconstruct polygon from multipolygon relation"); 50 50 this.rel = rel; 51 51 rel.addChosenRelationListener(this); … … 55 55 public void actionPerformed( ActionEvent e ) { 56 56 Relation r = rel.get(); 57 List<Way> ways = new ArrayList<>();58 boolean wont = false;59 for( RelationMember m : r.getMembers() ) {60 if( m.isWay() )61 ways.add(m.getWay());62 else63 wont = true;64 }65 if( wont ) {66 JOptionPane.showMessageDialog(Main.parent, tr("Multipolygon must consist only of ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE);67 return;68 }69 70 MultipolygonBuilder mpc = new MultipolygonBuilder();71 String error = mpc.makeFromWays(ways);72 if( error != null ) {73 JOptionPane.showMessageDialog(Main.parent, error);74 return;75 }76 77 if( !mpc.innerWays.isEmpty() ) {78 JOptionPane.showMessageDialog(Main.parent, tr("Reconstruction of polygons can be done only from outer ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE);79 return;80 }81 82 rel.clear();83 List<Way> newSelection = new ArrayList<>();84 List<Command> commands = new ArrayList<>();57 List<Way> ways = new ArrayList<>(); 58 boolean wont = false; 59 for( RelationMember m : r.getMembers() ) { 60 if( m.isWay() ) 61 ways.add(m.getWay()); 62 else 63 wont = true; 64 } 65 if( wont ) { 66 JOptionPane.showMessageDialog(Main.parent, tr("Multipolygon must consist only of ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE); 67 return; 68 } 69 70 MultipolygonBuilder mpc = new MultipolygonBuilder(); 71 String error = mpc.makeFromWays(ways); 72 if( error != null ) { 73 JOptionPane.showMessageDialog(Main.parent, error); 74 return; 75 } 76 77 if( !mpc.innerWays.isEmpty() ) { 78 JOptionPane.showMessageDialog(Main.parent, tr("Reconstruction of polygons can be done only from outer ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE); 79 return; 80 } 81 82 rel.clear(); 83 List<Way> newSelection = new ArrayList<>(); 84 List<Command> commands = new ArrayList<>(); 85 85 Command c = DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(r), true, true); 86 86 if( c == null ) 87 87 return; 88 commands.add(c);89 90 for( JoinedPolygon p : mpc.outerWays ) {91 // move all tags from relation and common tags from ways92 Map<String, String> tags = p.ways.get(0).getKeys();93 List<OsmPrimitive> relations = p.ways.get(0).getReferrers();94 Set<String> noTags = new HashSet<>(r.keySet());95 for( int i = 1; i < p.ways.size(); i++ ) {96 Way w = p.ways.get(i);97 for( String key : w.keySet() ) {98 String value = w.get(key);99 if( !noTags.contains(key) && tags.containsKey(key) && !tags.get(key).equals(value) ) {100 tags.remove(key);101 noTags.add(key);102 }103 }104 List<OsmPrimitive> referrers = w.getReferrers();105 for( Iterator<OsmPrimitive> ref1 = relations.iterator(); ref1.hasNext(); )106 if( !referrers.contains(ref1.next()) )107 ref1.remove();108 }109 tags.putAll(r.getKeys());110 tags.remove("type");111 112 // then delete ways that are not relevant (do not take part in other relations of have strange tags)113 Way candidateWay = null;114 for( Way w : p.ways ) {115 if( w.getReferrers().equals(relations) ) {116 // check tags that remain117 Set<String> keys = new HashSet<>(w.keySet());118 keys.removeAll(tags.keySet());119 keys.removeAll(IRRELEVANT_KEYS);120 if( keys.isEmpty() ) {121 if( candidateWay == null )122 candidateWay = w;123 else {124 if( candidateWay.isNew() && !w.isNew() ) {125 // prefer ways that are already in the database126 Way tmp = w;127 w = candidateWay;128 candidateWay = tmp;129 }130 commands.add(new DeleteCommand(w));131 }132 }133 }134 }135 136 // take the first way, put all nodes into it, making it a closed polygon137 Way result = candidateWay == null ? new Way() : new Way(candidateWay);138 result.setNodes(p.nodes);139 result.addNode(result.firstNode());140 result.setKeys(tags);141 newSelection.add(candidateWay == null ? result : candidateWay);142 commands.add(candidateWay == null ? new AddCommand(result) : new ChangeCommand(candidateWay, result));143 }144 88 commands.add(c); 89 90 for( JoinedPolygon p : mpc.outerWays ) { 91 // move all tags from relation and common tags from ways 92 Map<String, String> tags = p.ways.get(0).getKeys(); 93 List<OsmPrimitive> relations = p.ways.get(0).getReferrers(); 94 Set<String> noTags = new HashSet<>(r.keySet()); 95 for( int i = 1; i < p.ways.size(); i++ ) { 96 Way w = p.ways.get(i); 97 for( String key : w.keySet() ) { 98 String value = w.get(key); 99 if( !noTags.contains(key) && tags.containsKey(key) && !tags.get(key).equals(value) ) { 100 tags.remove(key); 101 noTags.add(key); 102 } 103 } 104 List<OsmPrimitive> referrers = w.getReferrers(); 105 for( Iterator<OsmPrimitive> ref1 = relations.iterator(); ref1.hasNext(); ) 106 if( !referrers.contains(ref1.next()) ) 107 ref1.remove(); 108 } 109 tags.putAll(r.getKeys()); 110 tags.remove("type"); 111 112 // then delete ways that are not relevant (do not take part in other relations of have strange tags) 113 Way candidateWay = null; 114 for( Way w : p.ways ) { 115 if( w.getReferrers().equals(relations) ) { 116 // check tags that remain 117 Set<String> keys = new HashSet<>(w.keySet()); 118 keys.removeAll(tags.keySet()); 119 keys.removeAll(IRRELEVANT_KEYS); 120 if( keys.isEmpty() ) { 121 if( candidateWay == null ) 122 candidateWay = w; 123 else { 124 if( candidateWay.isNew() && !w.isNew() ) { 125 // prefer ways that are already in the database 126 Way tmp = w; 127 w = candidateWay; 128 candidateWay = tmp; 129 } 130 commands.add(new DeleteCommand(w)); 131 } 132 } 133 } 134 } 135 136 // take the first way, put all nodes into it, making it a closed polygon 137 Way result = candidateWay == null ? new Way() : new Way(candidateWay); 138 result.setNodes(p.nodes); 139 result.addNode(result.firstNode()); 140 result.setKeys(tags); 141 newSelection.add(candidateWay == null ? result : candidateWay); 142 commands.add(candidateWay == null ? new AddCommand(result) : new ChangeCommand(candidateWay, result)); 143 } 144 145 145 Main.main.undoRedo.add(new SequenceCommand(tr("Reconstruct polygons from relation {0}", 146 r.getDisplayName(DefaultNameFormatter.getInstance())), commands));147 Main.main.getCurrentDataSet().setSelected(newSelection);146 r.getDisplayName(DefaultNameFormatter.getInstance())), commands)); 147 Main.main.getCurrentDataSet().setSelected(newSelection); 148 148 } 149 149 150 150 public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) { 151 setEnabled(isSuitableRelation(newRelation));151 setEnabled(isSuitableRelation(newRelation)); 152 152 } 153 153 154 154 private boolean isSuitableRelation( Relation newRelation ) { 155 if( newRelation == null || !"multipolygon".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0 )156 return false;157 else {158 for( RelationMember m : newRelation.getMembers() )159 if( "inner".equals(m.getRole()) )160 return false;161 return true;162 }155 if( newRelation == null || !"multipolygon".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0 ) 156 return false; 157 else { 158 for( RelationMember m : newRelation.getMembers() ) 159 if( "inner".equals(m.getRole()) ) 160 return false; 161 return true; 162 } 163 163 } 164 164 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java
r30737 r30738 25 25 26 26 public class SortAndFixAction extends AbstractAction implements ChosenRelationListener { 27 private static final long serialVersionUID = 1L;28 private ChosenRelation rel;27 private static final long serialVersionUID = 1L; 28 private ChosenRelation rel; 29 29 private List<RelationFixer> fixers; 30 30 … … 67 67 68 68 private RelationFixer getFixer( Relation rel ) { 69 for(RelationFixer fixer : fixers)70 if (fixer.isFixerApplicable(rel))71 return fixer;72 return new NothingFixer();69 for(RelationFixer fixer : fixers) 70 if (fixer.isFixerApplicable(rel)) 71 return fixer; 72 return new NothingFixer(); 73 73 } 74 74 -
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SplittingMultipolygons.java
r30737 r30738 24 24 25 25 public static boolean canProcess( Collection<Way> ways ) { 26 List<Way> rings = new ArrayList<>();27 List<Way> arcs = new ArrayList<>();28 Area a = Main.main.getCurrentDataSet().getDataSourceArea();29 for( Way way : ways ) {30 if( way.isDeleted() )31 return false;32 for( Node n : way.getNodes() ) {33 LatLon ll = n.getCoor();34 if( n.isIncomplete() || (a != null && !a.contains(ll.getX(), ll.getY())) )35 return false;36 }37 if( way.isClosed() )38 rings.add(way);39 else40 arcs.add(way);41 }42 43 // If there are more that one segment, check that they touch rings44 if( arcs.size() > 1 ) {45 for( Way segment : arcs ) {46 boolean found = false;47 for( Way ring : rings )48 if( ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode()) )49 found = true;50 if( !found )51 return false;52 }53 }54 55 if( rings.isEmpty() && arcs.isEmpty() )56 return false;57 58 // check for non-containment of rings59 for( int i = 0; i < rings.size() - 1; i++ ) {60 for( int j = i + 1; j < rings.size(); j++ ) {61 PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());62 if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )63 return false;64 }65 }66 67 return true;26 List<Way> rings = new ArrayList<>(); 27 List<Way> arcs = new ArrayList<>(); 28 Area a = Main.main.getCurrentDataSet().getDataSourceArea(); 29 for( Way way : ways ) { 30 if( way.isDeleted() ) 31 return false; 32 for( Node n : way.getNodes() ) { 33 LatLon ll = n.getCoor(); 34 if( n.isIncomplete() || (a != null && !a.contains(ll.getX(), ll.getY())) ) 35 return false; 36 } 37 if( way.isClosed() ) 38 rings.add(way); 39 else 40 arcs.add(way); 41 } 42 43 // If there are more that one segment, check that they touch rings 44 if( arcs.size() > 1 ) { 45 for( Way segment : arcs ) { 46 boolean found = false; 47 for( Way ring : rings ) 48 if( ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode()) ) 49 found = true; 50 if( !found ) 51 return false; 52 } 53 } 54 55 if( rings.isEmpty() && arcs.isEmpty() ) 56 return false; 57 58 // check for non-containment of rings 59 for( int i = 0; i < rings.size() - 1; i++ ) { 60 for( int j = i + 1; j < rings.size(); j++ ) { 61 PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes()); 62 if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST ) 63 return false; 64 } 65 } 66 67 return true; 68 68 } 69 69 70 70 public static List<Relation> process( Collection<Way> selectedWays ) { 71 // System.out.println("---------------------------------------");72 List<Relation> result = new ArrayList<>();73 List<Way> rings = new ArrayList<>();74 List<Way> arcs = new ArrayList<>();75 for( Way way : selectedWays ) {76 if( way.isClosed() )77 rings.add(way);78 else79 arcs.add(way);80 }81 82 for( Way ring : rings ) {83 List<Command> commands = new ArrayList<>();84 Relation newRelation = SplittingMultipolygons.attachRingToNeighbours(ring, commands);85 if( newRelation != null && !commands.isEmpty() ) {86 Main.main.undoRedo.add(commands.get(0));87 result.add(newRelation);88 }89 }90 91 for( Way arc : arcs) {92 List<Command> commands = new ArrayList<>();93 Relation newRelation = SplittingMultipolygons.tryToCloseOneWay(arc, commands);94 if( newRelation != null && !commands.isEmpty() ) {95 Main.main.undoRedo.add(commands.get(0));96 result.add(newRelation);97 }98 }99 return result;71 // System.out.println("---------------------------------------"); 72 List<Relation> result = new ArrayList<>(); 73 List<Way> rings = new ArrayList<>(); 74 List<Way> arcs = new ArrayList<>(); 75 for( Way way : selectedWays ) { 76 if( way.isClosed() ) 77 rings.add(way); 78 else 79 arcs.add(way); 80 } 81 82 for( Way ring : rings ) { 83 List<Command> commands = new ArrayList<>(); 84 Relation newRelation = SplittingMultipolygons.attachRingToNeighbours(ring, commands); 85 if( newRelation != null && !commands.isEmpty() ) { 86 Main.main.undoRedo.add(commands.get(0)); 87 result.add(newRelation); 88 } 89 } 90 91 for( Way arc : arcs) { 92 List<Command> commands = new ArrayList<>(); 93 Relation newRelation = SplittingMultipolygons.tryToCloseOneWay(arc, commands); 94 if( newRelation != null && !commands.isEmpty() ) { 95 Main.main.undoRedo.add(commands.get(0)); 96 result.add(newRelation); 97 } 98 } 99 return result; 100 100 } 101 101 … … 104 104 */ 105 105 private static void closePolygon( List<Node> base, List<Node> append ) { 106 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {107 List<Node> ap2 = new ArrayList<>(append);108 Collections.reverse(ap2);109 append = ap2;110 }111 base.remove(base.size() - 1);112 base.addAll(append);106 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) { 107 List<Node> ap2 = new ArrayList<>(append); 108 Collections.reverse(ap2); 109 append = ap2; 110 } 111 base.remove(base.size() - 1); 112 base.addAll(append); 113 113 } 114 114 … … 117 117 */ 118 118 private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) { 119 EastNorth en1 = n1.getEastNorth();120 EastNorth en2 = n2.getEastNorth();121 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));122 return Geometry.nodeInsidePolygon(testNode, polygon);119 EastNorth en1 = n1.getEastNorth(); 120 EastNorth en2 = n2.getEastNorth(); 121 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0)); 122 return Geometry.nodeInsidePolygon(testNode, polygon); 123 123 } 124 124 … … 131 131 */ 132 132 public static List<Way> splitWay( Way w, Node n1, Node n2, List<Command> commands ) { 133 List<Node> nodes = new ArrayList<>(w.getNodes());134 if( w.isClosed() )135 nodes.remove(nodes.size() - 1);136 int index1 = nodes.indexOf(n1);137 int index2 = n2 == null ? -1 : nodes.indexOf(n2);138 if( index1 > index2 ) {139 int tmp = index1;140 index1 = index2;141 index2 = tmp;142 }143 // right now index2 >= index1144 if( index2 < 1 || index1 >= w.getNodesCount() - 1 || index2 >= w.getNodesCount() )145 return Collections.emptyList();146 if( w.isClosed() && (index1 < 0 || index1 == index2 || index1 + w.getNodesCount() == index2) )147 return Collections.emptyList();148 149 // todo: download parent relations!150 151 // make a list of segments152 List<List<Node>> chunks = new ArrayList<>(2);153 List<Node> chunk = new ArrayList<>();154 for( int i = 0; i < nodes.size(); i++ ) {155 chunk.add(nodes.get(i));156 if( (w.isClosed() || chunk.size() > 1) && (i == index1 || i == index2) ) {157 chunks.add(chunk);158 chunk = new ArrayList<>();159 chunk.add(nodes.get(i));160 }161 }162 chunks.add(chunk);163 164 // for closed way ignore the way boundary165 if( w.isClosed() ) {166 chunks.get(chunks.size() - 1).addAll(chunks.get(0));167 chunks.remove(0);168 } else if( chunks.get(chunks.size() - 1).size() < 2 )169 chunks.remove(chunks.size() - 1);170 171 // todo remove debug: show chunks array contents172 /*for( List<Node> c1 : chunks ) {173 for( Node cn1 : c1 )174 System.out.print(cn1.getId() + ",");175 System.out.println();176 }*/177 178 // build a map of referencing relations179 Map<Relation, Integer> references = new HashMap<>();180 List<Command> relationCommands = new ArrayList<>();181 for( OsmPrimitive p : w.getReferrers() ) {182 if( p instanceof Relation ) {183 Relation rel = commands == null ? (Relation)p : new Relation((Relation)p);184 if( commands != null )185 relationCommands.add(new ChangeCommand((Relation)p, rel));186 for( int i = 0; i < rel.getMembersCount(); i++ )187 if( rel.getMember(i).getMember().equals(w) )188 references.put(rel, Integer.valueOf(i));189 }190 }191 192 // build ways193 List<Way> result = new ArrayList<>();194 Way updatedWay = commands == null ? w : new Way(w);195 updatedWay.setNodes(chunks.get(0));196 if( commands != null ) {197 commands.add(new ChangeCommand(w, updatedWay));198 result.add(updatedWay);199 }200 201 for( int i = 1; i < chunks.size(); i++ ) {202 List<Node> achunk = chunks.get(i);203 Way newWay = new Way();204 newWay.setKeys(w.getKeys());205 result.add(newWay);206 for( Relation rel : references.keySet() ) {207 int relIndex = references.get(rel);208 rel.addMember(relIndex + 1, new RelationMember(rel.getMember(relIndex).getRole(), newWay));209 }210 newWay.setNodes(achunk);211 if( commands != null )212 commands.add(new AddCommand(newWay));213 }214 if( commands != null )215 commands.addAll(relationCommands);216 return result;133 List<Node> nodes = new ArrayList<>(w.getNodes()); 134 if( w.isClosed() ) 135 nodes.remove(nodes.size() - 1); 136 int index1 = nodes.indexOf(n1); 137 int index2 = n2 == null ? -1 : nodes.indexOf(n2); 138 if( index1 > index2 ) { 139 int tmp = index1; 140 index1 = index2; 141 index2 = tmp; 142 } 143 // right now index2 >= index1 144 if( index2 < 1 || index1 >= w.getNodesCount() - 1 || index2 >= w.getNodesCount() ) 145 return Collections.emptyList(); 146 if( w.isClosed() && (index1 < 0 || index1 == index2 || index1 + w.getNodesCount() == index2) ) 147 return Collections.emptyList(); 148 149 // todo: download parent relations! 150 151 // make a list of segments 152 List<List<Node>> chunks = new ArrayList<>(2); 153 List<Node> chunk = new ArrayList<>(); 154 for( int i = 0; i < nodes.size(); i++ ) { 155 chunk.add(nodes.get(i)); 156 if( (w.isClosed() || chunk.size() > 1) && (i == index1 || i == index2) ) { 157 chunks.add(chunk); 158 chunk = new ArrayList<>(); 159 chunk.add(nodes.get(i)); 160 } 161 } 162 chunks.add(chunk); 163 164 // for closed way ignore the way boundary 165 if( w.isClosed() ) { 166 chunks.get(chunks.size() - 1).addAll(chunks.get(0)); 167 chunks.remove(0); 168 } else if( chunks.get(chunks.size() - 1).size() < 2 ) 169 chunks.remove(chunks.size() - 1); 170 171 // todo remove debug: show chunks array contents 172 /*for( List<Node> c1 : chunks ) { 173 for( Node cn1 : c1 ) 174 System.out.print(cn1.getId() + ","); 175 System.out.println(); 176 }*/ 177 178 // build a map of referencing relations 179 Map<Relation, Integer> references = new HashMap<>(); 180 List<Command> relationCommands = new ArrayList<>(); 181 for( OsmPrimitive p : w.getReferrers() ) { 182 if( p instanceof Relation ) { 183 Relation rel = commands == null ? (Relation)p : new Relation((Relation)p); 184 if( commands != null ) 185 relationCommands.add(new ChangeCommand((Relation)p, rel)); 186 for( int i = 0; i < rel.getMembersCount(); i++ ) 187 if( rel.getMember(i).getMember().equals(w) ) 188 references.put(rel, Integer.valueOf(i)); 189 } 190 } 191 192 // build ways 193 List<Way> result = new ArrayList<>(); 194 Way updatedWay = commands == null ? w : new Way(w); 195 updatedWay.setNodes(chunks.get(0)); 196 if( commands != null ) { 197 commands.add(new ChangeCommand(w, updatedWay)); 198 result.add(updatedWay); 199 } 200 201 for( int i = 1; i < chunks.size(); i++ ) { 202 List<Node> achunk = chunks.get(i); 203 Way newWay = new Way(); 204 newWay.setKeys(w.getKeys()); 205 result.add(newWay); 206 for( Relation rel : references.keySet() ) { 207 int relIndex = references.get(rel); 208 rel.addMember(relIndex + 1, new RelationMember(rel.getMember(relIndex).getRole(), newWay)); 209 } 210 newWay.setNodes(achunk); 211 if( commands != null ) 212 commands.add(new AddCommand(newWay)); 213 } 214 if( commands != null ) 215 commands.addAll(relationCommands); 216 return result; 217 217 } 218 218 219 219 public static List<Way> splitWay( Way w, Node n1, Node n2 ) { 220 return splitWay(w, n1, n2, null);220 return splitWay(w, n1, n2, null); 221 221 } 222 222 … … 225 225 */ 226 226 public static Relation tryToCloseOneWay( Way segment, List<Command> resultingCommands ) { 227 if( segment.isClosed() || segment.isIncomplete() )228 return null;229 230 List<Way> ways = intersection(231 OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class),232 OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class));233 ways.remove(segment);234 for( Iterator<Way> iter = ways.iterator(); iter.hasNext(); ) {235 boolean save = false;236 for( OsmPrimitive ref : iter.next().getReferrers() )237 if( ref instanceof Relation && ((Relation)ref).isMultipolygon() && !ref.isDeleted() )238 save = true;239 if( !save )240 iter.remove();241 }242 if( ways.isEmpty() )243 return null; // well...244 Way target = ways.get(0);245 246 // time to create a new multipolygon relation and a command stack247 List<Command> commands = new ArrayList<>();248 Relation newRelation = new Relation();249 newRelation.put("type", "multipolygon");250 newRelation.addMember(new RelationMember("outer", segment));251 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);252 Way segmentCopy = new Way(segment);253 boolean changed = false;254 for( String key : segmentCopy.keySet() ) {255 if( !linearTags.contains(key) ) {256 newRelation.put(key, segmentCopy.get(key));257 segmentCopy.remove(key);258 changed = true;259 }260 }261 if( changed )262 commands.add(new ChangeCommand(segment, segmentCopy));263 264 // now split the way, at last265 List<Way> newWays = new ArrayList<>(splitWay(target, segment.firstNode(), segment.lastNode(), commands));266 267 Way addingWay = null;268 if( target.isClosed() ) {269 Way utarget = newWays.get(1);270 Way alternate = newWays.get(0);271 List<Node> testRing = new ArrayList<>(segment.getNodes());272 closePolygon(testRing, utarget.getNodes());273 addingWay = segmentInsidePolygon(alternate.getNode(0), alternate.getNode(1), testRing) ? alternate : utarget;274 } else {275 for( Way w : newWays ) {276 if( (w.firstNode().equals(segment.firstNode()) && w.lastNode().equals(segment.lastNode()))277 || (w.firstNode().equals(segment.lastNode()) && w.lastNode().equals(segment.firstNode())) ) {278 addingWay = w;279 break;280 }281 }282 }283 newRelation.addMember(new RelationMember("outer", addingWay.getUniqueId() == target.getUniqueId() ? target : addingWay));284 commands.add(new AddCommand(newRelation));285 resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}",286 DefaultNameFormatter.getInstance().format(segment)), commands));287 return newRelation;227 if( segment.isClosed() || segment.isIncomplete() ) 228 return null; 229 230 List<Way> ways = intersection( 231 OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class), 232 OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class)); 233 ways.remove(segment); 234 for( Iterator<Way> iter = ways.iterator(); iter.hasNext(); ) { 235 boolean save = false; 236 for( OsmPrimitive ref : iter.next().getReferrers() ) 237 if( ref instanceof Relation && ((Relation)ref).isMultipolygon() && !ref.isDeleted() ) 238 save = true; 239 if( !save ) 240 iter.remove(); 241 } 242 if( ways.isEmpty() ) 243 return null; // well... 244 Way target = ways.get(0); 245 246 // time to create a new multipolygon relation and a command stack 247 List<Command> commands = new ArrayList<>(); 248 Relation newRelation = new Relation(); 249 newRelation.put("type", "multipolygon"); 250 newRelation.addMember(new RelationMember("outer", segment)); 251 Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS); 252 Way segmentCopy = new Way(segment); 253 boolean changed = false; 254 for( String key : segmentCopy.keySet() ) { 255 if( !linearTags.contains(key) ) { 256 newRelation.put(key, segmentCopy.get(key)); 257 segmentCopy.remove(key); 258 changed = true; 259 } 260 } 261 if( changed ) 262 commands.add(new ChangeCommand(segment, segmentCopy)); 263 264 // now split the way, at last 265 List<Way> newWays = new ArrayList<>(splitWay(target, segment.firstNode(), segment.lastNode(), commands)); 266 267 Way addingWay = null; 268 if( target.isClosed() ) { 269 Way utarget = newWays.get(1); 270 Way alternate = newWays.get(0); 271 List<Node> testRing = new ArrayList<>(segment.getNodes()); 272 closePolygon(testRing, utarget.getNodes()); 273 addingWay = segmentInsidePolygon(alternate.getNode(0), alternate.getNode(1), testRing) ? alternate : utarget; 274 } else { 275 for( Way w : newWays ) { 276 if( (w.firstNode().equals(segment.firstNode()) && w.lastNode().equals(segment.lastNode())) 277 || (w.firstNode().equals(segment.lastNode()) && w.lastNode().equals(segment.firstNode())) ) { 278 addingWay = w; 279 break; 280 } 281 } 282 } 283 newRelation.addMember(new RelationMember("outer", addingWay.getUniqueId() == target.getUniqueId() ? target : addingWay)); 284 commands.add(new AddCommand(newRelation)); 285 resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}", 286 DefaultNameFormatter.getInstance().format(segment)), commands)); 287 return newRelation; 288 288 } 289 289 … … 292 292 */ 293 293 private static <T> List<T> intersection( Collection<T> list1, Collection<T> list2 ) { 294 List<T> result = new ArrayList<>();295 for( T item : list1 )296 if( list2.contains(item) )297 result.add(item);298 return result;294 List<T> result = new ArrayList<>(); 295 for( T item : list1 ) 296 if( list2.contains(item) ) 297 result.add(item); 298 return result; 299 299 } 300 300 … … 303 303 */ 304 304 public static Relation attachRingToNeighbours( Way ring, List<Command> resultingCommands ) { 305 if( !ring.isClosed() || ring.isIncomplete() )306 return null;307 Map<Way, Boolean> touchingWays = new HashMap<>();308 for( Node n : ring.getNodes() ) {309 for( OsmPrimitive p : n.getReferrers() ) {310 if( p instanceof Way && !p.equals(ring) ) {311 for( OsmPrimitive r : p.getReferrers() ) {312 if( r instanceof Relation && ((Relation)r).hasKey("type") && ((Relation)r).get("type").equals("multipolygon") ) {313 if( touchingWays.containsKey((Way)p) )314 touchingWays.put((Way)p, Boolean.TRUE);315 else316 touchingWays.put((Way)p, Boolean.FALSE);317 break;318 }319 }320 }321 }322 }323 324 List<TheRing> otherWays = new ArrayList<>();325 for( Way w : touchingWays.keySet() )326 if( touchingWays.get(w) ) {327 otherWays.add(new TheRing(w));328 // System.out.println("Touching ring: " + otherWays.get(otherWays.size()-1));329 }330 331 // for( Iterator<Way> keys = touchingWays.keySet().iterator(); keys.hasNext(); ) {332 // if( !touchingWays.get(keys.next()) )333 // keys.remove();334 // }335 336 // now touchingWays has only ways that touch the ring twice337 List<Command> commands = new ArrayList<>();338 TheRing theRing = new TheRing(ring); // this is actually useful339 340 for( TheRing otherRing : otherWays )341 theRing.collide(otherRing);342 343 theRing.putSourceWayFirst();344 for( TheRing otherRing : otherWays )345 otherRing.putSourceWayFirst();346 347 Map<Relation, Relation> relationCache = new HashMap<>();348 for( TheRing otherRing : otherWays )349 commands.addAll(otherRing.getCommands(false, relationCache));350 commands.addAll(theRing.getCommands(relationCache));351 TheRing.updateCommandsWithRelations(commands, relationCache);352 resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}",353 DefaultNameFormatter.getInstance().format(ring)), commands));354 return theRing.getRelation();305 if( !ring.isClosed() || ring.isIncomplete() ) 306 return null; 307 Map<Way, Boolean> touchingWays = new HashMap<>(); 308 for( Node n : ring.getNodes() ) { 309 for( OsmPrimitive p : n.getReferrers() ) { 310 if( p instanceof Way && !p.equals(ring) ) { 311 for( OsmPrimitive r : p.getReferrers() ) { 312 if( r instanceof Relation && ((Relation)r).hasKey("type") && ((Relation)r).get("type").equals("multipolygon") ) { 313 if( touchingWays.containsKey((Way)p) ) 314 touchingWays.put((Way)p, Boolean.TRUE); 315 else 316 touchingWays.put((Way)p, Boolean.FALSE); 317 break; 318 } 319 } 320 } 321 } 322 } 323 324 List<TheRing> otherWays = new ArrayList<>(); 325 for( Way w : touchingWays.keySet() ) 326 if( touchingWays.get(w) ) { 327 otherWays.add(new TheRing(w)); 328 // System.out.println("Touching ring: " + otherWays.get(otherWays.size()-1)); 329 } 330 331 // for( Iterator<Way> keys = touchingWays.keySet().iterator(); keys.hasNext(); ) { 332 // if( !touchingWays.get(keys.next()) ) 333 // keys.remove(); 334 // } 335 336 // now touchingWays has only ways that touch the ring twice 337 List<Command> commands = new ArrayList<>(); 338 TheRing theRing = new TheRing(ring); // this is actually useful 339 340 for( TheRing otherRing : otherWays ) 341 theRing.collide(otherRing); 342 343 theRing.putSourceWayFirst(); 344 for( TheRing otherRing : otherWays ) 345 otherRing.putSourceWayFirst(); 346 347 Map<Relation, Relation> relationCache = new HashMap<>(); 348 for( TheRing otherRing : otherWays ) 349 commands.addAll(otherRing.getCommands(false, relationCache)); 350 commands.addAll(theRing.getCommands(relationCache)); 351 TheRing.updateCommandsWithRelations(commands, relationCache); 352 resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}", 353 DefaultNameFormatter.getInstance().format(ring)), commands)); 354 return theRing.getRelation(); 355 355 } 356 356 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java
r30737 r30738 36 36 37 37 public TheRing( Way source ) { 38 this.source = source;39 segments = new ArrayList<>(1);40 segments.add(new RingSegment(source));38 this.source = source; 39 segments = new ArrayList<>(1); 40 segments.add(new RingSegment(source)); 41 41 } 42 42 43 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 else49 return false;50 }51 if( rings.isEmpty() || ways.size() == 1 )52 return false;53 54 // check for non-containment of rings55 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 )59 return false;60 }61 }62 63 return true;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 ) 59 return false; 60 } 61 } 62 63 return true; 64 64 } 65 65 … … 69 69 */ 70 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;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 87 } 88 88 89 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 }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 116 } 117 117 … … 120 120 */ 121 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 bit128 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);133 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 nodes158 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;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); 133 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 185 } 186 186 187 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 else194 return result;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 195 } 196 196 197 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;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; 208 208 } 209 209 … … 213 213 */ 214 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 nodes223 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 == firstNode229 RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);230 // if secondPart == null, then thirdPart is between n1 and n2231 // otherwise, thirdPart is between n2 and lastNode232 // if thirdPart == null, then n2 == lastNode233 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;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; 239 239 } 240 240 … … 246 246 */ 247 247 public static void redistributeSegments( List<TheRing> rings ) { 248 // build segments map249 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 references256 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 segment260 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 deadlocking264 seg.swapReference();265 }266 }267 }268 }269 270 // initializing source way for each ring271 for( TheRing ring : rings )272 ring.putSourceWayFirst();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(); 273 273 } 274 274 275 275 private int countNonReferenceSegments() { 276 int count = 0;277 for( RingSegment seg : segments )278 if( !seg.isReference() )279 count++;280 return count;276 int count = 0; 277 for( RingSegment seg : segments ) 278 if( !seg.isReference() ) 279 count++; 280 return count; 281 281 } 282 282 283 283 public void putSourceWayFirst() { 284 for( RingSegment seg : segments ) {285 if( !seg.isReference() ) {286 seg.overrideWay(source);287 return;288 }289 }284 for( RingSegment seg : segments ) { 285 if( !seg.isReference() ) { 286 seg.overrideWay(source); 287 return; 288 } 289 } 290 290 } 291 291 292 292 public List<Command> getCommands() { 293 return getCommands(true, null);293 return getCommands(true, null); 294 294 } 295 295 296 296 public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) { 297 return getCommands(true, relationChangeMap);297 return getCommands(true, relationChangeMap); 298 298 } 299 299 … … 303 303 */ 304 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() ) {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 311 if( linearTags.contains(key) ) continue; 312 312 if( key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) continue; 313 313 relation.put(key, sourceCopy.get(key)); 314 314 sourceCopy.remove(key); 315 }316 }317 318 // build a map of referencing relations319 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;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 372 } 373 373 374 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)));375 for( Relation src : relationCache.keySet() ) 376 commands.add(new ChangeCommand(src, relationCache.get(src))); 377 377 } 378 378 … … 381 381 */ 382 382 public Relation getRelation() { 383 return relation;383 return relation; 384 384 } 385 385 386 386 @Override 387 387 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();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(); 398 398 } 399 399 … … 402 402 */ 403 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)) ) {405 List<Node> ap2 = new ArrayList<Node>(append);406 Collections.reverse(ap2);407 append = ap2;408 }409 base.remove(base.size() - 1);410 base.addAll(append);404 if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) { 405 List<Node> ap2 = new ArrayList<Node>(append); 406 Collections.reverse(ap2); 407 append = ap2; 408 } 409 base.remove(base.size() - 1); 410 base.addAll(append); 411 411 }*/ 412 412 … … 415 415 */ 416 416 /*private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) { 417 EastNorth en1 = n1.getEastNorth();418 EastNorth en2 = n2.getEastNorth();419 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));420 return Geometry.nodeInsidePolygon(testNode, polygon);417 EastNorth en1 = n1.getEastNorth(); 418 EastNorth en2 = n2.getEastNorth(); 419 Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0)); 420 return Geometry.nodeInsidePolygon(testNode, polygon); 421 421 }*/ 422 422 423 423 private static void log( String s ) { 424 // System.out.println(s);424 // System.out.println(s); 425 425 } 426 426 427 427 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() {435 }*/436 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 ) {450 this.nodes = null;451 this.references = ref;452 }*/453 454 /**455 * Splits this segment at node n. Retains nodes 0..n and moves456 * 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 ) {574 return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other);575 }*/576 577 @Override578 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 }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() { 435 }*/ 436 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 ) { 450 this.nodes = null; 451 this.references = ref; 452 }*/ 453 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 ) { 574 return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other); 575 }*/ 576 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 } 594 594 } 595 595 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/AssociatedStreetFixer.java
r30737 r30738 19 19 public class AssociatedStreetFixer extends RelationFixer { 20 20 21 public AssociatedStreetFixer() { 22 super("associatedStreet"); 23 } 24 25 @Override 26 public boolean isRelationGood(Relation rel) { 27 for (RelationMember m : rel.getMembers()) { 28 if (m.getType().equals(OsmPrimitiveType.NODE) && !"house".equals(m.getRole())) { 29 setWarningMessage(tr("Node without ''house'' role found")); 30 return false; 31 } 32 if (m.getType().equals(OsmPrimitiveType.WAY) && !("house".equals(m.getRole()) || "street".equals(m.getRole()))) { 33 setWarningMessage(tr("Way without ''house'' or ''street'' role found")); 34 return false; 35 } 36 if (m.getType().equals(OsmPrimitiveType.RELATION) && !"house".equals(m.getRole())) { 37 setWarningMessage(tr("Relation without ''house'' role found")); 38 return false; 39 } 40 } 41 // relation should have name 42 if (!rel.hasKey("name")) { 43 setWarningMessage(tr("Relation does not have name")); 44 return false; 45 } 46 // check that all street members have same name as relation (???) 47 String streetName = rel.get("name"); 48 if (streetName == null) streetName = ""; 49 for (RelationMember m : rel.getMembers()) { 50 if ("street".equals(m.getRole()) && !streetName.equals(m.getWay().get("name"))) { 51 String anotherName = m.getWay().get("name"); 52 if (anotherName != null && !anotherName.isEmpty()) { 53 setWarningMessage(tr("Relation has streets with different names")); 54 return false; 55 } 56 } 57 } 58 clearWarningMessage(); 59 return true; 60 } 21 public AssociatedStreetFixer() { 22 super("associatedStreet"); 23 } 61 24 62 25 @Override 63 public Command fixRelation(Relation source) { 64 // any way with highway tag -> street 65 // any way/point/relation with addr:housenumber=* or building=* or type=multipolygon -> house 66 // name - check which name is most used in street members and add to relation 67 // copy this name to the other street members (???) 68 Relation rel = new Relation(source); 69 boolean fixed = false; 26 public boolean isRelationGood(Relation rel) { 27 for (RelationMember m : rel.getMembers()) { 28 if (m.getType().equals(OsmPrimitiveType.NODE) && !"house".equals(m.getRole())) { 29 setWarningMessage(tr("Node without ''house'' role found")); 30 return false; 31 } 32 if (m.getType().equals(OsmPrimitiveType.WAY) && !("house".equals(m.getRole()) || "street".equals(m.getRole()))) { 33 setWarningMessage(tr("Way without ''house'' or ''street'' role found")); 34 return false; 35 } 36 if (m.getType().equals(OsmPrimitiveType.RELATION) && !"house".equals(m.getRole())) { 37 setWarningMessage(tr("Relation without ''house'' role found")); 38 return false; 39 } 40 } 41 // relation should have name 42 if (!rel.hasKey("name")) { 43 setWarningMessage(tr("Relation does not have name")); 44 return false; 45 } 46 // check that all street members have same name as relation (???) 47 String streetName = rel.get("name"); 48 if (streetName == null) streetName = ""; 49 for (RelationMember m : rel.getMembers()) { 50 if ("street".equals(m.getRole()) && !streetName.equals(m.getWay().get("name"))) { 51 String anotherName = m.getWay().get("name"); 52 if (anotherName != null && !anotherName.isEmpty()) { 53 setWarningMessage(tr("Relation has streets with different names")); 54 return false; 55 } 56 } 57 } 58 clearWarningMessage(); 59 return true; 60 } 70 61 71 for (int i = 0; i < rel.getMembersCount(); i++) { 72 RelationMember m = rel.getMember(i); 62 @Override 63 public Command fixRelation(Relation source) { 64 // any way with highway tag -> street 65 // any way/point/relation with addr:housenumber=* or building=* or type=multipolygon -> house 66 // name - check which name is most used in street members and add to relation 67 // copy this name to the other street members (???) 68 Relation rel = new Relation(source); 69 boolean fixed = false; 73 70 74 if (m.isNode()) { 75 Node node = m.getNode(); 76 if (!"house".equals(m.getRole()) && 77 (node.hasKey("building") || node.hasKey("addr:housenumber"))) { 78 fixed = true; 79 rel.setMember(i, new RelationMember("house", node)); 80 } 81 } else if (m.isWay()) { 82 Way way = m.getWay(); 83 if (!"street".equals(m.getRole()) && way.hasKey("highway")) { 84 fixed = true; 85 rel.setMember(i, new RelationMember("street", way)); 86 } else if (!"house".equals(m.getRole()) && 87 (way.hasKey("building") || way.hasKey("addr:housenumber"))) { 88 fixed = true; 89 rel.setMember(i, new RelationMember("house", way)); 90 } 91 } else if (m.isRelation()) { 92 Relation relation = m.getRelation(); 93 if (!"house".equals(m.getRole()) && 94 (relation.hasKey("building") || relation.hasKey("addr:housenumber") || "multipolygon".equals(relation.get("type")))) { 95 fixed = true; 96 rel.setMember(i, new RelationMember("house", relation)); 97 } 98 } 99 } 71 for (int i = 0; i < rel.getMembersCount(); i++) { 72 RelationMember m = rel.getMember(i); 100 73 101 // fill relation name 102 Map<String, Integer> streetNames = new HashMap<>(); 103 for (RelationMember m : rel.getMembers()) 104 if ("street".equals(m.getRole()) && m.isWay()) { 105 String name = m.getWay().get("name"); 106 if (name == null || name.isEmpty()) continue; 74 if (m.isNode()) { 75 Node node = m.getNode(); 76 if (!"house".equals(m.getRole()) && 77 (node.hasKey("building") || node.hasKey("addr:housenumber"))) { 78 fixed = true; 79 rel.setMember(i, new RelationMember("house", node)); 80 } 81 } else if (m.isWay()) { 82 Way way = m.getWay(); 83 if (!"street".equals(m.getRole()) && way.hasKey("highway")) { 84 fixed = true; 85 rel.setMember(i, new RelationMember("street", way)); 86 } else if (!"house".equals(m.getRole()) && 87 (way.hasKey("building") || way.hasKey("addr:housenumber"))) { 88 fixed = true; 89 rel.setMember(i, new RelationMember("house", way)); 90 } 91 } else if (m.isRelation()) { 92 Relation relation = m.getRelation(); 93 if (!"house".equals(m.getRole()) && 94 (relation.hasKey("building") || relation.hasKey("addr:housenumber") || "multipolygon".equals(relation.get("type")))) { 95 fixed = true; 96 rel.setMember(i, new RelationMember("house", relation)); 97 } 98 } 99 } 107 100 108 Integer count = streetNames.get(name); 101 // fill relation name 102 Map<String, Integer> streetNames = new HashMap<>(); 103 for (RelationMember m : rel.getMembers()) 104 if ("street".equals(m.getRole()) && m.isWay()) { 105 String name = m.getWay().get("name"); 106 if (name == null || name.isEmpty()) continue; 109 107 110 streetNames.put(name, count != null? count + 1 : 1); 111 } 112 String commonName = ""; 113 Integer commonCount = 0; 114 for (Map.Entry<String, Integer> entry : streetNames.entrySet()) { 115 if (entry.getValue() > commonCount) { 116 commonCount = entry.getValue(); 117 commonName = entry.getKey(); 118 } 119 } 108 Integer count = streetNames.get(name); 120 109 121 if (!rel.hasKey("name") && !commonName.isEmpty()) { 122 fixed = true; 123 rel.put("name", commonName); 124 } else { 125 commonName = ""; // set empty common name - if we already have name on relation, do not overwrite it 126 } 110 streetNames.put(name, count != null? count + 1 : 1); 111 } 112 String commonName = ""; 113 Integer commonCount = 0; 114 for (Map.Entry<String, Integer> entry : streetNames.entrySet()) { 115 if (entry.getValue() > commonCount) { 116 commonCount = entry.getValue(); 117 commonName = entry.getKey(); 118 } 119 } 127 120 128 List<Command> commandList = new ArrayList<>(); 129 if (fixed) { 130 commandList.add(new ChangeCommand(source, rel)); 131 } 121 if (!rel.hasKey("name") && !commonName.isEmpty()) { 122 fixed = true; 123 rel.put("name", commonName); 124 } else { 125 commonName = ""; // set empty common name - if we already have name on relation, do not overwrite it 126 } 132 127 133 /*if (!commonName.isEmpty()) 134 // fill common name to streets 135 for (RelationMember m : rel.getMembers()) 136 if ("street".equals(m.getRole()) && m.isWay()) { 137 String name = m.getWay().get("name"); 138 if (commonName.equals(name)) continue; 128 List<Command> commandList = new ArrayList<>(); 129 if (fixed) { 130 commandList.add(new ChangeCommand(source, rel)); 131 } 139 132 140 // TODO: ask user if he really wants to overwrite street name?? 133 /*if (!commonName.isEmpty()) 134 // fill common name to streets 135 for (RelationMember m : rel.getMembers()) 136 if ("street".equals(m.getRole()) && m.isWay()) { 137 String name = m.getWay().get("name"); 138 if (commonName.equals(name)) continue; 141 139 142 Way oldWay = m.getWay(); 143 Way newWay = new Way(oldWay); 144 newWay.put("name", commonName); 140 // TODO: ask user if he really wants to overwrite street name?? 145 141 146 commandList.add(new ChangeCommand(oldWay, newWay)); 147 } 148 */ 149 // return results 150 if (commandList.size() == 0) 151 return null; 152 if (commandList.size() == 1) 153 return commandList.get(0); 154 return new SequenceCommand(tr("fix associatedStreet relation"), commandList); 155 } 142 Way oldWay = m.getWay(); 143 Way newWay = new Way(oldWay); 144 newWay.put("name", commonName); 145 146 commandList.add(new ChangeCommand(oldWay, newWay)); 147 } 148 */ 149 // return results 150 if (commandList.size() == 0) 151 return null; 152 if (commandList.size() == 1) 153 return commandList.get(0); 154 return new SequenceCommand(tr("fix associatedStreet relation"), commandList); 155 } 156 156 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/BoundaryFixer.java
r28762 r30738 16 16 public class BoundaryFixer extends MultipolygonFixer { 17 17 18 public BoundaryFixer() {19 super("boundary", "multipolygon");20 }18 public BoundaryFixer() { 19 super("boundary", "multipolygon"); 20 } 21 21 22 /**23 * For boundary relations both "boundary" and "multipolygon" types are applicable, but24 * it should also have key boundary=administrative to be fully boundary.25 * @see http://wiki.openstreetmap.org/wiki/Relation:boundary26 */27 @Override28 public boolean isFixerApplicable(Relation rel) {29 return super.isFixerApplicable(rel) && "administrative".equals(rel.get("boundary"));30 }22 /** 23 * For boundary relations both "boundary" and "multipolygon" types are applicable, but 24 * it should also have key boundary=administrative to be fully boundary. 25 * @see http://wiki.openstreetmap.org/wiki/Relation:boundary 26 */ 27 @Override 28 public boolean isFixerApplicable(Relation rel) { 29 return super.isFixerApplicable(rel) && "administrative".equals(rel.get("boundary")); 30 } 31 31 32 @Override33 public boolean isRelationGood(Relation rel) {34 for( RelationMember m : rel.getMembers() ) {32 @Override 33 public boolean isRelationGood(Relation rel) { 34 for( RelationMember m : rel.getMembers() ) { 35 35 if (m.getType().equals(OsmPrimitiveType.RELATION) && !"subarea".equals(m.getRole())) { 36 36 setWarningMessage(tr("Relation without ''subarea'' role found")); … … 43 43 if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole()))) { 44 44 setWarningMessage(tr("Way without ''inner'' or ''outer'' role found")); 45 return false;45 return false; 46 46 } 47 47 } 48 clearWarningMessage();49 return true;50 }48 clearWarningMessage(); 49 return true; 50 } 51 51 52 @Override53 public Command fixRelation(Relation rel) {54 Relation r = rel;55 Relation rr = fixMultipolygonRoles(r);56 boolean fixed = false;57 if (rr != null) {58 fixed = true;59 r = rr;60 }61 rr = fixBoundaryRoles(r);62 if (rr != null) {63 fixed = true;64 r = rr;65 }66 return fixed ? new ChangeCommand(rel, r) : null;67 }52 @Override 53 public Command fixRelation(Relation rel) { 54 Relation r = rel; 55 Relation rr = fixMultipolygonRoles(r); 56 boolean fixed = false; 57 if (rr != null) { 58 fixed = true; 59 r = rr; 60 } 61 rr = fixBoundaryRoles(r); 62 if (rr != null) { 63 fixed = true; 64 r = rr; 65 } 66 return fixed ? new ChangeCommand(rel, r) : null; 67 } 68 68 69 private Relation fixBoundaryRoles( Relation source ) {69 private Relation fixBoundaryRoles( Relation source ) { 70 70 Relation r = new Relation(source); 71 71 boolean fixed = false; -
applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/MultipolygonFixer.java
r30737 r30738 22 22 public class MultipolygonFixer extends RelationFixer { 23 23 24 public MultipolygonFixer() {25 super("multipolygon");26 }24 public MultipolygonFixer() { 25 super("multipolygon"); 26 } 27 27 28 protected MultipolygonFixer(String...types) {29 super(types);30 }28 protected MultipolygonFixer(String...types) { 29 super(types); 30 } 31 31 32 32 33 @Override34 public boolean isRelationGood(Relation rel) {35 for (RelationMember m : rel.getMembers())36 if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole()))) {37 setWarningMessage(tr("Way without ''inner'' or ''outer'' role found"));38 return false;39 }40 clearWarningMessage();41 return true;42 }33 @Override 34 public boolean isRelationGood(Relation rel) { 35 for (RelationMember m : rel.getMembers()) 36 if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole()))) { 37 setWarningMessage(tr("Way without ''inner'' or ''outer'' role found")); 38 return false; 39 } 40 clearWarningMessage(); 41 return true; 42 } 43 43 44 @Override45 public Command fixRelation(Relation rel) {46 Relation rr = fixMultipolygonRoles(rel);47 return rr != null? new ChangeCommand(rel, rr) : null;48 }44 @Override 45 public Command fixRelation(Relation rel) { 46 Relation rr = fixMultipolygonRoles(rel); 47 return rr != null? new ChangeCommand(rel, rr) : null; 48 } 49 49 50 /**50 /** 51 51 * Basically, created multipolygon from scratch, and if successful, replace roles with new ones. 52 52 */ -
applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/NothingFixer.java
r28693 r30738 9 9 public class NothingFixer extends RelationFixer { 10 10 11 public NothingFixer() {12 super("");13 }14 @Override15 public boolean isFixerApplicable(Relation rel) {16 return true;17 }18 @Override19 public boolean isRelationGood(Relation rel) {20 return true;21 }11 public NothingFixer() { 12 super(""); 13 } 14 @Override 15 public boolean isFixerApplicable(Relation rel) { 16 return true; 17 } 18 @Override 19 public boolean isRelationGood(Relation rel) { 20 return true; 21 } 22 22 23 @Override24 public Command fixRelation(Relation rel) {25 return null;26 }23 @Override 24 public Command fixRelation(Relation rel) { 25 return null; 26 } 27 27 28 28 } -
applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/RelationFixer.java
r30737 r30738 15 15 public abstract class RelationFixer { 16 16 17 private List<String> applicableTypes;18 private SortAndFixAction sortAndFixAction;17 private List<String> applicableTypes; 18 private SortAndFixAction sortAndFixAction; 19 19 20 /**21 * Construct new RelationFixer by a list of applicable types22 * @param types23 */24 public RelationFixer(String... types) {25 applicableTypes = new ArrayList<>();26 for(String type: types) {27 applicableTypes.add(type);28 }29 }20 /** 21 * Construct new RelationFixer by a list of applicable types 22 * @param types 23 */ 24 public RelationFixer(String... types) { 25 applicableTypes = new ArrayList<>(); 26 for(String type: types) { 27 applicableTypes.add(type); 28 } 29 } 30 30 31 /**32 * Check if given relation is of needed type. You may override this method to check first type33 * and then check desired relation properties.34 * Note that this only verifies if current RelationFixer can be used to check and fix given relation35 * Deeper relation checking is at {@link isRelationGood}36 *37 * @param rel Relation to check38 * @return true if relation can be verified by current RelationFixer39 */40 public boolean isFixerApplicable(Relation rel) {41 if (rel == null)42 return false;43 if (!rel.hasKey("type"))44 return false;31 /** 32 * Check if given relation is of needed type. You may override this method to check first type 33 * and then check desired relation properties. 34 * Note that this only verifies if current RelationFixer can be used to check and fix given relation 35 * Deeper relation checking is at {@link isRelationGood} 36 * 37 * @param rel Relation to check 38 * @return true if relation can be verified by current RelationFixer 39 */ 40 public boolean isFixerApplicable(Relation rel) { 41 if (rel == null) 42 return false; 43 if (!rel.hasKey("type")) 44 return false; 45 45 46 String type = rel.get("type");47 for(String oktype: applicableTypes)48 if (oktype.equals(type))49 return true;46 String type = rel.get("type"); 47 for(String oktype: applicableTypes) 48 if (oktype.equals(type)) 49 return true; 50 50 51 return false;52 }51 return false; 52 } 53 53 54 /**55 * Check if given relation is OK. That means if all roles are given properly, all tags exist as expected etc.56 * Should be written in children classes.57 *58 * @param rel Relation to verify59 * @return true if given relation is OK60 */61 public abstract boolean isRelationGood(Relation rel);54 /** 55 * Check if given relation is OK. That means if all roles are given properly, all tags exist as expected etc. 56 * Should be written in children classes. 57 * 58 * @param rel Relation to verify 59 * @return true if given relation is OK 60 */ 61 public abstract boolean isRelationGood(Relation rel); 62 62 63 /**64 * Fix relation and return new relation with fixed tags, roles etc.65 * Note that is not obligatory to return true for isRelationGood for new relation66 *67 * @param rel Relation to fix68 * @return command that fixes the relation {@code null} if it cannot be fixed or is already OK69 */70 public abstract Command fixRelation(Relation rel);63 /** 64 * Fix relation and return new relation with fixed tags, roles etc. 65 * Note that is not obligatory to return true for isRelationGood for new relation 66 * 67 * @param rel Relation to fix 68 * @return command that fixes the relation {@code null} if it cannot be fixed or is already OK 69 */ 70 public abstract Command fixRelation(Relation rel); 71 71 72 72 public void setFixAction(SortAndFixAction sortAndFixAction) {
Note:
See TracChangeset
for help on using the changeset viewer.
