PolylineData.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. namespace HandyControl.Expression.Drawing;
  6. internal class PolylineData
  7. {
  8. private IList<double> _accumulates;
  9. private IList<double> _angles;
  10. private IList<double> _lengths;
  11. private IList<Vector> _normals;
  12. private double? _totalLength;
  13. public PolylineData(IList<Point> points)
  14. {
  15. if (points == null) throw new ArgumentNullException(nameof(points));
  16. if (points.Count <= 1) throw new ArgumentOutOfRangeException(nameof(points));
  17. Points = points;
  18. }
  19. public IList<double> AccumulatedLength =>
  20. _accumulates ?? ComputeAccumulatedLength();
  21. public IList<double> Angles =>
  22. _angles ?? ComputeAngles();
  23. public int Count =>
  24. Points.Count;
  25. public bool IsClosed =>
  26. Points[0] == Points.Last();
  27. public IList<double> Lengths =>
  28. _lengths ?? ComputeLengths();
  29. public IList<Vector> Normals =>
  30. _normals ?? ComputeNormals();
  31. public IList<Point> Points { get; }
  32. public double TotalLength
  33. {
  34. get
  35. {
  36. var length = _totalLength;
  37. return length ?? ComputeTotalLength();
  38. }
  39. }
  40. private IList<double> ComputeAccumulatedLength()
  41. {
  42. _accumulates = new double[Count];
  43. _accumulates[0] = 0.0;
  44. for (var i = 1; i < Count; i++) _accumulates[i] = _accumulates[i - 1] + Lengths[i - 1];
  45. _totalLength = _accumulates.Last();
  46. return _accumulates;
  47. }
  48. private IList<double> ComputeAngles()
  49. {
  50. _angles = new double[Count];
  51. for (var i = 1; i < Count - 1; i++) _angles[i] = -GeometryHelper.Dot(Normals[i - 1], Normals[i]);
  52. if (IsClosed)
  53. {
  54. var num2 = -GeometryHelper.Dot(Normals[0], Normals[Count - 2]);
  55. _angles[0] = _angles[Count - 1] = num2;
  56. }
  57. else
  58. {
  59. _angles[0] = _angles[Count - 1] = 1.0;
  60. }
  61. return _angles;
  62. }
  63. private IList<double> ComputeLengths()
  64. {
  65. _lengths = new double[Count];
  66. for (var i = 0; i < Count; i++) _lengths[i] = Difference(i).Length;
  67. return _lengths;
  68. }
  69. private IList<Vector> ComputeNormals()
  70. {
  71. _normals = new Vector[Points.Count];
  72. for (var i = 0; i < Count - 1; i++) _normals[i] = GeometryHelper.Normal(Points[i], Points[i + 1]);
  73. _normals[Count - 1] = _normals[Count - 2];
  74. return _normals;
  75. }
  76. private double ComputeTotalLength()
  77. {
  78. ComputeAccumulatedLength();
  79. // ReSharper disable once PossibleInvalidOperationException
  80. return _totalLength.Value;
  81. }
  82. public Vector Difference(int index)
  83. {
  84. var num = (index + 1) % Count;
  85. return Points[num].Subtract(Points[index]);
  86. }
  87. public Vector SmoothNormal(int index, double fraction, double cornerRadius)
  88. {
  89. if (cornerRadius > 0.0)
  90. {
  91. var num = Lengths[index];
  92. if (MathHelper.IsVerySmall(num))
  93. {
  94. var num2 = index - 1;
  95. if (num2 < 0 && IsClosed) num2 = Count - 1;
  96. var num3 = index + 1;
  97. if (IsClosed && num3 >= Count - 1) num3 = 0;
  98. if (num2 >= 0 && num3 < Count)
  99. return GeometryHelper.Lerp(Normals[num3], Normals[num2], 0.5).Normalized();
  100. return Normals[index];
  101. }
  102. var num4 = Math.Min(cornerRadius / num, 0.5);
  103. if (fraction <= num4)
  104. {
  105. var num5 = index - 1;
  106. if (IsClosed && num5 == -1) num5 = Count - 1;
  107. if (num5 >= 0)
  108. {
  109. var alpha = (num4 - fraction) / (2.0 * num4);
  110. return GeometryHelper.Lerp(Normals[index], Normals[num5], alpha).Normalized();
  111. }
  112. }
  113. else if (fraction >= 1.0 - num4)
  114. {
  115. var num7 = index + 1;
  116. if (IsClosed && num7 >= Count - 1) num7 = 0;
  117. if (num7 < Count)
  118. {
  119. var num8 = (fraction + num4 - 1.0) / (2.0 * num4);
  120. return GeometryHelper.Lerp(Normals[index], Normals[num7], num8).Normalized();
  121. }
  122. }
  123. }
  124. return Normals[index];
  125. }
  126. }