News:

Simutrans.com Portal
Our Simutrans site. You can find everything about Simutrans from here.

Station coverage: a proposal

Started by Carl, April 11, 2013, 01:39:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Carl

As part of the new walking features, it's recommended that we turn up the station coverage to much higher values than we are used to. As such, it's appropriate to scrutinise how this feature works at higher values.

The most noticeable aspect is that the "square" nature of station coverage is exacerbated at high values. Here's a diagram:



Each square represents an in-game tile. Imagine that the orange dot is a bus stop. If our station_coverage=6, then every square in the diagram will be covered by the stop. If we assume that each square is 100 metres, then we can say that the station's coverage radius should be 600m. And, in line with this, the green dot represents a square which is 600m away from the stop and receives coverage.

But the red dot is also covered by the stop - despite being more like 850m away from the stop, almost 50% more than the supposed coverage of the stop. (The grey circle here represents a 600m radius from the stop). This seems inconsistent.

To make station coverage consistent, it would be better if station coverage were roughly circular -- that it properly respect a consistent radius, so that only the squares touched by the grey circle are covered when station_coverage=6. (I believe this is how coverage works in, for instance, Cities in Motion).

I suspect that this aspect of the code is unchanged from Standard -- and I guess it has never been an important issue before since we've usually used station coverage of 2 or 3. But if we are to use much higher values in Experimental now, it would be interesting to see if we could switch to a more realistic, roughly circular model of station coverage.

Any thoughts?

ӔO

I can't recall where I've seen it, but I do remember that stations don't cover a perfect circle in the real world.

If the station is at an intersection, the coverage will extend X meters along the roads and results in a coverage that looks like a cross or star. This is because foot paths may not always have a direct route to the station and therefore the people have to make detours by following the road.
My Sketchup open project sources
various projects rolled up: http://dl.dropbox.com/u/17111233/Roll_up.rar

Colour safe chart:

Sarlock

In a perfect grid of roads it would resemble a diamond shape with jagged edges.  The shape would change according to local road layout/connections.  There is also a statistical drop-off of ridership as you move farther from the station (walking times increase).
It's probably best kept as a square for gameplay reasons, squares fit nicely together to cover an area and are the simplest to understand for players.
Current projects: Pak128 Trees, blender graphics

ӔO

Personally, I like the diamond shape.
My Sketchup open project sources
various projects rolled up: http://dl.dropbox.com/u/17111233/Roll_up.rar

Colour safe chart:

Isaac Eiland-Hall

If you want a radical idea that probably would be too complex.... You could seek down road tiles, X number of road tiles from the stop. Each road tile would connect X number of tiles next to it - with a decreasing number the farther away from the station. So maybe it would start at 3 tiles away, then on the 3rd road tile from the stop, it would be 2 tiles away; then at the 5th it would drop to a single tile away from the road.

Does that make sense? :)

The preview would obviously have to show the station coverage in real-time, but... this wouldn't be too hard on CPU I wouldn't think...

jamespetts

One ought to remember that the current release candidates of Experimental - and therefore the next release version - which use this larger station coverage take account of the actual walking time from the origin to the stop. The idea of the coverage area is that it should be sufficiently large to capture the majority of those passengers who would be content to walk to the station in light of their journey time tolerances. The actual work in determining who does in fact walk to the station is done by the walking time itself. The retention of a catchment area (but its substantial enlargement) was simply a way of achieving this aim with minimal changes to the code - that aim would rather be undermined by what would be a rather complicated change to the code to create an intricately shaped coverage area. If a significant number of would-be passengers whose journey time tolerances allow them to walk to the station are excluded by the catchment area, then just enlarge the catchment area: the real radius effect is simulated by the walking time together with journey time tolerances (and, if there are multiple possible modes of transport, the routing system of finding the fastest).
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Sarlock

So a station of coverage 20 tiles would likely have a similar catchment to a station of 40 tiles because it would probably already be outside their max walking time at 20 tilse?
Current projects: Pak128 Trees, blender graphics

jamespetts

It is slightly more subtle than that - different passengers have different journey time tolerances, and, of course, walking is slow. At 125m/tile, a 40 tile distance would give us 5km, or an hour's walk at the default of 5km/hour. This would be on top of the waiting time, the transfer time (if any) and the journey time of each connexion, and the walking time to the end. Some passengers would indeed be prepared to do this, but a very great many would not. Also, if there were any competing modes of transport (private car, closer stations, etc.), the passengers would be far more likely to choose those.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

sdog

consequence thereof would be that catchment areas ought to be dynamic. For a solitary station in 1900 century 40 tiles would be good. For bus stops in a city, this would cause a huge overlap and way too many pax would have to be considered.


ps.: 125m /tile make plane almost completely pointless, even on the largest of maps. 500 km would require 5000 tiles already.

ӔO

some of the shorter regional flights only have distances of 160km.

The smaller bombardier, avro, embraer and lockheed airplanes are popular with these regional routes.
My Sketchup open project sources
various projects rolled up: http://dl.dropbox.com/u/17111233/Roll_up.rar

Colour safe chart:

Sarlock

Quoteps.: 125m /tile make plane almost completely pointless, even on the largest of maps. 500 km would require 5000 tiles already.

Pretty much.  The edges might find air travel feasible to the opposite edges on a large map of 2,000+ tiles or so, but for anything in the interior of the map they would all be within 2-3 hours travel by moderate speed rail and even less with high speed rail (an hour or so).
The flexibility to set scale allows the player to decide whether to create a small regional map or a larger area.  Setting at 250m/tile on the same map would make air travel feasible for longer distances.
If you wanted a map purely to the graphical scale of around 20m/tile, then a 2,000x2,000 map would only be 10km².  Great for doing a detailed model of a single city.

Continued increases in computer hardware size and speed might make maps of 5,000² or larger possible within a few years.  At some point the restriction on maximum map size may have to be increased... although a map that huge would be so huge it would be difficult to manage from a gameplay perspective.  2,000x2,000 is already a massive map.  Perhaps with 40 players.
Current projects: Pak128 Trees, blender graphics

ӔO

one thing that occurred to me.

when pax travel diagonally, is their distance sqrt2 or 1?

also, slightly off topic, but should not diagonal ways also cost 1/sqrt2, instead of half per tile?
My Sketchup open project sources
various projects rolled up: http://dl.dropbox.com/u/17111233/Roll_up.rar

Colour safe chart:

Carl

Quote from: jamespetts on April 11, 2013, 11:44:12 PM
One ought to remember that the current release candidates of Experimental - and therefore the next release version - which use this larger station coverage take account of the actual walking time from the origin to the stop. The idea of the coverage area is that it should be sufficiently large to capture the majority of those passengers who would be content to walk to the station in light of their journey time tolerances. The actual work in determining who does in fact walk to the station is done by the walking time itself. The retention of a catchment area (but its substantial enlargement) was simply a way of achieving this aim with minimal changes to the code - that aim would rather be undermined by what would be a rather complicated change to the code to create an intricately shaped coverage area. If a significant number of would-be passengers whose journey time tolerances allow them to walk to the station are excluded by the catchment area, then just enlarge the catchment area: the real radius effect is simulated by the walking time together with journey time tolerances (and, if there are multiple possible modes of transport, the routing system of finding the fastest).

Hi James, thanks for this answer -- that's a very convincing explanation of why it's not worth changing the coverage feature.

Vonjo

CMIIW. It means that the station coverage feature is currently quite "useless". The reason why this feature is still there is because:
1. The feature has already been there, so it is easier to keep it.
2. It is good for the CPU, as it will limit the check to only the area inside the station coverage, instead of the entire map.

So, the optimal station coverage size should be as big as your computer can manage. If your computer works fine with station coverage which covers the entire map, then it is okay.
Am I right?

jamespetts

Quote from: sdog on April 12, 2013, 03:32:17 AM
consequence thereof would be that catchment areas ought to be dynamic. For a solitary station in 1900 century 40 tiles would be good. For bus stops in a city, this would cause a huge overlap and way too many pax would have to be considered.

Why would this overlap be a problem? I think that Vonjo is largely correct when he wrote,

Quote
So, the optimal station coverage size should be as big as your computer can manage.

As to this point:

Quote
ps.: 125m /tile make plane almost completely pointless, even on the largest of maps. 500 km would require 5000 tiles already.

It is possible to make a 16384 x 1024 map, which equates to 2,048km x 128km (or an 8192 x 2048 map - 1,024km x 256km), in respect of both of which air travel is feasible: if a large part of the middle of the map is empty ocean, this will not put a strain on people's computers, as empty map does not significantly add to memory or CPU load. Another idea relating to long distance travel is the portal to foreign destinations: around the map one might have dotted a number of portals to foreign ports/airports with a set of goods demanded/supplied (which might change over time depending on a configuration file, along with passenger demand changing over time), and where convoys can be sent, wherein they approximately simulate a long trip without actually moving (there is a lapse of time; they then load and unload and wait a further time before re-emerging onto the map, where the time is based on the vehicle's maximum speed and the supposed distance to the foreign destination, and during which time maintenance costs are charged in respect of that vehicle; although what to do about long sea voyages that take many real life months: a four month voyage would, at 6 hours per day, take 40 game years).

Quotealso, slightly off topic, but should not diagonal ways also cost 1/sqrt2, instead of half per tile?

Diagonal ways do indeed cost a specific fraction of the cost of a straight tile, based on the actual relationship between the length of a straight and a diagonal.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

wlindley

Sounds like what we need, in addition to a mode like "Hide buildings under cursor" is a mode to "Show actual station coverage, tile-by-tile, with a color gradation based upon walking time"

jamespetts

If anyone would like to program that, let me know!
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

o_O

#17
So essentially station catchment area is just a formality and passengers walk to a station (or refuse to) based on time tolorance and walking speed and what not?  So its probably a good idea to have more then 2-3 stops in a city.  That actually makes alot of sense.  In my head I was justifying the large areas by saying "well each stop represents a handful of stops in that general area, or maybe we assume that smaller routes link to player built trunk lines"

I don't think security delays and generally long airport lines are factored into simutrans airtravel.  Without that extra 1-2 hours per trip many shorter routes are viable that would not be with realistic conditions. 

Edit: Oh it actually does have that interesting.  I guess it would still have uses crossing water and nasty terrain, or small regional flights.

Carl

Actually, Experimental has a "minimum airport wait time" parameter to simulate security etc at airports. I believe this is set at 30 mins by default; were I using air travel often in-game, I think I'd set it somewhat higher than this.

neroden

I like the behavior in current experimental, with the "walking time".

...there is one weird result of station coverage in current experimental however.  Built a port on the ocean.  You can stop a ship on *any tile in the ocean* within the station coverage and it counts as "in port".

I don't think this is desirable.  I've had trouble directing ships into depots because the depot is within the station radius.  Is there some way to restrict the places where ships can dock, so that they have to actually be within one square of a dock?

Also, the station coverage radius ends up being very large for freight.  I actually like the idea that freight will get hauled on foot across the street to the factory (or whatever) -- it's been extremely useful -- but it does mean that you need a "walking time" equivalent for the FREIGHT as well as for the passengers and mail, representing how long from the factory to the loading dock.

The way walking is currently handled also gives some odd results in cases where the source and target freight factories are very close, within the radius of a single stop.  You have to build two stops and run trucks between them, but the freight will run in both directions :-).... this freight should be walking, not taking your trucks at all.

jamespetts

Ahh - thank you for pointing out the issue with ships docking: I had not considered this. This is a rather tricky question, actually, as currently the two mechanisms (the docking and the coverage radius) are one and the same, and it seems as though they might well need to be separated. Thoughts as to how I might achieve this separation cleanly and clearly to users would be welcome.

As to freight, however, I have already dealt with this: I have added a separate coverage radius for freight, which can be set separately in simuconf.tab with the line "station_coverage_size_factories=". In the next release of Pak128.Britain-Ex, this will be set to 1, meaning that a freight station will need to be immediately next to a factory in order to receive freight from it (no more hauling tons of coal over hundreds of meters by hand to the station). This reduced coverage is shown when placing a freight station or when holding down CTRL when placing a non-freight station (for example, a mixed passenger/freight stop). This reduced coverage applies only to goods - passengers will walk in their full coverage radius, and likewise people with letters to post.

Indeed, I wonder whether this could be the solution to the first problem - just use the freight station coverage for the ships in port; but would this be enough?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

jamespetts

I have modified the code on my Github branch so that ships only dock (and recognise as stops) if they are within the *goods* coverage radius of the port, which is a radius of 1 for Pak128.Britain-Ex. This ought to solve this issue.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

greenling

Hello James i think that a radius from om tile for goodsstations Can make problems with exitens games.
Opening hours 20:00 - 23:00
(In Night from friday on saturday and saturday on sunday it possibly that i be keep longer in Forum.)
I am The Assistant from Pakfilearcheologist!
Working on a big Problem!

jamespetts

Greenling,

thank you for your input. The best way to deal with this is to set station_coverage_size_factories in the simuconf.tab of the pakset when loading an old saved game to the same as the station_coverage_size value, or alternatively adjust it to match the station_coverage_size value in the advanced settings window (key "i" in Pak128.Britain-Ex) so that the old saved game will work as before.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

greenling

Hello Jamespetts i have look on the demo.sve out the simutrans exp 9.5 and there some factorys they only with
massiv earthmoving can be reach.
Opening hours 20:00 - 23:00
(In Night from friday on saturday and saturday on sunday it possibly that i be keep longer in Forum.)
I am The Assistant from Pakfilearcheologist!
Working on a big Problem!

MCollett

The current situation (Simutrans 112.2 Experimental 11.9005) appears to be that the reduced goods radius only applies for outward goods: inward goods are magically transported to a factory from any stop within the larger passenger radius.  I presume that the intent is for the reduced radius to apply both ways ...

Best wishes,
Matthew

neroden

Quote from: MCollett on April 29, 2013, 07:28:51 AM
The current situation (Simutrans 112.2 Experimental 11.9005) appears to be that the reduced goods radius only applies for outward goods: inward goods are magically transported to a factory from any stop within the larger passenger radius.  I presume that the intent is for the reduced radius to apply both ways ...

Actually, I've tested this quite recently.  The effective radius for freight is as large as the large passenger radius in BOTH directions.  station_coverage_size_factories simply does not work.   The station doesn't think that it's connected to the factory, but it doesn't matter: the goods will come and go anyway.

Now, before you try to fix this:  having the coverage distance for freight too small is not a good idea.  Many "final outcome" factories are only one tile large.  There isn't much room to put freight stops next to them, which will work out rather badly in multiplayer games.

Two possibilities:
(1) Handle freight exactly like passengers.  The stevedores can haul it up from the docks (or whatever), but at a low, time-consuming speed.  I like this idea.    Players who get closer-in stations will have an advantage, but players with further-out stations won't be shut out.

If it's possible to have *different walking times* for different freight, that would be ideal, and could be used to penalize far-out stations quite significantly.  The result does feel a little unrealistic with coal, but more realistic with vegetables, beer, etc.

It should also be easy to code, since you've already done it for passengers and mail.

(2) Increase the coverage distance to 2.  This would require making the freight coverage distance actually work, however, which may be a *lot* harder than it at first appears. 

I strongly advise that, rather than having separate "freight coverage distance", you simply handle the freight the same way as the passengers, with a walking distance.  It's elegant, and it actually makes sense... people do carry freight across roads, through parking lots, and in the old days, across fields.  Furthermore, freight will benefit automatically from any improvements to the "walking" system (for instance, if walking is redone to trace along roads, freight will automatically benefit).  Just use one system.

Of course, you could also do both (have a reduced freight coverage radius *and* measure walking time within that radius).

The docking mechanism should be separated out from the coverage radius in any case, and ships should always be required to actually be directly next to a dock, 1 tile away.  (No going out in rowboats to meet the ship.)

--
Anyway, currently the "freight radius" limit doesn't work at all.  And I wouldn't want it to work with a strict 1 tile coverage limit.  I have some rather nicely constructed games taking advantage of this.  In particular, it makes it significantly more possible to set up docks on rivers and shorelines prior to the availability of suitable canals.  These are usually a few tiles away from the factories, but sometimes not far enough away (only 2 squares, or 3) to actually build a viable trucking line.

jamespetts

Thank you very much for pointing out this bug/these bugs, and for proposing solutions. I should be very interested in: (1) historical precedents for this (information on the historical location of freight sidings, goods yards, canal docks, etc., relative to factories without interconnecting roads, narrow gauge railways, etc.); and (2) other people's views on the question. One possible solution is to have both: a trans-shipment time and a reduced radius (which can be set to 2), which would of course require the fixing of the radius. Nathaneal - do you have any particular reason to suspect that fixing this might be very difficult?

Another issue is how this works with different types of freight. I can see that it makes sense to have stevedores lugging boxes of piece goods, barrels of beer, bundles of planks, etc., down the road by hand - but how on earth would this work for coal, oil, clay, chemicals or livestock? Livestock, I suppose, could be hearded, but coal was generally unloaded by tipping the whole wagon up end so that its contents were deposited on a large pile of coal, in exactly the right place to be shovelled to its intended furnace (the wagons would go up inclines so that they were on top of the pile; these days, hopper wagons just empty the bottoms onto a huge conveyor belt), and oil and chemicals, of course, are unloaded by attaching pipes to the wagons.

As to docking ships, can anyone see any problems or issues if I just require all ships to dock within a single tile of any dock regardless of the freight station radius set in simuconf.tab?

One issue, however, is this: we are quite near now to the release and I do not want if I can possibly help it to increment the saved game version again before release. Having different speeds for hauling different types of freight would do this, as we need a separate simuconf.tab entry for each type (currently, there is a single entry for passengers), each of which has to be saved with the saved game.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Quote from: jamespetts on April 29, 2013, 11:12:06 AM
Thank you very much for pointing out this bug/these bugs, and for proposing solutions. I should be very interested in: (1) historical precedents for this (information on the historical location of freight sidings, goods yards, canal docks, etc., relative to factories without interconnecting roads, narrow gauge railways, etc.); and (2) other people's views on the question. One possible solution is to have both: a trans-shipment time and a reduced radius (which can be set to 2), which would of course require the fixing of the radius. Nathaneal - do you have any particular reason to suspect that fixing this might be very difficult?
The station coverage radius seems to be used in a *lot* of different places.  That's my only reason for suspecting that this is going to be difficult to fix: tracking down every usage.

QuoteAnother issue is how this works with different types of freight. I can see that it makes sense to have stevedores lugging boxes of piece goods, barrels of beer, bundles of planks, etc., down the road by hand - but how on earth would this work for coal, oil, clay, chemicals or livestock?  Livestock, I suppose, could be hearded, but coal was generally unloaded by tipping the whole wagon up end so that its contents were deposited on a large pile of coal, in exactly the right place to be shovelled to its intended furnace (the wagons would go up inclines so that they were on top of the pile; these days, hopper wagons just empty the bottoms onto a huge conveyor belt), and oil and chemicals, of course, are unloaded by attaching pipes to the wagons.

Historically, for liquids there were often pipelines (often, hidden underground pipelines) running from the docks to the factory.  This is still done.  Pipes under or over a road are particularly common with liquids unloading on the far side of a road from a factory.  Coal is a particular issue, it is certainly usually unloaded VERY close to the destination or even INSIDE the factory, though conveyor belts and miniature railways are two options which were used for dragging it from docks.  Also men with handcarts in very early "selling coal for fires" applications.

Now, the game isn't ever going to be perfectly realistic (for one thing, the roads and houses are 'officially' 125 meters wide by default... and I don't think we'll ever get this down to a realistic 10 meters for roads, and what would we we do for house pictures if we succeeded anyway).

f the *time penalty* for the distance from the source/destination could vary by good, we could get a decent approximation to realistic behavior, even if you have to imagine an "invisible conveyor belt" or "invisible pipeline".  So, for instance, it may only cost 3 minutes for a passenger or mail to travel to the station... but for a haul of coal it should cost 3 hours.  Even for a good which is time-insensitive, this is going to give the advantage to the competitor with the adjacent station.  I think.  I'd have to check on the algorithms there.

QuoteAs to docking ships, can anyone see any problems or issues if I just require all ships to dock within a single tile of any dock regardless of the freight station radius set in simuconf.tab?
*Nathanael listens for other responses*

QuoteOne issue, however, is this: we are quite near now to the release and I do not want if I can possibly help it to increment the saved game version again before release. Having different speeds for hauling different types of freight would do this, as we need a separate simuconf.tab entry for each type (currently, there is a single entry for passengers), each of which has to be saved with the saved game.
The existing situation is tolerable and playable -- give it a whirl -- and you shouldn't worry about it before release.

jamespetts

Would a workable solution be, I wonder, (1) to fix the broken parts; (2) to increase the factory radius to 2; (3) to separate the dock radius and have it fixed at 1; and (4) to introduce a trans-shipment time based on a dispersal speed of 1km/h for all freight?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

#30
Quote from: jamespetts on April 29, 2013, 05:01:22 PM
Would a workable solution be, I wonder, (1) to fix the broken parts; (2) to increase the factory radius to 2; (3) to separate the dock radius and have it fixed at 1; and (4) to introduce a trans-shipment time based on a dispersal speed of 1km/h for all freight?

Sounds fine.

I also had another thought -- make the dispersal speed based on the weight, which already exists.  Passengers and mail are the lightest.  :-)

---
(The idea is that wool weighs 380/70 = 5.5 times as much as passengers, so it should run at 1/5.5 = 0.18 times the speed of passengers.  But thinking about it, this would probably end up being 1 km/h for all freight anyway, so you might as well just go with 1 km/h.)

Junna

Quote from: jamespetts on April 29, 2013, 05:01:22 PM
Would a workable solution be, I wonder, (1) to fix the broken parts; (2) to increase the factory radius to 2; (3) to separate the dock radius and have it fixed at 1; and (4) to introduce a trans-shipment time based on a dispersal speed of 1km/h for all freight?

Would the trans-shipment penalty affect goods changing train at a station too?

jamespetts

Nathaneal - how would that relationship work, exactly? Passengers' speed are based on the actual average walking speed for humans. How can this scale to other goods by weight compared with passengers?

Junna - I think that it would probably have to do so, yes, if it were to be consistent.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

The idea was that wool weighs 380/70 = 5.5 times as much as passengers, so it should run at 1/5.5 = 0.18 times the speed of passengers.  But thinking about it, this would probably end up being 1 km/h -- or LESS -- for all freight anyway, so you might as well just go with 1 km/h.

neroden

FWIW, in real life, freight transshipment at stations is expensive in terms of time -- very time-consuming -- so it's just fine to have such a penalty as far as I am concerned.

neroden

Two more thoughts.  I believe passengers have a "just walk across town, don't take public transport or drive, walking is faster" option?  Is that still implemented?

The same should be true of freight.  I've ended up with a Pub only 4 squares from a Brewery, and similar things happen quite often.  The infrastructure for trucking is overkill here and takes up too much space.  For such short trips, "private freight transport" should be possible.  (Note that at the current scale of 125 meters/tile, 1 km/hr would only be a half hour trip in the example I gave.)

Also of note: the ability for passengers to *change stations* by walking seems to have gone away at some point; walking only seems to be working at origin and destination.  Changing stations on foot may be too stressful on the pathfinder, so I understand if it was removed for that reason.

Junna

Quote from: neroden on April 29, 2013, 05:50:12 PM
Two more thoughts.  I believe passengers have a "just walk across town, don't take public transport or drive, walking is faster" option?  Is that still implemented?

The same should be true of freight.  I've ended up with a Pub only 4 squares from a Brewery, and similar things happen quite often.  The infrastructure for trucking is overkill here and takes up too much space.  For such short trips, "private freight transport" should be possible.  (Note that at the current scale of 125 meters/tile, 1 km/hr would only be a half hour trip in the example I gave.)

This works in standard, I think it was changed at some point in experimental.

neroden

Playing my 1750 sample game again, freight coverage needs to be at least 3 tiles and should really be 4 tiles.  This is due to the fairly frequent need to jam in roads, railways, and canals around hills and fields.  With a coverage of less than 4 the earthworks become monumental.

The 1 km/h penalty for travel to a not-directly-adjacent station still sounds good.

jamespetts

Nathaneal - the passengers do indeed walk accross town (and, indeed, even between towns) if walking is faster and the journey is within the passengers' journey time tolerance; this is a feature exclusive to Experimental. In Standard, passengers walk if and only if their origin and destination are within the coverage radius of a single halt.

Can you give me some examples of the monumental earthworks to which you refer? The reality as I understand it is that freight depots are usually more or less next to the industries that they serve.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Quote from: jamespetts on April 29, 2013, 06:59:52 PM
Nathaneal - the passengers do indeed walk accross town (and, indeed, even between towns) if walking is faster and the journey is within the passengers' journey time tolerance; this is a feature exclusive to Experimental. In Standard, passengers walk if and only if their origin and destination are within the coverage radius of a single halt.

Can you give me some examples of the monumental earthworks to which you refer? The reality as I understand it is that freight depots are usually more or less next to the industries that they serve.

In Simutrans, farms frequently place themselves on top of a hill (often 2-3 tiles of hill) and surround themselves with fields (usually 1-2 tiles depth).  Good luck building a directly adjacent freight depot.

In real life, this situation often features a depot at the bottom of the hill, with the farmers walking their produce to the depot.  Now, there are some oddities related to the two scales of simutrans (the real hill would be the size of the one on the visual scale, not the one on the 'virtual' scale of 125 m / tile).  But you have to make some compromises in design due to that.

neroden

Quote from: jamespetts on April 29, 2013, 06:59:52 PM
Nathaneal - the passengers do indeed walk accross town (and, indeed, even between towns) if walking is faster and the journey is within the passengers' journey time tolerance; this is a feature exclusive to Experimental.

Do it with freight too.  Just make the freight really really slow (1 km/hr would be fine).

jamespetts

#41
Right - I have now fixed the original problem. Thank you both for pointing it out. I have also increased the station coverage for factories from 1 to 3 in the simuconf.tab file for Pak128.Britain-Ex and removed the relationship between this figure and ship docking, making that a fixed figure of 1 tile.

Also, I forgot to respond to this earlier:

QuoteAlso of note: the ability for passengers to *change stations* by walking seems to have gone away at some point; walking only seems to be working at origin and destination.  Changing stations on foot may be too stressful on the pathfinder, so I understand if it was removed for that reason.

This still exists, but it is disabled by default: look for the simuconf.tab setting: allow_routing_on_foot = 0 and change it to 1. This can also be changed in the in-game advanced settings GUI (key "i" in Pak128.Britain-Ex).

This was originally disabled after Knightly pointed out a number of discrepancies that this created in the day when passengers could not walk long distances to their final destination - I wonder whether it would be wise to enable it by default now?

I am about to look into adding transshipment times.

Edit: Transshipment times added, at a presumed speed of 1km/h, to the Github repository. Note that this only works for the origin stop - because of the way in which goods are distributed amongst routes, it would be difficult to take into account the timing at the destination stop. This should suffice for the present, however.

Edit 2: Actually, looking again at the code, it is indeed possible to add transshipment time to the destination stop, which I have just added to my Github branch.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

#42
Quote from: jamespetts on April 29, 2013, 10:16:50 PMThis still exists, but it is disabled by default: look for the simuconf.tab setting: allow_routing_on_foot = 0 and change it to 1. This can also be changed in the in-game advanced settings GUI (key "i" in Pak128.Britain-Ex).

This was originally disabled after Knightly pointed out a number of discrepancies that this created in the day when passengers could not walk long distances to their final destination - I wonder whether it would be wise to enable it by default now?

Huh.  Yeah, it would have caused discrepancies when people couldn't walk to their final destination.

Yeah, it probably should be enabled by default now that you've fixed that.  :-)  Make sure that the same transfer time penalty for walking between stations applies as for walking to final destinations or from origins, though, or the same discrepancies will come back.

Thanks for everything you've done on this -- you clearly know this part of the code a lot better than me. I can see what to do from a design point of view, but can't find where to program it.

--- added information --
Note that you want to modify the code to allow freight to "walk" as well as passengers (but at 1 km/h).  That isn't enabled in the current code.  The time delay for transferring should take care of all the "oddities" in both

I just tested your most recent version. 

First thing to know: The separate station coverage for freight is STILL not working right.  Told you it was going to be hard.

I have a setup with a Grain Mill, and 4 tiles away a Bakery.  There is a station directly next to the Grain Mill.  There is also a station *6* tiles away from the Bakery.  I have a boat line running from the Grain Mill station to the station *6* tiles away from the Bakery.

Right now, freight will happily queue up at the origin station, happily be transported to the destination station, and then... vanish!  It doesn't arrive at the Bakery.  However, it happily waltzes around getting transported by my ship before vanishing into thin air.

You haven't found all the places where the coverage distance is used.

Second thing to know: There's some new sort of breakage in freight generation (which may be responsible for the aforementioned problem).  The Grain Mill is now generating freight for Bakery locations which are thousands of squares away and completely disconnected from the transportation network.  (On different islands, in fact, so they couldn't even go by private car, even if that were implemented, which it isn't).

This means that even the passenger coverage distance isn't being respected right now.  We wanted freight to be able to "walk" short distances... not cross-country.

My origin station is 112, 743 and I'm getting flour generated with a destination of 1150, 816 -- 64 km away, and 64 hours at 1 km/h.  Hmm?

I think you have to dig into the path-search code which delivers factory products to make sure that it doesn't try to send products across routes which will turn out to be impossible or beyond the time tolerances.  (This may also be an issue with passenger and mail generation code, I haven't made a test case yet.)

(If you can't get the distance based coverage working, it's also possible that this could be handled by setting a time tolerance for freight in the freight generation code, but that may be harder.)

neroden

Doing a little debugging.

This patch is no good, because it triggers at the very end.  That's too late, and it's generating the nasty bug I just described, with disappearing goods.  You have to back this patch out.

You have to check whether the stop is within range of the factory much, MUCH earlier, during pathfinding.


@@ -1612,8 +1612,17 @@ void haltestelle_t::add_pax_no_route(int n)

void haltestelle_t::liefere_an_fabrik(const ware_t& ware) const //"deliver to the factory" (Google)
{
- fabrik_t *const factory = fabrik_t::get_fab( welt, ware.get_zielpos() );
- if(  factory  ) {
+ fabrik_t *const factory = fabrik_t::get_fab(welt, ware.get_zielpos());
+ if(factory)
+ {
+   if(ware.is_freight())
+   {
+     // Check to see whether this is within range.
+     if(!fab_list.is_contained(factory))
+     {
+       return;
+     }
+   }
    factory->liefere_an(ware.get_besch(), ware.menge);
  }
}


Specifically, you want to look at the part where stations decide what factories are within range (for destinations) and where factories decide what stations are within range for origins.  Don't mess with liefere_an.

neroden

Look, I did some further research.  You simply didn't implement the different freight station coverage distance at all.

The code for station coverage is in simplan.h and simplan.cc.  Mostly in the planquadrat_t code.

If you really want separate freight coverage, you need  to have a separate freight_halt_list distinct from the halt_list for passengers.  You need to duplicate all the halt_list management code in plan_quadrat_t.  Then you need to go find every single place where the halt_list is referenced (which is all OVER the code) and separate them out into freight and passenger uses.

Particularly path_explorer.cc and path_explorer.h

But also
bauer/fabrikbauer.cc
dings/gebaeude.cc (!!!)
simcity.cc
simhalt.cc

I do *not* think it is worth the work involved.

I *strongly* advise ripping out all the code related to a separate station coverage size for freight, since you never actually implemented the feature, and it really will involve ripping apart most of the codebase, including some of the most sensitive bits. 

But if you still want to implement freight_coverage radiuses, you now know where to start.  It will be weeks of work.

Implementing a time penalty for "walking" freight instead, which we're already doing, should be much easier to do and much easier to debug, since you've already managed to implement that for passengers; you just have to run through the code enabling it for freight.

neroden

Oh.  Another bug related to the walking code, while you're at it.  The passenger and mail walking time for attractions -- at least the one displayed in the info window -- is based on the top left hand corner.  It should be based on whichever corner of the attraction is closest.

I can't tell because it isn't displayed in the info window -- but I suspect factories, and likely all multi-tile buildings (headquarters, etc.) have the same problem.

This also needs to be addressed for the freight transport time, of course.

jamespetts

#46
Thank you very much for testing this and looking into it. I do not have time to examine these things in detail now or act on them, but I shall give these matters due consideration in due course over the next few days when I get a few minutes.

(I should add that the main difficulty, which I think that you have found, with the separate freight coverage area, is that the coverage area is based on marking a number of tiles, and subsequently checking those tiles, rather than actual distance checking at each step).

Edit: One potential problem with allowing goods from factories to "walk" (be hand-hauled) to their destination some distance away is that that would substantially reduce the economic impact of players' transportation. For passengers, this is not an issue, as passengers have a journey time tolerance, so many will not travel at all if the journey is too long. However, this is not so for freight, so goods would in fact be shipped instantly all over the map if the same rules were used for freight as for passengers, which would mean that all factories would always be fully supplied. This would not be serviceable, I think.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Quote from: jamespetts on May 02, 2013, 09:52:29 AM
Edit: One potential problem with allowing goods from factories to "walk" (be hand-hauled) to their destination some distance away is that that would substantially reduce the economic impact of players' transportation. For passengers, this is not an issue, as passengers have a journey time tolerance, so many will not travel at all if the journey is too long. However, this is not so for freight, so goods would in fact be shipped instantly all over the map if the same rules were used for freight as for passengers, which would mean that all factories would always be fully supplied. This would not be serviceable, I think.

(1) The freight would need a journey time tolerance as well.  If the "walking speed" of freight is slow, the journey time tolerance can be high and still prevent most cross-map freight transfers....
(2) There should be a walking distance limit for freight.  It would be perfectly acceptable if this limit were the same as the station coverage limit.  In fact, the limit for walking from a factory to a station should *already* be this low, for passengers *as well as* freight.  Isn't it?  If not, why not?  This should act as a computational cutoff: walking should not be considered beyond this distance.  I'm going to have to look at how you implemented the walking code.

(3) I do have a suggestion as to how to implement "walking distances" more efficiently.  Instead of simply storing a list of connected halts at each square on the map... store the halt *and* the walking distance to the halt (one walking distance for passengers, one for freight).  Then this only has to be updated when halts are built or deleted, in the same place where the halt_list is currently updated.  You don't have to make two halt_lists, and you don't have to recheck all the users of halt_list, only the parts measuring journey time.  It should be faster than computing walking distance for each trip...
(4) Finally, passenger and freight "direct" walking probably has to use separate code from walking between halts, which only looks within the coverage radius.  I'm not sure whether you did this.

(5) I just looked.  As far as I can tell, you haven't implemented walking from the halt to the final destination, or walking from the origin to the starting halt, either.  It's just cosmetic; it doesn't actually seem to be implemented.  If I'm wrong, point me to the actual code which you think does the work.  Yeesh!

(6) I am clearly going to have to program the walking code myself.   ;D

jamespetts

Thank you for your reply (and for your fix to the disappearing freight issue). Some of these topics are somewhat fundamental, so need careful consideration, I think. I shall deal with your points in numbered order.

(1) I am not sure that a journey time tolerance for freight makes sense. Passengers are people who could be doing something else if they were not travelling. People will only travel if the time that they invest in getting to their destination is worth the reward that they obtain when they reach it. Freight is different. Some goods might be perishable, in which case there is no point in dispatching them at all if they cannot reach their destinations in a certain time, but most goods are not. A factory that demands coal does not care one whit whether its coal left the mine an hour ago, a day ago, a week ago, a month ago or a year ago, provided that it has a steady supply of the stuff. In the days of canals, goods hauled about the country often took several weeks to reach their destinations. A week's journey time tolerance at 1km/h is 168km. On a 512x512 map at 125m/tile, there would be no point in connecting any factories at all: everything would get to where it is going within a week without a single road, canal or railway.

(2 and 5) The two are interrelated. The idea behind the walking system for passengers was to use the existing coverage radius (rather than have to check every single building tile on the map for every single halt, which would not perform well), but just add the time that passengers spend walking from their origin to the origin stop and the destination stop to the destination to the journey time calculations. This way, the walking feature could be implemented with minimal changes to the code and minimal impact on performance. To make this feature work correctly, we needed to increase the coverage area for passengers from 3 or 4 tiles to 16-24 or so, which in turn prompted the idea of having a separate freight coverage radius, as cargo loading points are, with good reason, almost inevitably right next to factories, rather than many kilometres away.

The code for the walking/freight haulage time from the destination stop to the ultimate destination is here:


uint16 haltestelle_t::find_route(minivec_tpl<halthandle_t> *ziel_list, ware_t &ware, const uint16 previous_journey_time, const koord destination_pos)
{
uint16 journey_time = previous_journey_time;

if(ziel_list->empty())
{
//no target station found
ware.set_ziel(halthandle_t());
ware.set_zwischenziel(halthandle_t());
return 65535;
}

// Now, find the best route from here.
// Added by : Knightly
// Adapted from : James' code
// Further adapted to incorporate walking
// times calculation: @jamespetts, January 2013

uint16 test_time;
halthandle_t test_transfer;

halthandle_t best_destination;
halthandle_t best_transfer;

const uint32 transfer_journey_time_factor = ((uint32)welt->get_settings().get_meters_per_tile() * 6) * 10;
const uint32 walking_time_divider = 100 * (uint32)welt->get_settings().get_walking_speed();
koord destination_stop_pos = destination_pos;

const uint8 ware_catg = ware.get_besch()->get_catg_index();
uint32 long_test_time;

for (uint8 i = 0; i < ziel_list->get_count(); i++)
{
path_explorer_t::get_catg_path_between(ware_catg, self, (*ziel_list)[i], test_time, test_transfer);

long_test_time = (uint32)test_time;

if(destination_pos != koord::invalid)
{
// Walking time is not relevant for freight.
if((*ziel_list)[i].is_bound())
{
destination_stop_pos = (*ziel_list)[i]->get_next_pos(destination_pos);
}

// Add the walking distance from the destination stop to the ultimate destination.
long_test_time += (shortest_distance(destination_stop_pos, destination_pos) * transfer_journey_time_factor) / walking_time_divider;
}

else if(ware.is_freight())
{
// For freight, we instead calculate a transshipment time based on a notional 1km/h dispersal speed.
if((*ziel_list)[i].is_bound())
{
destination_stop_pos = (*ziel_list)[i]->get_next_pos(ware.get_zielpos());
}

// Add the walking distance from the destination stop to the ultimate destination.
long_test_time += (shortest_distance(destination_stop_pos, ware.get_zielpos()) * transfer_journey_time_factor) / 100;
}

if(long_test_time > 65535)
{
test_time = 65535;
}
else
{
test_time = long_test_time;
}

if(test_time < journey_time)
{
best_destination = (*ziel_list)[i];
journey_time = test_time;
best_transfer = test_transfer;
}
}

if(journey_time < previous_journey_time)
{
ware.set_ziel(best_destination);
ware.set_zwischenziel(best_transfer);
return journey_time;
}

return journey_time;
}


The code for the walking time for passengers from their ultimate origin to their origin stop is here:


while(route_status != public_transport && route_status != private_car && route_status != on_foot && current_destination < destination_count)
{
const uint32 straight_line_distance = shortest_distance(origin_pos, destinations[current_destination].location);
const uint16 walking_time = (straight_line_distance * walking_journey_time_factor) / 100u;
car_minutes = 65535;

const bool can_walk = walking_time <= (quasi_tolerance / walking_tolerance_divider);

if(!has_private_car && !can_walk && start_halts.empty())
{
/**
* If the passengers have no private car, are not in reach of any public transport
* facilities and the journey is too long on foot, do not continue to check other things.
*/
current_destination ++;
continue;
}

// Dario: Check if there's a stop near destination
const planquadrat_t* dest_plan = welt->lookup(destinations[current_destination].location);
const halthandle_t* dest_list = dest_plan->get_haltlist();

// Knightly : we can avoid duplicated efforts by building destination halt list here at the same time

// Note that, although factories are only *connected* now if they are within the smaller factory radius
// (default: 1), they can take passengers within the wider square of the passenger radius. This is intended,
// and is as a result of using the below method for all destination types.


for (int h = dest_plan->get_haltlist_count() - 1; h >= 0; h--)
{
halthandle_t halt = dest_list[h];
if (halt->is_enabled(wtyp))
{
destination_list[current_destination].append(halt);
}
}

uint16 best_journey_time = 65535;

if(start_halts.get_count() == 1 && destination_list[current_destination].get_count() == 1 && start_halts[0] == destination_list[current_destination].get_element(0))
{
/** There is no public transport route, as the only stop
* for the origin is also the only stop for the desintation.
*/
start_halt = start_halts[0];
}
else
{
// Check whether public transport can be used.
// Journey start information needs to be added later.
pax.reset();
pax.set_zielpos(destinations[current_destination].location);
pax.menge = pax_left_to_do;
pax.to_factory = ( destinations[current_destination].factory_entry ? 1 : 0 );
//"Menge" = volume (Google)

// Search for a route using public transport.

uint8 best_start_halt = 0;
uint32 current_journey_time;
koord destination_stop_pos = destinations[current_destination].location;

ITERATE(start_halts, i)
{
halthandle_t current_halt = start_halts[i];

current_journey_time = current_halt->find_route(&destination_list[current_destination], pax, best_journey_time, destinations[current_destination].location);

// Add walking time from the origin to the origin stop.
// Note that the walking time to the destination stop is already added by find_route.
current_journey_time += (shortest_distance(start_halts[i]->get_next_pos(origin_pos), origin_pos) * walking_journey_time_factor) / 100u;
if(current_journey_time > 65535)
{
current_journey_time = 65535;
}
// TODO: Add facility to check whether station/stop has car parking facilities, and add the possibility of a (faster) private car journey.
// Use the private car journey time per tile from the passengers' origin to the city in which the stop is located.

if(current_journey_time < best_journey_time)
{
best_journey_time = current_journey_time;
best_start_halt = i;
}
if(pax.get_ziel().is_bound())
{
route_status = public_transport;
}
}

if(best_journey_time == 0)
{
best_journey_time = 1;
}

if(best_journey_time > walking_time && can_walk)
{
// If walking is faster than public transport, passengers will walk.
route_status = on_foot;
}

// Check first whether the best route is outside
// the passengers' tolerance.

if(route_status == public_transport && best_journey_time >= tolerance)
{
route_status = too_slow;

if(!too_slow_already_set)
{
best_bad_destination = destinations[current_destination].location;
best_bad_start_halt = best_start_halt;
too_slow_already_set = true;
}
}
else
{
// All passengers will use the quickest route.
if(start_halts.get_count() > 0)
{
start_halt = start_halts[best_start_halt];
}
}
}

INT_CHECK("simcity.cc 3333");

if(has_private_car)
{
// time_per_tile here is in 100ths of minutes per tile.
// 1/100th of a minute per tile = km/h * 6.
uint16 time_per_tile = 65535;
switch(destinations[current_destination].type)
{
case 1:
//Town
time_per_tile = check_road_connexion_to(destinations[current_destination].object.town);
break;
case FACTORY_PAX:
time_per_tile = check_road_connexion_to(destinations[current_destination].object.industry);
break;
case TOURIST_PAX:
time_per_tile = check_road_connexion_to(destinations[current_destination].object.attraction);
break;
default:
//Some error - this should not be reached.
dbg->error("simcity.cc", "Incorrect destination type detected");
};

if(time_per_tile < 65535)
{
// *Hundredths* of minutes used here for per tile times for accuracy.
// Convert to tenths, but only after multiplying to preserve accuracy.
// Use a uint32 intermediary to avoid overflow.
const uint32 car_mins = (time_per_tile * straight_line_distance) / 10;
car_minutes = car_mins > 0 ? car_mins : 1;

// Now, adjust the timings for congestion (this is already taken into account if the route was
// calculated using the route finder; note that journeys inside cities are not calculated using
// the route finder).

if(s.get_assume_everywhere_connected_by_road() || destinations[current_destination].object.town == this)
{
// Congestion here is assumed to be on the percentage basis: i.e. the percentage of extra time that
// a journey takes owing to congestion. This is the measure used by the TomTom congestion index,
// compiled by the satellite navigation company of that name, which provides useful research data.
// See: http://www.tomtom.com/lib/doc/congestionindex/2012-0704-TomTom%20Congestion-index-2012Q1europe-mi.pdf

//Average congestion of origin and destination towns.
uint16 congestion_total;
if(destinations[current_destination].type == 1 && destinations[current_destination].object.town != NULL && destinations[current_destination].object.town != this)
{
// Destination type is town and the destination town object can be found.
congestion_total = (city_history_month[0][HIST_CONGESTION] + destinations[current_destination].object.town->get_congestion()) / 2;
}
else
{
congestion_total = city_history_month[0][HIST_CONGESTION];
}

const uint32 congestion_extra_minutes = (car_minutes * congestion_total) / 100;

car_minutes += congestion_extra_minutes;
}
}
}

// Cannot be <=, as mail has a tolerance of 65535, which is used as the car_minutes when
// a private car journey is not possible.
if(car_minutes < tolerance)
{
const uint16 private_car_chance = (uint16)simrand(100, "void stadt_t::step_passagiere() (private car chance?)");

if(route_status != public_transport)
{
// The passengers can get to their destination by car but not by public transport.
// Therefore, they will always use their car unless it is faster to walk and they
// are not people who always prefer to use the car.
if(car_minutes > walking_time && can_walk && private_car_chance > always_prefer_car_percent)
{
// If walking is faster than taking the car, passengers will walk.
route_status = on_foot;
}
else
{
route_status = private_car;
}
}

else if(private_car_chance <= always_prefer_car_percent || car_minutes <= best_journey_time)
{
route_status = private_car;
}
}

INT_CHECK("simcity 3419");
if(route_status == no_route || route_status == too_slow)
{
// Do not increment the counter if there is a good status,
// or else entirely the wrong information will be recorded
// below!
current_destination ++;
}
} // While loop (route_status)

bool set_return_trip = false;
stadt_t* destination_town;

switch(route_status)
{
case public_transport:

if(destinations[current_destination].factory_entry)
{
register_factory_passenger_generation(&pax_left_to_do, wtyp, target_factories, destinations[current_destination].factory_entry);
destinations[current_destination].factory_entry->factory->book_stat( pax.menge, ( wtyp==warenbauer_t::passagiere ? FAB_PAX_DEPARTED : FAB_MAIL_DEPARTED ) );
}
pax.arrival_time = welt->get_zeit_ms();
pax.set_origin(start_halt);
start_halt->starte_mit_route(pax);
start_halt->unload_repeat_counter = 0;
merke_passagier_ziel(destinations[current_destination].location, COL_YELLOW);
set_return_trip = will_return != no_return;
// create pedestrians in the near area?
if (s.get_random_pedestrians() && wtyp == warenbauer_t::passagiere)
{
haltestelle_t::erzeuge_fussgaenger(welt, origin_pos_3d, pax_left_to_do);
}
// We cannot do this on arrival, as the ware packets do not remember their origin building.
if(wtyp != warenbauer_t::post)
{
// The generated passengers were *4 above to allow for this discrimination by preference of
// destination. 1st choice (current_destination == 0): 100% - 2nd choice: 75%; 3rd or subsequent
// choice: 50%.
const int multiplier = current_destination == 0 ? 4 : current_destination == 1 ? 3 : 2;
if(range == local)
{
gb->add_passengers_succeeded_local(pax_left_to_do * multiplier);
}
else
{
gb->add_passengers_succeeded_non_local(pax_left_to_do * multiplier);
}
}
break;

case private_car:

if(destinations[current_destination].factory_entry)
{
register_factory_passenger_generation(&pax_left_to_do, wtyp, target_factories, destinations[current_destination].factory_entry);
destinations[current_destination].factory_entry->factory->book_stat( pax.menge, ( wtyp==warenbauer_t::passagiere ? FAB_PAX_DEPARTED : FAB_MAIL_DEPARTED ) );
}
destination_town = destinations[current_destination].type == 1 ? destinations[current_destination].object.town : NULL;
set_private_car_trip(num_pax, destination_town);
merke_passagier_ziel(destinations[current_destination].location, COL_TURQUOISE);
#ifdef DESTINATION_CITYCARS
erzeuge_verkehrsteilnehmer(origin_pos, car_minutes, destinations[current_destination].location);
#endif
set_return_trip = will_return != no_return;
if(wtyp != warenbauer_t::post)
{
// The generated passengers were *4 above to allow for this discrimination by preference of
// destination. 1st choice (current_destination == 0): 100% - 2nd choice: 75%; 3rd or subsequent
// choice: 50%.
const int multiplier = current_destination == 0 ? 4 : current_destination == 1 ? 3 : 2;
if(range == local)
{
gb->add_passengers_succeeded_local(pax_left_to_do * multiplier);
}
else
{
gb->add_passengers_succeeded_non_local(pax_left_to_do * multiplier);
}
}
break;

case on_foot:

if(destinations[current_destination].factory_entry)
{
register_factory_passenger_generation(&pax_left_to_do, wtyp, target_factories, destinations[current_destination].factory_entry);
// workers who walk to the factory or customers who walk to the consumer store
destinations[current_destination].factory_entry->factory->book_stat( pax_left_to_do, ( wtyp==warenbauer_t::passagiere ? FAB_PAX_DEPARTED : FAB_MAIL_DEPARTED ) );
destinations[current_destination].factory_entry->factory->liefere_an(wtyp, pax_left_to_do);
}

// Walking passengers are not marked as "happy", as the player has not made them happy.

merke_passagier_ziel(destinations[current_destination].location, COL_DARK_YELLOW);
if (s.get_random_pedestrians() && wtyp == warenbauer_t::passagiere)
{
haltestelle_t::erzeuge_fussgaenger(welt, origin_pos_3d, pax_left_to_do);
}

if(wtyp == warenbauer_t::passagiere)
{
add_walking_passengers(pax_left_to_do);
}
set_return_trip = will_return != no_return;
if(wtyp != warenbauer_t::post)
{
// The generated passengers were *4 above to allow for this discrimination by preference of
// destination. 1st choice (current_destination == 0): 100% - 2nd choice: 75%; 3rd or subsequent
// choice: 50%.
const int multiplier = current_destination == 0 ? 4 : current_destination == 1 ? 3 : 2;
if(range == local)
{
gb->add_passengers_succeeded_local(pax_left_to_do * multiplier);
}
else
{
gb->add_passengers_succeeded_non_local(pax_left_to_do * multiplier);
}
}
break;

case too_slow:

merke_passagier_ziel(best_bad_destination, COL_LIGHT_PURPLE);

if(destinations[0].factory_entry)
{
register_factory_passenger_generation(&pax_left_to_do, wtyp, target_factories, destinations[0].factory_entry);
}

start_halt = start_halts[best_bad_start_halt];
if(start_halt.is_bound())
{
start_halt->add_pax_too_slow(pax_left_to_do);
}

break;

case no_route:

if(destinations[0].factory_entry)
{
register_factory_passenger_generation(&pax_left_to_do, wtyp, target_factories, destinations[0].factory_entry);
}

bool crowded_halts = false;
int destinations_checked;

if(start_halts.get_count() > 0)
{
/** Passengers/mail cannot reach their destination, but there are some stops in their locality.
* Record their inability to get where they are going at those local stops accordingly.
*/

start_halt = start_halts[best_bad_start_halt];
if(start_halt.is_bound())
{
start_halt->add_pax_no_route(pax_left_to_do);
}
}
else if(plan->get_haltlist_count() > 0)
{
/** The unhappy passengers will be added to any potential starting stops
  * that are crowded, and were therefore excluded from the initial search.
  * However, there might be no possible starting stop too.
  */

// Re-search for start halts, which must have been crowded, or else
// they would not have been excluded from the first search.
ware_t test_passengers(wtyp);
for(int h = plan->get_haltlist_count() - 1; h >= 0; h--)
{
destinations_checked = 0;
halthandle_t halt = halt_list[h];
for(; destinations_checked <= destination_count; destinations_checked ++)
{
// Only mark passengers as being unable to get to their destination due to crowded stops if the stops
// could actually have got the passengers to their destination if they were not crowded.
if(halt->is_enabled(wtyp) && halt->find_route(&destination_list[destinations_checked], test_passengers) < 65535)
{
halt->add_pax_unhappy(num_pax);
// Only show as being overcrowded if there are, in fact, potentially suitable but overcrowded stops.
crowded_halts = true;
break;
}
}
}
}

if(crowded_halts)
{
// If the passengers cannot get to a stop that they might reach because of
// overcrowding, and all other stops are no route, mark the specific destination
// unavailable to the passengers because of overcrowding.
merke_passagier_ziel(destinations[destinations_checked].location, COL_RED);
}

else
{
merke_passagier_ziel(destinations[0].location, COL_DARK_ORANGE);
}
};


(3) This is not a bad idea, actually - it would get rid of quite a few computations, including divisions, that are performed quite frequently. Would using a struct here be helpful, do you think (struct nearby_stop_t { halthandle_t halt; uint16 walking_distance; }?)

(4) This is indeed done for passengers in simcity.cc - I have not done anything for freight yet.

(6) It would be very kind if you could assist with this - your contributions are much appreciated. We just have to be sure that we get the economics/fundamentals right before starting any major work (especially the issue with hand haulage of freight, which is the trickiest issue, I think).
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Sorry I dropped off the net again, real life interfered as it so often does.    :-[

Thanks very much for pointing me to the code.  The destination to ultimate destination code in haltestelle_t looks OK.  I kind of whish it wasn't in haltestelle_t, however.

The ultimate orgin to origin stop code -- which file is that in?  Is it in simcity.cc?

Regarding the "code cleanup" ideas:
struct nearby_stop_t { halthandle_t halt; uint16 walking_distance; }
should, indeed do the trick.  That should clean up an awful lot of code.

The other thing to do is to stop duplicating this code:const uint16 walking_time = (straight_line_distance * walking_journey_time_factor) / 100u;

Instead there should be an inline function, probably in simunits.h:
const uint16 walking_time_for_distance(uint32 distance) { return distance * walking_journey_time_factor) / 100u; };

And another one for the freight version of walking:
const uint16 hand_hauling_time_for_distance(uint32 distance)

If you make the functions inline it's just as fast as typing it out, but it makes it a lot easier to make changes if we need to mess around with data types or units.  Subroutines!  Subroutines!

jamespetts

Hello - thank you for your reply. I have been working on this recently, and have just pushed a change to 112.x-private-car-merge which should deal with the factory coverage radius issue. I have made the walking_distance a uint8 figure, as there is no need to have coverages of more than 255 tiles. The ultimate origin to origin stop code is indeed in simcity.cc.

Do the changes in my latest commit seem sensible to you?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

neroden

Unfortunately, you're patching around some sort of fundamental problem in the code which you haven't found yet.

All the factory code is a bit of a mess, honestly, because it's very old.  There's a reason I wanted to rewrite it to connect factories directly, rather than through "koord" entries, because I think that will make it a lot clearer what's going on.  Then we might be able to find out what the actual game logic is.  Just poking around at different bits of it is not going to solve the problem.

jamespetts

I don't think that there is a single, fundamental undiscovered problem: the latest bug reports that you sent me by e-mail were both specific different problems, both of which I have now fixed.

However, I wonder whether the system of storing the distance to the halt in a struct inside the tile is reducing performance: there is a report here of reduced performance in the latest version compared to RC 11.9004, and this is the only feature so far as I can see that is capable of having a significant impact on performance. The call to check what halts are connected to a tile is made very, very many times in a step, and now it is returning a struct with a uint8 and a halthandle, rather than just a halthandle. Is this a realistically likely culprit, do you think? If so, what would the best strategies for dealing with it be?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.