From 3e32c00192902af145bcef5fca16abd816b1d9b7 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 14:19:06 +0100 Subject: [PATCH 01/18] choozi - Work indepent of the theme --- apps/choozi/appb2.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/choozi/appb2.js b/apps/choozi/appb2.js index 5f217f638..0ed4af25d 100644 --- a/apps/choozi/appb2.js +++ b/apps/choozi/appb2.js @@ -81,6 +81,7 @@ function arc(minR, maxR, minAngle, maxAngle) { // draw the arc segments around the perimeter function drawPerimeter() { + g.setBgColor('#000000'); g.clear(); for (var i = 0; i < N; i++) { g.setColor(colours[i%colours.length]); @@ -152,7 +153,7 @@ function choose() { // draw the current value of N in the middle of the screen, with // up/down arrows function drawN() { - g.setColor(g.theme.fg); + g.setColor('#ffffff'); g.setFont("Vector",fontSize); g.drawString(N,centreX-g.stringWidth(N)/2+4,centreY-fontSize/2); if (N < maxN) From b128d512a403746051e1d7168d2db62e39b05634 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 14:21:02 +0100 Subject: [PATCH 02/18] choozi - Do not keep backlight on --- apps/choozi/appb2.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/choozi/appb2.js b/apps/choozi/appb2.js index 0ed4af25d..20fbfb18a 100644 --- a/apps/choozi/appb2.js +++ b/apps/choozi/appb2.js @@ -187,7 +187,6 @@ function readN() { } shuffle(colours); // is this really best? -Bangle.setLCDTimeout(0); // keep screen on readN(); drawN(); From bca6722a1be92d2bb7b17a755fa12b4ed110b31e Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 14:23:16 +0100 Subject: [PATCH 03/18] choozi - Better colors for B2 and prefer solid colors --- apps/choozi/appb2.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/choozi/appb2.js b/apps/choozi/appb2.js index 20fbfb18a..f60c16300 100644 --- a/apps/choozi/appb2.js +++ b/apps/choozi/appb2.js @@ -4,7 +4,8 @@ * James Stanley 2021 */ -var colours = ['#ff0000', '#ff8080', '#00ff00', '#80ff80', '#0000ff', '#8080ff', '#ffff00', '#00ffff', '#ff00ff', '#ff8000', '#ff0080', '#8000ff', '#0080ff']; +var colours = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff']; +var colours2 = ['#808080', '#800080', '#808000', '#008080', '#ff4040', '#40ff40', '#4040ff']; var stepAngle = 0.18; // radians - resolution of polygon var gapAngle = 0.035; // radians - gap between segments @@ -32,12 +33,11 @@ var radians = 2*Math.PI; // radians per circle var defaultN = 3; // default value for N var minN = 2; -var maxN = colours.length; var N; var arclen; // https://www.frankmitchell.org/2015/01/fisher-yates/ -function shuffle (array) { +function shuffle(array) { var i = 0 , j = 0 , temp = null; @@ -187,6 +187,10 @@ function readN() { } shuffle(colours); // is this really best? +shuffle(colours2); +colours=colours.concat(colours2); +var maxN = colours.length; + readN(); drawN(); From 7c8d941e69448cc5a0f8cce7369fdb58bfd2863f Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 15:42:35 +0100 Subject: [PATCH 04/18] choozi - Recombine code for B1/B2 and use setUI --- apps/choozi/README.md | 9 +- apps/choozi/app.js | 52 +++++----- apps/choozi/appb2.js | 211 -------------------------------------- apps/choozi/metadata.json | 3 +- 4 files changed, 35 insertions(+), 240 deletions(-) delete mode 100644 apps/choozi/appb2.js diff --git a/apps/choozi/README.md b/apps/choozi/README.md index f1e4255bc..8d0aa97f4 100644 --- a/apps/choozi/README.md +++ b/apps/choozi/README.md @@ -11,16 +11,21 @@ the players seated in a circle, set the number of segments equal to the number of players, ensure that each person knows which colour represents them, and then choose a segment. After a short animation, the chosen segment will fill the screen. -You can use Choozi to randomly select an element from any set with 2 to 13 members, +You can use Choozi to randomly select an element from any set with 2 to 14 members, as long as you can define a bijection between members of the set and coloured segments on the Bangle.js display. -## Controls +## Controls Bangle 1 BTN1: increase the number of segments BTN2: choose a segment at random BTN3: decrease the number of segments +## Controls Bangle 2 + +Swipe up/down: increase/decrease the number of segments +BTN1 or tap: choose a segment at random + ## Creator James Stanley diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 1a5b2f17e..8ba040aab 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -5,14 +5,15 @@ * James Stanley 2021 */ -var colours = ['#ff0000', '#ff8080', '#00ff00', '#80ff80', '#0000ff', '#8080ff', '#ffff00', '#00ffff', '#ff00ff', '#ff8000', '#ff0080', '#8000ff', '#0080ff']; +var colours = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff']; +var colours2 = ['#808080', '#800080', '#808000', '#008080', '#ff4040', '#40ff40', '#4040ff']; var stepAngle = 0.18; // radians - resolution of polygon var gapAngle = 0.035; // radians - gap between segments -var perimMin = 110; // px - min. radius of perimeter -var perimMax = 120; // px - max. radius of perimeter +var perimMin = g.getWidth()*0.44; // px - min. radius of perimeter +var perimMax = g.getWidth()*0.49; // px - max. radius of perimeter -var segmentMax = 106; // px - max radius of filled-in segment +var segmentMax = g.getWidth()*0.42; // px - max radius of filled-in segment var segmentStep = 5; // px - step size of segment fill animation var circleStep = 4; // px - step size of circle fill animation @@ -22,10 +23,10 @@ var minSpeed = 0.001; // rad/sec var animStartSteps = 300; // how many steps before it can start slowing? var accel = 0.0002; // rad/sec/sec - acc-/deceleration rate var ballSize = 3; // px - ball radius -var ballTrack = 100; // px - radius of ball path +var ballTrack = g.getWidth()*0.40; // px - radius of ball path -var centreX = 120; // px - centre of screen -var centreY = 120; // px - centre of screen +var centreX = g.getWidth()*0.5; // px - centre of screen +var centreY = g.getWidth()*0.5; // px - centre of screen var fontSize = 50; // px @@ -33,7 +34,6 @@ var radians = 2*Math.PI; // radians per circle var defaultN = 3; // default value for N var minN = 2; -var maxN = colours.length; var N; var arclen; @@ -82,6 +82,7 @@ function arc(minR, maxR, minAngle, maxAngle) { // draw the arc segments around the perimeter function drawPerimeter() { + g.setBgColor('#000000'); g.clear(); for (var i = 0; i < N; i++) { g.setColor(colours[i%colours.length]); @@ -131,6 +132,7 @@ function animateChoice(target) { g.fillCircle(x, y, ballSize); oldx=x; oldy=y; + if (process.env.HWVERSION == 2) g.flip(); } } @@ -186,23 +188,23 @@ function readN() { } shuffle(colours); // is this really best? -Bangle.setLCDMode("direct"); -Bangle.setLCDTimeout(0); // keep screen on +shuffle(colours2); +colours=colours.concat(colours2); +var maxN = colours.length; +if (process.env.HWVERSION == 1){ + Bangle.setLCDMode("direct"); + Bangle.setLCDTimeout(0); // keep screen on +} readN(); drawN(); -setWatch(() => { - setN(N+1); - drawN(); -}, BTN1, {repeat:true}); - -setWatch(() => { - writeN(); - drawPerimeter(); - choose(); -}, BTN2, {repeat:true}); - -setWatch(() => { - setN(N-1); - drawN(); -}, BTN3, {repeat:true}); +Bangle.setUI("updown", (v)=>{ + if (!v){ + writeN(); + drawPerimeter(); + choose(); + } else { + setN(N+v); + drawN(); + } +}); diff --git a/apps/choozi/appb2.js b/apps/choozi/appb2.js deleted file mode 100644 index f60c16300..000000000 --- a/apps/choozi/appb2.js +++ /dev/null @@ -1,211 +0,0 @@ -/* Choozi - Choose people or things at random using Bangle.js. - * Inspired by the "Chwazi" Android app - * - * James Stanley 2021 - */ - -var colours = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff']; -var colours2 = ['#808080', '#800080', '#808000', '#008080', '#ff4040', '#40ff40', '#4040ff']; - -var stepAngle = 0.18; // radians - resolution of polygon -var gapAngle = 0.035; // radians - gap between segments -var perimMin = 80; // px - min. radius of perimeter -var perimMax = 87; // px - max. radius of perimeter - -var segmentMax = 70; // px - max radius of filled-in segment -var segmentStep = 5; // px - step size of segment fill animation -var circleStep = 4; // px - step size of circle fill animation - -// rolling ball animation: -var maxSpeed = 0.08; // rad/sec -var minSpeed = 0.001; // rad/sec -var animStartSteps = 300; // how many steps before it can start slowing? -var accel = 0.0002; // rad/sec/sec - acc-/deceleration rate -var ballSize = 3; // px - ball radius -var ballTrack = 75; // px - radius of ball path - -var centreX = 88; // px - centre of screen -var centreY = 88; // px - centre of screen - -var fontSize = 50; // px - -var radians = 2*Math.PI; // radians per circle - -var defaultN = 3; // default value for N -var minN = 2; -var N; -var arclen; - -// https://www.frankmitchell.org/2015/01/fisher-yates/ -function shuffle(array) { - var i = 0 - , j = 0 - , temp = null; - - for (i = array.length - 1; i > 0; i -= 1) { - j = Math.floor(Math.random() * (i + 1)); - temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } -} - -// draw an arc between radii minR and maxR, and between -// angles minAngle and maxAngle -function arc(minR, maxR, minAngle, maxAngle) { - var step = stepAngle; - var angle = minAngle; - var inside = []; - var outside = []; - var c, s; - while (angle < maxAngle) { - c = Math.cos(angle); - s = Math.sin(angle); - inside.push(centreX+c*minR); // x - inside.push(centreY+s*minR); // y - // outside coordinates are built up in reverse order - outside.unshift(centreY+s*maxR); // y - outside.unshift(centreX+c*maxR); // x - angle += step; - } - c = Math.cos(maxAngle); - s = Math.sin(maxAngle); - inside.push(centreX+c*minR); - inside.push(centreY+s*minR); - outside.unshift(centreY+s*maxR); - outside.unshift(centreX+c*maxR); - - var vertices = inside.concat(outside); - g.fillPoly(vertices, true); -} - -// draw the arc segments around the perimeter -function drawPerimeter() { - g.setBgColor('#000000'); - g.clear(); - for (var i = 0; i < N; i++) { - g.setColor(colours[i%colours.length]); - var minAngle = (i/N)*radians; - arc(perimMin,perimMax,minAngle,minAngle+arclen); - } -} - -// animate a ball rolling around and settling at "target" radians -function animateChoice(target) { - var angle = 0; - var speed = 0; - var oldx = -10; - var oldy = -10; - var decelFromAngle = -1; - var allowDecel = false; - for (var i = 0; true; i++) { - angle = angle + speed; - if (angle > radians) angle -= radians; - if (i < animStartSteps || (speed < maxSpeed && !allowDecel)) { - speed = speed + accel; - if (speed > maxSpeed) { - speed = maxSpeed; - /* when we reach max speed, we know how long it takes - * to accelerate, and therefore how long to decelerate, so - * we can work out what angle to start decelerating from */ - if (decelFromAngle < 0) { - decelFromAngle = target-angle; - while (decelFromAngle < 0) decelFromAngle += radians; - while (decelFromAngle > radians) decelFromAngle -= radians; - } - } - } else { - if (!allowDecel && (angle < decelFromAngle) && (angle+speed >= decelFromAngle)) allowDecel = true; - if (allowDecel) speed = speed - accel; - if (speed < minSpeed) speed = minSpeed; - if (speed == minSpeed && angle < target && angle+speed >= target) return; - } - - var r = i/2; - if (r > ballTrack) r = ballTrack; - var x = centreX+Math.cos(angle)*r; - var y = centreY+Math.sin(angle)*r; - g.setColor('#000000'); - g.fillCircle(oldx,oldy,ballSize+1); - g.setColor('#ffffff'); - g.fillCircle(x, y, ballSize); - oldx=x; - oldy=y; - g.flip(); - } -} - -// choose a winning segment and animate its selection -function choose() { - var chosen = Math.floor(Math.random()*N); - var minAngle = (chosen/N)*radians; - var maxAngle = minAngle + arclen; - animateChoice((minAngle+maxAngle)/2); - g.setColor(colours[chosen%colours.length]); - for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep) - arc(i, perimMax, minAngle, maxAngle); - arc(0, perimMax, minAngle, maxAngle); - for (var r = 1; r < segmentMax; r += circleStep) - g.fillCircle(centreX,centreY,r); - g.fillCircle(centreX,centreY,segmentMax); -} - -// draw the current value of N in the middle of the screen, with -// up/down arrows -function drawN() { - g.setColor('#ffffff'); - g.setFont("Vector",fontSize); - g.drawString(N,centreX-g.stringWidth(N)/2+4,centreY-fontSize/2); - if (N < maxN) - g.fillPoly([centreX-6,centreY-fontSize/2-7, centreX+6,centreY-fontSize/2-7, centreX, centreY-fontSize/2-14]); - if (N > minN) - g.fillPoly([centreX-6,centreY+fontSize/2+5, centreX+6,centreY+fontSize/2+5, centreX, centreY+fontSize/2+12]); -} - -// update number of segments, with min/max limit, "arclen" update, -// and screen reset -function setN(n) { - N = n; - if (N < minN) N = minN; - if (N > maxN) N = maxN; - arclen = radians/N - gapAngle; - drawPerimeter(); -} - -// save N to choozi.txt -function writeN() { - var file = require("Storage").open("choozi.txt","w"); - file.write(N); -} - -// load N from choozi.txt -function readN() { - var file = require("Storage").open("choozi.txt","r"); - var n = file.readLine(); - if (n !== undefined) setN(parseInt(n)); - else setN(defaultN); -} - -shuffle(colours); // is this really best? -shuffle(colours2); -colours=colours.concat(colours2); -var maxN = colours.length; - -readN(); -drawN(); - -setWatch(() => { - writeN(); - drawPerimeter(); - choose(); -}, BTN1, {repeat:true}); - -Bangle.on('touch', function(zone,e) { - if(e.x>+88){ - setN(N-1); - drawN(); - }else{ - setN(N+1); - drawN(); - } -}); diff --git a/apps/choozi/metadata.json b/apps/choozi/metadata.json index 79af76fa2..f0d309560 100644 --- a/apps/choozi/metadata.json +++ b/apps/choozi/metadata.json @@ -10,8 +10,7 @@ "allow_emulator": true, "screenshots": [{"url":"bangle1-choozi-screenshot1.png"},{"url":"bangle1-choozi-screenshot2.png"}], "storage": [ - {"name":"choozi.app.js","url":"app.js","supports": ["BANGLEJS"]}, - {"name":"choozi.app.js","url":"appb2.js","supports": ["BANGLEJS2"]}, + {"name":"choozi.app.js","url":"app.js"}, {"name":"choozi.img","url":"app-icon.js","evaluate":true} ] } From 4c16e3163141d98f3cec8baeef1b23d168cb4978 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 16:38:07 +0100 Subject: [PATCH 05/18] choozi - Better colors --- apps/choozi/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 8ba040aab..ff8b18e91 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -6,7 +6,7 @@ */ var colours = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff']; -var colours2 = ['#808080', '#800080', '#808000', '#008080', '#ff4040', '#40ff40', '#4040ff']; +var colours2 = ['#808080', '#404040', '#000040', '#004000', '#400000', '#ff8000', '#804000', '#4000c0']; var stepAngle = 0.18; // radians - resolution of polygon var gapAngle = 0.035; // radians - gap between segments From 5307fc83c7adba71a3c1f97162612c94f42e6638 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 16:38:49 +0100 Subject: [PATCH 06/18] choozi - Bigger segments to make distiguishing dithered colors easier --- apps/choozi/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index ff8b18e91..18d91cd34 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -10,10 +10,10 @@ var colours2 = ['#808080', '#404040', '#000040', '#004000', '#400000', '#ff8000' var stepAngle = 0.18; // radians - resolution of polygon var gapAngle = 0.035; // radians - gap between segments -var perimMin = g.getWidth()*0.44; // px - min. radius of perimeter +var perimMin = g.getWidth()*0.40; // px - min. radius of perimeter var perimMax = g.getWidth()*0.49; // px - max. radius of perimeter -var segmentMax = g.getWidth()*0.42; // px - max radius of filled-in segment +var segmentMax = g.getWidth()*0.38; // px - max radius of filled-in segment var segmentStep = 5; // px - step size of segment fill animation var circleStep = 4; // px - step size of circle fill animation @@ -23,7 +23,7 @@ var minSpeed = 0.001; // rad/sec var animStartSteps = 300; // how many steps before it can start slowing? var accel = 0.0002; // rad/sec/sec - acc-/deceleration rate var ballSize = 3; // px - ball radius -var ballTrack = g.getWidth()*0.40; // px - radius of ball path +var ballTrack = perimMin - ballSize*2; // px - radius of ball path var centreX = g.getWidth()*0.5; // px - centre of screen var centreY = g.getWidth()*0.5; // px - centre of screen From f01a673effd8e53879e51108440a674f1176a0f8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 16:39:11 +0100 Subject: [PATCH 07/18] choozi - Fix direction of UI --- apps/choozi/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 18d91cd34..5370da714 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -204,7 +204,7 @@ Bangle.setUI("updown", (v)=>{ drawPerimeter(); choose(); } else { - setN(N+v); + setN(N-v); drawN(); } }); From 7da2e3857e9aea84f9adfcad1ff429abe4bf73ba Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 16:41:57 +0100 Subject: [PATCH 08/18] choozi - Update screenshots --- apps/choozi/bangle1-choozi-screenshot1.png | Bin 3893 -> 3859 bytes apps/choozi/bangle1-choozi-screenshot2.png | Bin 3822 -> 3718 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/choozi/bangle1-choozi-screenshot1.png b/apps/choozi/bangle1-choozi-screenshot1.png index 104024958033693784f6457771d2343d0eb5340c..ee422ed10d90832816e05b4b34eb4aaffa3f8a40 100644 GIT binary patch delta 3848 zcmX|?cTiIc)5gz9LPw-XlVU93h0v~4DNCDxaSku#FXUXe-KJHO6Xh@5_x67lKW1(XAJd8_p*;jIN2sc!BE zy6*IkjEwv~@w@AQBsw8UXa~tos(7oJ1-}*o@-Cti7(##%kMpx>J$-ZQ%gzroNX$RU z7J$8SI1|>6=pd*M`SsBp;lUnu<@Y4}H2xcYuIyr4?2a>V&&JpY@Au085^4<(b}RDZ z^A)K!FN9^@4F*$5C~|$rlHi6qw&mLut548g_FT7^J+SEZ7rwZ6fgJ#>Fa(E-*65E# zW=l0dnxsOw(?tanf$povf5z-1`*RS>cCOo9x3-R*gaA+LwJ0Fm=Hf>a{_ZeyNJQ98YA_oPEzFq-E z@jcPr8l5N)b{rG~ZU5ZzEHiIw{6L(b)&D|$zrD#jFWapNyoPpMhR0tQ&r8F{!2`tc znI4E};ik-0TEW7Nzoi&k;-18D`;1;heA0Gk@M+mTfel{TQQp}3%HaoC#EA~9Y+vZ+ z!m=#rl?* zz5kk1o)Xt@fe{Dc!C*+L(5Kr{42gcBVd07`WIES1K4=GJ-O*? zsY2Y%>r9u)Z4NM?OOjsEX`Fz3S$C+yu{){TJS*teb(okWG?fGtxqMfB zxR43TNS5Dk(!(3CSk=p#m8yH|!c3Md?X(KPu6KXUn{U-Z5S~l8tW=h&>aeHA7|%^* z9!L~A;vjTQ4Gt;bd)e9}o|B^A`0*uKa~G(fTdL5Hj}b&}$2bRymgZR8V5pPZD;&c_ zDH&vG?+2B{pk0;p%jUTZ7m0hw=i3I-4)|etiF*kCump92DIWk0QBL6e3kpp?4?58gZ$N@q2cu?p;t(|&2tXfqnyhK7x8;Uya*gpR5qWU$R}BCLEEmM z2!&-xVZk6iA=M}41xf>e1~z7(3g{xhzcRlXF-Abhq_6-S(UZHJgPvJY6_@8Z3NZOa z$5THYbDY~rLI5A{ldN+`*NOmtXIG;28>5<)@(X+-)rJm#9@AIQ9Ag|hM{ zsS(uEgC6rR(4e`$N(KX-W7PF`d?L3iROB@&Y@_tR{`ji`p2}ajf_Ri-)A(YXM1dXAO)| zc)D*bZf-E2s>;dKGDYPr7c{cR%*V{3oamo3=f3rgPWS19=|r!aFwwKks&%66H(2A{ z7xsHfBQCo_OB6rHNW8z9BFkvG_w-Bh$zAK`_c1XvG_&W&iI*~*Q20^*YamDar7jJf z(~nc&4qWF>$+(K>kfxw}fhg^isq3#Fln*3;lsb?5XA$O-AFN^<9-LT$U0It8m!@Q; zEfDpRKzQZ4kHH?PYU{<133K#4nAV<$;Hb}&e82ao4q$q#(J$do3=8!S(r=rBv$((f zn5@F-^v73qLT3=ZU|n3p3!V79cGa1> z3g?6ITcVWzSa8m<+OG(7-4Y~8wQ{lA7;EJ;-u}f2C*BPN9lwmi^6&rpRE=s^Qh4ew+U$ZPwIy-9K70FZg^ z6gU+1q&fCI3UIsbo_{3^1^nMp6oTVc^)1PdM7k+IRR30)8NfZu^2Ag`D(u8l=%uWy z(>W2qC{*%1uk`2$#up0;iPOKc>d=cyOPNGRYg7+$D9Z7+QEZ@%y4Q~xH2 z$Vy$RI}gAc`MFJ;cl`(`v@4z`cestat8VCT{5}2x`Iz+=krMZ|z)}>y)$#!myK%vU z+kY>5G$*#n-CEI7)T1bfn}NU=LG?tX?D6giDM%L%Dbep;l=e2JdT?Ax)Q3hl*cG@> zBCWmM=_&0Mt@EyAs)xQ9KtJcUuwg;LIX=d0^7<6~r!veU0q3Y|^7MGbd+<~8LN19V zAH-40{BtPbi}j$UrC&o9S(RNeGd>b00Gh74)Jf^i{6&sMJR;egwu6A@BE7l5VLy8S z9(N4$>CA{~Zr(gAbP6_UPG&B{B?Y(7`oeCtsu}yL4ZK^znYWgS;}^JEM0_YroUj+K z?bAPw4`mQ1D9Nk|`r!%pMR=Gz*P(>=DY_~F52ws^xQNhJ<7_%x|4pdhrNf-;Hg5DL zTNc)fH?M4=4nZ8&A`BF3Bm24^0pwh#w3&&iS)&U_63R(@#?_}~r=y&o3CsJafuXe4 z0kf@6QR=bkJkGLSE;B9b(NX+`FRj~HaF=8{(&NStK*n>J)sNvRc*9SHoY~n!PQsD+ z3N4L4r=Ci8y<$jq-*TE&VVX7CeUiZi^Q-5OuSi4K`a|tvcCuQIy_#iL`JCsy9OQIT zaE@`Awz!Gxd3pyfpyA```KBqoW1K4pJ6VDndh1ywfDJ8LxrPaOGRNo%Ze}g*wvHOh zA}A8r*8K#NiFYLF#t%$)IYuZS!Oqmg0}1E!ccRD2r*4!v!Z>lAlo4CEylNGXrPRw% z?A`UekkW1$_1l*^jyP0GJ^*lGrS;~U9iI;y9?P`Qr&;3y(q&yYgU><(p-)|n^e!W$ zdHazYvmHc^Luw)6?S887fIMNB#D0BbqgFXwlV?oCQ?){rf^oWDs$(Ek3NL==#p+W- zPV!*MIirv#W{n?dqv}B$E3b?vBB4bXT_x6YHJ-)g2Ns))o-4$lKehPT&@6#O=ZbQZ z`wK#Yllhxb=ae2NJPvykqjpHcMj#^M`dU?<;JE5O!SEz|QSaj((TAftA6!;x-xX08 zgYS!utt`lihwo!#p70N5XXPauvIR$`yA%@<{57X)oD@5y!u4ngV^#;Up+_?jJYUt# zz2tOgg*~`w!YfZrAxQxn%Z&5AH!$U8-VxfXL5ATr+osw!j0-$faPjVUK6Z>3=(15V zDY$Go=ICy8Z0r=-O#CrBPQx9&VoARh^H;qAXO@%&Hdvbq=B3g2N&HnOW&6m62k{t2 z7D>B!kf~0ab-{!`XobRMXtp2@J%)NGvprMRuQi%gl=jupSZa(x)|U|BERE)u!t~*k zKiV?;ZW|tFZ~vnX{R)!yuFv&!J+5SCD|omsrBM*yL!b=BQI!LAZ#7uQ@B(UAFBD5J zo2A0zXQQt0sK4TUg;pkwIPYr*Hc%DS*?nn^4g&FRtSgKJ2uP2;5g54`aHhYOl-WKz z?*!xaasSCNmLHQ~yQk&H%2Xj5XJvjg2icrR_tXe{uJxI3p505SOJ4~hiQHu8YwEKM zfBM6399s^Jsw#aKKE^UM8{0;SHGItG8O*`{DRcBIU~c~4n^UQA@_{~Imiylj$1`7D zR4Q5bI}t7j?Ew!^__eDLxpVAFkfc+ddIvOGd1;U|!c}3Ojzbt7V80CqV=q@(r0tb& zf(BFk@#rprnAVdY=x#>=&und_E%k$}*8QqK)O=nastR%Qj(M5G1vR#4Nxp7g7zFS&hD?M{Ycf`WButo!ymPLnHFPlvdz_}7?iVo7cct^cO$iE0b{i1}x zw^G)tUfohmiC*wBI!4~pIeqa6x(FbbO8J^f>e#V=r)y-Gy~oqbfZeb?ZGWoD3J>1; E9|_G-F#rGn literal 3893 zcmW+(c|6qJ_rLR*#xj;hj4d&RFq5S`wv?tGSwpt5)fgU$P?nZKrq5WONK$$1`yNIV zF_`p8gG!bbX=Sn|WNaa+-+X_6+kyNWIkss&_mv+G@#X9H4p!{N7xtGpsl>m&ro<)mCz*^1lv} z;PfwEi}!|pOUz$s@c^S3@O$mof#E-m^8ThmJkR2d2&F*k-RgO>``I-MTyW^|CNocz z3!4g^m=m5oxpERSYK?86$~_LNQ{>h7N9*6Jq0s$HZ!tE~;IV#q1&6#fCe= z(O(V@+calgHH(y~2Q8ikIwGOEoGT;dQ}+nBmWlO>+)f}gOpU91bp?M@3?{|Gaao;RX4#?9jtk;Ra@DdjM4OYtr8^vAmkp+SNqBu`)R$V`mtd*YbR z#vz=O7+(g~rHYFJ%`V=&l?EMs*J^GbKVD6I--~=$Aqb0$v1T;4eyzS^|X&y9RPIdjy z8U50T%Ct&MK?ywHnhZ0{2Wk*CfIe3z_0`*rshKE2s+XlT^<9{=8MnlmlY_VD@qGhj z0PO$_b>jK|zAJ*9W0Iq9@Kf;o_;(7lzK2~@A9fiwfbc!ityP+4C&*DoRb`>D0f2Gv zSjfifMsR=-DV_v5VE)1hgJUb56`G-yNI;?~Q4fr$r;e18odjG5mB22{TR0;M4P@+2 zy{LIpoW|?Cty$zsli^C><>3d0|GkHWxOmSdLb6yHko7I-RzO#l8_G5jgU|YAT9@wb z5f3GyDt=nX$C}J&(J=SIFhaa2%C1on%r;1zBV|GBYsFgaY>&D(RsjX|Jpw0&Y|NF5 zVHsYHoauGJD-}UoP5xS29b4FtTfY^6e`$eT@W2c45?Lm_>+!3bXs&$;sZv2i@8juH zI!*>79b()nrzKT+E#&maugO?(B=R+5$9pLbInOB9DKWL_r4Wc{f9{t;qBD)1E871- z@$w?WQf(kzTwCSD#SRo`h-r7t7t*Aa2}&r9;6Ib~#0p}UD(!nQDyVa~Fb+iz8>|1N zgq4T()V9~f_6Z0fKZ3xgx}B;;COukGh^JMHln{wD zP~Z47{C8~t&bO}?Rz-pfBfOYji9`ZM;4~akTrTJZNijZai9|?PixI$nnYda$%~W`E zyL@^8_5WDAw7HW6j#$2d{vulm_;2iSxawdl!QMz*D|zH_qpZOS#VCw3@(KvV2+;!f zSv1d}wz-5x-XCVqdKjn#s@l_)=Ttrg3s#~=t za8P%9-?a@cOdgYMb-#vUyLTu)afM#!^DOc|x1s9W#&=3Xp^39&8W`S!;^{0DtncST z7QX~W4*HHp&ckKm^4nnH#2gdLB7#@;2{`@Lep7 z?o=^;png8%ABhu-Ie&Wr&Pc+N@Tswfexmsk?hDV4$ufm#@59y?0FR#LE`U)u`_hgA zBu#xe$b>SmAg|SO2pC7k?(djMkf)n+SHEEqs?A3KYjja(?up+dYN!P$FrB_cXkt+p z75#hI%YnxMyxpAi1_O(!*QmRIvyQbC72CwB_M~v#_*I34sha-|SlIk`;HV~G;cA?m zwU9>)bZ9xJpz{NIU%F8-8W{UHDIIwQi?by~1M`oF@gtO*Ue=zOni*Qk(i%ArM!=Ks6y3o`R2a|QrFR>NA&luQ7@WQUqn~^1o zvB%%+*ihna?&^-#Q&#ucBO^i~WBGMMW^3KvIWzO8nW~WY8U&pF5`1LKB??ZiwwA%ZPate0EezGUljTWRnJV67T?K~r>CiV zV&}jAif&DqRLa})_<87BvXaf?l3ZJqnemUj-@+ptibDQi`+6#&V(~}dewGo~n%1<8 zcqKB80*U2(<={fQrh!7E9P0-=S>0ozd-=OBLO{b_vbY$@7YKoa@DBKvI`u?Xev z7=xlaJ*sE@w!HE#!% z=~c~d*m}ine_!s4%cZdFFlvfAgcau!_NEI`3Wwxh_4ZvkTVBO=e$TkksTMbMN^G+) z@5jAYZ7Lt9O*q~Ryy%w;81@B{ox0As&7Wce9j0raW*9=l_Eze5=cmdkH|43T*iQ}l z{-lR8h6~9dsG)m{t=_(2Rrq=9T{z+ZcHRaw7bI12k4V2_*)fms{|zaQ?&p#}P1;3$ z);umgECZaA9upHF%ojVf9;THC!xFT}CGOwb-L?nGOVNnyKVwphlZ$Vjm5nN#89wvER)w;>ma;T8Ls*&mYDbsg z9(}BRNlg2mh1gSsV0ggm}%$Ji9&Rc%VoE*f^X4= zDj$RFc2h%Yk%zS%KL?&KyJL9~Yo5yFlT-3VsVfR7ZIHRnQIOWGP%NFfL+lBg^kPns z_yKe`{oLk)n)&k?!fP84m$6;DDrivRtHkVcIf^9%;-Otjj;((PpJcS?JLO`3TA4L! ze+2x5oR|J7>;-CAZw5Is6@x&X4LP2;sOjDBFR3bUF|?zyz+)%H(iurl7DmEr8I4;e zExzca?rG`&^MmwVMGD?9P+GLOb=dvXzeS@>m00-W1JhaSQ|)pxw0VQuO@LPAlrjhQ z|0%uK^`_#h5OO2X9pg`A6;^?F4l|GZb1(sLioO)+4)p#hF41Um9gUbQ7G3l8n-DtY eO6=JFMh5d6vj diff --git a/apps/choozi/bangle1-choozi-screenshot2.png b/apps/choozi/bangle1-choozi-screenshot2.png index f3b6868bf9587e9939785ea901c57213dad56281..20edf4c7860746c8005d5e41793174a324cde94f 100644 GIT binary patch delta 3705 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 Jy#?*s{{cC|)F}V} From f8d241bac4dab65f899e8749d186bee005b6fbfc Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 20:08:01 +0100 Subject: [PATCH 09/18] choozi - Prefer undithered colors only on B2 --- apps/choozi/app.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 5370da714..4c3f47071 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -187,9 +187,16 @@ function readN() { else setN(defaultN); } -shuffle(colours); // is this really best? -shuffle(colours2); -colours=colours.concat(colours2); + +if (process.env.HWVERSION == 1){ + colours=colours.concat(colours2); + shuffle(colours); +} else { + shuffle(colours); + shuffle(colours2); + colours=colours.concat(colours2); +} + var maxN = colours.length; if (process.env.HWVERSION == 1){ Bangle.setLCDMode("direct"); From f467227d8d37b317d80b7bebd567cece7888ffb8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 20:32:53 +0100 Subject: [PATCH 10/18] choozi - Extract drawing of arcs into lib for others to use --- apps/choozi/app.js | 37 ++++--------------------------------- modules/graphics_utils.js | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 33 deletions(-) create mode 100644 modules/graphics_utils.js diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 4c3f47071..725c4969a 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -4,7 +4,7 @@ * * James Stanley 2021 */ - +const GU = require("graphics_utils"); var colours = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff', '#ffffff']; var colours2 = ['#808080', '#404040', '#000040', '#004000', '#400000', '#ff8000', '#804000', '#4000c0']; @@ -51,35 +51,6 @@ function shuffle (array) { } } -// draw an arc between radii minR and maxR, and between -// angles minAngle and maxAngle -function arc(minR, maxR, minAngle, maxAngle) { - var step = stepAngle; - var angle = minAngle; - var inside = []; - var outside = []; - var c, s; - while (angle < maxAngle) { - c = Math.cos(angle); - s = Math.sin(angle); - inside.push(centreX+c*minR); // x - inside.push(centreY+s*minR); // y - // outside coordinates are built up in reverse order - outside.unshift(centreY+s*maxR); // y - outside.unshift(centreX+c*maxR); // x - angle += step; - } - c = Math.cos(maxAngle); - s = Math.sin(maxAngle); - inside.push(centreX+c*minR); - inside.push(centreY+s*minR); - outside.unshift(centreY+s*maxR); - outside.unshift(centreX+c*maxR); - - var vertices = inside.concat(outside); - g.fillPoly(vertices, true); -} - // draw the arc segments around the perimeter function drawPerimeter() { g.setBgColor('#000000'); @@ -87,7 +58,7 @@ function drawPerimeter() { for (var i = 0; i < N; i++) { g.setColor(colours[i%colours.length]); var minAngle = (i/N)*radians; - arc(perimMin,perimMax,minAngle,minAngle+arclen); + GU.drawArc(g, perimMin,perimMax,minAngle,minAngle+arclen); } } @@ -144,8 +115,8 @@ function choose() { animateChoice((minAngle+maxAngle)/2); g.setColor(colours[chosen%colours.length]); for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep) - arc(i, perimMax, minAngle, maxAngle); - arc(0, perimMax, minAngle, maxAngle); + GU.drawArc(g, i, perimMax, minAngle, maxAngle); + GU.drawArc(g, 0, perimMax, minAngle, maxAngle); for (var r = 1; r < segmentMax; r += circleStep) g.fillCircle(centreX,centreY,r); g.fillCircle(centreX,centreY,segmentMax); diff --git a/modules/graphics_utils.js b/modules/graphics_utils.js new file mode 100644 index 000000000..8e4b893ba --- /dev/null +++ b/modules/graphics_utils.js @@ -0,0 +1,27 @@ +// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle +exports.drawArc = function(graphics, minR, maxR, minAngle, maxAngle) { + var step = stepAngle; + var angle = minAngle; + var inside = []; + var outside = []; + var c, s; + while (angle < maxAngle) { + c = Math.cos(angle); + s = Math.sin(angle); + inside.push(centreX+c*minR); // x + inside.push(centreY+s*minR); // y + // outside coordinates are built up in reverse order + outside.unshift(centreY+s*maxR); // y + outside.unshift(centreX+c*maxR); // x + angle += step; + } + c = Math.cos(maxAngle); + s = Math.sin(maxAngle); + inside.push(centreX+c*minR); + inside.push(centreY+s*minR); + outside.unshift(centreY+s*maxR); + outside.unshift(centreX+c*maxR); + + var vertices = inside.concat(outside); + graphics.fillPoly(vertices, true); +} \ No newline at end of file From 6539dc48b1985f4cafbe39c00df97f194e458ad6 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 21:05:24 +0100 Subject: [PATCH 11/18] choozi - Save into normal file instead of storage file --- apps/choozi/app.js | 11 ++++------- apps/choozi/metadata.json | 3 +++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 725c4969a..9842c8d5a 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -144,21 +144,18 @@ function setN(n) { drawPerimeter(); } -// save N to choozi.txt +// save N to choozi.save function writeN() { - var file = require("Storage").open("choozi.txt","w"); - file.write(N); + require("Storage").write("choozi.save","" + N); } -// load N from choozi.txt +// load N from choozi.save function readN() { - var file = require("Storage").open("choozi.txt","r"); - var n = file.readLine(); + var n = require("Storage").read("choozi.save"); if (n !== undefined) setN(parseInt(n)); else setN(defaultN); } - if (process.env.HWVERSION == 1){ colours=colours.concat(colours2); shuffle(colours); diff --git a/apps/choozi/metadata.json b/apps/choozi/metadata.json index f0d309560..d997534e8 100644 --- a/apps/choozi/metadata.json +++ b/apps/choozi/metadata.json @@ -12,5 +12,8 @@ "storage": [ {"name":"choozi.app.js","url":"app.js"}, {"name":"choozi.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"choozi.save"} ] } From 6204206df321fbfe268379acc34c630ed7e5ba1d Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 21:11:59 +0100 Subject: [PATCH 12/18] choozi - Only write if actually changed --- apps/choozi/app.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 9842c8d5a..478cef009 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -146,14 +146,19 @@ function setN(n) { // save N to choozi.save function writeN() { - require("Storage").write("choozi.save","" + N); + var savedN = read(); + if (savedN != N) require("Storage").write("choozi.save","" + N); +} + +function read(){ + var n = require("Storage").read("choozi.save"); + if (n !== undefined) return parseInt(n); + return defaultN; } // load N from choozi.save function readN() { - var n = require("Storage").read("choozi.save"); - if (n !== undefined) setN(parseInt(n)); - else setN(defaultN); + setN(read()); } if (process.env.HWVERSION == 1){ From c0be24a5520a444c229d9ab2ffc031b48b8fe2d9 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 21:27:33 +0100 Subject: [PATCH 13/18] choozi - New icons --- apps/choozi/app-icon.js | 2 +- apps/choozi/app.png | Bin 7307 -> 551 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/choozi/app-icon.js b/apps/choozi/app-icon.js index 51b3bead3..560286098 100644 --- a/apps/choozi/app-icon.js +++ b/apps/choozi/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwggLIrnM4uqAAIhPgvMAAPFzIABzWgCxkMCweqC4QABDBYtC5QVFDBoWCCo5KLOQIWKDARFICxhJIFwOpC5owFFyAwGUYIuOGAwuRC4guSJAgXBCyIwDIyQXF5IXSzJeVMAReUAAOQhheTMAVcC6yOUC4aOUC7GZUyoXXzWqhQXVxGqC9mYC7OqC9eoxEKC6uBC6uIwAXBPCSmBwEAC6Z2BiAXBJCR2BgEAjQXSlGBC4JgSLwYABJCJGBLwJIDGB+IIwRIDGByNBIwZIDGBhdBRoQwSLoIuFGAYYKCwIuGGAgYI1QWBRgYYJMYmaFoSMEAAyrBAAgVCCxgYGjAWQAAMBC4UILZQA==")) +require("heatshrink").decompress(atob("mEwwcH/4AW/u27dt2wQL/YOBCIXbv4QI+AODAQVsh4RHwEbCI0LCI9gCIOANAXbsFbG437tkDPg1btoRFFoILBgmSpMggECHQO/CAf2CIVJkgRBAQIjC24RFsECCItIgIRFMYMAiQRFpMAlqmDVwPYgAOEAQUggu274RD4BWCCIskCIPbCIPt20ABwwCCwARFgIRJyEWCIVt2EJCJi2BCJmSUgIRCwARNt/7CIIOICI1sWAwCFoFbCOtt8EACJsAgARR8hwBCJlJk4RlgARQAgIRKDwMn/gRBdJgRPyARBn4RBpARLiQRB/4RBgIRJwAREpIRLAYP///ypMgCJMACI0ECI4JCp4RB/wZECIsAAYN/CIP/5JPDCIhjDCIraHTIWTCAX//K7DCI+fCIf/EZA1CCAn//ipCLIsBk4RF/5ZHCIIQG//wPo8vCI//6QRFpYQIAAPpCIeXCBQAC/VfBI4=")) \ No newline at end of file diff --git a/apps/choozi/app.png b/apps/choozi/app.png index 99c9fa07a55195ec45adbc70cc6e3521cdccaeda..50f09f164b2331133498bd8a3b762ccc09bea20f 100644 GIT binary patch delta 527 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 Date: Sun, 18 Dec 2022 21:46:05 +0100 Subject: [PATCH 14/18] choozi - Fix selection animation on B2 --- apps/choozi/app.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 478cef009..577ef606a 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -114,11 +114,15 @@ function choose() { var maxAngle = minAngle + arclen; animateChoice((minAngle+maxAngle)/2); g.setColor(colours[chosen%colours.length]); - for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep) + for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep){ GU.drawArc(g, i, perimMax, minAngle, maxAngle); + if (process.env.HWVERSION == 2) g.flip(); + } GU.drawArc(g, 0, perimMax, minAngle, maxAngle); - for (var r = 1; r < segmentMax; r += circleStep) + for (var r = 1; r < segmentMax; r += circleStep){ g.fillCircle(centreX,centreY,r); + if (process.env.HWVERSION == 2) g.flip(); + } g.fillCircle(centreX,centreY,segmentMax); } From 68523875a8e0c1476bf65d5c3832fc6449059641 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 18 Dec 2022 22:17:23 +0100 Subject: [PATCH 15/18] choozi - Bump version --- apps/choozi/ChangeLog | 6 ++++++ apps/choozi/metadata.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/choozi/ChangeLog b/apps/choozi/ChangeLog index 03f7ef832..35adc7430 100644 --- a/apps/choozi/ChangeLog +++ b/apps/choozi/ChangeLog @@ -1,3 +1,9 @@ 0.01: New App! 0.02: Support Bangle.js 2 0.03: Fix bug for Bangle.js 2 where g.flip was not being called. +0.04: Combine code for both apps + Better colors for Bangle.js 2 + Fix selection animation for Bangle.js 2 + New icon + Slightly wider arc segments for better visibility + Extract arc drawing code in library diff --git a/apps/choozi/metadata.json b/apps/choozi/metadata.json index d997534e8..c42abe079 100644 --- a/apps/choozi/metadata.json +++ b/apps/choozi/metadata.json @@ -1,7 +1,7 @@ { "id": "choozi", "name": "Choozi", - "version": "0.03", + "version": "0.04", "description": "Choose people or things at random using Bangle.js.", "icon": "app.png", "tags": "tool", From d8543f4d41cbc991aa72b27a3430e19a0f240da1 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 19 Dec 2022 12:52:33 +0100 Subject: [PATCH 16/18] choozi - Fix library not working standalone --- apps/choozi/app.js | 6 +++--- modules/graphics_utils.js | 32 ++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 577ef606a..517628470 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -58,7 +58,7 @@ function drawPerimeter() { for (var i = 0; i < N; i++) { g.setColor(colours[i%colours.length]); var minAngle = (i/N)*radians; - GU.drawArc(g, perimMin,perimMax,minAngle,minAngle+arclen); + GU.drawArc(g, perimMin,perimMax,minAngle,minAngle+arclen, centreX, centreY, stepAngle); } } @@ -115,10 +115,10 @@ function choose() { animateChoice((minAngle+maxAngle)/2); g.setColor(colours[chosen%colours.length]); for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep){ - GU.drawArc(g, i, perimMax, minAngle, maxAngle); + GU.drawArc(g, i, perimMax, minAngle, maxAngle, centreX, centreY, stepAngle); if (process.env.HWVERSION == 2) g.flip(); } - GU.drawArc(g, 0, perimMax, minAngle, maxAngle); + GU.drawArc(g, 0, perimMax, minAngle, maxAngle, centreX, centreY, stepAngle); for (var r = 1; r < segmentMax; r += circleStep){ g.fillCircle(centreX,centreY,r); if (process.env.HWVERSION == 2) g.flip(); diff --git a/modules/graphics_utils.js b/modules/graphics_utils.js index 8e4b893ba..925502afb 100644 --- a/modules/graphics_utils.js +++ b/modules/graphics_utils.js @@ -1,6 +1,6 @@ -// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle -exports.drawArc = function(graphics, minR, maxR, minAngle, maxAngle) { - var step = stepAngle; +// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle, all angles are radians +exports.drawArc = function(graphics, minR, maxR, minAngle, maxAngle, X, Y, stepAngle) { + var step = stepAngle || 0.2; var angle = minAngle; var inside = []; var outside = []; @@ -8,20 +8,28 @@ exports.drawArc = function(graphics, minR, maxR, minAngle, maxAngle) { while (angle < maxAngle) { c = Math.cos(angle); s = Math.sin(angle); - inside.push(centreX+c*minR); // x - inside.push(centreY+s*minR); // y + inside.push(X+c*minR); // x + inside.push(Y+s*minR); // y // outside coordinates are built up in reverse order - outside.unshift(centreY+s*maxR); // y - outside.unshift(centreX+c*maxR); // x + outside.unshift(Y+s*maxR); // y + outside.unshift(X+c*maxR); // x angle += step; } c = Math.cos(maxAngle); s = Math.sin(maxAngle); - inside.push(centreX+c*minR); - inside.push(centreY+s*minR); - outside.unshift(centreY+s*maxR); - outside.unshift(centreX+c*maxR); - + inside.push(X+c*minR); + inside.push(Y+s*minR); + outside.unshift(Y+s*maxR); + outside.unshift(X+c*maxR); + var vertices = inside.concat(outside); graphics.fillPoly(vertices, true); +} + +exports.degreesToRadians = function(degrees){ + return Math.PI/180 * degrees; +} + +exports.radiansToDegrees = function(radians){ + return 180/Math.PI * degrees; } \ No newline at end of file From bc20ce3f5bd1e0fd02699e1d6b6458f5e5bad9c5 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 19 Dec 2022 12:53:01 +0100 Subject: [PATCH 17/18] choozi - Correct README file --- apps/choozi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/choozi/README.md b/apps/choozi/README.md index 8d0aa97f4..ccaa97a27 100644 --- a/apps/choozi/README.md +++ b/apps/choozi/README.md @@ -11,7 +11,7 @@ the players seated in a circle, set the number of segments equal to the number of players, ensure that each person knows which colour represents them, and then choose a segment. After a short animation, the chosen segment will fill the screen. -You can use Choozi to randomly select an element from any set with 2 to 14 members, +You can use Choozi to randomly select an element from any set with 2 to 15 members, as long as you can define a bijection between members of the set and coloured segments on the Bangle.js display. From 36557e4f5ea5f721f450de7c71e56900ba72335c Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 19 Dec 2022 13:01:28 +0100 Subject: [PATCH 18/18] choozi - Rename drawArc to fillArc --- apps/choozi/app.js | 6 +++--- modules/graphics_utils.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/choozi/app.js b/apps/choozi/app.js index 517628470..b9f53bc89 100644 --- a/apps/choozi/app.js +++ b/apps/choozi/app.js @@ -58,7 +58,7 @@ function drawPerimeter() { for (var i = 0; i < N; i++) { g.setColor(colours[i%colours.length]); var minAngle = (i/N)*radians; - GU.drawArc(g, perimMin,perimMax,minAngle,minAngle+arclen, centreX, centreY, stepAngle); + GU.fillArc(g, centreX, centreY, perimMin,perimMax,minAngle,minAngle+arclen, stepAngle); } } @@ -115,10 +115,10 @@ function choose() { animateChoice((minAngle+maxAngle)/2); g.setColor(colours[chosen%colours.length]); for (var i = segmentMax-segmentStep; i >= 0; i -= segmentStep){ - GU.drawArc(g, i, perimMax, minAngle, maxAngle, centreX, centreY, stepAngle); + GU.fillArc(g, centreX, centreY, i, perimMax, minAngle, maxAngle, stepAngle); if (process.env.HWVERSION == 2) g.flip(); } - GU.drawArc(g, 0, perimMax, minAngle, maxAngle, centreX, centreY, stepAngle); + GU.fillArc(g, centreX, centreY, 0, perimMax, minAngle, maxAngle, stepAngle); for (var r = 1; r < segmentMax; r += circleStep){ g.fillCircle(centreX,centreY,r); if (process.env.HWVERSION == 2) g.flip(); diff --git a/modules/graphics_utils.js b/modules/graphics_utils.js index 925502afb..5c08188bc 100644 --- a/modules/graphics_utils.js +++ b/modules/graphics_utils.js @@ -1,5 +1,5 @@ -// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle, all angles are radians -exports.drawArc = function(graphics, minR, maxR, minAngle, maxAngle, X, Y, stepAngle) { +// draw an arc between radii minR and maxR, and between angles minAngle and maxAngle centered at X,Y. All angles are radians. +exports.fillArc = function(graphics, X, Y, minR, maxR, minAngle, maxAngle, stepAngle) { var step = stepAngle || 0.2; var angle = minAngle; var inside = [];