private void BehaelterAnnaehern(TBehaelter B1, TBehaelter B2) { const double Distanz = 1000; const double StrahlLaenge = 10 * Distanz; Vector B2Verschub = new Vector((B1.TempPos.X + Distanz) - B2.TempPos.X, 0 - B2.TempPos.Y); B2.Verschieben(B2Verschub); List <Vector> Results1 = new List <Vector>(); foreach (TDreieck D1 in B1.Dreiecke) { Point[] Eckpunkte = new Point[] { D1.A, D1.B, D1.C }; foreach (Point Eckpunkt in Eckpunkte) { foreach (TDreieck D2 in B2.Dreiecke) { Point B = Eckpunkt + new Vector(StrahlLaenge, 0); DreieckKollision(Eckpunkt, B, D2.A, D2.B, ref Results1); DreieckKollision(Eckpunkt, B, D2.B, D2.C, ref Results1); DreieckKollision(Eckpunkt, B, D2.C, D2.A, ref Results1); } } } List <Vector> Results2 = new List <Vector>(); foreach (TDreieck D2 in B2.Dreiecke) { Point[] Eckpunkte = new Point[] { D2.A, D2.B, D2.C }; foreach (Point Eckpunkt in Eckpunkte) { foreach (TDreieck D1 in B1.Dreiecke) { Point B = Eckpunkt + new Vector(-StrahlLaenge, 0); DreieckKollision(Eckpunkt, B, D1.A, D1.B, ref Results2); DreieckKollision(Eckpunkt, B, D1.B, D1.C, ref Results2); DreieckKollision(Eckpunkt, B, D1.C, D1.A, ref Results2); } } } List <double> Distanzen1 = new List <double>(); foreach (Vector V in Results1) { Distanzen1.Add(V.Y * StrahlLaenge); } foreach (Vector V in Results2) { Distanzen1.Add(V.Y * StrahlLaenge); } double KleinsteDistanz = double.PositiveInfinity; foreach (double D in Distanzen1) { if (D < KleinsteDistanz) { KleinsteDistanz = D; } } B2.Verschieben(new Vector(-KleinsteDistanz, 0)); }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ private void Berechnen() { // Alle Dreiecke in Liste zuordnen & Behaelterliste erstellen List <TDreieck> DreieckeUnzugeteilt = Dreiecke.ToList(); List <TBehaelter> _Behaelter = new List <TBehaelter>(); // Dreiecke nach KLEINSTER Kante ordnen | Worst Case: O(N)=N² Operation DreieckeUnzugeteilt = OrdneNachKleinsterStrecke(DreieckeUnzugeteilt); // Gesamtwinkel bestimmen double GesamtWinkel = 0.0; foreach (TDreieck D in DreieckeUnzugeteilt) { GesamtWinkel += D.WA; } // Handeln nach Gesamtwinkel if (GesamtWinkel < 180.0) { // 1 Behaelter ausreichend TBehaelter B = new TBehaelter(); B.BehaelterTyp = TBehaelter.TBehaelterTyp.Startbehaelter; _Behaelter.Add(B); while (DreieckeUnzugeteilt.Count > 0) { TDreieck D = DreieckeUnzugeteilt[DreieckeUnzugeteilt.Count - 1]; _Behaelter[0].DreieckHinzufügen(D); DreieckeUnzugeteilt.RemoveAt(DreieckeUnzugeteilt.Count - 1); } } else { // 2 oder mehr Behaelter notwendig? if (BerechnenMittelbehaelterNoetig(Dreiecke.ToList())) { // Start-, Mittel- und Endbehälter TBehaelter BStart = new TBehaelter(); TBehaelter BEnde = new TBehaelter(); BStart.BehaelterTyp = TBehaelter.TBehaelterTyp.Startbehaelter; BEnde.BehaelterTyp = TBehaelter.TBehaelterTyp.Endbehaelter; _Behaelter.Add(BStart); _Behaelter.Add(BEnde); // Mittelbehälterzahl (ungefähr - im worst case sind es mehr) int BehaelterZahlMindestens = (int)Math.Ceiling(GesamtWinkel / 180.0); int MittelbehaelterZahlMindestens = BehaelterZahlMindestens - 2; if (MittelbehaelterZahlMindestens > 0) { for (int I = 0; I < MittelbehaelterZahlMindestens; I++) { TBehaelter BMittel = new TBehaelter(); BMittel.BehaelterTyp = TBehaelter.TBehaelterTyp.Mittelbehaelter; _Behaelter.Insert(1, BMittel); } } // Abwechselnd Start- und Endbehälter auf 90° auffüllen (Dreiecke mit größter Strecke zuerst) bool InStartcontainer = true; double WinkelStart = 0.0; double WinkelEnd = 0.0; while ((WinkelStart < 90.0) && (WinkelEnd < 90.0) && DreieckeUnzugeteilt.Count > 0) { TDreieck D = DreieckeUnzugeteilt[DreieckeUnzugeteilt.Count - 1]; if (InStartcontainer) { WinkelStart += D.WA; if (WinkelStart > 90.0) { continue; } BStart.DreieckHinzufügen(D); } else { WinkelEnd += D.WA; if (WinkelEnd > 90.0) { continue; } BEnde.DreieckHinzufügen(D); } DreieckeUnzugeteilt.RemoveAt(DreieckeUnzugeteilt.Count - 1); // Flag umkehren InStartcontainer = !InStartcontainer; } // Temporären Winkel setzen foreach (TBehaelter B in _Behaelter) { B.TempWinkel = 0.0; } // Start- und Endbehälter sind bereits teilweise gefüllt BStart.TempWinkel = BStart.GefuellterWinkel(); BEnde.TempWinkel = BEnde.GefuellterWinkel(); // Restliche Dreiecke auch unter Mittelbehältern zuteilen int Index = 0; int Fehlzaehler = 0; while (DreieckeUnzugeteilt.Count > 0) { TBehaelter B = _Behaelter[Index]; TDreieck D = DreieckeUnzugeteilt[DreieckeUnzugeteilt.Count - 1]; // Dreieck hinzufügen wenn noch Platz ist B.TempWinkel += D.WA; if (B.TempWinkel < 180.0) { // Dreieck hinzufügen B.DreieckHinzufügen(D); DreieckeUnzugeteilt.RemoveAt(DreieckeUnzugeteilt.Count - 1); Fehlzaehler = 0; } else { Fehlzaehler++; } // Falls die Behälter nicht ausreichen wird ein neuer hinzugefügt if (Fehlzaehler >= _Behaelter.Count) { TBehaelter BNeu = new TBehaelter(); BNeu.BehaelterTyp = TBehaelter.TBehaelterTyp.Mittelbehaelter; BNeu.TempWinkel = 0; _Behaelter.Insert(1, BNeu); } // Nächste Iteration Index++; if (Index >= _Behaelter.Count) { Index = 0; } } } else { // Start- und Endbehälter TBehaelter BStart = new TBehaelter(); TBehaelter BEnde = new TBehaelter(); BStart.BehaelterTyp = TBehaelter.TBehaelterTyp.Startbehaelter; BEnde.BehaelterTyp = TBehaelter.TBehaelterTyp.Endbehaelter; _Behaelter.Add(BStart); _Behaelter.Add(BEnde); // Abwechselnd Dreiecke zu Start- und Endbehälter hinzufügen (Dreiecke mit größter Strecke zuerst) bool InStartcontainer = true; while (DreieckeUnzugeteilt.Count > 0) { TDreieck D = DreieckeUnzugeteilt[DreieckeUnzugeteilt.Count - 1]; if (InStartcontainer) { BStart.DreieckHinzufügen(D); } else { BEnde.DreieckHinzufügen(D); } DreieckeUnzugeteilt.RemoveAt(DreieckeUnzugeteilt.Count - 1); // Flag umkehren InStartcontainer = !InStartcontainer; } } } // Dreiecke in allen Behältern korrekt orientieren foreach (TBehaelter B in _Behaelter) { B.DreieckeAnordnen(); } TBehaelter[] BesteAnordnung; double BesteStrecke; if (_Behaelter.Count > 3) // Ab 3 sind Permuatation möglich (2 Behälter werden abgezogen) { // Permuatationen ohne Start- und Endbehälter List <TBehaelter> PermuatationsBehaelter = new List <TBehaelter>(_Behaelter); PermuatationsBehaelter.RemoveAt(0); PermuatationsBehaelter.RemoveAt(PermuatationsBehaelter.Count - 1); // Alle möglichen Kombinationen bestimmen var PermutationenRoh = BehaelterPermutationen(PermuatationsBehaelter, PermuatationsBehaelter.Count).ToArray(); List <TBehaelter[]> Permutationen = new List <TBehaelter[]>(); double[] Ergebnisse = new double[PermutationenRoh.Length]; for (int I = 0; I < PermutationenRoh.Length; I++) { List <TBehaelter> PermutationenUnvollstaendig = PermutationenRoh[I].ToList(); PermutationenUnvollstaendig.Insert(0, _Behaelter[0]); PermutationenUnvollstaendig.Add(_Behaelter[_Behaelter.Count - 1]); TBehaelter[] PermutationenVollstaendig = PermutationenUnvollstaendig.ToArray(); Permutationen.Add(PermutationenVollstaendig); TBerechnung Berechnung = new TBerechnung(PermutationenVollstaendig); Ergebnisse[I] = Berechnung.Berechnen(); } int BestePermuatationIndex = -1; for (int I = 0; I < Ergebnisse.Length; I++) { if (BestePermuatationIndex == -1 || Ergebnisse[I] < Ergebnisse[BestePermuatationIndex]) { BestePermuatationIndex = I; } } // Beste Permutation anzeigen TBehaelter[] BestePermutation = Permutationen[BestePermuatationIndex].ToArray(); BestePermutation[0].Verschieben(new Vector(-(BestePermutation[0].TempPos.X - 200), 0)); TBerechnung BerechnungBeste = new TBerechnung(BestePermutation); BerechnungBeste.Berechnen(); BesteAnordnung = BestePermutation; BesteStrecke = Ergebnisse[BestePermuatationIndex]; } else { TBerechnung Berechnung = new TBerechnung(_Behaelter.ToArray()); BesteStrecke = Berechnung.Berechnen(); BesteAnordnung = _Behaelter.ToArray(); } // Ausgabe StatusBarItemInfo.Content = "Distanz: " + (int)Math.Round(BesteStrecke) + "m"; // Behälter setzen & Zeichnen Behaelter = _Behaelter; Zeichne(); }