1

Using Gluon Mobile 4 and Gluon Maps 1.0.1, I am displaying a map with a layer showing foot steps. When the users double clicks the mouse button, a new foot step is shown. This works great, but I currently need a workaround to convert from pointer coordinates (where the user clicked) to MapPoints (needed for the layer).

enter image description here

Here is how the mouse click is obtained:

public MainView(String name) {
    super(name);
    MapView mapView = new MapView();
    mapView.setZoom(18f);
    mapView.setCenter(NUREMBERG);
    layer = new FootStepsLayer();
    mapView.addLayer(layer);
    setCenter(mapView);

    layer.addPoint(NUREMBERG);

    setOnMouseClicked(event -> {
        if ((event.getButton() == MouseButton.PRIMARY)
                && (event.getClickCount() == 2)) {
            double x = event.getX();
            double y = event.getY();
            layer.addPoint(x, y);
        }
    });
}

Currently my layer implementation looks like this:

public class FootStepsLayer extends MapLayer {

    private static final Image FOOTSTEPS
            = new Image(FootStepsLayer.class.getResourceAsStream("/footsteps.png"),
                    32, 32, true, true);

    private final ObservableList<Pair<MapPoint, Node>> points
            = FXCollections.observableArrayList();

    public void addPoint(MapPoint mapPoint) {
        Node node = new ImageView(FOOTSTEPS);
        Pair<MapPoint, Node> pair = new Pair<>(mapPoint, node);
        points.add(pair);
        getChildren().add(node);
        markDirty();
    }

    public void addPoint(double x, double y) {
        Bounds bounds = baseMap.getParent().getLayoutBounds();
       baseMap.moveX(x - bounds.getWidth() / 2);
        baseMap.moveY(y - bounds.getHeight() / 2);
        addPoint(new MapPoint(baseMap.centerLat().get(),
                baseMap.centerLon().get()));
    }

    @Override
    protected void layoutLayer() {
        // Warning: suggested conversion to functional style crashed app on BlueStacks
        for (Pair<MapPoint, Node> element : points) {
            MapPoint mapPoint = element.getKey();
            Node node = element.getValue();
            Point2D point = baseMap.getMapPoint(mapPoint.getLatitude(), mapPoint.getLongitude());
            node.setVisible(true);
            node.setTranslateX(point.getX());
            node.setTranslateY(point.getY());
        }
    }
}

My workaround is in public void addPoint(double x, double y): I am calling moveX() and moveY(), because after that I can query centerLat() and centerLong(). This is not ideal because the map moves and the new foot step becomes the center of the map. What I want is the map position to remain unchanged.

If I have not overlooked it, there seems to be no API for converting mouse coordinates to geo locations. As answered in question create a polyline in gluon mapLayer, the BaseMap class has two getMapPoint methods, but I have found none the other way round. But there must be a way to do it. ;-)

Community
  • 1
  • 1

1 Answers1

1

If you have a look at BaseMap, there is already one method that does precisely what you are looking for, but only for the center of the map: calculateCenterCoords.

Based on it, you could add your own method to BaseMap, where the sceneX and sceneY coordinates are taken into account instead:

public MapPoint getMapPosition(double sceneX, double sceneY) {
    double x = sceneX - this.getTranslateX();
    double y = sceneY - this.getTranslateY();
    double z = zoom.get();
    double latrad = Math.PI - (2 * Math.PI * y) / (Math.pow(2, z) * 256);
    double mlat = Math.toDegrees(Math.atan(Math.sinh(latrad)));
    double mlon = x / (256 * Math.pow(2, z)) * 360 - 180;
    return new MapPoint(mlat, mlon);
}

Then you can expose this method in MapView:

public MapPoint getMapPosition(double sceneX, double sceneY) {
    return baseMap.getMapPosition(sceneX, sceneY);
}

So you can use it on your map:

mapView.setOnMouseClicked(e -> {
        MapPoint mapPosition = mapView.getMapPosition(e.getSceneX(), e.getSceneY());
        System.out.println("mapPosition: " + mapPosition.getLatitude()+ ", " + mapPosition.getLongitude());
    });

This method should be part of Maps, so feel free to create a feature request or even a pull request.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Awesome, thanks a lot. Going to create a pull request. Might take a few days. –  Nov 01 '16 at 12:03