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 INTERFACE
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.
NETLOGO FEATURES
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.
RELATED MODELS
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
PROCEDURES
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
