Ignore:
Timestamp:
2011-10-09T09:51:22+02:00 (13 years ago)
Author:
zverik
Message:

ark to multipolygon, also base for rings to mp

File:
1 edited

Legend:

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

    r26290 r26811  
    1111import org.openstreetmap.josm.Main;
    1212import org.openstreetmap.josm.actions.JosmAction;
     13import org.openstreetmap.josm.actions.SplitWayAction;
    1314import org.openstreetmap.josm.command.*;
     15import org.openstreetmap.josm.data.coor.EastNorth;
    1416import org.openstreetmap.josm.data.osm.*;
     17import org.openstreetmap.josm.data.osm.MultipolygonCreate.JoinedPolygon;
     18import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
     19import org.openstreetmap.josm.gui.DefaultNameFormatter;
    1520import org.openstreetmap.josm.tools.GBC;
     21import org.openstreetmap.josm.tools.Geometry;
     22import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
    1623import org.openstreetmap.josm.tools.Shortcut;
    1724import relcontext.ChosenRelation;
     
    2936
    3037    public CreateMultipolygonAction( ChosenRelation chRel ) {
    31         super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"),
    32                 Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")),
    33                 KeyEvent.VK_B, Shortcut.GROUP_HOTKEY), true);
    34         this.chRel = chRel;
    35         updateEnabledState();
     38        super("Multi", "data/multipolygon", tr("Create a multipolygon from selected objects"),
     39                Shortcut.registerShortcut("reltoolbox:multipolygon", tr("Relation Toolbox: {0}", tr("Create multipolygon")),
     40                KeyEvent.VK_B, Shortcut.GROUP_HOTKEY), true);
     41        this.chRel = chRel;
     42        updateEnabledState();
    3643    }
    3744
    3845    public CreateMultipolygonAction() {
    39         this(null);
    40     }
    41    
     46        this(null);
     47    }
     48
    4249    public static boolean getDefaultPropertyValue( String property ) {
    43         if( property.equals("boundary") ) return false;
    44         else if( property.equals("boundaryways") ) return true;
    45         else if( property.equals("tags") ) return true;
    46         else if( property.equals("alltags") ) return false;
    47         else if( property.equals("single") ) return true;
    48         throw new IllegalArgumentException(property);
     50        if( property.equals("boundary") )
     51            return false;
     52        else if( property.equals("boundaryways") )
     53            return true;
     54        else if( property.equals("tags") )
     55            return true;
     56        else if( property.equals("alltags") )
     57            return false;
     58        else if( property.equals("single") )
     59            return true;
     60        throw new IllegalArgumentException(property);
    4961    }
    5062
    5163    private boolean getPref( String property ) {
    52         return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));
     64        return Main.pref.getBoolean(PREF_MULTIPOLY + property, getDefaultPropertyValue(property));
    5365    }
    5466
    5567    public void actionPerformed( ActionEvent e ) {
    56         // for now, just copying standard action
    57         MultipolygonCreate mpc = new MultipolygonCreate();
    58         String error = mpc.makeFromWays(getCurrentDataSet().getSelectedWays());
    59         if( error != null ) {
    60             JOptionPane.showMessageDialog(Main.parent, error);
    61             return;
    62         }
    63         Relation rel = new Relation();
    64         boolean isBoundary = getPref("boundary");
    65         if( isBoundary ) {
    66             rel.put("type", "boundary");
    67             rel.put("boundary", "administrative");
    68         } else
    69             rel.put("type", "multipolygon");
    70         for( MultipolygonCreate.JoinedPolygon poly : mpc.outerWays )
    71             for( Way w : poly.ways )
    72                 rel.addMember(new RelationMember("outer", w));
    73         for( MultipolygonCreate.JoinedPolygon poly : mpc.innerWays )
    74             for( Way w : poly.ways )
    75                 rel.addMember(new RelationMember("inner", w));
    76         List<Command> list = removeTagsFromInnerWays(rel);
    77         if( !list.isEmpty() && isBoundary ) {
    78             Main.main.undoRedo.add(new SequenceCommand(tr("Move tags from ways to relation"), list));
    79             list = new ArrayList<Command>();
    80         }
    81         if( isBoundary ) {
    82             if( !askForAdminLevelAndName(rel) )
    83                 return;
    84             addBoundaryMembers(rel);
    85             if( getPref("boundaryways") )
    86                 list.addAll(fixWayTagsForBoundary(rel));
    87         }
    88         list.add(new AddCommand(rel));
    89         Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));
    90        
    91         if( chRel != null )
    92             chRel.set(rel);
    93 
    94         getCurrentDataSet().setSelected(rel);
     68        boolean isBoundary = getPref("boundary");
     69        Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();
     70        if( !isBoundary && getPref("tags") ) {
     71            if( selectedWays.size() == 1 && !selectedWays.iterator().next().isClosed() ) {
     72                Relation newRelation = tryToCloseOneWay(selectedWays.iterator().next());
     73                if( newRelation != null ) {
     74                    if( chRel != null )
     75                        chRel.set(newRelation);
     76                    return;
     77                }
     78            }
     79            if( areAllOfThoseRings(getCurrentDataSet().getSelectedWays()) ) {
     80                List<Relation> rels = makeManySimpleMultipolygons(getCurrentDataSet().getSelectedWays());
     81                if( chRel != null )
     82                    chRel.set(rels.size() == 1 ? rels.get(0) : null);
     83                return;
     84            }
     85        }
     86
     87        // for now, just copying standard action
     88        MultipolygonCreate mpc = new MultipolygonCreate();
     89        String error = mpc.makeFromWays(getCurrentDataSet().getSelectedWays());
     90        if( error != null ) {
     91            JOptionPane.showMessageDialog(Main.parent, error);
     92            return;
     93        }
     94        Relation rel = new Relation();
     95        if( isBoundary ) {
     96            rel.put("type", "boundary");
     97            rel.put("boundary", "administrative");
     98        } else
     99            rel.put("type", "multipolygon");
     100        for( MultipolygonCreate.JoinedPolygon poly : mpc.outerWays )
     101            for( Way w : poly.ways )
     102                rel.addMember(new RelationMember("outer", w));
     103        for( MultipolygonCreate.JoinedPolygon poly : mpc.innerWays )
     104            for( Way w : poly.ways )
     105                rel.addMember(new RelationMember("inner", w));
     106        List<Command> list = removeTagsFromInnerWays(rel);
     107        if( !list.isEmpty() && isBoundary ) {
     108            Main.main.undoRedo.add(new SequenceCommand(tr("Move tags from ways to relation"), list));
     109            list = new ArrayList<Command>();
     110        }
     111        if( isBoundary ) {
     112            if( !askForAdminLevelAndName(rel) )
     113                return;
     114            addBoundaryMembers(rel);
     115            if( getPref("boundaryways") )
     116                list.addAll(fixWayTagsForBoundary(rel));
     117        }
     118        list.add(new AddCommand(rel));
     119        Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));
     120
     121        if( chRel != null )
     122            chRel.set(rel);
     123
     124        getCurrentDataSet().setSelected(rel);
    95125    }
    96126
    97127    @Override
    98128    protected void updateEnabledState() {
    99         if( getCurrentDataSet() == null ) {
    100             setEnabled(false);
    101         } else {
    102             updateEnabledState(getCurrentDataSet().getSelected());
    103         }
     129        if( getCurrentDataSet() == null ) {
     130            setEnabled(false);
     131        } else {
     132            updateEnabledState(getCurrentDataSet().getSelected());
     133        }
    104134    }
    105135
    106136    @Override
    107137    protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) {
    108         boolean enabled = true;
    109         if( selection == null || selection.isEmpty() )
    110             enabled = false;
    111         else {
    112             if( !getPref("boundary") ) {
    113                 for( OsmPrimitive p : selection ) {
    114                     if( !(p instanceof Way) ) {
    115                         enabled = false;
    116                         break;
    117                     }
    118                 }
    119             }
    120         }
    121         setEnabled(enabled);
     138        boolean isEnabled = true;
     139        if( selection == null || selection.isEmpty() )
     140            isEnabled = false;
     141        else {
     142            if( !getPref("boundary") ) {
     143                for( OsmPrimitive p : selection ) {
     144                    if( !(p instanceof Way) ) {
     145                        isEnabled = false;
     146                        break;
     147                    }
     148                }
     149            }
     150        }
     151        setEnabled(isEnabled);
    122152    }
    123153
     
    126156     */
    127157    private void addBoundaryMembers( Relation rel ) {
    128         for( OsmPrimitive p : getCurrentDataSet().getSelected() ) {
    129             String role = null;
    130             if( p.getType().equals(OsmPrimitiveType.RELATION) ) {
    131                 role = "subarea";
    132             } else if( p.getType().equals(OsmPrimitiveType.NODE) ) {
    133                 Node n = (Node)p;
    134                 if( !n.isIncomplete() ) {
    135                     if( n.hasKey("place") )
    136                         role = "admin_centre";
    137                     else
    138                         role = "label";
    139                 }
    140             }
    141             if( role != null )
    142                 rel.addMember(new RelationMember(role, p));
    143         }
     158        for( OsmPrimitive p : getCurrentDataSet().getSelected() ) {
     159            String role = null;
     160            if( p.getType().equals(OsmPrimitiveType.RELATION) ) {
     161                role = "subarea";
     162            } else if( p.getType().equals(OsmPrimitiveType.NODE) ) {
     163                Node n = (Node)p;
     164                if( !n.isIncomplete() ) {
     165                    if( n.hasKey("place") )
     166                        role = "admin_centre";
     167                    else
     168                        role = "label";
     169                }
     170            }
     171            if( role != null )
     172                rel.addMember(new RelationMember(role, p));
     173        }
    144174    }
    145175
     
    148178     */
    149179    private List<Command> fixWayTagsForBoundary( Relation rel ) {
    150         List<Command> commands = new ArrayList<Command>();
    151         if( !rel.hasKey("boundary") || !rel.hasKey("admin_level") )
    152             return commands;
    153         String adminLevelStr = rel.get("admin_level");
    154         int adminLevel = 0;
    155         try {
    156             adminLevel = Integer.parseInt(adminLevelStr);
    157         } catch( NumberFormatException e ) {
    158             return commands;
    159         }
    160         Set<OsmPrimitive> waysBoundary = new HashSet<OsmPrimitive>();
    161         Set<OsmPrimitive> waysAdminLevel = new HashSet<OsmPrimitive>();
    162         for( OsmPrimitive p : rel.getMemberPrimitives() ) {
    163             if( p instanceof Way ) {
    164                 int count = 0;
    165                 if( p.hasKey("boundary") && p.get("boundary").equals("administrative") )
    166                     count++;
    167                 if( p.hasKey("admin_level") )
    168                     count++;
    169                 if( p.keySet().size() - count == 0 ) {
    170                     if( !p.hasKey("boundary") )
    171                         waysBoundary.add(p);
    172                     if( !p.hasKey("admin_level") ) {
    173                         waysAdminLevel.add(p);
    174                     } else {
    175                         try {
    176                             int oldAdminLevel = Integer.parseInt(p.get("admin_level"));
    177                             if( oldAdminLevel > adminLevel )
    178                                 waysAdminLevel.add(p);
    179                         } catch( NumberFormatException e ) {
    180                             waysAdminLevel.add(p); // some garbage, replace it
    181                         }
    182                     }
    183                 }
    184             }
    185         }
    186         if( !waysBoundary.isEmpty() )
    187             commands.add(new ChangePropertyCommand(waysBoundary, "boundary", "administrative"));
    188         if( !waysAdminLevel.isEmpty() )
    189             commands.add(new ChangePropertyCommand(waysAdminLevel, "admin_level", adminLevelStr));
    190         return commands;
    191     }
    192 
    193     static public final String[] DEFAULT_LINEAR_TAGS = {"barrier", "source"};
    194 
     180        List<Command> commands = new ArrayList<Command>();
     181        if( !rel.hasKey("boundary") || !rel.hasKey("admin_level") )
     182            return commands;
     183        String adminLevelStr = rel.get("admin_level");
     184        int adminLevel = 0;
     185        try {
     186            adminLevel = Integer.parseInt(adminLevelStr);
     187        } catch( NumberFormatException e ) {
     188            return commands;
     189        }
     190        Set<OsmPrimitive> waysBoundary = new HashSet<OsmPrimitive>();
     191        Set<OsmPrimitive> waysAdminLevel = new HashSet<OsmPrimitive>();
     192        for( OsmPrimitive p : rel.getMemberPrimitives() ) {
     193            if( p instanceof Way ) {
     194                int count = 0;
     195                if( p.hasKey("boundary") && p.get("boundary").equals("administrative") )
     196                    count++;
     197                if( p.hasKey("admin_level") )
     198                    count++;
     199                if( p.keySet().size() - count == 0 ) {
     200                    if( !p.hasKey("boundary") )
     201                        waysBoundary.add(p);
     202                    if( !p.hasKey("admin_level") ) {
     203                        waysAdminLevel.add(p);
     204                    } else {
     205                        try {
     206                            int oldAdminLevel = Integer.parseInt(p.get("admin_level"));
     207                            if( oldAdminLevel > adminLevel )
     208                                waysAdminLevel.add(p);
     209                        } catch( NumberFormatException e ) {
     210                            waysAdminLevel.add(p); // some garbage, replace it
     211                        }
     212                    }
     213                }
     214            }
     215        }
     216        if( !waysBoundary.isEmpty() )
     217            commands.add(new ChangePropertyCommand(waysBoundary, "boundary", "administrative"));
     218        if( !waysAdminLevel.isEmpty() )
     219            commands.add(new ChangePropertyCommand(waysAdminLevel, "admin_level", adminLevelStr));
     220        return commands;
     221    }
     222    static public final List<String> DEFAULT_LINEAR_TAGS = Arrays.asList(new String[] {"barrier", "source"});
    195223    private static final Set<String> REMOVE_FROM_BOUNDARY_TAGS = new TreeSet<String>(Arrays.asList(new String[] {
    196         "boundary", "boundary_type", "type", "admin_level"
    197     }));
     224                "boundary", "boundary_type", "type", "admin_level"
     225            }));
    198226
    199227    /**
     
    202230     * Todo: rewrite it.
    203231     */
    204     private List<Command> removeTagsFromInnerWays(Relation relation) {
    205         Map<String, String> values = new HashMap<String, String>();
    206 
    207         if (relation.hasKeys()){
    208             for(String key: relation.keySet()) {
    209                 values.put(key, relation.get(key));
    210             }
    211         }
    212 
    213         List<Way> innerWays = new ArrayList<Way>();
    214         List<Way> outerWays = new ArrayList<Way>();
    215 
    216         Set<String> conflictingKeys = new TreeSet<String>();
    217 
    218         for (RelationMember m: relation.getMembers()) {
    219 
    220             if (m.hasRole() && m.getRole() == "inner" && m.isWay() && m.getWay().hasKeys()) {
    221                 innerWays.add(m.getWay());
    222             }
    223 
    224             if (m.hasRole() && m.getRole() == "outer" && m.isWay() && m.getWay().hasKeys()) {
    225                 Way way = m.getWay();
    226                 outerWays.add(way);
    227                 for (String key: way.keySet()) {
    228                     if (!values.containsKey(key)) { //relation values take precedence
    229                         values.put(key, way.get(key));
    230                     } else if( !relation.hasKey(key) && !values.get(key).equals(way.get(key)) ) {
    231                         conflictingKeys.add(key);
    232                     }
    233                 }
    234             }
    235         }
    236 
    237         // filter out empty key conflicts - we need second iteration
    238         boolean isBoundary = getPref("boundary");
    239         if( isBoundary || !getPref("alltags") )
    240         for( RelationMember m: relation.getMembers() )
    241             if( m.hasRole() && m.getRole().equals("outer") && m.isWay() )
    242                 for( String key : values.keySet() )
    243                     if( !m.getWay().hasKey(key) && !relation.hasKey(key) )
    244                         conflictingKeys.add(key);
    245 
    246         for( String key : conflictingKeys )
    247             values.remove(key);
    248 
    249         for( String linearTag : Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", Arrays.asList(DEFAULT_LINEAR_TAGS)))
    250             values.remove(linearTag);
    251 
    252         if( values.containsKey("natural") && values.get("natural").equals("coastline") )
    253             values.remove("natural");
    254 
    255         String name = values.get("name");
    256         if( isBoundary ) {
    257             Set<String> keySet = new TreeSet<String>(values.keySet());
    258             for( String key : keySet )
    259                 if( !REMOVE_FROM_BOUNDARY_TAGS.contains(key) )
    260                     values.remove(key);
    261         }
    262 
    263         values.put("area", "yes");
    264 
    265         List<Command> commands = new ArrayList<Command>();
    266         boolean moveTags = getPref("tags");
    267 
    268         for(String key: values.keySet()) {
    269             List<OsmPrimitive> affectedWays = new ArrayList<OsmPrimitive>();
    270             String value = values.get(key);
    271 
    272             for (Way way: innerWays) {
    273                 if( way.hasKey(key) && (isBoundary || value.equals(way.get(key))) ) {
    274                     affectedWays.add(way);
    275                 }
    276             }
    277 
    278             if( moveTags ) {
    279                 // remove duplicated tags from outer ways
    280                 for (Way way: outerWays) {
    281                     if (way.hasKey(key)) {
    282                         affectedWays.add(way);
    283                     }
    284                 }
    285             }
    286 
    287             if (affectedWays.size() > 0) {
    288                 commands.add(new ChangePropertyCommand(affectedWays, key, null));
    289             }
    290         }
    291 
    292         if( moveTags ) {
    293             // add those tag values to the relation
    294             if( isBoundary )
    295                 values.put("name", name);
    296             boolean fixed = false;
    297             Relation r2 = new Relation(relation);
    298             for( String key : values.keySet() ) {
    299                 if( !r2.hasKey(key) && !key.equals("area")
    300                         && (!isBoundary || key.equals("admin_level") || key.equals("name"))) {
    301                     if( relation.isNew() )
    302                         relation.put(key, values.get(key));
    303                     else
    304                         r2.put(key, values.get(key));
    305                     fixed = true;
    306                 }
    307             }
    308             if( fixed && !relation.isNew() )
    309                 commands.add(new ChangeCommand(relation, r2));
    310         }
    311 
    312         return commands;
     232    private List<Command> removeTagsFromInnerWays( Relation relation ) {
     233        Map<String, String> values = new HashMap<String, String>();
     234
     235        if( relation.hasKeys() ) {
     236            for( String key : relation.keySet() ) {
     237                values.put(key, relation.get(key));
     238            }
     239        }
     240
     241        List<Way> innerWays = new ArrayList<Way>();
     242        List<Way> outerWays = new ArrayList<Way>();
     243
     244        Set<String> conflictingKeys = new TreeSet<String>();
     245
     246        for( RelationMember m : relation.getMembers() ) {
     247
     248            if( m.hasRole() && "inner".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {
     249                innerWays.add(m.getWay());
     250            }
     251
     252            if( m.hasRole() && "outer".equals(m.getRole()) && m.isWay() && m.getWay().hasKeys() ) {
     253                Way way = m.getWay();
     254                outerWays.add(way);
     255                for( String key : way.keySet() ) {
     256                    if( !values.containsKey(key) ) { //relation values take precedence
     257                        values.put(key, way.get(key));
     258                    } else if( !relation.hasKey(key) && !values.get(key).equals(way.get(key)) ) {
     259                        conflictingKeys.add(key);
     260                    }
     261                }
     262            }
     263        }
     264
     265        // filter out empty key conflicts - we need second iteration
     266        boolean isBoundary = getPref("boundary");
     267        if( isBoundary || !getPref("alltags") )
     268            for( RelationMember m : relation.getMembers() )
     269                if( m.hasRole() && m.getRole().equals("outer") && m.isWay() )
     270                    for( String key : values.keySet() )
     271                        if( !m.getWay().hasKey(key) && !relation.hasKey(key) )
     272                            conflictingKeys.add(key);
     273
     274        for( String key : conflictingKeys )
     275            values.remove(key);
     276
     277        for( String linearTag : Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS) )
     278            values.remove(linearTag);
     279
     280        if( values.containsKey("natural") && values.get("natural").equals("coastline") )
     281            values.remove("natural");
     282
     283        String name = values.get("name");
     284        if( isBoundary ) {
     285            Set<String> keySet = new TreeSet<String>(values.keySet());
     286            for( String key : keySet )
     287                if( !REMOVE_FROM_BOUNDARY_TAGS.contains(key) )
     288                    values.remove(key);
     289        }
     290
     291        values.put("area", "yes");
     292
     293        List<Command> commands = new ArrayList<Command>();
     294        boolean moveTags = getPref("tags");
     295
     296        for( String key : values.keySet() ) {
     297            List<OsmPrimitive> affectedWays = new ArrayList<OsmPrimitive>();
     298            String value = values.get(key);
     299
     300            for( Way way : innerWays ) {
     301                if( way.hasKey(key) && (isBoundary || value.equals(way.get(key))) ) {
     302                    affectedWays.add(way);
     303                }
     304            }
     305
     306            if( moveTags ) {
     307                // remove duplicated tags from outer ways
     308                for( Way way : outerWays ) {
     309                    if( way.hasKey(key) ) {
     310                        affectedWays.add(way);
     311                    }
     312                }
     313            }
     314
     315            if( affectedWays.size() > 0 ) {
     316                commands.add(new ChangePropertyCommand(affectedWays, key, null));
     317            }
     318        }
     319
     320        if( moveTags ) {
     321            // add those tag values to the relation
     322            if( isBoundary )
     323                values.put("name", name);
     324            boolean fixed = false;
     325            Relation r2 = new Relation(relation);
     326            for( String key : values.keySet() ) {
     327                if( !r2.hasKey(key) && !key.equals("area")
     328                        && (!isBoundary || key.equals("admin_level") || key.equals("name")) ) {
     329                    if( relation.isNew() )
     330                        relation.put(key, values.get(key));
     331                    else
     332                        r2.put(key, values.get(key));
     333                    fixed = true;
     334                }
     335            }
     336            if( fixed && !relation.isNew() )
     337                commands.add(new ChangeCommand(relation, r2));
     338        }
     339
     340        return commands;
    313341    }
    314342
     
    319347     */
    320348    private boolean askForAdminLevelAndName( Relation rel ) {
    321         String relAL = rel.get("admin_level");
    322         String relName = rel.get("name");
    323         if( relAL != null && relName != null )
    324             return true;
    325 
    326         JPanel panel = new JPanel(new GridBagLayout());
    327         panel.add(new JLabel(tr("Enter admin level and name for the border relation:")), GBC.eol().insets(0, 0, 0, 5));
    328 
    329         final JTextField admin = new JTextField();
    330         admin.setText(relAL != null ? relAL : Main.pref.get(PREF_MULTIPOLY + "lastadmin", ""));
    331         panel.add(new JLabel(tr("Admin level")), GBC.std());
    332         panel.add(Box.createHorizontalStrut(10), GBC.std());
    333         panel.add(admin, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5));
    334 
    335         final JTextField name = new JTextField();
    336         if( relName != null )
    337             name.setText(relName);
    338         panel.add(new JLabel(tr("Name")), GBC.std());
    339         panel.add(Box.createHorizontalStrut(10), GBC.std());
    340         panel.add(name, GBC.eol().fill(GBC.HORIZONTAL));
    341 
    342         final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
    343             @Override
    344             public void selectInitialValue() {
    345                 admin.requestFocusInWindow();
    346                 admin.selectAll();
    347             }
    348         };
    349         final JDialog dlg = optionPane.createDialog(Main.parent, tr("Create a new relation"));
    350         dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
    351 
    352         name.addActionListener(new ActionListener() {
    353             public void actionPerformed( ActionEvent e ) {
    354                 dlg.setVisible(false);
    355                 optionPane.setValue(JOptionPane.OK_OPTION);
    356             }
    357         });
    358 
    359         dlg.setVisible(true);
    360 
    361         Object answer = optionPane.getValue();
    362         if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
    363                 || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) {
    364             return false;
    365         }
    366 
    367         String admin_level = admin.getText().trim();
    368         String new_name = name.getText().trim();
    369         if( admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0))) ) {
    370             rel.put("admin_level", admin_level);
    371             Main.pref.put(PREF_MULTIPOLY + "lastadmin", admin_level);
    372         }
    373         if( new_name.length() > 0 )
    374             rel.put("name", new_name);
    375         return true;
     349        String relAL = rel.get("admin_level");
     350        String relName = rel.get("name");
     351        if( relAL != null && relName != null )
     352            return true;
     353
     354        JPanel panel = new JPanel(new GridBagLayout());
     355        panel.add(new JLabel(tr("Enter admin level and name for the border relation:")), GBC.eol().insets(0, 0, 0, 5));
     356
     357        final JTextField admin = new JTextField();
     358        admin.setText(relAL != null ? relAL : Main.pref.get(PREF_MULTIPOLY + "lastadmin", ""));
     359        panel.add(new JLabel(tr("Admin level")), GBC.std());
     360        panel.add(Box.createHorizontalStrut(10), GBC.std());
     361        panel.add(admin, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 0, 5));
     362
     363        final JTextField name = new JTextField();
     364        if( relName != null )
     365            name.setText(relName);
     366        panel.add(new JLabel(tr("Name")), GBC.std());
     367        panel.add(Box.createHorizontalStrut(10), GBC.std());
     368        panel.add(name, GBC.eol().fill(GBC.HORIZONTAL));
     369
     370        final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
     371            @Override
     372            public void selectInitialValue() {
     373                admin.requestFocusInWindow();
     374                admin.selectAll();
     375            }
     376        };
     377        final JDialog dlg = optionPane.createDialog(Main.parent, tr("Create a new relation"));
     378        dlg.setModalityType(ModalityType.DOCUMENT_MODAL);
     379
     380        name.addActionListener(new ActionListener() {
     381            public void actionPerformed( ActionEvent e ) {
     382                dlg.setVisible(false);
     383                optionPane.setValue(JOptionPane.OK_OPTION);
     384            }
     385        });
     386
     387        dlg.setVisible(true);
     388
     389        Object answer = optionPane.getValue();
     390        if( answer == null || answer == JOptionPane.UNINITIALIZED_VALUE
     391                || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION) ) {
     392            return false;
     393        }
     394
     395        String admin_level = admin.getText().trim();
     396        String new_name = name.getText().trim();
     397        if( admin_level.equals("10") || (admin_level.length() == 1 && Character.isDigit(admin_level.charAt(0))) ) {
     398            rel.put("admin_level", admin_level);
     399            Main.pref.put(PREF_MULTIPOLY + "lastadmin", admin_level);
     400        }
     401        if( new_name.length() > 0 )
     402            rel.put("name", new_name);
     403        return true;
     404    }
     405
     406    private boolean areAllOfThoseRings( Collection<Way> ways ) {
     407        List<Way> rings = new ArrayList<Way>();
     408        List<Way> otherWays = new ArrayList<Way>();
     409        for( Way way : ways ) {
     410            if( way.isClosed() )
     411                rings.add(way);
     412            else
     413                otherWays.add(way);
     414        }
     415        if( rings.isEmpty() || ways.size() == 1 )
     416            return false; // todo: for one ring, attach it to neares multipolygons
     417
     418        // check that every segment touches just one ring
     419        for( Way segment : otherWays ) {
     420            boolean found = false;
     421            for( Way ring : rings ) {
     422                System.out.println("segment " + segment.getId() + ", ring " + ring.getId());
     423                System.out.println("ring.containsNode(segment.firstNode()) = " + ring.containsNode(segment.firstNode()));
     424                System.out.println("ring.containsNode(segment.lastNode() = " + ring.containsNode(segment.lastNode()));
     425                System.out.println("segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()) = " + segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()));
     426                if( ring.containsNode(segment.firstNode()) && ring.containsNode(segment.lastNode())
     427                        && !segmentInsidePolygon(segment.getNode(0), segment.getNode(1), ring.getNodes()) )
     428                    found = true;
     429            }
     430            if( !found )
     431                return false;
     432        }
     433
     434        // check for non-containment of rings
     435        for( int i = 0; i < rings.size() - 1; i++ ) {
     436            for( int j = i + 1; j < rings.size(); j++ ) {
     437                PolygonIntersection intersection = Geometry.polygonIntersection(rings.get(i).getNodes(), rings.get(j).getNodes());
     438                if( intersection == PolygonIntersection.FIRST_INSIDE_SECOND || intersection == PolygonIntersection.SECOND_INSIDE_FIRST )
     439                    return false;
     440            }
     441        }
     442
     443        return true;
     444    }
     445
     446    /**
     447     * Creates ALOT of Multipolygons and pets him gently.
     448     * @return list of new relations.
     449     */
     450    private List<Relation> makeManySimpleMultipolygons( Collection<Way> selection ) {
     451        List<Command> commands = new ArrayList<Command>();
     452        List<Way> ways = new ArrayList<Way>(selection.size());
     453        Map<Way, Way> wayDiff = new HashMap<Way, Way>(selection.size());
     454        List<Relation> relations = new ArrayList<Relation>(ways.size());
     455        Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);
     456        for( Way w : selection ) {
     457            Way newWay = new Way(w);
     458            wayDiff.put(w, newWay);
     459            commands.add(new ChangeCommand(w, newWay));
     460            ways.add(newWay);
     461            Relation r = new Relation();
     462            r.put("type", "multipolygon");
     463            r.addMember(new RelationMember("outer", w));
     464            // move tags to relations
     465            for( String key : newWay.keySet() ) {
     466                if( !linearTags.contains(key) ) {
     467                    r.put(key, newWay.get(key));
     468                    newWay.remove(key);
     469                }
     470            }
     471            if( !w.isClosed() ) {
     472                Way ring = null;
     473                for( Way tring : selection )
     474                    if( tring.containsNode(newWay.firstNode()) && tring.containsNode(newWay.lastNode())
     475                            && !segmentInsidePolygon(newWay.getNode(0), newWay.getNode(1), tring.getNodes()) )
     476                        ring = tring;
     477                Way intersection = makeIntersectionLine(newWay, ring);
     478                commands.add(new AddCommand(intersection));
     479                r.addMember(new RelationMember("outer", intersection));
     480            }
     481            relations.add(r);
     482        }
     483
     484        for( int i = 0; i < relations.size() - 1; i++ )
     485            for( int j = i + 1; j < relations.size(); j++ )
     486                collideMultipolygons(relations.get(i), relations.get(j), commands, wayDiff);
     487
     488        for( Relation r : relations )
     489            commands.add(new AddCommand(r));
     490        Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygons from rings"), commands));
     491        return relations;
     492    }
     493
     494    /**
     495     * Copies segment from {@code ring} to close a multipolygon containing {@code segment}.
     496     * @param segment Unclosed segment.
     497     * @param ring Closed ring.
     498     * @return Missing way.
     499     */
     500    private Way makeIntersectionLine( Way segment, Way ring ) {
     501        List<Node> nodes = new ArrayList<Node>(ring.getNodes());
     502        nodes.remove(nodes.size() - 1);
     503        int index1 = nodes.indexOf(segment.firstNode());
     504        int index2 = nodes.indexOf(segment.lastNode());
     505        if( index1 == index2 || index1 < 0 || index2 < 0 )
     506            return null;
     507
     508        // split ring
     509        List<List<Node>> chunks = new ArrayList<List<Node>>(2);
     510        chunks.add(new ArrayList<Node>());
     511        chunks.add(new ArrayList<Node>());
     512        int chunk = 0, i = index1;
     513        boolean madeCircle = false;
     514        while( i != index1 || !madeCircle ) {
     515            chunks.get(chunk).add(nodes.get(i));
     516            if( i == index2 ) {
     517                chunk = 1 - chunk;
     518                chunks.get(chunk).add(nodes.get(i));
     519            }
     520            if( ++i >= nodes.size() )
     521                i = 0;
     522            madeCircle = true;
     523        }
     524        chunks.get(chunk).add(nodes.get(i));
     525
     526        // check which segment to add
     527        List<Node> testRing = new ArrayList<Node>(segment.getNodes());
     528        closePolygon(testRing, chunks.get(0));
     529        chunk = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? 1 : 0;
     530
     531        // create way
     532        Way w = new Way();
     533        w.setKeys(segment.getKeys());
     534        w.setNodes(chunks.get(chunk));
     535        return w;
     536    }
     537
     538    /**
     539     * Appends "append" to "base" so the closed polygon forms.
     540     */
     541    private void closePolygon( List<Node> base, List<Node> append ) {
     542        if( append.get(0).equals(base.get(0)) && append.get(append.size() - 1).equals(base.get(base.size() - 1)) ) {
     543            List<Node> ap2 = new ArrayList<Node>(append);
     544            Collections.reverse(ap2);
     545            append = ap2;
     546        }
     547        base.remove(base.size() - 1);
     548        base.addAll(append);
     549    }
     550
     551    /**
     552     * Checks if a middle point between two nodes is inside a polygon. Useful to check if the way is inside.
     553     */
     554    private boolean segmentInsidePolygon( Node n1, Node n2, List<Node> polygon ) {
     555        EastNorth en1 = n1.getEastNorth();
     556        EastNorth en2 = n2.getEastNorth();
     557        Node testNode = new Node(new EastNorth((en1.east() + en2.east()) / 2.0, (en1.north() + en2.north()) / 2.0));
     558        return Geometry.nodeInsidePolygon(testNode, polygon);
     559    }
     560
     561    /**
     562     * Removes any intersections between multipolygons.
     563     * @param r1 First multipolygon.
     564     * @param r2 Second multipolygon.
     565     * @param commands List of commands. Only add way commands go there, also see wayDiff.
     566     * @param wayDiff The mapping old way to new Way: if there is no entry in this map, it is created, and
     567     * a ChangeCommand is issued.
     568     */
     569    private static void collideMultipolygons( Relation r1, Relation r2, List<Command> commands, Map<Way, Way> wayDiff ) {
     570    }
     571
     572    /**
     573     * Splits a way with regard to containing relations. This modifies the way and the relation, be prepared.
     574     * @param w The way.
     575     * @param n The node to split at.
     576     * @param commands List of commands to add way/relation changing to. If null, never mind.
     577     * @return Newly created ways. <b>Warning:</b> if commands is no not, newWays contains {@code w}.
     578     */
     579    public static List<Way> splitWay( Way w, Node n1, Node n2, List<Command> commands ) {
     580        List<Node> nodes = new ArrayList<Node>(w.getNodes());
     581        if( w.isClosed())
     582            nodes.remove(nodes.size()-1);
     583        int index1 = nodes.indexOf(n1);
     584        int index2 = n2 == null ? -1 : nodes.indexOf(n2);
     585        if( index1 > index2 ) {
     586            int tmp = index1;
     587            index1 = index2;
     588            index2 = tmp;
     589        }
     590        // right now index2 >= index1
     591        if( index2 < 1 || index1 >= w.getNodesCount() - 1 || index2 >= w.getNodesCount() )
     592            return Collections.emptyList();
     593        if( w.isClosed() && (index1 < 0 || index1 == index2 || index1 + w.getNodesCount() == index2) )
     594            return Collections.emptyList();
     595
     596        // make a list of segments
     597        List<List<Node>> chunks = new ArrayList<List<Node>>(2);
     598        List<Node> chunk = new ArrayList<Node>();
     599        for( int i = 0; i < nodes.size(); i++ ) {
     600            chunk.add(nodes.get(i));
     601            if( (w.isClosed() || chunk.size() > 1) && (i == index1 || i == index2) ) {
     602                chunks.add(chunk);
     603                chunk = new ArrayList<Node>();
     604                chunk.add(nodes.get(i));
     605            }
     606        }
     607        chunks.add(chunk);
     608
     609        // for closed way ignore the way boundary
     610        if( w.isClosed() ) {
     611            chunks.get(chunks.size() - 1).addAll(chunks.get(0));
     612            chunks.remove(0);
     613        } else if( chunks.get(chunks.size()-1).size() < 2 )
     614            chunks.remove(chunks.size()-1);
     615       
     616        // todo remove debug: show chunks array contents
     617        /*for( List<Node> c1 : chunks ) {
     618            for( Node cn1 : c1 )
     619                System.out.print(cn1.getId() + ",");
     620            System.out.println();
     621        }*/
     622
     623        // build a map of referencing relations
     624        Map<Relation, Integer> references = new HashMap<Relation, Integer>();
     625        List<Command> relationCommands = new ArrayList<Command>();
     626        for( OsmPrimitive p : w.getReferrers() ) {
     627            if( p instanceof Relation ) {
     628                Relation rel = commands == null ? (Relation)p : new Relation((Relation)p);
     629                if( commands != null )
     630                    relationCommands.add(new ChangeCommand((Relation)p, rel));
     631                for( int i = 0; i < rel.getMembersCount(); i++ )
     632                    if( rel.getMember(i).getMember().equals(w) )
     633                        references.put(rel, Integer.valueOf(i));
     634            }
     635        }
     636
     637        // build ways
     638        List<Way> result = new ArrayList<Way>();
     639        Way updatedWay = commands == null ? w : new Way(w);
     640        updatedWay.setNodes(chunks.get(0));
     641        if( commands != null ) {
     642            commands.add(new ChangeCommand(w, updatedWay));
     643            result.add(updatedWay);
     644        }
     645
     646        for( int i = 1; i < chunks.size(); i++ ) {
     647            List<Node> achunk = chunks.get(i);
     648            Way newWay = new Way();
     649            newWay.setKeys(w.getKeys());
     650            result.add(newWay);
     651            for( Relation rel : references.keySet() ) {
     652                int relIndex = references.get(rel);
     653                rel.addMember(relIndex + 1, new RelationMember(rel.getMember(relIndex).getRole(), newWay));
     654            }
     655            newWay.setNodes(achunk);
     656            if( commands != null )
     657                commands.add(new AddCommand(newWay));
     658        }
     659        if( commands != null )
     660            commands.addAll(relationCommands);
     661        return result;
     662    }
     663
     664    public static List<Way> splitWay( Way w, Node n1, Node n2 ) {
     665        return splitWay(w, n1, n2, null);
     666    }
     667
     668    /**
     669     * Find a way the tips of a segment, ensure it's in a multipolygon and try to close the relation.
     670     */
     671    private Relation tryToCloseOneWay( Way segment ) {
     672        if( segment.isClosed() || segment.isIncomplete() )
     673            return null;
     674
     675        List<Way> ways = intersection(
     676                OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class),
     677                OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class));
     678        ways.remove(segment);
     679        for( Iterator<Way> iter = ways.iterator(); iter.hasNext(); ) {
     680            boolean save = false;
     681            for( OsmPrimitive ref : iter.next().getReferrers() )
     682                if( ref instanceof Relation && ((Relation)ref).isMultipolygon() && !ref.isDeleted() )
     683                    save = true;
     684            if( !save )
     685                iter.remove();
     686        }
     687        if( ways.isEmpty() )
     688            return null; // well...
     689        Way target = ways.get(0);
     690
     691        // time to create a new multipolygon relation and a command stack
     692        List<Command> commands = new ArrayList<Command>();
     693        Relation newRelation = new Relation();
     694        newRelation.put("type", "multipolygon");
     695        newRelation.addMember(new RelationMember("outer", segment));
     696        Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);
     697        Way segmentCopy = new Way(segment);
     698        boolean changed = false;
     699        for( String key : segmentCopy.keySet() ) {
     700            if( !linearTags.contains(key) ) {
     701                newRelation.put(key, segmentCopy.get(key));
     702                segmentCopy.remove(key);
     703                changed = true;
     704            }
     705        }
     706        if( changed )
     707            commands.add(new ChangeCommand(segment, segmentCopy));
     708
     709        // now split the way, at last
     710        List<Way> newWays = new ArrayList<Way>(splitWay(target, segment.firstNode(), segment.lastNode(), commands));
     711
     712        Way addingWay = null;
     713        if( target.isClosed() ) {
     714            Way utarget = newWays.get(1);
     715            Way alternate = newWays.get(0);
     716            List<Node> testRing = new ArrayList<Node>(segment.getNodes());
     717            closePolygon(testRing, utarget.getNodes());
     718            addingWay = segmentInsidePolygon(alternate.getNode(0), alternate.getNode(1), testRing) ? alternate : utarget;
     719        } else {
     720            for( Way w : newWays ) {
     721                if( (w.firstNode().equals(segment.firstNode()) && w.lastNode().equals(segment.lastNode()))
     722                        || (w.firstNode().equals(segment.lastNode()) && w.lastNode().equals(segment.firstNode())) ) {
     723                    addingWay = w;
     724                    break;
     725                }
     726            }
     727        }
     728        newRelation.addMember(new RelationMember("outer", addingWay.getUniqueId() == target.getUniqueId() ? target : addingWay));
     729        commands.add(new AddCommand(newRelation));
     730        Main.main.undoRedo.add(new SequenceCommand(tr("Complete multipolygon for way {0}",
     731                DefaultNameFormatter.getInstance().format(segment)), commands));
     732        return newRelation;
     733    }
     734
     735    /**
     736     * Find a multipolygon at the tips of a segment, try to close the way.
     737     *
     738     * Note: this method is abandoned because of it's skyrocketing complexity. The only thing is
     739     * left to write is splitting and ordering ways (see below). But I doubt there is a point to it.
     740     */
     741    private Relation tryToCloseOneWayOld( Way segment ) {
     742        if( segment.isClosed() || segment.isIncomplete() )
     743            return null;
     744
     745        // find relations that have ways from both arrays
     746        Set<Relation> relations1 = new HashSet<Relation>();
     747        for( Way way : OsmPrimitive.getFilteredList(segment.firstNode().getReferrers(), Way.class) )
     748            relations1.addAll(OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class));
     749        Set<Relation> relations2 = new HashSet<Relation>();
     750        for( Way way : OsmPrimitive.getFilteredList(segment.lastNode().getReferrers(), Way.class) )
     751            relations2.addAll(OsmPrimitive.getFilteredList(way.getReferrers(), Relation.class));
     752        List<Relation> relations = intersection(relations1, relations2);
     753        for( Iterator<Relation> iter = relations.iterator(); iter.hasNext(); ) {
     754            Relation candidate = iter.next();
     755            if( !candidate.isMultipolygon() || candidate.isDeleted() || candidate.isIncomplete() )
     756                iter.remove();
     757        }
     758        if( relations.isEmpty() )
     759            return null;
     760        int i = 0;
     761        String error = "";
     762        MultipolygonCreate mpc = new MultipolygonCreate();
     763        JoinedPolygon poly = null;
     764        while( error != null && i < relations.size() ) {
     765            error = mpc.makeFromWays(OsmPrimitive.getFilteredSet(relations.get(i).getMemberPrimitives(), Way.class));
     766            if( error != null ) {
     767                for( JoinedPolygon p : mpc.outerWays ) {
     768                    if( p.nodes.contains(segment.firstNode()) && p.nodes.contains(segment.lastNode()) ) {
     769                        poly = p;
     770                        break;
     771                    }
     772                }
     773            }
     774            i++;
     775        }
     776        if( poly == null )
     777            return null; // no correct multipolygons with outer contour that segment touches
     778        Relation multipolygon = relations.get(i - 1);
     779
     780        // time to create a new multipolygon relation and a command stack
     781        List<Command> commands = new ArrayList<Command>();
     782        Relation newRelation = new Relation();
     783        newRelation.put("type", "multipolygon");
     784        newRelation.addMember(new RelationMember("outer", segment));
     785        Collection<String> linearTags = Main.pref.getCollection(PREF_MULTIPOLY + "lineartags", DEFAULT_LINEAR_TAGS);
     786        Way segmentCopy = new Way(segment);
     787        boolean changed = false;
     788        for( String key : segmentCopy.keySet() ) {
     789            if( !linearTags.contains(key) ) {
     790                newRelation.put(key, segmentCopy.get(key));
     791                segmentCopy.remove(key);
     792                changed = true;
     793            }
     794        }
     795        if( changed )
     796            commands.add(new ChangeCommand(segment, segmentCopy));
     797
     798        // find a path from one point to another via found outer contour
     799        // but first, determine in which order to traverse nodes
     800        int index1 = poly.nodes.indexOf(segment.firstNode());
     801        int index2 = poly.nodes.indexOf(segment.lastNode());
     802
     803        List<List<Node>> chunks = new ArrayList<List<Node>>(2);
     804        chunks.add(new ArrayList<Node>());
     805        chunks.add(new ArrayList<Node>());
     806        int chunk = 0;
     807        i = index1;
     808        boolean madeCircle = false;
     809        while( i != index1 || !madeCircle ) {
     810            chunks.get(chunk).add(poly.nodes.get(i));
     811            if( i == index2 ) {
     812                chunk = 1 - chunk;
     813                chunks.get(chunk).add(poly.nodes.get(i));
     814            }
     815            if( ++i >= poly.nodes.size() )
     816                i = 0;
     817            madeCircle = true;
     818        }
     819        chunks.get(chunk).add(poly.nodes.get(i));
     820
     821        // check which segment to add
     822        List<Node> testRing = new ArrayList<Node>(segment.getNodes());
     823        closePolygon(testRing, chunks.get(0));
     824//      Node startNode = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? segment.lastNode() : segment.firstNode();
     825//      Node endNode = startNode.equals(segment.firstNode()) ? segment.lastNode() : segment.firstNode();
     826        int startIndex = segmentInsidePolygon(chunks.get(1).get(0), chunks.get(1).get(1), testRing) ? index2 : index1;
     827        int endIndex = startIndex == index2 ? index1 : index2;
     828        Node startNode = poly.nodes.get(startIndex);
     829        Node endNode = poly.nodes.get(endIndex);
     830
     831        // add ways containing nodes from startNode to endNode
     832        // note: they are in order!
     833        i = 0;
     834        while( i < poly.ways.size() && !poly.ways.get(i).containsNode(startNode) )
     835            i++;
     836        int startNodeIndex = poly.ways.get(i).getNodes().indexOf(startNode);
     837        if( startNodeIndex == 0 || startNodeIndex == poly.ways.get(i).getNodesCount() - 1 )
     838            i++; // if it's the last node, take next way
     839
     840        if( poly.ways.get(i).containsNode(endNode) ) {
     841            // ok, both nodes are in the same way
     842            // split it, return the new part
     843            List<Way> newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);
     844            // find which of the parts we need (in case of closed way)
     845            Node testNode = poly.nodes.get((index1 + 1) % poly.nodes.size());
     846        } else {
     847            // so, let's take ways one by one
     848            // todo: split way 1 and add relevant part
     849            List<Way> newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);
     850            i++;
     851            while( !poly.ways.get(i).containsNode(endNode) ) {
     852                newRelation.addMember(new RelationMember("outer", poly.ways.get(i)));
     853                i++;
     854            }
     855            // todo: split way 2 and add relevant part
     856            newWays = splitWay(poly.ways.get(i), startNode, endNode, commands);
     857        }
     858
     859        commands.add(new AddCommand(newRelation));
     860        Main.main.undoRedo.add(new SequenceCommand(tr("Complete multipolygon for way {0}",
     861                DefaultNameFormatter.getInstance().format(segment)), commands));
     862        return newRelation;
     863    }
     864
     865    /**
     866     * Returns all elements from {@code list1} that are in {@code list2}.
     867     */
     868    private static <T> List<T> intersection( Collection<T> list1, Collection<T> list2 ) {
     869        List<T> result = new ArrayList<T>();
     870        for( T item : list1 )
     871            if( list2.contains(item) )
     872                result.add(item);
     873        return result;
    376874    }
    377875}
Note: See TracChangeset for help on using the changeset viewer.