Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
navpath.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2003 Mike Byron
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "vegastrike.h"
23 #if defined (_WIN32) && !defined (__CYGWIN__) && !defined (__MINGW32__)
24 //For WIN32 debugging.
25 #include <crtdbg.h>
26 #endif
27 
28 #include "navpath.h"
29 #include "gfx/cockpit.h"
30 #include "navscreen.h"
31 
32 #include <vector>
33 using std::vector;
34 #include <deque>
35 using std::deque;
36 #include <list>
37 using std::list;
38 #include <set>
39 using std::set;
40 #include <map>
41 using std::map;
42 #include <string>
43 using std::string;
44 #include <iostream>
45 using std::cout;
46 using std::endl;
47 using std::pair;
48 
49 //*******************************************************************//
51 //NavPath Class //
53 //*******************************************************************//
54 
55 bool NavPath::isAbsolute() const
56 {
57  if ( !isComplete() )
58  return false;
59  if ( !source->isAbsolute() || !destination->isAbsolute() )
60  return false;
61  return true;
62 }
63 
64 bool NavPath::isComplete() const
65 {
66  if (!source || !destination)
67  return false;
68  if ( source->getRequiredPath() )
69  if ( !source->getRequiredPath()->isEvaluated() )
70  return false;
73  return false;
74  return true;
75 }
76 
78 {
79  if (source)
80  if ( source->isCurrentDependant() )
81  return true;
82  if (destination)
84  return true;
85  return false;
86 }
87 
89 {
90  if (source)
91  if ( source->isTargetDependant() )
92  return true;
93  if (destination)
95  return true;
96  return false;
97 }
98 
100 {
101  string temp;
102 
103  temp = getName();
104  temp += "#n#";
105  temp += "----------#n#";
106  temp += "Visible: ";
107  temp += (getVisible() ? "True" : "False");
108  temp += "#n#";
109  if (source) {
110  temp += "Source:#n#";
111  temp += source->getDescription();
112  temp += "#n#";
113  }
114  if (destination) {
115  temp += "Destination:#n#";
116  temp += destination->getDescription();
117  temp += "#n#";
118  }
119  if (!source || !destination)
120  temp += "#n#INCOMPLETE#n#";
121  else if ( !isComplete() )
122  temp += "#n#PATH CHAIN IS UNSOLVED BEFORE THIS POINT#n#";
123  else if ( !isEvaluated() )
124  temp += "#n#PATH NOT FOUND#n#";
125  return temp;
126 }
127 
128 void NavPath::setVisible( bool vis )
129 {
130  visible = vis;
131 }
132 
134 {
135  color = col;
136 }
137 
138 void NavPath::setName( string n )
139 {
140  name = n;
141 }
142 
144 {
145  return visible;
146 }
147 
149 {
150  return color;
151 }
152 
153 string NavPath::getName() const
154 {
155  return name;
156 }
157 
159 {
160  if (!node)
161  return false;
162  if ( !node->isSourceable() )
163  return false;
164  PathNode *oldNode = source;
165  source = node;
166  if ( checkForCycles() ) {
167  source = oldNode;
168  delete node;
169  node = NULL;
170  return false;
171  } else {
172  if (oldNode)
173  if ( oldNode->getRequiredPath() )
174  oldNode->getRequiredPath()->removeDependant( this );
175  if ( node->getRequiredPath() )
176  node->getRequiredPath()->addDependant( this );
177  if (oldNode)
178  delete oldNode;
179  oldNode = NULL;
181  return true;
182  }
183 }
184 
186 {
187  if (!node)
188  return false;
189  PathNode *oldNode = destination;
190  destination = node;
191  if ( checkForCycles() ) {
192  destination = oldNode;
193  delete node;
194  node = NULL;
195  return false;
196  } else {
197  if (oldNode)
198  if ( oldNode->getRequiredPath() )
199  oldNode->getRequiredPath()->removeDependant( this );
200  if ( node->getRequiredPath() )
201  node->getRequiredPath()->addDependant( this );
202  if (oldNode)
203  delete oldNode;
204  oldNode = NULL;
206  return true;
207  }
208 }
209 
211 {
212  return path.front();
213 }
214 
216 {
217  return path.back();
218 }
219 
220 const std::list< unsigned >* NavPath::getAllPoints() const
221 {
222  return &path;
223 }
224 
225 std::list< unsigned >* NavPath::getAllPoints()
226 {
227  return &path;
228 }
229 
230 void NavPath::addDependant( NavPath *dependant )
231 {
232  if (dependant == NULL)
233  return;
234  dependants.insert( dependant );
235 }
236 
238 {
239  if (dependant == NULL)
240  return;
241  dependants.erase( dependant );
242 }
243 
244 const std::set< NavPath* >* NavPath::getDependants() const
245 {
246  return &dependants;
247 }
248 
249 std::set< NavPath* >* NavPath::getDependants()
250 {
251  return &dependants;
252 }
253 
254 std::vector< NavPath* >NavPath::getRequiredPaths() const
255 {
256  std::vector< NavPath* >temp;
257  if (source)
258  if ( source->getRequiredPath() )
259  temp.push_back( source->getRequiredPath() );
260  if (destination)
261  if ( destination->getRequiredPath() )
262  temp.push_back( destination->getRequiredPath() );
263  return temp;
264 }
265 
267 {
268  const NavPath *v;
269  vector< NavPath* >neighbors;
270  unsigned i;
271  deque< const NavPath* >pathStack;
272  pathStack.push_back( this );
273  bool cycle = false;
274  while (!pathStack.empty() && !cycle) {
275  v = pathStack.back();
276  pathStack.pop_back();
277  neighbors = v->getRequiredPaths();
278  for (i = 0; i < neighbors.size(); ++i) {
279  if (neighbors[i] == this) {
280  cycle = true;
281  break;
282  }
283  pathStack.push_back( neighbors[i] );
284  }
285  }
286  return cycle;
287 }
288 
290 {
292  path.clear();
293  static size_t max_size = XMLSupport::parse_int( vs_config->getVariable( "graphics", "nav_max_search_size", "16384" ) );
294  if ( !isComplete() )
295  return false;
296  if ( isAbsolute() ) {
297  //Using a double-rooted BFS search
298  unsigned originIndex = source->initSearchQueue().front();
299  unsigned destIndex = destination->initSearchQueue().front();
300  if (originIndex == destIndex) {
301  path.push_back( originIndex );
302  return true;
303  }
304  vector< unsigned >prev( systemIter.size() );
305  vector< unsigned >visited( systemIter.size(), 0 );
306  deque< unsigned > oriFront, destFront;
307  bool found = false;
308  unsigned midNode;
309  unsigned midNodePrevOri;
310  unsigned midNodePrevDest;
311  midNodePrevOri = midNodePrevDest = 0; //to shut up a warning about possibly used uninitialized --chuck_starchaser
312  bool oriTurn = true;
313  deque< unsigned > *front;
314  unsigned visitMark;
315  if ( originIndex >= visited.size() || destIndex >= visited.size() ) {
316  fprintf( stderr, "(previously) FATAL error with nav system, referencing value too big %d %d with visited size %d\n",
317  (int) originIndex, (int) destIndex, (int) visited.size() );
318  return false;
319  }
320  oriFront.push_back( originIndex );
321  visited[originIndex] = 1;
322  destFront.push_back( destIndex );
323  visited[destIndex] = 2;
324  while (oriFront.size() < max_size && destFront.size() < max_size && !oriFront.empty() && !destFront.empty()
325  && !found) {
326  //stay within memory bounds in case something goes wrong (it has, unfortunately on occasion)
327  if (oriTurn) {
328  front = &oriFront;
329  visitMark = 1;
330  } else {
331  front = &destFront;
332  visitMark = 2;
333  }
334  unsigned index = front->front();
335  front->pop_front();
336  for (unsigned adjs = 0; adjs < systemIter[index].GetDestinationSize(); ++adjs) {
337  unsigned adjIndex = systemIter[index].GetDestinationIndex( adjs );
338  if ( systemIter[adjIndex].isDrawable() ) {
339  if (visited[adjIndex] == 0) {
340  visited[adjIndex] = visitMark;
341  prev[adjIndex] = index;
342  front->push_back( adjIndex );
343  } else if (visited[adjIndex] != visitMark) {
344  midNode = adjIndex;
345  if (oriTurn) {
346  midNodePrevDest = prev[adjIndex];
347  midNodePrevOri = index;
348  } else {
349  midNodePrevOri = prev[adjIndex];
350  midNodePrevDest = index;
351  }
352  found = true;
353  break;
354  }
355  }
356  }
357  oriTurn = !oriTurn;
358  }
359  if (found) {
360  unsigned index = midNodePrevOri;
361  while (index != originIndex) {
362  path.push_front( index );
363  index = prev[index];
364  if (path.size() >= max_size) {
365  //this prevents some odd "out of memory" crashes we were getting where there might have been a loop in the path somehow
366  path.clear();
367  found = false;
368  return false;
369  }
370  }
371  path.push_front( originIndex );
372  if (destIndex == midNode) {
373  path.push_back( destIndex );
374  } else {
375  path.push_back( midNode );
376 
377  unsigned index = midNodePrevDest;
378  while (index != destIndex) {
379  path.push_back( index );
380  index = prev[index];
381  if (path.size() >= max_size) {
382  //this prevents some odd "out of memory" crashes we were getting where there might have been a loop in the path somehow
383  path.clear();
384  found = false;
385  return false;
386  }
387  }
388  path.push_back( destIndex );
389  }
390  }
391  return found;
392  } else {
393  //Using single-rooted BFS search
394  vector< unsigned >prev( systemIter.size() );
395  vector< bool > visited( systemIter.size(), false );
396  deque< unsigned > frontier = source->initSearchQueue();
397  set< unsigned > origins;
398  bool found = false;
399  unsigned index, destIndex = 0;
400  for (unsigned i = 0; i < frontier.size(); ++i) {
401  index = frontier.front();
402  frontier.pop_front();
403  visited[index] = true;
404  frontier.push_back( index );
405  origins.insert( index );
406  if ( destination->isDestination( index ) ) {
407  path.push_back( index );
408  return true;
409  }
410  }
411  while (frontier.size() < max_size && !frontier.empty() && !found) {
412  index = frontier.front();
413  frontier.pop_front();
414  for (unsigned adjs = 0; adjs < systemIter[index].GetDestinationSize(); ++adjs) {
415  unsigned adjIndex = systemIter[index].GetDestinationIndex( adjs );
416  if ( !visited[adjIndex] && systemIter[adjIndex].isDrawable() ) {
417  visited[adjIndex] = true;
418  prev[adjIndex] = index;
419  frontier.push_back( adjIndex );
420  if ( destination->isDestination( adjIndex ) ) {
421  found = true;
422  destIndex = adjIndex;
423  break;
424  }
425  }
426  }
427  }
428  if (found) {
429  index = destIndex;
430  path.push_front( index );
431  do {
432  index = prev[index];
433  path.push_front( index );
434  if (path.size() >= max_size) {
435  //this prevents some odd "out of memory" crashes we were getting where there might have been a loop in the path somehow
436  path.clear();
437  found = false;
438  return false;
439  }
440  } while ( !origins.count( index ) ); //While the index is not an origin
441  }
442  return found;
443  }
444 }
445 
447 {
449  //Erase old path
450  //*************************
451  for (list< unsigned >::iterator i = path.begin(); i != path.end(); ++i)
452  if ( systemIter[*i].paths.erase( this ) ) //This erases this path from the list of paths in system
453  if ( systemIter[*i].paths.empty() )
454  systemIter[*i].part_of_path = false;
455  pathNeighbors.clear();
456 }
457 
459 {
461 
462  int i;
463  unsigned system;
464  //Inscribe new path
465  //*************************
466 
467  list< unsigned >::iterator aux;
468  for (list< unsigned >::iterator iter = path.begin(); iter != path.end(); ++iter) {
469  if ( (*iter) != path.front() )
470  pathNeighbors[(*iter)].first = ( *--(aux = iter) );
471  if ( (*iter) != path.back() )
472  pathNeighbors[(*iter)].second = ( *++(aux = iter) );
473  systemIter[*iter].part_of_path = true;
474  systemIter[*iter].paths.insert( this );
475  }
476 }
477 
478 bool NavPath::isNeighborPath( unsigned system, unsigned neighbor )
479 {
480  map< unsigned, pair< unsigned, unsigned > >::iterator i = pathNeighbors.find( system );
481  if ( i == pathNeighbors.end() )
482  return false;
483  if ( system != path.front() )
484  if ( (*i).second.first == neighbor )
485  return true;
486  if ( system != path.back() )
487  if ( (*i).second.second == neighbor )
488  return true;
489  return false;
490 }
491 
493 {
494  removeOldPath();
495  if ( evaluate() ) {
496  addNewPath();
497  return true;
498  } else {
499  return false;
500  }
501 }
502 
504 {
505  name = "New Path";
506  visible = true;
507  color = GFXColor( 1, 0, 0 );
508  source = NULL;
509  destination = NULL;
510 }
511 
513 {
514  removeOldPath();
515  if (source) {
516  if ( source->getRequiredPath() )
518  delete source;
519  source = NULL;
520  }
521  if (destination) {
522  if ( destination->getRequiredPath() )
524  delete source;
525  source = NULL;
526  }
527  set< NavPath* > *depList = getDependants();
528  for (std::set< NavPath* >::iterator i = depList->begin(); i != depList->end(); ++i) {
529  if ( (*i)->source->getRequiredPath() == this ) {
530  delete (*i)->source;
531  (*i)->source = NULL;
532  }
533  if ( (*i)->destination->getRequiredPath() == this ) {
534  delete (*i)->destination;
535  (*i)->destination = NULL;
536  }
537  }
538 }
539 
540 //*******************************************************************//
542 //PathManager Class //
544 //*******************************************************************//
545 
547 {
548  NavPath *path = new NavPath();
549  path->setSourceNode( new CurrentPathNode() );
550  paths.push_back( path );
551 }
552 
554 {
555  bool ret = false;
556  for (std::vector< NavPath* >::iterator i = paths.begin(); i < paths.end(); ++i)
557  if ( (*i) == path ) {
558  delete (*i);
559  ret = true;
560  paths.erase( i );
561  }
562  return ret;
563 }
564 
566 {
567  for (std::vector< NavPath* >::iterator i = paths.begin(); i < paths.end(); ++i)
568  (*i)->setVisible( true );
569 }
570 
572 {
573  for (std::vector< NavPath* >::iterator i = paths.begin(); i < paths.end(); ++i)
574  (*i)->setVisible( false );
575 }
576 
578 {
579  path->updated = true;
580  path->update();
581  updateDependants( path );
582  return path->updated;
583 }
584 
586 {
587  std::list< NavPath* >::iterator i;
588  DFS();
589  if (type == ALL) {
590  for (std::vector< NavPath* >::iterator j = paths.begin(); j < paths.end(); ++j) {
591  std::cerr<<"Updating path: "<<(*j)->getName()<<endl;
592  (*j)->update();
593  }
594  } else if (type == CURRENT) {
595  for (i = topoOrder.begin(); i != topoOrder.end(); ++i)
596  (*i)->updated = false;
597  for (i = topoOrder.begin(); i != topoOrder.end(); ++i)
598  if ( (*i)->updated == false && (*i)->isCurrentDependant() ) {
599  std::cerr<<"Updating path: "<<(*i)->getName()<<endl;
600  updateSpecificPath( *i );
601  }
602  } else {
603  for (i = topoOrder.begin(); i != topoOrder.end(); ++i)
604  (*i)->updated = false;
605  for (i = topoOrder.begin(); i != topoOrder.end(); ++i)
606  if ( (*i)->updated == false && (*i)->isTargetDependant() ) {
607  std::cerr<<"Updating path: "<<(*i)->getName()<<endl;
608  updateSpecificPath( *i );
609  }
610  }
611 }
612 
614 {
615  set< NavPath* > *dependants = parent->getDependants();
616  for (std::set< NavPath* >::iterator i = dependants->begin(); i != dependants->end(); ++i)
617  updateSpecificPath( *i );
618 }
619 
621 {
622  topoOrder.clear();
623  std::vector< NavPath* >::iterator u;
624  for (u = paths.begin(); u < paths.end(); ++u)
625  (*u)->topoColor = TOPO_WHITE;
626  topoTime = 0;
627  for (u = paths.begin(); u < paths.end(); ++u)
628  if ( (*u)->topoColor == TOPO_WHITE )
629  dfsVisit( *u );
630 }
631 
633 {
634  path->topoColor = TOPO_GRAY;
635 
636  std::set< NavPath* > *dependants = path->getDependants();
637  for (std::set< NavPath* >::iterator v = dependants->begin(); v != dependants->end(); ++v)
638  if ( (*v)->topoColor == TOPO_WHITE )
639  dfsVisit( *v );
640  path->topoColor = TOPO_BLACK;
641  ++topoTime;
642  path->topoTime = topoTime;
643  topoOrder.push_front( path );
644 }
645 
647 
649 {
650  for (std::vector< NavPath* >::iterator i = paths.begin(); i < paths.end(); ++i) {
651  delete (*i);
652  (*i) = NULL;
653  }
654 }
655 
656 //*******************************************************************//
658 //AbsolutePathNode Class //
660 //*******************************************************************//
661 
663 {
664  return _Universe->AccessCockpit()->AccessNavSystem()->systemIter[system].GetName();
665 }
666 
667 std::deque< unsigned >AbsolutePathNode::initSearchQueue() const
668 {
669  deque< unsigned >temp;
670  temp.push_back( system );
671  return temp;
672 }
673 
674 //*******************************************************************//
676 //CurrentPathNode Class //
678 //*******************************************************************//
679 
680 bool CurrentPathNode::isDestination( unsigned index ) const
681 {
682  return _Universe->AccessCockpit()->AccessNavSystem()->currentsystemindex == index;
683 }
684 
685 std::deque< unsigned >CurrentPathNode::initSearchQueue() const
686 {
687  deque< unsigned >temp;
688  temp.push_back( _Universe->AccessCockpit()->AccessNavSystem()->currentsystemindex );
689  return temp;
690 }
691 
692 //*******************************************************************//
694 //TargetPathNode Class //
696 //*******************************************************************//
697 
698 bool TargetPathNode::isDestination( unsigned index ) const
699 {
700  return _Universe->AccessCockpit()->AccessNavSystem()->destinationsystemindex == index;
701 }
702 
703 std::deque< unsigned >TargetPathNode::initSearchQueue() const
704 {
705  deque< unsigned >temp;
706  temp.push_back( _Universe->AccessCockpit()->AccessNavSystem()->destinationsystemindex );
707  return temp;
708 }
709 
710 //*******************************************************************//
712 //CriteriaPathNode Class //
714 //*******************************************************************//
715 
717 {
718  assert( criteria != NULL );
719 
720  string temp = "Criteria: ";
721  temp += criteria->getDescription();
722  return temp;
723 }
724 
726 {
727  assert( criteria != NULL );
728  return criteria->isDestination( index );
729 }
730 
732 {
733  assert( criteria != NULL );
734 
735  CriteriaPathNode *newNode = new CriteriaPathNode();
736  newNode->criteria = static_cast< CriteriaRoot* > ( criteria->clone() );
737  return newNode;
738 }
739 
741 {
742  criteria = new CriteriaRoot();
743 }
744 
746 {
747  assert( criteria != NULL );
748 
749  delete criteria;
750 }
751 
752 //*******************************************************************//
754 //ChainPathNode Class //
756 //*******************************************************************//
757 
758 std::string ChainPathNode::getDescription() const
759 {
760  string temp = "Chain: ";
761  temp += supplierPath->getName();
762  if (type == SOURCE)
763  temp += " (Source)";
764  else if (type == DESTINATION)
765  temp += " (Destination)";
766  else
767  temp += " (All Points)";
768  return temp;
769 }
770 
771 std::deque< unsigned >ChainPathNode::initSearchQueue() const
772 {
773  deque< unsigned >systemDeque;
774  if (type == SOURCE) {
775  systemDeque.push_back( supplierPath->getAbsoluteSource() );
776  } else if (type == DESTINATION) {
777  systemDeque.push_back( supplierPath->getAbsoluteDestination() );
778  } else {
779  const list< unsigned > *systems = supplierPath->getAllPoints();
780  for (list< unsigned >::const_iterator i = systems->begin(); i != systems->end(); ++i)
781  systemDeque.push_back( *i );
782  }
783  return systemDeque;
784 }
785 
786 bool ChainPathNode::isDestination( unsigned index ) const
787 {
788  if (type == SOURCE) {
789  return supplierPath->getAbsoluteSource() == index;
790  } else if (type == DESTINATION) {
791  return supplierPath->getAbsoluteDestination() == index;
792  } else {
793  const list< unsigned > *systems = supplierPath->getAllPoints();
794  for (list< unsigned >::const_iterator i = systems->begin(); i != systems->end(); ++i)
795  if ( (*i) == index )
796  return true;
797  return false;
798  }
799 }
800