diff --git a/flatland/utils/editor.py b/flatland/utils/editor.py index df1a4f15ef6e42a75f88e3e293d94b744e4205d0..a2e43ea6271d30146ca0d213e33188569bbe002a 100644 --- a/flatland/utils/editor.py +++ b/flatland/utils/editor.py @@ -766,6 +766,7 @@ class EditorModel(object): # No - select the agent self.iSelectedAgent = iAgent + self.init_agents_static = None self.redraw() def add_target(self, rcCell): diff --git a/flatland/utils/graphics_layer.py b/flatland/utils/graphics_layer.py index 8e08f7f81204d15c1914f93050c91203aac5cb65..ec4641ff1c3c22a12d4da565f80d33e16237829c 100644 --- a/flatland/utils/graphics_layer.py +++ b/flatland/utils/graphics_layer.py @@ -68,7 +68,7 @@ class GraphicsLayer(object): def get_cmap(self, *args, **kwargs): return plt.get_cmap(*args, **kwargs) - def setRailAt(self, row, col, binTrans, iTarget=None): + def setRailAt(self, row, col, binTrans, iTarget=None,isSelected=False): """ Set the rail at cell (row, col) to have transitions binTrans. The target argument can contain the index of the agent to indicate that agent's target is at that cell, so that a station can be @@ -76,7 +76,7 @@ class GraphicsLayer(object): """ pass - def setAgentAt(self, iAgent, row, col, iDirIn, iDirOut): + def setAgentAt(self, iAgent, row, col, iDirIn, iDirOut,isSelected=False): pass def resize(self, env): diff --git a/flatland/utils/graphics_pil.py b/flatland/utils/graphics_pil.py index 119f6dbfd6c85586007bc3c0532ddf1dad7dbd5d..43be7ed9917cbd4c9aef5dd1a9ec308c41fb6d09 100644 --- a/flatland/utils/graphics_pil.py +++ b/flatland/utils/graphics_pil.py @@ -193,6 +193,13 @@ class PILGL(GraphicsLayer): img = Image.new("RGBA", (self.widthPx, self.heightPx), (255, 255, 255, opacity)) return img + def clear_layer(self,iLayer=0, opacity = None): + if opacity is None: + opacity = 0 if iLayer > 0 else 255 + self.layers[iLayer] = img = self.create_image(opacity) + # We also need to maintain a Draw object for each layer + self.draws[iLayer] = ImageDraw.Draw(img) + def create_layer(self, iLayer=0, clear=True): # If we don't have the layers already, create them if len(self.layers) <= iLayer: @@ -207,14 +214,13 @@ class PILGL(GraphicsLayer): else: # We do already have this iLayer. Clear it if requested. if clear: - opacity = 0 if iLayer > 0 else 255 - self.layers[iLayer] = img = self.create_image(opacity) - # We also need to maintain a Draw object for each layer - self.draws[iLayer] = ImageDraw.Draw(img) + self.clear_layer(iLayer) - def create_layers(self, clear=True): - self.create_layer(0, clear=clear) - self.create_layer(1, clear=clear) + def create_layers(self, clear=True): + self.create_layer(0, clear=clear) # rail / background (scene) + self.create_layer(1, clear=clear) # agents + self.create_layer(2, clear=clear) # drawing layer for selected agent + self.create_layer(3, clear=clear) # drawing layer for selected agent's target class PILSVG(PILGL): @@ -373,7 +379,7 @@ class PILSVG(PILGL): return dPil - def setRailAt(self, row, col, binTrans, iTarget=None): + def setRailAt(self, row, col, binTrans, iTarget=None,isSelected=False): if iTarget is None: if binTrans in self.dPilRail: pilTrack = self.dPilRail[binTrans] @@ -387,6 +393,12 @@ class PILSVG(PILGL): else: print("Illegal target rail:", row, col, format(binTrans, "#018b")[2:]) + if isSelected: + svgBG = self.pilFromSvgFile("./svg/Selected_Agent.svg") + self.clear_layer(3,0) + self.drawImageRC(svgBG,(row,col),layer=3) + + def recolorImage(self, pil, a3BaseColor, ltColors): rgbaImg = array(pil) lPils = [] @@ -435,7 +447,7 @@ class PILSVG(PILGL): for iColor, pilZug3 in enumerate(lPils): self.dPilZug[(iDirIn2, iDirOut2, iColor)] = lPils[iColor] - def setAgentAt(self, iAgent, row, col, iDirIn, iDirOut): + def setAgentAt(self, iAgent, row, col, iDirIn, iDirOut,isSelected): delta_dir = (iDirOut - iDirIn) % 4 iColor = iAgent % self.nAgentColors # when flipping direction at a dead end, use the "iDirOut" direction. @@ -444,6 +456,11 @@ class PILSVG(PILGL): pilZug = self.dPilZug[(iDirIn % 4, iDirOut % 4, iColor)] self.drawImageRC(pilZug, (row, col), layer=1) + if isSelected: + svgBG = self.pilFromSvgFile("./svg/Selected_Agent.svg") + self.clear_layer(2,0) + self.drawImageRC(svgBG,(row,col),layer=2) + def main2(): gl = PILSVG(10, 10) diff --git a/flatland/utils/rendertools.py b/flatland/utils/rendertools.py index 7db0cc531b1ac0b24054e32b58c1fd1cfd92733e..d7dca5d7e3a66dc95fca60fe3886b1454086a498 100644 --- a/flatland/utils/rendertools.py +++ b/flatland/utils/rendertools.py @@ -757,10 +757,13 @@ class RenderTool(object): # store the targets dTargets = {} + dSelected = {} for iAgent, agent in enumerate(self.env.agents_static): if agent is None: continue dTargets[tuple(agent.target)] = iAgent + dSelected[tuple(agent.target)] = (iAgent==iSelectedAgent) + # Draw each cell independently for r in range(env.height): @@ -768,9 +771,13 @@ class RenderTool(object): binTrans = env.rail.grid[r, c] if (r, c) in dTargets: target = dTargets[(r, c)] + isSelected = dSelected[(r, c)] + print("isSelected=", isSelected) else: target = None - self.gl.setRailAt(r, c, binTrans, iTarget=target) + isSelected = False + + self.gl.setRailAt(r, c, binTrans, iTarget=target,isSelected=isSelected) for iAgent, agent in enumerate(self.env.agents): @@ -788,7 +795,7 @@ class RenderTool(object): # setAgentAt uses the agent index for the color # cmap = self.gl.get_cmap('hsv', lut=max(len(self.env.agents), len(self.env.agents_static) + 1)) - self.gl.setAgentAt(iAgent, *position, old_direction, direction) # ,color=cmap(iAgent)) + self.gl.setAgentAt(iAgent, *position, old_direction, direction, iSelectedAgent==iAgent) # ,color=cmap(iAgent)) if show_observations: self.renderObs(range(env.get_num_agents()), env.dev_obs_dict) diff --git a/notebooks/Editor2.ipynb b/notebooks/Editor2.ipynb index 00250ea80c931d2bbaa1afcb3a3aa1fdebf27c23..0645909b911be07a5cf53d75225350ad01723def 100644 --- a/notebooks/Editor2.ipynb +++ b/notebooks/Editor2.ipynb @@ -78,7 +78,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "<flatland.utils.graphics_pil.PILSVG object at 0x0000021AB01F0198> <class 'flatland.utils.graphics_pil.PILSVG'>\n", + "<flatland.utils.graphics_pil.PILSVG object at 0x0000022C5FB44198> <class 'flatland.utils.graphics_pil.PILSVG'>\n", "<super: <class 'PILSVG'>, <PILSVG object>> <class 'super'>\n", "Clear rails\n" ] @@ -123,7 +123,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "0f3ff6aff8954f3cb369b80b053f9f1a", + "model_id": "094a0a3e4351403d8d119b0696abaee4", "version_major": 2, "version_minor": 0 }, @@ -135,15 +135,11 @@ "output_type": "display_data" }, { - "ename": "AttributeError", - "evalue": "'EditorModel' object has no attribute 'model'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32mc:\\users\\u216993\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\flatland_rl-0.1.1-py3.6.egg\\flatland\\utils\\editor.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self, event)\u001b[0m\n\u001b[0;32m 386\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 387\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mevent\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 388\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 389\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 390\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mstart_run\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mevent\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mc:\\users\\u216993\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\flatland_rl-0.1.1-py3.6.egg\\flatland\\utils\\editor.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 771\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 772\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mplayer\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 773\u001b[1;33m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minit_agents_static\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0magents_static\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 774\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mplayer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mPlayer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 775\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mregen_rail\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreplace_agents\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mAttributeError\u001b[0m: 'EditorModel' object has no attribute 'model'" + "name": "stdout", + "output_type": "stream", + "text": [ + "<flatland.utils.graphics_pil.PILSVG object at 0x0000022C6066EC50> <class 'flatland.utils.graphics_pil.PILSVG'>\n", + "<super: <class 'PILSVG'>, <PILSVG object>> <class 'super'>\n" ] } ], @@ -161,7 +157,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "8df099a612d94e34bc64abd0263ae21f", + "model_id": "98b1504729884d8a9362dbf246d81f78", "version_major": 2, "version_minor": 0 }, diff --git a/svg/Selected_Agent.svg b/svg/Selected_Agent.svg new file mode 100644 index 0000000000000000000000000000000000000000..15761df861dd79c22a7099e04e4d76aefefb58f7 --- /dev/null +++ b/svg/Selected_Agent.svg @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Ebene_1" + x="0px" + y="0px" + viewBox="0 0 240 240" + style="enable-background:new 0 0 240 240;" + xml:space="preserve" + sodipodi:docname="Selected_Agent.svg" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata + id="metadata11"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs9" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1137" + id="namedview7" + showgrid="false" + inkscape:zoom="2.7812867" + inkscape:cx="205.50339" + inkscape:cy="161.549" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="Ebene_1" /> +<style + type="text/css" + id="style2"> + .st0{fill:#9CCB89;} +</style> + +<rect + id="rect13" + width="23.389822" + height="23.38983" + x="1.697217e-07" + y="-0.23616901" /><rect + id="rect13-0" + width="23.389822" + height="23.38983" + x="216.82077" + y="0.26172119" /><rect + id="rect13-0-0" + width="23.389822" + height="23.38983" + x="216.75911" + y="216.39955" /><rect + id="rect13-0-0-4" + width="23.389822" + height="23.38983" + x="0.50847793" + y="216.6974" /><rect + id="rect60" + width="2.5168207" + height="198.4693" + x="10.067283" + y="22.474777" /><rect + id="rect60-8" + width="2.5168207" + height="198.4693" + x="228.49136" + y="22.115229" /><rect + id="rect60-8-5" + width="2.5168207" + height="198.4693" + x="-11.868174" + y="19.775019" + transform="rotate(-90)" /><rect + id="rect60-8-5-1" + width="2.5168207" + height="198.4693" + x="-230.11249" + y="20.853657" + transform="rotate(-90)" /></svg> \ No newline at end of file