diff --git a/MANIFEST.in b/MANIFEST.in index 2676ed3bd4ac7bcee65b67daf8acde27342d7407..3332b747feab75a4763c54894f951856df9c0222 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,7 +9,7 @@ include requirements_continuous_integration.txt -graft flatland/svg +graft flatland/png graft env_data diff --git a/examples/introduction_flatland_2_1.py b/examples/introduction_flatland_2_1.py index 3ec2d0d4cf2c63bd916b74d06c21a73d589c8c60..8ea267c18accf0a28f964bff5aecdbc70b50016e 100644 --- a/examples/introduction_flatland_2_1.py +++ b/examples/introduction_flatland_2_1.py @@ -63,7 +63,7 @@ schedule_generator = sparse_schedule_generator(speed_ration_map) # We can furthermore pass stochastic data to the RailEnv constructor which will allow for stochastic malfunctions # during an episode. -stochastic_data = MalfunctionParameters(malfunction_rate=10000, # Rate of malfunction occurence +stochastic_data = MalfunctionParameters(malfunction_rate=1/10000, # Rate of malfunction occurence min_duration=15, # Minimal duration of malfunction max_duration=50 # Max duration of malfunction ) diff --git a/flatland/envs/observations.py b/flatland/envs/observations.py index 8590922131d57cd76ba4a638b10e3e7e169a984a..83584a302f0e4064cef187171db291b637126242 100644 --- a/flatland/envs/observations.py +++ b/flatland/envs/observations.py @@ -295,21 +295,16 @@ class TreeObsForRailEnv(ObservationBuilder): if self.location_has_agent_direction[position] == direction: # Cummulate the number of agents on branch with same direction - other_agent_same_direction += self.location_has_agent_direction.get((position, direction), 0) + other_agent_same_direction += 1 # Check fractional speed of agents current_fractional_speed = self.location_has_agent_speed[position] if current_fractional_speed < min_fractional_speed: min_fractional_speed = current_fractional_speed - # Other direction agents - # TODO: Test that this behavior is as expected - other_agent_opposite_direction += \ - self.location_has_agent[position] - self.location_has_agent_direction.get((position, direction), - 0) - else: # If no agent in the same direction was found all agents in that position are other direction + # Attention this counts to many agents as a few might be going off on a switch. other_agent_opposite_direction += self.location_has_agent[position] # Check number of possible transitions for agent and total number of transitions in cell (type) diff --git a/flatland/png/Background_#91D1DD.png b/flatland/png/Background_#91D1DD.png new file mode 100644 index 0000000000000000000000000000000000000000..6fb65bb2a11d2f0dd1ff1ffa8ef531dcb95013fa Binary files /dev/null and b/flatland/png/Background_#91D1DD.png differ diff --git a/flatland/png/Background_#9CCB89.png b/flatland/png/Background_#9CCB89.png new file mode 100644 index 0000000000000000000000000000000000000000..37225578ba2f96d057f0c021e015298c8401072f Binary files /dev/null and b/flatland/png/Background_#9CCB89.png differ diff --git a/flatland/png/Background_#AA7B55.png b/flatland/png/Background_#AA7B55.png new file mode 100644 index 0000000000000000000000000000000000000000..4612900b00ba98a45c5437f9c9d244a187c8eb2c Binary files /dev/null and b/flatland/png/Background_#AA7B55.png differ diff --git a/flatland/png/Background_#DEBDA0.png b/flatland/png/Background_#DEBDA0.png new file mode 100644 index 0000000000000000000000000000000000000000..9b12f19a4968052e91eff8e7fb0d92742b63af7a Binary files /dev/null and b/flatland/png/Background_#DEBDA0.png differ diff --git a/flatland/png/Background_Light_green.png b/flatland/png/Background_Light_green.png new file mode 100644 index 0000000000000000000000000000000000000000..86c5ac45d980920f6230526158c0ac9294b293ca Binary files /dev/null and b/flatland/png/Background_Light_green.png differ diff --git a/flatland/png/Background_city.png b/flatland/png/Background_city.png new file mode 100644 index 0000000000000000000000000000000000000000..be605ec4d54091e1b7abf83bf6d67010cafde78c Binary files /dev/null and b/flatland/png/Background_city.png differ diff --git a/flatland/png/Background_rail.png b/flatland/png/Background_rail.png new file mode 100644 index 0000000000000000000000000000000000000000..ff4d94c2c5761d38f0bcebda9580fb79b61387aa Binary files /dev/null and b/flatland/png/Background_rail.png differ diff --git a/flatland/png/Background_white.png b/flatland/png/Background_white.png new file mode 100644 index 0000000000000000000000000000000000000000..60e2e79a23effda1f878f7b4fdb49d3180432c54 Binary files /dev/null and b/flatland/png/Background_white.png differ diff --git a/flatland/png/Background_white_filter.png b/flatland/png/Background_white_filter.png new file mode 100644 index 0000000000000000000000000000000000000000..5ca44a22542bcf0433cda44505facc7c296ca936 Binary files /dev/null and b/flatland/png/Background_white_filter.png differ diff --git a/flatland/png/Bahnhof_#d50000.png b/flatland/png/Bahnhof_#d50000.png new file mode 100644 index 0000000000000000000000000000000000000000..3d72c293e8668b194136a0c590151db354895d24 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000.png differ diff --git a/flatland/png/Bahnhof_#d50000_Deadend_links.png b/flatland/png/Bahnhof_#d50000_Deadend_links.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ca62361d9c21a05b22837106a461d7eb899d7c Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Deadend_links.png differ diff --git a/flatland/png/Bahnhof_#d50000_Deadend_oben.png b/flatland/png/Bahnhof_#d50000_Deadend_oben.png new file mode 100644 index 0000000000000000000000000000000000000000..b4549771e0cb6d6c89e25d44d4b3d47494266aa0 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Deadend_oben.png differ diff --git a/flatland/png/Bahnhof_#d50000_Deadend_rechts.png b/flatland/png/Bahnhof_#d50000_Deadend_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..ddf29db9292c3628f81b2c88f0b18c644189b801 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Deadend_rechts.png differ diff --git a/flatland/png/Bahnhof_#d50000_Deadend_unten.png b/flatland/png/Bahnhof_#d50000_Deadend_unten.png new file mode 100644 index 0000000000000000000000000000000000000000..6894e69a23af6657b6f6b376a0bc62f2160bf423 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Deadend_unten.png differ diff --git a/flatland/png/Bahnhof_#d50000_Gleis_horizontal.png b/flatland/png/Bahnhof_#d50000_Gleis_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..786f79ecb9abc3851b71dc6c724850130a804376 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Gleis_horizontal.png differ diff --git a/flatland/png/Bahnhof_#d50000_Gleis_vertikal.png b/flatland/png/Bahnhof_#d50000_Gleis_vertikal.png new file mode 100644 index 0000000000000000000000000000000000000000..989bb50b61eda56a77cad448baac68df3efa8ae4 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_Gleis_vertikal.png differ diff --git a/flatland/png/Bahnhof_#d50000_target.png b/flatland/png/Bahnhof_#d50000_target.png new file mode 100644 index 0000000000000000000000000000000000000000..8bf4844238ebeafced9007c6126b00962d853fc7 Binary files /dev/null and b/flatland/png/Bahnhof_#d50000_target.png differ diff --git a/flatland/png/Buildings-Bank.png b/flatland/png/Buildings-Bank.png new file mode 100644 index 0000000000000000000000000000000000000000..16f36237475709510d4d5692367bb3edc8fd3a99 Binary files /dev/null and b/flatland/png/Buildings-Bank.png differ diff --git a/flatland/png/Buildings-Bar.png b/flatland/png/Buildings-Bar.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb222ba686ffe83ee7fa3d856d4713f74149a64 Binary files /dev/null and b/flatland/png/Buildings-Bar.png differ diff --git a/flatland/png/Buildings-Fabrik_A.png b/flatland/png/Buildings-Fabrik_A.png new file mode 100644 index 0000000000000000000000000000000000000000..3c94bafec37a70a878a0827473f47bfee29532dc Binary files /dev/null and b/flatland/png/Buildings-Fabrik_A.png differ diff --git a/flatland/png/Buildings-Fabrik_B.png b/flatland/png/Buildings-Fabrik_B.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3f4771652f9e1a8b8f333177f7edf60d2dd3ee Binary files /dev/null and b/flatland/png/Buildings-Fabrik_B.png differ diff --git a/flatland/png/Buildings-Fabrik_C.png b/flatland/png/Buildings-Fabrik_C.png new file mode 100644 index 0000000000000000000000000000000000000000..bbbee1d0e184099c5ca865fc76ee94e9fd5b4076 Binary files /dev/null and b/flatland/png/Buildings-Fabrik_C.png differ diff --git a/flatland/png/Buildings-Fabrik_D.png b/flatland/png/Buildings-Fabrik_D.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb2fb938900aae809e59e7ff06608fc2ca70f22 Binary files /dev/null and b/flatland/png/Buildings-Fabrik_D.png differ diff --git a/flatland/png/Buildings-Fabrik_E.png b/flatland/png/Buildings-Fabrik_E.png new file mode 100644 index 0000000000000000000000000000000000000000..49920e1bfb1e5e5ec000b6213c59cc556e5a3c0b Binary files /dev/null and b/flatland/png/Buildings-Fabrik_E.png differ diff --git a/flatland/png/Buildings-Fabrik_F.png b/flatland/png/Buildings-Fabrik_F.png new file mode 100644 index 0000000000000000000000000000000000000000..662bac6c3c316a7e1a726de1a49db8a9e9cfaa8f Binary files /dev/null and b/flatland/png/Buildings-Fabrik_F.png differ diff --git a/flatland/png/Buildings-Fabrik_G.png b/flatland/png/Buildings-Fabrik_G.png new file mode 100644 index 0000000000000000000000000000000000000000..57c2f404e0d552737d09a7c3283623f901085b5b Binary files /dev/null and b/flatland/png/Buildings-Fabrik_G.png differ diff --git a/flatland/png/Buildings-Fabrik_H.png b/flatland/png/Buildings-Fabrik_H.png new file mode 100644 index 0000000000000000000000000000000000000000..4b18616022713bf71702963cfbdf31a3f6e9fc3d Binary files /dev/null and b/flatland/png/Buildings-Fabrik_H.png differ diff --git a/flatland/png/Buildings-Fabrik_I.png b/flatland/png/Buildings-Fabrik_I.png new file mode 100644 index 0000000000000000000000000000000000000000..00fc9e512854131faa00a3f3f22ac45d0b37a564 Binary files /dev/null and b/flatland/png/Buildings-Fabrik_I.png differ diff --git a/flatland/png/Buildings-Hochhaus.png b/flatland/png/Buildings-Hochhaus.png new file mode 100644 index 0000000000000000000000000000000000000000..e60202e4630e709780e023f5cba2517630ae3f9b Binary files /dev/null and b/flatland/png/Buildings-Hochhaus.png differ diff --git a/flatland/png/Buildings-Hotel.png b/flatland/png/Buildings-Hotel.png new file mode 100644 index 0000000000000000000000000000000000000000..bf14135fde6ad8be1160038477ce597cbab9b90c Binary files /dev/null and b/flatland/png/Buildings-Hotel.png differ diff --git a/flatland/png/Buildings-Office.png b/flatland/png/Buildings-Office.png new file mode 100644 index 0000000000000000000000000000000000000000..07647072287f63bcfbb42e44415e50d8a3f8ad32 Binary files /dev/null and b/flatland/png/Buildings-Office.png differ diff --git a/flatland/png/Buildings-Polizei.png b/flatland/png/Buildings-Polizei.png new file mode 100644 index 0000000000000000000000000000000000000000..bc273f49df0b821b6704db43ce09ed66339a9185 Binary files /dev/null and b/flatland/png/Buildings-Polizei.png differ diff --git a/flatland/png/Buildings-Post.png b/flatland/png/Buildings-Post.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f93c6659cfa43f7f0af739d146b4ae91edb23e Binary files /dev/null and b/flatland/png/Buildings-Post.png differ diff --git a/flatland/png/Buildings-Supermarkt.png b/flatland/png/Buildings-Supermarkt.png new file mode 100644 index 0000000000000000000000000000000000000000..ec8ebd504b0867e5b5564e49b3c81ce5a405b159 Binary files /dev/null and b/flatland/png/Buildings-Supermarkt.png differ diff --git a/flatland/png/Buildings-Tankstelle.png b/flatland/png/Buildings-Tankstelle.png new file mode 100644 index 0000000000000000000000000000000000000000..84d81081327994cb403ec587a909d737382a7af9 Binary files /dev/null and b/flatland/png/Buildings-Tankstelle.png differ diff --git a/flatland/png/Buildings-Wohnhaus.png b/flatland/png/Buildings-Wohnhaus.png new file mode 100644 index 0000000000000000000000000000000000000000..3a05a5a29a3ff65315d5c93ef6d10f902ee41000 Binary files /dev/null and b/flatland/png/Buildings-Wohnhaus.png differ diff --git a/flatland/png/Cell_occupied.png b/flatland/png/Cell_occupied.png new file mode 100644 index 0000000000000000000000000000000000000000..08db69fc682b16ad5adadafb31018f441316f50a Binary files /dev/null and b/flatland/png/Cell_occupied.png differ diff --git a/flatland/png/Gleis_Deadend.png b/flatland/png/Gleis_Deadend.png new file mode 100644 index 0000000000000000000000000000000000000000..47eb7687a8a2af37ba204ff02b58006ebc32705f Binary files /dev/null and b/flatland/png/Gleis_Deadend.png differ diff --git a/flatland/png/Gleis_Diamond_Crossing.png b/flatland/png/Gleis_Diamond_Crossing.png new file mode 100644 index 0000000000000000000000000000000000000000..9d3612a9851ae2fa44d130a4be438113395c68a8 Binary files /dev/null and b/flatland/png/Gleis_Diamond_Crossing.png differ diff --git a/flatland/png/Gleis_Kurve_oben_links.png b/flatland/png/Gleis_Kurve_oben_links.png new file mode 100644 index 0000000000000000000000000000000000000000..394c1b654b665f99f52d5b363ac925fe950cfa15 Binary files /dev/null and b/flatland/png/Gleis_Kurve_oben_links.png differ diff --git a/flatland/png/Gleis_Kurve_oben_links_unten_rechts.png b/flatland/png/Gleis_Kurve_oben_links_unten_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..c0b379760ba2c15784065eb4ffcce2560e87eb3e Binary files /dev/null and b/flatland/png/Gleis_Kurve_oben_links_unten_rechts.png differ diff --git a/flatland/png/Gleis_Kurve_oben_rechts.png b/flatland/png/Gleis_Kurve_oben_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff468049e196d90ade6d01027149671b358716b Binary files /dev/null and b/flatland/png/Gleis_Kurve_oben_rechts.png differ diff --git a/flatland/png/Gleis_Kurve_unten_links.png b/flatland/png/Gleis_Kurve_unten_links.png new file mode 100644 index 0000000000000000000000000000000000000000..9c462811b50afd3d72d1f6b432943df6f3855757 Binary files /dev/null and b/flatland/png/Gleis_Kurve_unten_links.png differ diff --git a/flatland/png/Gleis_Kurve_unten_rechts.png b/flatland/png/Gleis_Kurve_unten_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..4b3a0baca81c97dc16fcc701b8f74ab0dcb6b5a5 Binary files /dev/null and b/flatland/png/Gleis_Kurve_unten_rechts.png differ diff --git a/flatland/png/Gleis_horizontal.png b/flatland/png/Gleis_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..b1d2b1a8c91e6ccf312e5b35257f844b7bf87d76 Binary files /dev/null and b/flatland/png/Gleis_horizontal.png differ diff --git a/flatland/png/Gleis_horizontal_Perron.png b/flatland/png/Gleis_horizontal_Perron.png new file mode 100644 index 0000000000000000000000000000000000000000..97e9aedaf6445d7f6b20c0065bafc5a24b75b2c9 Binary files /dev/null and b/flatland/png/Gleis_horizontal_Perron.png differ diff --git a/flatland/png/Gleis_vertikal.png b/flatland/png/Gleis_vertikal.png new file mode 100644 index 0000000000000000000000000000000000000000..f7cbcf6476dfc6ed3de2c51f9ec6cd6b60984d25 Binary files /dev/null and b/flatland/png/Gleis_vertikal.png differ diff --git a/flatland/png/Gleis_vertikal_Perron.png b/flatland/png/Gleis_vertikal_Perron.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8e024921b77ac2591ee3db94387c512f7fe8ae Binary files /dev/null and b/flatland/png/Gleis_vertikal_Perron.png differ diff --git a/flatland/png/Scenery-Bergwelt_A_Teil_1_links.png b/flatland/png/Scenery-Bergwelt_A_Teil_1_links.png new file mode 100644 index 0000000000000000000000000000000000000000..473265c3385e88a4b5b731369a763626238dd9f6 Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_A_Teil_1_links.png differ diff --git a/flatland/png/Scenery-Bergwelt_A_Teil_2_mitte.png b/flatland/png/Scenery-Bergwelt_A_Teil_2_mitte.png new file mode 100644 index 0000000000000000000000000000000000000000..05e2a6b78303835fb33efdc25fae3b7e229ab419 Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_A_Teil_2_mitte.png differ diff --git a/flatland/png/Scenery-Bergwelt_A_Teil_3_rechts.png b/flatland/png/Scenery-Bergwelt_A_Teil_3_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..60dd90b55d05dd149a125e39a0972cfd3b551a7b Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_A_Teil_3_rechts.png differ diff --git a/flatland/png/Scenery-Bergwelt_B.png b/flatland/png/Scenery-Bergwelt_B.png new file mode 100644 index 0000000000000000000000000000000000000000..b5afa6d04945e6a5513364663b131c072e8ac717 Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_B.png differ diff --git a/flatland/png/Scenery-Bergwelt_C_Teil_1_links.png b/flatland/png/Scenery-Bergwelt_C_Teil_1_links.png new file mode 100644 index 0000000000000000000000000000000000000000..3e9dfdd5d3d8b3dad91e02f5e660517af737e567 Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_C_Teil_1_links.png differ diff --git a/flatland/png/Scenery-Bergwelt_C_Teil_2_rechts.png b/flatland/png/Scenery-Bergwelt_C_Teil_2_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..edb60268adcb47a97a90c1ce9896faf7ef777355 Binary files /dev/null and b/flatland/png/Scenery-Bergwelt_C_Teil_2_rechts.png differ diff --git a/flatland/png/Scenery-Laubbaume_A.png b/flatland/png/Scenery-Laubbaume_A.png new file mode 100644 index 0000000000000000000000000000000000000000..cdaafecaf5c9bd6daf70a4ab25281cb532a04044 Binary files /dev/null and b/flatland/png/Scenery-Laubbaume_A.png differ diff --git a/flatland/png/Scenery-Laubbaume_B.png b/flatland/png/Scenery-Laubbaume_B.png new file mode 100644 index 0000000000000000000000000000000000000000..fe75f1c20bbe9c3ad49755b20e3357a30a8ddae0 Binary files /dev/null and b/flatland/png/Scenery-Laubbaume_B.png differ diff --git a/flatland/png/Scenery-Laubbaume_C.png b/flatland/png/Scenery-Laubbaume_C.png new file mode 100644 index 0000000000000000000000000000000000000000..c3994a3dc849503381b4a90998795b4874f61e2f Binary files /dev/null and b/flatland/png/Scenery-Laubbaume_C.png differ diff --git a/flatland/png/Scenery-Nadelbaume_A.png b/flatland/png/Scenery-Nadelbaume_A.png new file mode 100644 index 0000000000000000000000000000000000000000..428d6e12419a1d33ee3c7d3c56ea2ede1213d65a Binary files /dev/null and b/flatland/png/Scenery-Nadelbaume_A.png differ diff --git a/flatland/png/Scenery-Nadelbaume_B.png b/flatland/png/Scenery-Nadelbaume_B.png new file mode 100644 index 0000000000000000000000000000000000000000..885596172225b6612b6b0fc9702023df1de09270 Binary files /dev/null and b/flatland/png/Scenery-Nadelbaume_B.png differ diff --git a/flatland/png/Scenery_Water.png b/flatland/png/Scenery_Water.png new file mode 100644 index 0000000000000000000000000000000000000000..d71fb9d17110f9da3d6e211dd95c6413b398b472 Binary files /dev/null and b/flatland/png/Scenery_Water.png differ diff --git a/flatland/png/Selected_Agent.png b/flatland/png/Selected_Agent.png new file mode 100644 index 0000000000000000000000000000000000000000..36586a336fd6b61372f0a94f087e426c77bafbd1 Binary files /dev/null and b/flatland/png/Selected_Agent.png differ diff --git a/flatland/png/Selected_Target.png b/flatland/png/Selected_Target.png new file mode 100644 index 0000000000000000000000000000000000000000..892e4de0fc8ee0c0038d4b7bbc6a7b3df835fdcb Binary files /dev/null and b/flatland/png/Selected_Target.png differ diff --git a/flatland/png/Weiche_Double_Slip.png b/flatland/png/Weiche_Double_Slip.png new file mode 100644 index 0000000000000000000000000000000000000000..e284da8f6c3871ec93717b2131739ecbeb21aca9 Binary files /dev/null and b/flatland/png/Weiche_Double_Slip.png differ diff --git a/flatland/png/Weiche_Single_Slip.png b/flatland/png/Weiche_Single_Slip.png new file mode 100644 index 0000000000000000000000000000000000000000..382620dea1eaec7c1b5a109efad70a862c12db23 Binary files /dev/null and b/flatland/png/Weiche_Single_Slip.png differ diff --git a/flatland/png/Weiche_Symetrical.png b/flatland/png/Weiche_Symetrical.png new file mode 100644 index 0000000000000000000000000000000000000000..d021af9aadddb741ad461ac37fe7e1ea635aabf1 Binary files /dev/null and b/flatland/png/Weiche_Symetrical.png differ diff --git a/flatland/png/Weiche_Symetrical_gerade.png b/flatland/png/Weiche_Symetrical_gerade.png new file mode 100644 index 0000000000000000000000000000000000000000..1439f35767d413b5f472c91076a9281bca1f9001 Binary files /dev/null and b/flatland/png/Weiche_Symetrical_gerade.png differ diff --git a/flatland/png/Weiche_horizontal_oben_links.png b/flatland/png/Weiche_horizontal_oben_links.png new file mode 100644 index 0000000000000000000000000000000000000000..1ba0640097f8043504de7833052acc31d60803ea Binary files /dev/null and b/flatland/png/Weiche_horizontal_oben_links.png differ diff --git a/flatland/png/Weiche_horizontal_oben_rechts.png b/flatland/png/Weiche_horizontal_oben_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..746ef4fc21e80cfbb84c3ba87a941b85ec05244a Binary files /dev/null and b/flatland/png/Weiche_horizontal_oben_rechts.png differ diff --git a/flatland/png/Weiche_horizontal_unten_links.png b/flatland/png/Weiche_horizontal_unten_links.png new file mode 100644 index 0000000000000000000000000000000000000000..eb8a122e5a9fd1fb29fa8e74535c110b8f4571b1 Binary files /dev/null and b/flatland/png/Weiche_horizontal_unten_links.png differ diff --git a/flatland/png/Weiche_horizontal_unten_rechts.png b/flatland/png/Weiche_horizontal_unten_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..513cf8fc12d45f862315c489474cf4c36ea4ff2b Binary files /dev/null and b/flatland/png/Weiche_horizontal_unten_rechts.png differ diff --git a/flatland/png/Weiche_vertikal_oben_links.png b/flatland/png/Weiche_vertikal_oben_links.png new file mode 100644 index 0000000000000000000000000000000000000000..bed9876779b7b7e71119ca2f8a710914a7987682 Binary files /dev/null and b/flatland/png/Weiche_vertikal_oben_links.png differ diff --git a/flatland/png/Weiche_vertikal_oben_rechts.png b/flatland/png/Weiche_vertikal_oben_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c18f8bf868545475cba31a8ecaa3d020f06792 Binary files /dev/null and b/flatland/png/Weiche_vertikal_oben_rechts.png differ diff --git a/flatland/png/Weiche_vertikal_unten_links.png b/flatland/png/Weiche_vertikal_unten_links.png new file mode 100644 index 0000000000000000000000000000000000000000..ac01b8f602212ca46a6e2893c96a7fe327a6989d Binary files /dev/null and b/flatland/png/Weiche_vertikal_unten_links.png differ diff --git a/flatland/png/Weiche_vertikal_unten_rechts.png b/flatland/png/Weiche_vertikal_unten_rechts.png new file mode 100644 index 0000000000000000000000000000000000000000..14d0dc4eaff52a1fcff059600acf3710187589a0 Binary files /dev/null and b/flatland/png/Weiche_vertikal_unten_rechts.png differ diff --git a/flatland/png/Zug_1_Weiche_#0091ea.png b/flatland/png/Zug_1_Weiche_#0091ea.png new file mode 100644 index 0000000000000000000000000000000000000000..9a8e079b2a96d53c0192a548e1ce28f200cad823 Binary files /dev/null and b/flatland/png/Zug_1_Weiche_#0091ea.png differ diff --git a/flatland/png/Zug_1_Weiche_#0091ea_old.png b/flatland/png/Zug_1_Weiche_#0091ea_old.png new file mode 100644 index 0000000000000000000000000000000000000000..f4188bab7837b4e9d1c240ded75a0d630816c21e Binary files /dev/null and b/flatland/png/Zug_1_Weiche_#0091ea_old.png differ diff --git a/flatland/png/Zug_1_Weiche_#00c853_old.png b/flatland/png/Zug_1_Weiche_#00c853_old.png new file mode 100644 index 0000000000000000000000000000000000000000..7251f050213324a61f3576dc69b1de4a99ad45e1 Binary files /dev/null and b/flatland/png/Zug_1_Weiche_#00c853_old.png differ diff --git a/flatland/png/Zug_1_Weiche_#d50000.png b/flatland/png/Zug_1_Weiche_#d50000.png new file mode 100644 index 0000000000000000000000000000000000000000..fd93c7bd24dc1976ee29cc972b7a04703152a276 Binary files /dev/null and b/flatland/png/Zug_1_Weiche_#d50000.png differ diff --git a/flatland/png/Zug_2_Weiche_#0091ea.png b/flatland/png/Zug_2_Weiche_#0091ea.png new file mode 100644 index 0000000000000000000000000000000000000000..6592ddf637c325b9356455d2a9e049e31fdbc921 Binary files /dev/null and b/flatland/png/Zug_2_Weiche_#0091ea.png differ diff --git a/flatland/png/Zug_2_Weiche_#0091ea_old.png b/flatland/png/Zug_2_Weiche_#0091ea_old.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ccd69a427c16d863ed715feea15e039e7b9b30 Binary files /dev/null and b/flatland/png/Zug_2_Weiche_#0091ea_old.png differ diff --git a/flatland/png/Zug_2_Weiche_#00c853_old.png b/flatland/png/Zug_2_Weiche_#00c853_old.png new file mode 100644 index 0000000000000000000000000000000000000000..9d0d518b73d846d47efa4001e3c28730320d1f7c Binary files /dev/null and b/flatland/png/Zug_2_Weiche_#00c853_old.png differ diff --git a/flatland/png/Zug_Gleis_#0091ea.png b/flatland/png/Zug_Gleis_#0091ea.png new file mode 100644 index 0000000000000000000000000000000000000000..d4091a3937846d5dd65538d329902abe8228b481 Binary files /dev/null and b/flatland/png/Zug_Gleis_#0091ea.png differ diff --git a/flatland/png/Zug_Gleis_#0091ea_old.png b/flatland/png/Zug_Gleis_#0091ea_old.png new file mode 100644 index 0000000000000000000000000000000000000000..e1283e36c621c037965db123437322e8c590ec03 Binary files /dev/null and b/flatland/png/Zug_Gleis_#0091ea_old.png differ diff --git a/flatland/png/Zug_Gleis_#00c853_old.png b/flatland/png/Zug_Gleis_#00c853_old.png new file mode 100644 index 0000000000000000000000000000000000000000..ea9e378a516c35676b78f9fdfe7b7246d72c9b65 Binary files /dev/null and b/flatland/png/Zug_Gleis_#00c853_old.png differ diff --git a/flatland/png/Zug_Gleis_#d50000.png b/flatland/png/Zug_Gleis_#d50000.png new file mode 100644 index 0000000000000000000000000000000000000000..f5d944b531b9adf180c7ea04873f0490ef00ed8c Binary files /dev/null and b/flatland/png/Zug_Gleis_#d50000.png differ diff --git a/flatland/png/__init__.py b/flatland/png/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/flatland/utils/flask_util.py b/flatland/utils/flask_util.py deleted file mode 100644 index e30fd72dfa30073f1404217257b20f8ee582c617..0000000000000000000000000000000000000000 --- a/flatland/utils/flask_util.py +++ /dev/null @@ -1,270 +0,0 @@ - - -from flask import Flask, request, redirect, Response -from flask_socketio import SocketIO, emit -from flask_cors import CORS, cross_origin -import threading -import os -import time -import webbrowser -import numpy as np -import typing -import socket - -from flatland.envs.rail_env import RailEnv, RailEnvActions - - -#async_mode = None - - -class simple_flask_server(object): - """ I wanted to wrap the flask server in a class but this seems to be quite hard; - eg see: https://stackoverflow.com/questions/40460846/using-flask-inside-class - I have made a messy sort of singleton pattern. - It might be easier to revert to the "standard" flask global functions + decorators. - """ - - static_folder = os.path.join(os.getcwd(), "static") - print("Flask static folder: ", static_folder) - app = Flask(__name__, - static_url_path='', - static_folder=static_folder) - - socketio = SocketIO(app, cors_allowed_origins='*') - - # This is the original format for the I/O. - # It comes from the format used in the msgpack saved episode. - # The lists here are truncated from the original - see CK's original main.py, in flatland-render. - gridmap = [ - # list of rows (?). Each cell is a 16-char binary string. Yes this is inefficient! - ["0000000000000000", "0010000000000000", "0000000000000000", "0000000000000000", "0010000000000000", "0000000000000000", "0000000000000000", "0000000000000000", "0010000000000000", "0000000000000000"], - ["0000000000000000", "1000000000100000", "0000000000000000", "0000000000000000", "0000000001001000", "0001001000000000", "0010000000000000", "0000000000000000", "1000000000100000", "0000000000000000"], # ... - ] - agents_static = [ - # [initial position], initial direction, [target], 0 (?) - [[7, 9], 2, [3, 5], 0, - # Speed and malfunction params - {"position_fraction": 0, "speed": 1, "transition_action_on_cellexit": 3}, - {"malfunction": 0, "malfunction_rate": 0, "next_malfunction": 0, "nr_malfunctions": 0}], - [[8, 8], 1, [1, 6], 0, - {"position_fraction": 0, "speed": 1, "transition_action_on_cellexit": 2}, - {"malfunction": 0, "malfunction_rate": 0, "next_malfunction": 0, "nr_malfunctions": 0}], - [[3, 7], 2, [0, 1], 0, - {"position_fraction": 0, "speed": 1, "transition_action_on_cellexit": 2}, - {"malfunction": 0, "malfunction_rate": 0, "next_malfunction": 0, "nr_malfunctions": 0}] - ] - - # "actions" are not really actions, but [row, col, direction] for each agent, at each time step - # This format does not yet handle agents which are in states inactive or done_removed - actions= [ - [[7, 9, 2], [8, 8, 1], [3, 7, 2]], [[7, 9, 2], [8, 7, 3], [2, 7, 0]], # ... - ] - - def __init__(self, env): - # Some ugly stuff with cls and self here - cls = self.__class__ - cls.instance = self # intended as singleton - - cls.app.config['CORS_HEADERS'] = 'Content-Type' - cls.app.config['SECRET_KEY'] = 'secret!' - - self.app = cls.app - self.socketio = cls.socketio - self.env = env - self.renderer_ready = False # to indicate env background not yet drawn - self.port = None # we only assign a port once we start the background server... - self.host = None - - def run_flask_server(self, host='127.0.0.1', port=None): - self.host = host - - if port is None: - self.port = self._find_available_port(host) - else: - self.port = port - - self.socketio.run(simple_flask_server.app, host=host, port=self.port) - - def run_flask_server_in_thread(self, host="127.0.0.1", port=None): - # daemon=True so that this thread exits when the main / foreground thread exits, - # usually when the episode finishes. - self.thread = threading.Thread( - target=self.run_flask_server, - kwargs={"host": host, "port": port}, - daemon=True) - self.thread.start() - # short sleep to allow thread to start (may be unnnecessary) - time.sleep(1) - - def open_browser(self): - webbrowser.open("http://localhost:{}".format(self.port)) - # short sleep to allow browser to request the page etc (may be unnecessary) - time.sleep(1) - - def _test_listen_port(self, host: str, port: int): - oSock = socket.socket() - try: - oSock.bind((host, port)) - except OSError: - return False # The port is not available - - del oSock # This should release the port - return True # The port is available - - def _find_available_port(self, host: str, port_start: int = 8080): - for nPort in range(port_start, port_start+100): - if self._test_listen_port(host, nPort): - return nPort - print("Could not find an available port for Flask to listen on!") - return None - - def get_endpoint_url(self): - return "http://{}:{}".format(self.host, self.port) - - @app.route('/', methods=['GET']) - def home(): - # redirects from "/" to "/index.html" which is then served from static. - # print("Here - / - cwd:", os.getcwd()) - return redirect("index.html") - - @staticmethod - @socketio.on('connect') - def connected(): - ''' - When the JS Renderer connects, - this method will send the env and agent information - ''' - cls = simple_flask_server - print('Client connected') - - # Do we really need this? - cls.socketio.emit('message', {'message': 'Connected'}) - - print('Send Env grid and agents') - # cls.socketio.emit('grid', {'grid': cls.gridmap, 'agents_static': cls.agents_static}, broadcast=False) - cls.instance.send_env() - print("Env and agents sent") - - @staticmethod - @socketio.on('disconnect') - def disconnected(): - print('Client disconnected') - - def send_actions(self, dict_actions): - ''' Sends the agent positions and directions, not really actions. - ''' - llAgents = self.agents_to_list() - self.socketio.emit('agentsAction', {'actions': llAgents}) - - def send_observation(self, agent_handles, dict_obs): - """ Send an observation. - TODO: format observation message. - """ - self.socketio.emit("observation", {"agents": agent_handles, "observations": dict_obs}) - - def send_env(self): - """ Sends the env, ie the rail grid, and the agents (static) information - """ - # convert 2d array of int into 2d array of 16char strings - g2sGrid = np.vectorize(np.binary_repr)(self.env.rail.grid, width=16) - llGrid = g2sGrid.tolist() - llAgents = self.agents_to_list_dict() - self.socketio.emit('grid', { - 'grid': llGrid, - 'agents_static': llAgents - }, - broadcast=False) - - def send_env_and_wait(self): - for iAttempt in range(30): - if self.is_renderer_ready(): - print("Background Render complete") - break - else: - print("Waiting for browser to signal that rendering complete") - time.sleep(1) - - @staticmethod - @socketio.on('renderEvent') - def handle_render_event(data): - cls=simple_flask_server - self = cls.instance - print('RenderEvent!!') - print('status: ' + data['status']) - print('message: ' + data['message']) - - if data['status'] == 'listening': - self.renderer_ready = True - - def is_renderer_ready(self): - return self.renderer_ready - - def agents_to_list_dict(self): - ''' Create a list of lists / dicts for serialisation - Maps from the internal representation in EnvAgent to - the schema used by the Javascript renderer. - ''' - llAgents = [] - for agent in self.env.agents: - if agent.position is None: - # the int()s are to convert from numpy int64 which causes problems in serialization - # to plain old python int - lPos = [int(agent.initial_position[0]), int(agent.initial_position[1])] - else: - lPos = [int(agent.position[0]), int(agent.position[1])] - - lAgent = [ - lPos, - int(agent.direction), - [int(agent.target[0]), int(agent.target[1])], 0, - { # dummy values: - "position_fraction": 0, - "speed": 1, - "transition_action_on_cellexit": 3 - }, - { - "malfunction": 0, - "malfunction_rate": 0, - "next_malfunction": 0, - "nr_malfunctions": 0 - } - ] - llAgents.append(lAgent) - return llAgents - - def agents_to_list(self): - llAgents = [] - for agent in self.env.agents: - if agent.position is None: - lPos = [int(agent.initial_position[0]), int(agent.initial_position[1])] - else: - lPos = [int(agent.position[0]), int(agent.position[1])] - iDir = int(agent.direction) - - lAgent = [*lPos, iDir] - - llAgents.append(lAgent) - return llAgents - - - -def main1(): - - print('Run Flask SocketIO Server') - server = simple_flask_server() - threading.Thread(target=server.run_flask_server).start() - # Open Browser - webbrowser.open('http://127.0.0.1:8080') - - print('Send Action') - for i in server.actions: - time.sleep(1) - print('send action') - server.socketio.emit('agentsAction', {'actions': i}) - - - - - -if __name__ == "__main__": - main1() \ No newline at end of file diff --git a/flatland/utils/graphics_pil.py b/flatland/utils/graphics_pil.py index 8ab3b662e0146efcf5a18e0e566ba21a62abbab8..4b51da2e1979e6365f5d7dabdc4871bc7aab9a8c 100644 --- a/flatland/utils/graphics_pil.py +++ b/flatland/utils/graphics_pil.py @@ -10,22 +10,6 @@ from pkg_resources import resource_string as resource_bytes from flatland.utils.graphics_layer import GraphicsLayer - -def enable_windows_cairo_support(): - if os.name == 'nt': - import site - import ctypes.util - default_os_path = os.environ['PATH'] - os.environ['PATH'] = '' - for s in site.getsitepackages(): - os.environ['PATH'] = os.environ['PATH'] + ';' + s + '\\cairo' - os.environ['PATH'] = os.environ['PATH'] + ';' + default_os_path - if ctypes.util.find_library('cairo') is None: - print("Error: cairo not installed") - - -enable_windows_cairo_support() -from cairosvg import svg2png # noqa: E402 from flatland.core.grid.rail_env_grid import RailEnvTransitions # noqa: E402 @@ -81,11 +65,9 @@ class PILGL(GraphicsLayer): sColors = "d50000#c51162#aa00ff#6200ea#304ffe#2962ff#0091ea#00b8d4#00bfa5#00c853" + \ "#64dd17#aeea00#ffd600#ffab00#ff6d00#ff3d00#5d4037#455a64" - self.agent_colors = [self.rgb_s2i(sColor) for sColor in sColors.split("#")] self.n_agent_colors = len(self.agent_colors) - # self.window_open = False self.firstFrame = True self.old_background_image = (None, None, None) self.create_layers() @@ -152,11 +134,24 @@ class PILGL(GraphicsLayer): self.draws[layer].rectangle([(x - r, y - r), (x + r, y + r)], fill=color, outline=color) def draw_image_xy(self, pil_img, xyPixLeftTop, layer=RAIL_LAYER, ): + + # Resize all PIL images just before drawing them + # to ensure that resizing doesnt affect the + # recolorizing strategies in place + # + # That said : All the code in this file needs + # some serious refactoring -_- to ensure the + # code style and structure is consitent. + # - Mohanty + pil_img = pil_img.resize( + (self.nPixCell, self.nPixCell) + ) + if (pil_img.mode == "RGBA"): pil_mask = pil_img else: pil_mask = None - + self.layers[layer].paste(pil_img, xyPixLeftTop, pil_mask) def draw_image_row_col(self, pil_img, rcTopLeft, layer=RAIL_LAYER, ): @@ -257,6 +252,11 @@ class PILGL(GraphicsLayer): class PILSVG(PILGL): + """ + Note : This class should now ideally be called as PILPNG, + but for backward compatibility, and to not introduce any breaking changes at this point + we are sticking to the legacy name of PILSVG (when in practice we are not using SVG anymore) + """ def __init__(self, width, height, jupyter=False, screen_width=800, screen_height=600): oSuper = super() oSuper.__init__(width, height, jupyter, screen_width, screen_height) @@ -282,106 +282,95 @@ class PILSVG(PILGL): self.lwAgents = [] self.agents_prev = [] - def pil_from_svg_file(self, package, resource): + def pil_from_png_file(self, package, resource): bytestring = resource_bytes(package, resource) - bytesPNG = svg2png(bytestring=bytestring, output_height=self.nPixCell, output_width=self.nPixCell) - with io.BytesIO(bytesPNG) as fIn: + with io.BytesIO(bytestring) as fIn: pil_img = Image.open(fIn) pil_img.load() - return pil_img - def pil_from_svg_bytes(self, bytesSVG): - bytesPNG = svg2png(bytesSVG, output_height=self.nPixCell, output_width=self.nPixCell) - with io.BytesIO(bytesPNG) as fIn: - pil_img = Image.open(fIn) - return pil_img - def load_buildings(self): lBuildingFiles = [ - "Buildings-Bank.svg", - "Buildings-Bar.svg", - "Buildings-Wohnhaus.svg", - "Buildings-Hochhaus.svg", - "Buildings-Hotel.svg", - "Buildings-Office.svg", - "Buildings-Polizei.svg", - "Buildings-Post.svg", - "Buildings-Supermarkt.svg", - "Buildings-Tankstelle.svg", - "Buildings-Fabrik_A.svg", - "Buildings-Fabrik_B.svg", - "Buildings-Fabrik_C.svg", - "Buildings-Fabrik_D.svg", - "Buildings-Fabrik_E.svg", - "Buildings-Fabrik_F.svg", - "Buildings-Fabrik_G.svg", - "Buildings-Fabrik_H.svg", - "Buildings-Fabrik_I.svg" + "Buildings-Bank.png", + "Buildings-Bar.png", + "Buildings-Wohnhaus.png", + "Buildings-Hochhaus.png", + "Buildings-Hotel.png", + "Buildings-Office.png", + "Buildings-Polizei.png", + "Buildings-Post.png", + "Buildings-Supermarkt.png", + "Buildings-Tankstelle.png", + "Buildings-Fabrik_A.png", + "Buildings-Fabrik_B.png", + "Buildings-Fabrik_C.png", + "Buildings-Fabrik_D.png", + "Buildings-Fabrik_E.png", + "Buildings-Fabrik_F.png", + "Buildings-Fabrik_G.png", + "Buildings-Fabrik_H.png", + "Buildings-Fabrik_I.png" ] - imgBg = self.pil_from_svg_file('flatland.svg', "Background_city.svg") + imgBg = self.pil_from_png_file('flatland.png', "Background_city.png") imgBg = imgBg.convert("RGBA") - #print("imgBg mode:", imgBg.mode) self.lBuildings = [] for sFile in lBuildingFiles: - #print("Loading:", sFile) - img = self.pil_from_svg_file('flatland.svg', sFile) - #print("img mode:", img.mode) + img = self.pil_from_png_file('flatland.png', sFile) img = Image.alpha_composite(imgBg, img) self.lBuildings.append(img) def load_scenery(self): scenery_files = [ - "Scenery-Laubbaume_A.svg", - "Scenery-Laubbaume_B.svg", - "Scenery-Laubbaume_C.svg", - "Scenery-Nadelbaume_A.svg", - "Scenery-Nadelbaume_B.svg", - "Scenery-Bergwelt_B.svg" + "Scenery-Laubbaume_A.png", + "Scenery-Laubbaume_B.png", + "Scenery-Laubbaume_C.png", + "Scenery-Nadelbaume_A.png", + "Scenery-Nadelbaume_B.png", + "Scenery-Bergwelt_B.png" ] scenery_files_d2 = [ - "Scenery-Bergwelt_C_Teil_1_links.svg", - "Scenery-Bergwelt_C_Teil_2_rechts.svg" + "Scenery-Bergwelt_C_Teil_1_links.png", + "Scenery-Bergwelt_C_Teil_2_rechts.png" ] scenery_files_d3 = [ - "Scenery-Bergwelt_A_Teil_1_links.svg", - "Scenery-Bergwelt_A_Teil_2_mitte.svg", - "Scenery-Bergwelt_A_Teil_3_rechts.svg" + "Scenery-Bergwelt_A_Teil_1_links.png", + "Scenery-Bergwelt_A_Teil_2_mitte.png", + "Scenery-Bergwelt_A_Teil_3_rechts.png" ] scenery_files_water = [ - "Scenery_Water.svg" + "Scenery_Water.png" ] - img_back_ground = self.pil_from_svg_file('flatland.svg', "Background_Light_green.svg").convert("RGBA") + img_back_ground = self.pil_from_png_file('flatland.png', "Background_Light_green.png").convert("RGBA") - self.scenery_background_white = self.pil_from_svg_file('flatland.svg', "Background_white.svg").convert("RGBA") + self.scenery_background_white = self.pil_from_png_file('flatland.png', "Background_white.png").convert("RGBA") self.scenery = [] for file in scenery_files: - img = self.pil_from_svg_file('flatland.svg', file) + img = self.pil_from_png_file('flatland.png', file) img = Image.alpha_composite(img_back_ground, img) self.scenery.append(img) self.scenery_d2 = [] for file in scenery_files_d2: - img = self.pil_from_svg_file('flatland.svg', file) + img = self.pil_from_png_file('flatland.png', file) img = Image.alpha_composite(img_back_ground, img) self.scenery_d2.append(img) self.scenery_d3 = [] for file in scenery_files_d3: - img = self.pil_from_svg_file('flatland.svg', file) + img = self.pil_from_png_file('flatland.png', file) img = Image.alpha_composite(img_back_ground, img) self.scenery_d3.append(img) self.scenery_water = [] for file in scenery_files_water: - img = self.pil_from_svg_file('flatland.svg', file) + img = self.pil_from_png_file('flatland.png', file) img = Image.alpha_composite(img_back_ground, img) self.scenery_water.append(img) @@ -389,55 +378,55 @@ class PILSVG(PILGL): """ Load the rail SVG images, apply rotations, and store as PIL images. """ rail_files = { - "": "Background_Light_green.svg", - "WE": "Gleis_Deadend.svg", - "WW EE NN SS": "Gleis_Diamond_Crossing.svg", - "WW EE": "Gleis_horizontal.svg", - "EN SW": "Gleis_Kurve_oben_links.svg", - "WN SE": "Gleis_Kurve_oben_rechts.svg", - "ES NW": "Gleis_Kurve_unten_links.svg", - "NE WS": "Gleis_Kurve_unten_rechts.svg", - "NN SS": "Gleis_vertikal.svg", - "NN SS EE WW ES NW SE WN": "Weiche_Double_Slip.svg", - "EE WW EN SW": "Weiche_horizontal_oben_links.svg", - "EE WW SE WN": "Weiche_horizontal_oben_rechts.svg", - "EE WW ES NW": "Weiche_horizontal_unten_links.svg", - "EE WW NE WS": "Weiche_horizontal_unten_rechts.svg", - "NN SS EE WW NW ES": "Weiche_Single_Slip.svg", - "NE NW ES WS": "Weiche_Symetrical.svg", - "NN SS EN SW": "Weiche_vertikal_oben_links.svg", - "NN SS SE WN": "Weiche_vertikal_oben_rechts.svg", - "NN SS NW ES": "Weiche_vertikal_unten_links.svg", - "NN SS NE WS": "Weiche_vertikal_unten_rechts.svg", - "NE NW ES WS SS NN": "Weiche_Symetrical_gerade.svg", - "NE EN SW WS": "Gleis_Kurve_oben_links_unten_rechts.svg" + "": "Background_Light_green.png", + "WE": "Gleis_Deadend.png", + "WW EE NN SS": "Gleis_Diamond_Crossing.png", + "WW EE": "Gleis_horizontal.png", + "EN SW": "Gleis_Kurve_oben_links.png", + "WN SE": "Gleis_Kurve_oben_rechts.png", + "ES NW": "Gleis_Kurve_unten_links.png", + "NE WS": "Gleis_Kurve_unten_rechts.png", + "NN SS": "Gleis_vertikal.png", + "NN SS EE WW ES NW SE WN": "Weiche_Double_Slip.png", + "EE WW EN SW": "Weiche_horizontal_oben_links.png", + "EE WW SE WN": "Weiche_horizontal_oben_rechts.png", + "EE WW ES NW": "Weiche_horizontal_unten_links.png", + "EE WW NE WS": "Weiche_horizontal_unten_rechts.png", + "NN SS EE WW NW ES": "Weiche_Single_Slip.png", + "NE NW ES WS": "Weiche_Symetrical.png", + "NN SS EN SW": "Weiche_vertikal_oben_links.png", + "NN SS SE WN": "Weiche_vertikal_oben_rechts.png", + "NN SS NW ES": "Weiche_vertikal_unten_links.png", + "NN SS NE WS": "Weiche_vertikal_unten_rechts.png", + "NE NW ES WS SS NN": "Weiche_Symetrical_gerade.png", + "NE EN SW WS": "Gleis_Kurve_oben_links_unten_rechts.png" } target_files = { - "EW": "Bahnhof_#d50000_Deadend_links.svg", - "NS": "Bahnhof_#d50000_Deadend_oben.svg", - "WE": "Bahnhof_#d50000_Deadend_rechts.svg", - "SN": "Bahnhof_#d50000_Deadend_unten.svg", - "EE WW": "Bahnhof_#d50000_Gleis_horizontal.svg", - "NN SS": "Bahnhof_#d50000_Gleis_vertikal.svg"} + "EW": "Bahnhof_#d50000_Deadend_links.png", + "NS": "Bahnhof_#d50000_Deadend_oben.png", + "WE": "Bahnhof_#d50000_Deadend_rechts.png", + "SN": "Bahnhof_#d50000_Deadend_unten.png", + "EE WW": "Bahnhof_#d50000_Gleis_horizontal.png", + "NN SS": "Bahnhof_#d50000_Gleis_vertikal.png"} # Dict of rail cell images indexed by binary transitions - pil_rail_files_org = self.load_svgs(rail_files, rotate=True) - pil_rail_files = self.load_svgs(rail_files, rotate=True, background_image="Background_rail.svg", - whitefilter="Background_white_filter.svg") + pil_rail_files_org = self.load_pngs(rail_files, rotate=True) + pil_rail_files = self.load_pngs(rail_files, rotate=True, background_image="Background_rail.png", + whitefilter="Background_white_filter.png") # Load the target files (which have rails and transitions of their own) # They are indexed by (binTrans, iAgent), ie a tuple of the binary transition and the agent index - pil_target_files_org = self.load_svgs(target_files, rotate=False, agent_colors=self.agent_colors) - pil_target_files = self.load_svgs(target_files, rotate=False, agent_colors=self.agent_colors, - background_image="Background_rail.svg", - whitefilter="Background_white_filter.svg") + pil_target_files_org = self.load_pngs(target_files, rotate=False, agent_colors=self.agent_colors) + pil_target_files = self.load_pngs(target_files, rotate=False, agent_colors=self.agent_colors, + background_image="Background_rail.png", + whitefilter="Background_white_filter.png") # Load station and recolorize them - station = self.pil_from_svg_file('flatland.svg', "Bahnhof_#d50000_target.svg") + station = self.pil_from_png_file('flatland.png', "Bahnhof_#d50000_target.png") self.station_colors = self.recolor_image(station, [0, 0, 0], self.agent_colors, False) - cell_occupied = self.pil_from_svg_file('flatland.svg', "Cell_occupied.svg") + cell_occupied = self.pil_from_png_file('flatland.png', "Cell_occupied.png") self.cell_occupied = self.recolor_image(cell_occupied, [0, 0, 0], self.agent_colors, False) # Merge them with the regular rails. @@ -445,7 +434,7 @@ class PILSVG(PILGL): self.pil_rail = {**pil_rail_files, **pil_target_files} self.pil_rail_org = {**pil_rail_files_org, **pil_target_files_org} - def load_svgs(self, file_directory, rotate=False, agent_colors=False, background_image=None, whitefilter=None): + def load_pngs(self, file_directory, rotate=False, agent_colors=False, background_image=None, whitefilter=None): pil = {} transitions = RailEnvTransitions() @@ -466,14 +455,14 @@ class PILSVG(PILGL): transition_16_bit_string = "".join(transition_16_bit) binary_trans = int(transition_16_bit_string, 2) - pil_rail = self.pil_from_svg_file('flatland.svg', file).convert("RGBA") + pil_rail = self.pil_from_png_file('flatland.png', file).convert("RGBA") if background_image is not None: - img_bg = self.pil_from_svg_file('flatland.svg', background_image).convert("RGBA") + img_bg = self.pil_from_png_file('flatland.png', background_image).convert("RGBA") pil_rail = Image.alpha_composite(img_bg, pil_rail) if whitefilter is not None: - img_bg = self.pil_from_svg_file('flatland.svg', whitefilter).convert("RGBA") + img_bg = self.pil_from_png_file('flatland.png', whitefilter).convert("RGBA") pil_rail = Image.alpha_composite(pil_rail, img_bg) if rotate: @@ -565,7 +554,7 @@ class PILSVG(PILGL): if target is not None: if is_selected: - svgBG = self.pil_from_svg_file('flatland.svg', "Selected_Target.svg") + svgBG = self.pil_from_png_file('flatland.png', "Selected_Target.png") self.clear_layer(PILGL.SELECTED_TARGET_LAYER, 0) self.draw_image_row_col(svgBG, (row, col), layer=PILGL.SELECTED_TARGET_LAYER) @@ -578,6 +567,7 @@ class PILSVG(PILGL): xy_color_mask = np.all(rgbaImg[:, :, 0:3] - a3BaseColor != 0, axis=2) else: xy_color_mask = np.all(rgbaImg[:, :, 0:3] - a3BaseColor == 0, axis=2) + rgbaImg2 = np.copy(rgbaImg) # Repaint the base color with the new color @@ -590,9 +580,9 @@ class PILSVG(PILGL): # Seed initial train/zug files indexed by tuple(iDirIn, iDirOut): file_directory = { - (0, 0): "Zug_Gleis_#0091ea.svg", - (1, 2): "Zug_1_Weiche_#0091ea.svg", - (0, 3): "Zug_2_Weiche_#0091ea.svg" + (0, 0): "Zug_Gleis_#0091ea.png", + (1, 2): "Zug_1_Weiche_#0091ea.png", + (0, 3): "Zug_2_Weiche_#0091ea.png" } # "paint" color of the train images we load - this is the color we will change. @@ -605,7 +595,7 @@ class PILSVG(PILGL): for directions, path_svg in file_directory.items(): in_direction, out_direction = directions - pil_zug = self.pil_from_svg_file('flatland.svg', path_svg) + pil_zug = self.pil_from_png_file('flatland.png', path_svg) # Rotate both the directions and the image and save in the dict for rot_direction in range(4): @@ -635,7 +625,7 @@ class PILSVG(PILGL): self.draw_image_row_col(self.scenery_background_white, (row, col), layer=PILGL.RAIL_LAYER) if is_selected: - bg_svg = self.pil_from_svg_file('flatland.svg', "Selected_Agent.svg") + bg_svg = self.pil_from_png_file('flatland.png', "Selected_Agent.png") self.clear_layer(PILGL.SELECTED_AGENT_LAYER, 0) self.draw_image_row_col(bg_svg, (row, col), layer=PILGL.SELECTED_AGENT_LAYER) if show_debug: diff --git a/flatland/utils/graphics_tkpil.py b/flatland/utils/graphics_tkpil.py deleted file mode 100644 index 7e89e734a170e746c07a4779f4f12e2ff88cf42e..0000000000000000000000000000000000000000 --- a/flatland/utils/graphics_tkpil.py +++ /dev/null @@ -1,52 +0,0 @@ - -import tkinter as tk - -from PIL import ImageTk -# from numpy import array -# from pkg_resources import resource_string as resource_bytes - -# from flatland.utils.graphics_layer import GraphicsLayer -from flatland.utils.graphics_pil import PILSVG - - -class TKPILGL(PILSVG): - # tk.Tk() must be a singleton! - # https://stackoverflow.com/questions/26097811/image-pyimage2-doesnt-exist - window = tk.Tk() - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.window_open = False - - def open_window(self): - print("open_window - tk") - assert self.window_open is False, "Window is already open!" - self.__class__.window.title("Flatland") - self.__class__.window.configure(background='grey') - self.window_open = True - - def close_window(self): - self.panel.destroy() - # quit but not destroy! - self.__class__.window.quit() - - def show(self, block=False): - # print("show - ", self.__class__) - img = self.alpha_composite_layers() - - if not self.window_open: - self.open_window() - - tkimg = ImageTk.PhotoImage(img) - - if self.firstFrame: - # Do TK actions for a new panel (not sure what they really do) - self.panel = tk.Label(self.window, image=tkimg) - self.panel.pack(side="bottom", fill="both", expand="yes") - else: - # update the image in situ - self.panel.configure(image=tkimg) - self.panel.image = tkimg - - self.__class__.window.update() - self.firstFrame = False diff --git a/flatland/utils/rendertools.py b/flatland/utils/rendertools.py index 196f4a382ac0b92f975384f9aeaa3d4127d6e93a..cfcb530fb75614b84155f85b08086bfd82535d0f 100644 --- a/flatland/utils/rendertools.py +++ b/flatland/utils/rendertools.py @@ -8,6 +8,7 @@ from numpy import array from recordtype import recordtype from flatland.utils.graphics_pil import PILGL, PILSVG +from flatland.utils.graphics_pgl import PGLGL # TODO: suggested renaming to RailEnvRenderTool, as it will only work with RailEnv! @@ -21,7 +22,8 @@ class AgentRenderVariant(IntEnum): class RenderTool(object): - """ RenderTool is a facade to a renderer, either local or browser + """ RenderTool is a facade to a renderer. + (This was introduced for the Browser / JS renderer which has now been removed.) """ def __init__(self, env, gl="PGL", jupyter=False, agent_render_variant=AgentRenderVariant.ONE_STEP_BEHIND, @@ -35,20 +37,13 @@ class RenderTool(object): self.agent_render_variant = agent_render_variant - if gl in ["PIL", "PILSVG", "TKPIL", "TKPILSVG", "PGL"]: + if gl in ["PIL", "PILSVG", "PGL"]: self.renderer = RenderLocal(env, gl, jupyter, agent_render_variant, show_debug, clear_debug_text, screen_width, screen_height) - - # To support legacy access to the GraphicsLayer (gl) - # DEPRECATED - TODO: remove these calls! self.gl = self.renderer.gl - - elif gl == "BROWSER": - from flatland.utils.flask_util import simple_flask_server - self.renderer = RenderBrowser(env, host=host, port=port) else: - print("[", gl, "] not found, switch to PILSVG or BROWSER") + print("[", gl, "] not found, switch to PGL") def render_env(self, show=False, # whether to call matplotlib show() or equivalent after completion @@ -98,7 +93,6 @@ class RenderTool(object): return None - class RenderBase(object): def __init__(self, env): pass @@ -124,56 +118,6 @@ class RenderBase(object): pass -class RenderBrowser(RenderBase): - def __init__(self, env, host="localhost", port=None): - self.server = simple_flask_server(env) - self.server.run_flask_server_in_thread(host=host, port=port) - self.env = env - self.background_rendered = False - - def render_env(self, - show=False, # whether to call matplotlib show() or equivalent after completion - show_agents=True, # whether to include agents - show_inactive_agents=False, - show_observations=True, # whether to include observations - show_predictions=False, # whether to include predictions - frames=False, # frame counter to show (intended since invocation) - episode=None, # int episode number to show - step=None, # int step number to show in image - selected_agent=None, # indicate which agent is "selected" in the editor): - return_image=False): # indicate if image is returned for use in monitor: - - if not self.background_rendered: - self.server.send_env_and_wait() - self.background_rendered = True - - self.server.send_actions({}) - - if show_observations: - self.render_observation(range(self.env.get_num_agents()), self.env.dev_obs_dict) - - def render_observation(self, agent_handles, dict_observation): - # Change keys to strings, and OrderedSet to list (of tuples) - dict_obs2 = {str(item[0]): list(item[1]) for item in self.env.dev_obs_dict.items()} - # Convert any ranges into a list - list_handles = list(agent_handles) - self.server.send_observation(list_handles, dict_obs2) - - def get_port(self): - return self.server.port - - def get_endpoint_url(self): - return self.server.get_endpoint_url() - - def close_window(self): - pass - - def reset(self): - pass - - def set_new_rail(self): - pass - class RenderLocal(RenderBase): """ Class to render the RailEnv and agents. @@ -211,19 +155,11 @@ class RenderLocal(RenderBase): self.gl = PILGL(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) elif gl == "PILSVG": self.gl = PILSVG(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) - elif gl in ["TKPILSVG", "TKPIL"]: - # Conditional import to avoid importing tkinter unless required. - print("Importing TKPILGL - requires a local display!") - from flatland.utils.graphics_tkpil import TKPILGL - self.gl = TKPILGL(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) - elif gl in ["PGL"]: - # Conditional import - from flatland.utils.graphics_pgl import PGLGL - self.gl = PGLGL(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) else: - print("[", gl, "] not found, switch to PGL, PILSVG, TKPIL (deprecated) or BROWSER") - print("Using PILSVG.") - self.gl = PILSVG(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) + if gl != "PGL": + print("[", gl, "] not found, switch to PGL, PILSVG") + print("Using PGL") + self.gl = PGLGL(env.width, env.height, jupyter, screen_width=screen_width, screen_height=screen_height) self.new_rail = True self.show_debug = show_debug @@ -582,7 +518,7 @@ class RenderLocal(RenderBase): """ # if type(self.gl) is PILSVG: - if self.gl_str in ["PILSVG", "TKPIL", "TKPILSVG", "PGL"]: + if self.gl_str in ["PILSVG", "PGL"]: return self.render_env_svg(show=show, show_observations=show_observations, show_predictions=show_predictions, diff --git a/requirements_dev.txt b/requirements_dev.txt index f0486d78d9de949b1735de6fbf7c3f402fc48fff..75ed1bf26924a366e3aabd8da1e2e34480f647bd 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -8,19 +8,14 @@ numpy>=1.16.2 recordtype>=1.3 matplotlib>=3.0.2 Pillow>=5.4.1 -CairoSVG>=2.3.1 msgpack==0.6.1 msgpack-numpy>=0.4.4.0 svgutils>=0.3.1 pyarrow>=0.13.0 pandas>=0.25.1 importlib-metadata>=0.17 -importlib-resources>=1.0.1 +importlib-resources>=1.0.1,<2 six>=1.12.0 timeout-decorator>=0.4.1 attrs -ushlex gym==0.14.0 -flask -flask_cors -flask_socketio diff --git a/scripts/convert_svg_2_png.py b/scripts/convert_svg_2_png.py new file mode 100755 index 0000000000000000000000000000000000000000..398835490ad54eb69a8fdf2e7daeac6f7ab1186d --- /dev/null +++ b/scripts/convert_svg_2_png.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +import glob +from cairosvg import svg2png +import os +import shutil +import tqdm + +import io +from PIL import Image + +######################################################## +######################################################## +# +# Converts SVG assets into PNG assets +# +# We use this approach to drop the CairoSVG dependency +# from the flatland requirements. +# +# Usage Requires : +# +# conda install cairo +# +######################################################## +######################################################## + +TARGET_PNG_WIDTH=300 +TARGET_PNG_HEIGHT=300 + +SVG_FOLDER="../flatland/svg" +TARGET_FOLDER="../flatland/png" + +# Delete target PNG files, if they exist +for _png_file in glob.glob(os.path.join(TARGET_FOLDER, "*.png")): + os.remove(_png_file) + +# Convert all SVG files into PNG files +for _source_svg_path in tqdm.tqdm(glob.glob(os.path.join(SVG_FOLDER, "*.svg"))): + base_filename = os.path.basename(_source_svg_path) + target_filename = base_filename.replace(".svg", ".png") + target_filepath = os.path.join( + TARGET_FOLDER, + target_filename + ) + bytesPNG = svg2png( + file_obj=open(_source_svg_path, "rb"), + output_height=TARGET_PNG_WIDTH, + output_width=TARGET_PNG_HEIGHT + ) + with io.BytesIO(bytesPNG) as fIn: + im = Image.open(fIn) + im.load() + assert im.size == (TARGET_PNG_WIDTH, TARGET_PNG_HEIGHT) + im.save(target_filepath) + diff --git a/setup.py b/setup.py index 3219cef388ff1972f859e68a4cb79a427973ddce..5070690a0f6f8becceb70ef8af4c1702e18f4b2c 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import sys from setuptools import setup, find_packages assert sys.version_info >= (3, 6) -with open('README.md') as readme_file: +with open('README.md', 'r', encoding='utf8') as readme_file: readme = readme_file.read() diff --git a/tox.ini b/tox.ini index e22607811c9741a347cdc67303ba459087e02d7c..0023ee34bca2e26f30199bc2e9b2c93bdf779dd2 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,6 @@ commands = flake8 flatland tests examples benchmarks [testenv:docs] -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 whitelist_externals = make passenv = @@ -29,8 +28,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk graphviz conda_channels : @@ -44,7 +41,6 @@ commands = make docs [testenv:coverage] -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 whitelist_externals = make passenv = @@ -53,8 +49,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -67,7 +61,6 @@ commands = python make_coverage.py [testenv:benchmarks] -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 setenv = PYTHONPATH = {toxinidir} @@ -87,7 +80,6 @@ commands = python {toxinidir}/benchmarks/benchmark_all_examples.py [testenv:profiling] -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 setenv = PYTHONPATH = {toxinidir} @@ -98,8 +90,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -113,7 +103,6 @@ commands = [testenv:examples] ; TODO should examples be run with py36 and py37?? -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 setenv = PYTHONPATH = {toxinidir} @@ -124,8 +113,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -139,7 +126,6 @@ commands = [testenv:notebooks] ; TODO should examples be run with py36 and py37?? -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 setenv = PYTHONPATH = {toxinidir} @@ -154,8 +140,6 @@ deps = -r{toxinidir}/requirements_dev.txt -r{toxinidir}/requirements_continuous_integration.txt conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -170,7 +154,6 @@ commands = python {toxinidir}/notebooks/run_all_notebooks.py [testenv:start_jupyter] -; use python3.6 because of incompatibility under Windows of the pycairo installed through conda for py37 basepython = python3.6 setenv = PYTHONPATH = {toxinidir} @@ -185,8 +168,6 @@ deps = -r{toxinidir}/requirements_dev.txt -r{toxinidir}/requirements_continuous_integration.txt conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -209,8 +190,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge @@ -224,7 +203,6 @@ commands = python -m pytest --basetemp={envtmpdir} {toxinidir} [testenv:py37] -; exclude py37 from Windows because of incompatibility the pycairo installed through conda for py37 platform = linux|linux2|darwin setenv = PYTHONPATH = {toxinidir} @@ -235,8 +213,6 @@ passenv = HTTP_PROXY HTTPS_PROXY conda_deps = - cairosvg - pycairo tk conda_channels : conda-forge