// private Border FindNextBorder() // { // // Alle Cluster enthalten zwei Punkte. Suche einen Joint, dessen angeschlossener // // ICurve2D länger als maxGap ist (warum eigentlich?) // // Gehe solange durch die Cluster, bis wieder der erste Punkt erreicht ist // Joint StartWith = null; // foreach (Cluster cl in clusterSet) // { // foreach (Joint lp in cl.Points) // { // if (lp.curve.Length>maxGap) // { // StartWith = lp; // RemoveJoint(lp,cl); // break; // } // } // if (StartWith!=null) break; // } // if (StartWith==null) return null; // keinen Anfang gefunden // Joint LastPoint = StartWith; // Cluster goon = null; // BorderBuilder makeBorder = new BorderBuilder(); // makeBorder.Precision = clusterSize; // while ((goon = ExtractCurve(LastPoint.curve,!LastPoint.isStartPoint))!=null) // { // makeBorder.AddSegment(LastPoint.curve.CloneReverse(!LastPoint.isStartPoint)); // if (goon.Points.Count==0) break; // auf den letzten und ersten Punkt gestoßen // LastPoint = (Joint)goon.Points[0]; // es sollte ja nur diesen einen geben // RemoveJoint(LastPoint,goon); // damit müsste dieser Cluster verschwinden // } // return makeBorder.BuildBorder(); // } // private bool FindSimpleBorder(Set clusterSet, ArrayList AllBorders, Set UsedJoints, ICurve2D startWith, bool forward) // { // Set tmpUsedJoints = new Set(); // tmpUsedJoints.Add(new UsedJoint(startWith,forward)); // // Anfangskante gefunden, wie gehts weiter // BorderBuilder bb = new BorderBuilder(); // bb.Precision = clusterSize; // if (forward) bb.AddSegment(startWith.Clone()); // else bb.AddSegment(startWith.CloneReverse(true)); // // while (!bb.IsClosed) // { // Cluster cl = FindCluster(startWith, bb.EndPoint, false); // if (cl==null) return false; // eine angefangene Border geht nicht weiter, sollte nicht passieren, da keine Sackgassen // int ind = -1; // double sa = -1.0; // for (int i=0; i<cl.Points.Count; ++i) // { // Joint j = cl.Points[i] as Joint; // if (j.curve==startWith) continue; // nicht auf der Stelle rückwärts weiter // UsedJoint uj = new UsedJoint(j.curve,j.isStartPoint); // if (!UsedJoints.Contains(uj) && !tmpUsedJoints.Contains(uj)) // { // SweepAngle d; // if (j.isStartPoint) d = new SweepAngle(bb.EndDirection,j.curve.StartDirection); // else d = new SweepAngle(bb.EndDirection,j.curve.EndDirection.Opposite()); // // d zwischen -PI und +PI // if (d+Math.PI > sa) // { // je mehr nach links umso größer is d // sa = d+Math.PI; // ind = i; // } // } // } // if (ind>=0) // { // Joint j = cl.Points[ind] as Joint; // if (j.isStartPoint) bb.AddSegment(j.curve.Clone()); // else bb.AddSegment(j.curve.CloneReverse(true)); // tmpUsedJoints.Add(new UsedJoint(j.curve,j.isStartPoint)); // startWith = j.curve; // } // else // { // return false; // kein weitergehen möglich // } // } // if (bb.IsOriented) // { // Border bdr = bb.BuildBorder(); // AllBorders.Add(bdr); // foreach (UsedJoint uj in tmpUsedJoints) // { // if (!UsedJoints.Contains(uj)) // { // UsedJoints.Add(uj); // } // else // { // int dbg = 0; // } // } // return true; // } // return false; // } // private bool FindSimpleBorder(Set clusterSet, ArrayList AllBorders, Set UsedJoints) // { // // es wird eine minimale Border gesucht: von irgend einem Cluster ausgehend immer // // linksrum bis man wieder am Anfang ist. // // UsedJoints enthält UsedJoint objekte, damit man feststellen kann, ob eine Kante bereits // // benutzt ist oder nicht // ICurve2D startWith = null; // bool forward = false; // foreach (Cluster cl in clusterSet) // { // for (int i=0; i<cl.Points.Count; ++i) // { // UsedJoint uj = new UsedJoint(); // Joint j = cl.Points[i] as Joint; // uj.curve = j.curve; // uj.forward = true; // if (!UsedJoints.Contains(uj)) // { // forward = j.isStartPoint; // startWith = j.curve; // if (FindSimpleBorder(clusterSet,AllBorders,UsedJoints,startWith,forward)) // return true; // } // uj.forward = false; // if (!UsedJoints.Contains(uj)) // { // forward = !j.isStartPoint; // startWith = j.curve; // if (FindSimpleBorder(clusterSet,AllBorders,UsedJoints,startWith,forward)) // return true; // } // } // } // return false; // } private Joint[] SortCluster() { // sortiert die Kanten (Joints) in einem Cluster im Gegenuhrzeigersinn // liefert alle Kanten // Verwerfen von identischen Kanten: // Zwei Kanten in einem Cluster, die das selbe "Gegencluster" haben // stehen im Verdacht identisch zu sein. Ihre Mittelpunkte werden auf // identität überprüft und die Kanten werden ggf. entfernt. foreach (Cluster cl in clusterSet) { for (int i = 0; i < cl.Joints.Count - 1; ++i) { int duplicate = -1; for (int j = i + 1; j < cl.Joints.Count; ++j) { Cluster cl1; Cluster cl2; Joint j1 = cl.Joints[i] as Joint; Joint j2 = cl.Joints[j] as Joint; if (j1.StartCluster == cl) { cl1 = j1.EndCluster; } else { cl1 = j1.StartCluster; } if (j2.StartCluster == cl) { cl2 = j2.EndCluster; } else { cl2 = j2.StartCluster; } if (cl1 == cl2) { // zwei Kanten verbinden dieselben Cluster. Sie könnten identisch sein ICurve2D curve1 = j1.curve.CloneReverse(j1.StartCluster != cl); ICurve2D curve2 = j2.curve.CloneReverse(j2.StartCluster != cl); // curve1 und curve2 haben jetzt die selbe Richtung GeoPoint2D p1 = curve1.PointAt(0.5); GeoPoint2D p2 = curve2.PointAt(0.5); if (Geometry.Dist(p1, p2) < clusterSize) { duplicate = j; break; } } } if (duplicate > 0) { cl.Joints.RemoveAt(duplicate); } } } // zu kurze Joints werden entfern foreach (Cluster cl in clusterSet) { for (int i = cl.Joints.Count - 1; i >= 0; --i) { Joint j1 = cl.Joints[i] as Joint; if (j1.curve.Length < this.clusterSize) { cl.Joints.RemoveAt(i); } } } UntypedSet allJoints = new UntypedSet(); foreach (Cluster cl in clusterSet) { if (cl.Joints.Count < 3) { foreach (Joint j in cl.Joints) { if (!allJoints.Contains(j)) { allJoints.Add(j); } } continue; } // zwei Punkte im cluster muss man nicht sortieren double minDist = double.MaxValue; foreach (Joint j in cl.Joints) { if (!allJoints.Contains(j)) { allJoints.Add(j); } GeoPoint2D p; if (j.StartCluster == cl) { p = j.EndCluster.center; } else { if (j.EndCluster != cl) { throw new CurveGraphException("SortCluster"); } p = j.StartCluster.center; } double d = Geometry.Dist(cl.center, p); if (d == 0.0) { if (j.StartCluster == j.EndCluster) { continue; } throw new CurveGraphException("SortCluster"); } if (d < minDist) { minDist = d; } } // Kreis um cl mit halber Entfernung zum nächsten Knoten als Radius Circle2D c2d = new Circle2D(cl.center, minDist / 2.0); foreach (Joint j in cl.Joints) { GeoPoint2DWithParameter[] ip = c2d.Intersect(j.curve); if (ip.Length > 0) { for (int i = 0; i < ip.Length; ++i) { if (j.curve.IsParameterOnCurve(ip[i].par2)) { Angle a = new Angle(ip[i].p, cl.center); j.tmpAngle = a.Radian; break; } } } else { // darf nicht vorkommen, eine Kante schneidet nicht den Kreis um // den Knoten mit halbem Radius zum nächsten knoten // der Sortierwert bleibt halt 0.0, aber man sollte solche Kanten // entfernen ... // kommt vor, das Problem liegt bei regle4!!! if (j.StartCluster == cl) { // curve startet hier j.tmpAngle = j.curve.StartDirection.Angle; } else { j.tmpAngle = j.curve.EndDirection.Opposite().Angle; } } } cl.Joints.Sort(); // es wird nach tmpAngle sortiert } Joint[] res = new Joint[allJoints.Count]; int ii = 0; foreach (Joint j in allJoints) { // die Kurve exakt ausrichten try { j.curve.StartPoint = j.StartCluster.center; j.curve.EndPoint = j.EndCluster.center; } catch (Curve2DException) { } // z.B. Kreise endpunkt setzen res[ii] = j; ++ii; } return(res); }