Changeset 13712 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2018-05-07T23:40:50+02:00 (6 years ago)
Author:
Don-vip
Message:

see #16256 - improve "building with almost square angle" autofix: try to move only the highlighted node

Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java

    r13670 r13712  
    3333import org.openstreetmap.josm.gui.MainApplication;
    3434import org.openstreetmap.josm.gui.Notification;
     35import org.openstreetmap.josm.tools.Geometry;
    3536import org.openstreetmap.josm.tools.JosmRuntimeException;
    3637import org.openstreetmap.josm.tools.Logging;
     
    166167
    167168        try {
    168             final SequenceCommand command = orthogonalize(sel);
    169             MainApplication.undoRedo.add(new SequenceCommand(tr("Orthogonalize"), command));
     169            MainApplication.undoRedo.add(orthogonalize(sel));
    170170        } catch (InvalidUserInputException ex) {
    171171            Logging.debug(ex);
     
    205205            }
    206206        }
    207         if (wayDataList.isEmpty() && nodeList.size() > 2) {
     207        final int nodesCount = nodeList.size();
     208        if (wayDataList.isEmpty() && nodesCount > 2) {
    208209            final WayData data = new WayData(nodeList);
    209210            final Collection<Command> commands = orthogonalize(Collections.singletonList(data), Collections.<Node>emptyList());
     
    212213            throw new InvalidUserInputException("usage");
    213214        } else {
    214             if (nodeList.size() == 2 || nodeList.isEmpty()) {
     215            if (nodesCount <= 2) {
    215216                OrthogonalizeAction.rememberMovements.clear();
    216217                final Collection<Command> commands = new LinkedList<>();
    217218
    218                 if (nodeList.size() == 2) {  // fixed direction
     219                if (nodesCount == 2) {  // fixed direction, or single node to move
    219220                    commands.addAll(orthogonalize(wayDataList, nodeList));
    220                 } else if (nodeList.isEmpty()) {
    221                     List<List<WayData>> groups = buildGroups(wayDataList);
    222                     for (List<WayData> g: groups) {
     221                } else if (nodesCount == 1) {
     222                    commands.add(orthogonalize(wayDataList, nodeList.get(0)));
     223                } else if (nodesCount == 0) {
     224                    for (List<WayData> g : buildGroups(wayDataList)) {
    223225                        commands.addAll(orthogonalize(g, nodeList));
    224226                    }
    225                 } else {
    226                     throw new IllegalStateException();
    227227                }
    228228
     
    265265            }
    266266        }
     267    }
     268
     269    /**
     270     * Try to orthogonalize the given ways by moving only a single given node
     271     * @param wayDataList list of ways
     272     * @param singleNode common node to ways to orthogonalize. Only this one will be moved
     273     * @return the command to move the node
     274     * @throws InvalidUserInputException if the command cannot be computed
     275     */
     276    private static Command orthogonalize(List<WayData> wayDataList, Node singleNode) throws InvalidUserInputException {
     277        List<EastNorth> rightAnglePositions = new ArrayList<>();
     278        int wayCount = wayDataList.size();
     279        for (WayData wd : wayDataList) {
     280            int n = wd.wayNodes.size();
     281            int i = wd.wayNodes.indexOf(singleNode);
     282            Node n0, n2;
     283            if (i == 0 && n >= 3 && singleNode.equals(wd.wayNodes.get(n-1))) {
     284                n0 = wd.wayNodes.get(n-2);
     285                n2 = wd.wayNodes.get(1);
     286            } else if (i > 0 && i < n-1) {
     287                n0 = wd.wayNodes.get(i-1);
     288                n2 = wd.wayNodes.get(i+1);
     289            } else {
     290                continue;
     291            }
     292            EastNorth n0en = n0.getEastNorth();
     293            EastNorth n1en = singleNode.getEastNorth();
     294            EastNorth n2en = n2.getEastNorth();
     295            double angle = Geometry.getNormalizedAngleInDegrees(Geometry.getCornerAngle(n0en, n1en, n2en));
     296            if (wayCount == 1 || (80 <= angle && angle <= 100)) {
     297                EastNorth c = n0en.getCenter(n2en);
     298                double r = n0en.distance(n2en) / 2d;
     299                double vX = n1en.east() - c.east();
     300                double vY = n1en.north() - c.north();
     301                double magV = Math.sqrt(vX*vX + vY*vY);
     302                rightAnglePositions.add(new EastNorth(c.east() + vX / magV * r,
     303                                                     c.north() + vY / magV * r));
     304            }
     305        }
     306        if (rightAnglePositions.isEmpty()) {
     307            throw new InvalidUserInputException("Unable to orthogonalize " + singleNode);
     308        }
     309        return new MoveCommand(singleNode, Main.getProjection().eastNorth2latlon(Geometry.getCentroidEN(rightAnglePositions)));
    267310    }
    268311
     
    307350                    totSum = EN.sum(totSum, w.segSum);
    308351                }
    309                 headingAll = EN.polar(new EastNorth(0., 0.), totSum);
     352                headingAll = EN.polar(EastNorth.ZERO, totSum);
    310353            } else {
    311354                headingAll = EN.polar(headingNodes.get(0).getEastNorth(), headingNodes.get(1).getEastNorth());
     
    334377        // calculate the centroid of all nodes
    335378        // it is used as rotation center
    336         EastNorth pivot = new EastNorth(0., 0.);
     379        EastNorth pivot = EastNorth.ZERO;
    337380        for (Node n : allNodes) {
    338381            pivot = EN.sum(pivot, n.getEastNorth());
  • trunk/src/org/openstreetmap/josm/data/validation/tests/RightAngleBuildingTest.java

    r13698 r13712  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.util.Collections;
     6import java.util.Arrays;
    77import java.util.List;
    88
     
    5252                                                     .primitives(w)
    5353                                                     .highlight(pair.b);
    54                 if (angles.stream().noneMatch(
    55                         p -> Math.abs(p.a - 90) >= maxAngleDelta && Math.abs(p.a - 180) >= minAngleDelta)) {
    56                     builder.fix(() -> {
    57                         try {
    58                             return OrthogonalizeAction.orthogonalize(Collections.singleton(w));
    59                         } catch (InvalidUserInputException e) {
    60                             Logging.warn(e);
    61                             return null;
    62                         }
    63                     });
    64                 }
     54                builder.fix(() -> {
     55                    try {
     56                        return OrthogonalizeAction.orthogonalize(Arrays.asList(w, pair.b));
     57                    } catch (InvalidUserInputException e) {
     58                        Logging.warn(e);
     59                        return null;
     60                    }
     61                });
    6562                errors.add(builder.build());
    6663                return;
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r13670 r13712  
    1616import java.util.Set;
    1717import java.util.function.Predicate;
     18import java.util.stream.Collectors;
    1819
    1920import org.openstreetmap.josm.Main;
     
    796797    }
    797798
    798     /** 
     799    /**
    799800     * Get angles in radians and return it's value in range [0, 180].
    800801     *
     
    814815     */
    815816    public static EastNorth getCentroid(List<Node> nodes) {
     817        return getCentroidEN(nodes.stream().map(Node::getEastNorth).collect(Collectors.toList()));
     818    }
     819
     820    /**
     821     * Compute the centroid/barycenter of nodes
     822     * @param nodes Coordinates for which the centroid is wanted
     823     * @return the centroid of nodes
     824     * @since 13712
     825     */
     826    public static EastNorth getCentroidEN(List<EastNorth> nodes) {
     827
     828        final int size = nodes.size();
     829        if (size == 1) {
     830            return nodes.get(0);
     831        } else if (size == 2) {
     832            return nodes.get(0).getCenter(nodes.get(1));
     833        }
    816834
    817835        BigDecimal area = BigDecimal.ZERO;
     
    819837        BigDecimal east = BigDecimal.ZERO;
    820838
    821         // See https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon for the equation used here
    822         for (int i = 0; i < nodes.size(); i++) {
    823             EastNorth n0 = nodes.get(i).getEastNorth();
    824             EastNorth n1 = nodes.get((i+1) % nodes.size()).getEastNorth();
     839        // See https://en.wikipedia.org/wiki/Centroid#Centroid_of_a_polygon for the equation used here
     840        for (int i = 0; i < size; i++) {
     841            EastNorth n0 = nodes.get(i);
     842            EastNorth n1 = nodes.get((i+1) % size);
    825843
    826844            if (n0 != null && n1 != null && n0.isValid() && n1.isValid()) {
Note: See TracChangeset for help on using the changeset viewer.