Root/eeshow/kicad/dwg.c

1/*
2 * kicad/dwg.c - Complex drawing functions for KiCad items
3 *
4 * Written 2016 by Werner Almesberger
5 * Copyright 2016 by Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#define _GNU_SOURCE /* for asprintf */
15#include <stdbool.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <assert.h>
19
20#include "misc/util.h"
21#include "gfx/misc.h"
22#include "gfx/style.h"
23#include "gfx/text.h"
24#include "gfx/gfx.h"
25#include "kicad/dwg.h"
26
27
28/* ----- Helper functions -------------------------------------------------- */
29
30
31static void bbox_from_poly(struct dwg_bbox *bbox, unsigned n,
32    const int *vx, const int *vy)
33{
34    unsigned i;
35    int xmax, ymax;
36
37    bbox->x = xmax = *vx;
38    bbox->y = ymax = *vy;
39    for (i = 1; i != n; i++) {
40        if (vx[i] < bbox->x)
41            bbox->x = vx[i];
42        if (vy[i] < bbox->y)
43            bbox->y = vy[i];
44        if (vx[i] > xmax)
45            xmax = vx[i];
46        if (vy[i] > ymax)
47            ymax = vy[i];
48    }
49    bbox->w = xmax - bbox->x + 1;
50    bbox->h = ymax - bbox->y + 1;
51}
52
53
54/* ----- Labels ------------------------------------------------------------ */
55
56
57enum box_type { // ___
58    box_simple, // [___]
59    box_left, // <___]
60    box_right, // [___>
61    box_both, // <___>
62};
63
64
65static enum box_type flip_box(enum box_type box)
66{
67    switch (box) {
68    case box_simple:
69        return box_simple;
70    case box_left:
71        return box_right;
72    case box_right:
73        return box_left;
74    case box_both:
75        return box_both;
76    default:
77        abort();
78    }
79}
80
81
82void dwg_label(int x, int y, const char *s, int dir, int dim,
83    enum dwg_shape shape, struct dwg_bbox *bbox)
84{
85    struct text txt = {
86        .s = s,
87        .size = dim,
88        .x = x,
89        .y = y,
90        .rot = 0,
91        .hor = 0,
92        .vert = text_min,
93    };
94    int dx = 0, dy = 0;
95
96    switch (dir) {
97    case 0: /* right */
98        txt.rot = 0;
99        txt.hor = text_min;
100        dy = 1;
101        break;
102    case 1: /* up */
103        txt.rot = 90;
104        txt.hor = text_min;
105        dx = -1;
106        break;
107    case 2: /* left */
108        txt.rot = 0;
109        txt.hor = text_max;
110        dy = 1;
111        break;
112    case 3: /* down */
113        txt.rot = 90;
114        txt.hor = text_max;
115        dx = -1;
116        break;
117    default:
118        assert(0);
119    }
120
121    txt.y -= dy * LABEL_OFFSET;
122    txt.x += dx * LABEL_OFFSET;
123    text_fig(&txt, COLOR_LABEL, LAYER_LABEL);
124}
125
126
127void dwg_glabel(int x, int y, const char *s, int dir, int dim,
128    enum dwg_shape shape, struct dwg_bbox *bbox)
129{
130    struct text txt = {
131        .s = s,
132        .size = dim,
133        .x = x,
134        .y = y,
135        .rot = 0,
136        .hor = 0,
137        .vert = text_mid,
138    };
139    int n = 6;
140    int vx[7];
141    int vy[7];
142    int half = (dim >> 1) + GLABEL_OFFSET;
143    enum box_type box;
144    int dx, shift_flat, shift_tip;
145    bool anchor_right = 1;
146    char *tag;
147
148    switch (shape) {
149    case dwg_unspec:
150        box = box_simple;
151        break;
152    case dwg_in:
153        box = box_right;
154        break;
155    case dwg_out:
156        box = box_left;
157        break;
158    case dwg_bidir:
159        box = box_both;
160        break;
161    default:
162        assert(0);
163    }
164
165    switch (dir) {
166    case 0: /* left */
167        txt.rot = 0;
168        txt.hor = text_max;
169        dx = -1;
170        break;
171    case 1: /* up */
172        txt.rot = 90;
173        txt.hor = text_min;
174        dx = 1;
175        box = flip_box(box);
176        anchor_right = !anchor_right;
177        break;
178    case 2: /* right */
179        txt.rot = 0;
180        txt.hor = text_min;
181        dx = 1;
182        box = flip_box(box);
183        anchor_right = !anchor_right;
184        break;
185    case 3: /* down */
186        txt.rot = 90;
187        txt.hor = text_max;
188        dx = -1;
189        break;
190    default:
191        assert(0);
192    }
193
194    shift_flat = dx * GLABEL_OFFSET;
195    shift_tip = dx * (GLABEL_OFFSET + half);
196
197    switch (box) {
198    case box_simple:
199        n = 5;
200        text_shift(&txt, txt.hor, text_mid, shift_flat, 0);
201        text_rel(&txt, text_min, text_min,
202            -GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
203        text_rel(&txt, text_max, text_min,
204            GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
205        text_rel(&txt, text_max, text_max,
206            GLABEL_OFFSET, -GLABEL_OFFSET, vx + 3, vy + 3);
207        text_rel(&txt, text_min, text_max,
208            -GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
209        break;
210    case box_right:
211        text_shift(&txt, txt.hor, text_mid,
212            anchor_right ? shift_tip : shift_flat, 0);
213        text_rel(&txt, text_min, text_min,
214            -GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
215        text_rel(&txt, text_max, text_min,
216            GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
217        text_rel(&txt, text_max, text_mid, GLABEL_OFFSET + half, 0,
218            vx + 3, vy + 3);
219        text_rel(&txt, text_max, text_max,
220            GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
221        text_rel(&txt, text_min, text_max,
222            -GLABEL_OFFSET, -GLABEL_OFFSET, vx + 5, vy + 5);
223        break;
224    case box_left:
225        text_shift(&txt, txt.hor, text_mid,
226            anchor_right ? shift_flat : shift_tip, 0);
227        text_rel(&txt, text_min, text_min,
228            -GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
229        text_rel(&txt, text_max, text_min,
230            GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
231        text_rel(&txt, text_max, text_max,
232            GLABEL_OFFSET, -GLABEL_OFFSET, vx + 3, vy + 3);
233        text_rel(&txt, text_min, text_max,
234            -GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
235        text_rel(&txt, text_min, text_mid, -GLABEL_OFFSET- half, 0,
236            vx + 5, vy + 5);
237        break;
238    case box_both:
239        n = 7;
240        text_shift(&txt, txt.hor, text_mid, shift_tip, 0);
241        text_rel(&txt, text_min, text_min,
242            -GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
243        text_rel(&txt, text_max, text_min,
244            GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
245        text_rel(&txt, text_max, text_mid, GLABEL_OFFSET + half, 0,
246            vx + 3, vy + 3);
247        text_rel(&txt, text_max, text_max,
248            GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
249        text_rel(&txt, text_min, text_max,
250            -GLABEL_OFFSET, -GLABEL_OFFSET, vx + 5, vy + 5);
251        text_rel(&txt, text_min, text_mid, -GLABEL_OFFSET- half, 0,
252            vx + 6, vy + 6);
253        break;
254    default:
255        assert(0);
256    }
257
258    text_fig(&txt, COLOR_GLABEL, LAYER_GLABEL);
259
260    vx[0] = vx[n - 1];
261    vy[0] = vy[n - 1];
262    gfx_poly(n, vx, vy, COLOR_GLABEL, COLOR_NONE, LAYER_GLABEL);
263
264    if (bbox)
265        bbox_from_poly(bbox, n, vx, vy);
266
267    if (asprintf(&tag, "G:%s", s)) {}
268    gfx_tag(tag, n, vx, vy);
269}
270
271
272static int make_box(enum box_type box, int h, int *vx, int *vy)
273{
274    int r = h / 2;
275
276    switch (box) {
277    case box_simple:
278        vx[0] = 0;
279        vy[0] = -r;
280        vx[1] = 2 * r;
281        vy[1] = -r;
282        vx[2] = 2 * r;
283        vy[2] = r;
284        vx[3] = 0;
285        vy[3] = r;
286        return 4;
287    case box_right:
288        vx[0] = 0;
289        vy[0] = -r;
290        vx[1] = r;
291        vy[1] = -r;
292        vx[2] = 2 * r;
293        vy[2] = 0;
294        vx[3] = r;
295        vy[3] = r;
296        vx[4] = 0;
297        vy[4] = r;
298        return 5;
299    case box_left:
300        vx[0] = r;
301        vy[0] = -r;
302        vx[1] = 2 * r;
303        vy[1] = -r;
304        vx[2] = 2 * r;
305        vy[2] = r;
306        vx[3] = r;
307        vy[3] = r;
308        vx[4] = 0;
309        vy[4] = 0;
310        return 5;
311    case box_both:
312        vx[0] = 0;
313        vy[0] = 0;
314        vx[1] = r;
315        vy[1] = -r;
316        vx[2] = 2 * r;
317        vy[2] = 0;
318        vx[3] = r;
319        vy[3] = r;
320        return 4;
321    default:
322        assert(0);
323    }
324}
325
326
327void dwg_hlabel(int x, int y, const char *s, int dir, int dim,
328    enum dwg_shape shape, struct dwg_bbox *bbox)
329{
330    struct text txt = {
331        .s = s,
332        .size = dim,
333        .x = x,
334        .y = y,
335        .rot = 0,
336        .hor = 0,
337        .vert = text_mid,
338    };
339    int vx[6], vy[6];
340    int rot;
341    int n, i;
342
343    switch (shape) {
344    case dwg_unspec:
345        n = make_box(box_simple, dim, vx, vy);
346        break;
347    case dwg_in:
348        n = make_box(box_left, dim, vx, vy);
349        break;
350    case dwg_out:
351        n = make_box(box_right, dim, vx, vy);
352        break;
353    case dwg_tri:
354    case dwg_bidir:
355        n = make_box(box_both, dim, vx, vy);
356        break;
357    default:
358        assert(0);
359    }
360
361    switch (dir) {
362    case 0: /* right */
363        rot = 180;
364        txt.hor = text_max;
365        break;
366    case 1: /* up */
367        rot = 90;
368        txt.hor = text_min;
369        break;
370    case 2: /* left */
371        rot = 0;
372        txt.hor = text_min;
373        break;
374    case 3: /* down */
375        rot = 270;
376        txt.hor = text_max;
377        break;
378    default:
379        assert(0);
380    }
381
382    txt.x += rx((1 + HLABEL_OFFSET_F) * dim, 0, rot);
383    txt.y += ry((1 + HLABEL_OFFSET_F) * dim, 0, rot);
384
385    for (i = 0; i != n; i++) {
386        int tmp;
387
388        tmp = x + rx(vx[i], vy[i], rot);
389        vy[i] = y + ry(vx[i], vy[i], rot);
390        vx[i] = tmp;
391    }
392
393    vx[n] = vx[0];
394    vy[n] = vy[0];
395
396    txt.rot = rot % 180;
397
398    text_fig(&txt, COLOR_HLABEL, LAYER_HLABEL);
399    gfx_poly(n + 1, vx, vy, COLOR_HLABEL, COLOR_NONE, LAYER_HLABEL);
400}
401
402
403/* ----- Text -------------------------------------------------------------- */
404
405
406void dwg_text(int x, int y, const char *s, int dir, int dim,
407    enum dwg_shape shape, struct dwg_bbox *bbox)
408{
409    struct text txt = {
410        .s = s,
411        .size = dim,
412        .x = x,
413        .y = y,
414        .rot = 0,
415        .hor = text_min,
416        .vert = text_min,
417    };
418
419    switch (dir) {
420    case 0: /* right */
421        break;
422    case 1: /* up */
423        text_rot(&txt, 90);
424        break;
425    case 2: /* left */
426        txt.hor = text_max;
427        break;
428    case 3: /* down */
429        text_rot(&txt, 90);
430        txt.hor = text_max;
431        break;
432    default:
433        assert(2 + 2 == 5);
434    }
435
436    text_fig(&txt, COLOR_TEXT, LAYER_TEXT);
437}
438
439
440/* ----- Connections ------------------------------------------------------- */
441
442
443void dwg_junction(int x, int y)
444{
445    gfx_circ(x, y, JUNCTION_R, COLOR_NONE, COLOR_WIRE, LAYER_WIRES);
446}
447
448
449void dwg_noconn(int x, int y)
450{
451    int vx[2] = { x - NOCONN_LEN, x + NOCONN_LEN };
452    int vy[2] = { y - NOCONN_LEN, y + NOCONN_LEN };
453
454    gfx_poly(2, vx, vy, COLOR_NOCONN, COLOR_NONE, LAYER_NOCONN);
455    swap(vy[0], vy[1]);
456    gfx_poly(2, vx, vy, COLOR_NOCONN, COLOR_NONE, LAYER_NOCONN);
457}
458
459
460/* ----- Lines ------------------------------------------------------------- */
461
462/*
463 * We can't use gfx_poly because lines are dashed and we don't have that
464 * property at the gfx_poly API.
465 *
466 * Since dashing may produce different results between going from A to B and
467 * going from B to A, we enforce a common direction, so that pixel diffs will
468 * treat reversed lines as still equal.
469 */
470
471void dwg_line(int sx, int sy, int ex, int ey)
472{
473    if (sx < ex || (sx == ex && sy < ey))
474        gfx_line(sx, sy, ex, ey, COLOR_SHEET_DWG, LAYER_LINES);
475    else
476        gfx_line(ex, ey, sx, sy, COLOR_SHEET_DWG, LAYER_LINES);
477}
478
479
480/* ----- Wires and busses -------------------------------------------------- */
481
482
483void dwg_wire(int sx, int sy, int ex, int ey)
484{
485    int vx[] = { sx, ex };
486    int vy[] = { sy, ey };
487
488    // WIDTH_WIRE
489    gfx_poly(2, vx, vy, COLOR_WIRE, COLOR_NONE, LAYER_WIRES);
490}
491
492
493void dwg_bus(int sx, int sy, int ex, int ey)
494{
495    int vx[] = { sx, ex };
496    int vy[] = { sy, ey };
497
498    // WIDTH_BUS
499    gfx_poly(2, vx, vy, COLOR_BUS, COLOR_NONE, LAYER_BUSSES);
500}
501

Archive Download this file

Branches:
master



interactive