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 
21 TypeHandle PointerEventList::_type_handle;
22 
23 /**
24  * Compute the difference between two angles. Returns a value in the range
25  * -180 to 180.
26  */
27 INLINE 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  */
39 INLINE 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  */
50 void PointerEventList::
51 output(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  */
70 void PointerEventList::
71 write(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  */
83 add_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  */
120 add_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  */
153 add_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  */
182 encircles(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  */
216 total_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  */
240 match_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  */
256 void PointerEventList::
257 parse_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 }
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PointerData
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
clockObject.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
cmath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PointerEventList::match_pattern
double match_pattern(const std::string &pattern, double rot, double seglen)
This function is not implemented yet.
Definition: pointerEventList.cxx:240
normalize_angle
double normalize_angle(double angle)
Compute the difference between two angles.
Definition: pointerEventList.cxx:39
PointerEventList::encircles
bool encircles(int x, int y) const
Returns true if the trail loops around the specified point.
Definition: pointerEventList.cxx:182
ClockObject::get_frame_time
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
PointerEventList::total_turns
double total_turns(double sec) const
returns the total angular deviation that the trail has made in the specified time period.
Definition: pointerEventList.cxx:216
pointerEventList.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
deg_2_rad.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PointerEvent
Records a pointer movement event.
Definition: pointerEvent.h:26
delta_angle
double delta_angle(double angle1, double angle2)
Compute the difference between two angles.
Definition: pointerEventList.cxx:27
PointerEventList::add_event
void add_event(const PointerData &data, int seq, double time)
Adds a new event from the given PointerData object.
Definition: pointerEventList.cxx:83