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