SizeRange.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using System;
  2. using System.ComponentModel;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Globalization;
  6. using FastReport.Utils;
  7. namespace FastReport.Map
  8. {
  9. /// <summary>
  10. /// Represents a set of size ranges used to draw points based on analytical value.
  11. /// </summary>
  12. [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))]
  13. public class SizeRanges
  14. {
  15. #region Fields
  16. private List<SizeRange> ranges;
  17. private float startSize;
  18. private float endSize;
  19. #endregion // Fields
  20. #region Properties
  21. /// <summary>
  22. /// Gets the list of ranges.
  23. /// </summary>
  24. public List<SizeRange> Ranges
  25. {
  26. get { return ranges; }
  27. }
  28. /// <summary>
  29. /// Gets or sets the number of ranges.
  30. /// </summary>
  31. public int RangeCount
  32. {
  33. get { return Ranges.Count; }
  34. set
  35. {
  36. if (Ranges.Count < value)
  37. {
  38. while (Ranges.Count < value)
  39. Ranges.Add(new SizeRange());
  40. }
  41. else if (Ranges.Count > value)
  42. {
  43. while (Ranges.Count > value)
  44. Ranges.RemoveAt(Ranges.Count - 1);
  45. }
  46. }
  47. }
  48. /// <summary>
  49. /// Gets or sets the start size.
  50. /// </summary>
  51. public float StartSize
  52. {
  53. get { return startSize; }
  54. set { startSize = value; }
  55. }
  56. /// <summary>
  57. /// Gets or sets the end size.
  58. /// </summary>
  59. public float EndSize
  60. {
  61. get { return endSize; }
  62. set { endSize = value; }
  63. }
  64. /// <summary>
  65. /// Gets or sets ranges as a string.
  66. /// </summary>
  67. [Browsable(false)]
  68. public string RangesAsString
  69. {
  70. get { return GetRangesAsString(); }
  71. set { SetRangesAsString(value); }
  72. }
  73. #endregion // Properties
  74. #region Private Methods
  75. private string GetRangesAsString()
  76. {
  77. StringBuilder result = new StringBuilder();
  78. foreach (SizeRange range in Ranges)
  79. {
  80. result.Append(range.GetAsString()).Append("\r\n");
  81. }
  82. if (result.Length > 2)
  83. result.Remove(result.Length - 2, 2);
  84. return result.ToString();
  85. }
  86. private void SetRangesAsString(string value)
  87. {
  88. Ranges.Clear();
  89. if (String.IsNullOrEmpty(value))
  90. return;
  91. string[] values = value.Split(new string[] { "\r\n" }, StringSplitOptions.None);
  92. foreach (string val in values)
  93. {
  94. SizeRange range = new SizeRange();
  95. range.SetAsString(val);
  96. Ranges.Add(range);
  97. }
  98. }
  99. #endregion // Private Methods
  100. #region Public Methods
  101. /// <summary>
  102. /// Copies the contents of another SizeRanges.
  103. /// </summary>
  104. /// <param name="src">The SizeRanges instance to copy the contents from.</param>
  105. public void Assign(SizeRanges src)
  106. {
  107. StartSize = src.StartSize;
  108. EndSize = src.EndSize;
  109. RangeCount = src.RangeCount;
  110. for (int i = 0; i < RangeCount; i++)
  111. Ranges[i].Assign(src.Ranges[i]);
  112. }
  113. /// <summary>
  114. /// Gets a size associated with given analytical value.
  115. /// </summary>
  116. /// <param name="value">The analytical value.</param>
  117. /// <returns>The size associated with this value, or 0 if no association found.</returns>
  118. public float GetSize(double value)
  119. {
  120. foreach (SizeRange range in Ranges)
  121. {
  122. if (value >= range.StartValue && value < range.EndValue)
  123. return range.Size;
  124. }
  125. return 0;
  126. }
  127. internal void Fill(double min, double max)
  128. {
  129. double delta = (max - min) / RangeCount;
  130. float sizeDelta = (EndSize - StartSize) / RangeCount;
  131. for (int i = 0; i < RangeCount; i++)
  132. {
  133. SizeRange range = Ranges[i];
  134. if (range.IsSizeEmpty)
  135. range.Size = StartSize + sizeDelta * i;
  136. if (range.IsStartValueEmpty)
  137. range.StartValue = min + delta * i;
  138. // make last EndValue bigger to fit largest data value in this range
  139. if (range.IsEndValueEmpty)
  140. range.EndValue = min + delta * (i + 1) + (i == RangeCount - 1 ? 0.1 : 0);
  141. }
  142. }
  143. internal void SaveState()
  144. {
  145. foreach (SizeRange range in Ranges)
  146. {
  147. range.SaveState();
  148. }
  149. }
  150. internal void RestoreState()
  151. {
  152. foreach (SizeRange range in Ranges)
  153. {
  154. range.RestoreState();
  155. }
  156. }
  157. internal void Serialize(FRWriter writer, string prefix)
  158. {
  159. writer.WriteFloat(prefix + ".StartSize", StartSize);
  160. writer.WriteFloat(prefix + ".EndSize", EndSize);
  161. writer.WriteStr(prefix + ".RangesAsString", RangesAsString);
  162. }
  163. #endregion // Public Methods
  164. /// <summary>
  165. /// Initializes a new instance of the <see cref="SizeRanges"/> class.
  166. /// </summary>
  167. public SizeRanges()
  168. {
  169. ranges = new List<SizeRange>();
  170. startSize = 4;
  171. endSize = 20;
  172. }
  173. }
  174. /// <summary>
  175. /// Represents a single size range.
  176. /// </summary>
  177. public class SizeRange
  178. {
  179. #region Fields
  180. private float size;
  181. private double startValue;
  182. private double endValue;
  183. private SizeRange state;
  184. #endregion // Fields
  185. #region Properties
  186. /// <summary>
  187. /// Gets or sets size of the range.
  188. /// </summary>
  189. public float Size
  190. {
  191. get { return size; }
  192. set { size = value; }
  193. }
  194. /// <summary>
  195. /// Gets or sets start value of the range.
  196. /// </summary>
  197. public double StartValue
  198. {
  199. get { return startValue; }
  200. set { startValue = value; }
  201. }
  202. /// <summary>
  203. /// Gets or sets end value of the range.
  204. /// </summary>
  205. public double EndValue
  206. {
  207. get { return endValue; }
  208. set { endValue = value; }
  209. }
  210. internal bool IsSizeEmpty
  211. {
  212. get { return float.IsNaN(Size); }
  213. }
  214. internal bool IsStartValueEmpty
  215. {
  216. get { return double.IsNaN(StartValue); }
  217. }
  218. internal bool IsEndValueEmpty
  219. {
  220. get { return double.IsNaN(EndValue); }
  221. }
  222. #endregion // Properties
  223. #region Public Methods
  224. /// <summary>
  225. /// Copies the contents of another SizeRange.
  226. /// </summary>
  227. /// <param name="src">The SizeRange instance to copy the contents from.</param>
  228. public void Assign(SizeRange src)
  229. {
  230. Size = src.Size;
  231. StartValue = src.StartValue;
  232. EndValue = src.EndValue;
  233. }
  234. internal void SaveState()
  235. {
  236. if (state == null)
  237. state = new SizeRange();
  238. state.Assign(this);
  239. }
  240. internal void RestoreState()
  241. {
  242. if (state != null)
  243. Assign(state);
  244. }
  245. internal string GetAsString()
  246. {
  247. return Size.ToString(CultureInfo.InvariantCulture.NumberFormat) + ";" +
  248. StartValue.ToString(CultureInfo.InvariantCulture.NumberFormat) + ";" +
  249. EndValue.ToString(CultureInfo.InvariantCulture.NumberFormat);
  250. }
  251. internal void SetAsString(string value)
  252. {
  253. Reset();
  254. if (String.IsNullOrEmpty(value))
  255. return;
  256. string[] val = value.Split(';');
  257. if (val.Length != 3)
  258. return;
  259. Size = float.Parse(val[0], CultureInfo.InvariantCulture.NumberFormat);
  260. StartValue = double.Parse(val[1], CultureInfo.InvariantCulture.NumberFormat);
  261. EndValue = double.Parse(val[2], CultureInfo.InvariantCulture.NumberFormat);
  262. }
  263. internal void Reset()
  264. {
  265. size = float.NaN;
  266. startValue = double.NaN;
  267. endValue = double.NaN;
  268. }
  269. #endregion
  270. /// <summary>
  271. /// Initializes a new instance of the <see cref="SizeRange"/> class.
  272. /// </summary>
  273. public SizeRange()
  274. {
  275. Reset();
  276. }
  277. /// <summary>
  278. /// Initializes a new instance of the <see cref="SizeRange"/> class with a specified parameters.
  279. /// </summary>
  280. /// <param name="size">The size of the range.</param>
  281. /// <param name="startValue">The start value of the range.</param>
  282. /// <param name="endValue">The end value of the range.</param>
  283. public SizeRange(float size, double startValue, double endValue)
  284. {
  285. this.size = size;
  286. this.startValue = startValue;
  287. this.endValue = endValue;
  288. }
  289. }
  290. }