Blob Blame Raw
#pragma once

#ifndef T_CURVES_INCLUDED
#define T_CURVES_INCLUDED

#include "tgeometry.h"

#undef DVAPI
#undef DVVAR
#ifdef TGEOMETRY_EXPORTS
#define DVAPI DV_EXPORT_API
#define DVVAR DV_EXPORT_VAR
#else
#define DVAPI DV_IMPORT_API
#define DVVAR DV_IMPORT_VAR
#endif

//=============================================================================
/*!
  TSegment Class to manage a segment
 */
class DVAPI TSegment
{
protected:
	TPointD m_c0, m_c1;

public:
	TSegment()
		: m_c0(), m_c1(){};

	//! p0,p1  are the two control points
	TSegment(const TPointD &p0, const TPointD &p1)
		: m_c0(p0), m_c1(p1 - p0) {}

	TSegment(double x0, double y0,
			 double x1, double y1)
		: m_c0(x0, y0), m_c1(x1 - x0, y1 - y0) {}

	TSegment(const TSegment &src)
		: m_c0(src.m_c0), m_c1(src.m_c1) {}

	//!Return the point of segment at parameter \b t.
	TPointD getPoint(double t) const
	{
		return m_c0 + t * m_c1;
	};

	//!Return speed of segment.
	TPointD getSpeed(double = 0) const
	{
		return m_c1;
	};

	//!Return first control point \b P0.
	TPointD getP0() const { return m_c0; }
	//!Return second control point \b P1.
	TPointD getP1() const { return m_c0 + m_c1; }

	//!Set the value of first control point \b P0 to \b p.
	void setP0(const TPointD &p)
	{
		m_c1 += m_c0 - p;
		m_c0 = p;
	}
	//!Set the value of second control point \b P1 to \b p.
	void setP1(const TPointD &p) { m_c1 = p - m_c0; }

	bool operator==(const TSegment &c) const
	{
		return m_c0 == c.m_c0 && m_c1 == c.m_c1;
	};

	bool operator!=(const TSegment &c) const
	{
		return !operator==(c);
	};

	//!Return rect that contains the segment.
	TRectD getBBox() const
	{
		return TRectD(getP0(), getP1());
	}

	//!Return the length of segment
	double getLength() const
	{
		return norm(m_c1);
	}

	//!Return true if segment is a point
	bool isPoint(double err2 = TConsts::epsilon) const
	{
		return norm2(m_c1) < err2;
	}
};

//-----------------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TSegment &segment);

//-----------------------------------------------------------------------------

//!\relates TAffine, TSegment
inline TSegment operator*(const TAffine &aff, const TSegment &seg)
{
	return TSegment(aff * seg.getP0(), aff * seg.getP1());
}

//=============================================================================
/*!
   TQuadratic class to manage a quadratic 
 */
class DVAPI TQuadratic
{
protected:
	TPointD
		m_p0,
		m_p1,
		m_p2;

public:
	TQuadratic()
		: m_p0(), m_p1(), m_p2() {}

	//! p0,p1,p2 are the three control points
	TQuadratic(const TPointD &p0,
			   const TPointD &p1,
			   const TPointD &p2)
		: m_p0(p0), m_p1(p1), m_p2(p2) {}

	TQuadratic(const TQuadratic &src)
		: m_p0(src.m_p0), m_p1(src.m_p1), m_p2(src.m_p2) {}

	TQuadratic &operator=(const TQuadratic &src)
	{
		m_p0 = src.m_p0;
		m_p1 = src.m_p1;
		m_p2 = src.m_p2;
		return *this;
	}

	//!Return the point of quadratic at parameter \b t.
	TPointD getPoint(double t) const;
	double getX(double t) const;
	double getY(double t) const;

	//!Return speed of quadratic at parameter \b t.
	TPointD getSpeed(double t) const
	{
		return 2 * ((t - 1) * m_p0 + (1.0 - 2.0 * t) * m_p1 + t * m_p2);
	}

	//!Return the y value of quadratic speed at parameter \b t.
	double getSpeedY(double t) const
	{
		return 2 * ((t - 1) * m_p0.y + (1.0 - 2.0 * t) * m_p1.y + t * m_p2.y);
	}

	//!Return acceleration of quadratic.
	TPointD getAcceleration(double = 0) const
	{
		return 2.0 * (m_p0 + m_p2 - 2.0 * m_p1);
	}

	//! Return curvature of quadratic at parameter \b t.
	/*! Calcolo della curvatura per una Quadratica.
        Vedi Farin pag.176 per la spiegazione della formula
        usata.
    */
	double getCurvature(double t) const;

	//!Return first control point \b P0.
	TPointD getP0() const { return m_p0; }
	//!Return second control point \b P1.
	TPointD getP1() const { return m_p1; }
	//!Return third control point \b P2.
	TPointD getP2() const { return m_p2; }

	//!Set the value of first control point \b P0 to \b p.
	void setP0(const TPointD &p) { m_p0 = p; }
	//!Set the value of second control point \b P1 to \b p.
	void setP1(const TPointD &p) { m_p1 = p; }
	//!Set the value of third control point \b P2 to \b p.
	void setP2(const TPointD &p) { m_p2 = p; }

	bool operator==(const TQuadratic &c) const
	{
		return m_p0 == c.m_p0 && m_p1 == c.m_p1 && m_p2 == c.m_p2;
	}

	bool operator!=(const TQuadratic &c) const
	{
		return !operator==(c);
	}

	//!Return a parameter that correspond to the point \b p in the quadratic.
	double getT(const TPointD &p) const;

	int getX(double y, double &x0, double &x1) const;

	int getY(double x, double &y0, double &y1) const;

	/*!
      N.B. if t==0 o t==1 return a quadratic with all points equal
     */
	void split(double t, TQuadratic &first, TQuadratic &second) const;

	//!Return rect that contains the quadratic.
	TRectD getBBox() const;

	/*!
      Return length of an arc between parameters t0 t1.
      N.B. Length returned is always positive. 
      \note t0 and t1 are clamped to [0,1] interval
      \note if t0>=t1 returns 0
     */
	double getLength(double t0, double t1) const;

	double getLength(double t1 = 1) const
	{
		return getLength(0, t1);
	}

	double getApproximateLength(double t0, double t1, double error) const;

	void reverse()
	{
		TPointD app;
		app = m_p0;
		m_p0 = m_p2;
		m_p2 = app;
	}
};

//-------------------------------------------------------

//!\relates TAffine, TQuadratic
inline TQuadratic operator*(const TAffine &aff, const TQuadratic &curve)
{
	TQuadratic quad;
	quad.setP0(aff * curve.getP0());
	quad.setP1(aff * curve.getP1());
	quad.setP2(aff * curve.getP2());
	return quad;
}

//-----------------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TQuadratic &curve);

//-----------------------------------------------------------------------------

inline std::ostream &operator<<(std::ostream &out, const TQuadratic *curve)
{
	assert(curve);
	return out << *curve;
}

//=============================================================================
/*!
   TCubic class to manage a cubic 
 */
class DVAPI TCubic
{
protected:
	TPointD m_p0, m_p1, m_p2, m_p3;

public:
	TCubic()
		: m_p0(), m_p1(), m_p2(), m_p3() {}

	//! p0,p1,p2,p3 are the four control points
	TCubic(const TPointD &p0,
		   const TPointD &p1,
		   const TPointD &p2,
		   const TPointD &p3)
		: m_p0(p0), m_p1(p1), m_p2(p2), m_p3(p3) {}

	TCubic(const TCubic &src)
		: m_p0(src.m_p0), m_p1(src.m_p1), m_p2(src.m_p2), m_p3(src.m_p3) {}

	TCubic &operator=(const TCubic &src)
	{
		m_p0 = src.m_p0;
		m_p1 = src.m_p1;
		m_p2 = src.m_p2;
		m_p3 = src.m_p3;
		return *this;
	}

	//!Return first control point \b P0.
	TPointD getP0() const { return m_p0; }
	//!Return second control point \b P1.
	TPointD getP1() const { return m_p1; }
	//!Return third control point \b P2.
	TPointD getP2() const { return m_p2; }
	//!Return fourth control point \b P3.
	TPointD getP3() const { return m_p3; }

	//!Set the value of first control point \b P0 to \b p.
	void setP0(const TPointD &p0) { m_p0 = p0; }
	//!Set the value of second control point \b P1 to \b p.
	void setP1(const TPointD &p1) { m_p1 = p1; }
	//!Set the value of third control point \b P2 to \b p.
	void setP2(const TPointD &p2) { m_p2 = p2; }
	//!Set the value of fourth control point \b P3 to \b p.
	void setP3(const TPointD &p3) { m_p3 = p3; }

	bool operator==(const TCubic &c) const
	{
		return m_p0 == c.m_p0 && m_p1 == c.m_p1 && m_p2 == c.m_p2 && m_p3 == c.m_p3;
	}

	bool operator!=(const TCubic &c) const
	{
		return !operator==(c);
	}

	//!Return rect that contains the cubic.
	TRectD getBBox() const
	{
		return TRectD(
			std::min({m_p0.x, m_p1.x, m_p2.x, m_p3.x}),
			std::min({m_p0.y, m_p1.y, m_p2.y, m_p3.y}),
			std::max({m_p0.x, m_p1.x, m_p2.x, m_p3.x}),
			std::max({m_p0.y, m_p1.y, m_p2.y, m_p3.y}));
	};

	//!Return the point of cubic at parameter \b t.
	TPointD getPoint(double t) const;

	//!Return speed of cubic at parameter \b t.
	TPointD getSpeed(double t) const;

	//!Return acceleration of cubic at parameter \b t.
	TPointD getAcceleration(double t) const
	{
		return 6.0 * ((m_p2 - 2 * m_p1 + m_p0) * (1 - t) + (m_p3 - 2 * m_p2 + m_p1) * t);
	};

	/*!
      Return length of an arc between parameters t0 t1.
      N.B. Length returned is always positive. 
      \note t0 and t1 are clamped to [0,1] interval
      \note if t0>=t1 returns 0
     */
	double getLength(double t0, double t1) const;

	inline double getLength(double t1 = 1.0) const
	{
		return getLength(0.0, t1);
	}

	/*! 
      N.B. if t==0 o t==1 return a quadratic with all points equal
     */
	void split(double t, TCubic &first, TCubic &second) const;
};

//-----------------------------------------------------------------------------

//!\relates TAffine, TCubic
inline TCubic operator*(const TAffine &aff, const TCubic &curve)
{
	TCubic out;
	out.setP0(aff * curve.getP0());
	out.setP1(aff * curve.getP1());
	out.setP2(aff * curve.getP2());
	out.setP3(aff * curve.getP3());
	return out;
}

//-----------------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TCubic &curve);

//-----------------------------------------------------------------------------

inline std::ostream &operator<<(std::ostream &out, const TCubic *curve)
{
	assert(curve);
	return out << *curve;
}

//=============================================================================
/*!
  TSegment Class to manage a segment with thickness
  \!relates TSegment
 */
class DVAPI TThickSegment : public TSegment
{
protected:
	double m_thickP0;
	double m_thickP1;

public:
	//! m_thickP0, m_thickP1 are thickness of segment control points
	TThickSegment()
		: TSegment(), m_thickP0(0), m_thickP1(0) {}

	TThickSegment(const TThickSegment &thickSegment)
		: TSegment(thickSegment), m_thickP0(thickSegment.m_thickP0), m_thickP1(thickSegment.m_thickP1) {}

	TThickSegment(const TSegment &seg)
		: TSegment(seg), m_thickP0(0), m_thickP1(0) {}

	TThickSegment(const TPointD &p0, double thickP0,
				  const TPointD &p1, double thickP1)
		: TSegment(p0, p1), m_thickP0(thickP0), m_thickP1(thickP1) {}

	TThickSegment(const TThickPoint &thickP0,
				  const TThickPoint &thickP1)
		: TSegment(thickP0, thickP1), m_thickP0(thickP0.thick), m_thickP1(thickP1.thick) {}

	TThickSegment &operator=(const TThickSegment &other)
	{
		m_c0.x = other.m_c0.x;
		m_c1.x = other.m_c1.x;
		m_c0.y = other.m_c0.y;
		m_c1.y = other.m_c1.y;
		m_thickP0 = other.m_thickP0;
		m_thickP1 = other.m_thickP1;
		return *this;
	}

	//!Set the value of first control point \b P0 to \b TThickPoint \b p0.
	void setThickP0(const TThickPoint &p0)
	{
		m_c0.x = p0.x;
		m_c0.y = p0.y;
		m_thickP0 = p0.thick;
	}
	//!Set the value of second control point \b P1 to \b TThickPoint \b p1.
	void setThickP1(const TThickPoint &p1)
	{
		m_c1.x = p1.x - m_c0.x;
		m_c1.y = p1.y - m_c0.y;
		m_thickP1 = p1.thick;
	}

	//!Return first control point \b P0.
	TThickPoint getThickP0() const { return TThickPoint(m_c0, m_thickP0); }
	//!Return second control point \b P1.
	TThickPoint getThickP1() const { return TThickPoint(m_c0 + m_c1, m_thickP1); }

	//!Return the \b TThickPoint of segment at parameter \b t.
	TThickPoint getThickPoint(double t) const
	{
		return TThickPoint(m_c0 + t * m_c1, (1 - t) * m_thickP0 + t * m_thickP1);
	}
};

//-----------------------------------------------------------------------------

inline TThickSegment operator*(const TAffine &aff, const TThickSegment &ts)
{
	TThickSegment out(ts);
	out.setP0(aff * ts.getP0());
	out.setP1(aff * ts.getP1());
	return out;
}

//-----------------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TThickSegment &segment);

//-----------------------------------------------------------------------------

inline std::ostream &operator<<(std::ostream &out, const TThickSegment *segment)
{
	assert(segment);
	return out << *segment;
}

//=============================================================================

/*!
  Class TThickQuadratic: manage a curve with thick
  \!relates TQuadratic
 */
class DVAPI TThickQuadratic : public TQuadratic
{
protected:
	double m_thickP0;
	double m_thickP1;
	double m_thickP2;

public:
	TThickQuadratic();

	//! thickP0, thickP1, thickP2 are thickness of quadratic control points
	TThickQuadratic(const TPointD &p0, double thickP0,
					const TPointD &p1, double thickP1,
					const TPointD &p2, double thickP2);

	TThickQuadratic(const TThickPoint &p0,
					const TThickPoint &p1,
					const TThickPoint &p2);

	TThickQuadratic(const TThickQuadratic &thickQuadratic);

	TThickQuadratic(const TQuadratic &quadratic);

	//!Set the value of first control point \b P0 to \b TThickPoint \b p.
	void setThickP0(const TThickPoint &p);
	//!Set the value of second control point \b P1 to \b TThickPoint \b p.
	void setThickP1(const TThickPoint &p);
	//!Set the value of third control point \b P2 to \b TThickPoint \b p.
	void setThickP2(const TThickPoint &p);

	//!Return the \b TThickPoint of quadratic at parameter \b t.
	TThickPoint getThickPoint(double t) const;

	//!Return first control point \b P0.
	TThickPoint getThickP0() const { return TThickPoint(m_p0, m_thickP0); }
	//!Return second control point \b P1.
	TThickPoint getThickP1() const { return TThickPoint(m_p1, m_thickP1); }
	//!Return third control point \b P2.
	TThickPoint getThickP2() const { return TThickPoint(m_p2, m_thickP2); }

	void split(double t, TThickQuadratic &first, TThickQuadratic &second) const;

	TRectD getBBox() const;
};

//---------------------------------------------------------------------

inline TThickQuadratic operator*(const TAffine &aff, const TThickQuadratic &tq)
{
	TThickQuadratic out(tq);
	out.setP0(aff * tq.getP0());
	out.setP1(aff * tq.getP1());
	out.setP2(aff * tq.getP2());

	return out;
}

//---------------------------------------------------------------------

inline TThickQuadratic transformQuad(const TAffine &aff, const TThickQuadratic &tq, bool doChangeThickness = false)
{
	if (!doChangeThickness)
		return aff * tq;

	TThickQuadratic out(tq);
	double det = aff.det();
	det = (det < 0) ? sqrt(-det) : sqrt(det);

	out.setThickP0(TThickPoint(aff * tq.getP0(), tq.getThickP0().thick * det));
	out.setThickP1(TThickPoint(aff * tq.getP1(), tq.getThickP1().thick * det));
	out.setThickP2(TThickPoint(aff * tq.getP2(), tq.getThickP2().thick * det));
	return out;
}

//---------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TThickQuadratic &tq);

//---------------------------------------------------------------------

inline std::ostream &operator<<(std::ostream &out, const TThickQuadratic *tq)
{
	assert(tq);
	return out << *tq;
}

//=============================================================================

/*!
  Class TThickCubic: manage a cubic with thick
  \!relates TCubic
 */
class DVAPI TThickCubic : public TCubic
{
protected:
	double m_thickP0;
	double m_thickP1;
	double m_thickP2;
	double m_thickP3;

public:
	TThickCubic();

	//! thickP0, thickP1, thickP2, thickP3 are thickness of cubic control points
	TThickCubic(const TPointD &p0, double thickP0,
				const TPointD &p1, double thickP1,
				const TPointD &p2, double thickP2,
				const TPointD &p3, double thickP3);

	TThickCubic(const TThickPoint &p0,
				const TThickPoint &p1,
				const TThickPoint &p2,
				const TThickPoint &p3);

	//  tonino ***************************************************************
	TThickCubic(const T3DPointD &p0,
				const T3DPointD &p1,
				const T3DPointD &p2,
				const T3DPointD &p3);

	//  tonino ***************************************************************

	TThickCubic(const TThickCubic &thickCubic);

	TThickCubic(const TCubic &cubic);

	//!Set the value of first control point \b P0 to \b TThickPoint \b p.
	void setThickP0(const TThickPoint &p);
	//!Set the value of second control point \b P1 to \b TThickPoint \b p.
	void setThickP1(const TThickPoint &p);
	//!Set the value of third control point \b P2 to \b TThickPoint \b p.
	void setThickP2(const TThickPoint &p);
	//!Set the value of fourth control point \b P3 to \b TThickPoint \b p.
	void setThickP3(const TThickPoint &p);

	//!Return the \b TThickPoint of cubic at parameter \b t.
	TThickPoint getThickPoint(double t) const;

	//!Return first control point \b P0.
	TThickPoint getThickP0() const { return TThickPoint(m_p0, m_thickP0); }
	//!Return second control point \b P1.
	TThickPoint getThickP1() const { return TThickPoint(m_p1, m_thickP1); }
	//!Return third control point \b P2.
	TThickPoint getThickP2() const { return TThickPoint(m_p2, m_thickP2); }
	//!Return fourth control point \b P3.
	TThickPoint getThickP3() const { return TThickPoint(m_p3, m_thickP3); }

	void split(double t, TThickCubic &first, TThickCubic &second) const;
};

//---------------------------------------------------------------------

inline TThickCubic operator*(const TAffine &aff, const TThickCubic &tc)
{
	TThickCubic out(tc);
	out.setP0(aff * tc.getP0());
	out.setP1(aff * tc.getP1());
	out.setP2(aff * tc.getP2());
	out.setP3(aff * tc.getP3());
	return out;
}

//---------------------------------------------------------------------

DVAPI std::ostream &operator<<(std::ostream &out, const TThickCubic &tc);

//---------------------------------------------------------------------

inline std::ostream &operator<<(std::ostream &out, const TThickCubic *tc)
{
	assert(tc);
	return out << *tc;
}

//=====================================================================

#endif //__T_CURVES_INCLUDED
//-----------------------------------------------------------------------------
//  End Of File
//-----------------------------------------------------------------------------