I would like to be able to iterate through the grid elements with a set step size. The fun part of this problem is that the grid will be rotated. I have developed an algorithm to do this and it is successful for some cases. The image below specifies the problem:
The conditions of the problem are that a grid spacing will be provided that is a factor of the grid length and width (As a side note the grid can be rectangular). The Algorithm must iterate through the grid and print out where it is. Here is some code and an example of it working:
int main() {
vector< vector<double> > bound;
vector<double> point;
point.push_back(0);
point.push_back(4);
bound.push_back(point);
point[0] = 6; point[1] = 10;
bound.push_back(point);
point[0] = 4; point[1] = 0;
bound.push_back(point);
point[0] = 10; point[1] = 6;
bound.push_back(point);
double d = 0.5;
double x, y;
int countx = 0, county = 0;
for (double i = bound[0][0]; i < bound[2][0]; i+=d) {
//std::cout << "I: " << i << std::endl;
for (double j = bound[0][1]; j < bound[1][1]; j+=d) {
//std::cout << "J: " << j << std::endl;
x = i+d+(double)county*d;
y = j-(double)countx*d;
++county;
std::cout << "i, j, x and y: " << i << "\t" << j << "\t" << x << "\t" << y << std::endl;
}
std::cout << "new Row--------------------\n";
++countx;
county = 0;
}
}
The code above works and prints correctly the grid elements, ie:
x and y: 4, 0.5
x and y: 4.5, 1
etc.
However when trying a rectangle with bounds:
[(0.5, 6), (3, 8.5), (5.5, 1), (8, 3.5)]
and a step size (d) of 1
It iterates to outside the rectangle bounds. I can see why this is happening, the iterator condition in the for loop will not contain it because of the extra +d.
My question is, is there a better way to approach this problem and how would i go about it?
Does anyone know if this has been implemented before and has some source code?
Cheers for the help.
Ben
The Way I ended up going about it was to calculate the length and width of the rectangle by Pythagoras rule on two of the sides. I then made a grid on a virtual rectangle which is aligned with its bottom corner at the origin. Then by using a pre-developed library for matrix rotations and translations, I transformed the points individually by translating them to by the displacement to the bottom left corner and rotating them to the calculated angle of the rectangle.
This is similar to the above solution but uses a full transformation matrix. The answer ended up being simpler then I thought it would be.
Thanks for the help.
Related
I have one requirement where I need to store 2 axis values into liner vector, some values like[x =0][y=1] and [y=0][x=1] i dint know how to save
I simply added i+j to find index but it now working in all case
I have 0>=x<=200 and 0>=y<=103
where x increment x= x+1
y increment y = y+1.5
is there any generic formula i can derive to save all data linearly
vector_1d_index = vector_2d_row_index * vector_2d_row_length + vector_2d_column_index
... assuming your 2D vector is i) row-major and ii) rectangular (uniform length rows).
(vector_1d_size = vector_2d_row_count * vector_2d_row_length).
Your description is vague. But what I can gather is that you are looking to store values from 2-d indices in a 1-d array. The general technique is to use something like follows:
Assume row, col are 2-d index coordinates
<1-d index> = <max number of columns> * row + col
If I have understood right, you want a way to store a 2D float-indexed array in C++. You will need some conversion, because C++ "only support 1D arrays" (that isn't strictly true, but we will pretend that it is).
First we need to know the ranges and the increments. You provided them, and for X the range is [0, 200] and for Y [0, 103] with increments 1 and 1.5 respectvely.
That means we have ((200-0)/1) = 200 possible values for X and ((103-0)/1.5) = 68.666... possible values for Y. We'll go with 69 possible values for Y.
So, we could have the following array:
int my_array_of_ints[69 * 200];
For example, the item [X=0][Y=0] will be our [0 * 69 + 0] index (item my_array_of_ints[0]), while our [X=1][Y=1.5] will be our [1 * 69 + 1] index (item my_array_of_ints[70]). Note that we can't have items with [Y=0.5] or [Y=1] because Y increment is fixed to 1.5 (i.e Y must be 0 or 1.5 or 3 or 4.5 or 6 or ...).
This function for converting the 2D index into a 1D linear index would be:
#include <cmath>
int get_element(float x, float y){
int index_x = std::round(x / 1);
int index_y = std::round(y / 1.5);
if ((0 <= index_x) && (index_x < 200) &&
(0 <= index_y) && (index_y < 69)){
return my_array_of_ints[index_y * 200 + index_x];
} else {
// You should decide what to do if x or y is out-of-range
return 0;
}
}
Where:
1 is the increment of x
1.5 is the increment of y
200 is the number of possibles values of x in that range with this increment
69 is the number of possibles values of y in that range with this increment.
So then we could do something like this:
get_element(1, 1.5)
And it would return the value of [X=1][Y=1.5] inside my_array_of_ints.
Wrapping this code around a class, templatizing the type of the array, generalizing the ranges and increments and providing a dummy main:
#include <cmath>
#include <iostream>
template <typename Datatype> class Vector2D {
float x_increment;
float x_minimum;
float x_maximum;
float y_increment;
float y_minimum;
float y_maximum;
// For example, Y range [0, 103] with increment 1.5
// results in 69 possibles values for Y, and we need to
// remember to "linearize" the indexes
int x_possibles;
int y_possibles;
Datatype *array;
public:
Vector2D(float x_increment, float y_increment,
float x_maximum, float y_maximum,
float x_minimum=0, float y_minimum=0)
: x_increment(x_increment), x_minimum(x_minimum),
x_maximum(x_maximum), y_increment(y_increment),
y_minimum(y_minimum), y_maximum(y_maximum),
// These two may seem arcane, but they are the
// generalization of how we found the values initially
x_possibles(std::ceil((x_maximum-x_minimum)/x_increment)),
y_possibles(std::ceil((y_maximum-y_minimum)/y_increment)),
array(new Datatype[y_possibles * x_possibles]) {
// This may help to understand this 2D Vector
std::cout << "Creating 2D vector X in range ["
<< x_minimum << ", " << x_maximum
<< "] with increment of " << x_increment
<< " (totalizing " << x_possibles
<< " possible values for x) "
<< " and Y in range [" << y_minimum
<< ", " << y_maximum << "] with increment of "
<< y_increment << " (totalizing " << y_possibles
<< " values for y)."
<< std::endl;
}
// Frees up the raw array
~Vector2D(){
delete this->array;
}
Datatype& get_element(float x, float y){
int index_x = std::round((x-x_minimum)/this->x_increment);
int index_y = std::round((y-y_minimum)/this->y_increment);
// This debug message may help understand this function
// It is, in some sense, the answer of this question
std::cout << "The 2D point [X=" << x << ", Y=" << y
<< "] is mapped into the vector index ["
<< index_y << " * " << x_possibles
<< " + " << index_x << "]" << std::endl;
if ((0 <= index_x) && (index_x < x_possibles) &&
(0 <= index_y) && (index_y < y_possibles)){
return this->array[index_y * x_possibles + index_x];
} else {
// You should decide what to do if x or y is out-of-range
return this->array[0];
}
}
};
int main(){
// And you could use that class like this:
// A 2D-like vector with X [0, 200] inc. 1
// and Y [0, 103] inc. 1.5 of floats
Vector2D<float> my_data(1, 1.5, 200, 103, 0, 0);
// Sets [X=1][Y=1] to 0.61345
my_data.get_element(1, 1) = 0.61345;
auto elem1 = my_data.get_element(1, 1);
// Prints the [X=1][Y=1] to screen
std::cout << "[X=1][Y=1] is "
<< elem1
<< std::endl;
// Gets a few more interesting points
my_data.get_element(0, 0);
my_data.get_element(1, 1.5);
my_data.get_element(10, 15);
my_data.get_element(200, 103);
// A separator
std::cout << "---" << std::endl;
// Another example, this time using chars
// X is [-10, 1] inc. 0.1 and Y is [-5, 3] inc. 0.05
Vector2D<char> my_chars(0.1, 0.05, 1, 3, -10, -5);
// Sets [X=-4.3][Y=2.25] to '!'
my_chars.get_element(-4.3, 2.25) = '!';
auto elem2 = my_chars.get_element(-4.3, 2.25);
std::cout << "[X=-4.3][Y=2.25] is "
<< elem2
<< std::endl;
}
Outputs:
Creating 2D vector X in range [0, 200] with increment of 1 (totalizing 200 possible values for x) and Y in range [0, 103] with increment of 1.5 (totalizing 69 values for y).
The 2D point [X=1, Y=1] is mapped into the vector index [1 * 200 + 1]
The 2D point [X=1, Y=1] is mapped into the vector index [1 * 200 + 1]
[X=1][Y=1] is 0.61345
The 2D point [X=0, Y=0] is mapped into the vector index [0 * 200 + 0]
The 2D point [X=1, Y=1.5] is mapped into the vector index [1 * 200 + 1]
The 2D point [X=10, Y=15] is mapped into the vector index [10 * 200 + 10]
The 2D point [X=200, Y=103] is mapped into the vector index [69 * 200 + 200]
---
Creating 2D vector X in range [-10, 1] with increment of 0.1 (totalizing 110 possible values for x) and Y in range [-5, 3] with increment of 0.05 (totalizing 160 values for y).
The 2D point [X=-4.3, Y=2.25] is mapped into the vector index [145 * 110 + 57]
The 2D point [X=-4.3, Y=2.25] is mapped into the vector index [145 * 110 + 57]
[X=-4.3][Y=2.25] is !
Hope that may help.
So what I am essentially trying to do here is arranging the 3D cartesian coordinates of points inside an inverted cone (radius decreases with height). The basic approach I have taken here is to have an integrally reducing height, h, and plotting points (x,y) that fall within a circle formed at height h. Since the radius of this circle is variable, I am using a simple similarity condition to determine that at every iteration. The initial height I have taken is 1000, the radius ought to initially be 3500. Also, these circles as centred at (0,0) [the z-axis passes through the vertex of the cone, and is perpendicular to the base]. Code isn't running properly, showing me an exit status of -1. Can anyone help me figure out if my implementation is off due to some size errors or something?
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
int main(){
float top[1010][9000][3];
ll i = 0;
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8;
i++;
}
}
}
i=0;
}
cout << "done";
for (ll m = 0; m < 1000; m++){
for(ll n = 0; n < 7000; n++){
if(top[m][n][2] == 9.8){
cout << top[m][n][0] << top[m][n][1];
}
}
}
}
You don't need to declare ll as long long int. The indexes you are using will fit inside of int.
Here's your problem: Change the code to this to see what's going on:
for(ll h = 999; h >=0; h--){
float r=(h+1)*(3.5);
for (ll x = floor(r) * (-1); x <= floor(r); x++){
for (ll y = floor(r) *(-1); y <= floor(r); y++){
if(pow(x,2) + pow(y,2) <= pow(floor(r),2)){
/* top[h][i][0] = x;
top[h][i][1] = y;
top[h][i][2] = 9.8; //*/
i++; // this gets really big
}
}
}
cout << "max i: " << i << endl;
i=0;
}
i gets really big and is indexing into a dimension that is only 9000.
Criticism of the code...
It looks like you are scanning the entire x,y,z block and 'testing' if the point is inside. If yes, saving the x,y coordinate of the point along with 9.8 (some field value?).
Perhaps you could forgo the float buffer and just print the {x,y} coordinates directly to see how your code works before attempting to save the output. redirect the output to a file and inspect.
cout << "{" << x << "," << y <<"}," << (i % 5 == 0 ? "\n" : " ");
Also, read up on why comparing floats with == doesn't work.
I have four coordinates: x,y,width=w,height=h and I have two rectangles with the following coordinates:
r1.x=2,r1.y=3,r1.w=5,r1.h=6;
r2.x=0, r2.y=7,r2.w=-4,r4.h=2
How you can observe this intersection is empty.
what I did until now it was:
rectangle intersection (rectangle r1, rectangle r2){
r1.x=max(r1.x,r2.x);
r1.y=max(r1.y,r2.y);
r1.w=min(r1.w,r2.w);
r1.h=min(r1.h,r2.h);
return r1;
}
I think the above code it is used when there is an intersection, but when the intersection is empty I do not know. Also, I would like to print a message "empty" when there is no intersection.
thanks!
The method you are using for rectangle intersection does NOT work when rectangles are represented with their width and height.
It could work if you store the rectangles' two opposite corners (instead of one corner and the dimensions) and make sure that the first corner's coordinates are always less than or equal to the second corner, effectively storing min_x, min_y, max_x, and max_y for your rectangles.
I would suggest that you adopt the convention of making sure the rectangles always include their min coordinates and always exclude their max coords.
Assuming you have something not very different from:
struct rectangle {
int x;
int y;
int w;
int h;
};
(or the same using float or double instead of int)
I will assume here that w and h are always positive, if they may be negative, you should first normalize the input rectangle to ensure that they are.
You find the intersection by finding its opposite corners, and ensuring that lower left come before upper right:
rectangle intersection(const rectangle& r1, const rectangle& r2) {
// optionaly control arguments:
if (r1.w < 0 || r1.h < 0 || r2.w < 0 || r2.h < 0) {
throw std::domain_error("Unnormalized rectangles on input");
}
int lowx = max(r1.x, r2.x); // Ok, x coordinate of lower left corner
int lowy = max(r1.y, r2.y); // same for y coordinate
int upx = min(r1.x + r1.w, r2.x + r2.w) // x for upper right corner
int upy = min(r1.y + r1.h, r2.y + r2.h) // y for upper right corner
if (upx < lowx || upy < lowy) { // empty intersection
throw std::domain_error("Empty intersection");
}
return rectangle(lowx, lowy, upx - lowx, upy - lowy);
}
You can normalize a rectangle by forcing positive values for width and height:
rectangle& normalize(rectangle& r) {
if (r.w < 0) {
r.x += r.w;
r.w = - r.w;
}
if (r.h < 0) {
r.y += r.h;
r.h = -r.h;
}
return r;
}
You can then use that in a second function to display the intersection result:
void display_intersection(std::outstream out, rectangle r1, rectangle r2) {
try {
rectangle inter = intersection(normalize(r1), normalize(r2));
out << "(" << inter.x << ", " << inter.y << ") to (";
out << inter.x + inter.w << ", " << inter.y + inter.h << ")" << std::endl;
}
except (std::domain_error& e) {
out << "empty" << std::endl;
}
}
I want to recreate the Enright Test results with OpenVDB as mentioned in the article by Ken Museth.
After setting up OpenVDB I've Created the sphere similarly to the way it was described in the OpenVDB test git.
I have recieved results which are very different than the results shown in the article.
my code is shown below:
openvdb::GridCPtrVec SphereTest(){
openvdb::GridCPtrVec GridVec;
float fGridSize = 512;
int iGridSize = 512;
double w = 1;
openvdb::Vec3f centerEnright(0.35*fGridSize, 0.35*fGridSize, 0.35*fGridSize);
openvdb::FloatGrid::Ptr grid(new openvdb::FloatGrid());
grid->setGridClass(openvdb::GridClass::GRID_LEVEL_SET);
auto tree = grid->treePtr();
auto outside = 5 * w;
auto inside = -outside;
for (int i = 0; i < iGridSize; ++i)
{
for (int j = 0; j < iGridSize; j++)
{
for (int k = 0; k < iGridSize; k++)
{
openvdb::Coord coord(i, j, k);
const openvdb::Vec3f p = grid->transform().indexToWorld(coord);
const float dist = float((p - centerEnright).length() - (0.15*fGridSize));
auto aDist = abs(dist);
if (aDist < outside)
{
if (dist>0)
tree->setValue(coord, dist);
else
tree->setValue(coord, dist);
}
else
{
if (dist>outside)
tree->setValueOff(coord, outside);
else
tree->setValueOff(coord, inside);
}
}
}
}
std::cout << "Active Voxels MV: " << grid->activeVoxelCount() / 1000000.0 << "\n";
double mem = MemInfo::virtualMemUsedByMe();
std::cout << "Memory MB: " << mem / 1000000.0 << "\n";
openvdb::tools::pruneLevelSet(grid->tree());
std::cout << "Active Voxels MV: " << grid->activeVoxelCount() / 1000000.0 << "\n";
double lastmem=mem;
mem = MemInfo::virtualMemUsedByMe();
std::cout << "Memory MB: " << (mem-lastmem) / 1000000.0 << "\n";
GridVec.push_back(grid);}
my results are as follows :
Active Voxels MV: 0.742089
Memory MB: 617.325
after
Active Voxels MV: 0.742089
Memory MB: 56.234
and as one can see it is ten folds bigger from the results in the article.
Results can be seen in Tables II ,III and IV in the article referring to the 512^3 gridsize , with the [6,5,4,3] tree branching. I've reached the almost the same number of active voxels(Table III) , but with significant additional memory consumption table(IV), while the results of Table II are very confusing. am I missing something? or doing something wrong , maybe not activating some kind of compression, or bit quantization as the article states.
also when looking at the generated grid using the viewer it shows a perfect rounded sphere(not voxelized in the boolean manner) , which is what I'm going for.
any thoughts?
thank you
I have 2 rotations represented as yaw, pitch, roll (Tait-Brian intrinsic right-handed). What is the recommended way to construct a single rotation that is equivalent to both of them?
EDIT: if I understand correctly from the answers, I must first convert yaw, pitch, roll to either matrix or quaternion, compose them and then transform the result back to yaw, pitch, roll representation.
Also, my first priority is simplicity, then numerical stability and efficiency.
Thanks :)
As a general answer, if you make a rotation matrix for each of the two rotations, you can then make a single matrix which is the product of the two (order is important!) to represent the effect of applying both rotations.
It is possible to conceive of instances where "gimbal lock" could make this numerically unstable for certain angles (typically involving angles very close to 90 degrees).
It is faster and more stable to use quaternions. You can see a nice treatment at http://www.genesis3d.com/~kdtop/Quaternions-UsingToRepresentRotation.htm - in summary, every rotation can be represented by a quaternion and multiple rotations are just represented by the product of the quaternions. They tend to have better stability properties.
Formulas for doing this can be found at http://en.m.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
UPDATE using the formulas provided at http://planning.cs.uiuc.edu/node102.html , you can adapt the following code to do a sequence of rotations. While the code is written in (and compiles as ) C++, I am not taking advantage of certain built in C++ types and methods that might make this code more elegant - showing my C roots here. The point is really to show how the rotation equations work, and how you can concatenate multiple rotations.
The two key functions are calcRot which computes the rotation matrix for given yaw, pitch and roll; and mMult which multiplies two matrices together. When you have two successive rotations, the product of their rotation matrices is the "composite" rotation - you do have to watch out for the order in which you do things. The example that I used shows this. First I rotate a vector by two separate rotations; then I compute a single matrix that combines both rotations and get the same result; finally I reverse the order of the rotations, and get a different result. All of which should help you solve your problem.
Make sure that the conventions I used make sense for you.
#include <iostream>
#include <cmath>
#define PI (2.0*acos(0.0))
//#define DEBUG
void calcRot(double ypr[3], double M[3][3]) {
// extrinsic rotations: using the world frame of reference
// ypr: yaw, pitch, roll in radians
double cy, sy, cp, sp, cr, sr;
// compute sin and cos of each just once:
cy = cos(ypr[0]);
sy = sin(ypr[0]);
cp = cos(ypr[1]);
sp = sin(ypr[1]);
cr = cos(ypr[2]);
sr = sin(ypr[2]);
// compute this rotation matrix:
// source: http://planning.cs.uiuc.edu/node102.html
M[0][0] = cy*cp;
M[0][1] = cy*sp*sr - sy*cr;
M[0][2] = cy*sp*cr + sy*sr;
M[1][0] = sy*cp;
M[1][1] = sy*sp*sr + cy*cr;
M[1][2] = sy*sp*sr - cy*sr;
M[2][0] = -sp;
M[2][1] = cp*sr;
M[2][2] = cp*cr;
}
void mMult(double M[3][3], double R[3][3]) {
// multiply M * R, returning result in M
double T[3][3] = {0};
for(int ii = 0; ii < 3; ii++) {
for(int jj = 0; jj < 3; jj++) {
for(int kk = 0; kk < 3; kk++ ) {
T[ii][jj] += M[ii][kk] * R[kk][jj];
}
}
}
// copy the result:
for(int ii = 0; ii < 3; ii++) {
for(int jj = 0; jj < 3; jj++ ) {
M[ii][jj] = T[ii][jj];
}
}
}
void printRotMat(double M[3][3]) {
// print 3x3 matrix - for debug purposes
#ifdef DEBUG
std::cout << "rotation matrix is: " << std::endl;
for(int ii = 0; ii < 3; ii++) {
for(int jj = 0; jj < 3; jj++ ) {
std::cout << M[ii][jj] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
#endif
}
void applyRot(double before[3], double after[3], double M[3][3]) {
// apply rotation matrix M to vector 'before'
// returning result in vector 'after'
double sumBefore = 0, sumAfter = 0;
std::cout << "Result of rotation:" << std::endl;
for(int ii = 0; ii < 3; ii++) {
std::cout << before[ii] << " -> ";
sumBefore += before[ii] * before[ii];
after[ii] = 0;
for( int jj = 0; jj < 3; jj++) {
after[ii] += M[ii][jj]*before[jj];
}
sumAfter += after[ii] * after[ii];
std::cout << after[ii] << std::endl;
}
std::cout << std::endl;
#ifdef DEBUG
std::cout << "length before: " << sqrt(sumBefore) << "; after: " << sqrt(sumAfter) << std::endl;
#endif
}
int main(void) {
double r1[3] = {0, 0, PI/2}; // order: yaw, pitch, roll
double r2[3] = {0, PI/2, 0};
double initPoint[3] = {3,4,5}; // initial point before rotation
double rotPoint[3], rotPoint2[3];
// initialize rotation matrix to I
double R[3][3];
double R2[3][3];
// compute first rotation matrix in-place:
calcRot(r1, R);
printRotMat(R);
applyRot(initPoint, rotPoint, R);
// apply second rotation on top of first:
calcRot(r2, R2);
std::cout << std::endl << "second rotation matrix: " << std::endl;
printRotMat(R2);
// applying second matrix to result of first rotation:
std::cout << std::endl << "applying just the second matrix to result of first: " << std::endl;
applyRot(rotPoint, rotPoint2, R2);
mMult(R2, R);
std::cout << "after multiplication: " << std::endl;
printRotMat(R2);
std::cout << "Applying the combined matrix to the intial vector: " << std::endl;
applyRot(initPoint, rotPoint2, R2);
// now in the opposite order:
double S[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
calcRot(r2, S);
printRotMat(S);
calcRot(r1, R2);
mMult(R2, S);
std::cout << "applying rotation in the opposite order: " << std::endl;
printRotMat(R2);
applyRot(initPoint, rotPoint, R2);
}
Output (with #DEBUG not defined - commented out):
Result of rotation:
3 -> 3
4 -> -5
5 -> 4
second rotation matrix:
applying just the second matrix to result of first:
Result of rotation:
3 -> 4
-5 -> -5
4 -> -3
after multiplication:
Applying the combined matrix to the intial vector:
Result of rotation:
3 -> 4
4 -> -5
5 -> -3
Note that these last two give the same result, showing that you can combine rotation matrices.
applying rotation in the opposite order:
Result of rotation:
3 -> 5
4 -> 3
5 -> 4
Now the result is different - the order is important.
If you are familiar with matrix operations, you may try Rodrigues' rotation formula. If you are familiar with quaternions, you may try the P' = q*P*q' approach.
Quaterion math is a bit more complicated to grasp, but code is simpler and faster.