00001 using System;
00002 using System.Collections.Generic;
00003 using System.Linq;
00004 using System.Text;
00005 using System.Windows;
00006 using System.Diagnostics;
00007
00008 namespace EdgeClustering
00009 {
00010
00011
00012
00013
00014
00015
00016 public class MergedSegment : IEquatable<MergedSegment>
00017 {
00018 public static double threshold = 15;
00019
00020
00021
00022
00023 public class Segment {
00024
00025 public Segment(int x, int y, double angle, int n)
00026 {
00027 this.x = x;
00028 this.y = y;
00029 this.angle = angle;
00030 this.n = n;
00031 }
00032
00033 public int x;
00034 public int y;
00035 public double angle;
00036 public int n;
00037 };
00038
00039 private double[] borders = new double[2];
00040 public List<Segment> segments = new List<Segment>();
00041 public double averageAngle;
00042
00043 public MergedSegment(Segment segment)
00044 {
00045 segments.Add(segment);
00046 borders[0] = segment.angle;
00047 borders[1] = segment.angle;
00048
00049 CalculateWeightedAverage();
00050 }
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 private double CalculateXPos(double y, double k, double Px, double Py)
00064 {
00065 return (((y - Py) / k) + Px);
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 private double CalculateYPos(double x, double k, double Px, double Py)
00080 {
00081 return (Py + (x - Px) * k);
00082 }
00083
00084
00085
00086
00087
00088
00089
00090 public SimpleEdge CalculateMeshEdge()
00091 {
00092 double normal = averageAngle + 90;
00093 if (normal >= 180) normal -= 180;
00094 List<GridPoint> points = new List<GridPoint>();
00095 int xmin = int.MaxValue, xmax = 0, ymin = int.MaxValue, ymax = 0;
00096
00097 foreach (Segment s in segments) {
00098 int x = s.x, y = s.y;
00099 points.Add(new GridPoint(x, y));
00100 if (x > xmax) xmax = x;
00101 if (x < xmin) xmin = x;
00102 if (y > ymax) ymax = y;
00103 if (y < ymin) ymin = y;
00104 }
00105
00106 xmax++;
00107 ymax++;
00108 double xcenter = (double)(xmax + xmin) / 2.0;
00109 double ycenter = (double)(ymax + ymin) / 2.0;
00110 int maxDist = (Math.Max((xmax - xmin), (ymax - ymin)) + 1) / 2;
00111
00112 double gradient = Math.Sin(normal * Math.PI / 180.0) / Math.Cos(normal * Math.PI / 180.0);
00113
00114
00115 if (gradient == double.NaN)
00116 {
00117 return new SimpleEdge(new Point(xcenter, (int)ymin), new Point(xcenter, (int)ymax));
00118 }
00119
00120 List<GridPoint> possiblePoints = new List<GridPoint>();
00121 GridPoint tmp = null;
00122
00123
00124 #region Find possible points
00125 for (int offset = 0; offset <= maxDist; offset++) {
00126 int x = (int)xcenter, y = (int)ycenter;
00127
00128 if (offset == 0)
00129 {
00130 if (x != xcenter || y != ycenter)
00131 {
00132 if (points.Contains(tmp = new GridPoint(x, y)))
00133 possiblePoints.Add(tmp);
00134 }
00135 else if (gradient >= 0 && points.Contains(tmp = new GridPoint(x, y)))
00136 possiblePoints.Add(tmp);
00137 }
00138 else
00139 {
00140 double ycalcplusd = CalculateYPos(x + offset, gradient, xcenter, ycenter);
00141 int ycalcplus = (int)ycalcplusd;
00142 if (ycalcplusd - ycalcplus == 0)
00143 {
00144 if (gradient < 0 && points.Contains(tmp = new GridPoint(x + offset, ycalcplus - 1)))
00145 possiblePoints.Add(tmp);
00146 else if (gradient >= 0 && points.Contains(tmp = new GridPoint(x + offset, ycalcplus)))
00147 possiblePoints.Add(tmp);
00148 }
00149 else if (points.Contains(tmp = new GridPoint(x + offset, ycalcplus)))
00150 possiblePoints.Add(tmp);
00151
00152 double xcalcplusd = CalculateXPos(y + offset, gradient, xcenter, ycenter);
00153 int xcalcplus = (int)xcalcplusd;
00154 if (xcalcplusd - xcalcplus == 0)
00155 {
00156 if (gradient < 0 && xcalcplusd - xcalcplus == 0 && points.Contains(tmp = new GridPoint(xcalcplus - 1, y + offset)))
00157 possiblePoints.Add(tmp);
00158 else if (gradient > 0 && points.Contains(tmp = new GridPoint(xcalcplus, y + offset)))
00159 possiblePoints.Add(tmp);
00160 }
00161 else if (points.Contains(tmp = new GridPoint(xcalcplus, y + offset)))
00162 possiblePoints.Add(tmp);
00163
00164 double ycalcminusd = CalculateYPos(x - offset + 1, gradient, xcenter, ycenter);
00165 int ycalcminus = (int)ycalcminusd;
00166 if (ycalcminusd - ycalcminus == 0)
00167 {
00168 if (gradient > 0 && points.Contains(tmp = new GridPoint(x - offset, ycalcminus - 1)))
00169 possiblePoints.Add(tmp);
00170 else if (gradient <= 0 && points.Contains(tmp = new GridPoint(x - offset, ycalcminus)))
00171 possiblePoints.Add(tmp);
00172 }
00173 else if (points.Contains(tmp = new GridPoint(x - offset, ycalcminus)))
00174 possiblePoints.Add(tmp);
00175
00176 double xcalcminusd = CalculateXPos(y - offset + 1, gradient, xcenter, ycenter);
00177 int xcalcminus = (int)xcalcminusd;
00178 if (xcalcminusd - xcalcminus == 0)
00179 {
00180 if (gradient > 0 && points.Contains(tmp = new GridPoint(xcalcminus - 1, y - offset)))
00181 possiblePoints.Add(tmp);
00182 else if (gradient < 0 && points.Contains(tmp = new GridPoint(xcalcminus, y - offset)))
00183 possiblePoints.Add(tmp);
00184 }
00185 else if (points.Contains(tmp = new GridPoint(xcalcminus, y - offset)))
00186 possiblePoints.Add(tmp);
00187 }
00188 }
00189 #endregion
00190
00191
00192 if (possiblePoints.Count == 0) return null;
00193
00194
00195 #region Min and Max of possible points
00196 GridPoint[] p = new GridPoint[4];
00197 p[0] = new GridPoint(int.MaxValue, int.MaxValue);
00198 p[1] = new GridPoint(0, 0);
00199 p[2] = new GridPoint(int.MaxValue, int.MaxValue);
00200 p[3] = new GridPoint(0, 0);
00201 xmin = int.MaxValue;
00202 xmax = 0;
00203 ymin = int.MaxValue;
00204 ymax = 0;
00205
00206 foreach (GridPoint po in possiblePoints) {
00207 if (po.X <= p[0].X && ( (po.X != p[0].X) || ((po.Y < p[0].Y) && (gradient > 0)) || ((po.Y > p[0].Y) && (gradient < 0)) )) p[0] = po;
00208 if (po.X >= p[1].X && ( (po.X != p[1].X) || ((po.Y > p[1].Y) && (gradient > 0)) || ((po.Y < p[1].Y) && (gradient < 0)) )) p[1] = po;
00209 if (po.Y <= p[2].Y) p[2] = po;
00210 if (po.Y >= p[3].Y) p[3] = po;
00211
00212 if (po.X > xmax) xmax = po.X;
00213 if (po.X < xmin) xmin = po.X;
00214 if (po.Y > ymax) ymax = po.Y;
00215 if (po.Y < ymin) ymin = po.Y;
00216 }
00217
00218 GridPoint gpmin, gpmax;
00219 bool ymode = false;
00220
00221 if (p[0].X != p[1].X)
00222 {
00223 gpmin = p[0];
00224 gpmax = p[1];
00225 }
00226 else
00227 {
00228 ymode = true;
00229 gpmin = p[2];
00230 gpmax = p[3];
00231 }
00232 #endregion
00233
00234
00235 Point min = new Point (gpmin.X, gpmin.Y), max = new Point(gpmax.X, gpmax.Y);
00236 #region Exact coordinates for gradient != 0
00237 if (gradient > 0)
00238 {
00239 double ycalc = CalculateYPos(gpmin.X, gradient, xcenter, ycenter);
00240 if (ycalc - gpmin.Y <= 1 && ycalc - gpmin.Y >= 0)
00241 {
00242 min.X = gpmin.X;
00243 min.Y = ycalc;
00244 }
00245 else
00246 {
00247 double xcalc = CalculateXPos(gpmin.Y, gradient, xcenter, ycenter);
00248 if (xcalc - gpmin.X > 1 || xcalc - gpmin.X < 0)
00249 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00250 min.X = xcalc;
00251 min.Y = gpmin.Y;
00252 }
00253 ycalc = CalculateYPos(gpmax.X + 1, gradient, xcenter, ycenter);
00254 if (ycalc - gpmax.Y <= 1 && ycalc - gpmax.Y >= 0)
00255 {
00256 max.X = gpmax.X + 1;
00257 max.Y = ycalc;
00258 }
00259 else
00260 {
00261 double xcalc = CalculateXPos(gpmax.Y + 1, gradient, xcenter, ycenter);
00262 if (xcalc - gpmax.X > 1 || xcalc - gpmax.X < 0)
00263 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00264 max.X = xcalc;
00265 max.Y = gpmax.Y + 1;
00266 }
00267 }
00268 else if (gradient < 0)
00269 {
00270 if (ymode)
00271 {
00272 double ycalc = CalculateYPos(gpmin.X + 1, gradient, xcenter, ycenter);
00273 if (ycalc - gpmin.Y <= 1 && ycalc - gpmin.Y >= 0)
00274 {
00275 min.X = gpmin.X + 1;
00276 min.Y = ycalc;
00277 }
00278 else
00279 {
00280 double xcalc = CalculateXPos(gpmin.Y, gradient, xcenter, ycenter);
00281 if (xcalc - gpmin.X > 1 || xcalc - gpmin.X < 0)
00282 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00283 min.X = xcalc;
00284 min.Y = gpmin.Y;
00285 }
00286
00287 ycalc = CalculateYPos(gpmax.X, gradient, xcenter, ycenter);
00288 if (ycalc - gpmax.Y <= 1 && ycalc - gpmax.Y >= 0)
00289 {
00290 max.X = gpmax.X;
00291 max.Y = ycalc;
00292 }
00293 else
00294 {
00295 double xcalc = CalculateXPos(gpmax.Y + 1, gradient, xcenter, ycenter);
00296 if (xcalc - gpmax.X > 1 || xcalc - gpmax.X < 0)
00297 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00298 max.X = xcalc;
00299 max.Y = gpmax.Y + 1;
00300 }
00301 }
00302 else
00303 {
00304 double ycalc = CalculateYPos(gpmin.X, gradient, xcenter, ycenter);
00305 if (ycalc - gpmin.Y <= 1 && ycalc - gpmin.Y >= 0)
00306 {
00307 min.X = gpmin.X;
00308 min.Y = ycalc;
00309 }
00310 else
00311 {
00312 double xcalc = CalculateXPos(gpmin.Y + 1, gradient, xcenter, ycenter);
00313 if (xcalc - gpmin.X > 1 || xcalc - gpmin.X < 0)
00314 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00315 min.X = xcalc;
00316 min.Y = gpmin.Y + 1;
00317 }
00318
00319 ycalc = CalculateYPos(gpmax.X + 1, gradient, xcenter, ycenter);
00320 if (ycalc - gpmax.Y <= 1 && ycalc - gpmax.Y >= 0)
00321 {
00322 max.X = gpmax.X + 1;
00323 max.Y = ycalc;
00324 }
00325 else
00326 {
00327 double xcalc = CalculateXPos(gpmax.Y, gradient, xcenter, ycenter);
00328 if (xcalc - gpmax.X > 1 || xcalc - gpmax.X < 0)
00329 Console.WriteLine("Something's wrong! - MergedSegments#CalculateMeshEdge():[calculate exact coordinates]");
00330 max.X = xcalc;
00331 max.Y = gpmax.Y;
00332 }
00333 }
00334 }
00335 #endregion
00336
00337 Console.WriteLine("(" + min.X + "; " + min.Y + ") - (" + max.X + "; " + max.Y + ")");
00338
00339 return new SimpleEdge(min, max);
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349 public double[] MergeBorders(double[] b1, double[] b2)
00350 {
00351
00352 double[] borders = { b1[0], b1[1], b2[0], b2[1] };
00353
00354 double[] minMax = { 180, 0 };
00355 foreach (double b in borders)
00356 {
00357 if(b < minMax[0])
00358 minMax[0] = b;
00359 if(b > minMax[1])
00360 minMax[1] = b;
00361 }
00362
00363 double[] med = {minMax[0],minMax[1]};
00364
00365
00366 foreach (double b in borders)
00367 {
00368 if (b < 90 && b > med[0])
00369 med[0] = b;
00370 if (b > 90 && b < med[1])
00371 med[1] = b;
00372 }
00373
00374 if (Math.Abs(minMax[1] - minMax[0]) <= threshold)
00375 return minMax;
00376
00377 if (Math.Abs(med[1] - med[0]) >= 180.0 - threshold)
00378 return med;
00379
00380 return null;
00381 }
00382
00383
00384
00385
00386
00387
00388 private bool CheckConnectivity(MergedSegment segment)
00389 {
00390 int xDiff, yDiff;
00391
00392 foreach (Segment s1 in this.segments)
00393 {
00394 foreach (Segment s2 in segment.segments)
00395 {
00396 xDiff = Math.Abs(s1.x - s2.x);
00397 yDiff = Math.Abs(s1.y - s2.y);
00398
00399 if (xDiff <= 1 && yDiff <= 1)
00400 return true;
00401 }
00402 }
00403 return false;
00404
00405
00406 }
00407
00408
00409
00410
00411
00412 private void CalculateWeightedAverage()
00413 {
00414 double diff = Math.Abs(borders[0] - borders[1]);
00415 int n = 0;
00416 double sum = 0;
00417
00418 foreach (Segment s in segments)
00419 {
00420 if (diff > threshold)
00421 Console.WriteLine("Stop");
00422
00423 if (diff > threshold && s.angle > 90)
00424 {
00425 sum += (s.angle - 180) * s.n;
00426
00427 }
00428 else
00429 sum += s.angle * s.n;
00430
00431 n += s.n;
00432 }
00433
00434
00435 sum /= n;
00436
00437
00438 if (sum < 0)
00439 sum += 180;
00440
00441 if (sum == 0)
00442 Console.WriteLine("Stop");
00443 averageAngle = sum;
00444 }
00445
00446
00447
00448
00449
00450 public void AddMergedSegment(MergedSegment segment)
00451 {
00452 double[] bnew = MergeBorders(borders, segment.borders);
00453
00454 if (bnew != null)
00455 {
00456 if (CheckConnectivity(segment))
00457 {
00458 segments.AddRange(segment.segments);
00459 borders = bnew;
00460 CalculateWeightedAverage();
00461 }
00462 }
00463 }
00464
00465 public bool Equals(MergedSegment other)
00466 {
00467 if (MergeBorders(this.borders, other.borders) != null)
00468 if(CheckConnectivity(other))
00469 return true;
00470
00471 return false;
00472 }
00473
00474 public override bool Equals(Object obj)
00475 {
00476 if (obj == null) return base.Equals(obj);
00477
00478 if (!(obj is MergedSegment))
00479 throw new InvalidCastException("The 'obj' argument is not a MergedSegment object.");
00480 else
00481 return Equals(obj as MergedSegment);
00482 }
00483
00484 public override int GetHashCode()
00485 {
00486 return this.GetHashCode();
00487 }
00488 }
00489 }