/**
* Name: 3D Display model and Height of Building using shapefiles
* Author: Arnaud Grignard
* Description: Model presenting a 3D display of people and buildings moving on a road network imported thanks to shapefiles. 
* 
* Two experiments are proposed : one showing people represented by a yellow sphere moving from a living 3D building to a working 3D building and coming back 
* using a road network (road_traffic). The second experiment distinguish the species by using different layers for species (road_traffic_multi_layer).
* Tags: 3d, shapefile, gis
*/
model tutorial_gis_city_traffic

global {
//Load of the different shapefiles used by the model
	file shape_file_buildings <- shape_file('../includes/building.shp', 0);
	file shape_file_roads <- shape_file('../includes/road.shp', 0);
	file shape_file_bounds <- shape_file('../includes/bounds.shp', 0);

	//Definition of the shape of the world as the bounds of the shapefiles to show everything contained
	// by the area delimited by the bounds
	geometry shape <- envelope(shape_file_bounds);
	int nb_people <- 1000;
	int day_time update: cycle mod 144;
	int min_work_start <- 36 const: true;
	int max_work_start <- 60 const: true;
	int min_work_end <- 84 const: true;
	int max_work_end <- 132 const: true;
	float min_speed <- 50.0 const: true;
	float max_speed <- 100.0 const: true;
	list residential_buildings;
	list industrial_buildings;

	//Declaration of a graph that will represent our road network
	graph the_graph;

	init {
		create building from: shape_file_buildings with: [type:: string(read('NATURE'))] {
			if type = "Industrial" {
				color <- #blue;
			}

			height <- 10 + rnd(90);
		}

		residential_buildings <- building where (each.type = 'Residential');
		industrial_buildings <- building where (each.type = 'Industrial');
		create road from: shape_file_roads;
		the_graph <- as_edge_graph(road);
		create people number: nb_people;
	}

}

species building {
	string type;
	rgb color <- #gray;
	int height;

	aspect base {
		draw shape color: color depth: height;
	}

}

species road {
	rgb color <- #black;

	aspect base {
		draw shape color: color;
	}

}

species people skills: [moving] {
	float speed <- min_speed + rnd(max_speed - min_speed);
	rgb color <- rnd_color(255);
	building living_place <- one_of(residential_buildings);
	building working_place <- one_of(industrial_buildings);
	point location <- any_location_in(living_place) + {0, 0, living_place.height};
	int start_work <- min_work_start + rnd(max_work_start - min_work_start);
	int end_work <- min_work_end + rnd(max_work_end - min_work_end);
	string objectif;
	point the_target;

	reflex time_to_work when: day_time = start_work {
		objectif <- 'working';
		the_target <- any_location_in(working_place);
	}

	reflex time_to_go_home when: day_time = end_work {
		objectif <- 'go home';
		the_target <- any_location_in(living_place);
	}

	reflex move when: the_target != nil {
		do goto(target: the_target, on: the_graph);
		switch the_target {
			match location {
				the_target <- nil;
				location <- {location.x, location.y, objectif = 'go home' ? living_place.height : working_place.height};
			}

		} }

	aspect default {
		draw sphere(3) color: color;
	} }

experiment "Road Traffic" type: gui {
	parameter 'Shapefile for the buildings:' var: shape_file_buildings category: 'GIS';
	parameter 'Shapefile for the roads:' var: shape_file_roads category: 'GIS';
	parameter 'Shapefile for the bounds:' var: shape_file_bounds category: 'GIS';
	parameter 'Earliest hour to start work' var: min_work_start category: 'People';
	parameter 'Latest hour to start work' var: max_work_start category: 'People';
	parameter 'Earliest hour to end work' var: min_work_end category: 'People';
	parameter 'Latest hour to end work' var: max_work_end category: 'People';
	parameter 'minimal speed' var: min_speed category: 'People';
	parameter 'maximal speed' var: max_speed category: 'People';
	parameter 'Number of people agents' var: nb_people category: 'People' min: 0 max: 100000 {
		int nb <- length(people);
		ask simulation {
			if (nb_people > nb) {
				create people number: nb_people - nb;
			} else {
				ask (nb - nb_people) among people {
					do die;
				}

			}

		}

	}

	output {
		display city_display type: opengl {
			light #ambient intensity: 180;
			light #default intensity: 180 direction: {0.5, 0.5, -1};
			species building aspect: base refresh: false;
			species road aspect: base refresh: false;
			species people refresh: true;
		}

	}

}

experiment "Multiple Layers" type: gui {
	parameter 'Shapefile for the buildings:' var: shape_file_buildings category: 'GIS';
	parameter 'Shapefile for the roads:' var: shape_file_roads category: 'GIS';
	parameter 'Shapefile for the bounds:' var: shape_file_bounds category: 'GIS';
	parameter 'Earliest hour to start work' var: min_work_start category: 'People';
	parameter 'Latest hour to start work' var: max_work_start category: 'People';
	parameter 'Earliest hour to end work' var: min_work_end category: 'People';
	parameter 'Latest hour to end work' var: max_work_end category: 'People';
	parameter 'minimal speed' var: min_speed category: 'People';
	parameter 'maximal speed' var: max_speed category: 'People';
	parameter 'Number of people agents' var: nb_people category: 'People' min: 0 max: 1000 {
		int nb <- length(people);
		ask simulation {
			if (nb_people > nb) {
				create people number: nb_people - nb;
			} else {
				ask (nb - nb_people) among people {
					do die;
				}

			}

		}

	}

	output {
		display city_display type: opengl {
			species road aspect: base;
			species building aspect: base position: {0, 0, 0.25};
			species people position: {0, 0, 0.5};
		}

	}

}