Changeset 30738 in osm for applications/editors/josm/plugins/reltoolbox
- Timestamp:
- 2014-10-19T01:27:04+02:00 (10 years ago)
- Location:
- applications/editors/josm/plugins/reltoolbox/src/relcontext
- Files:
-
- 15 edited
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 153 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 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 16 return null; 17 17 } 18 18 19 19 public String checkFormat( INode node, String defaultName ) { 20 20 return null; 21 21 } 22 22 23 23 public String checkFormat( IWay way, String defaultName ) { 24 25 26 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 31 32 33 34 35 36 37 38 39 40 41 42 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 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 31 32 33 34 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 38 this(null); 39 39 } 40 40 41 41 public static boolean getDefaultPropertyValue( String property ) { 42 43 44 45 46 47 48 49 50 51 52 53 54 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 58 return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property)); 59 59 } 60 60 61 61 public void actionPerformed( ActionEvent e ) { 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 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 131 132 133 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 140 141 142 143 144 145 146 147 148 149 150 151 152 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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 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 226 225 "boundary", "boundary_type", "type", "admin_level" 226 })); 227 227 228 228 /** … … 232 232 */ 233 233 private List<Command> removeTagsFromInnerWays( Relation relation ) { 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 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 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 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 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 147 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 151 setEnabled(isSuitableRelation(newRelation)); 152 152 } 153 153 154 154 private boolean isSuitableRelation( Relation newRelation ) { 155 156 157 158 159 160 161 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 28 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 70 71 72 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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 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 // 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 107 108 109 110 111 112 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 120 121 122 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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 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 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 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 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 295 296 297 298 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 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 // 329 330 331 // 332 // 333 // 334 // 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 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 39 40 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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 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 189 190 191 192 193 194 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 199 200 201 202 203 204 205 206 207 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 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 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 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 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 277 278 279 280 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 285 286 287 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 293 return getCommands(true, null); 294 294 } 295 295 296 296 public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) { 297 297 return getCommands(true, relationChangeMap); 298 298 } 299 299 … … 303 303 */ 304 304 public List<Command> getCommands( boolean createMultipolygon, Map<Relation, Relation> relationChangeMap ) { 305 306 307 308 309 310 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 319 320 321 322 323 324 325 326 327 328 329 330 331 } else {332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 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 376 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 383 return relation; 384 384 } 385 385 386 386 @Override 387 387 public String toString() { 388 389 390 391 392 393 394 395 396 397 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 405 406 407 408 409 410 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 418 419 420 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 // 424 // System.out.println(s); 425 425 } 426 426 427 427 private static class RingSegment { 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 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 19 20 18 public BoundaryFixer() { 19 super("boundary", "multipolygon"); 20 } 21 21 22 23 24 25 26 27 28 29 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 33 34 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 45 return false; 46 46 } 47 47 } 48 49 50 48 clearWarningMessage(); 49 return true; 50 } 51 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 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 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 25 26 24 public MultipolygonFixer() { 25 super("multipolygon"); 26 } 27 27 28 29 30 28 protected MultipolygonFixer(String...types) { 29 super(types); 30 } 31 31 32 32 33 34 35 36 37 38 39 40 41 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 45 46 47 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 12 13 14 15 16 17 18 19 20 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 24 25 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 18 17 private List<String> applicableTypes; 18 private SortAndFixAction sortAndFixAction; 19 19 20 21 22 23 24 25 26 27 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 33 34 35 36 37 38 39 40 41 42 43 44 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 47 48 49 46 String type = rel.get("type"); 47 for(String oktype: applicableTypes) 48 if (oktype.equals(type)) 49 return true; 50 50 51 52 51 return false; 52 } 53 53 54 55 56 57 58 59 60 61 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 65 66 67 68 69 70 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.