Reputation: 507
Is there a way to divide a rectangle into smaller, random size rectangles in Netlogo? Like the following image with 6 rectangles, one which has been subdivided, and the subdivision painted black:
This question is because I have a shp file of farmland loaded in Netlogo composed of regular rectangles, and want to simulate how they are subdivided and occupied by urban development. Size of subdivisions can be a range between 1/3 to 1/8 of total square. Thanks.
Upvotes: 0
Views: 204
Reputation: 10301
I think that's pretty tricky, especially if you want specific minimum dimensions. Maybe play around with the code below to see if it gets you started? It basically takes a rectangle input (a farm plot, potentially) and generates a whole bunch of overlapping rectangles. The problem with the random bit is that you can (as is) get sections that are narrower or taller than your 1/8 since you get overlap. Play around with the counter to increase or reduce the number of rectangles it makes- fewer means that the entire patch may not be subdivided, more means longer run time and potentially more small subdivisions.
patches-own [ id ]
to setup
ca
resize-world -50 50 -50 50
set-patch-size 4
ask patches [ set id -1 ]
ask rectangle -20 20 -40 40 [
set pcolor red
]
reset-ticks
end
to go
rectangle-sub -20 20 40 -40
tick
end
to rectangle-sub [ x0 x1 y0 y1 ]
; Make sure the x0 x1 / y0 y1 order is correct
let xp0 min (list x0 x1)
let xp1 max (list x0 x1)
let yp0 min (list y0 y1)
let yp1 max (list y0 y1)
; Define the rectangle to subdivide
let main_rect rectangle xp0 xp1 yp0 yp1
; Define width and height
let width xp1 - xp0
let height yp1 - yp0
let w3 round ( width / 3 )
let w8 round ( width / 8 )
let h3 round ( height / 3 )
let h8 round ( height / 8 )
; Set a while loop to make mini rectangles, with
; a counter to stop the loop after too many tries
let counter 0
while [ counter < 100 and any? main_rect with [id = -1 ] ] [
let newx0 xp0 + ( random width )
let newx1 newx0 + ( ceiling width / ( random 6 + 3 ) )
let newy0 yp0 + ( random height )
let newy1 newy0 + ( ceiling height / ( random 6 + 3 ) )
; define a sub rectangle
let newrect rectangle newx0 newx1 newy0 newy1
; remove any patches from the sub rectangle that are not
; also part of the main rectangle
set newrect newrect with [ member? self main_rect ]
if any? newrect [
; Make sure the dimensions aren't too small or big
let nwidth ( max [pxcor] of newrect - min [pxcor] of newrect )
let nheight ( max [pycor] of newrect - min [pycor] of newrect )
if nwidth < w3 and nwidth > w8 and nheight < h3 and nheight > h8 [
; Choose a random patch and assign its id to all others
; in the same newrect patch-set
let groupid random 10000
ask newrect [
set id groupid
set pcolor id / 100
]
]
]
set counter counter + 1
]
print counter
end
to-report rectangle [ x0 x1 y0 y1 ]
; reports a patch-set bounded by
; the coordinate arguments passed
report patches with [
pxcor > x0 and pxcor < x1 and
pycor > y0 and pycor < y1
]
end
EDITS:
Ok- I may have gone a bit overboard here but I like this problem. Here is an alternative solution that has turtles draw the rectangles- that way there is no overlap. Additionally, rectangles have to build off the outside or previously id-d rectangles, so you don't get random disconnected rectangles. However, it can leave one-patch squares with no id within the rectangle, so you'll have to sort those out as you like.
To see what how it works, put the display to continuous and slow it way down. In essence, a turtle sprouts on a patch without an id, hatches a partner who travels away some distance before they both turn the same direction and move forward and move some distance. The x and y coordinates of each corner patch are stored in a list then used to assign an id to the rectangle they define.
patches-own [ id ]
to setup
ca
resize-world -50 50 -50 50
set-patch-size 5
ask patches [ set id -1 ]
ask rectangle -20 20 -40 40 [
set pcolor red
]
reset-ticks
end
to go
turtle-define-rect -20 20 40 -40
tick
end
to turtle-define-rect [ x0 x1 y0 y1 ]
; Make sure the x0 x1 / y0 y1 order is correct
let xp0 min (list x0 x1)
let xp1 max (list x0 x1)
let yp0 min (list y0 y1)
let yp1 max (list y0 y1)
; Define the rectangle to subdivide
let main_rect rectangle xp0 xp1 yp0 yp1
let xlist []
let ylist []
let possible_area one-of main_rect with [
id = -1 and
any? neighbors4 with [id = -1] and
any? neighbors4 with [not member? self main_rect or id != -1]
]
if possible_area != nobody [
ask possible_area [
let w random 5 + 5
let h random 10 + 10
sprout 1 [
set color blue
set size 3
let start-patch patch-here
let id_temp [id] of patch-here
face one-of neighbors4 with [not member? self main_rect or id != -1]
rt 180
hatch 1 [
create-link-with one-of other turtles-here
repeat w [
if ( [id] of patch-ahead 1 = -1 ) and ( [ member? self main_rect] of patch-ahead 1 ) [
fd 1
]
]
]
set xlist lput xcor xlist
set ylist lput ycor ylist
ask link-neighbors [
set xlist lput xcor xlist
set ylist lput ycor ylist
]
let turn one-of [ 90 -90 ]
rt turn
ask link-neighbors [
rt turn
]
ask my-links [
tie
]
repeat h [
if (
( [id] of patch-ahead 1 = -1 ) and
( [ member? self main_rect] of patch-ahead 1 ) and
( [ [id] of patch-ahead 1 = -1 ] of link-neighbors = [true] ) and
( [ [ member? self main_rect] of patch-ahead 1 ] of link-neighbors = [true] )
)
[
fd 1
]
]
set xlist lput xcor xlist
set ylist lput ycor ylist
ask link-neighbors [
set xlist lput xcor xlist
set ylist lput ycor ylist
]
ask link-neighbors [ die ]
die
]
]
let xt0 min xlist
let xt1 max xlist
let yt0 min ylist
let yt1 max ylist
let new_id random 10000
ask rectangle xt0 xt1 yt0 yt1 [
set id new_id
]
]
ask main_rect with [ id != -1 ] [
set pcolor id / 100
]
end
to-report rectangle [ x0 x1 y0 y1 ]
; reports a patch-set bounded by
; the coordinate arguments passed
report patches with [
pxcor >= x0 and pxcor <= x1 and
pycor >= y0 and pycor <= y1
]
end
Output looks something like:
Where colors other than red indicate rectangles with different ids.
Upvotes: 1