예제 #1
0
        public CurveGraph(ICurve2D[] curves, double maxGap)
        {   // aus den ICurve2D wird eine Clusterliste erzeugt (Start- und Endpunkte)
            this.maxGap = maxGap;
            BoundingRect ext = BoundingRect.EmptyBoundingRect;

            for (int i = 0; i < curves.Length; ++i)
            {
                ext.MinMax(curves[i].GetExtent());
            }
            // clusterSize = (ext.Width + ext.Height) * 1e-8;
            clusterSize            = maxGap;
            clusterTree            = new QuadTree(ext);
            clusterTree.MaxDeepth  = 8;
            clusterTree.MaxListLen = 3;
            clusterSet             = new UntypedSet();
            for (int i = 0; i < curves.Length; ++i)
            {
                if (curves[i].Length > clusterSize)
                {
                    Insert(curves[i]);
                }
            }
        }
예제 #2
0
        //		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);
        }