Methoden Methoden anpassen und fehlende Funktionen hinzufügen

Frage: liegt Punkt C auf der Strecke AB?

Annahme: C != A und C != B.

Vektoren: a = OA (Ortsvektor von A), v = AB (Vektor), c = OC.

Dann gilt a+r*v = c für ein Skalar r. Also a.x+r*v.x = c.x und a.y+r*v.y = c.y

Falls v.x = 0: r = (c.y-a.y)/v.x; es muss gelten: 0 <= r < 1 und a.x = c.x
Falls v.y = 0: r = (c.x-a.x)/v.x; es muss gelten: 0 <= r < 1 und a.y = c.y

Da wir ganzzahlig unterwegs sind:
Falls a.x == b.x und a.x == c.x und (c.y-a.y)/(b.y-a.y) == 0
oder a.y == b.y und a.y == c.y und (c.x-a.x)/(b.x-a.x) == 0

EDIT: Ende stimmt nicht ganz, hier fehlt noch die Prüfung auf das Vorzeichen.
 
OK, ich habe jetzt die Methode fertig und sie funktioniert auch. Wenn ich allerdings den Zug auf einen Knoten setze, wird null ausgegeben, da noch nicht klar ist auf welchem Track der Zug steht. Hier muss jetzt irgendwie noch die Länge berücksichtigt werden. Jeder Zug hat Länge >= 1 und es kann daher eindeutig gesagt werden, auf welchem Track / Tracks er sich befindet. Ist der Zug länger als das Gleis auf dem der Zugkopf steht, kann er natürlich auch auf zwei oder mehr Gleisen stehen. Momentan gebe ich in der findTrack Methode eine Track zurück, aber falls es sich um eine Switch handelt, kann daraus gar nicht geschlossen werden um welche Switch es sich handelt, oder?
 
Die größere Frage ist hier doch eigentlich wie man bewerkstelligt, dass mittels der Zuglänge herausgefunden wird, ob sich der Zug auf mehreren Gleisen befindet. Denn vor dem gleichen Problem stehe ich auch, weil ich nur an die Kante rankomme auf dem sich der Zugkopf befindet...
 
Momentan gebe ich in der findTrack Methode eine Track zurück, aber falls es sich um eine Switch handelt, kann daraus gar nicht geschlossen werden um welche Switch es sich handelt, oder?
Vorab: ich gehe davon aus, dass die Methode findTack() bereits Switches richtig behandelt. D. h. es wird nur der Track zurückgegeben, der auch befahrbar ist.

Zur Frage: mach es Dir nicht so kompliziert und lass den Track die Arbeit machen. Es braucht Dich nicht zu interessieren, ob es ein Switch ist oder nicht. Es gibt doch letztlich zwei Fragen:
1. wenn ich an Punkt p bin und in Richtung r fahre, von welchem Endpunkt aus bin ich auf dem Track gestartet?
2. wie groß ist die Entfernung auf dem Track zwischen p und diesem Endpunkt?
Beide Fragen kann der Track beantworten.

Bei @Mika34 kann das Edge übernehmen.
 
ich gehe davon aus, dass die Methode findTack() bereits Switches richtig behandelt. D. h. es wird nur der Track zurückgegeben, der auch befahrbar ist.
Wie soll ich das implementieren? Dann kann der Rückgabewert ja nicht Track sein, oder?
Java:
    private Track findTrack(Point point) {
        for (Track track : tracks.values()) {
            if (inTrack(point, track)) {
                return track;
            }
        }
        return null;
    }
Außerdem ist mir noch nicht ganz klar wie das mit dem Richtungsvektor funktionieren soll. Dieser muss wahrscheinlich erst normiert werden, oder?
 
@mihe7 Inwiefern kann das Edge übernehmen? Denn Edge modelliert doch nur die Strecke zwischen zwei Punkten und hat dabei keinerlei Aufschluss auf die nächste verbundene Kante, außer das der Endpunkt der vorherigen Kante der Startpunkt der jetzigen Kante ist
 
Wie soll ich das implementieren? Dann kann der Rückgabewert ja nicht Track sein, oder?
Es geht nur um die Prüfung, ob der Punkt auf dem Track liegt. Die gezeigte Implementierung von Dir ist vollkommen ok, nur dass inTrack() eine Methode von Track sein sollte (also statt inTrack(point, track) einfach track.contains(point)).

Es muss Dich an der Stelle nicht interessieren, wie der Track aussieht. Stell Dir vor, Du bekommst morgen die Anforderung, dass die Tracks nicht mehr horizontal/vertikal sein müssen. Jetzt musst Du anfangen, Track zu ändern und dann überall suchen, wo davon ausgegangen wurde, dass der Track nur horizontal/vertikal sein darf.

EDIT: der Methodenname contains ist etwas irreführend. Es geht darum, ob der Track an der Stelle befahrbar ist.
 
Also muss der Rückgabewert nicht mal Track, sondern boolean sein...? Oder soll nur eine Track zurückgegeben werden, wenn sie befahrbar ist, also switchedTo auf dieses Gleis eingestellt ist?
 
Ja, wie Dein inTrack halt auch. Die findTrack-Methode muss natürlich Track zurückgeben.

Die Methode dürfte in Track etwa so aussehen (Fehler nicht ausgeschlossen):
Java:
public boolean canNavigateTo(Point p) {
    if (switchedTo == null) { return false; }
    Point p1 = getStartPoint();
    Point p2 = switchedTo;
    if (p1.equals(p) || p2.equals(p)) { return true; }

    return p1.x == p.x && p.x == p2.x && (p.y-p1.y)/(p2.y-p1.y) == 0 && (p2.y-p1.y)/(p.y-p1.y) > 0 ||
        p1.y == p.y && p.y == p2.y && (p.x-p1.x)/(p2.x-p1.x) == 0 && (p2.x-p1.x)/(p.x-p1.x) > 0;
}

Und findTrack in RailNetwork (oder wo auch immer die Tracks verwaltet werden):
Java:
    private Track findTrack(Point point) {
        for (Track track : tracks.values()) {
            if (track.canNavigateTo(point)) {
                return track;
            }
        }
        return null;
    }
 
In diesem Schritt wird dann der Punkt gesucht, falls dieser auf dem Netz liegt dann wird der Track zurückgegeben auf dem sich der Zugkopf befindet und falls dies nicht der Fall ist, dann wird null zurückgegeben, oder?
 
Ja, wobei durch die Prüfung in canNavigateTo sichergestellt ist, dass nur die befahrbare Strecke der Weiche berücksichtigt wird.
 
@mihe7 Inwiefern kann das Edge übernehmen? Denn Edge modelliert doch nur die Strecke zwischen zwei Punkten und hat dabei keinerlei Aufschluss auf die nächste verbundene Kante, außer das der Endpunkt der vorherigen Kante der Startpunkt der jetzigen Kante ist
Das reicht ja.

wenn ich an Punkt p bin und in Richtung r fahre, von welchem Endpunkt aus bin ich auf dem Track gestartet?
Bei Edge ist das sehr einfach, weil es immer nur zwei Endpunkte gibt.

wie groß ist die Entfernung auf dem Track zwischen p und diesem Endpunkt?
Auch das kann Edge beantworten. Es ist einfach der Abstand zwischen zwei gegebenen Punkten auf der Kante.
 
Die Methode dürfte in Track etwa so aussehen (Fehler nicht ausgeschlossen):
Java:
public boolean canNavigateTo(Point p) {
if (switchedTo == null) { return false; }
Point p1 = getStartPoint();
Point p2 = switchedTo;
if (p1.equals(p) || p2.equals(p)) { return true; }

return p1.x == p.x && p.x == p2.x && (p.y-p1.y)/(p2.y-p1.y) == 0 && (p2.y-p1.y)/(p.y-p1.y) > 0 ||
p1.y == p.y && p.y == p2.y && (p.x-p1.x)/(p2.x-p1.x) == 0 && (p2.x-p1.x)/(p.x-p1.x) > 0;
}
Danke, so ähnlich habe ich es im Prinzip auch gehabt. Durch ein paar kleine Änderungen funktioniert die Funktion jetzt auch tadellos.

Java:
    public void putTrain(Train train, Point point, Point directionVector) {
        ...
        if (!findTrack(point).isPresent()) {
            throw new ...("point " + point + " is not passable");
        }
        long trainLength = train.getLength();
    }

Wie geht es jetzt weiter? Sollte ich mich jetzt an den Richtungsvektor wagen und falls ja, muss er normiert werden, oder wie funktioniert das am besten?

EDIT: Wie speichere ich die aufgegleisten Züge am besten (Map<Point, Train> (?))? Es muss ja geschaut werden, ob auf den Gleisen bereits ein anderer Zug steht.
 
Zuletzt bearbeitet:
Speichert man im Track, dann das Objekt Zug ab oder wie soll das gemacht werden?
Ja.

Denn es kann durchaus sein, das der Zug auf mehreren Gleisen steht und daher mehrere Gleise dann mit dem gleichen Zug belegt werden
Ja.

Gespeichert werden ja nicht die Objekte selbst, sondern nur Referenzen darauf. Es ist also nicht so, dass da Kopien des Zugs gespeichert würden, sondern alle Tracks, auf denen der Zug steht, würden dann auf das selbe(!) Objekt verweisen.
 
OK, das ist natürlich sinnvoll!
Java:
        Track track = findTrack(point).get();
        if (track.getCurrentTrain() != null) {
            // Throw exception
        }
        track.setCurrentTrain(train);
Allerdings ist mir unklar, wie ich die Länge und den Richtungsvektor jetzt noch einbringen soll.
 
Allerdings ist mir unklar, wie ich die Länge jetzt noch einbringen soll.
Weil, Du auch hin und her springst. Wir waren ja noch nicht fertig.

Track muss noch zwei Dinge beantworten:

1. wenn ich an Punkt p bin und in Richtung r fahre, von welchem Endpunkt aus bin ich auf dem Track gestartet?
2. wie groß ist die Entfernung auf dem Track zwischen p und diesem Endpunkt?
Beide Fragen kann der Track beantworten.

Normieren in Point:
Java:
public Point toDirection() {
    return new Point((int)Math.signum(x), (int)Math.signum(y));
}
 
Mir ist noch nicht ganz klar, wie das mit dieser Modellierung funktionieren soll, da ein Zug auf mehreren Gleisen stehen kann. Wie soll ich den Verlauf des Zuges zurückverfolgen, um den hintersten Punkt zu bekommen? Ich habe die Länge, aber es geht ja nicht nur in die entgegengesetzte Richtung des Vektors, sondern es kann durch Weichen auch in ganz andere Richtungen gehen.
 
Ich habe die Länge, aber es geht ja nicht nur in die entgegengesetzte Richtung des Vektors, sondern es kann durch Weichen auch in ganz andere Richtungen gehen.
Die Weiche hat ja eine Stellung. Die kann sich schlecht ändern, wenn der Zug auf ihr steht.

Bezogen auf einen Track kann der Zug nur aus zwei Richtungen kommen: getStartPoint() oder switchedTo. Das lässt sich anhand des Richtungsvektors feststellen.

Wie soll ich den Verlauf des Zuges zurückverfolgen, um den hintersten Punkt zu bekommen?
Genau damit, dass Dir der Track sagt, welche Haltestelle der Zug zuletzt passiert haben muss. Über diesen Punkt kann das RailNetwork den anliegenden Track ermitteln, der Dir wieder sagen kann, welche Haltestelle der Zug zuletzt passiert haben muss usw. Das machst Du so lange, bis die Länge des Zugs erreicht wurde und schon hast Du alle Tracks, auf denen der Zug stehen muss.
 
Ja.


Ja.

Gespeichert werden ja nicht die Objekte selbst, sondern nur Referenzen darauf. Es ist also nicht so, dass da Kopien des Zugs gespeichert würden, sondern alle Tracks, auf denen der Zug steht, würden dann auf das selbe(!) Objekt verweisen.
Auf welche Weise lässt sich das dann implementieren?
Macht man dann eine Methode wie isTrainOnTrack oder passiert das erst beim Auflgeisen?
 
OK, das ist natürlich sinnvoll!
Java:
        Track track = findTrack(point).get();
        if (track.getCurrentTrain() != null) {
            // Throw exception
        }
        track.setCurrentTrain(train);
Allerdings ist mir unklar, wie ich die Länge und den Richtungsvektor jetzt noch einbringen soll.
Denn hier wird erneut nur auf das Gleis, auf welchem sich der Kopf des Zuges befindet mit der Referenz vom Zug bestückt und nicht die anderen Gleise, auf welchen sich der Zug potentiell befinden kann
 
Denn hier wird erneut nur auf das Gleis, auf welchem sich der Kopf des Zuges befindet mit der Referenz vom Zug bestückt und nicht die anderen Gleise, auf welchen sich der Zug potentiell befinden kann
Ah, jetzt verstehe ich die Frage. Das ist an der Stelle auch noch nicht richtig und kommt daher, weil Dagobert schon beim Aufgleisen war, obwohl der entscheidende Punkt noch nicht gelöst wurde 🙂

Wenn Du #76 anschaust, siehst Du, dass man eine Reihe von Tracks erhält. Auf die muss man dann aufgleisen. Auch ist das erstmal nur ein naiver Ansatz, ob es dabei bleibt, muss man sehen.
 
Jetzt habe ich es glaube ich geblickt. Es geht darum, ähnlich wie bei dem Entfernen von Gleisen, sich ein Set (beispielsweise kann auch eine Liste sein) von Tracks zurückgeben zu lassen, welche allesamt den gleichen Zug als Referenz gespeichert haben.
Ich hoffe ich täusche mich in dieser Annahme nicht
 
Jein, es geht zunächst nur darum, sich ein Set von Tracks geben zu lassen, auf dem der Zug stehen müsste.

Wenn kein Track eine Referenz auf einen Zug besitzt (sprich: alle Tracks sind frei), dann können alle Tracks aus dem Set die Referenz auf den Zug speichern.
 
Muss die Methode findTrack() also eine Liste von Tracks zurückgeben?
Nein. die Aufgabe von findTrack besteht einfach nur darin, den Track zu liefern, der den gegebenen Punkt enthält, sofern zu diesem überhaupt gefahren werden kann.

Damit wird ein Teil von
Java:
    /*
    TODO:
         - Check if there is even a track at the point <point>.
         - If it is a switch at point <point> then check if it's switched to this track.
         - Check if no other train is already on the required track(s) - note the length of the train
         - Check if directionVector fits with direction of track
    */
    public void putTrain(Train train, Point point, Point directionVector) throws LogicException {
        ...
        long trainLength = train.getLength();

    }

gelöst. Konkret die ersten beiden Punkte.

Als nächstes brauchst Du die "required track(s)". Den Starttrack hast Du schon mit findTrack gefunden. Du kannst also eine Methode schreiben, die Dir die requiredTracks() liefert - ausgehend vom Strarttrack, der Startposition des Zugs und des Richtungsvektors. (edit: und natürlich der Zuglänge).
 
required track(s) ist somit der Platzbedarf (gemessen in Tracks, welche benötigt werden um den Zug aufzugleisen) des einzelnen Zugs, welcher auf den Gleisen aufliegt.
Aber inwiefern erlange ich die Kenntnis wie viele Tracks denn gebraucht werden.
Ich kenne die Länge des gesamten Zugs und die Länge jedes Gleises und die genaue Länge von dem Gleis auf, welchem der Zugkopf aufliegt.
Daran scheitert es bei mir gerade noch sehr stark
 
required track(s) ist somit der Platzbedarf (gemessen in Tracks, welche benötigt werden um den Zug aufzugleisen) des einzelnen Zugs, welcher auf den Gleisen aufliegt.
Ja. Aber nicht die Anzahl sondern die Menge der Tracks.

Ich kenne die Länge des gesamten Zugs und die Länge jedes Gleises und die genaue Länge von dem Gleis auf, welchem der Zugkopf aufliegt.
Eben. Nehmen wir mal an, der Kopf des Zuges würde genau an einem Gleisende stehen, das betreffende Gleis befindet sich bereits in der Liste und len gäbe die noch auf den Gleisen unterzubringende Länge des Zugs an - anfangs also die komplette Länge des Zugs.

Dann gibt es zwei Möglichkeiten:
  1. der Zug passt auf das Gleis. Dann bist Du fertig und die Liste enthält die Gleise.
  2. der Zug passt nicht auf das Gleis. Dann ziehst Du von len die Gleislänge ab und arbeitest mit dem nächsten Gleis weiter. Gibt es keines oder befindet sich dieses bereits in der Liste -> Exception.
Den Spaß wiederholst Du, bis Du fertig bist (s. 1)
 
Könntest du den Vorgang beispielsweise durch Pseudo-Code etwas verdeutlichen?
Pseudocode:
Java:
Track currentTrack = startTrack;
Point pos = startPosition;
List<Track> required = new ArrayList<>();
while (len > 0) {
    if (currentTrack == null || required.contains(currentTrack)) {
        // Zug kann nicht positioniert werden
        throw new ...
    }
    required.add(currentTrack);
    Point passed = currentTrack.getPassedPoint(direction);
    len -= currentTrack.distance(pos, passed);
    pos = passed;
    currentTrack = getConnection(passed, currentTrack);
}
 
Ok, somit kann ich dann innerhalb der Methode mit einem getter auf die Länge der Tracks zugreifen.
Nun ist dann da das Problem wie man geschickt an die requiredTracks drankommt. Mir fällt dazu nichts ein, da man ja nur, wie oben erwähnt "die Länge des gesamten Zugs und die Länge jedes Gleises und die genaue Länge von dem Gleis auf, welchem der Zugkopf aufliegt." und somit nur den Zugkopf direkt in Relation mit einem track stellen kann und der Rest des Zuges dabei unberücksichtigt bleibt.
 
getPassedPoint() s. #57 Punkt 1.
getConnection(point, track): liefert das Anschlussgleis von track, an Punkt point. Hier kannst Du die Map tracks verwenden.
 
und somit nur den Zugkopf direkt in Relation mit einem track stellen kann und der Rest des Zuges dabei unberücksichtigt bleibt.
Ich weiß jetzt nicht, ob Du #88 gesehen hast, verstehe aber Dein Problem nicht:

Code:
V----------Z-----------------H
|          |                 |
|<-------->|<--------------->|
  Länge VZ     Länge ZH

Wenn Zug Z irgendwo steht und du weißt, dass er aus Richtung H gekommen ist, kannst Du doch ZH berechnen und weißt, wie viel vom Zug auf diesem Abschnitt höchstens stehen kann.
 
Ich weiß jetzt nicht, ob Du #88 gesehen hast, verstehe aber Dein Problem nicht:

Code:
V----------Z-----------------H
|          |                 |
|<-------->|<--------------->|
  Länge VZ     Länge ZH

Wenn Zug Z irgendwo steht und du weißt, dass er aus Richtung H gekommen ist, kannst Du doch ZH berechnen und weißt, wie viel vom Zug auf diesem Abschnitt höchstens stehen kann.
Ja, man hat dann die Restlänge von dem Zug, aber das gibt mir ja trotzdem keine Auskunft darüber auf welchen er letztendlich stehen tut. Es sagt mir die Länge VZ/VH befindet sich momentan auf einem anderen Zug in die entgegengesetzte Richtung vom Richtungsvektor.
long story short: Wie prüfe ich, auf welchen Gleisen er genau stehen tut, wenn du wie oben erklärt hast man die Länge vom "Restzug" schon hat
 
Sicher, ob dies der richtige Ansatz ist, weiß ich nicht.

Java:
    private Track getConnection(Point point, Track track) {
        return edges.get(point).stream().filter(...);
    }

Könntest du mir behilflich sein?
 
So in der Art müsste es doch klappen, oder?

Java:
    private Track getConnection(Point point, Track track) {
        return edges.get(point).stream().filter(x -> x.getSwitchedTo() != null);
    }

Leider bin ich noch nicht sehr vertraut mit der Stream API. Daher weiß ich nicht so recht, was an dem Ausdruck noch nicht stimmt.
 
Vergiss mal die Streams. Die Frage ist, was Du da überhaupt filterst. An einem Punkt laufen max. 2 Tracks zusammen. Der Anschlusstrack kann ja nur der von track verschiedene sein, sofern es ein solches überhaupt gibt.
 

Zurück
Oben