Map and Image Annotator NetLogo Model
Produced for the book series "Artificial Intelligence";
Author: W. J. Teahan; Publisher: Ventus Publishing Aps, Denmark.
powered by NetLogo
view/download model file: Map-and-Image-Annotator.nlogo
WHAT IS IT?
This model allows the user to annotate a map or an image. The model imports an image into the background for the environment. The user can then add arrows, circles, text and marks (i.e. x's). These can be later edited or erased if required.
HOW IT WORKS
The map or image is placed in the background using the import-drawing command. Separate turtle agent breeds - arrow, circle, text and mark - are used for drawing the corresponding object in the environment. A further side turtle agent is used for drawing the sides of the rectangular box used by the select-region and erase-region for selecting and erasing multiple objects.
Arrows are drawn using two arrow turtle agents. The start arrow turtle agent is given a circle shape, and the end arrow turtle agent is drawn using NetLogo's default arrowhead shape. The shaft of the arrow is drawn by creating a link between the two arrow turtle agents. Circles and marks are standard turtle agents with a specific size, colour and thickness drawn at a specific location using the mouse. Text is drawn by setting the label of turtle agents that are drawn with size 0 - i.e. only the label of the agent is made visible, not the agent itself.
NetLogo's distancxy reporter is used to find the nearest object by the select-object and erase-object procedures. The watch command is used to highlight the selected object. The global variable selected is used by the select-region and erase-region procedures to hold an agentset of objects that are within the specified region. The entire agentset can then easily be dragged together or erased in unison using a single ask command.
HOW TO USE IT
Pressing setup clears the environment and then loads the image as specified by the map-or-image-to-use chooser. Then the user can place arrows, circles, text and marks over the top of the image using the draw-arrow, draw-circle, draw-text and draw-mark buttons by pointing then clicking using the mouse.
The buttons in the Interface are defined as follows:
- setup: This clears the environment and loads a new image as specified by the map-or-image-to-use chooser
- draw-arrow: This will draw an arrow over the top of the image. If the user then clicks and drags the mouse, an arrow is drawn with the tail at the point the mouse was clicked, and the head at the point the mouse was released. (The mouse must be both clicked and dragged, otherwise no arrow is drawn). The colour and dimensions of the arrow are specified by the arrow-colour, arrow-start-size, arrow-end-size and arrow-thickness sliders. To get just a single arrow head shape without the shaft and arrow tail, then use the erase-object button to erase the end of the arrow. (This can also be used to erase the arrow head and leave just the tail if so desired).
- draw-circle: This will draw a circle over the top of the image at the point the mouse is next clicked. The colour and dimensions of the circle are specified by the circle-colour, circle-size and circle-thickness sliders.
- draw-text: This will draw text over the top of the image at the point the mouse is next clicked. Note that the right side of the text will be set to the mouse click point (rather than the left). The content of the text is specified by the text-to-insert input box. To update this, the user must click inside the input box, then edit the existing text or clear it and replace it with new text. The text update is only completed when the user types the return key. The colour of the text is specified by the text-colour slider.
- draw-mark: This will draw a mark over the top of the image at the point the mouse is next clicked.
- select-object: This will select an object if it is near to the next mouse click point. The object will have a halo placed around it to show when it has been selected. Subsequently dragging the mouse will result in the selected object being dragged around. An object is an arrow head or tail, a circle, text or a mark. When dragging the head or tail of an arrow, the other end will remain stationary (i.e. the arrow will pivot around the other end).
- erase-object: This will erase an object if it is near to the next mouse click point. If an arrow head or tail is erased, then the shaft is erased as well, and only the other end will remain.
- select-region: This allows multiple objects to be selected. Click using the mouse then drag. A rectangular box will delimit the region of objects that are selected. Temporarily stop clicking the mouse, then click back somewhere inside the rectangular box, then drag it and everything inside it using the mouse. All the objects inside the box will move to the point where the mouse is dragged to.
The Interface's choosers, sliders and input box are defined as follows:
- map-or-image-to-use: This specifies which image gets loaded into the environment. If set to "User-specified", then the user will be prompted for an image filename. (This will not work when the model is invoked in an applet).
- arrow-colour: This sets the colour of the arrow that is drawn when the draw-arrow button is next pressed. The colour is specified in a range from 0 to 140 using NetLogo's colour numbering scheme. Sample colour numbers are shown in the small text note at the left bottom of the Interface.
- arrow-start-size: This sets the size of the arrow tail (drawn as a filled-in circle).
- arrow-end-size: This sets the size of the arrow head (drawn using the default arrowhead shape).
- arrow-thickness: This sets the thickness of the arrow's shaft.
- circle-colour: This sets the colour of the circle that is drawn when the draw-circle button is next pressed. The colour is specified in a range from 0 to 140 using NetLogo's colour numbering scheme. Sample colour numbers are shown in the small text note at the left bottom of the Interface.
- circle-size: This sets the size of the circle.
- circle-thickness: This sets the thickness of the circle.
- text-to-insert: This sets the text that is drawn when the draw-text is next pressed. The text is right justified rather than left justified. i.e. The end of the text (not the start) will end up at the point where the mouse is clicked. The size of the text can be specified globally using the Settings button at the top of the Interface.
- text-colour: This sets the colour of the text that is drawn when the draw-text button is next pressed. The colour is specified in a range from 0 to 140 using NetLogo's colour numbering scheme. Sample colour numbers are shown in the small text note at the left bottom of the Interface.
- mark-colour: This sets the colour of the mark (i.e. a letter "x") that is drawn when the draw-mark button is next pressed. The colour is specified in a range from 0 to 140 using NetLogo's colour numbering scheme. Sample colour numbers are shown in the small text note at the left bottom of the Interface.
- mark-size: This sets the size of the mark.
THINGS TO NOTICE
Notice that some of the images do not fit the environment exactly (there are white unfilled areas above and below the image in the environment). This is because the import-drawing command maintains the same aspect ratio of the image (i.e. the width and height have the same ratio relative to each other as the image is scaled). The image, however, is sized to fit the environment, and therefore to keep the same aspect ratio, there will be some unfilled areas in the environment as a result.
THINGS TO TRY
Try using the model to annotate your own map or image, such as a photo you might have taken on holiday. Then use the print screen feature on your computer to save the annotated image.
EXTENDING THE MODEL
Try modifying the model so that it allows the user to draw lines and add further objects.
The code makes use of the watch, subject and perspective commands when the select-object button is used to place a halo around the selected object.
See the Mouse Drag Multiple Example and Mouse Drag One Example models.
CREDITS AND REFERENCES
The model makes use of code provided by Uri Wilensky in the Mouse Drag Multiple Example and Mouse Drag One Example models.
This model was created by William John Teahan.
To refer to this model in publications, please use:
Map and Image Annotator NetLogo model.
Teahan, W. J. (2010). Artificial Intelligence. Ventus Publishing Aps
breed [ arrows arrow ] ;; for drawing arrows breed [ circles circle ] ;; for drawing circles breed [ texts text ] ;; for drawing text breed [ marks mark ] ;; for drawing marks (i.e. "X" marks the spot) breed [ sides side ] ;; the four sides of the selection square globals [ selected ;; agentset of currently selected objects ] to setup ca ; clear everything ask patches [ set pcolor white ] ; make the background white setup-map-or-image ; ask turtles [ die ] set selected no-turtles set-default-shape sides "line" end to setup-map-or-image ifelse (map-or-image-to-use = "User-specified") [ import-drawing user-file ] [ let maps [ "Sample map 1" "Map-and-Image-Annotator-Sample-Map-1.jpg" "Sample map 2" "Map-and-Image-Annotator-Sample-Map-2.jpg" "Sample map 3" "Map-and-Image-Annotator-Sample-Map-3.png" "Sample map 4" "Map-and-Image-Annotator-Sample-Map-4.png" "Sample image 1" "Map-and-Image-Annotator-Sample-image-1.jpg" "Sample image 2" "Map-and-Image-Annotator-Sample-image-2.jpg" "Sample image 3" "Map-and-Image-Annotator-Sample-image-3.jpg" "Sample image 4" "Map-and-Image-Annotator-Sample-image-4.jpg" ] let p position map-or-image-to-use maps let filename item (p + 1) maps import-drawing filename ] end to draw-arrow ; Draws an arrow at the point the mouse has been pressed. let start-arrow-point nobody let end-arrow-point nobody if mouse-down? [ create-arrows 1 ; create the starting point of the arrow [ set start-arrow-point self set size arrow-start-size set shape "circle" ; hide-turtle set color arrow-colour setxy mouse-xcor mouse-ycor ] while [mouse-down?] [ ] ; wait until mouse is lifted create-arrows 1 ; create the ending point of the arrow [ set end-arrow-point self set size arrow-end-size set color arrow-colour setxy mouse-xcor mouse-ycor ifelse (xcor = [xcor] of start-arrow-point) and (ycor = [ycor] of start-arrow-point) [ ; the head and the tail are in the same place - delete them ask start-arrow-point [ die ] die ] [ ; the head the tail are at different locations, so draw the arrow face start-arrow-point ; head opposite to direction to start point rt 180 ; face opposite direction create-link-with start-arrow-point [ set thickness arrow-thickness set color arrow-colour ] ] ] ] display end to create-circle ; Creates a circle agent for drawing circles. set shape "thin ring" ; this was drawn with the Turtle Shapes Editor set size circle-size set color circle-colour __set-line-thickness circle-thickness setxy mouse-xcor mouse-ycor while [mouse-down?] [ display setxy mouse-xcor mouse-ycor ] end to draw-circle ; Draws a circle at the point the mouse has been pressed. if mouse-down? [ create-circles 1 [ create-circle ] ] display end to create-text ; Creates a text agent for drawing text. set label-color text-colour set size 0 set label text-to-insert setxy mouse-xcor mouse-ycor while [mouse-down?] [ display setxy mouse-xcor mouse-ycor ] end to draw-text ; Draws text at the point the mouse has been pressed. if mouse-down? [ create-texts 1 [ create-text ] ] display end to create-mark ; Creates a mark agent for drawing a mark (i.e. "X marks the spot". set color mark-colour set size mark-size set shape "x" setxy mouse-xcor mouse-ycor while [mouse-down?] [ display setxy mouse-xcor mouse-ycor ] end to draw-mark ; Draws text at the point the mouse has been pressed. if mouse-down? [ create-marks 1 [ create-mark ] ] display end to reorient-arrow-agents ; For ensuring that the arrowheads stay facing the same heading as the ; arrow shafts. if (shape != "circle") and (count link-neighbors > 0) [ face one-of link-neighbors rt 180 ; face away ] if (shape = "circle") and (count link-neighbors > 0) [ ask link-neighbors [ face myself rt 180 ; face away ] ] end to erase-object if mouse-down? [ let candidate min-one-of turtles [distancexy mouse-xcor mouse-ycor] if (candidate != nobody) [ if [distancexy mouse-xcor mouse-ycor] of candidate < 3 [ ask candidate [ die ]] ] display ] end to select-object ;; selects an object on the map and "watches" it if mouse-down? [ let candidate min-one-of turtles [distancexy mouse-xcor mouse-ycor] if [distancexy mouse-xcor mouse-ycor] of candidate < 3 [ ;; The WATCH primitive puts a "halo" around the watched turtle. watch candidate while [mouse-down?] [ ;; If we don't force the display to update, the user won't ;; be able to see the turtle moving around. display ;; The SUBJECT primitive reports the turtle being watched. ask subject [ setxy mouse-xcor mouse-ycor reorient-arrow-agents ] ] ;; Undoes the effects of WATCH. Can be abbreviated RP. reset-perspective ] ] end to erase-region ;; erases the selected region ask selected [ die ] ask sides [ die ] display set selected no-turtles ;;handle-select end to select-region if mouse-down? [ ifelse selected? mouse-xcor mouse-ycor [ handle-drag deselect ] [ handle-select ] ] end to handle-select ;; remember where the mouse pointer was located when ;; the user pressed the mouse button let old-x mouse-xcor let old-y mouse-ycor while [mouse-down?] [ select old-x old-y mouse-xcor mouse-ycor ;; update the view, otherwise the user can't see ;; what's going on display ] ;; if no turtles are selected, kill off ;; the selection square and start over if not any? selected [ deselect ] end to handle-drag ;; remember where the mouse pointer was located when ;; the user pressed the mouse button let old-x mouse-xcor let old-y mouse-ycor if selected? old-x old-y [ while [mouse-down?] [ let new-x mouse-xcor let new-y mouse-ycor let new-x1 0 let new-y1 0 ;; we need to move both the selected turtles and the sides ;; of the selection square by the same amount that the ;; mouse has moved. we do this by subtracting the current ;; mouse coordinates from the previous mouse coordinates ;; and adding the results to the coordinates of the turtles ;; and sides. ask selected [ set new-x1 xcor + new-x - old-x set new-y1 ycor + new-y - old-y if (new-x1 >= min-pxcor) and (new-x1 <= max-pxcor) and (new-y1 >= min-pycor) and (new-y1 <= max-pycor) [ setxy new-x1 new-y1 reorient-arrow-agents ] ] ask sides [ set new-x1 xcor + new-x - old-x set new-y1 ycor + new-y - old-y if (new-x1 >= min-pxcor) and (new-x1 <= max-pxcor) and (new-y1 >= min-pycor) and (new-y1 <= max-pycor) [ setxy new-x1 new-y1 ] ] set old-x new-x set old-y new-y ;; update the view, otherwise the user can't see ;; what's going on display ] ] end to deselect ask sides [ die ] set selected no-turtles end to select [x1 y1 x2 y2] ;; x1 y1 is initial corner and x2 y2 is current corner deselect ;; kill old selection square make-side x1 y1 x2 y1 make-side x1 y1 x1 y2 make-side x1 y2 x2 y2 make-side x2 y1 x2 y2 set selected turtles with [selected? xcor ycor] end to make-side [x1 y1 x2 y2] ;; for each side, one thin line shape is created at the mid point of each segment ;; of the bounding box and scaled to the proper length create-sides 1 [ set color gray setxy (x1 + x2) / 2 (y1 + y2) / 2 facexy x1 y1 set size 2 * distancexy x1 y1 ] end ;; helper procedure that determines whether a point is ;; inside the selection square to-report selected? [x y] if not any? sides [ report false ] let y-max max [ycor] of sides ;; largest ycor is where the top is let y-min min [ycor] of sides ;; smallest ycor is where the bottom is let x-max max [xcor] of sides ;; largest xcor is where the right side is let x-min min [xcor] of sides ;; smallest xcor is where the left side is ;; report whether the input coordinates are within the square report x >= x-min and x <= x-max and y >= y-min and y <= y-max end