mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-15 03:26:58 +08:00
- fix minimum area rectangle algo and make it public
- add tests - tidy up code
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -65,16 +65,13 @@
|
||||
/// 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)
|
||||
{
|
||||
if (polygon.Count == 1)
|
||||
else if (polygon.Count == 1)
|
||||
{
|
||||
return new PdfRectangle(polygon[0], polygon[0]);
|
||||
}
|
||||
@@ -82,40 +79,31 @@
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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,18 +131,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
u = R1.Subtract(R0);
|
||||
|
||||
double A = u.DotProduct(u) * smax;
|
||||
|
||||
if (A < Amin)
|
||||
@@ -162,18 +146,33 @@
|
||||
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);
|
||||
|
Reference in New Issue
Block a user