Richtungsvektor für ein Bitmap programmieren ?



  • Als Übungsaufgabe müssen wir für eine Koch-Kurve einen Richtungsvektor programmieren. Doch wie fängt man sowas an?

    Die rekursive Funktion soll eine Linie in 3 gleichlange Teile teilen. Das mittlere Stück muss dann entfernt werden. Am Ende der 1. Linie soll mit einem Richtungsvektor eine Linie gleicher Länge um +60° gedreht gezeichnet werden. Am Ende dieser Linie wiederum um -120° gedreht das nächste Stück, sodass am Ende die enfernte Line mit einem Dreieck überbrückt worden ist.

    Ich hoff das kann man verstehen 🙂 Wie setzt man denn sowas an? Hab keinen blassen Schimmer wie man nen Richtungsvektor erstellt.

    Ps: Die Pixel der .bmp wurden in ein Array eingelesen.



  • pippo schrieb:

    Ich hoff das kann man verstehen 🙂 Wie setzt man denn sowas an? Hab keinen blassen Schimmer wie man nen Richtungsvektor erstellt.

    ich auch nicht. aber ich kann programmieren. ich code mal, und du sagst, ob du einen richtungsvektor draus machen kannst.

    //ungetestet
    #define sin(x) sin(x/PI*180)
    #define cos(x) cos(x/PI*180)
    void drehlinks60grad(Vector v){
       return Vector(v.x*cos(60)-v.y*sin(60),v.//sowas irgendwie. 
       //angeblich benutzt man eine drehmatrize
    }
    void koch(Vektor a,Vector e,tiefe){
       if(tiefe==0){
          maleStrich(a,e);
       }
       else{
          Vektor b=(2*a+e)/3;
          Vektor d=(a+2*e)/3;
          Vector b+drehlinks60grad(d-b);
          koch(a,b,tiefe-1);
          koch(b,c,tiefe-1);
          koch(c,d,tiefe-1);
          koch(d,e,tiefe-1);
       }
    }
    


  • Warum gibt denn deine void nen Wert zurück? 😃

    Die Vektoren würd ich anders berechnen:

    b = a + (e-a)/3
    d = a + (e-a)/3*2

    Was ich aber noch nicht versteh ist, wie man das ganze dann in eine Funktion (maleStrich) umsetzt, die diese Punkte dann verbindet.
    Deine drehlinks60grad is mir auch net ganz schlüssig



  • So, für alle die es interessiert, wie man nen Header ausliest und ne Koch-Kurve in C++ erzeugt, hier der Code:

    // Übungsblatt 2.cpp : Koch-Kurve
    
    // DEFINES ********************************************************************
    
    // HEADER FILES ***************************************************************
    #include <iostream>
    #include <fstream>
    #include <cmath>
    #include "bmp.h"
    using namespace std;
    
    // FUNKTIONS ******************************************************************
    void OriginalEinlesen(char OffBits[], char Pixel[256][512]);
    void KochSchreiben(char OffBits[], char Pixel[256][512]);
    void RecKoch(int A[], int E[], short Tiefe, char Pixel[256][512]);
    void ZeicheStrich(int A[], int E[], char Pixel[256][512]);
    void Tausche(int A[], int E[]);
    
    // STREAMS ********************************************************************
    ifstream Original("template.bmp", ios::binary | ios::in);
    ofstream Koch("Koch-Kurve.bmp", ios::binary | ios::out);
    
    // VARIABLES ******************************************************************
    bmFileHeader bFH;
    
    // MAIN PROGRAM ***************************************************************
    int main() {
    	if (!Original.good()) {	//Prüfen, ob sich das Original ordnungsgemäß öffnen lässt
    		cout << "Fehler beim Oeffnen der Datei" << endl;
    		return 1;
    	}
    	Original.read(reinterpret_cast<char*>(&bFH),sizeof(bmFileHeader));	//Einlesen des Headers
    	Original.seekg(ios::beg);	//Zurück zu Pos. 1
    
    	char * OffBits = new char[bFH.bfOffBits];	//Array für alle Daten bis zum 1. Pixel
    	char Pixel[256][512];	//Array für alle Pixel
    	int A[2], E[2];	//Arrays für den Anfangs- und Endpunkt
    	short int Tiefe;
    
    	cout << "Informatik II - Uebungsblatt 2" << endl << "------------------------------" << endl << endl;
    	cout << "Geben sie die Anzahl der Schritte ein: ";	//Bestimmung der Rekursionstiefe
    	cin >> Tiefe;
    	OriginalEinlesen(OffBits, Pixel);	//Einlesen des Originals in das jeweilige Array
    	Original.close();  //Schließen der Originaldatei
    
    	A[0]=1;	//Festlegen der Grundlinie
    	A[1]=1;
    	E[0]=(bFH.biWidth-1);
    	E[1]=1;
    
    	RecKoch(A, E, Tiefe, Pixel);	//Berechnung aller Punkte
    	KochSchreiben(OffBits, Pixel);	//Schreiben des neuen Bildes
    	Koch.close();  //Schließen der erzeugten Datei
    	delete OffBits;	//Löschung des dynamischen Arrays
    	return 0;
    }
    
    void OriginalEinlesen(char OffBits[], char Pixel[256][512]) {    
    	for(long i=0; i<bFH.bfOffBits; i++) Original.get(OffBits[i]);
    	for(i=0; i<bFH.biHeight; i++) {
    		for(long j=0; j<bFH.biWidth; j++) Original.get(Pixel[i][j]);
    	}
    }
    
    void KochSchreiben(char OffBits[], char Pixel[256][512]) {
    	for (long i=0; i<bFH.bfOffBits; i++) Koch.put(OffBits[i]);
    	for(i=0; i<bFH.biHeight; i++) {
    		for(long j=0; j<bFH.biWidth; j++) Koch.put(Pixel[i][j]);
    	}
    }
    
    void RecKoch(int A[], int E[], short Tiefe, char Pixel[256][512]) { 
    	int B[2], C[2], D[2];
    
    	if(Tiefe==0) ZeicheStrich(A, E, Pixel);		//Rekursionsbasis
    	else {
        B[0] = A[0] + (E[0]-A[0])/3;	//Berechnung des linken Punktes der Grundlinie des Dreiecks
        B[1] = A[1] + (E[1]-A[1])/3; 
        D[0] = A[0] + ((E[0]-A[0])/3)*2;	//Berechnung des rechten Punktes der Grundlinie des Dreiecks
        D[1] = A[1] + ((E[1]-A[1])/3)*2; 
    	C[0] = B[0] + int(0.5*(D[0]-B[0]) - sqrt(3.0)/2*(D[1]-B[1]));	//Berechnung der Spitze des Dreiecks
        C[1] = B[1] + int(sqrt(3.0)/2*(D[0]-B[0]) + 0.5*(D[1]-B[1]));
        RecKoch(A, B, Tiefe-1, Pixel);	//Rekursionsschritte
    	RecKoch(B, C, Tiefe-1, Pixel); 
    	RecKoch(C, D, Tiefe-1, Pixel); 
    	RecKoch(D, E, Tiefe-1, Pixel); 
    	}
    } 
    
    void ZeicheStrich(int A[], int E[], char Pixel[256][512]) {
    	double Steigung, y, x;
    	int j, a=0;
    
    	if (E[0]-A[0]<0) {	//Prüfen, ob der Anfangspunkt links vom Endpunkt ist
    		Tausche(A, E);	//ggf. tauschen beider Punkte
    		a++;
    	}
    	y =(E[1]-A[1]);	//Berechnung des y-Wertes der Steigung
    	x =(E[0]-A[0]);	//Berechnung des x-Wertes der Steigung
    	if (x==0.0) Steigung=0.0;	//Abfangen der Division durch 0
    	else Steigung=y/x;
    	if (Steigung<0.0){	//Zeichnet die Linie von oben nach unten
    		Steigung*=(-1);	//Negieren der Steigung, damit j nicht negativ wird
    		for(int i=A[0], k=0; i<=E[0]; i++, k++) {
    			j=A[1]-int(Steigung*k);
    			Pixel[j][i]=0;	//Ändern der berechneten Pixel auf 0 (schwarz)
    		}
    	}
    	else {	//Zeichnet die Linie von unten nach oben
    		for(int i=A[0], k=0; i<=E[0]; i++, k++) {
    				j=A[1]+int(Steigung*k);
    				Pixel[j][i]=0;
    			}
    		}
    	if (a==1) Tausche(A, E);	//ggf. zurücktauschen beider Punkte
    }
    
    void Tausche(int A[], int E[]) {
    	int * Temp = new int [2];
    
    	Temp[0]=A[0];
    	Temp[1]=A[1];
    	A[0]=E[0];
    	A[1]=E[1];
    	E[0]=Temp[0];
    	E[1]=Temp[1];
    	delete Temp;	
    }
    

    bmp.h

    #pragma pack(1)
    struct bmFileHeader {            
       char bfType1, bfType2;        // dort steht 'B' 'M'
       long bfSize;                  // Dateilaenge
       short bfReserved1;			 // Reserve
       short bfReserved2;			 // Reserve
       long bfOffBits;               // * Abstand zum Beginn der Bilddaten
       //Beginn InfoHeader
       long biSize;                  // Laenge des Info Header
       long biWidth;                 // Anzahl Pixel horizontal
       long biHeight;                // Anzahl Pixel vertikal
       short biPlanes;               // muss eine 1 enthalten
       short biBitCount;             // Anzahl Bits je Pixel, hier: 8
       long biCompression;           // Komprimierung
       long biSizeImage;             // Anzahl der Bytes fuer das Bild
       long biXPelsPerMeter;         // hor. Aufloesung in Pixel/Meter
       long biYPelsPerMeter;         // vert. Aufloesung in Pixel/Meter
       long biClrUsed;               // Anzahl tatsaechlich benutzter Farben (0)
       long biClrImportant;          // Anzahl unbedingt benoetigter Farben (0)
    };
    #pragma pack ()
    

    Sollte jemand Verbesserungsvorschläge haben oder mir erklären können, wie man die Pixel in einen vector packt, damit man nicht so an bestimmte Auflösungen gebunden ist, soll er es bitte sagen



  • (Hab mir den code jetzt nicht durchgelesen.)
    Vielleicht kann ich dir mit den Vektoren weiterhelfen:
    Ein Vektor ist in deinem Fall zweidimension, ich kenne mich aber nur mit dreidimensionalen Vektoren aus. Ich benutz jetzt mal das, sollte ja keinen Unterschied machen.
    Ein richtungsvektor besteht aus, (in deinem Fall) zwei Zahlen, die einem Punkt im Koordinatensystem entsprechen. Wir nehemen als z-koordinate einfach 0. Die Länge eines Vektors berechnet sich aus der Wurzel der Summe der Quadrate der Komponenten. Einen Vektor nennt man normalisiert, wenn er die länge 1 hat. Man normalisiert einen Vektor, indem man jeden Komponenten durch die Länge teilt. Das besondere an einem normalisierten Richtungsvektor ist, dass er immer noch in die selbe Richtung zeigt wie der ausgangsvektor. Den Richtungsvektor zw. 2 Punkten errechnet sich aus der Differenz des 2. und des 1. Punktes (Komponentweise subtraktion). Das Rotieren ist interessanter. Dreidimensional mach ich das über quaternions, obs zweidimensional was besseres gibt, weiß ich net. Ein vektor wird als quaternion mit dem skalarteil 0 dargestellt. Ein Winkel a der Rotationsachse v(norm. Vektor) wird als quaternion (cos(a/2),x·sin(a/2),y·sin(a/2),z·sin(a/2))
    dargestellt. Das rotierte quaternion r brechnet sich als
    r=a*p*a' (a - winkel, p - Koordinate, beide als quaternion)
    a' ist die konjugierte Form von a.
    Die konjugierte Form eines quaternion ergibt sich als q'=(q.s,-q.i,-q.j,-q.k)
    Multilikation von quaternionen:
    s = s1s2 - i1i2 - j1j2 - k1k2
    i = s1i2 + i1s2 + j1k2 - k1j2
    j = s1j2 + j1s2 + k1i2 - i1k2
    k = s1k2 + k1s2 + i1j2 - j1i2 (könnte falsch sein, hab ich jetzt ausm Kopf...)
    Ich hoffe das hilft, auch wenns gleich ne ganze Menge ist...


Anmelden zum Antworten