Related
I have a problem with my code, every time I use my arrays (vTab or eTab) of an object inside of cube:3D_obj it returns me pointer ID or nan. Well just for context here's the whole code, but those arrays are only the problem because the code is running fine.
For debugging purposes, I wrote cout's in some places. Also, I tried to init vTab[] as new vertice[8], but the same results.
I came up with one problem, that I might have to init verticle object outside of functions but i don't know actually how to handle it.
If you need to know this project have to represent simple 3D figures as data with classes/objects
Two vertices make an edge, edges make figures, etc.
IDE: I use Visual Studio on Windows
#define pi 3.14159265359
#define eps 0.0001
#include <iostream>
#include <math.h>
using namespace std;
double aprox(double x, double y) {
return round(10000 * x) / 10000;
}
class vertice {
double x;
double y;
double z;
friend ostream& operator<< (ostream& c, vertice& orig);
public:
vertice() {//init funciton
x = y = z = 0;
}
vertice(double ix, double iy, double iz) {//init function
x = ix;
y = iy;
z = iz;
}
vertice& operator- (vertice& orig) {
vertice temp = *this;
temp.x -= orig.x;
temp.y -= orig.y;
temp.z -= orig.z;
return temp;
}
vertice& operator+ (vertice& orig) {
vertice temp = *this;
temp.x += orig.x;
temp.y += orig.y;
temp.z += orig.z;
return temp;
}
void position(double ix, double iy, double iz) { //change the position of the vertice
x = ix;
y = iy;
z = iz;
}
void position(double ix) {
x = ix;
}
void rotate(double ax, double ay, double az, vertice anchorPoint = vertice(0, 0, 0)) { //rotate in 3D (angle) axis using anchor point
vertice tempVertice = *this - anchorPoint;
double cosX = cos(ax * pi / 180), cosY = cos(ay * pi / 180), cosZ = cos(az * pi / 180), sinX = sin(ax * pi / 180), sinY = sin(ay * pi / 180), sinZ = sin(az * pi / 180);
//rotate X
y = aprox(tempVertice.y * cosX - tempVertice.z * sinX, eps);
z = aprox(tempVertice.z * cosX + tempVertice.y * sinX, eps);
tempVertice = *this;
//rotate Y
x = aprox(tempVertice.x * cosY - tempVertice.z * sinY, eps);
z = aprox(tempVertice.z * cosY + tempVertice.x * sinY, eps);
tempVertice = *this;
//rotate Z
x = aprox(tempVertice.x * cosZ - tempVertice.y * sinZ, eps);
y = aprox(tempVertice.y * cosZ + tempVertice.x * sinZ, eps);
//tempVertice = *this;
*this = *this + anchorPoint;
}
//~vertice() {};
};
ostream& operator<< (ostream& c, vertice& orig) { //using << operator to stream data from vertice
cout << "x= " << orig.x << " | y= " << orig.y << " | z= " << orig.z;
return c;
}
class edge {
friend ostream& operator<< (ostream& c, edge& orig);
public:
vertice* v1;
vertice* v2;
edge() {
v1 = new vertice();
v2 = new vertice();
}
edge(vertice iv1, vertice iv2) {
v1 = &iv1;
v2 = &iv2;
}
};
ostream& operator<< (ostream& c, edge& orig) { //printing edges as two vertex
cout << "Edge: \n* " << *orig.v1 << "\n* " << *orig.v2 << endl;
return c;
}
class obj_3D {
vertice position;
vertice anchorPoint;
//material type; //not using
public:
void Draw() {}
//~obj_3D() {};
};
class cube : public obj_3D {
double a;
edge eTab[12];
vertice vTab[8];
public:
cube(double ia) { //creating vertices, edges according to object properaties.
a = ia;
double Ph = aprox(asin(sqrt(2) / 2), eps), Alph = aprox(asin(3 * sqrt(2) / 3), eps);
double TPh = 0, TAlph = 0;
double R = a * sqrt(2) / 2;
for (int i = 0; i < 8; i++) { //initializing vertices
vTab[i] = vertice();
vTab[i].position(R);
vTab[i].rotate(Ph + TPh, Alph+ TAlph, 0);
if (i == 3) {
TPh = 0;
TAlph = 180;
}
else TPh += 90;
cout << vTab[i] << endl; //for debuging purp.
}
for (int i = 0; i < 10; i++) { //initializing edges
if (i < 4) {
eTab[i] = edge(vTab[i], vTab[(i + 1) % 4]);
eTab[i + 4] = edge(vTab[i], vTab[i + 4]);
cout << eTab[i] << eTab[i + 4] << endl;
}
else {
eTab[i + 4] = edge(vTab[i], vTab[((i + 1) % 4) + 4]);
cout << eTab[i + 4] << endl;
}
}
}
void print() {
cout << "Cube: \n";
for (int i = 0; i < 12; i++) {
edge temp = eTab[i];
cout << i+1 << ". " << temp << endl;
}
}
};
int main() {
/*vertice a = vertice();
vertice b = vertice(4.2, 1.3, 2.2);
cout << b;
b = b + a;
b = b - a;
b.rotate(90, 90, 90);
cout << endl << a;
edge e1 = edge(a, b);
cout << endl << e1;*/
//vertice b = vertice();
//cout << b;
cube c1 = cube(4);
//c1.print();
}
I really will appreciate your help because I really am stuck here and don't know what to do...
I want to overload the * operator for my QUATERNION class but somehow I'm unable to use it at the same time with QUATERNIONs methods (Q4 example).
Is it possible to use somehow Q1*Q2.conjugated() without creating any temp variables?
C:\Users\xXx\Documents\Arduino\libraries\QUATERNION\extras\Quaternions\main.cpp|19|error:
cannot bind non-const lvalue reference of type 'QUATERNION&' to an
rvalue of type 'QUATERNION'|
QUATERNION Q1(1,2,3,4);
QUATERNION Q2(5,6,7,8);
QUATERNION Q2c = Q2.conjugated();
QUATERNION Q3 = Q1*Q2c; // work fine
QUATERNION Q4 = Q1*Q2.conjugated(); // not working
QUATERNION.h
#ifndef QUATERNION_H
#define QUATERNION_H
class QUATERNION
{
public:
float w;
float x;
float y;
float z;
QUATERNION(void);
QUATERNION(float,float,float,float);
float magnitude(void);
void normalize(void);
void scale(float);
QUATERNION normalized(void);
QUATERNION conjugated(void);
};
// operatory ==========================================
QUATERNION operator * (QUATERNION&,QUATERNION&);
QUATERNION operator * (QUATERNION&,float);
bool operator == (QUATERNION&,QUATERNION&);
// funkcje ============================================
QUATERNION Q_mul(QUATERNION&,QUATERNION&);
QUATERNION Q_scaled(QUATERNION&,float);
QUATERNION Q_fromAngular(const float*);
void Q_toAngular(QUATERNION&,float*,bool);
#endif // QUATERNION_H
QUATERNION.cpp
#include "QUATERNION.h"
#include "math.h"
QUATERNION::QUATERNION() : QUATERNION(1,0,0,0)
{
}
QUATERNION::QUATERNION(float w,float x,float y,float z){
this->w = w;
this->x = x;
this->y = y;
this->z = z;
}
float QUATERNION::magnitude(){
return sqrt(w*w+x*x+y*y+z*z);
}
void QUATERNION::normalize(){
float invMag = 1.0/magnitude();
scale(invMag);
}
void QUATERNION::scale(float scalar){
w *= scalar;
x *= scalar;
y *= scalar;
z *= scalar;
}
QUATERNION QUATERNION::normalized(){
QUATERNION q = QUATERNION(w,x,y,z);
q.normalize();
return q;
}
QUATERNION QUATERNION::conjugated(){
return QUATERNION(w,-x,-y,-z);
}
// operatory ==========================================
QUATERNION operator * (QUATERNION &A,QUATERNION &B){
return Q_mul(A,B);
}
QUATERNION operator * (QUATERNION &q,float scalar){
return Q_scaled(q,scalar);
}
bool operator == (QUATERNION &A,QUATERNION &B){
float epsilon = 1.0e-5;
return fabs(A.w-B.w)<=epsilon && fabs(A.x-B.x)<=epsilon
&& fabs(A.y-B.y)<=epsilon && fabs(A.z-B.z)<=epsilon;
}
// funkcje ============================================
QUATERNION Q_mul(QUATERNION &A,QUATERNION &B){
return QUATERNION(
A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z, // w
A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y, // x
A.w * B.y - A.x * B.z + A.y * B.w + A.z * B.x, // y
A.w * B.z + A.x * B.y - A.y * B.x + A.z * B.w); // z
}
QUATERNION Q_scaled(QUATERNION &q,float scalar){
return QUATERNION(q.w*scalar,q.x*scalar,q.y*scalar,q.z*scalar);
}
QUATERNION Q_fromAngular(const float *w) {
float theta,q0,q1,q2,q3;
float dt = 1;
float x = w[0]*dt;
float y = w[1]*dt;
float z = w[2]*dt;
theta = sqrt(x*x + y*y + z*z);
if (theta<=1.0e-6) return QUATERNION(1,0,0,0);
q0 = cos(theta/2.0f);
q1 = sin(theta/2.0f)/theta * x;
q2 = sin(theta/2.0f)/theta * y;
q3 = sin(theta/2.0f)/theta * z;
return QUATERNION(q0,q1,q2,q3);
// w/theta - normalizacja wektora
}
void Q_toAngular(QUATERNION &q,float *angular,bool deg) {
// http://www.euclideanspace.com/physics/kinematics/angularvelocity/index.htm
float w=q.w,x=q.x,y=q.y,z=q.z;
if (w<0){
// w*=-1.0;
// x*=-1.0;
// y*=-1.0;
// z*=-1.0;
}
if (fabs(w)==1){
// unika dzielenia przez 0
// taki kwaternion nie zawiera rotacji
angular[0] = 0;
angular[1] = 0;
angular[2] = 0;
return;
}
// https://math.stackexchange.com/questions/3753611/quaternion-to-rotation-vector-sintheta-2-sqrt1-quaternion-w2
// theta = acos(w)*2
// sqrt(1-w*w) = sin(theta/2)
// float m = ( acos(w)*2.0 )/sqrt(1-w*w); // theta/sin(theta/2)
float theta = 2*acos(w);
float m = theta/sin(theta/2);
if (deg)
m*= 180.0/M_PI;
angular[0] = x*m;
angular[1] = y*m;
angular[2] = z*m;
}
In QUATERNION operator * (QUATERNION& A,QUATERNION& B);, you accept A and B by non-const reference. The compiler expects you to change them. That's obviously wrong for a multiplication. Add the missing const to both arguments, and to all other references in your code.
Also it appears that Angular might be a type. You currently use a float[3] for that.
When I add some extra formal parameters double tmin=0.0, double tmax=0.0 to the constructor of the Ray in the code below, I always obtain a wrong image with a white top border. These formal parameters currently contribute in no way (i.e. are unused) to the code. So how is it possible to obtain a different image?
System specifications:
OS: Windows 8.1
Compiler: MSVC 2015
Code:
#include "stdafx.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <random>
std::default_random_engine generator(606418532);
std::uniform_real_distribution<double> distribution = std::uniform_real_distribution<double>(0.0, 1.0);
double erand48(unsigned short *x) {
return distribution(generator);
}
#define M_PI 3.14159265358979323846
struct Vector3 {
double x, y, z;
Vector3(double x_ = 0, double y_ = 0, double z_ = 0) { x = x_; y = y_; z = z_; }
Vector3 operator+(const Vector3 &b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
Vector3 operator-(const Vector3 &b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
Vector3 operator*(double b) const { return Vector3(x*b, y*b, z*b); }
Vector3 mult(const Vector3 &b) const { return Vector3(x*b.x, y*b.y, z*b.z); }
Vector3& norm() { return *this = *this * (1 / sqrt(x*x + y*y + z*z)); }
double Dot(const Vector3 &b) const { return x*b.x + y*b.y + z*b.z; } // cross:
Vector3 operator%(Vector3&b) { return Vector3(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); }
};
//struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
enum Reflection_t { DIFFUSE, SPECULAR, REFRACTIVE };
struct Sphere {
double rad; // radius
Vector3 p, e, f; // position, emission, color
Reflection_t reflection_t; // reflection type (DIFFuse, SPECular, REFRactive)
Sphere(double rad_, Vector3 p_, Vector3 e_, Vector3 f_, Reflection_t reflection_t) :
rad(rad_), p(p_), e(e_), f(f_), reflection_t(reflection_t) {}
double intersect(const Ray &r) const {
Vector3 op = p - r.o;
double t, eps = 1e-4, b = op.Dot(r.d), det = b*b - op.Dot(op) + rad*rad;
if (det<0) return 0; else det = sqrt(det);
return (t = b - det)>eps ? t : ((t = b + det)>eps ? t : 0);
}
};
Sphere spheres[] = {
Sphere(1e5, Vector3(1e5 + 1,40.8,81.6), Vector3(),Vector3(.75,.25,.25),DIFFUSE),//Left
Sphere(1e5, Vector3(-1e5 + 99,40.8,81.6),Vector3(),Vector3(.25,.25,.75),DIFFUSE),//Rght
Sphere(1e5, Vector3(50,40.8, 1e5), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Back
Sphere(1e5, Vector3(50,40.8,-1e5 + 170), Vector3(),Vector3(), DIFFUSE),//Frnt
Sphere(1e5, Vector3(50, 1e5, 81.6), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Botm
Sphere(1e5, Vector3(50,-1e5 + 81.6,81.6),Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Top
Sphere(16.5,Vector3(27,16.5,47), Vector3(),Vector3(1,1,1)*.999, SPECULAR),//Mirr
Sphere(16.5,Vector3(73,16.5,78), Vector3(),Vector3(1,1,1)*.999, REFRACTIVE),//Glas
Sphere(600, Vector3(50,681.6 - .27,81.6),Vector3(12,12,12), Vector3(), DIFFUSE) //Lite
};
inline double clamp(double x) { return x<0 ? 0 : x>1 ? 1 : x; }
inline int toInt(double x) { return int(pow(clamp(x), 1 / 2.2) * 255 + .5); }
inline bool intersect(const Ray &r, double &t, int &id) {
double n = sizeof(spheres) / sizeof(Sphere), d, inf = t = 1e20;
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t) { t = d; id = i; }
return t<inf;
}
Vector3 radiance(const Ray &r_, int depth_, unsigned short *Xi) {
double t; // distance to intersection
int id = 0; // id of intersected object
Ray r = r_;
int depth = depth_;
Vector3 cl(0, 0, 0); // accumulated color
Vector3 cf(1, 1, 1); // accumulated reflectance
while (1) {
if (!intersect(r, t, id)) return cl; // if miss, return black
const Sphere &obj = spheres[id]; // the hit object
Vector3 x = r.o + r.d*t, n = (x - obj.p).norm(), nl = n.Dot(r.d)<0 ? n : n*-1, f = obj.f;
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl
cl = cl + cf.mult(obj.e);
if (++depth>5) if (erand48(Xi)<p) f = f*(1 / p); else return cl; //R.R.
cf = cf.mult(f);
if (obj.reflection_t == DIFFUSE) { // Ideal DIFFUSE reflection
double r1 = 2 * M_PI*erand48(Xi), r2 = erand48(Xi), r2s = sqrt(r2);
Vector3 w = nl, u = ((fabs(w.x)>.1 ? Vector3(0, 1) : Vector3(1)) % w).norm(), v = w%u;
Vector3 d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1 - r2)).norm();
r = Ray(x, d);
continue;
}
else if (obj.reflection_t == SPECULAR) {
r = Ray(x, r.d - n * 2 * n.Dot(r.d));
continue;
}
Ray reflRay(x, r.d - n * 2 * n.Dot(r.d));
bool into = n.Dot(nl)>0;
double nc = 1, nt = 1.5, nnt = into ? nc / nt : nt / nc, ddn = r.d.Dot(nl), cos2t;
if ((cos2t = 1 - nnt*nnt*(1 - ddn*ddn))<0) {
r = reflRay;
continue;
}
Vector3 tdir = (r.d*nnt - n*((into ? 1 : -1)*(ddn*nnt + sqrt(cos2t)))).norm();
double a = nt - nc, b = nt + nc, R0 = a*a / (b*b), c = 1 - (into ? -ddn : tdir.Dot(n));
double Re = R0 + (1 - R0)*c*c*c*c*c, Tr = 1 - Re, P = .25 + .5*Re, RP = Re / P, TP = Tr / (1 - P);
if (erand48(Xi)<P) {
cf = cf*RP;
r = reflRay;
}
else {
cf = cf*TP;
r = Ray(x, tdir);
}
continue;
}
}
int main(int argc, char *argv[]) {
int w = 512, h = 384, samps = argc == 2 ? atoi(argv[1]) / 4 : 1; // # samples
Ray cam(Vector3(50, 52, 295.6), Vector3(0, -0.042612, -1).norm()); // cam pos, dir
Vector3 cx = Vector3(w*.5135 / h), cy = (cx%cam.d).norm()*.5135, r, *c = new Vector3[w*h];
#pragma omp parallel for schedule(dynamic, 1) private(r) // OpenMP
for (int y = 0; y<h; y++) { // Loop over image rows
fprintf(stderr, "\rRendering (%d spp) %5.2f%%", samps * 4, 100.*y / (h - 1));
for (unsigned short x = 0, Xi[3] = { 0,0,y*y*y }; x<w; x++) // Loop cols
for (int sy = 0, i = (h - y - 1)*w + x; sy<2; sy++) // 2x2 subpixel rows
for (int sx = 0; sx<2; sx++, r = Vector3()) { // 2x2 subpixel cols
for (int s = 0; s<samps; s++) {
double r1 = 2 * erand48(Xi), dx = r1<1 ? sqrt(r1) - 1 : 1 - sqrt(2 - r1);
double r2 = 2 * erand48(Xi), dy = r2<1 ? sqrt(r2) - 1 : 1 - sqrt(2 - r2);
Vector3 d = cx*(((sx + .5 + dx) / 2 + x) / w - .5) +
cy*(((sy + .5 + dy) / 2 + y) / h - .5) + cam.d;
r = r + radiance(Ray(cam.o + d * 140, d.norm()), 0, Xi)*(1. / samps);
} // Camera rays are pushed ^^^^^ forward to start in interior
c[i] = c[i] + Vector3(clamp(r.x), clamp(r.y), clamp(r.z))*.25;
}
}
FILE *fp;
fopen_s(&fp, "image.ppm", "w"); // Write image to PPM file.
fprintf(fp, "P3\n%d %d\n%d\n", w, h, 255);
for (int i = 0; i<w*h; i++)
fprintf(fp, "%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z));
}
First Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
Results in:
Second Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
Results in:
The last image has a noticeable white top border which is not present in the first image.
Edit:
I used
size_t n = sizeof(spheres) / sizeof(Sphere);
Now I obtain the same images, but I also checked if the original int(n) could differ from 9 which is never the case.
Ok this is from the Debug build, which is different from the Release build.
Sounds like a memory error, looking quickly at your code I'm sceptical of this line:
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t)
I suspect accessing sphere[i] is out of bounds, perhaps you should try sphere[i-1]. You could also try compiling your code with a compiler that adds extra code for debugging/sanitising/checking memory addresses.
I am trying to write some position/orientation methods for my small & simple 3d-space calculation library. But I'm stuck on the following problem.
I store 3d line as start and end points. However it should be possible to store it as start point and line's length + orientation as well (it's just a good example to test if orientation calculations works).
By orientation I mean rotation from the initial "0" orientation (which places the end at start + [0,legth,0]). So I first rotate the [0,length,0] by orientation and then add start to it to get end point.
The problem is, my orientation calculations fails somewhere. After calculating the orientation I get different ending point.
I use left-handed coordinate system with Y-axis pointing up, but I don't think it's important here.
Here's the code (I've tried to name the methods in the way you can check if the steps are ok; here's the full source code if you want to compile it yourself):
Point3D start = { 5.0f, 4.0f, 7.0f };
Point3D end = { 15.0f, 6.0f, 14.0f };
Point3D direction = (end - start);
std::wcout << L"Direction: "; direction.output();
float angle = Point3D(0.0f, 1.0f, 0.0f).getAngleToAnotherVectorInRadians(direction);
Point3D axis = direction.getCrossProduct(Point3D(0.0f, 1.0f, 0.0f)).getNormalized();
Quaternion o = Quaternion(AxisAngle(axis, angle));
std::wcout << L"\nAxisAngle: "; AxisAngle(axis, angle).output();
std::wcout << L"\nOrientation: "; o.output();
//test - end2 should be equal to end
Point3D offset(0.0f, (end - start).getLengthAsVector(), 0.0f);
offset = o.rotatePoint(offset);
std::wcout << L"\nOffset: "; offset.output();
Point3D end2 = start + offset;
std::wcout << L"\nEnd2: "; end2.output();
The code produces such output (without a comments, of course):
Direction: {10, 2, 7} //looks ok
AxisAngle: {{-0.573462, 0, 0.819232}, 1.40839}
Orientation: {-0.371272, 0, 0.530388, 0.762132}
Offset: {-10, 2, -7} //Almost! It should be {10, 2, 7}
End2: {-5, 6, -9.53674e-07} //Wrong! It should be { 15, 6, 14 }
In case that all steps are ok but there are some mistakes in methods' implementations I post here the important code for classes (so you can reproduce the problem): Point3D, AxisAngle, Quaternion.
I highly believe that problem(s) lay(s) in my main steps or in AxisAngle calculations. I think that AxisAngle to Quaternion transformation is ok (but I pass the wrong AxisAngle to Quaternion constructor).
The Point3D:
struct Point3D {
protected:
float x, y, z;
public:
Point3D() : x(0.0f), y(0.0f), z(0.0f) {}
Point3D(float x, float y, float z) : x(x), y(y), z(z) {}
void output() { std::wcout << L"{" << x << L", " << y << L", " << z << L"}"; }
Point3D operator-(const Point3D &point) const {
Point3D temp;
temp.setX(getX() - point.getX());
temp.setY(getY() - point.getY());
temp.setZ(getZ() - point.getZ());
return temp;
}
Point3D operator+ (const Point3D &value) const {
Point3D temp;
temp.setX(getX() + value.getX());
temp.setY(getY() + value.getY());
temp.setZ(getZ() + value.getZ());
return temp;
}
inline float getX() const { return x; } inline float getY() const { return y; } inline float getZ() const { return z; }
inline void setX(float x) { this->x = x; } inline void setY(float y) { this->y = y; } inline void setZ(float z) { this->z = z; }
inline float getLengthAsVector() const {
return sqrt(x*x + y*y + z*z);
}
inline Point3D getCrossProduct(const Point3D &anotherVector) const {
//based on: http://www.sciencehq.com/physics/vector-product-multiplying-vectors.html
return Point3D(
y * anotherVector.z - anotherVector.y * z,
z * anotherVector.x - anotherVector.z * x,
x * anotherVector.y - anotherVector.x * y
);
}
inline float getDotProduct(const Point3D &anotherVector) const {
//based on: https://www.ltcconline.net/greenl/courses/107/Vectors/DOTCROS.HTM
return x * anotherVector.x + y * anotherVector.y + z * anotherVector.z;
}
inline float getAngleToAnotherVectorInRadians(const Point3D &anotherVector) const {
//based on: http://math.stackexchange.com/questions/974178/how-to-calculate-the-angle-between-2-vectors-in-3d-space-given-a-preset-function
return acos(getDotProduct(anotherVector) / (getLengthAsVector() * anotherVector.getLengthAsVector()));
}
Point3D getNormalized() const {
float length = std::abs(sqrt(x*x + y*y + z*z));
Point3D result(x / length, y / length, z / length);
return result;
}
};
The AxisAngle:
class AxisAngle {
protected:
Point3D axis;
float angleInRadians;
public:
AxisAngle(const AxisAngle &other) { axis = other.axis; angleInRadians = other.angleInRadians; }
AxisAngle::AxisAngle(float x, float y, float z, float angleInRadians) {
this->axis = Point3D(x, y, z);
this->angleInRadians = angleInRadians;
}
AxisAngle::AxisAngle(const Point3D &axis, float angleInRadians) {
this->axis = axis;
this->angleInRadians = angleInRadians;
}
Point3D getAxis() const { return axis; }
float getAngleInRadians() const { return angleInRadians; }
void output() { std::wcout << L"{"; axis.output(); std::wcout << L", " << angleInRadians << L"}"; }
};
And last but not least, Quaternion:
class Quaternion {
protected:
float x; float y; float z; float w;
public:
Quaternion() { x = 0.0f; y = 0.0f; z = 0.0f; w = 1.0f; }
Quaternion(const Quaternion &other) { x = other.x; y = other.y; z = other.z; w = other.w; }
Quaternion(float x, float y, float z, float w) { this->x = x; this->y = y; this->z = z; this->w = w; }
Quaternion(const AxisAngle &axisAngle) {
Point3D axis = axisAngle.getAxis();
float angleInRadians = axisAngle.getAngleInRadians();
x = sin(angleInRadians / 2) * axis.getX();
y = sin(angleInRadians / 2) * axis.getY();
z = sin(angleInRadians / 2) * axis.getZ();
w = cos(angleInRadians / 2);
normalizeIt();
}
float getLength() const {
return sqrt(x*x + y*y + z*z + w*w);
}
void normalizeIt() {
float length = getLength();
x = x / length;
y = y / length;
z = z / length;
w = w / length;
}
Quaternion getConjugated() const {
return Quaternion(-x, -y, -z, w);
}
Quaternion multiply(Quaternion by) {
//"R" for result
float wR = w * by.getW() - x * by.getX() - y * by.getY() - z * by.getZ();
float xR = x * by.getW() + w * by.getX() + y * by.getZ() - z * by.getY();
float yR = y * by.getW() + w * by.getY() + z * by.getX() - x * by.getZ();
float zR = z * by.getW() + w * by.getZ() + x * by.getY() - y * by.getX();
return Quaternion(xR, yR, zR, wR);
}
//rotate Point3D p around [0,0,0] with this Quaternion
Point3D rotatePoint(Point3D p) const {
Quaternion temp = multiply(p).multiply(getConjugated());
return Point3D(temp.getX(), temp.getY(), temp.getZ());
//G: P' = Q(P-G)Q' + G <- to rotate P around G with Quaternion
}
Quaternion multiply(Point3D r) const {
float wR = -x * r.getX() - y * r.getY() - z * r.getZ();
float xR = w * r.getX() + y * r.getZ() - z * r.getY();
float yR = w * r.getY() + z * r.getX() - x * r.getZ();
float zR = w * r.getZ() + x * r.getY() - y * r.getX();
return Quaternion(xR, yR, zR, wR);
}
inline float getX() const { return x; } inline void setX(float x) { this->x = x; }
inline float getY() const { return y; } inline void setY(float y) { this->y = y; }
inline float getZ() const { return z; } inline void setZ(float z) { this->z = z; }
inline float getW() const { return w; } inline void setW(float w) { this->w = w; }
void output() { std::wcout << L"{" << x << L", " << y << L", " << z << L", " << w << L"}"; }
};
In case somebody would ask: I do want to use quaternions. They may not look 100% needed here, but storing 3d object's orientation as quaternion has many benefits in more complex computations (and most game engines / 3d software use it as well "under the mask").
Your axis has the wrong orientation. It should be:
Point3D axis = Point3D(0.0f, 1.0f, 0.0f).getCrossProduct(direction).getNormalized();
Use the two left-hand rules to figure out the correct order.
I have to compute the distance from a point to a line (check if it is line or a line segment). I am not sure that the bool function IsSegment is working properly. Can i have some suggestions? Thank you.
double Distance_From_Line_to_Point(int *a, int *b, int *c, bool IsSegment) {
double distance;
int dot1;
int dot2;
distance = Cross_Product(a, b, c) / Distance(a, b);
if (IsSegment(a,b,c) == true) {
dot1 = Dot_Product(a, b, c);
if (dot1 > 0) {
return Distance(b, c);
}
dot2 = Dot_Product(b, a, c);
if (dot2 > 0) {
return Distance(a, c);
}
}
return fabs(distance);
}
bool IsSegment(int *a, int *b, int *c) {
double angle1;
double angle2;
angle1 = atan(double(b[1] - a[1]) / (b[0] - a[0]));
angle2 = atan(double(c[1] - b[1]) / (c[0] - b[0]));
if ((angle2 - angle1) * (180 / PI) > 90) {
return false;
}
return true;
}
Can't you just use the formula to get the distance?
So to find the line:
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
http://formule-matematica.tripod.com/distanta-de-dreapta.htm
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
Example on how to use the code:
#include <CMATH>
void getLine(double x1, double y1, double x2, double y2, double &a, double &b, double &c)
{
// (x- p1X) / (p2X - p1X) = (y - p1Y) / (p2Y - p1Y)
a = y1 - y2; // Note: this was incorrectly "y2 - y1" in the original answer
b = x2 - x1;
c = x1 * y2 - x2 * y1;
}
double dist(double pct1X, double pct1Y, double pct2X, double pct2Y, double pct3X, double pct3Y)
{
double a, b, c;
getLine(pct2X, pct2Y, pct3X, pct3Y, a, b, c);
return abs(a * pct1X + b * pct1Y + c) / sqrt(a * a + b * b);
}
int main(int argc, char* argv[])
{
double d = dist(1,2,3,4,5,6);
return 0;
}
Distance from a point to a line
You need 2 formulas:
Line formula: source this answer.
private Vector2 m_point1;
private Vector2 m_point1;
private float m_A;
private float m_B;
private float m_C;
public void CalculateLine()
{
m_A = m_point1.y - m_point2.y;
m_B = m_point2.x - m_point1.x;
m_C = m_point1.x * m_point2.y - m_point2.x * m_point1.y;
if(m_A == 0 && m_B == 0)
{
Debug.LogError("Line error: A & B = 0");
}
}
Distance from point to line: source Wikipedia
public float Distance2DPointToLine(Vector2 point)
{
return Mathf.Abs(m_A * point.x + m_B * point.y + m_C) /
Mathf.Sqrt(m_A * m_A + m_B * m_B);
}
Distance from a point to a line segment
It depends what you define "Distance from a point to a line segment"
Maybe distance from a point to a line segment is the distance from a point to the segment's middle point:
Maybe the distance is available if the point can be projected on the line segment
Maybe you didn't imagine what's result when you ask about segment, so I can't answer the segment part for you.