Ignore:
Timestamp:
2014-10-19T01:27:04+02:00 (10 years ago)
Author:
donvip
Message:

[josm_plugins] fix java 7 warnings / global usage of try-with-resource

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  
    150150                }
    151151            } 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);
    154154                drawRelations(g, mv, bbox, (Relation)element);
    155155                g.setColor(oldColor);
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/ChosenRelationListener.java

    r25649 r30738  
    99 */
    1010public interface ChosenRelationListener {
    11         void chosenRelationChanged( Relation oldRelation, Relation newRelation );
     11    void chosenRelationChanged( Relation oldRelation, Relation newRelation );
    1212}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/ExtraNameFormatHook.java

    r26802 r30738  
    1414
    1515    public String checkRelationTypeName( IRelation relation, String defaultName ) {
    16         return null;
     16    return null;
    1717    }
    1818
    1919    public String checkFormat( INode node, String defaultName ) {
    20         return null;
     20    return null;
    2121    }
    2222
    2323    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;
    2727    }
    2828
    2929    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                 else
    39                     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;
    4343    }
    4444}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextDialog.java

    r30737 r30738  
    9797/**
    9898 * The new, advanced relation editing panel.
    99  * 
     99 *
    100100 * @author Zverik
    101101 */
     
    103103
    104104    public final static String PREF_PREFIX = "reltoolbox";
    105    
     105
    106106    private final DefaultTableModel relationsData;
    107107    private ChosenRelation chosenRelation;
     
    142142        roleBox.addMouseListener(relationMouseAdapter);
    143143        roleBox.addItemListener(new ItemListener() {
     144            @Override
    144145            public void itemStateChanged( ItemEvent e ) {
    145146                if( e.getStateChange() == ItemEvent.DESELECTED ) return;
     
    174175
    175176        roleBox.addPropertyChangeListener("enabled", new PropertyChangeListener() {
     177            @Override
    176178            public void propertyChange( PropertyChangeEvent evt ) {
    177179                boolean showRoleBox = roleBox.isEnabled();
     
    182184
    183185        sortAndFixAction.addPropertyChangeListener(new PropertyChangeListener() {
     186            @Override
    184187            public void propertyChange( PropertyChangeEvent evt ) {
    185188                sortAndFixButton.setVisible(sortAndFixAction.isEnabled());
     
    189192
    190193        downloadChosenRelationAction.addPropertyChangeListener(new PropertyChangeListener() {
     194            @Override
    191195            public void propertyChange( PropertyChangeEvent evt ) {
    192196                downloadButton.setVisible(downloadChosenRelationAction.isEnabled());
     
    304308        columns.getColumn(0).setPreferredWidth(220);
    305309        relationsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
     310            @Override
    306311            public void valueChanged( ListSelectionEvent e ) {
    307312                int selectedRow = relationsTable.getSelectedRow();
     
    339344    }
    340345
     346    @Override
    341347    public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    342348        if( chosenRelationPanel != null && Main.pref.getBoolean(PREF_PREFIX + ".hidetopline", false) )
     
    348354    }
    349355
     356    @Override
    350357    public void selectionChanged( Collection<? extends OsmPrimitive> newSelection ) {
    351358        if( !isVisible() || relationsData == null )
     
    397404    }
    398405
     406    @Override
    399407    public void editLayerChanged( OsmDataLayer oldLayer, OsmDataLayer newLayer ) {
    400408        updateSelection();
     
    410418        super.destroy();
    411419    }
    412    
     420
    413421    private static final String POSSIBLE_ROLES_FILE = "relcontext/possible_roles.txt";
    414422    private static final Map<String, List<String>> possibleRoles = loadRoles();
     
    416424    private static Map<String, List<String>> loadRoles() {
    417425        Map<String, List<String>> result = new HashMap<>();
    418         try {
    419             ClassLoader classLoader = RelContextDialog.class.getClassLoader();
    420             final InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE);
     426        ClassLoader classLoader = RelContextDialog.class.getClassLoader();
     427        try (
     428            InputStream possibleRolesStream = classLoader.getResourceAsStream(POSSIBLE_ROLES_FILE);
    421429            BufferedReader r = new BufferedReader(new InputStreamReader(possibleRolesStream));
     430        ) {
    422431            while( r.ready() ) {
    423432                String line = r.readLine();
     
    431440                }
    432441            }
    433             r.close();
    434442        } 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);
    437445        }
    438446        return result;
     
    466474
    467475        role.getEditor().addActionListener(new ActionListener() {
     476            @Override
    468477            public void actionPerformed( ActionEvent e ) {
    469478                dlg.setVisible(false);
     
    589598        }
    590599
     600        @Override
    591601        public void actionPerformed( ActionEvent e ) {
    592602            String property = e.getActionCommand();
     
    609619        }
    610620
     621        @Override
    611622        public void actionPerformed( ActionEvent e ) {
    612623            if( roleBoxModel.membersRole != null ) {
     
    617628        }
    618629
     630        @Override
    619631        public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    620632            setEnabled(newRelation != null);
    621633        }
    622634    }
    623        
     635
    624636    private class RoleComboBoxModel extends AbstractListModel<String> implements ComboBoxModel<String> {
    625637        private List<String> roles = new ArrayList<>();
     
    704716        }
    705717
     718        @Override
    706719        public int getSize() {
    707720            return roles.size();
    708721        }
    709722
     723        @Override
    710724        public String getElementAt( int index ) {
    711725            return getRole(index);
     
    716730        }
    717731
     732        @Override
    718733        public void setSelectedItem( Object anItem ) {
    719734            int newIndex = anItem == null ? -1 : roles.indexOf(anItem);
     
    724739        }
    725740
     741        @Override
    726742        public Object getSelectedItem() {
    727743            return selectedIndex < 0 || selectedIndex >= getSize() ? null : getRole(selectedIndex);
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/RelContextPlugin.java

    r29535 r30738  
    1111    public RelContextPlugin( PluginInformation info ) {
    1212        super(info);
    13         DefaultNameFormatter.registerFormatHook(new ExtraNameFormatHook());
     13    DefaultNameFormatter.registerFormatHook(new ExtraNameFormatHook());
    1414    }
    1515
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java

    r30737 r30738  
    2828
    2929    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();
    3535    }
    3636
    3737    public CreateMultipolygonAction() {
    38         this(null);
     38    this(null);
    3939    }
    4040
    4141    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);
    5555    }
    5656
    5757    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));
    5959    }
    6060
    6161    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                 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);
     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);
    126126    }
    127127
    128128    @Override
    129129    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    }
    135135    }
    136136
    137137    @Override
    138138    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);
    153153    }
    154154
     
    157157     */
    158158    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                     else
    169                         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    }
    175175    }
    176176
     
    179179     */
    180180    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 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;
     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;
    222222    }
    223223    static public final List<String> DEFAULT_LINEAR_TAGS = Arrays.asList(new String[] {"barrier", "source"});
    224224    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        }));
    227227
    228228    /**
     
    232232     */
    233233    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 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;
     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;
    342342    }
    343343
     
    348348     */
    349349    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             @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;
     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;
    405405    }
    406406}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructPolygonAction.java

    r30737 r30738  
    4242   
    4343    private static final List<String> IRRELEVANT_KEYS = Arrays.asList(new String[] {
    44         "source", "created_by", "note"});
     44    "source", "created_by", "note"});
    4545
    4646    public ReconstructPolygonAction( ChosenRelation rel ) {
    4747        super(tr("Reconstruct polygon"));
    4848        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");
    5050        this.rel = rel;
    5151        rel.addChosenRelationListener(this);
     
    5555    public void actionPerformed( ActionEvent e ) {
    5656        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             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<>();
     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<>();
    8585        Command c = DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(r), true, true);
    8686        if( c == null )
    8787            return;
    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        
     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   
    145145        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);
    148148    }
    149149
    150150    public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    151         setEnabled(isSuitableRelation(newRelation));
     151    setEnabled(isSuitableRelation(newRelation));
    152152    }
    153153   
    154154    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    }
    163163    }
    164164}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java

    r30737 r30738  
    2525
    2626public 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;
    2929    private List<RelationFixer> fixers;
    3030
     
    6767
    6868    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();
    7373    }
    7474
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SplittingMultipolygons.java

    r30737 r30738  
    2424
    2525    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             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;
     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;
    6868    }
    6969   
    7070    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             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;
     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;
    100100    }
    101101
     
    104104     */
    105105    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);
    113113    }
    114114
     
    117117     */
    118118    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);
    123123    }
    124124
     
    131131     */
    132132    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 >= 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;
     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;
    217217    }
    218218
    219219    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);
    221221    }
    222222
     
    225225     */
    226226    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 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;
     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;
    288288    }
    289289
     
    292292     */
    293293    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;
    299299    }
    300300   
     
    303303     */
    304304    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                             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();
     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();
    355355    }
    356356}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java

    r30737 r30738  
    3636
    3737    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));
    4141    }
    4242   
    4343    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             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;
     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;
    6464    }
    6565
     
    6969     */
    7070    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;
    8787    }
    8888
    8989    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    }
    116116    }
    117117   
     
    120120     */
    121121    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 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;
     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;
    185185    }
    186186   
    187187    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         else
    194             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;
    195195    }
    196196   
    197197    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;
    208208    }
    209209
     
    213213     */
    214214    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 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;
     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;
    239239    }
    240240
     
    246246     */
    247247    public static void redistributeSegments( List<TheRing> rings ) {
    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();
     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();
    273273    }
    274274
    275275    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;
    281281    }
    282282
    283283    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    }
    290290    }
    291291   
    292292    public List<Command> getCommands() {
    293         return getCommands(true, null);
     293    return getCommands(true, null);
    294294    }
    295295   
    296296    public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) {
    297         return getCommands(true, relationChangeMap);
     297    return getCommands(true, relationChangeMap);
    298298    }
    299299   
     
    303303     */
    304304    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() ) {
    311311                if( linearTags.contains(key) ) continue;
    312312                if( key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) continue;
    313313                relation.put(key, sourceCopy.get(key));
    314314                sourceCopy.remove(key);
    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;
     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;
    372372    }
    373373   
    374374    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)));
    377377    }
    378378
     
    381381     */
    382382    public Relation getRelation() {
    383         return relation;
     383    return relation;
    384384    }
    385385
    386386    @Override
    387387    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();
    398398    }
    399399
     
    402402     */
    403403    /*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);
    411411    }*/
    412412
     
    415415     */
    416416    /*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);
    421421    }*/
    422422   
    423423    private static void log( String s ) {
    424 //      System.out.println(s);
     424//    System.out.println(s);
    425425    }
    426426   
    427427    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 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         }
     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    }
    594594    }
    595595}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/AssociatedStreetFixer.java

    r30737 r30738  
    1919public class AssociatedStreetFixer extends RelationFixer {
    2020
    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    }
    6124
    6225    @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    }
    7061
    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;
    7370
    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);
    10073
    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        }
    107100
    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;
    109107
    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);
    120109
    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        }
    127120
    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        }
    132127
    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        }
    139132
    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;
    141139
    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??
    145141
    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    }
    156156}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/BoundaryFixer.java

    r28762 r30738  
    1616public class BoundaryFixer extends MultipolygonFixer {
    1717
    18         public BoundaryFixer() {
    19                 super("boundary", "multipolygon");
    20         }
     18    public BoundaryFixer() {
     19        super("boundary", "multipolygon");
     20    }
    2121
    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         }
     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    }
    3131
    32         @Override
    33         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() ) {
    3535            if (m.getType().equals(OsmPrimitiveType.RELATION) && !"subarea".equals(m.getRole())) {
    3636                setWarningMessage(tr("Relation without ''subarea'' role found"));
     
    4343            if (m.getType().equals(OsmPrimitiveType.WAY) && !("outer".equals(m.getRole()) || "inner".equals(m.getRole()))) {
    4444                setWarningMessage(tr("Way without ''inner'' or ''outer'' role found"));
    45                                 return false;
     45                return false;
    4646            }
    4747        }
    48                 clearWarningMessage();
    49                 return true;
    50         }
     48        clearWarningMessage();
     49        return true;
     50    }
    5151
    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         }
     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    }
    6868
    69         private Relation fixBoundaryRoles( Relation source ) {
     69    private Relation fixBoundaryRoles( Relation source ) {
    7070        Relation r = new Relation(source);
    7171        boolean fixed = false;
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/MultipolygonFixer.java

    r30737 r30738  
    2222public class MultipolygonFixer extends RelationFixer {
    2323
    24         public MultipolygonFixer() {
    25                 super("multipolygon");
    26         }
     24    public MultipolygonFixer() {
     25        super("multipolygon");
     26    }
    2727
    28         protected MultipolygonFixer(String...types) {
    29                 super(types);
    30         }
     28    protected MultipolygonFixer(String...types) {
     29        super(types);
     30    }
    3131
    3232
    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         }
     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    }
    4343
    44         @Override
    45         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    }
    4949
    50         /**
     50    /**
    5151     * Basically, created multipolygon from scratch, and if successful, replace roles with new ones.
    5252     */
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/NothingFixer.java

    r28693 r30738  
    99public class NothingFixer extends RelationFixer {
    1010
    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         }
     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    }
    2222
    23         @Override
    24         public Command fixRelation(Relation rel) {
    25                 return null;
    26         }
     23    @Override
     24    public Command fixRelation(Relation rel) {
     25        return null;
     26    }
    2727
    2828}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/relationfix/RelationFixer.java

    r30737 r30738  
    1515public abstract class RelationFixer {
    1616
    17         private List<String> applicableTypes;
    18         private SortAndFixAction sortAndFixAction;
     17    private List<String> applicableTypes;
     18    private SortAndFixAction sortAndFixAction;
    1919
    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         }
     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    }
    3030
    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;
     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;
    4545
    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;
    5050
    51                 return false;
    52         }
     51        return false;
     52    }
    5353
    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);
     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);
    6262
    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);
     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);
    7171
    7272    public void setFixAction(SortAndFixAction sortAndFixAction) {
Note: See TracChangeset for help on using the changeset viewer.