Layout モジュールの書き込み

Atomsには、いくつかのLayoutモジュールがありますが、C ++を使用して、新しいモジュールを作成できます。こちらの例では、入力カーブに沿ってエージェントを生成するためのLayoutモジュールを作成する方法を説明しています。

こちらの例は、2つの部分から構成されています。


  • エージェントの作成を担当するLayoutジェネレータ、レイアウトの作成を担当するBehaviourモジュール
  • ジェネレータとそれをエージェントグループにアタッチを実施

Curve Layoutジェネレータを書く

Layoutジェネレータオブジェクトは、すべてのフレームで作成された新しいエージェントの描写を生成します。ジェネレータは、StaticでもDynamicのどちらでも構いません。Staticジェネレータは、最初のフレームでのみ、エージェントの描写を作成しますが、Dynamicジェネレータは、すべてのフレームで新しいエージェントを生成できます。この例では、エージェントはカーブに沿った最初のフレームでのみ作成されるので、ジェネレータはStaticです。Dynamicジェネレータを作成したい場合は、コンストラクタ内でsetAsStaticgenerator(false)関数を使用するだけです。


generate関数は、AgentInitDataオブジェクトのベクトルを作成します。このオブジェクトは、新しいエージェントの位置、方向、エージェントタイプ、グループIDを定義します。エージェントグループは、この情報を使用して新しいエージェントを作成します。

#include <Atoms/LayoutGenerators/LayoutGenerator.h>
#include <AtomsUtils/Curve.h>
#include <Atoms/AgentTypes.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 the curve is a valid
	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 tangent
				{
					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);
}

Curve Layout モジュールを書く

Curve Layoutジェネレータを使用する場合は、新規のBehaviourモジュールが必要です。このBehaviourモジュールは、ジェネレータのアトリビュートをユーザーに公開し、すべてのデータをジェネレータ自体に送信します。

#include <Atoms/BehaviourModule.h>
#include <Atoms/AgentTypes.h>
#include <Atoms/AgentGroup.h>
#include <AtomsCore/Metadata/IntMetadata.h>
#include <AtomsCore/Metadata/Vector3ArrayMetadata.h>
#include <AtomsCore/Metadata/StringMetadata.h>
#include <AtomsCore/Metadata/CurveMetadata.h>
#include <AtomsCore/Metadata/BoolMetadata.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));
	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 generator 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();
}

extern "C"
{
    ATOMSPLUGIN_EXPORT bool initializePlugin() 
    {
	return true;
    }

    ATOMSPLUGIN_EXPORT bool unitializePlugin() 
    {
	return true;
    }

    ATOMSPLUGIN_EXPORT bool initializeScene()
    {
        Atoms::BehaviourModules& moduleManager = Atoms::BehaviourModules::instance();
	moduleManager.registerBehaviourModule("SimpleCurveLayout", &CurveGeneratorModule::creator, 	Atoms::BehaviourModules::kNative);
        return true;
    }
 
    ATOMSPLUGIN_EXPORT bool unitializeScene()
    {

        return true;
    }
}

Copyright © 2017, Toolchefs LTD.