Ignore:
Timestamp:
2016-06-24T09:10:57+02:00 (9 years ago)
Author:
donvip
Message:

checkstyle, update to JOSM 10279

Location:
applications/editors/josm/plugins/reltoolbox/src/relcontext/actions
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/AddRemoveMemberAction.java

    r31662 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    3637    private SortAndFixAction sortAndFix;
    3738
    38     public AddRemoveMemberAction( ChosenRelation rel, SortAndFixAction sortAndFix ) {
     39    public AddRemoveMemberAction(ChosenRelation rel, SortAndFixAction sortAndFix) {
    3940        super(null, "relcontext/addremove", tr("Add/remove members from the chosen relation"),
    4041                Shortcut.registerShortcut("reltoolbox:addremove", tr("Relation Toolbox: {0}", tr("Add/remove members from the chosen relation")),
    41                 KeyEvent.VK_EQUALS, Shortcut.DIRECT), false);
     42                        KeyEvent.VK_EQUALS, Shortcut.DIRECT), false);
    4243        this.rel = rel;
    4344        this.sortAndFix = sortAndFix;
     
    4647    }
    4748
    48     public void actionPerformed( ActionEvent e ) {
    49         if( rel.get() == null )
     49    @Override
     50    public void actionPerformed(ActionEvent e) {
     51        if (rel.get() == null )
    5052            return;
    5153
     
    6365
    6466        // 2. add all new members
    65         for( OsmPrimitive p : toAdd ) {
     67        for (OsmPrimitive p : toAdd) {
    6668            int pos = -1; //p instanceof Way ? findAdjacentMember(p, r) : -1;
    67             if( pos < 0 )
     69            if (pos < 0 ) {
    6870                r.addMember(new RelationMember("", p));
    69             else
     71            } else {
    7072                r.addMember(pos, new RelationMember("", p));
     73            }
    7174        }
    7275
    7376        // 3. check for roles again (temporary)
    7477        Command roleFix = !isBroken && sortAndFix.needsFixing(r) ? sortAndFix.fixRelation(r) : null;
    75         if( roleFix != null )
     78        if (roleFix != null ) {
    7679            roleFix.executeCommand();
     80        }
    7781
    78         if( !r.getMemberPrimitives().equals(rel.get().getMemberPrimitives()) )
     82        if (!r.getMemberPrimitives().equals(rel.get().getMemberPrimitives()) ) {
    7983            Main.main.undoRedo.add(new ChangeCommand(rel.get(), r));
     84        }
    8085    }
    8186
     
    8489     * @see org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel#determineDirection
    8590     */
    86     protected int findAdjacentMember( Way w, Relation r ) {
     91    protected int findAdjacentMember(Way w, Relation r) {
    8792        Node firstNode = w.firstNode();
    8893        Node lastNode = w.lastNode();
    8994
    90         if( firstNode != null && !firstNode.equals(lastNode) ) {
    91             for( int i = 0; i < r.getMembersCount(); i++ ) {
    92                 if( r.getMember(i).getType().equals(OsmPrimitiveType.WAY) ) {
     95        if (firstNode != null && !firstNode.equals(lastNode)) {
     96            for (int i = 0; i < r.getMembersCount(); i++) {
     97                if (r.getMember(i).getType().equals(OsmPrimitiveType.WAY)) {
    9398                    Way rw = (Way)r.getMember(i).getMember();
    9499                    Node firstNodeR = rw.firstNode();
    95100                    Node lastNodeR = rw.lastNode();
    96                     if( firstNode.equals(firstNodeR) || firstNode.equals(lastNodeR) || lastNode.equals(firstNodeR) || lastNode.equals(lastNodeR) )
     101                    if (firstNode.equals(firstNodeR) || firstNode.equals(lastNodeR) || lastNode.equals(firstNodeR) || lastNode.equals(lastNodeR) )
    97102                        return i + 1;
    98103                }
     
    102107    }
    103108
    104     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     109    @Override
     110    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    105111        updateEnabledState();
    106112    }
     
    112118
    113119    @Override
    114     protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) {
     120    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
    115121        updateIcon();
    116         if( rel == null || rel.get() == null || selection == null || selection.isEmpty() ) {
     122        if (rel == null || rel.get() == null || selection == null || selection.isEmpty()) {
    117123            setEnabled(false);
    118124            return;
    119125        }
    120         if( selection.size() == 1 && selection.contains(rel.get()) ) {
     126        if (selection.size() == 1 && selection.contains(rel.get())) {
    121127            setEnabled(false);
    122128            return;
     
    128134        // todo: change icon based on selection
    129135        final int state; // 0=unknown, 1=add, 2=remove, 3=both
    130         if( getCurrentDataSet() == null || getCurrentDataSet().getSelected() == null
    131                 || getCurrentDataSet().getSelected().isEmpty() || rel == null || rel.get() == null )
     136        if (getCurrentDataSet() == null || getCurrentDataSet().getSelected() == null
     137                || getCurrentDataSet().getSelected().isEmpty() || rel == null || rel.get() == null ) {
    132138            state = 0;
    133         else {
     139        } else {
    134140            Collection<OsmPrimitive> toAdd = new ArrayList<>(getCurrentDataSet().getSelected());
    135141            toAdd.remove(rel.get());
    136142            int selectedSize = toAdd.size();
    137             if( selectedSize == 0 )
     143            if (selectedSize == 0 ) {
    138144                state = 0;
    139             else {
     145            } else {
    140146                toAdd.removeAll(rel.get().getMemberPrimitives());
    141                 if( toAdd.isEmpty() )
     147                if (toAdd.isEmpty() ) {
    142148                    state = 2;
    143                 else if( toAdd.size() < selectedSize )
     149                } else if (toAdd.size() < selectedSize ) {
    144150                    state = 3;
    145                 else
     151                } else {
    146152                    state = 1;
     153                }
    147154            }
    148155        }
     
    150157            @Override
    151158            public void run() {
    152 //        String name = state == 0 ? "?" : state == 1 ? "+" : state == 2 ? "-" : "±";
    153 //        putValue(Action.NAME, name);
     159                //        String name = state == 0 ? "?" : state == 1 ? "+" : state == 2 ? "-" : "±";
     160                //        putValue(Action.NAME, name);
    154161                if (state == 0) {
    155 //            putValue(NAME, "?");
     162                    //            putValue(NAME, "?");
    156163                    putValue(LARGE_ICON_KEY, ImageProvider.get("relcontext", "addremove"));
    157164                } else {
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ClearChosenRelationAction.java

    r25695 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
    36import java.awt.event.ActionEvent;
     7
    48import javax.swing.AbstractAction;
    59import javax.swing.Action;
    6 import static org.openstreetmap.josm.tools.I18n.tr;
     10
    711import org.openstreetmap.josm.data.osm.Relation;
    812import org.openstreetmap.josm.tools.ImageProvider;
     13
    914import relcontext.ChosenRelation;
    1015import relcontext.ChosenRelationListener;
     
    1318    private ChosenRelation rel;
    1419
    15     public ClearChosenRelationAction( ChosenRelation rel ) {
     20    public ClearChosenRelationAction(ChosenRelation rel) {
    1621        super();
    17 //        putValue(Action.NAME, "X");
     22        //        putValue(Action.NAME, "X");
    1823        putValue(Action.SMALL_ICON, ImageProvider.get("relcontext", "clear"));
    1924        putValue(Action.SHORT_DESCRIPTION, tr("Clear the chosen relation"));
     
    2328    }
    2429
    25     public void actionPerformed( ActionEvent e ) {
     30    @Override
     31    public void actionPerformed(ActionEvent e) {
    2632        rel.clear();
    2733    }
    2834
    29     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     35    @Override
     36    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3037        setEnabled(newRelation != null);
    3138    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateMultipolygonAction.java

    r30738 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    25
    36import java.awt.Dialog.ModalityType;
    47import java.awt.GridBagLayout;
    5 import static org.openstreetmap.josm.tools.I18n.tr;
    68import java.awt.event.ActionEvent;
    79import java.awt.event.ActionListener;
    810import java.awt.event.KeyEvent;
    9 import java.util.*;
    10 import javax.swing.*;
     11import java.util.ArrayList;
     12import java.util.Arrays;
     13import java.util.Collection;
     14import java.util.HashMap;
     15import java.util.HashSet;
     16import java.util.List;
     17import java.util.Map;
     18import java.util.Set;
     19import java.util.TreeSet;
     20
     21import javax.swing.Box;
     22import javax.swing.JDialog;
     23import javax.swing.JLabel;
     24import javax.swing.JOptionPane;
     25import javax.swing.JPanel;
     26import javax.swing.JTextField;
     27
    1128import org.openstreetmap.josm.Main;
    1229import org.openstreetmap.josm.actions.JosmAction;
    13 import org.openstreetmap.josm.command.*;
    14 import org.openstreetmap.josm.data.osm.*;
     30import org.openstreetmap.josm.command.AddCommand;
     31import org.openstreetmap.josm.command.ChangeCommand;
     32import org.openstreetmap.josm.command.ChangePropertyCommand;
     33import org.openstreetmap.josm.command.Command;
     34import org.openstreetmap.josm.command.SequenceCommand;
     35import org.openstreetmap.josm.data.osm.MultipolygonBuilder;
     36import org.openstreetmap.josm.data.osm.Node;
     37import org.openstreetmap.josm.data.osm.OsmPrimitive;
     38import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     39import org.openstreetmap.josm.data.osm.Relation;
     40import org.openstreetmap.josm.data.osm.RelationMember;
     41import org.openstreetmap.josm.data.osm.Way;
    1542import org.openstreetmap.josm.tools.GBC;
    1643import org.openstreetmap.josm.tools.Shortcut;
     44
    1745import relcontext.ChosenRelation;
    1846
     
    2755    protected ChosenRelation chRel;
    2856
    29     public CreateMultipolygonAction( ChosenRelation chRel ) {
    30     super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"),
    31         Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")),
    32         KeyEvent.VK_A, Shortcut.ALT_CTRL), false);
    33     this.chRel = chRel;
    34     updateEnabledState();
     57    public CreateMultipolygonAction(ChosenRelation chRel) {
     58        super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"),
     59                Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")),
     60                        KeyEvent.VK_A, Shortcut.ALT_CTRL), false);
     61        this.chRel = chRel;
     62        updateEnabledState();
    3563    }
    3664
    3765    public CreateMultipolygonAction() {
    38     this(null);
    39     }
    40 
    41     public static boolean getDefaultPropertyValue( String property ) {
    42     if( property.equals("boundary") )
    43         return false;
    44     else if( property.equals("boundaryways") )
    45         return true;
    46     else if( property.equals("tags") )
    47         return true;
    48     else if( property.equals("alltags") )
    49         return false;
    50     else if( property.equals("single") )
    51         return true;
    52     else if( property.equals("allowsplit") )
    53         return false;
    54     throw new IllegalArgumentException(property);
    55     }
    56 
    57     private boolean getPref( String property ) {
    58     return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));
    59     }
    60 
    61     public void actionPerformed( ActionEvent e ) {
    62     boolean isBoundary = getPref("boundary");
    63     Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();
    64     if( !isBoundary && getPref("tags") ) {
    65         List<Relation> rels = null;
    66         if( getPref("allowsplit") || selectedWays.size() == 1 ) {
    67         if( SplittingMultipolygons.canProcess(selectedWays) )
    68             rels = SplittingMultipolygons.process(getCurrentDataSet().getSelectedWays());
     66        this(null);
     67    }
     68
     69    public static boolean getDefaultPropertyValue(String property) {
     70        if (property.equals("boundary") )
     71            return false;
     72        else if (property.equals("boundaryways") )
     73            return true;
     74        else if (property.equals("tags") )
     75            return true;
     76        else if (property.equals("alltags") )
     77            return false;
     78        else if (property.equals("single") )
     79            return true;
     80        else if (property.equals("allowsplit") )
     81            return false;
     82        throw new IllegalArgumentException(property);
     83    }
     84
     85    private boolean getPref(String property) {
     86        return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));
     87    }
     88
     89    @Override
     90    public void actionPerformed(ActionEvent e) {
     91        boolean isBoundary = getPref("boundary");
     92        Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();
     93        if (!isBoundary && getPref("tags")) {
     94            List<Relation> rels = null;
     95            if (getPref("allowsplit") || selectedWays.size() == 1) {
     96                if (SplittingMultipolygons.canProcess(selectedWays) ) {
     97                    rels = SplittingMultipolygons.process(getCurrentDataSet().getSelectedWays());
     98                }
     99            } else {
     100                if (TheRing.areAllOfThoseRings(selectedWays)) {
     101                    List<Command> commands = new ArrayList<>();
     102                    rels = TheRing.makeManySimpleMultipolygons(getCurrentDataSet().getSelectedWays(), commands);
     103                    if (!commands.isEmpty() ) {
     104                        Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands));
     105                    }
     106                }
     107            }
     108            if (rels != null && !rels.isEmpty()) {
     109                if (chRel != null ) {
     110                    chRel.set(rels.size() == 1 ? rels.get(0) : null);
     111                }
     112                if (rels.size() == 1 ) {
     113                    getCurrentDataSet().setSelected(rels);
     114                } else {
     115                    getCurrentDataSet().clearSelection();
     116                }
     117                return;
     118            }
     119        }
     120
     121        // for now, just copying standard action
     122        MultipolygonBuilder mpc = new MultipolygonBuilder();
     123        String error = mpc.makeFromWays(getCurrentDataSet().getSelectedWays());
     124        if (error != null) {
     125            JOptionPane.showMessageDialog(Main.parent, error);
     126            return;
     127        }
     128        Relation rel = new Relation();
     129        if (isBoundary) {
     130            rel.put("type", "boundary");
     131            rel.put("boundary", "administrative");
    69132        } 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);
     133            rel.put("type", "multipolygon");
     134        }
     135        for (MultipolygonBuilder.JoinedPolygon poly : mpc.outerWays ) {
     136            for (Way w : poly.ways ) {
     137                rel.addMember(new RelationMember("outer", w));
     138            }
     139        }
     140        for (MultipolygonBuilder.JoinedPolygon poly : mpc.innerWays ) {
     141            for (Way w : poly.ways ) {
     142                rel.addMember(new RelationMember("inner", w));
     143            }
     144        }
     145        List<Command> list = removeTagsFromInnerWays(rel);
     146        if (!list.isEmpty() && isBoundary) {
     147            Main.main.undoRedo.add(new SequenceCommand(tr("Move tags from ways to relation"), list));
     148            list = new ArrayList<>();
     149        }
     150        if (isBoundary) {
     151            if (!askForAdminLevelAndName(rel) )
     152                return;
     153            addBoundaryMembers(rel);
     154            if (getPref("boundaryways") ) {
     155                list.addAll(fixWayTagsForBoundary(rel));
     156            }
     157        }
     158        list.add(new AddCommand(rel));
     159        Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));
     160
     161        if (chRel != null ) {
     162            chRel.set(rel);
     163        }
     164
     165        getCurrentDataSet().setSelected(rel);
    126166    }
    127167
    128168    @Override
    129169    protected void updateEnabledState() {
    130     if( getCurrentDataSet() == null ) {
    131         setEnabled(false);
    132     } else {
    133         updateEnabledState(getCurrentDataSet().getSelected());
    134     }
     170        if (getCurrentDataSet() == null) {
     171            setEnabled(false);
     172        } else {
     173            updateEnabledState(getCurrentDataSet().getSelected());
     174        }
    135175    }
    136176
    137177    @Override
    138     protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) {
    139     boolean isEnabled = true;
    140     if( selection == null || selection.isEmpty() )
    141         isEnabled = false;
    142     else {
    143         if( !getPref("boundary") ) {
    144         for( OsmPrimitive p : selection ) {
    145             if( !(p instanceof Way) ) {
     178    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
     179        boolean isEnabled = true;
     180        if (selection == null || selection.isEmpty() ) {
    146181            isEnabled = false;
    147             break;
    148             }
    149         }
    150         }
    151     }
    152     setEnabled(isEnabled);
     182        } else {
     183            if (!getPref("boundary")) {
     184                for (OsmPrimitive p : selection) {
     185                    if (!(p instanceof Way)) {
     186                        isEnabled = false;
     187                        break;
     188                    }
     189                }
     190            }
     191        }
     192        setEnabled(isEnabled);
    153193    }
    154194
     
    156196     * Add selected nodes and relations with corresponding roles.
    157197     */
    158     private void addBoundaryMembers( Relation rel ) {
    159     for( OsmPrimitive p : getCurrentDataSet().getSelected() ) {
    160         String role = null;
    161         if( p.getType().equals(OsmPrimitiveType.RELATION) ) {
    162         role = "subarea";
    163         } else if( p.getType().equals(OsmPrimitiveType.NODE) ) {
    164         Node n = (Node)p;
    165         if( !n.isIncomplete() ) {
    166             if( n.hasKey("place") )
    167             role = "admin_centre";
    168             else
    169             role = "label";
    170         }
    171         }
    172         if( role != null )
    173         rel.addMember(new RelationMember(role, p));
    174     }
     198    private void addBoundaryMembers(Relation rel) {
     199        for (OsmPrimitive p : getCurrentDataSet().getSelected()) {
     200            String role = null;
     201            if (p.getType().equals(OsmPrimitiveType.RELATION)) {
     202                role = "subarea";
     203            } else if (p.getType().equals(OsmPrimitiveType.NODE)) {
     204                Node n = (Node)p;
     205                if (!n.isIncomplete()) {
     206                    if (n.hasKey("place") ) {
     207                        role = "admin_centre";
     208                    } else {
     209                        role = "label";
     210                    }
     211                }
     212            }
     213            if (role != null ) {
     214                rel.addMember(new RelationMember(role, p));
     215            }
     216        }
    175217    }
    176218
     
    178220     * For all untagged ways in relation, add tags boundary and admin_level.
    179221     */
    180     private List<Command> fixWayTagsForBoundary( Relation rel ) {
    181     List<Command> commands = new ArrayList<>();
    182     if( !rel.hasKey("boundary") || !rel.hasKey("admin_level") )
     222    private List<Command> fixWayTagsForBoundary(Relation rel) {
     223        List<Command> commands = new ArrayList<>();
     224        if (!rel.hasKey("boundary") || !rel.hasKey("admin_level") )
     225            return commands;
     226        String adminLevelStr = rel.get("admin_level");
     227        int adminLevel = 0;
     228        try {
     229            adminLevel = Integer.parseInt(adminLevelStr);
     230        } catch(NumberFormatException e) {
     231            return commands;
     232        }
     233        Set<OsmPrimitive> waysBoundary = new HashSet<>();
     234        Set<OsmPrimitive> waysAdminLevel = new HashSet<>();
     235        for (OsmPrimitive p : rel.getMemberPrimitives()) {
     236            if (p instanceof Way) {
     237                int count = 0;
     238                if (p.hasKey("boundary") && p.get("boundary").equals("administrative") ) {
     239                    count++;
     240                }
     241                if (p.hasKey("admin_level") ) {
     242                    count++;
     243                }
     244                if (p.keySet().size() - count == 0) {
     245                    if (!p.hasKey("boundary") ) {
     246                        waysBoundary.add(p);
     247                    }
     248                    if (!p.hasKey("admin_level")) {
     249                        waysAdminLevel.add(p);
     250                    } else {
     251                        try {
     252                            int oldAdminLevel = Integer.parseInt(p.get("admin_level"));
     253                            if (oldAdminLevel > adminLevel ) {
     254                                waysAdminLevel.add(p);
     255                            }
     256                        } catch(NumberFormatException e) {
     257                            waysAdminLevel.add(p); // some garbage, replace it
     258                        }
     259                    }
     260                }
     261            }
     262        }
     263        if (!waysBoundary.isEmpty() ) {
     264            commands.add(new ChangePropertyCommand(waysBoundary, "boundary", "administrative"));
     265        }
     266        if (!waysAdminLevel.isEmpty() ) {
     267            commands.add(new ChangePropertyCommand(waysAdminLevel, "admin_level", adminLevelStr));
     268        }
    183269        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;
    222270    }
    223271    static public final List<String> DEFAULT_LINEAR_TAGS = Arrays.asList(new String[] {"barrier", "source"});
    224272    private static final Set<String> REMOVE_FROM_BOUNDARY_TAGS = new TreeSet<>(Arrays.asList(new String[] {
    225         "boundary", "boundary_type", "type", "admin_level"
    226         }));
     273            "boundary", "boundary_type", "type", "admin_level"
     274    }));
    227275
    228276    /**
     
    231279     * Todo: rewrite it.
    232280     */
    233     private List<Command> removeTagsFromInnerWays( Relation relation ) {
    234     Map<String, String> values = new HashMap<>();
    235 
    236     if( relation.hasKeys() ) {
    237         for( String key : relation.keySet() ) {
    238         values.put(key, relation.get(key));
    239         }
    240     }
    241 
    242     List<Way> innerWays = new ArrayList<>();
    243     List<Way> outerWays = new ArrayList<>();
    244 
    245     Set<String> conflictingKeys = new TreeSet<>();
    246 
    247     for( RelationMember m : relation.getMembers() ) {
    248 
    249         if( m.hasRole() && "inner".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {
    250         innerWays.add(m.getWay());
    251         }
    252 
    253         if( m.hasRole() && "outer".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {
    254         Way way = m.getWay();
    255         outerWays.add(way);
    256         for( String key : way.keySet() ) {
    257             if( !values.containsKey(key) ) { //relation values take 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) )
     281    private List<Command> removeTagsFromInnerWays(Relation relation) {
     282        Map<String, String> values = new HashMap<>();
     283
     284        if (relation.hasKeys()) {
     285            for (String key : relation.keySet()) {
     286                values.put(key, relation.get(key));
     287            }
     288        }
     289
     290        List<Way> innerWays = new ArrayList<>();
     291        List<Way> outerWays = new ArrayList<>();
     292
     293        Set<String> conflictingKeys = new TreeSet<>();
     294
     295        for (RelationMember m : relation.getMembers()) {
     296
     297            if (m.hasRole() && "inner".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys()) {
     298                innerWays.add(m.getWay());
     299            }
     300
     301            if (m.hasRole() && "outer".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys()) {
     302                Way way = m.getWay();
     303                outerWays.add(way);
     304                for (String key : way.keySet()) {
     305                    if (!values.containsKey(key)) { //relation values take precedence
     306                        values.put(key, way.get(key));
     307                    } else if (!relation.hasKey(key) && !values.get(key).equals(way.get(key))) {
     308                        conflictingKeys.add(key);
     309                    }
     310                }
     311            }
     312        }
     313
     314        // filter out empty key conflicts - we need second iteration
     315        boolean isBoundary = getPref("boundary");
     316        if (isBoundary || !getPref("alltags") ) {
     317            for (RelationMember m : relation.getMembers() )
     318                if (m.hasRole() && m.getRole().equals("outer") && m.isWay() ) {
     319                    for (String key : values.keySet() )
     320                        if (!m.getWay().hasKey(key) && !relation.hasKey(key) ) {
     321                            conflictingKeys.add(key);
     322                        }
     323                }
     324        }
     325
     326        for (String key : conflictingKeys ) {
    289327            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;
     328        }
     329
     330        for (String linearTag : Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS) ) {
     331            values.remove(linearTag);
     332        }
     333
     334        if (values.containsKey("natural") && values.get("natural").equals("coastline") ) {
     335            values.remove("natural");
     336        }
     337
     338        String name = values.get("name");
     339        if (isBoundary) {
     340            Set<String> keySet = new TreeSet<>(values.keySet());
     341            for (String key : keySet )
     342                if (!REMOVE_FROM_BOUNDARY_TAGS.contains(key) ) {
     343                    values.remove(key);
     344                }
     345        }
     346
     347        values.put("area", "yes");
     348
     349        List<Command> commands = new ArrayList<>();
     350        boolean moveTags = getPref("tags");
     351
     352        for (String key : values.keySet()) {
     353            List<OsmPrimitive> affectedWays = new ArrayList<>();
     354            String value = values.get(key);
     355
     356            for (Way way : innerWays) {
     357                if (way.hasKey(key) && (isBoundary || value.equals(way.get(key)))) {
     358                    affectedWays.add(way);
     359                }
     360            }
     361
     362            if (moveTags) {
     363                // remove duplicated tags from outer ways
     364                for (Way way : outerWays) {
     365                    if (way.hasKey(key)) {
     366                        affectedWays.add(way);
     367                    }
     368                }
     369            }
     370
     371            if (affectedWays.size() > 0) {
     372                commands.add(new ChangePropertyCommand(affectedWays, key, null));
     373            }
     374        }
     375
     376        if (moveTags) {
     377            // add those tag values to the relation
     378            if (isBoundary ) {
     379                values.put("name", name);
     380            }
     381            boolean fixed = false;
     382            Relation r2 = new Relation(relation);
     383            for (String key : values.keySet()) {
     384                if (!r2.hasKey(key) && !key.equals("area")
     385                        && (!isBoundary || key.equals("admin_level") || key.equals("name"))) {
     386                    if (relation.isNew() ) {
     387                        relation.put(key, values.get(key));
     388                    } else {
     389                        r2.put(key, values.get(key));
     390                    }
     391                    fixed = true;
     392                }
     393            }
     394            if (fixed && !relation.isNew() ) {
     395                commands.add(new ChangeCommand(relation, r2));
     396            }
     397        }
     398
     399        return commands;
    342400    }
    343401
     
    347405     * @return false if user pressed "cancel".
    348406     */
    349     private boolean askForAdminLevelAndName( Relation rel ) {
    350     String relAL = rel.get("admin_level");
    351     String relName = rel.get("name");
    352     if( relAL != null && relName != null )
     407    private boolean askForAdminLevelAndName(Relation rel) {
     408        String relAL = rel.get("admin_level");
     409        String relName = rel.get("name");
     410        if (relAL != null && relName != null )
     411            return true;
     412
     413        JPanel panel = new JPanel(new GridBagLayout());
     414        panel.add(new JLabel(tr("Enter admin level and name for the border relation:")), GBC.eol().insets(0, 0, 0, 5));
     415
     416        final JTextField admin = new JTextField();
     417        admin.setText(relAL != null ? relAL : Main.pref.get(PREF_MULTIPOLY + "lastadmin", ""));
     418        panel.add(new JLabel(tr("Admin level")), GBC.std());
     419        panel.add(Box.createHorizontalStrut(10), GBC.std());
     420        panel.add(admin, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5));
     421
     422        final JTextField name = new JTextField();
     423        if (relName != null ) {
     424            name.setText(relName);
     425        }
     426        panel.add(new JLabel(tr("Name")), GBC.std());
     427        panel.add(Box.createHorizontalStrut(10), GBC.std());
     428        panel.add(name, GBC.eol().fill(GBC.HORIZONTAL));
     429
     430        final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
     431            @Override
     432            public void selectInitialValue() {
     433                admin.requestFocusInWindow();
     434                admin.selectAll();
     435            }
     436        };
     437        final JDialog dlg = optionPane.createDialog(Main.parent, tr("Create a new relation"));
     438        dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
     439
     440        name.addActionListener(new ActionListener() {
     441            @Override
     442            public void actionPerformed(ActionEvent e) {
     443                dlg.setVisible(false);
     444                optionPane.setValue(JOptionPane.OK_OPTION);
     445            }
     446        });
     447
     448        dlg.setVisible(true);
     449
     450        Object answer = optionPane.getValue();
     451        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
     452                || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION))
     453            return false;
     454
     455        String admin_level = admin.getText().trim();
     456        String new_name = name.getText().trim();
     457        if (admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0)))) {
     458            rel.put("admin_level", admin_level);
     459            Main.pref.put(PREF_MULTIPOLY + "lastadmin", admin_level);
     460        }
     461        if (new_name.length() > 0 ) {
     462            rel.put("name", new_name);
     463        }
    353464        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;
    405465    }
    406466}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/CreateRelationAction.java

    r27927 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    25
    36import java.awt.Dialog.ModalityType;
    47import java.awt.GridBagLayout;
    5 import java.util.Collection;
    6 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    7 import static org.openstreetmap.josm.tools.I18n.tr;
    88import java.awt.event.ActionEvent;
    99import java.awt.event.ActionListener;
    1010import java.awt.event.KeyEvent;
    1111import java.util.Arrays;
     12import java.util.Collection;
    1213import java.util.List;
     14
    1315import javax.swing.Box;
    1416import javax.swing.JDialog;
     
    1618import javax.swing.JOptionPane;
    1719import javax.swing.JPanel;
     20
    1821import org.openstreetmap.josm.Main;
    1922import org.openstreetmap.josm.actions.JosmAction;
    2023import org.openstreetmap.josm.command.AddCommand;
     24import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2125import org.openstreetmap.josm.data.osm.Relation;
    2226import org.openstreetmap.josm.data.osm.RelationMember;
     
    2428import org.openstreetmap.josm.tools.GBC;
    2529import org.openstreetmap.josm.tools.Shortcut;
     30
    2631import relcontext.ChosenRelation;
    2732
     
    3641    protected ChosenRelation chRel;
    3742
    38     public CreateRelationAction( ChosenRelation chRel ) {
     43    public CreateRelationAction(ChosenRelation chRel) {
    3944        super(tr("New"), "data/relation", tr("Create a relation from selected objects"),
    4045                Shortcut.registerShortcut("reltoolbox:create", tr("Relation Toolbox: {0}", tr("Create a new relation")),
    41                 KeyEvent.VK_N, Shortcut.ALT_CTRL), false);
     46                        KeyEvent.VK_N, Shortcut.ALT_CTRL), false);
    4247        this.chRel = chRel;
    4348        updateEnabledState();
     
    4853    }
    4954
    50     public void actionPerformed( ActionEvent e ) {
     55    @Override
     56    public void actionPerformed(ActionEvent e) {
    5157        String type = askForType();
    52         if( type == null )
     58        if (type == null )
    5359            return;
    5460
    5561        Relation rel = new Relation();
    56         if( type.length() > 0 )
     62        if (type.length() > 0 ) {
    5763            rel.put("type", type);
    58         for( OsmPrimitive selected : getCurrentDataSet().getSelected() )
     64        }
     65        for (OsmPrimitive selected : getCurrentDataSet().getSelected() ) {
    5966            rel.addMember(new RelationMember("", selected));
     67        }
    6068
    6169        Main.main.undoRedo.add(new AddCommand(rel));
    6270
    63         if( chRel != null ) {
     71        if (chRel != null) {
    6472            chRel.set(rel);
    6573        }
     
    6876    @Override
    6977    protected void updateEnabledState() {
    70         if( getCurrentDataSet() == null ) {
     78        if (getCurrentDataSet() == null) {
    7179            setEnabled(false);
    7280        } else {
     
    7684
    7785    @Override
    78     protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) {
     86    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
    7987        setEnabled(selection != null && !selection.isEmpty());
    8088    }
     
    8290    // Thanks to TagInfo for the list
    8391    private static final List<String> RELATION_TYPES = Arrays.asList(new String[] {
    84         "multipolygon", "boundary", "route", "site", "restriction", "associatedStreet", "public_transport",
    85         "street", "collection", "address", "enforcement", "destination_sign", "route_master", "junction",
    86         "waterway", "bridge", "tunnel", "surveillance"
     92            "multipolygon", "boundary", "route", "site", "restriction", "associatedStreet", "public_transport",
     93            "street", "collection", "address", "enforcement", "destination_sign", "route_master", "junction",
     94            "waterway", "bridge", "tunnel", "surveillance"
    8795    });
    8896
     
    111119
    112120        keys.getEditor().addActionListener(new ActionListener() {
    113             public void actionPerformed( ActionEvent e ) {
     121            @Override
     122            public void actionPerformed(ActionEvent e) {
    114123                dlg.setVisible(false);
    115124                optionPane.setValue(JOptionPane.OK_OPTION);
     
    120129
    121130        Object answer = optionPane.getValue();
    122         if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    123                 || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) {
     131        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
     132                || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION))
    124133            return null;
    125         }
    126134
    127135        String result = keys.getEditor().getItem().toString().trim();
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/DeleteChosenRelationAction.java

    r28813 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
    57import java.util.Collections;
     8
    69import javax.swing.AbstractAction;
     10
    711import org.openstreetmap.josm.Main;
    812import org.openstreetmap.josm.command.Command;
     
    1014import org.openstreetmap.josm.data.osm.Relation;
    1115import org.openstreetmap.josm.tools.ImageProvider;
     16
    1217import relcontext.ChosenRelation;
    1318import relcontext.ChosenRelationListener;
     
    1621    private ChosenRelation rel;
    1722
    18     public DeleteChosenRelationAction( ChosenRelation rel ) {
     23    public DeleteChosenRelationAction(ChosenRelation rel) {
    1924        super(tr("Delete relation"));
    2025        putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
     
    2429    }
    2530
    26     public void actionPerformed( ActionEvent e ) {
     31    @Override
     32    public void actionPerformed(ActionEvent e) {
    2733        Relation r = rel.get();
    2834        rel.clear();
    2935        Command c = DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(r), true, true);
    30         if( c != null )
     36        if (c != null ) {
    3137            Main.main.undoRedo.add(c);
     38        }
    3239    }
    3340
    34     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     41    @Override
     42    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3543        setEnabled(newRelation != null);
    3644    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/DownloadChosenRelationAction.java

    r30737 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
    57import java.util.Collections;
    68import java.util.HashSet;
    79import java.util.Set;
     10
    811import javax.swing.AbstractAction;
     12
    913import org.openstreetmap.josm.Main;
    1014import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    1418import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationTask;
    1519import org.openstreetmap.josm.tools.ImageProvider;
     20
    1621import relcontext.ChosenRelation;
    1722import relcontext.ChosenRelationListener;
     
    1924/**
    2025 * Downloads or updates chosen relation members, depending on completeness.
    21  * 
     26 *
    2227 * @author Zverik
    2328 */
     
    2530    private ChosenRelation rel;
    2631
    27     public DownloadChosenRelationAction( ChosenRelation rel ) {
     32    public DownloadChosenRelationAction(ChosenRelation rel) {
    2833        super();
    29 //        putValue(NAME, "D");
     34        //        putValue(NAME, "D");
    3035        putValue(SMALL_ICON, ImageProvider.get("relcontext", "download"));
    3136        putValue(SHORT_DESCRIPTION, tr("Download incomplete members for the chosen relation"));
     
    3540    }
    3641
    37     public void actionPerformed( ActionEvent e ) {
     42    @Override
     43    public void actionPerformed(ActionEvent e) {
    3844        Relation relation = rel.get();
    39         if( relation == null || relation.isNew() ) return;
     45        if (relation == null || relation.isNew() ) return;
    4046        int total = relation.getMembersCount();
    4147        int incomplete = relation.getIncompleteMembers().size();
    42 //        if( incomplete <= 5 || (incomplete <= 10 && incomplete * 3 < total) )
    43         if( incomplete <= 10 && incomplete * 3 < total )
     48        //        if (incomplete <= 5 || (incomplete <= 10 && incomplete * 3 < total) )
     49        if (incomplete <= 10 && incomplete * 3 < total ) {
    4450            downloadIncomplete(relation);
    45         else
     51        } else {
    4652            downloadMembers(relation);
     53        }
    4754    }
    4855
    49     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     56    @Override
     57    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    5058        boolean incomplete = false;
    51         if( newRelation != null ) {
    52             for( RelationMember m : newRelation.getMembers()) {
    53                 if( m.getMember().isIncomplete() ) {
     59        if (newRelation != null) {
     60            for (RelationMember m : newRelation.getMembers()) {
     61                if (m.getMember().isIncomplete()) {
    5462                    incomplete = true;
    5563                    break;
     
    6068    }
    6169
    62     protected void downloadMembers( Relation rel ) {
    63         if( !rel.isNew() ) {
     70    protected void downloadMembers(Relation rel) {
     71        if (!rel.isNew()) {
    6472            Main.worker.submit(new DownloadRelationTask(Collections.singletonList(rel), Main.main.getEditLayer()));
    6573        }
    6674    }
    6775
    68     protected void downloadIncomplete( Relation rel ) {
    69         if( rel.isNew() ) return;
     76    protected void downloadIncomplete(Relation rel) {
     77        if (rel.isNew() ) return;
    7078        Set<OsmPrimitive> ret = new HashSet<>();
    7179        ret.addAll(rel.getIncompleteMembers());
    72         if( ret.isEmpty() ) return;
     80        if (ret.isEmpty() ) return;
    7381        Main.worker.submit(new DownloadRelationMemberTask(Collections.singletonList(rel), ret, Main.main.getEditLayer()));
    7482    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/DownloadParentsAction.java

    r30737 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    2526/**
    2627 * Downloads parent relations for this relation and all parent objects for its members.
    27  * 
     28 *
    2829 * @author Zverik
    2930 */
     
    3132    private ChosenRelation rel;
    3233
    33     public DownloadParentsAction( ChosenRelation rel ) {
     34    public DownloadParentsAction(ChosenRelation rel) {
    3435        super(tr("Download referrers"));
    3536        putValue(SMALL_ICON, ImageProvider.get("download"));
     
    4041    }
    4142
    42     public void actionPerformed( ActionEvent e ) {
     43    @Override
     44    public void actionPerformed(ActionEvent e) {
    4345        Relation relation = rel.get();
    44         if( relation == null ) return;
     46        if (relation == null ) return;
    4547        List<OsmPrimitive> objects = new ArrayList<>();
    4648        objects.add(relation);
     
    4951    }
    5052
    51     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     53    @Override
     54    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    5255        setEnabled(newRelation != null && Main.main.getEditLayer() != null);
    5356    }
    5457
    55     protected void downloadMembers( Relation rel ) {
    56         if( !rel.isNew() ) {
     58    protected void downloadMembers(Relation rel) {
     59        if (!rel.isNew()) {
    5760            Main.worker.submit(new DownloadRelationTask(Collections.singletonList(rel), Main.main.getEditLayer()));
    5861        }
    5962    }
    6063
    61     protected void downloadIncomplete( Relation rel ) {
    62         if( rel.isNew() ) return;
     64    protected void downloadIncomplete(Relation rel) {
     65        if (rel.isNew() ) return;
    6366        Set<OsmPrimitive> ret = new HashSet<>();
    6467        ret.addAll(rel.getIncompleteMembers());
    65         if( ret.isEmpty() ) return;
     68        if (ret.isEmpty() ) return;
    6669        Main.worker.submit(new DownloadRelationMemberTask(Collections.singletonList(rel), ret, Main.main.getEditLayer()));
    6770    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/DuplicateChosenRelationAction.java

    r26290 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
     7
    58import javax.swing.AbstractAction;
     9
    610import org.openstreetmap.josm.Main;
    711import org.openstreetmap.josm.command.AddCommand;
    812import org.openstreetmap.josm.data.osm.Relation;
    913import org.openstreetmap.josm.tools.ImageProvider;
     14
    1015import relcontext.ChosenRelation;
    1116import relcontext.ChosenRelationListener;
     
    1419    private ChosenRelation rel;
    1520
    16     public DuplicateChosenRelationAction( ChosenRelation rel ) {
     21    public DuplicateChosenRelationAction(ChosenRelation rel) {
    1722        super(tr("Duplicate relation"));
    1823        putValue(SMALL_ICON, ImageProvider.get("duplicate"));
     
    2328    }
    2429
    25     public void actionPerformed( ActionEvent e ) {
     30    @Override
     31    public void actionPerformed(ActionEvent e) {
    2632        Relation r = rel.get();
    2733        Relation copy = new Relation(r, true);
    2834        Main.main.undoRedo.add(new AddCommand(copy));
    2935        rel.set(copy);
    30         if( Main.main.getCurrentDataSet() != null )
     36        if (Main.main.getCurrentDataSet() != null ) {
    3137            Main.main.getCurrentDataSet().setSelected(copy);
     38        }
    3239    }
    3340
    34     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     41    @Override
     42    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3543        setEnabled(newRelation != null);
    3644    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/EditChosenRelationAction.java

    r30145 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
     7
    58import javax.swing.AbstractAction;
     9
    610import org.openstreetmap.josm.Main;
    711import org.openstreetmap.josm.data.osm.Relation;
    812import org.openstreetmap.josm.gui.dialogs.relation.RelationEditor;
    913import org.openstreetmap.josm.tools.ImageProvider;
     14
    1015import relcontext.ChosenRelation;
    1116import relcontext.ChosenRelationListener;
     
    1318/**
    1419 * Opens an editor for chosen relation.
    15  * 
     20 *
    1621 * @author Zverik
    1722 */
     
    1924    private ChosenRelation rel;
    2025
    21     public EditChosenRelationAction( ChosenRelation rel ) {
     26    public EditChosenRelationAction(ChosenRelation rel) {
    2227        super();
    23 //        putValue(NAME, "E");
     28        //        putValue(NAME, "E");
    2429        putValue(SMALL_ICON, ImageProvider.get("dialogs/mappaint", "pencil"));
    2530        putValue(SHORT_DESCRIPTION, tr("Open relation editor for the chosen relation"));
     
    2934    }
    3035
    31     public void actionPerformed( ActionEvent e ) {
     36    @Override
     37    public void actionPerformed(ActionEvent e) {
    3238        Relation relation = rel.get();
    33         if( relation == null ) return;
     39        if (relation == null ) return;
    3440        RelationEditor.getEditor(Main.main.getEditLayer(), relation, null).setVisible(true);
    3541    }
    3642
    37     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     43    @Override
     44    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3845        setEnabled(newRelation != null);
    3946    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/FindRelationAction.java

    r30737 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    25
    36import java.awt.BorderLayout;
    47import java.awt.Dialog.ModalityType;
    58import java.awt.Dimension;
    6 import java.awt.event.*;
    7 import static org.openstreetmap.josm.tools.I18n.tr;
    8 import java.util.*;
     9import java.awt.event.ActionEvent;
     10import java.awt.event.ActionListener;
     11import java.awt.event.KeyAdapter;
     12import java.awt.event.KeyEvent;
     13import java.awt.event.MouseAdapter;
     14import java.awt.event.MouseEvent;
    915import java.util.ArrayList;
    10 import javax.swing.*;
     16import java.util.Collection;
     17import java.util.Collections;
     18import java.util.List;
     19
     20import javax.swing.AbstractListModel;
     21import javax.swing.DefaultListSelectionModel;
     22import javax.swing.JDialog;
     23import javax.swing.JList;
     24import javax.swing.JOptionPane;
     25import javax.swing.JPanel;
     26import javax.swing.JScrollPane;
     27import javax.swing.JTextField;
     28import javax.swing.ListSelectionModel;
     29import javax.swing.SwingUtilities;
     30
    1131import org.openstreetmap.josm.Main;
    1232import org.openstreetmap.josm.actions.JosmAction;
     
    1535import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
    1636import org.openstreetmap.josm.tools.Shortcut;
     37
    1738import relcontext.ChosenRelation;
    1839
     
    2546    protected ChosenRelation chRel;
    2647
    27     public FindRelationAction( ChosenRelation chRel ) {
     48    public FindRelationAction(ChosenRelation chRel) {
    2849        super(tr("Find"), "relcontext/find", tr("Find a relation"),
    2950                Shortcut.registerShortcut("reltoolbox:find", tr("Relation Toolbox: {0}", tr("Find a relation")),
    30                 KeyEvent.VK_F, Shortcut.ALT_CTRL), false);
     51                        KeyEvent.VK_F, Shortcut.ALT_CTRL), false);
    3152        this.chRel = chRel;
    3253    }
    3354
    34     public void actionPerformed( ActionEvent e ) {
     55    @Override
     56    public void actionPerformed(ActionEvent e) {
    3557        JPanel panel = new JPanel(new BorderLayout());
    3658        final JTextField searchField = new JTextField();
     
    5577        relationsList.addMouseListener(new MouseAdapter() {
    5678            @Override
    57             public void mouseClicked( MouseEvent e ) {
    58                 if( e.getClickCount() >= 2 && !relationsList.isSelectionEmpty() ) {
     79            public void mouseClicked(MouseEvent e) {
     80                if (e.getClickCount() >= 2 && !relationsList.isSelectionEmpty()) {
    5981                    dlg.setVisible(false);
    6082                    optionPane.setValue(JOptionPane.OK_OPTION);
     
    6486
    6587        searchField.addActionListener(new ActionListener() {
    66             public void actionPerformed( ActionEvent e ) {
    67                 if( !relationsList.isSelectionEmpty() ) {
     88            @Override
     89            public void actionPerformed(ActionEvent e) {
     90                if (!relationsList.isSelectionEmpty()) {
    6891                    dlg.setVisible(false);
    6992                    optionPane.setValue(JOptionPane.OK_OPTION);
     
    7497        searchField.addKeyListener(new KeyAdapter() {
    7598            @Override
    76             public void keyTyped( KeyEvent e ) {
     99            public void keyTyped(KeyEvent e) {
    77100                SwingUtilities.invokeLater(new Runnable() {
     101                    @Override
    78102                    public void run() {
    79103                        updateRelationData(relationsData, searchField.getText());
     
    83107
    84108            @Override
    85             public void keyPressed( KeyEvent e ) {
    86                 if( shouldForward(e) )
     109            public void keyPressed(KeyEvent e) {
     110                if (shouldForward(e) ) {
    87111                    relationsList.dispatchEvent(e);
    88             }
    89 
    90             @Override
    91             public void keyReleased( KeyEvent e ) {
    92                 if( shouldForward(e) )
     112                }
     113            }
     114
     115            @Override
     116            public void keyReleased(KeyEvent e) {
     117                if (shouldForward(e) ) {
    93118                    relationsList.dispatchEvent(e);
    94             }
    95 
    96             private boolean shouldForward( KeyEvent e ) {
     119                }
     120            }
     121
     122            private boolean shouldForward(KeyEvent e) {
    97123                return e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN
    98124                        || e.getKeyCode() == KeyEvent.VK_PAGE_DOWN || e.getKeyCode() == KeyEvent.VK_PAGE_UP
     
    105131
    106132        Object answer = optionPane.getValue();
    107         if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    108                 || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) {
     133        if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
     134                || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION))
    109135            return;
    110         }
    111 
    112         Relation r = (Relation)relationsList.getSelectedValue();
    113         if( r != null )
     136
     137        Relation r = relationsList.getSelectedValue();
     138        if (r != null ) {
    114139            chRel.set(r);
     140        }
    115141    }
    116142
     
    120146    }
    121147
    122     protected void updateRelationData( FindRelationListModel data, String filter ) {
     148    protected void updateRelationData(FindRelationListModel data, String filter) {
    123149        String[] keywords = filter == null ? new String[0] : filter.split("\\s+");
    124         if( keywords.length > 0 ) {
     150        if (keywords.length > 0) {
    125151            List<String> filteredKeywords = new ArrayList<>(keywords.length);
    126             for( String s : keywords )
    127                 if( s.length() > 0 )
     152            for (String s : keywords )
     153                if (s.length() > 0 ) {
    128154                    filteredKeywords.add(s.trim().toLowerCase());
     155                }
    129156            keywords = filteredKeywords.toArray(new String[0]);
    130157        }
    131158
    132159        System.out.println("keywords.length = " + keywords.length);
    133         for( int i = 0; i < keywords.length; i++ )
     160        for (int i = 0; i < keywords.length; i++ ) {
    134161            System.out.println("keyword["+i+"] = " + keywords[i]);
     162        }
    135163
    136164        List<Relation> relations = new ArrayList<>();
    137         if( getEditLayer() != null ) {
    138             for( Relation r : getEditLayer().data.getRelations() ) {
    139                 if( !r.isDeleted() && r.isVisible() && !r.isIncomplete() ) {
     165        if (getEditLayer() != null) {
     166            for (Relation r : getEditLayer().data.getRelations()) {
     167                if (!r.isDeleted() && r.isVisible() && !r.isIncomplete()) {
    140168                    boolean add = true;
    141                     for( int i = 0; i < keywords.length && add; i++ ) {
     169                    for (int i = 0; i < keywords.length && add; i++) {
    142170                        boolean ok = false;
    143                         if( String.valueOf(r.getPrimitiveId().getUniqueId()).contains(keywords[i]) )
     171                        if (String.valueOf(r.getPrimitiveId().getUniqueId()).contains(keywords[i]) ) {
    144172                            ok = true;
    145                         else {
    146                             for( String key : r.keySet() ) {
    147                                 if( key.contains(keywords[i]) || r.get(key).toLowerCase().contains(keywords[i])
    148                                         || tr(r.get(key)).toLowerCase().contains(keywords[i]) ) {
     173                        } else {
     174                            for (String key : r.keySet()) {
     175                                if (key.contains(keywords[i]) || r.get(key).toLowerCase().contains(keywords[i])
     176                                        || tr(r.get(key)).toLowerCase().contains(keywords[i])) {
    149177                                    ok = true;
    150178                                    break;
     
    152180                            }
    153181                        }
    154                         if( !ok ) add = false;
     182                        if (!ok ) {
     183                            add = false;
     184                        }
    155185                    }
    156                     if( add )
     186                    if (add ) {
    157187                        relations.add(r);
     188                    }
    158189                }
    159190            }
     
    171202        private DefaultListSelectionModel selectionModel;
    172203
    173         public FindRelationListModel( DefaultListSelectionModel selectionModel ) {
     204        public FindRelationListModel(DefaultListSelectionModel selectionModel) {
    174205            super();
    175206            this.selectionModel = selectionModel;
     
    190221
    191222        @Override
    192         public Relation getElementAt( int index ) {
     223        public Relation getElementAt(int index) {
    193224            return relations.get(index);
    194225        }
     
    197228            int selectedIndex = selectionModel.getMinSelectionIndex();
    198229            Relation sel =  selectedIndex < 0 ? null : getElementAt(selectedIndex);
    199            
     230
    200231            this.relations.clear();
    201232            selectionModel.clearSelection();
    202             if( relations != null )
     233            if (relations != null ) {
    203234                this.relations.addAll(relations);
     235            }
    204236            fireIntervalAdded(this, 0, getSize());
    205237
    206             if( sel != null ) {
     238            if (sel != null) {
    207239                selectedIndex = this.relations.indexOf(sel);
    208                 if( selectedIndex >= 0 )
     240                if (selectedIndex >= 0 ) {
    209241                    selectionModel.addSelectionInterval(selectedIndex, selectedIndex);
    210             }
    211             if( selectionModel.isSelectionEmpty() && !this.relations.isEmpty() )
     242                }
     243            }
     244            if (selectionModel.isSelectionEmpty() && !this.relations.isEmpty() ) {
    212245                selectionModel.addSelectionInterval(0, 0);
     246            }
    213247        }
    214248    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/PublicTransportHelper.java

    r30841 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    3 import org.openstreetmap.josm.data.osm.Node;
    44import org.openstreetmap.josm.data.osm.OsmPrimitive;
    55import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    66import org.openstreetmap.josm.data.osm.RelationMember;
    7 import org.openstreetmap.josm.data.osm.Way;
    87
    98/**
     
    2625    public final static String BUS_STOP = "bus_stop";
    2726    public final static String RAILWAY_HALT = "halt";
    28     public final static String RAILWAY_STATION = "station";   
    29    
     27    public final static String RAILWAY_STATION = "station";
     28
    3029    private PublicTransportHelper() {
    3130        // Hide default constructor for utils classes
    32     }       
    33    
     31    }
     32
    3433    public static String getRoleByMember(RelationMember m) {
    3534        if (isMemberStop(m)) return STOP;
     
    3736        return null;
    3837    }
    39    
     38
    4039    public static boolean isMemberStop(RelationMember m) {
    4140        return isNodeStop(m);   // stop is only node
    4241    }
    43    
     42
    4443    public static boolean isMemberPlatform(RelationMember m) {
    4544        return isNodePlatform(m) || isWayPlatform(m);
    4645    }
    47    
     46
    4847    public static boolean isNodeStop(RelationMember m) {
    4948        return isNodeStop(m.getMember());
    5049    }
    51    
     50
    5251    public static boolean isNodeStop(OsmPrimitive p) {
    5352        if (p.getType() == OsmPrimitiveType.NODE && !p.isIncomplete()) {
     
    6362        return false;
    6463    }
    65    
     64
    6665    public static boolean isNodePlatform(RelationMember m) {
    6766        return isNodePlatform(m.getMember());
    6867    }
    69    
     68
    7069    public static boolean isNodePlatform(OsmPrimitive p) {
    7170        if (p.getType() == OsmPrimitiveType.NODE && !p.isIncomplete()) {
     
    8786        return isWayPlatform(m.getMember());
    8887    }
    89    
     88
    9089    public static boolean isWayPlatform(OsmPrimitive p) {
    9190        if (p.getType() == OsmPrimitiveType.WAY && !p.isIncomplete()) {
     
    103102        return false;
    104103    }
    105    
     104
    106105    public static boolean isMemberRouteway(RelationMember m) {
    107106        return isWayRouteway(m.getMember());
    108107    }
    109    
     108
    110109    public static boolean isWayRouteway(OsmPrimitive p) {
    111         if (p.getType() == OsmPrimitiveType.WAY && !p.isIncomplete()) {
     110        if (p.getType() == OsmPrimitiveType.WAY && !p.isIncomplete())
    112111            return p.hasKey(HIGHWAY) || p.hasKey(RAILWAY);
    113         }
    114112        return false;
    115113    }
    116    
     114
    117115    public static String getNameViaStoparea(RelationMember m) {
    118116        return getNameViaStoparea(m.getMember());
    119117    }
    120    
     118
    121119    public static String getNameViaStoparea(OsmPrimitive prim) {
    122120        String result = prim.getName();
     
    125123        for (OsmPrimitive refOp : prim.getReferrers())
    126124            if (refOp.getType() == OsmPrimitiveType.RELATION
    127                 && refOp.hasTag(PUBLIC_TRANSPORT, STOP_AREA)) {
     125            && refOp.hasTag(PUBLIC_TRANSPORT, STOP_AREA)) {
    128126                result = refOp.getName();
    129127                if (result != null) return result;
    130128            }
    131129        return result;
    132     }   
     130    }
    133131}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructPolygonAction.java

    r30738 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    4041public class ReconstructPolygonAction extends AbstractAction implements ChosenRelationListener {
    4142    private ChosenRelation rel;
    42    
     43
    4344    private static final List<String> IRRELEVANT_KEYS = Arrays.asList(new String[] {
    44     "source", "created_by", "note"});
     45            "source", "created_by", "note"});
    4546
    46     public ReconstructPolygonAction( ChosenRelation rel ) {
     47    public ReconstructPolygonAction(ChosenRelation rel) {
    4748        super(tr("Reconstruct polygon"));
    4849        putValue(SMALL_ICON, ImageProvider.get("dialogs", "filter"));
    49     putValue(LONG_DESCRIPTION, "Reconstruct polygon from multipolygon relation");
     50        putValue(LONG_DESCRIPTION, "Reconstruct polygon from multipolygon relation");
    5051        this.rel = rel;
    5152        rel.addChosenRelationListener(this);
     
    5354    }
    5455
    55     public void actionPerformed( ActionEvent e ) {
     56    @Override
     57    public void actionPerformed(ActionEvent e) {
    5658        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<>();
    85         Command c = DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(r), true, true);
    86         if( c == null )
    87             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);
     59        List<Way> ways = new ArrayList<>();
     60        boolean wont = false;
     61        for (RelationMember m : r.getMembers()) {
     62            if (m.isWay() ) {
     63                ways.add(m.getWay());
     64            } else {
     65                wont = true;
    10266            }
    10367        }
    104         List<OsmPrimitive> referrers = w.getReferrers();
    105         for( Iterator<OsmPrimitive> ref1 = relations.iterator(); ref1.hasNext(); )
    106             if( !referrers.contains(ref1.next()) )
    107             ref1.remove();
     68        if (wont) {
     69            JOptionPane.showMessageDialog(Main.parent, tr("Multipolygon must consist only of ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE);
     70            return;
    10871        }
    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;
     72
     73        MultipolygonBuilder mpc = new MultipolygonBuilder();
     74        String error = mpc.makeFromWays(ways);
     75        if (error != null) {
     76            JOptionPane.showMessageDialog(Main.parent, error);
     77            return;
     78        }
     79
     80        if (!mpc.innerWays.isEmpty()) {
     81            JOptionPane.showMessageDialog(Main.parent, tr("Reconstruction of polygons can be done only from outer ways"), tr("Reconstruct polygon"), JOptionPane.ERROR_MESSAGE);
     82            return;
     83        }
     84
     85        rel.clear();
     86        List<Way> newSelection = new ArrayList<>();
     87        List<Command> commands = new ArrayList<>();
     88        Command c = DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(r), true, true);
     89        if (c == null )
     90            return;
     91        commands.add(c);
     92
     93        for (JoinedPolygon p : mpc.outerWays) {
     94            // move all tags from relation and common tags from ways
     95            Map<String, String> tags = p.ways.get(0).getKeys();
     96            List<OsmPrimitive> relations = p.ways.get(0).getReferrers();
     97            Set<String> noTags = new HashSet<>(r.keySet());
     98            for (int i = 1; i < p.ways.size(); i++) {
     99                Way w = p.ways.get(i);
     100                for (String key : w.keySet()) {
     101                    String value = w.get(key);
     102                    if (!noTags.contains(key) && tags.containsKey(key) && !tags.get(key).equals(value)) {
     103                        tags.remove(key);
     104                        noTags.add(key);
     105                    }
    129106                }
    130                 commands.add(new DeleteCommand(w));
     107                List<OsmPrimitive> referrers = w.getReferrers();
     108                for (Iterator<OsmPrimitive> ref1 = relations.iterator(); ref1.hasNext(); )
     109                    if (!referrers.contains(ref1.next()) ) {
     110                        ref1.remove();
     111                    }
    131112            }
     113            tags.putAll(r.getKeys());
     114            tags.remove("type");
     115
     116            // then delete ways that are not relevant (do not take part in other relations of have strange tags)
     117            Way candidateWay = null;
     118            for (Way w : p.ways) {
     119                if (w.getReferrers().equals(relations)) {
     120                    // check tags that remain
     121                    Set<String> keys = new HashSet<>(w.keySet());
     122                    keys.removeAll(tags.keySet());
     123                    keys.removeAll(IRRELEVANT_KEYS);
     124                    if (keys.isEmpty()) {
     125                        if (candidateWay == null ) {
     126                            candidateWay = w;
     127                        } else {
     128                            if (candidateWay.isNew() && !w.isNew()) {
     129                                // prefer ways that are already in the database
     130                                Way tmp = w;
     131                                w = candidateWay;
     132                                candidateWay = tmp;
     133                            }
     134                            commands.add(new DeleteCommand(w));
     135                        }
     136                    }
     137                }
    132138            }
     139
     140            // take the first way, put all nodes into it, making it a closed polygon
     141            Way result = candidateWay == null ? new Way() : new Way(candidateWay);
     142            result.setNodes(p.nodes);
     143            result.addNode(result.firstNode());
     144            result.setKeys(tags);
     145            newSelection.add(candidateWay == null ? result : candidateWay);
     146            commands.add(candidateWay == null ? new AddCommand(result) : new ChangeCommand(candidateWay, result));
    133147        }
    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    
     148
    145149        Main.main.undoRedo.add(new SequenceCommand(tr("Reconstruct polygons from relation {0}",
    146         r.getDisplayName(DefaultNameFormatter.getInstance())), commands));
    147     Main.main.getCurrentDataSet().setSelected(newSelection);
     150                r.getDisplayName(DefaultNameFormatter.getInstance())), commands));
     151        Main.main.getCurrentDataSet().setSelected(newSelection);
    148152    }
    149153
    150     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    151     setEnabled(isSuitableRelation(newRelation));
     154    @Override
     155    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
     156        setEnabled(isSuitableRelation(newRelation));
    152157    }
    153    
    154     private boolean isSuitableRelation( Relation newRelation ) {
    155     if( newRelation == null || !"multipolygon".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0 )
    156         return false;
    157     else {
    158         for( RelationMember m : newRelation.getMembers() )
    159         if( "inner".equals(m.getRole()) )
     158
     159    private boolean isSuitableRelation(Relation newRelation) {
     160        if (newRelation == null || !"multipolygon".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0 )
    160161            return false;
    161         return true;
    162     }
     162        else {
     163            for (RelationMember m : newRelation.getMembers() )
     164                if ("inner".equals(m.getRole()) )
     165                    return false;
     166            return true;
     167        }
    163168    }
    164169}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/ReconstructRouteAction.java

    r30841 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    25
    36import java.awt.event.ActionEvent;
     
    69import java.util.List;
    710import java.util.Map;
     11
    812import javax.swing.AbstractAction;
    9 import static javax.swing.Action.LONG_DESCRIPTION;
    10 import static javax.swing.Action.SMALL_ICON;
     13
    1114import org.openstreetmap.josm.Main;
    1215import org.openstreetmap.josm.command.ChangeCommand;
     
    2124import org.openstreetmap.josm.gui.dialogs.relation.sort.RelationSorter;
    2225import org.openstreetmap.josm.tools.Geometry;
    23 import static org.openstreetmap.josm.tools.I18n.tr;
    2426import org.openstreetmap.josm.tools.ImageProvider;
     27
    2528import relcontext.ChosenRelation;
    2629import relcontext.ChosenRelationListener;
     
    3235public class ReconstructRouteAction  extends AbstractAction implements ChosenRelationListener {
    3336    private final ChosenRelation rel;
    34    
     37
    3538    public ReconstructRouteAction (ChosenRelation rel) {
    3639        super(tr("Reconstruct route"));
     
    4144        setEnabled(isSuitableRelation(rel.get()));
    4245    }
    43    
    44     public void actionPerformed( ActionEvent e ) {
     46
     47    @Override
     48    public void actionPerformed(ActionEvent e) {
    4549        Relation r = rel.get();
    46         Relation recRel = new Relation(r);       
     50        Relation recRel = new Relation(r);
    4751        recRel.removeMembersFor(recRel.getMemberPrimitives());
    48        
     52
    4953        Map<OsmPrimitive, RelationMember> stopMembers = new LinkedHashMap<>();
    5054        Map<String, List<RelationMember>> platformMembers = new LinkedHashMap<>();
     
    5256        List<RelationMember> routeMembers = new ArrayList<>();
    5357        List<RelationMember> wtfMembers = new ArrayList<>();
    54        
     58
    5559        int mCount = r.getMembersCount();
    5660        for (int i = 0; i < mCount; i++) {
     
    5862            if (PublicTransportHelper.isMemberStop(m)) {
    5963                RelationMember rm = new RelationMember(
    60                         m.hasRole() ? m.getRole() : PublicTransportHelper.STOP, 
    61                         m.getMember());
     64                        m.hasRole() ? m.getRole() : PublicTransportHelper.STOP,
     65                                m.getMember());
    6266                stopMembers.put(rm.getMember(), rm);
    6367            }
    6468            else if (PublicTransportHelper.isMemberPlatform(m)) {
    6569                RelationMember rm = new RelationMember(
    66                         m.hasRole() ? m.getRole() : PublicTransportHelper.PLATFORM, 
    67                         m.getMember());
     70                        m.hasRole() ? m.getRole() : PublicTransportHelper.PLATFORM,
     71                                m.getMember());
    6872                String platformName = PublicTransportHelper.getNameViaStoparea(rm);
    69                 if (platformName == null) platformName = "";
    70                 if (platformMembers.containsKey(platformName)) platformMembers.get(platformName).add(rm);
    71                 else {
     73                if (platformName == null) {
     74                    platformName = "";
     75                }
     76                if (platformMembers.containsKey(platformName)) {
     77                    platformMembers.get(platformName).add(rm);
     78                } else {
    7279                    List<RelationMember> nList = new ArrayList<>();
    7380                    nList.add(rm);
    7481                    platformMembers.put(platformName, nList);
    75                 }               
    76             }
    77             else if (PublicTransportHelper.isMemberRouteway(m)) routeMembers.add(new RelationMember(m));
    78             else wtfMembers.add(new RelationMember(m));
    79         }
    80        
     82                }
     83            }
     84            else if (PublicTransportHelper.isMemberRouteway(m)) {
     85                routeMembers.add(new RelationMember(m));
     86            } else {
     87                wtfMembers.add(new RelationMember(m));
     88            }
     89        }
     90
    8191        routeMembers = RelationSorter.sortMembersByConnectivity(routeMembers);
    82        
     92
    8393        Node lastNode = null;
    8494        for (int rIndex = 0; rIndex < routeMembers.size(); rIndex++) {
     
    91101                        dirForward = true;
    92102                        lastNode = w.lastNode();
    93                     } else lastNode = w.firstNode();
     103                    } else {
     104                        lastNode = w.firstNode();
     105                    }
    94106                } // else one segment - direction unknown
    95107            } else {
    96                 if (lastNode.equals(w.firstNode())) { dirForward = true; lastNode = w.lastNode(); }
    97                 else lastNode = w.firstNode();
     108                if (lastNode.equals(w.firstNode())) { dirForward = true; lastNode = w.lastNode(); } else {
     109                    lastNode = w.firstNode();
     110                }
    98111            }
    99112            final int wayNodeBeginIndex = (dirForward ? 0 : w.getNodesCount() - 1);
    100113            final int wayNodeEndIndex = (dirForward ? w.getNodesCount() - 1 : 0);
    101114            final int increment = (dirForward ? 1 : -1);
    102             for(int nIndex = wayNodeBeginIndex;
     115            for (int nIndex = wayNodeBeginIndex;
    103116                    nIndex != wayNodeEndIndex;
    104117                    nIndex += increment) {
     
    109122                        stopMembers.remove(refNode);
    110123                        String stopName = PublicTransportHelper.getNameViaStoparea(refNode);
    111                         if (stopName == null) stopName = "";
     124                        if (stopName == null) {
     125                            stopName = "";
     126                        }
    112127                        boolean existsPlatform = platformMembers.containsKey(stopName);
    113128                        if (!existsPlatform) { stopName = ""; } // find of the nameless
     
    118133                                lMember.remove(0);
    119134                            } else {
    120                                 // choose closest                               
     135                                // choose closest
    121136                                RelationMember candidat = getClosestPlatform(lMember, refNode);
    122137                                if (candidat != null) {
     
    125140                                }
    126141                            }
    127                             if (lMember.isEmpty()) platformMembers.remove(stopName);                           
     142                            if (lMember.isEmpty()) {
     143                                platformMembers.remove(stopName);
     144                            }
    128145                        }
    129146                    }
     
    131148            }
    132149        }
    133        
     150
    134151        for (RelationMember stop : stopMembers.values()) {
    135152            recRel.addMember(stop);
     
    137154            boolean existsPlatform = platformMembers.containsKey(stopName);
    138155            if (!existsPlatform) { stopName = ""; } // find of the nameless
    139             if (existsPlatform || platformMembers.containsKey(stopName)) {           
     156            if (existsPlatform || platformMembers.containsKey(stopName)) {
    140157                List<RelationMember> lMember = platformMembers.get(stopName);
    141158                if (lMember.size() == 1) {
     
    143160                    lMember.remove(0);
    144161                } else {
    145                     // choose closest                               
     162                    // choose closest
    146163                    RelationMember candidat = getClosestPlatform(lMember, stop.getNode());
    147164                    if (candidat != null) {
     
    150167                    }
    151168                }
    152                 if (lMember.isEmpty()) platformMembers.remove(stopName);                           
    153             }
    154         }
    155        
    156         for (List<RelationMember> lPlatforms : platformMembers.values())
    157             for (RelationMember platform : lPlatforms)
     169                if (lMember.isEmpty()) {
     170                    platformMembers.remove(stopName);
     171                }
     172            }
     173        }
     174
     175        for (List<RelationMember> lPlatforms : platformMembers.values()) {
     176            for (RelationMember platform : lPlatforms) {
    158177                recRel.addMember(platform);
    159        
    160         for (RelationMember route : routeMembers)
     178            }
     179        }
     180
     181        for (RelationMember route : routeMembers) {
    161182            recRel.addMember(route);
    162         for (RelationMember wtf : wtfMembers)
    163             recRel.addMember(wtf);       
     183        }
     184        for (RelationMember wtf : wtfMembers) {
     185            recRel.addMember(wtf);
     186        }
    164187        Command command = new ChangeCommand(r, recRel);
    165188        Main.main.undoRedo.add(command);
    166189    }
    167    
    168     private static final double maxSqrDistBetweenStopAndPlatform = 2000; // ~ 26m   
     190
     191    private static final double maxSqrDistBetweenStopAndPlatform = 2000; // ~ 26m
    169192    private RelationMember getClosestPlatform(List<RelationMember> members, Node stop) {
    170193        if (stop == null || members.isEmpty()) return null;
     
    182205                Way way = member.getWay();
    183206                EastNorth closest = Geometry.closestPointToSegment(
    184                                 way.firstNode().getEastNorth(), 
    185                                 way.lastNode().getEastNorth(), 
    186                                 stop.getEastNorth()
    187                 );
     207                        way.firstNode().getEastNorth(),
     208                        way.lastNode().getEastNorth(),
     209                        stop.getEastNorth()
     210                        );
    188211                double sqrDist = stop.getEastNorth().distanceSq(closest);
    189212                if (sqrDist < maxDist) {
     
    195218        return result;
    196219    }
    197  
    198     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    199         setEnabled(isSuitableRelation(newRelation));
    200     }   
    201    
     220
     221    @Override
     222    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
     223        setEnabled(isSuitableRelation(newRelation));
     224    }
     225
    202226    private boolean isSuitableRelation (Relation newRelation) {
    203227        return !(newRelation == null || !"route".equals(newRelation.get("type")) || newRelation.getMembersCount() == 0);
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/RelationHelpAction.java

    r30737 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
    57import java.net.HttpURLConnection;
     
    810import java.util.ArrayList;
    911import java.util.List;
     12
    1013import javax.swing.AbstractAction;
     14
    1115import org.openstreetmap.josm.Main;
    1216import org.openstreetmap.josm.data.osm.Relation;
     
    1418import org.openstreetmap.josm.tools.LanguageInfo;
    1519import org.openstreetmap.josm.tools.OpenBrowser;
     20
    1621import relcontext.ChosenRelation;
    1722import relcontext.ChosenRelationListener;
     
    2025    private ChosenRelation rel;
    2126
    22     public RelationHelpAction( ChosenRelation rel ) {
     27    public RelationHelpAction(ChosenRelation rel) {
    2328        super();
    2429        putValue(NAME, tr("Open relation wiki page"));
     
    3035    }
    3136
    32     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     37    @Override
     38    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3339        setEnabled(newRelation != null);
    3440    }
     
    3743     * Copypasted from {@link org.openstreetmap.josm.gui.dialogs.properties.PropertiesDialog.HelpAction}.
    3844     */
    39     public void actionPerformed( ActionEvent e ) {
    40         if( rel.get() == null )
     45    @Override
     46    public void actionPerformed(ActionEvent e) {
     47        if (rel.get() == null )
    4148            return;
    4249        try {
     
    5562
    5663            Main.worker.execute(new Runnable(){
     64                @Override
    5765                public void run() {
    5866                    try {
     
    7381                                        .replace("=", "%3D") /* do not URLencode whole string! */
    7482                                        .replaceFirst("/wiki/", "/w/index.php?redirect=no&title=")
    75                                 ).toURL().openConnection();
     83                                        ).toURL().openConnection();
    7684                                conn.setConnectTimeout(5000);
    7785
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SelectInRelationPanelAction.java

    r25711 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
     7
    58import javax.swing.AbstractAction;
     9
    610import org.openstreetmap.josm.Main;
    711import org.openstreetmap.josm.data.osm.Relation;
    812import org.openstreetmap.josm.tools.ImageProvider;
     13
    914import relcontext.ChosenRelation;
    1015import relcontext.ChosenRelationListener;
     
    1318    private ChosenRelation rel;
    1419
    15     public SelectInRelationPanelAction( ChosenRelation rel ) {
     20    public SelectInRelationPanelAction(ChosenRelation rel) {
    1621        super();
    1722        putValue(NAME, tr("Select in relation list"));
     
    2328    }
    2429
    25     public void actionPerformed( ActionEvent e ) {
    26         if( rel.get() != null ) {
     30    @Override
     31    public void actionPerformed(ActionEvent e) {
     32        if (rel.get() != null) {
    2733            Main.map.relationListDialog.selectRelation(rel.get());
    2834            Main.map.relationListDialog.unfurlDialog();
     
    3036    }
    3137
    32     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     38    @Override
     39    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    3340        setEnabled(newRelation != null);
    3441    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SelectMembersAction.java

    r30145 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
     7
    58import javax.swing.AbstractAction;
     9
    610import org.openstreetmap.josm.Main;
    711import org.openstreetmap.josm.data.osm.Relation;
    812import org.openstreetmap.josm.tools.ImageProvider;
     13
    914import relcontext.ChosenRelation;
    1015import relcontext.ChosenRelationListener;
     
    1318    private ChosenRelation rel;
    1419
    15     public SelectMembersAction( ChosenRelation rel ) {
     20    public SelectMembersAction(ChosenRelation rel) {
    1621        super(tr("Select members"));
    1722        putValue(SMALL_ICON, ImageProvider.get("selectall"));
     
    2126    }
    2227
    23     public void actionPerformed( ActionEvent e ) {
     28    @Override
     29    public void actionPerformed(ActionEvent e) {
    2430        Main.main.getEditLayer().data.setSelected(rel.get() == null ? null : rel.get().getMemberPrimitives());
    2531    }
    2632
    27     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     33    @Override
     34    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    2835        setEnabled(newRelation != null);
    2936    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SelectRelationAction.java

    r30145 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
    34import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.event.ActionEvent;
     7
    58import javax.swing.AbstractAction;
     9
    610import org.openstreetmap.josm.Main;
    711import org.openstreetmap.josm.data.osm.Relation;
    812import org.openstreetmap.josm.tools.ImageProvider;
     13
    914import relcontext.ChosenRelation;
    1015import relcontext.ChosenRelationListener;
     
    1318    private ChosenRelation rel;
    1419
    15     public SelectRelationAction( ChosenRelation rel ) {
     20    public SelectRelationAction(ChosenRelation rel) {
    1621        super(tr("Select relation"));
    1722        putValue(SHORT_DESCRIPTION, tr("Select relation in main selection."));
     
    2227    }
    2328
    24     public void actionPerformed( ActionEvent e ) {
     29    @Override
     30    public void actionPerformed(ActionEvent e) {
    2531        Main.main.getEditLayer().data.setSelected(rel.get() == null ? null : rel.get());
    2632    }
    2733
    28     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
     34    @Override
     35    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
    2936        setEnabled(newRelation != null);
    3037    }
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SortAndFixAction.java

    r30841 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    3031    private List<RelationFixer> fixers;
    3132
    32     public SortAndFixAction( ChosenRelation rel ) {
     33    public SortAndFixAction(ChosenRelation rel) {
    3334        super();
    34 //        putValue(Action.NAME, "AZ");
     35        //        putValue(Action.NAME, "AZ");
    3536        putValue(Action.SMALL_ICON, ImageProvider.get("data", "warning"));
    3637        putValue(Action.SHORT_DESCRIPTION, tr("Fix roles of the chosen relation members"));
     
    4748        fixers.add(new PublicTransportFixer()); //public_transport
    4849
    49         for(RelationFixer fix : fixers) {
     50        for (RelationFixer fix : fixers) {
    5051            fix.setFixAction(this);
    5152        }
     
    5354
    5455    @Override
    55     public void actionPerformed( ActionEvent e ) {
     56    public void actionPerformed(ActionEvent e) {
    5657        Command c = fixRelation(rel.get());
    57         if( c != null )
     58        if (c != null ) {
    5859            Main.main.undoRedo.add(c);
     60        }
    5961    }
    6062
    6163    @Override
    62     public void chosenRelationChanged( Relation oldRelation, Relation newRelation ) {
    63         setEnabled(newRelation != null && needsFixing( newRelation));
     64    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
     65        setEnabled(newRelation != null && needsFixing(newRelation));
    6466    }
    6567
    66     public boolean needsFixing( Relation rel ) {
     68    public boolean needsFixing(Relation rel) {
    6769        return !isIncomplete(rel) && !getFixer(rel).isRelationGood(rel);
    6870    }
    6971
    70     private RelationFixer getFixer( Relation rel ) {
    71         for(RelationFixer fixer : fixers)
     72    private RelationFixer getFixer(Relation rel) {
     73        for (RelationFixer fixer : fixers)
    7274            if (fixer.isFixerApplicable(rel))
    7375                return fixer;
     
    7577    }
    7678
    77     public Command fixRelation( Relation rel ) {
     79    public Command fixRelation(Relation rel) {
    7880        return getFixer(rel).fixRelation(rel);
    7981    }
    8082
    81     protected static boolean isIncomplete( Relation r ) {
    82         if( r == null || r.isIncomplete() || r.isDeleted() )
     83    protected static boolean isIncomplete(Relation r) {
     84        if (r == null || r.isIncomplete() || r.isDeleted() )
    8385            return true;
    84         for( RelationMember m : r.getMembers())
    85             if( m.getMember().isIncomplete() )
     86        for (RelationMember m : r.getMembers())
     87            if (m.getMember().isIncomplete() )
    8688                return true;
    8789        return false;
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/SplittingMultipolygons.java

    r30738 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
    36import java.awt.geom.Area;
    4 
    5 import static org.openstreetmap.josm.tools.I18n.tr;
    6 
    7 import java.util.*;
     7import java.util.ArrayList;
     8import java.util.Collection;
     9import java.util.Collections;
     10import java.util.HashMap;
     11import java.util.Iterator;
     12import java.util.List;
     13import java.util.Map;
    814
    915import org.openstreetmap.josm.Main;
    10 import org.openstreetmap.josm.command.*;
     16import org.openstreetmap.josm.command.AddCommand;
     17import org.openstreetmap.josm.command.ChangeCommand;
     18import org.openstreetmap.josm.command.Command;
     19import org.openstreetmap.josm.command.SequenceCommand;
    1120import org.openstreetmap.josm.data.coor.EastNorth;
    1221import org.openstreetmap.josm.data.coor.LatLon;
    13 import org.openstreetmap.josm.data.osm.*;
     22import org.openstreetmap.josm.data.osm.Node;
     23import org.openstreetmap.josm.data.osm.OsmPrimitive;
     24import org.openstreetmap.josm.data.osm.Relation;
     25import org.openstreetmap.josm.data.osm.RelationMember;
     26import org.openstreetmap.josm.data.osm.Way;
    1427import org.openstreetmap.josm.gui.DefaultNameFormatter;
    1528import org.openstreetmap.josm.tools.Geometry;
     
    2336    private static final String PREF_MULTIPOLY = "reltoolbox.multipolygon.";
    2437
    25     public static boolean canProcess( Collection<Way> ways ) {
    26     List<Way> rings = new ArrayList<>();
    27     List<Way> arcs = new ArrayList<>();
    28     Area a = Main.main.getCurrentDataSet().getDataSourceArea();
    29     for( Way way : ways ) {
    30         if( way.isDeleted() )
    31         return false;
    32         for( Node n : way.getNodes() ) {
    33             LatLon ll = n.getCoor();
    34             if( n.isIncomplete() || (a != null && !a.contains(ll.getX(), ll.getY())) )
     38    public static boolean canProcess(Collection<Way> ways) {
     39        List<Way> rings = new ArrayList<>();
     40        List<Way> arcs = new ArrayList<>();
     41        Area a = Main.main.getCurrentDataSet().getDataSourceArea();
     42        for (Way way : ways) {
     43            if (way.isDeleted() )
    3544                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 )
     45            for (Node n : way.getNodes()) {
     46                LatLon ll = n.getCoor();
     47                if (n.isIncomplete() || (a != null && !a.contains(ll.getX(), ll.getY())) )
     48                    return false;
     49            }
     50            if (way.isClosed() ) {
     51                rings.add(way);
     52            } else {
     53                arcs.add(way);
     54            }
     55        }
     56
     57        // If there are more that one segment, check that they touch rings
     58        if (arcs.size() > 1) {
     59            for (Way segment : arcs) {
     60                boolean found = false;
     61                for (Way ring : rings )
     62                    if (ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode()) ) {
     63                        found = true;
     64                    }
     65                if (!found )
     66                    return false;
     67            }
     68        }
     69
     70        if (rings.isEmpty() && arcs.isEmpty() )
    5171            return false;
    52         }
    53     }
    54 
    55     if( rings.isEmpty() && arcs.isEmpty() )
    56         return false;
    57 
    58     // check for non-containment of rings
    59     for( int i = 0; i < rings.size() - 1; i++ ) {
    60         for( int j = i + 1; j < rings.size(); j++ ) {
    61         PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
    62         if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
    63             return false;
    64         }
    65     }
    66 
    67     return true;
    68     }
    69    
    70     public static List<Relation> process( Collection<Way> selectedWays ) {
    71 //    System.out.println("---------------------------------------");
    72     List<Relation> result = new ArrayList<>();
    73     List<Way> rings = new ArrayList<>();
    74     List<Way> arcs = new ArrayList<>();
    75     for( Way way : selectedWays ) {
    76         if( way.isClosed() )
    77         rings.add(way);
    78         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;
     72
     73        // check for non-containment of rings
     74        for (int i = 0; i < rings.size() - 1; i++) {
     75            for (int j = i + 1; j < rings.size(); j++) {
     76                PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
     77                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
     78                    return false;
     79            }
     80        }
     81
     82        return true;
     83    }
     84
     85    public static List<Relation> process(Collection<Way> selectedWays) {
     86        //    System.out.println("---------------------------------------");
     87        List<Relation> result = new ArrayList<>();
     88        List<Way> rings = new ArrayList<>();
     89        List<Way> arcs = new ArrayList<>();
     90        for (Way way : selectedWays) {
     91            if (way.isClosed() ) {
     92                rings.add(way);
     93            } else {
     94                arcs.add(way);
     95            }
     96        }
     97
     98        for (Way ring : rings) {
     99            List<Command> commands = new ArrayList<>();
     100            Relation newRelation = SplittingMultipolygons.attachRingToNeighbours(ring, commands);
     101            if (newRelation != null && !commands.isEmpty()) {
     102                Main.main.undoRedo.add(commands.get(0));
     103                result.add(newRelation);
     104            }
     105        }
     106
     107        for (Way arc : arcs) {
     108            List<Command> commands = new ArrayList<>();
     109            Relation newRelation = SplittingMultipolygons.tryToCloseOneWay(arc, commands);
     110            if (newRelation != null && !commands.isEmpty()) {
     111                Main.main.undoRedo.add(commands.get(0));
     112                result.add(newRelation);
     113            }
     114        }
     115        return result;
    100116    }
    101117
     
    103119     * Appends "append" to "base" so the closed polygon forms.
    104120     */
    105     private static void closePolygon( List<Node> base, List<Node> append ) {
    106     if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {
    107         List<Node> ap2 = new ArrayList<>(append);
    108         Collections.reverse(ap2);
    109         append = ap2;
    110     }
    111     base.remove(base.size() - 1);
    112     base.addAll(append);
     121    private static void closePolygon(List<Node> base, List<Node> append) {
     122        if (append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1))) {
     123            List<Node> ap2 = new ArrayList<>(append);
     124            Collections.reverse(ap2);
     125            append = ap2;
     126        }
     127        base.remove(base.size() - 1);
     128        base.addAll(append);
    113129    }
    114130
     
    116132     * Checks if a middle point between two nodes is inside a polygon. Useful to check if the way is inside.
    117133     */
    118     private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) {
    119     EastNorth en1 = n1.getEastNorth();
    120     EastNorth en2 = n2.getEastNorth();
    121     Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));
    122     return Geometry.nodeInsidePolygon(testNode, polygon);
     134    private static boolean segmentInsidePolygon(Node n1, Node n2, List<Node> polygon) {
     135        EastNorth en1 = n1.getEastNorth();
     136        EastNorth en2 = n2.getEastNorth();
     137        Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));
     138        return Geometry.nodeInsidePolygon(testNode, polygon);
    123139    }
    124140
     
    130146     * @return Newly created ways. <b>Warning:</b> if commands is no not, newWays contains {@code w}.
    131147     */
    132     public static List<Way> splitWay( Way w, Node n1, Node n2, List<Command> commands ) {
    133     List<Node> nodes = new ArrayList<>(w.getNodes());
    134     if( w.isClosed() )
    135         nodes.remove(nodes.size() - 1);
    136     int index1 = nodes.indexOf(n1);
    137     int index2 = n2 == null ? -1 : nodes.indexOf(n2);
    138     if( index1 > index2 ) {
    139         int tmp = index1;
    140         index1 = index2;
    141         index2 = tmp;
    142     }
    143     // right now index2 >= 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) ) {
     148    public static List<Way> splitWay(Way w, Node n1, Node n2, List<Command> commands) {
     149        List<Node> nodes = new ArrayList<>(w.getNodes());
     150        if (w.isClosed() ) {
     151            nodes.remove(nodes.size() - 1);
     152        }
     153        int index1 = nodes.indexOf(n1);
     154        int index2 = n2 == null ? -1 : nodes.indexOf(n2);
     155        if (index1 > index2) {
     156            int tmp = index1;
     157            index1 = index2;
     158            index2 = tmp;
     159        }
     160        // right now index2 >= index1
     161        if (index2 < 1 || index1 >= w.getNodesCount() - 1 || index2 >= w.getNodesCount() )
     162            return Collections.emptyList();
     163        if (w.isClosed() && (index1 < 0 || index1 == index2 || index1 + w.getNodesCount() == index2) )
     164            return Collections.emptyList();
     165
     166        // todo: download parent relations!
     167
     168        // make a list of segments
     169        List<List<Node>> chunks = new ArrayList<>(2);
     170        List<Node> chunk = new ArrayList<>();
     171        for (int i = 0; i < nodes.size(); i++) {
     172            chunk.add(nodes.get(i));
     173            if ((w.isClosed() || chunk.size() > 1) && (i == index1 || i == index2)) {
     174                chunks.add(chunk);
     175                chunk = new ArrayList<>();
     176                chunk.add(nodes.get(i));
     177            }
     178        }
    157179        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 )
     180
     181        // for closed way ignore the way boundary
     182        if (w.isClosed()) {
     183            chunks.get(chunks.size() - 1).addAll(chunks.get(0));
     184            chunks.remove(0);
     185        } else if (chunks.get(chunks.size() - 1).size() < 2 ) {
     186            chunks.remove(chunks.size() - 1);
     187        }
     188
     189        // todo remove debug: show chunks array contents
     190        /*for (List<Node> c1 : chunks) {
     191    for (Node cn1 : c1 )
    174192    System.out.print(cn1.getId() + ",");
    175193    System.out.println();
    176194    }*/
    177195
    178     // build a map of referencing relations
    179     Map<Relation, Integer> references = new HashMap<>();
    180     List<Command> relationCommands = new ArrayList<>();
    181     for( OsmPrimitive p : w.getReferrers() ) {
    182         if( p instanceof Relation ) {
    183         Relation rel = commands == null ? (Relation)p : new Relation((Relation)p);
    184         if( commands != null )
    185             relationCommands.add(new ChangeCommand((Relation)p, rel));
    186         for( int i = 0; i < rel.getMembersCount(); i++ )
    187             if( rel.getMember(i).getMember().equals(w) )
    188             references.put(rel, Integer.valueOf(i));
    189         }
    190     }
    191 
    192     // build ways
    193     List<Way> result = new ArrayList<>();
    194     Way updatedWay = commands == null ? w : new Way(w);
    195     updatedWay.setNodes(chunks.get(0));
    196     if( commands != null ) {
    197         commands.add(new ChangeCommand(w, updatedWay));
    198         result.add(updatedWay);
    199     }
    200 
    201     for( int i = 1; i < chunks.size(); i++ ) {
    202         List<Node> achunk = chunks.get(i);
    203         Way newWay = new Way();
    204         newWay.setKeys(w.getKeys());
    205         result.add(newWay);
    206         for( Relation rel : references.keySet() ) {
    207         int relIndex = references.get(rel);
    208         rel.addMember(relIndex + 1, new RelationMember(rel.getMember(relIndex).getRole(), newWay));
    209         }
    210         newWay.setNodes(achunk);
    211         if( commands != null )
    212         commands.add(new AddCommand(newWay));
    213     }
    214     if( commands != null )
    215         commands.addAll(relationCommands);
    216     return result;
    217     }
    218 
    219     public static List<Way> splitWay( Way w, Node n1, Node n2 ) {
    220     return splitWay(w, n1, n2, null);
     196        // build a map of referencing relations
     197        Map<Relation, Integer> references = new HashMap<>();
     198        List<Command> relationCommands = new ArrayList<>();
     199        for (OsmPrimitive p : w.getReferrers()) {
     200            if (p instanceof Relation) {
     201                Relation rel = commands == null ? (Relation)p : new Relation((Relation)p);
     202                if (commands != null ) {
     203                    relationCommands.add(new ChangeCommand(p, rel));
     204                }
     205                for (int i = 0; i < rel.getMembersCount(); i++ )
     206                    if (rel.getMember(i).getMember().equals(w) ) {
     207                        references.put(rel, Integer.valueOf(i));
     208                    }
     209            }
     210        }
     211
     212        // build ways
     213        List<Way> result = new ArrayList<>();
     214        Way updatedWay = commands == null ? w : new Way(w);
     215        updatedWay.setNodes(chunks.get(0));
     216        if (commands != null) {
     217            commands.add(new ChangeCommand(w, updatedWay));
     218            result.add(updatedWay);
     219        }
     220
     221        for (int i = 1; i < chunks.size(); i++) {
     222            List<Node> achunk = chunks.get(i);
     223            Way newWay = new Way();
     224            newWay.setKeys(w.getKeys());
     225            result.add(newWay);
     226            for (Relation rel : references.keySet()) {
     227                int relIndex = references.get(rel);
     228                rel.addMember(relIndex + 1, new RelationMember(rel.getMember(relIndex).getRole(), newWay));
     229            }
     230            newWay.setNodes(achunk);
     231            if (commands != null ) {
     232                commands.add(new AddCommand(newWay));
     233            }
     234        }
     235        if (commands != null ) {
     236            commands.addAll(relationCommands);
     237        }
     238        return result;
     239    }
     240
     241    public static List<Way> splitWay(Way w, Node n1, Node n2) {
     242        return splitWay(w, n1, n2, null);
    221243    }
    222244
     
    224246     * Find a way the tips of a segment, ensure it's in a multipolygon and try to close the relation.
    225247     */
    226     public static Relation tryToCloseOneWay( Way segment, List<Command> resultingCommands ) {
    227     if( segment.isClosed() || segment.isIncomplete() )
    228         return null;
    229 
    230     List<Way> ways = intersection(
    231         OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class),
    232         OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class));
    233     ways.remove(segment);
    234     for( Iterator<Way> iter = ways.iterator(); iter.hasNext(); ) {
    235         boolean save = false;
    236         for( OsmPrimitive ref : iter.next().getReferrers() )
    237         if( ref instanceof Relation && ((Relation)ref).isMultipolygon() && !ref.isDeleted() )
    238             save = true;
    239         if( !save )
    240         iter.remove();
    241     }
    242     if( ways.isEmpty() )
    243         return null; // well...
    244     Way target = ways.get(0);
    245 
    246     // time to create a new multipolygon relation and a command 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;
     248    public static Relation tryToCloseOneWay(Way segment, List<Command> resultingCommands) {
     249        if (segment.isClosed() || segment.isIncomplete() )
     250            return null;
     251
     252        List<Way> ways = intersection(
     253                OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class),
     254                OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class));
     255        ways.remove(segment);
     256        for (Iterator<Way> iter = ways.iterator(); iter.hasNext();) {
     257            boolean save = false;
     258            for (OsmPrimitive ref : iter.next().getReferrers() )
     259                if (ref instanceof Relation && ((Relation)ref).isMultipolygon() && !ref.isDeleted() ) {
     260                    save = true;
     261                }
     262            if (!save ) {
     263                iter.remove();
     264            }
     265        }
     266        if (ways.isEmpty() )
     267            return null; // well...
     268        Way target = ways.get(0);
     269
     270        // time to create a new multipolygon relation and a command stack
     271        List<Command> commands = new ArrayList<>();
     272        Relation newRelation = new Relation();
     273        newRelation.put("type", "multipolygon");
     274        newRelation.addMember(new RelationMember("outer", segment));
     275        Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
     276        Way segmentCopy = new Way(segment);
     277        boolean changed = false;
     278        for (String key : segmentCopy.keySet()) {
     279            if (!linearTags.contains(key)) {
     280                newRelation.put(key, segmentCopy.get(key));
     281                segmentCopy.remove(key);
     282                changed = true;
     283            }
     284        }
     285        if (changed ) {
     286            commands.add(new ChangeCommand(segment, segmentCopy));
     287        }
     288
     289        // now split the way, at last
     290        List<Way> newWays = new ArrayList<>(splitWay(target, segment.firstNode(), segment.lastNode(), commands));
     291
     292        Way addingWay = null;
     293        if (target.isClosed()) {
     294            Way utarget = newWays.get(1);
     295            Way alternate = newWays.get(0);
     296            List<Node> testRing = new ArrayList<>(segment.getNodes());
     297            closePolygon(testRing, utarget.getNodes());
     298            addingWay = segmentInsidePolygon(alternate.getNode(0), alternate.getNode(1), testRing) ? alternate : utarget;
     299        } else {
     300            for (Way w : newWays) {
     301                if ((w.firstNode().equals(segment.firstNode()) && w.lastNode().equals(segment.lastNode()))
     302                        || (w.firstNode().equals(segment.lastNode()) && w.lastNode().equals(segment.firstNode()))) {
     303                    addingWay = w;
     304                    break;
     305                }
     306            }
     307        }
     308        newRelation.addMember(new RelationMember("outer", addingWay.getUniqueId() == target.getUniqueId() ? target : addingWay));
     309        commands.add(new AddCommand(newRelation));
     310        resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}",
     311                DefaultNameFormatter.getInstance().format(segment)), commands));
     312        return newRelation;
    288313    }
    289314
     
    291316     * Returns all elements from {@code list1} that are in {@code list2}.
    292317     */
    293     private static <T> List<T> intersection( Collection<T> list1, Collection<T> list2 ) {
    294     List<T> result = new ArrayList<>();
    295     for( T item : list1 )
    296         if( list2.contains(item) )
    297         result.add(item);
    298     return result;
    299     }
    300    
     318    private static <T> List<T> intersection(Collection<T> list1, Collection<T> list2) {
     319        List<T> result = new ArrayList<>();
     320        for (T item : list1 )
     321            if (list2.contains(item) ) {
     322                result.add(item);
     323            }
     324        return result;
     325    }
     326
    301327    /**
    302328     * Make a multipolygon out of the ring, but split it to attach to neighboring multipolygons.
    303329     */
    304     public static Relation attachRingToNeighbours( Way ring, List<Command> resultingCommands ) {
    305     if( !ring.isClosed() || ring.isIncomplete() )
    306         return null;
    307     Map<Way, Boolean> touchingWays = new HashMap<>();
    308     for( Node n : ring.getNodes() ) {
    309         for( OsmPrimitive p : n.getReferrers() ) {
    310         if( p instanceof Way && !p.equals(ring) ) {
    311             for( OsmPrimitive r : p.getReferrers() ) {
    312             if( r instanceof Relation && ((Relation)r).hasKey("type") && ((Relation)r).get("type").equals("multipolygon") ) {
    313                 if( touchingWays.containsKey((Way)p) )
    314                 touchingWays.put((Way)p, Boolean.TRUE);
    315                 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();
     330    public static Relation attachRingToNeighbours(Way ring, List<Command> resultingCommands) {
     331        if (!ring.isClosed() || ring.isIncomplete() )
     332            return null;
     333        Map<Way, Boolean> touchingWays = new HashMap<>();
     334        for (Node n : ring.getNodes()) {
     335            for (OsmPrimitive p : n.getReferrers()) {
     336                if (p instanceof Way && !p.equals(ring)) {
     337                    for (OsmPrimitive r : p.getReferrers()) {
     338                        if (r instanceof Relation && ((Relation)r).hasKey("type") && ((Relation)r).get("type").equals("multipolygon")) {
     339                            if (touchingWays.containsKey(p) ) {
     340                                touchingWays.put((Way)p, Boolean.TRUE);
     341                            } else {
     342                                touchingWays.put((Way)p, Boolean.FALSE);
     343                            }
     344                            break;
     345                        }
     346                    }
     347                }
     348            }
     349        }
     350
     351        List<TheRing> otherWays = new ArrayList<>();
     352        for (Way w : touchingWays.keySet() )
     353            if (touchingWays.get(w)) {
     354                otherWays.add(new TheRing(w));
     355                //        System.out.println("Touching ring: " + otherWays.get(otherWays.size()-1));
     356            }
     357
     358        //    for (Iterator<Way> keys = touchingWays.keySet().iterator(); keys.hasNext();) {
     359        //        if (!touchingWays.get(keys.next()) )
     360        //        keys.remove();
     361        //    }
     362
     363        // now touchingWays has only ways that touch the ring twice
     364        List<Command> commands = new ArrayList<>();
     365        TheRing theRing = new TheRing(ring); // this is actually useful
     366
     367        for (TheRing otherRing : otherWays ) {
     368            theRing.collide(otherRing);
     369        }
     370
     371        theRing.putSourceWayFirst();
     372        for (TheRing otherRing : otherWays ) {
     373            otherRing.putSourceWayFirst();
     374        }
     375
     376        Map<Relation, Relation> relationCache = new HashMap<>();
     377        for (TheRing otherRing : otherWays ) {
     378            commands.addAll(otherRing.getCommands(false, relationCache));
     379        }
     380        commands.addAll(theRing.getCommands(relationCache));
     381        TheRing.updateCommandsWithRelations(commands, relationCache);
     382        resultingCommands.add(new SequenceCommand(tr("Complete multipolygon for way {0}",
     383                DefaultNameFormatter.getInstance().format(ring)), commands));
     384        return theRing.getRelation();
    355385    }
    356386}
  • applications/editors/josm/plugins/reltoolbox/src/relcontext/actions/TheRing.java

    r30738 r32395  
     1// License: GPL. For details, see LICENSE file.
    12package relcontext.actions;
    23
     
    2526 * One ring that contains segments forming an outer way of multipolygon.
    2627 * This class is used in {@link CreateMultipolygonAction#makeManySimpleMultipolygons(java.util.Collection)}.
    27  * 
     28 *
    2829 * @author Zverik
    2930 */
     
    3536    private Relation relation = null;
    3637
    37     public TheRing( Way source ) {
    38     this.source = source;
    39     segments = new ArrayList<>(1);
    40     segments.add(new RingSegment(source));
    41     }
    42    
    43     public static boolean areAllOfThoseRings( Collection<Way> ways ) {
    44     List<Way> rings = new ArrayList<>();
    45     for( Way way : ways ) {
    46         if( way.isClosed() )
    47         rings.add(way);
    48         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 )
     38    public TheRing(Way source) {
     39        this.source = source;
     40        segments = new ArrayList<>(1);
     41        segments.add(new RingSegment(source));
     42    }
     43
     44    public static boolean areAllOfThoseRings(Collection<Way> ways) {
     45        List<Way> rings = new ArrayList<>();
     46        for (Way way : ways) {
     47            if (way.isClosed() ) {
     48                rings.add(way);
     49            } else
     50                return false;
     51        }
     52        if (rings.isEmpty() || ways.size() == 1 )
    5953            return false;
    60         }
    61     }
    62 
    63     return true;
     54
     55        // check for non-containment of rings
     56        for (int i = 0; i < rings.size() - 1; i++) {
     57            for (int j = i + 1; j < rings.size(); j++) {
     58                PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
     59                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
     60                    return false;
     61            }
     62        }
     63
     64        return true;
    6465    }
    6566
     
    6869     * @return list of new relations.
    6970     */
    70     public static List<Relation> makeManySimpleMultipolygons( Collection<Way> selection, List<Command> commands ) {
    71     log("---------------------------------------");
    72     List<TheRing> rings = new ArrayList<>(selection.size());
    73     for( Way w : selection )
    74         rings.add(new TheRing(w));
    75     for( int i = 0; i < rings.size() - 1; i++ )
    76         for( int j = i + 1; j < rings.size(); j++ )
    77         rings.get(i).collide(rings.get(j));
    78     redistributeSegments(rings);
    79     List<Relation> relations = new ArrayList<>();
    80     Map<Relation, Relation> relationCache = new HashMap<>();
    81     for( TheRing r : rings ) {
    82         commands.addAll(r.getCommands(relationCache));
    83         relations.add(r.getRelation());
    84     }
    85     updateCommandsWithRelations(commands, relationCache);
    86     return relations;
    87     }
    88 
    89     public void collide( TheRing other ) {
    90     boolean collideNoted = false;
    91     for( int i = 0; i < segments.size(); i++ ) {
    92         RingSegment segment1 = segments.get(i);
    93         if( !segment1.isReference() ) {
    94         for( int j = 0; j < other.segments.size(); j++ ) {
    95             RingSegment segment2 = other.segments.get(j);
    96             if( !segment2.isReference() ) {
    97             log("Comparing " + segment1 + " and " + segment2);
    98             Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());
    99             if( split != null ) {
    100                 if( !collideNoted ) {
    101                 log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
    102                 collideNoted = true;
    103                 }
    104                 RingSegment segment = splitRingAt(i, split[0], split[1]);
    105                 RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);
    106                 if( !areSegmentsEqual(segment, otherSegment) )
    107                 throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
    108                 segment.makeReference(otherSegment);
    109             }
    110             }
    111             if( segment1.isReference() )
    112             break;
    113         }
    114         }
    115     }
    116     }
    117    
     71    public static List<Relation> makeManySimpleMultipolygons(Collection<Way> selection, List<Command> commands) {
     72        log("---------------------------------------");
     73        List<TheRing> rings = new ArrayList<>(selection.size());
     74        for (Way w : selection ) {
     75            rings.add(new TheRing(w));
     76        }
     77        for (int i = 0; i < rings.size() - 1; i++ ) {
     78            for (int j = i + 1; j < rings.size(); j++ ) {
     79                rings.get(i).collide(rings.get(j));
     80            }
     81        }
     82        redistributeSegments(rings);
     83        List<Relation> relations = new ArrayList<>();
     84        Map<Relation, Relation> relationCache = new HashMap<>();
     85        for (TheRing r : rings) {
     86            commands.addAll(r.getCommands(relationCache));
     87            relations.add(r.getRelation());
     88        }
     89        updateCommandsWithRelations(commands, relationCache);
     90        return relations;
     91    }
     92
     93    public void collide(TheRing other) {
     94        boolean collideNoted = false;
     95        for (int i = 0; i < segments.size(); i++) {
     96            RingSegment segment1 = segments.get(i);
     97            if (!segment1.isReference()) {
     98                for (int j = 0; j < other.segments.size(); j++) {
     99                    RingSegment segment2 = other.segments.get(j);
     100                    if (!segment2.isReference()) {
     101                        log("Comparing " + segment1 + " and " + segment2);
     102                        Node[] split = getSplitNodes(segment1.getNodes(), segment2.getNodes(), segment1.isRing(), segment2.isRing());
     103                        if (split != null) {
     104                            if (!collideNoted) {
     105                                log("Rings for ways " + source.getUniqueId() + " and " + other.source.getUniqueId() + " collide.");
     106                                collideNoted = true;
     107                            }
     108                            RingSegment segment = splitRingAt(i, split[0], split[1]);
     109                            RingSegment otherSegment = other.splitRingAt(j, split[2], split[3]);
     110                            if (!areSegmentsEqual(segment, otherSegment) )
     111                                throw new IllegalArgumentException("Error: algorithm gave incorrect segments: " + segment + " and " + otherSegment);
     112                            segment.makeReference(otherSegment);
     113                        }
     114                    }
     115                    if (segment1.isReference() ) {
     116                        break;
     117                    }
     118                }
     119            }
     120        }
     121    }
     122
    118123    /**
    119124     * Returns array of {start1, last1, start2, last2} or null if there is no common nodes.
    120125     */
    121     public static Node[] getSplitNodes( List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2 ) {
    122     int pos = 0;
    123     while( pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) )
    124         pos++;
    125     boolean collideFound = pos == nodes1.size();
    126     if( pos == 0 && isRing1 ) {
    127         // rewind a 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);
     126    public static Node[] getSplitNodes(List<Node> nodes1, List<Node> nodes2, boolean isRing1, boolean isRing2) {
     127        int pos = 0;
     128        while(pos < nodes1.size() && !nodes2.contains(nodes1.get(pos)) ) {
     129            pos++;
     130        }
     131        boolean collideFound = pos == nodes1.size();
     132        if (pos == 0 && isRing1) {
     133            // rewind a bit
     134            pos = nodes1.size() - 1;
     135            while(pos > 0 && nodes2.contains(nodes1.get(pos)) ) {
     136                pos--;
     137            }
     138            if (pos == 0 && nodes1.size() == nodes2.size()) {
     139                JOptionPane.showMessageDialog(Main.parent, "Two rings are equal, and this must not be.", "Multipolygon from rings", JOptionPane.ERROR_MESSAGE);
     140                return null;
     141            }
     142            pos = pos == nodes1.size() - 1 ? 0 : pos + 1;
     143        }
     144        int firstPos = isRing1 ? pos : nodes1.size();
     145        while(!collideFound) {
     146            log("pos=" + pos);
     147            int start1 = pos;
     148            int start2 = nodes2.indexOf(nodes1.get(start1));
     149            int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
     150            int last2 = start2;
     151            int increment2 = 0;
     152            if (last1 >= 0) {
     153                last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
     154                if (last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) {
     155                    increment2 = -1;
     156                } else {
     157                    last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
     158                    if (last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) ) {
     159                        increment2 = 1;
     160                    }
     161                }
     162            }
     163            log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);
     164            if (increment2 != 0) {
     165                // find the first nodes
     166                boolean reachedEnd = false;
     167                while(!reachedEnd) {
     168                    int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
     169                    int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
     170                    if (newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) ) {
     171                        reachedEnd = true;
     172                    } else {
     173                        last1 = newLast1;
     174                        last2 = newLast2;
     175                    }
     176                }
     177                log("last1=" + last1 + " last2=" + last2);
     178                if (increment2 < 0) {
     179                    int tmp = start2;
     180                    start2 = last2;
     181                    last2 = tmp;
     182                }
     183                return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};
     184            } else {
     185                pos = last1;
     186                while(pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) ) {
     187                    pos = incrementBy(pos, 1, nodes1.size(), isRing1);
     188                }
     189                if (pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) ) {
     190                    collideFound = true;
     191                }
     192            }
     193        }
    133194        return null;
    134         }
    135         pos = pos == nodes1.size() - 1 ? 0 : pos + 1;
    136     }
    137     int firstPos = isRing1 ? pos : nodes1.size();
    138     while( !collideFound ) {
    139         log("pos=" + pos);
    140         int start1 = pos;
    141         int start2 = nodes2.indexOf(nodes1.get(start1));
    142         int last1 = incrementBy(start1, 1, nodes1.size(), isRing1);
    143         int last2 = start2;
    144         int increment2 = 0;
    145         if( last1 >= 0 ) {
    146         last2 = incrementBy(start2, -1, nodes2.size(), isRing2);
    147         if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    148             increment2 = -1;
    149         else {
    150             last2 = incrementBy(start2, 1, nodes2.size(), isRing2);
    151             if( last2 >= 0 && nodes1.get(last1).equals(nodes2.get(last2)) )
    152             increment2 = 1;
    153         }
    154         }
    155         log("last1=" + last1 + " last2=" + last2 + " increment2=" + increment2);
    156         if( increment2 != 0 ) {
    157         // find the first nodes
    158         boolean reachedEnd = false;
    159         while( !reachedEnd ) {
    160             int newLast1 = incrementBy(last1, 1, nodes1.size(), isRing1);
    161             int newLast2 = incrementBy(last2, increment2, nodes2.size(), isRing2);
    162             if( newLast1 < 0 || newLast2 < 0 || !nodes1.get(newLast1).equals(nodes2.get(newLast2)) )
    163             reachedEnd = true;
    164             else {
    165             last1 = newLast1;
    166             last2 = newLast2;
    167             }
    168         }
    169         log("last1=" + last1 + " last2=" + last2);
    170         if( increment2 < 0 ) {
    171             int tmp = start2;
    172             start2 = last2;
    173             last2 = tmp;
    174         }
    175         return new Node[] {nodes1.get(start1), nodes1.get(last1), nodes2.get(start2), nodes2.get(last2)};
    176         } else {
    177         pos = last1;
    178         while( pos != firstPos && pos >= 0 && !nodes2.contains(nodes1.get(pos)) )
    179             pos = incrementBy(pos, 1, nodes1.size(), isRing1);
    180         if( pos < 0 || pos == firstPos || !nodes2.contains(nodes1.get(pos)) )
    181             collideFound = true;
    182         }
    183     }
    184     return null;
    185     }
    186    
    187     private static int incrementBy( int value, int increment, int limit1, boolean isRing ) {
    188     int result = value + increment;
    189     if( result < 0 )
    190         return isRing ? result + limit1 : -1;
    191     else if( result >= limit1 )
    192         return isRing ? result - limit1 : -1;
    193     else
    194         return result;
    195     }
    196    
    197     private boolean areSegmentsEqual( RingSegment seg1, RingSegment seg2 ) {
    198     List<Node> nodes1 = seg1.getNodes();
    199     List<Node> nodes2 = seg2.getNodes();
    200     int size = nodes1.size();
    201     if( size != nodes2.size() )
    202         return false;
    203     boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0));
    204     for( int i = 0; i < size; i++ )
    205         if( !nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) )
    206         return false;
    207     return true;
     195    }
     196
     197    private static int incrementBy(int value, int increment, int limit1, boolean isRing) {
     198        int result = value + increment;
     199        if (result < 0 )
     200            return isRing ? result + limit1 : -1;
     201        else if (result >= limit1 )
     202            return isRing ? result - limit1 : -1;
     203        else
     204            return result;
     205    }
     206
     207    private boolean areSegmentsEqual(RingSegment seg1, RingSegment seg2) {
     208        List<Node> nodes1 = seg1.getNodes();
     209        List<Node> nodes2 = seg2.getNodes();
     210        int size = nodes1.size();
     211        if (size != nodes2.size() )
     212            return false;
     213        boolean reverse = size > 1 && !nodes1.get(0).equals(nodes2.get(0));
     214        for (int i = 0; i < size; i++ )
     215            if (!nodes1.get(i).equals(nodes2.get(reverse ? size-1-i : i)) )
     216                return false;
     217        return true;
    208218    }
    209219
     
    212222     * @return The segment between nodes.
    213223     */
    214     private RingSegment splitRingAt( int segmentIndex, Node n1, Node n2 ) {
    215     if( n1.equals(n2) )
    216         throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());
    217     RingSegment segment = segments.get(segmentIndex);
    218     boolean isRing = segment.isRing();
    219     log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());
    220     boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);
    221     if( reversed && !isRing ) {
    222         // order 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;
     224    private RingSegment splitRingAt(int segmentIndex, Node n1, Node n2) {
     225        if (n1.equals(n2) )
     226            throw new IllegalArgumentException("Both nodes are equal, id=" + n1.getUniqueId());
     227        RingSegment segment = segments.get(segmentIndex);
     228        boolean isRing = segment.isRing();
     229        log("Split segment " + segment + " at nodes " + n1.getUniqueId() + " and " + n2.getUniqueId());
     230        boolean reversed = segment.getNodes().indexOf(n2) < segment.getNodes().indexOf(n1);
     231        if (reversed && !isRing) {
     232            // order nodes
     233            Node tmp = n1;
     234            n1 = n2;
     235            n2 = tmp;
     236        }
     237        RingSegment secondPart = isRing ? segment.split(n1, n2) : segment.split(n1);
     238        // if secondPart == null, then n1 == firstNode
     239        RingSegment thirdPart = isRing ? null : secondPart == null ? segment.split(n2) : secondPart.split(n2);
     240        // if secondPart == null, then thirdPart is between n1 and n2
     241        // otherwise, thirdPart is between n2 and lastNode
     242        // if thirdPart == null, then n2 == lastNode
     243        int pos = segmentIndex + 1;
     244        if (secondPart != null ) {
     245            segments.add(pos++, secondPart);
     246        }
     247        if (thirdPart != null ) {
     248            segments.add(pos++, thirdPart);
     249        }
     250        return isRing || secondPart == null ? segment : secondPart;
    239251    }
    240252
     
    242254     * Tries to arrange segments in order for each ring to have at least one.
    243255     * Also, sets source way for all rings.
    244      * 
     256     *
    245257     * If this method is not called, do not forget to call {@link #putSourceWayFirst()} for all rings.
    246258     */
    247     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();
     259    public static void redistributeSegments(List<TheRing> rings) {
     260        // build segments map
     261        Map<RingSegment, TheRing> segmentMap = new HashMap<>();
     262        for (TheRing ring : rings ) {
     263            for (RingSegment seg : ring.segments )
     264                if (!seg.isReference() ) {
     265                    segmentMap.put(seg, ring);
     266                }
     267        }
     268
     269        // rearrange references
     270        for (int i = 0; i < rings.size(); i++) {
     271            TheRing ring = rings.get(i);
     272            if (ring.countNonReferenceSegments() == 0) {
     273                // need to find one non-reference segment
     274                for (RingSegment seg : ring.segments) {
     275                    TheRing otherRing = segmentMap.get(seg.references);
     276                    if (otherRing.countNonReferenceSegments() > 1) {
     277                        // we could check for >0, but it is prone to deadlocking
     278                        seg.swapReference();
     279                    }
     280                }
     281            }
     282        }
     283
     284        // initializing source way for each ring
     285        for (TheRing ring : rings ) {
     286            ring.putSourceWayFirst();
     287        }
    273288    }
    274289
    275290    private int countNonReferenceSegments() {
    276     int count = 0;
    277     for( RingSegment seg : segments )
    278         if( !seg.isReference() )
    279         count++;
    280     return count;
     291        int count = 0;
     292        for (RingSegment seg : segments )
     293            if (!seg.isReference() ) {
     294                count++;
     295            }
     296        return count;
    281297    }
    282298
    283299    public void putSourceWayFirst() {
    284     for( RingSegment seg : segments ) {
    285         if( !seg.isReference() ) {
    286         seg.overrideWay(source);
    287         return;
    288         }
    289     }
    290     }
    291    
     300        for (RingSegment seg : segments) {
     301            if (!seg.isReference()) {
     302                seg.overrideWay(source);
     303                return;
     304            }
     305        }
     306    }
     307
    292308    public List<Command> getCommands() {
    293     return getCommands(true, null);
    294     }
    295    
    296     public List<Command> getCommands( Map<Relation, Relation> relationChangeMap ) {
    297     return getCommands(true, relationChangeMap);
    298     }
    299    
     309        return getCommands(true, null);
     310    }
     311
     312    public List<Command> getCommands(Map<Relation, Relation> relationChangeMap) {
     313        return getCommands(true, relationChangeMap);
     314    }
     315
    300316    /**
    301317     * Returns a list of commands to make a new relation and all newly created ways.
    302318     * The first way is copied from the source one, ChangeCommand is issued in this case.
    303319     */
    304     public List<Command> getCommands( boolean createMultipolygon, Map<Relation, Relation> relationChangeMap ) {
    305     Way sourceCopy = new Way(source);
    306     if( createMultipolygon ) {
    307         Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
    308         relation = new Relation();
    309         relation.put("type", "multipolygon");
    310         for( String key : sourceCopy.keySet() ) {
    311                 if( linearTags.contains(key) ) continue;
    312                 if( key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) continue;
     320    public List<Command> getCommands(boolean createMultipolygon, Map<Relation, Relation> relationChangeMap) {
     321        Way sourceCopy = new Way(source);
     322        if (createMultipolygon) {
     323            Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", CreateMultipolygonAction.DEFAULT_LINEAR_TAGS);
     324            relation = new Relation();
     325            relation.put("type", "multipolygon");
     326            for (String key : sourceCopy.keySet()) {
     327                if (linearTags.contains(key) ) {
     328                    continue;
     329                }
     330                if (key.equals("natural") && sourceCopy.get("natural").equals("coastline") ) {
     331                    continue;
     332                }
    313333                relation.put(key, sourceCopy.get(key));
    314334                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;
    372     }
    373    
    374     public static void updateCommandsWithRelations( List<Command> commands, Map<Relation, Relation> relationCache ) {
    375     for( Relation src : relationCache.keySet() )
    376         commands.add(new ChangeCommand(src, relationCache.get(src)));
     335            }
     336        }
     337
     338        // build a map of referencing relations
     339        Map<Relation, Integer> referencingRelations = new HashMap<>();
     340        List<Command> relationCommands = new ArrayList<>();
     341        for (OsmPrimitive p : source.getReferrers()) {
     342            if (p instanceof Relation) {
     343                Relation rel = null;
     344                if (relationChangeMap != null) {
     345                    if (relationChangeMap.containsKey(p) ) {
     346                        rel = relationChangeMap.get(p);
     347                    } else {
     348                        rel = new Relation((Relation)p);
     349                        relationChangeMap.put((Relation)p, rel);
     350                    }
     351                } else {
     352                    rel = new Relation((Relation)p);
     353                    relationCommands.add(new ChangeCommand(p, rel));
     354                }
     355                for (int i = 0; i < rel.getMembersCount(); i++ )
     356                    if (rel.getMember(i).getMember().equals(source) ) {
     357                        referencingRelations.put(rel, Integer.valueOf(i));
     358                    }
     359            }
     360        }
     361        // todo: когда два кольца менÑ�ÑŽÑ‚ одно и то же отношение, в Ñ�пиÑ�ок команд добавлÑ�етÑ�Ñ�
     362        // изменение базового отношениÑ� на новое, а не предыдущего
     363        // поÑ�тому Ñ�охранÑ�етÑ�Ñ� только первое изменение
     364
     365        List<Command> commands = new ArrayList<>();
     366        boolean foundOwnWay = false;
     367        for (RingSegment seg : segments) {
     368            boolean needAdding = !seg.isWayConstructed();
     369            Way w = seg.constructWay(seg.isReference() ? null : sourceCopy);
     370            if (needAdding ) {
     371                commands.add(new AddCommand(w));
     372            }
     373            if (w.equals(source)) {
     374                if (createMultipolygon || !seg.getWayNodes().equals(source.getNodes())) {
     375                    sourceCopy.setNodes(seg.getWayNodes());
     376                    commands.add(new ChangeCommand(source, sourceCopy));
     377                }
     378                foundOwnWay = true;
     379            } else {
     380                for (Relation rel : referencingRelations.keySet()) {
     381                    int relIndex = referencingRelations.get(rel);
     382                    rel.addMember(new RelationMember(rel.getMember(relIndex).getRole(), w));
     383                }
     384            }
     385            if (createMultipolygon ) {
     386                relation.addMember(new RelationMember("outer", w));
     387            }
     388        }
     389        if (!foundOwnWay ) {
     390            commands.add(new DeleteCommand(source));
     391        }
     392        commands.addAll(relationCommands);
     393        if (createMultipolygon ) {
     394            commands.add(new AddCommand(relation));
     395        }
     396        return commands;
     397    }
     398
     399    public static void updateCommandsWithRelations(List<Command> commands, Map<Relation, Relation> relationCache) {
     400        for (Relation src : relationCache.keySet() ) {
     401            commands.add(new ChangeCommand(src, relationCache.get(src)));
     402        }
    377403    }
    378404
     
    381407     */
    382408    public Relation getRelation() {
    383     return relation;
     409        return relation;
    384410    }
    385411
    386412    @Override
    387413    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();
     414        StringBuilder sb = new StringBuilder("TheRing@");
     415        sb.append(this.hashCode()).append('[').append("wayId: ").append(source == null ? "null" : source.getUniqueId()).append("; segments: ");
     416        if (segments.isEmpty() ) {
     417            sb.append("empty");
     418        } else {
     419            sb.append(segments.get(0));
     420            for (int i = 1; i < segments.size(); i++ ) {
     421                sb.append(", ").append(segments.get(i));
     422            }
     423        }
     424        return sb.append(']').toString();
    398425    }
    399426
     
    401428     * Appends "append" to "base" so the closed polygon forms.
    402429     */
    403     /*private static void closePolygon( List<Node> base, List<Node> append ) {
    404     if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {
     430    /*private static void closePolygon(List<Node> base, List<Node> append) {
     431    if (append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1))) {
    405432        List<Node> ap2 = new ArrayList<Node>(append);
    406433        Collections.reverse(ap2);
     
    414441     * Checks if a middle point between two nodes is inside a polygon. Useful to check if the way is inside.
    415442     */
    416     /*private static boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) {
     443    /*private static boolean segmentInsidePolygon(Node n1, Node n2, List<Node> polygon) {
    417444    EastNorth en1 = n1.getEastNorth();
    418445    EastNorth en2 = n2.getEastNorth();
     
    420447    return Geometry.nodeInsidePolygon(testNode, polygon);
    421448    }*/
    422    
    423     private static void log( String s ) {
    424 //    System.out.println(s);
    425     }
    426    
     449
     450    private static void log(String s) {
     451        //    System.out.println(s);
     452    }
     453
    427454    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() {
     455        private List<Node> nodes;
     456        private RingSegment references;
     457        private Way resultingWay = null;
     458        private boolean wasTemplateApplied = false;
     459        private boolean isRing;
     460
     461        /*private RingSegment() {
    435462    }*/
    436463
    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 ) {
     464        public RingSegment(Way w) {
     465            this(w.getNodes());
     466        }
     467
     468        public RingSegment(List<Node> nodes) {
     469            this.nodes = nodes;
     470            isRing = nodes.size() > 1 && nodes.get(0).equals(nodes.get(nodes.size() - 1));
     471            if (isRing ) {
     472                nodes.remove(nodes.size() - 1);
     473            }
     474            references = null;
     475        }
     476
     477        /*public RingSegment(RingSegment ref) {
    450478        this.nodes = null;
    451479        this.references = ref;
    452480    }*/
    453481
    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 ) {
     482        /**
     483         * Splits this segment at node n. Retains nodes 0..n and moves
     484         * nodes n..N to a separate segment that is returned.
     485         * @param n node at which to split.
     486         * @return new segment, {@code null} if splitting is unnecessary.
     487         */
     488        public RingSegment split(Node n) {
     489            if (nodes == null )
     490                throw new IllegalArgumentException("Cannot split segment: it is a reference");
     491            int pos = nodes.indexOf(n);
     492            if (pos <= 0 || pos >= nodes.size() - 1 )
     493                return null;
     494            List<Node> newNodes = new ArrayList<>(nodes.subList(pos, nodes.size()));
     495            nodes.subList(pos + 1, nodes.size()).clear();
     496            return new RingSegment(newNodes);
     497        }
     498
     499        /**
     500         * Split this segment as a way at two nodes. If one of them is null or at the end,
     501         * split as an arc. Note: order of nodes is important.
     502         * @return A new segment from n2 to n1.
     503         */
     504        public RingSegment split(Node n1, Node n2) {
     505            if (nodes == null )
     506                throw new IllegalArgumentException("Cannot split segment: it is a reference");
     507            if (!isRing) {
     508                if (n1 == null || nodes.get(0).equals(n1) || nodes.get(nodes.size() - 1).equals(n1) )
     509                    return split(n2);
     510                if (n2 == null || nodes.get(0).equals(n2) || nodes.get(nodes.size() - 1).equals(n2) )
     511                    return split(n1);
     512                throw new IllegalArgumentException("Split for two nodes is called for not-ring: " + this);
     513            }
     514            int pos1 = nodes.indexOf(n1);
     515            int pos2 = nodes.indexOf(n2);
     516            if (pos1 == pos2 )
     517                return null;
     518
     519            List<Node> newNodes = new ArrayList<>();
     520            if (pos2 > pos1) {
     521                newNodes.addAll(nodes.subList(pos2, nodes.size()));
     522                newNodes.addAll(nodes.subList(0, pos1 + 1));
     523                if (pos2 + 1 < nodes.size() ) {
     524                    nodes.subList(pos2 + 1, nodes.size()).clear();
     525                }
     526                if (pos1 > 0 ) {
     527                    nodes.subList(0, pos1).clear();
     528                }
     529            } else {
     530                newNodes.addAll(nodes.subList(pos2, pos1 + 1));
     531                nodes.addAll(new ArrayList<>(nodes.subList(0, pos2 + 1)));
     532                nodes.subList(0, pos1).clear();
     533            }
     534            isRing = false;
     535            return new RingSegment(newNodes);
     536        }
     537
     538        public List<Node> getNodes() {
     539            return nodes == null ? references.nodes : nodes;
     540        }
     541
     542        public List<Node> getWayNodes() {
     543            if (nodes == null )
     544                throw new IllegalArgumentException("Won't give you wayNodes: it is a reference");
     545            List<Node> wayNodes = new ArrayList<>(nodes);
     546            if (isRing ) {
     547                wayNodes.add(wayNodes.get(0));
     548            }
     549            return wayNodes;
     550        }
     551
     552        public boolean isReference() {
     553            return nodes == null;
     554        }
     555
     556        public boolean isRing() {
     557            return isRing;
     558        }
     559
     560        public void makeReference(RingSegment segment) {
     561            log(this + " was made a reference to " + segment);
     562            this.nodes = null;
     563            this.references = segment;
     564        }
     565
     566        public void swapReference() {
     567            this.nodes = references.nodes;
     568            references.nodes = null;
     569            references.references = this;
     570            this.references = null;
     571        }
     572
     573        public boolean isWayConstructed() {
     574            return isReference() ? references.isWayConstructed() : resultingWay != null;
     575        }
     576
     577        public Way constructWay(Way template) {
     578            if (isReference() )
     579                return references.constructWay(template);
     580            if (resultingWay == null) {
     581                resultingWay = new Way();
     582                resultingWay.setNodes(getWayNodes());
     583            }
     584            if (template != null && !wasTemplateApplied) {
     585                resultingWay.setKeys(template.getKeys());
     586                wasTemplateApplied = true;
     587            }
     588            return resultingWay;
     589        }
     590
     591        public void overrideWay(Way source) {
     592            if (isReference() ) {
     593                references.overrideWay(source);
     594            } else {
     595                resultingWay = source;
     596                wasTemplateApplied = true;
     597            }
     598        }
     599
     600        /**
     601         * Compares two segments with respect to referencing.
     602         * @return true if ways are equals, or one references another.
     603         */
     604        /*public boolean isReferencingEqual(RingSegment other) {
    574605        return this.equals(other) || (other.isReference() && other.references == this) || (isReference() && references == other);
    575606    }*/
    576607
    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     }
     608        @Override
     609        public String toString() {
     610            StringBuilder sb = new StringBuilder("RingSegment@");
     611            sb.append(this.hashCode()).append('[');
     612            if (isReference() ) {
     613                sb.append("references ").append(references.hashCode());
     614            } else if (nodes.isEmpty() ) {
     615                sb.append("empty");
     616            } else {
     617                if (isRing ) {
     618                    sb.append("ring:");
     619                }
     620                sb.append(nodes.get(0).getUniqueId());
     621                for (int i = 1; i < nodes.size(); i++ ) {
     622                    sb.append(',').append(nodes.get(i).getUniqueId());
     623                }
     624            }
     625            return sb.append(']').toString();
     626        }
    594627    }
    595628}
Note: See TracChangeset for help on using the changeset viewer.