////////////////////////////////////////////////////////////////////// // fp3: 3D point class. struct Pointf3 : Moveable { 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 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 Unit(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(Pointf a, Pointf 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)); 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 Unit(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 { 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; 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; };