Blob Blame Raw
#pragma once

#ifndef TCG_POLYLINE_OPS
#define TCG_POLYLINE_OPS

// tcg includes
#include "traits.h"
#include "containers_reader.h"
#include "point.h"
#include "point_ops.h"

namespace tcg
{
namespace polyline_ops
{

//**************************************************************************************
//    Polyline Basic Operations
//**************************************************************************************

/*!
  Computes the length of the polyline between the specified point iterators.
  \return   The input polyline's length
*/

template <typename ForIt>
double length(ForIt begin, ForIt end)
{
	typedef typename std::iterator_traits<ForIt>::value_type point_type;

	double result = 0.0;

	for (ForIt jt = begin, it = ++jt; jt != end; it = jt, ++jt)
		result += tcg::point_ops::dist(*it, *jt);

	return result;
}

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

/*!
  Computes the area enclosed by the input polyline's \a closure.

  \note    The input polyline is implicitly \a connected at the endpoints
           with a straight segment. This has obviously makes no difference
           if the supplied polyline already had coincident endpoints.

  \return  The area enclosed by the polyline's \a closure.
*/

template <typename ForIt>
double area(ForIt begin, ForIt end)
{
	typedef typename std::iterator_traits<ForIt>::value_type point_type;

	double result = 0.0;

	if (begin != end) {
		ForIt jt = begin, it = jt++;

		for (; jt != end; it = jt++)
			result += 0.5 *
					  (tcg::point_traits<point_type>::y(*jt) + tcg::point_traits<point_type>::y(*it)) *
					  (tcg::point_traits<point_type>::x(*jt) - tcg::point_traits<point_type>::x(*it));

		result += 0.5 *
				  (tcg::point_traits<point_type>::y(*begin) + tcg::point_traits<point_type>::y(*it)) *
				  (tcg::point_traits<point_type>::x(*begin) - tcg::point_traits<point_type>::x(*it));
	}

	return result;
}

//**************************************************************************************
//    Quadratic Conversions
//**************************************************************************************

/*!
  Standard direct conversion function used in polyline-to-quadratics conversion.

  Point a has already been inserted in the output; this function must add the
  remaining part of a sequence of quadratics approximating the triplet (a, *bt, c).
*/

//Note: typename iter_type::value_type == point_type
template <typename point_type, typename iter_type>
void tripletToQuadratics(const point_type &a, const iter_type &bt, const point_type &c,
						 tcg::sequential_reader<std::vector<point_type>> &output)
{
	//Direct conversion
	output.addElement(*bt);
	output.addElement(c);
}

/*!
  Performs a conversion of the specified polyline into a sequence of quadratics, then
  applies a quadratics sub-sequence optimal merging algorithm.

  A user-made local triplet-to-quadratics conversion can be supplied to recognize corners
  or supply a tight starting approximation.

\warning Passed polylines with equal endpoints are interpreted as closed (circular) polylines;
         in this case, the resulting endpoints of the quadratic sequence will be displaced to
         the first segment mid-point.
*/

template <typename iter_type, typename containers_reader, typename toQuadsFunc>
void toQuadratics(iter_type begin, iter_type end, containers_reader &output,
				  toQuadsFunc &toQuads = &tripletToQuadratics<
										 typename iter_type::value_type, iter_type>,
				  double mergeTol = 1.0);

//**************************************************************************************
//    Standard Polyline Evaluators
//**************************************************************************************

/*!
  Calculates the (weighted) standard deviation of a polyline's sub-paths with respect
  to the segment connecting the endpoints.

  \warning For efficiency reasons, the returned value is the actual standard
  deviation, times the endpoints-segment length.
*/

template <typename RanIt>
class StandardDeviationEvaluator
{
public:
	typedef RanIt iterator_type;
	typedef typename std::iterator_traits<RanIt>::difference_type diff_type;
	typedef typename std::iterator_traits<RanIt>::value_type point_type;
	typedef typename tcg::point_traits<point_type>::value_type value_type;
	typedef double penalty_type;

protected:
	iterator_type m_begin, m_end;

	std::vector<double> m_sums_x, m_sums_y;   //!< Sums of the points coordinates
	std::vector<double> m_sums2_x, m_sums2_y; //!< Sums of the points coordinates' squares
	std::vector<double> m_sums_xy;			  //!< Sums of the coordinates products

public:
	StandardDeviationEvaluator(const iterator_type &begin, const iterator_type &end);

	penalty_type penalty(const iterator_type &a, const iterator_type &b);

	const iterator_type &begin() const { return m_begin; }
	const iterator_type &end() const { return m_end; }

	const std::vector<double> &sums_x() const { return m_sums_x; }
	const std::vector<double> &sums_y() const { return m_sums_y; }
	const std::vector<double> &sums2_x() const { return m_sums2_x; }
	const std::vector<double> &sums2_y() const { return m_sums2_y; }
	const std::vector<double> &sums_xy() const { return m_sums_xy; }
};
}
} //namespace tcg::polyline_ops

#ifdef INCLUDE_HPP
#include "hpp/polyline_ops.hpp"
#endif

#endif //TCG_POLYLINE_OPS