source: projects/visualisator/lochstreifen.c @ 3

Last change on this file since 3 was 3, checked in by sven, 11 years ago

Das Lochstreifenvisualisierungsprogramm wurde komplett umgeschrieben. Die
Datei gtkprogram.c wurde aufgeteilt in ein neues Objekt, GtkPaperTape,
welches alle Zeichenoperationen mit dem Lowlevel-Objekt LOCHSTREIFEN
abgleicht sowie zahlreiche GUI-Menues und aehnliches zur Verfuegung stellt.
Letztlich sieht die Verzeichnisstruktur jetzt so aus:

  • lochstreifen.c, lochstreifen.h: Das LOCHSTREIFEN Cairo-Zeichenobjekt
  • gtkpapertape.c, gtkpapertape.h: Das GtkPaperTape GTK-Widget
  • gtk.c: Ein GTK-Programm, welches das GtkPaperTape-Widget in einem Fenster anzeigt.
  • cli.c: Ein Kommandozeilenprogramm, welches ein Kommandozeileninterface (per Aufrufparameter) fuer das LOCHSTREIFEN-Objekt bietet
File size: 26.4 KB
Line 
1/**
2 * Lochstreifen mit Cairo zeichnen
3 *
4 * Diese Datei stellt ein Objekt (LOCHSTREIFEN) zur Verfuegung,
5 * welches mit Cairo Lochstreifen auf vielfaeltige Weise rendern
6 * kann. Ueber die zahlreichen Funktionen koennen die Variablen
7 * eingestellt werden.
8 *
9 * Diese Lochstreifenroutinen sind bewusst nur mit Cairo programmiert
10 * worden (kompilieren mit `pkg-config --cflags --libs cairo`), sie
11 * benoetigen kein installiertes GTK oder Glib.
12 *
13 * Die Variationsmoeglichkeiten fuer die gezeichneten Lochstreifen
14 * sind sehr vielfaeltig und koennen einzeln voellig frei miteinander
15 * kombiniert werden. So kann man saemtliche geometrischen Abstaende
16 * aendern (Abstand der Lochreihen, Lochspalten, Fuehrungloecher,
17 * Durchmesser der unterschiedlichen Loecher, Abstaende in und um
18 * den Lochstreifen, usw.) oder verhaeltnissmaessig angeben.
19 * Ausserdem laesst sich der Lochstreifen sehr leicht in 45°-Schritten
20 * drehen oder um beide Achsen spiegeln. Saemtliche Farben sind frei
21 * einstellbar, einzelne Objekte koennen auf Wunsch auch nicht
22 * gezeichnet werden.
23 *
24 * Anzumerken sei auch, dass diese Routinen nur die Zeichenarbeit
25 * uebernehmen -- das Cairoobjekt muss das Programm stellen. Damit sind
26 * voellige Freiheiten zur Wahl der Cairo-Surface gegeben (SVG, PNG,
27 * PDF, ... -- alles moeglich, Cairo eben). Da man bei der Erstellung
28 * einer Cairosurface ueblicherweise Groessenangaben braucht, kriegt
29 * man diese aus den aktuellen Parametern berechnet mit
30 * lochstreifen_get_width und lochstreifen_get_height.
31 *
32 * Fuer die Bedeutung der einzelnen Felder der LOCHSTREIFEN-Struktur
33 * siehe Header-File, fuer genauere Erklaerungen zu den Funktionen
34 * siehe direkt bei deren Implementierungen (diese Datei).
35 *
36 * sven, im November 2007.
37 *
38 **/
39#include <math.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include "lochstreifen.h"
45
46#define DEBUG 1
47
48int file_get_contents(FILE *stream, byte_t **content) {
49    /**
50    * Kleine Behelfsfunktion, die den stream (z.B. stdin, eine Datei) als Bytes
51    * komplett einliest.
52    * Erwartet: Stream, Zeiger auf Zeiger (für Array)
53    * Gibt zurück:  Return-value:      Laenge von content, rechnend ab 1
54    *               Call-by-reference: Content wird alloziiert als Array mit Inhalt
55    *
56    * Erzeugt seltsamerweise manchmal komische Fehler,
57    * g_file_get_contents von Glib funktioniert zuverlaessiger.
58    **/
59    // das war meine Version, bevor ich mir alles von g_file_get_contents
60    // abgeschaut habe. Einen Fehler hab ich zumindest gerade entdeckt:
61    // realloc gibt ggf. einen neuen Pointer zurück. Das würde erklären, warum auch
62    // das ganze *mal* ging und *mal* nicht. Offensichtlich kopiert realloc dann auch
63    // die Daten, wenn es entscheidet, sie woanders auf dem heap abzusieldeln...
64    /*
65    // um wie viel Zeichen das dynamische Array jeweils erhoeht werden soll
66    // ein Kompromiss zwischen Platzverschwendung (zuviel allokatierter aber ungenutzter
67    // Speicher) und Perfomance beim Einlesen (zu oft das Array erweitern)
68    #define FILE_GET_CONTENT_STEPSIZE 20
69
70    int length;
71    int extended = 1; // wie oft bereits erweitert
72    *content = (byte_t*) malloc(sizeof(byte_t) * FILE_GET_CONTENT_STEPSIZE);
73    if(*content == NULL) return 0; // schlecht.
74
75    for(length=0;;) {
76        (*content)[length] = (byte_t)fgetc(stream);
77        if(feof(stream) != 0) break; // EOF vor dem Einlesen!
78        printf("%03d. Zeichen eingelesen: 0x%02X (=%c)\n", length+1, (*content)[length], (*content)[length]);
79        if(extended*FILE_GET_CONTENT_STEPSIZE == ++length) {// Speicherende erreicht?
80             printf("=> Bereits %d mal den %d-Puffer verwendet, erweitere auf %d...\n", extended, FILE_GET_CONTENT_STEPSIZE, (extended+1)*FILE_GET_CONTENT_STEPSIZE);
81             if(realloc(*content, sizeof(byte_t)*(++extended)*FILE_GET_CONTENT_STEPSIZE) == NULL) // Speicher vergroessern
82                 return length; // Fehler - das eingelesene zumindest zurueckgeben.
83        }
84    }
85
86    return length; // wir wollen ab 1 zaehlen, das wurde indirekt durch den letzten unnoetigen ++inkrement gemacht
87    }
88    int file_get_contents(FILE *stream, byte_t **content) {
89    */
90    /**
91     * Neugeschrieben nach etwas Inspiration von der glib am 05.04.2008.
92     * Funktion get_contents_stdio, gfileutils.c im Sourcecode von glib-2.14.3.
93     * Router natürlich aus (03:11!), aber da sieht man mal wieder den Vorteil von Gentoo:
94     * Gleich alle Sourcecodes auf der Platte =)
95     *
96     *
97     *
98     **/
99     // *stream = *f
100     // *content = **contents
101     // gsize *length
102
103     char buf[4096];
104     size_t bytes; // gerade eben eingelesene bytes
105     char *str = NULL;
106     size_t total_bytes = 0;     // alle bis jetzt eingelesenen bytes
107     size_t total_allocated = 0;
108     char *tmp; // fuers realloc
109
110     while(!feof(stream)) {
111         bytes = fread(buf, 1, sizeof(buf), stream);
112
113         while( (total_bytes + bytes) > total_allocated) {
114             if(str)
115                 total_allocated *= 2;
116             else
117                 total_allocated = bytes > sizeof(buf) ? bytes : sizeof(buf);
118
119             tmp = realloc(str, total_allocated);
120
121             if(tmp == NULL) {
122                 fprintf(stderr, "*** file_get_contents ERROR*** Could not reallocate\n");
123                 //return length; // Fehler - das eingelesene zumindest zurueckgeben.
124                 // nee, gar nichts zurückgeben. Das geht so nicht.
125                 return 0;
126             }
127
128             str = tmp;
129        } // while innen
130
131        memcpy(str + total_bytes, buf, bytes);
132        total_bytes += bytes;
133     } // while
134
135     if(total_allocated == 0)
136         str = malloc(1); // ein leerer String halt.
137
138     //str[total_bytes] = '\0'; // wenns ein string wäre.
139
140     *content = str;
141
142     return total_bytes;
143}
144
145void lochstreifen_set_color(cairo_pattern_t *color, byte_t red, byte_t green, byte_t blue, byte_t alpha) {
146    /** Kleine Befehlsfunktion, die ein Cairopattern erzeugt. Farbwerte zwischen 0 und 255.
147        alpha = 255 ist unnoetig => einfach das Patternobjekt auf NULL setzen und die Zeichenfunktion
148        wird es nicht zeichnen. */
149    color = cairo_pattern_create_rgba(red/255, green/255, blue/255, alpha/255);
150}
151
152
153LOCHSTREIFEN *lochstreifen_new() {
154    /** Neues Lochstreifenobjekt erzeugen */
155    LOCHSTREIFEN *l = malloc(sizeof(LOCHSTREIFEN));
156    // Defaultwerte setzen:
157    l->d = 10;
158    l->data_length = 0;
159    l->data = NULL;
160    l->empty_start = 0;
161    l->empty_end = 0;
162    l->debug = 0;
163    l->hintergrund = NULL; // nicht zeichnen
164    l->streifenbg = cairo_pattern_create_rgb(0.7,0.7,0.7);
165    l->punched = cairo_pattern_create_rgb(0,0,0);
166    l->notpunched = cairo_pattern_create_rgb(0.827, 0.827, 0.827); //220/255, 220/255, 220/255);
167    l->fuehrung = cairo_pattern_create_rgb(143/255, 175/255, 255/255);
168    //cairo_matrix_init_identity(&(l->transformation));
169        //, 1, 0, 0, 1, 0, 0); // Standardmatrix einrichten (keine Drehung)
170    l->drehung = 0;
171    l->spiegelung_hor = 0;
172    l->spiegelung_ver = 0;
173    l->highlight_byte = 0;
174    l->highlight_color = NULL;
175    lochstreifen_flush_only_start_area(l);
176    return l;
177}
178
179void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end) {
180    /** Zu druckende Daten eingeben, Anzahl gewuenschter Leerbytes vorne/hinten eingeben,
181        ist empty_start/empty_end < 0, wird das entsprechende nicht gesetzt */
182    l->data_length = data_length;
183    if(l->data != NULL) // unbenutzten Speicher freigeben!
184        free(l->data);
185    l->data = data;
186    if(empty_start >= 0) l->empty_start = empty_start;
187    if(empty_end >= 0) l->empty_end = empty_end;
188}
189
190void lochstreifen_set_highlight(LOCHSTREIFEN* l, int byte_number) {
191    l->highlight_byte = byte_number;
192    if(l->highlight_color == NULL)
193        l->highlight_color = cairo_pattern_create_rgb(242/255, 255/255, 0);
194}
195
196int lochstreifen_set_only_start_area(LOCHSTREIFEN *l, int x, int y, int width, int height) {
197    /** Clipping-Rechteck setzen. Damit wird beim naechsten Zeichnen nur in diesem
198        Bereich gezeichnet. Es handelt sich jedoch um kein exiplites ordentliches
199        cairo_clipping, sondern eine grobe Naehrung zwecks Perfomance.
200        Die Koordinaten beziehen sich auf die entgueltige Form (inkl. Drehung, ...)
201    */
202    l->only_start_x = x;
203    l->only_start_y = y;
204    l->only_width = width;
205    l->only_height = height;
206}
207
208int lochstreifen_flush_only_start_area(LOCHSTREIFEN *l) {
209    /** Clipping-Rechteck loeschen -- beim naechsten Zeichnen alles zeichnen */
210    l->only_start_x = 0;
211    l->only_start_y = 0;
212    l->only_width = 0;
213    l->only_height = 0;
214}
215
216void lochstreifen_set_d(LOCHSTREIFEN *l, int d) {
217    /** Durchmesser eines Loches uebergeben (allgemeine Referenzeinheit fuer Dimensionen) */
218    l->d = d;
219    l->bspace = d*0.7/1.9;  // Abstand der Bytes voneinander (Reihen)
220    l->hspace = d/2;  // Abstand der Loecher in der Bytereihe
221    l->padding = d; // Abstand Löcher <=> Lochstreifenrand
222    l->df = d/2; // Durchmesser Lochfuehrungsloch
223    l->fspace = 1.1*(d+ l->hspace); // Breite der Lochfuehrungs"nut"
224    l->margin = d*2; // Abstand um Lochstreifen herum (an allen Seiten)
225    l->abriss = (8*d+6* l->hspace + l->fspace)/2; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
226}
227
228int lochstreifen_get_orientation(LOCHSTREIFEN *l) {
229    /** Gibt die Orientierung des Lochstreifens zurueck; 1 = horizontal, 0 = vertikal */
230    return (l->drehung % 2 == 0) ? 1 : 0;
231}
232
233int lochstreifen_get_width(LOCHSTREIFEN *l) {
234    /** Berechnet aktuelle Breite aus Lochstreifenkonstanten */
235    // interne Ersetzungen...
236    #define LOCHSTREIFEN_WIDTH  2*l->abriss + 2*l->margin + \
237        (l->data_length + l->empty_start + l->empty_end) * (l->d + l->bspace) - l->bspace // ein bspace zuviel am Ende
238    #define LOCHSTREIFEN_HEIGHT 8*l->d + 6*l->hspace + l->fspace + l->margin*2 + l->padding*2 \
239                                     //  ^ weil letztes hspace + hspace über fspace unnötig
240    return (l->drehung % 2 == 0) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
241}
242
243int lochstreifen_get_height(LOCHSTREIFEN *l) {
244    /** Berechnet aktuelle Hoehe aus Lochstreifenkonstanten */
245    return (l->drehung % 2 == 1) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
246}
247
248void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width) {
249    /**
250     * Umkehrfunktion zu set_d (dort wird die Breite/Hoehe durch d berechnet),
251     * hier wird d durch die vorgegebene Breite berechnet. Die Hoehe ergibt
252     * sich dann natuerlich auch automatisch.
253     * Evventuelle Drehungen werden miteinberechnet, d.h. wenn der Lochstreifen
254     * z.B. nach oben/unten zeigt, bezieht sich width auf die "echte" Hoehe.
255     **/
256    // Gleichung zum Berechnen von LOCHSTREIFEN_WIDTH nach
257    // d aufgeloest mit MuPad Pro 3.2 ( ;-) )
258    #define LOCHSTREIFEN_INV_WIDTH  (double) (1 / (6187./380. + 26./19. * (double)(l->data_length + l->empty_start + l->empty_end)))
259    #define LOCHSTREIFEN_INV_HEIGHT  (double) (1 * 20./373.)
260    lochstreifen_set_d(l,
261        (int)rint((double)width * ((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
262    );
263    //printf("Width soll %d ==> %d | %d\n", width, lochstreifen_get_width(l), lochstreifen_get_height(l));
264}
265
266void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height) {
267    /**
268     * Siehe set_d_by_width, nur wird hier d abhaengig von der gewuenschten Hoehe
269     * berechnet.
270     **/
271    lochstreifen_set_d(l,
272        (int)rint((double) height * LOCHSTREIFEN_INV_HEIGHT) //((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
273    );
274    //printf("Height soll %03d ==> d=%02d | %f, w/h = %03d | %03d\n", height, l->d,
275    //    (double)height*LOCHSTREIFEN_INV_HEIGHT
276    //    , lochstreifen_get_width(l), lochstreifen_get_height(l));
277}
278
279void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver) {
280    /**
281     * Transformationen der Lochstreifenausrichtung
282     * drehung: 0 = Kopf nach links
283     *          1 = oben
284     *          2 = rechts
285     *          3 = unten
286     *         -1 = nicht aendern
287     *          4 = um 90° im Uhrzeigersinn drehen
288     *          5 = um 90° gegen Uhrzeigersinn drehen
289     * Spiegelung horizontal/vertikal: 0 = nein
290     *                                 1 = ja
291     *                                 2 = vertauschen
292     *                                -1 = nicht aendern
293     **/
294     if(drehung >= 0) {
295         // Das "Ausprobieren" zwecks "Autodrehung" mit Aufruf wie
296         // lochstreifen_set_direction(l, l->drehung++, -1, -1);
297         //if(drehung > 4) drehung -= 4; // bei zu grossen Werten mal ausprobieren
298         //if(drehung < 0) drehung += 4; // bei zu kleinen Werten mal ausprobieren
299         //if(drehung % 4 == 0) drehung = 0; // quasi keine Drehung
300         if(drehung >= 4) {
301             if(drehung == 4) l->drehung++;
302             else if(drehung == 5) l->drehung--;
303             if(l->drehung >= 4) l->drehung -= 4; // bei zu grossen Werten
304             if(l->drehung < 0) l->drehung += 4; // bei zu kleinen Werten
305         } else {
306             //if(drehung > 0 && drehung < 4) // gute Werte
307             // normale Drehung mit festem Zielwert
308             l->drehung = drehung;
309         }
310     }
311     if(spiegelung_hor > -1) {
312         if(spiegelung_hor == 2) l->spiegelung_hor = l->spiegelung_hor == 0 ? 1 : 0; // negotieren
313         else l->spiegelung_hor = spiegelung_hor; // normal
314     }
315     if(spiegelung_ver > -1) {
316         if(spiegelung_ver == 2) l->spiegelung_ver = l->spiegelung_ver == 0 ? 1 : 0; // negotieren
317         else l->spiegelung_ver = spiegelung_ver; // normal
318     }
319}
320
321/*
322void lochstreifen_rotate(LOCHSTREIFEN *l) {
323    **
324     * Wird den Lochstreifen beim naechsten Zeichnen um 45° mit dem
325     * Uhrzeigersinn rotiert anzeigen. Nur mit diesen Funktionen wird
326     * die Hoehen/Breitenberechnung im Vorhinein noch funktionieren!
327     **
328     cairo_matrix_rotate(&(l->transformation), M_PI);
329     cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0),
330     l->drehung++; // ...
331}
332
333void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal) {
334    **
335     * Spiegelt den Lochstreifen, ist horizontal = 1 dann horizontal,
336     * sonst vertikal (oder so aehnlich)
337     **
338     if(horizontal != 0) { // vertikal
339         cairo_matrix_scale(&(l->transformation), -1, 1);
340         cairo_matrix_translate((&l->transformation), 0, lochstreifen_get_height(l));
341     } else {
342         cairo_matrix_scale(&(l->transformation), 1, -1);
343         cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0);
344     }
345}
346*/
347
348int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y) {
349     /**
350      * Anhand der Koordinaten (x|y) wird der Index des Bytes (fuers Datenarray, ab 1 zaehlend),
351      * welches damit "erfasst" wird, zurueckgegeben.
352      * Befindet sich (x|y) nicht im Bereich eines Bytes, dann wird je nach Fall zurueckgegeben:
353      *    0 = ausserhalb Lochstreifens
354      *   -1 = in Emptystart/Emptyend-Bytes (die nicht in der Datei existieren)
355      *        oder in Abrissbereichen
356      **/
357    int byte;
358    // BETRACHTUNG HORIZONTALE AUSRICHTUNG
359
360    if(y <= l->margin || y >= LOCHSTREIFEN_HEIGHT - l->margin) return 0; // ueber/unter Lochstreifen
361    x -= l->margin; // erst mal Rand abziehen
362    if(x <= 0) return 0; // links neben dem Lochstreifen.
363    x -= l->abriss + (l->empty_start)*(l->d + l->bspace); // Emptystart+Abrissbereich
364    if(x <= 0) return -1; // in diesem Bereich gewesen
365    // jetzt sind wir im Bytebereich
366    byte = (int) (x / (l->d + l->bspace)) + 1; // Abrunden: Auf welchem Byte man ist + ab 1 zaehlen.
367    if(byte > l->data_length + l->empty_start) return 0; // komplett ausserhalb Lochstreifens
368    else if(byte > l->data_length) return -1; // im Emptyendbereich
369    else return byte; // im gueltigen Bereich -- Byte gefunden!
370}
371
372int lochstreifen_coordinate_by_byte(LOCHSTREIFEN *l, int byte) {
373    /**
374     * Anhang eines Bytes (fuers Datenarray, ab 0 zaehlend) wird -- abhaengig nach aktueller
375     * Ausrichtung des Lochstreifens -- die Koordinate des Bytes in der Dimension der
376     * Ausrichtung des Lochstreifens zurueckgegeben..
377     * Liegt der Lochstreifen horizontal, so wird die x-Koordinate zurueckgegeben. Liegt er
378     * vertikal, dann die y-Koordinate.
379     *
380     **/
381     int xy;
382     //if(lochstreifen_get_orientation(l)) { // horizontal = 1 | vertical = 0
383        xy = l->margin + l->abriss + (l->d + l->bspace) * (byte + l->empty_start);
384     //}
385
386     return xy;
387     // TODO! Richtige implementierung!
388}
389
390void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr) {
391    /**
392     * Den Lochstreifen auf das uebergebene Cairoobjekt zeichnen.
393     * Die Funktion zeichnet nach den aktuellen Lochstreifenobjekt-Angaben
394     * (Groesse/Breite) -- wenn die cairo_image_surface nicht diesen Dimensionen
395     * entspricht, ist das alt schlecht.
396     *
397     **/
398    int byte,loch,x,y; // temp fuer Schleifen
399    int height = lochstreifen_get_height(l);
400    int width = lochstreifen_get_width(l);
401    // 4 Eckpunkte des Zeichenbereichs bestimmen...
402    int x1,x2,y1,y2;
403    x1 = l->only_start_x; y1 = l->only_start_y;
404    x2 = x1 + width; y2 = y1 + height;
405
406    /*int x1,y1,x2,y2,x3,y3,x4,y4;
407    x1 = l->only_start_x; y1 = l->only_start_y;
408    x2 = x1+width; y2 = y1;
409    x3 = x2; y3 = y2+height;
410    x4 = x1; y4 = y3;*/
411
412    // Verschiebungsmatrix erst hier berechnen, weil Verschiebungen vorher unklar
413    // wunderbare affine Abbildungen ;-)
414    cairo_matrix_t matrix, temp; // temp: Temporaere Matrix zur Matrizenmulitiplikation
415    cairo_matrix_init_identity(&matrix);
416    if(l->drehung > 0) {
417        if(l->drehung == 1) {
418            cairo_matrix_init(&temp, 0, -1, 1, 0, 0, height);
419            x = width; width = height; height = x;                // Breiten und Hoehen
420            x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
421        } else if(l->drehung == 2) {
422            cairo_matrix_init(&temp, -1, 0, 0, -1, width, height);
423        } else if(l->drehung == 3) {
424            cairo_matrix_init(&temp, 0, 1, -1, 0, width, 0);
425            x = width; width = height; height = x;                // Breiten und Hoehen
426            x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
427        }
428        cairo_matrix_multiply(&matrix, &matrix, &temp);
429    }
430
431    if(l->spiegelung_hor != 0) {
432         cairo_matrix_init(&temp, -1, 0, 0, 1,
433             l->drehung % 2 == 0 ? width : height, // Default bei Nicht-Drehung: width
434             0);
435         cairo_matrix_multiply(&matrix, &matrix, &temp);
436    }
437    if(l->spiegelung_ver != 0) {
438         cairo_matrix_init(&temp, 1, 0, 0, -1, 0,
439             l->drehung % 2 == 0 ? height: width); // Default bei Nicht-Drehung: height
440         cairo_matrix_multiply(&matrix, &matrix, &temp);
441    }
442
443    //if(l->drehung > 0) {
444        /*cairo_matrix_rotate(&matrix, l->drehung/2 *M_PI);
445        if(l->drehung == 1) { // 90°, im III. Sektor
446            //x = width; width = height; height = x;
447            //cairo_matrix_translate(&matrix, 0, 0);
448        } else if(l->drehung == 2) { // 180°, im IV Sektor
449            cairo_matrix_translate(&matrix, width, height);
450        } else if(l->drehung == 3) { // 270°, im I. Sektor
451            //x = width; width = height; height = x;
452            cairo_matrix_translate(&matrix, width, height);
453        }*/
454        // 4. Sektor kommt nicht vor
455    //}
456    cairo_set_matrix(cr, &matrix);
457    // -1, 0, 0, 1, width, 0 = spiegelung x-achse
458
459    //cairo_device_to_user(cr, (double*)&(l->only_start_x), (double*)&(l->only_start_y));
460    cairo_device_to_user(cr, (double*)&(x1), (double*)&(y1));
461    cairo_device_to_user(cr, (double*)&(x2), (double*)&(y2));
462
463    l->only_start_x = x2 < x1 ? x2 : x1;
464    l->only_start_y = y2 < y1 ? y2 : y1;
465
466    cairo_set_source(cr, l->fuehrung);
467    cairo_rectangle(cr, l->only_start_x, l->only_start_y, l->only_width, l->only_height);
468    //printf("Only: %d|%d, %d * %d\n", l->only_start_x, l->only_start_y, l->only_width, l->only_height);
469    cairo_paint(cr);
470
471    // Hintergrundfarbe zeichnen.
472    if(0||l->hintergrund != NULL) {
473        //l->hintergrund = cairo_pattern_create_rgb(1,1,1);
474        cairo_set_source(cr, l->hintergrund);
475        cairo_paint(cr);
476    }
477
478    // sache zeichnen
479    cairo_set_source(cr, l->streifenbg);
480    cairo_rectangle(cr, -10, -10, width+20, height+20);
481    cairo_stroke(cr);
482    if(0==1){
483        double x,y, a,b;
484        int xx,yy,aa,bb;
485        x=0;y=0; a=width;b=height;
486        cairo_matrix_transform_point(&matrix, &x, &y);
487        cairo_matrix_transform_point(&matrix, &a, &b);
488        xx=(int)x;yy=(int)y;aa=(int)a;bb=(int)b;
489        printf("Punkt (0/0)=(%i|%i) und (%i|%i)=(%i/%i)\n", xx, yy, width, height, aa, bb);
490    }
491
492    // Lochstreifenhintergrund inklusive Abriss vorne/hinten malen
493    if(l->streifenbg != NULL) {
494        cairo_set_source(cr, l->streifenbg);
495
496        // Abriss vorne
497        cairo_move_to(cr, l->margin + l->abriss*0.8, l->margin); // oben rechts
498        cairo_line_to(cr, l->margin, l->margin + l->padding+ 3*l->d + 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
499        cairo_line_to(cr, l->margin + l->abriss, height - l->margin); // unten ganz rechts
500        cairo_line_to(cr, l->margin + l->abriss, l->margin); // nach oben ganz rechts...
501        cairo_close_path(cr); // schliessen
502        // normaler Bereich
503        cairo_rectangle(cr, l->margin + l->abriss, l->margin,
504            width - 2*l->margin - 2*l->abriss, height - 2*l->margin);
505        /*printf("Zeichne Rechteck x|y = (%d|%d) width*height = %d * %d\n",
506            l->margin + l->abriss, l->margin,
507            width - 2*l->margin - 2*l->abriss, height - 2*l->margin
508        );*/
509        // Abriss hinten...
510        cairo_move_to(cr, width - l->margin - l->abriss*0.2, l->margin); // oben mitte
511        cairo_line_to(cr, width - l->margin - l->abriss,
512            l->margin + l->padding + 3*l->d+ 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
513        cairo_line_to(cr, width - l->margin, height - l->margin); // unten ganz rechts
514        cairo_line_to(cr, width - l->margin - l->abriss, height - l->margin); // unten ganz links
515        cairo_line_to(cr, width - l->margin - l->abriss, l->margin); // nach oben zum schliessen
516        cairo_close_path(cr);
517
518        cairo_fill(cr);
519    }
520
521
522    // Lochstreifenlöcher malen
523
524    /*if(l->only_start_x > 0) {
525        // nur in bestimmten Bereich zeichnen
526        int start_byte = l->empty_start + lochstreifen_byte_by_coordinate(l, l->only_start_x, l->only_start_y); // absolut inkl. empty bytes
527
528    } else byte = -l->empty_start; // leere Bytes vorne eingeschlossen
529    }*/
530
531    // Bytes durchgehen, leere Bytes vorne/hinten mit eingeschlossen
532    for(byte = -l->empty_start, x=l->margin + l->abriss; byte < l->data_length + l->empty_end; x += l->d + l->bspace, byte++) {
533        // Clipping: Um unnoetiges Zeichnen zu ersparen, erst ab X-Koordinate zeichnen
534        if(x < l->only_start_x - (l->d + l->bspace)) continue; // - 1x Loch weniger, damit nicht ein gerade abgeschnittenes nichtgezeichnet wird
535        // und nur bis zur rechten Begrenzung zeichnen -- dannach genuegt Abbruch.
536        if(l->only_width != 0 && x > l->only_start_x + l->only_width) break;
537
538        // ggf. Byte hervorheben
539        if(byte == l->highlight_byte && l->highlight_color != NULL) {
540            cairo_set_source(cr, l->highlight_color);
541            cairo_rectangle(cr, x - l->bspace/2, l->margin, l->df*2 + l->bspace, height - 2*l->margin);
542            cairo_fill(cr);
543        }
544
545        // Bits des entsprechenden Bytes durchgehen
546        for(loch=0, y = l->margin + l->padding; loch < 8; y += l->d + l->hspace, loch++) {
547            // Clipping: Erst ab Y-Koordinate zeichnen (-1xLoch-Korrektur gegen Abschnitt)
548            if(y < l->only_start_y - (l->d - l->hspace)) continue;
549            // bis zur unteren Begrenzung -- anschliessend Abbruch
550            if(l->only_height != 0 && y > l->only_start_y + l->only_height) break;
551
552            // Ggf. Lochstreifenfuehrung zeichnen
553            if(loch==3 && l->fuehrung != NULL) {
554                // Nur vor dem 3. Loch (wenn ueberhaupt)
555                y -= l->hspace; // den Abstand vom vorherigen Loch wieder wegnehmen
556                cairo_set_source(cr, l->fuehrung);
557                cairo_arc(cr, x+l->d/2, y+l->fspace/2, l->df/2, 0., 2*M_PI);
558                cairo_fill(cr);
559                y += l->fspace;
560            } else if(loch == 3) // 3. Loch, aber keine Fuehrung zeichnen => Platz freilassen!
561                y += l->fspace - l->hspace;
562
563            // Debugausgaben machen?
564            if(l->debug != 0 && byte >= 0 && byte < l->data_length) {
565                if(loch == 0) printf("byte %3i von %3i: 0x%2x = ", byte, l->data_length, l->data[byte]);
566                fprintf(stderr, "%c", (((l->data[byte] >> loch) & 0x01) == 0x01) ? '#' : ' ');
567                if(loch == 7) printf("\n");
568            }
569
570            if((byte < 0 || byte >= l->data_length) ||    // wenn ein Nullbyte gezeichnet wird
571               (((l->data[byte] >> loch) & 0x01) != 0x01) // oder das Bit an der Stelle nicht gesetzt ist
572               ) {                                        // ist es not-Punched
573                if(l->notpunched != NULL) { // notpunched zeichnen? (muss subif sein)
574                    cairo_set_source(cr, l->notpunched);
575                    cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
576                    cairo_fill(cr);
577                }
578            } else if(l->punched != NULL) { // es ist Punched. Zeichnen?
579                cairo_set_source(cr, l->punched);
580                cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
581                cairo_fill(cr);
582            }
583            // Die Routine wegen dem Zeichnen?-Ding hervorgehoben.
584            /*cairo_set_source(cr,
585                 (byte < 0 || byte >= data_length) ||      // wenn ein Nullbyte gezeichnet wird
586                 (((data[byte] >> loch) & 0x01) != 0x01) ? // oder das Bit an der Stelle nicht gesetzt ist
587                 notpunched : punched);                    // dann dies farbig kennzeichnen
588            cairo_arc(cr, x+d/2, y+d/2, d/2, 0., 2*M_PI);
589            cairo_fill(cr);*/
590
591            // y+= war hier.
592        } // for bits (loecher)
593        // x += war hier.
594    } // for bytes
595
596    // Lochstreifenfuehrung im vorderen Abriss malen
597    if(l->fuehrung != NULL) {
598        cairo_set_source(cr, l->fuehrung);
599        y = l->margin + l->padding + 3*l->d + 2*l->hspace + l->fspace/2; // fspace-Mitte
600        x = l->margin + l->abriss - l->d - l->bspace; // Start-x
601        for(; x > l->margin;) {
602            cairo_arc(cr, x + l->d/2, y, l->df/2, 0., 2*M_PI);
603            x -= l->d + l->bspace;
604        }
605        cairo_fill(cr);
606    }
607
608    // fertig mit dem Lochstreifenzeichnen.
609} // function draw_lochstreifen
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License