I am creating a Discrete Element Method simulation program and I am using CGAL to describe the polyhedrons. From reading literature I was planning to do my differential equations for rotation with Quaternions due to the better numerical stability and lack of gimbal lock. However CGAL does not seem to support rotation based on quaternions. (Please tell me if I am incorrect here) I find it a bit surprising that this seems to be missing, certainly since CGAL likes to be absolute in its accuracy which seems to fit well with the numerical stability of quaternions.
Question: Can I somehow combine Boost Quaternions with CGAL or is there any easy way to implement this. And if so, would this be a logical idea to try?
The other options I think I have are:
writing my differential equations for the affine rotation used is CGAL and deal with the downsides there.
store the orientation as an affine rotation matrix and convert it to Quaternions and use this in the diff. equations. Obviously I am worried about the needed conversion step here every timestep.
Any suggestions or other options that I might think of are greatly appreciated.
First Option: Use the Aff_transformation_3 class
CGAL does not provide a quaternion class, it does provide the Aff_transformation_3 class though. Which you could easily use like this:
CGAL::Surface_mesh<Kernel> P;
std::transform( P.points_begin(), P.points_end(), P.points_begin(), yourAffineTransformation);
for defining the transformation matrix see this.
Second Option: Use Quaternions
If you want to use quaternions you would need to construct one with an external library. For example you could use Eigen:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> //or whichever kernel suits your needs
#include <CGAL/Surface_mesh.h>
#include <Eigen/Geometry>
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Polyhedron = CGAL::Surface_mesh<Kernel>;
using Point = CGAL::Point_3<Kernel>;
// define the function that rotates your mesh
template <typename Vect, typename Quaternion>
void rotateCGALPolyhedron(Polyhedron P, Vect to_rotation_center,
Quaternion quat) {
for (auto vi : P.vertices()) {
Point p = P.point(vi);
// translate your point to the rotation center. In your case this would be
// the center of mass of the Polyhderon
Vect V(p[0] - to_rotation_center[0], p[1] - to_rotation_center[1],
p[2] - to_rotation_center[2]);
// construct the translation vector that moves your point to the rotated
// position
Vect v = quat * V; //the Vect operator*(Quaternion, Vect) must be implemented!! If you use Eigen::Quaternion you could use Eigen::Vector3d
// retranslate the point back to its initial position and translate it using
// the previously created translation vector
P.point(size_t(vi)) =
Point(to_rotation_center[0] + v[0], to_rotation_center[1] + v[1],
to_rotation_center[2] + v[2]);
}
}
int main() {
// define your rotation using eigen's quaternion class
Eigen::Quaternion<double> quad(..);
Eigen::Vector_3d centerOfMass; //find the center of mass of the mesh you want to rotate
rotateCGALPolyhedron(P.vertices.begin(), P.vertices.end(), centerOfMass,
quad);
return 0;
}
As you can see since cgal does not have an implementation for quaternions if you want to use quaternions the code is lengthy compared to the Aff_transformation_3 case.
Related
I do not know how to approach this math problem. Any hint would be much appreciated. Before I could solve such problem using Atan2 method to get two vector angles, when axes c and a are orthogonal.
Problem: there are two non orthogonal to each other vectors c and a. I need to rotate one time around vector c then around vector a to obtain vector v orientation.
Question: how can I get c and a vector rotations, when I only know vector v orientation?
In the image below, c and a vector rotations are both 0.
I was using atan2 for orthogonal system to get two rotations, but in this cases axis A is not perpendicular to C.
double RotationC = Math.Atan2(V_.X, V_.Y);
double RotationA = Math.Atan2(Math.Sqrt(V_.X * V_.X + V_.Y * V_.Y), V_.Z);
I want to extract the three first values of a Vector4 type in Eigen, into a Vector3 type. So far I am doing it in a for-loop. Is there a smarter way to do it?
The .head() member function returns the first n elements of a vector. If n is a compile-time constant, then you can use the templated variant (as in the code example below) and the Eigen library will automatically unroll the loop.
Eigen::Vector4f vec4;
// initialize vec4
Eigen::Vector3f vec3 = vec4.head<3>();
In the Eigen documentation, see Block operations for an introduction to similar operations for extracting parts of vectors and matrices, and DenseBase::head() for the specific function.
The answer of #Jitse Niesen is correct. Maybe this should be a comment on the original question, but I found this question because I had some confusion about Eigen. In case the original questioner, or some future reader has the same confusion, I wanted to provide some additional explanation.
If the goal is to transform 3d (“position”) vectors by a 4x4 homogeneous transformation matrix, as is common in 3d graphics (e.g. OpenGL etc), then Eigen provides a cleaner way to do that with its Transform template class, often represented as the concrete classes Affine3f or Affine3d (as tersely described here). So while you can write such a transform like this:
Eigen::Matrix4f transform; // your 4x4 homogeneous transformation
Eigen::Vector3f input; // your input
Eigen::Vector4f input_temp;
input_temp << input, 1; // input padded with w=1 for 4d homogeneous space
Eigen::Vector4f output_temp = transform * input_temp;
Eigen::Vector3f output = output_temp.head<3>() / output_temp.w(); // output in 3d
You can more concisely write it like this:
Eigen::Affine3f transform; // your 4x4 homogeneous transformation
Eigen::Vector3f input; // your input
Eigen::Vector3f output = transform * input;
That is: an Eigen::Affine3f is a 4x4 homogeneous transformation that maps from 3d to 3d.
Yeah, because you know the size is static (3 elements) you should unroll the loop and copy them explicitly. This optimization might be performed by the compiler already, but it can't hurt to do it yourself just in case.
I am looking for an algorithm to check if a point is coplanar with a given 3D plane, defined out of three vertices, while minimizing floating point errors.
I would like to minimize the amount of multiplications and division to mitigate floating point errors.
My implementation uses floats, I cannot go double.
I cannot use an external library.
My current method suffers from these errors:
I have code defining a plane using the general form of the plane equation:
ax + by + cz + d = 0
I compute these coefficients using three 3D vertices v0, v1 and v2 as follow:
// Pseudo-code to define a plane (with class Vector3 defining a vector in 3D)
Vector3 A = v1 - v0;
Vector3 B = v2 - v0;
Vector3 N = cross_product(A,B); // Normal vector
N.Normalize(); // Unit normal vector storing coefs. a, b, c
float d = dot_product(N,v0);
To check if another vertex p is coplanar, I plug the point into the plane equation and check if the result is 0:
// Pseudo-code for coplanar test:
bool is_coplanar()
{
float res = N.x()*p.x() + N.y()*p.y() + N.z()*p.z() - d;
return true if res is "almost" null; // "almost" is: abs(res)<EPSILON
}
My code fails in this case:
v0 = [-8.50001907, 0, 323]
v1 = [8.49998093, 0, 323]
v2 = [-8.50001907, 1.49999976, 322.598083]
Then the plane coefficients are:
N = [-0, 0.258814692, 0.965926945]
d = 311.994415
And when I plug the point v2, I find a result "far" from 0 (although v2 was used to define the plane):
res = -3.05175781e-05
My EPSILON is currently 1e-5.
Tested on compiler qcc 4.4.2 (QNX Momentics, similar to gcc). With no optimization -O0.
Such geometric predicates suffer in a lot of ways from floating point errors. The only industrial strength solution is to use adaptable arithmetic filtering (provided that a robust implementation of the coplanar test is not covering you).
Luckily such implementations (that would take quite some time to write) are already available. In the previous link the orient3d predicate does what you need: Given 3 plane forming points, decide whether a 4th one lies above,below or on the plane
If such an implementation is an overkill, check the simple one. It offers 4 in total:
orient3dfast() Approximate 3D orientation test. Nonrobust.
orient3dexact() Exact 3D orientation test. Robust.
orient3dslow() Another exact 3D orientation test. Robust.
orient3d() Adaptive exact 3D orientation test. Robust.
Disclaimer: The code listing is provided as a tutorial of the mathematical concepts and programming techniques needed to reach a robust solution. I'm neither suggesting nor implying copy-pasting anything.
My question: How to convert a 3D coordinate on a 2D screen?
I red a lot about that but all my research just showed half answered or even unanswered replies, some were wrong (tested them) so I ask again and try to add as much detail as possible.
Here are the structures we will work with:
struct COORD3D
{
int X;
int Y;
int Z;
};
struct PAN3D//Rotate around these axis
{
float X;
float Y;
float Z;
};
struct COLOR
{
Uint8 R;//RED
Uint8 G;//GREEN
Uint8 B;//BLUE
Uint8 A;//ALPHA
};
struct CAMERA
{
COORD3D Pos;
PAN3D Rot;
float angle;
int RESX;//X Resolution
int RESY;//Y Resolution
};
struct POI
{
COORD3D Pos;
COLOR Col;
};
struct OBJECT
{
COORD3D Pos;//absolute position
list<POI> dots;//relative to object position
list<pair<POI*, POI*>> lines;//Pointers to the dots to connect them
PAN3D Rot;//absolute rotation
};
Now what I need is a function that looks like:
POI Convert3dTo2d(CAMERA cam, POI point);
(must be a "POI" because of the color ;) )
I already got an alogythm that goes through all objects and all of their points
And the fact that there is a camera tells you that it's not an orthograhic voew but a perspective.
Please comment the code you write here ropperly so everyone can understand it.
If you got no clue of how to do this or just got approaches or non direct solutions, please don't answer, that doesn't really help us.
http://sta.sh/0de60ynp9id <- This image should describe it a bit
Os (Windows 7), Microsoft Visual Studio 2013(I'm just using the c++ part of it)
I Build it for x64 (if it is important ;) )
But I don't think that is important for a little bit mathematic algorythms
If you got any questions, feel free to ask me
Okay, I think I got a new( to me new) way to do this, gonna try it tomorrow and will tell you if it work's (that's the part that everyone forgets but I try not to forget it)
You need to multiply your point by a view and projection matrix.
A view matrix translates the point into camera space. Aka, relative to CAMERA.
A projection matrix transforms the point from 3D space into a projection space. You'll need to decide what sort of projection you want. For example, orthographic projection or perspective projection.
See the matrix at the bottom of these pages for the layout of these matrices.
LookAtLH, or the view matrix:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb281710(v=vs.85).aspx
OrthoLH, or the projection matrix using orthographic projection:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb281723(v=vs.85).aspx
You'll also need to look into how to perform matrix multiplication.
The only way I can interpret this question is that you want to project a 3d point(s) onto a 2d plane. If that's not what you're looking for, clarify your question. If that is what you want, countless resources for 3d projection are around: http://en.wikipedia.org/wiki/3D_projection
You will need to multiply your points by a projection matrices to project(or "convert"?) your points on a 2d plane.
I suggest you can look at the following links for an explanation of transform 3D coordinates to 2D coordinates,
The OpenGL transform pipeline
OpenGL transform
I have been working on Unigine and been trying to code a flight program for weeks, I need to find the direction between two dummy nodes so I can use this direction to rotate the wings of the aircraft. Any explanation would be appreciated.
First you have to calculate the length of the distance between P1 and P2.
distance = abs(P2(y) - P1(y))
Then you can use the angular functions to calculate the angle.
a = sin(distance / length(P12))
As already stated in the comments, the vector from P1 to P2 is given by P = P2 - P1.
The direction can be attained in two ways.
1. Directly compute angle = tan_inverse( P.y() / P.x() ).
In this method however, 1st quadrant and 3rd quadrant are treated in the same way as the signs cancel out.
2.You can normalize this vector to get a unit vector. This is the preferred way since it alleviates the quadrant issues.
P(normalized) = P / (mod(p))
Now you can get the projection of any vector in this direction by just calculating the dot-product by this unit vector.
I just randomly came across this question and therefore it might be useful for someone else to read some more useful information here, regardless of the fact that this question has been asked years ago.
Currently, there is no accepted answer, which could mean that it wasn't very clear what the OP was asking so I'll confront two problems here.
Finding the direction of a vector
I am not very fluent in C++ so I'll
go one abstraction below and write C. Consider the following function
double get_vector_direction (vector v)
{
return atan2(v.q.y - v.p.y, v.q.x - v.p.x); /* atan(ratio) */
}
As simple as this! Also, I like to define vectors this way:
typedef struct POINT { double x, y; } point;
typedef struct VECTOR { point p, q; } vector;
the atan family of functions returns the inverse tangent and this function returns the direction of a vector, which is the measure of the angle it makes with a horizontal line (in radians).
There is a diagram in the answers here that shows the horizontal line as the x component of a vector. It's a simplistic implementation of a Cartesian to Polar coordinates conversion.
Finding the distance between the initial and terminal point
You may also want to know the magnitude of the vector, which could be obtained using the distance formula: sqrt(pow(v.q.x-v.p.x, 2)+pow(v.q.y-v.p.y, 2));
The two functions make up direction() and distance() which are the two most essential functions when dealing with algebra during game development. I would also recommend vectoradd and maybe even vectorsub and of course, radtodeg to convert radians to degrees if the angle is to be showed to the player.
If under the direction you mean angle w.r.t. an arbitrary vector (let it be (p1,p3)), then you can calculate the angle using:
angle = arcos( (p1,p2) * (p1,p3) / (modulus((p1,p2)) * modulus((p1,p3)) ))
where * is the dot product. The angle will be in radians. To change it to degrees you can multiply it by 180/PI (PI=3.1415926...). Modulus is length of vector:
modulus((p1,p2))=square root((p1,p2) * (p1,p2)).
The answer is rather about math than C++ but the implementation of the simple formula is straightforward.