/*--------------\
| General Geometry library
|
| These functions perform operations on
| polygons, triangles, planes, vectors, points,
| lines, rays, and segments, etc...
|
\--------------*/
/*----------------------\
| NOTES:
| unlike the underlying vector library, no special effort was made
| to make this library particularily robust, what I mean by that is
| PASSING THE SAME BUFFER FOR DESTINATION AND SOURCE MAY FAIL!
| The code is the only real documentation for this.
|
| Also unlike the vector library, functions return either void or int,
| depending on whether or not the math is "unstable".
| (e.g. plane-plane intersection that never
| happens because the planes are parallel)
|
| All effort was made to make this library behave in a resonable manner.
| A simple epsilon value may be set and should any divisor ever fall below this
| value in magnitude then the function in question will return 0.
| (although the full calculation will still be performed)
| Functions that are inherently "stable" are simply typed void.
| All functions that can be "stable" are.
| Affine invarience is preserved as far as I know.
|
| This library is designed to make as few decisions for you as possible,
| in other words it is a dumb geometry library. For example, the function
| int geomPRdV[fd](v[3], p[4]. o[3], d[3])
| returns 0 only when a divisor approaches 0, if the ray simply does not
| intersect the plane (because it points away) this will not affect the math.
| if you want to check for plane ray intersection use geomPRdZ[fd]() to get
| the distance along the ray to the plane.
| If this distance is negative, then the ray is pointing away.
|
| It is assumed that all unit vectors are indeed unit vectors etc....
\-----------------------*/
/*--------------------\
| <<Naming>>
|
| geom{SrcTypes}{Operation(s)}{DstTypes}[fd](DstList..., SrcList...);
| Sources and destinations are listed
| 1. in size order, larger first, (see list below)
| 2. "operated on" before "environment" (geomVVpV[fd](dst, v, dir))
| 3. as noted.
+---------------------+
|
| <<Types>>
|
| T:triangle : p1[3], p2[3], p3[3]
| L:line : origin[3], direction[3] (in prototypes: o[3], d[3])
| R:ray : origin[3], direction[3] (in prototypes: o[3], d[3])
| S:segement : a[3], b[3]
| D:edge : a[3], b[3], counter clockwise around polygon
| P:plane : p[4] = {A,B,C,D}, defined by A*x + B*y + C*z + D == 0
| Q:2-space line : q[3] = {A,B,C}, defined by A*x + B*y + C == 0
| V:vector : v[3]
| U:unit vector : u[3], norm3(u) == 1.0
| X:point : x[3]
| W:2-direction : w[2]
| E:2-point : e[2]
| Z:scalar : z
| C:class int : i, bool or enum
|
+---------------------+
|
| <<Operations>>
|
| x:intersection
| d:distance
| c:classification
| n:nearest
| i:interpret
| p:project
|
\---------------------*/
/*--------------------------------------\
| Disclaimer:
| This code is certified by me to work, and work well,
| Since I have no credentials as yet,
| (perhaps other than this code here)
| my certification means nothing whatsoever.
|
| Simply stated: USE AT YOUR OWN RISK
|
| You have permision to use this library free
| free programs free of charge.
| However for anything commercial, I get
| a copy of the product.
\---------------------------------------*/
#ifndef GEOM_H_
#define GEOM_H_
#define _F float
#define _D double
#define _CF const float
#define _CD const double
#if defined(WIN32) && !defined(GEOM_NO_DLL)
# ifdef GEOM_BUILD_DLL
# define GEOM_SPEC __declspec(dllexport)
# else
# define GEOM_SPEC __declspec(dllimport)
# ifndef CZ_NOLIBPRAGMA
# pragma comment(lib, "geom")
# endif
# endif
# define GEOM_CALL __stdcall
#else
# ifdef WIN32
# define GEOM_SPEC
# define GEOM_CALL __stdcall
# else
# define GEOM_SPEC
# define GEOM_CALL
# endif
#endif
#define GEOM_R(ret) GEOM_SPEC ret GEOM_CALL
#ifndef GEOM_NO_CHECK
# ifndef GEOM_CHECKS_ABORT
/* Default case, checking performed, no abort on failure */
# define GEOM_CHECK_VAR int __check;
# define GEOM_CHECK_PASS(exp) __check = exp
# define GEOM_CHECKf(n) (__check = geomZcCf(n))
# define GEOM_CHECKd(n) (__check = geomZcCd(n))
# define GEOM_CHECK_RETURN return __check;
# define GEOM_CHECK_TYPE int
# else
/* GEOM_CHECKS_ABORT defined, we return a value immediatly after failure */
# define GEOM_CHECK_VAR
# define GEOM_CHECK_PASS(exp) if(!(exp)) return 0
# define GEOM_CHECKf(n) do if(!geomZcCf(n)) return 0; while(0)
# define GEOM_CHECKd(n) do if(!geomZcCd(n)) return 0; while(0)
# define GEOM_CHECK_RETURN return 1;
# define GEOM_CHECK_TYPE int
# endif
#else
/* Fast mode, all checks turned off */
# define GEOM_CHECK_VAR
# define GEOM_CHECK_PASS(exp) exp
# define GEOM_CHECKf(n)
# define GEOM_CHECKd(n)
# define GEOM_CHECK_RETURN
# define GEOM_CHECK_TYPE void
#endif
/*----------------\
| Set epsilon value, values less than this will be "considered 0"
| (this would be the (+-)distance from a plane which is still "on" the plane
| NOTE: (float and double epsilons are maintained SEPERATELY!)
| returns the previous value
| Only available when checking is supported.
\----------------*/
#ifndef GEOM_NO_CHECK
_F geomSetEpsilionf(_F epsilonf);
_D geomSetEpsiliond(_D epsilond);
#endif
/*----------------\
| check against epsilon values
\----------------*/
#ifndef GEOM_NO_CHECK
GEOM_R(int) geomZcCf(_F f);
GEOM_R(int) geomZcCd(_D d);
#endif
/*----------------\
| Point to point distance
\----------------*/
GEOM_R(void) geomXXdZf(_F *z, _CF x1[3], _CF x2[3]);
GEOM_R(void) geomXXdZd(_D *z, _CD x1[3], _CD x2[3]);
/*----------------\
| Point to point difference
\----------------*/
GEOM_R(void) geomXXdVf(_F v[3], _CF x1[3], _CF x2[3]);
GEOM_R(void) geomXXdVd(_D b[3], _CD x1[3], _CD x2[3]);
/*----------------\
| normalize vector
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomViUf(_F u[3], _CF v[3]);
GEOM_R(GEOM_CHECK_TYPE) geomViUd(_D u[3], _CD v[3]);
/*----------------\
| line is an equivalent format to ray
\----------------*/
#define geomSiLf geomSiRf
#define geomSiLd geomSiRd
/*----------------\
| Ray from a to b
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomSiRf(_F o[3], _F d[3], _CF a[3], _CF b[3]);
GEOM_R(GEOM_CHECK_TYPE) geomSiRd(_D o[3], _D d[3], _CD a[3], _CD b[3]);
/*----------------\
| interpret ray to plane
\----------------*/
GEOM_R(void) geomRiPd(_D p[4], _CD o[3], _CD d[3]);
GEOM_R(void) geomRiPf(_F p[4], _CF o[3], _CF d[3]);
/*----------------\
| Interpret plane from Triangle
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomTiPf(_F p[4], _CF p1[3], _CF p2[3], _CF p3[3]);
GEOM_R(GEOM_CHECK_TYPE) geomTiPd(_D p[4], _CD p1[3], _CD p2[3], _CD p3[3]);
/*----------------\
| project vector
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomVVpVf(_F dst[3], _CF v[3], _CF vref[3]);
GEOM_R(GEOM_CHECK_TYPE) geomVVpVd(_D dst[3], _CD v[3], _CD vref[3]);
/*-----------------------------------\
| classify point as "inside" segment,
| returns
| 1: point "between" the planes at the segment's endpoints
| 0: otherwise
\-----------------------------------*/
GEOM_R(GEOM_CHECK_TYPE) geomSXcCf(int *i, _CF a[3], _CF b[3], _CF x[3]);
GEOM_R(GEOM_CHECK_TYPE) geomSXcCd(int *i, _CD a[3], _CD b[3], _CD x[3]);
/*----------------\
| Point along ray
\----------------*/
GEOM_R(void) geomRZiXf(_F x[3], _CF o[3], _CF d[3], _F z);
GEOM_R(void) geomRZiXd(_D x[3], _CD o[3], _CD d[3], _D z);
/*----------------\
| Distance to Line from point
\----------------*/
GEOM_R(void) geomLXdZf(_F *f, _CF o[3], _CF d[3], _CF x[3]);
GEOM_R(void) geomLXdZd(_D *f, _CD o[3], _CD d[3], _CD x[3]);
/*----------------\
| Distance to Ray from point
\----------------*/
#define geomRXdZf geomLXdZf
#define geomRXdZd geomLXdZd
/*----------------\
| Closest point on line to point
\----------------*/
GEOM_R(void) geomLXnXf(_F ox[3], _CF o[3], _CF d[3], _CF x[3]);
GEOM_R(void) geomLXnXd(_D ox[3], _CD o[3], _CD d[3], _CD x[3]);
/*----------------\
| Closest vector from point to line
\----------------*/
GEOM_R(void) geomLXdVf(_F dif[3], _CF o[3], _CF d[3], _CF v[3]);
GEOM_R(void) geomLXdVd(_D dif[3], _CD o[3], _CD d[3], _CD v[3]);
/*----------------\
| Distance from line to line
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLdZf(_F *d, _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLdZd(_D *d, _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| Nearest point on line a to line b
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLnXf(_F n[3], _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLnXd(_D n[3], _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| Difference vector from line to line
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLdVf(_F x[3], _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLdVd(_D x[3], _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| Nearest point on first line w/ distance between lines
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLndXZf(_F p[3], _F *z, _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLndXZd(_D p[3], _D *z, _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| Nearest 2 points on lines a, b
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLnnXXf(_F x1[3], _F x2[3], _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLnnXXd(_D x1[3], _D x2[3], _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| Nearest point on first line w/ minimum vector to the other
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomLLndXVf(_F x[3], _F d[3], _CF o1[3], _CF d1[3], _CF o2[3], _CF d2[3]);
GEOM_R(GEOM_CHECK_TYPE) geomLLndXVd(_D x[3], _D d[3], _CD o1[3], _CD d1[3], _CD o2[3], _CD d2[3]);
/*----------------\
| (signed) Distance from a Plane
\----------------*/
GEOM_R(void) geomPXdZf(_F *z, _CF p[4], _CF x[3]);
GEOM_R(void) geomPXdZd(_D *z, _CD p[4], _CD x[3]);
/*----------------\
| (signed) Intersection distance along ray
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomPRxZf(_F *x, _CF p[4], _CF o[3], _CF d[3]);
GEOM_R(GEOM_CHECK_TYPE) geomPRxZd(_D *x, _CD p[4], _CD o[3], _CD d[3]);
/*----------------\
| Nearest point on plane to another point
\----------------*/
GEOM_R(void) geomPXnXf(_F ox[3], _CF p[4], _CF x[3]);
GEOM_R(void) geomPXnXd(_D ox[3], _CD p[4], _CD x[3]);
/*----------------\
| Could be thought of as a projection...
\----------------*/
#define geomPXpXf geomPXnXf
#define geomPXpXd geomPXnXd
/*----------------\
| Nearest vector from point to plane
\----------------*/
GEOM_R(void) geomPXdVf(_F v[3], _CF p[4], _CF x[3]);
GEOM_R(void) geomPXdVd(_D v[3], _CD p[4], _CD x[3]);
/*----------------\
| Plane-line intersection point
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomPLxXf(_F x[3], _CF p[4], _CF o[3], _CF d[3]);
GEOM_R(GEOM_CHECK_TYPE) geomPLxXd(_D x[3], _CD p[4], _CD o[3], _CD d[3]);
/*----------------\
| Plane-ray intersection is equivalent
\----------------*/
#define geomPRxXf geomPLxXf
#define geomPRxXd geomPLxXd
/*----------------\
| Intersection vector along ray
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomPRdVf(_F v[3], _CF p[4], _CF o[3], _CF d[3]);
GEOM_R(GEOM_CHECK_TYPE) geomPRdVd(_D v[3], _CD p[4], _CD o[3], _CD d[3]);
/*----------------\
| Line at Plane-Plane intersection
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomPPxLf(_F o[3], _F d[3], _F p1[4], _F p2[4]);
GEOM_R(GEOM_CHECK_TYPE) geomPPxLd(_D o[3], _D d[3], _D p1[4], _D p2[4]);
/*----------------\
| project 3-space point into 2-space (tangent space) given by e_1 and e_2
\----------------*/
GEOM_R(void) geomVVXiEf(_F w[2], _CF ve1[3], _CF ve2[3], _CF x[3]);
GEOM_R(void) geomVVXiEd(_D w[2], _CD ve1[3], _CD ve2[3], _CD x[3]);
/*----------------\
| since this interpretation is a "projection" in a sense...
\----------------*/
#define geomVVXpEf geomVVXiEf
#define geomVVXpEd geomVVXiEd
/*----------------\
| vectors interpret/project too...
\----------------*/
#define geomVVViWf geomVVXiEf
#define geomVVViWd geomVVXiEd
#define geomVVVpWf geomVVXiEf
#define geomVVVpWd geomVVXiEd
/*----------------\
| Ray projected onto a plane
\----------------*/
GEOM_R(GEOM_CHECK_TYPE) geomPRpRf(_F oo[3], _F od[3], _CF p[4], _CF o[3], _CF d[3]);
GEOM_R(GEOM_CHECK_TYPE) geomPRpRd(_D oo[3], _D od[3], _CD p[4], _CD o[3], _CD d[3]);
/*----------------\
| a ray is a line
\----------------*/
#define geomPRpLf geomPRpRf
#define geomPRpLd geomPRpRd
#define geomPLpLf geomPRpRf
#define geomPLpLd geomPRpRd
/*----------------\
| point rotated around line
\----------------*/
GEOM_R(void) geomLXZrXf(_F ox[3], _CF o[3], _CF d[3], _CF x[3], _F rad);
GEOM_R(void) geomLXZrXd(_D ox[3], _CD o[3], _CD d[3], _CD x[3], _D rad);
/*----------------\
| point rotated around ray is the same...
\----------------*/
#define geomRXZrXf geomLXZrXf
#define geomRXZrXd geomLXZrXd
/*----------------\
| ray rotated around line
\----------------*/
GEOM_R(void) geomLRZrRf(_F oro[3], _F ord[3], _CF o[3], _CF d[3], _CF ro[3], _CF rd[3], _F rad);
GEOM_R(void) geomLRZrRd(_D oro[3], _D ord[3], _CD o[3], _CD d[3], _CD ro[3], _CD rd[3], _D rad);
/*----------------\
| line rotated around line is just as hard...
\----------------*/
#define geomLLZrLf geomLRZrRf
#define geomLLZrLd geomLRZrRd
/*----------------\
| could be phrased as line around ray...
\----------------*/
#define geomRLZrLf geomLRZrRf
#define geomRLZrLd geomLRZrRd
/*----------------\
| test for point interior to triangle
\----------------*/
GEOM_R(void) geomTXcCf(int *inside, _CF p1[3], _CF p2[3], _CF p3[3], _CF x[3]);
GEOM_R(void) geomTXcCd(int *inside, _CD p1[3], _CD p2[3], _CD p3[3], _CD x[3]);
/*----------------\
| test for point interior to triangle along specified normal
\----------------*/
GEOM_R(void) geomTVXcCf(int *inside, _CF p1[3], _CF p2[3], _CF p3[3], _CF v[3], _CF x[3]);
GEOM_R(void) geomTVXcCd(int *inside, _CD p1[3], _CD p2[3], _CD p3[3], _CD v[3], _CD x[3]);
/*----------------\
| test for point along ray
\----------------*/
GEOM_R(void) geomTRcCf(int *inside, _CF p1[3], _CF p2[3], _CF p3[3], _CF o[3], _CF d[3]);
GEOM_R(void) geomTRcCd(int *inside, _CD p1[3], _CD p2[3], _CD p3[3], _CD o[3], _CD d[3]);
/*----------------\
| test for point interior to polygon edge
\----------------*/
GEOM_R(void) geomPDXcCf(int *inside, _CF p[4], _CF a[3], _CF b[3], _CF x[3]);
GEOM_R(void) geomPDXcCd(int *inside, _CD p[4], _CD a[3], _CD b[3], _CD x[3]);
#endif