Dieses Tutorial beschreibt, wie einzelne Objekte automatisiert mit dem Graph::Aligner Knoten ausgerichtet werden können.
ContainerAlignment
Ganz generell und unabhängig vom Aligner Graphenknoten kann bei einigen Objekten (wie etwa PlaneGeometry oder TextGeometry) der Ankerpunkte für die Positionierung mit den Attributen containerAlignmentX und containerAlignmentY angepasst werden. Standardmäßig liegt der Ankerpunkt immer im Zentrum.
Die gültigen Werte sind im Enum IEnums::AlignmentX bzw. IEnums::AlignmentY aufgelistet:
UNDEFINEDLEFT(oderBOTTOMfür Y)CENTER(default)RIGHT(oderTOPfür Y)NEGATIVEPOSITIVE
Zur Veranschaulichung positionieren wir drei Planes an derselben Position 0/0/0 und ändern lediglich die Parameter containerAlignmentX und containerAlignmentY (sowie den Farbparameter).
<!-- blue plane -->
<PlaneGeometry id="box_plane_01"
posX="0" posY="0" scaleFactor="100"
parametersSlot="0" materialSlot="2"/>
<!-- red plane -->
<PlaneGeometry id="box_plane_02"
posX="0" posY="0" scaleFactor="100"
parametersSlot="1" materialSlot="2"
containerAlignmentX="LEFT" containerAlignmentY="TOP"/>
<!-- green plane -->
<PlaneGeometry id="box_plane_03"
posX="0" posY="0" scaleFactor="100"
parametersSlot="2" materialSlot="2"
containerAlignmentX="RIGHT" containerAlignmentY="BOTTOM"/>
Als Ergebnis erhalten wir drei Planes die entsprechend ihren Alignment-Vorgaben unterschiedlich positioniert werden. Alle drei Planes haben die gleiche Ankerposition in der virtuellen Welt (0/0/0), allerdings liegt der Ankerpunkt bei der blauen Plane im Zentrum, bei der roten links oben und bei der grünen rechts unten.
Aligner Graphenknoten
Der Aligner Graphenknoten kann verwendet werden um Objekte entlang einer vorgegebenen Achse automatisch anordnen zu lassen. Dabei berechnet der Aligner Knoten für alle seine direkten Kindknoten (bzw. Sub-Graphen) die entsprechende Container-Größe und ordnet sie nacheinander an. Als erstes Beispiel ordnen wir drei PlaneGeometry-Objekte entlang der Y-Achse an.
<Aligner id="aligner01"
axis="Y" posX="-200" >
<!-- blue plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="0" materialSlot="2"/>
<!-- red plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="1" materialSlot="2"
containerAlignmentX="LEFT" containerAlignmentY="TOP"/>
<!-- green plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="2" materialSlot="2"
containerAlignmentX="RIGHT" containerAlignmentY="BOTTOM"/>
</Aligner>
Das Zentrum des Aligner Knoten legen wir nach links an die Position -200/0/0. Die PlaneGeometry Objekte werden entlang der Y-Achse des Aligners angeordnet. Die anderen Koordinatenwerte (X/Z) bleiben unverändert.
Mit dem Attribut objectAlignment können auch die Koordinatenwerte der verbleibenden Achsen (in unserem Fall X/Z) angepasst werden. Beispielsweise bewirkt die Angabe objectAlignmentX="LEFT", dass alle Objekte entlang des linken Rands des Aligners ausgerichtet werden.
Zur Veranschaulichung erstellen wir einen neuen Aligner Knoten, bei dem das Attribut objectAlignmentX gesetzt ist. Durch die Angabe von posY="150" und containerAlignmentY="TOP" wird der obere Rand des Aligner an die Position 150 gelegt. Die Angabe von order="DESCENDING" bewirkt eine absteigende Anordnung.
<Aligner id="aligner02"
axis="Y" posX="-350" posY="150" containerAlignmentY="TOP"
objectAlignmentX="LEFT"
order="DESCENDING">
<!-- blue plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="0" materialSlot="2"/>
<!-- red plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="1" materialSlot="2"
containerAlignmentX="LEFT" containerAlignmentY="TOP"/>
<!-- green plane -->
<PlaneGeometry scaleFactor="100" parametersSlot="2" materialSlot="2"
containerAlignmentX="RIGHT" containerAlignmentY="BOTTOM"/>
</Aligner>
Mit dem Attribut spacing kann ein Abstand zwischen den angeordneten Objekten definiert werden und mit dem Attribut padding kann ein äußerer Rand für den Aligner festgelegt werden.
<Aligner id="aligner03"
axis="Y" posX="250" posY="250" containerAlignmentY="TOP"
containerSizeX="200" order="DESCENDING" spacing="20">
<TextGeometry
materialSlot="4" systemFontName="SansBold"
fontSize="20"
textColor="255i, 255i, 255i, 255i"
backgroundColor="0i, 0i, 0i, 0i"
text="Line 1 centered"
enableWordWrapping="yes"
containerSizeX="200"
textAlignmentX="CENTER"
/>
<TextGeometry
materialSlot="4" systemFontName="SansBold"
fontSize="20"
textColor="255i, 255i, 255i, 255i"
backgroundColor="0i, 0i, 0i, 0i"
text="A auto wrapped text line"
enableWordWrapping="yes"
containerSizeX="200"
textAlignmentX="CENTER"
/>
<TextGeometry
materialSlot="4" systemFontName="SansBold"
fontSize="20"
textColor="255i, 255i, 255i, 255i"
backgroundColor="0i, 0i, 0i, 0i"
text="A manually wrapped line"
enableWordWrapping="yes"
containerSizeX="200"
textAlignmentX="CENTER"
/>
<TextGeometry
materialSlot="4" systemFontName="SansBold"
fontSize="20"
textColor="255i, 255i, 255i, 255i"
backgroundColor="0i, 0i, 0i, 0i"
text="Left aligned text"
enableWordWrapping="yes"
containerSizeX="200"
textAlignmentX="LEFT"
/>
<TextGeometry
materialSlot="4" systemFontName="SansBold"
fontSize="20"
textColor="255i, 255i, 255i, 255i"
backgroundColor="0i, 0i, 0i, 0i"
text="Right aligned text"
enableWordWrapping="yes"
containerSizeX="200"
textAlignmentX="RIGHT"
/>
<Node>
<PlaneGeometry scaleFactor="100" parametersSlot="0" materialSlot="2" containerAlignmentY="TOP"/>
<PlaneGeometry scaleFactor="100" parametersSlot="1" materialSlot="2"
containerAlignmentX="LEFT" />
<PlaneGeometry posX="25" posY="-25" scaleFactor="100" parametersSlot="2" materialSlot="2"
containerAlignmentX="RIGHT" containerAlignmentY="BOTTOM"/>
</Node>
</Aligner>
Die resultierende Größe des Aligner nach dem Anordnen kann mit der Methode GetBoundingVolume() abgefragt werden. Allerdings muss die Abfrage in der Methode OnFinishTick() und nicht in der Methode OnProcessTick() erfolgen, da das Ausrichten der Objekte im Aligner erst nach erfolgter Abarbeitung von OnProcessTick() durchgeführt wird. Eine Abfrage in OnProcessTick() liefert daher immer die Werte des vorherigen Frames.
void App::AlignerLogic::OnFinishTick(const Logic::IState* state)
{
// Size
if (mPrintBoundingValues)
{
const Graph::IBoundingVolume* boundingVolume = mAligner->GetBoundingVolume();
const Graph::Box& box = boundingVolume->GetInnerLocalBox();
const Graph::Vector& min = box.GetMinimum();
const Graph::Vector& max = box.GetMaximum();
Debug::Trace("From OnFinishTick:");
Debug::Trace(" Bounding X %f / %f", min.x, max.x);
Debug::Trace(" Bounding Y %f / %f", min.y, max.y);
Debug::Trace(" Bounding Z %f / %f", min.z, max.z);
mPrintBoundingValues = false;
}
}
Als Ergebnis erhalten wir für den Aligner aligner03 und das erste Frame:
Für alle weiteren Frames liefert OnProcessTick() und OnFinishTick() dasselbe Ergebnis, da sich in unserem Beispiel die Inhalte des Aligner nicht mehr ändern und damit das IBoundingVolume gleich bleibt. Durch Drücken der Taste P kann das IBoundingVolume für ein weiteres Frame ausgegeben werden:
Wir können das berechnete IBoundingVolume noch optisch mit einem PlaneGeometry Knoten verifizieren:
<PlaneGeometry posX="250" posY="250" containerAlignmentY="TOP"
scaleFactorX="200" scaleFactorY="450"
parametersSlot="3" materialSlot="2" depthOrder="-1" />