1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Two fingers camera manipulation, pinch to zoom and slide to scroll
16 module camera_control_android
21 redef class EulerCamera
22 # Smoothened history of pointers in the current motion event
23 private var last_motion_pointers
= new HashMap[Int, Point[Float]] is lazy
25 # Start time of the current motion event
26 private var last_motion_start
: Int = -1
28 redef fun accept_scroll_and_zoom
(event
)
30 if not event
isa AndroidMotionEvent then return false
32 if event
.pointers
.length
< 2 then
33 # Intercept leftovers of the last motion
34 return event
.down_time
== last_motion_start
37 # Collect active pointer and their world position
38 var new_motion_pointers
= new HashMap[Int, Point[Float]]
39 var ids
= new Array[Int]
40 for pointer
in event
.pointers
do
41 var id
= pointer
.pointer_id
43 new_motion_pointers
[id
] = camera_to_world
(pointer
.x
, pointer
.y
)
46 var last_motion_pointers
= last_motion_pointers
47 if last_motion_start
== event
.down_time
and
48 last_motion_pointers
.keys
.has
(ids
[0]) and last_motion_pointers
.keys
.has
(ids
[1]) then
49 # Continued motion event
51 # Get new and old position for 2 fingers
52 var new_motion_a
= new_motion_pointers
[ids
[0]]
53 var new_motion_b
= new_motion_pointers
[ids
[1]]
54 var prev_pos_a
= last_motion_pointers
[ids
[0]]
55 var prev_pos_b
= last_motion_pointers
[ids
[1]]
58 var prev_middle_pos
= prev_pos_a
.lerp
(prev_pos_b
, 0.5)
59 var new_middle_pos
= new_motion_a
.lerp
(new_motion_b
, 0.5)
60 position
.x
-= new_middle_pos
.x
- prev_middle_pos
.x
61 position
.y
-= new_middle_pos
.y
- prev_middle_pos
.y
64 var prev_dist
= prev_pos_a
.dist
(prev_pos_b
)
65 var new_dist
= new_motion_a
.dist
(new_motion_b
)
67 position
.z
= prev_dist
* position
.z
/ new_dist
69 # Prepare for a new motion event
70 last_motion_pointers
.clear
71 last_motion_start
= event
.down_time
74 # Keep a smooth history
76 if last_motion_pointers
.keys
.has
(ids
[i
]) then
77 last_motion_pointers
[ids
[i
]] = last_motion_pointers
[ids
[i
]]*0.5 +
78 new_motion_pointers
[ids
[i
]]*0.5
79 else last_motion_pointers
[ids
[i
]] = new_motion_pointers
[ids
[i
]]
87 private fun *(scalar
: Numeric): Point[N
]
88 do return new Point[N
](x
.mul
(scalar
), y
.mul
(scalar
))
90 private fun +(other
: Point[N
]): Point[N
]
91 do return new Point[N
](x
.add
(other
.x
), y
.add
(other
.y
))