Goal: Automatic generation of a realistic-looking city
including road structure and buildings
Optional interaction between these steps
Primary, secondary, tertiary streets are used in urban planning
→ Simplified distinction between “highways” and normal streets
New potential segments are evaluated after existing ones
red = current step
green = next step
Normal streets branching from highways have an additional delay (blue)
This prevents highways from being cut off by normal streets
If a new segment
Population map (generated with layered simplex noise):
Highways try to connect population centers.
Possible new directions are sampled, the one with largest population is chosen
Streets only branch if population is larger than some threshold:
Different patterns found in cities:
http://maps.stamen.com/
Original implementation by Parish and Müller (2001)
w: R(0, initialRuleAttr) ?I(initRoadAttr, UNASSIGNED)
p1: R(del, ruleAttr) : del<0 -> e
p2: R(del, ruleAttr) > ?I(roadAttr,state) : state==SUCCEED
{ globalGoals(ruleAttr,roadAttr) creates the parameters for:
pDel[0-2], pRuleAttr[0-2], pRoadAttr[0-2] }
-> +(roadAttr.angle)F(roadAttr.length)
B(pDel[1],pRuleAttr[1],pRoadAttr[1]),
B(pDel[2],pRuleAttr[2],pRoadAttr[2]),
R(pDel[0],pRuleAttr[0]) ?I(pRoadAttr[0],UNASSIGNED)[i]
p3: R(del, ruleAttr) > ?I(roadAttr, state) : state==FAILED -> e
p4: B(del, ruleAttr, roadAttr) : del>0 -> B(del-1, ruleAttr, roadAttr)
p5: B(del, ruleAttr, roadAttr) : del==0 -> [R(del, ruleAttr)?I(roadAttr, UNASSIGNED)]
p6: B(del, ruleAttr, roadAttr) : del<0 -> e
p7: R(del, ruleAttr) < ?I(roadAttr,state) : del<0 -> e
p8: ?I(roadAttr,state) : state==UNASSIGNED
{ localConstraints(roadAttr) adjusts the parameters for:
state, roadAttr}
-> ?I(roadAttr, state)
p9: ?I(roadAttr,state) : state!=UNASSIGNED -> e
→ unnecessarily complicated
originally from Sean Barrett (2008)
function generate() {
let Q = new PriorityQueue<Segment>();
Q.enqueueAll(makeInitialSegments());
let segments = [];
while (!Q.empty() && segments.length < SEG_LIMIT) {
let minSegment = Q.dequeue();
// resolve conflicts
let accepted = applyLocalConstraints(minSegment, segments);
if (accepted) {
segments.push(minSegment);
// create new segments
Q.enqueueAll(globalGoalsGenerate(minSegment));
}
}
}
(+ a quadtree in applyLocalConstraints)
(10000 segments, not full speed)
Parish and Müller (2001)
Approaches:
Slides including source code: