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 | |
---|
48 | int 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 | |
---|
145 | void 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 | |
---|
153 | LOCHSTREIFEN *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 | |
---|
174 | void 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 | |
---|
185 | int 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 | |
---|
197 | int 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 | |
---|
205 | void 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 | |
---|
217 | int 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 | |
---|
222 | int 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 | |
---|
232 | int lochstreifen_get_height(LOCHSTREIFEN *l) { |
---|
233 | /** Berechnet aktuelle Hoehe aus Lochstreifenkonstanten */ |
---|
234 | return (l->drehung % 2 == 1) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT; |
---|
235 | } |
---|
236 | |
---|
237 | void 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 | |
---|
255 | void 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 | |
---|
268 | void 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 | /* |
---|
311 | void 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 | |
---|
322 | void 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 | |
---|
337 | int 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 | |
---|
362 | void 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 |
---|