source: projects/visualisator/lochstreifen.c @ 1

Last change on this file since 1 was 1, checked in by sven, 16 years ago

Erstimport

File size: 25.1 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->debug = 0;
160    l->hintergrund = NULL; // nicht zeichnen
161    l->streifenbg = cairo_pattern_create_rgb(0.7,0.7,0.7);
162    l->punched = cairo_pattern_create_rgb(0,0,0);
163    l->notpunched = cairo_pattern_create_rgb(0.827, 0.827, 0.827); //220/255, 220/255, 220/255);
164    l->fuehrung = cairo_pattern_create_rgb(143/255, 175/255, 255/255);
165    //cairo_matrix_init_identity(&(l->transformation));
166        //, 1, 0, 0, 1, 0, 0); // Standardmatrix einrichten (keine Drehung)
167    l->drehung = 0;
168    l->spiegelung_hor = 0;
169    l->spiegelung_ver = 0;
170    lochstreifen_flush_only_start_area(l);
171    return l;
172}
173
174void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end) {
175    /** Zu druckende Daten eingeben, Anzahl gewuenschter Leerbytes vorne/hinten eingeben,
176        ist empty_start/empty_end < 0, wird das entsprechende nicht gesetzt */
177    l->data_length = data_length;
178    if(l->data != NULL) // unbenutzten Speicher freigeben!
179        free(l->data);
180    l->data = data;
181    if(empty_start >= 0) l->empty_start = empty_start;
182    if(empty_end >= 0) l->empty_end = empty_end;
183}
184
185int lochstreifen_set_only_start_area(LOCHSTREIFEN *l, int x, int y, int width, int height) {
186    /** Clipping-Rechteck setzen. Damit wird beim naechsten Zeichnen nur in diesem
187        Bereich gezeichnet. Es handelt sich jedoch um kein exiplites ordentliches
188        cairo_clipping, sondern eine grobe Naehrung zwecks Perfomance.
189        Die Koordinaten beziehen sich auf die entgueltige Form (inkl. Drehung, ...)
190    */
191    l->only_start_x = x;
192    l->only_start_y = y;
193    l->only_width = width;
194    l->only_height = height;
195}
196
197int lochstreifen_flush_only_start_area(LOCHSTREIFEN *l) {
198    /** Clipping-Rechteck loeschen -- beim naechsten Zeichnen alles zeichnen */
199    l->only_start_x = 0;
200    l->only_start_y = 0;
201    l->only_width = 0;
202    l->only_height = 0;
203}
204
205void lochstreifen_set_d(LOCHSTREIFEN *l, int d) {
206    /** Durchmesser eines Loches uebergeben (allgemeine Referenzeinheit fuer Dimensionen) */
207    l->d = d;
208    l->bspace = d*0.7/1.9;  // Abstand der Bytes voneinander (Reihen)
209    l->hspace = d/2;  // Abstand der Loecher in der Bytereihe
210    l->padding = d; // Abstand Löcher <=> Lochstreifenrand
211    l->df = d/2; // Durchmesser Lochfuehrungsloch
212    l->fspace = 1.1*(d+ l->hspace); // Breite der Lochfuehrungs"nut"
213    l->margin = d*2; // Abstand um Lochstreifen herum (an allen Seiten)
214    l->abriss = (8*d+6* l->hspace + l->fspace)/2; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
215}
216
217int lochstreifen_get_orientation(LOCHSTREIFEN *l) {
218    /** Gibt die Orientierung des Lochstreifens zurueck; 1 = horizontal, 0 = vertikal */
219    return (l->drehung % 2 == 0) ? 1 : 0;
220}
221
222int lochstreifen_get_width(LOCHSTREIFEN *l) {
223    /** Berechnet aktuelle Breite aus Lochstreifenkonstanten */
224    // interne Ersetzungen...
225    #define LOCHSTREIFEN_WIDTH  2*l->abriss + 2*l->margin + \
226        (l->data_length + l->empty_start + l->empty_end) * (l->d + l->bspace) - l->bspace // ein bspace zuviel am Ende
227    #define LOCHSTREIFEN_HEIGHT 8*l->d + 6*l->hspace + l->fspace + l->margin*2 + l->padding*2 \
228                                     //  ^ weil letztes hspace + hspace über fspace unnötig
229    return (l->drehung % 2 == 0) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
230}
231
232int lochstreifen_get_height(LOCHSTREIFEN *l) {
233    /** Berechnet aktuelle Hoehe aus Lochstreifenkonstanten */
234    return (l->drehung % 2 == 1) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
235}
236
237void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width) {
238    /**
239     * Umkehrfunktion zu set_d (dort wird die Breite/Hoehe durch d berechnet),
240     * hier wird d durch die vorgegebene Breite berechnet. Die Hoehe ergibt
241     * sich dann natuerlich auch automatisch.
242     * Evventuelle Drehungen werden miteinberechnet, d.h. wenn der Lochstreifen
243     * z.B. nach oben/unten zeigt, bezieht sich width auf die "echte" Hoehe.
244     **/
245    // Gleichung zum Berechnen von LOCHSTREIFEN_WIDTH nach
246    // d aufgeloest mit MuPad Pro 3.2 ( ;-) )
247    #define LOCHSTREIFEN_INV_WIDTH  (double) (1 / (6187./380. + 26./19. * (double)(l->data_length + l->empty_start + l->empty_end)))
248    #define LOCHSTREIFEN_INV_HEIGHT  (double) (1 * 20./373.)
249    lochstreifen_set_d(l,
250        (int)rint((double)width * ((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
251    );
252    //printf("Width soll %d ==> %d | %d\n", width, lochstreifen_get_width(l), lochstreifen_get_height(l));
253}
254
255void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height) {
256    /**
257     * Siehe set_d_by_width, nur wird hier d abhaengig von der gewuenschten Hoehe
258     * berechnet.
259     **/
260    lochstreifen_set_d(l,
261        (int)rint((double) height * LOCHSTREIFEN_INV_HEIGHT) //((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
262    );
263    //printf("Height soll %03d ==> d=%02d | %f, w/h = %03d | %03d\n", height, l->d,
264    //    (double)height*LOCHSTREIFEN_INV_HEIGHT
265    //    , lochstreifen_get_width(l), lochstreifen_get_height(l));
266}
267
268void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver) {
269    /**
270     * Transformationen der Lochstreifenausrichtung
271     * drehung: 0 = Kopf nach links
272     *          1 = oben
273     *          2 = rechts
274     *          3 = unten
275     *         -1 = nicht aendern
276     *          4 = um 90° im Uhrzeigersinn drehen
277     *          5 = um 90° gegen Uhrzeigersinn drehen
278     * Spiegelung horizontal/vertikal: 0 = nein
279     *                                 1 = ja
280     *                                 2 = vertauschen
281     *                                -1 = nicht aendern
282     **/
283     if(drehung >= 0) {
284         // Das "Ausprobieren" zwecks "Autodrehung" mit Aufruf wie
285         // lochstreifen_set_direction(l, l->drehung++, -1, -1);
286         //if(drehung > 4) drehung -= 4; // bei zu grossen Werten mal ausprobieren
287         //if(drehung < 0) drehung += 4; // bei zu kleinen Werten mal ausprobieren
288         //if(drehung % 4 == 0) drehung = 0; // quasi keine Drehung
289         if(drehung >= 4) {
290             if(drehung == 4) l->drehung++;
291             else if(drehung == 5) l->drehung--;
292             if(l->drehung >= 4) l->drehung -= 4; // bei zu grossen Werten
293             if(l->drehung < 0) l->drehung += 4; // bei zu kleinen Werten
294         } else {
295             //if(drehung > 0 && drehung < 4) // gute Werte
296             // normale Drehung mit festem Zielwert
297             l->drehung = drehung;
298         }
299     }
300     if(spiegelung_hor > -1) {
301         if(spiegelung_hor == 2) l->spiegelung_hor = l->spiegelung_hor == 0 ? 1 : 0; // negotieren
302         else l->spiegelung_hor = spiegelung_hor; // normal
303     }
304     if(spiegelung_ver > -1) {
305         if(spiegelung_ver == 2) l->spiegelung_ver = l->spiegelung_ver == 0 ? 1 : 0; // negotieren
306         else l->spiegelung_ver = spiegelung_ver; // normal
307     }
308}
309
310/*
311void lochstreifen_rotate(LOCHSTREIFEN *l) {
312    **
313     * Wird den Lochstreifen beim naechsten Zeichnen um 45° mit dem
314     * Uhrzeigersinn rotiert anzeigen. Nur mit diesen Funktionen wird
315     * die Hoehen/Breitenberechnung im Vorhinein noch funktionieren!
316     **
317     cairo_matrix_rotate(&(l->transformation), M_PI);
318     cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0),
319     l->drehung++; // ...
320}
321
322void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal) {
323    **
324     * Spiegelt den Lochstreifen, ist horizontal = 1 dann horizontal,
325     * sonst vertikal (oder so aehnlich)
326     **
327     if(horizontal != 0) { // vertikal
328         cairo_matrix_scale(&(l->transformation), -1, 1);
329         cairo_matrix_translate((&l->transformation), 0, lochstreifen_get_height(l));
330     } else {
331         cairo_matrix_scale(&(l->transformation), 1, -1);
332         cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0);
333     }
334}
335*/
336
337int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y) {
338     /**
339      * Anhand der Koordinaten (x|y) wird der Index des Bytes (fuers Datenarray, ab 1 zaehlend),
340      * welches damit "erfasst" wird, zurueckgegeben.
341      * Befindet sich (x|y) nicht im Bereich eines Bytes, dann wird je nach Fall zurueckgegeben:
342      *    0 = ausserhalb Lochstreifens
343      *   -1 = in Emptystart/Emptyend-Bytes (die nicht in der Datei existieren)
344      *        oder in Abrissbereichen
345      **/
346    int byte;
347    // BETRACHTUNG HORIZONTALE AUSRICHTUNG
348
349    if(y <= l->margin || y >= LOCHSTREIFEN_HEIGHT - l->margin) return 0; // ueber/unter Lochstreifen
350    x -= l->margin; // erst mal Rand abziehen
351    if(x <= 0) return 0; // links neben dem Lochstreifen.
352    x -= l->abriss + (l->empty_start)*(l->d + l->bspace); // Emptystart+Abrissbereich
353    if(x <= 0) return -1; // in diesem Bereich gewesen
354    // jetzt sind wir im Bytebereich
355    byte = (int) (x / (l->d + l->bspace)) + 1; // Abrunden: Auf welchem Byte man ist + ab 1 zaehlen.
356    if(byte > l->data_length + l->empty_start) return 0; // komplett ausserhalb Lochstreifens
357    else if(byte > l->data_length) return -1; // im Emptyendbereich
358    else return byte; // im gueltigen Bereich -- Byte gefunden!
359
360}
361
362void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr) {
363    /**
364     * Den Lochstreifen auf das uebergebene Cairoobjekt zeichnen.
365     * Die Funktion zeichnet nach den aktuellen Lochstreifenobjekt-Angaben
366     * (Groesse/Breite) -- wenn die cairo_image_surface nicht diesen Dimensionen
367     * entspricht, ist das alt schlecht.
368     *
369     **/
370    int byte,loch,x,y; // temp fuer Schleifen
371    int height = lochstreifen_get_height(l);
372    int width = lochstreifen_get_width(l);
373    // 4 Eckpunkte des Zeichenbereichs bestimmen...
374    int x1,x2,y1,y2;
375    x1 = l->only_start_x; y1 = l->only_start_y;
376    x2 = x1 + width; y2 = y1 + height;
377   
378    /*int x1,y1,x2,y2,x3,y3,x4,y4;
379    x1 = l->only_start_x; y1 = l->only_start_y;
380    x2 = x1+width; y2 = y1;
381    x3 = x2; y3 = y2+height;
382    x4 = x1; y4 = y3;*/
383
384    // Verschiebungsmatrix erst hier berechnen, weil Verschiebungen vorher unklar
385    // wunderbare affine Abbildungen ;-)
386    cairo_matrix_t matrix, temp; // temp: Temporaere Matrix zur Matrizenmulitiplikation
387    cairo_matrix_init_identity(&matrix);
388    if(l->drehung > 0) {
389        if(l->drehung == 1) {
390            cairo_matrix_init(&temp, 0, -1, 1, 0, 0, height);
391            x = width; width = height; height = x;                // Breiten und Hoehen
392            x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
393        } else if(l->drehung == 2) {
394            cairo_matrix_init(&temp, -1, 0, 0, -1, width, height);
395        } else if(l->drehung == 3) {
396            cairo_matrix_init(&temp, 0, 1, -1, 0, width, 0);
397            x = width; width = height; height = x;                // Breiten und Hoehen
398            x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
399        }
400        cairo_matrix_multiply(&matrix, &matrix, &temp);
401    }
402
403    if(l->spiegelung_hor != 0) {
404         cairo_matrix_init(&temp, -1, 0, 0, 1,
405             l->drehung % 2 == 0 ? width : height, // Default bei Nicht-Drehung: width
406             0);
407         cairo_matrix_multiply(&matrix, &matrix, &temp);
408    }
409    if(l->spiegelung_ver != 0) {
410         cairo_matrix_init(&temp, 1, 0, 0, -1, 0,
411             l->drehung % 2 == 0 ? height: width); // Default bei Nicht-Drehung: height
412         cairo_matrix_multiply(&matrix, &matrix, &temp);
413    }
414   
415    //if(l->drehung > 0) {
416        /*cairo_matrix_rotate(&matrix, l->drehung/2 *M_PI);
417        if(l->drehung == 1) { // 90°, im III. Sektor
418            //x = width; width = height; height = x;
419            //cairo_matrix_translate(&matrix, 0, 0);
420        } else if(l->drehung == 2) { // 180°, im IV Sektor
421            cairo_matrix_translate(&matrix, width, height);
422        } else if(l->drehung == 3) { // 270°, im I. Sektor
423            //x = width; width = height; height = x;
424            cairo_matrix_translate(&matrix, width, height);
425        }*/
426        // 4. Sektor kommt nicht vor
427    //}
428    cairo_set_matrix(cr, &matrix);
429    // -1, 0, 0, 1, width, 0 = spiegelung x-achse
430   
431    //cairo_device_to_user(cr, (double*)&(l->only_start_x), (double*)&(l->only_start_y));
432    cairo_device_to_user(cr, (double*)&(x1), (double*)&(y1));
433    cairo_device_to_user(cr, (double*)&(x2), (double*)&(y2));
434
435    l->only_start_x = x2 < x1 ? x2 : x1;
436    l->only_start_y = y2 < y1 ? y2 : y1;
437
438    cairo_set_source(cr, l->fuehrung);
439    cairo_rectangle(cr, l->only_start_x, l->only_start_y, l->only_width, l->only_height);
440    //printf("Only: %d|%d, %d * %d\n", l->only_start_x, l->only_start_y, l->only_width, l->only_height);
441    cairo_paint(cr);
442
443    // Hintergrundfarbe zeichnen.
444    if(0||l->hintergrund != NULL) {
445        //l->hintergrund = cairo_pattern_create_rgb(1,1,1);
446        cairo_set_source(cr, l->hintergrund);
447        cairo_paint(cr);
448    }
449
450    // sache zeichnen
451    cairo_set_source(cr, l->streifenbg);
452    cairo_rectangle(cr, -10, -10, width+20, height+20);
453    cairo_stroke(cr);
454    if(0==1){
455        double x,y, a,b;
456        int xx,yy,aa,bb;
457        x=0;y=0; a=width;b=height;
458        cairo_matrix_transform_point(&matrix, &x, &y);
459        cairo_matrix_transform_point(&matrix, &a, &b);
460        xx=(int)x;yy=(int)y;aa=(int)a;bb=(int)b;
461        printf("Punkt (0/0)=(%i|%i) und (%i|%i)=(%i/%i)\n", xx, yy, width, height, aa, bb);
462    }
463
464    // Lochstreifenhintergrund inklusive Abriss vorne/hinten malen
465    if(l->streifenbg != NULL) {
466        cairo_set_source(cr, l->streifenbg);
467
468        // Abriss vorne
469        cairo_move_to(cr, l->margin + l->abriss*0.8, l->margin); // oben rechts
470        cairo_line_to(cr, l->margin, l->margin + l->padding+ 3*l->d + 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
471        cairo_line_to(cr, l->margin + l->abriss, height - l->margin); // unten ganz rechts
472        cairo_line_to(cr, l->margin + l->abriss, l->margin); // nach oben ganz rechts...
473        cairo_close_path(cr); // schliessen
474        // normaler Bereich
475        cairo_rectangle(cr, l->margin + l->abriss, l->margin,
476            width - 2*l->margin - 2*l->abriss, height - 2*l->margin);
477        /*printf("Zeichne Rechteck x|y = (%d|%d) width*height = %d * %d\n",
478            l->margin + l->abriss, l->margin,
479            width - 2*l->margin - 2*l->abriss, height - 2*l->margin
480        );*/
481        // Abriss hinten...
482        cairo_move_to(cr, width - l->margin - l->abriss*0.2, l->margin); // oben mitte
483        cairo_line_to(cr, width - l->margin - l->abriss,
484            l->margin + l->padding + 3*l->d+ 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
485        cairo_line_to(cr, width - l->margin, height - l->margin); // unten ganz rechts
486        cairo_line_to(cr, width - l->margin - l->abriss, height - l->margin); // unten ganz links
487        cairo_line_to(cr, width - l->margin - l->abriss, l->margin); // nach oben zum schliessen
488        cairo_close_path(cr);
489
490        cairo_fill(cr);
491    }
492
493
494    // Lochstreifenlöcher malen
495
496    /*if(l->only_start_x > 0) {
497        // nur in bestimmten Bereich zeichnen
498        int start_byte = l->empty_start + lochstreifen_byte_by_coordinate(l, l->only_start_x, l->only_start_y); // absolut inkl. empty bytes
499
500    } else byte = -l->empty_start; // leere Bytes vorne eingeschlossen
501    }*/
502
503    // Bytes durchgehen, leere Bytes vorne/hinten mit eingeschlossen
504    for(byte = -l->empty_start, x=l->margin + l->abriss; byte < l->data_length + l->empty_end; x += l->d + l->bspace, byte++) {
505        // Clipping: Um unnoetiges Zeichnen zu ersparen, erst ab X-Koordinate zeichnen
506        if(x < l->only_start_x - (l->d + l->bspace)) continue; // - 1x Loch weniger, damit nicht ein gerade abgeschnittenes nichtgezeichnet wird
507        // und nur bis zur rechten Begrenzung zeichnen -- dannach genuegt Abbruch.
508        if(l->only_width != 0 && x > l->only_start_x + l->only_width) break;
509
510        // Bits des entsprechenden Bytes durchgehen
511        for(loch=0, y = l->margin + l->padding; loch < 8; y += l->d + l->hspace, loch++) {
512            // Clipping: Erst ab Y-Koordinate zeichnen (-1xLoch-Korrektur gegen Abschnitt)
513            if(y < l->only_start_y - (l->d - l->hspace)) continue;
514            // bis zur unteren Begrenzung -- anschliessend Abbruch
515            if(l->only_height != 0 && y > l->only_start_y + l->only_height) break;
516
517            // Ggf. Lochstreifenfuehrung zeichnen
518            if(loch==3 && l->fuehrung != NULL) {
519                // Nur vor dem 3. Loch (wenn ueberhaupt)
520                y -= l->hspace; // den Abstand vom vorherigen Loch wieder wegnehmen
521                cairo_set_source(cr, l->fuehrung);
522                cairo_arc(cr, x+l->d/2, y+l->fspace/2, l->df/2, 0., 2*M_PI);
523                cairo_fill(cr);
524                y += l->fspace;
525            } else if(loch == 3) // 3. Loch, aber keine Fuehrung zeichnen => Platz freilassen!
526                y += l->fspace - l->hspace;
527
528            // Debugausgaben machen?
529            if(l->debug != 0 && byte >= 0 && byte < l->data_length) {
530                if(loch == 0) printf("byte %3i von %3i: 0x%2x = ", byte, l->data_length, l->data[byte]);
531                fprintf(stderr, "%c", (((l->data[byte] >> loch) & 0x01) == 0x01) ? '#' : ' ');
532                if(loch == 7) printf("\n");
533            }
534
535            if((byte < 0 || byte >= l->data_length) ||    // wenn ein Nullbyte gezeichnet wird
536               (((l->data[byte] >> loch) & 0x01) != 0x01) // oder das Bit an der Stelle nicht gesetzt ist
537               ) {                                        // ist es not-Punched
538                if(l->notpunched != NULL) { // notpunched zeichnen? (muss subif sein)
539                    cairo_set_source(cr, l->notpunched);
540                    cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
541                    cairo_fill(cr);
542                }
543            } else if(l->punched != NULL) { // es ist Punched. Zeichnen?
544                cairo_set_source(cr, l->punched);
545                cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
546                cairo_fill(cr);
547            }
548            // Die Routine wegen dem Zeichnen?-Ding hervorgehoben.
549            /*cairo_set_source(cr,
550                 (byte < 0 || byte >= data_length) ||      // wenn ein Nullbyte gezeichnet wird
551                 (((data[byte] >> loch) & 0x01) != 0x01) ? // oder das Bit an der Stelle nicht gesetzt ist
552                 notpunched : punched);                    // dann dies farbig kennzeichnen
553            cairo_arc(cr, x+d/2, y+d/2, d/2, 0., 2*M_PI);
554            cairo_fill(cr);*/
555
556            // y+= war hier.
557        } // for bits (loecher)
558        // x += war hier.
559    } // for bytes
560
561    // Lochstreifenfuehrung im vorderen Abriss malen
562    if(l->fuehrung != NULL) {
563        cairo_set_source(cr, l->fuehrung);
564        y = l->margin + l->padding + 3*l->d + 2*l->hspace + l->fspace/2; // fspace-Mitte
565        x = l->margin + l->abriss - l->d - l->bspace; // Start-x
566        for(; x > l->margin;) {
567            cairo_arc(cr, x + l->d/2, y, l->df/2, 0., 2*M_PI);
568            x -= l->d + l->bspace;
569        }
570        cairo_fill(cr);
571    }
572
573    // fertig mit dem Lochstreifenzeichnen.
574} // 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