FlexsimObject
説明
ObjectDataTypeを継承します。
FlexSimObjectは、オブジェクトの継承の元になる基本的な開始オブジェクトとして使用されます。他のFlexsimオブジェクトが、自分で作成したオブジェクトとの間で、メッセージング、停止/再開、アイテムのロード/アンロードなどの標準機構を使用して自動的に連携するには、作成するオブジェクトが最低でもFlexSimObjectを継承する必要があります。FlexSimObjectは主に「仮想」オブジェクトで、インターフェイスのみを設定し、サブクラスがそのインターフェイスを実装します。このオブジェクトでは、それらのインターフェイスについて、いくつかの非常に基本的なデフォルト機能が定義され、サブクラスはその「バニラ」ロジックを使用できますが、FlexSimObjectの主な目的は、サブクラスでそれらのインターフェイスをオーバーライド可能にすることです。
直接の子クラス
クラス | 説明 |
---|---|
FixedResource | |
Dispatcher | |
Navigator | |
NetworkNode | |
VisualTool | |
Recorder |
実装
注:これらの関数の多くはユーティリティ関数とも呼ばれ、子クラスで再実装されることを意図していません。ただし他の理由から、仮想であることが必要です。特定のユーティリティメソッドの詳細については、子クラス、たとえばTaskExecuterのドキュメントを参照してください。
メソッド |
---|
double onReceive(treenode item, int port) |
double onSend(treenode item, int port) |
double onTimerEvent(treenode involved, int code, char *strdata) |
double onCreate(double dropx, double dropy, double dropz, int iscopy = 0) |
double onDestroy(double xloc, double yloc, double zloc) |
double onDraw(treenode view) |
double onDrawPlanar(treenode view) |
double onPreDraw(treenode view) |
double onOutOpen(int port) |
double onInOpen(int port) |
double onClick(treenode view, int code) |
double onKeyedClick(treenode view, int code, char k) |
double onMessage(treenode fromobject, double par1, double par2, double par3) |
double onReset(void) |
double onDrag(treenode view) |
double onRunWarm(void) |
その他の仮想メソッド
メソッド | 説明 |
---|---|
double stopObject(int stopstate) | 「停止/再開」を参照 |
double resumeObject(void) | 「停止/再開」を参照 |
double dragConnection(treenode toobject, char characterpressed, unsigned int classtype) | 「ドラッグ接続/クラスタイプ」を参照 |
double getPickOffset(treenode involvedobj, treenode toobject, double* returnarray) | 「ピッキング/配置のオフセット」を参照 |
double getPlaceOffset(treenode involvedobj, treenode fromobject, double* returnarray) | 「ピッキング/配置のオフセット」を参照 |
double updateLocations() | 「updateLocations()とonPreDraw()」を参照 |
unsigned int getClassType(void) | 「ドラッグ接続/クラスタイプ」を参照 |
double saveState(void) | 「状態の保存/ロード」を参照 |
double loadState(void) | 「状態の保存/ロード」を参照 |
double rotateAroundAxis(double angle, double x, double y) | 「各種のユーザー操作ロジック」を参照 |
double fliparoundAxis(int axis, double x , double y) | 「各種のユーザー操作ロジック」を参照 |
double copyVariables(treenode otherobject) | 「各種のユーザー操作ロジック」を参照 |
イベントの処理
ObjectDataTypeと同様に、FlexSimObjectクラスは属性ノードを使用してイベントをキャッチできます。ただし、FlexSimObjectはイベント属性ノードを仮想メソッドに自動的にマップします。このため、サブクラスでは仮想メソッドをオーバーライドするだけで標準のFlexsimイベントを操作できます。
このシーケンスの詳細については、ツリーのMAIN:/project/library/FlexSimObject>behaviourを参照してください。eventfunctionsサブノードには、そのオブジェクトに関連付けられている各種のイベントに対応する、OnReset、OnTimerEvent、OnMessageなどの属性があります。ここで、cppfunctionsサブノードの動作を調べてみましょう。ここには、C++形式の関数宣言ノードがあります。これらは、FlexSimObject用のC++仮想クラスメソッドを宣言しています。メソッドの多くは、eventfunctionsにある属性と基本的に同じ名前であることに注意してください。eventfunctions属性に戻り、各種のイベント属性のコードを分析します。これらの属性のコードはほとんどの部分で、現在のオブジェクト(c)に関連付けられているFlexSimObjectへの参照を取得し、FlexSimObjectの関連するメソッドを呼び出すだけであることに注目してください。cppfunctionsノードを見返すと、これらのメソッドで通常はFlexSimObjectが何も行わないことが分かります。サブクラスでは、これらのメソッドをオーバーライドして、これらのイベントに関連するロジックを実装できます。これが、この「マッピング」の目的です。FlexSimObjectは、エンジンのディスパッチメカニズムによりディスパッチされるイベントを自動的にキャッチし、クラスメソッドの呼び出しにマップします。このため、FlexSimObjectのサブクラスでは、関連するクラスメソッドをオーバーライドするだけでカスタムのイベントロジックを定義できます。イベントの属性をクラスに設定してから、それらの属性をグローバルC++コードで定義する必要はありません。
メッセージング
FlexSimObjectには、ユーザーのメッセージングを自動的に処理するメカニズムがあります。FlexSimの初期設計において、メッセージングシステムはsendmessage()およびsenddelayedmessage()コマンドによってトリガーされ、主にユーザーへプッシュされて、sendmessageによるすべてのメッセージングは、ユーザーが各オブジェクトに定義可能なトリガーを起動するだけという構造が定められました。このために、FlexSimObjectにはmessagetriggerという変数があります。このノードには、エンドユーザーが定義できるコードが含まれているため、エンドユーザーはいくつかの共通機能を実行するときsendmessage()を呼び出し、メッセージのトリガー変数にコードを定義します。FlexSimObjectはOnMessage属性からメッセージイベントをキャッチし、OnMessage()メソッドにディスパッチします。OnMessage()メソッドは、そのメッセージトリガーノードのnodefunction()を呼び出します。
sendmessage()コマンドはエンジンに実装されていますが、senddelayedmessage()は実際にはコンテンツレベルで実装されており、FlexSimObjectがこの実装の鍵となっています。senddelayedmessage()はオブジェクトのcreateevent()を呼び出し、イベントコードとしてEVENT_MESSAGEを使用します。次に、FlexSimObjectのOnTimerEvent属性で、それがメッセージイベントかどうかのチェックが行われ、そうであれば自分に対してsendmessage()を呼び出し、上述のシーケンスがトリガーされます。
このアーキテクチャでは、FlexSimObjectのonMessage()メソッドをオーバーライドする独自のonMessage()メソッドをサブクラスで実装することは禁止されていません。特定のタイプのメッセージについて独自のサブクラスロジックを定義してから、他のメッセージについてはFlexSimObject::onMessage()を呼び出すことができます。ただし、これはルールというより例外です。ユーザーがサブクラスのカスタムロジックにアクセスするには、sendmessage()以外にも、コマンドリストにコマンドを追加する方法もあります。FlexSimObjectのonMessage()をオーバーライドすることが便利な状況の1つは、タスクシーケンスです。クラスでタスクシーケンスを構築して実行する場合、タスクシーケンスの途中でクラスのコードを実行するか、クラスのコードにより決定されるサブタスクを呼び出すと便利なことがあります。このための最も直接的な方法は、TASKTYPE_SENDMESSAGE(またはTASKTYPE_CALLSUBTASKS)コマンドを使用してから、FlexSimObjectのOnMessage()メソッドをオーバーライドすることです。通常は、ユーザーが使用する可能性のあるメッセージコードと競合しないメッセージコード(msgparam(1)は一般に誰でも使用する「メッセージコード」です)を使用するため、非常に大きい数値、または負の数値を使用します。
描画
FlexSimObjectには、ユーザー定義の描画を自動的に行うメカニズムもあります。基本的にすべてのライブラリオブジェクトでエンドユーザーが描画をカスタマイズできるように、FlexSimObjectにはこのメカニズムが実装されています。FlexSimObjectには、描画シーケンスの一部として実行するコードをエンドユーザーが定義できるdrawtrigger変数があります。FlexSimはOnDrawイベント属性をキャッチすると、ユーザーのdrawtrigger変数を呼び出し、変数が0を返すか、または実装されていない場合、FlexSimObjectがOnDraw()メソッドを呼び出します。これにより、エンドユーザーは必要に応じて、任意のクラス定義の描画コードを実際にオーバーライドできます。
注:オブジェクトに「shape」属性ノードが存在し、そのノードに.3dsファイルへのパスが存在する場合、カスタム描画コードとともに.3dsの形状も描画されます。
停止/再開
FlexSimObjectには、オブジェクトの停止と再開を行うメカニズムが用意されています。当社は、設計の段階で、オブジェクトを別のオブジェクトから停止して後で動作を再開できる何らかの共通メカニズムが必要だと判断しました。これは、stopobject()およびresumeobject()コマンドで行われます。停止要求は累積されるため、stopobject()が何回も呼び出されると、同じ回数だけresumeobject()が呼び出されるまで、オブジェクトは再開されません。FlexSimObjectは、nrofstops、statebeforestop、timeoflaststop変数を使用して停止要求を追跡します。また、FlexSimObjectは仮想メソッドstopObject()およびresumeObject()も宣言します。これらのメソッドをサブクラスでオーバーライドし、停止/再開の方法を示すカスタムロジックを定義します。FlexSimObjectはstopObject()とresumeObject()の「バニラ」実装を定義します。この実装ではオブジェクトに関連付けられているすべての保留中のイベントは、オブジェクトの再開まで単に遅延され、再開後にイベントも再開されますが、オブジェクトが停止していた時間だけ遅延します。FlexSimObjectのサブクラスで、停止と再開にこれ以外の動作が必要な場合は、stopObject()とresumeObject()をオーバーライドします。
stopObject()のオーバーライドでは、次の動作を行います。
- v_nrofstopsをインクリメントします(v_nrofstops++)。
- v_nrofstopsが1なら、time()をv_timeoflaststopに、現在の状態をv_statebeforestopに格納し、オブジェクトを停止させるためのロジックを実行します。
- オブジェクトの状態を、要求された状態に設定します。
resumeObject()のオーバーライドでは、次の動作を行います。
- v_nrofstopsをデクリメントします(v_nrofstops--)。
- v_nrofstopsが0なら、オブジェクトを再開するロジックを実行します。
- オブジェクトの状態をv_statebeforestopに設定します。
stopObject()/resumeObject()のオーバーライドでは、単にFlexSimObject::stopObject()/resumeObject()を呼び出して、これらの動作を自動的に行ってから、別の動作を加えることもできます。
updateLocations()とonPreDraw()
FlexSimObjectクラスには、updateLocations()という仮想メソッドが実装されています。このメソッドは、現在のシミュレーション時間を使用して、オブジェクトの場所を更新するためのものです。たとえば、コンベヤのupdateLocations()は、コンベヤ上のすべてのフローアイテムを走査し、フローアイテムの場所を更新します。フローアイテムの場所は、ベルトの速度や集積などの係数によって異なります。これらのロジックはすべて、updateLocations()関数に定義します。
updateLocations()は次の2つの時点で呼び出されます。
- オブジェクトのonPreDraw()イベント関数の一部として
- updatelocations()アプリケーションコマンドの結果として
onPreDraw()イベントは、オブジェクトがビューに表示されている場合にのみ発生します。ビューが更新される直前に、ビュー内のオブジェクトごとにonPreDraw()イベントが発生します。通常、onPreDraw()がupdateLocations()を呼び出せば、ビューは正しく更新されます。オブジェクトを含むビューについて特別な動作を行う必要がない限り、onPreDraw()メソッドを再実装する必要はありません。
場所に関するすべてのロジックは、onPreDraw()ではなくupdateLocations()に組み入れることに注意してください。ビューが存在しない場合、onPreDraw()は呼び出されません。ビューが存在しても、ビューが更新された時点と、シミュレーション時間とは大きく異なる可能性があります。オブジェクトの場所とシミュレーション時間とを正確に結び付けるには、場所に関するすべてのロジックをupdateLocations()に組み込みます。
とはいえ、updateLocations()は頻繁に呼び出され、計算量が非常に多くなる可能性があります。特にナビゲータクラスでその傾向が強くなります。updateLocations()が呼び出されるときのシミュレーション時間を格納する変数を保持し、ロジックを実行する前にシミュレーション時間が増加したと確認することをお勧めします。
リセット
FlexSimObjectクラスには、リセットに関係する次の機能が用意されています。
- 仮想onReset()メソッド
- 仮想でないresetVariables()メソッド
- node_v_resetというツリーノード
FlexSimObjectを拡張するすべてのクラスはonReset()メソッドを上書きし、独自の仮想でないresetVariables()メソッドを保有する必要があります。通常、onReset()メソッドは、リセットロジックが実装されているresetVariables()メソッドを呼び出します。その後で各クラスは、独自の変数をリセットし、親クラスのresetVariables()メソッドを呼び出すことができます。このチェーンはFlexSimObjectに到達するまで続き、FlexSimObjectでリセットトリガーノードのnode_v_resetが実行されます。このノードは、エンドユーザーが定義するためのものです。下の図は、この動作を示したものです。
状態の保存/ロード
FlexSimObjectは、状態の保存とロード用の仮想メソッドのセットも定義しています。状態の保存/ロードは、シミュレーションの実行途中にモデルの状態を保存するために用意されています。ツリーに正しく格納されていないデータをシミュレーション中に使用する場合、サブクラスには、正しい形式でないデータをツリーに格納するsaveState()メソッドと、そのデータをツリーから読み戻すloadState()を実装する必要があります。
ドラッグ接続/クラスタイプ
FlexSimObjectは、仮想dragConnection()メソッドを定義しています。このメソッドは、ユーザーがキーを押したまま、2つのオブジェクトの間をクリックしてドラッグしたときに起動します。dragConnection()は、ドラッグのFROMオブジェクトから呼び出されます。このメソッドが呼び出される前に、システムはFlexSimObjectの仮想getclasstype()メソッドを使用して、TOオブジェクトのクラスタイプを取得します。このメソッドからは、そのオブジェクトがメンバーである各種クラス、すなわちCLASSTYPE_FLEXSIMOBJECT、CLASSTYPE_FIXEDRESOURCEなどのビット単位のマスクが返されます。その後でdragConnection()は、どのタイプの接続を作成するかを決定します。単にisclasstype()コマンドを使用して、クラスの実際の名前を渡すこともできます。
また、ドラッグ接続のTOオブジェクトである場合にdragConnectionを処理するには、getclasstype()をオーバーライドし、ビット単位のマスクの一部としてCLASSTYPE_WANTCONNECTLOGICを返します。FROMオブジェクトが同様にCLASSTYPE_WANTCONNECTLOGICを返さない限りは、FROMオブジェクトではなく自分の作成したオブジェクトでdragConnection()が呼び出されます。
ピッキング/配置のオフセット
FlexSimObjectでは、ピッキング/配置のオフセットを定義するために、getPickOffset()とgetPlaceOffset()という仮想メソッドが定義されています。getPickOffset()は、オブジェクトから別のオブジェクトがアイテムをロードする前に、そのアイテムをピックアップする際のオフセットを知るために呼び出されます。getPlaceOffset()は、オブジェクトに別のオブジェクトがアイテムをアンロードする前に、アイテムをドロップする際のオフセットを知るために呼び出されます。この詳細については、ユーザーマニュアルのTaskExecuterページにある「オフセット移動」セクションを参照してください。また、TASKTYPE_PICKOFFSETとTASKTYPE_PLACEOFFSETのドキュメントも参照してください。
衝突検出
FlexSimObjectクラスには、いくつかの基本的な衝突検出ロジックが実装されています。衝突球を作成し、モデルに存在する他のすべての衝突球に対して、指定した間隔でチェックを実行できます。衝突のチェックは、checkCollisions()メソッドで行われます。checkCollisions()メソッドを呼び出すループは、サブクラスで実装する必要があります。TaskExecuterクラスには、このために使用できるループロジックが含まれています。
各種のユーザー操作ロジック
FlexSimObjectには、別のオブジェクトからの変数のコピー、軸を基準としたオブジェクト反転など、ユーザー操作ロジック用の各種仮想メソッドも実装されています。これらの操作は、FlexSimの[ビュー] > [モデル作成ユーティリティ]で使用できます。これらのイベントの動作は、FlexSimObjectの任意のサブクラスで定義できます。