Spatial Model Tutorials
This spatial model is an extension to CanvasMap and can simulate a variety of 2D and 3D phenomenon. The CMSpatialModel class will manage the user interface for you but you can always override classes in any of the classes to customize them as you desire.
The model works by first creating a map to work in and then adding layers for the types of data you want to include in your model. Below is a simple model to add 100 agents to a model with random placement and movement vectors between 0 and 20. Try changing the size of the map, number of individuals, and their velocity range to see how it impacts the movement of the animals.
function SetupModel(MySpatialModel,TheContainerElement)
{
MySpatialModel.Setup(1000,1000); // width, height in reference units
var TheAgents=MySpatialModel.AddAgentLayer(); // add the agent layer to the model
TheAgents.AddRandomInividuals(100,0,20); // add 100 individuals to the agent layer with velocities between 0 and 20
}
Examples
There are a series of examples available:
- Simple movement
- Flocking
- Simple predator prey
Below are tutorials based on some of the examples.
Flocking Model
Appearance
The agents are a little boring at this point so lets give them a color and create a polygon that defines their shape. We'll also change the name of the layer to "TheBirds". Your code should look similar to the code below but then try different colors and polygon shapes.
function SetupModel(MySpatialModel,TheContainerElement)
{
MySpatialModel.Setup(1000,1000); // width, height in reference units
var TheBirds=MySpatialModel.AddAgentLayer(); // add the agent layer to the model
TheBirds.AddRandomInividuals(100,0,20); // add 100 individuals to the agent layer with velocities between 0 and 20 TheBirds.SetSetting("Style","fillStyle","Red"); TheBirds.SetPolygon([[0,-10,0,10],[-5,5,0,5]]);
}
Position and Movement
CMLayerAgents maintains data for each agent in the attribute table for the layer. This includes an x,y (and z in 3D) values for the location of each agent. Addtional information is added as needed.
The attributes also include x and y components of velocity vectors. The velocity vectors determine the direction and speed of the agent. Movement of agents can change based on different types of forces that infulence the agents. These include:
- MOVEMENT_ALIGNMENT: Force to alighn the direction of travel with other agents in the layer. This is like birds migrating in the same direction.
- MOVEMENT_COHESION: Force that pulls agents together.
- MOVEMENT_SEPARATION: Force that pushes agents apart.
- MOVEMENT_RANDOM: A randome change to the direction of the agent.
Each of these types of forces can have the following settings:
- MaxSpeed: A limit on the
- Distance: The force will only be applied within this distance.
- Force: Amount of force to apply
- Factor: An additional factor to mulitply the force by to scale the force larger or smaller than other forces.
Add the following code to the end of your function and you should see flocking behavior when you click "Start". Try changing the values of the properties to see the impact they have on flocking. Do not worry too much about breaking the model as you can always change the values back and refresh your browser (you can crash a browser with code like this but just close and reopen it and everything should be fine).
// set the maximum speed for each bird TheBirds.SetSetting("Individuals","MaxSpeed",4); // save the force properties to make the birds flock var AlignmentProperties={ Type:CMLayerAgents.MOVEMENT_ALIGNMENT, MaxSpeed:4, Distance:50, Force:40, } var CohesionProperties={ Type:CMLayerAgents.MOVEMENT_COHESION, MaxSpeed:4, Distance:50, Force:40 } var SeparationProperties={ Type:CMLayerAgents.MOVEMENT_SEPARATION, MaxSpeed:4, Distance:25, Force:40, Factor:1.5 } var RandomProperties={ Type:CMLayerAgents.MOVEMENT_RANDOM, Force:0, } var PositionProperties=[AlignmentProperties,CohesionProperties,SeparationProperties,RandomProperties]; TheBirds.SetPositionProperties(PositionProperties);
User Interface
We can add user interface controls and connect them to our model with just one line of code. Add the following lines of code to the end of your function. The first line just creates a slider that allows you to control the "MaxSpeed" setting for your agents. The other lines create sliders that will call a function when the user changes the value of the slider. The function at the end then changes the appropriate value in the properties.
// create a slider for the maximum speed CMGUIUtil.SetupSettingSlider(TheContainerElement,TheBirds,"Individuals","MaxSpeed"); // create sliders for the various properties CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Separation Force: ",0,100,SeparationProperties.Force,function(NewValue){ SeparationProperties.Force=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Separation Distance: ",0,100,SeparationProperties.Distance,function(NewValue){ SeparationProperties.Distance=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Cohesion Force: ",0,100,CohesionProperties.Force,function(NewValue){ CohesionProperties.Force=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Cohesion Distance: ",0,100,CohesionProperties.Force,function(NewValue){ CohesionProperties.Distance=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Alignment Force: ",0,100,AlignmentProperties.Force,function(NewValue){ AlignmentProperties.Force=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Alignment Distance: ",0,100,AlignmentProperties.Force,function(NewValue){ AlignmentProperties.Distance=NewValue; }) CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Random Force: ",0,100,RandomProperties.Force,function(NewValue){ RandomProperties.Force=NewValue; })
The CMGUIUtil.SetupSettingSlider() function can be used with any of the settings defined for the layer.
CMGUIUtil.SetupCallbackSlider() creates a slider that has a function attached to it that will be called when the slider value changes. The parameters for this function are listed in the reference section below.
Simple Predator/Prey Model
Movement is interesting but we also might want to model life stages and the resource requirements that animals have. To add this, we have taken the flocking sample from above and renamed "TheBirds" to "ThePrey" and saved it in a new file.
Life Stages
Animals go through life stages including being born, growing and dying. Below, we have defined three life stages for a prey animal.
//****************************************************************
// setup life stages
var DeadStage={
Name:"Dead",
MarkType:CMMARK_TRIANGLE,
CyclesInStage:40,
NextStage:null,
MaxSpeed:0
};
var MatureStage={
Name:"Mature",
MarkType:CMMARK_CIRCLE,
CyclesInStage:100,
CyclesToRepoduce:40,
NextStage:DeadStage
};
var YoungStage={
Name:"Young",
MarkType:CMMARK_SQUARE,
CyclesInStage:40,
NextStage:MatureStage
};
var LifeStages=[YoungStage,MatureStage,DeadStage];
ThePrey.SetLifeStages(LifeStages);
The last stage in the life stages will always be "dead". This causes all movement and requirements consumption to stop.
Controls
We can add sliders for any of the numeric properties for our agents. Below is an exmaple for the number of cycles the agents spend in the mature life stage and for how many cycles it takes between the time they reproduce.
CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Mature Cycles: ",0,100,MatureStage.CyclesInStage,function(NewValue){ MatureStage.CyclesInStage=NewValue; })
CMGUIUtil.SetupCallbackSlider(TheContainerElement,"Mature Cycles To Repoduce: ",0,100,MatureStage.CyclesToRepoduce,function(NewValue){ MatureStage.CyclesToRepoduce=NewValue; })
Cover
Animals need to feed on something so we are going to add a layer with grass for the animals to feed on. Add the code below to your file.
//**************************************************************** // the cover layer var LAND_COVER_ROCK=102; var LAND_COVER_WATER=101; TheLandCover=TheSpatialModel.AddCoverLayer(100,100);
// setup our cover types // grass pixels will go from 0% (bare ground) to 100% cover. var GrassType={ Name:"Grass", Min:0, Max:100, MinColor:[255,255,255], MaxColor:[0,255,0], RecoveryPerCycle:1 }; // set the cover types into the layer var TheCoverTypes=[GrassType]; TheLandCover.SetCoverTypes(TheCoverTypes); // setup the initial land cover spatial distribution TheLandCover.SetValue(99); // set all pixels to 100% grass
Requirements
Our prey animals need to feed on grass so we will add a requirement to them where they need to feed on grass or their "Food" setting will drop.
//*************************************************************** // setup resource requirements ThePrey.SetCover(TheLandCover); var PreyGrassRequirements={ Name:"Food", CoverType:GrassType, ChangePerCycle:-1, MaxAmountConsumed:10, ConversionFactor:1, Maximum:100, Min:1, Default:100 }; var PreyRequirements=[PreyGrassRequirements]; ThePrey.SetRequirements(PreyRequirements);
We'll want to see how our grass is doing so let's add a chart showing the amount of grass available.
// add a chart to track the amount of grass available
TheSpatialModel.AddLabel(TheContainerElement,"Grass Cover");
TheSpatialModel.AddChart(TheContainerElement,TheLandCover,GrassType);
Predators
We add predators by just adding another agent layer. We'll want to give it different symbology so we can tell the difference between the prey and the predators. Add the code below and see how the predators move about the field.
var ThePredators=TheSpatialModel.AddAgentLayer(); ThePredators.SetSetting("Name","Predators"); ThePredators.AddRandomInividuals(10); ThePredators.SetSetting("Style","fillStyle","Blue"); ThePredators.SetSetting("Mark","Size",20);
We can add a cohesive force to have the predators to move toward the prey. This is similar to the cohesion we used earilier except we've added a "Layer2" property to link the predators to the prey layer. We also add a random force so we can set it to 0 or increase it to add some randomness to the predator movement.
var PredatorCohesionProperties={ Type:CMLayerAgents.MOVEMENT_COHESION, MaxSpeed:4, Distance:500, MaxForce:5, Layer2:ThePrey } var PredatorRandomProperties={ Type:CMLayerAgents.MOVEMENT_RANDOM, Force:0, } ThePredators.SetPositionProperties([PredatorCohesionProperties]);
When you add this, you may notice the predators can become a bit confused when they are equaldistance from their prey.
Reference
CMLayerAgents
This layer models agents which can be individuals or groups of individuals that move together. Each agent is modeled as a point.
AddRandomVelocityVectors=function(MinVelocity,MaxVelocity)
AddRandomInividuals=function(NumIndividuals,MinVelocity,MaxVelocity)
CMLayerAgents.prototype.SetCover=function(LandCover)
CMLayerAgents.prototype.SetPositionProperties=function(PositionProperties)
Requirements
Requirements are set by creating one or more JavaScirpt objects with the following entries and then calling SetRequirements() with an array containing the requirement objects.
- Required:
- Name: used to create an attribute to track the reqruirment level
- ChangePerCycle: amount added to the requirement attribute for each cycle
- MaxAmountConsumed: maximum amount of food the agent can consume each cycle
- ConversionFactor: a factor to convert the resource into the current value (e.g. 10 units of grass may only convert to 2 units of engery so a factor of 0.2 would be used)
- Max: maximum amount for the requirement level
- Min: lower value causes death
- Default: initial starting value for new agents
- Required for requirments from a cover layer:
- CoverType: The type of cover layer the requirements are drawn from, if any
- CoverType: The type of cover layer the requirements are drawn from, if any
SetRequirements=function([RequirementObject1,RequirementObject2])
CMGUIUtil
CMGUIUtil.SetupCallbackSlider(Label,Min,Max,CurrentValue,Function)