GR32_ArrowHeads.pas 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. unit GR32_ArrowHeads;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Vectorial Polygon Rasterizer for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Angus Johnson < http://www.angusj.com >
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. uses
  35. SysUtils,
  36. GR32,
  37. GR32_Polygons,
  38. GR32_VectorUtils,
  39. GR32_Geometry;
  40. type
  41. TArrowHeadAbstract = class
  42. private
  43. FSize: TFloat;
  44. FTipPoint: TFloatPoint;
  45. FBasePoint: TFloatPoint;
  46. protected
  47. function GetPointsInternal: TArrayOfFloatPoint; virtual; abstract;
  48. public
  49. constructor Create(size: TFloat); virtual;
  50. function GetPoints(const Line: TArrayOfFloatPoint; AtEnd: Boolean): TArrayOfFloatPoint;
  51. //Size: distance between arrow tip and arrow base
  52. property Size: TFloat read FSize write FSize;
  53. end;
  54. TArrowHeadSimple = class(TArrowHeadAbstract)
  55. protected
  56. function GetPointsInternal: TArrayOfFloatPoint; override;
  57. end;
  58. TArrowHeadFourPt = class(TArrowHeadAbstract)
  59. protected
  60. function GetPointsInternal: TArrayOfFloatPoint; override;
  61. end;
  62. TArrowHeadCircle = class(TArrowHeadAbstract)
  63. protected
  64. function GetPointsInternal: TArrayOfFloatPoint; override;
  65. end;
  66. TArrowHeadDiamond = class(TArrowHeadAbstract)
  67. protected
  68. function GetPointsInternal: TArrayOfFloatPoint; override;
  69. end;
  70. resourcestring
  71. RCStrInsufficientPointsInArray = 'Insufficient points in array';
  72. implementation
  73. uses
  74. Math,
  75. Types,
  76. GR32_Math;
  77. constructor TArrowHeadAbstract.Create(Size: TFloat);
  78. begin
  79. FSize := Size;
  80. end;
  81. //------------------------------------------------------------------------------
  82. function TArrowHeadAbstract.GetPoints(const Line: TArrayOfFloatPoint;
  83. AtEnd: Boolean): TArrayOfFloatPoint;
  84. var
  85. HighI: Integer;
  86. UnitVec: TFloatPoint;
  87. begin
  88. HighI := high(Line);
  89. if HighI < 1 then
  90. raise exception.create(RCStrInsufficientPointsInArray);
  91. if AtEnd then
  92. begin
  93. FBasePoint := Line[HighI];
  94. UnitVec := GetUnitVector(Line[HighI -1], Line[HighI]);
  95. end else
  96. begin
  97. FBasePoint := Line[0];
  98. UnitVec := GetUnitVector(Line[1], Line[0]);
  99. end;
  100. FTipPoint := OffsetPoint(FBasePoint, UnitVec.X * FSize, UnitVec.Y * FSize);
  101. Result := GetPointsInternal;
  102. end;
  103. //------------------------------------------------------------------------------
  104. function TArrowHeadSimple.GetPointsInternal: TArrayOfFloatPoint;
  105. var
  106. UnitNorm: TFloatPoint;
  107. Sz: Single;
  108. begin
  109. SetLength(Result, 3);
  110. UnitNorm := GetUnitNormal(FTipPoint, FBasePoint);
  111. Sz := FSize * 0.5;
  112. Result[0] := FTipPoint;
  113. Result[1] := OffsetPoint(FBasePoint, UnitNorm.X *Sz, UnitNorm.Y *Sz);
  114. Result[2] := OffsetPoint(FBasePoint, -UnitNorm.X *Sz, -UnitNorm.Y *Sz);
  115. end;
  116. //------------------------------------------------------------------------------
  117. function TArrowHeadFourPt.GetPointsInternal: TArrayOfFloatPoint;
  118. var
  119. Angle: Double;
  120. begin
  121. SetLength(Result, 4);
  122. Result[0] := FTipPoint;
  123. Angle := GetAngleOfPt2FromPt1(FTipPoint, FBasePoint);
  124. Result[1] := GetPointAtAngleFromPoint(FBasePoint, FSize * 0.5, Angle + CRad60);
  125. Result[2] := FBasePoint;
  126. Result[3] := GetPointAtAngleFromPoint(FBasePoint, FSize * 0.5, Angle - CRad60);
  127. end;
  128. //------------------------------------------------------------------------------
  129. function TArrowHeadCircle.GetPointsInternal: TArrayOfFloatPoint;
  130. var
  131. MidPt: TFloatPoint;
  132. begin
  133. MidPt := GR32_Geometry.Average(FTipPoint, FBasePoint);
  134. Result := Circle(MidPt.X, MidPt.Y, FSize * 0.5, Round(FSize));
  135. end;
  136. //------------------------------------------------------------------------------
  137. function TArrowHeadDiamond.GetPointsInternal: TArrayOfFloatPoint;
  138. var
  139. MidPt, UnitNorm: TFloatPoint;
  140. Sz: Single;
  141. begin
  142. MidPt := GR32_Geometry.Average(FTipPoint, FBasePoint);
  143. UnitNorm := GetUnitNormal(FTipPoint, FBasePoint);
  144. Sz := FSize / 3;
  145. SetLength(Result, 4);
  146. Result[0] := FTipPoint;
  147. Result[1] := OffsetPoint(MidPt, UnitNorm.X * Sz, UnitNorm.Y * Sz);
  148. Result[2] := FBasePoint;
  149. Result[3] := OffsetPoint(MidPt, -UnitNorm.X * Sz, -UnitNorm.Y * Sz);
  150. end;
  151. //------------------------------------------------------------------------------
  152. end.