/********************************************************************
Pickover Attraktor
Plugin für Cinema Version 7.0
(c) Jürgen Meier (J.Meier@Dialup.Nacamar.de)
Version : 1.00
20.09.2001
*********************************************************************/

// Globale Variablen und Konstanten
   // Plugin ID Nummer
      const var cPluginID = 1006515;
   // Pluginname
      const var cPlugName = "Pickover Attraktor";
   // Pluginhilfstext
      const var cPlugHelp = "Erzeugt den Pickover Attraktor";
   // Objektname
      const var cObjName = "Pickover Attraktor";
   // Index
      var i;
   // Koordinaten der Punkte
      var x,y,z;
   // Alter Wert von x
      var xa;
   // Differenzen
      var dx,dy,dz;
   // Breite des Menütextes
      var Breite=150;
   // Maximalwerte
      var cMaxFloat=1000000;
      var cMaxInt=100000000;
   // Objektvariable
      var qObj;
   // Dialogvariable
      var gDial;
   // Attraktorspezifische Variablen
      // Konstanten
         var a=2.24;
         var b=0.43;
         var c=-0.65;
         var d=-2.43;
      // Radius
         var Radius=0.1;
      // Anzahl Iterationen
         var N=1000;
      // Startwerte
         var x0=0.0;
         var y0=0.2;
         var z0=0.3;
      // Skalierungsfaktor
         var Faktor=100;

// ******************************************************************
// Funktion zum Objekt aktivieren (c) h.g.seib
// ******************************************************************
   fSetActiveObject(vDoc,vObj)
   {
   // Aktives Objekt ermitteln
      var vAObj = GetActiveObject(vDoc);
   // Active object Bit bzw. Flag setzen
      if (vAObj) vAObj->DelBit(BIT_AOBJ);
          vObj->SetBit(BIT_AOBJ);
   // Änderung im Dokument bekanngeben (neues Objekt selektiert)
      GeEventAdd(NEW_ACTIVE_OBJECT);
   }

// ******************************************************************
// Funktion zur Berechnung des Attraktors
   fAttraktor(vDoc)
   {
   // Nullobjekt erzeugen
      var attraktor = new(NullObject);
   // Name zuweisen
      attraktor->SetName(cObjName);
   // Nullobjekt in die Szene einfügen
      vDoc->InsertObject(attraktor,NULL,NULL);
   // Neues Primitive Object erzeugen
      var kugel = new(PrimitiveObject);
   // Aus dem Primitive Object eine Kugel machen
      kugel->SetPrimitiveType(PRIMITIVE_SPHERE);
   // Container erzeugen
      var sc = kugel->GetContainer();
   // Radius der Kugel setzen
      sc->SetData(PRIM_SPHERE_RAD,Radius);
   // Container Variablen zurückgeben
      kugel->SetContainer(sc);
   // Name zuweisen
      kugel->SetName("Kugel");
   // Objekt in der Dokumenthierarchie positionieren
      vDoc->InsertObject(kugel,attraktor,NULL);
   // Attraktor berechnen
      // Ersten Punkt berechnen
         // Startwerte übergeben
            xa=x0;
            y=y0;
            z=z0;
         // Punkt berechnen
            x = sin(a*y)-z*cos(b*xa);
            y = z*sin(c*xa)-cos(d*y);
            z = sin(xa);
         // Erste Kugel positionieren
            kugel->SetPosition(vector(x*Faktor,y*Faktor,z*Faktor));
         // x Wert aktualisieren
            xa=x;
      // Restliche Punkte berechnen
         for (i=0;i<N;i++)
             {
              // Neue Koordinaten berechnen
                 x = sin(a*y)-z*cos(b*xa);
                 y = z*sin(c*xa)-cos(d*y);
                 z = sin(xa);
              // Instanz der Kugel erzeugen
                 var instanz = new(InstanceObject);
                 var ic = instanz->GetContainer();
              // Instanz auf Kugel setzen
                 ic->SetData(INSTANCEOBJECT_SOURCE,"Kugel");
                 instanz->SetContainer(ic);
              // Name zuweisen
                 instanz->SetName("I-Kugel"+tostring(i));
              // Instanz positionieren
                 instanz->SetPosition(vector(x*Faktor,y*Faktor,z*Faktor));
              // Objekt in der Dokumenthierarchie positionieren
                 vDoc->InsertObject(instanz,attraktor,NULL);
                 GeEventAdd(DOCUMENT_CHANGED);
              // x Wert aktualisieren
                 xa=x;
             }
   // Objekt aktivieren
      fSetActiveObject(vDoc,attraktor);
      GeEventAdd(DOCUMENT_CHANGED);
    return TRUE;
   }

// ******************************************************************
// Ableitung der Klasse MyDialog von GeDialog
// ******************************************************************
class MyDialog : GeDialog
{
   public:
      MyDialog();
      CreateLayout();
      Init();
      CoreMessage(vID,vMSG);
      Command(vID,vMSG);
}
// ******************************************************************
// Deklaration des Konstruktors
   MyDialog::MyDialog()
   {
   // Konstruktor der parent class aufrufen
      super(cPluginID);
   }

// ******************************************************************
// Deklaration der Methode CreateLayout
   MyDialog::CreateLayout()
   {     
   // Plugintitel setzen
      SetTitle(cPlugName);
   // Gruppe für die Konstanten
      AddGroupBeginV(1000,BFH_CENTER,2,"",0);
      {
         AddStaticText(0,BFH_LEFT,Breite,0," Konstante a",0);
         AddEditNumber(2000,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Konstante b",0);
         AddEditNumber(2001,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Konstante c",0);
         AddEditNumber(2002,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Konstante d",0);
         AddEditNumber(2003,BFH_LEFT,100,0);
      }
      // Vertikal orientierte Gruppe schliessen
         AddGroupEnd();
   // Waagerechte Trennlinie
      AddSeparatorH(0);
   // Gruppe für die Startwerte
      AddGroupBeginV(1001,BFH_CENTER,2,"",0);
      {
         AddStaticText(0,BFH_LEFT,Breite,0," Start x",0);
         AddEditNumber(2500,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Start y",0);
         AddEditNumber(2501,BFH_LEFT,100,0);
      }
      // Vertikal orientierte Gruppe schliessen
         AddGroupEnd();
   // Waagerechte Trennlinie
      AddSeparatorH(0);
   // Gruppe für die Parameter der Iteration
      AddGroupBeginV(1002,BFH_CENTER,2,"",0);
      {
         AddStaticText(0,BFH_LEFT,Breite,0," Radius Kugel",0);
         AddEditNumber(2502,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Anzahl N",0);
         AddEditNumber(2503,BFH_LEFT,100,0);
         AddStaticText(0,BFH_LEFT,Breite,0," Faktor",0);
         AddEditNumber(2504,BFH_LEFT,100,0);
      }
      // Vertikal orientierte Gruppe schliessen
         AddGroupEnd();
   // Waagerechte Trennlinie
      AddSeparatorH(0);
   // Button für den Start der Berechnung
      AddButton (3000,BFH_CENTER,200,0,"Start");
      return TRUE;
   }

// ******************************************************************
// Deklaration der Methode Init
   MyDialog::Init()
   {
   // Startwerte setzen
      SetFloat(2000,a,-cMaxFloat,cMaxFloat,0);
      SetFloat(2001,b,-cMaxFloat,cMaxFloat,0);
      SetFloat(2002,c,-cMaxFloat,cMaxFloat,0);
      SetFloat(2003,d,-cMaxFloat,cMaxFloat,0);
      SetFloat(2500,x0,-cMaxFloat,cMaxFloat,0);
      SetFloat(2501,y0,-cMaxFloat,cMaxFloat,0);
      SetFloat(2502,Radius,-cMaxFloat,cMaxFloat,0);
      SetInt(2503,N,0,cMaxInt,0);
      SetFloat(2504,Faktor,0,cMaxFloat,0);
      return TRUE;
   }

// ******************************************************************
// Deklaration der Methode CoreMessage
   MyDialog::CoreMessage(vID,vMSG)
   {
      switch (vID)
         {
            case NEW_DOCUMENT:
            case DOCUMENT_CHANGED:
            case NEW_ACTIVE_OBJECT:
            case ACTIVE_OBJECT_CHANGED:
            return TRUE;
            break;
         }
      return FALSE;
   }

// ******************************************************************
// Deklaration der Methode Command
   MyDialog::Command(vID,vMSG)
   {
      var vDoc;
   //
      StopAllThreads();
      switch (vID)
      {
        case 3000 : // Start Button gedrückt
                      {
                         vDoc = GetActiveDocument();
                         if (!vDoc) return FALSE;
                         fAttraktor(vDoc);
                      }
        case 2000 : a=GetFloat(2000);
        case 2001 : b=GetFloat(2001);
        case 2002 : c=GetFloat(2002);
        case 2003 : d=GetFloat(2003);
        case 2500 : x0=GetFloat(2500);
        case 2501 : y0=GetFloat(2501);
        case 2502 : Radius=GetFloat(2502);
        case 2503 : N=GetInt(2503);
        case 2504 : Faktor=GetFloat(2504);
      }
      return TRUE;
   }


// ******************************************************************
// Ableitung der Klasse MyMenuPlugin von MenuPlugin
// ******************************************************************
   class MyMenuPlugin : MenuPlugin
   {  public:
          MyMenuPlugin();
          GetID();
          GetName();
          GetHelp();
          Execute(doc);
          RestoreLayout(secret);
   }
// ******************************************************************
// Deklaration des Konstruktors
   MyMenuPlugin::MyMenuPlugin()
   { 
      super();
   }

// ******************************************************************
// Deklaration der Methode GetID
   MyMenuPlugin::GetID()
   {
      return cPluginID;
   }

// ******************************************************************
// Deklaration der Methode GetName
   MyMenuPlugin::GetName()
   {
       return cPlugName;
   }

// ******************************************************************
// Deklaration der Methode GetHelp
   MyMenuPlugin::GetHelp()
   {
       return cPlugHelp;
   }

// ******************************************************************
// Deklaration der Methode Execute
   MyMenuPlugin::Execute(doc)
   {
      if (!gDial)
         gDial=new(MyDialog);
     gDial->Open(TRUE,-1,-1);
   }
// ******************************************************************
// Deklaration der Methode RestoreLayout
   MyMenuPlugin::RestoreLayout(secret)
   {
      if (!gDial)
         gDial=new(MyDialog);
      gDial->RestoreLayout(secret);
   }

// ******************************************************************
main()
{
    Register(MyMenuPlugin);
}

