- fix minimum area rectangle algo and make it public

- add tests
- tidy up code
This commit is contained in:
BobLd
2020-03-15 15:04:03 +00:00
committed by Eliot Jones
parent bd6b03c2e8
commit c1a1fa1f7f
2 changed files with 517 additions and 63 deletions

View File

@@ -8,6 +8,10 @@
public class PdfPointTests
{
private static readonly DoubleComparer DoubleComparer = new DoubleComparer(3);
private static readonly DoubleComparer PreciseDoubleComparer = new DoubleComparer(6);
private static readonly PointComparer PointComparer = new PointComparer(DoubleComparer);
#region data
public static IEnumerable<object[]> GrahamScanData => new[]
{
@@ -86,6 +90,442 @@
new PdfPoint(286.54125213, 590.83326057),
new PdfPoint(30.50024994, 37.34818875)
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(744.3155504888274, 444.2270145755189),
new PdfPoint(569.808503219366, 795.0780697464061),
new PdfPoint(979.4238467088927, 747.7769460740175),
new PdfPoint(263.9656530143659, 534.1164778047929),
new PdfPoint(700.0199185779105, 59.67088755550021),
new PdfPoint(350.4405052982569, 201.5075034147189),
new PdfPoint(951.4434324059339, 276.4851544966993),
new PdfPoint(221.2620795357345, 889.4493759697666),
new PdfPoint(26.40411497910822, 836.0708485933704),
new PdfPoint(967.4534816241033, 692.8854748787957),
},
new PdfPoint[]
{
new PdfPoint(979.4238467088927, 747.7769460740175),
new PdfPoint(700.0199185779105, 59.67088755550021),
new PdfPoint(350.4405052982569, 201.5075034147189),
new PdfPoint(951.4434324059339, 276.4851544966993),
new PdfPoint(221.2620795357345, 889.4493759697666),
new PdfPoint(26.40411497910822, 836.0708485933704),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(120.21183721137064, 840.2513067067979),
new PdfPoint(415.52861888639114, 204.0116313873851),
new PdfPoint(415.9664683980775, 832.443368995516),
new PdfPoint(277.74879682552734, 502.12519702578516),
new PdfPoint(395.35090532250103, 384.0997616867551),
new PdfPoint(26.98104432607229, 654.2675428223525),
new PdfPoint(507.0471750863688, 822.9947002774292),
},
new PdfPoint[]
{
new PdfPoint(120.21183721137064, 840.2513067067979),
new PdfPoint(415.52861888639114, 204.0116313873851),
new PdfPoint(415.9664683980775, 832.443368995516),
new PdfPoint(26.98104432607229, 654.2675428223525),
new PdfPoint(507.0471750863688, 822.9947002774292),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(101.52924170788602, 157.72180559576165),
new PdfPoint(89.13969305519842, 437.7399878683488),
new PdfPoint(963.8109736953475, 34.8258382181843),
new PdfPoint(323.44164253397423, 760.0469522615875),
new PdfPoint(553.8798287152455, 601.37868940649),
new PdfPoint(24.169651959285442, 205.03651103426347),
new PdfPoint(598.6426557134453, 973.1839362109574),
new PdfPoint(404.2148279309453, 642.4272597428419),
new PdfPoint(425.99787946258795, 235.338843056625),
new PdfPoint(733.837562543066, 304.97834592908157),
new PdfPoint(253.06825516770635, 639.1969849161718),
new PdfPoint(702.043917830561, 241.6302720665372),
new PdfPoint(43.233323888316356, 214.65896998517496),
new PdfPoint(192.04610854054195, 609.086536570487),
new PdfPoint(93.436372304046, 130.4501167748684),
},
new PdfPoint[]
{
new PdfPoint(89.13969305519842, 437.7399878683488),
new PdfPoint(963.8109736953475, 34.8258382181843),
new PdfPoint(323.44164253397423, 760.0469522615875),
new PdfPoint(24.169651959285442, 205.03651103426347),
new PdfPoint(598.6426557134453, 973.1839362109574),
new PdfPoint(192.04610854054195, 609.086536570487),
new PdfPoint(93.436372304046, 130.4501167748684),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(440.61717693569, 109.0846453611043),
new PdfPoint(306.3112668458863, 236.31457456363236),
new PdfPoint(520.2265439015014, 849.1406402603602),
new PdfPoint(991.7951837792907, 716.5936071305995),
new PdfPoint(210.02069783227006, 396.9897189605061),
new PdfPoint(844.0889978638492, 40.8614368982706),
new PdfPoint(105.18279221346272, 598.2338764791806),
new PdfPoint(481.07852218200696, 791.2951914667244),
new PdfPoint(306.45291569755994, 923.936778153581),
new PdfPoint(959.6247632028106, 131.810977239897),
new PdfPoint(800.8517955224195, 350.74228914407433),
new PdfPoint(663.4680772483941, 352.304508375042),
new PdfPoint(222.58588801803648, 629.9145459539977),
new PdfPoint(158.01097092542204, 266.66678727838047),
new PdfPoint(63.28771038884462, 52.73381563522583),
new PdfPoint(931.6304534780719, 325.3140887623456),
new PdfPoint(781.7202794605689, 932.8040026798695),
new PdfPoint(691.9750284379987, 896.4394191971841),
new PdfPoint(354.5191195854491, 319.9839791539775),
new PdfPoint(177.99172848582566, 831.9975645935383),
new PdfPoint(237.7316548429551, 731.2752736686494),
new PdfPoint(989.397359729622, 217.92540678980444),
new PdfPoint(509.249200783335, 621.5474147516464),
new PdfPoint(744.8852601187607, 917.8174495950592),
new PdfPoint(308.86394317440534, 345.03042856046795),
new PdfPoint(716.4931552373788, 116.87982985630296),
new PdfPoint(8.999928995218953, 752.2282844071755),
new PdfPoint(294.01152638529305, 979.8820875548174),
new PdfPoint(919.862114089302, 218.09062242740873),
new PdfPoint(58.10245428844474, 679.4146645720332),
new PdfPoint(298.5501112825898, 76.27703572384658),
new PdfPoint(642.7813627195759, 506.9457773647057),
new PdfPoint(95.40371527671387, 849.060165476576),
new PdfPoint(462.81907479511983, 59.56530610812505),
new PdfPoint(883.4162795690498, 4.108824339342565),
new PdfPoint(255.30517910829244, 890.9400020559517),
new PdfPoint(127.06302493344879, 246.8462701575741),
new PdfPoint(995.1831247109899, 371.7538001202371),
new PdfPoint(189.37270784653683, 888.4231305357099),
new PdfPoint(924.0107481155084, 775.4673044677166),
new PdfPoint(865.7452979418968, 373.2043310431542),
new PdfPoint(409.76929412279594, 192.26266847186992),
new PdfPoint(438.8872219529338, 819.6826378850956),
},
new PdfPoint[]
{
new PdfPoint(991.7951837792907, 716.5936071305995),
new PdfPoint(959.6247632028106, 131.810977239897),
new PdfPoint(63.28771038884462, 52.73381563522583),
new PdfPoint(781.7202794605689, 932.8040026798695),
new PdfPoint(989.397359729622, 217.92540678980444),
new PdfPoint(8.999928995218953, 752.2282844071755),
new PdfPoint(294.01152638529305, 979.8820875548174),
new PdfPoint(95.40371527671387, 849.060165476576),
new PdfPoint(883.4162795690498, 4.108824339342565),
new PdfPoint(995.1831247109899, 371.7538001202371),
}
}
};
public static IEnumerable<object[]> MinimumAreaRectangleData => new[]
{
new object[]
{
new PdfPoint[]
{
// collinear points case: y = 15.7894 + 1.572431x
new PdfPoint(16, 40.948296),
new PdfPoint(18, 44.093158),
new PdfPoint(21, 48.810451),
new PdfPoint(30, 62.96233),
new PdfPoint(49, 92.838519),
new PdfPoint(55, 102.273105),
new PdfPoint(60, 110.13526),
new PdfPoint(64, 116.424984),
new PdfPoint(65, 117.997415),
new PdfPoint(68, 122.714708),
new PdfPoint(75, 133.721725),
new PdfPoint(84, 147.873604),
new PdfPoint(86, 151.018466),
new PdfPoint(90, 157.30819),
new PdfPoint(97, 168.315207),
new PdfPoint(99, 171.460069),
new PdfPoint(105, 180.894655),
new PdfPoint(106, 182.467086),
new PdfPoint(110, 188.75681),
new PdfPoint(113, 193.474103),
new PdfPoint(119, 202.908689),
new PdfPoint(121, 206.053551),
new PdfPoint(122, 207.625982),
new PdfPoint(123, 209.198413)
},
new PdfPoint[]
{
new PdfPoint(16, 40.948296),
new PdfPoint(16, 40.948296),
new PdfPoint(123, 209.198413),
new PdfPoint(123, 209.198413)
}
},
new object[]
{
new PdfPoint[]
{
// collinear points case: y = 87.483 + 99.2934520998549x
new PdfPoint(10.5114328889726, 1131.19945806204),
new PdfPoint(11.1542565096881, 1195.02763445421),
new PdfPoint(15.3153242359356, 1608.19441341462),
new PdfPoint(15.795577716642, 1655.88043939693),
new PdfPoint(16.3319701583886, 1709.14069661821),
new PdfPoint(17.1302715938114, 1788.40680195762),
new PdfPoint(17.9770489556469, 1872.48624937427),
new PdfPoint(22.4037700355884, 2312.03066688486),
new PdfPoint(23.7647419889928, 2447.16627034947),
new PdfPoint(26.9327398551415, 2761.72771472434),
new PdfPoint(28.7600875228236, 2943.17137283512),
new PdfPoint(32.8221934632313, 3346.51189445353),
new PdfPoint(34.4943972831614, 3512.55078434895),
new PdfPoint(34.5363374306664, 3516.7151663763),
new PdfPoint(36.0282475627216, 3664.85207361081)
},
new PdfPoint[]
{
new PdfPoint(10.5114328889726, 1131.19945806204),
new PdfPoint(10.5114328889726, 1131.19945806204),
new PdfPoint(36.0282475627216, 3664.85207361081),
new PdfPoint(36.0282475627216, 3664.85207361081)
}
},
new object[]
{
new PdfPoint[]
{
// collinear points case: vertical
new PdfPoint(446.78, 217.9),
new PdfPoint(446.78, 228.82),
new PdfPoint(446.78, 247.52),
new PdfPoint(446.78, 256.84),
new PdfPoint(446.78, 301.4),
new PdfPoint(446.78, 321.39),
new PdfPoint(446.78, 369.08),
new PdfPoint(446.78, 387.05),
new PdfPoint(446.78, 393.22),
new PdfPoint(446.78, 397.29),
new PdfPoint(446.78, 463.16),
new PdfPoint(446.78, 471.88),
new PdfPoint(446.78, 480.13),
new PdfPoint(446.78, 495.82),
new PdfPoint(446.78, 498.99)
},
new PdfPoint[]
{
new PdfPoint(446.78, 217.9),
new PdfPoint(446.78, 217.9),
new PdfPoint(446.78, 498.99),
new PdfPoint(446.78, 498.99)
}
},
new object[]
{
new PdfPoint[]
{
// collinear points case: horizontal
new PdfPoint(220, 208.821),
new PdfPoint(258.92, 208.821),
new PdfPoint(268.61, 208.821),
new PdfPoint(283.56, 208.821),
new PdfPoint(312.49, 208.821),
new PdfPoint(344.93, 208.821),
new PdfPoint(356, 208.821),
new PdfPoint(356.06, 208.821),
new PdfPoint(366.71, 208.821),
new PdfPoint(371.07, 208.821),
new PdfPoint(430.95, 208.821),
new PdfPoint(445.84, 208.821),
new PdfPoint(464.95, 208.821),
new PdfPoint(470.19, 208.821),
new PdfPoint(498.19, 208.821)
},
new PdfPoint[]
{
new PdfPoint(220, 208.821),
new PdfPoint(220, 208.821),
new PdfPoint(498.19, 208.821),
new PdfPoint(498.19, 208.821)
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(433.8664544437276, 532.7739491464265),
new PdfPoint(653.8805470338659, 817.2121262831644),
new PdfPoint(531.2551432261636, 360.68316491741035),
new PdfPoint(418.79076902856593, 111.73491145462933),
},
new PdfPoint[]
{
new PdfPoint(653.880547033866, 817.2121262831644),
new PdfPoint(461.3184174727883, 100.31182441133716),
new PdfPoint(327.3696296297328, 136.2909748899142),
new PdfPoint(519.9317591908105, 853.1912767617414),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(556.0000554986003, 83.08490003544556),
new PdfPoint(413.249212383334, 618.580307645359),
new PdfPoint(526.8827917872168, 111.78528983363456),
new PdfPoint(220.19687765118178, 377.83114567978316),
},
new PdfPoint[]
{
new PdfPoint(556.0000554986004, 83.08490003544566),
new PdfPoint(315.83633925060445, 19.06273944752293),
new PdfPoint(173.0854961353382, 554.5581470574363),
new PdfPoint(413.24921238333417, 618.580307645359),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(14.004896521066401, 809.4941990011544),
new PdfPoint(703.95616092419, 970.7474069029789),
new PdfPoint(835.551079058811, 661.2654117428186),
new PdfPoint(200.4833132016346, 14.581989889114745),
new PdfPoint(73.40355670360321, 345.2226372321663),
},
new PdfPoint[]
{
new PdfPoint(945.970699704068, 188.81492303383516),
new PdfPoint(153.25937285270737, 3.544961240987477),
new PdfPoint(-32.56092111592515, 798.6109846932103),
new PdfPoint(760.1504057354355, 983.8809464860581),
}
},
new object[]
{
// duplicate points case
new PdfPoint[]
{
new PdfPoint(14.004896521066401, 809.4941990011544),
new PdfPoint(703.95616092419, 970.7474069029789),
new PdfPoint(835.551079058811, 661.2654117428186),
new PdfPoint(703.95616092419, 970.7474069029789),
new PdfPoint(703.95616092419, 970.7474069029789),
new PdfPoint(200.4833132016346, 14.581989889114745),
new PdfPoint(200.4833132016346, 14.581989889114745),
new PdfPoint(73.40355670360321, 345.2226372321663),
new PdfPoint(73.40355670360321, 345.2226372321663),
new PdfPoint(73.40355670360321, 345.2226372321663),
},
new PdfPoint[]
{
new PdfPoint(945.970699704068, 188.81492303383516),
new PdfPoint(153.25937285270737, 3.544961240987477),
new PdfPoint(-32.56092111592515, 798.6109846932103),
new PdfPoint(760.1504057354355, 983.8809464860581),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(737.1041856902102, 648.0900313433699),
new PdfPoint(258.83885597639045, 32.15501719959235),
new PdfPoint(354.5500618726748, 908.7838113897652),
new PdfPoint(867.6475306924474, 47.361938752654595),
new PdfPoint(352.7960490248145, 283.67860449564785),
new PdfPoint(955.4087841797756, 833.327418435315),
new PdfPoint(578.2403790703082, 67.4511148622331),
new PdfPoint(722.9995401934759, 407.36102955779796),
new PdfPoint(404.3710508165602, 736.1127320695537),
new PdfPoint(56.25949705397548, 45.503737933916824),
},
new PdfPoint[]
{
new PdfPoint(956.3312379371301, 841.5886588013605),
new PdfPoint(857.4507470077488, -43.95763180386355),
new PdfPoint(56.25949705397548, 45.503737933916824),
new PdfPoint(155.13998798335692, 931.0500285391407),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(37.79696601832361, 984.5348223984452),
new PdfPoint(881.8169100214427, 818.3604232045343),
new PdfPoint(732.8834668881201, 907.4453370173243),
new PdfPoint(142.89010125285918, 183.62301422208304),
new PdfPoint(292.4319539617013, 383.1685740348906),
new PdfPoint(658.9302664366852, 781.9569855570855),
new PdfPoint(501.7748878713084, 321.0551716869758),
new PdfPoint(104.96397346166219, 658.8420562657931),
new PdfPoint(931.1420702804029, 235.94015835854032),
new PdfPoint(489.5915692144058, 835.989512769871),
},
new PdfPoint[]
{
new PdfPoint(931.1420702804029, 235.9401583585403),
new PdfPoint(91.18213738971586, 180.19110018351975),
new PdfPoint(37.79696601832373, 984.5348223984452),
new PdfPoint(877.7568989090107, 1040.2838805734657),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(360.50496116131137, 475.0257075944493),
new PdfPoint(463.6183053562707, 550.6502767074434),
new PdfPoint(719.7530742800635, 986.4011287537438),
new PdfPoint(746.9948030700444, 387.8044519192034),
new PdfPoint(868.5846874204865, 248.33194807842352),
new PdfPoint(485.3109455640756, 39.94793327837021),
new PdfPoint(504.8344865133781, 708.8088010613369),
new PdfPoint(352.0102119724019, 820.2239288583693),
new PdfPoint(28.306241810454267, 579.9713087166957),
new PdfPoint(801.671925406638, 886.8351079919669),
},
new PdfPoint[]
{
new PdfPoint(1131.0092157743165, 443.1030548242194),
new PdfPoint(485.483254766563, -36.005383122939776),
new PdfPoint(28.306241810454186, 579.9713087166958),
new PdfPoint(673.8322028182079, 1059.079746663855),
}
},
new object[]
{
new PdfPoint[]
{
new PdfPoint(384.5196462100093, 457.53938224300975),
new PdfPoint(388.62152246674617, 197.75832374394065),
new PdfPoint(40.7654267847265, 320.51104165848284),
new PdfPoint(443.45264559634137, 22.11792681360786),
new PdfPoint(345.74164027022573, 484.01784165724456),
new PdfPoint(453.33094307272717, 441.7802101118389),
new PdfPoint(470.9897811308254, 63.67713677117809),
new PdfPoint(277.98105707671505, 321.72593673466497),
new PdfPoint(447.8012370058249, 358.25102431521026),
new PdfPoint(345.94253780510235, 111.25057954480089),
},
new PdfPoint[]
{
new PdfPoint(647.6991334648283, 297.75247084308063),
new PdfPoint(443.4526455963414, 22.117926813607856),
new PdfPoint(40.7654267847265, 320.5110416584829),
new PdfPoint(245.0119146532134, 596.1455856879556),
}
}
};
#endregion
@@ -126,8 +566,23 @@
for (var i = 0; i < expected.Length; i++)
{
Assert.Equal(expected[i].X, convexHull[i].X, 6);
Assert.Equal(expected[i].Y, convexHull[i].Y, 6);
Assert.Equal(expected[i], convexHull[i], PointComparer);
}
}
[Theory]
[MemberData(nameof(MinimumAreaRectangleData))]
public void MinimumAreaRectangle(PdfPoint[] points, PdfPoint[] expected)
{
expected = expected.OrderBy(p => p.X).ThenBy(p => p.Y).ToArray();
var marRectangle = GeometryExtensions.MinimumAreaRectangle(points);
var mar = new[] { marRectangle.BottomLeft, marRectangle.BottomRight, marRectangle.TopLeft, marRectangle.TopRight }.OrderBy(p => p.X).ThenBy(p => p.Y).ToArray();
for (var i = 0; i < expected.Length; i++)
{
Assert.Equal(expected[i], mar[i], PointComparer);
}
}
}

View File

@@ -65,57 +65,45 @@
/// The vertices of P are assumed to be in strict cyclic sequential order, either clockwise or
/// counter-clockwise relative to the origin P0.
/// </param>
internal static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList<PdfPoint> polygon)
private static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList<PdfPoint> polygon)
{
if (polygon == null || polygon.Count == 0)
{
throw new ArgumentException("ParametricPerpendicularProjection(): polygon cannot be null and must contain at least one point.");
throw new ArgumentException("ParametricPerpendicularProjection(): polygon cannot be null and must contain at least one point.", nameof(polygon));
}
if (polygon.Count < 4)
else if (polygon.Count == 1)
{
if (polygon.Count == 1)
{
return new PdfRectangle(polygon[0], polygon[0]);
}
else if (polygon.Count == 2)
{
return new PdfRectangle(polygon[0], polygon[1]);
}
else
{
PdfPoint p3 = polygon[0].Add(polygon[1].Subtract(polygon[2]));
return new PdfRectangle(p3, polygon[1], polygon[0], polygon[2]);
}
return new PdfRectangle(polygon[0], polygon[0]);
}
else if (polygon.Count == 2)
{
return new PdfRectangle(polygon[0], polygon[1]);
}
PdfPoint[] MBR = new PdfPoint[0];
double Amin = double.MaxValue;
double tmin = 1;
double tmax = 0;
double smax = 0;
double Amin = double.PositiveInfinity;
int j = 1;
int k = 0;
int l = -1;
PdfPoint Q = new PdfPoint();
PdfPoint R0 = new PdfPoint();
PdfPoint R1 = new PdfPoint();
PdfPoint u = new PdfPoint();
int nv = polygon.Count;
while (true)
{
var Pk = polygon[k];
PdfPoint Pk = polygon[k];
PdfPoint v = polygon[j].Subtract(Pk);
double r = 1.0 / v.DotProduct(v);
for (j = 0; j < nv; j++)
double tmin = 1;
double tmax = 0;
double smax = 0;
int l = -1;
for (j = 0; j < polygon.Count; j++)
{
if (j == k) continue;
PdfPoint Pj = polygon[j];
u = Pj.Subtract(Pk);
double t = u.DotProduct(v) * r;
@@ -143,37 +131,48 @@
}
}
if (l == -1)
if (l != -1)
{
// All points are colinear - rectangle has no area (need more tests)
var bottomLeft = polygon.OrderBy(p => p.X).ThenBy(p => p.Y).First();
var topRight = polygon.OrderByDescending(p => p.Y).OrderByDescending(p => p.X).First();
return new PdfRectangle(bottomLeft, topRight, bottomLeft, topRight);
}
PdfPoint PlMinusQ = polygon[l].Subtract(Q);
PdfPoint R2 = R1.Add(PlMinusQ);
PdfPoint R3 = R0.Add(PlMinusQ);
PdfPoint PlMinusQ = polygon[l].Subtract(Q);
PdfPoint R2 = R1.Add(PlMinusQ);
PdfPoint R3 = R0.Add(PlMinusQ);
u = R1.Subtract(R0);
double A = u.DotProduct(u) * smax;
u = R1.Subtract(R0);
if (A < Amin)
{
Amin = A;
MBR = new[] { R0, R1, R2, R3 };
double A = u.DotProduct(u) * smax;
if (A < Amin)
{
Amin = A;
MBR = new[] { R0, R1, R2, R3 };
}
}
k++;
j = k;
j = k + 1;
if (j == nv) j = 0;
if (k == nv) break;
if (j == polygon.Count) j = 0;
if (k == polygon.Count) break;
}
return new PdfRectangle(MBR[2], MBR[3], MBR[1], MBR[0]);
}
/// <summary>
/// Algorithm to find the (oriented) minimum area rectangle (MAR) by first finding the convex hull of the points
/// and then finding its MAR.
/// </summary>
/// <param name="points">The points.</param>
public static PdfRectangle MinimumAreaRectangle(IEnumerable<PdfPoint> points)
{
if (points == null || points.Count() == 0)
{
throw new ArgumentException("MinimumAreaRectangle(): points cannot be null and must contain at least one point.", nameof(points));
}
return ParametricPerpendicularProjection(GrahamScan(points.Distinct()).ToList());
}
/// <summary>
/// Algorithm to find the oriented bounding box (OBB) by first fitting a line through the points to get the slope,
/// then rotating the points to obtain the axis-aligned bounding box (AABB), and then rotating back the AABB.
@@ -241,10 +240,10 @@
if (points.Count() < 3) return points;
Func<PdfPoint, PdfPoint, double> polarAngle = (PdfPoint point1, PdfPoint point2) =>
double polarAngle(PdfPoint point1, PdfPoint point2)
{
return Math.Atan2(point2.Y - point1.Y, point2.X - point1.X) % Math.PI;
};
}
Stack<PdfPoint> stack = new Stack<PdfPoint>();
var sortedPoints = points.OrderBy(p => p.Y).ThenBy(p => p.X).ToList();
@@ -607,25 +606,25 @@
{
if (!IntersectsWith(p11, p12, p21, p22)) return null;
var eq1 = GetSlopeIntercept(p11, p12);
var eq2 = GetSlopeIntercept(p21, p22);
var (Slope1, Intercept1) = GetSlopeIntercept(p11, p12);
var (Slope2, Intercept2) = GetSlopeIntercept(p21, p22);
if (double.IsNaN(eq1.Slope))
if (double.IsNaN(Slope1))
{
var x = eq1.Intercept;
var y = eq2.Slope * x + eq2.Intercept;
var x = Intercept1;
var y = Slope2 * x + Intercept2;
return new PdfPoint(x, y);
}
else if (double.IsNaN(eq2.Slope))
else if (double.IsNaN(Slope2))
{
var x = eq2.Intercept;
var y = eq1.Slope * x + eq1.Intercept;
var x = Intercept2;
var y = Slope1 * x + Intercept1;
return new PdfPoint(x, y);
}
else
{
var x = (eq2.Intercept - eq1.Intercept) / (eq1.Slope - eq2.Slope);
var y = eq1.Slope * x + eq1.Intercept;
var x = (Intercept2 - Intercept1) / (Slope1 - Slope2);
var y = Slope1 * x + Intercept1;
return new PdfPoint(x, y);
}
}
@@ -875,7 +874,7 @@
else // Casus irreducibilis
{
// François Viète's formula
Func<double, double, double, double> vietTrigonometricSolution = (p_, q_, k) => 2.0 * Math.Sqrt(-p_ / 3.0)
double vietTrigonometricSolution(double p_, double q_, double k) => 2.0 * Math.Sqrt(-p_ / 3.0)
* Math.Cos(OneThird * Math.Acos((3.0 * q_) / (2.0 * p_) * Math.Sqrt(-3.0 / p_)) - (2.0 * Math.PI * k) / 3.0);
double p = Q * 3.0; // (3.0 * a * c - b * b) / (3.0 * aSquared);