gamnit :: camera_control_android $ EulerCamera
Simple camera with perspective oriented with Euler angles (pitch, yaw, roll)
			gamnit :: camera_control_android $ EulerCamera
Simple camera with perspective oriented with Euler angles (pitch, yaw, roll)
			Serializable::inspect to show more useful information
			more_collections :: more_collections
Highly specific, but useful, collections-related classes.serialization :: serialization_core
Abstract services to serialize Nit objects to different formatscore :: union_find
union–find algorithm using an efficient disjoint-set data structureaccept_scroll_and_zoom
			
# Two fingers camera manipulation, pinch to zoom and slide to scroll
module camera_control_android
import android
import camera_control
redef class EulerCamera
	# Smoothened history of pointers in the current motion event
	private var last_motion_pointers = new HashMap[Int, Point[Float]] is lazy
	# Start time of the current motion event
	private var last_motion_start: Int = -1
	redef fun accept_scroll_and_zoom(event)
	do
		if not event isa AndroidMotionEvent then return false
		if event.pointers.length < 2 then
			# Intercept leftovers of the last motion
			return event.down_time == last_motion_start
		end
		# Collect active pointer and their world position
		var new_motion_pointers = new HashMap[Int, Point[Float]]
		var ids = new Array[Int]
		for pointer in event.pointers do
			var id = pointer.pointer_id
			ids.add id
			new_motion_pointers[id] = camera_to_world(pointer.x, pointer.y)
		end
		var last_motion_pointers = last_motion_pointers
		if last_motion_start == event.down_time and
		   last_motion_pointers.keys.has(ids[0]) and last_motion_pointers.keys.has(ids[1]) then
			# Continued motion event
			# Get new and old position for 2 fingers
			var new_motion_a = new_motion_pointers[ids[0]]
			var new_motion_b = new_motion_pointers[ids[1]]
			var prev_pos_a = last_motion_pointers[ids[0]]
			var prev_pos_b = last_motion_pointers[ids[1]]
			# Move camera
			var prev_middle_pos = prev_pos_a.lerp(prev_pos_b, 0.5)
			var new_middle_pos = new_motion_a.lerp(new_motion_b, 0.5)
			position.x -= new_middle_pos.x - prev_middle_pos.x
			position.y -= new_middle_pos.y - prev_middle_pos.y
			# Zoom camera
			var prev_dist = prev_pos_a.dist(prev_pos_b)
			var new_dist = new_motion_a.dist(new_motion_b)
			position.z = prev_dist * position.z / new_dist
		else
			# Prepare for a new motion event
			last_motion_pointers.clear
			last_motion_start = event.down_time
		end
		# Keep a smooth history
		for i in [0..1] do
			if last_motion_pointers.keys.has(ids[i]) then
				last_motion_pointers[ids[i]] = last_motion_pointers[ids[i]]*0.5 +
				                                new_motion_pointers[ids[i]]*0.5
			else last_motion_pointers[ids[i]] = new_motion_pointers[ids[i]]
		end
		return true
	end
end
redef class Point[N]
	private fun *(scalar: Numeric): Point[N]
	do return new Point[N](x.mul(scalar), y.mul(scalar))
	private fun +(other: Point[N]): Point[N]
	do return new Point[N](x.add(other.x), y.add(other.y))
end
lib/gamnit/camera_control_android.nit:15,1--92,3