You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.7 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof (RawImage))]
[AddComponentMenu("UI/Pinch and Zoom Image")]
public class PinchZoomImage : MonoBehaviour
,IDragHandler, IPointerDownHandler, IPointerUpHandler
{
[Range(0, 0.1f)]
public float posDuration = 0.05f;
[Range(0, 0.1f)]
public float rotDuration = 0.05f;
[Range(0, 0.1f)]
public float scaleDuration = 0.05f;
public bool isRotation = true;
public bool isScale = true;
private bool simulatedByMouse = false;
public void SetPosition(Vector3 position)
{
target_pos = position;
}
public Vector3 GetPosition()
{
return target_pos;
}
//IDragHandler
public void OnDrag(PointerEventData eventData)
{
//Debug.Log("OnDrag"+Time.time);
pointers[eventData.pointerId] = eventData;
}
//IPointerDownHandler
public void OnPointerDown(PointerEventData eventData)
{
//Debug.Log("OnPointerDown" + Time.time);
if (simulatedByMouse && pointers.Count == 0)
{
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
PointerEventData p = new PointerEventData(EventSystem.current);
p.position = new Vector2(pos.x, pos.y);
p.pointerId = -2;
pointers.Add(p.pointerId, p);
}
pointers.Add(eventData.pointerId, eventData);
ResetAnchor();
transform.SetSiblingIndex(transform.childCount - 1);
}
//IPointerUpHandler
public void OnPointerUp(PointerEventData eventData)
{
//Debug.Log("OnPointerUp" + Time.time);
pointers.Remove(eventData.pointerId);
if (simulatedByMouse && pointers.Count == 1)
pointers.Remove(-2);
if (pointers.Count > 0)
ResetAnchor();
}
List<Vector2> GetPositionList()
{
List < Vector2 > result = new List<Vector2>();
foreach (int key in pointers.Keys)
result.Add(pointers[key].position);
return result;
}
private static Vector2 Average(List<Vector2> list)
{
Vector2 sum = Vector2.zero;
foreach (Vector2 v in list)
sum += v;
return sum / list.Count;
}
private static List<Vector2> Substract(List<Vector2> list, Vector2 pos)
{
List<Vector2> result = new List<Vector2>();
foreach (Vector2 v in list)
result.Add(v - pos);
return result;
}
private static float AverageMagnitude(List<Vector2> list)
{
float sum = 0.0f;
foreach (Vector2 v in list)
sum += v.magnitude;
return sum / list.Count;
}
Vector2 getAveragePosition()
{
Vector2 sum = Vector2.zero;
foreach (int key in pointers.Keys)
sum += pointers[key].position;
return sum / pointers.Count;
}
float getAverageDistance(Dictionary<int, Vector2> directions)
{
float sum = 0.0f;
foreach (int key in directions.Keys)
sum += directions[key].magnitude;
return sum / pointers.Count;
}
Dictionary<int, Vector2> getDirection(Vector2 pos)
{
Dictionary<int, Vector2> result = new Dictionary<int, Vector2>();
foreach (int key in pointers.Keys)
{
result.Add(key,pointers[key].position - pos);
}
return result;
}
// Use this for initialization
void Start () {
target_pos = transform.localPosition;
target_q = transform.localRotation;
target_scale = transform.localScale.x;
}
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.Escape))
Application.Quit();
if (Time.deltaTime == 0)
return;
if (pointers.Count > 0)
{
List<Vector2> pos_list = GetPositionList();
Vector2 pos = Average(pos_list);
List<Vector2> diff_list = Substract(pos_list, pos);
float magnitude = AverageMagnitude(diff_list);
{//translation
Vector3 diff_pos = pos - pre_pos;
target_pos += diff_pos;
vel += (diff_pos / Time.deltaTime - vel) * Mathf.Clamp01(Time.deltaTime / 0.2f);
pre_pos = pos;
}
if (pointers.Count > 1)
{
if (isScale)
{//Scale
target_scale = target_scale * magnitude / pre_magnitude;
pre_magnitude = magnitude;
}
if (isRotation)
{//rotation
Quaternion average = new Quaternion(0, 0, 0, 0);
for(int i=0;i<diff_list.Count; ++i)
{
Quaternion q = Quaternion.FromToRotation(pre_diff_list[i].normalized, diff_list[i].normalized);
average = Quaternion.Slerp(average, q, 1.0f / (i+1));
}
target_q = target_q * average;
pre_diff_list = diff_list;
}
}
}else
{
if (posDuration == 0.0f)
vel = Vector3.zero;
target_pos += vel * Time.deltaTime;
vel *= 0.9f;
}
float pos_step = Mathf.Clamp01(Time.deltaTime / posDuration);
float rot_step = Mathf.Clamp01(Time.deltaTime / rotDuration);
float scale_step = Mathf.Clamp01(Time.deltaTime / scaleDuration);
if (Application.isPlaying == false)
pos_step = rot_step = scale_step = 1.0f;
Vector3 new_pos = Vector3.Lerp(transform.localPosition, target_pos, pos_step); ;
transform.localPosition = new_pos;
transform.localRotation = Quaternion.Slerp(transform.localRotation, target_q, rot_step);
float s = Mathf.Lerp(transform.localScale.x, target_scale, scale_step);
transform.localScale = new Vector3(s, s, 1.0f);
}
private void ResetAnchor()
{
vel = Vector3.zero;
List<Vector2> pos_list = GetPositionList();
//target_pos = transform.localPosition;
pre_pos = Average(pos_list);
pre_diff_list = Substract(pos_list, pre_pos);
pre_magnitude = AverageMagnitude(pre_diff_list);
}
private Dictionary<int, PointerEventData> pointers = new Dictionary<int, PointerEventData>();
private Vector3 target_pos;
private Quaternion target_q;
private float target_scale;
private Vector2 pre_pos;
private List<Vector2> pre_diff_list;
private float pre_magnitude;
private Vector3 vel = Vector3.zero;
}