I'm trying to understand the Eigen library's "eulerAngles" function, and I have some test code that doesn't make sense.
My testing includes determining if the Euler function call "eulerAngles(0, 1, 2)" corresponds to a "XYZ" Euler sequence of the static frame. For Eigen's column major matrix multiplication, it should correspond to "Z * Y * X". I have confirmed that with some simple tests, but for negative angles around the X axis I don't understand the results. Instead of using a Euler 3 Angle constructor, I'm using the "AngleAxisd" function:
rot3x3 = AngleAxisd( -M_PI, Vector3d::UnitX() );
Vector3d vec = rot3x3.eulerAngles(0, 1, 2);
For positive angles around the X axis, it works the way I expect. For the -M_PI angle (equivalent to 180 degrees), I'm seeing the following:
Euler angles: -0, 3.14159, -3.14159
I expect the first element in the array to be near -π, and the other two to be near zero. I expect the range of the first and last angles to be ±π, and the middle angle to be ±π/2. The middle angle is out of range.
The program is below:
#include "stdafx.h"
#include <iostream>
#include "<Eigen\Dense"
#include "<unsupported\Eigen\MatrixFunctions"
using namespace std;
using namespace Eigen;
int main(int argc, char* argv[])
{
Matrix3d rot3x3;
rot3x3 = AngleAxisd( -M_PI, Vector3d::UnitX() );
cout << "Here is rot3x3:" << endl << rot3x3 << endl << endl;
Vector3d vec = rot3x3.eulerAngles(0, 1, 2); // => 1-2-3 => XYZ => Z*Y*X
cout << "Euler angles: " << vec.x() << ", "
<< vec.y() << ", "
<< vec.z() << endl << endl;
system("pause");
return 0;
}
The output is:
Here is rot3x3:
1 0 0
0 -1 1.22465e-016
0 -1.22465e-016 -1
Euler angles: -0, 3.14159, -3.14159
This result is equivalent to a -π around the X axis (and it is the same as a positive π rotation around the X axis as well). Shouldn't the middle angle though be in the range that is equivalent to ±90 degrees?
Euler angles are not uniquely defined. In case of ambiguity, eulerAngles always pick the solution that minimizes the first angles. See also the following bug entries for related discussions: 609, 801, 947.
Related
I am trying a simple test: compute the intersection of 2 segments with Boost Geometry. It does not compile. I also tried with some variations (int points instead of float points, 2D instead of 3D) with no improvement.
Is it really possible that boost doesn't implement segment intersection ? Or what did I do wrong ? Missing some hpp ? Confusion between algorithms "intersects" & "intersection" ?
The code is very basic:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
typedef boost::geometry::model::point<float, 3, boost::geometry::cs::cartesian> testPoint;
typedef boost::geometry::model::segment<testPoint> testSegment;
testSegment s1(
testPoint(-1.f, 0.f, 0.f),
testPoint(1.f, 0.f, 0.f)
);
testSegment s2(
testPoint(0.f, -1.f, 0.f),
testPoint(0.f, 1.f, 0.f)
);
std::vector<testPoint> output;
bool intersectionExists = boost::geometry::intersects(s1, s2, output);
But I got the following errors at compile time by Visual:
- Error C2039 'apply' n'est pas membre de 'boost::geometry::dispatch::disjoint<Geometry1,Geometry2,3,boost::geometry::segment_tag,boost::geometry::segment_tag,false>' CDCadwork C:\Program Files\Boost\boost_1_75_0\boost\geometry\algorithms\detail\disjoint\interface.hpp 54
- Error C2338 This operation is not or not yet implemented. CDCadwork C:\Program Files\Boost\boost_1_75_0\boost\geometry\algorithms\not_implemented.hpp 47
There are indeed two problems:
you're intersecting 3D geometries. That's not implemented
Instead you can do the same operation on a projection.
you're passing an "output" geometry to intersects (which indeed only returns the true/false value as your chosen name intersectionExists suggested). In the presence of a third parameter, it would be used as a Strategy - a concept for which output obviously doesn't satisfy.
Note intersection always returns true: What does boost::geometry::intersection return - although that's not part of the documented interface
Since your geometries are trivially projected onto 2d plane Z=0:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using Point = bgm::point<float, 2, bg::cs::cartesian>;
using Segment = bgm::segment<Point>;
int main() {
Segment s1{{-1, 0}, {1, 0}};
Segment s2{{0, -1}, {0, 1}};
bool exists = bg::intersects(s1, s2);
std::vector<Point> output;
/*bool alwaysTrue = */ bg::intersection(s1, s2, output);
std::cout << bg::wkt(s1) << "\n";
std::cout << bg::wkt(s2) << "\n";
for (auto& p : output) {
std::cout << bg::wkt(p) << "\n";
}
return exists? 0:1;
}
Prints
LINESTRING(-1 0,1 0)
LINESTRING(0 -1,0 1)
POINT(0 0)
I am completely new to Computational Geometry. I want to generate convex hull of a set of points and then get plane equations for the generated convex polyhedron so that I can check inclusion/exclusion of points. I have followed the docs and tried the whole procedure probably a dozen times but there is always some issue. Maybe I'm missing some subtle point here. The whole procedure is as follows. I have the following plot, generated in Mathematica.
I want to include every point that is on the plot inside a convex hull. So I take all the points lying on all corners of both planes and the origin (Maybe that's the problem. Maybe there is a way to properly choose points so that all points on the plot are covered). The points for this specific plot are as follows. Note that the points are generated using infinite precision so they are exact values.
pts = {
{-24298771/25000000000,-223461425901/50000000000,0},
{11285077/10000000000,-223461425901/50000000000,0},
{-24298771/25000000000,0,0},
{-24298771/25000000000,-11285077/10000000000,0},
{-24298771/25000000000,120551411529/25000000000,-24298771/25000000000},
{11285077/10000000000,120551411529/25000000000,11285077/10000000000},
{11285077/10000000000,0,11285077/10000000000},
{-24298771/25000000000,24298771/25000000000,-24298771/25000000000},
{0,0,0}
};
Then, I use the following CGAL program to generate the convex hull and plane equations. Again, trying to keep things in infinite precision.
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/GMP/Gmpq_type.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/number_utils.h>
#include <unistd.h>
#include <iomanip>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Plane_3 Plane_3;
typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Side_of_triangle_mesh<Polyhedron_3, Kernel> Point_inside;
struct Plane_equation {
template <class Facet>
typename Facet::Plane_3 operator()( Facet& f) {
typename Facet::Halfedge_handle h = f.halfedge();
typedef typename Facet::Plane_3 Plane;
return Plane( h->vertex()->point(),
h->next()->vertex()->point(),
h->next()->next()->vertex()->point());
}
};
Point_3 create_point(std::vector<std::string> points) {
auto x = points[0], y = points[1], z = points[2];
Point_3 p;
std::istringstream input(x + " " + y + " " + z);
input >> p;
return p;
}
std::vector<std::string> create_coords_from_line(std::string line) {
std::vector<std::string> points;
std::istringstream stream(line);
std::string pt;
getline(stream, pt, ' ');
points.push_back(pt);
getline(stream, pt, ' ');
points.push_back(pt);
getline(stream, pt);
points.push_back(pt);
return points;
}
int main() {
std::vector<Point_3> points;
std::string line;
for (auto i = 0; i < 9; ++i) {
getline(std::cin, line);
points.push_back(create_point(create_coords_from_line(line)));
}
Polyhedron_3 poly;
CGAL::convex_hull_3(points.begin(), points.end(), poly);
// CGAL::draw(poly);
std::transform(poly.facets_begin(), poly.facets_end(), poly.planes_begin(), Plane_equation());
CGAL::set_pretty_mode(std::cout);
for (auto it = poly.planes_begin(); it != poly.planes_end(); ++it) {
if (isatty(fileno(stdin))) {
std::cout << "A = " << it->a().exact() << "\n";
std::cout << "B = " << it->b().exact() << "\n";
std::cout << "C = " << it->c().exact() << "\n";
std::cout << "D = " << it->d().exact() << "\n";
std::cout << "\n";
} else {
std::cout << it->a().exact() << " " << it->b().exact() << " "
<< it->c().exact() << " " << it->d().exact() << "\n";
}
}
return EXIT_SUCCESS;
}
Now, in order to make sure that the generated equations are correct and cover all the points, I create a Z3py script. In that, f is the function used to generate the plot, g is the conjunction of all plane equations with proper inequality (<, =, >). Then I check if f ---> g. I use the theory of reals for infinite precision. But it always comes up with a counter-example. And these counter examples are always on some edge of the plane. Here are a couple of pictures where red circle indicates the location of counterexample. This is a different plot from the one above but the process is the same. Just the input values to f is different.
Now, I don't really need infinite precision for my problem. But I would like to make sure that the procedure works with infinite precision so that I can be confident about correctness. But then I tried with CPLEX, which uses only 64-bits, and with that too, counterexamples were generated, in similar fashion to Z3. Here's an example
Now I have no idea in which step of the process am I making a mistake. My suspicion is the selection of initial points for convex hull. It would be great if someone can help me find the convex hull properly. As far as I have read, the convex hull algorithms are exact if infinite precision is used. That's why I didn't use Mathematica's convex hull feature, because it is not using infinite precision.
EDIT: There are two smaller planes which Mathematica is failing to show, as shown below. I want all points on those planes to be selected too. But the endpoints of the smaller planes coincide with the endpoints of larger planes. That's why I have taken only the corners of larger planes.
EDIT 2: Due to the range of y being so large compared to the other two variables, the convex hull generated for the above specified points looks just like a single line.
However, after diving the y values by 1000, we can see a clearer picture.
I've encountered a strange thing in CGAL. I have a line and a point that is supposed to be on this line. This code
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
int main( ) {
CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);
std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
std::cout << l.y_at_x(-3.0).exact() << std::endl;
return 0;
}
Produces output:
0
36028797018963967/18014398509481984
OK, maybe the Exact_predicates_exact_constructions_kernel is not good enough... (WHY?)
I tried to use kernel defined with CGAL::Quotient instead:
typedef CGAL::Quotient<CGAL::MP_Float> NT;
typedef CGAL::Cartesian<NT> Kernel;
int main( ) {
CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);
std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
std::cout << l.y_at_x(-3.0) << std::endl;
return 0;
}
And the result is even more mysterious to me:
0
2/1
Am I missing something or is it a bug?
When you construct the line from 0.2, two conversions happen. The string "0.2" is converted to a double by the compiler. Then, this double is converted to the number type of the kernel (an exact rational in this case).
The problem is that the conversion of 0.2 to double is not exact, since 0.2 is a rational that is not representable by a floating-point value, so, some inexactness is introduced. CGAL cannot do anything about this.
If you need to represent 0.2 exactly, you need to use something like :
CGAL::Line_2<Kernel> l(NT(2)/NT(10), 1.0, NT(-14)/NT(10));
Alternatively, scale your problem by a power of ten so that all your coordinates becomes integers.
It is also possible that some rational number types have the ability to construct directly from a string representing a rational number without any rounding, but I don't think CGAL::Quotient<MP_Float> can.
In the last week i have been programming some 2-dimensional convolutions with FFTW, by passing to the frequency domain both signals, multiplying, and then coming back.
Surprisingly, I am getting the correct result only when input size is less than a fixed number!
I am posting some working code, in which i take simple initial constant matrixes of value 2 for the input, and 1 for the filter on the spatial domain. This way, the result of convolving them should be a matrix of the average of the first matrix values, i.e., 2, since it is constant. This is the output when I vary the sizes of width and height from 0 to h=215, w=215 respectively; If I set h=216, w=216, or greater, then the output gets corrupted!! I would really appreciate some clues about where could I be making some mistake. Thank you very much!
#include <fftw3.h>
int main(int argc, char* argv[]) {
int h=215, w=215;
//Input and 1 filter are declared and initialized here
float *in = (float*) fftwf_malloc(sizeof(float)*w*h);
float *identity = (float*) fftwf_malloc(sizeof(float)*w*h);
for(int i=0;i<w*h;i++){
in[i]=5;
identity[i]=1;
}
//Declare two forward plans and one backward
fftwf_plan plan1, plan2, plan3;
//Allocate for complex output of both transforms
fftwf_complex *inTrans = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex)*h*(w/2+1));
fftwf_complex *identityTrans = (fftwf_complex*) fftw_malloc(sizeof(fftwf_complex)*h*(w/2+1));
//Initialize forward plans
plan1 = fftwf_plan_dft_r2c_2d(h, w, in, inTrans, FFTW_ESTIMATE);
plan2 = fftwf_plan_dft_r2c_2d(h, w, identity, identityTrans, FFTW_ESTIMATE);
//Execute them
fftwf_execute(plan1);
fftwf_execute(plan2);
//Multiply in frequency domain. Theoretically, no need to multiply imaginary parts; since signals are real and symmetric
//their transform are also real, identityTrans[i][i] = 0, but i leave here this for more generic implementation.
for(int i=0; i<(w/2+1)*h; i++){
inTrans[i][0] = inTrans[i][0]*identityTrans[i][0] - inTrans[i][1]*identityTrans[i][1];
inTrans[i][1] = inTrans[i][0]*identityTrans[i][1] + inTrans[i][1]*identityTrans[i][0];
}
//Execute inverse transform, store result in identity, where identity filter lied.
plan3 = fftwf_plan_dft_c2r_2d(h, w, inTrans, identity, FFTW_ESTIMATE);
fftwf_execute(plan3);
//Output first results of convolution(in, identity) to see if they are the average of in.
for(int i=0;i<h/h+4;i++){
for(int j=0;j<w/w+4;j++){
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(w*h*w*h) << endl;
}
}std::cout<<endl;
//Compute average of data
float sum=0.0;
for(int i=0; i<w*h;i++)
sum+=in[i];
std::cout<<"Mean of input was " << (float)sum/(w*h) << endl;
std::cout<< endl;
fftwf_destroy_plan(plan1);
fftwf_destroy_plan(plan2);
fftwf_destroy_plan(plan3);
return 0;
}
Your problem has nothing to do with fftw ! It comes from this line :
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(w*h*w*h) << endl;
if w=216 and h=216 then `w*h*w*h=2 176 782 336. The higher limit for signed 32bit integer is 2 147 483 647. You are facing an overflow...
Solution is to cast the denominator to float.
std::cout<<"After convolution, component (" << i <<","<< j << ") is " << identity[j+i*w]/(((float)w)*h*w*h) << endl;
The next trouble that you are going to face is this one :
float sum=0.0;
for(int i=0; i<w*h;i++)
sum+=in[i];
Remember that a float has 7 useful decimal digits. If w=h=4000, the computed average will be lower than the real one. Use a double or write two loops and sum on the inner loop (localsum) before summing the outer loop (sum+=localsum) !
Bye,
Francis
I want to find the maximum values and indices by row of a matrix. I based this on an example on the eigen website (example 7).
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf mat(2,4);
mat << 1, 2, 6, 9,
3, 1, 7, 2;
MatrixXf::Index maxIndex;
VectorXf maxVal = mat.rowwise().maxCoeff(&maxIndex);
std::cout << "Maxima at positions " << endl;
std::cout << maxIndex << std::endl;
std::cout << "maxVal " << maxVal << endl;
}
Problem here is that my line
VectorXf maxVal = mat.rowwise().maxCoeff(&maxIndex);
is wrong. The original example has
float maxNorm = mat.rowwise().sum().maxCoeff(&maxIndex);
i.e. there is an additional reduction .sum() involved. any suggestions? I guess I just want the eigen equivalent to what in matlab I would write as
[maxval maxind] = max(mymatrix,[],2)
i.e. find maximum value and it's index over the second dimension of mymatrix and return in a (nrow(mymatrix),2) matrix.
thanks!
(sent to the eigen list as well, sorry for cross-posting.)
My guess is that this is not possible without using a for loop using the current api. As you said yourself, you can get the vector of maximum row values using
VectorXf maxVal = mat.rowwise().maxCoeff();
As far as I can tell from the API Documentation for maxCoeff() it will only write back a single index value. Following code (untested) should give you what you want:
MatrixXf::Index maxIndex[2];
VectorXf maxVal(2);
for(int i=0;i<2;++i)
maxVal(i) = mat.row(i).maxCoeff( &maxIndex[i] );
Besides the "for loop" solution by Jakob, you could also use libigl's igl::mat_max which functions like MATLAB's row-/column-wise max
Eigen::MatrixXf mat(2,4);
mat << 1, 2, 6, 9,
3, 1, 7, 2;
Eigen::VectorXi maxIndices;
Eigen::VectorXf maxVals;
igl::mat_max(mat,2,maxVals,maxIndices);
Then maxVals would contain [9;7] and maxIndices would contain [3;2].