ultimatepp/uppsrc/Geom/fp3.h
2023-10-11 17:25:40 +02:00

296 lines
16 KiB
C++

//////////////////////////////////////////////////////////////////////
// fp3: 3D point class.
struct Pointf3 : Moveable<Pointf3>
{
public:
Pointf3() {}
Pointf3(const Nuller&) : x(Null), y(Null), z(Null) {}
Pointf3(double x, double y, double z) : x(x), y(y), z(z) {}
Pointf3(Pointf p, double z = 0) : x(p.x), y(p.y), z(z) {}
explicit Pointf3(double t) : x(t), y(t), z(t) {}
void Serialize(Stream& stream) { stream % x % y % z; }
double operator [] (int i) const { return i == 0 ? x : i == 1 ? y : z; }
double& operator [] (int i) { return i == 0 ? x : i == 1 ? y : z; }
Pointf XY() const { return Pointf(x, y); }
Pointf YX() const { return Pointf(y, x); }
Pointf YZ() const { return Pointf(y, z); }
Pointf ZY() const { return Pointf(y, z); }
Pointf XZ() const { return Pointf(x, z); }
Pointf ZX() const { return Pointf(z, x); }
Pointf3& operator += (Pointf3 p) { x += p.x; y += p.y; z += p.z; return *this; }
Pointf3& operator -= (Pointf3 p) { x -= p.x; y -= p.y; z -= p.z; return *this; }
Pointf3& operator *= (double val) { x *= val; y *= val; z *= val; return *this; }
Pointf3& operator *= (Pointf3 p) { x *= p.x; y *= p.y; z *= p.z; return *this; }
Pointf3& operator /= (double val) { x /= val; y /= val; z /= val; return *this; }
Pointf3& operator /= (Pointf3 p) { x /= p.x; y /= p.y; z /= p.z; return *this; }
public:
double x, y, z;
};
//inline Pointf3 Pointf3_0() { return Pointf3(0, 0, 0); }
//inline Pointf3 Pointf3_X() { return Pointf3(1, 0, 0); }
//inline Pointf3 Pointf3_Y() { return Pointf3(0, 1, 0); }
//inline Pointf3 Pointf3_Z() { return Pointf3(0, 0, 1); }
//inline Pointf3 Pointf3_Null() { return Pointf3(Null); }
inline bool IsNull(Pointf3 p) { return IsNull(p.x); }
inline Pointf3 Nvl(Pointf3 p, Pointf3 q) { return !IsNull(p) ? p : q; }
extern String AsString(const Pointf3& p);
inline bool operator == (Pointf3 p, Pointf3 q) { return q.x == p.x && q.y == p.y && q.z == p.z; }
inline bool operator != (Pointf3 p, Pointf3 q) { return !(q == p); }
inline Pointf3 operator - (Pointf3 p) { return Pointf3(-p.x, -p.y, -p.z); }
inline Pointf3 operator + (Pointf3 p, Pointf3 q) { return Pointf3(p.x + q.x, p.y + q.y, p.z + q.z); }
inline Pointf3 operator - (Pointf3 p, Pointf3 q) { return Pointf3(p.x - q.x, p.y - q.y, p.z - q.z); }
inline Pointf3 operator * (Pointf3 p, double val) { return Pointf3(p.x * val, p.y * val, p.z * val); }
inline Pointf3 operator * (Pointf3 p, Pointf3 q) { return Pointf3(p.x * q.x, p.y * q.y, p.z * q.z); }
inline Pointf3 operator * (double val, Pointf3 p) { return Pointf3(p.x * val, p.y * val, p.z * val); }
inline Pointf3 operator / (Pointf3 p, double val) { return Pointf3(p.x / val, p.y / val, p.z / val); }
inline Pointf3 operator / (Pointf3 p, Pointf3 q) { return Pointf3(p.x / q.x, p.y / q.y, p.z / q.z); }
inline double ScalarProduct(Pointf3 p, Pointf3 q) { return p.x * q.x + p.y * q.y + p.z * q.z; }
inline Pointf3 VectorProduct(Pointf3 p, Pointf3 q) { return Pointf3(p.y * q.z - p.z * q.y, p.z * q.x - p.x * q.z, p.x * q.y - p.y * q.x); }
inline double operator ^ (Pointf3 p, Pointf3 q) { return p.x * q.x + p.y * q.y + p.z * q.z; }
inline Pointf3 operator % (Pointf3 p, Pointf3 q) { return Pointf3(p.y * q.z - p.z * q.y, p.z * q.x - p.x * q.z, p.x * q.y - p.y * q.x); }
inline Pointf3 Mid(Pointf3 p, Pointf3 q) { return Pointf3((p.x + q.x) / 2, (p.y + q.y) / 2, (p.z + q.z) / 2); }
inline Pointf3 Mid(Pointf3 p, Pointf3 q, double w) { return p + (q - p) * w; }
inline double Squared(Pointf3 p) { return p.x * p.x + p.y * p.y + p.z * p.z; }
inline double Length(Pointf3 p) { return sqrt(Squared(p)); }
extern Pointf3 Length(Pointf3 p, double l);
inline double Distance(Pointf3 p, Pointf3 q) { return Length(p - q); }
inline Pointf3 UnitV(Pointf3 p) { return Length(p, 1.0); }
inline Pointf3 Scale(Pointf3 p, double d, Pointf3 c = Pointf(0, 0)) { return (p - c) * d + c; }
inline double Determinant(Pointf3 a, Pointf3 b, Pointf3 c) { return (a % b) ^ c; }
extern Pointf3 Bezier2(Pointf3 a, Pointf3 b, Pointf3 c, double t);
extern Pointf3 Orthogonal(Pointf3 v, Pointf3 against);
extern Pointf3 Orthonormal(Pointf3 v, Pointf3 against);
extern Pointf3 FarthestAxis(Pointf3 v);
extern Pointf3 AtLine(Pointf3 a, double ta, Pointf3 b, double tb, double tx, double *ratio = NULL);
inline double GetXYBearing(Pointf3 a) { return atan2(a.y, a.x); }
inline double GetYZBearing(Pointf3 a) { return atan2(a.z, a.y); }
inline double GetZXBearing(Pointf3 a) { return atan2(a.x, a.z); }
extern double Angle(Pointf3 a, Pointf3 b);
inline Pointf3 fpmin(Pointf3 p, Pointf3 q) { return Pointf3(min(p.x, q.x), min(p.y, q.y), min(p.z, q.z)); }
inline Pointf3 fpmax(Pointf3 p, Pointf3 q) { return Pointf3(max(p.x, q.x), max(p.y, q.y), max(p.z, q.z)); }
inline double fpmin(Pointf3 p) { return min(min(p.x, p.y), p.z); }
inline double fpmax(Pointf3 p) { return max(max(p.x, p.y), p.z); }
inline double fpabsmin(Pointf3 p) { return min(min(fabs(p.x), fabs(p.y)), fabs(p.z)); }
inline double fpabsmax(Pointf3 p) { return max(max(fabs(p.x), fabs(p.y)), fabs(p.z)); }
inline Pointf3 PolarPointf3XY(double angle) { return Pointf3(cos(angle), sin(angle), 0.0); }
inline Pointf3 PolarPointf3YZ(double angle) { return Pointf3(0.0, cos(angle), sin(angle)); }
inline Pointf3 PolarPointf3ZX(double angle) { return Pointf3(sin(angle), 0.0, cos(angle)); }
extern Pointf3 RotateX(Pointf3 v, double angle, Pointf3 centre = Pointf3(0, 0, 0));
extern Pointf3 RotateY(Pointf3 v, double angle, Pointf3 centre = Pointf3(0, 0, 0));
extern Pointf3 RotateZ(Pointf3 v, double angle, Pointf3 centre = Pointf3(0, 0, 0));
extern Pointf3 Rotate(Pointf3 v, Pointf3 axis, double angle, Pointf3 centre = Pointf3(0, 0, 0));
double LineSegmentsDistance(const Pointf3& P0, const Pointf3& P1, const Pointf3& Q0, const Pointf3& Q1);
class Plane3
{
public:
Plane3() {}
Plane3(double delta, Pointf3 normal) : delta(delta), normal(normal) {}
Plane3(Pointf3 A, Pointf3 normal) : delta(-(normal ^ A)), normal(normal) {}
Plane3(Pointf3 A, Pointf3 B, Pointf3 C) { normal = (B - A) % (C - A); delta = -(normal ^ A); }
public:
double delta;
Pointf3 normal; // (normal ^ point) + delta = 0
};
String AsString(const Plane3& plane);
inline double Distance(Plane3 plane, Pointf3 point) { return (point ^ plane.normal) + plane.delta; }
extern double Intersect(Plane3 p, Pointf3 la, Pointf3 lb);
inline Plane3 operator - (Plane3 p) { return Plane3(-p.delta, -p.normal); }
inline Plane3& operator += (Plane3& p, Pointf3 v) { p.delta += v ^ p.normal; return p; }
inline Plane3& operator -= (Plane3& p, Pointf3 v) { p.delta -= v ^ p.normal; return p; }
inline Plane3 operator + (Plane3 p, Pointf3 v) { Plane3 r = p; r += v; return r; }
inline Plane3 operator - (Plane3 p, Pointf3 v) { Plane3 r = p; r -= v; return r; }
extern Plane3 Unit3(Plane3 p);
struct Matrixf3;
const Matrixf3& Matrixf3_0();
const Matrixf3& Matrixf3_1();
const Matrixf3& Matrixf3_Null();
const Matrixf3& Matrixf3_MirrorX(); // mirror X axis
const Matrixf3& Matrixf3_MirrorY(); // mirror Y axis
const Matrixf3& Matrixf3_MirrorZ(); // mirror Z axis
struct Matrixf3 : Moveable<Matrixf3>
{
Pointf3 x, y, z, a;
Matrixf3() { *this = Matrixf3_1(); }
Matrixf3(const Nuller&) : a(Null) {}
Matrixf3(Pointf3 x, Pointf3 y, Pointf3 z, Pointf3 a = Pointf3(0, 0, 0))
: x(x), y(y), z(z), a(a) {}
Matrixf3(const Matrixf3& (*fn)()) { *this = fn(); }
Matrixf3(double xx, double xy, double xz,
double yx, double yy, double yz,
double zx, double zy, double zz,
double ax = 0, double ay = 0, double az = 0)
: x(xx, xy, xz), y(yx, yy, yz), z(zx, zy, zz), a(ax, ay, az) {}
void Serialize(Stream& stream);
bool IsIdentity() const { return x.x == 1 && x.y == 0 && x.z == 0 && y.x == 0 && y.y == 1 && y.z == 0 && z.x == 0 && z.y == 0 && z.z == 1 && a.x == 0 && a.y == 0 && a.z == 0; }
bool IsZero() const { return x.x == 0 && x.y == 0 && x.z == 0 && y.x == 0 && y.y == 0 && y.z == 0 && z.x == 0 && z.y == 0 && z.z == 0 && a.x == 0 && a.y == 0 && a.z == 0; }
bool IsNullInstance() const { return IsNull(a); }
Matrixf3& Fix(const Pointf3& v) { a = v - v.x * x - v.y * y - v.z * z; return *this; }
Matrixf3& operator *= (const Matrixf3& another);
Pointf3 CX() const { return Pointf3(x.x, y.x, z.x); }
Pointf3 CY() const { return Pointf3(x.y, y.y, z.y); }
Pointf3 CZ() const { return Pointf3(x.z, y.z, z.z); }
String ToString() const;
};
inline Matrixf3& operator *= (Matrixf3& m, double d) { m.x *= d; m.y *= d; m.z *= d; m.a *= d; return m; }
inline Matrixf3& operator /= (Matrixf3& m, double d) { m.x /= d; m.y /= d; m.z /= d; m.a /= d; return m; }
//template DumpType<Matrixf3>;
extern Matrixf3 Matrixf3Move (Pointf3 vector);
extern Matrixf3 Matrixf3RotateX(double angle, Pointf3 fix = Pointf3(0, 0, 0));
extern Matrixf3 Matrixf3RotateY(double angle, Pointf3 fix = Pointf3(0, 0, 0));
extern Matrixf3 Matrixf3RotateZ(double angle, Pointf3 fix = Pointf3(0, 0, 0));
extern Matrixf3 Matrixf3Rotate (Pointf3 axis, double angle);
extern Matrixf3 Matrixf3Scale (double scale, Pointf3 fix = Pointf3(0, 0, 0));
extern Matrixf3 Matrixf3Scale (Pointf3 scale, Pointf3 fix = Pointf3(0, 0, 0));
//extern Matrixf3 Matrixf3Mirror (Pointf A, Pointf B);
extern Matrixf3 Matrixf3Affine(Pointf3 src1, Pointf3 dest1, Pointf3 src2, Pointf3 dest2);
extern Matrixf3 Matrixf3Affine(Pointf3 src1, Pointf3 dest1, Pointf3 src2, Pointf3 dest2,
Pointf3 src3, Pointf3 dest3);
extern Matrixf3 Matrixf3Affine(Pointf3 src1, Pointf3 dest1, Pointf3 src2, Pointf3 dest2,
Pointf3 src3, Pointf3 dest3, Pointf3 src4, Pointf3 dest4);
extern Matrixf3 Matrixf3Inverse(const Matrixf3& mx);
extern double Determinant (const Matrixf3& mx);
inline bool IsReversing (const Matrixf3& mx) { return Determinant(mx) < 0; }
extern double Matrixf3Measure(const Matrixf3& mx);
inline bool operator == (const Matrixf3& m1, const Matrixf3& m2) { return m1.x == m2.x && m1.y == m2.y && m1.z == m2.z && m1.a == m2.a; }
inline bool operator != (const Matrixf3& m1, const Matrixf3& m2) { return !(m1 == m2); }
inline Pointf3 operator % (Pointf3 vector, const Matrixf3& matrix) { return vector.x * matrix.x + vector.y * matrix.y + vector.z * matrix.z; }
inline Pointf3 operator * (Pointf3 point, const Matrixf3& matrix) { return point % matrix + matrix.a; }
inline Pointf3& operator %= (Pointf3& point, const Matrixf3& matrix) { return point = point % matrix; }
inline Pointf3& operator *= (Pointf3& point, const Matrixf3& matrix) { return point = point * matrix; }
inline Matrixf3 operator * (const Matrixf3& m1, const Matrixf3& m2) { return Matrixf3(m1) *= m2; }
inline Matrixf3 operator / (const Matrixf3& m1, const Matrixf3& m2) { return m1 * Matrixf3Inverse(m2); }
extern Plane3 operator * (Plane3 p, const Matrixf3& m);
const double BIGDOUBLE = 1e300;
class Box3
{
public:
Box3(const Nuller& = Null) { low[0] = Null; }
Box3(const Pointf3 *n, const double *l, const double *h)
{
normal[0] = n[0]; normal[1] = n[1]; normal[2] = n[2];
low[0] = l[0]; low[1] = l[1]; low[2] = l[2];
high[0] = h[0]; high[1] = h[1]; high[2] = h[2];
}
Plane3 GetMinPlane(int coord) const { return Plane3(low[coord], normal[coord]); }
Plane3 GetMaxPlane(int coord) const { return Plane3(-high[coord], -normal[coord]); }
bool IsEmpty() const { return low[0] > high[0] || low[1] > high[1] || low[2] > high[2]; }
void Clear() { low[0] = low[1] = low[2] = BIGDOUBLE; high[0] = high[1] = high[2] = -BIGDOUBLE; }
void Union(Pointf3 pt);
Pointf3 normal[3];
double low[3];
double high[3];
};
inline bool IsNull(Box3 b) { return IsNull(b.low[0]); }
class Camera
{
public:
Camera();
void Serialize(Stream& stream);
Camera& Location(Pointf3 new_location) { location = new_location; return *this; }
Camera& Target(Pointf3 new_target) { target = new_target; return *this; }
Camera& Upwards(Pointf3 new_upwards) { upwards = new_upwards; return *this; }
Camera& ViewingAngle(double new_va) { viewing_angle = new_va; return *this; }
Camera& Viewport(double wmm, double hmm) { width_mm = wmm; height_mm = hmm; return *this; }
Camera& Viewport(Sizef mm) { width_mm = mm.cx; height_mm = mm.cy; return *this; }
Camera& ViewportOffset(double xc, double yc) { shift_x = xc; shift_y = yc; return *this; }
Camera& ViewportSize(Sizef px) { view_px = px.cx; view_py = px.cy; return *this; }
Camera& ViewportSize(double px, double py) { view_px = px; view_py = py; return *this; }
Camera& Projection(const Matrixf3& pm) { projection_matrix = pm; return *this; }
Camera& FarDistance(double new_fd) { far_distance = new_fd; return *this; }
Camera& NearDistance(double new_nd) { near_distance = new_nd; return *this; }
double GetDistance(Pointf3 v) const { return (v ^ direction) + distance_delta; }
double GetLengthByDistance(double l, double d) { return l * near_distance / d; }
double GetDistanceByLength(double l, double t) { return near_distance * l / t; }
void Update(); // recalculates camera parameters
Pointf3 Transform(Pointf3 point) const;
bool TransformClip(Pointf3 a, Pointf3 b, Pointf& outa, Pointf& outb) const;
Pointf3 InverseXY(Pointf point, double z) const;
void SetPolar(Pointf3 dz, Pointf3 dx,
double distance, double azimuth, double bearing, double rotation);
void GetPolar(Pointf3 dz, Pointf3 dx,
double& distance, double& azimuth, double& bearing, double& rotation) const;
public:
Pointf3 location;
Pointf3 target;
Pointf3 upwards;
double viewing_angle;
double width_mm, height_mm;
double view_px, view_py;
double shift_x, shift_y;
double near_distance;
double far_distance;
Matrixf3 projection_matrix;
// calculated parameters
Pointf3 straight_up;
Pointf3 straight_right;
Pointf3 direction;
double distance_delta;
Matrixf3 camera_matrix;
Matrixf3 invcam_matrix;
Matrixf3 transform_matrix;
double z_delta;
double viewing_distance;
};