/Main/src/DynamicDataDisplay/Charts/Isolines/CellInfo.cs
C# | 399 lines | 294 code | 49 blank | 56 comment | 39 complexity | 56df94dfa6289290548c06decfd26880 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
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}