reduce overhead on NodePath::find() operations

This commit is contained in:
David Rose 2003-04-09 15:59:53 +00:00
parent c231386f16
commit 5c48c68569
7 changed files with 133 additions and 44 deletions

View File

@ -23,11 +23,12 @@
// Description:
////////////////////////////////////////////////////////////////////
INLINE FindApproxLevelEntry::
FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
FindApproxLevelEntry(const WorkingNodePath &node_path, FindApproxPath &approx_path) :
_node_path(node_path),
_approx_path(approx_path)
{
_i = 0;
nassertv(_node_path.is_valid());
}
////////////////////////////////////////////////////////////////////
@ -36,11 +37,12 @@ FindApproxLevelEntry(const NodePath &node_path, FindApproxPath &approx_path) :
// Description:
////////////////////////////////////////////////////////////////////
INLINE FindApproxLevelEntry::
FindApproxLevelEntry(const FindApproxLevelEntry &copy) :
FindApproxLevelEntry(const FindApproxLevelEntry &copy, int increment) :
_node_path(copy._node_path),
_i(copy._i),
_i(copy._i + increment),
_approx_path(copy._approx_path)
{
nassertv(_node_path.is_valid());
}
////////////////////////////////////////////////////////////////////
@ -53,6 +55,7 @@ operator = (const FindApproxLevelEntry &copy) {
_node_path = copy._node_path;
_i = copy._i;
nassertv(&_approx_path == &copy._approx_path);
nassertv(_node_path.is_valid());
}
@ -63,8 +66,8 @@ operator = (const FindApproxLevelEntry &copy) {
// must be a stashed node, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool FindApproxLevelEntry::
next_is_stashed() const {
return _approx_path.matches_stashed(_i);
next_is_stashed(int increment) const {
return _approx_path.matches_stashed(_i + increment);
}
////////////////////////////////////////////////////////////////////
@ -75,6 +78,6 @@ next_is_stashed() const {
// been successfully matched.
////////////////////////////////////////////////////////////////////
INLINE bool FindApproxLevelEntry::
is_solution() const {
return (_i >= _approx_path.get_num_components());
is_solution(int increment) const {
return (_i + increment >= _approx_path.get_num_components());
}

View File

@ -30,7 +30,7 @@
void FindApproxLevelEntry::
output(ostream &out) const {
out << "(" << _node_path << "):";
if (is_solution()) {
if (is_solution(0)) {
out << " solution!";
} else {
out << "(";
@ -46,34 +46,39 @@ output(ostream &out) const {
////////////////////////////////////////////////////////////////////
void FindApproxLevelEntry::
consider_node(NodePathCollection &result, FindApproxLevel &next_level,
int max_matches) const {
nassertv(_i < _approx_path.get_num_components());
int max_matches, int increment) const {
nassertv(_i + increment < _approx_path.get_num_components());
if (_approx_path.is_component_match_many(_i)) {
if (_approx_path.is_component_match_many(_i + increment)) {
// Match any number, zero or more, levels of nodes. This is the
// tricky case that requires this whole nutty breadth-first thing.
// This means we must reconsider our own entry with the next path
// entry, before we consider the next entry--this supports
// matching zero levels of nodes.
FindApproxLevelEntry reconsider(*this);
++reconsider._i;
if (reconsider.is_solution()) {
// We used to make a temporary copy of our own record, and then
// increment _i on that copy, but we can't do that nowadays
// because the WorkingNodePath object stores a pointer to each
// previous generation, which means we can't use any temporary
// FindApproxLevelEntry objects. Instead, we pass around the
// increment parameter, which increments _i on the fly.
if (is_solution(increment + 1)) {
// Does this now represent a solution?
result.add_path(reconsider._node_path);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
result.add_path(_node_path.get_node_path());
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
} else {
reconsider.consider_node(result, next_level, max_matches);
consider_node(result, next_level, max_matches, increment + 1);
}
}
PandaNode *this_node = _node_path.node();
nassertv(this_node != (PandaNode *)NULL);
bool stashed_only = next_is_stashed();
bool stashed_only = next_is_stashed(increment);
if (!stashed_only) {
// Check the normal list of children.
@ -81,7 +86,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
for (int i = 0; i < num_children; i++) {
PandaNode *child_node = this_node->get_child(i);
consider_next_step(result, child_node, next_level, max_matches);
consider_next_step(result, child_node, next_level, max_matches, increment);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
@ -94,7 +99,7 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
for (int i = 0; i < num_stashed; i++) {
PandaNode *stashed_node = this_node->get_stashed(i);
consider_next_step(result, stashed_node, next_level, max_matches);
consider_next_step(result, stashed_node, next_level, max_matches, increment);
if (max_matches > 0 && result.get_num_paths() >= max_matches) {
return;
}
@ -115,7 +120,8 @@ consider_node(NodePathCollection &result, FindApproxLevel &next_level,
////////////////////////////////////////////////////////////////////
void FindApproxLevelEntry::
consider_next_step(NodePathCollection &result, PandaNode *child_node,
FindApproxLevel &next_level, int max_matches) const {
FindApproxLevel &next_level, int max_matches,
int increment) const {
if (!_approx_path.return_hidden() &&
child_node->get_draw_mask().is_zero()) {
// If the approx path does not allow us to return hidden nodes,
@ -124,25 +130,25 @@ consider_next_step(NodePathCollection &result, PandaNode *child_node,
return;
}
nassertv(_i < _approx_path.get_num_components());
nassertv(_i + increment < _approx_path.get_num_components());
if (_approx_path.is_component_match_many(_i)) {
if (_approx_path.is_component_match_many(_i + increment)) {
// Match any number, zero or more, levels of nodes. This is the
// tricky case that requires this whole nutty breadth-first thing.
// And now we just add the next entry without incrementing its
// path entry.
FindApproxLevelEntry next(*this);
next._node_path = NodePath(_node_path, child_node);
FindApproxLevelEntry next(*this, increment);
next._node_path = WorkingNodePath(_node_path, child_node);
next_level.add_entry(next);
} else {
if (_approx_path.matches_component(_i, child_node)) {
if (_approx_path.matches_component(_i + increment, child_node)) {
// That matched, and it consumes one path entry.
FindApproxLevelEntry next(*this);
++next._i;
next._node_path = NodePath(_node_path, child_node);
FindApproxLevelEntry next(*this, increment);
next._i++;
next._node_path = WorkingNodePath(_node_path, child_node);
next_level.add_entry(next);
}
}

View File

@ -22,7 +22,7 @@
#include "pandabase.h"
#include "findApproxPath.h"
#include "nodePath.h"
#include "workingNodePath.h"
class FindApproxLevel;
class NodePathCollection;
@ -36,25 +36,25 @@ class NodePathCollection;
////////////////////////////////////////////////////////////////////
class FindApproxLevelEntry {
public:
INLINE FindApproxLevelEntry(const NodePath &node_path,
INLINE FindApproxLevelEntry(const WorkingNodePath &node_path,
FindApproxPath &approx_path);
INLINE FindApproxLevelEntry(const FindApproxLevelEntry &copy);
INLINE FindApproxLevelEntry(const FindApproxLevelEntry &copy, int increment = 0);
INLINE void operator = (const FindApproxLevelEntry &copy);
INLINE bool next_is_stashed() const;
INLINE bool next_is_stashed(int increment) const;
void consider_node(NodePathCollection &result, FindApproxLevel &next_level,
int max_matches) const;
int max_matches, int increment) const;
void consider_next_step(NodePathCollection &result,
PandaNode *child_node, FindApproxLevel &next_level,
int max_matches) const;
INLINE bool is_solution() const;
int max_matches, int increment) const;
INLINE bool is_solution(int increment) const;
void output(ostream &out) const;
// _node_path represents the most recent node that we have
// previously accepted as being a partial solution.
NodePath _node_path;
WorkingNodePath _node_path;
// _i represents the next component in the approx_path that must be
// matched against all of the children of _node_path, above. If _i

View File

@ -3083,7 +3083,8 @@ find_matches(NodePathCollection &result, FindApproxPath &approx_path,
<< "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
return;
}
FindApproxLevelEntry start(*this, approx_path);
FindApproxLevelEntry start(WorkingNodePath(*this), approx_path);
nassertv(start._node_path.is_valid());
FindApproxLevel level;
level.add_entry(start);
r_find_matches(result, level, max_matches, _max_search_depth);
@ -3114,11 +3115,11 @@ r_find_matches(NodePathCollection &result,
for (li = level._v.begin(); li != level._v.end() && okflag; ++li) {
const FindApproxLevelEntry &entry = (*li);
if (entry.is_solution()) {
if (entry.is_solution(0)) {
// Does this entry already represent a solution?
result.add_path(entry._node_path);
result.add_path(entry._node_path.get_node_path());
} else {
entry.consider_node(result, next_level, max_matches);
entry.consider_node(result, next_level, max_matches, 0);
}
if (max_matches > 0 && result.get_num_paths() >= max_matches) {

View File

@ -33,6 +33,21 @@ WorkingNodePath(const NodePath &start) {
_node = start.node();
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE WorkingNodePath::
WorkingNodePath(const WorkingNodePath &copy) :
_next(copy._next),
_start(copy._start),
_node(copy._node)
{
nassertv(_next != (WorkingNodePath *)NULL ||
_start != (NodePathComponent *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::Constructor
// Access: Public
@ -57,6 +72,21 @@ INLINE WorkingNodePath::
~WorkingNodePath() {
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void WorkingNodePath::
operator = (const WorkingNodePath &copy) {
_next = copy._next;
_start = copy._start;
_node = copy._node;
nassertv(_next != (WorkingNodePath *)NULL ||
_start != (NodePathComponent *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::get_node_path
// Access: Public
@ -80,3 +110,9 @@ INLINE PandaNode *WorkingNodePath::
node() const {
return _node;
}
INLINE ostream &
operator << (ostream &out, const WorkingNodePath &node_path) {
node_path.output(out);
return out;
}

View File

@ -19,9 +19,27 @@
#include "workingNodePath.h"
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::is_valid
// Access: Public
// Description: Returns true if the WorkingNodePath object appears to
// be a valid NodePath reference, false otherwise.
////////////////////////////////////////////////////////////////////
bool WorkingNodePath::
is_valid() const {
if (_node == (PandaNode *)NULL) {
return false;
}
if (_next == (WorkingNodePath *)NULL) {
return (_start != (NodePathComponent *)NULL);
}
return _next->is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::get_num_nodes
// Access: Published
// Access: Public
// Description: Returns the number of nodes in the path from the root
// to the current node.
//
@ -40,7 +58,7 @@ get_num_nodes() const {
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::get_node
// Access: Published
// Access: Public
// Description: Returns the nth node of the path, where 0 is the
// referenced (bottom) node and get_num_nodes() - 1 is
// the top node. This requires iterating through the
@ -60,6 +78,18 @@ get_node(int index) const {
return _next->get_node(index - 1);
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void WorkingNodePath::
output(ostream &out) const {
// Cheesy and slow, but when you're outputting the thing, presumably
// you're not in a hurry.
get_node_path().output(out);
}
////////////////////////////////////////////////////////////////////
// Function: WorkingNodePath::r_get_node_path
// Access: Private
@ -70,6 +100,7 @@ get_node(int index) const {
PT(NodePathComponent) WorkingNodePath::
r_get_node_path() const {
if (_next == (WorkingNodePath *)NULL) {
nassertr(_start != (NodePathComponent *)NULL, NULL);
return _start;
}
@ -78,5 +109,8 @@ r_get_node_path() const {
PT(NodePathComponent) comp = _next->r_get_node_path();
nassertr(comp != (NodePathComponent *)NULL, NULL);
return PandaNode::get_component(comp, _node);
PT(NodePathComponent) result = PandaNode::get_component(comp, _node);
nassertr(result != (NodePathComponent *)NULL, NULL);
return result;
}

View File

@ -49,15 +49,22 @@
class EXPCL_PANDA WorkingNodePath {
public:
INLINE WorkingNodePath(const NodePath &start);
INLINE WorkingNodePath(const WorkingNodePath &copy);
INLINE WorkingNodePath(const WorkingNodePath &parent, PandaNode *child);
INLINE ~WorkingNodePath();
INLINE void operator = (const WorkingNodePath &copy);
bool is_valid() const;
INLINE NodePath get_node_path() const;
INLINE PandaNode *node() const;
int get_num_nodes() const;
PandaNode *get_node(int index) const;
void output(ostream &out) const;
private:
PT(NodePathComponent) r_get_node_path() const;
@ -70,6 +77,8 @@ private:
PandaNode *_node;
};
INLINE ostream &operator << (ostream &out, const WorkingNodePath &node_path);
#include "workingNodePath.I"
#endif