1 (edited by ShaneTheKing 2017-02-09 19:08:20)

Topic: Gesture zoom with custom inputs?

Greetings,

I'd like to be able to zoom in using VR controllers sort of like pinch to zoom but pulling the triggers on the controllers to zoom, but as far as I can tell, current gesture zoom is only for mobile devices and overriding input locations only works with one input.

Is there any way to do this without writing my own zoom method?

Thank you

Re: Gesture zoom with custom inputs?

Hello.

No, in your case (VR) you need to implement it yourself.

Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

Re: Gesture zoom with custom inputs?

Hi Shane,

Do you want smooth zoom or is regular changing of the zoom levels also OK?
We just used the touchpad (on Vive controllers), where if you press on the bottom side of the pad you zoom out, while pressing on the top side of the pad zooms you out. It's a regular map.zoom-- and map.zoom++ though so it's not that neat looking.

Are you going to do a pinching motion with the controllers? I'm interested in seeing how you would make that work smile
Right now we're looking into more of a scrolling mechanism that we could use with the touchpad and hopefully make it a bit smoother. Kind of like scrolling on maps.google.com
Unfortunately this seems a bit more challenging on a 3D map.

Re: Gesture zoom with custom inputs?

Hello.

You can quite easily make your own a smooth zoom.
How to make a smooth zoom in general:

using UnityEngine;

public class FloatZoom:MonoBehaviour
{
    public float currentZoom; // To change the zoom using the Inspector.

    private float _zoom;
    private OnlineMaps map;
    private Vector3 originalPosition;
    private Vector3 originalScale;
    private Vector3 smoothZoomOffset;
    private Transform mapTransform;

    public float zoom
    {
        get { return _zoom; }
        set
        {
            _zoom = Mathf.Clamp(value, 3, OnlineMaps.MAXZOOM);
            UpdateZoom();
        }
    }

    private void Start()
    {
        map = OnlineMaps.instance;
        currentZoom = _zoom = map.zoom;
        mapTransform = map.transform;
        originalPosition = mapTransform.position;
        originalScale = mapTransform.localScale;

        // This part can be simplified, but I just copied it from Tileset Control.
        Vector3 smoothZoomHitPoint = mapTransform.position + mapTransform.rotation * new Vector3(map.tilesetSize.x / -2, 0, map.tilesetSize.y / 2);
        smoothZoomOffset = Quaternion.Inverse(mapTransform.rotation) * (originalPosition - smoothZoomHitPoint);
        smoothZoomOffset.Scale(new Vector3(-1f / map.tilesetWidth, 0, -1f / map.tilesetHeight));
    }

    private void Update()
    {
        if (currentZoom != _zoom) zoom = currentZoom;
    }

    private void UpdateZoom()
    {
        currentZoom = _zoom;
        map.zoom = (int) _zoom;
        float offset = _zoom - (int) _zoom + 1;
        mapTransform.localScale = originalScale * offset;
        Vector3 p = mapTransform.rotation * new Vector3(map.tilesetWidth * (mapTransform.localScale.x - 1) * smoothZoomOffset.x, 0, map.tilesetHeight * (mapTransform.localScale.z - 1) * smoothZoomOffset.z);
        mapTransform.localPosition = originalPosition - p;
    }
}

I hope this helps you.

P.S. In Online Maps v2.6 is planned to add a float zoom for all controls.

Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

Re: Gesture zoom with custom inputs?

This is nice, thank you smile
It seems however that the entire map gets displaced when the zoom is first changed. I am now just incrementing and decrementing this zoom instead of the original map zoom.

6 (edited by alexandra 2017-02-15 14:18:54)

Re: Gesture zoom with custom inputs?

Sorry for the thread hijack, feel free to take it back whenever Shane wink
I've attached our map settings. When the smooth zoom float is changed the whole map gets displaced to a different location. This only happens on the first change. After that it scales as it should (in that new location). Could it have anything to do with the scale or size of our map?

[EDIT: It had to do with our scale. We set it back to 1 instead of 0.25 and it worked correctly. We couldn't find a way to make it work with the 0.25 scale so we're just rewriting other scripts now tongue]

Post's attachments

Attachment icon mapsettings.png 36.58 kb, 237 downloads since 2017-02-15 

Re: Gesture zoom with custom inputs?

The problem was in scale.
Actually, you can simply specify Width / Height (pixels) = 64.

I improved the script, and now it will work correctly.

using UnityEngine;

public class FloatZoom:MonoBehaviour
{
    public float currentZoom; // To change the zoom using the Inspector.

    private float _zoom;
    private OnlineMaps map;
    private Vector3 originalPosition;
    private Vector3 originalScale;
    private Vector3 smoothZoomOffset;
    private Transform mapTransform;

    public float zoom
    {
        get { return _zoom; }
        set
        {
            _zoom = Mathf.Clamp(value, 3, OnlineMaps.MAXZOOM);
            UpdateZoom();
        }
    }

    private void Start()
    {
        map = OnlineMaps.instance;
        currentZoom = _zoom = map.zoom;
        mapTransform = map.transform;
        originalPosition = mapTransform.localPosition;
        originalScale = mapTransform.localScale;

        // This part can be simplified, but I just copied it from Tileset Control.
        Vector3 smoothZoomHitPoint = originalPosition + mapTransform.rotation * new Vector3(map.tilesetSize.x / -2 * originalScale.x, 0, map.tilesetSize.y / 2 * originalScale.z);
        smoothZoomOffset = Quaternion.Inverse(mapTransform.rotation) * (originalPosition - smoothZoomHitPoint);
        smoothZoomOffset.Scale(new Vector3(-1f / map.tilesetWidth, 0, -1f / map.tilesetHeight));
    }

    private void Update()
    {
        if (currentZoom != _zoom) zoom = currentZoom;
    }

    private void UpdateZoom()
    {
        currentZoom = _zoom;
        map.zoom = (int) _zoom;
        float offset = _zoom - (int) _zoom + 1;
        Vector3 newScale = originalScale * offset;

        mapTransform.localScale = newScale;
        Vector3 s = newScale - originalScale;
        s.Scale(new Vector3(1f / originalScale.x, 1 / originalScale.y, 1 / originalScale.z));
        Vector3 p = mapTransform.rotation * new Vector3(map.tilesetWidth * s.x * smoothZoomOffset.x, 0, map.tilesetHeight * s.z * smoothZoomOffset.z);
        mapTransform.localPosition = originalPosition - p;
    }
}
Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

Re: Gesture zoom with custom inputs?

While using the smooth zoom sometimes I get this error:

ArgumentException: An element with the same key already exists in the dictionary.
System.Collections.Generic.Dictionary`2[System.UInt64,Minimap+TileItem].Add (UInt64 key, .TileItem value) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:404)
Minimap.UpdateMinimap () (at Assets/Minimap/Minimap.cs:83)
Minimap.<Start>m__0 () (at Assets/Minimap/Minimap.cs:36)
OnlineMaps.DispatchEvent (.OnlineMapsEvents[] evs) (at Assets/Infinity Code/Online maps/Scripts/OnlineMaps.cs:951)
OnlineMaps.set_zoom (Int32 value) (at Assets/Infinity Code/Online maps/Scripts/OnlineMaps.cs:584)
FloatZoom.UpdateZoom () (at Assets/FloatZoom.cs:43)
FloatZoom.set_zoom (Single value) (at Assets/FloatZoom.cs:22)
FloatZoom.Update () (at Assets/FloatZoom.cs:65)

(cs:64 refers to
if (currentZoom != _zoom) zoom = currentZoom;
)

Re: Gesture zoom with custom inputs?

Hello.

I have nothing on this stack trace.
You have modified the script, right?!

This error occurs when you try to add an element to the dictionary whose key is already in the dictionary.
The original script contains checks for the key in the dictionary.
Please send modified Minimap.cs.

Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

Re: Gesture zoom with custom inputs?

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Minimap : MonoBehaviour
{
    public int zoom = 10;
    public RectTransform tileContainer;

    private static OnlineMaps map;
    private Dictionary<ulong, TileItem> tiles;
    private List<ulong> keysForRemove;

    private void OnTileDownloaded(OnlineMapsTile tile)
    {
        if (tiles.ContainsKey(tile.key))
        {
            TileItem item = tiles[tile.key];
            if (string.IsNullOrEmpty(tile.www.error))
            {
                Texture2D texture = new Texture2D(128, 128);
                tile.www.LoadImageIntoTexture(texture);
                texture.wrapMode = TextureWrapMode.Clamp;
                item.SetTexture(texture);
                UpdateMinimap();
            }
        }
    }

    private void Start()
    {
        map = OnlineMaps.instance;
        zoom = map.zoom - 5;
        map.OnChangePosition += UpdateMinimap;
        map.OnChangeZoom += delegate { zoom = map.zoom - 5; UpdateMinimap(); };
        OnlineMapsTile.OnTileDownloaded += OnTileDownloaded;

        tiles = new Dictionary<ulong, TileItem>();

        UpdateMinimap();
    }
    private void UpdateMinimap()
    {
        //gameObject.transform.rotation = new Quaternion(0, 0, 0, 0);
        int maxX = 1 << zoom;

        double lng, lat;
        double lng2, lat2;
        map.GetPosition(out lng, out lat);
        map.GetBottomRightPosition(out lng2, out lat2);
        lng = (lng2 + lng *2) /3;
        lat = (lat2 + lat *2) /3;


        double tx, ty;
        map.projection.CoordinatesToTile(lng, lat, zoom, out tx, out ty);

        int itx = (int) tx - 1;
        int ity = (int) ty - 1;

        if (itx < 0) itx -= maxX;
        if (ity < 0) ity = 0;

        foreach (KeyValuePair<ulong, TileItem> pair in tiles)
        {
            pair.Value.used = false;
        }

        for (int x = 0; x < 3; x++)
        {
            int cx = x + itx;

            for (int y = 0; y < 3; y++)
            {
                int cy = y + ity;
                ulong tileKey = OnlineMapsTile.GetTileKey(zoom, cx, cy);
                TileItem tile;
                if (tiles.ContainsKey(tileKey)) tile = tiles[tileKey];
                else
                {
                    tile = new TileItem(cx, cy, zoom, tileContainer);
                    tiles.Add(tile.key, tile);
                }

                tile.used = true;
                tile.UpdatePosition(tx, ty);
            }
        }

        UnloadUnusedTiles();
    }

    private void UnloadUnusedTiles()
    {
        if (keysForRemove == null) keysForRemove = new List<ulong>(9);
        else keysForRemove.Clear();

        foreach (KeyValuePair<ulong, TileItem> pair in tiles)
        {
            if (!pair.Value.used)
            {
                keysForRemove.Add(pair.Value.key);
                pair.Value.Dispose();
            }
        }

        if (keysForRemove.Count > 0)
        {
            foreach (ulong key in keysForRemove)
            {
                tiles.Remove(key);
            }
        }
    }

    internal class TileItem
    {
        public OnlineMapsTile tile;
        public ulong key;
        public GameObject instance;
        public bool used;

        private int tx;
        private int ty;
        private RectTransform rectTransform;
        private RawImage rawImage;

        public TileItem(int tx, int ty, int zoom, RectTransform container)
        {
            this.tx = tx;
            this.ty = ty;
            tile = new OnlineMapsTile(tx, ty, zoom, map, false);
            key = tile.key;
            map.StartDownloadTile(tile);
            instance = new GameObject(zoom + "x" + tx + "+" + ty);
            rawImage = instance.AddComponent<RawImage>();
            rectTransform = instance.transform as RectTransform;
            rectTransform.SetParent(container);
            rectTransform.anchorMin = new Vector2(0, 1);
            rectTransform.anchorMax = new Vector2(0, 1);
            rectTransform.pivot = new Vector2(0, 1);
            rectTransform.sizeDelta = new Vector2(OnlineMapsUtils.tileSize, OnlineMapsUtils.tileSize);
        }

        public void Dispose()
        {
            tile.Dispose();
            Destroy(instance);

            tile = null;
            instance = null;
            rectTransform = null;
        }

        internal void UpdatePosition(double cx, double cy)
        {
            double px = (tx - cx) * (OnlineMapsUtils.tileSize);
            double py = (cy - ty) * (OnlineMapsUtils.tileSize);
            rectTransform.localPosition = new Vector3((float)px, (float)py, 0);
        }

        public void SetTexture(Texture2D texture)
        {
            rawImage.texture = texture;
        }
    }
}

I added a bit to start so the minimap also zooms out when the player zooms out.

Re: Gesture zoom with custom inputs?

Your script looks fine.
This problem can be only if «tileKey != tile.key».
But I do not know the situation, when this is possible.

Try it this way (line 82):

tile = new TileItem(cx, cy, zoom, tileContainer);
try
{
    tiles.Add(tile.key, tile);
}
catch (Exception)
{
    Debug.Log("Oops. Something happened.");
    Debug.Log(tileKey);
    Debug.Log(tile.key);
    Debug.Log(tiles.ContainsKey(tileKey));
    throw;
}

I am very interested what will happen.

Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

Re: Gesture zoom with custom inputs?

I will add that and report back to you smile
Using this smooth zoom the markers are also scaled. Is there a way to stop the markers from scaling along with the decimal values of the zoom?

13 (edited by alexandra 2017-02-16 14:34:52)

Re: Gesture zoom with custom inputs?

This is the result of the Console.
It seems to happen only on zoom levels that are more zoomed out, around when I get clusters.

[EDIT: It happens in the entirety of zoomlevel 6. So from 6.0 to 6.9. It does not happen on any other zoomlevel for some reason.]

Post's attachments

Attachment icon unity log.png 144.2 kb, 276 downloads since 2017-02-16 

Re: Gesture zoom with custom inputs?

I understood.
The problem occurs at the intersection of longitude 180 / -180.
Solution (line 71):

int cx = x + itx;
if (cx >= maxX) cx -= maxX;


You need to change the scale of markers.
Something like:
http://forum.infinity-code.com/viewtopi … 1692#p1692
For 3D markers you need to use OnlineMapsControlBase3D.markers3D.

Kind Regards,
Infinity Code Team.

Boost your productivity a lot and immediately using Ultimate Editor Enhancer. Trial and non-commerce versions available.

15 (edited by ShaneTheKing 2017-02-20 14:40:00)

Re: Gesture zoom with custom inputs?

Hey guys, thanks for the input (hah). Sorry I totally forgot about this thread lol... I ended up just implementing a zoom where the user could pull the trigger on the vive and move the controller vertically to zoom in and out. It seemed pretty intuitive and ended up working pretty well, so we stuck with that at the time.

I ended up with a couple issues that have sort of janky fixes, though. One of them was that OnlineMapsControlBase.instance.ZoomOnPoint wasn't putting me in the right place, so I had to call OnlineMaps.instance.SetPosition afterwards weirdly. The other was with elevation turned on you could end up going under the ground just by zooming in, so I had to add a script to the camera rig to make it so you're always x distance above the terrain.