/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */

#include "config.h"

#include "triangle.h"

static double dot(g2d_vect_t p1, g2d_vect_t p2)
{
	return (double)p1.x * (double)p2.x + (double)p1.y * (double)p2.y;
}

/* Compute whether point is inside a triangle formed by 3 other points
   Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html
   Same as in librnd poly lib. */
int csch_point_in_triangle(g2d_vect_t A, g2d_vect_t B, g2d_vect_t C, g2d_vect_t P)
{
	g2d_vect_t v0, v1, v2;
	double dot00, dot01, dot02, dot11, dot12;
	double invDenom;
	double u, v;

	/* Compute vectors */
	v0.x = C.x - A.x;
	v0.y = C.y - A.y;
	v1.x = B.x - A.x;
	v1.y = B.y - A.y;
	v2.x = P.x - A.x;
	v2.y = P.y - A.y;

	/* Compute dot products */
	dot00 = dot(v0, v0);
	dot01 = dot(v0, v1);
	dot02 = dot(v0, v2);
	dot11 = dot(v1, v1);
	dot12 = dot(v1, v2);

	/* Compute barycentric coordinates */
	invDenom = 1. / (dot00 * dot11 - dot01 * dot01);
	u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	v = (dot00 * dot12 - dot01 * dot02) * invDenom;

	/* Check if point is in triangle */
	return (u > 0.0) && (v > 0.0) && (u + v < 1.0);
}

int csch_any_point_in_triangle(g2d_vect_t A, g2d_vect_t B, g2d_vect_t C, g2d_vect_t *P, int npts)
{
	g2d_vect_t v0, v1, v2;
	double dot00, dot01, dot02, dot11, dot12;
	double invDenom;
	double u, v;
	int n;

	/* Compute vectors */
	v0.x = C.x - A.x;
	v0.y = C.y - A.y;
	v1.x = B.x - A.x;
	v1.y = B.y - A.y;


	/* Compute dot products */
	dot00 = dot(v0, v0);
	dot01 = dot(v0, v1);
	dot11 = dot(v1, v1);

	/* Compute barycentric coordinates */
	invDenom = 1. / (dot00 * dot11 - dot01 * dot01);

	/* calc only the variable part for each point, return the first time we are in */
	for(n = 0; n < npts; n++,P++) {
		v2.x = (*P).x - A.x;
		v2.y = (*P).y - A.y;
		dot02 = dot(v0, v2);
		dot12 = dot(v1, v2);

		/* Compute barycentric coordinates */
		u = (dot11 * dot02 - dot01 * dot12) * invDenom;
		v = (dot00 * dot12 - dot01 * dot02) * invDenom;

		/* Check if point is in triangle */
		if ((u > 0.0) && (v > 0.0) && (u + v < 1.0))
			return 1;
	}

	return 0;
}
