-
-
Notifications
You must be signed in to change notification settings - Fork 10
Sim tooltips and double slip switches #195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 185-model-railway-simulator
Are you sure you want to change the base?
Sim tooltips and double slip switches #195
Conversation
Allow fast reload with Ctrl + L
@gfgit I thought a bit about it during the day, see image:
We also know the angle of both points, so we draw virtually two lines (red/orange) and calculate the intersection point Point calcIntersection(Point pointA, float angleA, Point pointB, float angleB)
{
// Direction vectors
float dxA = std::cos(angleA);
float dyA = std::sin(angleA);
float dxB = std::cos(angleB);
float dyB = std::sin(angleB);
// Solve:
// pointA + t * dirA = pointB + s * dirB
// Rearranged: (pointB - pointA) = t * dirA - s * dirB
const float det = dxA * (-dyB) - dyA * (-dxB); // determinant of 2x2 system
if(std::fabs(det) < 1e-6f)
{
return invalidPoint; // Lines are parallel or nearly parallel, no unique intersection.
}
const float rhsX = pointB.x - pointA.x;
const float rhsY = pointB.y - pointA.y;
// Solve for t using Cramer's rule
const float t = (rhsX * (-dyB) - rhsY * (-dxB)) / det;
Point intersection;
intersection.x = pointA.x + t * dxA;
intersection.y = pointA.y + t * dyA;
return intersection;
}Using the distance of
That needs to be modified, We can also use those two straights for crossings, they can then be defined by a
Do you mean for the trains that are moving? I'll take a look at the other improvements :) |
|
I like the maths, it was like I imagined except I had not thinked yet about the intersection algorithm.
About trains we now have getNextSegment passing omly true/false.
But for cross or double slip segments we need to know where we are coming from.
I suggest we split in:
1) store side we come from in vehicle face
2) get opposite segment side (depends on segment type and state)
3) trivially get adjacent segment on that side.
Also I've discovered a bug when 2 turnouts are connected by the curve side: sometimes train suddenly slide at crazy speed on turnout curve and then returns to it's normal speed.
I'n currently using google earth images to build Padua layout. I did 1 unit = 1 meter, hence I increased max zoom level.
What happens if a segment is shorter than vehicle position delta on simulator tick?
I'm also thinking about position sensor. They could be activated if vehicle position delta includes sensor position.
This would "pulse" sensor on/off.
But I need to power a relay which is slow, so I could start a 3 seconds timer which then deactivates the sensor, like real world weight sensor which have slow return to nornal position.
|
I agree, that will work, we can add an
I've a test layout with that too, but no issue. Can you create a minimum example? Then I'll look into it :)
That doesn't work currently, it only tests for one overflow, we must add a while loop around it, but that will affect occupation sensors as well. It currently works like an axle counter, but that won't work when it jumps over it in one simulator tick. I'm going to think about it, I you have an idea, its welcome :)
Or the sensor can just send a triggered message, then the consuming application can do a delay if it needs that. What if the sensor is triggered again within these 3 seconds, should it stay high aka restart the 3 sec timer? Can you upload the JSON again?, I can't download it, link results in an error. |
|
Changing the turnout position while a train is on it doesn't work properly indeed, still a bit in doubt how to handle that. Possible solutions:
Also when you enter a turnout from the "curved" position while the turnout is in the "straight" position the train will make a weird jump. Possible solutions:
I think we should make in configurable in the JSON file. For automated testing Traintastic stuff you most likely want an error, because Traintastic made an mistake and the test should fail then. What's your opinion? |
bug_simulator_train.mp4This shows the bug with multiple wagons on another part of layout but same behavior. |
|
I've started the build, but it is failing on the sim. That is indeed not correct, I'll try to reproduce and look into it. There are no short segments in between? |
|
@gfgit can you upload your JSON file (or send it by email)? |
|
Yes, we could add a while loop.
About axle-counter behavior I think it's fine as is.
Short tracks are just for adjusting layout shape so usually are part of same sensor as adjacent tracks.
Thus whole sensor is already occupied when train passes over a short track.
I didn't use them in my layout yet but it's still a case that has to be covered.
Position sensor with delay should restart the timer each time they get pressed.
So if a train runs fast over it it could happen to get pressed with fisrt axle and then stay pressed until whole train has passed, then last axle will trigger 3s delay to get up again.
If train is slow or has long wagons, the sensor might be able to get up after 3 seconds and the get pressed again by next axle.
Delay can be configured as a JSON property of sensor.
Zero delay will make it pulse on/off at each axle, so we cannot wait updateSensors() to trigger, we must switch it inside vehicle position update.
I can also add delay on consuming application if you think it's better.
Real word delay is mechanical and happens inside the sensor itself. It's basically an oil piston, going down it has a big pipe and to go back up it has a really small pipe so oil will flow slowly.
For turnouts in real railways there are 2 kinds of them:
- Ones which will change position if taken from wrong side
- Ones which will make train deray and also break the turnout mechanism.
Some turnouts in Italian railways can switch behavior based on reserved route.
We could make it a property, auto switch on train passage if true, stop train and raise error if false.
|
SimulatorView: blink unknown state turnouts - Toggle to unknown by shift + left click
…t now checks for overflows until it is within a segment, see #195.
You're right they are most likely share a sensor or don't have a sensor, so that will work for common case, i've added the loop, see c4f5592
I prefer to the sensor trigger stuff in the
We can add a global property to control that behavior and allow overriding it on turnout level. Do you need to be able to switch that behavior at runtime as well? Something else I thought about today, currently the simulator is part of the Traintastic installer. But as it becomes more and more an application that also can be used by other applications I think it is better to build a separate Windows installer for it. |
|
Definitely we need a seprate installer for simulator!
Switching turnout behavior at runtime is not really a priority for me. It can be done leter if needed.
We need to move trains away from static data.
By polishing my PR we could add right click context menu, get the segment under mouse cursor and spawn/delete a train.
In future I could work on a timetable like feature.
|
|
Also I understand you want to keep it simple with updateSensor() and possible jitter is not a problem.
But this approach does not respect sensor trigger order.
For now is not much relevant as track circuits are longer than tick position delta so you trigger only one new sensor per vehicle move.
But it's weak and with new sensor types it can lead to inconsistencies.
For example near a Padua we had a small line segment, about 1 km or less, with a curious semi-automatic block circuit.
think it was unique and not repeated elsewhere because circuit is a mess.
Anyway to free the block it wants to see track circuits get occupied in sequential order, then freed in sequential order and a position sensor to be triggered after forst 2 track circuits.
It doesn't matter how fast events happen but they must come in order otherwise the block remains in occupied stste even if train has already left.
Also axle couter sensors need to trigger for each axle and updateSensor() cannot know how many axle have passed on a sensor.
Converting delay into ticks is fine and adds a bit of randomness.
|
Set to manual when stopAllTrains()
|
Hi Reinder,
I've encountered a strange bug on traintstic simulator interaction with circuit simulator.
Since I've put padua central station, padua Campo di Marte, Montà Junction and line towards Milan... Track sections begin to be a lot...
I've used sensor channel to distinguish by station/area since often names repeat on different circuits (basically each station begins counting from 1).
Now each circuit session gets informed about everything even if it doesn't care. Like for example signalbox A should be informed/command only its circuits, turnouts, signals whatever and not know anything about the rest.
Signalbixes already communicate via relays for the tracks shared in common.
So basically track section is always owned by a single signalbox and the other if needed has a relay which repeats the state but no direct connection to the same track circuit!
Anyway this could be fine for now as I'm just ignoring messages not relevant to the session but...
Campo di Marte session which is the latest added and also the last in JSON file so higher segment index in staticData starts with all track sicuits occupied because it misses the initial state sync messages upon connection establishment.
If then I run a train over a tracksection it occupies and frees in simulatir side and it also frees the corresponding track sensor on circuit side.
Could it be because of too many rapid pmessages on start?
But being TCP receiving side should get all messages...
|
|
It might be an issue with the buffers, they are only 1024 bytes currently. Did you try to enlarge them? The write function just drops messages when there is no room in the write buffer. (That should be improved, there should be at least some kind of indication that it is happening.) |
|
Wow didn't think of this.
Can we make a sort of callback when buffer is free again to restart sending?
Or maybe an error code and then enqueing a retry to send.
Also I was thinking about a subscribe message so circuit sessions can subscribe to some sensor channels and it will only get theur initial status plus their state change.
This should greatly reduce network traffic on start and maybe we never hit buffer full again.
|
|
The buffers are really small currently, only 1kB. For my use case that was good enough, but for yours it isn't :) I suggest we first enlange the buffers to e.g. 16kB. If it still happens an auto resize buffer is probably better, else we have to implement another buffering system. Filtering is a nice option, I prefer that by default everything is send and the limiting it to certain channel is an option. |
|
We could have a welcome nessage with some fields to request such behavior
|
Hi, this is an experiment branch.
I've added fast reload of JSON, so you can edit and see the new result instantly.
Then I've increased a bit the max zoom level and temporarily draw all segment in red because of better contrast on image background.
Image background is done with QPainter because I don't know OpenGL well enough...
Tooltips are super useful when building layout to adjust values. Code is still a bit messy.
Now about double slip switches: