public static bool IsPointOnLineSegment(Vector2 p, Vector2 v0, Vector2 v1) { var vp = p - v0; var l = v1 - v0; if (Vector2Ext.Equality(vp, Vector2Ext.Zero)) { return(true); //p == v0 } var vpNormal = vp.Normal(); var lNormal = l.Normal(); if ((float)Math.Abs((double)Vector2Ext.Dot(vpNormal, lNormal)) < OneMinusEps) { return(false); } //Lines are the same, are they within the length if (vp.Length() <= l.Length()) { return(true); } return(false); }
public static Vector2 UnitInDirection(Vector2 from, Vector2 too) { if (Vector2Ext.Equality(from, too)) { return(Vector2.Zero); } return((too - from).Normal()); }
public void UpdateParamaters(Vector2 point0, Vector2 tangent0, Vector2 point1, Vector2 tangent1) { if (_p0 != null && _p1 != null && _t0 != null && _t1 != null) { //Only recompute arc if any of the paramaters have changed if (Vector2Ext.Equality(_p0, point0) && Vector2Ext.Equality(_t0, tangent0) && Vector2Ext.Equality(_p1, point1) && Vector2Ext.Equality(_t1, tangent1)) { return; } } SetParams(point0, tangent0, point1, tangent1); }
public AABB(Vector2 min, Vector2 max, int unused, bool validate = false) //Dirt! { if (validate) { if (Vector2Ext.Equality(min, max)) { max.X += 1.0f; max.Y += 1.0f; } if (max.X < min.X) { var s = max.X; max.X = min.X; min.X = s; } if (max.Y < min.Y) { var s = max.Y; max.Y = min.Y; min.Y = s; } } Min = min; Max = max; Centre = 0.5f * (Min + Max); Extents = 0.5f * (Max - Min); Top = Max.Y; Bottom = Min.Y; Left = Min.X; Right = Max.X; Width = Right - Left; Height = Top - Bottom; }
private void ComputeArcs() { //Using Approach as detailed in: http://www.ryanjuckett.com/programming/biarc-interpolation/ _valid = false; Arc0 = new Arc(); Arc1 = new Arc(); //Need to ensure tangents are normalised. Technique here is to renormalise and then check for if equal zero length (which happens if the normalise fails). Can replace with more robust / direct method later, if this becomes a concern _t0 = _t0.Normal(); _t1 = _t1.Normal(); if (_t0.LengthSquared() == 0.0f || _t1.LengthSquared() == 0.0f) { return; } Vector2 v = _p1 - _p0; //If points equal then no interpolation required if (Vector2Ext.Equality(v, Vector2.Zero)) { Arc0.Centre = _p0; Arc0.Radius = 0.0f; Arc0.Axis = v; Arc0.Angle = 0.0f; Arc0.ArcLength = 0.0f; Arc1.Centre = _p1; Arc1.Radius = 0.0f; Arc1.Axis = v; Arc1.Angle = 0.0f; Arc1.ArcLength = 0.0f; _valid = true; return; } float pi = (float)Math.PI; float vDotV = Vector2.Dot(v, v); //We are using the approach that automatically picks the values of d, where d1 = d2 //The formula for deriving d2 is a quadratic /* * d2 = [ -(v.t) +/- sqrt((v.t)^2 + 2.(1 + t1.t2)(v.v)) ] / (2* (1 - t1.t2)) */ //Compute denominator of the quadratic formula as it tells us if it is solvable or not (i.e. is it = 0) Vector2 t = _t0 + _t1; float vDotT = Vector2.Dot(v, t); float t0DotT1 = Vector2.Dot(_t0, _t1); float denominator = 2.0f * (1.0f - t0DotT1); float d; //Set for those cases that do not return straight away with solution //If quadratic formula denominator is zero. There are 2 cases here. In both cases the tangents are equal. In one the vector between the two curve points are perpendicular to them if (denominator == 0.0f) { float vDotT1 = Vector2.Dot(v, _t1); if ((float)Math.Abs(vDotT1) == 0.0f) { //Tangents are equal to each other AND perpendicular to p0 and p1. The solution is two equal semi-circles float vMag = v.Length(); float radius = 0.25f * vMag; Vector2 quarterV = 0.25f * v; Vector2 pm = _p0 + (2.0f * quarterV); float vCrossT1 = (v.X * _t1.Y) - (v.Y * _t1.X); Arc0.Centre = _p0 + quarterV; Arc0.Radius = radius; Arc0.Axis = _p0 - Arc0.Centre; Arc0.Angle = vCrossT1 > 0.0f ? pi : -pi; //Need to check this > or <. standard is < then > but doesn't seem to work... Arc0.ArcLength = pi * radius; Arc1.Centre = _p0 + (3.0f * quarterV); Arc1.Radius = radius; Arc1.Axis = _p1 - Arc1.Centre; Arc1.Angle = vCrossT1 > 0.0f ? pi : -pi; Arc1.ArcLength = pi * radius; _valid = true; return; } else { //The Tangents are equal to each other (this is the only route through where d can be negative) d = vDotV / (4.0f * vDotT1); } } else { //Standard result, we use the positive version of the quadratic formula to calculate d float discriminant = (vDotT * vDotT) + (denominator * vDotV); d = (-vDotT + (float)Math.Sqrt(discriminant)) / denominator; } //At this stage we have either calculated the value of d (d1 = d2), or we have set the two arcs appropriately for special cases //Calculate the mid point //pm=p1+p2+d2(t1−t2)/2 Vector2 mid = 0.5f * (_p0 + _p1 + (d * (_t0 - _t1))); //Caclulate Vectors from the curve points to the mid point Vector2 p0ToMid = mid - _p0; Vector2 p1ToMid = mid - _p1; //Calculate Arc Centre, Radius and Angle values Arc0 = ComputeSingleArc(_p0, _t0, p0ToMid); Arc1 = ComputeSingleArc(_p1, _t1, p1ToMid); if (d < 0.0f) { //Use longer path around if d is negative (doesn't seem to work right yet) /* * float arc0mul = 2.0f * pi; * arc0mul *= _arc0.Angle >= 0.0f ? 1.0f : -1.0f; * _arc0.Angle = arc0mul - _arc0.Angle; * * float arc1mul = 2.0f * pi; * arc1mul *= _arc1.Angle >= 0.0f ? 1.0f : -1.0f; * _arc1.Angle = arc1mul - _arc1.Angle; */ } //Ignoring the code to check for negative d in the example, as surely should always be positive (i.e. we are taking the shorter parth around the circles) Arc0.Axis = _p0 - Arc0.Centre; Arc1.Axis = _p1 - Arc1.Centre; Arc0.ArcLength = Arc0.Radius == 0.0f ? p0ToMid.Length() : (float)Math.Abs(Arc0.Radius * Arc0.Angle); Arc1.ArcLength = Arc1.Radius == 0.0f ? p1ToMid.Length() : (float)Math.Abs(Arc1.Radius * Arc1.Angle); _valid = true; }
public static LineIntersectionResult RobustLineIntersectAndResult(Vector2 a0, Vector2 a1, Vector2 b0, Vector2 b1, bool fireOnOverlap = true) { //Fail on zero length lines if (Vector2Ext.Equality(a0, a1) || Vector2Ext.Equality(b0, b1)) { return new LineIntersectionResult() { Intersecting = false, CoLinear = false, IntersectPoint = Vector2.Zero } } ; var r = a1 - a0; var s = b1 - b0; var qMp = b0 - a0; float rXs = Vector2Ext.Cross(r, s); float qMpXr = Vector2Ext.Cross(qMp, r); //1. Colinear Check if (IsFuzzyZero(rXs) && IsFuzzyZero(qMpXr)) { //They are colinear if (fireOnOverlap) { float qMpDOTr = Vector2Ext.Dot(qMp, r); float rDOTr = Vector2Ext.Dot(r, r); var pMq = a0 - b0; float pMqDOTs = Vector2Ext.Dot(pMq, s); float sDOTs = Vector2Ext.Dot(s, s); if ((qMpDOTr >= 0.0f && qMpDOTr <= rDOTr) || (pMqDOTs >= 0.0f && pMqDOTs <= sDOTs)) { //You do not get provided a valid intersect point as the lines lie on top of each other return(new LineIntersectionResult() { Intersecting = true, CoLinear = true, IntersectPoint = Vector2.Zero }); } } //Not classifying overlap as intersection return(new LineIntersectionResult() { Intersecting = false, CoLinear = true, IntersectPoint = Vector2.Zero }); } //2. Paralell - Do not intersect if (IsFuzzyZero(rXs) && !IsFuzzyZero(qMpXr)) { return(new LineIntersectionResult() { Intersecting = false, CoLinear = false, IntersectPoint = Vector2.Zero }); } //3.Intersect at Single Point float t = Vector2Ext.Cross(qMp, s) / rXs; float u = Vector2Ext.Cross(qMp, r) / rXs; if (!IsFuzzyZero(rXs) && t >= 0.0f && t <= 1.0f && u >= 0.0f && u <= 1.0f) { return(new LineIntersectionResult() { Intersecting = true, CoLinear = false, IntersectPoint = a0 + (r * t) }); } //4. Do not intersect return(new LineIntersectionResult() { Intersecting = false, CoLinear = false, IntersectPoint = Vector2.Zero }); }