Panda3D
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.
Definition: clockObject.I:215
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.
Definition: pointerEvent.h:26
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: dcindent.cxx:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.