~ubuntu-branches/ubuntu/warty/dasher/warty

« back to all changes in this revision

Viewing changes to Src/DasherCore/DasherModel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2003-06-05 11:10:04 UTC
  • Revision ID: james.westby@ubuntu.com-20030605111004-kqiutbrlvs7td9ic
Tags: upstream-3.2.10
ImportĀ upstreamĀ versionĀ 3.2.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// DasherModel.h
 
2
//
 
3
/////////////////////////////////////////////////////////////////////////////
 
4
//
 
5
// Copyright (c) 2001-2002 David Ward
 
6
//
 
7
/////////////////////////////////////////////////////////////////////////////
 
8
 
 
9
#include "DasherModel.h"
 
10
 
 
11
using namespace Dasher;
 
12
using namespace std;
 
13
 
 
14
//////////////////////////////////////////////////////////////////////
 
15
// CDasherModel
 
16
//////////////////////////////////////////////////////////////////////
 
17
 
 
18
CDasherModel::CDasherModel(CDashEditbox* Editbox, CLanguageModel* LanguageModel, bool Dimensions, bool Eyetracker)
 
19
  : m_editbox(Editbox), m_languagemodel(LanguageModel), m_Root(0), m_Dimensions(Dimensions), m_Eyetracker(Eyetracker)
 
20
{
 
21
        LearnContext = m_languagemodel->GetRootNodeContext();
 
22
        
 
23
        // various settings
 
24
        int iShift = 12;
 
25
        m_DasherY = 1<<iShift;
 
26
        m_DasherOY = m_DasherY/2;
 
27
        m_DasherOX = m_DasherY/2;
 
28
        m_dAddProb = 0.003;
 
29
}
 
30
 
 
31
 
 
32
CDasherModel::~CDasherModel()
 
33
{
 
34
        m_languagemodel->ReleaseNodeContext(LearnContext);
 
35
 
 
36
 
 
37
        // DJW 20031106 - hope to get it right this time
 
38
        
 
39
        if (oldroots.size()>0) { 
 
40
                delete oldroots[0];
 
41
                oldroots.clear();
 
42
                // At this point we have also deleted the root - so better NULL pointer
 
43
                m_Root=NULL;
 
44
        }
 
45
        
 
46
        delete m_Root;
 
47
 
 
48
 
 
49
        /*
 
50
        // This is yukky
 
51
 
 
52
        while (oldroots.size()>1) {
 
53
          oldroots[0]->Delete_dead(oldroots[1]);
 
54
          delete oldroots[0];
 
55
          oldroots.pop_front();
 
56
        }
 
57
 
 
58
        // even more yukky
 
59
        if (oldroots.size()==1)
 
60
        {
 
61
                 oldroots[0]->Delete_dead(m_Root);
 
62
                delete oldroots[0];
 
63
                oldroots.clear();
 
64
        }
 
65
 
 
66
        delete m_Root;  // which will also delete all the whole structure
 
67
*/
 
68
 
 
69
}
 
70
 
 
71
 
 
72
void CDasherModel::Make_root(int whichchild)
 
73
 // find a new root node 
 
74
{
 
75
  /*    symbol t=m_Root->Symbol();
 
76
 
 
77
        if (m_Root->Control()==true) {
 
78
          m_editbox->outputcontrol(m_Root->GetControlTree()->pointer,m_Root->GetControlTree()->data);
 
79
        } else {
 
80
          if (t) {
 
81
            m_editbox->output(t);
 
82
            m_languagemodel->LearnNodeSymbol(LearnContext, t);
 
83
          }
 
84
        }
 
85
  */
 
86
 
 
87
  symbol t=m_Root->Symbol();
 
88
  if (t) {
 
89
    m_languagemodel->LearnNodeSymbol(LearnContext, t);
 
90
  }
 
91
 
 
92
        CDasherNode * oldroot=m_Root;
 
93
        
 
94
        CDasherNode **children=m_Root->Children();
 
95
        m_Root=children[whichchild];
 
96
        //      oldroot->Children()[whichchild]=0;  // null the pointer so we don't delete the whole tree
 
97
        //      delete oldroot;
 
98
        
 
99
        oldroots.push_back(oldroot);
 
100
 
 
101
        while (oldroots.size()>10) {
 
102
          oldroots[0]->Delete_dead(oldroots[1]);
 
103
          delete oldroots[0];
 
104
          oldroots.pop_front();
 
105
        }
 
106
 
 
107
        myint range=m_Rootmax-m_Rootmin;
 
108
        m_Rootmax=m_Rootmin+(range*m_Root->Hbnd())/Normalization();
 
109
        m_Rootmin+=(range*m_Root->Lbnd())/Normalization();
 
110
}
 
111
 
 
112
void CDasherModel::Reparent_root(int lower, int upper)
 
113
{
 
114
 
 
115
  /* Change the root node to the parent of the existing node
 
116
     We need to recalculate the coordinates for the "new" root as the 
 
117
     user may have moved around within the current root */
 
118
 
 
119
  if (oldroots.size()==0) // There is no node to reparent to
 
120
    return;
 
121
 
 
122
  /* Determine how zoomed in we are */
 
123
  double scalefactor=(m_Rootmax-m_Rootmin)/static_cast<double>(upper-lower);
 
124
 
 
125
  m_Root=oldroots.back();
 
126
  oldroots.pop_back();
 
127
  
 
128
  m_Rootmax=int(m_Rootmax+((Normalization()-upper)*scalefactor));
 
129
  m_Rootmin=int(m_Rootmin-(lower*scalefactor));
 
130
 
 
131
}
 
132
 
 
133
/////////////////////////////////////////////////////////////////////////////
 
134
 
 
135
CDasherNode * CDasherModel::Get_node_under_crosshair()
 
136
{
 
137
        return m_Root->Get_node_under(Normalization(),m_Rootmin,m_Rootmax,m_DasherOX,m_DasherOY);
 
138
}
 
139
 
 
140
/////////////////////////////////////////////////////////////////////////////
 
141
 
 
142
 
 
143
CDasherNode * CDasherModel::Get_node_under_mouse(myint Mousex,myint Mousey)
 
144
{
 
145
        return m_Root->Get_node_under(Normalization(),m_Rootmin,m_Rootmax,Mousex,Mousey);
 
146
}
 
147
 
 
148
/////////////////////////////////////////////////////////////////////////////
 
149
 
 
150
 
 
151
void CDasherModel::Get_string_under_mouse(const myint Mousex,const myint Mousey, vector<symbol> &str)
 
152
{
 
153
        m_Root->Get_string_under(Normalization(),m_Rootmin,m_Rootmax,Mousex,Mousey,str);
 
154
        return;
 
155
}
 
156
 
 
157
/////////////////////////////////////////////////////////////////////////////
 
158
 
 
159
 
 
160
void CDasherModel::Update(CDasherNode *node,CDasherNode *under_mouse,int iSafe)
 
161
// go through the Dasher nodes, delete ones who have expired
 
162
// decrease the time left for nodes which arent safe
 
163
// safe nodes are those which are under the mouse or offspring of this node
 
164
{
 
165
  if (node==under_mouse) {
 
166
                iSafe=1;
 
167
  }
 
168
        
 
169
        if (node->Alive()) {
 
170
                CDasherNode **children=node->Children();
 
171
                if (children) {
 
172
                        unsigned int i;
 
173
                        for (i=1;i<node->Chars();i++)
 
174
                                Update(children[i],under_mouse,iSafe);
 
175
                }
 
176
        }
 
177
        return;
 
178
}
 
179
 
 
180
/////////////////////////////////////////////////////////////////////////////
 
181
 
 
182
void CDasherModel::Start()
 
183
{
 
184
        m_Rootmin=0;
 
185
        m_Rootmax=m_DasherY;
 
186
 
 
187
        
 
188
        /*
 
189
        // DJW 20031106 - this is unsafe - oldroots[1] is not valid when size == 1
 
190
        while (oldroots.size()>0) {
 
191
          oldroots[0]->Delete_dead(oldroots[1]);
 
192
          delete oldroots[0];
 
193
          oldroots.pop_front();
 
194
        }
 
195
        */
 
196
 
 
197
        // DJW 20031106 - hope to get it right this time
 
198
        
 
199
        if (oldroots.size()>0) { 
 
200
                delete oldroots[0];
 
201
                oldroots.clear();
 
202
                // At this point we have also deleted the root - so better NULL pointer
 
203
                m_Root=NULL;
 
204
        }
 
205
        
 
206
        delete m_Root;
 
207
        
 
208
        m_Root=new CDasherNode(0,0,0,0,Opts::Nodes1,0,Normalization(),m_languagemodel, false, 7);
 
209
        CLanguageModel::CNodeContext* therootcontext=m_languagemodel->GetRootNodeContext();
 
210
 
 
211
        if (m_editbox) {
 
212
                string ContextString;
 
213
                m_editbox->get_new_context(ContextString,5);
 
214
                if (ContextString.size()==0) {
 
215
                  // If there is no root context, pretend that we've just
 
216
                  // finished a sentence
 
217
                  ContextString=". " + ContextString;
 
218
                }
 
219
                m_languagemodel->EnterText(therootcontext, ContextString);
 
220
                m_languagemodel->ReleaseNodeContext(LearnContext);
 
221
                LearnContext = m_languagemodel->CloneNodeContext(therootcontext);
 
222
        }
 
223
 
 
224
        m_Root->Push_Node(therootcontext);
 
225
        m_Root->Recursive_Push_Node(0);
 
226
        
 
227
        m_languagemodel->ReleaseNodeContext(therootcontext);
 
228
//      ppmmodel->dump();
 
229
//      dump();
 
230
        
 
231
}
 
232
 
 
233
/////////////////////////////////////////////////////////////////////////////
 
234
 
 
235
void CDasherModel::Get_new_root_coords(myint Mousex,myint Mousey)
 
236
{
 
237
        int cappedrate=0;
 
238
        double dRx=1.0,dRxnew=1.0;
 
239
        double dRxnew2;
 
240
 
 
241
        int iSteps=m_fr.Steps();
 
242
 
 
243
        if (Mousex<m_DasherOX) {
 
244
                if (Mousex<=0)
 
245
                        Mousex=1;
 
246
                dRx=1.0*m_DasherOX/Mousex;
 
247
                dRxnew=pow(dRx,1.0/iSteps);  // or exp(log(rx)/steps) - i think the replacement is faster   
 
248
        
 
249
                dRxnew2=1+(dRx-1)/iSteps;
 
250
                
 
251
                const double dRxmax=m_fr.Rxmax();
 
252
                if (dRxnew>dRxmax)
 
253
                 dRxnew=dRxmax;
 
254
        } else {
 
255
                if (Mousex==m_DasherOX)
 
256
                        Mousex++;
 
257
                dRx=1.0001*m_DasherOX/Mousex;
 
258
                dRxnew=exp(log(dRx)/iSteps);
 
259
                if (m_Rootmax<m_DasherY && m_Rootmin>0) {
 
260
                  return;
 
261
                }
 
262
        } 
 
263
        myint above=(Mousey-m_Rootmin);//*(1-rxnew)/(1-rx);
 
264
        myint below=(m_Rootmax-Mousey);//*(1-rxnew)/(1-rx);
 
265
 
 
266
        myint miDistance=m_DasherY/2-Mousey;
 
267
        miDistance=myint(miDistance*(dRxnew-1)/(dRx-1));
 
268
        myint miNewrootzoom=Mousey+miDistance;
 
269
 
 
270
        myint newRootmax=miNewrootzoom+myint(below*dRxnew);
 
271
        myint newRootmin=miNewrootzoom-myint(above*dRxnew);
 
272
        if (newRootmin<m_DasherY/2 && newRootmax>m_DasherY/2 && newRootmax<LLONG_MAX && newRootmin>LLONG_MIN) {
 
273
                m_Rootmax=newRootmax;
 
274
                m_Rootmin=newRootmin;   
 
275
        }
 
276
}
 
277
 
 
278
void CDasherModel::Get_new_goto_coords(myint MouseX, myint MouseY)
 
279
{
 
280
  // First, we need to work out how far we need to zoom in
 
281
  float zoomfactor=(m_DasherOX-MouseX)/(m_DasherOX*1.0);
 
282
 
 
283
  // Then zoom in appropriately
 
284
  m_Rootmax+=zoomfactor*(m_Rootmax-m_DasherY/2);
 
285
  m_Rootmin+=zoomfactor*(m_Rootmin-m_DasherY/2);
 
286
 
 
287
  // Afterwards, we need to take care of the vertical offset.
 
288
  myint up=(m_DasherY/2)-MouseY;
 
289
  m_Rootmax+=up;
 
290
  m_Rootmin+=up;
 
291
}
 
292
 
 
293
myint CDasherModel::PlotGoTo(myint MouseX, myint MouseY)
 
294
{
 
295
  // First, we need to work out how far we need to zoom in
 
296
  float zoomfactor=(m_DasherOX-MouseX)/(m_DasherOX*1.0);
 
297
  zoomfactor=pow(float(0.5),zoomfactor);
 
298
 
 
299
  myint height=m_DasherY*zoomfactor/2;
 
300
 
 
301
  return height;
 
302
}
 
303
  
 
304
 
 
305
/////////////////////////////////////////////////////////////////////////////
 
306
 
 
307
void CDasherModel::Tap_on_display(myint miMousex,myint miMousey, unsigned long Time) 
 
308
        // work out the next viewpoint, opens some new nodes
 
309
{
 
310
        // Find out the current node under the crosshair
 
311
        CDasherNode *old_under_cross=Get_node_under_crosshair();        
 
312
        
 
313
        // works out next viewpoint
 
314
        Get_new_root_coords(miMousex,miMousey);
 
315
 
 
316
        // opens up new nodes
 
317
 
 
318
        // push node under mouse
 
319
        CDasherNode *under_mouse=Get_node_under_mouse(miMousex,miMousey);
 
320
        under_mouse->Push_Node();
 
321
 
 
322
        if (Framerate() > 4) {
 
323
                // push node under mouse but with x coord on RHS
 
324
                CDasherNode *right=Get_node_under_mouse(50,miMousey);
 
325
                right->Push_Node();
 
326
        }
 
327
 
 
328
        if (Framerate() > 8) {
 
329
                // push node under the crosshair
 
330
                CDasherNode* under_cross=Get_node_under_crosshair();
 
331
                under_cross->Push_Node();
 
332
        }
 
333
 
 
334
        unsigned int iRandom;
 
335
#if defined(_WIN32_WCE)
 
336
        iRandom=Random();
 
337
#else
 
338
        iRandom=rand();
 
339
#endif
 
340
        if (Framerate() > 8) {
 
341
                // add some noise and push another node
 
342
                CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%500-250);
 
343
                right->Push_Node();
 
344
        }
 
345
#if defined(_WIN32_WCE)
 
346
        iRandom=Random();
 
347
#else
 
348
        iRandom=rand();
 
349
#endif
 
350
        if (Framerate() > 15) {
 
351
                // add some noise and push another node
 
352
                CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%500-250);
 
353
                right->Push_Node();
 
354
        }
 
355
 
 
356
        // only do this is Dasher is flying
 
357
        if (Framerate() > 30) {
 
358
                for (int i=1;i<int(Framerate()-30)/3;i++) {
 
359
#if defined(_WIN32_WCE) 
 
360
                iRandom=Random();
 
361
#else
 
362
                iRandom=rand();
 
363
#endif
 
364
                // push at a random node on the RHS
 
365
                CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%1000-500);
 
366
                right->Push_Node();
 
367
        
 
368
                }
 
369
        }
 
370
 
 
371
        Update(m_Root,under_mouse,0);
 
372
 
 
373
        CDasherNode* new_under_cross = Get_node_under_crosshair();
 
374
 
 
375
        if (new_under_cross!=old_under_cross) {
 
376
          DeleteCharacters(new_under_cross,old_under_cross);
 
377
        }
 
378
 
 
379
        if (new_under_cross->isSeen()==true) {
 
380
          if (new_under_cross->Control()!=true) {
 
381
            SetBitrate(m_dMaxRate);
 
382
          }
 
383
          return;
 
384
        }
 
385
 
 
386
        new_under_cross->Seen(true);
 
387
 
 
388
        symbol t=new_under_cross->Symbol();
 
389
 
 
390
        if (new_under_cross->Control()==true) {
 
391
          //            m_editbox->outputcontrol(new_under_cross->GetControlTree()->pointer,new_under_cross->GetControlTree()->data,new_under_cross->GetControlTree()->type);
 
392
                OutputCharacters(new_under_cross);
 
393
                SetBitrate(m_dMaxRate/3);
 
394
        } else {
 
395
          OutputCharacters(new_under_cross);
 
396
          SetBitrate(m_dMaxRate);
 
397
        }
 
398
        //      m_Root->Recursive_Push_Node(0);
 
399
}
 
400
 
 
401
void CDasherModel::GoTo(myint miMousex,myint miMousey) 
 
402
        // work out the next viewpoint, opens some new nodes
 
403
{
 
404
        // Find out the current node under the crosshair
 
405
        CDasherNode *old_under_cross=Get_node_under_crosshair();        
 
406
        
 
407
        // works out next viewpoint
 
408
        Get_new_goto_coords(miMousex,miMousey);
 
409
 
 
410
        // push node under crosshair
 
411
 
 
412
        CDasherNode* new_under_cross = Get_node_under_crosshair();
 
413
 
 
414
        new_under_cross->Push_Node();
 
415
 
 
416
        // push node under goto point
 
417
 
 
418
        CDasherNode* node_under_goto = Get_node_under_mouse(miMousex, miMousey);
 
419
 
 
420
        node_under_goto->Push_Node();
 
421
 
 
422
        Update(m_Root,new_under_cross,0);
 
423
 
 
424
        if (new_under_cross!=old_under_cross) {
 
425
          DeleteCharacters(new_under_cross,old_under_cross);
 
426
        }
 
427
 
 
428
        if (new_under_cross->isSeen()==true)
 
429
          return;
 
430
 
 
431
        new_under_cross->Seen(true);
 
432
 
 
433
        symbol t=new_under_cross->Symbol();
 
434
 
 
435
        OutputCharacters(new_under_cross);
 
436
}
 
437
 
 
438
void CDasherModel::OutputCharacters(CDasherNode *node) {
 
439
  if (node->Parent()!=NULL && node->Parent()->isSeen()!=true) {
 
440
    node->Parent()->Seen(true);
 
441
    OutputCharacters(node->Parent());
 
442
  }
 
443
  symbol t=node->Symbol();
 
444
  if (t) {
 
445
    m_editbox->output(t);
 
446
  } else if (node->Control()==true) {
 
447
          m_editbox->outputcontrol(node->GetControlTree()->pointer,node->GetControlTree()->data,node->GetControlTree()->type);
 
448
  }
 
449
}
 
450
 
 
451
bool CDasherModel::DeleteCharacters (CDasherNode *newnode, CDasherNode *oldnode) {
 
452
  if (newnode==NULL||oldnode==NULL) {
 
453
    return false;
 
454
  }
 
455
  // This deals with the trivial instance - we're reversing back over
 
456
  // text that we've seen already
 
457
  if (newnode->isSeen()==true) {
 
458
    if (oldnode->Parent()==newnode) {
 
459
      if (oldnode->Symbol()!=m_languagemodel->GetControlSymbol()&&oldnode->Control()==false&&oldnode->Symbol()!=0) {
 
460
        m_editbox->deletetext(oldnode->Symbol());
 
461
      }
 
462
      oldnode->Seen(false);
 
463
      return true;
 
464
    }
 
465
    if (DeleteCharacters(newnode,oldnode->Parent())==true) {
 
466
      if (oldnode->Symbol()!=m_languagemodel->GetControlSymbol()&&oldnode->Control()==false&&oldnode->Symbol()!=0) {
 
467
        m_editbox->deletetext(oldnode->Symbol());
 
468
      }
 
469
      oldnode->Seen(false);
 
470
      return true;
 
471
    }
 
472
  } else {
 
473
    // This one's more complicated - the user may have moved onto a new branch
 
474
    // Find the last seen node on the new branch
 
475
    CDasherNode *lastseen=newnode->Parent();
 
476
    while (lastseen!=NULL && lastseen->isSeen()==false) {      
 
477
      lastseen=lastseen->Parent();
 
478
    };
 
479
    // Delete back to last seen node
 
480
    while (oldnode!=lastseen) {
 
481
      oldnode->Seen(false);
 
482
      if (oldnode->Control()==true||oldnode->Symbol()==m_languagemodel->GetControlSymbol() || oldnode->Symbol()==0) {
 
483
        oldnode=oldnode->Parent();
 
484
        continue;
 
485
      }
 
486
      m_editbox->deletetext(oldnode->Symbol());
 
487
      oldnode=oldnode->Parent();
 
488
      if (oldnode==NULL) {
 
489
        return false;
 
490
      }
 
491
    }
 
492
  }
 
493
  return false;
 
494
}
 
495
 
 
496
/////////////////////////////////////////////////////////////////////////////
 
497
 
 
498
void CDasherModel::Dump() const 
 
499
        // diagnostic dump
 
500
{
 
501
                // OutputDebugString(TEXT(" ptr   symbol   context Next  Child    pushme pushed cscheme   lbnd  hbnd \n"));
 
502
                m_Root->Dump_node();
 
503
}
 
504
 
 
505
 
 
506