

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file MathClasses.h
    @brief Geometry and 2D/3D math value classes: Color, Size, Point, PointFloat, Line, PolyLine, Box, Vector2D, Vector3D and a random path generator.

    These lightweight value types are used across CMSDK/Psyclone for image
    regions, tracking, visualization and spatial reasoning. All members are
    public by design; the classes are simple aggregates with convenience math.
    Angles are radians unless noted; coordinate system is screen-style with
    the origin at the upper-left and y growing downward (relevant for Box). */
#if !defined(_MATHCLASSES_H)
#define _MATHCLASSES_H

#define _USE_MATH_DEFINES
// #define __USE_GNU
#include <math.h>
#include <map>
#include <array>

#include "Utils.h"

namespace cmlabs {

class Size;
class PointFloat;
class Vector2D;
class Vector3D;


/*! @brief Lookup table mapping ~200 CSS/X11 color names (with and without spaces) to 8-bit RGB triplets; used by Color(const char*). */
const std::map<std::string, std::array<uint8, 3> > ColorMap = {
	{ "maroon",{ { 128,0,0 } } },
	{ "dark red",{ { 139,0,0 } } },
	{ "darkred",{ { 139,0,0 } } },
	{ "brown",{ { 165,42,42 } } },
	{ "firebrick",{ { 178,34,34 } } },
	{ "crimson",{ { 220,20,60 } } },
	{ "red",{ { 255,0,0 } } },
	{ "tomato",{ { 255,99,71 } } },
	{ "coral",{ { 255,127,80 } } },
	{ "indian red",{ { 205,92,92 } } },
	{ "indianred",{ { 205,92,92 } } },
	{ "light coral",{ { 240,128,128 } } },
	{ "lightcoral",{ { 240,128,128 } } },
	{ "dark salmon",{ { 233,150,122 } } },
	{ "darksalmon",{ { 233,150,122 } } },
	{ "salmon",{ { 250,128,114 } } },
	{ "light salmon",{ { 255,160,122 } } },
	{ "lightsalmon",{ { 255,160,122 } } },
	{ "orange red",{ { 255,69,0 } } },
	{ "orangered",{ { 255,69,0 } } },
	{ "dark orange",{ { 255,140,0 } } },
	{ "darkorange",{ { 255,140,0 } } },
	{ "orange",{ { 255,165,0 } } },
	{ "gold",{ { 255,215,0 } } },
	{ "dark golden rod",{ { 184,134,11 } } },
	{ "darkgoldenrod",{ { 184,134,11 } } },
	{ "golden rod",{ { 218,165,32 } } },
	{ "goldenrod",{ { 218,165,32 } } },
	{ "pale golden rod",{ { 238,232,170 } } },
	{ "palegoldenrod",{ { 238,232,170 } } },
	{ "dark khaki",{ { 189,183,107 } } },
	{ "darkkhaki",{ { 189,183,107 } } },
	{ "khaki",{ { 240,230,140 } } },
	{ "olive",{ { 128,128,0 } } },
	{ "yellow",{ { 255,255,0 } } },
	{ "yellow green",{ { 154,205,50 } } },
	{ "yellowgreen",{ { 154,205,50 } } },
	{ "dark olive green",{ { 85,107,47 } } },
	{ "darkolivegreen",{ { 85,107,47 } } },
	{ "olive drab",{ { 107,142,35 } } },
	{ "olivedrab",{ { 107,142,35 } } },
	{ "lawn green",{ { 124,252,0 } } },
	{ "lawngreen",{ { 124,252,0 } } },
	{ "chart reuse",{ { 127,255,0 } } },
	{ "chartreuse",{ { 127,255,0 } } },
	{ "green yellow",{ { 173,255,47 } } },
	{ "greenyellow",{ { 173,255,47 } } },
	{ "dark green",{ { 0,100,0 } } },
	{ "darkgreen",{ { 0,100,0 } } },
	{ "green",{ { 0,128,0 } } },
	{ "forest green",{ { 34,139,34 } } },
	{ "forestgreen",{ { 34,139,34 } } },
	{ "lime",{ { 0,255,0 } } },
	{ "lime green",{ { 50,205,50 } } },
	{ "limegreen",{ { 50,205,50 } } },
	{ "light green",{ { 144,238,144 } } },
	{ "lightgreen",{ { 144,238,144 } } },
	{ "pale green",{ { 152,251,152 } } },
	{ "palegreen",{ { 152,251,152 } } },
	{ "dark sea green",{ { 143,188,143 } } },
	{ "darkseagreen",{ { 143,188,143 } } },
	{ "medium spring green",{ { 0,250,154 } } },
	{ "mediumspringgreen",{ { 0,250,154 } } },
	{ "spring green",{ { 0,255,127 } } },
	{ "springgreen",{ { 0,255,127 } } },
	{ "sea green",{ { 46,139,87 } } },
	{ "seagreen",{ { 46,139,87 } } },
	{ "medium aqua marine",{ { 102,205,170 } } },
	{ "mediumaquamarine",{ { 102,205,170 } } },
	{ "medium sea green",{ { 60,179,113 } } },
	{ "mediumseagreen",{ { 60,179,113 } } },
	{ "light sea green",{ { 32,178,170 } } },
	{ "lightseagreen",{ { 32,178,170 } } },
	{ "dark slate gray",{ { 47,79,79 } } },
	{ "darkslategray",{ { 47,79,79 } } },
	{ "teal",{ { 0,128,128 } } },
	{ "dark cyan",{ { 0,139,139 } } },
	{ "darkcyan",{ { 0,139,139 } } },
	{ "aqua",{ { 0,255,255 } } },
	{ "cyan",{ { 0,255,255 } } },
	{ "light cyan",{ { 224,255,255 } } },
	{ "lightcyan",{ { 224,255,255 } } },
	{ "dark turquoise",{ { 0,206,209 } } },
	{ "darkturquoise",{ { 0,206,209 } } },
	{ "turquoise",{ { 64,224,208 } } },
	{ "medium turquoise",{ { 72,209,204 } } },
	{ "mediumturquoise",{ { 72,209,204 } } },
	{ "pale turquoise",{ { 175,238,238 } } },
	{ "paleturquoise",{ { 175,238,238 } } },
	{ "aqua marine",{ { 127,255,212 } } },
	{ "aquamarine",{ { 127,255,212 } } },
	{ "powder blue",{ { 176,224,230 } } },
	{ "powderblue",{ { 176,224,230 } } },
	{ "cadet blue",{ { 95,158,160 } } },
	{ "cadetblue",{ { 95,158,160 } } },
	{ "steel blue",{ { 70,130,180 } } },
	{ "steelblue",{ { 70,130,180 } } },
	{ "corn flower blue",{ { 100,149,237 } } },
	{ "cornflowerblue",{ { 100,149,237 } } },
	{ "deep sky blue",{ { 0,191,255 } } },
	{ "deepskyblue",{ { 0,191,255 } } },
	{ "dodger blue",{ { 30,144,255 } } },
	{ "dodgerblue",{ { 30,144,255 } } },
	{ "light blue",{ { 173,216,230 } } },
	{ "lightblue",{ { 173,216,230 } } },
	{ "sky blue",{ { 135,206,235 } } },
	{ "skyblue",{ { 135,206,235 } } },
	{ "light sky blue",{ { 135,206,250 } } },
	{ "lightskyblue",{ { 135,206,250 } } },
	{ "midnight blue",{ { 25,25,112 } } },
	{ "midnightblue",{ { 25,25,112 } } },
	{ "navy",{ { 0,0,128 } } },
	{ "dark blue",{ { 0,0,139 } } },
	{ "darkblue",{ { 0,0,139 } } },
	{ "medium blue",{ { 0,0,205 } } },
	{ "mediumblue",{ { 0,0,205 } } },
	{ "blue",{ { 0,0,255 } } },
	{ "royal blue",{ { 65,105,225 } } },
	{ "royalblue",{ { 65,105,225 } } },
	{ "blue violet",{ { 138,43,226 } } },
	{ "blueviolet",{ { 138,43,226 } } },
	{ "indigo",{ { 75,0,130 } } },
	{ "dark slate blue",{ { 72,61,139 } } },
	{ "darkslateblue",{ { 72,61,139 } } },
	{ "slate blue",{ { 106,90,205 } } },
	{ "slateblue",{ { 106,90,205 } } },
	{ "medium slate blue",{ { 123,104,238 } } },
	{ "mediumslateblue",{ { 123,104,238 } } },
	{ "medium purple",{ { 147,112,219 } } },
	{ "mediumpurple",{ { 147,112,219 } } },
	{ "dark magenta",{ { 139,0,139 } } },
	{ "darkmagenta",{ { 139,0,139 } } },
	{ "dark violet",{ { 148,0,211 } } },
	{ "darkviolet",{ { 148,0,211 } } },
	{ "dark orchid",{ { 153,50,204 } } },
	{ "darkorchid",{ { 153,50,204 } } },
	{ "medium orchid",{ { 186,85,211 } } },
	{ "mediumorchid",{ { 186,85,211 } } },
	{ "purple",{ { 128,0,128 } } },
	{ "thistle",{ { 216,191,216 } } },
	{ "plum",{ { 221,160,221 } } },
	{ "violet",{ { 238,130,238 } } },
	{ "magenta",{ { 255,0,255 } } },
	{ "fuchsia",{ { 255,0,255 } } },
	{ "orchid",{ { 218,112,214 } } },
	{ "medium violet red",{ { 199,21,133 } } },
	{ "mediumvioletred",{ { 199,21,133 } } },
	{ "pale violet red",{ { 219,112,147 } } },
	{ "palevioletred",{ { 219,112,147 } } },
	{ "deep pink",{ { 255,20,147 } } },
	{ "deeppink",{ { 255,20,147 } } },
	{ "hot pink",{ { 255,105,180 } } },
	{ "hotpink",{ { 255,105,180 } } },
	{ "light pink",{ { 255,182,193 } } },
	{ "lightpink",{ { 255,182,193 } } },
	{ "pink",{ { 255,192,203 } } },
	{ "antique white",{ { 250,235,215 } } },
	{ "antiquewhite",{ { 250,235,215 } } },
	{ "beige",{ { 245,245,220 } } },
	{ "bisque",{ { 255,228,196 } } },
	{ "blanched almond",{ { 255,235,205 } } },
	{ "blanchedalmond",{ { 255,235,205 } } },
	{ "wheat",{ { 245,222,179 } } },
	{ "corn silk",{ { 255,248,220 } } },
	{ "cornsilk",{ { 255,248,220 } } },
	{ "lemon chiffon",{ { 255,250,205 } } },
	{ "lemonchiffon",{ { 255,250,205 } } },
	{ "light golden rod yellow",{ { 250,250,210 } } },
	{ "lightgoldenrodyellow",{ { 250,250,210 } } },
	{ "light yellow",{ { 255,255,224 } } },
	{ "lightyellow",{ { 255,255,224 } } },
	{ "saddle brown",{ { 139,69,19 } } },
	{ "saddlebrown",{ { 139,69,19 } } },
	{ "sienna",{ { 160,82,45 } } },
	{ "chocolate",{ { 210,105,30 } } },
	{ "peru",{ { 205,133,63 } } },
	{ "sandy brown",{ { 244,164,96 } } },
	{ "sandybrown",{ { 244,164,96 } } },
	{ "burly wood",{ { 222,184,135 } } },
	{ "burlywood",{ { 222,184,135 } } },
	{ "tan",{ { 210,180,140 } } },
	{ "rosy brown",{ { 188,143,143 } } },
	{ "rosybrown",{ { 188,143,143 } } },
	{ "moccasin",{ { 255,228,181 } } },
	{ "navajo white",{ { 255,222,173 } } },
	{ "navajowhite",{ { 255,222,173 } } },
	{ "peach puff",{ { 255,218,185 } } },
	{ "peachpuff",{ { 255,218,185 } } },
	{ "misty rose",{ { 255,228,225 } } },
	{ "mistyrose",{ { 255,228,225 } } },
	{ "lavender blush",{ { 255,240,245 } } },
	{ "lavenderblush",{ { 255,240,245 } } },
	{ "linen",{ { 250,240,230 } } },
	{ "old lace",{ { 253,245,230 } } },
	{ "oldlace",{ { 253,245,230 } } },
	{ "papaya whip",{ { 255,239,213 } } },
	{ "papayawhip",{ { 255,239,213 } } },
	{ "sea shell",{ { 255,245,238 } } },
	{ "seashell",{ { 255,245,238 } } },
	{ "mint cream",{ { 245,255,250 } } },
	{ "mintcream",{ { 245,255,250 } } },
	{ "slate gray",{ { 112,128,144 } } },
	{ "slategray",{ { 112,128,144 } } },
	{ "light slate gray",{ { 119,136,153 } } },
	{ "lightslategray",{ { 119,136,153 } } },
	{ "light steel blue",{ { 176,196,222 } } },
	{ "lightsteelblue",{ { 176,196,222 } } },
	{ "lavender",{ { 230,230,250 } } },
	{ "floral white",{ { 255,250,240 } } },
	{ "floralwhite",{ { 255,250,240 } } },
	{ "alice blue",{ { 240,248,255 } } },
	{ "aliceblue",{ { 240,248,255 } } },
	{ "ghost white",{ { 248,248,255 } } },
	{ "ghostwhite",{ { 248,248,255 } } },
	{ "honeydew",{ { 240,255,240 } } },
	{ "ivory",{ { 255,255,240 } } },
	{ "azure",{ { 240,255,255 } } },
	{ "snow",{ { 255,250,250 } } },
	{ "black",{ { 0,0,0 } } },
	{ "dim gray",{ { 105,105,105 } } },
	{ "dimgray",{ { 105,105,105 } } },
	{ "dim grey",{ { 105,105,105 } } },
	{ "dimgrey",{ { 105,105,105 } } },
	{ "gray",{ { 128,128,128 } } },
	{ "grey",{ { 128,128,128 } } },
	{ "dark grey",{ { 169,169,169 } } },
	{ "darkgrey",{ { 169,169,169 } } },
	{ "dark gray",{ { 169,169,169 } } },
	{ "darkgray",{ { 169,169,169 } } },
	{ "silver",{ { 192,192,192 } } },
	{ "light gray",{ { 211,211,211 } } },
	{ "lightgray",{ { 211,211,211 } } },
	{ "light grey",{ { 211,211,211 } } },
	{ "lightgrey",{ { 211,211,211 } } },
	{ "gainsboro",{ { 220,220,220 } } },
	{ "white smoke",{ { 245,245,245 } } },
	{ "whitesmoke",{ { 245,245,245 } } },
	{ "white",{ { 255,255,255 } } }
};

/*! @brief 24-bit RGB color with mixing, inversion, distance and palette-generation helpers.

    A Color is three 8-bit components (r, g, b) with no alpha; transparency
    is handled separately by the drawing code (e.g. Bitmap::putTransPixel()'s
    weight parameter). Colors can be constructed from ~200 CSS/X11 names via
    ColorMap, blended with mixOn(), compared with distance(), and generated
    as maximally distinguishable palettes for charts/overlays with
    createColorsMaxDifference().

    @code
    using namespace cmlabs;
    Color red("red");                 // from ColorMap; unknown names give black
    Color bg(30, 30, 30);
    Color blended = red.mixOn(bg, 0.25);   // 25% red over dark grey background
    double d = red.distance(bg);           // RGB-space Euclidean distance
    std::vector<Color> palette = Color::createColorsMaxDifference(8);
    @endcode */
class Color
{
public:
	Color(); //!< Black (0,0,0).
	Color(uint8 red, uint8 green, uint8 blue); //!< From RGB components.
	Color(const char* name); //!< From a named color in ColorMap (case-insensitive); black when unknown.
	Color(const Color &color); //!< Copy constructor.
	virtual ~Color();

	/*! @brief Blend this color onto a background color.
	    Computes @c this*weight + @p color*(1-weight) per component, i.e.
	    @p weight is the fraction of <b>this</b> color in the result and
	    @p color acts as the background. Weight is clamped to [0,1].
	    @param color Background color. @param weight Fraction [0,1] of this color in the result.
	    @return Mixed color (neither input is modified). */
	Color mixOn(Color& color, double weight);
	Color getReverseColor(); //!< Component-wise inverse (255-r, 255-g, 255-b).
	uint8 getGreyValue(); //!< Grey value as the plain average (r+g+b)/3. @note Not perceptually weighted (no 0.299/0.587/0.114 luma coefficients).

	uint8 r, g, b;
	uint32 size;

	/*! @brief Euclidean distance to another color in RGB space. @param otherColor Other color. @return Distance in [0, ~441.7]. */
	double distance(Color &otherColor);
	//bool setNoColor();
	//bool isValid();
	//bool isNoColor();

	/*! @brief Generate @p count colors spread for maximum mutual visual difference (e.g. for chart series).
	    @param count Number of colors. @param mix Interleave rather than order by hue. @return Generated palette. */
	static std::vector<Color> createColorsMaxDifference(uint32 count, bool mix = false);
	/*! @brief Format as "r,g,b" decimal text. @return RGB string. */
	std::string toRGBString() {
		return utils::StringFormat("%u,%u,%u", r, g, b);
	}

private:
	bool init(uint8 red, uint8 green, uint8 blue);
	bool init(const char* colorName);
};


/////////////////////////////////////////////////////////////////////
// Size Class
/////////////////////////////////////////////////////////////////////

/*! @brief 2D/3D extent (width, height, optional depth) stored as doubles. */
class Size
{
public:
	Size(); //!< Zero size.
	Size(double width, double height, double depth = 0); //!< From explicit dimensions.
	virtual ~Size();

	double w; //!< Width.
	double h; //!< Height.
	double d; //!< Depth (0 for 2D use).

	bool equals(const Size& size) const; //!< Exact component equality. @return true when equal.
	bool operator==(const Size &p) const; //!< Same as equals().
	Size operator*(const Vector2D &v) const; //!< Scale w by v.x and h by v.y. @return Scaled size.

	double getHeight() const; //!< @return Height.
	double getWidth() const; //!< @return Width.
	double getDepth() const; //!< @return Depth.

	bool setHeight(double height); //!< Set height. @return true.
	bool setWidth(double width); //!< Set width. @return true.
	bool setDepth(double depth); //!< Set depth. @return true.

	bool isNonZero() const; //!< @return true when any dimension is non-zero.
	double getArea() const; //!< @return w*h.
	double getDiagonalLenth() const; //!< @return Diagonal length sqrt(w²+h²). @note Name typo kept for API stability.

	std::string print() ; //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// Point Class
/////////////////////////////////////////////////////////////////////

/*! @brief Integer 3D point with an optional attached Size; interoperates with PointFloat and vectors.

    Arithmetic operators are element-wise; operator[] indexes x=0, y=1, z=2.
    Mixed Point/PointFloat arithmetic promotes to PointFloat; converting a
    PointFloat back to Point truncates (does not round) each coordinate.
    The attached Size lets a point double as "position + extent" (e.g. a
    detection center with its bounding size) without a separate Box.

    @code
    using namespace cmlabs;
    Point p(10, 20);
    PointFloat q(10.5, 19.25);
    PointFloat d = q - p;                 // element-wise, promoted to float
    double dist  = p.getDistanceTo(q);    // Euclidean distance
    Point r = (Point)q;                   // truncates to (10, 19)
    @endcode */
class Point
{
public:
	Point(); //!< Origin (0,0,0).
	Point(int px, int py, int pz=0, Size psize=Size()); //!< From coordinates and optional size.
	virtual ~Point();

	operator PointFloat() const; //!< Implicit conversion to the floating-point variant.

	int x;
	int y;
	int z;
	Size size;

	int operator[](int n) const; //!< Component access: 0=x, 1=y, 2=z.
	bool operator==(const Point &p) const; //!< Exact coordinate equality.
	bool operator==(const PointFloat &p) const; //!< Equality against a float point.
	Point operator-(const Point &p) const; //!< Element-wise difference.
	PointFloat operator-(const PointFloat &p) const; //!< Difference, promoted to float.
	Point operator+(const Point &p) const; //!< Element-wise sum.
	PointFloat operator+(const PointFloat &p) const; //!< Sum, promoted to float.
	PointFloat operator+(const Vector2D &v) const; //!< Translate by a 2D vector.
	PointFloat operator+(const Vector3D &v) const; //!< Translate by a 3D vector.
	Point operator*(const Point &p) const; //!< Element-wise product.
	PointFloat operator*(const PointFloat &p) const; //!< Element-wise product, promoted to float.
	Point operator-(double a) const; //!< Subtract scalar from each coordinate.
	Point operator+(double a) const; //!< Add scalar to each coordinate.
	Point operator*(double a) const; //!< Scale each coordinate.

	int getX() const; //!< @return x.
	int getY() const; //!< @return y.
	int getZ() const; //!< @return z.
	Size getSize() const; //!< @return Attached size.

	bool set(int x, int y, int z=0); //!< Set all coordinates. @return true.
	bool setX(int n); //!< Set x. @return true.
	bool setY(int n); //!< Set y. @return true.
	bool setZ(int n); //!< Set z. @return true.
	bool setSize(Size s); //!< Set the attached size. @return true.

	double getDistanceTo(Point &p) const; //!< Euclidean distance to another point.
	double getDistanceTo(PointFloat &p) const; //!< Euclidean distance to a float point.

	std::string print() ; //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// PointFloat Class
/////////////////////////////////////////////////////////////////////

/*! @brief Floating-point 3D point with an optional attached Size; float counterpart of Point.
    Arithmetic operators are element-wise; operator[] indexes x=0, y=1, z=2. */
class PointFloat
{
public:
	PointFloat(); //!< Origin (0,0,0).
	PointFloat(double px, double py, double pz=0, Size psize=Size()); //!< From coordinates and optional size.
	virtual ~PointFloat();

	operator Point() const; //!< Conversion to the integer variant (truncates).

	double x;
	double y;
	double z;
	Size size;

	double operator[](int n) const; //!< Component access: 0=x, 1=y, 2=z.
	bool operator==(const Point &p) const; //!< Equality against an integer point.
	bool operator==(const PointFloat &p) const; //!< Coordinate equality.
	PointFloat operator-(const Point &p) const; //!< Element-wise difference.
	PointFloat operator-(const PointFloat &p) const; //!< Element-wise difference.
	PointFloat operator+(const Point &p) const; //!< Element-wise sum.
	PointFloat operator+(const PointFloat &p) const; //!< Element-wise sum.
	PointFloat operator+(const Vector2D &v) const; //!< Translate by a 2D vector.
	PointFloat operator+(const Vector3D &v) const; //!< Translate by a 3D vector.
	PointFloat operator*(const Point &p) const; //!< Element-wise product.
	PointFloat operator*(const PointFloat &p) const; //!< Element-wise product.
	PointFloat operator-(double a) const; //!< Subtract scalar from each coordinate.
	PointFloat operator+(double a) const; //!< Add scalar to each coordinate.
	PointFloat operator*(double a) const; //!< Scale each coordinate.

	double getX() const; //!< @return x.
	double getY() const; //!< @return y.
	double getZ() const; //!< @return z.
	Size getSize() const; //!< @return Attached size.

	bool set(double x, double y, double z=0); //!< Set all coordinates. @return true.
	bool setX(double v); //!< Set x. @return true.
	bool setY(double v); //!< Set y. @return true.
	bool setZ(double v); //!< Set z. @return true.
	bool setSize(Size s); //!< Set the attached size. @return true.

	double getDistanceTo(const Point &p) const; //!< Euclidean distance to an integer point.
	double getDistanceTo(const PointFloat &p) const; //!< Euclidean distance to a float point.

	std::string print(); //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// Line Class
/////////////////////////////////////////////////////////////////////

/*! @brief Line segment between two PointFloat endpoints with a drawing width. */
class Line
{
public:
	Line(); //!< Degenerate line at the origin.
	Line(PointFloat startpoint, PointFloat endpoint, double width = 0); //!< From endpoints and optional width.
	virtual ~Line();

	PointFloat startPoint; //!< First endpoint.
	PointFloat endPoint;   //!< Second endpoint.
	double lineWidth;      //!< Stroke width (drawing hint).

	PointFloat getStartPoint() const; //!< @return Start point.
	PointFloat getEndPoint() const; //!< @return End point.
	double getLineWidth() const; //!< @return Stroke width.

	bool setStartPoint(PointFloat point); //!< Set the start point. @return true.
	bool setEndPoint(PointFloat point); //!< Set the end point. @return true.
	bool setLineWidth(double width); //!< Set the stroke width. @return true.

	std::string print(); //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// PolyLine Class
/////////////////////////////////////////////////////////////////////

/*! @brief Ordered collection of Line segments (not necessarily connected). */
class PolyLine
{
public:
	PolyLine();
	virtual ~PolyLine();

	std::vector<Line> lines; //!< The segments, in order.

	uint32 getLineCount() const; //!< @return Number of segments.
	Line getLine(uint32 pos) const; //!< @param pos Zero-based index. @return Segment at @p pos (default Line when out of range).
	bool addLine(Line line); //!< Append a segment. @return true.
	bool replaceLine(uint32 pos, Line newline); //!< Replace the segment at @p pos. @return false when out of range.
	bool removeLine(uint32 pos); //!< Remove the segment at @p pos. @return false when out of range.

	std::string print(); //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// Box Class
/////////////////////////////////////////////////////////////////////

/*! @brief Axis-aligned rectangle defined by an upper-left corner and a Size, with overlap/containment math.

    Widely used for image regions and tracked object bounding boxes.
    Y grows downward (screen convention): getUpperY() < getLowerY(), and
    "upper left" is the minimum-x/minimum-y corner. All geometric queries
    treat the box as axis-aligned; the @c orientation field is metadata only.
    Optional metadata (name, comment, orientation) travels with the box.

    @code
    using namespace cmlabs;
    Box a(10, 10, 100, 50);         // x, y, w, h
    Box b(60, 20, 100, 50);
    Box overlap = a.getOverlapBox(b);      // zero-sized when disjoint
    double frac = a.percentOverlap(b);     // fraction [0,1], NOT 0-100
    Box bounds  = a.getBoundingBox(b);     // smallest box containing both
    a.constrainTo(0, 0, 640, 480);         // clip in place to the image area
    @endcode */
class Box
{
public:
	Box(); //!< Empty box at the origin.
	Box(PointFloat upperleft, Size boxsize, double linewidth = 0); //!< From corner + size.
	Box(PointFloat upperleft, PointFloat lowerright, double linewidth = 0); //!< From two opposite corners.
	Box(double x, double y, double w, double h, double linewidth = 0); //!< From scalar corner and dimensions.
	virtual ~Box();

	PointFloat upperLeft; //!< Upper-left corner.
	Size size;            //!< Extent.
	double lineWidth;     //!< Stroke width (drawing hint).
	std::string name;     //!< Optional label.
	std::string comment;  //!< Optional free-form comment.
	double orientation;   //!< Optional rotation metadata (radians); not applied by the geometric queries.

	double getUpperY() const; //!< @return Top edge y.
	double getLowerY() const; //!< @return Bottom edge y.
	double getLeftX() const; //!< @return Left edge x.
	double getRightX() const; //!< @return Right edge x.
	double getArea() const; //!< @return w*h.

	double getCMX() const; //!< @return Center-of-mass x.
	double getCMY() const; //!< @return Center-of-mass y.
	PointFloat getCM() const; //!< @return Center of mass.

	PointFloat getUpperLeft() const; //!< @return Upper-left corner.
	PointFloat getUpperRight() const; //!< @return Upper-right corner.
	PointFloat getLowerLeft() const; //!< @return Lower-left corner.
	PointFloat getLowerRight() const; //!< @return Lower-right corner.
	double getLineWidth() const; //!< @return Stroke width.
	Size getSize() const; //!< @return Extent.
	double getWidth() const; //!< @return Width.
	double getHeight() const; //!< @return Height.

	Box operator-(const Point &p) const; //!< Box translated by -p.
	Box operator-(const PointFloat &p) const; //!< Box translated by -p.
	Box operator+(const Point &p) const; //!< Box translated by +p.
	Box operator+(const PointFloat &p) const; //!< Box translated by +p.
	bool move(double dx, double dy); //!< Translate in place. @return true.
	bool moveTo(double x, double y); //!< Move the upper-left corner to (x,y). @return true.
	bool set(double x, double y, double w, double h, double linewidth = 0); //!< Reset all geometry. @return true.
	bool setUpperLeft(const PointFloat& point); //!< Set the corner. @return true.
	bool setSize(const Size& boxsize); //!< Set the extent. @return true.
	bool setLineWidth(double width); //!< Set the stroke width. @return true.
	bool grow(double dw, double dh); //!< Enlarge by (dw,dh), keeping the upper-left corner. @return true.

	bool isPointWithin(const PointFloat& point) const; //!< @return true when @p point lies inside (inclusive).
	bool isPointWithin(int x, int y) const; //!< @return true when (x,y) lies inside (inclusive).
	PointFloat getCentreMass() const; //!< @return Center of mass (same as getCM()).

	bool hasZeroSize() const; //!< @return true when width or height is zero.
	bool equals(const Box &otherbox) const; //!< Exact geometric equality.
	bool equals(const Box &otherbox, double maxerror) const; //!< Approximate equality within @p maxerror per component.
	Box getBoundingBox(const Box &otherbox) const; //!< @return Smallest box containing both boxes.
	bool growToBoundingBox(const Box &otherbox); //!< Enlarge in place to include @p otherbox. @return true.
	bool growToIncludePoint(const Point& point, int padX = 0, int padY = 0); //!< Enlarge to include @p point plus padding. @return true.
	Box getOverlapBox(const Box &otherbox) const; //!< @return Intersection box (zero-sized when disjoint).
	/*! @brief Overlap between the two boxes as a fraction of the larger area.
	    Computed as overlapArea/myArea when this box is the larger, otherwise
	    the ratio is inverted so the result stays in [0,1].
	    @return Overlap fraction in [0,1] (0 when disjoint). @note Despite the
	    name, the value is a fraction (0..1), not a percentage (0..100). */
	double percentOverlap(const Box &otherbox) const;

	Box getDoubleSizeSameCenter(); //!< @return Box with doubled dimensions and the same center.
	bool constrainTo(const Box& box); //!< Clip this box in place to lie within @p box. @return true when still valid.
	bool constrainTo(double x, double y, double w, double h); //!< Clip in place to the given rectangle. @return true when still valid.
	Box getConstrainedCopy(const Box& box); //!< @return Clipped copy within @p box.
	Box getConstrainedCopy(double x, double y, double w, double h); //!< @return Clipped copy within the given rectangle.

	std::string print(); //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// Vector2D Class
/////////////////////////////////////////////////////////////////////

/*! @brief 2D vector with the usual linear algebra: dot product, determinant, projection, rotation, angles.

    operator* between vectors is the dot product; use det() for the 2D cross
    product. Angles are always radians. Most operations return a new vector;
    the @c *It / @c make* / @c set* variants modify in place. Note that in the
    screen coordinate system used by Box/Bitmap (y down), a mathematically
    counter-clockwise rotation appears clockwise on screen.

    @code
    using namespace cmlabs;
    Vector2D v(3, 4);
    double len = v.length();               // 5
    Vector2D u = v.getUnitVector();        // (0.6, 0.8); v unchanged
    v.rotateIt(M_PI / 2);                  // in place: (3,4) -> (-4,3)
    Vector2D w(1, 0);
    double dot  = v * w;                   // dot product
    double turn = w.det(v);                // sign gives turn direction
    double ang  = w.getAngle(v);           // unsigned angle in [0, pi]
    Vector2D p  = v.getProjectionOn(w);    // component of v along w
    @endcode */
class Vector2D
{
public:
	Vector2D(); //!< Zero vector.
	Vector2D(double x, double y); //!< From components.
	virtual ~Vector2D();

	double x; //!< X component.
	double y; //!< Y component.

	double operator[](int n) const; //!< Component access: 0=x, 1=y.
	bool operator==(const Vector2D &v) const; //!< Component equality.
	Vector2D operator-(const Vector2D &v) const; //!< Difference.
	Vector2D operator+(const Vector2D &v) const; //!< Sum.
	double operator*(const Vector2D &v) const; //!< Dot product.
	Vector2D operator-(double a) const; //!< Subtract scalar from each component.
	Vector2D operator+(double a) const; //!< Add scalar to each component.
	Vector2D operator*(double a) const; //!< Scale.
	const Vector2D& operator-=(const Vector2D &v); //!< In-place subtract.
	const Vector2D& operator+=(const Vector2D &v); //!< In-place add.
	const Vector2D& operator-=(double a); //!< In-place scalar subtract.
	const Vector2D& operator+=(double a); //!< In-place scalar add.
	const Vector2D& operator*=(double a); //!< In-place scale.

	double getX() const; //!< @return x.
	double getY() const; //!< @return y.

	bool set(const PointFloat& p1, const PointFloat& p2); //!< Set as p2-p1. @return true.
	bool set(double x1, double y1, double x2, double y2); //!< Set as (x2-x1, y2-y1). @return true.
	bool set(double x, double y); //!< Set components. @return true.
	bool setX(double v); //!< Set x. @return true.
	bool setY(double v); //!< Set y. @return true.
	bool setLength(double l); //!< Rescale to length @p l, keeping direction. @return false for the zero vector.
	bool makeUnitVector(); //!< Normalize in place. @return false for the zero vector.

	double length() const; //!< @return Euclidean length.
	double det(const Vector2D &v) const; //!< 2D cross product / determinant (x*v.y - y*v.x); sign gives turn direction.
	bool isOrthogonalWith(const Vector2D &v) const; //!< @return true when the dot product is (approximately) zero.
	bool isParallelWith(const Vector2D &v) const; //!< @return true when det() is (approximately) zero.
	Vector2D getProjectionOn(const Vector2D &v) const; //!< @return Orthogonal projection of this vector onto @p v.
	Vector2D getUnitVector() const; //!< @return Normalized copy.
	Vector2D getOrthogonalVector() const; //!< @return Vector rotated 90 degrees.
	double getAngle(const Vector2D &v) const; //!< Unsigned angle to @p v via acos of the normalized dot product. @return Radians in [0, pi]; 0 when either vector is zero. @note Sign/turn direction is lost; combine with det() to recover it.
	double getArea(const Vector2D &v) const; //!< @return Area of the parallelogram spanned with @p v (|det|).

	Vector2D rotate(double angle); //!< Rotated copy; this vector is unchanged. @param angle Radians, counter-clockwise in a y-up frame (appears clockwise with screen y-down coordinates). @return Rotated copy; the zero vector rotates to the zero vector.
	bool rotateIt(double angle); //!< Rotate in place by @p angle radians (same convention as rotate()). @return false for the zero vector (nothing to rotate), true otherwise.

	std::string print(); //!< Human-readable representation for debugging.
};


/////////////////////////////////////////////////////////////////////
// Vector3D Class
/////////////////////////////////////////////////////////////////////

/*! @brief 3D vector with dot/cross products, projection and angle math.

    operator* between vectors is the dot product; use product() for the cross
    product. Angles are radians. Follows the same conventions as Vector2D.

    @code
    using namespace cmlabs;
    Vector3D a(1, 0, 0), b(0, 1, 0);
    double dot = a * b;                    // 0
    Vector3D n  = a.product(b);            // cross product: (0,0,1)
    double ang  = a.getAngle(b);           // pi/2
    Vector3D u  = Vector3D(2, 2, 1).getUnitVector();
    @endcode */
class Vector3D
{
public:
	Vector3D(); //!< Zero vector.
	Vector3D(double x, double y, double z); //!< From components.
	virtual ~Vector3D();

	double x; //!< X component.
	double y; //!< Y component.
	double z; //!< Z component.

	double operator[](int n) const; //!< Component access: 0=x, 1=y, 2=z.
	bool operator==(const Vector3D &v) const; //!< Component equality.
	Vector3D operator-(const Vector3D &v) const; //!< Difference.
	Vector3D operator+(const Vector3D &v) const; //!< Sum.
	double operator*(const Vector3D &v) const; //!< Dot product.
	Vector3D operator-(double a) const; //!< Subtract scalar from each component.
	Vector3D operator+(double a) const; //!< Add scalar to each component.
	Vector3D operator*(double a) const; //!< Scale.
	const Vector3D& operator-=(const Vector3D &v); //!< In-place subtract.
	const Vector3D& operator+=(const Vector3D &v); //!< In-place add.
	const Vector3D& operator-=(double a); //!< In-place scalar subtract.
	const Vector3D& operator+=(double a); //!< In-place scalar add.
	const Vector3D& operator*=(double a); //!< In-place scale.

	double getX() const; //!< @return x.
	double getY() const; //!< @return y.
	double getZ() const; //!< @return z.

	bool set(const PointFloat& p1, const PointFloat& p2); //!< Set as p2-p1. @return true.
	bool set(double x1, double y1, double z1, double x2, double y2, double z2); //!< Set as the difference of two coordinate triples. @return true.
	bool set(double x, double y, double z); //!< Set components. @return true.
	bool setX(double v); //!< Set x. @return true.
	bool setY(double v); //!< Set y. @return true.
	bool setZ(double v); //!< Set z. @return true.

	double length() const; //!< @return Euclidean length.
	Vector3D product(const Vector3D &v) const; //!< Cross product with @p v.
	bool isOrthogonalWith(const Vector3D &v) const; //!< @return true when the dot product is (approximately) zero.
	bool isParallelWith(const Vector3D &v) const; //!< @return true when the cross product is (approximately) zero.
	Vector3D getProjectionOn(const Vector3D &v) const; //!< @return Orthogonal projection of this vector onto @p v.
	Vector3D getUnitVector() const; //!< @return Normalized copy.
	double getAngle(const Vector3D &v) const; //!< @return Angle to @p v in radians.
	double getArea(const Vector3D &v) const; //!< @return Area of the parallelogram spanned with @p v.
	
	std::string print(); //!< Human-readable representation for debugging.
};

/////////////////////////////////////////////////////////////////////
// RandomPathGenerator Class
/////////////////////////////////////////////////////////////////////

/*! @brief Generates a smoothly wandering 2D path: each call to generateNextPoint() advances the
    last point along a direction vector perturbed by a random variation, useful for simulated motion in tests/demos. */
class RandomPathGenerator {
public:
	RandomPathGenerator();
	~RandomPathGenerator();

	bool setStartPoint(double x, double y); //!< Set the initial position. @return true.
	bool setDirection(double dx, double dy); //!< Set the base movement direction per step. @return true.
	bool setVariation(double var); //!< Set the random perturbation magnitude. @return true.

	PointFloat generateNextPoint(); //!< Advance one step and return the new position.

	uint64 lastPointTime; //!< Timestamp of the last generated point (ms).
	PointFloat lastPoint; //!< Most recently generated position.
	Vector2D direction;   //!< Current movement direction.
	Vector2D variation;   //!< Random variation applied per step.

};

/*! @brief Unit test for the MathClasses module (geometry / vectors / boxes). @return true when all checks pass. */
bool MathClasses_UnitTest();

} // namespace cmlabs

#endif // !defined(_MATHCLASSES_H)
