Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cdf7855 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Add basic Circle support

parent c9ec565b
Loading
Loading
Loading
Loading
+41 −9
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package org.microg.gms.maps;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.View;

import com.google.android.gms.R;
import org.microg.gms.maps.bitmap.DefaultBitmapDescriptor;

import org.microg.gms.maps.camera.CameraUpdate;
import org.microg.gms.maps.markup.Markup;
import org.oscim.android.MapView;
@@ -40,6 +42,8 @@ import org.oscim.theme.VtmThemes;
import org.oscim.tiling.source.oscimap4.OSciMap4TileSource;

public class BackendMap {
    private final static String TAG = "GmsBackendMap";

    private final Context context;
    private final MapView mapView;
    private final BuildingLayer buildings;
@@ -135,8 +139,21 @@ public class BackendMap {
    }

    public <T extends Markup> T add(T markup) {
        switch (markup.getType()) {
            case MARKER:
                items.addItem(markup.getMarkerItem(context));
                redraw();
                break;
            case LAYER:
                Layers layers = mapView.map().layers();
                layers.add(markup.getLayer(context, mapView.map()));
                layers.remove(items);
                layers.add(items);
                redraw();
                break;
            default:
                Log.d(TAG, "Unknown markup: " + markup);
        }
        return markup;
    }

@@ -146,14 +163,29 @@ public class BackendMap {
    }

    public void remove(Markup markup) {
        switch (markup.getType()) {
            case MARKER:
                items.removeItem(items.getByUid(markup.getId()));
                redraw();
                break;
            default:
                Log.d(TAG, "Unknown markup: " + markup);
        }
    }

    public void update(Markup markup) {
        switch (markup.getType()) {
            case MARKER:
                // TODO: keep order
                items.removeItem(items.getByUid(markup.getId()));
                items.addItem(markup.getMarkerItem(context));
                redraw();
                break;
            case LAYER:
                redraw();
                break;
            default:
                Log.d(TAG, "Unknown markup: " + markup);
        }
    }
}
+46 −7
Original line number Diff line number Diff line
@@ -22,14 +22,48 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.internal.*;
import com.google.android.gms.maps.model.*;
import com.google.android.gms.maps.model.internal.*;
import com.google.android.gms.maps.internal.ICancelableCallback;
import com.google.android.gms.maps.internal.IGoogleMapDelegate;
import com.google.android.gms.maps.internal.IInfoWindowAdapter;
import com.google.android.gms.maps.internal.ILocationSourceDelegate;
import com.google.android.gms.maps.internal.IOnCameraChangeListener;
import com.google.android.gms.maps.internal.IOnInfoWindowClickListener;
import com.google.android.gms.maps.internal.IOnMapClickListener;
import com.google.android.gms.maps.internal.IOnMapLoadedCallback;
import com.google.android.gms.maps.internal.IOnMapLongClickListener;
import com.google.android.gms.maps.internal.IOnMarkerClickListener;
import com.google.android.gms.maps.internal.IOnMarkerDragListener;
import com.google.android.gms.maps.internal.IOnMyLocationButtonClickListener;
import com.google.android.gms.maps.internal.IOnMyLocationChangeListener;
import com.google.android.gms.maps.internal.IProjectionDelegate;
import com.google.android.gms.maps.internal.ISnapshotReadyCallback;
import com.google.android.gms.maps.internal.IUiSettingsDelegate;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.GroundOverlayOptions;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.google.android.gms.maps.model.internal.ICircleDelegate;
import com.google.android.gms.maps.model.internal.IGroundOverlayDelegate;
import com.google.android.gms.maps.model.internal.IMarkerDelegate;
import com.google.android.gms.maps.model.internal.IPolygonDelegate;
import com.google.android.gms.maps.model.internal.IPolylineDelegate;
import com.google.android.gms.maps.model.internal.ITileOverlayDelegate;

import org.microg.gms.maps.camera.CameraUpdate;
import org.microg.gms.maps.markup.*;
import org.microg.gms.maps.markup.CircleImpl;
import org.microg.gms.maps.markup.GroundOverlayImpl;
import org.microg.gms.maps.markup.MarkerImpl;
import org.microg.gms.maps.markup.Markup;
import org.microg.gms.maps.markup.PolygonImpl;
import org.microg.gms.maps.markup.PolylineImpl;
import org.microg.gms.maps.markup.TileOverlayImpl;
import org.oscim.event.Event;
import org.oscim.event.MotionEvent;
import org.oscim.map.Map;
@@ -45,6 +79,7 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
    private final ProjectionImpl projection;

    private int markerCounter = 0;
    private int circleCounter = 0;

    public GoogleMapImpl(LayoutInflater inflater, GoogleMapOptions options) {
        context = inflater.getContext();
@@ -75,6 +110,10 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub
        return "m" + markerCounter++;
    }

    private String getNextCircleId() {
        return "c" + circleCounter++;
    }
    
    /*
    Camera
     */
@@ -136,7 +175,7 @@ public class GoogleMapImpl extends IGoogleMapDelegate.Stub

    @Override
    public ICircleDelegate addCircle(CircleOptions options) throws RemoteException {
        return new CircleImpl(options); // TODO
        return backendMap.add(new CircleImpl(getNextCircleId(), options, this));
    }

    @Override
+205 −26
Original line number Diff line number Diff line
@@ -16,102 +16,136 @@

package org.microg.gms.maps.markup;

import android.content.Context;
import android.os.RemoteException;

import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.internal.ICircleDelegate;

public class CircleImpl extends ICircleDelegate.Stub {
    private LatLng center;
    private double radius;
    private float zIndex;
    private boolean visible;
    private String id;
    private float strokeWidth;
    private int strokeColor;
    private int fillColor;
import org.oscim.android.gl.AndroidGL;
import org.oscim.backend.GL20;
import org.oscim.backend.canvas.Color;
import org.oscim.core.Box;
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.layers.Layer;
import org.oscim.layers.marker.MarkerItem;
import org.oscim.map.Map;
import org.oscim.renderer.GLShader;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.LayerRenderer;
import org.oscim.renderer.MapRenderer;

import static org.oscim.core.MercatorProjection.groundResolution;
import static org.oscim.core.MercatorProjection.latitudeToY;
import static org.oscim.core.MercatorProjection.longitudeToX;

public class CircleImpl extends ICircleDelegate.Stub implements Markup {

    private final String id;
    private final CircleOptions options;
    private final MarkupListener listener;
    private CircleLayer layer;
    private Point point;
    private float drawRadius;

    public CircleImpl(CircleOptions options) {
    public CircleImpl(String id, CircleOptions options, MarkupListener listener) {
        this.id = id;
        this.listener = listener;
        this.options = options == null ? new CircleOptions() : options;
        LatLng center = this.options.getCenter();
        if (center != null) {
            point = new Point(longitudeToX(center.longitude), latitudeToY(center.latitude));
            drawRadius = (float) (options.getRadius() / groundResolution(center.latitude, 1));
        }
    }

    @Override
    public void remove() throws RemoteException {

        listener.remove(this);
    }

    @Override
    public String getId() throws RemoteException {
    public String getId() {
        return id;
    }

    @Override
    public void setCenter(LatLng center) throws RemoteException {
        this.center = center;
        options.center(center);
        point = new Point(longitudeToX(center.longitude), latitudeToY(center.latitude));
        drawRadius = (float) (options.getRadius() / groundResolution(center.latitude, 1));
    }

    @Override
    public LatLng getCenter() throws RemoteException {
        return center;
        return options.getCenter();
    }

    @Override
    public void setRadius(double radius) throws RemoteException {
        this.radius = radius;
        options.radius(radius);
        if (point != null) {
            this.drawRadius = (float) (options.getRadius() / groundResolution(options.getCenter().latitude, 1));
        }
    }

    @Override
    public double getRadius() throws RemoteException {
        return radius;
        return options.getRadius();
    }

    @Override
    public void setStrokeWidth(float width) throws RemoteException {
        this.strokeWidth = width;
        options.strokeWidth(width);
    }

    @Override
    public float getStrokeWidth() throws RemoteException {
        return strokeWidth;
        return options.getStrokeWidth();
    }

    @Override
    public void setStrokeColor(int color) throws RemoteException {
        this.strokeColor = color;
        options.strokeColor(color);
    }

    @Override
    public int getStrokeColor() throws RemoteException {
        return strokeColor;
        return options.getStrokeColor();
    }

    @Override
    public void setFillColor(int color) throws RemoteException {
        this.fillColor = color;
        options.fillColor(color);
        listener.update(this);
    }

    @Override
    public int getFillColor() throws RemoteException {
        return fillColor;
        return options.getFillColor();
    }

    @Override
    public void setZIndex(float zIndex) throws RemoteException {
        this.zIndex = zIndex;
        options.zIndex(zIndex);
    }

    @Override
    public float getZIndex() throws RemoteException {
        return zIndex;
        return options.getZIndex();
    }

    @Override
    public void setVisible(boolean visible) throws RemoteException {
        this.visible = visible;
        options.visible(visible);
    }

    @Override
    public boolean isVisible() throws RemoteException {
        return visible;
        return options.isVisible();
    }

    @Override
@@ -123,4 +157,149 @@ public class CircleImpl extends ICircleDelegate.Stub {
    public int hashCodeRemote() throws RemoteException {
        return id.hashCode();
    }

    @Override
    public MarkerItem getMarkerItem(Context context) {
        return null;
    }

    @Override
    public Layer getLayer(Context context, Map map) {
        if (layer == null) {
            layer = new CircleLayer(map);
        }
        return layer;
    }

    @Override
    public Type getType() {
        return Type.LAYER;
    }

    private class CircleLayer extends Layer {

        public CircleLayer(Map map) {
            super(map);
            mRenderer = new CircleRenderer();
        }

        private class CircleRenderer extends LayerRenderer {
            private final Box bBox = new Box();
            private final Point screenPoint = new Point();
            private final Point indicatorPosition = new Point();
            private AndroidGL GL = new AndroidGL();

            private int shader;
            private int vertexPosition;
            private int matrixPosition;
            private int phase;
            private int scale;
            private int direction;
            private int color;

            @Override
            public void update(GLViewport viewport) {
                if (!isEnabled()) {
                    setReady(false);
                    return;
                }

                if (!viewport.changed() && isReady()) return;

                setReady(true);

                int width = mMap.getWidth();
                int height = mMap.getHeight();

                // clamp location to a position that can be
                // savely translated to screen coordinates
                viewport.getBBox(bBox, 0);

                double x = point.x;
                double y = point.y;

                // get position of Location in pixel relative to
                // screen center
                viewport.toScreenPoint(x, y, screenPoint);

                x = screenPoint.x + width / 2;
                y = screenPoint.y + height / 2;

                viewport.fromScreenPoint(x, y, indicatorPosition);
            }

            @Override
            public void render(GLViewport viewport) {

                GLState.useProgram(shader);
                GLState.blend(true);
                GLState.test(false, false);

                GLState.enableVertexArrays(vertexPosition, -1);
                MapRenderer.bindQuadVertexVBO(vertexPosition);

                float radius = (float) (drawRadius * viewport.pos.scale);
                GL.uniform1f(scale, radius);

                double x = indicatorPosition.x - viewport.pos.x;
                double y = indicatorPosition.y - viewport.pos.y;
                double tileScale = Tile.SIZE * viewport.pos.scale;

                viewport.mvp.setTransScale((float) (x * tileScale), (float) (y * tileScale), 1);
                viewport.mvp.multiplyMM(viewport.viewproj, viewport.mvp);
                viewport.mvp.setAsUniform(matrixPosition);
                GL.uniform1f(phase, 1);
                GL.uniform2f(direction, 0, 0);
                float alpha = Color.aToFloat(options.getFillColor());
                GL.uniform4f(color,
                        Color.rToFloat(options.getFillColor()) * alpha,
                        Color.gToFloat(options.getFillColor()) * alpha,
                        Color.bToFloat(options.getFillColor()) * alpha,
                        alpha);

                GL.drawArrays(GL20.GL_TRIANGLE_STRIP, 0, 4);
            }

            @Override
            public boolean setup() {
                shader = GLShader.createProgram(vShaderStr, fShaderStr);
                if (shader == 0)
                    return false;
                vertexPosition = GL.getAttribLocation(shader, "a_pos");
                matrixPosition = GL.getUniformLocation(shader, "u_mvp");
                phase = GL.getUniformLocation(shader, "u_phase");
                scale = GL.getUniformLocation(shader, "u_scale");
                direction = GL.getUniformLocation(shader, "u_dir");
                color = GL.getUniformLocation(shader, "u_color");
                return true;
            }
        }
    }


    private final static String vShaderStr = ""
            + "precision mediump float;"
            + "uniform mat4 u_mvp;"
            + "uniform float u_phase;"
            + "uniform float u_scale;"
            + "attribute vec2 a_pos;"
            + "varying vec2 v_tex;"
            + "void main() {"
            + "  gl_Position = u_mvp * vec4(a_pos * u_scale * u_phase, 0.0, 1.0);"
            + "  v_tex = a_pos;"
            + "}";

    private final static String fShaderStr = ""
            + "precision mediump float;"
            + "varying vec2 v_tex;"
            + "uniform float u_scale;"
            + "uniform float u_phase;"
            + "uniform vec2 u_dir;"
            + "uniform vec4 u_color;"

            + "void main() {"
            + "  float len = 1.0 - length(v_tex);"
            + "  float a = smoothstep(0.0, 2.0 / u_scale, len);"
            + "  gl_FragColor = u_color * a;"
            + "}";
}
+15 −71
Original line number Diff line number Diff line
@@ -27,85 +27,19 @@ import com.google.android.gms.maps.model.internal.IMarkerDelegate;
import org.microg.gms.maps.GmsMapsTypeHelper;
import org.microg.gms.maps.bitmap.BitmapDescriptorImpl;
import org.oscim.android.canvas.AndroidBitmap;
import org.oscim.layers.Layer;
import org.oscim.layers.marker.MarkerItem;
import org.oscim.layers.marker.MarkerSymbol;
import org.oscim.map.Map;

public class MarkerImpl extends IMarkerDelegate.Stub implements Markup {
    private static final String TAG = MarkerImpl.class.getName();

    private final String id;

    private MarkerOptions options;
    private final MarkerOptions options;
    private final MarkupListener listener;
    private BitmapDescriptorImpl icon;

    private MarkupListener listener;
    /*private Overlay overlay = new Overlay() {
        private Point point = new Point();

        @Override
        public boolean onTap(GeoPoint p, MapView mapView) {
            Point touchPoint = mapView.getProjection().toPixels(p, null);
            Bitmap bitmap = icon.getBitmap();
            if (bitmap == null)
                return false;
            //mapView.getProjection().toPixels(position.toGeoPoint(), point);
            float xTest = bitmap.getWidth() * anchorU + touchPoint.x - point.x;
            float yTest = bitmap.getHeight() * anchorV + touchPoint.y - point.y;
            if (0 < xTest && xTest < bitmap.getWidth() && 0 < yTest && yTest < bitmap.getHeight()) {
                Log.d(TAG, "touched " + title);
                IOnMarkerClickListener markerClickListener = map.getMarkerClickListener();
                boolean result = false;
                if (markerClickListener != null) {
                    try {
                        result = markerClickListener.onMarkerClick(MarkerImpl.this);
                    } catch (RemoteException e) {
                        Log.w(TAG, e);
                    }
                }
                if (!result) {
                    mapView.getController().animateTo(position.toGeoPoint());
                    map.showInfoWindow(MarkerImpl.this);
                }
                return true;
            }
            return false;
        }

        @Override
        public void draw(Canvas canvas, MapView mapView, boolean shadow) {
            if (shadow && flat)
                return; // shadows are broken right now, we skip them
            Bitmap bitmap = icon.getBitmap();
            if (bitmap != null) {
                //mapView.getProjection().toPixels(position.toGeoPoint(), point);
                float x = point.x - bitmap.getWidth() * anchorU;
                float y = point.y - bitmap.getHeight() * anchorV;
                Paint paint = new Paint();
                paint.setAlpha((int) (alpha * 255));
                if (shadow) {
                    paint.setColorFilter(
                            new PorterDuffColorFilter(Color.argb((int) (128 * alpha), 0, 0, 0),
                                    PorterDuff.Mode.SRC_IN));
                }
                Matrix matrix = new Matrix();
                matrix.setRotate(rotation, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
                if (shadow) {
                    matrix.postSkew(-0.9F, 0);
                    matrix.postScale(1, 0.5F);
                }
                matrix.postTranslate(x, y);
                canvas.drawBitmap(bitmap, matrix, paint);
            } else {
                icon.loadBitmapAsync(map.getContext(), new Runnable() {
                    @Override
                    public void run() {
                        map.redraw();
                    }
                });
            }
        }
    };*/

    public MarkerImpl(String id, MarkerOptions options, MarkupListener listener) {
        this.id = id;
        this.listener = listener;
@@ -274,7 +208,7 @@ public class MarkerImpl extends IMarkerDelegate.Stub implements Markup {
            if (icon.getBitmap() != null) {
                item.setMarker(
                        new MarkerSymbol(new AndroidBitmap(icon.getBitmap()), options.getAnchorU(),
                                options.getAnchorV(), isFlat()));
                                options.getAnchorV(), !options.isFlat()));
            } else {
                icon.loadBitmapAsync(context, new Runnable() {
                    @Override
@@ -286,4 +220,14 @@ public class MarkerImpl extends IMarkerDelegate.Stub implements Markup {
        }
        return item;
    }

    @Override
    public Layer getLayer(Context context, Map map) {
        return null;
    }

    @Override
    public Type getType() {
        return Type.MARKER;
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -17,13 +17,24 @@
package org.microg.gms.maps.markup;

import android.content.Context;

import org.oscim.layers.Layer;
import org.oscim.layers.marker.MarkerItem;
import org.oscim.map.Map;

public interface Markup {
    public MarkerItem getMarkerItem(Context context);

    public Layer getLayer(Context context, Map map);

    public Type getType();

    public String getId();

    public static enum Type {
        MARKER, LAYER
    }

    public static interface MarkupListener {
        void update(Markup markup);