1 | // This file is part of SmallBASIC |
2 | // |
3 | // SmallBASIC RTL - GRAPHICS |
4 | // |
5 | // This program is distributed under the terms of the GPL v2.0 or later |
6 | // Download the GNU Public License (GPL) from www.gnu.org |
7 | // |
8 | // Copyright(C) 2000 Nicholas Christopoulos |
9 | |
10 | #include "common/pproc.h" |
11 | #include "common/messages.h" |
12 | |
13 | // graphics - relative coordinates |
14 | int gra_x; |
15 | int gra_y; |
16 | |
17 | void graph_reset() { |
18 | gra_x = gra_y = 0; |
19 | } |
20 | |
21 | // |
22 | // VIEW [x1,y1,x2,y2[,c[,b]]] |
23 | // |
24 | void cmd_view() { |
25 | ipt_t p1, p2; |
26 | int32_t prev_color = dev_fgcolor; |
27 | int32_t color = dev_bgcolor; |
28 | int32_t bcolor = -1; |
29 | |
30 | if (code_peek() != kwTYPE_EOC && code_peek() != kwTYPE_LINE) { |
31 | p1 = par_getipt(); |
32 | if (prog_error) |
33 | return; |
34 | par_getcomma(); |
35 | if (prog_error) |
36 | return; |
37 | p2 = par_getipt(); |
38 | if (prog_error) |
39 | return; |
40 | if (code_peek() == kwTYPE_SEP) { |
41 | par_getcomma(); |
42 | if (prog_error) |
43 | return; |
44 | color = par_getint(); |
45 | if (prog_error) |
46 | return; |
47 | if (code_peek() == kwTYPE_SEP) { |
48 | par_getcomma(); |
49 | if (prog_error) |
50 | return; |
51 | bcolor = par_getint(); |
52 | if (prog_error) |
53 | return; |
54 | } |
55 | } |
56 | |
57 | dev_setcolor(color); |
58 | dev_rect(p1.x, p1.y, p2.x, p2.y, 1); |
59 | if (bcolor != -1) { |
60 | dev_setcolor(bcolor); |
61 | dev_rect(p1.x - 1, p1.y - 1, p2.x + 1, p2.y + 1, 0); |
62 | } |
63 | dev_setcolor(prev_color); |
64 | dev_viewport(p1.x, p1.y, p2.x, p2.y); |
65 | } else { |
66 | dev_viewport(0, 0, 0, 0); |
67 | } |
68 | } |
69 | |
70 | // |
71 | // WINDOW [x1,y1,x2,y2] |
72 | // |
73 | void cmd_window() { |
74 | ipt_t p1, p2; |
75 | |
76 | if (code_peek() != kwTYPE_EOC && code_peek() != kwTYPE_LINE) { |
77 | p1 = par_getipt(); |
78 | if (prog_error) |
79 | return; |
80 | par_getcomma(); |
81 | if (prog_error) |
82 | return; |
83 | p2 = par_getipt(); |
84 | if (prog_error) |
85 | return; |
86 | dev_window(p1.x, p2.y, p2.x, p1.y); // QB compatible |
87 | // dev_window(p1.x, p1.y, p2.x, p2.y); // SB default (logical one) |
88 | } else { |
89 | dev_window(0, 0, 0, 0); |
90 | } |
91 | } |
92 | |
93 | // |
94 | // PSET [STEP] x, y [, color | COLOR color] |
95 | // |
96 | void cmd_pset() { |
97 | long color = dev_fgcolor; |
98 | int32_t step1 = 0; |
99 | ipt_t pt; |
100 | |
101 | /* |
102 | * [STEP] x, y |
103 | */ |
104 | if (code_peek() == kwSTEP) { |
105 | code_skipnext(); |
106 | step1 = 1; |
107 | } |
108 | |
109 | pt = par_getipt(); |
110 | if (step1) |
111 | (pt.x += gra_x, pt.y += gra_y); |
112 | |
113 | if (code_peek() == kwCOLOR) { |
114 | code_skipnext(); |
115 | color = par_getint(); |
116 | if (prog_error) |
117 | return; |
118 | } |
119 | if (code_peek() == kwTYPE_SEP) { |
120 | par_getcomma(); |
121 | if (prog_error) |
122 | return; |
123 | color = par_getint(); |
124 | if (prog_error) |
125 | return; |
126 | } |
127 | |
128 | gra_x = pt.x; |
129 | gra_y = pt.y; |
130 | |
131 | if (color != dev_fgcolor) { |
132 | int prev_color = dev_fgcolor; |
133 | |
134 | dev_setcolor(color); |
135 | dev_setpixel(pt.x, pt.y); |
136 | dev_setcolor(prev_color); |
137 | } else |
138 | dev_setpixel(pt.x, pt.y); |
139 | } |
140 | |
141 | // |
142 | // LINE [STEP] x, y [{,|STEP} x2, y2] [, color | COLOR color] |
143 | // |
144 | void cmd_line() { |
145 | ipt_t p1, p2; |
146 | byte step = 0; |
147 | int32_t color = dev_fgcolor; |
148 | |
149 | /* |
150 | * [STEP] x, y |
151 | */ |
152 | if (code_peek() == kwSTEP) { |
153 | code_skipnext(); |
154 | step = 1; |
155 | } |
156 | |
157 | p1 = par_getipt(); |
158 | if (step) { |
159 | (p1.x += gra_x, p1.y += gra_y, step = 0); |
160 | } |
161 | if (code_peek() == kwTYPE_SEP) { |
162 | par_getcomma(); |
163 | } |
164 | /* |
165 | * x, y [,] ---> [STEP] ? |
166 | */ |
167 | if (code_peek() == kwSTEP) { |
168 | code_skipnext(); |
169 | step = 1; |
170 | } |
171 | |
172 | if (code_peek() != kwCOLOR && code_peek() != kwTYPE_EOC && code_peek() != kwTYPE_LINE) { |
173 | /* |
174 | * [STEP] x, y [[,]STEP] ---> x2, y2 |
175 | */ |
176 | p2 = par_getipt(); |
177 | if (step) |
178 | (p2.x += p1.x, p2.y += p1.y); |
179 | } else { |
180 | p2 = p1; |
181 | p1.x = gra_x; |
182 | p1.y = gra_y; |
183 | } |
184 | |
185 | if (code_peek() == kwTYPE_SEP) { |
186 | par_getcomma(); |
187 | if (prog_error) |
188 | return; |
189 | color = par_getint(); |
190 | if (prog_error) |
191 | return; |
192 | } |
193 | if (code_peek() == kwCOLOR) { |
194 | code_skipnext(); |
195 | color = par_getint(); |
196 | if (prog_error) |
197 | return; |
198 | } |
199 | |
200 | /* |
201 | * draw |
202 | */ |
203 | gra_x = p2.x; |
204 | gra_y = p2.y; |
205 | |
206 | if (color != dev_fgcolor) { |
207 | int32_t prev_color = dev_fgcolor; |
208 | |
209 | dev_setcolor(color); |
210 | dev_line(p1.x, p1.y, p2.x, p2.y); |
211 | dev_setcolor(prev_color); |
212 | } else |
213 | dev_line(p1.x, p1.y, p2.x, p2.y); |
214 | } |
215 | |
216 | // |
217 | // RECT [STEP] x, y [{,|STEP} x2, y2] [COLOR color] [FILLED] |
218 | // |
219 | void cmd_rect() { |
220 | ipt_t p1, p2; |
221 | int32_t color = dev_fgcolor; |
222 | byte fill = 0, step = 0; |
223 | |
224 | /* |
225 | * [STEP] x, y |
226 | */ |
227 | if (code_peek() == kwSTEP) { |
228 | code_skipnext(); |
229 | step = 1; |
230 | } |
231 | |
232 | p1 = par_getipt(); |
233 | if (step) |
234 | (p1.x += gra_x, p1.y += gra_y, step = 0); |
235 | |
236 | if (code_peek() == kwTYPE_SEP) |
237 | par_getcomma(); |
238 | |
239 | /* |
240 | * x, y [,] ---> [STEP] ? |
241 | */ |
242 | if (code_peek() == kwSTEP) { |
243 | code_skipnext(); |
244 | step = 1; |
245 | } |
246 | |
247 | if (code_peek() != kwCOLOR && code_peek() != kwFILLED && code_peek() != kwTYPE_EOC |
248 | && code_peek() != kwTYPE_LINE) { |
249 | /* |
250 | * [STEP] x, y [[,]STEP] ---> x2, y2 |
251 | */ |
252 | p2 = par_getipt(); |
253 | if (step) |
254 | (p2.x += p1.x, p2.y += p1.y); |
255 | } else { |
256 | p2 = p1; |
257 | p1.x = gra_x; |
258 | p1.y = gra_y; |
259 | } |
260 | |
261 | if (code_peek() == kwTYPE_SEP) { |
262 | par_getcomma(); |
263 | if (prog_error) |
264 | return; |
265 | color = par_getint(); |
266 | if (prog_error) |
267 | return; |
268 | } |
269 | if (code_peek() == kwCOLOR) { |
270 | code_skipnext(); |
271 | color = par_getint(); |
272 | if (prog_error) |
273 | return; |
274 | } |
275 | if (code_peek() == kwFILLED) { |
276 | code_skipnext(); |
277 | fill = 1; |
278 | } |
279 | |
280 | /* |
281 | * draw |
282 | */ |
283 | gra_x = p2.x; |
284 | gra_y = p2.y; |
285 | |
286 | if (color != dev_fgcolor) { |
287 | int prev_color = dev_fgcolor; |
288 | |
289 | dev_setcolor(color); |
290 | dev_rect(p1.x, p1.y, p2.x, p2.y, fill); |
291 | dev_setcolor(prev_color); |
292 | } else |
293 | dev_rect(p1.x, p1.y, p2.x, p2.y, fill); |
294 | } |
295 | |
296 | // |
297 | // DRAWPOLY v() [, xorg, yorg [, scale[, color]] [COLOR color] [FILLED] |
298 | // |
299 | // 0,2,4... x |
300 | // 1,3,5... y |
301 | // |
302 | void cmd_drawpoly() { |
303 | int i, count; |
304 | var_num_t xorg = 0, yorg = 0; |
305 | int32_t prev_color = dev_fgcolor; |
306 | int32_t color = dev_fgcolor; |
307 | byte filled = 0, scalef = 0; |
308 | var_num_t scale = 1.0; |
309 | ipt_t *poly = NULL; |
310 | |
311 | // array |
312 | count = par_getipoly(&poly); |
313 | if (prog_error) { |
314 | free(poly); |
315 | return; |
316 | } |
317 | if (count == 0) { |
318 | free(poly); |
319 | return; |
320 | } |
321 | // x,y origin |
322 | if (code_peek() == kwTYPE_SEP) { |
323 | par_getcomma(); |
324 | if (!prog_error) { |
325 | xorg = par_getreal(); |
326 | if (!prog_error) { |
327 | par_getcomma(); |
328 | if (!prog_error) |
329 | yorg = par_getreal(); |
330 | } |
331 | } |
332 | |
333 | if (prog_error) { |
334 | free(poly); |
335 | return; |
336 | } |
337 | |
338 | // scale factor |
339 | if (code_peek() == kwTYPE_SEP) { |
340 | par_getcomma(); |
341 | if (!prog_error) { |
342 | scale = par_getnum(); |
343 | if (!prog_error) { |
344 | scalef++; |
345 | if (code_peek() == kwTYPE_SEP) { |
346 | par_getcomma(); |
347 | if (!prog_error) |
348 | color = par_getint(); |
349 | } |
350 | } |
351 | } |
352 | } |
353 | |
354 | if (prog_error) { |
355 | free(poly); |
356 | return; |
357 | } |
358 | } |
359 | |
360 | // color |
361 | if (code_peek() == kwCOLOR) { |
362 | code_skipnext(); |
363 | color = par_getint(); |
364 | if (prog_error) { |
365 | free(poly); |
366 | return; |
367 | } |
368 | } |
369 | |
370 | // filled |
371 | if (code_peek() == kwFILLED) { |
372 | code_skipnext(); |
373 | filled++; |
374 | } |
375 | |
376 | // scale it and move it |
377 | if (scalef || xorg != 0 || yorg != 0) { |
378 | if (scalef) { |
379 | for (i = 0; i < count; i++) { |
380 | poly[i].x = xorg + poly[i].x * scale; |
381 | poly[i].y = yorg + poly[i].y * scale; |
382 | } |
383 | } else { |
384 | for (i = 0; i < count; i++) { |
385 | poly[i].x = xorg + poly[i].x; |
386 | poly[i].y = yorg + poly[i].y; |
387 | } |
388 | } |
389 | } |
390 | |
391 | // ready |
392 | if (color != dev_fgcolor) |
393 | dev_setcolor(color); |
394 | |
395 | if (!filled) { |
396 | for (i = 1; i < count; i++) |
397 | dev_line(poly[i - 1].x, poly[i - 1].y, poly[i].x, poly[i].y); |
398 | } else |
399 | dev_pfill(poly, count); |
400 | |
401 | // cleanup |
402 | free(poly); |
403 | |
404 | if (color != prev_color) |
405 | dev_setcolor(prev_color); |
406 | } |
407 | |
408 | // |
409 | // CIRCLE [STEP] x, y, r [, aspect[, color]] [COLOR color] [FILLED] |
410 | // |
411 | void cmd_circle() { |
412 | int32_t color = dev_fgcolor; |
413 | byte fill = 0, step = 0; |
414 | ipt_t pt; |
415 | int r; |
416 | var_num_t aspect = 1.0; |
417 | byte code; |
418 | |
419 | /* |
420 | * [STEP] x, y |
421 | */ |
422 | code = code_peek(); |
423 | if (code == kwSTEP) { |
424 | code_skipnext(); |
425 | step = 1; |
426 | } |
427 | |
428 | // xc,yc |
429 | pt = par_getipt(); |
430 | if (prog_error) |
431 | return; |
432 | // r |
433 | par_getcomma(); |
434 | if (prog_error) |
435 | return; |
436 | r = par_getint(); |
437 | if (prog_error) |
438 | return; |
439 | if (step) |
440 | (pt.x += gra_x, pt.y += gra_y); |
441 | |
442 | // aspect |
443 | if (code_peek() == kwTYPE_SEP) { |
444 | par_getcomma(); |
445 | if (prog_error) |
446 | return; |
447 | aspect = par_getnum(); |
448 | if (prog_error) |
449 | return; |
450 | |
451 | if (code_peek() == kwTYPE_SEP) { |
452 | par_getcomma(); |
453 | if (prog_error) |
454 | return; |
455 | color = par_getint(); |
456 | if (prog_error) |
457 | return; |
458 | } |
459 | } |
460 | |
461 | // COLOR |
462 | if (code_peek() == kwCOLOR) { |
463 | code_skipnext(); |
464 | color = par_getint(); |
465 | if (prog_error) |
466 | return; |
467 | } |
468 | |
469 | // FILLED |
470 | if (code_peek() == kwFILLED) { |
471 | code_skipnext(); |
472 | fill = 1; |
473 | } |
474 | |
475 | if (color != dev_fgcolor) { |
476 | int32_t prev_color = dev_fgcolor; |
477 | |
478 | dev_setcolor(color); |
479 | dev_ellipse(pt.x, pt.y, r, r, aspect, fill); |
480 | dev_setcolor(prev_color); |
481 | } else |
482 | dev_ellipse(pt.x, pt.y, r, r, aspect, fill); |
483 | } |
484 | |
485 | // |
486 | // ARC [STEP] x, y, r, start, end [, aspect[, color]] [COLOR color] |
487 | // |
488 | void cmd_arc() { |
489 | int32_t color = dev_fgcolor; |
490 | byte step = 0; |
491 | int r; |
492 | var_num_t as, ae, aspect = 1.0; |
493 | byte code; |
494 | ipt_t pt; |
495 | |
496 | /* |
497 | * [STEP] x, y |
498 | */ |
499 | code = code_peek(); |
500 | if (code == kwSTEP) { |
501 | code_skipnext(); |
502 | step = 1; |
503 | } |
504 | |
505 | // xc,yc |
506 | pt = par_getipt(); |
507 | if (prog_error) |
508 | return; |
509 | |
510 | // r |
511 | par_getcomma(); |
512 | if (prog_error) |
513 | return; |
514 | r = par_getint(); |
515 | if (prog_error) |
516 | return; |
517 | |
518 | // a.st. |
519 | par_getcomma(); |
520 | if (prog_error) |
521 | return; |
522 | as = par_getnum(); |
523 | if (prog_error) |
524 | return; |
525 | |
526 | // a.end |
527 | par_getcomma(); |
528 | if (prog_error) |
529 | return; |
530 | ae = par_getnum(); |
531 | if (prog_error) |
532 | return; |
533 | |
534 | if (step) |
535 | (pt.x += gra_x, pt.y += gra_y); |
536 | |
537 | // aspect |
538 | if (code_peek() == kwTYPE_SEP) { |
539 | par_getcomma(); |
540 | if (prog_error) |
541 | return; |
542 | aspect = par_getnum(); |
543 | if (prog_error) |
544 | return; |
545 | |
546 | if (code_peek() == kwTYPE_SEP) { |
547 | par_getcomma(); |
548 | if (prog_error) |
549 | return; |
550 | color = par_getint(); |
551 | if (prog_error) |
552 | return; |
553 | } |
554 | } |
555 | |
556 | if (code_peek() == kwCOLOR) { |
557 | code_skipnext(); |
558 | color = par_getint(); |
559 | if (prog_error) |
560 | return; |
561 | } |
562 | |
563 | if (color != dev_fgcolor) { |
564 | int32_t prev_color = dev_fgcolor; |
565 | |
566 | dev_setcolor(color); |
567 | dev_arc(pt.x, pt.y, r, as, ae, aspect); |
568 | dev_setcolor(prev_color); |
569 | } else { |
570 | dev_arc(pt.x, pt.y, r, as, ae, aspect); |
571 | } |
572 | } |
573 | |
574 | // |
575 | // PAINT [STEP] x, y [, fillcolor [, bordercolor]] |
576 | // |
577 | void cmd_paint() { |
578 | int32_t prev_color = dev_fgcolor; |
579 | int32_t color = dev_fgcolor; |
580 | byte step = 0; |
581 | int32_t fc = dev_fgcolor, bc = -1; |
582 | byte code; |
583 | ipt_t pt; |
584 | |
585 | /* |
586 | * [STEP] x, y |
587 | */ |
588 | code = code_peek(); |
589 | if (code == kwSTEP) { |
590 | code_skipnext(); |
591 | step = 1; |
592 | } |
593 | |
594 | // xc,yc |
595 | pt = par_getipt(); |
596 | if (prog_error) { |
597 | return; |
598 | } |
599 | if (step) { |
600 | (pt.x += gra_x, pt.y += gra_y); |
601 | } |
602 | // fillcolor |
603 | if (code_peek() == kwTYPE_SEP) { |
604 | par_getcomma(); |
605 | if (prog_error) { |
606 | return; |
607 | } |
608 | fc = par_getint(); |
609 | if (prog_error) { |
610 | return; |
611 | } |
612 | } |
613 | |
614 | // bordercolor |
615 | if (code_peek() == kwTYPE_SEP) { |
616 | par_getcomma(); |
617 | if (prog_error) { |
618 | return; |
619 | } |
620 | bc = par_getint(); |
621 | if (prog_error) { |
622 | return; |
623 | } |
624 | } |
625 | |
626 | dev_setcolor(color); |
627 | dev_ffill(pt.x, pt.y, fc, bc); |
628 | dev_setcolor(prev_color); |
629 | } |
630 | |
631 | // |
632 | char *draw_getval(const char *src, int *c) { |
633 | char *p = (char *) src; |
634 | char *dst, buf[64]; |
635 | |
636 | dst = buf; |
637 | p++; |
638 | *c = 0; |
639 | if (*p == '-') { |
640 | *dst = '-'; |
641 | dst++; |
642 | p++; |
643 | } |
644 | |
645 | while (is_digit(*p)) { |
646 | *dst++ = *p++; |
647 | } |
648 | *dst = '\0'; |
649 | |
650 | *c = xstrtol(buf); |
651 | return p; |
652 | } |
653 | |
654 | // |
655 | // DRAW "commands" |
656 | // |
657 | void cmd_draw() { |
658 | register int draw = 1, update = 1; |
659 | int x, y, r; |
660 | int32_t prev_color = dev_fgcolor; |
661 | char *p; |
662 | var_t var; |
663 | |
664 | par_getstr(&var); |
665 | if (prog_error) { |
666 | return; |
667 | } |
668 | p = var.v.p.ptr; |
669 | while (*p) { |
670 | |
671 | // 'N' command must affect only the next drawing command. |
672 | update = 1; |
673 | // Haraszti -- 'B' command must affect only the next drawing command. |
674 | draw = 1; |
675 | |
676 | // commands prefix |
677 | while (strchr("BbNn" , *p)) { |
678 | if (*p == 'B' || *p == 'b') { // do not draw |
679 | draw = 0; |
680 | p++; |
681 | } else { |
682 | draw = 1; |
683 | } |
684 | if (*p == 'N' || *p == 'n') { // do not update the position |
685 | update = 0; |
686 | p++; |
687 | } else { |
688 | update = 1; |
689 | } |
690 | } |
691 | |
692 | // commands |
693 | switch (*p) { |
694 | case 'U': |
695 | case 'u': // up |
696 | p = draw_getval(p, &y); |
697 | if (draw) { |
698 | dev_line(gra_x, gra_y, gra_x, gra_y - y); |
699 | } |
700 | if (update) { |
701 | gra_y -= y; |
702 | } |
703 | continue; |
704 | case 'D': |
705 | case 'd': // down |
706 | p = draw_getval(p, &y); |
707 | if (draw) { |
708 | dev_line(gra_x, gra_y, gra_x, gra_y + y); |
709 | } |
710 | if (update) { |
711 | gra_y += y; |
712 | } |
713 | continue; |
714 | case 'L': |
715 | case 'l': // left |
716 | p = draw_getval(p, &x); |
717 | if (draw) { |
718 | dev_line(gra_x, gra_y, gra_x - x, gra_y); |
719 | } |
720 | if (update) { |
721 | gra_x -= x; |
722 | } |
723 | continue; |
724 | case 'R': |
725 | case 'r': // right |
726 | p = draw_getval(p, &x); |
727 | if (draw) { |
728 | dev_line(gra_x, gra_y, gra_x + x, gra_y); |
729 | } |
730 | if (update) { |
731 | gra_x += x; |
732 | } |
733 | continue; |
734 | case 'E': |
735 | case 'e': // up & right |
736 | p = draw_getval(p, &x); |
737 | if (draw) { |
738 | dev_line(gra_x, gra_y, gra_x + x, gra_y - x); |
739 | } |
740 | if (update) { |
741 | gra_x += x; |
742 | gra_y -= x; |
743 | } |
744 | continue; |
745 | case 'F': |
746 | case 'f': // down & right |
747 | p = draw_getval(p, &x); |
748 | if (draw) { |
749 | dev_line(gra_x, gra_y, gra_x + x, gra_y + x); |
750 | } |
751 | if (update) { |
752 | gra_x += x; |
753 | gra_y += x; |
754 | } |
755 | continue; |
756 | case 'G': |
757 | case 'g': // down & left |
758 | p = draw_getval(p, &x); |
759 | if (draw) { |
760 | dev_line(gra_x, gra_y, gra_x - x, gra_y + x); |
761 | } |
762 | if (update) { |
763 | gra_x -= x; |
764 | gra_y += x; |
765 | } |
766 | continue; |
767 | case 'H': |
768 | case 'h': // up & left |
769 | p = draw_getval(p, &x); |
770 | if (draw) { |
771 | dev_line(gra_x, gra_y, gra_x - x, gra_y - x); |
772 | } |
773 | if (update) { |
774 | gra_x -= x; |
775 | gra_y -= x; |
776 | } |
777 | continue; |
778 | case 'M': |
779 | case 'm': // move to x, y |
780 | if (*(p + 1) == '-') { // relative |
781 | r = -1; |
782 | p++; |
783 | } |
784 | if (*(p + 1) == '+') { // relative |
785 | r = 1; |
786 | p++; |
787 | } else { |
788 | r = 0; // absolute |
789 | } |
790 | p = draw_getval(p, &x); |
791 | if (*p != ',') { |
792 | rt_raise(ERR_DRAW_SEP); |
793 | v_free(&var); |
794 | return; |
795 | } else { |
796 | // Haraszti -- next pointer forward is an error because draw_getval |
797 | // contain p++ too!!! |
798 | // p ++; |
799 | } |
800 | p = draw_getval(p, &y); |
801 | |
802 | if (r) { |
803 | if (draw) |
804 | dev_line(gra_x, gra_y, gra_x + x * r, gra_y + y * r); |
805 | if (update) { |
806 | gra_x += x * r; |
807 | gra_y += x * r; |
808 | } |
809 | } else { |
810 | if (draw) { |
811 | dev_line(gra_x, gra_y, x, y); |
812 | } |
813 | if (update) { |
814 | gra_x = x; |
815 | gra_y = y; |
816 | } |
817 | } |
818 | continue; |
819 | case 'C': |
820 | case 'c': // color |
821 | p = draw_getval(p, &x); |
822 | dev_setcolor(x); |
823 | continue; |
824 | // Haraszti -- next case filter out the spaces or tabs and semicolons |
825 | // (GWBASIC compatibility) |
826 | case ' ': |
827 | case '\t': |
828 | case ';': |
829 | p++; |
830 | continue; |
831 | default: |
832 | rt_raise(ERR_DRAW_CMD, *p); |
833 | v_free(&var); |
834 | return; |
835 | } |
836 | p++; |
837 | } |
838 | |
839 | dev_setcolor(prev_color); |
840 | v_free(&var); |
841 | } |
842 | |
843 | // |
844 | // CHART chart-type, v() [, mark-type [, x1, y1, x2, y2]] |
845 | // |
846 | // chart-type |
847 | // 1 = line-chart |
848 | // 2 = bar-chart |
849 | // |
850 | // mark-type (bit-mask) |
851 | // 0 = none |
852 | // 1 = labels |
853 | // 2 = ruler |
854 | // |
855 | void cmd_chart_fstr(var_num_t v, char *buf) { |
856 | if (fabsl(v) >= 10E+9) { |
857 | ftostr(v / 1E+9, buf); |
858 | if (buf[3] == '.') { |
859 | buf[3] = '\0'; |
860 | } else { |
861 | buf[4] = '\0'; |
862 | } |
863 | strcat(buf, "G" ); |
864 | } else if (fabsl(v) >= 10E+6) { |
865 | ftostr(v / 1E+6, buf); |
866 | if (buf[3] == '.') { |
867 | buf[3] = '\0'; |
868 | } else { |
869 | buf[4] = '\0'; |
870 | } |
871 | strcat(buf, "M" ); |
872 | } else if (fabsl(v) >= 10E+3) { |
873 | ftostr(v / 1E+3, buf); |
874 | if (buf[3] == '.') { |
875 | buf[3] = '\0'; |
876 | } else { |
877 | buf[4] = '\0'; |
878 | } |
879 | strcat(buf, "K" ); |
880 | } else { |
881 | ftostr(v, buf); |
882 | buf[5] = '\0'; |
883 | } |
884 | } |
885 | |
886 | /* |
887 | * draw a chart |
888 | * |
889 | * x1,y1-x2,y2 = the area to draw |
890 | * vals = the values |
891 | * count = the number of the values |
892 | * xvals, xcount = for ruler the xvalues (use NULL for default) |
893 | * chart = chart type (1=line chart, 0=bar chart, 5=points) |
894 | * marks = marks type (2 & ruler, 1 & marks) |
895 | */ |
896 | void chart_draw(int x1, int y1, int x2, int y2, var_num_t *vals, int count, |
897 | var_num_t *xvals, int xcount, int chart, int marks) { |
898 | var_num_t lx, ly; |
899 | char buf[32]; |
900 | int32_t color = 0; |
901 | int rx1 = x1; |
902 | |
903 | // ready |
904 | dev_settextcolor(0, 15); |
905 | int *pts = (int *) malloc(sizeof(int) * count * 2); |
906 | |
907 | if (marks & 0x2) { |
908 | // ruler |
909 | x1 += dev_textwidth("00000" ) + 1; |
910 | y2 -= (dev_textheight("0" ) + 1); |
911 | } |
912 | |
913 | if (marks & 0x1) { |
914 | if (chart == 1) { |
915 | // line |
916 | x1 += 2; |
917 | x2 -= 2; |
918 | y1 += 2; |
919 | y2 -= 2; |
920 | } |
921 | } |
922 | |
923 | int dx = (x2 - x1); |
924 | int dy = (y2 - y1); |
925 | |
926 | // limits |
927 | var_num_t vmin = vals[0]; |
928 | var_num_t vmax = vals[0]; |
929 | for (int i = 1; i < count; i++) { |
930 | if (vmin > vals[i]) { |
931 | vmin = vals[i]; |
932 | } |
933 | if (vmax < vals[i]) { |
934 | vmax = vals[i]; |
935 | } |
936 | } |
937 | |
938 | if (chart == 1) { |
939 | // line-chart |
940 | lx = ((var_num_t) dx) / (var_num_t) (count - 1); |
941 | } else { |
942 | lx = ((var_num_t) dx) / (var_num_t) count; |
943 | } |
944 | ly = ((var_num_t) dy) / (vmax - vmin); |
945 | |
946 | // calc points |
947 | for (int i = 0; i < count; i++) { |
948 | int x = x1 + i * lx; |
949 | int y = y1 + (dy - ((vals[i] - vmin) * ly)); |
950 | pts[i * 2] = x > 0 ? x : 0; |
951 | pts[i * 2 + 1] = y > 0 ? y : 0; |
952 | } |
953 | |
954 | // draw ruler |
955 | if (marks & 0x2) { |
956 | // vertical |
957 | int fh = dev_textheight("0" ); |
958 | int n = dy / (fh * 1.5); |
959 | |
960 | if ((n - 1) > 0) { |
961 | for (int i = 0; i <= n; i++) { |
962 | var_num_t v; |
963 | if (i == 0) { |
964 | v = vmin; |
965 | } |
966 | else if (i == n) { |
967 | v = vmax; |
968 | } else { |
969 | v = vmin + (((var_num_t) i + 1) * ((vmax - vmin) / (var_num_t) (n + 1))); |
970 | } |
971 | cmd_chart_fstr(v, buf); |
972 | |
973 | int y = y1 + (dy - ((v - vmin) * ly)); |
974 | if (i != 0) { |
975 | dev_setxy(rx1 + 1, y + 1, 0); |
976 | } else { |
977 | dev_setxy(rx1 + 1, y - fh, 0); |
978 | } |
979 | dev_print(buf); |
980 | dev_line(x1 - 4, y, x1, y); |
981 | } |
982 | } |
983 | |
984 | // horizontal |
985 | int fw = dev_textwidth("000" ); |
986 | n = -1; |
987 | if (count <= 24) { |
988 | if (count * (fw * 1.34) < dx) { |
989 | n = count; |
990 | } |
991 | } |
992 | |
993 | if (n == -1) { |
994 | n = dx / (fw * 1.5); |
995 | } |
996 | if ((n - 1) > 0) { |
997 | for (int i = 0; i < n; i++) { |
998 | var_num_t v; |
999 | if (i == 0) { |
1000 | v = 0; |
1001 | } else { |
1002 | v = i * ((var_num_t) count / (var_num_t) n); |
1003 | } |
1004 | if (xvals) { |
1005 | // I have xvals |
1006 | var_num_t x; |
1007 | var_num_t xmin = xvals[0]; |
1008 | var_num_t xmax = xvals[xcount - 1]; |
1009 | var_num_t dx = xmax - xmin; |
1010 | if (i == 0) { |
1011 | x = xmin; |
1012 | } else if (i == n) { |
1013 | x = xmax; |
1014 | } else { |
1015 | x = xmin + ((dx / n) * i); |
1016 | } |
1017 | ftostr(x, buf); |
1018 | } else { |
1019 | // i don't have xvals |
1020 | ftostr(i + 1, buf); |
1021 | } |
1022 | |
1023 | buf[3] = '\0'; |
1024 | fw = dev_textwidth(buf); |
1025 | |
1026 | int x = x1 + v * lx; |
1027 | if (chart == 1 || chart == 5) { |
1028 | dev_setxy(x - fw, y2 + 1, 0); |
1029 | } else { |
1030 | if (x + fw + 1 < x2) { |
1031 | dev_setxy(x + 1, y2 + 1, 0); |
1032 | } |
1033 | } |
1034 | |
1035 | dev_print(buf); |
1036 | dev_line(x, y2, x, y2 + 4); |
1037 | } |
1038 | } |
1039 | |
1040 | dev_line(x1, y1, x1, y2); |
1041 | dev_line(x1, y2, x2, y2); |
1042 | |
1043 | x1++; |
1044 | y2--; |
1045 | dx = (x2 - x1); |
1046 | dy = (y2 - y1); |
1047 | } |
1048 | |
1049 | // draw |
1050 | switch (chart) { |
1051 | case 1: |
1052 | case 5: |
1053 | // line chart |
1054 | // points |
1055 | if (chart == 5) { |
1056 | for (int i = 0; i < count; i++) { |
1057 | dev_setpixel(pts[i * 2], pts[i * 2 + 1]); |
1058 | } |
1059 | } else { |
1060 | for (int i = 1; i < count; i++) { |
1061 | dev_line(pts[(i - 1) * 2], pts[(i - 1) * 2 + 1], pts[i * 2], pts[i * 2 + 1]); |
1062 | } |
1063 | } |
1064 | |
1065 | // draw marks |
1066 | if (marks & 0x1) { |
1067 | for (int i = 0; i < count; i++) { |
1068 | cmd_chart_fstr(vals[i], buf); |
1069 | |
1070 | int fw = dev_textwidth(buf); |
1071 | int fh = dev_textheight(buf); |
1072 | int mx = pts[i * 2] - fw / 2; |
1073 | int my = pts[i * 2 + 1]; |
1074 | |
1075 | if (my > (y1 + (y2 - y1) / 2)) { |
1076 | my -= fh; |
1077 | } |
1078 | if (mx <= x1) { |
1079 | mx = x1 + 1; |
1080 | } |
1081 | if (mx + fw >= x2) { |
1082 | mx = x2 - fw; |
1083 | } |
1084 | dev_setxy(mx, my, 0); |
1085 | dev_print(buf); |
1086 | dev_rect(pts[i * 2] - 2, pts[i * 2 + 1] - 2, |
1087 | pts[i * 2] + 2, pts[i * 2 + 1] + 2, 1); |
1088 | } |
1089 | } |
1090 | break; |
1091 | |
1092 | case 2: |
1093 | // bar chart |
1094 | // draw rect |
1095 | color = 0; |
1096 | for (int i = 1; i < count; i++) { |
1097 | if (os_color_depth > 2) { |
1098 | dev_setcolor(color); |
1099 | color++; |
1100 | if (color >= 15) { |
1101 | color = 0; |
1102 | } |
1103 | } |
1104 | dev_rect(pts[(i - 1) * 2], pts[(i - 1) * 2 + 1], pts[i * 2] - 2, y2, 1); |
1105 | } |
1106 | |
1107 | if (os_color_depth > 2) { |
1108 | dev_setcolor(color); |
1109 | } |
1110 | dev_rect(pts[(count - 1) * 2], pts[(count - 1) * 2 + 1], |
1111 | pts[(count - 1) * 2] + lx - 1, y2, 1); |
1112 | |
1113 | // draw marks |
1114 | if (marks & 0x1) { |
1115 | color = 0; |
1116 | for (int i = 0; i < count; i++) { |
1117 | cmd_chart_fstr(vals[i], buf); |
1118 | |
1119 | int fw = dev_textwidth(buf); |
1120 | int fh = dev_textheight(buf); |
1121 | int mx = pts[i * 2] + lx / 2 - fw / 2; |
1122 | int my = pts[i * 2 + 1]; |
1123 | |
1124 | if (os_color_depth > 2) { |
1125 | if (my - fh >= y1) { |
1126 | dev_settextcolor(0, 15); |
1127 | } else { |
1128 | if (color >= 7 && color != 8) { |
1129 | dev_settextcolor(0, color); |
1130 | } else { |
1131 | dev_settextcolor(15, color); |
1132 | } |
1133 | } |
1134 | |
1135 | color++; |
1136 | if (color >= 15) { |
1137 | color = 0; |
1138 | } |
1139 | } |
1140 | |
1141 | if (my - fh >= y1) { |
1142 | my -= fh; |
1143 | } |
1144 | if (mx <= x1) { |
1145 | mx = x1 + 1; |
1146 | } |
1147 | if (mx + fw >= x2) { |
1148 | mx = x2 - fw; |
1149 | } |
1150 | dev_setxy(mx, my, 0); |
1151 | dev_print(buf); |
1152 | } |
1153 | } |
1154 | break; |
1155 | }; |
1156 | |
1157 | free(pts); |
1158 | } |
1159 | |
1160 | // |
1161 | // CHART |
1162 | // |
1163 | void cmd_chart() { |
1164 | int32_t prev_fgcolor = dev_fgcolor; |
1165 | int32_t prev_bgcolor = dev_bgcolor; |
1166 | int x1 = 0; |
1167 | int y1 = 0; |
1168 | int x2 = os_graf_mx; |
1169 | int y2 = os_graf_my; |
1170 | |
1171 | // chart type |
1172 | int chart = par_getint(); IF_PROG_ERR_RTN; |
1173 | par_getcomma(); IF_PROG_ERR_RTN; |
1174 | |
1175 | // array |
1176 | var_t *var_p = par_getvarray(); IF_PROG_ERR_RTN; |
1177 | if (!var_p || var_p->type != V_ARRAY) { |
1178 | err_varisnotarray(); |
1179 | return; |
1180 | } |
1181 | |
1182 | // optional labels-flag |
1183 | int marks; |
1184 | if (code_peek() == kwTYPE_SEP) { |
1185 | par_getcomma(); IF_PROG_ERR_RTN; |
1186 | marks = par_getint(); IF_PROG_ERR_RTN; |
1187 | |
1188 | // optional x1,y1,x2,y2 |
1189 | if (code_peek() == kwTYPE_SEP) { |
1190 | par_getcomma(); IF_PROG_ERR_RTN; |
1191 | x1 = par_getint(); IF_PROG_ERR_RTN; |
1192 | par_getcomma(); IF_PROG_ERR_RTN; |
1193 | y1 = par_getint(); IF_PROG_ERR_RTN; |
1194 | par_getcomma(); IF_PROG_ERR_RTN; |
1195 | x2 = par_getint(); IF_PROG_ERR_RTN; |
1196 | par_getcomma(); IF_PROG_ERR_RTN; |
1197 | y2 = par_getint(); IF_PROG_ERR_RTN; |
1198 | } |
1199 | } else { |
1200 | marks = 0; |
1201 | } |
1202 | |
1203 | // get array's values |
1204 | int count = v_asize(var_p); |
1205 | var_num_t *vals = (var_num_t *) malloc(sizeof(var_num_t) * count); |
1206 | for (int i = 0; i < count; i++) { |
1207 | var_t *elem_p = v_elem(var_p, i); |
1208 | if (prog_error) { |
1209 | free(vals); |
1210 | return; |
1211 | } |
1212 | switch (elem_p->type) { |
1213 | case V_INT: |
1214 | vals[i] = elem_p->v.i; |
1215 | break; |
1216 | case V_NUM: |
1217 | vals[i] = elem_p->v.n; |
1218 | break; |
1219 | case V_STR: |
1220 | vals[i] = v_getreal(elem_p); |
1221 | break; |
1222 | default: |
1223 | err_typemismatch(); |
1224 | free(vals); |
1225 | return; |
1226 | } |
1227 | } |
1228 | |
1229 | chart_draw(x1, y1, x2, y2, vals, count, NULL, 0, chart, marks); |
1230 | |
1231 | free(vals); |
1232 | dev_settextcolor(prev_fgcolor, prev_bgcolor); |
1233 | } |
1234 | |
1235 | var_t *par_getm3() { |
1236 | // array |
1237 | var_t *vp = par_getvarray(); |
1238 | if (prog_error) { |
1239 | return NULL; |
1240 | } |
1241 | if (vp == NULL || vp->type != V_ARRAY || v_asize(vp) != 9) { |
1242 | err_typemismatch(); |
1243 | return NULL; |
1244 | } |
1245 | return vp; |
1246 | } |
1247 | |
1248 | void m3combine(var_t *m, var_num_t nm[3][3]) { |
1249 | var_num_t om[3][3]; |
1250 | int i, j; |
1251 | var_t *e; |
1252 | |
1253 | // copy m to om |
1254 | for (i = 0; i < 3; i++) { |
1255 | for (j = 0; j < 3; j++) { |
1256 | e = v_elem(m, (i * 3 + j)); |
1257 | if (e->type == V_NUM) { |
1258 | om[i][j] = e->v.n; |
1259 | } else if (e->type == V_INT) { |
1260 | om[i][j] = e->v.i; |
1261 | } else { |
1262 | om[i][j] = v_getval(e); |
1263 | } |
1264 | } |
1265 | } |
1266 | |
1267 | // combine |
1268 | for (i = 0; i < 3; i++) { |
1269 | for (j = 0; j < 3; j++) { |
1270 | e = v_elem(m, (i * 3 + j)); |
1271 | if (e->type != V_NUM) { |
1272 | v_free(e); |
1273 | } |
1274 | e->type = V_NUM; |
1275 | e->v.n = nm[i][0] * om[0][j] + nm[i][1] * om[1][j] + nm[i][2] * om[2][j]; |
1276 | } |
1277 | } |
1278 | |
1279 | } |
1280 | |
1281 | // |
1282 | void m3ident(var_num_t m[3][3]) { |
1283 | int i, j; |
1284 | |
1285 | for (i = 0; i < 3; i++) { |
1286 | for (j = 0; j < 3; j++) { |
1287 | m[i][j] = (i == j) ? 1.0 : 0.0; |
1288 | } |
1289 | } |
1290 | } |
1291 | |
1292 | // |
1293 | // M3IDENT BYREF m3x3 |
1294 | // |
1295 | void cmd_m3ident() { |
1296 | var_t *m, *e; |
1297 | int i, j; |
1298 | |
1299 | m = par_getm3(); |
1300 | if (prog_error) { |
1301 | return; |
1302 | } |
1303 | for (i = 0; i < 3; i++) { |
1304 | for (j = 0; j < 3; j++) { |
1305 | e = v_elem(m, (i * 3 + j)); |
1306 | v_init(e); |
1307 | e->type = V_NUM; |
1308 | e->v.n = (i == j) ? 1.0 : 0.0; |
1309 | } |
1310 | } |
1311 | } |
1312 | |
1313 | // |
1314 | // M3ROTATE BYREF m3x3, angle[, x, y] |
1315 | // |
1316 | void cmd_m3rotate() { |
1317 | var_t *m; |
1318 | var_num_t angle, x = 0, y = 0, c, s; |
1319 | var_num_t matrix[3][3]; |
1320 | |
1321 | m = par_getm3(); |
1322 | if (prog_error) { |
1323 | return; |
1324 | } |
1325 | par_getcomma(); |
1326 | if (prog_error) { |
1327 | return; |
1328 | } |
1329 | angle = par_getnum(); |
1330 | if (prog_error) { |
1331 | return; |
1332 | } |
1333 | if (code_peek() == kwTYPE_SEP) { |
1334 | par_getcomma(); |
1335 | if (prog_error) |
1336 | return; |
1337 | x = par_getnum(); |
1338 | if (prog_error) |
1339 | return; |
1340 | par_getcomma(); |
1341 | if (prog_error) |
1342 | return; |
1343 | y = par_getnum(); |
1344 | if (prog_error) { |
1345 | return; |
1346 | } |
1347 | } |
1348 | |
1349 | c = cos(angle); |
1350 | s = sin(angle); |
1351 | |
1352 | m3ident(matrix); |
1353 | matrix[0][0] = c; |
1354 | matrix[0][1] = s; |
1355 | matrix[1][0] = -s; |
1356 | matrix[1][1] = c; |
1357 | matrix[2][0] = (1.0 - c) * x + (s * y); |
1358 | matrix[2][1] = (1.0 - c) * y - (s * x); |
1359 | m3combine(m, matrix); |
1360 | } |
1361 | |
1362 | // |
1363 | // M3SCALE BYREF m3x3, x, y, fx, fy |
1364 | // |
1365 | void cmd_m3scale() { |
1366 | var_t *m; |
1367 | var_num_t x, y, fx, fy; |
1368 | var_num_t matrix[3][3]; |
1369 | |
1370 | m = par_getm3(); |
1371 | if (prog_error) |
1372 | return; |
1373 | par_getcomma(); |
1374 | if (prog_error) |
1375 | return; |
1376 | x = par_getnum(); |
1377 | if (prog_error) |
1378 | return; |
1379 | par_getcomma(); |
1380 | if (prog_error) |
1381 | return; |
1382 | y = par_getnum(); |
1383 | if (prog_error) |
1384 | return; |
1385 | par_getcomma(); |
1386 | if (prog_error) |
1387 | return; |
1388 | fx = par_getnum(); |
1389 | if (prog_error) |
1390 | return; |
1391 | par_getcomma(); |
1392 | if (prog_error) |
1393 | return; |
1394 | fy = par_getnum(); |
1395 | if (prog_error) |
1396 | return; |
1397 | |
1398 | m3ident(matrix); |
1399 | matrix[0][0] = fx; |
1400 | matrix[1][1] = fy; |
1401 | matrix[2][0] = (1.0 - fx) * x; |
1402 | matrix[2][1] = (1.0 - fy) * y; |
1403 | m3combine(m, matrix); |
1404 | } |
1405 | |
1406 | // |
1407 | // M3TRANS BYREF m3x3, x, y |
1408 | // |
1409 | void cmd_m3translate() { |
1410 | var_t *m; |
1411 | var_num_t x, y; |
1412 | var_num_t matrix[3][3]; |
1413 | |
1414 | m = par_getm3(); |
1415 | if (prog_error) |
1416 | return; |
1417 | par_getcomma(); |
1418 | if (prog_error) |
1419 | return; |
1420 | x = par_getnum(); |
1421 | if (prog_error) |
1422 | return; |
1423 | par_getcomma(); |
1424 | if (prog_error) |
1425 | return; |
1426 | y = par_getnum(); |
1427 | if (prog_error) |
1428 | return; |
1429 | |
1430 | m3ident(matrix); |
1431 | matrix[2][0] = x; |
1432 | matrix[2][1] = y; |
1433 | m3combine(m, matrix); |
1434 | } |
1435 | |
1436 | // |
1437 | // M3APPLY m3x3, BYREF poly |
1438 | // |
1439 | void cmd_m3apply() { |
1440 | var_t *m, *p, *e; |
1441 | var_num_t om[3][3], x, y; |
1442 | int i, j, count; |
1443 | |
1444 | m = par_getm3(); |
1445 | if (prog_error) |
1446 | return; |
1447 | par_getcomma(); |
1448 | if (prog_error) |
1449 | return; |
1450 | p = par_getvarray(); |
1451 | if (prog_error) |
1452 | return; |
1453 | count = v_asize(p); |
1454 | |
1455 | // copy m to om |
1456 | for (i = 0; i < 3; i++) { |
1457 | for (j = 0; j < 3; j++) { |
1458 | e = v_elem(m, i * 3 + j); |
1459 | om[i][j] = v_getreal(e); |
1460 | } |
1461 | } |
1462 | |
1463 | // apply |
1464 | e = v_elem(p, 0); |
1465 | if (e->type != V_ARRAY) { |
1466 | int o; |
1467 | |
1468 | count = (v_asize(p) >> 1); |
1469 | for (i = 0; i < count; i++) { |
1470 | o = i << 1; |
1471 | x = v_getreal(v_elem(p, o)); |
1472 | y = v_getreal(v_elem(p, o + 1)); |
1473 | v_setreal(v_elem(p, o), x * om[0][0] + y * om[1][0] + om[2][0]); |
1474 | v_setreal(v_elem(p, o + 1), x * om[0][1] + y * om[1][1] + om[2][1]); |
1475 | } |
1476 | } else { |
1477 | for (i = 0; i < count; i++) { |
1478 | e = v_elem(p, i); |
1479 | |
1480 | if (e->type != V_ARRAY) |
1481 | err_parsepoly(i, 10); |
1482 | else if ((v_asize(e) % 2) != 0) |
1483 | err_parsepoly(i, 11); |
1484 | |
1485 | if (prog_error) |
1486 | break; |
1487 | |
1488 | x = v_getreal(v_elem(e, 0)); |
1489 | y = v_getreal(v_elem(e, 1)); |
1490 | v_setreal(v_elem(e, 0), x * om[0][0] + y * om[1][0] + om[2][0]); |
1491 | v_setreal(v_elem(e, 1), x * om[0][1] + y * om[1][1] + om[2][1]); |
1492 | } |
1493 | } |
1494 | } |
1495 | |
1496 | // |
1497 | // INTERSECT a.x, a.y, b.x, b.y, c.x, c.y, d.x, d.y, BYREF type, BYREF r.x, BYREF r.y |
1498 | // |
1499 | void cmd_intersect() { |
1500 | var_num_t a, b, c, s; |
1501 | pt_t A, B, C, D, R; |
1502 | var_t *type, *vrx, *vry = NULL; |
1503 | byte style = 0; |
1504 | |
1505 | // parameters |
1506 | A = par_getpt(); |
1507 | if (prog_error) |
1508 | return; |
1509 | par_getcomma(); |
1510 | if (prog_error) |
1511 | return; |
1512 | B = par_getpt(); |
1513 | if (prog_error) |
1514 | return; |
1515 | par_getcomma(); |
1516 | if (prog_error) |
1517 | return; |
1518 | C = par_getpt(); |
1519 | if (prog_error) |
1520 | return; |
1521 | par_getcomma(); |
1522 | if (prog_error) |
1523 | return; |
1524 | D = par_getpt(); |
1525 | if (prog_error) |
1526 | return; |
1527 | par_getcomma(); |
1528 | if (prog_error) |
1529 | return; |
1530 | |
1531 | type = par_getvar_ptr(); |
1532 | if (prog_error) |
1533 | return; |
1534 | par_getcomma(); |
1535 | if (prog_error) |
1536 | return; |
1537 | |
1538 | vrx = par_getvar_ptr(); |
1539 | if (prog_error) |
1540 | return; |
1541 | if (code_peek() == kwTYPE_SEP) { |
1542 | par_getcomma(); |
1543 | if (prog_error) |
1544 | return; |
1545 | vry = par_getvar_ptr(); |
1546 | if (prog_error) |
1547 | return; |
1548 | } else |
1549 | style = 1; |
1550 | |
1551 | // initialize vars |
1552 | v_free(type); |
1553 | R.x = R.y = 0; |
1554 | |
1555 | // |
1556 | a = (B.y - A.y) * (D.x - C.x) - (B.x - A.x) * (D.y - C.y); |
1557 | b = (A.x - C.x) * (D.y - C.y) - (A.y - C.y) * (D.x - C.x); |
1558 | c = (A.x - C.x) * (B.y - A.y) - (A.y - C.y) * (B.x - A.x); |
1559 | |
1560 | if (a == 0.0) |
1561 | type->v.i = (b == 0.0) ? 3 : 2; |
1562 | else { |
1563 | if (a > 0.0) { |
1564 | if ((b >= 0.0 && b <= a) && (c >= 0.0 && c <= a)) { |
1565 | type->v.i = 1; |
1566 | } else { |
1567 | type->v.i = 0; |
1568 | } |
1569 | } else { |
1570 | if ((b <= 0.0 && b >= a) && (c <= 0.0 && c >= a)) { |
1571 | type->v.i = 1; |
1572 | } else { |
1573 | type->v.i = 0; |
1574 | } |
1575 | } |
1576 | } |
1577 | |
1578 | // |
1579 | if (type->v.i == 1 || type->v.i == 0) { |
1580 | |
1581 | if (b == a || c == a || c == 0.0) |
1582 | if (type->v.i == 1) |
1583 | type->v.i = 4; // Special case |
1584 | |
1585 | s = b / a; |
1586 | |
1587 | if (C.x == D.x) |
1588 | R.x = C.x; |
1589 | else |
1590 | R.x = A.x + ((B.x - A.x) * s); |
1591 | |
1592 | if (C.y == D.y) |
1593 | R.y = C.y; |
1594 | else |
1595 | R.y = A.y + ((B.y - A.y) * s); |
1596 | } |
1597 | |
1598 | // |
1599 | if (style == 1) { |
1600 | v_toarray1(vrx, 2); |
1601 | v_setreal(v_elem(vrx, 0), R.x); |
1602 | v_setreal(v_elem(vrx, 1), R.y); |
1603 | } else { |
1604 | v_setreal(vrx, R.x); |
1605 | v_setreal(vry, R.y); |
1606 | } |
1607 | } |
1608 | |
1609 | // |
1610 | // POLYEXT poly, BYREF xmin, BYREF ymin, BYREF xmax, BYREF ymax |
1611 | // |
1612 | void cmd_polyext() { |
1613 | var_t *xmin, *ymin, *xmax, *ymax; |
1614 | int count, i; |
1615 | pt_t *poly = NULL; |
1616 | |
1617 | count = par_getpoly(&poly); |
1618 | if (prog_error) |
1619 | return; |
1620 | |
1621 | par_massget("PPPP" , &xmin, &ymin, &xmax, &ymax); |
1622 | if (prog_error) { |
1623 | free(poly); |
1624 | return; |
1625 | } |
1626 | |
1627 | // initialize vars |
1628 | v_free(xmin); |
1629 | xmin->type = V_NUM; |
1630 | v_free(xmax); |
1631 | xmax->type = V_NUM; |
1632 | v_free(ymin); |
1633 | ymin->type = V_NUM; |
1634 | v_free(ymax); |
1635 | ymax->type = V_NUM; |
1636 | |
1637 | if (count == 0) { |
1638 | xmin->v.n = ymin->v.n = xmax->v.n = ymax->v.n = 0.0; |
1639 | free(poly); |
1640 | return; |
1641 | } |
1642 | |
1643 | xmin->v.n = xmax->v.n = poly[0].x; |
1644 | ymin->v.n = ymax->v.n = poly[0].y; |
1645 | for (i = 1; i < count; i++) { |
1646 | if (poly[i].x > xmax->v.n) |
1647 | xmax->v.n = poly[i].x; |
1648 | if (poly[i].x < xmin->v.n) |
1649 | xmin->v.n = poly[i].x; |
1650 | |
1651 | if (poly[i].y > ymax->v.n) |
1652 | ymax->v.n = poly[i].y; |
1653 | if (poly[i].y < ymin->v.n) |
1654 | ymin->v.n = poly[i].y; |
1655 | } |
1656 | |
1657 | free(poly); |
1658 | } |
1659 | |