public override unsafe SignedDistance SignedDistance(Vector2 origin, ref double param) { var qa = _p[0] - origin; var ab = _p[1] - _p[0]; var br = _p[0] + _p[2] - _p[1] - _p[1]; var coefficient = stackalloc[] { Vector2.Dot(br, br), 3 * Vector2.Dot(ab, br), 2 * Vector2.Dot(ab, ab) + Vector2.Dot(qa, br), Vector2.Dot(qa, ab) }; var t = stackalloc double[3]; var solutions = Equations.SolveCubic(t, coefficient); var minDistance = Arithmetic.NonZeroSign(Vector2.Cross(ab, qa)) * qa.Length(); // distance from A param = -Vector2.Dot(qa, ab) / Vector2.Dot(ab, ab); { var distance = Arithmetic.NonZeroSign(Vector2.Cross(_p[2] - _p[1], _p[2] - origin)) * (_p[2] - origin).Length(); // distance from B if (Math.Abs(distance) < Math.Abs(minDistance)) { minDistance = distance; param = Vector2.Dot(origin - _p[1], _p[2] - _p[1]) / Vector2.Dot(_p[2] - _p[1], _p[2] - _p[1]); } } for (var i = 0; i < solutions; ++i) { if (t[i] > 0 && t[i] < 1) { var endpoint = _p[0] + 2 * t[i] * ab + t[i] * t[i] * br; var distance = Arithmetic.NonZeroSign(Vector2.Cross(_p[2] - _p[0], endpoint - origin)) * (endpoint - origin).Length(); if (Math.Abs(distance) <= Math.Abs(minDistance)) { minDistance = distance; param = t[i]; } } } if (param >= 0 && param <= 1) { return(new SignedDistance(minDistance, 0)); } if (param < .5) { return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot(ab.Normalize(), qa.Normalize())))); } return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot((_p[2] - _p[1]).Normalize(), (_p[2] - origin).Normalize())))); }
public override SignedDistance SignedDistance(Vector2 origin, ref double param) { var aq = origin - _p[0]; var ab = _p[1] - _p[0]; param = Vector2.Dot(aq, ab) / Vector2.Dot(ab, ab); var eq = _p[param > 0.5 ? 1 : 0] - origin; var endpointDistance = eq.Length(); if (param > 0 && param < 1) { var orthoDistance = Vector2.Dot(ab.GetOrthonormal(), aq); if (Math.Abs(orthoDistance) < endpointDistance) { return(new SignedDistance(orthoDistance, 0)); } } return(new SignedDistance(Arithmetic.NonZeroSign(Vector2.Cross(aq, ab)) * endpointDistance, Math.Abs(Vector2.Dot(ab.Normalize(), eq.Normalize())))); }
public override SignedDistance SignedDistance(Vector2 origin, ref double param) { var qa = _p[0] - origin; var ab = _p[1] - _p[0]; var br = _p[2] - _p[1] - ab; var as_ = _p[3] - _p[2] - (_p[2] - _p[1]) - br; var epDir = Direction(0); var minDistance = Arithmetic.NonZeroSign(Vector2.Cross(epDir, qa)) * qa.Length(); // distance from A param = -Vector2.Dot(qa, epDir) / Vector2.Dot(epDir, epDir); { epDir = Direction(1); var distance = Arithmetic.NonZeroSign(Vector2.Cross(epDir, _p[3] - origin)) * (_p[3] - origin).Length(); // distance from B if (Math.Abs(distance) < Math.Abs(minDistance)) { minDistance = distance; param = Vector2.Dot(origin + epDir - _p[3], epDir) / Vector2.Dot(epDir, epDir); } } // Iterative minimum distance search for (var i = 0; i <= MsdfgenCubicSearchStarts; ++i) { var t = (double)i / MsdfgenCubicSearchStarts; for (var step = 0;; ++step) { var qpt = Point(t) - origin; var distance = Arithmetic.NonZeroSign(Vector2.Cross(Direction(t), qpt)) * qpt.Length(); if (Math.Abs(distance) < Math.Abs(minDistance)) { minDistance = distance; param = t; } if (step == MsdfgenCubicSearchSteps) { break; } // Improve t var d1 = 3 * as_ * t * t + 6 * br * t + 3 * ab; var d2 = 6 * as_ * t + 6 * br; t -= Vector2.Dot(qpt, d1) / (Vector2.Dot(d1, d1) + Vector2.Dot(qpt, d2)); if (t < 0 || t > 1) { break; } } } if (param >= 0 && param <= 1) { return(new SignedDistance(minDistance, 0)); } if (param < .5) { return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot(Direction(0).Normalize(), qa.Normalize())))); } return(new SignedDistance(minDistance, Math.Abs(Vector2.Dot(Direction(1).Normalize(), (_p[3] - origin).Normalize())))); }