using System; using System.ComponentModel; using System.Collections.Generic; using System.Text; using System.Globalization; using FastReport.Utils; namespace FastReport.Map { /// /// Represents a set of size ranges used to draw points based on analytical value. /// [TypeConverter(typeof(FastReport.TypeConverters.FRExpandableObjectConverter))] public class SizeRanges { #region Fields private List ranges; private float startSize; private float endSize; #endregion // Fields #region Properties /// /// Gets the list of ranges. /// public List Ranges { get { return ranges; } } /// /// Gets or sets the number of ranges. /// public int RangeCount { get { return Ranges.Count; } set { if (Ranges.Count < value) { while (Ranges.Count < value) Ranges.Add(new SizeRange()); } else if (Ranges.Count > value) { while (Ranges.Count > value) Ranges.RemoveAt(Ranges.Count - 1); } } } /// /// Gets or sets the start size. /// public float StartSize { get { return startSize; } set { startSize = value; } } /// /// Gets or sets the end size. /// public float EndSize { get { return endSize; } set { endSize = value; } } /// /// Gets or sets ranges as a string. /// [Browsable(false)] public string RangesAsString { get { return GetRangesAsString(); } set { SetRangesAsString(value); } } #endregion // Properties #region Private Methods private string GetRangesAsString() { StringBuilder result = new StringBuilder(); foreach (SizeRange range in Ranges) { result.Append(range.GetAsString()).Append("\r\n"); } if (result.Length > 2) result.Remove(result.Length - 2, 2); return result.ToString(); } private void SetRangesAsString(string value) { Ranges.Clear(); if (String.IsNullOrEmpty(value)) return; string[] values = value.Split(new string[] { "\r\n" }, StringSplitOptions.None); foreach (string val in values) { SizeRange range = new SizeRange(); range.SetAsString(val); Ranges.Add(range); } } #endregion // Private Methods #region Public Methods /// /// Copies the contents of another SizeRanges. /// /// The SizeRanges instance to copy the contents from. public void Assign(SizeRanges src) { StartSize = src.StartSize; EndSize = src.EndSize; RangeCount = src.RangeCount; for (int i = 0; i < RangeCount; i++) Ranges[i].Assign(src.Ranges[i]); } /// /// Gets a size associated with given analytical value. /// /// The analytical value. /// The size associated with this value, or 0 if no association found. public float GetSize(double value) { foreach (SizeRange range in Ranges) { if (value >= range.StartValue && value < range.EndValue) return range.Size; } return 0; } internal void Fill(double min, double max) { double delta = (max - min) / RangeCount; float sizeDelta = (EndSize - StartSize) / RangeCount; for (int i = 0; i < RangeCount; i++) { SizeRange range = Ranges[i]; if (range.IsSizeEmpty) range.Size = StartSize + sizeDelta * i; if (range.IsStartValueEmpty) range.StartValue = min + delta * i; // make last EndValue bigger to fit largest data value in this range if (range.IsEndValueEmpty) range.EndValue = min + delta * (i + 1) + (i == RangeCount - 1 ? 0.1 : 0); } } internal void SaveState() { foreach (SizeRange range in Ranges) { range.SaveState(); } } internal void RestoreState() { foreach (SizeRange range in Ranges) { range.RestoreState(); } } internal void Serialize(FRWriter writer, string prefix) { writer.WriteFloat(prefix + ".StartSize", StartSize); writer.WriteFloat(prefix + ".EndSize", EndSize); writer.WriteStr(prefix + ".RangesAsString", RangesAsString); } #endregion // Public Methods /// /// Initializes a new instance of the class. /// public SizeRanges() { ranges = new List(); startSize = 4; endSize = 20; } } /// /// Represents a single size range. /// public class SizeRange { #region Fields private float size; private double startValue; private double endValue; private SizeRange state; #endregion // Fields #region Properties /// /// Gets or sets size of the range. /// public float Size { get { return size; } set { size = value; } } /// /// Gets or sets start value of the range. /// public double StartValue { get { return startValue; } set { startValue = value; } } /// /// Gets or sets end value of the range. /// public double EndValue { get { return endValue; } set { endValue = value; } } internal bool IsSizeEmpty { get { return float.IsNaN(Size); } } internal bool IsStartValueEmpty { get { return double.IsNaN(StartValue); } } internal bool IsEndValueEmpty { get { return double.IsNaN(EndValue); } } #endregion // Properties #region Public Methods /// /// Copies the contents of another SizeRange. /// /// The SizeRange instance to copy the contents from. public void Assign(SizeRange src) { Size = src.Size; StartValue = src.StartValue; EndValue = src.EndValue; } internal void SaveState() { if (state == null) state = new SizeRange(); state.Assign(this); } internal void RestoreState() { if (state != null) Assign(state); } internal string GetAsString() { return Size.ToString(CultureInfo.InvariantCulture.NumberFormat) + ";" + StartValue.ToString(CultureInfo.InvariantCulture.NumberFormat) + ";" + EndValue.ToString(CultureInfo.InvariantCulture.NumberFormat); } internal void SetAsString(string value) { Reset(); if (String.IsNullOrEmpty(value)) return; string[] val = value.Split(';'); if (val.Length != 3) return; Size = float.Parse(val[0], CultureInfo.InvariantCulture.NumberFormat); StartValue = double.Parse(val[1], CultureInfo.InvariantCulture.NumberFormat); EndValue = double.Parse(val[2], CultureInfo.InvariantCulture.NumberFormat); } internal void Reset() { size = float.NaN; startValue = double.NaN; endValue = double.NaN; } #endregion /// /// Initializes a new instance of the class. /// public SizeRange() { Reset(); } /// /// Initializes a new instance of the class with a specified parameters. /// /// The size of the range. /// The start value of the range. /// The end value of the range. public SizeRange(float size, double startValue, double endValue) { this.size = size; this.startValue = startValue; this.endValue = endValue; } } }