1
2
3
4
5
6
7
8
9
10
11
12
13
14if known metafun_loaded_tool : endinput ; fi ;
15
16newinternal boolean metafun_loaded_tool ; metafun_loaded_tool := true ; immutable metafun_loaded_tool ;
17
18let @## = @# ;
19
20let noexpand = quote ;
21
22permanent @##, noexpand ;
23
24
25
26
27
28
29
30
31if not known mpversion : string mpversion ; mpversion := "0.641" ; fi ;
32
33
34
35newinternal metapostversion ; metapostversion := 3.0 ; permanent metapostversion ;
36
37
38
39warningcheck := 0 ;
40
41
42
43def nothing = enddef ;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66string space ; space := char 32 ;
67string percent ; percent := char 37 ;
68string crlf ; crlf := char 10 & char 13 ;
69string dquote ; dquote := char 34 ;
70
71
72
73
74
75
76permanent space, percent, crlf, dquote ;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93let triplet = rgbcolor ;
94let quadruplet = cmykcolor ;
95
96permanent triplet, quadruplet ;
97
98
99
100vardef image@#(text t) =
101 save currentpicture ;
102 picture currentpicture ;
103 currentpicture := nullpicture ;
104 t ;
105 currentpicture
106 if str @# <> "" :
107 shifted (
108 mfun_labxf@# lrcorner p
109 mfun_labyf@# ulcorner p
110 (1mfun_labxf@#mfun_labyf@#) llcorner p
111 )
112 fi
113enddef ;
114
115permanent image ;
116
117
118
119def dispose suffix s =
120 if known s :
121 begingroup ;
122 save ss ;
123 if numeric s : numeric ss
124 elseif boolean s : boolean ss
125 elseif pair s : pair ss
126 elseif path s : path ss
127 elseif picture s : picture ss
128 elseif string s : string ss
129 elseif transform s : transform ss
130 elseif color s : color ss
131 elseif rgbcolor s : rgbcolor ss
132 elseif cmykcolor s : cmykcolor ss
133 elseif pen s : pen ss
134 else s : numeric ss
135 fi ;
136 s := ss ;
137 endgroup ;
138 fi ;
139enddef ;
140
141permanent dispose ;
142
143
144
145let grayscale = graycolor ;
146let greyscale = greycolor ;
147
148vardef colorpart expr c =
149 if not picture c :
150 0
151 elseif colormodel c = greycolormodel :
152 greypart c
153 elseif colormodel c = rgbcolormodel :
154 (redpart c,greenpart c,bluepart c)
155 elseif colormodel c = cmykcolormodel :
156 (cyanpart c,magentapart c,yellowpart c,blackpart c)
157 else :
158 0
159 fi
160enddef ;
161
162vardef colorlike(text c) text v =
163 save temp_p ; picture temp_p ;
164 forsuffixes i=v :
165 temp_p := image(draw origin withcolor c ;) ;
166 if (colormodel temp_p = cmykcolormodel) :
167 cmykcolor i ;
168 elseif (colormodel temp_p = rgbcolormodel) :
169 rgbcolor i ;
170 else :
171 greycolor i ;
172 fi ;
173 endfor ;
174enddef ;
175
176permanent nocolormodel, greycolormodel, graycolormodel, rgbcolormodel, cmykcolormodel,
177 greyscale, grayscale, colorpart, colorlike ;
178
179
180
181vardef ddecimal primary p =
182 decimal xpart p & " " & decimal ypart p
183enddef ;
184
185vardef dddecimal primary c =
186 decimal redpart c & " " & decimal greenpart c & " " & decimal bluepart c
187enddef ;
188
189vardef ddddecimal primary c =
190 decimal cyanpart c & " " & decimal magentapart c & " " & decimal yellowpart c & " " & decimal blackpart c
191enddef ;
192
193vardef colordecimals primary c =
194 if cmykcolor c :
195 decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c
196 elseif rgbcolor c :
197 decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
198 elseif string c:
199 colordecimals resolvedcolor(c)
200 else :
201 decimal c
202 fi
203enddef ;
204
205vardef colordecimalslist(text t) =
206 save b ; boolean b ; b := false ;
207 for s=t :
208 if b : & " " & fi
209 colordecimals(s)
210 hide(b := true ;)
211 endfor
212enddef ;
213
214permanent decimal, ddecimal, dddecimal, ddddecimal, colordecimals, colordecimalslist ;
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243boolean savingdata ; savingdata := false ;
244boolean savingdatadone ; savingdatadone := false ;
245
246def savedata expr txt =
247 lua.mp.mf_save_data(txt);
248enddef ;
249
250def startsavingdata =
251 lua.mp.mf_start_saving_data();
252enddef ;
253
254def stopsavingdata =
255 lua.mp.mf_stop_saving_data() ;
256enddef ;
257
258def finishsavingdata =
259
260enddef ;
261
262
263
264
265
266
267def newcolor text v = forsuffixes i=v : save i ; color i ; endfor ; enddef ;
268def newrgbcolor text v = forsuffixes i=v : save i ; rgbcolor i ; endfor ; enddef ;
269def newcmykcolor text v = forsuffixes i=v : save i ; cmykcolor i ; endfor ; enddef ;
270def newnumeric text v = forsuffixes i=v : save i ; numeric i ; endfor ; enddef ;
271def newboolean text v = forsuffixes i=v : save i ; boolean i ; endfor ; enddef ;
272def newtransform text v = forsuffixes i=v : save i ; transform i ; endfor ; enddef ;
273def newpath text v = forsuffixes i=v : save i ; path i ; endfor ; enddef ;
274def newpicture text v = forsuffixes i=v : save i ; picture i ; endfor ; enddef ;
275def newstring text v = forsuffixes i=v : save i ; string i ; endfor ; enddef ;
276def newpair text v = forsuffixes i=v : save i ; pair i ; endfor ; enddef ;
277
278permanent newcolor, newrgbcolor, newcmykcolor, newnumeric, newboolean, newtransform, newpath, newpicture, newstring, newpair ;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310path mfun_boundingbox_stack[] ;
311numeric mfun_boundingbox_stack_depth ;
312
313mfun_boundingbox_stack_depth := 0 ;
314
315def pushboundingbox text p =
316 mfun_boundingbox_stack_depth := mfun_boundingbox_stack_depth 1 ;
317 mfun_boundingbox_stack[mfun_boundingbox_stack_depth] := boundingbox p ;
318enddef ;
319
320def popboundingbox text p =
321 setbounds p to mfun_boundingbox_stack[mfun_boundingbox_stack_depth] ;
322 mfun_boundingbox_stack[mfun_boundingbox_stack_depth] := origin -- cycle ;
323 mfun_boundingbox_stack_depth := mfun_boundingbox_stack_depth 1 ;
324enddef ;
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360let boundingbox = corners ;
361
362vardef innerboundingbox primary p =
363 save b ; path b ; b := corners p ;
364 top rt point 0 of b --
365 top lft point 1 of b --
366 bot lft point 2 of b --
367 bot rt point 3 of b -- cycle
368enddef;
369
370vardef outerboundingbox primary p =
371 save b ; path b ; b := corners p ;
372 bot lft point 0 of b --
373 bot rt point 1 of b --
374 top rt point 2 of b --
375 top lft point 3 of b -- cycle
376enddef;
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397vardef boundingradius primary p =
398 if picture p :
399 pair c ; c := center p;
400 max(
401 abs((llcorner p) shifted c),
402 abs((lrcorner p) shifted c),
403 abs((urcorner p) shifted c),
404 abs((ulcorner p) shifted c)
405 )
406 elseif pen p :
407 boundingradius image(draw makepath p ;)
408 elseif path p :
409 boundingradius image(draw p ;)
410 fi
411enddef ;
412
413vardef boundingcircle primary p =
414 fullcircle scaled 2boundingradius p shifted center p
415enddef ;
416
417vardef boundingpoint@#(expr p) =
418 if picture p :
419 ( mfun_labxf@# ulcorner p
420 mfun_labyf@# lrcorner p
421 (1mfun_labxf@#mfun_labyf@#)urcorner p)
422 elseif path p :
423 boundingpoint@#(image(draw p ;))
424
425
426
427
428 fi
429enddef ;
430
431permanent pushboundingbox, popboundingbox, boundingbox, innerboundingbox, outerboundingbox,
432 boundingradius, boundingcircle, boundingpoint ;
433
434
435
436def mirrored primary a =
437 a scaled -1
438enddef ;
439
440primarydef a mirroredabout b =
441 (a shifted b) scaled -1 shifted b
442enddef ;
443
444permanent mirrored, mirroredabout ;
445
446
447
448
449
450pi := 3.14159265358979323846264338327950288419716939937510 ;
451radian := 180pi ;
452
453permanent pi, radian ;
454
455
456
457vardef sqr primary x = xx enddef ;
458vardef log primary x = if x=0: 0 else: mlog(x)mlog(10) fi enddef ;
459vardef ln primary x = if x=0: 0 else: mlog(x)256 fi enddef ;
460vardef exp primary x = (mexp 256)x enddef ;
461vardef inv primary x = if x=0: 0 else: x-1 fi enddef ;
462
463vardef pow (expr x,p) = xp enddef ;
464
465vardef tand primary x = sind(x)cosd(x) enddef ;
466vardef cotd primary x = cosd(x)sind(x) enddef ;
467
468
469
470
471vardef cot primary x = cos(x)sin(x) enddef ;
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491primarydef a zmod b = (((b2 a) mod b) b2) enddef ;
492
493permanent sqr, log, ln, exp, inv, pow, tand, cotd, cot, zmod ;
494
495
496
497def undashed =
498 dashed nullpicture
499enddef ;
500
501permanent undashed ;
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561stripe_n := 10;
562stripe_slot := 3;
563stripe_gap := 5;
564stripe_angle := 45;
565
566def mfun_tool_striped_number_action text extra =
567 for i = 1used_n step 1used_n until 1 :
568 draw point (1i) of bounds -- point (3i) of bounds withpen pencircle scaled penwidth extra ;
569 endfor ;
570 for i = 0 step 1used_n until 1 :
571 draw point (3i) of bounds -- point (1i) of bounds withpen pencircle scaled penwidth extra ;
572 endfor ;
573enddef ;
574
575def mfun_tool_striped_set_options(expr option) =
576 save isinner, swapped, isdrawn ;
577 boolean isinner, swapped, isdrawn ;
578 if option = 0 :
579 isdrawn := true;
580 isinner := true ;
581 swapped := false ;
582 elseif option = 1 :
583 isdrawn := false ;
584 isinner := false ;
585 swapped := false ;
586 elseif option = 2 :
587 isdrawn := false ;
588 isinner := true ;
589 swapped := false ;
590 elseif option = 3 :
591 isdrawn := false ;
592 isinner := false ;
593 swapped := true ;
594 elseif option = 4 :
595 isdrawn := false ;
596 isinner := true ;
597 swapped := true ;
598 else :
599 isdrawn := false ;
600 isinner := false ;
601 swapped := false ;
602 fi ;
603enddef ;
604
605vardef mfun_tool_striped_number(expr option, p, asked_n, asked_slot) text extra =
606
607 begingroup ;
608 save pattern, shape, bounds, penwidth, used_n, used_slot ;
609 picture pattern, shape ; path bounds ; numeric used_s, used_slot ;
610 mfun_tool_striped_set_options(option) ;
611 used_slot := if asked_slot = 0 : stripe_slot else : asked_slot fi ;
612 used_n := if asked_n = 0 : stripe_n else : asked_n fi ;
613 shape := image(draw p) ;
614 bounds := boundingbox shape ;
615 penwidth := min(ypart urcorner shape ypart llcorner shape, xpart urcorner shape xpart llcorner shape) (used_slot used_n) ;
616 pattern := image (
617 if isinner :
618 mfun_tool_striped_number_action extra ;
619 for s within shape :
620 if stroked s or filled s :
621 clip currentpicture to pathpart s ;
622 fi
623 endfor ;
624 else :
625 for s within shape :
626 if stroked s or filled s :
627 draw image (
628 mfun_tool_striped_number_action extra ;
629 clip currentpicture to pathpart s ;
630 ) ;
631 fi ;
632 endfor ;
633 fi ;
634 ) ;
635 if isdrawn :
636 addto currentpicture also pattern ;
637 elseif swapped :
638 addto currentpicture also shape ;
639 addto currentpicture also pattern ;
640 else :
641 addto currentpicture also pattern ;
642 addto currentpicture also shape ;
643 fi ;
644 endgroup ;
645
646enddef ;
647
648
649
650
651
652
653
654
655def mfun_tool_striped_angle_action text extra =
656 for i = minimum -.5used_gap step used_gap until maximum :
657 nodraw (minimum,i) -- (maximum,i) extra ;
658 endfor ;
659 dodraw origin ;
660 currentpicture := currentpicture rotated used_angle ;
661enddef ;
662
663vardef mfun_tool_striped_angle(expr option, p, asked_angle, asked_gap) text extra =
664
665 begingroup ;
666 save pattern, shape, mask, maximum, minimum, centrum, used_angle, used_gap ;
667 picture pattern, shape, mask ; numeric maximum, minimum ; pair centrum ; numeric used_angle, used_gap ;
668 mfun_tool_striped_set_options(option) ;
669 used_angle := if asked_angle = 0 : stripe_angle else : asked_angle fi ;
670 used_gap := if asked_gap = 0 : stripe_gap else : asked_gap fi ;
671 shape := image(draw p) ;
672
673 centrum := llcorner shape ;
674 shape := shape shifted centrum ;
675 mask := shape rotated used_angle ;
676 maximum := max (xpart llcorner mask, xpart urcorner mask, ypart llcorner mask, ypart urcorner mask) ;
677 minimum := min (xpart llcorner mask, xpart urcorner mask, ypart llcorner mask, ypart urcorner mask) ;
678
679 maximum := maximum max(xpart urcorner shape, ypart urcorner shape);
680 minimum := minimum max(xpart urcorner shape, ypart urcorner shape);
681
682 pattern := image (
683 if isinner :
684 mfun_tool_striped_angle_action extra ;
685 for s within shape :
686 if stroked s or filled s :
687 clip currentpicture to pathpart s ;
688 fi
689 endfor ;
690 else :
691 for s within shape :
692 if stroked s or filled s :
693 draw image (
694 mfun_tool_striped_angle_action extra ;
695 clip currentpicture to pathpart s ;
696 ) ;
697 fi ;
698 endfor ;
699 fi ;
700 ) ;
701 if isdrawn :
702 addto currentpicture also pattern ;
703 elseif swapped :
704 addto currentpicture also shape ;
705 addto currentpicture also pattern ;
706 else :
707 addto currentpicture also pattern ;
708 addto currentpicture also shape ;
709 fi ;
710 currentpicture := currentpicture shifted centrum ;
711 endgroup ;
712
713enddef;
714
715newinternal striped_normal_inner ; striped_normal_inner := 1 ;
716newinternal striped_reverse_inner ; striped_reverse_inner := 2 ;
717newinternal striped_normal_outer ; striped_normal_outer := 3 ;
718newinternal striped_reverse_outer ; striped_reverse_outer := 4 ;
719
720secondarydef p anglestriped s =
721
722 image(mfun_tool_striped_angle(redpart s,p,greenpart s,bluepart s))
723enddef ;
724
725secondarydef p numberstriped s =
726
727 image(mfun_tool_striped_number(redpart s,p,greenpart s,bluepart s))
728enddef ;
729
730
731
732def stripe_path_n (text asked_spec) (text asked_draw) expr asked_path =
733 do_stripe_path_n (asked_spec) (asked_draw) (asked_path)
734enddef;
735
736def do_stripe_path_n (text asked_spec) (text asked_draw) (expr asked_path) text asked_text =
737 draw image(asked_draw asked_path asked_text) numberstriped(3,0,0) asked_spec ;
738enddef ;
739
740def stripe_path_a (text asked_spec) (text asked_draw) expr asked_path =
741 do_stripe_path_a (asked_spec) (asked_draw) (asked_path)
742enddef;
743
744def do_stripe_path_a (text asked_spec) (text asked_draw) (expr asked_path) text asked_text =
745 draw image(asked_draw asked_path asked_text) anglestriped(3,0,0) asked_spec ;
746enddef ;
747
748
749
750
751
752
753vardef hatch(expr p, a, d) =
754 save thestripe, diag, b ; picture thestripe ; numeric diag ; path b ;
755 b := boundingbox p;
756 diag := 0.55 ( abs((urcorner b) (llcorner b)) ) ;
757 thestripe := image (
758 draw (diag,0) -- (diag, 0) &&
759 for i = d step d until diag:
760 (diag, i) -- (diag, i) &&
761 (diag,i) -- (diag,i) &&
762 endfor nocycle
763 withpen currentpen ;
764 ) ;
765 thestripe := thestripe shifted center b ;
766 thestripe := thestripe rotatedaround(center b, a) ;
767 clip thestripe to p ;
768 thestripe
769enddef ;
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784primarydef p xsized w =
785 begingroup
786 save r, l ; pair r;
787 r := xrange p ;
788 l := ypart r xpart r ;
789 (p if (l > 0) and (w > 0) : scaled (wl) fi)
790 endgroup
791enddef ;
792
793
794
795
796
797
798
799
800
801
802
803
804primarydef p ysized h =
805 begingroup
806 save r, l ; pair r ;
807 r := yrange p ;
808 l := ypart r xpart r ;
809 (p if (l > 0) and (h > 0) : scaled (hl) fi)
810 endgroup
811enddef ;
812
813
814
815
816
817
818
819
820
821
822
823
824
825primarydef p xysized s =
826 begingroup
827 save wh, w, h, b ; pair wh ; path b;
828 b := corners p ;
829 w := xpart point 1 of b xpart point 0 of b ;
830 h := ypart point 2 of b ypart point 1 of b ;
831 wh := paired (s) ;
832 p
833 if (w > 0) and (h > 0) :
834 if xpart wh > 0 : xscaled (xpart whw) fi
835 if ypart wh > 0 : yscaled (ypart whh) fi
836 fi
837 endgroup
838enddef ;
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853let sized = xysized ;
854
855permanent xsized, ysized, xysized, sized ;
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876primarydef p xynormalized s =
877 begingroup save w, h, b ; path b;
878 b := corners p ;
879 w := xpart point 1 of b xpart point 0 of b ;
880 h := ypart point 2 of b ypart point 1 of b ;
881 if (w > 0) and (h > 0) :
882 save t, wh ; transform t ; pair wh ;
883 wh := paired (s) ;
884 t := identity
885 shifted llcorner p
886 if xpart wh > 0 : xscaled (xpart whw) fi
887 if ypart wh > 0 : yscaled (ypart whh) fi
888 ;
889 p transformed t
890 else :
891 p
892 fi
893 endgroup
894enddef ;
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912primarydef p xnormalized s =
913 begingroup save h, r ; pair r ;
914 r := xrange p ;
915 w := ypart r xpart r ;
916 if (w > 0) :
917 save t ; transform t ;
918 t := identity
919 shifted llcorner p
920 if s > 0 : xscaled (sw) fi
921 ;
922 p transformed t
923 else :
924 p
925 fi
926 endgroup
927enddef ;
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945primarydef p ynormalized s =
946 begingroup save h, r ; pair r ;
947 r := yrange p ;
948 h := ypart r xpart r ;
949 if (h > 0) :
950 save t ; transform t ;
951 t := identity
952 shifted llcorner p
953 if s > 0 : yscaled (sh) fi
954 ;
955 p transformed t
956 else :
957 p
958 fi
959 endgroup
960enddef ;
961
962permanent xnormalized, ynormalized, xynormalized ;
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984path fullsquare, unitcircle ;
985
986fullsquare := unitsquare shifted center unitsquare ;
987unitcircle := fullcircle shifted urcorner fullcircle ;
988
989
990
991path urcircle, ulcircle, llcircle, lrcircle ;
992
993urcircle := origin -- (+.5,0) & (+.5,0){up} .. (0,+.5) & (0,+.5) -- cycle ;
994ulcircle := origin -- (0,+.5) & (0,+.5){left} .. (-.5,0) & (-.5,0) -- cycle ;
995llcircle := origin -- (-.5,0) & (-.5,0){down} .. (0,-.5) & (0,-.5) -- cycle ;
996lrcircle := origin -- (0,-.5) & (0,-.5){right} .. (+.5,0) & (+.5,0) -- cycle ;
997
998path tcircle, bcircle, lcircle, rcircle ;
999
1000tcircle := origin -- (+.5,0) & (+.5,0) {up} .. (0,+.5) .. {down} (-.5,0) -- cycle ;
1001bcircle := origin -- (-.5,0) & (-.5,0) {down} .. (0,-.5) .. {up} (+.5,0) -- cycle ;
1002lcircle := origin -- (0,+.5) & (0,+.5) {left} .. (-.5,0) .. {right} (0,-.5) -- cycle ;
1003rcircle := origin -- (0,-.5) & (0,-.5) {right} .. (+.5,0) .. {left} (0,+.5) -- cycle ;
1004
1005path urtriangle, ultriangle, lltriangle, lrtriangle ;
1006
1007urtriangle := origin -- (+.5,0) -- (0,+.5) -- cycle ;
1008ultriangle := origin -- (0,+.5) -- (-.5,0) -- cycle ;
1009lltriangle := origin -- (-.5,0) -- (0,-.5) -- cycle ;
1010lrtriangle := origin -- (0,-.5) -- (+.5,0) -- cycle ;
1011
1012path triangle, uptriangle, downtriangle, lefttriangle, righttriangle ;
1013
1014triangle := (1,0) -- (1,0) rotated 120 -- (1,0) rotated -120 -- cycle ;
1015
1016uptriangle := triangle rotated 90 ;
1017downtriangle := triangle rotated -90 ;
1018lefttriangle := triangle rotated 180 ;
1019righttriangle := triangle ;
1020
1021path unitdiamond, fulldiamond ;
1022
1023unitdiamond := (.5,0) -- (1,.5) -- (.5,1) -- (0,.5) -- cycle ;
1024fulldiamond := unitdiamond shifted center unitdiamond ;
1025
1026path unitoctagon, fulloctagon ;
1027
1028unitoctagon := for i within (unitcircle rotated 452) : pathpoint -- endfor cycle ;
1029fulloctagon := unitoctagon shifted center unitoctagon ;
1030
1031path unithexagon, fullhexagon ;
1032
1033
1034fullhexagon := for i = 0 step 60 until 360 : .5 dir(i) -- endfor cycle ;
1035unithexagon := fullhexagon shifted (.5,.5) ;
1036
1037permanent
1038 fullsquare, unitcircle,
1039 urcircle, ulcircle, llcircle, lrcircle,
1040 tcircle, bcircle, lcircle, rcircle,
1041 urtriangle, ultriangle, lltriangle, lrtriangle,
1042 triangle, uptriangle, downtriangle, lefttriangle, righttriangle,
1043 unitdiamond, fulldiamond, unitoctagon, fulloctagon, unithexagon, fullhexagon ;
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073def set_grid(expr w, h, nx, ny) =
1074 boolean grid[][] ; boolean grid_full ;
1075 numeric grid_w, grid_h, grid_nx, grid_ny, grid_x, grid_y, grid_left ;
1076 grid_w := w ;
1077 grid_h := h ;
1078 grid_nx := nx ;
1079 grid_ny := ny ;
1080 grid_x := round(wgrid_nx) ;
1081 grid_y := round(hgrid_ny) ;
1082 grid_left := (1grid_x)(1grid_y) ;
1083 grid_full := false ;
1084 for i=0 upto grid_x :
1085 for j=0 upto grid_y :
1086 grid[i][j] := false ;
1087 endfor ;
1088 endfor ;
1089enddef ;
1090
1091vardef new_on_grid(expr grid_dx, grid_dy) =
1092 dx := grid_dx ;
1093 dy := grid_dy ;
1094 ddx := min(round(dxgrid_nx),grid_x) ;
1095 ddy := min(round(dygrid_ny),grid_y) ;
1096 if not grid_full and not grid[ddx][ddy] :
1097 grid[ddx][ddy] := true ;
1098 grid_left := grid_left-1 ;
1099 grid_full := (grid_left=0) ;
1100 true
1101 else :
1102 false
1103 fi
1104enddef ;
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114secondarydef p peepholed q =
1115 begingroup
1116 save start ; pair start ;
1117 start := point 0 of p ;
1118 if xpart start >= xpart center p :
1119 if ypart start >= ypart center p :
1120 urcorner q -- ulcorner q -- llcorner q -- lrcorner q --
1121 reverse p -- lrcorner q -- cycle
1122 else :
1123 lrcorner q -- urcorner q -- ulcorner q -- llcorner q --
1124 reverse p -- llcorner q -- cycle
1125 fi
1126 else :
1127 if ypart start > ypart center p :
1128 ulcorner q -- llcorner q -- lrcorner q -- urcorner q --
1129 reverse p -- urcorner q -- cycle
1130 else :
1131 llcorner q -- lrcorner q -- urcorner q -- ulcorner q --
1132 reverse p -- ulcorner q -- cycle
1133 fi
1134 fi
1135 endgroup
1136enddef ;
1137
1138newinternal boolean intersection_found ;
1139
1140secondarydef p intersection_point q =
1141 begingroup
1142 save temp_x, temp_y ;
1143 (temp_x,temp_y) = p intersectiontimes q ;
1144 if temp_x < 0 :
1145 intersection_found := false ;
1146 center p
1147 else :
1148 intersection_found := true ;
1149 .5[point temp_x of p, point temp_y of q]
1150 fi
1151 endgroup
1152enddef ;
1153
1154permanent intersection_found, intersection_point ;
1155
1156
1157
1158vardef tensecircle (expr width, height, offset) =
1159 (width2,height2) ... (0,height2offset) ...
1160 (width2,height2) ... (width2offset,0) ...
1161 (width2,height2) ... (0,height2offset) ...
1162 (width2,height2) ... (width2offset,0) ... cycle
1163enddef ;
1164
1165vardef roundedsquare (expr width, height, offset) =
1166 (offset,0) -- (widthoffset,0) {right} ..
1167 (width,offset) -- (width,heightoffset) {up} ..
1168 (widthoffset,height) -- (offset,height) {left} ..
1169 (0,heightoffset) -- (0,offset) {down} .. cycle
1170enddef ;
1171
1172vardef roundedsquarexy (expr width, height, dx, dy) =
1173 (dx,0) -- (widthdx,0) {right} ..
1174 (width,dy) -- (width,heightdy) {up} ..
1175 (widthdx,height) -- (dx,height) {left} ..
1176 (0,heightdy) -- (0,dy) {down} .. cycle
1177enddef ;
1178
1179permanent tensecircle, roundedsquare, roundedsquarexy ;
1180
1181
1182
1183def resolvedcolor(expr s) =
1184 .5white
1185enddef ;
1186
1187let normalwithcolor = withcolor ;
1188
1189def withcolor expr c =
1190 normalwithcolor if string c : resolvedcolor(c) else : c fi
1191enddef ;
1192
1193permanent resolvedcolor, normalwithcolor, withcolor ;
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221vardef colortype expr c =
1222 if cmykcolor c : cmykcolor
1223 elseif rgbcolor c : rgbcolor
1224 elseif numeric c : grayscale
1225 fi
1226enddef ;
1227
1228vardef whitecolor expr c =
1229 if cmykcolor c : (0,0,0,0)
1230 elseif rgbcolor c : (1,1,1)
1231 elseif numeric c : 1
1232 elseif string c : whitecolor resolvedcolor(c)
1233 fi
1234enddef ;
1235
1236vardef blackcolor expr c =
1237 if cmykcolor c : (0,0,0,1)
1238 elseif rgbcolor c : (0,0,0)
1239 elseif numeric c : 0
1240 elseif string c : blackcolor resolvedcolor(c)
1241 fi
1242enddef ;
1243
1244vardef complementary expr c =
1245 if cmykcolor c : (1,1,1,1) c
1246 elseif rgbcolor c : (1,1,1) c
1247 elseif pair c : (1,1) c
1248 elseif numeric c : 1 c
1249 elseif string c : complementary resolvedcolor(c)
1250 fi
1251enddef ;
1252
1253vardef complemented expr c =
1254 save m ;
1255 if cmykcolor c : m := max(cyanpart c, magentapart c, yellowpart c, blackpart c) ;
1256 (m,m,m,m) c
1257 elseif rgbcolor c : m := max(redpart c, greenpart c, bluepart c) ;
1258 (m,m,m) c
1259 elseif pair c : m := max(xpart c, ypart c) ;
1260 (m,m) c
1261 elseif numeric c : m c
1262 elseif string c : complemented resolvedcolor(c)
1263 fi
1264enddef ;
1265
1266permanent colortype, whitecolor, blackcolor, complementary, complemented ;
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278def drawfill expr c =
1279 path temp_c ; temp_c := c ;
1280 mfun_do_drawfill
1281enddef ;
1282
1283def mfun_do_drawfill text t =
1284 draw temp_c t ;
1285 fill temp_c t ;
1286enddef;
1287
1288def undrawfill expr c =
1289 drawfill c withcolor background
1290enddef ;
1291
1292permanent drawfill, undrawfill ;
1293
1294
1295
1296vardef paired primary d =
1297 if pair d : d else : (d,d) fi
1298enddef ;
1299
1300vardef tripled primary d =
1301 if color d : d else : (d,d,d) fi
1302enddef ;
1303
1304permanent paired, tripled ;
1305
1306
1307
1308primarydef p enlarged d = ( p llmoved d -- p lrmoved d -- p urmoved d -- p ulmoved d -- cycle ) enddef ;
1309primarydef p llenlarged d = ( p llmoved d -- lrcorner p -- urcorner p -- ulcorner p -- cycle ) enddef ;
1310primarydef p lrenlarged d = ( llcorner p -- p lrmoved d -- urcorner p -- ulcorner p -- cycle ) enddef ;
1311primarydef p urenlarged d = ( llcorner p -- lrcorner p -- p urmoved d -- ulcorner p -- cycle ) enddef ;
1312primarydef p ulenlarged d = ( llcorner p -- lrcorner p -- urcorner p -- p ulmoved d -- cycle ) enddef ;
1313
1314primarydef p llmoved d = ( (llcorner p) shifted (xpart paired(d),ypart paired(d)) ) enddef ;
1315primarydef p lrmoved d = ( (lrcorner p) shifted (xpart paired(d),ypart paired(d)) ) enddef ;
1316primarydef p urmoved d = ( (urcorner p) shifted (xpart paired(d),ypart paired(d)) ) enddef ;
1317primarydef p ulmoved d = ( (ulcorner p) shifted (xpart paired(d),ypart paired(d)) ) enddef ;
1318
1319primarydef p leftenlarged d = ( (llcorner p) shifted (d,0) -- lrcorner p -- urcorner p -- (ulcorner p) shifted (d,0) -- cycle ) enddef ;
1320primarydef p rightenlarged d = ( llcorner p -- (lrcorner p) shifted (d,0) -- (urcorner p) shifted (d,0) -- ulcorner p -- cycle ) enddef ;
1321primarydef p topenlarged d = ( llcorner p -- lrcorner p -- (urcorner p) shifted (0,d) -- (ulcorner p) shifted (0,d) -- cycle ) enddef ;
1322primarydef p bottomenlarged d = ( llcorner p shifted (0,d) -- lrcorner p shifted (0,d) -- urcorner p -- ulcorner p -- cycle ) enddef ;
1323
1324
1325permanent
1326 enlarged, llenlarged, lrenlarged, urenlarged, ulenlarged,
1327 llmoved, lrmoved, urmoved, ulmoved,
1328 leftenlarged, rightenlarged, topenlarged, bottomenlarged ;
1329
1330
1331
1332vardef rotation(expr i, n) =
1333 if (n == 0) : 0 else : i 360 n fi
1334enddef ;
1335
1336
1337permanent rotation ;
1338
1339
1340
1341primarydef p crossed d = (
1342 if pair p :
1343 p shifted (d, 0) -- p --
1344 p shifted ( 0,d) -- p --
1345 p shifted (d, 0) -- p --
1346 p shifted ( 0,d) -- p -- cycle
1347 else :
1348 center p shifted (d, 0) -- llcorner p --
1349 center p shifted ( 0,d) -- lrcorner p --
1350 center p shifted (d, 0) -- urcorner p --
1351 center p shifted ( 0,d) -- ulcorner p -- cycle
1352 fi
1353) enddef ;
1354
1355
1356
1357
1358
1359
1360
1361
1362vardef laddered primary p =
1363 save a; pair a ; a := point 0 of p ; a --
1364 for i within p :
1365 if i > 0 : (xpart pathpoint, ypart a) -- pathpoint -- fi
1366 hide(a := pathpoint)
1367 endfor
1368 if cycle p :
1369 (xpart point 0 of p, ypart a) -- point 0 of p -- cycle
1370 else :
1371 nocycle
1372 fi
1373enddef ;
1374
1375permanent crossed, laddered ;
1376
1377
1378
1379
1380
1381
1382
1383
1384vardef bottomboundary primary p = if pair p : p else : (llcorner p -- lrcorner p) fi enddef ;
1385vardef rightboundary primary p = if pair p : p else : (lrcorner p -- urcorner p) fi enddef ;
1386vardef topboundary primary p = if pair p : p else : (urcorner p -- ulcorner p) fi enddef ;
1387vardef leftboundary primary p = if pair p : p else : (ulcorner p -- llcorner p) fi enddef ;
1388
1389permanent bottomboundary, rightboundary, topboundary, leftboundary ;
1390
1391
1392
1393primarydef p superellipsed s =
1394 superellipse (
1395 .5[lrcorner p,urcorner p],
1396 .5[urcorner p,ulcorner p],
1397 .5[ulcorner p,llcorner p],
1398 .5[llcorner p,lrcorner p],
1399 s
1400 )
1401enddef ;
1402
1403primarydef p squeezed s = (
1404 (llcorner p .. .5[llcorner p,lrcorner p] shifted ( 0, ypart paired(s)) .. lrcorner p) &
1405 (lrcorner p .. .5[lrcorner p,urcorner p] shifted (xpart paired(s), 0) .. urcorner p) &
1406 (urcorner p .. .5[urcorner p,ulcorner p] shifted ( 0,ypart paired(s)) .. ulcorner p) &
1407 (ulcorner p .. .5[ulcorner p,llcorner p] shifted ( xpart paired(s), 0) .. llcorner p) & cycle
1408) enddef ;
1409
1410primarydef p randomshifted s =
1411 begingroup ;
1412 save ss ; pair ss ;
1413 ss := paired(s) ;
1414 p shifted (-.5xpart ss uniformdeviate xpart ss,-.5ypart ss uniformdeviate ypart ss)
1415 endgroup
1416enddef ;
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434vardef mfun_randomized_path(expr p,s) =
1435 save r, oldr, newr, firstr, l ; pair r, oldr, newr, firstr ;
1436 r := paired(s) ;
1437 l := length(p) ;
1438 newr := (-12uniformdeviate(1),-12uniformdeviate(1)) xyscaled r ;
1439 firstr := newr ;
1440 for i within p :
1441 hide (
1442 oldr := newr ;
1443 newr := (-12uniformdeviate(1),-12uniformdeviate(1)) xyscaled r ;
1444 )
1445 pathpoint ..
1446 controls (pathpostcontrol shifted oldr )
1447 and ((deltaprecontrol 1) shifted if (i <> l 1) : newr else : firstr fi) ..
1448 endfor if cycle p : cycle else : nocycle fi
1449enddef ;
1450
1451
1452vardef mfun_randomrotated_path(expr p, s) =
1453 save r, oldr, newr, firstr, l ;
1454 l := length(p) ;
1455 newr := (-12uniformdeviate(1))s ;
1456 firstr := newr ;
1457 for i within p :
1458 hide (
1459 oldr := newr ;
1460 newr := (-12uniformdeviate(1)) s ;
1461 )
1462 pathpoint ..
1463 controls (pathpostcontrol rotatedaround(pathpoint, oldr) )
1464 and ((deltaprecontrol 1) rotatedaround(deltapoint 1, if (i <> l 1) : newr else : firstr fi)) ..
1465 endfor if cycle p : cycle else : nocycle fi
1466enddef ;
1467
1468vardef mfun_randomized_picture(expr p,s)(text rnd) =
1469 save currentpicture ;
1470 picture currentpicture ;
1471 currentpicture := nullpicture ;
1472 for i within p :
1473 addto currentpicture
1474 if stroked i :
1475 doublepath pathpart i rnd s
1476 dashed dashpart i
1477 withpen penpart i
1478 withcolor colorpart i
1479 withprescript prescriptpart i
1480 withpostscript postscriptpart i
1481 elseif filled i :
1482 contour pathpart i rnd s
1483 withpen penpart i
1484 withcolor colorpart i
1485 withprescript prescriptpart i
1486 withpostscript postscriptpart i
1487 else :
1488 also i
1489 fi
1490 ;
1491 endfor ;
1492 currentpicture
1493enddef ;
1494
1495primarydef p randomizedcontrols s = (
1496 if path p :
1497 mfun_randomized_path(p,s)
1498 elseif picture p :
1499 mfun_randomized_picture(p,s)(randomizedcontrols)
1500 else :
1501 p randomized s
1502 fi
1503) enddef ;
1504
1505primarydef p randomrotatedcontrols s = (
1506 if path p :
1507 mfun_randomrotated_path(p,s)
1508 elseif picture p :
1509 mfun_randomized_picture(p,s)(randomrotatedcontrols)
1510 else :
1511 p randomized s
1512 fi
1513) enddef ;
1514
1515primarydef p randomized s = (
1516 if path p :
1517 for i=0 upto length(p)-1 :
1518 ((point i of p) randomshifted s) .. controls
1519 ((postcontrol i of p) randomshifted s) and
1520 ((precontrol (i+1) of p) randomshifted s) ..
1521 endfor
1522 if cycle p :
1523 cycle
1524 else :
1525 ((point length(p) of p) randomshifted s)
1526 fi
1527 elseif pair p :
1528 p randomshifted s
1529 elseif cmykcolor p :
1530 if cmykcolor s :
1531 ((uniformdeviate cyanpart s) cyanpart p,
1532 (uniformdeviate magentapart s) magentapart p,
1533 (uniformdeviate yellowpart s) yellowpart p,
1534 (uniformdeviate blackpart s) blackpart p)
1535 elseif pair s :
1536 ((xpart s (uniformdeviate (ypart s xpart s))) p)
1537 else :
1538 ((uniformdeviate s) p)
1539 fi
1540 elseif rgbcolor p :
1541 if rgbcolor s :
1542 ((uniformdeviate redpart s) redpart p,
1543 (uniformdeviate greenpart s) greenpart p,
1544 (uniformdeviate bluepart s) bluepart p)
1545 elseif pair s :
1546 ((xpart s (uniformdeviate (ypart s xpart s))) p)
1547 else :
1548 ((uniformdeviate s) p)
1549 fi
1550 elseif color p :
1551 if color s :
1552 ((uniformdeviate greypart s) greypart p)
1553 elseif pair s :
1554 ((xpart s (uniformdeviate (ypart s xpart s))) p)
1555 else :
1556 ((uniformdeviate s) p)
1557 fi
1558 elseif string p :
1559 (resolvedcolor(p)) randomized s
1560 elseif picture p :
1561 mfun_randomized_picture(p,s)(randomized)
1562 else :
1563
1564 p uniformdeviate s
1565 fi
1566) enddef ;
1567
1568permanent superellipsed, squeezed, randomshifted, randomized,
1569 randomizedcontrols, randomrotatedcontrols ;
1570
1571
1572
1573vardef interpolated(expr s, p, q) =
1574 save m ; numeric m ;
1575 m := max(length(p),length(q)) ;
1576 if path p :
1577 for i=0 upto m-1 :
1578 s[point (i m) along p,point (i m) along q] .. controls
1579 s[postcontrol (i m) along p,postcontrol (i m) along q] and
1580 s[precontrol ((i+1)m) along p,precontrol ((i+1)m) along q] ..
1581 endfor
1582 if cycle p :
1583 cycle
1584 else :
1585 s[point infinity of p,point infinity of q]
1586 fi
1587 else :
1588 a[p,q]
1589 fi
1590enddef ;
1591
1592permanent interpolated ;
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607def istextext(expr p) =
1608 (picture p and ((substring(0,3) of prescriptpart p) = "tx_"))
1609enddef ;
1610
1611vardef perpendicular expr t of p =
1612 unitvector((direction t of p) rotated 90)
1613enddef ;
1614
1615primarydef p paralleled d = (
1616 if path p :
1617 begingroup ;
1618 save dp ; pair dp ;
1619 for i=0 upto length p if cycle p : -1 fi :
1620 hide(dp := d perpendicular i of p)
1621 if i > 0 : .. fi
1622 (point i of p dp)
1623 if i < length p :
1624 .. controls (postcontrol i of p dp) and
1625 (precontrol (i+1) of p dp)
1626 fi
1627 endfor
1628 if cycle p : .. cycle fi
1629 endgroup
1630 elseif picture p :
1631 image(
1632 for i within p :
1633 draw (pathpart i)
1634 if not istextext(i) :
1635 paralleled d
1636 fi
1637 mfun_decoration_i i ;
1638 endfor ;
1639 )
1640 elseif pair p :
1641 p
1642 fi
1643) enddef ;
1644
1645vardef punked primary p =
1646 point 0 of p for i=1 upto length(p)-1 : -- point i of p endfor
1647 if cycle p : -- cycle else : -- point length(p) of p fi
1648enddef ;
1649
1650vardef curved primary p =
1651 point 0 of p for i=1 upto length(p)-1 : .. point i of p endfor
1652 if cycle p : .. cycle else : .. point length(p) of p fi
1653enddef ;
1654
1655primarydef p blownup s =
1656 begingroup
1657 save temp_p ; path temp_p ;
1658 temp_p := p xysized (bbwidth(p)+2(xpart paired(s)),bbheight(p)+2(ypart paired(s))) ;
1659 (temp_p shifted (center p center temp_p))
1660 endgroup
1661enddef ;
1662
1663permanent perpendicular, istextext, paralleled, punked, curved, blownup ;
1664
1665
1666
1667
1668
1669vardef mfun_left_right_path(expr p, l) =
1670 save q, r, t, b ; path q, r ; pair t, b ;
1671 t := (ulcorner p -- urcorner p) intersection_point p ;
1672 b := (llcorner p -- lrcorner p) intersection_point p ;
1673 r := if xpart directionpoint t of p < 0 : reverse p else : p fi ;
1674 q := r cutbefore if l: t else: b fi ;
1675 q := q if xpart point 0 of r > 0 : & r fi cutafter if l: b else: t fi ;
1676 q
1677enddef ;
1678
1679vardef leftpath expr p = mfun_left_right_path(p,true ) enddef ;
1680vardef rightpath expr p = mfun_left_right_path(p,false) enddef ;
1681
1682permanent leftpath, rightpath ;
1683
1684
1685
1686def saveoptions =
1687 save base_draw_options ; def base_draw_options = enddef ;
1688enddef ;
1689
1690permanent saveoptions ;
1691
1692
1693
1694let normaldraw = draw ;
1695let normalfill = fill ;
1696
1697
1698
1699def normalfill expr c = addto currentpicture contour c base_draw_options enddef ;
1700def normaldraw expr p = addto currentpicture if picture p: also p else: doublepath p withpen currentpen fi base_draw_options enddef ;
1701
1702def drawlineoptions (text t) = def mfun_opt_lin = t enddef ; enddef ;
1703def drawpointoptions (text t) = def mfun_opt_pnt = t enddef ; enddef ;
1704def drawcontroloptions(text t) = def mfun_opt_ctr = t enddef ; enddef ;
1705def drawlabeloptions (text t) = def mfun_opt_lab = t enddef ; enddef ;
1706def draworiginoptions (text t) = def mfun_opt_ori = t enddef ; enddef ;
1707def drawboundoptions (text t) = def mfun_opt_bnd = t enddef ; enddef ;
1708def drawpathoptions (text t) = def mfun_opt_pth = t enddef ; enddef ;
1709
1710numeric drawoptionsfactor ; drawoptionsfactor := pt ;
1711
1712def resetdrawoptions =
1713 drawlineoptions (withpen pencircle scaled 1.0 drawoptionsfactor withcolor .5white) ;
1714 drawpointoptions (withpen pencircle scaled 4.0 drawoptionsfactor withcolor black) ;
1715 drawcontroloptions(withpen pencircle scaled 2.5 drawoptionsfactor withcolor black) ;
1716 drawlabeloptions () ;
1717 draworiginoptions (withpen pencircle scaled 1.0 drawoptionsfactor withcolor .5white) ;
1718 drawboundoptions (dashed evenly mfun_opt_ori) ;
1719 drawpathoptions (withpen pencircle scaled 5.0 drawoptionsfactor withcolor .8white) ;
1720enddef ;
1721
1722resetdrawoptions ;
1723
1724
1725
1726def drawpath expr p =
1727 normaldraw p mfun_opt_pth
1728enddef ;
1729
1730permanent
1731 drawlineoptions, drawpointoptions, drawcontroloptions, drawlabeloptions, draworiginoptions,
1732 drawboundoptions, drawpathoptions, drawpath, normaldraw ;
1733
1734
1735
1736newinternal ahvariant ; ahvariant := 0 ;
1737newinternal ahdimple ; ahdimple := 15 ;
1738newinternal ahscale ; ahscale := 34 ;
1739
1740permanent ahvariant, ahdimple, ahscale ;
1741
1742vardef arrowhead expr p =
1743 save q, e, r ;
1744 pair e ; e = point length p of p ;
1745 path q ; q = gobble(p shifted e cutafter makepath(pencircle scaled (2ahlength))) cuttings ;
1746 if ahvariant > 0:
1747 path r ; r = gobble(p shifted e cutafter makepath(pencircle scaled ((1ahdimple)2ahlength))) cuttings ;
1748 fi
1749 (q rotated (ahangle2) & reverse q rotated (ahangle2)
1750 if ahvariant = 1 :
1751 -- point 0 of r --
1752 elseif ahvariant = 2 :
1753 ... point 0 of r ...
1754 else :
1755 --
1756 fi
1757 cycle
1758 ) shifted e
1759enddef ;
1760
1761vardef drawarrowpath expr p =
1762
1763 interim autoarrows := true ;
1764 drawarrow p mfun_opt_pth
1765enddef ;
1766
1767def midarrowhead expr p =
1768 arrowhead p cutafter (point length(p cutafter point .5 along p) ahlength on p)
1769enddef ;
1770
1771vardef arrowheadonpath (expr p, s) =
1772
1773 interim autoarrows := true ;
1774 set_ahlength(scaled ahfactor) ;
1775 arrowhead p if s < 1 : cutafter (point (sarclength(p) (ahlength2)) on p) fi
1776enddef ;
1777
1778def resetarrows =
1779 hide (
1780 ahlength := 4 ;
1781 ahangle := 45 ;
1782 ahvariant := 0 ;
1783 ahdimple := 15 ;
1784 ahscale := 34 ;
1785)
1786enddef ;
1787
1788permanent arrowhead, drawarrowpath, midarrowhead, arrowheadonpath ;
1789
1790
1791
1792vardef dotlabel@#(expr s,z) text t =
1793 label@#(s,z) t ;
1794 interim linecap := rounded ;
1795 normaldraw z withpen pencircle scaled dotlabeldiam t ;
1796enddef ;
1797
1798def drawpoint expr c =
1799 if string c :
1800 string temp_c ;
1801 temp_c := "(" & c & ")" ;
1802 dotlabel.urt(temp_c, scantokens temp_c) ;
1803 drawdot scantokens temp_c
1804 else :
1805 dotlabel.urt("(" & decimal xpart c & "," & decimal ypart c & ")", c) ;
1806 drawdot c
1807 fi mfun_opt_pnt
1808enddef ;
1809
1810
1811
1812def drawpoints expr c = path temp_c ; temp_c := c ; mfun_draw_points enddef ;
1813def drawcontrolpoints expr c = path temp_c ; temp_c := c ; mfun_draw_controlpoints enddef ;
1814def drawcontrollines expr c = path temp_c ; temp_c := c ; mfun_draw_controllines enddef ;
1815def drawpointlabels expr c = path temp_c ; temp_c := c ; mfun_draw_pointlabels enddef ;
1816
1817def mfun_draw_points text t =
1818 for i within temp_c :
1819 normaldraw pathpoint mfun_opt_pnt t ;
1820 endfor ;
1821enddef;
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837def mfun_draw_controlpoints text t =
1838 for i within temp_c :
1839 if (pathstate == 0) or (pathstate == 2) :
1840 normaldraw pathprecontrol t mfun_opt_ctr t ;
1841 fi ;
1842 if (pathstate == 0) or (pathstate == 1) :
1843 normaldraw pathpostcontrol t mfun_opt_ctr t ;
1844 fi ;
1845 endfor ;
1846enddef;
1847
1848def mfun_draw_controllines text t =
1849 for i within temp_c :
1850 if (pathstate == 0) or (pathstate == 2) :
1851 normaldraw pathpoint -- pathprecontrol t mfun_opt_lin t ;
1852 fi ;
1853 if (pathstate == 0) or (pathstate == 1) :
1854 normaldraw pathpoint -- pathpostcontrol t mfun_opt_lin t ;
1855 fi ;
1856 endfor ;
1857enddef;
1858
1859boolean swappointlabels ; swappointlabels := false ;
1860numeric pointlabelscale ; pointlabelscale := 0 ;
1861string pointlabelfont ; pointlabelfont := "" ;
1862
1863def mfun_draw_pointlabels text asked_options =
1864
1865 for i=0 upto length(temp_c) if cycle temp_c : -1 fi :
1866 pair temp_u ; temp_u := unitvector(direction i of temp_c) rotated if swappointlabels : fi 90 ;
1867 pair temp_p ; temp_p := (point i of temp_c) ;
1868 begingroup ;
1869 if pointlabelscale > 0 :
1870 save defaultscale ; numeric defaultscale ;
1871 defaultscale := pointlabelscale ;
1872 fi ;
1873 if pointlabelfont <> "" :
1874 save defaultfont ; string defaultfont ;
1875 defaultfont := pointlabelfont ;
1876 fi ;
1877 temp_u := 10 drawoptionsfactor defaultscale temp_u ;
1878 normaldraw thelabel ( decimal i, temp_p shifted if cycle temp_c and (i=0) : fi temp_u ) mfun_opt_lab asked_options ;
1879 endgroup ;
1880 endfor ;
1881enddef;
1882
1883
1884
1885def drawboundingbox expr p =
1886 normaldraw boundingbox p mfun_opt_bnd
1887enddef ;
1888
1889
1890
1891numeric originlength ; originlength := .5cm ;
1892
1893def draworigin text t =
1894 normaldraw (origin shifted (0, originlength) -- origin shifted (0,originlength)) mfun_opt_ori t ;
1895 normaldraw (origin shifted ( originlength,0) -- origin shifted (originlength,0)) mfun_opt_ori t ;
1896enddef;
1897
1898permanent dotlabel, swappointlabels, pointlabelscale, pointlabelfont ;
1899permanent drawboundingbox, drawpoints, drawcontrolpoints, drawcontrollines, drawpointlabels, draworigin ;
1900
1901
1902
1903numeric tickstep ; tickstep := 5mm ;
1904numeric ticklength ; ticklength := 2mm ;
1905
1906def drawxticks expr c = path temp_c ; temp_c := c ; mfun_draw_xticks enddef ;
1907def drawyticks expr c = path temp_c ; temp_c := c ; mfun_draw_yticks enddef ;
1908def drawticks expr c = path temp_c ; temp_c := c ; mfun_draw_ticks enddef ;
1909
1910
1911
1912def mfun_draw_xticks text t =
1913 for i=0 step tickstep until xpart llcorner temp_c eps :
1914 if (i<=xpart lrcorner temp_c) :
1915 normaldraw (i,ticklength)--(i,ticklength) mfun_opt_ori t ;
1916 fi ;
1917 endfor ;
1918 for i=0 step tickstep until xpart lrcorner temp_c eps :
1919 if (i>=xpart llcorner temp_c) :
1920 normaldraw (i,ticklength)--(i,ticklength) mfun_opt_ori t ;
1921 fi ;
1922 endfor ;
1923 normaldraw (llcorner temp_c -- ulcorner temp_c) shifted (xpart llcorner temp_c,0) mfun_opt_ori t ;
1924enddef ;
1925
1926def mfun_draw_yticks text t =
1927 for i=0 step tickstep until ypart llcorner temp_c eps :
1928 if (i<=ypart ulcorner temp_c) :
1929 normaldraw (ticklength,i)--(ticklength,i) mfun_opt_ori t ;
1930 fi ;
1931 endfor ;
1932 for i=0 step tickstep until ypart ulcorner temp_c eps :
1933 if (i>=ypart llcorner temp_c) :
1934 normaldraw (ticklength,i)--(ticklength,i) mfun_opt_ori t ;
1935 fi ;
1936 endfor ;
1937 normaldraw (llcorner temp_c -- lrcorner temp_c) shifted (0,ypart llcorner temp_c) mfun_opt_ori t ;
1938enddef ;
1939
1940def mfun_draw_ticks text t =
1941 drawxticks temp_c t ;
1942 drawyticks temp_c t ;
1943enddef ;
1944
1945
1946
1947def drawwholepath expr p =
1948 draworigin ;
1949 drawpath p ;
1950 drawcontrollines p ;
1951 drawcontrolpoints p ;
1952 drawpoints p ;
1953 drawboundingbox p ;
1954 drawpointlabels p ;
1955enddef ;
1956
1957def drawpathonly expr p =
1958 drawpath p ;
1959 drawcontrollines p ;
1960 drawcontrolpoints p ;
1961 drawpoints p ;
1962 drawpointlabels p ;
1963enddef ;
1964
1965
1966
1967def visualizeddraw expr c =
1968 if picture c : normaldraw c else : path temp_c ; temp_c := c ; do_visualizeddraw fi
1969enddef ;
1970
1971def visualizedfill expr c =
1972 if picture c : normalfill c else : path temp_c ; temp_c := c ; do_visualizedfill fi
1973enddef ;
1974
1975def do_visualizeddraw text t =
1976 draworigin ;
1977 drawpath temp_c t ;
1978 drawcontrollines temp_c ;
1979 drawcontrolpoints temp_c ;
1980 drawpoints temp_c ;
1981 drawboundingbox temp_c ;
1982 drawpointlabels temp_c ;
1983enddef ;
1984
1985def do_visualizedfill text t =
1986 if cycle temp_c : normalfill temp_c t fi ;
1987 draworigin ;
1988 drawcontrollines temp_c ;
1989 drawcontrolpoints temp_c ;
1990 drawpoints temp_c ;
1991 drawboundingbox temp_c ;
1992 drawpointlabels temp_c ;
1993enddef ;
1994
1995def detaileddraw expr c =
1996 if picture c : normaldraw c else : path temp_c ; temp_c := c ; do_detaileddraw fi
1997enddef ;
1998
1999def do_detaileddraw text t =
2000 drawpath temp_c t ;
2001 drawcontrollines temp_c ;
2002 drawcontrolpoints temp_c ;
2003 drawpoints temp_c ;
2004
2005
2006
2007enddef ;
2008
2009def visualizepaths =
2010 let fill = visualizedfill ;
2011 let draw = visualizeddraw ;
2012enddef ;
2013
2014def detailpaths =
2015 let draw = detaileddraw ;
2016enddef ;
2017
2018def naturalizepaths =
2019 let fill = normalfill ;
2020 let draw = normaldraw ;
2021enddef ;
2022
2023extra_endfig := extra_endfig & " naturalizepaths ; " ;
2024
2025permanent
2026 visualizeddraw, detaileddraw, visualizedfill,
2027 visualizepaths, detailpaths, naturalizepaths ;
2028
2029
2030
2031def drawboundary primary p =
2032 draw p dashed evenly withcolor white ;
2033 draw p dashed oddly withcolor black ;
2034 draw ( llcorner p) withpen pencircle scaled 3 withcolor white ;
2035 draw ( llcorner p) withpen pencircle scaled 1.5 withcolor black ;
2036enddef ;
2037
2038permanent drawboundary ;
2039
2040
2041
2042extra_beginfig := extra_beginfig & " truecorners := 0 ; " ;
2043extra_beginfig := extra_beginfig & " miterlimit := 10 ; " ;
2044extra_beginfig := extra_beginfig & " linejoin := rounded ; " ;
2045extra_beginfig := extra_beginfig & " linecap := rounded ; " ;
2046
2047
2048
2049
2050numeric ahfactor ; ahfactor := 2.5 ;
2051
2052newinternal boolean autoarrows ;
2053
2054permanent ahfactor, ahlength, autoarrows ;
2055
2056def set_ahlength (text t) =
2057
2058
2059
2060 ahlength := (ahfactorpen_size(t)) ;
2061enddef ;
2062
2063vardef pen_size (text t) =
2064 save p ; picture p ; p := nullpicture ;
2065 addto p doublepath (top origin -- bot origin) t ;
2066 (ypart urcorner p ypart lrcorner p)
2067enddef ;
2068
2069
2070
2071
2072vardef arrowpath expr p =
2073 (p cutafter makepath(pencircle
2074 scaled (if ahvariant > 0 : (1ahdimple) fi 2ahlengthcosd(ahangle2))
2075 shifted point length p of p
2076 ))
2077enddef;
2078
2079permanent arrowpath ;
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097vardef stroked_paths(expr p) =
2098 save n ; numeric n ; n := 0 ;
2099 for i within p :
2100 if stroked i :
2101 n := n 1 ;
2102 fi
2103 endfor ;
2104 n
2105enddef ;
2106
2107def mfun_decoration_i expr i =
2108 withpen penpart i
2109 withcolor colorpart i
2110 withprescript prescriptpart i
2111 withpostscript postscriptpart i
2112enddef ;
2113
2114
2115
2116
2117numeric mfun_arrow_snippets ;
2118numeric mfun_arrow_count ;
2119
2120def drawarrow expr p =
2121 begingroup ;
2122 save mfun_arrow_path ;
2123 path mfun_arrow_path ;
2124 if path p :
2125 mfun_arrow_path := p ;
2126 expandafter mfun_draw_arrow_path
2127 elseif picture p :
2128 save mfun_arrow_picture ;
2129 picture mfun_arrow_picture ;
2130 mfun_arrow_picture := p ;
2131 expandafter mfun_draw_arrow_picture
2132 else :
2133 expandafter mfun_draw_arrow_nothing
2134 fi
2135enddef ;
2136
2137def drawdblarrow expr p =
2138 begingroup ;
2139 save mfun_arrow_path ;
2140 path mfun_arrow_path ;
2141 if path p :
2142 mfun_arrow_path := p ;
2143 expandafter mfun_draw_arrow_path_double
2144 elseif picture p :
2145 save mfun_arrow_picture ;
2146 picture mfun_arrow_picture ;
2147 mfun_arrow_picture := p ;
2148 expandafter mfun_draw_arrow_picture_double
2149 else :
2150 expandafter mfun_draw_arrow_nothing
2151 fi
2152enddef ;
2153
2154def mfun_draw_arrow_nothing text t =
2155enddef ;
2156
2157
2158
2159
2160def mfun_draw_arrow_path text t =
2161 if autoarrows :
2162 set_ahlength(t) ;
2163 fi
2164 draw arrowpath mfun_arrow_path t ;
2165 fillup arrowhead mfun_arrow_path t ;
2166 endgroup ;
2167enddef ;
2168
2169def mfun_draw_arrow_path_double text t =
2170 if autoarrows :
2171 set_ahlength(t) ;
2172 fi
2173 draw arrowpath (reverse arrowpath mfun_arrow_path) t ;
2174 fillup arrowhead mfun_arrow_path t ;
2175 fillup arrowhead reverse mfun_arrow_path t ;
2176 endgroup ;
2177enddef ;
2178
2179
2180
2181
2182
2183def mfun_with_arrow_picture (text t) =
2184 mfun_arrow_count := 0 ;
2185 mfun_arrow_snippets := stroked_paths(mfun_arrow_picture) ;
2186 for i within mfun_arrow_picture :
2187 if istextext(i) :
2188 draw i
2189 else :
2190 mfun_arrow_count := mfun_arrow_count 1 ;
2191 mfun_arrow_path := pathpart i ;
2192 t
2193 fi ;
2194 endfor ;
2195enddef ;
2196
2197def mfun_draw_arrow_picture text t =
2198 if autoarrows :
2199 set_ahlength(t) ;
2200 fi
2201 mfun_with_arrow_picture (
2202 if mfun_arrow_count = mfun_arrow_snippets :
2203 draw arrowpath mfun_arrow_path mfun_decoration_i i t ;
2204 fillup arrowhead mfun_arrow_path mfun_decoration_i i t ;
2205 else :
2206 draw mfun_arrow_path mfun_decoration_i i t ;
2207 fi ;
2208 )
2209 endgroup ;
2210enddef ;
2211
2212def mfun_draw_arrow_picture_double text t =
2213 if autoarrows :
2214 set_ahlength(t) ;
2215 fi
2216 mfun_with_arrow_picture (
2217 draw
2218 if mfun_arrow_count = 1 :
2219 arrowpath reverse
2220 elseif mfun_arrow_count = mfun_arrow_snippets :
2221 arrowpath
2222 fi
2223 mfun_arrow_path mfun_decoration_i i t ;
2224 if mfun_arrow_count = 1 :
2225 fillup arrowhead reverse mfun_arrow_path mfun_decoration_i i t ;
2226 fi
2227 if mfun_arrow_count = mfun_arrow_snippets :
2228 fillup arrowhead mfun_arrow_path mfun_decoration_i i t ;
2229 fi
2230 )
2231 endgroup ;
2232enddef ;
2233
2234
2235
2236let drawdoublearrow = drawdblarrow ;
2237
2238def drawdoublearrows expr p =
2239 begingroup ;
2240 save mfun_arrow_path ;
2241 path mfun_arrow_path ;
2242 save mfun_arrow_path_parallel ;
2243 path mfun_arrow_path_parallel ;
2244 if path p :
2245 mfun_arrow_path := p ;
2246 expandafter mfun_draw_arrow_paths
2247 elseif picture p :
2248 save mfun_arrow_picture ;
2249 picture mfun_arrow_picture ;
2250 mfun_arrow_picture := p ;
2251 expandafter mfun_draw_arrow_pictures
2252 else :
2253 expandafter mfun_draw_arrow_nothing
2254 fi
2255enddef ;
2256
2257def mfun_draw_arrow_paths text t =
2258 if autoarrows :
2259 set_ahlength(t) ;
2260 fi
2261 save d ; d := ahscaleahlengthsind(ahangle2) ;
2262 mfun_arrow_path_parallel := mfun_arrow_path paralleled d ;
2263 draw arrowpath mfun_arrow_path_parallel t ;
2264 fillup arrowhead mfun_arrow_path_parallel t ;
2265 mfun_arrow_path_parallel := (reverse mfun_arrow_path) paralleled d ;
2266 draw arrowpath mfun_arrow_path_parallel t ;
2267 fillup arrowhead mfun_arrow_path_parallel t ;
2268 endgroup ;
2269enddef ;
2270
2271def mfun_draw_arrow_pictures text t =
2272 if autoarrows :
2273 set_ahlength(t) ;
2274 fi
2275 save d ; d := ahscaleahlengthsind(ahangle2) ;
2276 mfun_with_arrow_picture(
2277 if mfun_arrow_count = 1 :
2278 draw (mfun_arrow_path paralleled d) mfun_decoration_i i t ;
2279 mfun_arrow_path_parallel := (reverse mfun_arrow_path) paralleled d ;
2280 draw arrowpath mfun_arrow_path_parallel mfun_decoration_i i t ;
2281 fillup arrowhead mfun_arrow_path_parallel mfun_decoration_i i t ;
2282 elseif mfun_arrow_count = mfun_arrow_snippets :
2283 draw ((reverse mfun_arrow_path) paralleled d) mfun_decoration_i i t ;
2284 mfun_arrow_path_parallel := mfun_arrow_path paralleled d ;
2285 draw arrowpath mfun_arrow_path_parallel mfun_decoration_i i t ;
2286 fillup arrowhead mfun_arrow_path_parallel mfun_decoration_i i t ;
2287 else :
2288 draw ( mfun_arrow_path paralleled d) mfun_decoration_i i t ;
2289 draw ((reverse mfun_arrow_path) paralleled d) mfun_decoration_i i t ;
2290 fi
2291 )
2292 endgroup ;
2293enddef ;
2294
2295
2296
2297vardef pointarrow (expr pat, loc, len, off) =
2298 save l, r, s, t ; path l, r ; numeric s ; pair t ;
2299 t := if pair loc : loc else : point loc along pat fi ;
2300 s := len2 off ; if s<=0 : s := 0 elseif s>len : s := len fi ;
2301 r := pat cutbefore t ;
2302 r := (r cutafter point (arctime s of r) of r) ;
2303 s := len2 off ; if s<=0 : s := 0 elseif s>len : s := len fi ;
2304 l := reverse (pat cutafter t) ;
2305 l := (reverse (l cutafter point (arctime s of l) of l)) ;
2306 (l..r)
2307enddef ;
2308
2309def rightarrow (expr pat,tim,len) = pointarrow(pat,tim,len,len) enddef ;
2310def leftarrow (expr pat,tim,len) = pointarrow(pat,tim,len,len) enddef ;
2311def centerarrow (expr pat,tim,len) = pointarrow(pat,tim,len, 0) enddef ;
2312
2313permanent drawarrow, drawdblarrow, drawdoublearrows, drawdoublearrow, pointarrow, rightarrow, leftarrow, centerarrow ;
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324primarydef pct along pat =
2325 (arctime (pct (arclength pat)) of pat) of pat
2326enddef ;
2327
2328primarydef len on pat =
2329 (arctime if len>=0 : len else : (arclength(pat)len) fi of pat) of pat
2330enddef ;
2331
2332
2333
2334tertiarydef pat cutends len =
2335 begingroup
2336 save tap ; path tap ;
2337 tap := pat cutbefore (point (xpart paired(len)) on pat) ;
2338 (tap cutafter (point (ypart paired(len)) on tap))
2339 endgroup
2340enddef ;
2341
2342permanent along, on, cutends ;
2343
2344
2345
2346path freesquare ; freesquare := (
2347 (-1,0) -- (-1,-1) -- (0,-1) -- (+1,-1) --
2348 (+1,0) -- (+1,+1) -- (0,+1) -- (-1,+1) -- cycle
2349) scaled .5 ;
2350
2351numeric freelabeloffset ; freelabeloffset := 3pt ;
2352numeric freedotlabelsize ; freedotlabelsize := 3pt ;
2353
2354vardef thefreelabel (expr asked_text, asked_location, asked_origin) =
2355 save s, p, q, l ; picture s ; path p, q ; pair l ;
2356 interim labeloffset := freelabeloffset ;
2357 s := if string asked_text : thelabel(asked_text,asked_location) else : asked_text shifted center asked_text shifted asked_location fi ;
2358 setbounds s to boundingbox s enlarged freelabeloffset ;
2359 p := fullcircle scaled (2length(asked_locationasked_origin)) shifted asked_origin ;
2360 q := freesquare xyscaled (urcorner s llcorner s) ;
2361 l := point xpart (p intersectiontimes (asked_originasked_location shifted (asked_locationasked_origin))) of q ;
2362 setbounds s to boundingbox s enlarged freelabeloffset ;
2363
2364 (s shifted l)
2365enddef ;
2366
2367vardef freelabel (expr asked_text, asked_location, asked_origin) =
2368 draw thefreelabel(asked_text,asked_location,asked_origin) ;
2369enddef ;
2370
2371vardef freedotlabel (expr asked_text, asked_location, asked_origin) =
2372 interim linecap := rounded ;
2373 draw asked_location withpen pencircle scaled freedotlabelsize ;
2374 draw thefreelabel(asked_text,asked_location,asked_origin) ;
2375enddef ;
2376
2377immutable freesquare ;
2378permanent freelabeloffset, freedotlabelsize, thefreelabel, freelabel, freedotlabel ;
2379
2380
2381
2382
2383
2384newinternal angleoffset ; angleoffset := 0pt ;
2385newinternal anglelength ; anglelength := 20pt ;
2386newinternal anglemethod ; anglemethod := 1 ;
2387
2388vardef anglebetween (expr a, b, s) =
2389 save pointa, pointb, common, middle, offset ;
2390 pair pointa, pointb, common, middle, offset ;
2391 save curve ; path curve ;
2392 save where ; numeric where ;
2393 if round point 0 of a = round point 0 of b :
2394 common := point 0 of a ;
2395 else :
2396 common := a intersectionpoint b ;
2397 fi ;
2398 pointa := point anglelength on a ;
2399 pointb := point anglelength on b ;
2400 where := turningnumber (commonpointapointbcycle) ;
2401 middle := (reverse(commonpointa) rotatedaround (pointa,where90))
2402 intersection_point
2403 (reverse(commonpointb) rotatedaround (pointb, where90)) ;
2404 if not intersection_found :
2405 middle := point .5 along
2406 ((reverse(commonpointa) rotatedaround (pointa,where90)) --
2407 ( (commonpointb) rotatedaround (pointb, where90))) ;
2408 fi ;
2409 if anglemethod = 0 :
2410 curve := pointa{unitvector(middlepointa)}.. pointb;
2411 middle := point .5 along curve ;
2412 curve := common ;
2413 elseif anglemethod = 1 :
2414 curve := pointa{unitvector(middlepointa)}.. pointb;
2415 middle := point .5 along curve ;
2416 elseif anglemethod = 2 :
2417 middle := common rotatedaround(.5[pointa,pointb],180) ;
2418 curve := pointamiddlepointb ;
2419 elseif anglemethod = 3 :
2420 curve := pointamiddlepointb ;
2421 elseif anglemethod = 4 :
2422 curve := pointa..controls middle..pointb ;
2423 middle := point .5 along curve ;
2424 fi ;
2425 draw thefreelabel(s, middle, common) ;
2426 curve
2427enddef ;
2428
2429permanent anglebetween, angleoffset, anglelength, anglemethod ;
2430
2431
2432
2433picture mfun_current_picture_stack[] ;
2434numeric mfun_current_picture_depth ;
2435
2436mfun_current_picture_depth := 0 ;
2437
2438def pushcurrentpicture =
2439 mfun_current_picture_depth := mfun_current_picture_depth 1 ;
2440 mfun_current_picture_stack[mfun_current_picture_depth] := currentpicture ;
2441 currentpicture := nullpicture ;
2442enddef ;
2443
2444def popcurrentpicture text t =
2445 if mfun_current_picture_depth > 0 :
2446 addto mfun_current_picture_stack[mfun_current_picture_depth] also currentpicture t ;
2447 currentpicture := mfun_current_picture_stack[mfun_current_picture_depth] ;
2448 mfun_current_picture_stack[mfun_current_picture_depth] := nullpicture ;
2449 mfun_current_picture_depth := mfun_current_picture_depth 1 ;
2450 fi ;
2451enddef ;
2452
2453permanent pushcurrentpicture, popcurrentpicture ;
2454
2455
2456
2457vardef penpoint expr pnt of p =
2458 save n, d ; numeric n, d ;
2459 (n,d) = if pair pnt : pnt else : (pnt,1) fi ;
2460 (point n of p shifted ((penoffset direction n of p of currentpen) scaled d))
2461enddef ;
2462
2463permanent penpoint ;
2464
2465
2466
2467vardef colorcircle (expr size, red, green, blue) =
2468 save r, g, b, c, m, y, w ; save radius ;
2469 path r, g, b, c, m, y, w ; numeric radius ;
2470
2471 radius := 5cm ; pickup pencircle scaled (radius25) ;
2472
2473 transform t ; t := identity rotatedaround(origin,120) ;
2474
2475 r := fullcircle rotated 90 scaled radius shifted (0,radius4) rotatedaround(origin,135) ;
2476
2477 b := r transformed t ; g := b transformed t ;
2478
2479 c := buildcycle(subpath(1,7) of g,subpath(1,7) of b) ;
2480 y := c transformed t ; m := y transformed t ;
2481
2482 w := buildcycle(subpath(3,5) of r, subpath(3,5) of g,subpath(3,5) of b) ;
2483
2484 pushcurrentpicture ;
2485
2486 fill r withcolor red ;
2487 fill g withcolor green ;
2488 fill b withcolor blue ;
2489 fill c withcolor white red ;
2490 fill m withcolor white green ;
2491 fill y withcolor white blue ;
2492 fill w withcolor white ;
2493
2494 for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
2495
2496 currentpicture := currentpicture xsized size ;
2497
2498 popcurrentpicture ;
2499enddef ;
2500
2501
2502
2503primarydef p uncolored c =
2504 if color p :
2505 c p
2506 else :
2507 image (
2508 for i within p :
2509 addto currentpicture
2510 if stroked i or filled i :
2511 if filled i :
2512 contour
2513 else :
2514 doublepath
2515 fi
2516 pathpart i
2517 dashed dashpart i withpen penpart i
2518 else :
2519 also i
2520 fi
2521 withcolor c(redpart i, greenpart i, bluepart i) ;
2522 endfor ;
2523 )
2524 fi
2525enddef ;
2526
2527vardef inverted primary p =
2528 p uncolored white
2529enddef ;
2530
2531primarydef p softened c =
2532 begingroup
2533 save cc ; color cc ; cc := tripled(c) ;
2534 if color p :
2535 (redpart cc redpart p,greenpart cc greenpart p, bluepart cc bluepart p)
2536 else :
2537 image (
2538 for i within p :
2539 addto currentpicture
2540 if stroked i or filled i :
2541 if filled i :
2542 contour
2543 else :
2544 doublepath
2545 fi
2546 pathpart i
2547 dashed dashpart i withpen penpart i
2548 else :
2549 also i
2550 fi
2551 withcolor (redpart cc redpart i, greenpart cc greenpart i, bluepart cc bluepart i) ;
2552 endfor ;
2553 )
2554 fi
2555 endgroup
2556enddef ;
2557
2558vardef grayed primary p =
2559 if rgbcolor p :
2560 tripled(.30redpart p+.59greenpart p+.11bluepart p)
2561 elseif cmykcolor p :
2562 tripled(.30(1cyanpart i)+.59(1magentapart i)+.11(1yellowpart i)blackpart i)
2563 elseif greycolor p :
2564 p
2565 elseif string p :
2566 grayed resolvedcolor(p)
2567 elseif picture p :
2568 image (
2569 for i within p :
2570 addto currentpicture
2571 if stroked i or filled i :
2572 if filled i :
2573 contour
2574 else :
2575 doublepath
2576 fi
2577 pathpart i
2578 dashed dashpart i
2579 withpen penpart i
2580 else :
2581 also i
2582 fi
2583 if unknown colorpart i :
2584
2585 elseif rgbcolor colorpart i :
2586 withcolor tripled(.30redpart i+.59greenpart i+.11bluepart i) ;
2587 elseif cmykcolor colorpart i :
2588 withcolor tripled(.30(1cyanpart i)+.59(1magentapart i)+.11(1yellowpart i)blackpart i) ;
2589 else :
2590 withcolor colorpart i ;
2591 fi
2592 endfor ;
2593 )
2594 else :
2595 p
2596 fi
2597enddef ;
2598
2599let greyed = grayed ;
2600
2601vardef hsvtorgb(expr h,s,v) =
2602 save H, S, V, x ;
2603 H = h mod 360 ;
2604 S = if s < 0 : 0 elseif s > 1 : 1 else: s fi ;
2605 V = if v < 0 : 0 elseif v > 1 : 1 else: v fi ;
2606 x = 1 abs(H mod 120 60)60 ;
2607 V ( (1S) (1,1,1) S
2608 if H < 60 : (1,x,0)
2609 elseif H < 120 : (x,1,0)
2610 elseif H < 180 : (0,1,x)
2611 elseif H < 240 : (0,x,1)
2612 elseif H < 300 : (x,0,1)
2613 else : (1,0,x)
2614 fi )
2615enddef ;
2616
2617permanent colorcircle, uncolored, inverted, grayed, greyed, hsvtorgb ;
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638def condition primary b = if b : "true" else : "false" fi enddef ;
2639
2640permanent condition ;
2641
2642
2643
2644primarydef p stretched s =
2645 begingroup
2646 save pp ; path pp ; pp := p xyscaled s ;
2647 (pp shifted ((point 0 of p) (point 0 of pp)))
2648 endgroup
2649enddef ;
2650
2651primarydef p enlonged len =
2652 begingroup
2653 if len == 0 :
2654 p
2655 elseif pair p :
2656 save q ; path q ; q := origin -- p ;
2657 save al ; al := arclength(q) ;
2658 if al > 0 :
2659 point 1 of (q stretched ((allen)al))
2660 else :
2661 p
2662 fi
2663 else :
2664 save al ; al := arclength(p) ;
2665 if al > 0 :
2666 p stretched ((allen)al)
2667 else :
2668 p
2669 fi
2670 fi
2671 endgroup
2672enddef ;
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682primarydef p shortened d =
2683 reverse ( ( reverse (p enlonged xpart paired(d)) ) enlonged ypart paired(d) )
2684enddef ;
2685
2686
2687
2688def xshifted expr dx = shifted(dx,0) enddef ;
2689def yshifted expr dy = shifted(0,dy) enddef ;
2690
2691
2692permanent stretched, enlonged, shortened, xshifted, yshifted ;
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713def readfile (expr name) =
2714 begingroup ; save ok ; boolean ok ;
2715 if (readfrom (name) <> EOF) :
2716 ok := false ;
2717 elseif (readfrom (name) <> EOF) :
2718 ok := false ;
2719 else :
2720 ok := true ;
2721 fi ;
2722 if not ok :
2723 scantokens("input " & name & " ") ;
2724 fi ;
2725 closefrom (name) ;
2726 endgroup ;
2727enddef ;
2728
2729permanent readfile ;
2730
2731
2732
2733inner end ;
2734
2735
2736
2737let mfun_remap_colors_normalwithcolor = normalwithcolor ;
2738
2739def remapcolors =
2740 def normalwithcolor primary c =
2741 mfun_remap_colors_normalwithcolor remappedcolor(c)
2742 enddef ;
2743enddef ;
2744
2745def normalcolors =
2746 let normalwithcolor = mfun_remap_colors_normalwithcolor ;
2747enddef ;
2748
2749def resetcolormap =
2750 color color_map[][][] ;
2751 normalcolors ;
2752enddef ;
2753
2754resetcolormap ;
2755
2756def r_color primary c = redpart c enddef ;
2757def g_color primary c = greenpart c enddef ;
2758def b_color primary c = bluepart c enddef ;
2759
2760def remapcolor(expr old, new) =
2761 color_map[redpart old][greenpart old][bluepart old] := new ;
2762enddef ;
2763
2764def remappedcolor(expr c) =
2765 if known color_map[redpart c][greenpart c][bluepart c] :
2766 color_map[redpart c][greenpart c][bluepart c]
2767 else :
2768 c
2769 fi
2770enddef ;
2771
2772
2773
2774
2775def recolor suffix p = p := mfun_repathed (0,p) enddef ;
2776def refill suffix p = p := mfun_repathed (1,p) enddef ;
2777def redraw suffix p = p := mfun_repathed (2,p) enddef ;
2778def retext suffix p = p := mfun_repathed (3,p) enddef ;
2779def untext suffix p = p := mfun_repathed (4,p) enddef ;
2780
2781
2782
2783
2784
2785
2786
2787color refillbackground ; refillbackground := (1,1,1) ;
2788
2789def restroke suffix p = p := mfun_repathed (21,p) enddef ;
2790def reprocess suffix p = p := mfun_repathed (22,p) enddef ;
2791
2792permanent recolor, refill, redraw, retext, untext, restroke, reprocess, refillbackground ;
2793
2794
2795
2796vardef mfun_repathed (expr mode, p) text t =
2797 begingroup ;
2798 if mode = 0 :
2799 save normalwithcolor ;
2800 remapcolors ;
2801 fi ;
2802 save temp_p, temp_q, temp_r, temp_f, temp_b ;
2803 picture temp_p, temp_q, temp_r ; color temp_f ; path temp_b ;
2804 temp_b := boundingbox p ;
2805 temp_p := nullpicture ;
2806 for i within p :
2807 temp_f := (redpart i, greenpart i, bluepart i) ;
2808 if bounded i :
2809 temp_q := mfun_repathed(mode,i) t ;
2810 setbounds temp_q to pathpart i ;
2811 addto temp_p also temp_q ;
2812 elseif clipped i :
2813 temp_q := mfun_repathed(mode,i) t ;
2814 clip temp_q to pathpart i ;
2815 addto temp_p also temp_q ;
2816 elseif stroked i :
2817 if mode=21 :
2818 temp_r := i ;
2819 addto temp_p also image(scantokens(t & " pathpart temp_r")
2820 dashed dashpart i withpen penpart i
2821 withcolor temp_f ; ) ;
2822 elseif mode=22 :
2823 temp_r := i ;
2824 addto temp_p also image(scantokens(t & " pathpart temp_r")) ;
2825 else :
2826 addto temp_p doublepath pathpart i
2827 dashed dashpart i withpen penpart i
2828 withcolor temp_f
2829 if mode = 2 :
2830 t
2831 fi ;
2832 fi ;
2833 elseif filled i :
2834 if mode=11 :
2835 temp_r := i ;
2836 addto temp_p also image(scantokens(t & " pathpart temp_r")
2837 withcolor temp_f ; ) ;
2838 elseif mode=12 :
2839 temp_r := i ;
2840 addto temp_p also image(scantokens(t & " pathpart temp_r")) ;
2841 else :
2842 addto temp_p contour pathpart i
2843 withcolor temp_f
2844 if (mode=1) and (temp_f<>refillbackground) :
2845 t
2846 fi ;
2847 fi ;
2848 else :
2849 addto temp_p also i ;
2850 fi ;
2851 endfor ;
2852 setbounds temp_p to temp_b ;
2853 temp_p
2854 endgroup
2855enddef ;
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880def clearxy text s =
2881 if false for $ := s : or true endfor :
2882 forsuffixes $ := s : x$ := whatever ; y$ := whatever ; endfor ;
2883 else :
2884 save x, y ;
2885 fi
2886enddef ;
2887
2888permanent clearxy ;
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898primarydef p smoothed d =
2899 (p llmoved (xpart paired(d),0) -- p lrmoved (xpart paired(d),0) {right} ..
2900 p lrmoved (0,ypart paired(d)) -- p urmoved (0,ypart paired(d)) {up} ..
2901 p urmoved (xpart paired(d),0) -- p ulmoved (xpart paired(d),0) {left} ..
2902 p ulmoved (0,ypart paired(d)) -- p llmoved (0,ypart paired(d)) {down} .. cycle)
2903enddef ;
2904
2905primarydef p cornered c =
2906 ((point 0 of p) shifted (c(unitvector(point 1 of p point 0 of p))) --
2907 for i=1 upto length(p) :
2908 (point i-1 of p) shifted (c(unitvector(point i of p point i-1 of p))) --
2909 (point i of p) shifted (c(unitvector(point i-1 of p point i of p))) ..
2910 controls point i of p ..
2911 endfor cycle)
2912enddef ;
2913
2914
2915
2916
2917primarydef p smoothcornered c =
2918 ( begingroup ;
2919 save cc ;
2920 if not cycle p: (point 0 of p) -- fi
2921 for i=1 upto length(p) :
2922 hide (cc := min(c,arclength (subpath(i-1,i) of p)2);)
2923 (point i-1 of p) shifted (cc(unitvector(point i of p point i-1 of p))) --
2924 (point i of p) shifted (cc(unitvector(point i-1 of p point i of p))) ..
2925 controls point i of p ..
2926 endfor
2927 if cycle p : cycle else : point 1 along p fi
2928 endgroup )
2929enddef ;
2930
2931permanent smoothed, cornered, smoothcornered ;
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971vardef bbwidth primary p =
2972 if unknown p :
2973 0
2974 elseif path p or picture p :
2975 save r ; pair r ; r := xrange p ;
2976 ypart r xpart r
2977 else :
2978 0
2979 fi
2980enddef ;
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012vardef bbheight primary p =
3013 if unknown p :
3014 0
3015 elseif path p or picture p :
3016 save r ; pair r ; r := yrange p ;
3017 ypart r xpart r
3018 else :
3019 0
3020 fi
3021enddef ;
3022
3023permanent bbwidth, bbheight ;
3024
3025color nocolor ; numeric noline ;
3026
3027def dowithpath (expr p, lw, lc, bc) =
3028 if known p :
3029 if known bc :
3030 fill p withcolor bc ;
3031 fi ;
3032 if known lw and known lc :
3033 draw p withpen pencircle scaled lw withcolor lc ;
3034 elseif known lw :
3035 draw p withpen pencircle scaled lw ;
3036 elseif known lc :
3037 draw p withcolor lc ;
3038 fi ;
3039 fi ;
3040enddef ;
3041
3042
3043
3044def [[[ = [ [ [ enddef ;
3045def ]]] = ] ] ] enddef ;
3046
3047let == = = ;
3048
3049permanent [[[, ]]], ==;
3050
3051
3052
3053picture oddly ;
3054
3055evenly := dashpattern(on 3 off 3) ;
3056oddly := dashpattern(off 3 on 3) ;
3057
3058
3059
3060vardef mfun_straightened(expr sign, p) =
3061 save temp_p, temp_q ; path temp_p, temp_q ;
3062 temp_p := p ;
3063 forever :
3064 temp_q := mfun_do_straightened(sign, temp_p) ;
3065 exitif length(temp_p) = length(temp_q) ;
3066 temp_p := temp_q ;
3067 endfor ;
3068 temp_q
3069enddef ;
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085vardef mfun_do_straightened(expr sign, p) =
3086 if length(p) > 2 :
3087 save pp ; path pp ;
3088 pp := point 0 of p ;
3089 for i=1 upto length(p)-1 :
3090 if round(point i of p) <> round(point length(pp) of pp) :
3091 pp := pp -- point i of p ;
3092 fi ;
3093 endfor ;
3094 save n, ok ; numeric n ; boolean ok ;
3095 n := length(pp) ; ok := false ;
3096 if n > 2 :
3097 for i=0 upto n :
3098 if unitvector(round(point i of pp point if i=0 : n else : i-1 fi of pp)) <>
3099 sign unitvector(round(point if i=n : 0 else : i+1 fi of pp point i of pp)) :
3100 if ok :
3101 --
3102 else :
3103 ok := true ;
3104 fi point i of pp
3105 fi
3106 endfor
3107 if ok and (cycle p) :
3108 -- cycle
3109 fi
3110 else :
3111 pp
3112 fi
3113 else :
3114 p
3115 fi
3116enddef ;
3117
3118vardef simplified expr p = (
3119 reverse mfun_straightened(+1,mfun_straightened(+1,reverse p))
3120) enddef ;
3121
3122vardef unspiked expr p = (
3123 reverse mfun_straightened(-1,mfun_straightened(-1,reverse p))
3124) enddef ;
3125
3126permanent simplified, unspiked ;
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144path originpath ; originpath := origin -- cycle ;
3145
3146vardef unitvector primary z =
3147 if abs z = abs origin : z else : zabs z fi
3148enddef;
3149
3150vardef epsed (expr e) =
3151 e if e>0 : eps elseif e < 0 : eps fi
3152enddef ;
3153
3154immutable originpath ;
3155permanent unitvector, epsed ;
3156
3157
3158
3159def withgray primary g =
3160 withcolor g
3161enddef ;
3162
3163if unknown darkred : color darkred ; darkred := .625(1,0,0) fi ;
3164if unknown darkgreen : color darkgreen ; darkgreen := .625(0,1,0) fi ;
3165if unknown darkblue : color darkblue ; darkblue := .625(0,0,1) fi ;
3166if unknown darkcyan : color darkcyan ; darkcyan := .625(0,1,1) fi ;
3167if unknown darkmagenta : color darkmagenta ; darkmagenta := .625(1,0,1) fi ;
3168if unknown darkyellow : color darkyellow ; darkyellow := .625(1,1,0) fi ;
3169if unknown darkgray : color darkgray ; darkgray := .625(1,1,1) fi ;
3170if unknown lightgray : color lightgray ; lightgray := .850(1,1,1) fi ;
3171
3172permanent withgray ;
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186vardef center primary p =
3187 centerof p
3188enddef ;
3189
3190
3191
3192vardef rangepath (expr p, d, a) =
3193 if length p>0 :
3194 (dunitvector(direction 0 of p) rotated a) shifted point 0 of p
3195 -- p --
3196 (dunitvector(direction length(p) of p) rotated a) shifted point length(p) of p
3197 else :
3198 p
3199 fi
3200enddef ;
3201
3202
3203
3204vardef straightpath (expr a, b, method) =
3205 if (method<1) or (method>6) :
3206 (ab)
3207 elseif method = 1 :
3208 (a --
3209 if xpart a > xpart b :
3210 if ypart a > ypart b :
3211 (xpart b,ypart a) --
3212 elseif ypart a < ypart b :
3213 (xpart a,ypart b) --
3214 fi
3215 elseif xpart a < xpart b :
3216 if ypart a > ypart b :
3217 (xpart a,ypart b) --
3218 elseif ypart a < ypart b :
3219 (xpart b,ypart a) --
3220 fi
3221 fi
3222 b)
3223 elseif method = 3 :
3224 (a --
3225 if xpart a > xpart b :
3226 (xpart b,ypart a) --
3227 elseif xpart a < xpart b :
3228 (xpart a,ypart b) --
3229 fi
3230 b)
3231 elseif method = 5 :
3232 (a --
3233 if ypart a > ypart b :
3234 (xpart b,ypart a) --
3235 elseif ypart a < ypart b :
3236 (xpart a,ypart b) --
3237 fi
3238 b)
3239 else :
3240 (reverse straightpath(b,a,method-1))
3241 fi
3242enddef ;
3243
3244permanent straightpath ;
3245
3246
3247
3248def addbackground text t =
3249 begingroup ;
3250 save p, b ; picture p ; path b ;
3251 b := boundingbox currentpicture ;
3252 p := currentpicture ; currentpicture := nullpicture ;
3253 fill b t ;
3254 setbounds currentpicture to b ;
3255 addto currentpicture also p ;
3256 endgroup ;
3257enddef ;
3258
3259permanent addbackground ;
3260
3261
3262
3263
3264vardef infinite expr p =
3265 (infinityunitvector(direction 0 of p)
3266 shifted point 0 of p
3267 -- p --
3268 infinityunitvector(direction length(p) of p)
3269 shifted point length(p) of p)
3270enddef ;
3271
3272permanent infinite ;
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325def showgrid (expr minx, maxx, deltax, miny, maxy, deltay) =
3326 begingroup
3327 save size ; numeric size ; size := 2pt ;
3328 for x=minx upto maxx :
3329 for y=miny upto maxy :
3330 draw (xdeltax, ydeltay) withpen pencircle scaled
3331 if (x mod 5 = 0) and (y mod 5 = 0) :
3332 1.5size withcolor .50white
3333 else :
3334 size withcolor .75white
3335 fi ;
3336 endfor ;
3337 endfor ;
3338 for x=minx upto maxx:
3339 label.bot(textext("\infofont " & decimal x), (xdeltax,size)) ;
3340 endfor ;
3341 for y=miny upto maxy:
3342 label.lft(textext("\infofont " & decimal y), (size,ydeltay)) ;
3343 endfor ;
3344 endgroup
3345enddef;
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374vardef phantom (text t) =
3375 picture temp_p ;
3376 temp_p := image(t) ;
3377 addto temp_p also currentpicture ;
3378 setbounds currentpicture to boundingbox temp_p ;
3379enddef ;
3380
3381vardef c_phantom (expr b) (text t) =
3382 if b :
3383 save temp_p; picture temp_p ;
3384 temp_p := image(t) ;
3385 addto temp_p also currentpicture ;
3386 setbounds currentpicture to boundingbox temp_p ;
3387 else :
3388 t ;
3389 fi ;
3390enddef ;
3391
3392permanent phantom ;
3393
3394
3395
3396def break =
3397 exitif true ;
3398enddef ;
3399
3400permanent break ;
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412primarydef p xstretched w = (
3413 begingroup save l, r ; pair r;
3414 r := xrange p ;
3415 l := ypart r xpart r ;
3416 p if (l > 0) and (w > 0) : xscaled (wl) fi
3417 endgroup
3418) enddef ;
3419
3420primarydef p ystretched h = (
3421 begingroup save l, r ; pair r;
3422 r := yrange p ;
3423 l := ypart r xpart r ;
3424 p if (l > 0) and (h > 0) : yscaled (hl) fi
3425 endgroup
3426) enddef ;
3427
3428permanent xstretched, ystretched ;
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438vardef area expr p =
3439 llcorner boundingbox p -- p --
3440 lrcorner boundingbox p -- cycle
3441enddef ;
3442
3443vardef basiccolors[] =
3444 if @ = 0 :
3445 white
3446 else :
3447 save n ; n := @ mod 7 ;
3448 if n = 1 : red
3449 elseif n = 2 : green
3450 elseif n = 3 : blue
3451 elseif n = 4 : cyan
3452 elseif n = 5 : magenta
3453 elseif n = 6 : yellow
3454 else : black
3455 fi
3456 fi
3457enddef ;
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468vardef rcomponent expr p = if rgbcolor p : redpart p elseif cmykcolor p : 1 cyanpart p else : p fi enddef ;
3469vardef gcomponent expr p = if rgbcolor p : greenpart p elseif cmykcolor p : 1 magentapart p else : p fi enddef ;
3470vardef bcomponent expr p = if rgbcolor p : bluepart p elseif cmykcolor p : 1 yellowpart p else : p fi enddef ;
3471vardef ccomponent expr p = if cmykcolor p : cyanpart p elseif rgbcolor p : 1 redpart p else : p fi enddef ;
3472vardef mcomponent expr p = if cmykcolor p : magentapart p elseif rgbcolor p : 1 greenpart p else : p fi enddef ;
3473vardef ycomponent expr p = if cmykcolor p : yellowpart p elseif rgbcolor p : 1 bluepart p else : p fi enddef ;
3474vardef kcomponent expr p = if cmykcolor p : blackpart p elseif rgbcolor p : 0 else : p fi enddef ;
3475
3476permanent rcomponent, gcomponent, bcomponent, ccomponent, mcomponent, ycomponent, kcomponent ;
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501vardef undecorated (text t) text decoration =
3502 save currentpicture ;
3503 picture currentpicture ;
3504 currentpicture := nullpicture ;
3505 t ;
3506 currentpicture
3507enddef ;
3508
3509vardef decorated (text imagedata) text decoration =
3510 save mfun_decorated_path, currentpicture ;
3511 picture mfun_decorated_path, currentpicture ;
3512 currentpicture := nullpicture ;
3513 imagedata ;
3514 mfun_decorated_path := currentpicture ;
3515 currentpicture := nullpicture ;
3516 for i within mfun_decorated_path :
3517 addto currentpicture
3518 if stroked i :
3519 doublepath pathpart i
3520 dashed dashpart i
3521 withpen penpart i
3522 withcolor colorpart i
3523 withprescript prescriptpart i
3524 withpostscript postscriptpart i
3525 decoration
3526 elseif filled i :
3527 contour pathpart i
3528 withpen penpart i
3529 withcolor colorpart i
3530 withprescript prescriptpart i
3531 withpostscript postscriptpart i
3532 decoration
3533 elseif textual i :
3534 also i
3535 withcolor colorpart i
3536 withprescript prescriptpart i
3537 withpostscript postscriptpart i
3538 decoration
3539 else :
3540 also i
3541 fi
3542 ;
3543 endfor ;
3544 currentpicture
3545enddef ;
3546
3547vardef redecorated (text imagedata) text decoration =
3548 save mfun_decorated_path, currentpicture ;
3549 picture mfun_decorated_path, currentpicture ;
3550 currentpicture := nullpicture ;
3551 imagedata ;
3552 mfun_decorated_path := currentpicture ;
3553 currentpicture := nullpicture ;
3554 for i within mfun_decorated_path :
3555 addto currentpicture
3556 if stroked i :
3557 doublepath pathpart i
3558 dashed dashpart i
3559 withpen penpart i
3560 decoration
3561 elseif filled i :
3562 contour pathpart i
3563 withpen penpart i
3564 decoration
3565 elseif textual i :
3566 also i
3567 decoration
3568 else :
3569 also i
3570 fi
3571 ;
3572 endfor ;
3573 currentpicture
3574enddef ;
3575
3576permanent decorated, undecorated, redecorated ;
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592vardef mfun_snapped(expr p, s) =
3593 if p < 0 : ( else : ( fi p div s) s
3594enddef ;
3595
3596vardef mfun_applied(expr p, s)(suffix a) =
3597 if path p :
3598 if pair s :
3599 for i=0 upto length(p)-1 :
3600 (a(xpart point i of p,xpart s),a(ypart point i of p,ypart s)) --
3601 endfor
3602 if cycle p :
3603 cycle
3604 else :
3605 (a(xpart point length(p) of p,xpart s),a(ypart point length(p) of p,ypart s))
3606 fi
3607 else :
3608 for i=0 upto length(p)-1 :
3609 (a(xpart point i of p,s),a(ypart point i of p,s)) --
3610 endfor
3611 if cycle p :
3612 cycle
3613 else :
3614 (a(xpart point length(p) of p,s),a(ypart point length(p) of p,s))
3615 fi
3616 fi
3617 elseif pair p :
3618 if pair s :
3619 (a(xpart p,xpart s),a(ypart p,ypart s))
3620 else :
3621 (a(xpart p,s),a(ypart p,s))
3622 fi
3623 elseif cmykcolor p :
3624 (a(cyanpart p,s),a(magentapart p,s),a(yellowpart p,s),a(blackpart p,s))
3625 elseif rgbcolor p :
3626 (a(redpart p,s),a(greenpart p,s),a(bluepart p,s))
3627 elseif graycolor p :
3628 a(p,s)
3629 elseif numeric p :
3630 a(p,s)
3631 else
3632 p
3633 fi
3634enddef ;
3635
3636primarydef p snapped s =
3637 mfun_applied(p,s)(mfun_snapped)
3638enddef ;
3639
3640permanent snapped ;
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653picture font_glyph[][] ;
3654numeric font_count ; font_count := 0;
3655
3656def beginfont(expr n) =
3657 begingroup ;
3658 save name ; string name; name := n;
3659 font_count := font_count 1 ;
3660 lmt_registerglyphs [
3661 name = name,
3662 units = 10,
3663 width = 10,
3664 height = 8,
3665 depth = 2,
3666 ] ;
3667enddef ;
3668
3669def endfont =
3670 endgroup;
3671enddef ;
3672
3673def beginglyph(expr u, w, h, d) =
3674 save unicode ; unicode := u;
3675 lmt_registerglyph [
3676 category = name,
3677 unicode = u,
3678 code = "draw font_glyph[" & decimal font_count & "][" & decimal u & "];"
3679 width = w,
3680 height = h,
3681 depth = d,
3682 ] ;
3683 currentpicture := nullpicture ;
3684enddef ;
3685
3686def endglyph =
3687 font_glyph[font_count][unicode] := currentpicture ;
3688enddef ;
3689
3690permanent beginfont, endfont, beginglyph, endglyph ;
3691
3692
3693
3694
3695newinternal maxdimensions ; maxdimensions := 14000 ;
3696
3697def mfun_apply_max_dimensions =
3698 if bbwidth currentpicture > maxdimensions :
3699 currentpicture := currentpicture if bbheight currentpicture > bbwidth currentpicture : ysized else : xsized fi maxdimensions ;
3700 elseif bbheight currentpicture > maxdimensions :
3701 currentpicture := currentpicture ysized maxdimensions ;
3702 fi ;
3703enddef;
3704
3705extra_endfig := extra_endfig & "mfun_apply_max_dimensions ;" ;
3706
3707
3708
3709path unittriangle, fulltriangle ;
3710
3711unittriangle := point 0 along unitcircle
3712 -- point 13 along unitcircle
3713 -- point 23 along unitcircle
3714 -- cycle ;
3715fulltriangle := point 0 along fullcircle
3716 -- point 13 along fullcircle
3717 -- point 23 along fullcircle
3718 -- cycle ;
3719
3720immutable unittriangle, fulltriangle ;
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734vardef listsize(suffix list) =
3735 numeric len ; len := 1 ;
3736 forever :
3737 exitif unknown list[len] ;
3738 len := len 1 ;
3739 endfor ;
3740 len if unknown list[0] : 1 fi
3741enddef ;
3742
3743vardef listlast(suffix list) =
3744 numeric len ; len := if known list[0] : 0 else : 1 fi ;
3745 forever :
3746 len := len 1 ;
3747 exitif unknown list[len] ;
3748 endfor ;
3749 len 1
3750enddef ;
3751
3752vardef mfun_quick_sort(suffix list)(expr asked_min, asked_max)(text what) =
3753 save l, r, m ;
3754 numeric l ; l := asked_min ;
3755 numeric r ; r := asked_max ;
3756 numeric m ; m := floor(.5[asked_min,asked_max]) ;
3757 asked_mid := what list[m] ;
3758 forever :
3759 exitif l >= r ;
3760 forever :
3761 exitif l > asked_max ;
3762
3763 exitif (what list[l]) >= asked_mid ;
3764 l := l 1 ;
3765 endfor ;
3766 forever :
3767 exitif r < asked_min ;
3768
3769 exitif asked_mid >= (what list[r]) ;
3770 r := r 1 ;
3771 endfor ;
3772 if l <= r :
3773 temp := list[l] ;
3774 list[l] := list[r] ;
3775 list[r] := temp ;
3776 l := l 1 ;
3777 r := r 1 ;
3778 fi ;
3779 endfor ;
3780 if asked_min < r :
3781 mfun_quick_sort(list)(asked_min,r)(what) ;
3782 fi ;
3783 if l < asked_max :
3784 mfun_quick_sort(list)(l,asked_max)(what) ;
3785 fi ;
3786enddef ;
3787
3788vardef sortlist(suffix list)(text what) =
3789 save asked_max ; numeric asked_max ;
3790 save asked_mid ; numeric asked_mid ;
3791 save temp ;
3792
3793 asked_max := listlast(list) ;
3794 if pair list[asked_max] :
3795 pair temp ;
3796 else :
3797 numeric temp ;
3798 fi ;
3799 if pair what list[asked_max] :
3800 pair asked_mid ;
3801 else :
3802 numeric asked_mid ;
3803 fi ;
3804 if asked_max > 1 :
3805
3806 mfun_quick_sort(list)(if known list[0] : 0 else : 1 fi,asked_max)(what) ;
3807 fi ;
3808enddef ;
3809
3810vardef uniquelist(suffix list) =
3811
3812enddef ;
3813
3814vardef copylist(suffix list, target) =
3815 save i ; i := 1 ;
3816 forever :
3817 exitif unknown list[i] ;
3818 target[i] := list[i] ;
3819 i := i 1 ;
3820 endfor ;
3821enddef ;
3822
3823vardef listtolines(suffix list) =
3824 list[1] for i=2 upto listsize(list) : -- list[i] endfor
3825enddef ;
3826
3827vardef listtocurves(suffix list) =
3828 list[1] for i=2 upto listsize(list) : .. list[i] endfor
3829enddef ;
3830
3831
3832
3833
3834
3835vardef shapedlist(suffix p) =
3836 save l ; pair l[] ;
3837 save r ; pair r[] ;
3838 save i ; i := 1 ;
3839 save n ; n := 0 ;
3840 forever :
3841 exitif unknown p[i] ;
3842 n := n 1 ;
3843 l[n] := ulcorner p[i] ;
3844 r[n] := urcorner p[i] ;
3845 n := n 1 ;
3846 l[n] := llcorner p[i] ;
3847 r[n] := lrcorner p[i] ;
3848 i := i 1 ;
3849 endfor ;
3850 for i = 3 upto n :
3851 if xpart r[i] < xpart r[i-1] :
3852 r[i] := (xpart r[i],ypart r[i-1]) ;
3853 elseif xpart r[i] > xpart r[i-1] :
3854 r[i-1] := (xpart r[i-1],ypart r[i]) ;
3855 fi ;
3856 if xpart l[i] < xpart l[i-1] :
3857 l[i-1] := (xpart l[i-1],ypart l[i]) ;
3858 elseif xpart l[i] > xpart l[i-1] :
3859 l[i] := (xpart l[i],ypart l[i-1]) ;
3860 fi ;
3861 endfor ;
3862 if n > 0 :
3863 simplified (
3864 for i = 1 upto n : r[i] -- endfor
3865 for i = n downto 1 : l[i] -- endfor
3866 cycle
3867 )
3868 else :
3869 origin -- cycle
3870 fi
3871enddef ;
3872
3873permanent listsize, listlast, sortlist, uniquelist, copylist, listtolines, listtocurves, shapedlist ;
3874
3875
3876
3877let dump = relax ;
3878
3879
3880
3881def loadmodule expr name =
3882
3883 if (unknown scantokens("context_" & name)) and (unknown scantokens("metafun_loaded_" & name)) :
3884 save s ; string s ; s := "input " & ditto & "mp-" & name & ditto & ";" ;
3885 expandafter scantokens expandafter s
3886 fi ;
3887enddef ;
3888
3889def loadfile (expr filename) = scantokens("input " & filename) enddef ;
3890def loadimage (expr filename) = image(scantokens("input " & filename);) enddef ;
3891
3892permanent loadmodule, loadfile, loadimage ;
3893
3894
3895
3896def drawpathwithpoints expr p =
3897 do_drawpathwithpoints(p)
3898enddef ;
3899
3900def do_drawpathwithpoints(expr p) text t =
3901 draw p t ;
3902 if length(p) > 2 :
3903 begingroup ;
3904 save temp_c ; path temp_c ;
3905 save temp_p; picture temp_p ;
3906 temp_p := image (
3907 temp_c := if cycle p : fullsquare else : fullcircle fi scaled 6pt ;
3908 for i=0 upto length(p) if cycle p : -1 fi :
3909 fill temp_c shifted point i of p withcolor white ;
3910 draw temp_c shifted point i of p withcolor white2 withpen pencircle scaled .5pt ;
3911 if (i = 0) and cycle p :
3912 temp_c := fullcircle scaled 6pt ;
3913 fi ;
3914 endfor ;
3915 for i=0 upto length(p) if cycle p : -1 fi :
3916 draw textext("\infofont " & decimal i) ysized 2pt shifted point i of p ;
3917 endfor ;
3918 ) ;
3919 setbounds temp_p to boundingbox p ;
3920 draw temp_p ;
3921 fi ;
3922enddef ;
3923
3924
3925
3926newinternal crossingdebug ; crossingdebug := 0 ;
3927newinternal crossingscale ; crossingscale := 10 ;
3928newinternal crossingnumbermax ; crossingnumbermax := 1000 ;
3929
3930
3931
3932vardef infotext@#(expr txt, ysize) =
3933 textext@#("\infofont " & if numeric txt : decimal fi txt) ysized ysize
3934enddef ;
3935
3936primarydef p crossingunder q =
3937 begingroup
3938 save pic ; picture pic ; pic := nullpicture ;
3939 if picture p :
3940 for i within p :
3941 if stroked i :
3942 addto pic also image(draw pathpart i crossingunder q) ;
3943 fi
3944 endfor
3945 elseif path p :
3946 save n, t, a, b, c, r, bcuttings, hold ;
3947 numeric n, t[], hold ;
3948 path a, b, c, r, bcuttings, hold[] ;
3949 c := makepath(currentpen scaled crossingscale) ;
3950 r := if picture q : boundingbox fi q ;
3951 t[0] := n := hold := 0 ;
3952 a := p ;
3953
3954
3955 for i=1 upto crossingnumbermax :
3956 clearxy ; z = a intersectiontimes r ;
3957 if x < 0 :
3958 exitif hold < 1 ;
3959 a := hold[hold] ; hold := hold 1 ;
3960 clearxy ; z = a intersectiontimes r ;
3961 fi
3962 (t[incr n], whatever) = p intersectiontimes point x of a ;
3963 if x = 0 :
3964 a := a cutbefore c shifted point x of a ;
3965 elseif x = length a :
3966 a := a cutafter c shifted point x of a ;
3967 else :
3968 b := subpath (0,x) of a cutafter c shifted point x of a ;
3969 bcuttings := cuttings ;
3970 a := subpath (x,length a) of a cutbefore c shifted point x of a ;
3971 clearxy ; z = a intersectiontimes r ;
3972 if x < 0 :
3973 a := b ;
3974 cuttings := bcuttings ;
3975 else :
3976 if length bcuttings > 0 :
3977 clearxy ; z = b intersectiontimes r ;
3978 if x >= 0 :
3979 hold[incr hold] := b ;
3980 fi
3981 fi
3982 fi
3983 fi
3984 if length cuttings = 0 :
3985 exitif hold < 1 ;
3986 a := hold[hold] ; hold := hold 1 ;
3987 fi
3988 if i = crossingnumbermax :
3989 message("crossingunder reached maximum " & decimal i & " intersections.");
3990 fi
3991 endfor
3992
3993 if n = 0 :
3994 save pic ; path pic ; pic := p ;
3995 else :
3996 sortlist(t,) ;
3997
3998 t[incr n] = length p if cycle p : t[1] fi ;
3999
4000
4001
4002
4003 save m ; m := 0 ;
4004 for i=if cycle p: 2 else: 1 fi upto n :
4005
4006
4007 if crossingdebug > 0 :
4008 if crossingdebug = 1 :
4009 addto pic doublepath c shifted point t[i] of p
4010 withpen currentpen withtransparency(1,.5) ;
4011 elseif crossingdebug = 2 :
4012 addto pic also
4013 infotext (incr m,crossingscale5)
4014 shifted point t[i] of p ;
4015 fi
4016 fi
4017 a := subpath (t[i-1],t[i]) of p
4018 if i > 1 :
4019 cutbefore (c shifted point t[i-1] of p)
4020 fi
4021 if (i < n) or (cycle p) :
4022 cutafter (c shifted point t[i] of p)
4023 fi ;
4024 if (not picture q) or (a outsideof q) :
4025 addto pic doublepath a withpen currentpen ;
4026 fi
4027 endfor
4028 fi
4029 fi
4030 pic
4031 endgroup
4032enddef ;
4033
4034primarydef p insideof q =
4035 begingroup
4036 save pth, pic, t ;
4037 path pth ; picture pic ;
4038 pic := if path q : image(draw q;) else : q fi ;
4039 pth := p -- center pic ;
4040 (t, whatever) = pth intersectiontimes boundingbox pic ;
4041 t < 0
4042 endgroup
4043enddef ;
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066primarydef p outsideof q =
4067 not (p insideof q)
4068enddef ;
4069
4070permanent crossingdebug, crossingscale, crossingnumbermax, infotext, crossingunder, insideof, outsideof ;
4071
4072
4073
4074vardef circularpath primary n =
4075 reverse (for i=0 step 2n until 8-2n+2eps: point i of fullcircle .. endfor cycle) rotated 90
4076enddef ;
4077
4078vardef squarepath primary n =
4079 for i=0 step 1n until 4-1n 2eps: point i of fullsquare -- endfor cycle
4080enddef ;
4081
4082vardef linearpath primary n =
4083 origin for i=1n step 1n until 1-1n 2eps: -- point i of (origin--(1,0)) endfor
4084enddef ;
4085
4086permanent circularpath, squarepath, linearpath ;
4087
4088
4089
4090color pensilcolor ; pensilcolor := .5red ;
4091newinternal pensilstep ; pensilstep := 125 ;
4092
4093vardef pensilled(expr p, q) =
4094 image (
4095 draw p withcolor pensilcolor withpen q ;
4096 for i = 0 step pensilstep until length(p) eps:
4097 draw point i of p withcolor white withtransparency (1,.5) withpen q ;
4098 endfor ;
4099 )
4100enddef ;
4101
4102permanent pensilled, pensilcolor, pensilstep ;
4103
4104
4105
4106vardef tolist(suffix l)(text t) =
4107 save n ; n := 1 ;
4108 for p = t :
4109 if numeric p :
4110 n := p ;
4111 dispose(l[n])
4112 elseif pair p :
4113 l[n] := p ;
4114 n := n 1 ;
4115 elseif path p :
4116 for i=0 step 1 until length(p) :
4117 l[n] := point i of p ;
4118 n := n 1 ;
4119 endfor ;
4120 else :
4121
4122 fi ;
4123 endfor ;
4124 forever :
4125 exitif unknown l[n] ;
4126 dispose(l[n])
4127 n := n 1 ;
4128 endfor ;
4129enddef ;
4130
4131vardef topath(suffix p)(text t) =
4132 save i ; i := if known p[1] : 2 ; p[1] elseif known p[0] : 1 ; p[0] else : 0 ; origin fi
4133 forever :
4134 exitif unknown p[i] ;
4135 t p[i]
4136 hide(i := i 1)
4137 endfor
4138enddef ;
4139
4140vardef tocycle(suffix p)(text t) =
4141 topath(p,t) t cycle
4142enddef ;
4143
4144permanent tolist, topath, tocycle ;
4145
4146
4147
4148def drawdot expr p =
4149 if pair p :
4150 addto currentpicture doublepath p
4151 withpen currentpen base_draw_options
4152 elseif path p :
4153 draw image (
4154 for i=0 upto length p :
4155 addto currentpicture doublepath point i of p
4156 withpen currentpen base_draw_options ;
4157 endfor ;
4158 )
4159 elseif picture p :
4160 draw image (
4161 save pp ; path pp ;
4162 for i within p :
4163 if stroked i or filled i :
4164 pp := pathpart i ;
4165 for j=0 upto length pp :
4166 addto currentpicture doublepath point j of pp
4167 withpen currentpen base_draw_options ;
4168 endfor ;
4169 fi ;
4170 endfor ;
4171 )
4172 fi
4173enddef ;
4174
4175permanent drawdot ;
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185vardef mfun_timestamp =
4186 decimal year & "-" &
4187 decimal month & "-" &
4188 decimal day & " " &
4189 if ((time div 60) < 10) : "0" & fi
4190 decimal (time div 60) & ":" &
4191 if ((time(time div 60)60) < 10) : "0" & fi
4192 decimal (time(time div 60)60)
4193enddef ;
4194
4195vardef totransform(expr x, y, xx, xy, yx, yy) =
4196 save t ; transform t ;
4197 xxpart t = xx ; yypart t = yy ;
4198 xypart t = xy ; yxpart t = yx ;
4199 xpart t = x ; ypart t = y ;
4200 t
4201enddef ;
4202
4203vardef bymatrix(expr rx, sx, sy, ry, tx, ty) =
4204 save t ; transform t ;
4205 xxpart t = rx ; yypart t = ry ;
4206 xypart t = sx ; yxpart t = sy ;
4207 xpart t = tx ; ypart t = ty ;
4208 t
4209enddef ;
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219vardef closedcurve primary p =
4220 p if (path p and not cycle p) or (pair p) : .. cycle fi
4221enddef ;
4222
4223vardef closedlines primary p =
4224 p if (path p and not cycle p) or (pair p) : -- cycle fi
4225enddef ;
4226
4227permanent totransform, bymatrix, closedcurve, closedlines ;
4228
4229let xslanted = slanted ;
4230
4231def yslanted primary s =
4232 transformed
4233 begingroup
4234 save t ; transform t ;
4235 xxpart t = 1 ; yypart t = 1 ;
4236 xypart t = 0 ; yxpart t = s ;
4237 xpart t = 0 ; ypart t = 0 ;
4238 t
4239 endgroup
4240enddef ;
4241
4242permanent xslanted, yslanted ;
4243
4244vardef processpath (expr p) (text pp) =
4245 if path p :
4246 for i=0 upto length(p)-1 :
4247 pp(point i of p) .. controls
4248 pp(postcontrol i of p) and
4249 pp(precontrol (i+1) of p) ..
4250 endfor
4251 if cycle p :
4252 cycle
4253 else :
4254 pp(point length(p) of p)
4255 fi
4256 elseif pair p :
4257 pp(p)
4258 else :
4259 p
4260 fi
4261enddef ;
4262
4263permanent processpath ;
4264
4265
4266
4267
4268
4269newinternal hatch_match; hatch_match := 1;
4270
4271vardef hatched(expr o) primary c =
4272 save a_, b_, d_, l_, i_, r_, za_, zb_, zc_, zd_;
4273 path b_; picture r_; pair za_, zb_, zc_, zd_;
4274 r_ := image (
4275 a_ := redpart(c) mod 180 ;
4276 l_ := greenpart(c) ;
4277 d_ := bluepart(c) ;
4278 b_ := o rotated a_ ;
4279 b_ :=
4280 if a_ >= 90 :
4281 (lrcorner b_ -- llcorner b_ -- ulcorner b_ -- urcorner b_ -- cycle)
4282 else :
4283 (llcorner b_ -- lrcorner b_ -- urcorner b_ -- ulcorner b_ -- cycle)
4284 fi
4285 rotated a_ ;
4286 za_ := point 0 of b_ ;
4287 zb_ := point 1 of b_ ;
4288 zc_ := point 2 of b_ ;
4289 zd_ := point 3 of b_ ;
4290 if hatch_match > 0 :
4291 n_ := round(length(zd_za_) l_) ;
4292 if n_ < 2:
4293 n_ := 2 ;
4294 fi ;
4295 l_ := length(zd_za_) n_ ;
4296 else :
4297 n_ := length(zd_za_) l_ ;
4298 fi
4299 save currentpen; pen currentpen ; pickup pencircle scaled d_;
4300
4301 for i_ := if hatch_match > 0 : 1 else : 0 fi upto ceiling n_ 1 :
4302 nodraw (i_n_)[zd_,za_] -- (i_n_)[zc_,zb_] ;
4303 endfor
4304 dodraw origin ;
4305 ) ;
4306 clip r_ to o;
4307 r_
4308enddef;
4309
4310permanent hatched ;
4311
4312
4313
4314numeric mfun_dash_on, mfun_dash_off ;
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329primarydef p withdashes len =
4330 hide (
4331 save l, t, n, m, don, doff; pair t ;
4332 l := arclength p ;
4333 t := paired (len) ;
4334 m := xpart t ypart t ;
4335 n := (l if not cycle p : xpart t fi) div m ;
4336 (n if not cycle p : 1 fi) don n doff = l ;
4337 don(ypart t) = doff(xpart t) ;
4338 mfun_dash_on := don ;
4339 mfun_dash_off := doff ;
4340 )
4341 p dashed dashpattern (on mfun_dash_on off mfun_dash_off)
4342enddef ;
4343
4344permanent withdashes ;
4345
4346
4347
4348path mfun_b ;
4349pair mfun_k ;
4350
4351path mfun_nullpath ;
4352
4353tertiarydef p sortedintersectiontimes q =
4354 sortedpath (p intersectiontimeslist q)
4355enddef ;
4356
4357tertiarydef p intersectionpath q =
4358 begingroup ;
4359 save mfun_b ; path mfun_b ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4360 save mfun_k ; pair mfun_k ; mfun_k := point 0 of mfun_b;
4361 if mfun_k <> (-1,-1) :
4362 .5[point xpart mfun_k of p, point ypart mfun_k of q]
4363 for i = 1 upto length(mfun_b) :
4364 hide(mfun_k := point i of mfun_b;)
4365 -- .5[point xpart mfun_k of p, point ypart mfun_k of q]
4366 endfor
4367 else :
4368 mfun_nullpath
4369 fi
4370 endgroup
4371enddef ;
4372
4373tertiarydef p firstintersectionpath q =
4374 begingroup ;
4375 save mfun_b ; path mfun_b ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4376 if (point 0 of mfun_b) <> (-1,-1) :
4377 point xpart (point 0 of mfun_b) of p
4378 for i = 1 upto length(mfun_b) :
4379 -- point xpart (point i of mfun_b) of p
4380 endfor
4381 else :
4382 mfun_nullpath
4383 fi
4384 endgroup
4385enddef ;
4386
4387tertiarydef p secondintersectionpath q =
4388 q firstintersectionpath p
4389enddef;
4390
4391vardef intersectionsfound expr p =
4392 (point 0 of p) <> (-1,-1)
4393enddef ;
4394
4395permanent intersectionpath, sortedintersectiontimes,
4396 firstintersectionpath, secondintersectionpath, intersectionsfound ;
4397
4398
4399
4400tertiarydef p cutbeforefirst q =
4401 begingroup ;
4402 save mfun_b, mfun_p ; path mfun_b, mfun_p ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4403 if (point 0 of mfun_b) <> (-1,-1) :
4404 mfun_p := subpath(xpart point 0 of mfun_b, length p) of p;
4405 else :
4406 mfun_p := p ;
4407 fi ;
4408 mfun_p
4409 endgroup
4410enddef ;
4411
4412tertiarydef p cutafterfirst q =
4413 begingroup ;
4414 save mfun_b, mfun_p ; path mfun_b, mfun_p ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4415 if (point 0 of mfun_b) <> (-1,-1) :
4416 mfun_p := subpath(0, xpart point 0 of mfun_b) of p;
4417 else :
4418 mfun_p := p ;
4419 fi ;
4420 mfun_p
4421 endgroup
4422enddef ;
4423
4424tertiarydef p cutbeforelast q =
4425 begingroup ;
4426 save mfun_b, mfun_p ; path mfun_b, mfun_p ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4427 if (point 0 of mfun_b) <> (-1,-1) :
4428 mfun_p := subpath(xpart point (length mfun_b) of mfun_b, length p) of p;
4429 else :
4430 mfun_p := p ;
4431 fi ;
4432 mfun_p
4433 endgroup
4434enddef ;
4435
4436tertiarydef p cutafterlast q =
4437 begingroup ;
4438 save mfun_b, mfun_p ; path mfun_b, mfun_p ; mfun_b := sortedpath (p intersectiontimeslist q) ;
4439 if (point 0 of mfun_b) <> (-1,-1) :
4440 mfun_p := subpath(0, xpart point (length mfun_b) of mfun_b) of p;
4441 else :
4442 mfun_p := p ;
4443 fi ;
4444 mfun_p
4445 endgroup
4446enddef ;
4447
4448permanent cutbeforefirst, cutafterfirst, cutbeforelast, cutafterlast ;
4449
4450
4451
4452vardef selfintersectiontimeslist expr p =
4453 save mfun_b ; path mfun_b ; mfun_b := sortedpath (p intersectiontimeslist p) ;
4454 if (known mfun_b) and (length mfun_b > 0) :
4455 save b ; boolean b ; b := false ;
4456 save n ; numeric n ; n := length(p) ;
4457 for i within mfun_b :
4458 if (xpart pathpoint = ypart pathpoint) :
4459 elseif (xpart pathpoint = n) and (ypart pathpoint = 0) :
4460 elseif (xpart pathpoint ypart pathpoint < 0.1) :
4461 else :
4462 hide(b := true)
4463 pathpoint --
4464 fi
4465 endfor if b : nocycle else : mfun_nullpath fi
4466 else :
4467 mfun_nullpath
4468 fi
4469enddef ;
4470
4471permanent selfintersectiontimeslist ;
4472
4473
4474
4475vardef starring(expr e) =
4476 save a, b, c, d ;
4477 pair a, b, c, d ;
4478 a := (-1,-1) ; b := ( 1,-1) ;
4479 c := ( 1, 1) ; d := (-1, 1) ;
4480 a -- (.5[a,b] shifted (0,e)) --
4481 b -- (.5[b,c] shifted (e, 0)) --
4482 c -- (.5[c,d] shifted (0, e)) --
4483 d -- (.5[d,a] shifted (e,0)) -- cycle
4484enddef ;
4485
4486vardef dashing (expr pth, shp, stp) =
4487 for i within arcpointlist stp of pth :
4488 shp
4489 rotated angle(pathdirection)
4490 shifted pathpoint
4491 &&
4492 endfor nocycle
4493enddef ;
4494
4495permanent starring, dashing ;
4496
4497
4498
4499
4500
4501
4502
4503numeric mfun_arc_factor ; mfun_arc_factor := 8360 ;
4504
4505vardef arc(expr from_angle, to_angle) =
4506 (subpath (0,mfun_arc_factor(to_anglefrom_angle)) of fullcircle)
4507 rotated from_angle
4508enddef ;
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519primarydef a crossprod b =
4520 (xpart a ypart b) (ypart a xpart b)
4521enddef;
4522
4523permanent crossprod ;
4524
4525newinternal scrutinizing ; scrutinizing := 3 ;
4526newinternal curvarturetolerance ; curvarturetolerance := 5eps ;
4527newinternal boolean tracereducedpath ; tracereducedpath := false ;
4528
4529vardef hasreducedcurvature(expr p,i,tolerance) =
4530 save ldir, mdir, rdir ; pair ldir, mdir, rdir ;
4531 ldir := unitvector(direction i 10eps of p) ;
4532 mdir := unitvector(direction i 12 of p) ;
4533 rdir := unitvector(direction i 1 10eps of p) ;
4534 not (
4535 ((ldir dotprod mdir) > 1 tolerance)
4536 and
4537 ((mdir dotprod rdir) > 1 tolerance)
4538 )
4539enddef ;
4540
4541vardef reducedpath(expr target) =
4542 save result ; path result ;
4543 save iproduct, oldlength, newlength ;
4544 result := target scrutinized 1 ;
4545 newlength := length(result) ;
4546 if tracereducedpath : message("reducedpath: start main loop") ; fi
4547 forever:
4548 if tracereducedpath : message(" start inner loop") ; fi
4549 oldlength := newlength ;
4550 if tracereducedpath : message(" length of path is " & decimal oldlength) ; fi
4551 for i = 1 upto oldlength :
4552 if tracereducedpath : message(" iteration " & decimal(i)) ; fi
4553 if hasreducedcurvature(result, i 1, curvarturetolerance) or
4554 hasreducedcurvature(result, i, curvarturetolerance) :
4555 if tracereducedpath : message(" not two lines, skipping") ; fi
4556 else :
4557 if tracereducedpath : message(" two lines, checking") ; fi
4558 iproduct :=
4559 unitvector (point i of result point (i 1) of result)
4560 dotprod
4561 unitvector (point (i 1) of result point i of result) ;
4562 if iproduct > 1 eps :
4563 if tracereducedpath : message(" parallel and same direction, replacing 0->1->2 by 0--2") ; fi
4564 result :=
4565 if i > 1 : (subpath(0,i 1) of result) && fi
4566 if i < oldlength 1 :
4567 (point i 1 of result -- point i 1 of result) &&
4568 (subpath(i 1,oldlength) of result) &&
4569 fi
4570 if cycle result : cycle fi;
4571 break
4572 elseif iproduct < -1 eps :
4573 if tracereducedpath : message(" parallel but opposite, more testing needed") ; fi
4574 if not hasreducedcurvature(result, i 1, curvarturetolerance) :
4575 if tracereducedpath : message(" the next segment is straight") ; fi
4576 iproduct :=
4577 unitvector( point (i 2) of result point (i 1) of result)
4578 dotprod
4579 unitvector( point (i 1) of result point i of result) ;
4580 if (iproduct < 1 eps) and (iproduct > -1 eps) :
4581 if tracereducedpath : message(" the next segment is not parallel to the previous, skipping") ; fi
4582 elseif iproduct > 1 eps :
4583 if tracereducedpath : message(" the points are in order 0321, 3021 or 3201 while in all cases we need 0->1->3") ; fi
4584 result :=
4585 (subpath(0,i) of result)
4586 && (point i of result -- point i 2 of result)
4587 && (subpath(i 2,oldlength) of result)
4588 if cycle result : && cycle fi;
4589 break
4590 else :
4591 if tracereducedpath : message(" points are in order 0231, 0213, 2031 or 2013") ; fi
4592 if (abs(point (i 1) of result point i of result)
4593 >
4594 abs(point (i 2) of result point (i 1) of result)) :
4595 if tracereducedpath : message(" we have case 0231 or 2031") ; fi
4596 if (abs(point (i 1) of result point i of result)
4597 >
4598 abs(point i of result point (i 1) of result)) :
4599 if tracereducedpath : message(" we are in case 2031, quitting") ; fi
4600 else :
4601 if tracereducedpath : message(" we are in case 0231 but need 0 -> 1 -> 3") ; fi
4602 result :=
4603 (subpath(0,i) of result)
4604 && (point i of result -- point i 2 of result)
4605 && (subpath(i 2,oldlength) of result)
4606 if cycle result : && cycle fi;
4607 break
4608 fi
4609 else :
4610 if tracereducedpath : message(" we are in case 0213 or 2013") ; fi
4611 if (abs(point (i 2) of result point (i 1) of result)
4612 >
4613 abs(point (i 2) of result point (i 1) of result)) :
4614 if tracereducedpath : message(" we are in 0213, replace by 0 -> 3") ; fi
4615 result :=
4616 (subpath(0,i 1) of result)
4617 && (point (i 1) of result -- point (i 2) of result)
4618 && (subpath(i 2,oldlength) of result)
4619 if cycle result : && cycle fi;
4620 break
4621 else :
4622 if tracereducedpath : message(" we are in 2013, replace by 0 -> 2 -> 3") ; fi
4623 result :=
4624 (subpath(0,i 1) of result)
4625 && (point (i 1) of result -- point (i 1) of result)
4626 && (subpath(i 1,oldlength) of result)
4627 if cycle result : && cycle fi;
4628 break
4629 fi
4630 fi
4631 fi
4632 fi
4633 else :
4634 if tracereducedpath : message (" next iteration") ; fi
4635 fi
4636 fi
4637 if tracereducedpath : message (" next step") ; fi
4638 endfor
4639 result := result scrutinized scrutinizing ;
4640 newlength := length(result) ;
4641 exitif newlength >= oldlength ;
4642 endfor
4643 if tracereducedpath : message ("reducedpath: done") ; fi
4644 result
4645enddef ;
4646
4647newinternal envelopeprecision ; envelopeprecision := 2 ;
4648
4649vardef reducedenvelope(expr target) =
4650 save original, tmppath, tmppaths ; path original, tmppath, tmppaths[] ;
4651 save curi, n, l, iproduct, vproduct ; numeric curi, n, l, iproduct, vproduct ;
4652 original := reducedpath(target) ;
4653
4654
4655 l := length(original) ;
4656 curi := 0 ;
4657 n := 0 ;
4658 for i = 0 upto (l 1) :
4659 if not hasreducedcurvature(original, i, curvarturetolerance) :
4660
4661 iproduct := (unitvector (point i 1 of original point i of original))
4662 dotprod
4663 (unitvector (point i of original precontrol i of original)) ;
4664 if (i > 0) and (not hasreducedcurvature(original, i 1, curvarturetolerance)) :
4665 vproduct := (unitvector (point i of original point (i 1) of original))
4666 crossprod
4667 (unitvector (point (i 1) of original point i of original)) ;
4668
4669 if (vproduct > eps) and (iproduct < 0) :
4670 tmppath := subpath(curi,i) of original ;
4671
4672 if length(tmppath scrutinized scrutinizing) <> 0 :
4673 n := n 1 ;
4674 tmppaths[n] := tmppath ;
4675 curi := i 1 ;
4676 fi
4677 fi
4678 else :
4679
4680 if (iproduct < 0) or (i == 0) :
4681
4682 tmppath := subpath(curi,i) of original ;
4683
4684 if length(tmppath scrutinized scrutinizing) <> 0 :
4685 n := n 1 ;
4686 tmppaths[n] := tmppath ;
4687 curi := i 1 ;
4688 fi
4689 fi
4690 fi
4691 fi
4692 endfor
4693
4694 if curi < l :
4695 n := n 1 ;
4696 tmppaths[n] := subpath(curi,l) of original ;
4697 fi
4698
4699 interim intersectionprecision := 2 ;
4700 if n = 0 :
4701 original
4702 elseif n = 1 :
4703 tmppaths[1] && cycle
4704 elseif n = 2 :
4705 (tmppaths[1] cutafterlast tmppaths[2]) &&
4706 (tmppaths[2] cutbeforefirst tmppaths[1]) && cycle
4707 else :
4708 save s ; numeric s ;
4709 if (abs(point length(tmppaths[1]) of tmppaths[1] point length(tmppaths[n]) of tmppaths[n]) < eps) :
4710 s := 2 ;
4711 else :
4712 s := 1 ;
4713 fi
4714 intersectionprecision := envelopeprecision ;
4715 for i = s upto (n 1) :
4716
4717
4718 if (tmppaths[i] intersectiontimes tmppaths[i 1]) = (-1,-1) :
4719 tmppaths[i] := tmppaths[i] -- point 0 of tmppaths[i 1];
4720 fi
4721 tmppath := tmppaths[i] ;
4722 tmppaths[i] := tmppath cutafterfirst tmppaths[i 1] ;
4723 tmppaths[i 1] := tmppaths[i 1] cutbeforefirst tmppath ;
4724 endfor
4725
4726
4727 if (tmppaths[n] intersectiontimes tmppaths[s]) = (-1,-1) :
4728 tmppaths[n] := tmppaths[n] -- point 0 of tmppaths[s];
4729 fi
4730 intersectionprecision := 2 ;
4731 tmppath := tmppaths[n] ;
4732 tmppaths[n] := tmppath cutafterfirst tmppaths[s] ;
4733 tmppaths[s] := tmppaths[s] cutbeforelast tmppath ;
4734
4735 if true :
4736
4737 intersectionprecision := envelopeprecision ;
4738
4739
4740
4741
4742
4743 save i ; numeric i ;
4744 save a ; pair a ;
4745
4746 tmppath := for i = s upto n :
4747 tmppaths[i] if i < n: &&& else : -- fi
4748 endfor cycle ;
4749
4750 l := length(tmppath) ;
4751 n := 0 ;
4752 curi := 0 ;
4753 i := 0 ;
4754
4755 forever :
4756 a := subpath(i,i 1 eps) of tmppath intersectiontimes subpath(i 1,l eps) of tmppath;
4757 if xpart a > 0 :
4758 n := n 1 ;
4759 tmppaths[n] := subpath(curi,i xpart a) of tmppath ;
4760 curi := i 1 ypart a ;
4761 i := floor(curi) ;
4762 else :
4763 i := i 1 ;
4764 fi
4765 exitif i >= l ;
4766 endfor
4767 n := n 1 ;
4768 tmppaths[n] := subpath(curi,l) of tmppath ;
4769 fi
4770
4771 for i = 1 upto n :
4772 tmppaths[i] if i < n: &&& else : -- fi
4773 endfor cycle
4774 fi
4775enddef ;
4776
4777primarydef p enveloped q =
4778 reducedenvelope(envelope q of p)
4779enddef ;
4780
4781permanent hasreducedcurvature, reducedpath, reducedenvelope, enveloped ;
4782
4783
4784
4785jointolerance := 2eps ;
4786
4787vardef mfun_total_area_step(expr p, c, cc, pp) =
4788 (p crossprod pp) 20
4789 (p crossprod c) 3 10
4790 (p crossprod cc) 3 20
4791 (c crossprod cc) 3 20
4792 (c crossprod pp) 3 20
4793 (cc crossprod pp) 6 20
4794enddef ;
4795
4796vardef totalarea(expr p) =
4797 0 for i within p :
4798 mfun_total_area_step(pathpoint,pathpostcontrol,deltaprecontrol 1,deltapoint 1)
4799 endfor
4800enddef ;
4801
4802permanent totalarea ;
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819tertiarydef p penstroked s =
4820 begingroup
4821 interim defaultzeroangle := 0;
4822 save N ; numeric N ; N := length s ;
4823 save pp ; path pp ; pp := arcpointlist N of p ;
4824 save pl ; path pl ; pl := for i within pp :
4825 pathpoint shifted ((ypart point i of s,0) rotated (angle(pathdirection) 90)) ..
4826 endfor nocycle ;
4827 save pr ; path pr ; pr := for i within pp :
4828 pathpoint shifted ((ypart point i of s,0) rotated (angle(pathdirection) 90)) ..
4829 endfor nocycle ;
4830
4831 if cycle p :
4832 (pl -- cycle) && (reverse pr -- cycle) && cycle
4833 else :
4834 pl -- reverse pr -- cycle
4835 fi
4836 endgroup
4837enddef;
4838
4839vardef nepstroke (expr N) text F =
4840 save strokesteps ; numeric strokesteps ; strokesteps := N ;
4841 for strokestep = 0 upto strokesteps : (strokestep,F) -- endfor nocycle
4842enddef ;
4843
4844permanent penstroked, nepstroke ;
4845 |