summaryrefslogtreecommitdiffstats
path: root/user-programs
diff options
context:
space:
mode:
authorJacob Haip <jhaip@users.noreply.github.com>2023-04-27 01:36:08 +0000
committerJacob Haip <jhaip@users.noreply.github.com>2023-04-27 01:36:08 +0000
commite2cd8504aaafe779b801d41f6d837385ade02651 (patch)
tree003eaf6aa975f5d0db0091e4f83a1149ed6f1107 /user-programs
parentremove comments (diff)
downloadfolk-e2cd8504aaafe779b801d41f6d837385ade02651.tar.gz
folk-e2cd8504aaafe779b801d41f6d837385ade02651.zip
save laser-region-manager.folk and highlight-laser-region.folk
Diffstat (limited to 'user-programs')
-rw-r--r--user-programs/haippi7/highlight-laser-region.folk27
-rw-r--r--user-programs/haippi7/laser-region-manager.folk153
2 files changed, 180 insertions, 0 deletions
diff --git a/user-programs/haippi7/highlight-laser-region.folk b/user-programs/haippi7/highlight-laser-region.folk
new file mode 100644
index 00000000..56e7d3dc
--- /dev/null
+++ b/user-programs/haippi7/highlight-laser-region.folk
@@ -0,0 +1,27 @@
+source "vendor/math/geometry.tcl"
+
+When /someone/ claims /something/ region /id/ data /regionData/ & \
+ laser blob /t/ has center /c/ size /s/ {
+ # Unnest {{0 0} {1 1}} into {0 0 1 1}
+ set unnestedRegionDataPoints $regionData
+ while {[set t [join $unnestedRegionDataPoints]] ne $unnestedRegionDataPoints} {set unnestedRegionDataPoints $t}
+ if {[::math::geometry::pointInsidePolygon $c $unnestedRegionDataPoints]} {
+ Claim laser blob $t inside region $id
+ }
+}
+
+When laser blob /something/ inside region /id/ & \
+ /someone/ claims /something/ region /id/ data /regionData/ {
+ set tl [::cameraToProjector [lindex $regionData 0]]
+ set tr [::cameraToProjector [lindex $regionData 1]]
+ set br [::cameraToProjector [lindex $regionData 2]]
+ set bl [::cameraToProjector [lindex $regionData 3]]
+ Display::stroke [list $tl $tr] 5 red
+ Display::stroke [list $tr $br] 5 red
+ Display::stroke [list $br $bl] 5 red
+ Display::stroke [list $bl $tl] 5 red
+}
+
+When laser blob /something/ inside region 1 {
+ Display::text fb 500 50 20 "Laser inside region 1!" 0
+} \ No newline at end of file
diff --git a/user-programs/haippi7/laser-region-manager.folk b/user-programs/haippi7/laser-region-manager.folk
new file mode 100644
index 00000000..cfca7d46
--- /dev/null
+++ b/user-programs/haippi7/laser-region-manager.folk
@@ -0,0 +1,153 @@
+When the collected matches for [list /someone/ claims /something/ region /id/ data /data/] are /regionMatches/ {
+ set regionDataJsStrList {}
+ foreach match $regionMatches {
+ set m [dict get $match data]
+ # Convert tcl list to javascript array
+ lappend regionDataJsStrList "\[[string map {"{" "\[" "}" "\]" " " ", "} $m]\]"
+ }
+ set jsArrayString "\[[join $regionDataJsStrList ", "]\]"
+ Wish the web server handles route "/laser-regions-test" with handler [list Evaluator::tryRunInSerializedEnvironment {
+ html [string map [list REGION_DATA $jsArrayString] {
+ <html><head></head>
+ <body>
+ <div style="display: flex">
+ <span id="status">Status</span>
+ <button id="reset">Reset</button>
+ <button id="addRegion">Add Region</button>
+ <button id="reloadFrame">Reload frame</button>
+ </div>
+ <canvas id="canvas" width="1280" height="720"></canvas>
+ <h3>Regions</h3>
+ <ul id="regionsList">
+ </ul>
+
+<script>
+const regionsData = REGION_DATA;
+const thisProgramId = "laser-regions-test.folk";
+const canvas = document.getElementById('canvas');
+const ctx = canvas.getContext('2d');
+canvas.addEventListener("click", onClick, false);
+const resetButton = document.getElementById('reset');
+const regionList = document.getElementById('regionsList');
+const addRegionButton = document.getElementById('addRegion');
+const reloadFrameButton = document.getElementById('reloadFrame');
+var frameImage = new Image();
+var haveImage = false;
+let pendingRegion = [];
+let ws = new WebSocket(window.location.origin.replace("http", "ws") + "/ws");
+
+function updateFrameImage() {
+ console.log("refreshing frame");
+ haveImage = false;
+ frameImage.onload = () => {
+ haveImage = true;
+ renderCanvas();
+ };
+ frameImage.onerror = () => {
+ haveImage = false;
+ renderCanvas();
+ }
+ frameImage.src = '/frame-image/';
+}
+updateFrameImage();
+
+function onClick(e) {
+ var element = canvas;
+ var offsetX = 0, offsetY = 0;
+ if (element.offsetParent) {
+ do {
+ offsetX += element.offsetLeft;
+ offsetY += element.offsetTop;
+ } while ((element = element.offsetParent));
+ }
+ const x = e.pageX - offsetX;
+ const y = e.pageY - offsetY;
+ if (pendingRegion.length < 4) {
+ pendingRegion.push([x, y]);
+ renderCanvas();
+ }
+}
+
+function renderCanvas() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ if (haveImage) {
+ ctx.drawImage(frameImage, 0, 0, canvas.width, canvas.height);
+ } else {
+ ctx.fillStyle = 'rgba(0, 0, 255, 1)';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ if (pendingRegion.length > 0) {
+ ctx.fillStyle = 'rgba(255, 165, 0, 0.2)';
+ ctx.strokeStyle = 'rgba(255, 165, 0, 0.5)';
+ ctx.beginPath();
+ ctx.moveTo(pendingRegion[0][0], pendingRegion[0][1]);
+ for (let i = 1; i < pendingRegion.length; i++) {
+ ctx.lineTo(pendingRegion[i][0], pendingRegion[i][1]);
+ }
+ ctx.closePath();
+ ctx.fill();
+ ctx.stroke();
+ for (let i = 0; i < pendingRegion.length; i++) {
+ ctx.fillStyle = 'rgba(255, 165, 0, 0.7)';
+ ctx.beginPath();
+ ctx.arc(pendingRegion[i][0], pendingRegion[i][1], 5, 0, 2 * Math.PI);
+ ctx.closePath();
+ ctx.fill();
+ }
+ }
+}
+
+const updateRegionsList = () => {
+ regionList.innerHTML = "";
+ regionsData.forEach((region) => {
+ const li = document.createElement('li');
+ li.innerText = JSON.stringify(region);
+ regionList.appendChild(li);
+ });
+};
+updateRegionsList();
+
+reloadFrameButton.onclick = () => {
+ updateFrameImage();
+};
+
+resetButton.onclick = () => {
+ pendingRegion = [];
+ renderCanvas();
+};
+
+addRegionButton.onclick = () => {
+ if (pendingRegion.length !== 4) { alert("only supporting 4 points regions for now"); return; }
+ regionsData.push(pendingRegion);
+ pendingRegion = [];
+ updateRegionsList();
+ renderCanvas();
+ let statement = `Retract web claims {${thisProgramId}} region /id/ data /data/;`;
+ regionsData.forEach((region, i) => {
+ const j = JSON.stringify(region).replaceAll("[", "{").replaceAll("]", "}").replaceAll(",", " ");
+ statement += `Assert web claims {${thisProgramId}} region {${i}} data ${j};`;
+ });
+ ws.send(statement);
+};
+
+ws.onopen = () => {
+ document.getElementById('status').innerHTML = "<span style=background-color:seagreen;color:white;>Connnected</span>";
+};
+ws.onclose = window.onbeforeunload = () => {
+ document.getElementById('status').innerHTML = "<span style=background-color:red;color:white;>Disconnnected</span>";
+ // ws.send(`Retract web claims {${thisProgramId}} is /blah/`);
+};
+ws.onerror = (err) => {
+ document.getElementById('status').innerText = "Error";
+ console.error('Socket encountered error: ', err.message, 'Closing socket');
+ ws.close();
+}
+ws.onmessage = (msg) => {
+ console.log(msg.data);
+}
+</script>
+ </body>
+ </html>
+ }]
+ } [Evaluator::serializeEnvironment]]
+} \ No newline at end of file