inline std::tuple<MathLib::Point3d, MathLib::Point3d, MathLib::Point3d>
getEdgeMiddlePoints(GeoLib::Triangle const& tri)
{
    return std::make_tuple(
               getEdgeMiddlePoint(*tri.getPoint(0), *tri.getPoint(1)),
               getEdgeMiddlePoint(*tri.getPoint(1), *tri.getPoint(2)),
               getEdgeMiddlePoint(*tri.getPoint(2), *tri.getPoint(0)));
}
double LinearInterpolationOnSurface::interpolateInTri(const GeoLib::Triangle &tri, double const* const vertex_values, double const* const pnt) const
{
	std::vector<GeoLib::Point> pnts;
	for (unsigned i=0; i<3; i++)
		pnts.emplace_back(*tri.getPoint(i));
	std::vector<GeoLib::Point*> p_pnts = {{&pnts[0], &pnts[1], &pnts[2]}};
	GeoLib::rotatePointsToXY(p_pnts);

	GeoLib::Point const& v1(pnts[0]);
	GeoLib::Point const& v2(pnts[1]);
	GeoLib::Point const& v3(pnts[2]);
	const double area = GeoLib::calcTriangleArea(v1, v2, v3);

	if (area==.0) {
		// take average if all points have the same coordinates
		return std::accumulate(vertex_values, vertex_values+3, 0.0) / 3;
	}

	// interpolate as
	//   u(x,y) = sum_i[N_i(x,y)*u_i]  (i=1,2,3)
	//   N_i(x,y) = 1/(2A)*(a_i + b_i*x + c_i*y)

	double a[3], b[3], c[3];
	// 1st vertex
	a[0] = 0.5/area*(v2[0]*v3[1]-v3[0]*v2[1]);
	b[0] = 0.5/area*(v2[1]-v3[1]);
	c[0] = 0.5/area*(v3[0]-v2[0]);
	// 2nd vertex
	a[1] = 0.5/area*(v3[0]*v1[1]-v1[0]*v3[1]);
	b[1] = 0.5/area*(v3[1]-v1[1]);
	c[1] = 0.5/area*(v1[0]-v3[0]);
	// 3rd vertex
	a[2] = 0.5/area*(v1[0]*v2[1]-v2[0]*v1[1]);
	b[2] = 0.5/area*(v1[1]-v2[1]);
	c[2] = 0.5/area*(v2[0]-v1[0]);

	double val = .0;
	for (unsigned i=0; i<3; i++)
		val += (a[i]+b[i]*pnt[0]+c[i]*pnt[1]) * vertex_values[i];

	return val;
}