PageRenderTime 50ms CodeModel.GetById 10ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 1ms

/Main/src/DynamicDataDisplay/Charts/Isolines/CellInfo.cs

#
C# | 399 lines | 294 code | 49 blank | 56 comment | 39 complexity | 56df94dfa6289290548c06decfd26880 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Text;
  5using System.Diagnostics;
  6using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
  7using System.Windows;
  8
  9namespace Microsoft.Research.DynamicDataDisplay.Charts.Isolines
 10{
 11	/// <summary>
 12	/// Isoline's grid cell
 13	/// </summary>
 14	internal interface ICell
 15	{
 16		Vector LeftTop { get; }
 17		Vector LeftBottom { get; }
 18		Vector RightTop { get; }
 19		Vector RightBottom { get; }
 20	}
 21
 22	internal sealed class IrregularCell : ICell
 23	{
 24		public IrregularCell(Vector leftBottom, Vector rightBottom, Vector rightTop, Vector leftTop)
 25		{
 26			this.leftBottom = leftBottom;
 27			this.rightBottom = rightBottom;
 28			this.rightTop = rightTop;
 29			this.leftTop = leftTop;
 30		}
 31
 32		public IrregularCell(Point lb, Point rb, Point rt, Point lt)
 33		{
 34			leftTop = lt.ToVector();
 35			leftBottom = lb.ToVector();
 36			rightTop = rt.ToVector();
 37			rightBottom = rb.ToVector();
 38		}
 39
 40		#region ICell Members
 41
 42		private readonly Vector leftTop;
 43		public Vector LeftTop
 44		{
 45			get { return leftTop; }
 46		}
 47
 48		private readonly Vector leftBottom;
 49		public Vector LeftBottom
 50		{
 51			get { return leftBottom; }
 52		}
 53
 54		private readonly Vector rightTop;
 55		public Vector RightTop
 56		{
 57			get { return rightTop; }
 58		}
 59
 60		private readonly Vector rightBottom;
 61		public Vector RightBottom
 62		{
 63			get { return rightBottom; }
 64		}
 65
 66		#endregion
 67
 68		#region Sides
 69		public Vector LeftSide
 70		{
 71			get { return (leftBottom + leftTop) / 2; }
 72		}
 73
 74		public Vector RightSide
 75		{
 76			get { return (rightBottom + rightTop) / 2; }
 77		}
 78		public Vector TopSide
 79		{
 80			get { return (leftTop + rightTop) / 2; }
 81		}
 82		public Vector BottomSide
 83		{
 84			get { return (leftBottom + rightBottom) / 2; }
 85		}
 86		#endregion
 87
 88		public Point Center
 89		{
 90			get { return ((LeftSide + RightSide) / 2).ToPoint(); }
 91		}
 92
 93		public IrregularCell GetSubRect(SubCell sub)
 94		{
 95			switch (sub)
 96			{
 97				case SubCell.LeftBottom:
 98					return new IrregularCell(LeftBottom, BottomSide, Center.ToVector(), LeftSide);
 99				case SubCell.LeftTop:
100					return new IrregularCell(LeftSide, Center.ToVector(), TopSide, LeftTop);
101				case SubCell.RightBottom:
102					return new IrregularCell(BottomSide, RightBottom, RightSide, Center.ToVector());
103				case SubCell.RightTop:
104				default:
105					return new IrregularCell(Center.ToVector(), RightSide, RightTop, TopSide);
106			}
107		}
108	}
109
110	internal enum SubCell
111	{
112		LeftBottom = 0,
113		LeftTop = 1,
114		RightBottom = 2,
115		RightTop = 3
116	}
117
118	internal class ValuesInCell
119	{
120        double min = Double.MaxValue, max = Double.MinValue;
121
122        /// <summary>Initializes values in four corners of cell</summary>
123        /// <param name="leftBottom"></param>
124        /// <param name="rightBottom"></param>
125        /// <param name="rightTop"></param>
126        /// <param name="leftTop"></param>
127        /// <remarks>Some or all values can be NaN. That means that value is not specified (misssing)</remarks>
128		public ValuesInCell(double leftBottom, double rightBottom, double rightTop, double leftTop)
129		{
130			this.leftTop = leftTop;
131			this.leftBottom = leftBottom;
132			this.rightTop = rightTop;
133			this.rightBottom = rightBottom;
134
135            // Find max and min values (with respect to possible NaN values)
136            if (!Double.IsNaN(leftTop))
137            {
138                if (min > leftTop)
139                    min = leftTop;
140                if (max < leftTop)
141                    max = leftTop;
142            }
143
144            if (!Double.IsNaN(leftBottom))
145            {
146                if (min > leftBottom)
147                    min = leftBottom;
148                if (max < leftBottom)
149                    max = leftBottom;
150            }
151
152            if (!Double.IsNaN(rightTop))
153            {
154                if (min > rightTop)
155                    min = rightTop;
156                if (max < rightTop)
157                    max = rightTop;
158            }
159
160            if (!Double.IsNaN(rightBottom))
161            {
162                if (min > rightBottom)
163                    min = rightBottom;
164                if (max < rightBottom)
165                    max = rightBottom;
166            }
167
168            left = (leftTop + leftBottom) / 2;
169            bottom = (leftBottom + rightBottom) / 2;
170            right = (rightTop + rightBottom) / 2;
171            top = (rightTop + leftTop) / 2;
172		}
173
174        public ValuesInCell(double leftBottom, double rightBottom, double rightTop, double leftTop, double missingValue)
175		{
176			DebugVerify.IsNotNaN(leftBottom);
177			DebugVerify.IsNotNaN(rightBottom);
178			DebugVerify.IsNotNaN(rightTop);
179			DebugVerify.IsNotNaN(leftTop);
180           
181            // Copy values and find min and max with respect to possible missing values
182            if (leftTop != missingValue)
183            {
184                this.leftTop = leftTop;
185                if (min > leftTop)
186                    min = leftTop;
187                if (max < leftTop)
188                    max = leftTop;
189            }
190            else
191                this.leftTop = Double.NaN;
192
193            if (leftBottom != missingValue)
194            {
195                this.leftBottom = leftBottom;
196                if (min > leftBottom)
197                    min = leftBottom;
198                if (max < leftBottom)
199                    max = leftBottom;
200            }
201            else
202                this.leftBottom = Double.NaN;
203
204            if (rightTop != missingValue)
205            {
206                this.rightTop = rightTop;
207                if (min > rightTop)
208                    min = rightTop;
209                if (max < rightTop)
210                    max = rightTop;
211            }
212            else
213                this.rightTop = Double.NaN;
214
215            if (rightBottom != missingValue)
216            {
217                this.rightBottom = rightBottom;
218                if (min > rightBottom)
219                    min = rightBottom;
220                if (max < rightBottom)
221                    max = rightBottom;
222            }
223            else
224                this.rightBottom = Double.NaN;
225
226            left = (this.leftTop + this.leftBottom) / 2;
227            bottom = (this.leftBottom + this.rightBottom) / 2;
228            right = (this.rightTop + this.rightBottom) / 2;
229            top = (this.rightTop + this.leftTop) / 2;
230
231
232/*            
233            if (leftTop != missingValue && )
234            {
235                if (leftBottom != missingValue)
236                    left = (leftTop + leftBottom) / 2;
237                else
238                    left = Double.NaN;
239
240                if (rightTop != missingValue)
241                    top = (leftTop + rightTop) / 2;
242                else
243                    top = Double.NaN;
244            }
245
246            if (rightBottom != missingValue)
247            {
248                if (leftBottom != missingValue)
249                    bottom = (leftBottom + rightBottom) / 2;
250                else
251                    bottom = Double.NaN;
252
253                if (rightTop != missingValue)
254                    right = (rightTop + rightBottom) / 2;
255                else
256                    right = Double.NaN;
257            }*/
258		}
259
260
261		/*internal bool ValueBelongTo(double value)
262		{
263			IEnumerable<double> values = new double[] { leftTop, leftBottom, rightTop, rightBottom };
264
265			return !(values.All(v => v > value) || values.All(v => v < value));
266		}*/
267
268        internal bool ValueBelongTo(double value)
269        {
270            return (min <= value && value <= max);
271        }
272
273		#region Edges
274		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
275		private readonly double leftTop;
276		public double LeftTop { get { return leftTop; } }
277
278		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
279		private readonly double leftBottom;
280		public double LeftBottom { get { return leftBottom; } }
281
282		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
283		private readonly double rightTop;
284		public double RightTop
285		{
286			get { return rightTop; }
287		}
288
289		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
290		private readonly double rightBottom;
291		public double RightBottom
292		{
293			get { return rightBottom; }
294		}
295		#endregion
296
297		#region Sides & center
298		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
299		private readonly double left;
300		public double Left
301		{
302			get { return left; }
303		}
304
305		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
306		private readonly double right;
307		public double Right
308		{
309			get { return right; }
310		}
311
312		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
313		private readonly double top;
314		public double Top
315		{
316			get { return top; }
317		}
318
319		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
320		private readonly double bottom;
321		public double Bottom
322		{
323			get { return bottom; }
324		}
325
326		public double Center
327		{
328			get { return (Left + Right) * 0.5; }
329		}
330		#endregion
331
332		#region SubCells
333		public ValuesInCell LeftTopCell
334		{
335			get { return new ValuesInCell(Left, Center, Top, LeftTop); }
336		}
337
338		public ValuesInCell RightTopCell
339		{
340			get { return new ValuesInCell(Center, Right, RightTop, Top); }
341		}
342
343		public ValuesInCell RightBottomCell
344		{
345			get { return new ValuesInCell(Bottom, RightBottom, Right, Center); }
346		}
347
348		public ValuesInCell LeftBottomCell
349		{
350			get { return new ValuesInCell(LeftBottom, Bottom, Center, Left); }
351		}
352
353		public ValuesInCell GetSubCell(SubCell subCell)
354		{
355			switch (subCell)
356			{
357				case SubCell.LeftBottom:
358					return LeftBottomCell;
359				case SubCell.LeftTop:
360					return LeftTopCell;
361				case SubCell.RightBottom:
362					return RightBottomCell;
363				case SubCell.RightTop:
364				default:
365					return RightTopCell;
366			}
367		}
368
369		#endregion
370
371		/// <summary>
372		/// Returns bitmask of comparison of values at cell corners with reference value.
373		/// Corresponding bit is set to one if value at cell corner is greater than reference value. 
374		/// a------b
375		/// | Cell |
376		/// d------c
377		/// </summary>
378		/// <param name="a">Value at corner (see figure)</param>
379		/// <param name="b">Value at corner (see figure)</param>
380		/// <param name="c">Value at corner (see figure)</param>
381		/// <param name="d">Value at corner (see figure)</param>
382		/// <param name="value">Reference value</param>
383		/// <returns>Bitmask</returns>
384		public CellBitmask GetCellValue(double value)
385		{
386			CellBitmask n = CellBitmask.None;
387			if (!Double.IsNaN(leftTop) && leftTop > value)
388				n |= CellBitmask.LeftTop;
389			if (!Double.IsNaN(leftBottom) && leftBottom > value)
390				n |= CellBitmask.LeftBottom;
391			if (!Double.IsNaN(rightBottom) && rightBottom > value)
392				n |= CellBitmask.RightBottom;
393			if (!Double.IsNaN(rightTop) && rightTop > value)
394				n |= CellBitmask.RightTop;
395
396			return n;
397		}
398	}
399}