/**
* Copyright 2019 Oskar Sigvardsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GK {
public class Geom : MonoBehaviour {
///
/// Are these two vectors (approximately) coincident
///
public static bool AreCoincident(Vector2 a, Vector2 b) {
return (a - b).magnitude < 0.000001f;
}
///
/// Is point p to the left of the line from l0 to l1?
///
public static bool ToTheLeft(Vector2 p, Vector2 l0, Vector2 l1) {
return ((l1.x-l0.x)*(p.y-l0.y) - (l1.y-l0.y)*(p.x-l0.x)) >= 0;
}
///
/// Is point p to the right of the line from l0 to l1?
///
public static bool ToTheRight(Vector2 p, Vector2 l0, Vector2 l1) {
return !ToTheLeft(p, l0, l1);
}
///
/// Is point p inside the triangle formed by c0, c1 and c2 (assuming c1,
/// c2 and c3 are in CCW order)
///
public static bool PointInTriangle(Vector2 p, Vector2 c0, Vector2 c1, Vector2 c2) {
return ToTheLeft(p, c0, c1)
&& ToTheLeft(p, c1, c2)
&& ToTheLeft(p, c2, c0);
}
///
/// Is point p inside the circumcircle formed by c0, c1 and c2?
///
public static bool InsideCircumcircle(Vector2 p, Vector2 c0, Vector2 c1, Vector2 c2) {
var ax = c0.x-p.x;
var ay = c0.y-p.y;
var bx = c1.x-p.x;
var by = c1.y-p.y;
var cx = c2.x-p.x;
var cy = c2.y-p.y;
return (
(ax*ax + ay*ay) * (bx*cy-cx*by) -
(bx*bx + by*by) * (ax*cy-cx*ay) +
(cx*cx + cy*cy) * (ax*by-bx*ay)
) > 0.000001f;
}
///
/// Rotate vector v left 90 degrees
///
public static Vector2 RotateRightAngle(Vector2 v) {
var x = v.x;
v.x = -v.y;
v.y = x;
return v;
}
///
/// General line/line intersection method. Each line is defined by a
/// two vectors, a point on the line (p0 and p1 for the two lines) and a
/// direction vector (v0 and v1 for the two lines). The returned value
/// indicates whether the lines intersect. m0 and m1 are the
/// coefficients of how much you have to multiply the direction vectors
/// to get to the intersection.
///
/// In other words, if the intersection is located at X, then:
///
/// X = p0 + m0 * v0
/// X = p1 + m1 * v1
///
/// By checking the m0/m1 values, you can check intersections for line
/// segments and rays.
///
public static bool LineLineIntersection(Vector2 p0, Vector2 v0, Vector2 p1, Vector2 v1, out float m0, out float m1) {
var det = (v0.x * v1.y - v0.y * v1.x);
if (Mathf.Abs(det) < 0.001f) {
m0 = float.NaN;
m1 = float.NaN;
return false;
} else {
m0 = ((p0.y - p1.y) * v1.x - (p0.x - p1.x) * v1.y) / det;
if (Mathf.Abs(v1.x) >= 0.001f) {
m1 = (p0.x + m0*v0.x - p1.x) / v1.x;
} else {
m1 = (p0.y + m0*v0.y - p1.y) / v1.y;
}
return true;
}
}
///
/// Returns the intersections of two lines. p0/p1 are points on the
/// line, v0/v1 are the direction vectors for the lines.
///
/// If there are no intersections, returns a NaN vector
///
public static Vector2 LineLineIntersection(Vector2 p0, Vector2 v0, Vector2 p1, Vector2 v1) {
float m0, m1;
if (LineLineIntersection(p0, v0, p1, v1, out m0, out m1)) {
return p0 + m0 * v0;
} else {
return new Vector2(float.NaN, float.NaN);
}
}
///
/// Returns the center of the circumcircle defined by three points (c0,
/// c1 and c2) on its edge.
///
public static Vector2 CircumcircleCenter(Vector2 c0, Vector2 c1, Vector2 c2) {
var mp0 = 0.5f * (c0 + c1);
var mp1 = 0.5f * (c1 + c2);
var v0 = RotateRightAngle(c0 - c1);
var v1 = RotateRightAngle(c1 - c2);
float m0, m1;
Geom.LineLineIntersection(mp0, v0, mp1, v1, out m0, out m1);
return mp0 + m0 * v0;
}
///
/// Returns the triangle centroid for triangle defined by points c0, c1
/// and c2.
///
public static Vector2 TriangleCentroid(Vector2 c0, Vector2 c1, Vector2 c2) {
var val = (1.0f/3.0f) * (c0 + c1 + c2) ;
return val;
}
///
/// Returns the signed area of a polygon. CCW polygons return a positive
/// area, CW polygons return a negative area.
///
public static float Area(IList polygon) {
var area = 0.0f;
var count = polygon.Count;
for (int i = 0; i < count; i++) {
var j = (i == count - 1) ? 0 : (i + 1);
var p0 = polygon[i];
var p1 = polygon[j];
area += p0.x*p1.y - p1.y*p1.x;
}
return 0.5f * area;
}
}
}