• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Suche Algorithmus zum ändern der Basisfarben eines Balls in

Hallo zusammen,

ich suche einen Algorithmus für folgende Situation in einem Programm für C++ und Qt Bibliotheken (geschrieben wird das ganze im QtCreator)

Ein Ball ist in Bewegung. Dabei durchläuft er eine Farbveränderung, wobei jeder Bewegung um ein Pixel eine Farbveränderung um "eins" entspricht. Dabei geht der Farbverlauf von RGB {0, 0, 0} zunächst zu {255, 0, 0} danach zu {255, 255, 0} danach: { 255, 255, 255 }, {0, 255, 255}, { 0, 0, 255}, { 0, 0, 0 } wonach er sich wiederholt.

Der Ball wird folgendermaßen befüllt:

Code:
painter.setBrush(QBrush(QColor(colorX, colorY, colorZ), Qt::SolidPattern));

Nun ist dies mein Lösungsansatz:

Code:
if (increment) // increment = 1 also ist der Ball in Bewegung

        switch (color) {

        case 0:
            if (colorX <= 255 && colorY == 0 && colorZ == 0) {
                colorX++;
            }
                else color = 1;

                //break;

        case 1:
            if (colorX >= 255 && colorY <= 255 && colorZ == 0) {
                colorX = 255;
                colorY++;

            }
                else color = 2;
                //break;

        case 2:
            if (colorX >= 255 && colorY >= 255 && colorZ <= 255) {
                colorX = 255;
                colorY = 255;
                colorZ++;
            }
                else color = 3;
                //break;

        case 3:
            if (colorX >= 255 && colorY >= 255 && colorZ >= 255) {
                colorX--;
                colorY = 255;
                colorZ = 255;
            }
                else color = 4;
                //break;

        case 4:
            if (colorX <= 0 && colorY >= 255 && colorZ >= 255){
                colorX = 0;
                colorY--;
                colorZ = 255;
            }
                else color = 5;
                //break;

        case 5:
            if (colorX <= 0 && colorY <= 0 && colorZ >= 255){
                colorX = 0;
                colorY = 0;
                colorZ--;
            }
                else color = 6;
                //break;

        case 6:
            if (colorX <= 0 && colorY <= 0 && colorZ <= 0){
                colorX = 0;
                colorY = 0;
                colorZ = 0;
            }
                color = 0;
                //break;


        }

Der Fehler muss sich irgendwo in case 3 befinden, da die Kugel ja weiß wird und sich dann nicht mehr verändert. Bei 255, 255, 255 müsste ja der Wert weiß erreicht sein. Wo ist hier der Fehler? Hat jemand hier eine elegantere Variante?

Danke und grüße
 

framp

Moderator
Teammitglied
Warum benutzt Du nicht den Modulooperator? Dann musst Du nur unterscheiden zwischen inc Phase und bei 255.255.255 dann auf dec Phase umschalten und bei 0.0.0 wieder inc.
 
Ich würd's mal ohne case schreiben. (In Python, meiner bevorzugten Sprache, gibt's case auch gar nicht.)
Dann würde die switch case Anweisung doch gar nicht mehr funktionieren oder?

Ich habe mittlerweile den Fehler gefunden: Die if Abfrage in case 3 wird genau einmal ausgeführt. Wenn der Wert dekrementiert ist, ist die erste Bedingung nicht mehr erfüllt.

Code:
if (colorX > 0 && colorY >= 255 && colorZ >= 255) {
...
}

usw. für die nachfolgenden cases.

Ich bin mittlerweile auch über eine Lösung mit dem Modulo Operator gestossen, hier als Java Code:

Code:
public class Colorswitch
{
	public Colorswitch ()
	{
		int colorX = 0; 
		int colorY = 0; 
		int colorZ = 0; 
		int cnt = 0; 
		
		while (6*256 > cnt++) 
		{
			System.out.println (colorX + "\t" + colorY  + "\t" + colorZ);
			switch ((cnt%(6*256)-1)/255) {
				case 0: colorX++; break;
				case 1: colorY++; break;
				case 2: colorZ++; break;
				case 3: colorX--; break;
				case 4: colorY--; break;
				case 5: colorZ--; break;
			}
		}
	}

	public static void main (String args[])
	{
		new Colorswitch ();		
	}
}

Ich denke so werde ich es mal versuchen. Vielen Dank für Euren Rat!
 

abgdf

Guru
Es müßte übrigens 256 * 256 * 256 = 16,78 Mio. Möglichkeiten geben (das sind ja glaube ich auch alle Farben, die das Auge unterscheiden kann). Ganz schön lange für einen Durchlauf.
 

framp

Moderator
Teammitglied
Einentlich dachte ich bei Modulo an eine etwas andere Nutzung :roll:
Code:
#!/usr/bin/env python 

max=10 # 256

color= [0] * 3;

for l in range(0,max**3):
    print color;
    for i in [0,1,2]:
        color[i]=(color[i]+1)%max;
        if color[i] != 0:            
            break
        
color= [max-1] * 3;
for l in range(max**3,0,-1):
    print color;
    for i in [0,1,2]:
        color[i]=(color[i]-1)%max;
        if color[i] != max-1:            
            break
 

abgdf

Guru
abgdf schrieb:
Es müßte übrigens 256 * 256 * 256 = 16,78 Mio. Möglichkeiten geben (das sind ja glaube ich auch alle Farben, die das Auge unterscheiden kann). Ganz schön lange für einen Durchlauf.
Ähh, hier lag ich wohl nicht ganz richtig. :ups:

Ich glaube, man kann das relativ einfach z.B. so machen:
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

a = [0, 0, 0]
b = 1

while True:
    if b == 1 and a[0] < 255:
        a[0] += 1
    if b == 1 and a[0] >= 255:
        b = 2
        a[0] = 255
    if b == 2 and a[1] < 255:
        a[1] += 1
    if b == 2 and a[1] >= 255:
        b = 3
        a[1] = 255
    if b == 3 and a[2] < 255:
        a[2] += 1
    if b == 3 and a[2] >= 255:
        b = 4
        a[2] = 255
    if b == 4 and a[0] > 0:
        a[0] -= 1
    if b == 4 and a[0] <= 0:
        b = 5
        a[0] = 0
    if b == 5 and a[1] > 0:
        a[1] -= 1
    if b == 5 and a[1] <= 0:
        b = 6
        a[1] = 0
    if b == 6 and a[2] > 0:
        a[2] -= 1
    if b == 6 and a[2] <= 0:
        b = 1
        a[2] = 0
    print a
Mal die Ausgabe mit "skript.py > out.txt" nach "out.txt" leiten und sich die Sache ansehen. Ist vielleicht noch nicht so superschön, aber was soll's. Oben hast Du ja mehrere Zustände oder "Richtungen" beschrieben; das bilde ich hier durch Variable "b" ab.

Mit der farbigen Kugel könnte das dann (in Python/Tkinter) z.B. so aussehen:
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

try:
    import Tkinter as tk
except:
    import tkinter as tk

class myWindow:

    def __init__(self):

        self.mw = tk.Tk()
        self.mw.option_add("*font", ("Arial", 15, "normal"))
        self.mw.geometry("+250+200")
        self.mw.title('Farbkugel')

        self.cv = tk.Canvas(self.mw,
                                 width = 320,
                                 height = 240,
                                 bg = "white")
        self.cv.pack()

        self.btn2 = tk.Button(self.mw, text = "Exit", command = self.mw.destroy)
        self.btn2.pack()

        self.k1 = Ball("#000000", 5, 8, 100, 80, self.mw, self.cv)
        self.mw.after_idle(self.k1.run)
        self.mw.mainloop()


class Ball:

    def __init__(self, color, vx, vy, x, y, mw, cv):

        self.vx = vx
        self.vy = vy
        self.x = x
        self.y = y
        self.color = color
        self.colors = [0, 0, 0]
        self.colordir = 1
        self.mw = mw
        self.cv = cv
        self.kugel = self.cv.create_oval(x, y,
                                         x + 15, y + 15,
                                         fill = color)
    def run(self):
        self.changeColor()
        self.moveit()
        self.mw.after(30, self.run)

    def changeColor(self):
        if self.colordir == 1 and self.colors[0] < 255:
            self.colors[0] += 1
        if self.colordir == 1 and self.colors[0] >= 255:
            self.colordir = 2
            self.colors[0] = 255
        if self.colordir == 2 and self.colors[1] < 255:
            self.colors[1] += 1
        if self.colordir == 2 and self.colors[1] >= 255:
            self.colordir = 3
            self.colors[1] = 255
        if self.colordir == 3 and self.colors[2] < 255:
            self.colors[2] += 1
        if self.colordir == 3 and self.colors[2] >= 255:
            self.colordir = 4
            self.colors[2] = 255
        if self.colordir == 4 and self.colors[0] > 0:
            self.colors[0] -= 1
        if self.colordir == 4 and self.colors[0] <= 0:
            self.colordir = 5
            self.colors[0] = 0
        if self.colordir == 5 and self.colors[1] > 0:
            self.colors[1] -= 1
        if self.colordir == 5 and self.colors[1] <= 0:
            self.colordir = 6
            self.colors[1] = 0
        if self.colordir == 6 and self.colors[2] > 0:
            self.colors[2] -= 1
        if self.colordir == 6 and self.colors[2] <= 0:
            self.colordir = 1
            self.colors[2] = 0

        self.cv.itemconfig(self.kugel, fill = self.getHexString())

    def getHexString(self):
        a = "#"
        for i in self.colors:
            h = hex(i)
            h = h[2:]
            if i < 16:
                h = "0" + h
            a += h
        return a


    def moveit(self):
        self.x += self.vx
        self.y += self.vy
        if self.x > int(self.cv["width"]) - 15 or self.x < 15:
            self.vx = - self.vx
        if self.y > int(self.cv["height"]) - 15 or self.y < 15:
            self.vy = - self.vy
        self.cv.move(self.kugel, self.vx, self.vy)

if __name__ == "__main__":
   app = myWindow()
;)
 

abgdf

Guru
abgdf schrieb:
Ich glaube, man kann das relativ einfach z.B. so machen:
Code:
#!/usr/bin/python
#-*- coding: iso-8859-1 -*-

a = [0, 0, 0]
b = 1

while True:
    if b == 1 and a[0] < 255:
        a[0] += 1
    if b == 1 and a[0] >= 255:
        b = 2
        a[0] = 255
    if b == 2 and a[1] < 255:
        a[1] += 1
    if b == 2 and a[1] >= 255:
        b = 3
        a[1] = 255
    if b == 3 and a[2] < 255:
        a[2] += 1
    if b == 3 and a[2] >= 255:
        b = 4
        a[2] = 255
    if b == 4 and a[0] > 0:
        a[0] -= 1
    if b == 4 and a[0] <= 0:
        b = 5
        a[0] = 0
    if b == 5 and a[1] > 0:
        a[1] -= 1
    if b == 5 and a[1] <= 0:
        b = 6
        a[1] = 0
    if b == 6 and a[2] > 0:
        a[2] -= 1
    if b == 6 and a[2] <= 0:
        b = 1
        a[2] = 0
    print a
Da das Ganze dann doch relativ gleichförmig ist, kann man es noch ein bißchen "kürzen":
Code:
#!/usr/bin/python
# coding: iso-8859-1

color = [0, 0, 0]
downlimit = 0
uplimit = 255
colorval = 0
addition = 1

print color

x = 0
while x < 10000:

    if color[colorval] <= uplimit and color[colorval] >= downlimit:
        color[colorval] += addition

    if color[colorval] > uplimit or color[colorval] < downlimit:
        if addition == 1:
            color[colorval] = uplimit
        elif addition == -1:
            color[colorval] = downlimit
        colorval += 1
        if colorval > len(color) - 1:
            colorval = 0
            addition *= -1
            continue
       
    print color
    x += 1
Es ist aber beinahe die Frage, ob das nun einfacher zu verstehen ist als die vorherige Version.
Allerdings ist das dann schon recht dicht an dem gewünschten Algorithmus; könnte man vielleicht so nach C++ übersetzen.
Python wird ja oft verwendet, um Prototypen für C++-Code zu schreiben.

Edit: Wow, gab' doch noch 1/2 Bugs: Wurden oben ausgebessert.
 

abgdf

Guru
Yo, läßt sich tatsächlich ohne nennenswerte Probleme nach C übertragen:
Code:
#include <stdio.h>

int main() {
    int color[] = {0, 0, 0};
    int downlimit = 0;
    int uplimit = 255;
    int colorval = 0;
    int addition = 1;
    int x = 0;

    printf("{%d, %d, %d}\n", color[0], color[1], color[2]);

    while (x < 10000) {
        if (color[colorval] <= uplimit && color[colorval] >= downlimit) {
            color[colorval] += addition;
        }

        if (color[colorval] > uplimit || color[colorval] < downlimit) {
            if (addition == 1) {
                color[colorval] = uplimit;
            } else if (addition == -1) {
                color[colorval] = downlimit;
            }
            colorval++;
            if (colorval > sizeof(color) / sizeof(int) - 1) {
                colorval = 0;
                addition *= -1;
                continue;
            }
        }
    printf("{%d, %d, %d}\n", color[0], color[1], color[2]);
    x++;
    }
    return 0;
}
Das freut einen doch. :)
 
Oben