bersama catatan peribadi & teknikalnya.

Melukis Grafik Dengan ConTeXt

~ MetaFun (MetaPost)


geeky stuff
#context | #metafun | #metapost

Sejak PdPR bermula, ada sebahagian masa ibu terfikir-fikir apa yang boleh ibu buat dalam menyediakan bahan bantu untuk ibu ajarkan sendiri kepada Kak Long, terutamanya apabila melibatkan subjek Matematik.

Dengan silibus yang semakin meningkat serta melebihi keupayaan seorang kanak-kanak normal dan biasa, kenalah juga ibu kreatif dalam memberikan penerangan. Yalah, dalam keadaan pandemik sekarang, ibu bapalah yang berperanan dalam mendidik anak-anaknya.

Sebagai contoh, perbundaran kepada puluh terdekat sudah diperkenalkan kepada anak-anak tahun satu. Susah juga untuk ibu terangkan kepada Kak Long apa logiknya disebalik mengetahui perbundaran dalam usia 7 tahun ini.

Jadinya, ibu sediakan satu lampiran yang boleh dirujuk oleh Kak Long untuk mengenalpasti puluh mana yang terdekat dengan nombor-nombor yang ibu kelaskan seperti ditunjuk di dalam gambar di bawah ini.


Ibu sediakan dokumen ini dengan menggunakan enjin typesetting iaitu CONTEXT LMTX kali ini. It is easier to use a TEX distribution because I could copy the code for the same layout over and over again without having to rely on the mouse usage to drag the boxes and frames.

Arahan-arahan ConTeXt yang dicuba:-


Learned The Hard Way



  • Rules: \hbox & \frule

Jika diturutkan, banyak cara boleh digunakan untuk mendapatkan design seperti di atas. Mencari yang tepat sesungguhnya boleh tahan sukar juga kerana ada terlalu banyak dokumentasi yang disediakan dalam laman web milik PRAGMA ADE.

Cari punya cari, saya rujuk kepada dokumentasi bertajuk Rules dahulu.

Justifikasi: Contoh-contoh yang diberikan ada menggunakan MetaPost, dan ada grafik berbentuk segi empat serta bulatan yang mengandungi teks di dalamnya. Juga terkandung di dalamnya contoh penggunaan anak panah.

Walaubagaimanapun, anak panah yang disediakan di dalam dokumentasi berkenaan tidak menepati apa yang saya kehendaki.

Pun begitu, saya cuba juga bereksperimentasi melalui kod contoh yang telah diberikan untuk mendapatkan grafik segi empat, garisan melintang dan bulatan.

Berikut adalah kod bagi susun atur dokumen berserta definisi tulisan dan warna (yang mana layout-nya akan dirombak semula kemudian nanti):-

 1\setuppapersize[A4][A4]
 2\setuplayout[topspace=.5in,backspace=1in,
 3  header=24pt,headerdistance=1.735em,
 4  footerdistance=0em,
 5  height=middle,width=middle]
 6\setupheadertexts[Matematik\hfill \bf Perbundaran Kepada Puluh Terdekat]
 7\setupbackgrounds[header][text][bottomframe=on]
 8\setuppagenumbering[location={},style=bold]
 9\setupbodyfont[iwona,18pt]
10\definefont[MyBigFont][euler-math sa 1.4]
11\definecolor[lightorange][x=FBCB85]

Kod bagi segi empat dengan keempat-empat bucu mempunyai jejari (selepas tag pemula iaitu \starttext. Dokumen tex mesti dimulai dengan arahan ini selepas setup dan definisi serta diakhiri dengan arahan \stoptext):-

1\hbox\bgroup
2  \white \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt type fill\relax
3  \hskip-13mm
4  \darkgreen \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt\relax
5  \hskip-13mm
6  \hbox to 13mm{\black \bold \hfill N\hfill}%
7\egroup

Daripada kod di atas, terdapat tiga kotak yang dilukis; \frule ① ialah kotak di ruangan dalam berwarna putih ⇒ (type fill), \frule ke-② ialah kotak di bahagian luar dengan garisan berwarna hijau gelap manakala yang ketiga ialah kotak \hbox yang mengandungi teks. Kesemuanya ini disatukan di dalam satu kumpulan \hbox dengan tag \bgroup sebagai permulaan dan \egroup sebagai pengakhiran. Kesemua unit ukuran adalah sama terutamanya bagi lebar.

Kod bagi garisan melintang berwarna biru:-

{\blue \leaders\hrule height 1mm\relax\hfill}

Manakala bagi bulatan tengah berwarna jingga itu, adanya penggunaan MetaPost seperti berikut:-

1\startuseMPgraphic{shape:back}
2  fill unitcircle xysized (RuleWidth,RuleHeight+RuleDepth)
3    withcolor RuleColor ;
4\stopuseMPgraphic
5\startuseMPgraphic{shape:fore}
6  draw unitcircle xysized (RuleWidth,RuleHeight+RuleDepth)
7    withcolor RuleColor withpen pencircle scaled 4RuleThickness ;
8\stopuseMPgraphic

Setelah itu, MPgraphic yang telah dinamakan sebagai {shape:back} dan {shape:fore} di atas dipanggil dengan kod di bawah:-
1\hbox\bgroup
2  \color[lightorange]{\frule width 20mm height 12mm depth 6mm type mp line 1pt
3    data {\includeMPgraphic{shape:back}}}\relax
4  \hskip-20mm
5  \orange \frule width 20mm height 12mm depth 6mm type mp line 1pt
6    data {\includeMPgraphic{shape:fore}}\relax
7  \hskip-20mm
8  \hbox to 20mm{\black \bold \hfill \MyBigFont N\hfill}
9\egroup

Maka seterusnya adalah sebahagian kod (yang perlu disalintampal untuk pengulangan penggunaan) di bawah arahan \dontleavehmode bagi memaparkan kesemuanya di dalam satu baris dengan jarak diantara setiap kotak ditentukan melalui arahan \hskip:-

 1\dontleavehmode
 2\hbox\bgroup
 3  \white \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt type fill\relax
 4  \hskip-13mm
 5  \darkgreen \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt\relax
 6  \hskip-13mm
 7  \hbox to 13mm{\black \bold \hfill N\hfill}%
 8\egroup
 9\hskip1.5mm
10{\blue \leaders\hrule height 1mm\relax\hfill}
11\hskip1.5mm
12\hbox\bgroup
13  \color[lightorange]{\frule width 20mm height 12mm depth 6mm type mp line 1pt
14    data {\includeMPgraphic{shape:back}}}\relax
15  \hskip-20mm
16  \orange \frule width 20mm height 12mm depth 6mm type mp line 1pt
17    data {\includeMPgraphic{shape:fore}}\relax
18  \hskip-20mm
19  \hbox to 20mm{\black \bold \hfill \MyBigFont N\hfill}
20\egroup
21\hskip-.5mm
22{\blue \leaders\hrule height 1mm\relax\hfill}
23\hskip-.5mm
24\hbox\bgroup
25  \white \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt type fill\relax
26  \hskip-13mm
27  \red \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt\relax
28  \hskip-13mm
29  \hbox to 13mm{\black \bold \hfill N\hfill}%
30\egroup

Cara di atas ini disebut di dalam dokumentasi Rules sebagai:

"Of course this is a rather low level way of doing frames and such, but when you like that kind of low level programming you get the possibility here."

Cara aras tinggi kemudiannya dibincangkan iaitu dengan membuat tetapan \blackrules. Sekiranya ia bakal diulangguna, setup ia di bahagian atas sebagai tetapan lalai:-

\setupblackrules[width=20mm,height=12mm,depth=6mm,type=mp]

Dan seterusnya, kod di atas ini digantikan dengan kod di bawah (peliknya dengan cara ini, 4RuleThickness perlu ditukar kepada 10RuleThickness untuk mendapatkan ketebalan garisan bingkai bulatan yang sama):-

\hbox\bgroup
  \color[lightorange]{\blackrule[mp=shape:back]}\relax
  \hskip-20mm
  {\blackrule[color=orange,mp=shape:fore]}\relax
  \hskip-20mm
  \hbox to 20mm{\black \bold \hfill \MyBigFont N\hfill}
\egroup

Saya berpendapat, \blackrule ini lebih sesuai digunakan untuk metapost. Kerana tetapan lalai bagi opsyen type hanya mempunyai pilihan mp sahaja dan tidak selainnya (e.g. type fill→Ⓧ). Sebagai contoh, jika saya tetapkan arahan \setupblackrules seperti ini:-

\setupblackrules[width=13mm,height=7.5mm,depth=3mm,radius=2mm,line=1pt,color=white]

Saya hanya dapat menggunakan arahan \blackrule sekali sahaja walaupun kedua-dua ruang dalam dan luar segi empat mempunyai unit ukuran dan ciri-ciri yang sama untuk mendapatkan grafik kotak sebagaimana di atas:-

1\hbox\bgroup
2  \white \blackrule\relax
3  \hskip-13mm
4  \darkgreen \frule width 13mm height 7.5mm depth 3mm radius 2mm line 1pt\relax
5  \hskip-13mm
6  \hbox to 13mm{\black \bold \hfill N\hfill}%
7\egroup

Jika saya gunakan arahan \blackrule pada kedua-dua ruang i.e.,

1\hbox\bgroup
2  \white \blackrule\relax
3  \hskip-13mm
4  \darkgreen \blackrule\relax
5  \hskip-13mm
6  \hbox to 13mm{\black \bold \hfill N\hfill}%
7\egroup

\blackrule kedua akan mendominasi kerana tiada tetapan untuk opsyen type fill bagi \blackrule. Hasil:

Kesimpulan: Menggunakan \hbox dan \frule ini memakan banyak baris kod untuk menghasilkan grafik kelas perbundaran di atas. Sudah pastinya ada cara lain yang lebih baik.


  • Bounding Box

Melukis boundingbox dengan MetaPost untuk menghasilkan sempadan kotak segi empat. Contoh:

 1\dontleavehmode
 2\startMPcode
 3  draw btex N etex scaled 1.5 ;
 4  draw boundingbox currentpicture scaled 1.5
 5    withpen pencircle scaled .5mm withcolor .625red ;
 6\stopMPcode
 7\hskip.5cm
 8\startMPcode{extrafun}
 9  draw textext(10) scaled 2 withcolor .625green ;
10  draw boundingbox currentpicture enlarged 2pt ;
11\stopMPcode

menghasilkan output berikut:-

Namun cara ini menjadi kompleks jika kita ingin menghasilkan garis sempadan yang unik dan berjejari.

Saya sediakan satu contoh yang saya adaptasi daripada dokumentasi yang telah disediakan oleh PRAGMA ADE. Berikut adalah kodnya:-

 1\setuppapersize[A4][A4]
 2\setuplayout[topspace=.75in,backspace=1in,
 3  header=24pt,headerdistance=4em,
 4  footerdistance=0em,
 5  height=middle,width=middle]
 6\setupheadertexts[MetaFun\hfill \bf{Eksperimen}]
 7\setupbackgrounds[header][text][bottomframe=on]
 8\setuppagenumbering[location={},style=bold]
 9\setupbodyfont[dejavu]
10
11\defineoverlay[FunnyFrame][\useMPgraphic{FunnyFrame}]
12\defineframedtext[FunnyText][frame=off,background=FunnyFrame]
13\def\StartFrame{\startFunnyText}
14\def\StopFrame{\stopFunnyText}
15\def\FrameTitle#1
16  {\setMPtext{FunnyFrame}{\hbox spread 1em{\hss\strut#1\hss}}}
17  \setMPtext{FunnyFrame}{} % initialize the text variable
18
19\starttext
20\startuseMPgraphic{FunnyFrame}
21  picture p ; numeric o ; path a, b ; pair c ;
22  p := textext.rt(\MPstring{FunnyFrame}) ;
23  o := BodyFontSize ;
24  a := unitsquare xyscaled(OverlayWidth,OverlayHeight) ;
25  p := p shifted (2o,OverlayHeight-ypart center p) ;
26  drawoptions (withpen pencircle scaled 1pt withcolor .625red) ;
27  b := a superellipsed .95 ;
28  fill b withcolor .85white ; draw b ;
29  b := (boundingbox p) superellipsed .95 ;
30  fill b withcolor .85white ; draw b ;
31  draw p withcolor black ;
32  setbounds currentpicture to a ;
33\stopuseMPgraphic
34
35\FrameTitle{What is {\CONTEXT}?}
36\StartFrame
37  {\CONTEXT} is a document engineering system based on {\TEX}.
38  {\TEX} is a typesetting system and a program to typeset and produce documents.
39  {\CONTEXT} is easy to use and enables you to make complex paper and electronic documents.
40\StopFrame
41\stoptext

Imej berikutnya ialah output daripada kod di atas selepas menjalankan ‘context filename’:-


Demonstrasi modifikasi ke atas boundingbox ini boleh diteliti daripada dokumentasi yang disediakan oleh PRAGMA ADE di manual metafun-p pada muka surat 144 - 148.

Disebabkan oleh penggunaannya yang kompleks, saya teruskan mencari kaedah lain pula.


A Neat Solution: \framed



Di bawah dokumentasi metafun-p.pdf, terdapat satu arahan ConTeXt yang disebut sebagai berkuasa iaitu:-

"One of the most powerful and flexible commands of CONTEXT is \framed. We can use the background features of this command to invoke and position graphics that adapt themselves to the current situation. Once understood, overlays will become a natural part of the CONTEXT users toolkit."

Saya amat berpuas hati dengan pencarian terakhir ini yang mana arahan inilah saya gunakan seterusnya untuk menghasilkan dokumen ini.

Saya mulakan dengan perubahan layout dan saiz tulisan dahulu (susun atur selebihnya masih sama. Rujuk layout di atas):-

\setuplayout[topspace=.75in,backspace=1in,
  header=24pt,headerdistance=2.25em,
  footerdistance=0em,
  height=middle,width=middle]
\setupbodyfont[iwona,18pt]

\setupframed sebagai tetapan lalai bagi kotak segi empat:-

\setupframed[width=.047\textwidth,
  frame=off,
  depth=-1mm,
  offset=-8.5pt]

Opsyen offset digunakan untuk menentukan kedudukan \framed pada bahagian melintang.

Kemudian, tetapkan definisi overlay yang akan memanggil kod \uniqueMPgraphic mengikut nama ditentukan masing-masing:-

\defineoverlay[square before][\uniqueMPgraphic{square before}]
\defineoverlay[circle][\uniqueMPgraphic{circle}]
\defineoverlay[square after][\uniqueMPgraphic{square after}]

Tetapkan kod \uniqueMPgraphic{nama} seperti yang telah didefinisikan melalui \defineoverlay di atas:-

\startuniqueMPgraphic{square before}
  path p ;
  p := unitsquare scaled 1.5 smoothed .2 xyscaled (.875cm,.65cm) ;
  fill p withcolor white ;
  draw p withpen pencircle scaled 1pt withcolor .625green ;
\stopuniqueMPgraphic

\startuniqueMPgraphic{circle}
  path p ;
  p := fullcircle xscaled 2cm yscaled 1.75cm ;
  fill p withcolor \MPcolor{lightorange} ;
  draw p withpen pencircle scaled 4pt withcolor \MPcolor{orange} ;
\stopuniqueMPgraphic

\startuniqueMPgraphic{square after}
  path p ;
  p := unitsquare scaled 1.5 smoothed .2 xyscaled (.875cm,.65cm) ;
  fill p withcolor white ;
  draw p withpen pencircle scaled 1pt withcolor .9red ;
\stopuniqueMPgraphic

Kod bagi anak-anak panah kanan dan kiri pula adalah seperti berikut:-

\startuseMPgraphic{rightarrow}
  pickup pencircle scaled 1mm ; autoarrows := true ;
  drawarrow origin -- right * .55cm withcolor .625blue ;
\stopuseMPgraphic

\startuseMPgraphic{leftarrow}
  pickup pencircle scaled 1mm ; autoarrows := true ;
  drawarrow origin -- left * .55cm withcolor .625blue ;
\stopuseMPgraphic

Untuk mendapatkan kepala panah yang kemas berkadaran dengan skala yang ditetapkan i.e. 1mm, tetapkan autoarrows kepada := true.

Selepas itu, lukis grafik dengan arahan \framed:-

\dontleavehmode
\hskip.25cm
\framed[background=square before]{\bf 5}\quad
\framed[background=square before]{\bf 6}\quad
\framed[background=square before]{\bf 7}\quad
\framed[background=square before]{\bf 8}\quad
\framed[background=square before]{\bf 9}\quad
\hskip-.25cm
\useMPgraphic{rightarrow}\quad
\hskip.1cm
\framed[background=circle,depth=-2.5mm,offset=-11pt]
  {\MyBigFont 10}\quad
\hskip.1cm
\useMPgraphic{leftarrow}\quad
\hskip-.25cm
\framed[background=square after]{\bf 11}\quad
\framed[background=square after]{\bf 12}\quad
\framed[background=square after]{\bf 13}\quad
\framed[background=square after]{\bf 14}\quad

Kod-kod di atas menghasilkan:-


Kod penuh boleh didapati daripada pautan yang disediakan di seksyen Lihat juga. Manakala perbezaan arahan-arahan MPgraphic boleh dibaca lanjut melalui pautan Wiki di bawah.


Warna di dalam MetaPost boleh dipanggil dengan arahan:-
  1. 'withcolor colorname' secara langsung e.g. white / black / .625red etc,
  2. 'withcolor \MPcolor{lightorange}', melalui definisi warna \definecolor[lightorange][x=FBCB85], atau
  3. 'withcolor \blue' melalui definisi warna \def\blue{.625blue}.

Bentuk-bentuk grafik yang pelbagai juga disediakan oleh MetaPost antaranya fullcircle, unitsquare, fulltriangle, unitdiamond dan banyak lagi. Rujuk dokumentasi metafun-p bermula dari muka surat 379.



Kali terakhir dikemaskini:
Top