Interface Design für eine Grafik Library



  • Alle Member statisch? Dann würde ich doch trotzdem mit dem Singleton Prinzip arbeiten müssen, da static Member ja nur andere static Member benutzen dürfen. Aber was soll an Singleton schlimm sein?

    explicit sorgt dafür, dass man den Konstruktor explizit aufrufen muss und der Compiler folgendes nicht mehr erlaubt

    pixel p=1;
    

    Side meint sicher so etwas

    class grafic
    {
      handle hnd;
    public:
      grafic() { create_hnd(hnd); }
      void putpixel(int x, int y, color col);
      //...
    }
    


  • Wo ist das Problem mit Static ?

    Mach's doch so :

    class CGraphic
    {
    public : 
    
         static void putpixel (int, int, color);
         static void setbg (color);
    
    private :
    
         static handle m_handle;
         static bool bereit;
         static int fensterx, fenstery;
    };
    

    Du brauchst wahrscheinlich eh nur eine Instanz von CGraphic. Es passt ganz gut dort alles static zu machen. Um zu verhindern dass jm eine Instanz deiner Klasse bildet, kannst du den Konstruktor ja private machen.

    So ähnlich wird das auch bei der Clanlib (www.clanlib.org, wie SDL nur in C++ && mehr highlevel) gemacht. Es ist einfach viel bequemer auf CL_Display::get_width() zuzugreifen anstatt auf g_display.get_width () 🙂



  • irgend wie mag ich das nicht so. Was hälst du den von Version2?



  • Könntest du deine Variante 2 nochmal was ausführlicher Erläutern ?
    Was machst du mit der Klasse point ?



  • Die Klassen beinhalten nur die Eigenschaften der grafischen Elemente.

    class point
    {
      int x_, y_;
      color col;
    public:
      explicit point(int x=0, int y=0, color c=0)
       : x_(x), y_(y), col(c) { }
      inline ~point() { }
      void paint(void) const;
      inline int x(void) const { return x_; }
      //...
    };
    

    Wenn man nun ein Punkt malen will, dann macht man das so:

    point pt(1,5,gruen);
    pt.paint();
    


  • Ich finde das extrem umständlich

    Stell dir vor du willst ein paar Punkte mehr zeichnen, für mich wäre das zuviel Schreibarbeit.

    Mh, wie wäre dies hier :

    class CGraphicalObject
    {
    protected
         //jedes objekt hat eine farbe
         color m_color;
    
         //linke obere Ecke des Objektes
         int m_x, m_y;
    
    public :
    
         //jedes objekt kann gezeichnet werden
         virtual void paint () = 0;
    };
    
    class CRect : public CGraphicalObject
    {
    private :
    
          //höhe und breite
          int m_h, m_w;
    
    public :
          virtual void paint (int x, int y, int w, int h, in color);
    };
    
    class CCircle : public CGraphicalObject 
    {
    /////
    }
    

    Mit diesem Ansatz hast du aber immer noch das Problem, dass es recht umständlich ist verschiedene Ausgabegeräte anzusprechen.

    Mein "Lieblingsansatz" ist der 9.te Post von oben, wo alles von der CABCGraphic abgeleitet wird. Im Prinzip muss deine Graphiclib nur Punkte zeichnen können. Aus Punkten kannst du dann alles zusammensetzen.
    Dann kannst du auch eine Klasse CRect, CCircle oder sonstwas bauen. Diese greifen auf ein -am Besten 100% statisches- von CABCGraphic abgeleitetes Objekt zu. D.h. deiner Zeichenklassen ist es Kackegal ob du mit OGL, SDL, Text oder sonstwas arbeitest.
    Darauf kommt es imo auch an : Versuche vor den Zeichenfunktionen die unterliegenden Ausgabegeräte zu verstecken und zu kapseln !



  • @kingruedi liege ich richtig? du hast http://www.c-plusplus.net/titel_21.htm noch nicht gelesen?
    das fliegen gewicht muster könnte passen und ein oder zwei ander muster(habe das buch jetzt nicht da)

    also was ich mir unter user freundlich vorstele ist

    int main()
    {
       pixel pix( kordinate( 10, 10 ), farbe( 255, 255, 255 ) );
       pix.draw()
       line lin( kordinate( 100, 100 ), kordinate( 200, 200 ), farbe( 255, 255, 255 ) );
    }
    

    überlege einfach wie würdes du diese zeichen arbeit am tisch machen und versuche das zu programmieren.
    eine funktion putpixel ist so als ob du mit ein stift zu einer kordinate gehst und ein punkt malst, wenn du jetzt den punkt in bewegng haben willst, muss du das blatt wegschmeissen und ein neuen pixel malen
    das wird bei vielen objekten ziemlich aufwändig.

    dagegen, ein pixel objekt ist so als ob du ein stück papier abschneidest und auf das blatt legst, du kannst es verschieben und co. (aber pixel ausschneiden ist aufwändiger als ein pixel mit den stift zu malen)

    [ Dieser Beitrag wurde am 19.01.2003 um 06:32 Uhr von Dimah editiert. ]



  • Ich denke der Ansatz ist zu Granular... das macht Sinn für eine Lib, die sich auf Vektorgrafiken abstützt. Aber wenn es pixelbasiert sein soll, dann arbeitet man so nicht.

    Schaut man sich andere Implementationen an, so wird regelmäßig als kleinstes Objekt eher auf der Ebene des Canvas mit der Klassenbildung begonnen - der Hintergrund ist doch klar:

    Wenn ich ein

    pix(400, 100, farbe(255, 128, 0)).draw();
    

    schreiben muß um einen Punkt zu zeichnen, dann wird das Objekt auf dem Stack angelegt, die Werte werden in Membervariablen umkopiert, intern dann die Zeichenfunktion aufgerufen und die Membervariablen vom Stack auf den Stack umkopiert und die eigentliche Grafikfunktion aufgerufen. Das klingt nicht schnell. Und sich darauf verlassen, daß der Compiler das schon durchoptimiert... da hätte ich Bauchschmerzen.

    Außerdem will ich gerne so ein Problem gelöst haben:

    pix(400, 100, farbe(255, 128, 0)).draw();
    line(200, 100).draw(); // soll die gleiche Farbe wie der Punkt haben!
    

    Macht man die Farbe zu einer Eigenschaft des Punktes, so verzerrt das etwas... eigentlich ist die Farbe eine Eigenschaft des aktuellen Zeichenstiftes. Also muß bei der Linienkonstruktion - da die Farbe wieder als Attribut der Linie auftaucht - die aktuelle Farbe ermittelt werden (woher? vom letzten Punkt?) und zwischengespeichert zu werden, um erneut verwendet zu werden im draw(). Der Informationsfluß ist zu aufwendig, zu viele Kopien.



  • hmm dann stimm ich für beides..

    in php habe ich es genossen, auch sowas machen zu können

    for ($x=0; $x<=$breite; $x++){
       for ($y=0; $y<=$breite; $y++){
           $fn =sqrt($x*$x +$y*$y);
           $rundung=$fn%$breite;
           imagesetpixel($bild,$x,$y,$farbe[$rundung]);
       }
    }
    

    also daß der letzte parameter, die farbe.. auch pixelweise gesetzt werden kann..
    damit farbverläufe herstellen ist nett.

    aber nur am rande



  • @Elise: was wäre in Deinem Beispiel der Unterschied dazu, die Farbe als Stifteigenschaft zu betrachten und den Stift am Canvas aufzuhängen? Ok, ich brauche dann zwei Aufrufe, aber es entstehen dadurch doch keine neuen Möglichkeiten?



  • Hi !

    Die Variante mit dem Stift klingt sehr vielversprechend. OpenGL mach das so ähnlich :

    glBegin (GL_QUADS); //Vierecke zeichnen
    
         glColor3f (1.0f,0.0f,0.0f); //rote Farbe setzen
    
         glVertex3f (....);//rechteck rendern, Farbe rot wird übernommen
         glVertex3f (....);
         glVertex3f (....);
         glVertex3f (....);
    
    glEnd (); //nix mehr zeichnen
    

    Das ist sehr praktisch, zumal man sich den Overhead spart die Stiftfarbe jedesmal per Parameter zu übergeben 🙂



  • menschlicher ist die stift idee..

    aber bei farbverläufen müsste ich aber immer den stift weglegen, einen neuen nehmen, punkt, stift weglegen einen neuen nehmen...

    aber die sache mit der linie, die die vorherige farbe hat, überzeugt ebenso..

    hm .. ich seh grad, in mfc ist es mal so mal so?

    CClientDC dc(this);     //Geraetekontext herstellen
    RECT rect;
    GetClientRect(&rect);
    
    //dc.FillRect(&rect, new CBrush(RGB (255,0,0)));  //hier würde ich einen stift nehmen
    
    for (int i=rect.left; i<rect.right; i++)
        for (int j= rect.top; j<rect.bottom; j++){
    
        dc.SetPixel(i, j, RGB(255,0,0));   //hier kann ich dem punkt direkt eine farbe zuweisen
    }
    

    ps: ich kann kein mfc 😉

    [ Dieser Beitrag wurde am 19.01.2003 um 10:50 Uhr von elise editiert. ]



  • Deswegen gibt's ja auch den Brush... weil Du einen Farbverlauf ja nicht mit einem Stift machen würdest. Naja, wenn man die Analogie so weit treibt.

    Da wünsche ich mir eher einen Brush, Größe 40 x 20, Startfarbe (0,0,0), Endfarbe(0,0,255), Farbverlauf linear, von oben-links nach unten-rechts. Brushobjekt fertig. [Gleichzeitig kann der Brush natürlich auch Texturen unterstützen, die aus einem File kommen.]

    Danach zeichne ich mit diesem Brush auf dem Canvas.

    Vermutlich kommt zum Schluß eine Zwitterlösung raus:

    Der Canvas bekommt einige elementare Zeichenroutinen (Pixel, Move, Line) verpasst, die er direkt als Methoden ausführt. Für komplexere Gebilde führt man ein Objekt-Interface ein, von dem man dann Kreise, Rechtecke etc ableiten kann und die auch z.B. farbige Punkte umfassen können.

    Aha, wenn ich darüber nachdenke kommt man auf den Unterschied zwischen Pixel und Punkt - ein Pixel ist eine Speicherstelle im Canvas, schon fast was Binäres. Das Setzen eines Pixels im Canvas eine elementare Zeichenoperation, schnell und direkt, Lowlevel. Ein Punkt ist aber bereits ein Objekt, das Informationen wie Position und Farbe umfasst. D.h. es gäbe durchaus die Berechtigung für Punkt-Klassen, solange man nicht gezwungen wird jedes grafische Element auf der Punkt-Klasse abzustützen.



  • Original erstellt von Marc++us:
    Da wünsche ich mir eher einen Brush, Größe 40 x 20, Startfarbe (0,0,0), Endfarbe(0,0,255), Farbverlauf linear, von oben-links nach unten-rechts. Brushobjekt fertig. [Gleichzeitig kann der Brush natürlich auch Texturen unterstützen, die aus einem File kommen.]

    Interessant fände ich auch sowas:

    Brush::Brush(Color (*fn)(int, int));
    

    Wobei die Paramater an fn immer relativ zur Ecke sind...



  • @Marc++us
    würde das deinem Ansatz entsprechen?

    class canvas
    {
      friend class pen;
      friend class brush;
      static hnd handler;
    public:
      canvas(int breite, int hoehe);
      //...
    };
    
    class pen
    {
    public:
      pen(color x);
      //...
      setpixel(int x, int y);
    };
    
    class brush
    {
    public:
      typedef color (*farb)(int,int);
      brush(color c, int breite, int hoehe);
      brush(const char *texture);
      brush(color start, color end, int breite, int hoehe);
      brush(farb c);
      //...
      move(int x0, int y0, int x1, int y1);
    };
    

    @Dimah
    Nein, das Buch habe ich noch nicht gelesen, steht aber schon in meiner "zu-lesen" Liste (die ist nur so unendlich lang und das Budget ist so unendlich klein 😞 )

    solange helf ich mir mit http://home.earthlink.net/~huston2/dp/patterns.html

    [ Dieser Beitrag wurde am 19.01.2003 um 12:31 Uhr von kingruedi editiert. ]

    [ Dieser Beitrag wurde am 19.01.2003 um 14:28 Uhr von kingruedi editiert. ]



  • und wie übersetzt man Farbverlauf ins englische?



  • Colormissrunning (AE)
    oder
    gradient (BE)



  • 1. der Programmierer neigt dazu ein globales grafic Object anzulegen

    Einfach Singleton, ein Grafikausgang muss pro Programm reichen.

    2. der Programmierer könnte auf die Idee kommen mehrere grafic Objekte anzulegen

    Siehe erstens...

    2. Finde ich ebenfalls viel zu umständlich. 3. wie bereits gesagt zu "C-lich". Also wieder zurück zu 1.:

    Warum nicht so? Text drunter lesen!!

    // singleton:
    class init_graph
    {
       // den buffer-käse eben ;-)   
    };
    
    class krlib
    {
        public:
        krlib ( init_graph * unique );
    
        private:
    
        bool setcolor ( ... );
        bool setsonstwas ( ... );
        COLOR getcolor ();
        SONSTWAS getsonstwas ();    
    
        bool draw ( point apoint );
        ...
    
        init_graph * _uni;
    
        friend class point;
    
    };
    
    class point
    {
        public:
    
        point ( int x , int y );
    
        setpos ( int x , int y );
        COORD getpos ();
    
        draw () { krlib::draw ( *this ) ); } // Geht sowas??
    
        private:
    
        int itsx, itsy; 
    };
    
    // Und dann:
    int main ()
    {
        init_graph * MYGRAPH = init_graph::get_instance ( std::cout , std::cin );
        krlib GRAFIK ( MYGRAPH );
    
        GRAFIK.setcolor (RED);    
    
        point apoint;    
    
        for ( int i = 1 ; i < XMAX - 50 ; ++i )
        {
            for ( int j = 1 ; j < YMAX ; ++j )    
            { 
                apoint.setpos ( i , j );
                apoint.draw ();  
            }        
        }    
    
        return ( 0 );
    }
    

    Zwei Punkte haben dann imho keinen Sinn mehr - pos muss immer geändert werden, mehr hat point nicht mehr also singleton?!

    Also soll der Punkt auch die Farbe bekommen (warum auch nicht??), aber den Puffer in den er mit draw() gemalt wird bekommt er über friend-Zugriff auf GRAFIK. GRAFIK wiederrum verwaltet grundsätzlich nur welche Objekte es gibt(nachteil: keine eigenen Objekte) und da es als einziges die draw()-Methoden besitzt, bestimmt es Koordinatensystem, etc. allgemeine Dinge eben.

    Also obrigen Code so abändern, das Punkt auch die Farbe enthält (also GRAFIK hat kein setcolor, getcolor, etc. mehr).

    PROBLEM: Wenn der User MYGRAPH zwar an GRAFIK (also an krlib) übergibt, aber keine Instanz geholt hat und auch MYGRAPH nicht auf 0 sitzt gibts kleine Festplattenlöschungen...

    explicit:

    class xxx
    {
        xxx ( double x );
        operator double ();
    };
    
    xxx a, b;
    
    a = b + 45,6; // Nun gäbe es double (b) + 45,6 und b + xxx(45,6)
    

    Wird stattdesen oben explicit vor xxx geschrieben ist nur noch die Umwandlung in double möglich, oder es wird _explizit_ xxx() angegeben. Soweit ich das richtig verstanden habe 🙄.

    BTW: Habe vom Code nichts kontrolliert - also viele Fehler wahrscheinlich - habe keine Zeit mehr den Code zu kontrollieren...

    MfG SideWinder

    [ Dieser Beitrag wurde am 19.01.2003 um 18:00 Uhr von SideWinder editiert. ]

    [ Dieser Beitrag wurde am 19.01.2003 um 18:04 Uhr von SideWinder editiert. ]



  • Ich mach das jetzt ungefähr so wie Marc++us mir das Vorgeschlagen hat (bzw. so wie ich es verstanden habe ;))


Anmelden zum Antworten