Structural deformable models
Model.cpp
Go to the documentation of this file.
1 #ifdef WIN32
2 #include <windows.h>
3 #endif
4 
5 #include <stdlib.h>
6 #include <iostream>
7 #include <fstream>
8 #include <sstream>
9 #include <ctype.h>
10 
11 #include "Model.h"
12 #include "SensorSet.h"
13 #include "SensorColl.h"
14 #include "Data.h"
15 #include "PartParam.h"
16 #include "Searcher.h"
17 #include "crc.h"
18 #include "mathutil.h"
19 
20 //#include "camgraph/gprocess.h"
21 
22 using namespace std;
23 
25 
27  : m_TimeStamp(0), m_Dataset(_dataset), m_Sensors(sensors),
28  m_Flags(0), m_PCFlags(PC_NOTHING), m_InstCount(1), m_HLNode(-1), m_ID(0)
29 {
33  setName("00");
35  m_DirNodeInd=-1;
36  if(m_Sensors) m_Sensors->refModel(this);
37 }
38 
39 Model::Model(const Model& rhs)
40 {
41  m_Sensors = NULL;
42  operator=(rhs);
43 }
44 
46 {
48 }
49 
51 {
52  if(&rhs == this) return *this;
53  m_Dataset = rhs.m_Dataset;
56  nodes = rhs.nodes;
57  edges = rhs.edges;
58  for(EdgeArray::iterator e=edges.begin(); e!=edges.end(); e++)
59  {
60  e->setNodesList(nodes);
61  }
62  m_Flags = rhs.m_Flags;
63 // phys.gravitational = rhs.phys.gravitational;
64 // phys.viscousdrag = rhs.phys.viscousdrag;
65  phys = rhs.phys;
66  m_Name = rhs.m_Name;
67  m_CRC = rhs.m_CRC;
68  m_ppmm = rhs.m_ppmm;
71  m_PCFlags = rhs.m_PCFlags;
72  m_PropVec = rhs.m_PropVec;
75  m_QOF = rhs.m_QOF;
77  m_Filename = rhs.m_Filename;
78  m_HLNode = rhs.m_HLNode;
79  //m_Deriv = rhs.m_Deriv;
80  //m_LastDT = rhs.m_LastDT;
81  m_ID = rhs.m_ID;
82  return *this;
83 }
84 
86  if(m_Dataset == dataset) return;
87  m_Dataset = dataset;
88  if(m_Sensors && m_Sensors->getSensor("d0") != dataset)
89  m_Sensors->addSensor("d0",
90  std::dynamic_pointer_cast<Sensor>(
91  std::const_pointer_cast<Dataset>(dataset)));
93 }
94 
96 {
97  nodes.clear();
98  edges.clear();
99  //m_Deriv.clear();
100  m_DirNodeInd=-1;
101 }
102 
104 {
105  clear();
106  m_TimeStamp = 0; //vector<float>(TS_LAST, 0);
107  m_Flags=0;
109  m_InstCount=1;
113  setName("00");
114  //m_ppmm = DEFAULT_PPMM;
115  m_Filename.clear();
116 }
117 
120 int Model::addNode(const Node &node)
121 {
122  if(node.index!=-1 && nodes.size()>(dword)node.index) {
123  TRACE(node.index);
124  nodes[node.index] = node;
125  return node.index;
126  }
127  int index = nodes.size();
128  //nodes[index] = node;
129  nodes.push_back(node);
130  //nodes.end()->index = index;
131  nodes[index].index = index;
132  assert(nodes[index].index == index);
133  return index;
134 }
135 
138 int Model::addEdge(const Edge &edge)
139 {
140  int index = edges.size();
141  edges.push_back(edge);
142  edges[index].index = index;
143  edges[index].setNodesList(nodes);
144  edges[index].fromNode().edges.push_back(index+1);
145  edges[index].toNode().edges.push_back(-index-1);
146  return index;
147 }
148 
151 int Model::addEdge(const Node &from, const Node &to)
152 {
153  int fi = addNode(from);
154  int ti = addNode(to);
155  return addEdge(Edge(fi,ti,nodes));
156 }
157 
160 int Model::addEdge(int ifrom, int ito)
161 {
162  assert((dword)ifrom<nodes.size() &&
163  (dword)ito<nodes.size() && ifrom>=0 && ito>=0);
164  return addEdge( Edge(ifrom, ito, nodes, &phys) );
165 }
166 
168 {
169  if(!is.getNextLine()) return false;
170  if(is.getKey() != "e") {
171  is.pushLine();
172  return false;
173  }
174  istringstream vs(is.getValue());
175  vs >> ws;
176  int from, to;
177  vs >> from;
178  from--;
179  int size = nodes.size();
180  if(from<0 || from>size-1) throw new IOException("Edge is made of node indices that don't exist.");
181  vs >> to;
182  to--;
183  if(to<0 || to>size-1) throw new IOException("Edge is made of node indices that don't exist.");
184  Edge &ed = edges[addEdge(from, to)];
185  string param;
186  while(vs >> param) {
187  if(param == "sc")
188  vs >> ed.springconstant;
189  else if(param == "dc")
190  vs >> ed.dampingconstant;
191  else if(param == "rl")
192  vs >> ed.restlength;
193  else if(param == "es") {
194  char ft = 0;
195  vs >> ft;
196  if(ft == 'f') vs >> ed.edgesensor;
197  else if(ft == 't') { vs >> ed.edgesensor; ed.edgesensor *= -1; }
198  else {
199  is.setParseError("error reading edge parameter [es]");
200  throw new IOException("error reading edge parameter [es]");
201  }
202  } else {
203  is.setParseError("error reading edge parameters");
204  throw new IOException("error reading edge parameters");
205  }
206  }
207  return true;
208 }
209 
211 {
212  if(!is.getNextLine()) return false;
213  if(is.getKey() != "v") {
214  is.pushLine();
215  return false;
216  }
217  istringstream vs(is.getValue());
218  vs >> ws;
219  Node n(&phys);
220  vs >> n.x;
221  vs >> n.y;
223  string param;
224  while(vs >> param) {
225  if(param == "s") {
226  vs >> param;
227  if(m_Sensors) n.attachSensor(m_Sensors->getSensor(param));
228  else {
229  is.setParseError("tried to load undefined sensor");
230  throw new IOException("tried to load undefined sensor");
231  }
232  } else if(param == "m")
233  vs >> n.mass;
234  else {
235  is.setParseError("error reading node parameters");
236  throw new IOException("error reading node parameters");
237  }
238  }
239  addNode(n);
240  //debugline: cout << addNode(n) << " - " << n << endl;
241  return true;
242 }
243 
245 {
246  if(!is.getNextLine()) return false;
247  if(is.getKey() == "sensors") {
248  ParseFile sf(is.getPath()+is.getValue());
249  if(sf) {
250  m_SensorFile = is.getValue();
251  while(sf) readSensor(sf);
252  } else cerr << "couldn't load sensor file "
253  << is.getPath()+is.getValue() << endl;
254  } else is.pushLine();
255  if(!m_Sensors) m_Sensors = new SensorCollection();
257  if(!s) return false;
258  m_Sensors->addSensor(s);
259  //s->enableUpdate(Sensor::UPD_MINMAX); done in Node::attachSensor
260  return true;
261 }
262 
264 {
265  if(!is.getNextLine()) return false;
266  if(is.getKey() != "p") {
267  is.pushLine();
268  return false;
269  }
270  istringstream vs(is.getValue());
271  string pname;
272  vs >> pname;
273  if(pname == "mass") {
274  vs >> phys.mass;
275  } else if(pname == "springconst") {
276  vs >> phys.springconst;
277  } else if(pname == "grav") {
278  vs >> phys.gravitational;
279  } else if(pname == "viscousdrag") {
280  vs >> phys.viscousdrag;
281  } else if(pname == "damping") {
282  vs >> phys.damping;
283  } else if(pname == "imageforce") {
284  vs >> phys.imgforce;
285  } else if(pname == "torque") {
286  vs >> phys.torque;
287  } else if(pname == "name") {
288  string name;
289  vs >> name;
290  setName(name);
291  } else if(pname == "ppmm") {
292  vs >> m_ppmm;
293  } else if(pname == "dirnode") {
294  vs >> m_DirNodeInd;
295  }
296  return true;
297 }
298 
300 {
301  g.reset();
302  g.m_Filename = is.getFilename();
304  g.setName("<noname>");
305  g.m_ppmm = DEFAULT_PPMM;
306  try{
307  int phase=0;
308  while(is) {
309  if(phase == 0) {
310  if(!g.readSensor(is) && !g.readParameter(is))
311  phase++;
312  }
313  if(phase == 1) {
314  if(!g.readNode(is))
315  phase++;
316  }
317  if(phase == 2) {
318  if(!g.readEdge(is))
319  phase++;
320  }
321  if(phase == 3 && !is.eof()) {
322  g.reset();
323  throw new IOException("Error reading model file.");
324  }
325  }
326  } catch(const IOException *e) {
327  const char* omsg = e->getMessage();
328  int l=strlen(omsg);
329  char msg[l+256];
330  sprintf(msg,"%s (interpreted line %i)", omsg, is.getLineNumber());
331  throw new IOException(msg);
332  }
333  g.adaptDataScale();
334  g.prepareTorque();
335  return is;
336 }
337 
338 ostream& operator<<(ostream &os, const Model &g)
339 {
340  os << "p name " << g.m_Name << endl;
341  if(g.m_ppmm != DEFAULT_PPMM)
342  os << "p ppmm " << g.m_ppmm << endl;
343  os << "p dirnode " << g.m_DirNodeInd << endl;
344  os << g.phys;
345  os << endl;
346  if(!g.m_SensorFile.empty()) {
347  ofstream sf((ParseFile::getPath(g.m_Filename)+g.m_SensorFile).c_str());
348  sf << *g.m_Sensors;
349  os << "sensors " << g.m_SensorFile << endl;
350  } else {
352  for(NodeArray::const_iterator n = g.nodes.begin(); n != g.nodes.end();
353  n++)
354  n->sensor->hprint(os, (SensorCollection*)g.m_Sensors);
355  }
356  os << endl;
357  for(NodeArray::const_iterator n = g.nodes.begin(); n != g.nodes.end(); n++)
358  os << *n;
359  os << endl;
360  for(EdgeArray::const_iterator e = g.edges.begin(); e != g.edges.end(); e++)
361  os << *e;
362  return os;
363 }
364 
365 bool Model::readFile(const char *filename, bool fullread)
366 {
367  ParseFile is(filename);
368  if(is) {
369  try {
370  is >> *this;
371  } catch (const IOException *e) {
372  cerr << "IOException: " << e->getMessage() << endl
373  << "reading file " << filename << endl;
374  reset();
375  return false;
376  }
377  return true;
378  } else return false;
379 }
380 
381 bool Model::writeFile(const char *filename) const
382 {
383  ofstream os(filename);
384  if(os) {
385  try {
386  os << "# file '" << filename << "' "<<endl;
387  ParticleParam::global = phys;
388  os << *this;
389  } catch (const IOException *e) {
390  cerr << "IOException: " << e->getMessage() << endl
391  << "writing file " << filename << endl;
392  return false;
393  }
394  os.close();
395  return true;
396  } else return false;
397 }
398 
399 void Model::setName(const string &name)
400 {
401  m_Name = name;
402  m_CRC = (dword)CRC((unsigned char*)m_Name.c_str(), m_Name.size());
403 }
404 
405 void Model::setHLNode(int hlnode) {
406  if(m_HLNode>=0 && m_HLNode<getNNodes())
408  m_HLNode = hlnode;
409  if(m_HLNode>=0 && m_HLNode<getNNodes())
411  else m_HLNode = -1;
412 }
413 
416 {
417  DMatrixf adjm(getNNodes(), getNNodes(), 0.0f);
418  for(EdgeArray::const_iterator e=edges.begin(); e!=edges.end(); e++)
419  {
420  assert(e->from < getNNodes() && e->to < getNNodes());
421  adjm.at(e->from, e->to)++;
422  }
423  DMatrixf tri(getNNodes(), getNNodes());
424  tri.setLower();
425  tri*=adjm; tri.transpose();
426  adjm += tri;
427  adjm.setLower(0);
428  return adjm;
429 }
430 
432 {
433  DMatrixf selmc(getNNodes(), getNNodes());
434  DMatrixf selmr(getNNodes(), getNNodes());
435  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++)
436  if(n->hasState(Node::ST_SELECT)) {
437  selmr.setRow(n->getIndex());
438  selmc.setCol(n->getIndex());
439  }
440  selmr+=selmc;
441  selmc=selmr;
442  selmr.min(1);
443  return selmc-=selmr;
444 }
445 
448 {
449  assert(adjm.sizeX() == adjm.sizeY() && adjm.sizeX() == (dword)getNNodes());
450  dword count=0;
451  EdgeArray::iterator e=edges.begin();
452  while(e!=edges.end()) {
453  int from,to;
454  if(e->from > e->to) { from = e->from; to = e->to; }
455  else { from = e->to; to = e->from; }
456  assert(e->to < getNNodes());
457  if(adjm.at(from, to)>0.0001) {
458  edges.erase(e);
459  adjm.at(from, to)--;
460  count++;
461  } else e++;
462  }
463  if(count) rebuildIndexTables();
464  return count;
465 }
466 
469 {
470  assert(adjm.sizeX() == adjm.sizeY() && adjm.sizeX() == (dword)getNNodes());
471  dword count=0;
472  for(dword j=0; j<adjm.sizeY(); j++)
473  for(dword i=0; i<adjm.sizeX(); i++) {
474  if(adjm.at(i,j)>0.0001) {
475  addEdge(i,j);
476  count++;
477  }
478  }
479  return count;
480 }
481 
484 {
485  DMatrixf selm = selMaskMat();
486  selm.setLower(0);
487  DMatrixf adjm = adjMat();
488  adjm.min(1);
489  DMatrixf crem(selm);
490  adjm *= selm;
491  crem -= adjm;
492  dword nc = createByAdjMat(crem);
493  if(nc) prepareTorque();
494  return nc;
495 }
496 
499 {
500  DMatrixf selm = selMaskMat();
501  selm *= adjMat();
502  dword nc = removeByAdjMat(selm);
503  if(nc) prepareTorque();
504  return nc;
505 }
506 
508 void Model::removeNode(int nid)
509 {
510  if(!(nid>=0 && nid<getNNodes())) return;
511  EdgeArray::iterator e=edges.begin();
512  while(e!=edges.end()) {
513  if(e->to == nid || e->from == nid) edges.erase(e);
514  else {
515  if(e->to > nid) e->to--;
516  if(e->from > nid) e->from--;
517  e++;
518  }
519  }
520  m_DirNodeInd = -1;
521  m_HLNode = -1;
522  nodes.erase(nodes.begin()+nid);
524  prepareTorque();
525 }
526 
528 {
529  dword idx=0;
530  for(NodeArray::iterator n=nodes.begin(); n!=nodes.end(); n++,idx++) {
531  n->index = idx;
532  n->edges.clear();
533  }
534  idx=0;
535  for(EdgeArray::iterator e=edges.begin(); e!=edges.end(); e++, idx++) {
536  e->index = idx;
537  e->fromNode().edges.push_back(e->index+1);
538  e->toNode().edges.push_back(-e->index-1);
539  }
540 }
541 
542 void Model::draw(bool drawPoints) const {
543  if(!edges.empty()) {
544  glBegin(GL_LINES);
545  for(EdgeArray::const_iterator e=edges.begin(); e!=edges.end(); e++)
546  {
547  e->fromNode().glVertex();
548  e->toNode().glVertex();
549  }
550  glEnd();
551  }
552  if(drawPoints && !nodes.empty()) {
553  glPointSize(3.0f);
554  glEnable(GL_POINT_SMOOTH);
555  glColor3f(0,0,1);
556  glBegin(GL_POINTS);
557  for(NodeArray::const_iterator n=nodes.begin(); n!=nodes.end(); n++)
558  {
559  n->glVertex();
560  }
561  glEnd();
562  glDisable(GL_POINT_SMOOTH);
563  glPointSize(1.0f);
564  for(NodeArray::const_iterator n=nodes.begin(); n!=nodes.end(); n++)
565  {
566  if(n->hasState()) n->draw();
567  }
568  }
569 }
570 
571 /*
572  void Model::drawPS(CAMgraphicsProcess& gp, dword mode) const {
573  double x[2], y[2];
574  double height = !m_Dataset || !m_Dataset->initialized() ? 0.0
575  : m_Dataset->getDim2Size();
576  for(EdgeArray::const_iterator e=edges.begin(); e!=edges.end(); e++)
577  {
578  const Node& from = e->fromNode();
579  const Node& to = e->toNode();
580  x[0] = from.x; x[1] = to.x;
581  if(height > 0.0) { y[0] = from.y; y[1] = to.y; }
582  else { y[0] = height-from.y; y[1] = height-to.y; }
583  gp.plot(x,y,2);
584  }
585  }
586 */
587 
589 {
590  if(m_Sensors == sc) return;
591  if(m_Sensors) m_Sensors->unrefModel(this);
592  if(sc) sc->refModel(this);
593  m_Sensors = sc;
594 }
595 
597 {
598  if(!sensors) return;
599  if(m_Sensors != NULL) {
600  sensors->merge(*m_Sensors);
601  }
602  m_Sensors = sensors;
603 }
604 
605 float Model::getNodeAngle(const Node &n) const {
606  if(n.edges.size()>=2) {
607  int eind1 = n.edges[0];
608  Point e1 = eind1<0 ? edges[-eind1-1].idir() : edges[eind1-1].dir();
609  int eind2 = n.edges[1];
610  Point e2 = eind2<0 ? edges[-eind2-1].idir() : edges[eind2-1].dir();
611  //TRACE(e1<<" "<<e2<<" "<<e1.angle(e2));
612  return e1.angle(e2);
613  } return 0.0;
614 }
615 
617  for (NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
618  p->attachSensor(m_Sensors->getSensor(p->sensorID));
619  }
620 }
621 
623 {
624  float smpdist = getStdRadius()*dist;
625  if(smpdist < 0.000001) return 0;
626  dword nsens=0;
627  for(EdgeArray::iterator e=edges.begin(); e!=edges.end(); e++)
628  {
629  if(e->fromNode().sensor == e->toNode().sensor && e->fromNode().sensor)
630  { // positive means from-node
631  nsens += (e->edgesensor = (int)(e->length()/smpdist));
632  }
633  }
634  return nsens;
635 }
636 
637 //----------------------------------------------------------------------------
638 //---- Spring model stuff -----
639 
641 {
642  Point zero;
643  for (NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
644  p->f = zero;
645  }
646 }
647 // Update the forces on each particle
649 {
650  Point down(0.0f, -1.0f);
651  Point f;
652  float imgf, ifscale;
653  if(phys.imgforce == 0) {
654  imgf = 0;
655  ifscale = 0;
656  } else {
657  imgf = addImageForces(dt);
658  ifscale=1;
659  }
660  if(imgf>0.0) ifscale = ((float)phys.imgforce/imgf)*(float)nodes.size();
661  //TRACE(imgf<< " scale="<<ifscale);
662  for (NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
663  //if (p->fixed) continue;
664  p->f *= ifscale;
665  p->f += p->ef/dt;
666  p->ef = 0.;
667  /* Gravitation */
668  if(phys.gravitational > 0.0f)
669  p->f = (down * (phys.gravitational * p->mass));
670 
671  /* Viscous drag */
672  if(phys.viscousdrag > 0.0f)
673  p->f -= (p->v * phys.viscousdrag);
674  }
675 
676  /* Handle the spring interaction */
677  for (EdgeArray::iterator s=edges.begin(); s!=edges.end(); s++)
678  {
679  Point d = s->fromNode();
680  d -= s->toNode();
681  float len = d.norm();
682  float len1 = 1/len;
683  //spring force
684  f = (s->springconstant * (len - s->restlength));
685  //calc damping force
686  Point vd(s->fromNode().v);
687  vd -= s->toNode().v;
688  d *= len1; //spring direction normalized
689  //vd.times(d); //project velocity difference to spring
690  vd = vd.dot(d); //project velocity difference to spring
691  vd *= s->dampingconstant;
692  f += vd;
693  f *= (d*-1);
694 
695  //if not fixed - maybe
696  s->fromNode().f += f;
697  s->toNode().f -= f;
698  }
699 }
700 
701 float Model::addImageForces(float dt) {
702  if(!m_Dataset || !m_Dataset->initialized()) return 0.0f;
703  if(m_Dataset) const_cast<vuMutex&>(m_Dataset->writeMutex).lock();
704  float allf=0;
705  for (NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
706  p->addSensorForce();
707  allf += p->f.norm();
708  }
709  if(m_Dataset) const_cast<vuMutex&>(m_Dataset->writeMutex).unlock();
710  return allf;
711 }
712 
714  for(NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
715  p->oangle = getNodeAngle(*p);
716  }
717 }
718 
719 void Model::addTorque(float dt) {
720  //doesn't really work with a node array other than nodes
721  //(because of edges.fromNode()...
722  if(m_Dataset) const_cast<vuMutex&>(m_Dataset->writeMutex).lock();
723  //NodeArray &narr = tp ? *tp : nodes;
724  for(NodeArray::iterator p=nodes.begin(); p!=nodes.end();p++) {
725  if(!p->edges.empty()) {
726  float da = mapAnglePI(getNodeAngle(*p) - p->oangle);
727  //TRACE(da << " " << p->oangle << " " << getNodeAngle(*p));
728  if(da!=0.0) {
729  int eind = p->edges[0];
730  Edge &e1 = eind<0 ? edges[-eind-1]:edges[eind-1];
731  Node &n1 = eind<0 ? e1.fromNode() : e1.toNode();
732  Point d1(n1-*p);
733  d1.normalize();
734  eind = p->edges[1];
735  Edge &e2 = eind<0 ? edges[-eind-1]:edges[eind-1];
736  Node &n2 = eind<0 ? e2.fromNode() : e2.toNode();
737  Point d2(*p-n2);
738  d2.normalize();
739  Point t1 = d1.flipOrtho()*(da*phys.torque*0.5);
740  n1.f -= t1;
741  p->f += t1;
742  Point t2 = d2.flipOrtho()*(da*phys.torque*0.5);
743  n2.f -= t2;
744  p->f += t2;
745  }
746  }
747  }
748  if(m_Dataset) const_cast<vuMutex&>(m_Dataset->writeMutex).unlock();
749 }
750 
751 // Perform one step of the solver
752 void Model::updateParticles(float dt,int method)
753 {
754  method = getSearchPara().m_ParaSolver;
755  if(nodes.empty()) return;
756  switch (method) {
757  case 0: // Euler
758  {
759  std::vector<NodeDerivative> m_Deriv(getNNodes());
760  resetForces();
761  calculateForces(dt);
762  addTorque(dt);
763  calculateDerivatives(m_Deriv);
764  vector<NodeDerivative>::iterator d=m_Deriv.begin();
765  for (NodeArray::iterator n=nodes.begin();
766  n != nodes.end(), d != m_Deriv.end(); n++, d++) {
767  *n += (d->dpdt*dt);
768  n->v += (d->dvdt*dt);
769  }
770  }
771  break;
772  case 1: // Midpoint
773  {
774  int i;
775  std::vector<NodeDerivative> m_Deriv(getNNodes());
776  resetForces();
777  calculateForces(dt);
778  addTorque(dt);
779  calculateDerivatives(m_Deriv);
780  NodeArray ptmp(nodes);
781  for (i=0;i<(int)nodes.size();i++) {
782  nodes[i] += (m_Deriv[i].dpdt * (dt * 0.5));
783  nodes[i].v += (m_Deriv[i].dvdt * (dt * 0.5));
784  }
785  vector<NodeDerivative> deriv2(getNNodes());
786  resetForces();
787  calculateForces(dt);
788  addTorque(dt);
789  calculateDerivatives(deriv2);
790  for (i=0;i<(int)nodes.size();i++) {
791  nodes[i].setPos(ptmp[i]+
792  ((m_Deriv[i].dpdt+deriv2[i].dpdt)* (0.5*dt)));
793  nodes[i].v = ptmp[i].v+
794  ((m_Deriv[i].dvdt+deriv2[i].dvdt)*(0.5*dt));
795  }
796  }
797  break;
798  case 2: // latent midpoint
799  {
800  // the goal of this approach is to use information about
801  // the last derivative to get more stable results if step
802  // size is increasing. actually, there is no point in using
803  // a derivative of a long past position to correct the
804  // current derivative for further steps. incorporating the
805  // old one makes the method even more instable...
806 
807  // in the original implementation this is preserved from last time
808  std::vector<NodeDerivative> m_Deriv(getNNodes());
809  float m_LastDT = 0;
810  vector<NodeDerivative> deriv(getNNodes());
811  resetForces();
812  calculateForces(dt);
813  addTorque(dt);
814  calculateDerivatives(deriv);
815  if(m_LastDT == 0 || deriv.size() != m_Deriv.size()) {
816  m_Deriv = deriv;
817  m_LastDT = 0;
818  }
819  //float wnow = dt*m_LastDT / (dt+m_LastDT);
820  //float wlast = dt*dt / (dt+m_LastDT);
821  float wnow = 0.9*dt;
822  float wlast = dt - wnow;
823  int i;
824  for (i=0;i<(int)nodes.size();i++) {
825  nodes[i] += (m_Deriv[i].dpdt*wlast+deriv[i].dpdt*wnow);
826  nodes[i].v += (m_Deriv[i].dvdt*wlast+deriv[i].dvdt*wnow);
827  }
828  m_Deriv = deriv;
829  m_LastDT = dt;
830  }
831  break;
832  }
833  invalidatePC();
834 }
835 
836 // Calculate the derivatives
837 // dp/dt = v
838 // dv/dt = f / m
839 void Model::calculateDerivatives(vector<NodeDerivative> &deriv)
840 {
841  deriv.resize(nodes.size());
842  vector<NodeDerivative>::iterator d = deriv.begin();
843  for (NodeArray::iterator n = nodes.begin();
844  d != deriv.end(), n != nodes.end();
845  d++, n++) {
846  d->dpdt = n->v;
847  d->dvdt = n->f;
848  d->dvdt *= (1/n->mass);
849  }
850 }
851 
852 const Point Model::getCenter() const {
853  if(!(m_PCFlags&PC_CENTER)) {
854  Point c(0,0);
855  if(!nodes.empty()) {
856  for (NodeArray::const_iterator n = nodes.begin();
857  n != nodes.end();
858  n++)
859  {
860  c+=*n;
861  }
862  c *= (1.0f/nodes.size());
863  }
864  setPropPos(m_PropVec, c);
866  }
867  return getPropPos(m_PropVec);
868 }
869 
870 const Node& Model::getDirNode() const {
871  static const Node dummy;
872  if(!getNNodes()) return dummy;
873  if(m_DirNodeInd < 0) {
874  Point c = getCenter();
875  float cdist = -1.;
876  dword cind = 0;
877  for(NodeArray::const_iterator n=nodes.begin();
878  n!=nodes.end(); n++, cind++)
879  {
880  float dist = (*n-c).norm2();
881  if(cdist < dist) {
882  cdist = dist;
883  m_DirNodeInd = cind;
884  }
885  }
886  }
887  return getNode(m_DirNodeInd);
888 }
889 
890 float Model::getDirection() const {
891  if(!(m_PCFlags&PC_DIR)) {
892  setPropDir(m_PropVec, nodes.empty() ? 0 :
893  mapAngle2PI((getDirNode()-getCenter()).angle()) );
894  m_PCFlags|=PC_DIR;
895  }
896  return getPropDir(m_PropVec);
897 }
898 
899 //-----------------------------------------------------------------------------
900 //--- misc functions
901 void Model::addNoise(float r)
902 {
903  /*
904  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
905  Point d(r-2*frand(r), r-2*frand(r));
906  n->ef += d;
907  }
908  */
909  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
910  float minlen=-1;
911  for(vector<int>::const_iterator edi=n->edges.begin();
912  edi!=n->edges.end(); edi++) {
913  float elen = edges[abs(*edi)-1].length();
914  if(minlen==-1) minlen = elen;
915  else if(minlen>elen) minlen=elen;
916  }
917  float er = r*minlen;
918  Point d(er-2*frand(er), er-2*frand(er));
919  n->ef += d;
920  }
921 }
922 
923 void Model::translate(const Point &t)
924 {
925  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
926  *n += t;
927  }
929 }
930 
931 void Model::push(const Point &t)
932 {
933  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
934  n->f += t;
935  }
936 }
937 
939 {
940  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
941  e->adaptRestLength();
942  }
943  prepareTorque();
944 }
945 
946 void Model::rotate(float angle, const Point &c)
947 {
948  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
949  (Point2D&)*n = c+(*n-c).rotate(angle);
950  }
952 }
953 
954 void Model::pushRotate(const Point &c, float angle)
955 {
956  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
957  n->ef += (*n-c).flipOrtho().copyNormalized()*angle;
958  }
959 }
960 
961 void Model::attract(const Point &c, float factor)
962 {
963  for(NodeArray::iterator n = nodes.begin(); n != nodes.end(); n++) {
964  n->ef -= (*n-c)*factor;
965  }
966 }
967 
968 float Model::getLengthRatio() const {
969  float lengths=0,restlengths=0;
970  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
971  lengths+=e->length();
972  restlengths+=e->restlength;
973  }
974  return lengths/restlengths;
975 #ifdef NOTLENGTHWEIGHTED
976  float lenrat=0;
977  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
978  lenrat += e->lengthRatio();
979  }
980  return lenrat/(float)edges.size();
981 #endif
982 }
983 
985  float vlengths=0,restlengths=0;
986  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
987  register float dl = e->restlength-e->length();
988  vlengths+=dl*dl;
989  restlengths+=e->restlength;
990  }
991  register float n = edges.size();
992  return sqrt(vlengths*n)/(restlengths);
993 }
994 
995 float Model::getDeformation() const {
996  if(edges.empty()) return 0.0;
997  float vlengths=0,restlengths=0;
998  float scale = 1/getLengthRatio();
999  float scscale = 1/ParticleParam::global.springconst;
1000  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
1001  register float dl = e->restlength-e->length()*scale;
1002  //dl *= e->springconstant*scscale; // weight by relative springconst
1003  vlengths+=dl*dl;
1004  restlengths+=e->restlength;
1005  }
1006  register float n = edges.size();
1007  return sqrt(vlengths*n)/(restlengths);
1008 }
1009 
1010 float Model::getFullLength() const {
1011  float length=0;
1012  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
1013  length += e->length();
1014  }
1015  return length;
1016 }
1017 
1018 float Model::getStdRadius(const Point& center) const {
1020  float dist = 0;
1021  if(!nodes.empty()) {
1022  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++)
1023  dist += (*n-center).norm2();
1024  dist /= (float)nodes.size();
1025  dist = sqrt(dist);
1026  }
1027  setPropScale(m_PropVec, dist);
1029  return dist;
1030 }
1031 
1032 float Model::getMaxRadius(const Point& center) const {
1033  if(nodes.empty()) return 0;
1034  float dist = 0;
1035  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++) {
1036  register float td = (*n-center).norm2();
1037  if(dist<td) dist=td;
1038  }
1039  return sqrt(dist);
1040  //return (center-getDirNode()).norm();
1041 }
1042 
1043 float Model::distance(const Model& rhs, enum Model::DistType kind) const
1044 {
1045  switch(kind) {
1046  case DIST_XY:
1047  return (getCenter() - rhs.getCenter()).norm();
1048  break;
1049  case DIST_XYS:
1050  {
1051  float scaledist = getStdRadius() - rhs.getStdRadius();
1052  return sqrt((getCenter() - rhs.getCenter()).norm2()
1053  + scaledist*scaledist);
1054  }
1055  break;
1056  case DIST_PVEC:
1057  {
1058  PropVec prop = getProperties();
1059  PropVec rhsprop = rhs.getProperties();
1060  Point2D sd = getPropSDir(prop);
1061  Point2D rhssd = getPropSDir(rhsprop);
1062  prop[2] = sd.x; prop[3] = sd.y;
1063  rhsprop[2] = rhssd.x; rhsprop[3] = rhssd.y;
1064  return (prop - rhsprop).norm();
1065  }
1066  break;
1067  case DIST_POINTS:
1068  if(getNNodes() != rhs.getNNodes())
1069  return std::numeric_limits<float>::max();
1070  else {
1071  float dist=0;
1072  for(NodeArray::const_iterator thisn = nodes.begin(),
1073  rhsn = rhs.nodes.begin();
1074  thisn != nodes.end(); thisn++, rhsn++)
1075  {
1076  dist += (*thisn-*rhsn).norm2();
1077  }
1078  return sqrt(dist);
1079  }
1080  break;
1081  case DIST_HPOINTS: // Chamfer distance
1082  case DIST_CPOINTS: // Hausdorff distance
1083  {
1084  if(getNNodes()==0 || rhs.getNNodes()==0)
1085  return std::numeric_limits<float>::max();
1086  double dist=0;
1087  for(NodeArray::const_iterator thisn = nodes.begin();
1088  thisn != nodes.end(); thisn++)
1089  {
1090  float mindist = std::numeric_limits<float>::max();
1091  for(NodeArray::const_iterator rhsn = rhs.nodes.begin();
1092  rhsn != rhs.nodes.end(); rhsn++)
1093  {
1094  register float d = (*thisn-*rhsn).norm2();
1095  if(d<mindist) mindist = d;
1096  }
1097  if(kind == DIST_HPOINTS && mindist>dist) dist=(double)mindist;
1098  if(kind == DIST_CPOINTS ) dist += sqrt((double)mindist);
1099  }
1100  if(kind == DIST_HPOINTS) dist = sqrt(dist);
1101  if(kind == DIST_CPOINTS) dist /= getNNodes();
1102  return float(dist);
1103  }
1104  }
1105  return 0;
1106 }
1107 
1108 int Model::nearestNode(const Point& pos, float& dist) const
1109 {
1110  if(nodes.empty()) return -1;
1111  int rid=0, cid=0;
1112  float tdist;
1113  float& mindist = &dist ? dist : tdist;
1114  rid = 0;
1115  mindist = std::numeric_limits<float>::max();
1116  for(NodeArray::const_iterator ni = nodes.begin();
1117  ni != nodes.end(); ni++, cid++)
1118  {
1119  register float d = (pos-*ni).norm2();
1120  if(d<mindist) { mindist = d; rid = cid; }
1121  }
1122  mindist = sqrt(mindist);
1123  return rid;
1124 }
1125 
1126 void Model::adaptRestLength(float ratio)
1127 {
1128  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
1129  e->adaptRestLength(ratio);
1130  }
1131 }
1132 
1133 void Model::adaptRestLengthSel(float ratio, const DMatrixf& selm)
1134 {
1135  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
1136  e->adaptRestLength(ratio);
1137  }
1138 }
1139 
1140 void Model::scale(float factor, bool movepoints)
1141 {
1142  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
1143  e->restlength*=factor;
1144  }
1145  if(movepoints) {
1146  Point center = getCenter();
1147  for(NodeArray::iterator n = nodes.begin();
1148  n != nodes.end(); n++)
1149  {
1150  n->setPos(center + ((*n-center)*factor));
1151  }
1153  }
1154 }
1155 
1156 void Model::scaleSel(float factor, const DMatrixf& selm)
1157 {
1158  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
1159  if(selm.at(e->from, e->to) > 0.001)
1160  e->restlength*=factor;
1161  }
1162 }
1163 
1164 void Model::adaptProportion(float ratio)
1165 {
1166  float corrat = getLengthRatio();
1167  corrat -= (corrat-1)*(1-ratio);
1168  for(EdgeArray::iterator e = edges.begin(); e != edges.end(); e++) {
1169  e->restlength *= corrat;
1170  }
1171 }
1172 
1173 float Model::getSensorFit(dword* npts) const
1174 {
1175  if(nodes.empty()) { if(npts) *npts = 0; return 0.0; }
1176  float fit = 0;
1177  dword nsns = 0;
1178  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++)
1179  if(n->sensor) {
1180  float i=n->sensor->getWeightedValue((int)n->x,(int)n->y);
1181  //float gm = n->sensor->getGradient(*n).norm();
1182  //float vel = n->v.norm();
1183  fit += i;
1184  nsns++;
1185  }
1186  if(nsns) fit /= (float)nsns;
1187  if(npts) *npts = nsns;
1188  return fit;
1189 }
1190 
1191 float Model::getEdgeSensorFit(dword* npts) const
1192 {
1193  if(edges.empty()) { if(npts) *npts = 0; return 0.0; }
1194  float fit = 0;
1195  dword npoints = 0;
1196  for(EdgeArray::const_iterator e = edges.begin(); e != edges.end(); e++) {
1197  float i=e->getSensorValue(fit, npoints);
1198  }
1199  if(npoints) fit /= (float)npoints;
1200  if(npts) *npts = npoints;
1201  return fit;
1202 }
1203 
1205 {
1206  if(m_PCFlags&PC_QOF) return m_QOF;
1207  if(nodes.empty() || edges.empty()
1208  || !m_Dataset || !m_Dataset->initialized()) m_QOF=0;
1209  else {
1210  dword nns=0, nes=0;
1211  float ns = getSensorFit(&nns); // node sensors
1212  float es = getEdgeSensorFit(&nes); // edge sensors
1213  m_QOF = (es*nes+ns*nns)/float(nns+nes);
1214  //DEBUG: use deformation*10?
1215  register float lv = getDeformation(); //getLengthVariation();
1216  m_QOF = (1-m_ShapeWeight)*m_QOF + (m_ShapeWeight)*exp(-5*abs(lv));
1217  }
1218  m_PCFlags|=PC_QOF;
1219  return m_QOF;
1220 }
1221 
1223 {
1224  if(m_PCFlags&PC_LIVE) return m_Liveliness;
1225  m_Liveliness = 0;
1226  if(!nodes.empty() && !edges.empty()) {
1227  float dist= 0;
1228  Point c = getCenter();
1229  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++)
1230  {
1231  m_Liveliness += n->v.norm();
1232  dist += (c-*n).norm2();
1233  }
1234  if(dist > 0.00001) m_Liveliness /= sqrt(dist);
1235  }
1236  m_PCFlags|=PC_LIVE;
1237  return m_Liveliness;
1238 }
1239 
1241  if(!ppmm) {
1242  if(!m_Dataset) return;
1243  if(!(ppmm = m_Dataset->getPPMM())) return;
1244  }
1245  if(m_ppmm) scale(float(ppmm)/m_ppmm, true);
1246  m_ppmm = ppmm;
1247 }
1248 
1249 void Model::adaptProperties(const PropVec &prop) {
1250  if(nodes.empty()) return;
1251  Point2D nc = getPropPos(prop);
1252  float ndir = getPropDir(prop);
1253  float nscale = getPropScale(prop);
1254  Point center = getCenter();
1255  float cscale = getStdRadius();
1256  float cdir = getDirection();
1257  rotate(ndir-cdir);
1258  if(nscale>0.001 && cscale>0.0000001)
1259  scale(nscale/cscale, true);
1260  translate(nc-center);
1261 }
1262 
1264 {
1265  if((m_PCFlags&PC_PVEC) != PC_PVEC) {
1266  if((m_PCFlags&PC_CENTER) == 0) getCenter(); //setPropPos(m_PropVec,..
1267  if((m_PCFlags&PC_SCALE) == 0) getStdRadius();
1268  if((m_PCFlags&PC_DIR) == 0) getDirection();
1269  }
1270  return m_PropVec;
1271 }
1272 
1275 {
1276  PropVec prop(getProperties());
1277  convertPropToMM(prop);
1278  return prop;
1279 }
1282 {
1284 }
1286 {
1287  if(m_ppmm) pt *= (float)m_ppmm;
1288  if(m_Dataset) pt += m_Dataset->getOrigin();
1289  return pt;
1290 }
1292 {
1293  if(m_Dataset) pt -= m_Dataset->getOrigin();
1294  if(m_ppmm) pt /= (float)m_ppmm;
1295  return pt;
1296 }
1298 {
1299  Point2D pos(getPropPos(prop));
1300  setPropPos(prop, convertPointFromMM(pos));
1301  if(m_ppmm) setPropScale(prop, getPropScale(prop)*m_ppmm);
1302  return prop;
1303 }
1305 {
1306  Point2D pos(getPropPos(prop));
1307  setPropPos(prop, convertPointToMM(pos));
1308  if(m_ppmm) setPropScale(prop, getPropScale(prop)/m_ppmm);
1309  return prop;
1310 }
1311 
1313 {
1314  if(&mergemod != this && !mergemod.hasFlags(Model::ST_DEL)) {
1315  m_InstCount += mergemod.m_InstCount;
1316  mergemod.m_InstCount=0;
1317  bool mergeID = false;
1318  if(m_TimeStamp > mergemod.m_TimeStamp) {
1319  m_TimeStamp = mergemod.m_TimeStamp;
1320  mergeID = mergemod.m_ID != 0;
1321  } else mergeID = (m_ID==0 && mergemod.m_ID != 0);
1322  if(mergeID) {
1323  m_ID = mergemod.m_ID;
1324  mergemod.m_ID = 0;
1325  if(mergemod.hasFlags(Model::ST_NODEL)) {
1327  }
1328  }
1329  mergemod.setFlags(Model::ST_DEL);
1330  }
1331  return m_InstCount;
1332 }
1333 
1335 {
1336  dword count=0;
1337  for(NodeArray::const_iterator n = nodes.begin(); n != nodes.end(); n++)
1338  if(n->hasState(state)) count++;
1339  return count;
1340 }
MT & transpose()
Definition: DMatrix.h:260
void clearPrintList(bool skipdefaults=true)
Definition: SensorColl.cpp:66
float getLiveliness() const
Definition: Model.cpp:1222
float m_QOF
Definition: Model.h:276
float imgforce
Definition: PartParam.h:67
static ParticleParam global
Definition: PartParam.h:72
#define NULL
Definition: simpletypes.h:9
dataset_cptr m_Dataset
Definition: Model.h:265
bool writeFile(const char *filename) const
Definition: Model.cpp:381
PropVec & convertPropFromMM(PropVec &prop) const
Definition: Model.cpp:1297
const std::string & getFilename() const
Definition: ParseFile.h:53
float getQualityOfFit() const
Definition: Model.cpp:1204
void prepareTorque()
Definition: Model.cpp:713
std::string m_SensorFile
Definition: Model.h:267
void attachSensor(sensor_cptr _sensor)
Definition: Node.cpp:50
PropVec & convertPropToMM(PropVec &prop) const
Definition: Model.cpp:1304
void attachDataset(dataset_cptr dataset)
Definition: Model.cpp:85
void rotate(float angle, const Point &c)
Definition: Model.cpp:946
void addTorque(float dt)
Definition: Model.cpp:719
Implements a Node used by Model and Edge.
Definition: Node.h:13
void calculateForces(float dt)
Definition: Model.cpp:648
float getEdgeSensorFit(dword *npts=NULL) const
get average fit of sensors along edges
Definition: Model.cpp:1191
#define frand(max)
Definition: mathutil.h:48
void mergeSensorCollection(SensorCollection *sensors)
Definition: Model.cpp:596
friend ParseFile & operator>>(ParseFile &is, Model &g)
Definition: Model.cpp:299
PropVec getPropertiesMM() const
return property vector using millimeter scale
Definition: Model.cpp:1274
const PropVec & getProperties() const
Definition: Model.cpp:1263
float getStdRadius(const Point &center) const
Returns mean squared distance from centroid.
Definition: Model.cpp:1018
void pushRotate(const Point &c, float angle)
Definition: Model.cpp:954
~Model()
Destructor.
Definition: Model.cpp:45
bool readSensor(ParseFile &is)
read sensor from stream
Definition: Model.cpp:244
std::vector< int > edges
Definition: Node.h:60
void adaptDataScale(dword ppmm=0)
Definition: Model.cpp:1240
std::vector< Node > NodeArray
Definition: Model.h:19
void setHLNode(int hlnode)
Definition: Model.cpp:405
void adaptProportion(float ratio)
overall rest lengths sum is adapted to overall edge lengths by ratio
Definition: Model.cpp:1164
float y
Definition: Point.h:224
Point2D getPropPos(const PropVec &prop)
Definition: PropVec.h:13
const Node & getDirNode() const
Definition: Model.cpp:870
Point f
Definition: Node.h:52
#define TRACE(msg)
Definition: common.h:14
std::string m_Filename
Definition: Model.h:281
void calculateDerivatives(std::vector< NodeDerivative > &deriv)
Definition: Model.cpp:839
dword createEdgeSensors(float dist=0.1)
auto-create appropriate edge sensors (dist*stdRadius is distance)
Definition: Model.cpp:622
STL namespace.
float mass
Mass.
Definition: Node.h:48
void rebuildIndexTables()
rebuild cross indexing between nodes and edges
Definition: Model.cpp:527
int m_DirNodeInd
Definition: Model.h:273
float dampingconstant
damping constant
Definition: Edge.h:136
std::string m_Name
Definition: Model.h:270
float getDirection() const
Definition: Model.cpp:890
Implements an Edge with spring functionality.
Definition: Edge.h:14
dword createByAdjMat(const DMatrixf &adjm)
create edges mentioned in adjacency matrix
Definition: Model.cpp:468
ParticleParam phys
physical parameter set
Definition: Model.h:257
float getPropScale(const PropVec &prop)
Definition: PropVec.h:19
float m_ShapeWeight
Definition: Model.h:268
std::shared_ptr< const Dataset > dataset_cptr
Definition: types_fwd.h:21
float norm() const
returns 2-norm aka length or absolute
Definition: Point.h:170
std::shared_ptr< Sensor > sensor_ptr
Definition: types_fwd.h:15
Model(dataset_cptr _dataset=NULL, SensorCollection *sensors=NULL)
Default constructor.
Definition: Model.cpp:26
void disableState(dword nstate=0xffffffff)
Definition: Node.h:39
void scale(float factor, bool movepoints=false)
multiply all rest lengths by factor
Definition: Model.cpp:1140
void refModel(Model *model) const
Definition: SensorColl.cpp:282
dword connectNodes()
Connect selected nodes.
Definition: Model.cpp:483
int nearestNode(const Point &pos, float &dist=*(float *)(NULL)) const
Definition: Model.cpp:1108
void adaptRestLength(float ratio)
adapt restlengths towards current lengths by ratio
Definition: Model.cpp:1126
sensor_ptr getSensor(const std::string &id)
Definition: SensorColl.cpp:52
const std::string & getValue() const
Definition: ParseFile.h:57
int m_HLNode
Definition: Model.h:283
float mapAngle2PI(float a)
Definition: mathutil.h:97
dword m_CRC
Definition: Model.h:271
sensor_ptr getZeroSensor()
Definition: Sensor.cpp:234
void attachSensorColl(SensorCollection *sc)
set reference to and from sensor collection for correct updates
Definition: Model.cpp:588
SensorCollection * m_Sensors
Definition: Model.h:266
int edgesensor
0-none, >0-use from sensor n times, <0 use to sensor
Definition: Edge.h:137
unsigned short CRC(const unsigned char *Data, unsigned int Length)
Definition: crc.h:56
const Point getCenter() const
Definition: Model.cpp:852
float getSensorFit(dword *npts=NULL) const
get average sensor value
Definition: Model.cpp:1173
PropVec & setPropDir(PropVec &prop, float dir)
Definition: PropVec.h:28
int index
Index in the list (Model.nodes)
Definition: Node.h:56
float getFullLength() const
Returns overall sum of edge lengths.
Definition: Model.cpp:1010
void reattachSensors()
get sensors from sensor collection
Definition: Model.cpp:616
void resetForces()
Definition: Model.cpp:640
int getNNodes() const
Definition: Model.h:77
void attract(const Point &c, float factor)
Definition: Model.cpp:961
float mass
Definition: PartParam.h:66
MT & min(const MT &rhs)
Definition: DMatrix.h:129
PropVec & setPropPos(PropVec &prop, const Point2D &p)
Definition: PropVec.h:16
float springconstant
spring constant
Definition: Edge.h:134
PropVec m_PropVec
Definition: Model.h:275
float normalize()
normalizes the vector; returns old norm
Definition: Point.h:175
dword mergeModel(Model &mergemod)
Definition: Model.cpp:1312
float getStdRadius() const
Definition: Model.h:132
float getPropDir(const PropVec &prop)
Definition: PropVec.h:25
float angle(const Point2D &rhs=Point2D(1, 0)) const
Definition: Point.h:93
Node & fromNode()
Definition: Edge.h:121
EdgeArray edges
indexed list of edges
Definition: Model.h:263
const std::string & getPath() const
Definition: ParseFile.h:52
bool eof() const
Definition: ParseFile.h:49
const std::string & getKey() const
Definition: ParseFile.h:56
DMatrix< T > & abs(DMatrix< T > &mat)
Definition: DMatrixUtil.h:132
dword removeEdges()
Remove edges between selected nodes.
Definition: Model.cpp:498
int addNode(const Node &node)
Definition: Model.cpp:120
dword m_PCFlags
Definition: Model.h:274
Point2D & convertPointToMM(Point2D &pt) const
Definition: Model.cpp:1291
dword sizeX() const
Definition: DMatrix.h:42
const Node & getNode(int index) const
Definition: Model.h:74
const char * getMessage() const
Definition: Errors.h:41
int m_ParaSolver
method for solving ODE, 0-gauss, 1-midpnt
Definition: Searcher.h:189
float getNodeAngle(const Node &n) const
Definition: Model.cpp:605
Definition: Model.h:33
NodeArray nodes
indexed list of nodes
Definition: Model.h:262
void setName(const std::string &name)
Definition: Model.cpp:399
const Point2D rotate(float angle) const
Definition: Point.h:211
void reset()
reset all model information (including geometry)
Definition: Model.cpp:103
float damping
Definition: PartParam.h:65
float getLengthRatio() const
relation of overall edge length by overall rest length sum
Definition: Model.cpp:968
float addImageForces(float dt)
Definition: Model.cpp:701
friend std::ostream & operator<<(std::ostream &is, const Model &g)
Definition: Model.cpp:338
dword getSelectedNodesN(dword state=Node::ST_SELECT) const
get number of selected nodes
Definition: Model.cpp:1334
SearcherParams & getSearchPara()
Definition: Searcher.h:194
void unrefModel(Model *model) const
Definition: SensorColl.cpp:287
unsigned long dword
Definition: simpletypes.h:6
void adaptRestLengthSel(float ratio, const DMatrixf &selm)
adapt restlengths of selected edges towards current lengths by ratio
Definition: Model.cpp:1133
void adaptProperties(const PropVec &prop)
Definition: Model.cpp:1249
void adaptPropertiesMM(PropVec prop)
adapt to a property vector using millimeter scale
Definition: Model.cpp:1281
void translate(const Point &t)
Definition: Model.cpp:923
float viscousdrag
Definition: PartParam.h:63
const Point2D flipOrtho() const
Definition: Point.h:202
void draw(bool drawPoints=false) const
Draw using OpenGL.
Definition: Model.cpp:542
bool readNode(ParseFile &is)
read node from stream
Definition: Model.cpp:210
float torque
Definition: PartParam.h:68
bool readParameter(ParseFile &is)
read model parameters
Definition: Model.cpp:263
int addEdge(const Edge &edge)
Definition: Model.cpp:138
void removeNode(int nid)
Removes a node and its adjacent edges.
Definition: Model.cpp:508
DMatrixf adjMat() const
compute undirected adjacency matrix
Definition: Model.cpp:415
dword m_ppmm
Definition: Model.h:272
float distance(const Model &rhs, enum Model::DistType kind=DIST_POINTS) const
Definition: Model.cpp:1043
void updateParticles(float dt, int method=0)
Definition: Model.cpp:752
bool hasFlags(dword flags) const
Definition: Model.h:197
float restlength
Definition: Edge.h:132
void freeze()
Definition: Model.cpp:938
void setParseError(const std::string &msg="")
Definition: ParseFile.h:80
Point2D getPropSDir(const PropVec &prop)
Definition: PropVec.h:31
float getLengthVariation() const
mean squared difference from restlength normalized by restlength sum
Definition: Model.cpp:984
Model & operator=(const Model &rhs)
Definition: Model.cpp:50
void invalidatePC(dword pcflags=PC_ALL)
Definition: Model.h:220
MT & setCol(dword col, MT &vec)
Definition: DMatrix.h:163
#define __SHAPEWEIGHT
Definition: Brain.cpp:22
float getMaxRadius() const
Definition: Model.h:135
MT & setLower(const T &val=1, int offset=0)
Definition: DMatrix.h:250
bool readFile(const char *filename, bool fullread=true)
Definition: Model.cpp:365
dword sizeY() const
Definition: DMatrix.h:43
dword & setFlags(dword flags)
Definition: Model.h:198
MT & setRow(dword row, MT &vec)
Definition: DMatrix.h:177
void clear()
remove and destroy all geometry information (nodes and edges)
Definition: Model.cpp:95
dword m_Flags
Definition: Model.h:269
float m_Liveliness
Definition: Model.h:277
Definition: Point.h:16
DMatrixf selMaskMat() const
compute mask matrix of selected nodes
Definition: Model.cpp:431
T & at(dword x, dword y)
Definition: DMatrix.h:46
float mapAnglePI(float a)
Definition: mathutil.h:107
void scaleSel(float factor, const DMatrixf &selm)
multiply all rest lengths of selected edges by factor
Definition: Model.cpp:1156
bool readEdge(ParseFile &is)
read edge from stream
Definition: Model.cpp:167
DistType
Definition: Model.h:40
#define DEFAULT_PPMM
Definition: Data.h:16
float springconst
Definition: PartParam.h:64
SensorCollection & merge(SensorCollection &rhs)
Definition: SensorColl.cpp:256
PropVec & setPropScale(PropVec &prop, float pscale)
Definition: PropVec.h:22
void pushLine(const std::string &line)
Definition: ParseFile.h:74
Point2D & convertPointFromMM(Point2D &pt) const
Definition: Model.cpp:1285
void addNoise(float r)
Definition: Model.cpp:901
float getDeformation() const
normalized length variation to compensate for different sizes
Definition: Model.cpp:995
dword m_InstCount
number of merged instances
Definition: Model.h:280
float x
Definition: Point.h:224
dword m_ID
Definition: Model.h:284
float gravitational
Definition: PartParam.h:62
sensor_ptr readSensor(ParseFile &is)
Definition: SensorColl.cpp:101
dword removeByAdjMat(DMatrixf &adjm)
remove edged not mentioned in (non-directional) adjacency matrix
Definition: Model.cpp:447
void enableState(dword nstate)
Definition: Node.h:38
const bool getNextLine()
Definition: ParseFile.h:59
sensor_ptr addSensor(const std::string &key, sensor_ptr s)
Definition: SensorColl.cpp:24
float dot(const Point2D &rhs) const
Definition: Point.h:82
Node & toNode()
Definition: Edge.h:122
const int getLineNumber() const
Definition: ParseFile.h:58
float m_TimeStamp
time stamps (see. TTimeStamp)
Definition: Model.h:259
DMatrix< T > & sqrt(DMatrix< T > &mat)
Definition: DMatrixUtil.h:81
void push(const Point &t)
Definition: Model.cpp:931