Atoms has several layout modules but you can create new modules with c++. This example show how create a layout module that generate agents along a input curve.
This example is composed by two part, the layout generator that creates the agents and a behaviour module that creates the layout generator and attach it to the agent group
Writing the curve layout generator
The layout generator object generate the description of new agents created at every frame. A generator can be static or dynamic. A static generator creates the agents description only at the first frame, while a dynamic one can generate new agents at every frame. In this example our generator is static, since the agents are created only at the first frame along the cuve. If you want create a dynamic generator just use the setAsStaticgenerator(false) function inside the constructor.
The generate function creates a vector of AgentInitData objects. This object define the position, direction, agent type, groupId of the new agents. The agent group use this information to create new agents.
コード ブロック | ||
---|---|---|
| ||
#include <Atoms/LayoutGenerators/LayoutGenerator.h>
#include <AtomsUtils/Curve.h>
class CurveLayoutGenerator : public LayoutGenerator
{
public:
CurveLayoutGenerator();
virtual ~CurveLayoutGenerator();
// the generator function
virtual std::vector<AgentInitData> generate(double time);
inline void setCurve(AtomsUtils::Curve& curve) { m_curve = curve; }
inline void setDirection(AtomsCore::Vector3& dir) { m_direction = dir; }
inline void setUpVector(AtomsCore::Vector3& dir) { m_upVector = dir; }
inline void setNumberOfAgents(size_t value) { m_numberOfAgents = value; }
inline void setDirectionType(short value) { m_directionType = value; }
inline void setInvertDirection(short value) { m_invertDirection = value; }
inline void setAgentTypeOverride(const std::map<int, std::string>& value) { m_agentTypeOverride = value; }
inline void setDirectionOverride(const std::map<int, AtomsCore::Vector3>& value) { m_directionOverride = value; }
private:
// Input curve
AtomsUtils::Curve m_curve;
// Agent direction
AtomsCore::Vector3 m_direction;
// Up vector
AtomsCore::Vector3 m_upVector;
// Agent direction override
std::map<int, AtomsCore::Vector3> m_directionOverride;
// Agent type override
std::map<int, std::string> m_agentTypeOverride;
// Number of agents along the curve
size_t m_numberOfAgents;
// Direction type: 0 - tangent, 1 - normal, 2 - custom
short m_directionType;
// Invert the direction
bool m_invertDirection;
};
CurveLayoutGenerator::CurveLayoutGenerator(): LayoutGenerator(),
m_direction(1.0,0.0,0.0),
m_upVector(0.0,1.0,0.0),
m_numberOfAgents(0),
m_directionType(0),
m_invertDirection(false)
{
setAsStaticGenerator(true);
}
CurveLayoutGenerator::~CurveLayoutGenerator()
{
}
// the generator function since is a static generator this function is called once
std::vector<AgentInitData> CurveLayoutGenerator::generate(double time)
{
// Check if is a valid curve
if ((m_curve.cvs().size() < 2) || (m_numberOfAgents < 1))
return std::vector<AgentInitData>();
Atoms::AgentTypes &agTypes = Atoms::AgentTypes::instance();
// initialize the vector
std::vector<AgentInitData> data(m_numberOfAgents);
// curve parameter step
float curveStep = m_curve.maxU() / static_cast<float>(std::max(static_cast<size_t>(1), m_numberOfAgents - 1));
for (size_t i = 0; i < m_numberOfAgents; i++)
{
float param = static_cast<float>(i) * curveStep;
AgentInitData& agentData = data[i];
// set the agent position
agentData.position = m_curve.pointOnCurve(param);
// set the agent group id, this must be unique
agentData.groupId = i;
// set the agent type checking if there is any override
auto atIt = m_agentTypeOverride.find(i);
if (atIt != m_agentTypeOverride.end())
{
agentData.agentType = agTypes.agentType(atIt->second);
}
else
{
agentData.agentType = agentType();
}
// set the agent direction checking if there is any override
auto dIt = m_directionOverride.find(i);
if (dIt != m_directionOverride.end())
{
agentData.direction = dIt->second;
}
else
{
switch (m_directionType)
{
case 0: // use the tanget
{
agentData.direction = m_curve.tangentOnCurve(param);
break;
}
case 1: // use the normal
{
agentData.direction = m_curve.tangentOnCurve(param);
agentData.direction = agentData.direction.cross(m_upVector);
break;
}
default:
{
agentData.direction = m_direction;
break;
}
}
}
if (m_invertDirection)
{
agentData.direction *= -1.0;
}
}
return std::move(data);
}
|
Writing the curve layout modules
To use the curve layout generator a new behaviour modules is used. This behaviour module expose the generator attributes to the user and pass all the data to the generator itself and at the end it adds the generator to the agent group.
コード ブロック | ||
---|---|---|
| ||
#include <Atoms/BehaviourModule.h>
class CurveGeneratorModule : public Atoms::BehaviourModule
{
public:
CurveGeneratorModule();
~CurveGeneratorModule();
virtual void initSimulation(Atoms::AgentGroup* agentGroup = nullptr);
static Atoms::BehaviourModule* creator(const std::string& parameter);
};
CurveGeneratorModule::CurveGeneratorModule() :
Atoms::BehaviourModule()
{
AtomsCore::MapMetadata& metadata = attributes();
AtomsCore::StringMetadata atype("atomsRobot");
addAttribute("agentType", &atype, true);
AtomsCore::CurveMetadata curve;
metadata.addEntry("curve", &curve);
AtomsCore::IntMetadata numAgents(10);
metadata.addEntry("numAgents", &numAgents);
AtomsCore::IntMetadata dirType(0);
metadata.addEntry("directionType", &dirType);
AtomsCore::BoolMetadata invDir(false);
metadata.addEntry("invertDirection", &invDir);
AtomsCore::Vector3Metadata dir(AtomsCore::Vector3(1.0, 0.0, 0.0));
addAttribute("direction", &dir, true);
AtomsCore::Vector3Metadata up(AtomsCore::Vector3(0.0, 1.0, 0.0));
//metadata.addEntry("direction", &dir);
addAttribute("upVector", &up, false);
}
CurveGeneratorModule::~CurveGeneratorModule()
{}
void CurveGeneratorModule::initSimulation(Atoms::AgentGroup* agentGroup)
{
// Get the module attributes
AtomsCore::MapMetadata& metadata = attributes();
AtomsPtr<AtomsCore::CurveMetadata> curvePtr = metadata.getTypedEntry<AtomsCore::CurveMetadata>("curve");
AtomsPtr<AtomsCore::IntMetadata> numAgentsPtr = metadata.getTypedEntry<AtomsCore::IntMetadata>("numAgents");
AtomsPtr<AtomsCore::IntMetadata> directionTypePtr = metadata.getTypedEntry<AtomsCore::IntMetadata>("directionType");
AtomsPtr<AtomsCore::BoolMetadata> invertDirectionPtr = metadata.getTypedEntry<AtomsCore::BoolMetadata>("invertDirection");
AtomsPtr<AtomsCore::Vector3Metadata> directionPtr = metadata.getTypedEntry<AtomsCore::Vector3Metadata>("direction");
AtomsPtr<AtomsCore::Vector3Metadata> upPtr = metadata.getTypedEntry<AtomsCore::Vector3Metadata>("upVector");
AtomsPtr<AtomsCore::StringMetadata> agentTypePtr = metadata.getTypedEntry<AtomsCore::StringMetadata>("agentType");
// Check if the agent type is valid
Atoms::AgentTypePtr aType = Atoms::AgentTypes::instance().agentType(agentTypePtr->value());
if (!aType)
{
return;
}
// Get all agent type overrides
AtomsPtr<AtomsCore::MapMetadata> atypeOverride = metadata.getTypedEntry<AtomsCore::MapMetadata>("agentType_override");
std::map<int, std::string> aTypesOverride;
for (auto it = atypeOverride->begin(); it != atypeOverride->end(); it++)
{
if (!it->second)
continue;
if (it->second->typeId() != AtomsCore::StringMetadata::staticTypeId())
continue;
auto value = std::static_pointer_cast<AtomsCore::StringMetadata>(it->second);
if (!value)
continue;
Atoms::AgentTypePtr aType = Atoms::AgentTypes::instance().agentType(value->get());
if (!aType)
{
continue;
}
aTypesOverride[std::stoi(it->first)] = value->get();
}
// Get all agent direction overrides
AtomsPtr<AtomsCore::MapMetadata> directionOverride = metadata.getTypedEntry<AtomsCore::MapMetadata>("direction_override");
std::map<int, AtomsCore::Vector3> dirOverride;
for (auto it = directionOverride->begin(); it != directionOverride->end(); it++)
{
if (!it->second)
continue;
if (it->second->typeId() != AtomsCore::Vector3Metadata::staticTypeId())
continue;
auto value = std::static_pointer_cast<AtomsCore::Vector3Metadata>(it->second);
if (value)
dirOverride[std::stoi(it->first)] = value->get();
}
// Create the layout generato and set all the attributes
Atoms::CurveLayoutGenerator* curveLayout = new Atoms::CurveLayoutGenerator();
curveLayout->setCurve(curvePtr->get());
curveLayout->setNumberOfAgents(numAgentsPtr->value());
curveLayout->setDirectionType(directionTypePtr->value());
curveLayout->setInvertDirection(invertDirectionPtr->value());
curveLayout->setDirection(directionPtr->value());
curveLayout->setUpVector(upPtr->value());
curveLayout->setAgentTypeOverride(aTypesOverride);
curveLayout->setDirectionOverride(dirOverride);
Atoms::LayoutGeneratorPtr generator(curveLayout);
generator->setAgentType(aType);
agentGroup->setLayoutGenerator(generator);
}
Atoms::BehaviourModule* CurveGeneratorModule::creator(const std::string& parameter)
{
return new CurveGeneratorModule();
} |