From 5a8fd0a27538d7394ccb172a473ebc60946126d8 Mon Sep 17 00:00:00 2001 From: yukkop Date: Fri, 14 Nov 2025 15:51:28 +0000 Subject: [PATCH] feat(package): `voronoi`: simple voronoi algoritm realization --- package/voronoi/README.md | 4 +++ package/voronoi/gen-voronoi-points.sh | 17 +++++++++ package/voronoi/voronoi.awk | 49 ++++++++++++++++++++++++++ package/voronoi/voronoi.frag | 49 ++++++++++++++++++++++++++ package/voronoi/voronoi.png | Bin 0 -> 8404 bytes package/voronoi/voronoi.sh | 23 ++++++++++++ 6 files changed, 142 insertions(+) create mode 100644 package/voronoi/README.md create mode 100644 package/voronoi/gen-voronoi-points.sh create mode 100644 package/voronoi/voronoi.awk create mode 100644 package/voronoi/voronoi.frag create mode 100644 package/voronoi/voronoi.png create mode 100644 package/voronoi/voronoi.sh diff --git a/package/voronoi/README.md b/package/voronoi/README.md new file mode 100644 index 0000000..ed129b7 --- /dev/null +++ b/package/voronoi/README.md @@ -0,0 +1,4 @@ +```sh +sh voronoi.sh 500 500 65 "$(sh ./gen-voronoi-points.sh 400 0 0 500 0 0 500)" 0,0,255 255,0,0 \ +| magick -size 200x200 xc:white -draw @- voronoi.png +``` diff --git a/package/voronoi/gen-voronoi-points.sh b/package/voronoi/gen-voronoi-points.sh new file mode 100644 index 0000000..dcf8ebf --- /dev/null +++ b/package/voronoi/gen-voronoi-points.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# posix: uniform points in a 2D parallelogram for Voronoi seeds +# usage: ./gen N x0 y0 ax ay bx by +# generates N points p = (x0,y0) + u*(ax,ay) + v*(bx,by), with u,v ~ U[0,1) + +[ "$#" -eq 7 ] || { echo "usage: $0 N x0 y0 ax ay bx by" >&2; exit 1; } + +awk -v n="$1" -v x0="$2" -v y0="$3" -v ax="$4" -v ay="$5" -v bx="$6" -v by="$7" ' +BEGIN{ + srand(); + for(i=0;i1?1:v) } +function color_lerp(p, q, r1, g1, b1, r2, g2, b3, x){ + t = (x - p) / (q - p) + t = clamp(t) + r = int(r1 + t*(r2 - r1) + 0.5) + g = int(g1 + t*(g2 - g1) + 0.5) + b = int(b1 + t*(b2 - b1) + 0.5) + return sprintf("#%02X%02X%02X", r, g, b) +} +BEGIN { + # external variables + # PTS is voronoi centers + # W is canvas width + # H is canvas height + # FADE is fade max distance + # C1 is first color in gradient + # C2 is secont color in gradient + + if (C1 == "") C1 = "0,0,0" + if (C2 == "") C2 = "255,255,255" + split(C1, c1, ",") + split(C2, c2, ",") + + n = split(PTS, pairs, " ") + for (i = 1; i <= n; ++i) { + split(pairs[i], xy, ",") + px[i] = xy[1] + 0 + py[i] = xy[2] + 0 + } + + for (y = 0; y < H; y++) + for (x = 0; x < W; x++) { + min_d = 1e308 + for (i = 1; i <= n; i++) { + dx = x - px[i] + dy = y - py[i] + d = sqrt(dx*dx + dy*dy) + if (d < min_d) + min_d = d + } + + fade = FADE - min_d + if (fade < 0) fade = 0 + + color = color_lerp(0, FADE, c1[1],c1[2],c1[3], c2[1],c2[2],c2[3], fade) + + printf "fill %s point %d,%d\n", color, x, y + } +} diff --git a/package/voronoi/voronoi.frag b/package/voronoi/voronoi.frag new file mode 100644 index 0000000..6b16e76 --- /dev/null +++ b/package/voronoi/voronoi.frag @@ -0,0 +1,49 @@ +#define PTS_N 500 +#define + +// Author @patriciogv - 2015 +// http://patriciogonzalezvivo.com + +#ifdef GL_ES +precision mediump float; +#endif + +uniform vec2 u_resolution; +uniform vec2 u_mouse; +uniform float u_time; + +float random (vec2 st) { + return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 st = gl_FragCoord.xy/u_resolution.xy; + + float rnd = random( st ); + + for(i=0;iYQVtoDuIE)Y6b&?c)^@qfi?^bOy&VTA+8MT85lM(Fl=F9*v7!HgMncu z1H&2yh7}A9OBfgyFfhzvV3^LpFo}Vomw};!fuWg!p^kx}l7XR^fgzWHA%lS-iGd-8 zfgzlMA&`N=n}NZVfx(`E!IFW&n1R8Bfx(V}!G(drlYzmHfgzZIA%cM+k%1wNfgy{5 zA&-Hfgn^-ofuVtcp^br|hk;=R1H(K9hLsEqTNxO3F)-|BU^v3SaFT)HECa(u28JsP z4A&VLZZI(1WMJ69z_5{lVKW26ItGSi3=9Vt7>+S8oMB+N#=vl!f#E&_!y^WUrwk0w z7#J=wFq{Ji({2Wag$xX{85pKAFic=z=we`KVPI%vU}$Gx=wo1*$iOg}fng5=!#)Ov zwG0eP85pK9Fw`(Glrby4D%Tn`WYDN85q(T7{VAB0vH&)7#M6B7_1l=92giv85p7%7!nv5Di|1A z85lYl7#1-woMK>j%fRrFf#DMa!(0Z2?F=G{|~jFcQG(9FeZ7syX^70 z^yobU0|R@Br>`sfOKu)sZQbARVt5!BWXn8V978H@&5ix-9Da10d<_GWR>GnO%9E$B zT+rEH!`c-YsKqb;gjqDun^o8NYlPuMdzY52@ms#@`Muxg@6Nor`TM-c z&DUnV|M=V4_5R-P<>#yFuFcwdjbox|-k+9EVRb(Vdp+-z=TH1joz|aWlbV$n_;Jhh zWz)~hh>SAJ{x)al=J&yn13w>$CmwrA6>Z9CN3di!?SmTPZvZiWV2h`X>SH{1E!uaD7YI`!*6 z-u=S%ef^Jb-8|nOC7U+?O8L05uYcK_KR>=KX?wGVbN-yl{M5_K{Ljz3UGwhE z^4YV(_LV=I%qbRoZoTyXe=|kj@B8=i+5XrcZ$6*b`;+^5`MX6&FWphy%4*szt~+bj z;?g4TgU5e=%HIFu5qFc9+}SH{Uw!&hd;7>Hf3rD}b%l?QK20~P*_2Zg_V?1Adza6~ zZ`=0ObJ`bw{hcL0Pwi<;j^~{=HEv(k+p6@hO^+7#xtix~dvkhs>%`rKkJ;MwUaP-} z`}cL#)%5$jKAhctzxMap*6rtZb)P$xH>2d&_ zx_j53vbgmttTz`Pz24i~8^8WW#j?E9-y^Gw-s!B&oxdhBsJ48^BKMQm4($E?`Sk8K zd7Bu8pBw)kJ9~2Xr~KzhPwL8#O1A4o3cuDfGh1u<{agC|e}CKe*Z;nG`}rN${?+Gq zPTju#>9VSn;W*``svmsmB~qWj~!dKb@u(Ae|F3Nd)@xtuKsxJ zm*0=C&pp3)?*7;Ae^01J7fTnNvp;w4TwRUaQlTX?ciHZ;S?;)?X!+5yhpV}NY1i-i z_2eJt(Fx11^Oc6lS8NM7b@kl0Ke>C$RX*Dmt+4%1X?-EFex{p@NMOnGu|jnUZ&)0c^gi~7wq+NoflAC%{}?Ze5v z+g1u*VBOcZ`9*iB@YD5Q>jEd(Tryh7F_q!$leg239)051{r1Xye@)eiY!&w|Dz~5B z%~vXCvtfVo@4i{Fzqk3`+Ff$KD)arH`=4Ggu^fr~a%@*;{)*Nu(fvL?tWHa}-h2D< zDbr+Y-EBdhaZx~-vx@VtTT%OS?C#Fqy~Qqj&$jXjzvW_MrrNd_AE`{q z(K33_QM%LNiJs7H=~`Fi#g`_3De0d&^;-zf{k7M4X5NY0{lxFwyfyE)yL{u*IkLDr z+vTG?bHB+lr8Uamo+j}+E}3=o(&U~n&*?X8m#Mt2y87ZoKw@+@_m^Gom}_=fQdy2Yi-%OSibgSyA@)Vm^{$R(E`GN)Qj{6^c^7(Tj zqP+i$(qd)TTJt4c2{(?|I0$mTTI}u0@Fu9f?eN^YdO{`tn5L&cx_NxpQtLHRQ{!A- z{Sx0RVb+`cwKbmZ0wInPGowQ z&wXlQr{A9}N5l8LMxE}5tcuD?Ke;PCJXZW8EO7Pq_x}Q9XKvVcuWL?l!JGY#YJy1@ zvOJ^Ik9fYwWD)xue6xRJhWy5;Q!TSP4&TW9od2KKsPpD?);}Fn{)NOObM}YIxbm&| zefUsXrc>&Pj8@G_`j?uO@)e9uEV}d9c6SZGXT*t#Pt*na1m3;pk($zM;JRPgiSyyQ zZ+`E${rNW6JYOg3#~X*z=L@s_pWokaUeI(jD#+-|;}}`bnSBcEO1IV@zNBK{b1{hd z!n|E^OA?FxoZnqjUH)D4P0rqpD;{52e6jBAgpH1q9T#565B7;To)x*i|H#c1zb9vP z%?QxK-gMdZbyX+zS6*RpvRrcfkjPPucnjA_cTV5`Ug&uG$u-&Fr7@!O*SuS!GxOr* z+LjXwJkDO4^jgqtQo#eA#v6;}O!poMV^h-Bu6Za@xNB=d_~~=AuF2-!<`(zbxoX`i zos}B%|DW13y_2VFqq0Pz>ca$u_g%Kn0&|xweb#yERNBua0^Q5+{MqPMTertDwea@0 zeSM44`Ds0|V}*Ah8ylwr`;o;=rbcR0&YbF7{k!vy>_mu`1Rz}jf;<&eb`(%H|N(p`TwQvmMh=C-#^=Y zX9s9$YwI`2{PfXz^JC|R_4$GE@ej|-a<@M*S{C}odgHd|q4e_2$ZjN?#?dzP`CSk@+&;zAKisKW_18h9|50 z-I*PJEG=Nllixk=S1!Bp&2v}1#Kv;2Pp=?Sb-yULpIn7WP)v-?rxyoKvM#>*ckX5W zsU@**XV#~#d2`~g_R^(y8Q1U2TDsryk+hGrWyKW*AxoDh!m$rHmj4R-V!y`DVwD~H zYWZ*Bcc-47@Mg!Izo#Z@FKwS6Gw6<;IZ>{ykFO@ zs43XKdGo4Ot2Tdr*L>>rVbxgUdFSTbuif$c!_#@6R!>h0DJd;wo$!8@+k-@4(a(X{ku6`8s)8{Db&z&I`MeD^oT<^s` z42VxrHpma^l8KS_b5Y#6{qx0m?^sWzITyDd3fQ}Pb<(k=tDka;@7m?nwqE_tqs7ji zF3x{{9IbsYce)b$@zp|kPO3#cPEq1Ju1h>Lx!>i%f9iB~Rob~NI}0*?-CgBU|Dz)I z`NIZ{p9dX#WMt+zTjotY(a6QQGp*%vjqaAzNmhpS&n`>yiT_&d9^4HIeA$m5HF@}w zo(L%WZ@uW|s5$k-N0CdH7iV-IyQ4Q{y+rlW-$g%rvQ_!Sm&r%m4x zzN&ibTRq3hT$L=AmCt$DU%78tVrJED2@Aurr=2OsKYTeio$pqR#w(4I0*Umk9ER)% z9b05Vjyi_OHM|SXjF#PaDcSyuDR0;xjlRCAcAD!ocK%zizv>p_Z0_3Iw_{Sygm4D5 z9p~Z`QV7>o_Kn>T*!)(;Yw~oB>B}cLxPK}A_}1yu<4jl2)aQo-ck;AzXJ&eQu`0RC z_L8eCQ-~oWcJG6Wn-}%j+3)Dg*_!&!rnRI_VV~ZvSdX2nez>PDuiSN(b+w6#kie!% zZ6)VEsj1w!Xi|LmY{~9Bks=`;v!7lo{VH^|d&jfmA8tQt3YAI<*~Ys5)=rOus-?nW zbzYi&!VG15nMI8K6@yjhFl5EKR0e%!<|_I0_L4xd%g49jGV{G|FU~t8%#<0}9opEW zVHa}Zh)&b%YrW#Js-9>2qZbt4RttS|&A{3D;pLoK;faer)(e>*4N&Y||8bqP`jVTj zCpVja_hV)<5df)pp{A6{)|w#wP-dZ%oBq4_>8f%Qn7W_DeEwAH?EL8R3pK6Ymn&3* z``N{pyPVvgclvviq2lX}K6}frS}@IbGr!pR^h&^{uN47zo&^7Wt>Vv;eC7D!YW0Tv zYwxYs9l3L4$*wED|jdsDLPTXC`LoaG{yX*@nen&!q)6xoU4{TV9MC!m+BtfGLh4C zYgX`$OGM->W-~2yUwCHzH{}4opij3}cobyXn`q8nw9G|I_GwWbmq;^f(Z(o= zyq7nIDo&sOm?boQ(#POQ5l8C~zV`r1iE)ENq^dRrcPs~{=f6_HvUc+7u| zo%W5l$_pwPOcU+r&Ai!N+H&)<@dCEblg%oXyLH61Zt&WMe^$tHI;v>wp0Y-4?`bJv zp3jrtO>0w`AGIQ3dqnQp&w;@^-l_!{RMyV8^W99T=a*;uo=ID(7B=1g;^*1BKFcjar_`x7$#y-gyJVQNd+~Ph8cC-^Y&;yoemcxQ_CzdII5TZ&tTfYS*}X6P zRqWy}U-{zPA+ydvg;V{5*Q$VGA;AkXL|pcC`aH2)RIlvAuAd~fYI8}*Ncw=c+fioNGwm0!tK3zfu@;%9G_DNxK{mgTYa3!WO85yqL;EdNRF-kR=& z{gVCcjo!2Za2=ewFeaZwR+`x=Gtu4fXu^QTFg6TuD)b4f4cvrgtNlU2LUlkE5tj^ zogEt`rZh&&TrJ*NTcr2OdDFpz9){BO6H}^h-JSbY*3i8)Z~mT{orgE(6d07PKOV25 zDN&%pr>N^*S~b7MGuL{qq~qp;4|7gczHyzjlyjTCsrTlVC01Mg*G>L*kV|F)FW@FW4E%3|Nrtkty>c;FveGA=zcZ)6g1u*t$0?h33yAuU4BJet2NU0b^Cs#4kMud5e@xHm66VLsuL-?5%V z*_+%q^Nr7cQ?{_Ledzgizc`QTy;)lvQbgppMeW?q_&fL6&3U%Yby04@d1uvsbk4ba z@JXmsor~U$#Q(|54;?-f#bWOnI^9iJ%=<`3*k-P;mwc9KKe@S-L+y=u&Bhti7sW3+ z)?Qe7DWmC=sBp5%OqTOA%?x)QXSjCB&2iIx!zr4dS*EJ^?8?s&Sk#l&9)9gle zoq+3|X4}6MD&9(+WH<9PTe0N>5ABPkQeS3YvrPDtlH1`~d+X?m^B=Zv)Hs;Zyi;bw zw#h9|Tt9jwO%1Hu6lVMD=OgB@!_0!~Z%tX?dFV-lGP}=BCRxQ}VUkbPU#BZKb_4}4 zOPJjgp6fNi>C}^kt;}g_Huv0AUcP2p^M}cRibL9bEz9oq}tm{q$(~D)O=!k)YV~<$Co^vMV%!aTMiZ+dB2~-J<_h{_~i|&-ZOd$O)sC+ zXTNH%;zhQ_%6wa|)TaxiRyK-m%~5&v;FDi%muk+l?rl*H@AJN=38ac1TpJlAFwtVd zS!>T}AF894$bbBz*Ya}lCX4Mqy57YfRVp@nZ(?%jy;0CS*||1H+#`1dT-4mRD4zH1 z)DL2ThefPDyC$v`@2XaHfAdJ&%F$JU?VQr8Ck)enDqVQbou<^~)^X6rp|)_9k(goE zik)Y~*CkcQnV5fhkswrI%&Fyc?q&M%9}`d3EEH5yyfZW9^{U4QW_tz%PHTTs)+PV) zjJVk5$v^KE{QHt}XZmr~6)*0k#{AFu<6#$}(5-yme8$BvU&USe{oVl=?@4a&(5qV_ zr&Ghe`py3~@mt9ka;;W1&h!nK7%A(i(4x#>AH*+KPP1SKdoK?7vPK-I457 zw+_mE8fc~1thwk~PwJGo7tO7EEspO=-x2=Szif%r-^DDUY{4%2dqn;96jUUtH+YCY zpIN@Cs$u>ckKVWooU446b!2_>==QiJGIe4Lzu3t~0xSA|s;R9rn=IRzC}HI|^`gi{ z4;BgS_iK|L1}yAY*(Sv0$nCT2uuqxFvB@tSQ+#|Fr%pQ9zwbbqj*#G0jf<{MyPsW1 zaZgIsf_H5O^@F^ZvNairOJ7#)qA@KR;%_Teoxubkgjrc;md_>kr}2=lV$B~z8yTR ze(K%nr54HS+S+gSX)(Ne@uQc)PRT;0>gx3aee7!1a@GI-IG>zSo&4Q*CCkBb7 zi{rE!#1%S9ae6Xe7xDd=HKi3|G)d~>nCT= z{B3`{?q}+@KL?EW9$<`Fx8s7KX(X%akBO^)8411Ot2UNvU?lN0> zVWU>+y`K!VQ|9?pmn3Xk`(m?@cMrSvxtZPR{k5y zwx9XdTepEplx^#VCo8#@S)Ewae|(ZdRZYj-dv7e9#n&E4VAbGx_IXCJo=@on)s6cm zZOC-h_bUz%Z%`Mow>sFh+Q36?qHX1o5cZp9M~tIm7KwLX){)_1RCf3>_4?X`qoES# zU+*q*dvlTF_^Rr@7SFxOg|kFwGKf_ePBSV>%UpM;BF=vD%<>||b@N;QwejVjI3*~o z%_LS4xZbcRYw5Z}4D0)MWW=~Ld}{pHc4yurE%%f!e1~J~`30qS{y0@Jx9|G#*ENBw zSvP2WF%PLY9NuSB!ywFGm!@G>^ug=&>tF-1ugVu{9qOG6TGq=*zHMKrpc0yOc;R)F`IUZysXwHoeskuWI`MGjyFQ0{)s}|Wn^}a~4se?9OHZ#> z{&2=V^~r~`?QdHf^X$q?7SH-QBNp)<6SK-so&LxQzkBcHP!j=)M+{{y+0q$ zs`>xtox}ftZ0SwbZjzRpnrs3pd7oEv-8ojszDtL*wB)Le+c#}ZW%unyY`?U9qn(VF z&e>3SrcrM>vu#;cpYo<=9|_A{r!#Cc9S-H=6)I+_5}aYb<}TPh=Oc6M7KsUyq)&=PeRqx@`rHDQIKzJ?kLR0kH8Bb6N^|b!c-?>OKVyH3R_E_U8~Y---PoV`MokKt#%yTt z#dX)if=E~M%S@${R@^L_E*q^|esJEgr;!>QU5yLZ+s|a&F1J4UWBr06(NdLy8;MWc z|7^Z3Bb~8WL4(b(cA?9IZ!)hBoH+F?yR+~*ANPBu^L^LWs>Pjjb=(lBots%)BJzF1 zkCW~-rRITk%&Wtm?B1`*v0AW_|HePABL~)cb*)us-H&9LU%j>mSqzubIz ze>Cp!*xUI1jmQF5t{q2RE@kPQeekC6f!)iKJaP)5CpBXA&nD_}T~Jc}%48dKZN`re zHy_{Q%zbNp@eni11hv^&Ccjjh%a)vUT;P5xOZMc8H-!>TZ*p9@`S%=;c$i=-*+0S2 z`cj$F2j$eMS5LfnQ>cHof?3z5p=ax1#}wITi6s}_nKN-d^0-;}bxJFH(gW4Hjfa@? zn-ACJTCH2uT(;lTTfqI)B@K=V=e>_6x3U*Z+Ic&~?|7)B=_2?0T#q~=H%>XXYgZ@J z4ojx8zC~LL*v}diibg(9o?B|H_bW`m{glz+8pl^`dErN^D+}sE_WYWlSYlKgl0Bn) z&Xw&<_CaO-e3MIA7vD|Hm5t0;QZF$x>)e<5f@>2C5Wy=&pBlYO;69*N z%`w$IiPLLc_BH*-OALB_*|d+Y4w|XL^{Ui7^^NVVfP-3T9F~0*tg<4tt+#*6cXv

OU}+pn(DyX_(4heR!Q5eXy>&WA6Fl~&R23atY7cK-QYd%IP-URo6TKV z_E>M9=uxiK2MU>WRzFr+alq!mfA)(Hzt^qVXqCahz@S><8c~vxSdwa$T$GwvlFDFY zU}UOmXsByw6k=#>Wnye)WTtIkU}a#i-eYqSiiX_$l+3hB+#2qQa-U;hV9mdKI;Vst0GMxgqW}N^ literal 0 HcmV?d00001 diff --git a/package/voronoi/voronoi.sh b/package/voronoi/voronoi.sh new file mode 100644 index 0000000..2f50bc0 --- /dev/null +++ b/package/voronoi/voronoi.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Usage: ./voronoi_data.sh WIDTH HEIGHT "x1,y1 x2,y2 ..." + +if [ $# -lt 4 ]; then + printf 'Usage: %s WIDTH HEIGHT FADE "x1,y1 x2,y2 ..."\n' "$0" >&2 + exit 1 +fi + +W=$1 +H=$2 +FADE=$3 +PTS=$4 +C1=$5 +C2=$6 + +awk \ + -v W="$W" \ + -v H="$H" \ + -v PTS="$PTS" \ + -v FADE="$FADE" \ + -v C1="$C1" \ + -v C2="$C2" \ + -f ./voronoi.awk