I have sparse openvdb grid and want to iterate over active CoordBBox in parallel, as far as it can change tree topology I cannot use openvdb::tools::foreach
I come up with this solution, but maybe there are something better:
auto activeBox = grid->evalActiveVoxelBoundingBox();
// make dense topology tree to copy its nodes topology to original grid
std::unique_ptr<openvdb::TopologyTree> topologyTree = std::make_unique<openvdb::TopologyTree>();
// make it dense
topologyTree->denseFill( activeBox, {} );
grid->tree().topologyUnion( *topologyTree ); // after this all voxels should be active and trivial parallelism is ok
// free topology tree
topologyTree.reset();
tbb::parallel_for( tbb::blocked_range<int>( 0, int( activeBox.volume() ) ),
[&] ( const tbb::blocked_range<int>& range )
{
auto accessor = grid->getAccessor();
for ( auto i = range.begin(); i < range.end(); ++i )
{
// do something
}
} );
Related
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;
}
I want to have conformal meshes in the interface of two solids but the import 2D algorithm misidentifies which nodes belongs to which sub-shape and raises an error.I went through source files and couldn't find the problem and I wast able to join Salome forum.
and here is the copied mesh :
it correctly identifies the node belonging to edge 541 but the next node is set to belong to another edge.this problem only happens when there is an extra vertex like so:
I suspect this part of the source code to be the problem:
// check if a not shared link lies on face boundary
bool nodesOnBoundary = true;
list< TopoDS_Shape > bndShapes;
for ( int is1stN = 0; is1stN < 2 && nodesOnBoundary; ++is1stN )
{
const SMDS_MeshNode* n = is1stN ? link.node1() : link.node2();
if ( !subShapeIDs.count( n->getshapeId() )) // n is assigned to FACE
{
for ( size_t iE = 0; iE < edges.size(); ++iE )
if ( helper.CheckNodeU( edges[iE], n, u=0, projTol, /*force=*/true ))
{
BRep_Tool::Range(edges[iE],f,l);
if ( Abs(u-f) < 2 * faceTol || Abs(u-l) < 2 * faceTol )
// duplicated node on vertex
return error("Source elements overlap one another");
tgtFaceSM->RemoveNode( n );
tgtMesh->SetNodeOnEdge( n, edges[iE], u );
break;
}
nodesOnBoundary = subShapeIDs.count( n->getshapeId());
}
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.
Unfortunately my math abilities and objective-c/c/c++ isn't developed enough to understand how to do this.
I have a vector set up like this:
[2,2,3,3,4,4,5,5,6,6] <-- i think thats how vectors are set up correct?
This is sort of what i think it should be set up:
vector<CGPoint>::iterator i;
vector<CGPoint>* dp = xGraph.GraphPoints;
for(i = dp->begin(); i != dp->end(); ++i){
/* grab y points only code here*/
}
Now I want to write some kind of for statement that takes xGraph.GraphPoints and only grabs the y coords.
and... i guess puts it into another vector of only y coords, which looks like [2,3,4,5,6] after the code is finished
Can someone help me out here?
Cheers
Ok, my interpretation of your question is that you have a vector that contains CGPoint objects and you want to extract only the y coordinate from all of the points. In that case you want something like (using C++11 lambdas):
std::vector<CGFloat> ycoord;
std::transform( dp->begin(), dp->end(), std::back_inserter( ycoord ),
[]( CGPoint const & p ){ return p.y; } );
If the compiler does not support lambdas, you can write a simple function to perform the extraction:
CGFloat extractY( CGPoint const & p ) {
return p.y;
}
std::transform( dp->begin(), dp->end(), std::back_inserter( ycoord ),
&extractY );
Or functor:
struct extractYfunctor {
CGFloat operator()( CGPoint const & p ) const {
return p.y;
}
};
std::transform( dp->begin(), dp->end(), std::back_inserter( ycoord ),
extractYfuctor() );
If you can use the boost libraries:
std::transform( dp->begin(), dp->end(), std::back_inserter( ycoord ),
boost::bind( &CGPoint::y, _1 ) );
Or with a plain loop:
for ( std::vector< CGPoint >::const_iterator it = dp->begin(); it != dp->end(); ++it ) {
ycoord.push_back( it->y );
}
Your vector is not set up like [2,2,3,3,4,4,5,5,6,6]. It's set up like this: [(2,2),(3,3),(4,4),(5,5),(6,6)]. That is, it's a list of pairs of numbers, not just a list of numbers. To get the y component of each element in the vector, you can write a loop like this:
vector<CGPoint>* dp = xGraph.GraphPoints;
for(i = dp->begin(); i != dp->end(); ++i){
/* grab y points only code here*/
CGFloat current_y = i->y;
}
vector<CGPoint>::iterator i;
vector<CGPoint>* dp = xGraph.GraphPoints;
vector<CGFloat> dp = yPoints;
for(i = dp->begin(); i != dp->end(); ++i){
yPoints.push_back(i->y);
}
vectors are indeed laid out like that in memory, but not logically. Don't overthink things. It's still a vector of CGFloat objects.
I implemented a path simplification algorithm after reading the article here:
http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/
It's worked for me pretty well for generating optimized level geometry for my game. But, I'm using it now to clean up a* pathfinding paths and it's got a weird edge case that fails miserably.
Here's a screenshot of it working - optimizing the path from red circle to the blue circle. The faint green line is the a* output, and the lighter whiteish line is the optimized path.
And here's a screenshot of it failing:
Here's my code. I adapted the ObjC code from the article to c++
Note: vec2fvec is a std::vector< vec2<float> >, and 'real' is just a typedef'd float.
void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
if ( in.size() <= 2 )
{
out = in;
return;
}
//
// Find the vertex farthest from the line defined by the start and and of the path
//
real maxDist = 0;
size_t maxDistIndex = 0;
LineSegment line( in.front(), in.back() );
for ( vec2fvec::const_iterator it(in.begin()),end(in.end()); it != end; ++it )
{
real dist = line.distance( *it );
if ( dist > maxDist )
{
maxDist = dist;
maxDistIndex = it - in.begin();
}
}
//
// If the farhtest vertex is greater than our threshold, we need to
// partition and optimize left and right separately
//
if ( maxDist > threshold )
{
//
// Partition 'in' into left and right subvectors, and optimize them
//
vec2fvec left( maxDistIndex+1 ),
right( in.size() - maxDistIndex ),
leftSimplified,
rightSimplified;
std::copy( in.begin(), in.begin() + maxDistIndex + 1, left.begin() );
std::copy( in.begin() + maxDistIndex, in.end(), right.begin() );
rdpSimplify(left, leftSimplified, threshold );
rdpSimplify(right, rightSimplified, threshold );
//
// Stitch optimized left and right into 'out'
//
out.resize( leftSimplified.size() + rightSimplified.size() - 1 );
std::copy( leftSimplified.begin(), leftSimplified.end(), out.begin());
std::copy( rightSimplified.begin() + 1, rightSimplified.end(), out.begin() + leftSimplified.size() );
}
else
{
out.push_back( line.a );
out.push_back( line.b );
}
}
I'm really at a loss as to what's going wrong. My spidey sense says it's in the std::copy calls... I must be copying garbage in some circumstances.
EDIT:
I've rewritten the algorithm dropping any use of iterators and std::copy, and the like. It still fails in the exact same way.
void rdpSimplify( const vec2fvec &in, vec2fvec &out, real threshold )
{
if ( in.size() <= 2 )
{
out = in;
return;
}
//
// Find the vertex farthest from the line defined by the start and and of the path
//
real maxDist = 0;
size_t maxDistIndex = 0;
LineSegment line( in.front(), in.back() );
for ( size_t i = 0, N = in.size(); i < N; i++ )
{
real dist = line.distance( in[i] );
if ( dist > maxDist )
{
maxDist = dist;
maxDistIndex = i;
}
}
//
// If the farthest vertex is greater than our threshold, we need to
// partition and optimize left and right separately
//
if ( maxDist > threshold )
{
//
// Partition 'in' into left and right subvectors, and optimize them
//
vec2fvec left, right, leftSimplified, rightSimplified;
for ( size_t i = 0; i < maxDistIndex + 1; i++ ) left.push_back( in[i] );
for ( size_t i = maxDistIndex; i < in.size(); i++ ) right.push_back( in[i] );
rdpSimplify(left, leftSimplified, threshold );
rdpSimplify(right, rightSimplified, threshold );
//
// Stitch optimized left and right into 'out'
//
out.clear();
for ( size_t i = 0, N = leftSimplified.size(); i < N; i++ ) out.push_back(leftSimplified[i]);
for ( size_t i = 1, N = rightSimplified.size(); i < N; i++ ) out.push_back( rightSimplified[i] );
}
else
{
out.push_back( line.a );
out.push_back( line.b );
}
}
I can't find any faults in your code.
Some things to try:
Add some debug print statements to check what maxDist is in the failing case. It should be really low, but if it comes out high then you know there's a problem with your line segment distance code.
Check that the path you are seeing actually matches the path that your algorithm returns. If not then perhaps there is something wrong with your path rendering? Maybe a bug when the path only has two points?
Check that your input path is what you expect it to be by printing out all its coordinates at the start of the algorithm.
It shouldn't take too long to find the cause of the problem if you just investigate a little. After a few minutes, staring at code is a very poor way to debug.