I am trying to implement a Breadth First Search (BFS) on my custom octree data structure to find the shortest path between two voxels in a 3D voxel octree. The start and end voxels are specified by their 3D positions (startVoxel and endVoxel) in the octree. The voxel_size is the size of a single voxel in the octree. The max_distance parameter specifies the maximum distance that the BFS search should cover. The function returns the path length (i.e., the number of voxels that need to be traversed) between the start and end voxels, or -1 if the end voxel is not found within the maximum distance.
As I am experiencing some issues with the positional coordinates of my voxels (i suspect some rounding errors) I am trying to use end_voxel_distancethreshold to eliminate the need to find the exact location of the end voxels but have some "buffer". The issue is if I make it too large, I return a lot of 0 distance, if I make it too small, I return some valid results but after a certain distance, I suddenly only return -1.
My question is: Is the below implementation valid or am I overlooking something that could result in this unexpected behavior? I am confident that my K-nearest neighbor is working correctly and returns the six nearest neighbors within a radius of the voxel size.
double bfs ( Custom_Octree& octree, double voxel_size, Eigen::Vector3d startVoxel, Eigen::Vector3d endVoxel, double max_distance )
{
// Threshold for checking if the current voxel is close enough to the end voxel
double end_voxel_distance_threshold = voxel_size;
// Create a queue and push the start voxel into it
std::queue< Eigen::Vector3d > q;
q.push( startVoxel );
// Create a vector to keep track of the visited voxels
std::vector< Eigen::Vector3d > visited;
visited.push_back( startVoxel );
// Initialize distance to 0
double distance = 0;
// Keep looping until the queue is empty
while( !q.empty() ) {
// Get the size of the queue
int size = q.size();
// For each voxel in the queue
while( size-- ) {
// Get the current voxel from the front of the queue
Eigen::Vector3d currentVoxel = q.front();
q.pop();
// Check if the current voxel is close enough to the end voxel
if( ( currentVoxel - endVoxel ).norm() <= end_voxel_distance_threshold )
{
// Return the distance between the start and end voxel
return distance;
}
// Get the center of the current voxel
Eigen::Vector3d current_voxel_center( currentVoxel[0], currentVoxel[1], currentVoxel[2] );
// Find the 6 nearest neighbors of the current voxel
auto neighbors = octree.k_nearest_neighbors( current_voxel_center, voxel_size, 6 );
// For each neighbor
for( auto neighbor : neighbors ) {
// Get the center of the neighbor voxel
double x = neighbor->x_center();
double y = neighbor->y_center();
double z = neighbor->z_center();
Eigen::Vector3d nb( x, y, z );
// If the neighbor has not been visited and the distance from the start voxel is within the max_distance
if( std::find( visited.begin(), visited.end(), nb ) == visited.end() && distance <= max_distance ) {
// Push the neighbor voxel into the queue
q.push( nb );
// Add the neighbor voxel to the visited vector
visited.push_back( nb );
}
}
}
// Increment the distance by the voxel size
distance += voxel_size;
}
// Return -1 if the end voxel was not found
return -1;
}
Related
I have a mesh which is mostly planar I'd like to find all the coplanar faces by using normals. I'll take that by finding all normals pointing in the same direction; that is, checking all collinear normal vectors within a tolerance, by a dot product.
But that means I've to check by looping for every vector.
MatrixXd VL = ... // Collinear vectors list taken from mesh normals
collinearEpsilon = 1e-8;
for (long i = 0, j = 0; i < VL.rows(); i++)
{
// get previous vector
Vector3d p = VL.row(i);
// loop around last vector
j = i + 1;
if (j == size)
{
j = 0;
}
// get next vector
Vector3d n = VL.row(j);
// if dot product is one, they're colinear
VectorXd CL(1);
p = p.normalized();
n = n.normalized();
CL(0) = 1 - abs(p.dot(n));
// check with epsilon
if (CL.isZero(collinearEpsilon))
// vector is collinear
else
// exit on first non-collinear
}
Thus my question: is there a better way to check the collinearity of a set of vectors, all together in a more compact way without looping, in Eigen?
EDIT: added assuming mesh is mostly planar
I've found and constructed an optical flow map, I'd now like to remove any vectors that fall below a certain threshold. This is how I've set up my Farneback optical flow:
if (prevgray.empty() == false ) {
calcOpticalFlowFarneback(prevgray,gray,flowUmat, 0.4,1,50,2,5,1.2,0);
flowUmat.copyTo(flow);
for( int y=0; y<original.rows; y+=7){
for (int x=0;x<original.cols;x+=7){
const Point2f& flowatxy=flow.at<Point2f>(y,x);
line(original, Point(x,y), Point(cvRound(x+flowatxy.x*4), cvRound(y+flowatxy.y*4)), Scalar(0,255,0));
theta=atan((flowatxy.y)/(flowatxy.x)); //very unsure of this
circle(original, Point(x,y), 0.1, Scalar(0,0,0),-1);
}
}
gray.copyTo(prevgray);
}
else{gray.copyTo(prevgray);}
I was thinking of something of comparing each vector to neighbouring vectors or to an average of all the vectors in the image.
To remove any vectors that fall below a certain threshold you first need to estimate the length, if you want e.g. discard long motion vectors. Your loop will than look like:
...
const Point2f& flowatxy=flow.at<Point2f>(y,x);
float flowVectorLength = flowatxy.x * flowatxy.x + flowatxy.y * flowatxy.y;
if( flowVectorLength > threshold * threshold)
continue;
...
Actually the motion vector length has to be computed by float flowVectorLength = sqrt(flowatxy.x * flowatxy.x + flowatxy.y * flowatxy.y); but to avoid the computational complex estimation of the square root (sqrt) you can compare it with the square of the threshold.
Is there a way to modify this to show the route of the shortest path? For example, if i had a list of numbers like (3,1),(3,0),(4,3),(2,1) the output for getting from 4 to 1 would be 4->3,3->1
// Prints shortest paths from src to all other vertices
void Graph::shortestPath(int src)
{
// Create a priority queue to store vertices that
// are being preprocessed. This is weird syntax in C++.
// Refer below link for details of this syntax
// http://geeksquiz.com/implement-min-heap-using-stl/
priority_queue< iPair, vector <iPair> , greater<iPair> > pq;
// Create a vector for distances and initialize all
// distances as infinite (INF)
vector<int> dist(V, INF);
// Insert source itself in priority queue and initialize
// its distance as 0.
pq.push(make_pair(0, src));
dist[src] = 0;
/* Looping till priority queue becomes empty (or all
distances are not finalized) */
while (!pq.empty())
{
// The first vertex in pair is the minimum distance
// vertex, extract it from priority queue.
// vertex label is stored in second of pair (it
// has to be done this way to keep the vertices
// sorted distance (distance must be first item
// in pair)
int u = pq.top().second;
pq.pop();
// 'i' is used to get all adjacent vertices of a vertex
list< pair<int, int> >::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
// Get vertex label and weight of current adjacent
// of u.
int v = (*i).first;
int weight = (*i).second;
// If there is shorted path to v through u.
if (dist[v] > dist[u] + weight)
{
// Updating distance of v
dist[v] = dist[u] + weight;
pq.push(make_pair(dist[v], v));
}
}
}
// Print shortest distances stored in dist[]
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
Putting in an array that stores the numbers of the path like 4,3,3,1 (using above example) seems like the best idea but i don't know where to insert the array in this code to do that.
Just as you save the distances for each vertex in the dist vector, save the predecessor vertex that last updated it in a vector called predecessor.
vector<int> dist(V, INF);
vector<int> predecessor(V, 0);
Then whenever you update the distance, update the predecessor:
dist[v] = dist[u] + weight;
predecessor[v] = u;
Finally, you can trace for any vertex the shortest path (Backward) to the source:
printf("Vertex Distance from Source shortest path from source\n");
for (int i = 0; i < V; ++i)
{
printf("%d \t\t %d\t\t", i, dist[i]);
int j = i;
do
{
printf("%d,", j);
j = predecessor[j];
} while(j != src);
printf("\n");
}
Sounds like a homework problem.
Your idea to store the numbers of the path would be great, if this were a DFS. Unfortunately, Djikstra's algorithm doesn't naturally keep track of the path like a DFS does; it simply takes the next closest node and updates the distance values. It's probably more similar to a BFS in that regard.
What you could do is as you update the distances to each node, somehow store which node you're coming from (maybe in your iPair struct if you're allowed to, maybe in a map/array if you have a way to ID your nodes). I'll call it a "from" reference for the sake of this post. Then, each time you find a shorter path to a node, you can also update that from reference.
How do you find the path to a given node then? Simple: just start at the end node, and follow the "from" references back to the source.
Normally to find the connected components on a set of points, I build a graph from the points that are placed in 2 dimensional Euclidean space where the edges are determined with thresholding. Namely, if the distance between two points is closer than a predetermined cut-off radius, then I consider them as neighbors. Then I do a depth-first search on this graph to determine the connected components.
The problem with this approach is I have to use thresholding to build the graph in the first place. I am not a computer scientist, so I never took an algorithms class. I would like to know if there is an algorithm with which I can find nearest neighbors or connected components without building the edges with thresholding? The main issue that makes thresholding so preferable is the fact that this box is periodic. That's why googling alone didn't help me much.
My code for this look like this:
// +++++
// Graph
// +++++
// ( Note that edges are lines connecting nodes or vertices )
class Graph
{
public:
Graph() {}
~Graph() {}
void setNumNodes( int nds );
int getNumNodes() { return numNodes; }
void addEdge( int nd_idx, set<int> dest );
map<int,set<int> > edges; // [node, destination]
void setThreshold( double cutoff, double carpan );
double getThreshold() { return threshold; }
private:
int numNodes;
double threshold;
};
void Graph::setNumNodes( int nds ){
numNodes = nds;
}
void Graph::addEdge( int nd_idx, set<int> dest ){
edges.insert( pair<int,set<int> >( nd_idx, dest ) );
}
void Graph::setThreshold( double cutoff, double carpan ){
threshold = 2*R + carpan*cutoff;
}
// +++++
// Function for depth-first search from a starting node
int dfsFromNode( Graph& graph, int i, stack<int>& S, vector<bool>& visited ){
int connected_comp = 0;
// Add the node to the stack
S.push( i );
// While there are nodes that are not visited
// (so as long as stack is not empty ..)
while( !S.empty() ){
// Remove the top of the stack (backtracking process)
S.pop();
if( !visited[i] ){
visited[i] = true;
connected_comp++;
set<int> neighbors;
neighbors = graph.edges[i];
for( auto j: neighbors ){
i = j;
S.push( i );
}
} // if the node is visited before, get out
} // while loop to check if the stack is empty or not
return connected_comp;
}
edit:
To reiterate the question, how can I find the nearest neighbors or connected components without doing thresholding in periodic boundary settings?
For finding connected components, you can use kd-trees. A k-d tree, (abbrev. k-dimensional tree) is an algorithm in which you split your data points into two alternating between orthogonal directions in each degrees of freedom. I find the following link quite useful for explanation.
Specifically, in the case of periodic boundary conditions, you can just ghost/image particles outside of the primary box and build the kd-tree including these particles.
I'm using ANN kdtree library to find nearest neighbors. I want to find the nearest neighbors with a minimum distance. I have included the regular code (from ANN library) below. It is obvious I can check the distance each time I find a neighbor, but I'm seeking a more efficient approach.
void ANNkd_tree::annkSearch(
ANNpoint q, // the query point
int k, // number of near neighbors to return
ANNidxArray nn_idx, // nearest neighbor indices (returned)
ANNdistArray dd, // the approximate nearest neighbor
double eps) // the error bound
{
ANNkdDim = dim; // copy arguments to static equivs
ANNkdQ = q;
ANNkdPts = pts;
ANNptsVisited = 0; // initialize count of points visited
if (k > n_pts) { // too many near neighbors?
annError("Requesting more near neighbors than data points", ANNabort);
}
ANNkdMaxErr = ANN_POW(1.0 + eps);
ANN_FLOP(2) // increment floating op count
ANNkdPointMK = new ANNmin_k(k); // create set for closest k points
// search starting at the root
root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
for (int i = 0; i < k; i++) { // extract the k-th closest points
dd[i] = ANNkdPointMK->ith_smallest_key(i);
nn_idx[i] = ANNkdPointMK->ith_smallest_info(i);
}
delete ANNkdPointMK; // deallocate closest point set
}
//----------------------------------------------------------------------
// kd_split::ann_search - search a splitting node
//----------------------------------------------------------------------
void ANNkd_split::ann_search(ANNdist box_dist)
{
// check dist calc term condition
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
// distance to cutting plane
ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val;
if (cut_diff < 0) { // left of cutting plane
child[ANN_LO]->ann_search(box_dist);// visit closer child first
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if close enough
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
child[ANN_HI]->ann_search(box_dist);
}
else { // right of cutting plane
child[ANN_HI]->ann_search(box_dist);// visit closer child first
ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI];
if (box_diff < 0) // within bounds - ignore
box_diff = 0;
// distance to further box
box_dist = (ANNdist) ANN_SUM(box_dist,
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
// visit further child if close enough
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
child[ANN_LO]->ann_search(box_dist);
}
ANN_FLOP(10) // increment floating ops
ANN_SPL(1) // one more splitting node visited
}
//----------------------------------------------------------------------
// kd_leaf::ann_search - search points in a leaf node
// Note: The unreadability of this code is the result of
// some fine tuning to replace indexing by pointer operations.
//----------------------------------------------------------------------
void ANNkd_leaf::ann_search(ANNdist box_dist)
{
register ANNdist dist; // distance to data point
register ANNcoord* pp; // data coordinate pointer
register ANNcoord* qq; // query coordinate pointer
register ANNdist min_dist; // distance to k-th closest point
register ANNcoord t;
register int d;
min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far
for (int i = 0; i < n_pts; i++) { // check points in bucket
pp = ANNkdPts[bkt[i]]; // first coord of next data point
qq = ANNkdQ; // first coord of query point
dist = 0;
for(d = 0; d < ANNkdDim; d++) {
ANN_COORD(1) // one more coordinate hit
ANN_FLOP(4) // increment floating ops
t = *(qq++) - *(pp++); // compute length and adv coordinate
// exceeds dist to k-th smallest?
if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
break;
}
}
if (d >= ANNkdDim && // among the k best?
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
// add it to the list
ANNkdPointMK->insert(dist, bkt[i]);
min_dist = ANNkdPointMK->max_key();
}
}
ANN_LEAF(1) // one more leaf node visited
ANN_PTS(n_pts) // increment points visited
ANNptsVisited += n_pts; // increment number of points visited
}