Пишу сижу последние дни всякую простейшую математику, которая часто юзается.
В итоге вышел вот такой класс:
using System;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
public static class CustomMath
{
//Возвращает индекс минимального элемента
public static int MinIndex(float[] values)
{
return GetABResultIndex<float>(values, (a, b) => a > b, f => true);
}
//Возвращает индекс минимального элемента, при том у элемента должно выполнять некоторое условие
public static int MinIndex(float[] values, Predicate<float> condition)
{
return GetABResultIndex<float>(values, (a, b) => a > b, condition);
}
//Возвращает индекс максимального элемента
public static int MaxIndex(float[] values)
{
return GetABResultIndex<float>(values, (a, b) => a < b, f => true);
}
//Возвращает индекс минимального элемента, при том у элемента должно выполнять некоторое условие
public static int MaxIndex(float[] values, Predicate<float> condition)
{
return GetABResultIndex<float>(values, (a, b) => a < b, condition);
}
private static int GetABResultIndex<T>(T[] values, Func<T, T, bool> conditionAB, Predicate<T> conditionElement)
{
var resultIndex = -1;
for (int i = 0; i < values.Length; i++)
{
if ((resultIndex == -1 || conditionAB(values[resultIndex], values[i])) && conditionElement(values[i]))
resultIndex = i;
}
return -1;
}
//Функции округления тупо продублированы с понятными мне именами
public static float Round(float value)
{
return Mathf.Round(value);
}
public static float RoundMin(float value)
{
return Mathf.Floor(value);
}
public static float RoundMax(float value)
{
return Mathf.Ceil(value);
}
public static float RoundToInt(float value)
{
return Mathf.RoundToInt(value);
}
public static float RoundMinToInt(float value)
{
return Mathf.FloorToInt(value);
}
public static float RoundMaxToInt(float value)
{
return Mathf.CeilToInt(value);
}
//Округление векторов, епты
public static Vector3 Round(Vector3 value)
{
return new Vector3(Mathf.Round(value.x), Mathf.Round(value.y), Mathf.Round(value.z));
}
public static Vector3 RoundMin(Vector3 value)
{
return new Vector3(Mathf.Floor(value.x), Mathf.Floor(value.y), Mathf.Floor(value.z));
}
public static Vector3 RoundMax(Vector3 value)
{
return new Vector3(Mathf.Ceil(value.x), Mathf.Ceil(value.y), Mathf.Ceil(value.z));
}
public static Vector2 Round(Vector2 value)
{
return new Vector2(Mathf.Round(value.x), Mathf.Round(value.y));
}
public static Vector2 RoundMin(Vector2 value)
{
return new Vector2(Mathf.Floor(value.x), Mathf.Floor(value.y));
}
public static Vector2 RoundMax(Vector2 value)
{
return new Vector2(Mathf.Ceil(value.x), Mathf.Ceil(value.y));
}
public static Vector3 defaultScale
{
get { return new Vector3(1, 1, 1); }
}
//Нормали в отрезке
public static int GetNormal(float value)
{
if (value > 0)
return 1;
if (value < 0)
return -1;
return 0;
}
public static int GetNormalPositive(float value)
{
if (value > 0)
return 1;
return 0;
}
public static int GetNormalNegative(float value)
{
if (value < 0)
return -1;
return 0;
}
//Поиск площади фигуры
public static class Area
{
/// <summary>
/// Формула Герона
/// </summary>
public static float TriangleFromPoints(Vector3 a, Vector3 b, Vector3 c)
{
var longitudes = Longitudes(a, b, c);
var perimeter = longitudes.Sum();
var p = perimeter/2f;
var sqrS = p*(p - longitudes[0])*(p - longitudes[1])*(p - longitudes[2]);
var s = Mathf.Sqrt(sqrS);
return s;
}
/// <summary>
///
/// </summary>
/// <param name="aSide"></param>
/// <param name="bSide"></param>
/// <param name="cSide"></param>
/// <returns></returns>
public static float TriangleFromSides(float aSide, float bSide, float cSide)
{
var perimeter = aSide + bSide + cSide;
var p = perimeter/2f;
var sqrS = p*(p - aSide)*(p - bSide)*(p - cSide);
var s = Mathf.Sqrt(sqrS);
return s;
}
public static float TriangleFromPoints_Fast(Vector3 a, Vector3 b, Vector3 c)
{
var dir1 = (a - b);
var dir2 = (c - b);
return WedgeProduct(dir1, dir2);
}
/// <summary>
///
/// </summary>
/// <param name="side">Длина одной из сторон треугольника</param>
/// <param name="h">Проведенная к этой длине высота</param>
/// <returns></returns>
public static float TriangleFromSideAndHeight(float side, float h)
{
return .5f*side*h;
}
/// <summary>
///
/// </summary>
/// <param name="perimeter"></param>
/// <param name="r">Радиус вписанной окружности</param>
/// <returns></returns>
public static float TriangleFromPerimeterAndInradius(float perimeter, float r)
{
var p = perimeter/2f;
return p*r;
}
/// <summary>
///
/// </summary>
/// <param name="aSide"></param>
/// <param name="bSide"></param>
/// <param name="cSide"></param>
/// <param name="R">Радиус описанной окружности</param>
/// <returns></returns>
public static float TriangleFromSidesAndOutradius(float aSide, float bSide, float cSide, float R)
{
return (aSide*bSide*cSide)/(4*R);
}
public static float TriangleFromSidesAndAngle(float aSide, float bSide, float angleAB)
{
return .5f * aSide * bSide * Degrees.Sin(angleAB);
}
public static float SquareFromSide(float side)
{
return side*side;
}
public static float SquareFromDiagonal(float diagonal)
{
return .5f*(diagonal*diagonal);
}
public static float RectangleFromSides(float aSide, float bSide)
{
return aSide*bSide;
}
public static float RectangleFromPoints(Vector3 a, Vector3 b, Vector3 c)
{
var aSide = Vector3.Distance(a, b);
var bSide = Vector3.Distance(b, c);
return RectangleFromSides(aSide, bSide);
}
/// <summary>
/// Формула площади параллелограмма по длине стороны и высоте.
/// Площадь параллелограмма равна произведению длины его стороны и длины опущенной на эту сторону высоты.
/// </summary>
/// <param name="aSide"></param>
/// <param name="height"></param>
/// <returns></returns>
public static float ParallelogramFromSideAndHeight(float aSide, float height)
{
return aSide*height;
}
public static float ParallelogramFromPoints(Vector3 a, Vector3 b, Vector3 c)
{
var aSide = Vector3.Distance(a, b);
var bSide = Vector3.Distance(b, c);
var dirBA = (a - b);
var dirBC = (c - b);
var angle = Vector3.Angle(dirBA, dirBC);
return ParallelogramFromSidesAndAngle(aSide, bSide, angle);
}
public static float ParallelogramFromPoints_Fast(Vector3 a, Vector3 b, Vector3 c)
{
var dir1 = (a - b);
var dir2 = (c - b);
return WedgeProduct(dir1, dir2);
}
public static float ParallelogramFromSidesAndAngle(float aSide, float bSide, float angleAB)
{
return aSide * bSide * Degrees.Sin(angleAB);
}
public static float ParallelogramFromDiagonalAndAngle(float d1, float d2, float angleD1D2)
{
return d1 * d2 * Degrees.Sin(angleD1D2);
}
public static float CircleFromRadius(float radius)
{
return Mathf.PI*(radius*radius);
}
public static float CircleFromDiameter(float diameter)
{
return .25f * Mathf.PI * (diameter * diameter);
}
public static float Ellipse(float radius1, float radius2)
{
return Mathf.PI*radius1*radius2;
}
public static float TrapezeFromSides(float a, float b, float c, float d)
{
var p = (a + b + c + d)/2f;
var n1 = a + b;
var n2 = 4 - Mathf.Abs(a - b);
var n3 = (p - a)*(p - b)*(p - a - c)*(p - a - d);
var s = (n1/n2)*Mathf.Sqrt(n3);
return s;
}
public static float TrapezeFromBasesAndHeight(float aBase, float bBase, float height)
{
return .5f*(aBase + bBase)*height;
}
public static float RhombusFromSideAndHeight(float aSide, float height)
{
return aSide*height;
}
public static float RhombusFromSideAndAngle(float aSide, float angleInDegrees)
{
return aSide*aSide*Degrees.Sin(angleInDegrees);
}
public static float RhombusFromDiagonals(float diagonal1, float diagonal2)
{
return .5f*diagonal1*diagonal2;
}
public static float SphereFromRadius(float radius)
{
return 4*Mathf.PI*(radius*radius);
}
/// <summary>
/// Все точки должны быть в одной плоскости
/// </summary>
/// <param name="points"></param>
/// <returns></returns>
public static float PolygonFromPoints_Fast(params Vector2[] points)
{
if (points.Length < 3)
throw new Exception("Need minimum 3 points");
var s = 0f;
for (int i = 0; i < points.Length; i++)
{
var iplus = (i + 1)%points.Length;
var a = points[i];
var b = points[iplus];
var c = new Vector2(b.x, 0);
var d = new Vector2(a.x, 0);
s += TrapezeFromBasesAndHeight(a.y, b.y, c.x - d.x);
}
return Mathf.Abs(s);
}
public static float PolygonFromPoints(params Vector2[] points)
{
if (points.Length < 3)
throw new Exception("Need minimum 3 points");
var min = points.Min(v => v.y);
var s = 0f;
for (int i = 0; i < points.Length; i++)
{
var iplus = (i + 1) % points.Length;
var a = points[i];
var b = points[iplus];
var c = new Vector2(b.x, min);
var d = new Vector2(a.x, min);
s += TrapezeFromBasesAndHeight(a.y - min, b.y - min, c.x - d.x);
}
return Mathf.Abs(s);
}
}
public static class Perimeter
{
public static float Points(params Vector3[] points)
{
if (points.GetCount() < 3)
throw new Exception("points.Length need value >= 3");
return Longitudes(points).Sum();
}
public static float Points(params Vector2[] points)
{
if (points.GetCount() < 3)
throw new Exception("points.Length need value >= 3");
return Longitudes(points).Sum();
}
public static float CircleFromRadius(float radius)
{
return 2*Mathf.PI * radius;
}
public static float CircleFromDiameter(float diameter)
{
return diameter * Mathf.PI;
}
public static float Sides(params float[] sides)
{
if (sides.Length < 3)
throw new Exception("sides.Length need value >= 3");
return sides.Sum();
}
public static float Rhombus(float aSide)
{
return 4*aSide;
}
public static float Square(float aSide)
{
return 4*aSide;
}
public static float Rectangle(float aSide, float bSide)
{
return 2*(aSide+bSide);
}
public static float Parallelogram(float aSide, float bSide)
{
return 2*(aSide*bSide);
}
}
public static class Volume
{
public static float Cube(float aSide)
{
return aSide*aSide*aSide;
}
public static float Prism(float sBase, float height)
{
return sBase*height;
}
public static float Parallelepiped(Vector3 a, Vector3 b, Vector3 c)
{
return Mathf.Abs(TripleScalarProduct(a,b,c));
}
public static float Parallelepiped(float sBase, float height)
{
return sBase*height;
}
public static float Cuboid(float aSide, float bSide, float height)
{
return aSide*bSide*height;
}
public static float Pyramid(float sBase, float height)
{
return (sBase*height)/3f;
}
public static float RegularTetrahedron(float aSide)
{
var n1 = aSide*aSide*aSide;
var n2 = Mathf.Sqrt(2);
return (n1*n2)/12;
}
public static float CylinderFromRadius(float radius, float height)
{
return Mathf.PI*(radius*radius)*height;
}
public static float CylinderFromS(float sBase, float height)
{
return sBase * height;
}
public static float ConeFromRadius(float radius, float height)
{
return CylinderFromRadius(radius, height)/3f;
}
public static float ConeFromS(float sBase, float height)
{
return CylinderFromS(sBase, height) / 3f;
}
public static float Sphere(float radius)
{
return 4f/3f*Mathf.PI*(radius*radius*radius);
}
}
public static class Degrees
{
public static float Sin(float value)
{
return Mathf.Sin(value*Mathf.Deg2Rad);
}
public static float Cos(float value)
{
return Mathf.Cos(value * Mathf.Deg2Rad);
}
public static float Acos(float value)
{
return Mathf.Acos(value * Mathf.Deg2Rad);
}
public static float Asin(float value)
{
return Mathf.Asin(value * Mathf.Deg2Rad);
}
public static float Atan(float value)
{
return Mathf.Atan(value * Mathf.Deg2Rad);
}
public static float Tan(float value)
{
return Mathf.Tan(value * Mathf.Deg2Rad);
}
}
public static float WedgeProduct(Vector2 lhs, Vector2 rhs)
{
return lhs.x*rhs.y - lhs.y*rhs.x;
}
public static float TripleScalarProduct(Vector3 a, Vector3 b, Vector3 c)
{
return Vector3.Dot(a, Vector3.Cross(b, c));
}
public static Vector3 TripleVectorProduct(Vector3 a, Vector3 b, Vector3 c)
{
return Vector3.Cross(a, Vector3.Cross(b, c));
}
public static Vector3 CrossProduct(Vector3 lhs, Vector3 rhs)
{
return Vector3.Cross(lhs, rhs);
}
public static float DotProduct(Vector2 lhs, Vector3 rhs)
{
return lhs.x*rhs.x + lhs.y*rhs.y;
}
public static class Intersect
{
//Отрезки 2D
public static bool Segments(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
{
var dirA = a2 - a1;
var dirB = b2 - b1;
var dir1 = b1 - a1;
var dirX1 = a2 - b1;
var dirX2 = b2 - a1;
var f1 = WedgeProduct(dirB, -dir1);
var f2 = WedgeProduct(dirB, dirX1);
var f3 = WedgeProduct(dirA, dir1);
var f4 = WedgeProduct(dirA, dirX2);
var result = (f1*f2 < 0) && (f3*f4 < 0);
return result;
}
//Отрезки 3D
public static bool Segments(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result)
{
result = new Vector3();
Vector3 intersect;
float t;
if (Straight(a1, a2, b1, b2, out intersect, out t))
{
result = intersect;
return t >= 0 && t <= 1;
}
return false;
}
public static bool Segments(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
Vector3 intersect;
float t;
if (Straight(a1, a2, b1, b2, out intersect, out t))
return t >= 0 && t <= 1;
return false;
}
public static Vector3? SegmentsNullable(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
Vector3 intersect;
float t;
if (Straight(a1, a2, b1, b2, out intersect, out t))
return t >= 0 && t <= 1 ? (Vector3?) intersect : null;
return null;
}
public static bool Straight(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
{
var a = a2 - a1;
var b = b2 - b1;
return WedgeProduct(a, b).EqualsApprox(0f);
}
//Прямая 3D
public static Vector3? StraightNullable(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
Vector3 intersect;
float t;
return Straight(a1, a2, b1, b2, out intersect, out t) ? (Vector3?) intersect : null;
}
public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
Vector3 intersect;
float t;
return Straight(a1, a2, b1, b2, out intersect, out t);
}
public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result)
{
result = new Vector3();
Vector3 intersect;
float t;
if (Straight(a1, a2, b1, b2, out intersect, out t))
{
result = intersect;
return true;
}
return false;
}
public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result, out float t)
{
var aDir = (a2 - a1).normalized;
var bDir = (b2 - b1).normalized;
result = new Vector3();
t = -1;
for (int xIndex = 0; xIndex < 3; xIndex++)
{
var yIndex = (xIndex + 1)%3;
var zIndex = (xIndex + 2)%3;
var n1 = new Vector2(aDir[xIndex], aDir[yIndex]);
var n2 = -new Vector2(bDir[xIndex], bDir[yIndex]);
var n3 = new Vector2(
b1[xIndex] - a1[xIndex],
b1[yIndex] - a1[yIndex]
);
var det = n1.x * n2.y - n2.x * n1.y;
if (Mathf.Abs(det) >= Mathf.Epsilon) // if det != 0
{
var d1 = n3.x * n2.y - n2.x * n3.y;
var d2 = n1.x * n3.y - n1.y * n3.x;
var t1 = d1 / det;
var t2 = d2 / det;
var temp1 = a1[zIndex] + aDir[zIndex] * t1;
var temp2 = b1[zIndex] + bDir[zIndex] * t2;
if (Mathf.Abs(temp1 - temp2) < Mathf.Epsilon)
{
result = a1 + aDir*t1;
t = t1;
return true; // if temp1 = temp2
}
return false;
}
}
return false;
}
}
public static class Contains
{
public static bool Rectangle(Rect rect, Vector2 point)
{
return rect.Contains(point);
}
public static bool Segment(Vector2 a1, Vector2 a2, Vector2 point)
{
var v1 = a2 - a1;
var v2 = point - a1;
return WedgeProduct(v1, v2).EqualsApprox(0f) && Vector2.Dot(a1 - point, a2 - point) <= 0;
}
public static bool Straight(Vector2 a1, Vector2 a2, Vector2 point)
{
var v1 = (a2 - a1);
var v2 = (point - a1);
var diff = WedgeProduct(v1, v2);
return diff.EqualsApprox(0f);
}
public static bool RayFromPoints(Vector2 aStart, Vector2 aFinish, Vector2 point)
{
return RayFromDir(aStart, (aFinish - aStart).normalized, point);
}
public static bool RayFromDir(Vector2 origin, Vector2 dir, Vector2 point)
{
var v1 = dir;
var v2 = (point - origin);
return WedgeProduct(v1, v2).EqualsApprox(0f) && Vector2.Dot(v1, v2) >= 0;
}
}
/// <summary>
/// Указывает, является ли угол выпуклым (по часовой стрелке)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <returns></returns>
public static bool IsConvex(Vector2 a, Vector2 b, Vector2 c)
{
var AB = -(a - b);
var BC = (c - b);
var diff = WedgeProduct(AB, BC);
return diff <= 0;
}
/// <summary>
/// Указывает, является ли угол выпуклым (по часовой стрелке)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <returns></returns>
public static bool IsConvex(Vector3 a, Vector3 b, Vector3 c)
{
var AB = -(a - b);
var BC = (c - b);
var dAB = Vector3.ProjectOnPlane(AB, new Vector3(0, 0, 1));
var dBC = Vector3.ProjectOnPlane(BC, new Vector3(0, 0, 1));
return IsConvex((Vector2)dAB, Vector2.zero, (Vector2)dBC);
}
public static Vector3 GetNormal(Vector3 a, Vector3 b, Vector3 c)
{
return Vector3.Normalize(Vector3.Cross(b - a, c - a));
}
/// <summary>
/// Возвращает длины между двумя точками.
/// Если точек больше двух, то возвращается так же длина между первой и последней точкой.
/// Минимум 2 точки.
/// </summary>
public static float[] Longitudes(params Vector3[] points)
{
if (points.Length < 2)
return new float[0];
var count = points.Length != 2 ? points.Length : (points.Length - 1);
var longitudes = new float[count];
for (int i = 0; i < count; i++)
{
longitudes[i] = Vector3.Distance(points[i], points[(i + 1) % points.Length]);
}
return longitudes;
}
/// <summary>
/// Возвращает длины между двумя точками.
/// Если точек больше двух, то возвращается так же длина между первой и последней точкой.
/// Минимум 2 точки.
/// </summary>
public static float[] Longitudes(params Vector2[] points)
{
if (points.Length < 2)
return new float[0];
var count = points.Length != 2 ? points.Length : (points.Length - 1);
var longitudes = new float[count];
for (int i = 0; i < count; i++)
{
longitudes[i] = Vector2.Distance(points[i], points[(i + 1) % points.Length]);
}
return longitudes;
}
}
Много всякой херни, но вкратце по основному:
MinIndex/MaxIndex - возвращают индекс наименьшего/наибольшего элемента в массиве. Могут еще на доп условие проверить
Функции округления в большую/меньшую/ближайшую сторону - это тупо было скопировано из библиотеки Mathf под другими именами. Так лично мне удобней.
Функции округления для векторов - ну а почему бы и нет.
vectorScale - тупо заготовленный единичный вектор для размера. Не нашел нигде.
GetNormal для числа - нормализация числа, тобиш возврат единичного отрезка. Бывает необходимо.
Разные Product'ы для векторов - тут парочка старых добрых скалярного/векторного произведения + косое произведение + тройное векторное + тройное скалярное
MinIndex/MaxIndex - возвращают индекс наименьшего/наибольшего элемента в массиве. Могут еще на доп условие проверить
Функции округления в большую/меньшую/ближайшую сторону - это тупо было скопировано из библиотеки Mathf под другими именами. Так лично мне удобней.
Функции округления для векторов - ну а почему бы и нет.
vectorScale - тупо заготовленный единичный вектор для размера. Не нашел нигде.
GetNormal для числа - нормализация числа, тобиш возврат единичного отрезка. Бывает необходимо.
Разные Product'ы для векторов - тут парочка старых добрых скалярного/векторного произведения + косое произведение + тройное векторное + тройное скалярное
В подклассе Area формулы чтобы посчитать площадь фигуры
В подклассе Perimeter формулы чтобы посчитать периметр фигуры
В подклассе Volume формулы чтобы посчитать объем фигуры
В подклассе Intersect формулы чтобы посчитать пересекаются ли фигуры
В подклассе Contains формулы чтобы посчитать содержит ли фигура точку
IsConvex - проверяет выпуклый ли угол по часовой стрелке
Longitudes - возвращает массив длин по указанным точкам
В подклассе Perimeter формулы чтобы посчитать периметр фигуры
В подклассе Volume формулы чтобы посчитать объем фигуры
В подклассе Intersect формулы чтобы посчитать пересекаются ли фигуры
В подклассе Contains формулы чтобы посчитать содержит ли фигура точку
IsConvex - проверяет выпуклый ли угол по часовой стрелке
Longitudes - возвращает массив длин по указанным точкам
Ну и собственно - к чему я пишу. Я вообще по правде туп по части математики.
Потому хочу тут услышать ваши дополнения и быстрые алгоритмы чтобы что-то посчитать.
Меня очень напрягают функции Longitudes, IsConvex для Vector3, Intersect.Straight для Vector3.
Хотелось бы знать, если у вас есть лучшие решения для этих функций.
И еще в рунете не нашел никакой инфы "для чайников" по части вычислений с тройным скалярным произведением, как я понимаю решения через них самые быстрые. Если есть знатоки - пишите формулы, расскажите хоть-что нибудь об этом.
Потому хочу тут услышать ваши дополнения и быстрые алгоритмы чтобы что-то посчитать.
Меня очень напрягают функции Longitudes, IsConvex для Vector3, Intersect.Straight для Vector3.
Хотелось бы знать, если у вас есть лучшие решения для этих функций.
И еще в рунете не нашел никакой инфы "для чайников" по части вычислений с тройным скалярным произведением, как я понимаю решения через них самые быстрые. Если есть знатоки - пишите формулы, расскажите хоть-что нибудь об этом.
Ред. Devion
Вроде тут понятно написано.
Находишь точку пересечений прямых, потом смотришь, лежит ли она внутри обоих из отрезков.
По поводу пересечения прямых - это чтото большое) Я хоть тоже с математикой не особо в ладах, но не проще ли было сначала найти пересечение проекций на какую нибудь координатную плоскость, а затем проверить совпадение оставшейся, еще не использованной, координатой?
Для поиска точек пересечения на плоскости можно воспользоваться ссылкой Hellfirm.
Ред. AsagiriGen
Т.е. если (a1/b1==a2/b2==a3/b3) верно, то они не пересекутся(они паралельны или сливаются). Иначе: пересекутся.
Ред. Devion
GeneralElConsul, сверить то можно, а вот как сделать так, чтобы узнать в какой точке это произошло? Формула выше как бы учитывает это тоже, там out параметрами возврат точки идет
Extravert:
эт понятно, я уже вписал ее. Вот так же выходит, верно?
Ред. Hellfim
Этот код сравнивает одни и тем же направляющим вектором заданы 2 отрезка, или нет.
Потому что нормализация вектора это скрытый sqrt, магнитуда и т д. А тупо сделать три деления побыстрее. Я вот чем руководствуюсь.
В общем то проверим
В общем вот такие функции вышли
Ред. Devion
Вот так сделал
Просто странно. Если ты занялся оптимизацией, то зачем тогда StraightIfNull?
Ред. Mihahail
первая прямая: r=r1+a*t
вторая прямая: r=r2+b*t
t - параметр, в случае прямой пробегает всю числовую ось, в случае отрезка - отрезок.
Где ( a, b, c ) - смешанное произведение, (a,b) - скалярное.
Будет сделано 9 умножений, 3 вычитания и 3 сложения для смешанного произведения; и ещё 3 сложения и 3 умножения для скалярного. Если вычисления ленивые(хз как C#), то именно в таком порядке проверки.
Пусть у нас есть две прямые, лежащие "почти" в одной плоскости с точностью epsilon, и для них выполнено, что (a,b)!=0, т.е. они не параллельные. Тогда они пересекаются.
А вот и не факт. Если они лежат в двух плоскостях, лишь чуть-чуть наклонённых друг относительно друга, и ещё они разнесены( |r1-r2| велико ), то они на дальних расстояниях вообще будут далеко одна от другой. А мы их считаем пересекшимися, потому что наш метод работает только с какой-то точностью epsilon и может не почувствовать маленький угол, дающий большое расхождение на дальних дистанциях.
Так, стоп, нужно только в 2D? Тогда зря я это написал, тогда это в гугл...
Только там ещё если r1-r2 ~ 0, то точка пересечения r=r1=r2
Т.е. через расстояние между скрещивающимися прямыми, только там надо их проверить на параллельность сначала, а то на ноль поделить можно.