Rotation of points about an axis - c++

currently struggling with a project for my computing class in c++. Being asked to rotate a point in 3d space by 3 angles relative to the 3 axis.
feel like im kinda close on having all the parts needed just struggling to put them together, lecture notes were a bit vague on multiplying matrices :( . any help is appreciated.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
std::cout << "Enter a number for x";
int x;
std::cin >> x;
std::cout << "Enter a number for y";
int y;
std::cin >> y;
std::cout << "Enter a number for z";
int z;
std::cin >> z;
std::cout << "Enter value for Theta";
int theta;
std::cin >> theta;
std::cout << "Enter value for Beta";
int beta;
std::cin >> beta;
std::cout << "Enter value for Gamma";
int gamma;
std::cin >> gamma;
//function allows the insertion of xyz and the three angles
{void RTheta(const double& theta, double array[3][3]);
int array =
{
{cos(theta), sin(theta), 0}, //the matrice for theta values
{sin(theta), cos(theta), 0},
{0,0,1}
};
std::cout << RTheta; //outputs value for theta
}
{
void RBeta(const double& beta, double array[3][3]);
int array =
{
{cos(beta), 0, -sin(beta)}, //the matrice for beta values
{0, 1, 0}, //outputs values for beta
{sin(beta), 0, cos(beta)}
};
std::cout << RBeta;
}
{
void RGamma(const double& gamma, double array[3][3]);
int array =
{
{1,0,0}, //the matrice for gamma
{0,cos(gamma), sin(gamma)}, //outputs values for gamma
{0, -sin(gamma), cos(gamma)}
};
std::cout << RGamma;
}
return 0;
}
the question if this helps: i.imgur.com/eN5RqEe.png

You need to start thinking from an abstraction point of view and not get lost in the details. You need the abstractions Point and Transform and create functions that work with those abstractions.
If you are working with 2D points, use:
struct Point
{
double x;
double y;
};
If you need to work with 3D points, use:
struct Point
{
double x;
double y;
double z;
};
If you are interested only in rotational transforms, you can use the following for 2D transforms:
struct Transform
{
double matrix[2][2];
};
For 3D transforms, you can use:
struct Transform
{
double matrix[3][3];
};
and then add functions to construct points, transforms and performs operations on them. E.g.
Point constructPoint(double x, double y);
Transfrom constructIdentityTransform();
Transfrom constructRotateAroundXTransform(double xrot);
Transfrom constructRotateAroundYTransform(double yrot);
Transfrom constructRotateAroundZTransform(double yrot);
Transform operator*(Transform const& lhs, Transform const& rhs);
Point operator*(Transform const& trans, Point const& p);
I hope this gives you enough information to complete the rest.

Related

opencv FLANN radiusSearch give bad results

I'd like to do radius search to find all valid neighbors, but it seems to give me wrong results. Here is my code
#include "opencv/cv.hpp"
#include <iostream>
#include <vector>
int main () {
// create a group of points
std::vector<cv::Point2f> points;
points.emplace_back(438.6, 268.8);
points.emplace_back(439.1, 268.6);
points.emplace_back(438.2, 268.1);
points.emplace_back(498.3, 285.9);
points.emplace_back(312.9, 245.9);
points.emplace_back(313.4, 245.7);
points.emplace_back(313.1, 245.5);
points.emplace_back(312.5, 245.4);
points.emplace_back(297.6, 388.1);
points.emplace_back(291.7, 309.8);
points.emplace_back(194.1, 369.8);
points.emplace_back(439.9, 314.9);
points.emplace_back(312.8, 246.0);
// create features array
cv::Mat_<float> features(0, 2);
for (auto && point : points) {
//Fill matrix
cv::Mat row = (cv::Mat_<float>(1, 2) << point.x, point.y);
features.push_back(row);
}
std::cout << features << std::endl;
cv::flann::Index flann_index(features, cv::flann::KDTreeIndexParams());
std::vector<float> query{ 300.6f, 268.8f };
std::vector<int> ind;
std::vector<float> d;
unsigned int max_neighbours = 10;
// Here I deliberately increase the radius to contain all the points
double radius = 500.0;
flann_index.radiusSearch(query, ind, d, radius, max_neighbours,
cv::flann::SearchParams());
}
Output of ind is [0,0,0,0,0,0,0,0,0,0], all zeros, which is unexpected.
Anyone knows why?
=-=-=-=-=-=-=-=-=-=-= Update
int main() {
// create a group of points
std::vector<cv::Point2f> points;
points.emplace_back(438.6, 268.8);
points.emplace_back(439.1, 268.6);
points.emplace_back(438.2, 268.1);
points.emplace_back(498.3, 285.9);
points.emplace_back(312.9, 245.9);
points.emplace_back(313.4, 245.7);
points.emplace_back(313.1, 245.5);
points.emplace_back(312.5, 245.4);
points.emplace_back(297.6, 388.1);
points.emplace_back(291.7, 309.8);
points.emplace_back(194.1, 369.8);
points.emplace_back(439.9, 314.9);
points.emplace_back(312.8, 246.0);
// create features array
cv::Mat_<float> features(0, 2);
for (auto && point : points) {
//Fill matrix
cv::Mat row = (cv::Mat_<float>(1, 2) << point.x, point.y);
features.push_back(row);
}
std::cout << features << std::endl;
cv::flann::GenericIndex<cvflann::L2<float> > index(features, cvflann::KDTreeIndexParams());
std::vector<float> query(438.6f, 268.8f);
std::vector<int> ind;
std::vector<float> d;
index.radiusSearch(query, ind, d, 45.f, cvflann::SearchParams());
// I can print std::vector by some method, the reader may not, so I comment this line
//std::cout << d << std::endl;
}
As cv::flann::Index is deprecated, I change to new API, but this time, the program just doesn't work anymore.
If you check the example of the plain FLANN I had used here, you would see that they call buildIndex(), which you don't. Could that be?
Try:
cv::flann::Index flann_index(features, cv::flann::KDTreeIndexParams());
flann_index.buildIndex();
You have to set the size of ind and d.
I encountered this issue, and the solution is that radius must be specified as radius squared (^2). And the length of ind and d will be set by max_neighbors, but the return of radiusSearch must be checked to find out which is less, num_found or max_neighbours;
double radius = 500.0;
int num_found = flann_index.radiusSearch(query, ind, d, radius*radius, max_neighbours, cv::flann::SearchParams());
num_found = min(num_found,(int)ind.size()); // check correct size
for(int i=0; i<num_found; i++) { ... ind[i] ... d[i] ... }
in my case, i also had to adjust the index and search parameters to return correct results:
flann::KDTreeIndexParams indexParams(128);
flann::SearchParams searchParams(1024,0.0,true);

Convert class to fixed-length float array

How can I convert the following class to a fixed-length float array?
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
float x, y, z;
};
For example, I would like to use it like so:
Vertex v(0, 1, 0);
float arr[3] = v; // How to convert here?
Thanks!
Edit:
I should have added some background information before posting this question.
The reason why I'm using C-style arrays is because I want to combine the high level vertex objects into a vertex array for rendering with OpenGL, which as far as I know requires a collection of raw arrays (float[3]) or structs.
For that purpose I think user2079303's answer is the best option. However, if a more elegant solution exists that would be even better. :)
#include <iostream>
#include <array>
using namespace std;
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3>() const {
return {x,y,z};
}
/* See #user2079303's answer for a compile-time check of the array dimension */
void fillArray(float arr[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
float x, y, z;
};
int main() {
Vertex v(1,1.4,2);
array<float, 3> arr = v;
float arr2[3];
v.fillArray(arr2);
for (int i = 0; i < 3; i++) {
cout << arr[i] << " " << arr2[i] << endl;
}
return 0;
}
Live Demo
std::array is as efficient as using a C-style array, no performance is lost. You can also use std::vector instead.
You can't just return and copy an array, even in C. That's why if you absolutely want to use a C array, you have to have a function like fillArray.
A class cannot be convertible to a (raw) array, because the cast operator would have to return an array, which is not allowed in c++. Furthermore, arrays cannot be copy-initialized anyway.
What you can do is define an array, and pass it to a function that populates the array according to the contents of an object:
void Vertex::fill_arr(float (&arr)[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
// usage
Vertex v(1, 2, 3);
float arr[3];
v.fill_arr(arr);
Another option is to use std::array which can be returned and copy-initialized normally.
You have many options, and it which you choose depends a lot on context. Here are four different ways to "convert" your vertex:
class Vertex
{
public:
Vertex(float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3> () const {
return {x, y, z};
}
array<float, 3> array_copy() const {
return {x, y, z};
}
unique_ptr<float[]> c_array_copy() const {
return unique_ptr<float[]>(new float[3]{ x, y, z });
}
void copy_into(float in[3]) const {
in[0] = x;
in[1] = y;
in[2] = z;
}
float x, y, z;
};
First, you can just cast the class using the () operator:
cout << "Direct access" << endl;
auto as_array = (array<float, 3>)vertex;
cout << as_array[0] << as_array[1] << as_array[2] << endl;
Second, you can let copy semantics to some work for you with array_copy():
cout << "Get a copy" << endl;
auto as_copy = vertex.array_copy();
cout << as_copy[0] << as_copy[1] << as_copy[2] << endl;
Third, you can get a more c-style array copy with a unique pointer to a dynamically allocated array:
cout << "Get a c-style copy" << endl;
auto as_c_copy = vertex.c_array_copy();
cout << as_c_copy[0] << as_c_copy[1] << as_c_copy[2] << endl;
Finally, you can copy into an out-parameter:
cout << "Copy onto an out-parameter" << endl;
float copied[3];
vertex.copy_into(copied);
cout << copied[0] << copied[1] << copied[2] << endl;
As I say, which you choose really depends on context and performance requirements.
Note that in no case can you just return a c-style array.
You can define a conversion operator to construct your array. Also I would suggest using a std::array instead of a raw array.
#include <array>
class Vertex
{
public:
Vertex(float x = 0.0f, float y = 0.0f, float z = 0.0f)
: x(x), y(y), z(z)
{}
float x;
float y;
float z;
operator const std::array<float, 3>() const
{
return {x, y, z};
}
};
int main()
{
Vertex v(0.0f, 1.0f, 0.0f);
std::array<float, 3> arr = v;
}

Confusion over Initializing variables and changing them in C++

I'm trying to make a program that will allow the user to enter in a heighth and width of a rectangle, and display the area, however every step of my program is done using functions as part of the assignment.
The issue I'm having is that I have the variables assigned and intialized, though I'm not sure how to overwrite them with user inputted data. If I don't initialize the variables at all the program will not run. I was hoping someone could tell me what I'm doing wrong. My code is:
#include <iostream>
using namespace std;
double getWidth(int x);
double getLength(int y);
double getArea(double x, double y, double a);
double displayData(double a);
int main()
{
int x = 0, y = 0, a = 0;
getWidth(x);
getLength(y);
getArea(x, y, a);
displayData(a);
system("pause");
return 0;
}
double getWidth(int x)
{
cout << "Please enter the width: ";
cin >> x;
return x;
}
double getLength(int y)
{
cout << "Please enter the length: ";
cin >> y;
return y;
}
double getArea(double x, double y, double a)
{
a = x*y;
return a;
}
double displayData(double a)
{
cout << a << endl;
return a;
}
There are two ways of passing variables. Method number one is to pass by value. This is the most common method, and it is the one your program is doing. In this method, a copy of the data in the variable is being made and supplied to the function. Your function only changes the copy and not the original variable.
The second method is to pass by reference. When passing by reference, your function effectively has a pointer to the original variable and can thus change it. To pass by reference, put in an ampersand (&) in front of the variable in the function header. Note in the code below that it is not necessary to pass x and y to getArea by reference because getArea only needs to read these variables not write to them.
This however will introduce a new problem for you. When you pass by value it is possible to change the variable type to a larger type without an explicit cast. This is not possible with passing by reference because the different parts of the program would then be trying to treat the variable as a different type. i.e. main wants to write to/read from a as if it is an integer and getArea wants to write to/read from a as if it is a double. These two data types have different sizes and and different formats so this is not possible. Thus you have to declare a is a double in main.
#include <iostream>
using namespace std;
double getWidth(int &x);
double getLength(int &y);
double getArea(double x, double y, double &a);
double displayData(double a);
int main()
{
int x = 0, y = 0;
double a;
getWidth(x);
getLength(y);
getArea(x, y, a);
displayData(a);
system("pause");
return 0;
}
double getWidth(int &x)
{
cout << "Please enter the width: ";
cin >> x;
return x;
}
double getLength(int &y)
{
cout << "Please enter the length: ";
cin >> y;
return y;
}
double getArea(double x, double y, double &a)
{
a = x*y;
return a;
}
double displayData(double a)
{
cout << a << endl;
return a;
}
You seem to be confusing a few different concepts. You should either be passing references and assigning them within the functions, or passing less values and assigning them to some variable in main. For example, your getWidth should be:
double getWidth() {
double w;
cin >> w;
return w;
}
and in your main you should have:
int main() {
/* ... */
double width = getWidth();
/* ... */
}
And so on for the others as well. You should be looking into references and pointers in C++ as well, that would be the other way that you could do this (and you are seemingly confused about). Finally you should definitely find an introduction to functions in some intro to C++ book, as someone said above.

How to write a separate function that computes scalar product?

I am aware there exists a C++ function template (std::inner_product), but I want to try writing my own. Here's some code I found but it runs in the main function:
#include <iostream>
using namespace std;
int main(){
float vectorA[3], vectorB[3], scalar=0.0;
int i;
// Get input vectors from user.
cout << "Enter elements of first vector: " << endl;
for(i=0;i<3;i++)
{
cin >> vectorA[i];
}
cout << "Enter elements of second vector: " << endl;
for(i=0;i<3;i++)
{
cin >> vectorB[i];
}
// Calculate scalar product.
for(i=0;i<3;i++)
{
scalar = scalar + (vectorA[i] * vectorB[i]);
}
// Output result.
cout << "The scalar product is " << scalar << endl;
return 0;
}
Next, I want to write this into a separate reusable function that I can call from my main loop. This is the best I could come up with.
float scalarProduct(float a1, float a2, float a3, float b1, float b2, float b3) {
float vectorA[3], vectorB[3], scalar;
vectorA[0]=a1;
vectorA[1]=a2;
vectorA[2]=a3;
vectorB[0]=b1;
vectorB[1]=b2;
vectorB[2]=b3;
for(int i=0;i<3;i++) // Calculate scalar product.
{
scalar = scalar + (vectorA[i] * vectorB[i]);
}
return scalar;
}
int main() {
cout << scalarProduct(1,2,3,4,5,6);
}
So my questions are:
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
scalar = scalar + (vectorA[i] * vectorB[i]);
The program still runs and computes the correct answer but how can I make this warning go away?
Question
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.
Change the function to accept two arrays as argument. For the sake of safety, also pass the number of elements in the array.
float scalarProduct(float a[], float b[], size_t num);
Change the function to accept two std:vectors as argument.
float scalarProduct(std::vector<float> const& a, std::vector<float> const& b);
Change the function to accept two std:arrays as argument.
float scalarProduct(std::array<float, 3> const& a, std::array<float, 3> const& b);
In all of these cases, you can access the elements of the collection using the array syntax.
float scalarProduct(std::array<float, 3> const& a, std::array<float, 3> const& b)
{
// Initialize scalar to 0
float scalar = 0.0f;
for(int i=0;i<3;i++) // Calculate scalar product.
{
scalar = scalar + (a[i] * b[i]);
}
return scalar;
}
The implementations will be a little different if you use the other signatures but not too different.
Question
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
I have already added the line to initialize scalar. Without that, the initial value of scalar is not predictable. Also, accessing the value of an uninitialized variable is cause of undefined behavior.
How can I pass an array into this function? There must be a better way than having six parameters but I can't figure out how.quote
To pass an array into your function, simply do:
float scalarProduct(float arr[6])
In your main(), it will look like:
float array[6] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
cout << scalarProduct(array);
From there you can use your array like:
vectorA[0]=arr[0];
vectorA[1]=arr[1];
vectorA[2]=arr[2];
vectorB[0]=arr[3];
vectorB[1]=arr[4];
vectorB[2]=arr[5];
When I run the program in Xcode, I get the warning 'Variable scalar may be uninitialised when used here' at the line
Maybe try and initialize scalar with an initial value:
float scalar = 0.0;
Just have your function take in a reference to a vector (or array as stated by Hayden). A vector is better as you don't have to hard-code the size of the vector.
Also, it is useful to have a template function for this case.
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
T scalarProduct(const vector<T>& a, const vector<T>& b)
{
// Check that the size of a and b match here.
// If not, do what you deem is necessary.
T product = 0; // Not initializing variable is cause of your warning.
for (int i = 0; i < a.size(); i++)
product += a[i] * b[i];
return product;
}
int main(void)
{
// Compile for c++ 11
// vector<float> a = {1.0, 2.0, 3.0};
// vector<float> b = {1, 1, 1};
// Else
vector<float> a;
vector<float> b;
a.push_back(1);
a.push_back(2);
a.push_back(3);
b.push_back(1);
b.push_back(1);
b.push_back(1);
cout << scalarProduct<float>(a, b) << endl;
return 0;
}

Why wont the vector be empty?

I am wondering why this wont recognize the vector is empty and supply vector pStack with double start? The object of the program is just to simply supply the stack vector with 50 the first time around when it is empty. Then once it is supplied with the starting amount it should subtract with the user input (being bet). Then since its a vector it carries over the old sum into the 2nd time around so it can be subtracted with the user input of bet again.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Bet
{
public:
void set_stack(double n);
void set_bet(double n);
double analyze();
double get_stack();
double get_bet();
private:
double pCount;
double bet;
};
double Bet::analyze()
{
double p = pCount;
double b = bet;
double z = p - b;
return z;
}
void Bet::set_bet(double n)
{
bet = z;
}
double Bet::get_bet()
{
return bet;
}
void Bet::set_stack(double n)
{
pCount = n;
}
double Bet::get_stack()
{
return pCount;
}
double start = 50; // Start needs to go inside of pStack
double bbet;
vector<double> pStack(1);
int main()
{
bool con = true;
while(con){
if(pStack.empty()){
pStack.push_back(start); // pStack should be supplied with start when empty
}
double adjst = pStack[0];
Bet rr;
rr.set_stack(adjst);
pStack.clear();
cout << "Enter min 1 Bet: ";
cin >> bbet;
rr.set_bet(bbet);
double aStack = rr.analyze();
pStack.push_back(aStack);
rr.set_stack(aStack);
double newStack = rr.get_stack();
cout << "Stack: " << newStack << endl;
cout << "Bet: " << bbet << endl;
}
system("pause");
return 0;
}
vector<double> pStack(1);
You are initializing your vector with it having an initial size of 1, that's why your pStack.empty() check returns false.
Do this instead to make its initial state empty.
vector<double> pStack;
Also, remove the empty() check and hoist your push_back outside your while loop.
bool con = true;
pStack.push_back(start);
while(con){
...
You might also want to reconsider your usage of global variables. As far as I can see, you can just put start, bbet and pStack inside main().
You are using the fill constructor. This line will initialize the vector to 1 element, default constructed.
vector<double> pStack(1);
If you wanted the vector to start out empty, you should just use the default constructor.
vector<double> pStack;
When you define the pStack vector you use the constructor that takes an integer that represent the number of elements to allocate.
vector<double> pStack(1);
As a result your vector will have 1 default-initialized element.
To create an empty vector do this:
vector<double> pStack;