Panda3D
Loading...
Searching...
No Matches
pointerEventList.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pointerEventList.cxx
10 * @author jyelon
11 * @date 2007-09-20
12 */
13
14#include "pointerEventList.h"
15#include "indent.h"
16#include "config_event.h"
17#include "clockObject.h"
18#include "deg_2_rad.h"
19#include "cmath.h"
20
21TypeHandle PointerEventList::_type_handle;
22
23/**
24 * Compute the difference between two angles. Returns a value in the range
25 * -180 to 180.
26 */
27INLINE double delta_angle(double angle1, double angle2) {
28 double deltang = angle2 - angle1;
29 while (deltang < -180.0) deltang += 360.0;
30 while (deltang > 180.0) deltang -= 360.0;
31 return deltang;
32}
33
34
35/**
36 * Compute the difference between two angles. Returns a value in the range
37 * -180 to 180.
38 */
39INLINE double normalize_angle(double angle) {
40 while (angle < 0.0) angle += 360.0;
41 while (angle > 360.0) angle -= 360.0;
42 return angle;
43}
44
45
46
47/**
48 *
49 */
50void PointerEventList::
51output(std::ostream &out) const {
52 if (_events.empty()) {
53 out << "(no pointers)";
54 } else {
55 Events::const_iterator ei;
56 ei = _events.begin();
57 out << "(" << (*ei);
58 ++ei;
59 while (ei != _events.end()) {
60 out << " " << (*ei);
61 ++ei;
62 }
63 out << ")";
64 }
65}
66
67/**
68 *
69 */
70void PointerEventList::
71write(std::ostream &out, int indent_level) const {
72 indent(out, indent_level) << _events.size() << " events:\n";
73 Events::const_iterator ei;
74 for (ei = _events.begin(); ei != _events.end(); ++ei) {
75 indent(out, indent_level + 2) << (*ei) << "\n";
76 }
77}
78
79/**
80 * Adds a new event from the given PointerData object.
81 */
83add_event(const PointerData &data, int seq, double time) {
84 PointerEvent pe;
85 pe._in_window = data._in_window;
86 pe._type = data._type;
87 pe._id = data._id;
88 pe._xpos = data._xpos;
89 pe._ypos = data._ypos;
90 pe._pressure = data._pressure;
91 pe._sequence = seq;
92 pe._time = time;
93 if (_events.size() > 0) {
94 pe._dx = data._xpos - _events.back()._xpos;
95 pe._dy = data._ypos - _events.back()._ypos;
96 double ddx = pe._dx;
97 double ddy = pe._dy;
98 pe._length = csqrt(ddx*ddx + ddy*ddy);
99 if (pe._length > 0.0) {
100 pe._direction = normalize_angle(rad_2_deg(catan2(-ddy,ddx)));
101 } else {
102 pe._direction = _events.back()._direction;
103 }
104 pe._rotation = delta_angle(_events.back()._direction, pe._direction);
105 } else {
106 pe._dx = 0;
107 pe._dy = 0;
108 pe._length = 0.0;
109 pe._direction = 0.0;
110 pe._rotation = 0.0;
111 }
112 _events.push_back(pe);
113}
114
115/**
116 * Adds a new event to the end of the list. Automatically calculates the dx,
117 * dy, length, direction, and rotation for all but the first event.
118 */
120add_event(bool in_win, int xpos, int ypos, int seq, double time) {
121 PointerEvent pe;
122 pe._in_window = in_win;
123 pe._xpos = xpos;
124 pe._ypos = ypos;
125 pe._sequence = seq;
126 pe._time = time;
127 if (_events.size() > 0) {
128 pe._dx = xpos - _events.back()._xpos;
129 pe._dy = ypos - _events.back()._ypos;
130 double ddx = pe._dx;
131 double ddy = pe._dy;
132 pe._length = csqrt(ddx*ddx + ddy*ddy);
133 if (pe._length > 0.0) {
134 pe._direction = normalize_angle(rad_2_deg(catan2(-ddy,ddx)));
135 } else {
136 pe._direction = _events.back()._direction;
137 }
138 pe._rotation = delta_angle(_events.back()._direction, pe._direction);
139 } else {
140 pe._dx = 0;
141 pe._dy = 0;
142 pe._length = 0.0;
143 pe._direction = 0.0;
144 pe._rotation = 0.0;
145 }
146 _events.push_back(pe);
147}
148
149/**
150 * Adds a new event to the end of the list based on the given mouse movement.
151 */
153add_event(bool in_win, int xpos, int ypos, double xdelta, double ydelta, int seq, double time) {
154 PointerEvent pe;
155 pe._in_window = in_win;
156 pe._xpos = xpos;
157 pe._ypos = ypos;
158 pe._dx = xdelta;
159 pe._dy = ydelta;
160 pe._sequence = seq;
161 pe._time = time;
162 pe._length = csqrt(xdelta*xdelta + ydelta*ydelta);
163 if (pe._length > 0.0) {
164 pe._direction = normalize_angle(rad_2_deg(catan2(-ydelta,xdelta)));
165 } else if (!_events.empty()) {
166 pe._direction = _events.back()._direction;
167 } else {
168 pe._direction = 0.0;
169 }
170 if (!_events.empty()) {
171 pe._rotation = delta_angle(_events.back()._direction, pe._direction);
172 } else {
173 pe._rotation = 0.0;
174 }
175 _events.push_back(pe);
176}
177
178/**
179 * Returns true if the trail loops around the specified point.
180 */
182encircles(int x, int y) const {
183 int tot_events = _events.size();
184 if (tot_events < 3) {
185 return false;
186 }
187 int last = tot_events-1;
188 double dx = _events[last]._xpos - x;
189 double dy = _events[last]._ypos - y;
190 double lastang = rad_2_deg(catan2(dy, dx));
191 double total = 0.0;
192 for (int i=last; (i>=0) && (total < 360.0) && (total > -360.0); i--) {
193 dx = _events[i]._xpos - x;
194 dy = _events[i]._ypos - y;
195 if ((dx==0.0)&&(dy==0.0)) {
196 continue;
197 }
198 double angle = rad_2_deg(catan2(dy,dx));
199 double deltang = delta_angle(lastang, angle);
200 if (deltang * total < 0.0) {
201 total = 0.0;
202 }
203 total += deltang;
204 lastang = angle;
205 }
206 return (total > 360.0) || (total < -360.0);
207}
208
209/**
210 * returns the total angular deviation that the trail has made in the
211 * specified time period. A small number means that the trail is moving in a
212 * relatively straight line, a large number means that the trail is zig-
213 * zagging or spinning. The result is in degrees.
214 */
216total_turns(double sec) const {
217 double old = ClockObject::get_global_clock()->get_frame_time() - sec;
218 int pos = _events.size()-1;
219 double tot = 0.0;
220 while ((pos >= 0)&&(_events[pos]._time >= old)) {
221 double rot = _events[pos]._rotation;
222 if (rot < 0.0) rot = -rot;
223 tot += rot;
224 }
225 return tot;
226}
227
228/**
229 * This function is not implemented yet. It is a work in progress. The
230 * intent is as follows:
231 *
232 * Returns a nonzero value if the mouse movements match the specified pattern.
233 * The higher the value, the better the match. The pattern is a sequence of
234 * compass directions (ie, "E", "NE", etc) separated by spaces. If rot is
235 * nonzero, then the pattern is rotated counterclockwise by the specified
236 * amount before testing. Seglen is the minimum length a mouse movement needs
237 * to be in order to be considered significant.
238 */
240match_pattern(const std::string &ascpat, double rot, double seglen) {
241 // Convert the pattern from ascii to a more usable form.
242 vector_double pattern;
243 parse_pattern(ascpat, pattern);
244
245 // Apply the rotation to the pattern.
246 for (size_t i=0; i<pattern.size(); i++) {
247 pattern[i] = normalize_angle(pattern[i] + rot);
248 }
249
250 return 0.0;
251}
252
253/**
254 * Parses a pattern as used by match_pattern.
255 */
256void PointerEventList::
257parse_pattern(const std::string &ascpat, vector_double &pattern) {
258 int chars = 0;
259 double dir = 180.0;
260 for (size_t i=0; i<ascpat.size(); i++) {
261 char c = ascpat[i];
262 double ang = -1.0;
263 if ((c=='E')||(c=='e')) ang=0.0;
264 else if ((c=='N')||(c=='n')) ang=90.0;
265 else if ((c=='W')||(c=='w')) ang=180.0;
266 else if ((c=='S')||(c=='s')) ang=270.0;
267 if (ang >= 0.0) {
268 double offset = delta_angle(dir, ang);
269 double newang = dir + offset;
270 dir = normalize_angle((dir * chars + newang) / (chars + 1));
271 chars += 1;
272 } else {
273 if ((c != ' ')&&(c != '\t')) {
274 event_cat.warning() <<
275 "Invalid pattern in PointerEventList::match_pattern\n";
276 pattern.clear();
277 return;
278 }
279 if (chars > 0) {
280 pattern.push_back(dir);
281 }
282 chars = 0;
283 dir = 180.0;
284 }
285 }
286 if (chars > 0) {
287 pattern.push_back(dir);
288 }
289
290 std::cerr << "Pattern: ";
291 for (int i=0; i<(int)pattern.size(); i++) {
292 std::cerr << pattern[i] << " ";
293 }
294 std::cerr << "\n";
295}
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition clockObject.h:91
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Holds the data that might be generated by a 2-d pointer input device, such as the mouse in the Graphi...
Definition pointerData.h:38
bool encircles(int x, int y) const
Returns true if the trail loops around the specified point.
void add_event(const PointerData &data, int seq, double time)
Adds a new event from the given PointerData object.
double total_turns(double sec) const
returns the total angular deviation that the trail has made in the specified time period.
double match_pattern(const std::string &pattern, double rot, double seglen)
This function is not implemented yet.
Records a pointer movement event.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
double normalize_angle(double angle)
Compute the difference between two angles.
double delta_angle(double angle1, double angle2)
Compute the difference between two angles.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.