Changeset 30872 in osm


Ignore:
Timestamp:
2014-12-21T13:55:57+01:00 (10 years ago)
Author:
donvip
Message:

[josm_terracer] fix #josm6552 - terracer unnecessarily deletes objects in favour of new ones

Location:
applications/editors/josm/plugins/terracer/src/terracer
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/terracer/src/terracer/HouseNumberInputDialog.java

    r30737 r30872  
    5555    final static String DEFAULT_SEGMENTS = "plugins.terracer.segments";
    5656    final static String HANDLE_RELATION = "plugins.terracer.handle_relation";
    57     final static String DELETE_OUTLINE = "plugins.terracer.delete_outline";
     57    final static String KEEP_OUTLINE = "plugins.terracer.keep_outline";
    5858    final static String INTERPOLATION = "plugins.terracer.interpolation";
    5959
     
    8383    Choice interpolation;
    8484    JCheckBox handleRelationCheckBox;
    85     JCheckBox deleteOutlineCheckBox;
     85    JCheckBox keepOutlineCheckBox;
    8686
    8787    HouseNumberInputHandler inputHandler;
     
    182182
    183183            handleRelationCheckBox = new JCheckBox(txt, relationExists ? Main.pref.getBoolean(HANDLE_RELATION, true) : false);
    184             deleteOutlineCheckBox = new JCheckBox(tr("delete outline way"), Main.pref.getBoolean(DELETE_OUTLINE, true));
     184            keepOutlineCheckBox = new JCheckBox(tr("keep outline way"), Main.pref.getBoolean(KEEP_OUTLINE, false));
    185185
    186186            inputPanel = new JPanel();
     
    209209            inputPanel.add(getBuilding(), GBC.eol().insets(5,3,0,0));
    210210            inputPanel.add(handleRelationCheckBox, GBC.eol().insets(3,3,0,0));
    211             inputPanel.add(deleteOutlineCheckBox, GBC.eol().insets(3,3,0,0));
    212            
     211            inputPanel.add(keepOutlineCheckBox, GBC.eol().insets(3,3,0,0));
     212
    213213            if (numbers.isVisible()) {
    214214                loLabel.setVisible(false);
     
    261261        return hi;
    262262    }
    263    
     263
    264264    /**
    265265     * This method initializes numbers
     
    270270        if (numbers == null) {
    271271            numbers = new JTextField();
    272            
     272
    273273            Iterator<Node> it = housenumbers.iterator();
    274274            StringBuilder s = new StringBuilder(256);
     
    282282                numbers.setVisible(false);
    283283            }
    284            
     284
    285285            numbers.setText(s.toString());
    286286            numbers.setEditable(false);
     
    306306        return streetComboBox;
    307307    }
    308    
     308
    309309    /**
    310310     * This method initializes building
  • applications/editors/josm/plugins/terracer/src/terracer/HouseNumberInputHandler.java

    r30643 r30872  
    304304                            streetName(),
    305305                            doHandleRelation(),
    306                             doDeleteOutline(), buildingType());
     306                            doKeepOutline(), buildingType());
    307307                    } catch (UserCancelException ex) {
    308308                        // Ignore
     
    380380        return getItemText(dialog.streetComboBox);
    381381    }
    382    
     382
    383383    /**
    384384     * Gets the building type.
     
    389389        return getItemText(dialog.buildingComboBox);
    390390    }
    391    
     391
    392392    private static String getItemText(AutoCompletingComboBox box) {
    393393        Object selected = box.getSelectedItem();
     
    430430
    431431    /**
    432      * Whether the user likes to delete the outline way.
    433      */
    434     public boolean doDeleteOutline() {
    435         return dialog.deleteOutlineCheckBox.isSelected();
     432     * Whether the user likes to keep the outline way.
     433     */
     434    public boolean doKeepOutline() {
     435        return dialog.keepOutlineCheckBox.isSelected();
    436436    }
    437437
     
    454454    public void saveValues() {
    455455        Main.pref.put(HouseNumberInputDialog.HANDLE_RELATION, doHandleRelation());
    456         Main.pref.put(HouseNumberInputDialog.DELETE_OUTLINE, doDeleteOutline());
     456        Main.pref.put(HouseNumberInputDialog.KEEP_OUTLINE, doKeepOutline());
    457457        Main.pref.put(HouseNumberInputDialog.INTERPOLATION, stepSize().toString());
    458458    }
  • applications/editors/josm/plugins/terracer/src/terracer/TerracerAction.java

    r30737 r30872  
    6969
    7070    Collection<Command> commands;
    71    
     71
    7272    private Collection<OsmPrimitive> primitives;
    7373    private TagCollection tagsInConflict;
     
    9696        return result;
    9797    }
    98    
     98
    9999    private static final class InvalidUserInputException extends Exception {
    100100        InvalidUserInputException(String message) {
     
    182182            if (outline == null || !outline.isClosed() || outline.getNodesCount() < 5)
    183183                throw new InvalidUserInputException("wrong or missing outline");
    184        
     184
    185185        } catch (InvalidUserInputException ex) {
    186186            Main.warn("Terracer: "+ex.getMessage());
     
    202202            candidates.add(street);
    203203        }
    204        
     204
    205205        Set<Relation> associatedStreets = findAssociatedStreets(candidates);
    206        
     206
    207207        if (!associatedStreets.isEmpty()) {
    208208            associatedStreet = associatedStreets.iterator().next();
     
    212212            }
    213213        }
    214        
     214
    215215        if (streetname == null && associatedStreet != null && associatedStreet.hasKey("name")) {
    216216            streetname = associatedStreet.get("name");
     
    297297     * @param associatedStreet
    298298     * @param segments The number of segments to generate
    299      * @param From Starting housenumber
    300      * @param To Ending housenumber
     299     * @param start Starting housenumber
     300     * @param end Ending housenumber
    301301     * @param step The step width to use
    302302     * @param housenumbers List of housenumbers to use. From and To are ignored
     
    306306     * @param handleRelations If the user likes to add a relation or extend an
    307307     *        existing relation
    308      * @param deleteOutline If the outline way should be deleted when done
     308     * @param keepOutline If the outline way should be kept
    309309     * @param buildingValue The value for {@code building} key to add
    310      * @throws UserCancelException
    311      */
    312     public void terraceBuilding(final Way outline,
    313                 Node init,
    314                 Way street,
    315                 Relation associatedStreet,
    316                 Integer segments,
    317                 String From,
    318                 String To,
    319                 int step,
    320                 ArrayList<Node> housenumbers,
    321                 String streetName,
    322                 boolean handleRelations,
    323                 boolean deleteOutline, String buildingValue) throws UserCancelException {
     310     * @throws UserCancelException
     311     */
     312    public void terraceBuilding(final Way outline, Node init, Way street, Relation associatedStreet, Integer segments,
     313                String start, String end, int step, List<Node> housenumbers, String streetName, boolean handleRelations,
     314                boolean keepOutline, String buildingValue) throws UserCancelException {
    324315        final int nb;
    325316        Integer to = null, from = null;
    326317        if (housenumbers == null || housenumbers.isEmpty()) {
    327             to = getNumber(To);
    328             from = getNumber(From);
     318            to = getNumber(end);
     319            from = getNumber(start);
    329320            if (to != null && from != null) {
    330321                nb = 1 + (to.intValue() - from.intValue()) / step;
     
    336327                        "Could not determine segments from parameters, this is a bug. "
    337328                                + "Parameters were: segments " + segments
    338                                 + " from " + from + " to " + to + " step "
    339                                 + step);
     329                                + " from " + from + " to " + to + " step " + step);
    340330            }
    341331        } else {
     
    346336        Pair<Way, Way> interp = findFrontAndBack(outline);
    347337
    348         boolean swap = false;
    349         if (init != null) {
    350             if (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init)) {
    351                 swap = true;
    352             }
    353         }
     338        final boolean swap = init != null && (interp.a.lastNode().equals(init) || interp.b.lastNode().equals(init));
    354339
    355340        final double frontLength = wayLength(interp.a);
     
    357342
    358343        // new nodes array to hold all intermediate nodes
    359         // This set will contain at least 4 existing nodes from the original outline (those, which coordinates match coordinates of outline nodes)
    360         Node[][] new_nodes = new Node[2][nb + 1];
     344        // This set will contain at least 4 existing nodes from the original outline
     345        // (those, which coordinates match coordinates of outline nodes)
     346        Node[][] newNodes = new Node[2][nb + 1];
    361347        // This list will contain nodes of the outline that are used in new lines.
    362348        // These nodes will not be deleted with the outline (if deleting was prompted).
    363         ArrayList<Node> reused_nodes = new ArrayList<>();
     349        List<Node> reusedNodes = new ArrayList<>();
    364350
    365351        this.commands = new LinkedList<>();
     
    367353
    368354        if (nb > 1) {
     355            // add required new nodes and build list of nodes to reuse
    369356            for (int i = 0; i <= nb; ++i) {
    370                 int i_dir = swap ? nb - i : i;
    371                 new_nodes[0][i] = interpolateAlong(interp.a, frontLength * i_dir / nb);
    372                 new_nodes[1][i] = interpolateAlong(interp.b, backLength * i_dir / nb);
    373                 if (!outline.containsNode(new_nodes[0][i]))
    374                     this.commands.add(new AddCommand(new_nodes[0][i]));
     357                int iDir = swap ? nb - i : i;
     358                newNodes[0][i] = interpolateAlong(interp.a, frontLength * iDir / nb);
     359                newNodes[1][i] = interpolateAlong(interp.b, backLength * iDir / nb);
     360                if (!outline.containsNode(newNodes[0][i]))
     361                    this.commands.add(new AddCommand(newNodes[0][i]));
    375362                else
    376                     reused_nodes.add(new_nodes[0][i]);
    377                 if (!outline.containsNode(new_nodes[1][i]))
    378                     this.commands.add(new AddCommand(new_nodes[1][i]));
     363                    reusedNodes.add(newNodes[0][i]);
     364                if (!outline.containsNode(newNodes[1][i]))
     365                    this.commands.add(new AddCommand(newNodes[1][i]));
    379366                else
    380                     reused_nodes.add(new_nodes[1][i]);
     367                    reusedNodes.add(newNodes[1][i]);
    381368            }
    382369
    383370            // assemble new quadrilateral, closed ways
    384371            for (int i = 0; i < nb; ++i) {
    385                 Way terr = new Way();
    386                 terr.addNode(new_nodes[0][i]);
    387                 terr.addNode(new_nodes[0][i + 1]);
    388                 terr.addNode(new_nodes[1][i + 1]);
    389                 terr.addNode(new_nodes[1][i]);
    390                 terr.addNode(new_nodes[0][i]);
    391 
    392                 // add the tags of the outline to each building (e.g. source=*)
    393                 TagCollection.from(outline).applyTo(terr);
    394                 ways.add(addressBuilding(terr, street, streetName, associatedStreet, housenumbers, i,
     372                final Way terr;
     373                if (i > 0 || keepOutline) {
     374                    terr = new Way();
     375                    // add the tags of the outline to each building (e.g. source=*)
     376                    TagCollection.from(outline).applyTo(terr);
     377                } else {
     378                    terr = new Way(outline);
     379                    terr.setNodes(null);
     380                }
     381
     382                terr.addNode(newNodes[0][i]);
     383                terr.addNode(newNodes[0][i + 1]);
     384                terr.addNode(newNodes[1][i + 1]);
     385                terr.addNode(newNodes[1][i]);
     386                terr.addNode(newNodes[0][i]);
     387
     388                ways.add(addressBuilding(terr, street, streetName, associatedStreet, housenumbers, i,
    395389                        from != null ? Integer.toString(from + i * step) : null, buildingValue));
    396                
    397                 this.commands.add(new AddCommand(terr));
    398             }
    399 
    400             if (deleteOutline) {
     390
     391                if (i > 0 || keepOutline) {
     392                    this.commands.add(new AddCommand(terr));
     393                } else {
     394                    this.commands.add(new ChangeCommand(outline, terr));
     395                }
     396            }
     397
     398            if (!keepOutline) {
    401399                // Delete outline nodes having no tags and referrers but the outline itself
    402400                List<Node> nodes = outline.getNodes();
    403401                ArrayList<Node> nodesToDelete = new ArrayList<>();
    404402                for (Node n : nodes)
    405                     if (!n.hasKeys() && n.getReferrers().size() == 1 && !reused_nodes.contains(n))
     403                    if (!n.hasKeys() && n.getReferrers().size() == 1 && !reusedNodes.contains(n))
    406404                        nodesToDelete.add(n);
    407                 if (nodesToDelete.size() > 0)
     405                if (!nodesToDelete.isEmpty())
    408406                    this.commands.add(DeleteCommand.delete(Main.main.getEditLayer(), nodesToDelete));
    409                 // Delete the way itself without nodes
    410                 this.commands.add(DeleteCommand.delete(Main.main.getEditLayer(), Collections.singleton(outline), false, true));
    411 
    412407            }
    413408        } else {
    414409            // Single building, just add the address details
    415             ways.add(addressBuilding(outline, street, streetName, associatedStreet, housenumbers, 0, From, buildingValue));
    416         }
    417 
    418         // Remove the address nodes since their tags have been incorporated into
    419         // the terraces.
     410            ways.add(addressBuilding(outline, street, streetName, associatedStreet, housenumbers, 0, start, buildingValue));
     411        }
     412
     413        // Remove the address nodes since their tags have been incorporated into the terraces.
    420414        // Or should removing them also be an option?
    421415        if (!housenumbers.isEmpty()) {
     
    426420        if (handleRelations) { // create a new relation or merge with existing
    427421            if (associatedStreet == null) {  // create a new relation
    428                 associatedStreet = new Relation();
    429                 associatedStreet.put("type", "associatedStreet");
    430                 if (street != null) { // a street was part of the selection
    431                     associatedStreet.put("name", street.get("name"));
    432                     associatedStreet.addMember(new RelationMember("street", street));
    433                 } else {
    434                     associatedStreet.put("name", streetName);
    435                 }
    436                 for (Way w : ways) {
    437                     associatedStreet.addMember(new RelationMember("house", w));
    438                 }
    439                 this.commands.add(new AddCommand(associatedStreet));
     422                addNewAssociatedStreetRelation(street, streetName, ways);
    440423            } else { // relation exists already - add new members
    441                 Relation newAssociatedStreet = new Relation(associatedStreet);
    442                 // remove housenumbers as they have been deleted
    443                 newAssociatedStreet.removeMembersFor(housenumbers);
    444                 for (Way w : ways) {
    445                     newAssociatedStreet.addMember(new RelationMember("house", w));
    446                 }
    447                 if (deleteOutline) {
    448                     newAssociatedStreet.removeMembersFor(outline);
    449                 }
    450                 this.commands.add(new ChangeCommand(associatedStreet, newAssociatedStreet));
    451             }
    452         }
    453 
    454         Main.main.undoRedo.add(new SequenceCommand(tr("Terrace"), commands) {
     424                updateAssociatedStreetRelation(associatedStreet, housenumbers, ways);
     425            }
     426        }
     427
     428        Main.main.undoRedo.add(createTerracingCommand(outline));
     429        if (nb <= 1 && street != null) {
     430            // Select the way (for quick selection of a new house (with the same way))
     431            Main.main.getCurrentDataSet().setSelected(street);
     432        } else {
     433            // Select the new building outlines (for quick reversing)
     434            Main.main.getCurrentDataSet().setSelected(ways);
     435        }
     436    }
     437
     438    private void updateAssociatedStreetRelation(Relation associatedStreet, List<Node> housenumbers, Collection<Way> ways) {
     439        Relation newAssociatedStreet = new Relation(associatedStreet);
     440        // remove housenumbers as they have been deleted
     441        newAssociatedStreet.removeMembersFor(housenumbers);
     442        for (Way w : ways) {
     443            newAssociatedStreet.addMember(new RelationMember("house", w));
     444        }
     445        /*if (!keepOutline) {
     446            newAssociatedStreet.removeMembersFor(outline);
     447        }*/
     448        this.commands.add(new ChangeCommand(associatedStreet, newAssociatedStreet));
     449    }
     450
     451    private void addNewAssociatedStreetRelation(Way street, String streetName, Collection<Way> ways) {
     452        Relation associatedStreet = new Relation();
     453        associatedStreet.put("type", "associatedStreet");
     454        if (street != null) { // a street was part of the selection
     455            associatedStreet.put("name", street.get("name"));
     456            associatedStreet.addMember(new RelationMember("street", street));
     457        } else {
     458            associatedStreet.put("name", streetName);
     459        }
     460        for (Way w : ways) {
     461            associatedStreet.addMember(new RelationMember("house", w));
     462        }
     463        this.commands.add(new AddCommand(associatedStreet));
     464    }
     465
     466    private Command createTerracingCommand(final Way outline) {
     467        return new SequenceCommand(tr("Terrace"), commands) {
    455468            @Override
    456469            public boolean executeCommand() {
     
    481494                return result;
    482495            }
    483         });
    484         if (nb <= 1 && street != null) {
    485             // Select the way (for quick selection of a new house (with the same way))
    486             Main.main.getCurrentDataSet().setSelected(street);
    487         } else {
    488             // Select the new building outlines (for quick reversing)
    489             Main.main.getCurrentDataSet().setSelected(ways);
    490         }
    491     }
    492    
     496        };
     497    }
     498
    493499    /**
    494500     * Adds address details to a single building
     
    500506     * @param buildingValue The value for {@code building} key to add
    501507     * @return {@code outline}
    502      * @throws UserCancelException
    503      */
    504     private Way addressBuilding(Way outline, Way street, String streetName, Relation associatedStreet, ArrayList<Node> housenumbers, int i, String defaultNumber, String buildingValue) throws UserCancelException {
     508     * @throws UserCancelException
     509     */
     510    private Way addressBuilding(Way outline, Way street, String streetName, Relation associatedStreet,
     511            List<Node> housenumbers, int i, String defaultNumber, String buildingValue) throws UserCancelException {
    505512        Node houseNum = (housenumbers != null && i >= 0 && i < housenumbers.size()) ? housenumbers.get(i) : null;
    506513        boolean buildingAdded = false;
     
    508515        if (houseNum != null) {
    509516            primitives = Arrays.asList(new OsmPrimitive[]{houseNum, outline});
    510            
     517
    511518            TagCollection tagsToCopy = TagCollection.unionOfAllPrimitives(primitives).getTagsFor(houseNum.keySet());
    512519            tagsInConflict = tagsToCopy.getTagsFor(tagsToCopy.getKeysWithMultipleValues());
    513520            tagsToCopy = tagsToCopy.minus(tagsInConflict).minus(TagCollection.from(outline));
    514            
     521
    515522            for (Tag tag : tagsToCopy) {
    516523                this.commands.add(new ChangePropertyCommand(outline, tag.getKey(), tag.getValue()));
    517524            }
    518            
     525
    519526            buildingAdded = houseNum.hasKey("building");
    520527            numberAdded = houseNum.hasKey("addr:housenumber");
Note: See TracChangeset for help on using the changeset viewer.