Selektieren von Container-Elementen

In diesem Beispiel werden Container-Elemente mit Hilfe einer benutzerdefinierten Bedingung gefiltert. Dazu wird die Funktion F_VN_CopyContainerElementsConditional_ITcVnContainer genutzt, da es sich bei den Container-Elementen wiederum um Container handelt. Falls die Container-Elemente Iteratoren sind, kann dazu auch die Funktion F_VN_CopyContainerElementsConditional_ITcVnForwardIterator genutzt werden.

Erklärung

Wenn die Elemente von mehrdimensionalen Containern gefiltert werden sollen, entsteht durch den Zugriff auf die Sub-Elemente schnell großer Programmieraufwand. Um dem entgegenzuwirken, stellt TwinCAT Vision genau dafür eine Funktionalität bereit, die z.B. wie folgt genutzt wird:

Es wird ein Funktionsblock angelegt, der das Interface ITcVnCustomElementCondition_ITcVnContainer implementiert. Dieses Interface besitzt die Methode Condition, welche ein Element vom Typ ITcVnContainer entgegennimmt. In der Implementierung dieser Methode wird die Filterbedingung festgelegt, die auf das Element angewandt werden soll. Der Funktionsblock mit der Filterbedingung wird dann an die Funktion F_VN_CopyContainerElementsConditional_ITcVnContainer übergeben, um die Filterung aller Elemente eines Containers durchzuführen. In diesem Beispiel werden die Elemente danach gefiltert, ob sie mehr als fünf Sub-Elemente besitzen.

Anwendung

Beispielhaft werden die Sub-Container eines Containers danach gefiltert, wie viele Elemente sie jeweils besitzen. Konkret sollen nur die Sub-Container in einen neuen Container übernommen werden, die mehr als fünf Elemente haben. Die Struktur des Containers kann mittels des Arrays aContainerStructure variiert werden. Die Elemente geben an, wie viele Sub-Elemente jeder Sub-Container hat. Wenn ebenfalls die Anzahl der der Sub-Container selbst variiert wird, muss die Konstante cNumberOfSubContainers darauf abgestimmt werden.

Programm

MAIN

Zunächst wird ein konstanter Integer definiert, um die Anzahl der Sub-Container einfach variieren zu können:

VAR CONSTANT
    cNumberOfSubContainers  :   INT := 5;
END_VAR

Daraufhin werden alle benötigten Variablen deklariert:

VAR
    aContainerStructure     :   ARRAY [0..(cNumberOfSubContainers-1)] OF INT := [2, 7, 3, 5, 12];
    ipHelper                :   ITcVnContainer;
    ipContainerBase         :   ITcVnContainer;
    ipContainerFiltered     :   ITcVnContainer;
    fbCondition             :   FB_ConditionMoreThanFive;
    nSelectedContainers     :   ULINT;
    hr                      :   HRESULT;
    i                       :   INT;
END_VAR

aContainerStructure

Definition der Container-Struktur. Ein Array der Länge 5 mit den Initialisierungswerten [2, 7, 3, 5, 12] bedeutet z. B., dass im Beispiel ein Container mit 5 Sub-Containern erstellt werden soll. Dabei soll der erste Sub-Container 2 Elemente haben, der zweite Sub-Container 7 Elemente haben, usw.

Die Länge des Arrays wird durch die Konstante cNumberOfSubContainers definiert.

ipHelper

Hilfs-Interface-Pointer, der dazu benutzt wird, den Hauptcontainer ipContainer mit Sub-Containern zu füllen.

ipContainerBase

Container, in dem die in aNumberOfElement definierten Sub-Container erstellt werden.

fbCondition

Funktionsblock, der die Filterbedingung enthält.

ipContainerFiltered

Container, der am Ende nur die Sub-Container aus ipContainer enthalten soll, die die Filterbedingung erfüllen.

nSelectedContainers

Integer, der anzeigt, wie viele Sub-Container die Filterbedingung tatsächlich erfüllen.

hr

Statusvariable vom Typ HRESULT.

i

Hilfsvariable

Im Programmteil wird ein Container erstellt, der mit den oben definierten Sub-Containern gefüllt wird. Der Aufruf von F_VN_ReserveContainerMemory ist dabei optional und dient nur einer besseren Performance.

hr := F_VN_CreateContainer(ipContainerBase, ContainerType_Vector_Vector_REAL, 0, hr);
hr := F_VN_ReserveContainerMemory(ipContainerBase, cNumberOfSubContainers, hr);
FOR i:=0 TO (cNumberOfSubContainers-1) DO
    hr := F_VN_CreateContainer(ipHelper, ContainerType_Vector_REAL, aContainerStructure[i], hr);
    hr := F_VN_AppendToContainer_ITcVnContainer(ipHelper, ipContainerBase, hr);
END_FOR

Daraufhin wird der gerade erstellte Container gefiltert. Als Filterbedingung wird der Funktionsblock mit der selbst-geschriebenen Bedingung angegeben.

hr := F_VN_CopyContainerElementsConditional_ITcVnContainer(
    ipSrcContainer      :=  ipContainerBase,
    ipDestContainer     :=  ipContainerSelection,
    ipConditionFB       :=  fbCondition,
    hr);

Um die Funktionalität der Funktion nachzuvollziehen, werden die Elemente, die die geschriebene Bedingung erfüllen, gezählt. Die Variable nSelectedContainers ändert sich nun abhängig von den Sub-Containern und der Filterbedingung.

hr := F_VN_GetNumberOfElements(ipContainerSelection, nSelectedContainers, hr);

In diesem Fall gibt die Anzahl an, wie viele der Sub-Container mehr als fünf Sub-Elemente haben.

Funktionsblock mit Filterbedingung

Die Filterbedingung wird als Funktionsblock mit einer Methode Condition übergeben. Damit ein selbst-geschriebener Funktionsblock an die Funktion übergeben werden kann, muss dieser das Interface ITcVnCustomElementCondition_ITcVnContainer implementieren:

FUNCTION_BLOCK FB_ConditionMoreThanFive IMPLEMENTS ITcVnCustomElementCondition_ITcVnContainer

Die Methode Condition definiert die Filterbedingung. Sie wird für jeden Sub-Container einzeln aufgerufen. Je nachdem, ob der Rückgabewert TRUE oder FALSE ist, wird der jeweilige Sub-Container in den neuen Container übernommen oder nicht.

METHOD Condition : BOOL

Bei jedem Aufruf der Methode wird die aktuelle Sub-Container als Eingangsparameter übergeben:

VAR_INPUT
    ipElement           :   ITcVnContainer;
END_VAR

In diesem Fall soll ein Element übernommen werden, wenn es mehr als fünf Sub-Elemente hat. Dafür wird die Anzahl der Sub-Elemente berechnet und abhängig vom Ergebnis der Wert TRUE oder FALSE zurückgegeben.

hr := F_VN_GetNumberOfElements(ipElement, nNumberOfElements, hr);
IF FAILED(hr) OR nNumberOfElements <= 5 THEN
    Condition := FALSE;
ELSE
    Condition := TRUE;
END_IF

Die benötigten Variablen sind wie folgt deklariert:

VAR
    nNumberOfElements   :   ULINT;
    hr                  :   HRESULT;
END_VAR

Sowohl der Funktionsblock selbst als auch die Methode Condition müssen das Compiler-Attribut {attribute 'c++_compatible'} enthalten.