graphReducer.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. // Filename: graphReducer.cxx
  2. // Created by: drose (26Apr00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "graphReducer.h"
  6. #include "config_graph.h"
  7. #include "namedNode.h"
  8. #include "pt_Node.h"
  9. #include <map>
  10. #include <list>
  11. ////////////////////////////////////////////////////////////////////
  12. // Function: GraphReducer::Constructor
  13. // Access: Public
  14. // Description:
  15. ////////////////////////////////////////////////////////////////////
  16. GraphReducer::
  17. GraphReducer(TypeHandle graph_type) :
  18. _graph_type(graph_type)
  19. {
  20. }
  21. ////////////////////////////////////////////////////////////////////
  22. // Function: GraphReducer::Destructor
  23. // Access: Public
  24. // Description:
  25. ////////////////////////////////////////////////////////////////////
  26. GraphReducer::
  27. ~GraphReducer() {
  28. }
  29. ////////////////////////////////////////////////////////////////////
  30. // Function: GraphReducer::flatten
  31. // Access: Public
  32. // Description: Simplifies the graph by removing unnecessary nodes
  33. // and arcs.
  34. //
  35. // In general, a node (and its parent arc) is a
  36. // candidate for removal if the node has no siblings and
  37. // the node and arc have no special properties. The
  38. // definition of what, precisely, is a 'special
  39. // property' may be extended by subclassing from this
  40. // type and redefining consider_arc() appropriately.
  41. //
  42. // If combine_siblings is true, sibling nodes may also
  43. // be collapsed into a single node. This will further
  44. // reduce scene graph complexity, sometimes
  45. // substantially, at the cost of reduced spatial
  46. // separation.
  47. //
  48. // Returns the number of arcs removed from the graph.
  49. ////////////////////////////////////////////////////////////////////
  50. int GraphReducer::
  51. flatten(Node *root, bool combine_siblings) {
  52. int num_total_nodes = 0;
  53. int num_pass_nodes;
  54. do {
  55. num_pass_nodes = 0;
  56. DownRelations::const_iterator dri;
  57. dri = root->_children.find(_graph_type);
  58. if (dri != root->_children.end()) {
  59. const DownRelationPointers &drp = (*dri).second;
  60. // Get a copy of the children list, so we don't have to worry
  61. // about self-modifications.
  62. DownRelationPointers drp_copy = drp;
  63. // Now visit each of the children in turn.
  64. DownRelationPointers::const_iterator drpi;
  65. for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
  66. NodeRelation *arc = (*drpi);
  67. num_pass_nodes += r_flatten(arc->get_child(), combine_siblings);
  68. }
  69. }
  70. num_total_nodes += num_pass_nodes;
  71. // If combine_siblings is true, we should repeat the above until
  72. // we don't get any more benefit from flattening, because each
  73. // pass could convert cousins into siblings, which may get
  74. // flattened next pass. If combine_siblings is not true, the
  75. // first pass will be fully effective, and there's no point in
  76. // trying again.
  77. } while (combine_siblings && num_pass_nodes != 0);
  78. return num_total_nodes;
  79. }
  80. ////////////////////////////////////////////////////////////////////
  81. // Function: GraphReducer::r_flatten
  82. // Access: Protected
  83. // Description: The recursive implementation of flatten().
  84. ////////////////////////////////////////////////////////////////////
  85. int GraphReducer::
  86. r_flatten(Node *root, bool combine_siblings) {
  87. int num_nodes = 0;
  88. DownRelations::const_iterator dri;
  89. dri = root->_children.find(_graph_type);
  90. if (dri != root->_children.end()) {
  91. const DownRelationPointers &drp = (*dri).second;
  92. // Get a copy of the children list, so we don't have to worry
  93. // about self-modifications.
  94. DownRelationPointers drp_copy = drp;
  95. // Now visit each of the children in turn.
  96. DownRelationPointers::const_iterator drpi;
  97. for (drpi = drp_copy.begin(); drpi != drp_copy.end(); ++drpi) {
  98. NodeRelation *arc = (*drpi);
  99. num_nodes += r_flatten(arc->get_child(), combine_siblings);
  100. }
  101. if (combine_siblings && drp.size() >= 2) {
  102. num_nodes += flatten_siblings(root);
  103. }
  104. if (drp.size() == 1) {
  105. // If we have exactly one child, consider flattening it.
  106. NodeRelation *arc = *drp.begin();
  107. if (consider_arc(arc)) {
  108. if (flatten_arc(arc)) {
  109. num_nodes++;
  110. }
  111. }
  112. }
  113. }
  114. return num_nodes;
  115. }
  116. class SortByTransitions {
  117. public:
  118. INLINE bool
  119. operator () (const NodeRelation *arc1, const NodeRelation *arc2) const;
  120. };
  121. INLINE bool SortByTransitions::
  122. operator () (const NodeRelation *arc1, const NodeRelation *arc2) const {
  123. return (arc1->compare_transitions_to(arc2) < 0);
  124. }
  125. ////////////////////////////////////////////////////////////////////
  126. // Function: GraphReducer::flatten_siblings
  127. // Access: Protected
  128. // Description: Attempts to collapse together any pairs of siblings
  129. // of the indicated node that share the same properties.
  130. ////////////////////////////////////////////////////////////////////
  131. int GraphReducer::
  132. flatten_siblings(Node *root) {
  133. int num_nodes = 0;
  134. // First, collect the children into groups of arcs with common
  135. // properties.
  136. typedef map<NodeRelation *, list<NodeRelation *>, SortByTransitions> Children;
  137. Children children;
  138. DownRelations::const_iterator dri;
  139. dri = root->_children.find(_graph_type);
  140. if (dri != root->_children.end()) {
  141. const DownRelationPointers &drp = (*dri).second;
  142. DownRelationPointers::const_iterator drpi;
  143. for (drpi = drp.begin(); drpi != drp.end(); ++drpi) {
  144. NodeRelation *arc = (*drpi);
  145. children[arc].push_back(arc);
  146. }
  147. }
  148. // Now visit each of those groups and try to collapse them together.
  149. Children::iterator ci;
  150. for (ci = children.begin(); ci != children.end(); ++ci) {
  151. list<NodeRelation *> &arcs = (*ci).second;
  152. list<NodeRelation *>::iterator ai1;
  153. ai1 = arcs.begin();
  154. while (ai1 != arcs.end()) {
  155. list<NodeRelation *>::iterator ai1_hold = ai1;
  156. NodeRelation *arc1 = (*ai1);
  157. ++ai1;
  158. list<NodeRelation *>::iterator ai2 = ai1;
  159. while (ai2 != arcs.end()) {
  160. list<NodeRelation *>::iterator ai2_hold = ai2;
  161. NodeRelation *arc2 = (*ai2);
  162. ++ai2;
  163. if (consider_siblings(root, arc1, arc2)) {
  164. NodeRelation *new_arc = collapse_siblings(root, arc1, arc2);
  165. if (new_arc != (NodeRelation *)NULL) {
  166. // We successfully collapsed an arc.
  167. arcs.erase(ai2_hold);
  168. arcs.erase(ai1_hold);
  169. arcs.push_back(new_arc);
  170. ai1 = arcs.begin();
  171. ai2 = arcs.end();
  172. num_nodes++;
  173. }
  174. }
  175. }
  176. }
  177. }
  178. return num_nodes;
  179. }
  180. ////////////////////////////////////////////////////////////////////
  181. // Function: GraphReducer::consider_arc
  182. // Access: Protected, Virtual
  183. // Description: Decides whether or not the indicated arc is a
  184. // suitable candidate for removal. Returns true if the
  185. // arc may be removed, false if it should be kept. This
  186. // function may be extended in a user class to protect
  187. // special kinds of arcs from deletion.
  188. ////////////////////////////////////////////////////////////////////
  189. bool GraphReducer::
  190. consider_arc(NodeRelation *arc) {
  191. if (arc->has_sub_render_trans()) {
  192. if (graph_cat.is_debug()) {
  193. graph_cat.debug()
  194. << "Not removing " << *arc
  195. << " because it contains a sub_render transition.\n";
  196. }
  197. return false;
  198. }
  199. return true;
  200. }
  201. ////////////////////////////////////////////////////////////////////
  202. // Function: GraphReducer::consider_siblings
  203. // Access: Protected, Virtual
  204. // Description: Decides whether or not the indicated sibling nodes
  205. // (and their associated arcs) should be collapsed into
  206. // a single node or not. Returns true if the arcs may
  207. // be collapsed, false if they should be kept distinct.
  208. ////////////////////////////////////////////////////////////////////
  209. bool GraphReducer::
  210. consider_siblings(Node *, NodeRelation *arc1, NodeRelation *arc2) {
  211. // Don't attempt to combine any sibling arcs with different
  212. // transitions.
  213. return (arc1->compare_transitions_to(arc2) == 0);
  214. }
  215. ////////////////////////////////////////////////////////////////////
  216. // Function: GraphReducer::flatten_arc
  217. // Access: Protected, Virtual
  218. // Description: Removes the indicated arc, collapsing together the
  219. // two nodes and leaving them parented in the same
  220. // place. The return value is true if the arc is
  221. // successfully collapsed, false if we chickened out.
  222. //
  223. // This function may be extended in a user class to
  224. // handle special kinds of nodes.
  225. ////////////////////////////////////////////////////////////////////
  226. bool GraphReducer::
  227. flatten_arc(NodeRelation *arc) {
  228. PT_Node parent = arc->get_parent();
  229. PT_Node child = arc->get_child();
  230. if (graph_cat.is_debug()) {
  231. graph_cat.debug()
  232. << "Removing " << *arc << "\n";
  233. }
  234. PT_Node new_parent = collapse_nodes(parent, child, false);
  235. if (new_parent == (Node *)NULL) {
  236. if (graph_cat.is_debug()) {
  237. graph_cat.debug()
  238. << "Decided not to remove " << *arc << "\n";
  239. }
  240. return false;
  241. }
  242. choose_name(new_parent, parent, child);
  243. move_children(new_parent, parent);
  244. move_children(new_parent, child);
  245. // Move all of the transitions from the arc to the parent's arcs.
  246. int num_grandparents = parent->get_num_parents(_graph_type);
  247. for (int i = 0; i < num_grandparents; i++) {
  248. NodeRelation *grandparent_arc = parent->get_parent(_graph_type, i);
  249. grandparent_arc->compose_transitions_from(arc);
  250. if (new_parent != parent) {
  251. // Also switch out the parent node.
  252. grandparent_arc->change_child(new_parent);
  253. }
  254. }
  255. remove_arc(arc);
  256. return true;
  257. }
  258. ////////////////////////////////////////////////////////////////////
  259. // Function: GraphReducer::collapse_siblings
  260. // Access: Protected, Virtual
  261. // Description: Performs the work of collapsing two sibling arcs
  262. // together into a single arc (and their associated
  263. // nodes into a single node).
  264. //
  265. // Returns a pointer to a NodeRelation the reflects the
  266. // combined arc (which may be either of the source arcs,
  267. // or a new arc altogether) if the siblings are
  268. // successfully collapsed, or NULL if we chickened out.
  269. ////////////////////////////////////////////////////////////////////
  270. NodeRelation *GraphReducer::
  271. collapse_siblings(Node *parent, NodeRelation *arc1, NodeRelation *arc2) {
  272. PT_Node node1 = arc1->get_child();
  273. PT_Node node2 = arc2->get_child();
  274. PT_Node new_node = collapse_nodes(node1, node2, true);
  275. if (new_node == (Node *)NULL) {
  276. graph_cat.debug()
  277. << "Decided not to collapse " << *node1 << " and " << *node2 << "\n";
  278. return NULL;
  279. }
  280. move_children(new_node, node1);
  281. move_children(new_node, node2);
  282. arc1->change_parent_and_child(parent, node1);
  283. remove_arc(arc2);
  284. return arc1;
  285. }
  286. ////////////////////////////////////////////////////////////////////
  287. // Function: GraphReducer::collapse_nodes
  288. // Access: Protected, Virtual
  289. // Description: Collapses the two nodes into a single node, if
  290. // possible. The 'siblings' flag is true if the two
  291. // nodes are siblings nodes; otherwise, node1 is a
  292. // parent of node2. The return value is the resulting
  293. // node, which may be either one of the source nodes, or
  294. // a new node altogether, or it may be NULL to indicate
  295. // that the collapse operation could not take place.
  296. //
  297. // This function may be extended in a user class to
  298. // handle combining special kinds of nodes.
  299. ////////////////////////////////////////////////////////////////////
  300. Node *GraphReducer::
  301. collapse_nodes(Node *node1, Node *node2, bool) {
  302. // We get to choose whether to remove node1 or node2.
  303. if (node2->is_exact_type(Node::get_class_type()) ||
  304. node2->is_exact_type(NamedNode::get_class_type())) {
  305. // Node2 isn't anything special, so preserve node1.
  306. return node1;
  307. } else if (node1->is_exact_type(Node::get_class_type()) ||
  308. node1->is_exact_type(NamedNode::get_class_type())) {
  309. // Node1 isn't anything special, so preserve node2.
  310. return node2;
  311. } else {
  312. // Both node1 and node2 are some special kind of node. Don't
  313. // want to risk removing either of them.
  314. return NULL;
  315. }
  316. }
  317. ////////////////////////////////////////////////////////////////////
  318. // Function: GraphReducer::choose_name
  319. // Access: Protected, Virtual
  320. // Description: Chooses a suitable name for the collapsed node, based
  321. // on the names of the two sources nodes.
  322. ////////////////////////////////////////////////////////////////////
  323. void GraphReducer::
  324. choose_name(Node *preserve, Node *source1, Node *source2) {
  325. if (!preserve->is_of_type(NamedNode::get_class_type())) {
  326. // It's not even a namable class, so we can't name it anyway.
  327. // Never mind.
  328. return;
  329. }
  330. NamedNode *named_preserve;
  331. DCAST_INTO_V(named_preserve, preserve);
  332. if (source1->is_of_type(NamedNode::get_class_type())) {
  333. NamedNode *named_source1;
  334. DCAST_INTO_V(named_source1, source1);
  335. if (!named_source1->get_name().empty()) {
  336. named_preserve->set_name(named_source1->get_name());
  337. return;
  338. }
  339. }
  340. if (source2->is_of_type(NamedNode::get_class_type())) {
  341. NamedNode *named_source2;
  342. DCAST_INTO_V(named_source2, source2);
  343. if (!named_source2->get_name().empty()) {
  344. named_preserve->set_name(named_source2->get_name());
  345. return;
  346. }
  347. }
  348. }
  349. ////////////////////////////////////////////////////////////////////
  350. // Function: GraphReducer::move_children
  351. // Access: Protected
  352. // Description: Moves all of the children arcs of the 'from' node to
  353. // the 'to' node.
  354. ////////////////////////////////////////////////////////////////////
  355. void GraphReducer::
  356. move_children(Node *to, Node *from) {
  357. if (to != from) {
  358. int num_children = from->get_num_children(_graph_type);
  359. while (num_children > 0) {
  360. NodeRelation *arc =
  361. from->get_child(_graph_type, num_children - 1);
  362. arc->change_parent(to);
  363. num_children--;
  364. nassertv(num_children == from->get_num_children(_graph_type));
  365. }
  366. }
  367. }
  368. ////////////////////////////////////////////////////////////////////
  369. // Function: GraphReducer::copy_children
  370. // Access: Protected
  371. // Description: Copies all of the children arcs of the 'from' node to
  372. // the 'to' node, without removing the from the 'from'
  373. // node.
  374. ////////////////////////////////////////////////////////////////////
  375. void GraphReducer::
  376. copy_children(Node *to, Node *from) {
  377. if (to != from) {
  378. int num_children = from->get_num_children(_graph_type);
  379. for (int i = 0; i < num_children; i++) {
  380. NodeRelation *arc = from->get_child(_graph_type, i);
  381. NodeRelation *new_arc = NodeRelation::create_typed_arc
  382. (_graph_type, to, arc->get_child());
  383. nassertv(new_arc != (NodeRelation *)NULL);
  384. nassertv(new_arc->is_exact_type(_graph_type));
  385. new_arc->copy_transitions_from(arc);
  386. }
  387. }
  388. }