3
/////////////////////////////////////////////////////////////////////////////
5
// Copyright (c) 2001-2002 David Ward
7
/////////////////////////////////////////////////////////////////////////////
9
#include "DasherModel.h"
11
using namespace Dasher;
14
//////////////////////////////////////////////////////////////////////
16
//////////////////////////////////////////////////////////////////////
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)
21
LearnContext = m_languagemodel->GetRootNodeContext();
25
m_DasherY = 1<<iShift;
26
m_DasherOY = m_DasherY/2;
27
m_DasherOX = m_DasherY/2;
32
CDasherModel::~CDasherModel()
34
m_languagemodel->ReleaseNodeContext(LearnContext);
37
// DJW 20031106 - hope to get it right this time
39
if (oldroots.size()>0) {
42
// At this point we have also deleted the root - so better NULL pointer
52
while (oldroots.size()>1) {
53
oldroots[0]->Delete_dead(oldroots[1]);
59
if (oldroots.size()==1)
61
oldroots[0]->Delete_dead(m_Root);
66
delete m_Root; // which will also delete all the whole structure
72
void CDasherModel::Make_root(int whichchild)
73
// find a new root node
75
/* symbol t=m_Root->Symbol();
77
if (m_Root->Control()==true) {
78
m_editbox->outputcontrol(m_Root->GetControlTree()->pointer,m_Root->GetControlTree()->data);
82
m_languagemodel->LearnNodeSymbol(LearnContext, t);
87
symbol t=m_Root->Symbol();
89
m_languagemodel->LearnNodeSymbol(LearnContext, t);
92
CDasherNode * oldroot=m_Root;
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
99
oldroots.push_back(oldroot);
101
while (oldroots.size()>10) {
102
oldroots[0]->Delete_dead(oldroots[1]);
104
oldroots.pop_front();
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();
112
void CDasherModel::Reparent_root(int lower, int upper)
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 */
119
if (oldroots.size()==0) // There is no node to reparent to
122
/* Determine how zoomed in we are */
123
double scalefactor=(m_Rootmax-m_Rootmin)/static_cast<double>(upper-lower);
125
m_Root=oldroots.back();
128
m_Rootmax=int(m_Rootmax+((Normalization()-upper)*scalefactor));
129
m_Rootmin=int(m_Rootmin-(lower*scalefactor));
133
/////////////////////////////////////////////////////////////////////////////
135
CDasherNode * CDasherModel::Get_node_under_crosshair()
137
return m_Root->Get_node_under(Normalization(),m_Rootmin,m_Rootmax,m_DasherOX,m_DasherOY);
140
/////////////////////////////////////////////////////////////////////////////
143
CDasherNode * CDasherModel::Get_node_under_mouse(myint Mousex,myint Mousey)
145
return m_Root->Get_node_under(Normalization(),m_Rootmin,m_Rootmax,Mousex,Mousey);
148
/////////////////////////////////////////////////////////////////////////////
151
void CDasherModel::Get_string_under_mouse(const myint Mousex,const myint Mousey, vector<symbol> &str)
153
m_Root->Get_string_under(Normalization(),m_Rootmin,m_Rootmax,Mousex,Mousey,str);
157
/////////////////////////////////////////////////////////////////////////////
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
165
if (node==under_mouse) {
170
CDasherNode **children=node->Children();
173
for (i=1;i<node->Chars();i++)
174
Update(children[i],under_mouse,iSafe);
180
/////////////////////////////////////////////////////////////////////////////
182
void CDasherModel::Start()
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]);
193
oldroots.pop_front();
197
// DJW 20031106 - hope to get it right this time
199
if (oldroots.size()>0) {
202
// At this point we have also deleted the root - so better NULL pointer
208
m_Root=new CDasherNode(0,0,0,0,Opts::Nodes1,0,Normalization(),m_languagemodel, false, 7);
209
CLanguageModel::CNodeContext* therootcontext=m_languagemodel->GetRootNodeContext();
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;
219
m_languagemodel->EnterText(therootcontext, ContextString);
220
m_languagemodel->ReleaseNodeContext(LearnContext);
221
LearnContext = m_languagemodel->CloneNodeContext(therootcontext);
224
m_Root->Push_Node(therootcontext);
225
m_Root->Recursive_Push_Node(0);
227
m_languagemodel->ReleaseNodeContext(therootcontext);
233
/////////////////////////////////////////////////////////////////////////////
235
void CDasherModel::Get_new_root_coords(myint Mousex,myint Mousey)
238
double dRx=1.0,dRxnew=1.0;
241
int iSteps=m_fr.Steps();
243
if (Mousex<m_DasherOX) {
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
249
dRxnew2=1+(dRx-1)/iSteps;
251
const double dRxmax=m_fr.Rxmax();
255
if (Mousex==m_DasherOX)
257
dRx=1.0001*m_DasherOX/Mousex;
258
dRxnew=exp(log(dRx)/iSteps);
259
if (m_Rootmax<m_DasherY && m_Rootmin>0) {
263
myint above=(Mousey-m_Rootmin);//*(1-rxnew)/(1-rx);
264
myint below=(m_Rootmax-Mousey);//*(1-rxnew)/(1-rx);
266
myint miDistance=m_DasherY/2-Mousey;
267
miDistance=myint(miDistance*(dRxnew-1)/(dRx-1));
268
myint miNewrootzoom=Mousey+miDistance;
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;
278
void CDasherModel::Get_new_goto_coords(myint MouseX, myint MouseY)
280
// First, we need to work out how far we need to zoom in
281
float zoomfactor=(m_DasherOX-MouseX)/(m_DasherOX*1.0);
283
// Then zoom in appropriately
284
m_Rootmax+=zoomfactor*(m_Rootmax-m_DasherY/2);
285
m_Rootmin+=zoomfactor*(m_Rootmin-m_DasherY/2);
287
// Afterwards, we need to take care of the vertical offset.
288
myint up=(m_DasherY/2)-MouseY;
293
myint CDasherModel::PlotGoTo(myint MouseX, myint MouseY)
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);
299
myint height=m_DasherY*zoomfactor/2;
305
/////////////////////////////////////////////////////////////////////////////
307
void CDasherModel::Tap_on_display(myint miMousex,myint miMousey, unsigned long Time)
308
// work out the next viewpoint, opens some new nodes
310
// Find out the current node under the crosshair
311
CDasherNode *old_under_cross=Get_node_under_crosshair();
313
// works out next viewpoint
314
Get_new_root_coords(miMousex,miMousey);
316
// opens up new nodes
318
// push node under mouse
319
CDasherNode *under_mouse=Get_node_under_mouse(miMousex,miMousey);
320
under_mouse->Push_Node();
322
if (Framerate() > 4) {
323
// push node under mouse but with x coord on RHS
324
CDasherNode *right=Get_node_under_mouse(50,miMousey);
328
if (Framerate() > 8) {
329
// push node under the crosshair
330
CDasherNode* under_cross=Get_node_under_crosshair();
331
under_cross->Push_Node();
334
unsigned int iRandom;
335
#if defined(_WIN32_WCE)
340
if (Framerate() > 8) {
341
// add some noise and push another node
342
CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%500-250);
345
#if defined(_WIN32_WCE)
350
if (Framerate() > 15) {
351
// add some noise and push another node
352
CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%500-250);
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)
364
// push at a random node on the RHS
365
CDasherNode *right=Get_node_under_mouse(50,miMousey+iRandom%1000-500);
371
Update(m_Root,under_mouse,0);
373
CDasherNode* new_under_cross = Get_node_under_crosshair();
375
if (new_under_cross!=old_under_cross) {
376
DeleteCharacters(new_under_cross,old_under_cross);
379
if (new_under_cross->isSeen()==true) {
380
if (new_under_cross->Control()!=true) {
381
SetBitrate(m_dMaxRate);
386
new_under_cross->Seen(true);
388
symbol t=new_under_cross->Symbol();
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);
395
OutputCharacters(new_under_cross);
396
SetBitrate(m_dMaxRate);
398
// m_Root->Recursive_Push_Node(0);
401
void CDasherModel::GoTo(myint miMousex,myint miMousey)
402
// work out the next viewpoint, opens some new nodes
404
// Find out the current node under the crosshair
405
CDasherNode *old_under_cross=Get_node_under_crosshair();
407
// works out next viewpoint
408
Get_new_goto_coords(miMousex,miMousey);
410
// push node under crosshair
412
CDasherNode* new_under_cross = Get_node_under_crosshair();
414
new_under_cross->Push_Node();
416
// push node under goto point
418
CDasherNode* node_under_goto = Get_node_under_mouse(miMousex, miMousey);
420
node_under_goto->Push_Node();
422
Update(m_Root,new_under_cross,0);
424
if (new_under_cross!=old_under_cross) {
425
DeleteCharacters(new_under_cross,old_under_cross);
428
if (new_under_cross->isSeen()==true)
431
new_under_cross->Seen(true);
433
symbol t=new_under_cross->Symbol();
435
OutputCharacters(new_under_cross);
438
void CDasherModel::OutputCharacters(CDasherNode *node) {
439
if (node->Parent()!=NULL && node->Parent()->isSeen()!=true) {
440
node->Parent()->Seen(true);
441
OutputCharacters(node->Parent());
443
symbol t=node->Symbol();
445
m_editbox->output(t);
446
} else if (node->Control()==true) {
447
m_editbox->outputcontrol(node->GetControlTree()->pointer,node->GetControlTree()->data,node->GetControlTree()->type);
451
bool CDasherModel::DeleteCharacters (CDasherNode *newnode, CDasherNode *oldnode) {
452
if (newnode==NULL||oldnode==NULL) {
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());
462
oldnode->Seen(false);
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());
469
oldnode->Seen(false);
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();
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();
486
m_editbox->deletetext(oldnode->Symbol());
487
oldnode=oldnode->Parent();
496
/////////////////////////////////////////////////////////////////////////////
498
void CDasherModel::Dump() const
501
// OutputDebugString(TEXT(" ptr symbol context Next Child pushme pushed cscheme lbnd hbnd \n"));