import * as util from './utils.js'
import AgentArray from './AgentArray.js'
/**
* Geometry methods for patches, turtles, and other AgentArrays
* Return all agents within rect, radius, cone from given agent.
* If meToo, include given object, default excludes it
* Typically the AgentArray is a subset of larger sets, reducing
* the size, then uses these inRect, inRadius or inCone methods
*/
class AgentList extends AgentArray {
/**
*
* @param {Model} model The Model this AgentList belongs to
* @param {...any} args The arguments passed to super
*/
constructor(model, ...args) {
if (!model) throw Error('AgentList requires model')
super(...args)
this.model = model
}
/**
* Return all agents within rectangle from given agent.
* dx & dy are (float) half width/height of rect
*
* @param {Agent} agent
* @param {number} dx
* @param {number} dy
* @param {boolean} meToo
* @returns An AgentList of agents within the rect. Include agent if metoo
*/
inRect(agent, dx, dy = dx, meToo = false) {
const agents = new AgentList(this.model)
const minX = agent.x - dx // ok if max/min off-world, agent, a are in-world
const maxX = agent.x + dx
const minY = agent.y - dy
const maxY = agent.y + dy
this.ask(a => {
if (minX <= a.x && a.x <= maxX && minY <= a.y && a.y <= maxY) {
if (meToo || agent !== a) agents.push(a)
}
})
return agents
}
/**
* Return all agents in AgentArray within radius from given agent.
*
* @param {Agent} agent
* @param {number} radius
* @param {boolean} meToo
* @returns An AgentList of agents within the radius. Include agent if metoo
*/
inRadius(agent, radius, meToo = false) {
const agents = new AgentList(this.model)
// const {x, y} = agent // perf?
const d2 = radius * radius
const sqDistance = util.sqDistance // Local function 2-3x faster, inlined?
this.ask(a => {
if (sqDistance(agent.x, agent.y, a.x, a.y) <= d2) {
if (meToo || agent !== a) agents.push(a)
}
})
return agents
}
/**
* As above, but also limited to the angle `coneAngle` around
* an `angle` from object `agent`. coneAngle and direction in radians.
*
* @param {Agent} agent
* @param {number} radius
* @param {number} coneAngle
* @param {number} heading
* @param {boolean} meToo
* @returns An AgentList of agents within the angle. Include agent if metoo
*/
inCone(agent, radius, coneAngle, heading, meToo = false) {
heading = this.model.toRads(heading)
coneAngle = this.model.toAngleRads(coneAngle)
const agents = new AgentList(this.model)
this.ask(a => {
if (
util.inCone(
a.x,
a.y,
radius,
coneAngle,
heading,
agent.x,
agent.y
)
) {
if (meToo || agent !== a) agents.push(a)
}
})
return agents
}
}
export default AgentList