/* Framework: POV-Ray-Zauberwürfel von Stefan K. Baur */
#include "atoms.pov"
// ----------------------------------------------------------------------------
/* Konfiguration */
// Konfigurationsmöglichkeit einer 3x3x3-Matrix (State), siehe "Cube_Init".
// Jeder Slot dieser Matrix bekommt ein Grafikobjekt (Atome: A???).
#macro Cube_Config(State,
A020, A120, A220,
A021, A121, A221,
A022, A122, A222,
A010, A110, A210,
A011, A111, A211,
A012, A112, A212,
A000, A100, A200,
A001, A101, A201,
A002, A102, A202)
// Oberste Ebene
#declare State[0][2][0] = object { A020 translate -x+y-z }
#declare State[1][2][0] = object { A120 translate +y-z }
#declare State[2][2][0] = object { A220 translate +x+y-z }
#declare State[0][2][1] = object { A021 translate -x+y }
#declare State[1][2][1] = object { A121 translate +y }
#declare State[2][2][1] = object { A221 translate +x+y }
#declare State[0][2][2] = object { A022 translate -x+y+z }
#declare State[1][2][2] = object { A122 translate +y+z }
#declare State[2][2][2] = object { A222 translate +x+y+z }
// Mittlere Ebene
#declare State[0][1][0] = object { A010 translate -x -z }
#declare State[1][1][0] = object { A110 translate -z }
#declare State[2][1][0] = object { A210 translate +x -z }
#declare State[0][1][1] = object { A011 translate -x }
#declare State[1][1][1] = object { A111 }
#declare State[2][1][1] = object { A211 translate +x }
#declare State[0][1][2] = object { A012 translate -x +z }
#declare State[1][1][2] = object { A112 translate +z }
#declare State[2][1][2] = object { A212 translate +x +z }
// Unterste Ebene
#declare State[0][0][0] = object { A000 translate -x-y-z }
#declare State[1][0][0] = object { A100 translate -y-z }
#declare State[2][0][0] = object { A200 translate +x-y-z }
#declare State[0][0][1] = object { A001 translate -x-y }
#declare State[1][0][1] = object { A101 translate -y }
#declare State[2][0][1] = object { A201 translate +x-y }
#declare State[0][0][2] = object { A002 translate -x-y+z }
#declare State[1][0][2] = object { A102 translate -y+z }
#declare State[2][0][2] = object { A202 translate +x-y+z }
#end
// Der Würfel wird mit 27 Standard-Atomen vorbelegt bzw. konfiguriert.
#macro Cube_Default(State)
Cube_Config(State,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom,
Atom, Atom, Atom)
#end
// Anfangskonfiguration eines Zauberwürfels.
#macro Cube_Init(State, TexA, TexR, TexL, TexU, TexD, TexB, TexF)
// Aufkleber erzeugen
#local TagR = CreateTag(TexR, +x); // rechts
#local TagL = CreateTag(TexL, -x); // links
#local TagU = CreateTag(TexU, +y); // oben
#local TagD = CreateTag(TexD, -y); // unten
#local TagB = CreateTag(TexB, +z); // hinten
#local TagF = CreateTag(TexF, -z); // vorne
#local CenterAtom = object { Atom texture { TexA } }
// Konfiguration eines gelösten Zauberwürfels
Cube_Config(State,
// Oberste Ebene
CreateAtom3(TexA, TagL, TagU, TagF),
CreateAtom2(TexA, TagU, TagF),
CreateAtom3(TexA, TagR, TagU, TagF),
CreateAtom2(TexA, TagL, TagU ),
CreateAtom1(TexA, TagU ),
CreateAtom2(TexA, TagR, TagU ),
CreateAtom3(TexA, TagL, TagU, TagB),
CreateAtom2(TexA, TagU, TagB),
CreateAtom3(TexA, TagR, TagU, TagB),
// Mittlere Ebene
CreateAtom2(TexA, TagL, TagF),
CreateAtom1(TexA, TagF),
CreateAtom2(TexA, TagR, TagF),
CreateAtom1(TexA, TagL, ),
CenterAtom,
CreateAtom1(TexA, TagR, ),
CreateAtom2(TexA, TagL, TagB),
CreateAtom1(TexA, TagB),
CreateAtom2(TexA, TagR, TagB),
// Unterste Ebene
CreateAtom3(TexA, TagL, TagD, TagF),
CreateAtom2(TexA, TagD, TagF),
CreateAtom3(TexA, TagR, TagD, TagF),
CreateAtom2(TexA, TagL, TagD ),
CreateAtom1(TexA, TagD ),
CreateAtom2(TexA, TagR, TagD ),
CreateAtom3(TexA, TagL, TagD, TagB),
CreateAtom2(TexA, TagD, TagB),
CreateAtom3(TexA, TagR, TagD, TagB))
#end
// Ausgabe der konfigurierten 3x3x3-Matrix, Ausgabe des Zauberwürfels.
#macro Cube_Show(State)
union {
#local X = 0;
#while (X < 3)
#local Y = 0;
#while (Y < 3)
#local Z = 0;
#while (Z < 3)
object { State[X][Y][Z] }
#local Z = Z + 1;
#end
#local Y = Y + 1;
#end
#local X = X + 1;
#end
}
#end
// ----------------------------------------------------------------------------
/* Rotationen */
// x-Rotation: Eine y-z-Ebene (XIndex) wird um einen Winkel (Angle) gedreht.
#macro Cube_RotateX(State, XIndex, Angle)
#if (Angle != 0.0) // höhere Effizienz
#local X = XIndex;
#local Y = 0;
#while (Y < 3)
#local Z = 0;
#while (Z < 3)
#local State[X][Y][Z] = object {
State[X][Y][Z]
rotate x * Angle
}
#local Z = Z + 1;
#end
#local Y = Y + 1;
#end
#end
#end
// y-Rotation: Eine x-z-Ebene (YIndex) wird um einen Winkel (Angle) gedreht.
#macro Cube_RotateY(State, YIndex, Angle)
#if (Angle != 0.0) // höhere Effizienz
#local Y = YIndex;
#local X = 0;
#while (X < 3)
#local Z = 0;
#while (Z < 3)
#local State[X][Y][Z] = object {
State[X][Y][Z]
rotate y * Angle
}
#local Z = Z + 1;
#end
#local X = X + 1;
#end
#end
#end
// z-Rotation: Eine x-y-Ebene (ZIndex) wird um einen Winkel (Angle) gedreht.
#macro Cube_RotateZ(State, ZIndex, Angle)
#if (Angle != 0.0) // höhere Effizienz
#local Z = ZIndex;
#local X = 0;
#while (X < 3)
#local Y = 0;
#while (Y < 3)
#local State[X][Y][Z] = object {
State[X][Y][Z]
rotate z * Angle
}
#local Y = Y + 1;
#end
#local X = X + 1;
#end
#end
#end
// ----------------------------------------------------------------------------
/* Rotationssequenzen */
// Kernfunktion für Sequenzen, die einen Wert zwischen 0 und 1 ermittelt.
// Anwendung: Für Animationen kann man für Value die Zeit (clock) einsetzen.
// Voraussetzung: Start < End
// Resultat:
// * Falls (Value <= Start) -> 0.0
// * Falls (Value >= End) -> 1.0
// * Sonst (Start < Value < End) -> ((Value - Start) / (End - Start))
#declare interpolator = function(Start, End, Value) {
min(1.0, max(0.0, (Value - Start) / (End - Start)))
}
// Turn: Eine Ebene (?Index) wird in Abhängigkeit von Value (z. B.: clock)
// minimal um 0° (clock <= Start) und maximal um 90° (clock >= End) gedreht.
// Ist clock >= End wirkt sich die Rotation auch auf die gegebene
// 3x3x3-Matrix (State) aus.
// Der Spin {Negative = -1.0; Positive = +1.0} drückt die Drehrichtung aus.
// Konsistenz: Der Zustand des Würfels (State bzw. 3x3x3-Matrix) muss nach
// abgeschlossener 90°-Drehung (Grafik-Drehung) ebenfalls mit einer adäquaten
// Drehung (State-Drehung) angepasst werden, damit weitere Turns unabhängig
// von den vorhergehenden Turns ausgeführt werden können.
// x-Turn: Eine y-z-Ebene (XIndex) wird konsistent gedreht (Grafik & State).
#macro Cube_TurnX(State, XIndex, Spin, Start, End, Value)
#local X = XIndex;
// Grafik-Drehung
Cube_RotateX(State, X, 90.0 * Spin * interpolator(Start, End, Value))
#if (Value >= End) // Abschlussbedingung -> State-Drehung
#if (Spin > 0.0)
#local MemX00 = State[X][0][0];
#local State[X][0][0] = State[X][0][2];
#local State[X][0][2] = State[X][2][2];
#local State[X][2][2] = State[X][2][0];
#local State[X][2][0] = MemX00;
#local MemX01 = State[X][0][1];
#local State[X][0][1] = State[X][1][2];
#local State[X][1][2] = State[X][2][1];
#local State[X][2][1] = State[X][1][0];
#local State[X][1][0] = MemX01;
#else
#local MemX00 = State[X][0][0];
#local State[X][0][0] = State[X][2][0];
#local State[X][2][0] = State[X][2][2];
#local State[X][2][2] = State[X][0][2];
#local State[X][0][2] = MemX00;
#local MemX01 = State[X][0][1];
#local State[X][0][1] = State[X][1][0];
#local State[X][1][0] = State[X][2][1];
#local State[X][2][1] = State[X][1][2];
#local State[X][1][2] = MemX01;
#end
#end
#end
// y-Turn: Eine x-z-Ebene (YIndex) wird konsistent gedreht (Grafik & State).
#macro Cube_TurnY(State, YIndex, Spin, Start, End, Value)
#local Y = YIndex;
// Grafik-Drehung
Cube_RotateY(State, Y, 90.0 * Spin * interpolator(Start, End, Value))
#if (Value >= End) // Abschlussbedingung -> State-Drehung
#if (Spin > 0.0)
#local Mem0Y0 = State[0][Y][0];
#local State[0][Y][0] = State[2][Y][0];
#local State[2][Y][0] = State[2][Y][2];
#local State[2][Y][2] = State[0][Y][2];
#local State[0][Y][2] = Mem0Y0;
#local Mem1Y0 = State[1][Y][0];
#local State[1][Y][0] = State[2][Y][1];
#local State[2][Y][1] = State[1][Y][2];
#local State[1][Y][2] = State[0][Y][1];
#local State[0][Y][1] = Mem1Y0;
#else
#local Mem0Y0 = State[0][Y][0];
#local State[0][Y][0] = State[0][Y][2];
#local State[0][Y][2] = State[2][Y][2];
#local State[2][Y][2] = State[2][Y][0];
#local State[2][Y][0] = Mem0Y0;
#local Mem1Y0 = State[1][Y][0];
#local State[1][Y][0] = State[0][Y][1];
#local State[0][Y][1] = State[1][Y][2];
#local State[1][Y][2] = State[2][Y][1];
#local State[2][Y][1] = Mem1Y0;
#end
#end
#end
// z-Turn: Eine x-y-Ebene (ZIndex) wird konsistent gedreht (Grafik & State).
#macro Cube_TurnZ(State, ZIndex, Spin, Start, End, Value)
#local Z = ZIndex;
// Grafik-Drehung
Cube_RotateZ(State, Z, 90.0 * Spin * interpolator(Start, End, Value))
#if (Value >= End) // Abschlussbedingung -> State-Drehung
#if (Spin > 0.0)
#local Mem00Z = State[0][0][Z];
#local State[0][0][Z] = State[0][2][Z];
#local State[0][2][Z] = State[2][2][Z];
#local State[2][2][Z] = State[2][0][Z];
#local State[2][0][Z] = Mem00Z;
#local Mem10Z = State[1][0][Z];
#local State[1][0][Z] = State[0][1][Z];
#local State[0][1][Z] = State[1][2][Z];
#local State[1][2][Z] = State[2][1][Z];
#local State[2][1][Z] = Mem10Z;
#else
#local Mem00Z = State[0][0][Z];
#local State[0][0][Z] = State[2][0][Z];
#local State[2][0][Z] = State[2][2][Z];
#local State[2][2][Z] = State[0][2][Z];
#local State[0][2][Z] = Mem00Z;
#local Mem10Z = State[1][0][Z];
#local State[1][0][Z] = State[2][1][Z];
#local State[2][1][Z] = State[1][2][Z];
#local State[1][2][Z] = State[0][1][Z];
#local State[0][1][Z] = Mem10Z;
#end
#end
#end
// ----------------------------------------------------------------------------
/* Mnemonik & Abstraktion */
#declare Positive = +1.0;
#declare Negative = -1.0;
#declare Center = 1;
#declare Left = 0;
#declare Right = 2;
#declare Up = 2;
#declare Down = 0;
#declare Front = 0;
#declare Back = 2;
// L := Eine viertel Umdrehung der linken Ebene im Uhrzeigersinn.
#macro Cube_L (State, Start, End, Value)
Cube_TurnX(State, Left, Negative, Start, End, Value)
#end
// L_ := Eine viertel Umdrehung der linken Ebene gegen den Uhrzeigersinn.
#macro Cube_L_(State, Start, End, Value)
Cube_TurnX(State, Left, Positive, Start, End, Value)
#end
// R := Eine viertel Umdrehung der rechten Ebene im Uhrzeigersinn.
#macro Cube_R (State, Start, End, Value)
Cube_TurnX(State, Right, Positive, Start, End, Value)
#end
// R_ := Eine viertel Umdrehung der rechten Ebene gegen den Uhrzeigersinn.
#macro Cube_R_(State, Start, End, Value)
Cube_TurnX(State, Right, Negative, Start, End, Value)
#end
// U := Eine viertel Umdrehung der oberen Ebene im Uhrzeigersinn.
#macro Cube_U (State, Start, End, Value)
Cube_TurnY(State, Up, Positive, Start, End, Value)
#end
// U_ := Eine viertel Umdrehung der oberen Ebene gegen den Uhrzeigersinn.
#macro Cube_U_(State, Start, End, Value)
Cube_TurnY(State, Up, Negative, Start, End, Value)
#end
// D := Eine viertel Umdrehung der unteren Ebene im Uhrzeigersinn.
#macro Cube_D (State, Start, End, Value)
Cube_TurnY(State, Down, Negative, Start, End, Value)
#end
// D_ := Eine viertel Umdrehung der unteren Ebene gegen den Uhrzeigersinn.
#macro Cube_D_(State, Start, End, Value)
Cube_TurnY(State, Down, Positive, Start, End, Value)
#end
// F := Eine viertel Umdrehung der vorderen Ebene im Uhrzeigersinn.
#macro Cube_F (State, Start, End, Value)
Cube_TurnZ(State, Front, Negative, Start, End, Value)
#end
// F_ := Eine viertel Umdrehung der vorderen Ebene gegen den Uhrzeigersinn.
#macro Cube_F_(State, Start, End, Value)
Cube_TurnZ(State, Front, Positive, Start, End, Value)
#end
// B := Eine viertel Umdrehung der hinteren Ebene im Uhrzeigersinn.
#macro Cube_B (State, Start, End, Value)
Cube_TurnZ(State, Back, Positive, Start, End, Value)
#end
// B_ := Eine viertel Umdrehung der hinteren Ebene gegen den Uhrzeigersinn.
#macro Cube_B_(State, Start, End, Value)
Cube_TurnZ(State, Back, Negative, Start, End, Value)
#end |