Posted By: Kartoffel
floating point vectors - 01/31/17 09:17
Because of accuracy reasons I created floating-point versions of most vector functions found in acknex. Feel free to use them for whatever you'd like:
copy-paste (lots of lines):
or download here.
edit: for more info have a look at the file
edit2: small changes to fvec_normalize()
copy-paste (lots of lines):
Click to reveal..
Code:
/* Acknex-style float vectors free for any use created by 'Kartoffel', last edited on: 31.01.2017 // description floating-point vectors, similar to VECTOR/ANGLE in acknex. most (but not all) standard vec_-functions are included. there are also some additional functions. note: - for more info read the following lines (up to line ~100) - some minor settings at line ~100 - not all functions have been tested thoroughly - vec_bounce works differently here! (acknex's vec_bounce buggy?) - ang_rotate rotates 'roll' differently here */ #ifndef _FVEC_H_ #define _FVEC_H_ //// Datatypes // FVECTOR: like VECTOR; floating point vector type, contains: x, y, z typedef struct FVECTOR { float x, y, z; } FVECTOR; // FANGLE: like ANGLE; floating point angle type, contains: pan, tilt, roll (FVECTOR can be used instead, aswell; (same as VECTOR/ANGLE compatibility)) typedef struct FANGLE { float pan, tilt, roll; } FANGLE; // startup function, is automatically called! void _FVEC_startp(); // non-zero when startup function is done var FVEC_INITIALIZED = 0; // FVECTOR version of 'nullvector' (using floats) FVECTOR * fnullvector = NULL; // returns temporary FVECTOR* with given XYZ (like vector() for VECTOR), buffer size configurable at settings section FVECTOR * fvector(float X, float Y, float Z); //// VECTOR -> FVECTOR conversion // copies VECTOR* pVecB to FVECTOR* pVecA void fvec_from_vec(FVECTOR * pVecA, VECTOR * pVecB); // returns VECTOR* pVecB as temporary FVECTOR* (using fvector()-function) FVECTOR * fvec_from_vec(VECTOR * pVecB); //// FVECTOR -> VECTOR conversion // copies FVECTOR* pVecB to VECTOR* pVecA void * vec_from_fvec(VECTOR * pVecA, FVECTOR * pVecB); // returns FVECTOR* pVecB as temporary VECTOR* (using vector()-function) VECTOR * fvec_from_vec(VECTOR * pVecB); //// FVECTOR functions (work the same as Acknex's VECTOR/ANGLE-functions, but use FVECTOR/FANGLE/float instead of VECTOR/ANGLE/var) void fvec_set(FVECTOR * pVecA, FVECTOR * pVecB); void fvec_set_xyz(FVECTOR * pVec, float X, float Y, float Z); void fvec_fill(FVECTOR * pVec, float Value); void fvec_add(FVECTOR * pVecA, FVECTOR * pVecB); void fvec_sub(FVECTOR * pVecA, FVECTOR * pVecB); void fvec_scale(FVECTOR * pVec, float Factor); void fvec_inverse(FVECTOR * pVec); float fvec_length(FVECTOR * pVec); float fvec_dist(FVECTOR * pVecA, FVECTOR * pVecB); void fvec_normalize(FVECTOR * pVec, float Length); void fvec_normalize(FVECTOR * pVec); // uses length = 1 float fvec_dot(FVECTOR * pVecA, FVECTOR * pVecB); float fvec_dot_norm(FVECTOR * pVecA, FVECTOR * pVecB); // uses normalized vectors void fvec_cross(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB); void fvec_bounce(FVECTOR * pVecRay, FVECTOR * pVecNormal); void fvec_bounce_norm(FVECTOR * pVecRay, FVECTOR * pVecNormal); // uses normalized normal vector void fvec_lerp(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB, float BlendFactor); void fvec_slerp(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB, float BlendFactor); // same as lerp but using sine-falloff void fvec_for_angle(FVECTOR * pVec, FANGLE * pAng); // uses degrees void fvec_to_angle(FANGLE * pAng, FVECTOR * pVec); // uses degrees void fvec_rotate(FVECTOR * pVec, FANGLE * pAng); // uses degrees void fang_rotate(FANGLE * pAngA, FANGLE * pAngB); // uses degrees void fvec_for_angle_rad(FVECTOR * pVec, FANGLE * pAng); // uses radians void fvec_to_angle_rad(FANGLE * pAng, FVECTOR * pVec); // uses radians void fvec_rotate_rad(FVECTOR * pVec, FANGLE * pAng); // uses radians void fang_rotate_rad(FANGLE * pAngA, FANGLE * pAngB); // uses radians float fvec_accelerate(FVECTOR * pVecSpeed, FVECTOR * pVecAccel, float Friction); //// Settings: //#define FVEC_UNSAFE // disables pointer checking #define FVEC_USE_TEMP_VECTORS // silghtly slower, allows to use one vector as both input and output (for example: fvec_cross(VecA, VecA, VecB)) #define FVEC_FVECTOR_BUFFER_NUM 32 // number of temporary vectors for the fvector() function /// no more info / settings from here on ////////////////////////////////////////////////// #ifndef DEG_TO_RAD #define DEG_TO_RAD(X) ((X) * 3.141593 / 180.0) #endif #ifndef RAD_TO_DEG #define RAD_TO_DEG(X) ((X) * 180.0 / 3.141593) #endif // int __fvector_buffer_current = 0; FVECTOR __fvector_buffer[FVEC_FVECTOR_BUFFER_NUM]; // FVECTOR * fvector(float X, float Y, float Z) { int this_fvec = __fvector_buffer_current; __fvector_buffer_current = (__fvector_buffer_current + 1) % FVEC_FVECTOR_BUFFER_NUM; __fvector_buffer[this_fvec].x = X; __fvector_buffer[this_fvec].y = Y; __fvector_buffer[this_fvec].z = Z; return &(__fvector_buffer[this_fvec]); } void fvec_from_vec(FVECTOR * pVecA, VECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_from_vec()':nnempty pointer."); return; } #endif pVecA->x = (float)pVecB->x; pVecA->y = (float)pVecB->y; pVecA->z = (float)pVecB->z; } void vec_from_fvec(VECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'vec_from_fvec()':nnempty pointer."); return; } #endif pVecA->x = (var)pVecB->x; pVecA->y = (var)pVecB->y; pVecA->z = (var)pVecB->z; } FVECTOR * fvec_from_vec(VECTOR * pVec) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_from_vec()':nnempty pointer."); return fnullvector; } #endif return fvector((float)pVec->x, (float)pVec->y, (float)pVec->z); } VECTOR * vec_from_fvec(FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'vec_from_fvec()':nnempty pointer."); return nullvector; } #endif return vector((var)pVec->x, (var)pVec->y, (var)pVec->z); } void fvec_set(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_set()':nnempty pointer."); return; } #endif memcpy(pVecA, pVecB, sizeof(float) * 3); } void fvec_set_xyz(FVECTOR * pVec, float X, float Y, float Z) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_set_xyz()':nnempty pointer."); return; } #endif memcpy(pVec, &X, sizeof(float) * 3); } void fvec_fill(FVECTOR * pVec, float Value) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_fill()':nnempty pointer."); return; } #endif pVec->x = pVec->y = pVec->z = Value; } void fvec_add(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_add()':nnempty pointer."); return; } #endif pVecA->x += pVecB->x; pVecA->y += pVecB->y; pVecA->z += pVecB->z; } void fvec_sub(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_sub()':nnempty pointer."); return; } #endif pVecA->x -= pVecB->x; pVecA->y -= pVecB->y; pVecA->z -= pVecB->z; } void fvec_diff(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecTarget == NULL || pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_diff()':nnempty pointer."); return; } #endif #ifdef FVEC_USE_TEMP_VECTORS FVECTOR TempVec; fvec_set(&TempVec, pVecA); fvec_sub(&TempVec, pVecB); fvec_set(pVecTarget, &TempVec); #else fvec_set(pVecTarget, pVecA); fvec_sub(pVecTarget, pVecB); #endif } void fvec_scale(FVECTOR * pVec, float Factor) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_scale()':nnempty pointer."); return; } #endif pVec->x *= Factor; pVec->y *= Factor; pVec->z *= Factor; } void fvec_mul(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_mul()':nnempty pointer."); return; } #endif pVecA->x *= pVecB->x; pVecA->y *= pVecB->y; pVecA->z *= pVecB->z; } void fvec_inverse(FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_inverse()':nnempty pointer."); return; } #endif pVec->x = -pVec->x; pVec->y = -pVec->y; pVec->z = -pVec->z; } float fvec_length(FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_length()':nnempty pointer."); return 0; } #endif return sqrt(pVec->x * pVec->x + pVec->y * pVec->y + pVec->z * pVec->z); } float fvec_dist(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_dist()':nnempty pointer."); return 0; } #endif FVECTOR TempVec; fvec_set(&TempVec, pVecB); fvec_sub(&TempVec, pVecA); return fvec_length(&TempVec); } void fvec_normalize(FVECTOR * pVec, float Length) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_normalize()':nnempty pointer."); return; } #endif float CurrentLength = fvec_length(pVec); if(CurrentLength != 0.0) { fvec_scale(pVec, Length / CurrentLength); } } void fvec_normalize(FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pVec == NULL) { printf("error in 'fvec_normalize()':nnempty pointer."); return; } #endif float CurrentLength = fvec_length(pVec); if(CurrentLength != 0.0) { fvec_scale(pVec, 1.0 / CurrentLength); } } float fvec_dot(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_dot()':nnempty pointer."); return 0; } #endif return pVecA->x * pVecB->x + pVecA->y * pVecB->y + pVecA->z * pVecB->z; } float fvec_dot_norm(FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_dot_norm()':nnempty pointer."); return 0; } #endif float Dot = pVecA->x * pVecB->x + pVecA->y * pVecB->y + pVecA->z * pVecB->z; float Length = fvec_length(pVecA) * fvec_length(pVecB); if(Length != 0.0) { Dot /= Length; } return Dot; } void fvec_cross(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB) { #ifndef FVEC_UNSAFE if(pVecTarget == NULL || pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_cross()':nnempty pointer."); return; } #endif #ifdef FVEC_USE_TEMP_VECTORS FVECTOR TempVec; TempVec.x = pVecA->y * pVecB->z - pVecA->z * pVecB->y; TempVec.y = pVecA->z * pVecB->x - pVecA->x * pVecB->z; TempVec.z = pVecA->x * pVecB->y - pVecA->y * pVecB->x; fvec_set(pVecTarget, &TempVec); #else pVecTarget->x = pVecA->y * pVecB->z - pVecA->z * pVecB->y; pVecTarget->y = pVecA->z * pVecB->x - pVecA->x * pVecB->z; pVecTarget->z = pVecA->x * pVecB->y - pVecA->y * pVecB->x; #endif } void fvec_bounce(FVECTOR * pVecRay, FVECTOR * pVecNormal) { #ifndef FVEC_UNSAFE if(pVecRay == NULL || pVecNormal == NULL) { printf("error in 'fvec_bounce()':nnempty pointer."); return; } #endif float Dot = fvec_dot(pVecNormal, pVecRay); pVecRay->x -= 2.0 * Dot * pVecNormal->x; pVecRay->y -= 2.0 * Dot * pVecNormal->y; pVecRay->z -= 2.0 * Dot * pVecNormal->z; } void fvec_bounce_norm(FVECTOR * pVecRay, FVECTOR * pVecNormal) { #ifndef FVEC_UNSAFE if(pVecRay == NULL || pVecNormal == NULL) { printf("error in 'fvec_bounce_norm()':nnempty pointer."); return; } #endif FVECTOR Normal; fvec_set(&Normal, pVecNormal); fvec_normalize(&Normal); float Dot = fvec_dot(&Normal, pVecRay); pVecRay->x -= 2.0 * Dot * Normal.x; pVecRay->y -= 2.0 * Dot * Normal.y; pVecRay->z -= 2.0 * Dot * Normal.z; } // lerp void fvec_lerp(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB, float BlendFactor) { #ifndef FVEC_UNSAFE if(pVecTarget == NULL || pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_lerp()':nnempty pointer."); return; } #endif #ifdef FVEC_USE_TEMP_VECTORS FVECTOR TempVec; TempVec.x = pVecA->x + (pVecB->x - pVecA->x) * BlendFactor; TempVec.y = pVecA->y + (pVecB->y - pVecA->y) * BlendFactor; TempVec.z = pVecA->z + (pVecB->z - pVecA->z) * BlendFactor; fvec_set(pVecTarget, &TempVec); #else pVecTarget->x = pVecA->x + (pVecB->x - pVecA->x) * BlendFactor; pVecTarget->y = pVecA->y + (pVecB->y - pVecA->y) * BlendFactor; pVecTarget->z = pVecA->z + (pVecB->z - pVecA->z) * BlendFactor; #endif } // smooth lerp (sine) void fvec_slerp(FVECTOR * pVecTarget, FVECTOR * pVecA, FVECTOR * pVecB, float BlendFactor) { #ifndef FVEC_UNSAFE if(pVecTarget == NULL || pVecA == NULL || pVecB == NULL) { printf("error in 'fvec_slerp()':nnempty pointer."); return; } #endif BlendFactor = clamp(BlendFactor, 0.0, 1.0); BlendFactor = BlendFactor * BlendFactor * (3.0 - BlendFactor * 2.0); #ifdef FVEC_USE_TEMP_VECTORS FVECTOR TempVec; TempVec.x = pVecA->x + (pVecB->x - pVecA->x) * BlendFactor; TempVec.y = pVecA->y + (pVecB->y - pVecA->y) * BlendFactor; TempVec.z = pVecA->z + (pVecB->z - pVecA->z) * BlendFactor; fvec_set(pVecTarget, &TempVec); #else pVecTarget->x = pVecA->x + (pVecB->x - pVecA->x) * BlendFactor; pVecTarget->y = pVecA->y + (pVecB->y - pVecA->y) * BlendFactor; pVecTarget->z = pVecA->z + (pVecB->z - pVecA->z) * BlendFactor; #endif } // uses degrees void fvec_for_angle(FVECTOR * pVec, FANGLE * pAng) { #ifndef FVEC_UNSAFE if(pVec == NULL || pAng == NULL) { printf("error in 'fvec_for_angle()':nnempty pointer."); return; } #endif float pan = DEG_TO_RAD(pAng->pan); float tilt = DEG_TO_RAD(pAng->tilt); float roll = DEG_TO_RAD(pAng->roll); pVec->x = cos(pan) * cos(tilt); pVec->y = sin(pan) * cos(tilt); pVec->z = sin(tilt); } // uses radians void fvec_for_angle_rad(FVECTOR * pVec, FANGLE * pAng) { #ifndef FVEC_UNSAFE if(pVec == NULL || pAng == NULL) { printf("error in 'fvec_for_angle_rad()':nnempty pointer."); return; } #endif pVec->x = cos(pAng->pan) * cos(pAng->tilt); pVec->y = sin(pAng->pan) * cos(pAng->tilt); pVec->z = sin(pAng->tilt); } // uses degrees void fvec_to_angle(FANGLE * pAng, FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pAng == NULL || pVec == NULL) { printf("error in 'fvec_to_angle()':nnempty pointer."); return; } #endif pAng->pan = RAD_TO_DEG(atan(pVec->y / pVec->x)); pAng->tilt = RAD_TO_DEG(asin(pVec->z / fvec_length(pVec))); pAng->roll = 0.0; } // uses radians void fvec_to_angle_rad(FANGLE * pAng, FVECTOR * pVec) { #ifndef FVEC_UNSAFE if(pAng == NULL || pVec == NULL) { printf("error in 'fvec_to_angle_rad()':nnempty pointer."); return; } #endif pAng->pan = atan(pVec->y / pVec->x); pAng->tilt = asin(pVec->z / fvec_length(pVec)); pAng->roll = 0.0; } // uses degrees void fvec_rotate(FVECTOR * pVec, FANGLE * pAng) { #ifndef FVEC_UNSAFE if(pVec == NULL || pAng == NULL) { printf("error in 'fvec_rotate()':nnempty pointer."); return; } #endif float pan_sin = sin(DEG_TO_RAD(pAng->pan)); float pan_cos = cos(DEG_TO_RAD(pAng->pan)); float tilt_sin = sin(DEG_TO_RAD(pAng->tilt)); float tilt_cos = cos(DEG_TO_RAD(pAng->tilt)); float roll_sin = sin(DEG_TO_RAD(pAng->roll)); float roll_cos = cos(DEG_TO_RAD(pAng->roll)); FVECTOR new; new.x = pVec->x; new.y = pVec->y * roll_cos - pVec->z * roll_sin; new.z = pVec->y * roll_sin + pVec->z * roll_cos; pVec->x = new.x * tilt_cos - new.z * tilt_sin; pVec->y = new.y; pVec->z = new.x * tilt_sin + new.z * tilt_cos; new.x = pVec->x * pan_cos - pVec->y * pan_sin; new.y = pVec->x * pan_sin + pVec->y * pan_cos; new.z = pVec->z; fvec_set(pVec, &new); } // uses radians void fvec_rotate_rad(FVECTOR * pVec, FANGLE * pAng) { #ifndef FVEC_UNSAFE if(pVec == NULL || pAng == NULL) { printf("error in 'fvec_rotate_rad()':nnempty pointer."); return; } #endif float pan_sin = sin(pAng->pan); float pan_cos = cos(pAng->pan); float tilt_sin = sin(pAng->tilt); float tilt_cos = cos(pAng->tilt); float roll_sin = sin(pAng->roll); float roll_cos = cos(pAng->roll); FVECTOR new; new.x = pVec->x; new.y = pVec->y * roll_cos - pVec->z * roll_sin; new.z = pVec->y * roll_sin + pVec->z * roll_cos; pVec->x = new.x * tilt_cos - new.z * tilt_sin; pVec->y = new.y; pVec->z = new.x * tilt_sin + new.z * tilt_cos; new.x = pVec->x * pan_cos - pVec->y * pan_sin; new.y = pVec->x * pan_sin + pVec->y * pan_cos; new.z = pVec->z; fvec_set(pVec, &new); } void fang_rotate(FANGLE * pAngA, FANGLE * pAngB) { #ifndef FVEC_UNSAFE if(pAngA == NULL || pAngB == NULL) { printf("error in 'fang_rotate()':nnempty pointer."); return; } #endif FVECTOR TempVec; float roll = pAngA->roll + pAngB->roll; fvec_for_angle(&TempVec, pAngB); fvec_rotate(&TempVec, pAngA); fvec_to_angle(pAngA, &TempVec); pAngA->roll = roll; } void fang_rotate_rad(FANGLE * pAngA, FANGLE * pAngB) { #ifndef FVEC_UNSAFE if(pAngA == NULL || pAngB == NULL) { printf("error in 'fang_rotate_rad()':nnempty pointer."); return; } #endif FVECTOR TempVec; float roll = pAngA->roll + pAngB->roll; fvec_for_angle_rad(&TempVec, pAngA); fvec_rotate_rad(&TempVec, pAngB); fvec_to_angle_rad(pAngA, &TempVec); pAngA->roll = roll; } float fvec_accelerate(FVECTOR * pVecSpeed, FVECTOR * pVecAccel, float Friction) { #ifndef FVEC_UNSAFE if(pVecSpeed == NULL || pVecAccel == NULL) { printf("error in 'fvec_accelerate()':nnempty pointer."); return; } #endif FVECTOR Distance; float ftime_step = (float)time_step; if(Friction == 0) { Distance.x = pVecSpeed->x * ftime_step + pVecAccel->x * ftime_step * ftime_step * 0.5; Distance.y = pVecSpeed->y * ftime_step + pVecAccel->y * ftime_step * ftime_step * 0.5; Distance.z = pVecSpeed->z * ftime_step + pVecAccel->z * ftime_step * ftime_step * 0.5; pVecSpeed->x += pVecAccel->x * ftime_step; pVecSpeed->y += pVecAccel->y * ftime_step; pVecSpeed->z += pVecAccel->z * ftime_step; } else { float InvFriction = 1.0 / Friction; float TempFactor = (1.0 - exp(-Friction * ftime_step)) * InvFriction; Distance.x = pVecAccel->x * ftime_step * InvFriction + (pVecSpeed->x - pVecAccel->x * InvFriction) * TempFactor; Distance.y = pVecAccel->y * ftime_step * InvFriction + (pVecSpeed->y - pVecAccel->y * InvFriction) * TempFactor; Distance.z = pVecAccel->z * ftime_step * InvFriction + (pVecSpeed->z - pVecAccel->z * InvFriction) * TempFactor; TempFactor = exp(-Friction * ftime_step); pVecSpeed->x = pVecAccel->x * InvFriction + (pVecSpeed->x - pVecAccel->x * InvFriction) * TempFactor; pVecSpeed->y = pVecAccel->y * InvFriction + (pVecSpeed->y - pVecAccel->y * InvFriction) * TempFactor; pVecSpeed->z = pVecAccel->z * InvFriction + (pVecSpeed->z - pVecAccel->z * InvFriction) * TempFactor; } return fvec_length(&Distance); } // void _FVEC_startup() { fnullvector = sys_malloc(sizeof(FVECTOR)); fnullvector->x = 0; fnullvector->y = 0; fnullvector->z = 0; // FVEC_INITIALIZED = 1; } #endif
or download here.
edit: for more info have a look at the file
edit2: small changes to fvec_normalize()