could not train model by calculating and applying gradient - tensorflow

I'm trying to train a simple sequential model. I want to decompose fit algorithm to gather gradient phase and apply gradient' phase in order to use reinforcement learning.
this idea is taken from cart pole example.
cart pole example
anyway I can not receive good result even if the problem (defined in func()) is comparatively easy to solve by model trained by fit method. The best I can achieve is something like this :
I must be missing something. Could anyone can direct me what's wrong?
Here you can find github source with net output visualization
import {layers, sequential, Sequential} from "#tensorflow/tfjs-layers";
import {
tensor2d,
Tensor,
losses,
variableGrads,
tidy,
train,
NamedTensorMap,
stack,
mean,
concat
} from "#tensorflow/tfjs";
import {ActivationIdentifier} from "#tensorflow/tfjs-layers/src/keras_format/activation_config";
import {NamedTensor} from "#tensorflow/tfjs-core/dist/tensor_types";
import {InitializerIdentifier} from "#tensorflow/tfjs-layers/src/initializers";
import {addHeatmap} from "./vis/heatmap";
const func = (...x) => {
const y1 = x[0] * x[1] * 0.9 + (1 - x[0]) * (1 - x[1]) * 0.9;
return tensor2d([y1], [1, 1])
}
const activation: ActivationIdentifier = "tanh"
const kernelInitializer: InitializerIdentifier = null
const model: Sequential = sequential();
const inputLayer = layers.dense({
units: 2,
inputShape: [2],
kernelInitializer,
});
const hiddenLayer1 = layers.dense({
units: 16,
activation: activation,
//kernelInitializer,
useBias: true
});
const outputLayer = layers.dense({
units: 1,
activation: "sigmoid",
kernelInitializer,
useBias: true
});
const dim = 10; // error sampling density
model.add(inputLayer);
model.add(hiddenLayer1);
model.add(outputLayer);
const optimizer = train.adam(0.1);
const calculateGradient = () => {
return tidy(() => {
const vGrads = variableGrads(() => tidy(() => {
const x1 = Math.random();
const x2 = Math.random();
const labels = func(x1, x2)
const input = tensor2d([x1, x2], [1, 2])
return losses.meanSquaredError(
labels,
model.predict(input) as Tensor
).asScalar();
}));
return vGrads.grads;
})
}
const createBatch = (n: number) => {
return tidy(() => {
const gradientsArrays = {}
for (let i = 0; i < n; i++) {
const gradient = calculateGradient();
Object.keys(gradient).forEach((entry) => {
gradientsArrays[entry] ? gradientsArrays[entry].push(gradient[entry]) : gradientsArrays[entry] = [gradient[entry]]
})
}
const gradientsMeans = {}
Object.keys(gradientsArrays).forEach(key => {
gradientsMeans[key] = mean(stack(gradientsArrays[key], 0))
})
return gradientsMeans;
})
}
const epoch = (iterations: number) => {
for (let i = 0; i < iterations; i++) {
let batch = createBatch(16);
optimizer.applyGradients(batch)
}
}
const calculateDesiredOutputs = () => {
const desiredOutputs = [];
for (let y = 0; y < 1; y += 1 / dim) {
for (let x = 0; x < 1; x += 1 / dim) {
desiredOutputs.push({x, y, value: func(x, y).dataSync()[0]});
}
}
return desiredOutputs;
}
const calculateNetOutputs = () => {
const netOutputs = [];
for (let y = 0; y < 1; y += 1 / dim) {
for (let x = 0; x < 1; x += 1 / dim) {
const value = (<any>model.predict(tensor2d([x, y], [1, 2]))).dataSync()[0];
netOutputs.push({x, y, value});
}
}
return netOutputs
}
const calculateError = (a: { value: number }[], b: { value: number }[]) => {
let error = 0;
for (let i = 0; i < a.length; i++) {
let e = a[i].value - b[i].value;
error += e * e
}
return Math.sqrt(error) / (dim * dim);
}
const run = async () => {
const desiredOutputs = calculateDesiredOutputs();
const desiredOutputsHeatmap = addHeatmap({dim});
desiredOutputsHeatmap.update(desiredOutputs)
const netOutputHeatmap = addHeatmap({dim});
let i = 0;
while (i < 256) {
epoch(20);
let netOutputs = calculateNetOutputs();
console.log("epoch: ", i)
console.log(calculateError(desiredOutputs, netOutputs))
netOutputHeatmap.update(netOutputs);
await new Promise((r) => setTimeout(() => r(), 100));
i++;
}
}
run();

Related

shading between two boundary boxes

I have model prediction which detects the end box of verses of quran. I need to shade the area between them as shown in pictures which when the endbox hits the edge it start again from the another edge and the two drawn shadows have the same id. I know it seems complicated but you will save my day if you figure it out here is some of my code to help you reference
"use client";
import LABELS from "#app-datasets/coco/classes.json";
import {
Box,
Button,
ButtonGroup,
Center,
chakra,
Container,
Heading,
Icon,
Text,
useBoolean,
VisuallyHiddenInput,
VStack,
} from "#app-providers/chakra-ui";
import * as tf from "#tensorflow/tfjs";
import "#tensorflow/tfjs-backend-webgl";
import { useEffect, useRef, useState } from "react";
import { FaTimes } from "react-icons/fa";
const ZOO_MODEL = [{ name: "yolov5", child: ["yolov5n", "yolov5s"] }];
function Home() {
// LET RHE USEWER CHOOSE THE MINIMUM SCORE TO SHOW
const [model, setModel] = useState(null);
const [aniId, setAniId] = useState(null);
const [modelName, setModelName] = useState(ZOO_MODEL[0]);
const [loading, setLoading] = useState(0);
const imageRef = useRef(null);
const videoRef = useRef(null);
const canvasRef = useRef(null);
const inputImageRef = useRef(null);
const [singleImage, setSingleImage] = useBoolean();
const [liveWebcam, setliveWebcam] = useBoolean();
useEffect(() => {
tf.loadGraphModel(`/model/${modelName.name}/${modelName.child[1]}/model.json`, {
onProgress: (fractions) => {
setLoading(fractions);
},
}).then(async (mod) => {
// warming up the model before using real data
const dummy = tf.ones(mod.inputs[0].shape);
const res = await mod.executeAsync(dummy);
// clear memory
tf.dispose(res);
tf.dispose(dummy);
// save to state
setModel(mod);
});
}, [modelName]);
// helper for drawing into canvas //IoU threshold 0.5
const renderPrediction = (boxesData, scoresData, classesData , ) => {
const ctx = canvasRef.current.getContext("2d");
// clean canvas
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const font = "16px sans-serif";
ctx.font = font;
ctx.textBaseline = "top";
// LET RHE USEWER CHOOSE minval SCORE TO SHOW
const minval = 0.5;
for (let i = 0; i < scoresData.length; ++i) {
if (scoresData[i] < minval) continue;
const klass = LABELS[classesData[i]];
const score = (scoresData[i] * 100).toFixed(1);
let [x1, y1, x2, y2] = boxesData.slice(i * 4, (i + 1) * 4);
x1 *= canvasRef.current.width;
x2 *= canvasRef.current.width;
y1 *= canvasRef.current.height;
y2 *= canvasRef.current.height;
const width = x2 - x1;
const height = y2 - y1;
// draw the bounding box
ctx.strokeStyle = "#C53030";
ctx.lineWidth = 2;
ctx.strokeRect(x1, y1, width, height);
// fill the area between the boxes
const label = klass + " - " + score + "%";
const textWidth = ctx.measureText(label).width;
const textHeight = parseInt(font, 10); // base 10
// draw the label background
ctx.fillStyle = "#C53030";
ctx.fillRect(x1 - 1, y1 - (textHeight + 4), textWidth + 6, textHeight + 4);
// draw the label text
ctx.fillStyle = "#FFFFFF";
ctx.fillText(label, x1 + 2, y1 - (textHeight + 2));
}
};
I was expecting a shade with the method above

Expand Text of Compact Data

I am stuck with some data manipulation.
This is a small portion of the input data (df):
site=c("C000-C002","C420-C421,C424")
histology=c("9835-9836","9811-9812,9837")
category=c("Leukemia","Leukemia")
df=data.frame(site,histology,category)
And this is what I want the processed data to look like:
You may assume Site and Histology are both 4-digit after text splitting.
In case anyone is interested, the full data table is here
Please help with the text processing, or if anyone knows an existing processed package or database in a similar format as the image, that would be great too.
Thank you very much.
I don't know R language. So I tried with Javascript as following.
function mapStartEnd(start, end) {
let list = [];
let info = {};
const siteStart = start.match(/([A-Z])(\d{3})/);
if (siteStart) {
const siteEnd = end.match(/([A-Z])(\d{3})/);
info = {
type: "site",
prefix: siteStart[1],
numLength: 3,
from: parseInt(siteStart[2], 10),
to: parseInt(siteEnd[2], 10),
};
}
const histologyStart = start.match(/\d{4}/);
if (histologyStart) {
const histologyEnd = end.match(/\d{4}/);
info = {
type: "histology",
prefix: "",
numLength: 4,
from: parseInt(histologyStart[0], 10),
to: parseInt(histologyEnd[0], 10),
};
}
const categoryStart = start.match(/[A-Z][a-z]+/);
if (categoryStart) {
const categoryEnd = end.match(/[A-Z][a-z]+/);
info = {
type: "category",
prefix: "",
numLength: 0,
from: categoryStart[0],
to: categoryEnd[0],
};
}
if (!info.numLength) {
list = [info.from, info.to];
} else {
for (let i = info.from; i <= info.to; i++) {
list.push(info.prefix + i.toString().padStart(info.numLength, "0"));
}
}
return list;
}
function c(list) {
return list.map((list2) => {
return list2.split(",").reduce((prev, cur) => {
const [start, end] = cur.split("-");
if (!end) prev.push(start);
else prev = [...prev, ...mapStartEnd(start, end)];
return prev;
}, []);
});
}
function map3(sites, histologys, categorys) {
let list = [];
for (let i = 0; i < sites.length; i++) {
const site = sites[i];
for (let j = 0; j < histologys.length; j++) {
const histology = histologys[j];
for (let k = 0; k < categorys.length; k++) {
const category = categorys[k];
// JSON format
// list.push({ site, histology, category });
// CSV format
list.push(`${site},${histology},${category}`);
}
}
}
return list;
}
function frame(sites, histologys, categorys) {
let list = [];
for (let i = 0; i < sites.length; i++) {
const site = sites[i];
const histology = histologys[i];
const category = categorys[i];
list = [...list, ...map3(site, histology, category)];
}
return list;
}
const site = c(["C000-C002", "C420-C421,C424"]);
const histology = c(["9835-9836", "9811-9812,9837"]);
const category = c(["Leukemia", "Leukemia"]);
const df = frame(site, histology, category);
console.log(df);
Result:
[
"C000,9835,Leukemia",
"C000,9836,Leukemia",
"C001,9835,Leukemia",
"C001,9836,Leukemia",
"C002,9835,Leukemia",
"C002,9836,Leukemia",
"C420,9811,Leukemia",
"C420,9812,Leukemia",
"C420,9837,Leukemia",
"C421,9811,Leukemia",
"C421,9812,Leukemia",
"C421,9837,Leukemia",
"C424,9811,Leukemia",
"C424,9812,Leukemia",
"C424,9837,Leukemia"
]
https://jsfiddle.net/dnu2g0vr/

TypeError: Cannot read property 'width' of undefined - Nuxt JS and canvas

I am trying to run a sketch on the canvas element in Nuxt JS but I am having some issues (I am completely new to Vue JS).
While I have no errors in VS Code, there is an error in the browser console:
client.js?06a0:84 TypeError: Cannot read property 'width' of undefined
at Blob.get (Blob_Point.js?a5e5:126)
at Blob.render (Blob_Point.js?a5e5:29)
below is the code for my Vue file:
<template>
<div>
<h1 class="pa-5 text-center">Blob</h1>
<canvas id="myCanvas" width="600" height="400"></canvas>
<!--<v-btn #click="drawRect">Clear</v-btn> -->
</div>
</template>
<script>
import Blob from "../assets/content/Blob_Point"
//import { Point } from "../assets/content/Blob_Point"
//import Point from "../assets/content/Blob_Point"
let oldMousePoint = { x: 0, y: 0 }
let blob = new Blob()
//let point = new Point()
let hover = false
let canvas
export default {
data() {
return {
canvas: null,
x: 0,
y: 0,
isDrawing: false,
rectWidth: 200,
//hover: false,
//oldMousePoint: { x: 0, y: 0 },
}
},
mounted() {
let canvas = document.getElementById("myCanvas")
this.canvas = canvas.getContext("2d")
},
created() {
new Blob("#C09EFF")
blob.canvas = canvas
blob.init()
blob.render()
},
methods: {
/* showCoordinates(e) {
this.x = e.offsetX
this.y = e.offsetY
},
drawLine(x1, y1, x2, y2) {
let ctx = this.vueCanvas
ctx.beginPath()
ctx.strokeStyle = "black"
ctx.lineWidth = 1
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.stroke()
ctx.closePath()
},
draw(e) {
if (this.isDrawing) {
this.drawLine(this.x, this.y, e.offsetX, e.offsetY)
this.x = e.offsetX
this.y = e.offsetY
}
},
beginDrawing(e) {
this.x = e.offsetX
this.y = e.offsetY
this.isDrawing = true
},
stopDrawing(e) {
if (this.isDrawing) {
this.drawLine(this.x, this.y, e.offsetX, e.offsetY)
this.x = 0
this.y = 0
this.isDrawing = false
//windowWidth = 0,
}
}, */
resize() {
document.getElementById("myCanvas").width = window.innerWidth
document.getElementById("myCanvas").height = window.innerHeight
},
/*drawRect() {
this.vueCanvas.clearRect(0, 0, 600, 800)
//this.vueCanvas.beginPath()
//this.vueCanvas.rect(20, 20, this.rectWidth, 100)
//this.vueCanvas.stroke()
},*/
mouseMove(e) {
let pos = blob.center
let diff = { x: e.clientX - pos.x, y: e.clientY - pos.y }
let dist = Math.sqrt(diff.x * diff.x + diff.y * diff.y)
let angle = null
blob.mousePos = {
x: pos.x - e.clientX,
y: pos.y - e.clientY,
}
if (dist < blob.radius && hover === false) {
let vector = {
x: e.clientX - pos.x,
y: e.clientY - pos.y,
}
angle = Math.atan2(vector.y, vector.x)
hover = true
// blob.color = '#77FF00';
} else if (dist > blob.radius && hover === true) {
let vector = {
x: e.clientX - pos.x,
y: e.clientY - pos.y,
}
angle = Math.atan2(vector.y, vector.x)
hover = false
blob.color = null
}
if (typeof angle == "number") {
let nearestPoint = null
let distanceFromPoint = 100
blob.points.forEach((point) => {
if (Math.abs(angle - point.azimuth) < distanceFromPoint) {
// console.log(point.azimuth, angle, distanceFromPoint);
nearestPoint = point
distanceFromPoint = Math.abs(angle - point.azimuth)
}
})
if (nearestPoint) {
let strength = {
x: oldMousePoint.x - e.clientX,
y: oldMousePoint.y - e.clientY,
}
strength =
Math.sqrt(strength.x * strength.x + strength.y * strength.y) * 1
if (strength > 100) strength = 100
nearestPoint.acceleration = (strength / 100) * (hover ? -1 : 1)
}
}
oldMousePoint.x = e.clientX
oldMousePoint.y = e.clientY
},
},
}
</script>
<style scoped>
#myCanvas {
border: 1px solid grey;
}
</style>
and below is the Blob_Point JS file that I am importing:
/* eslint-disable */
// Blob Class
export default class Blob {
// setup function
constructor(color) {
//the objects setup
// 'this' is a reference to the current class
this.points = []
this._color = color
}
init() {
for (let i = 0; i < this.numPoints; i++) {
let point = new Point(this.divisional * (i + 1), this)
//point.acceleration = -1 + Math.random() * 2;
this.push(point)
}
}
render() {
let canvas = this.canvas
let ctx = this.ctx
let position = this.position
let pointsArray = this.points
let radius = this.radius
let points = this.numPoints
let divisional = this.divisional
let center = this.center
ctx.clearRect(0, 0, canvas.width, canvas.height)
pointsArray[0].solveWith(pointsArray[points - 1], pointsArray[1])
let p0 = pointsArray[points - 1].position
let p1 = pointsArray[0].position
let _p2 = p1
// this is the draw
ctx.beginPath()
ctx.moveTo(center.x, center.y)
ctx.moveTo((p0.x + p1.x) / 2, (p0.y + p1.y) / 2)
for (let i = 1; i < points; i++) {
pointsArray[i].solveWith(
pointsArray[i - 1],
pointsArray[i + 1] || pointsArray[0]
)
let p2 = pointsArray[i].position
var xc = (p1.x + p2.x) / 2
var yc = (p1.y + p2.y) / 2
ctx.quadraticCurveTo(p1.x, p1.y, xc, yc)
// ctx.lineTo(p2.x, p2.y);
//ctx.fillStyle = this.color;
// ctx.fillRect(p1.x-2.5, p1.y-2.5, 5, 5);
p1 = p2
}
var xc = (p1.x + _p2.x) / 2
var yc = (p1.y + _p2.y) / 2
ctx.quadraticCurveTo(p1.x, p1.y, xc, yc)
ctx.lineTo(_p2.x, _p2.y)
ctx.closePath()
ctx.fillStyle = this.color
ctx.fill()
ctx.strokeStyle = this.color
// ctx.stroke();
/*
ctx.fillStyle = '#000000';
if(this.mousePos) {
let angle = Math.atan2(this.mousePos.y, this.mousePos.x) + Math.PI;
}*/
//requestAnimationFrame(this.render.bind(this))
}
push(item) {
if (item instanceof Point) {
this.points.push(item)
}
}
set color(value) {
this._color = value
}
get color() {
return this._color
}
set canvas(value) {
if (
value instanceof HTMLElement &&
value.tagName.toLowerCase() === "canvas"
) {
this._canvas = canvas
this.ctx = this._canvas.getContext("2d")
}
}
get canvas() {
return this._canvas
}
set numPoints(value) {
if (value > 10) {
this._points = value
}
}
get numPoints() {
return this._points || 32
}
set radius(value) {
if (value > 0) {
this._radius = value
}
}
get radius() {
return this._radius || 300
}
set position(value) {
if (typeof value == "object" && value.x && value.y) {
this._position = value
}
}
get position() {
return this._position || { x: 0.5, y: 0.5 }
}
get divisional() {
return (Math.PI * 2) / this.numPoints
}
get center() {
return {
x: this.canvas.width * this.position.x,
y: this.canvas.height * this.position.y,
}
}
set running(value) {
this._running = value === true
}
get running() {
return this.running !== false
}
}
// Point Class
export class Point {
constructor(azimuth, parent) {
this.parent = parent
this.azimuth = Math.PI - azimuth
this._components = {
x: Math.cos(this.azimuth),
y: Math.sin(this.azimuth),
}
this.acceleration = -0.3 + Math.random() * 0.6
}
solveWith(leftPoint, rightPoint) {
this.acceleration =
(-0.3 * this.radialEffect +
(leftPoint.radialEffect - this.radialEffect) +
(rightPoint.radialEffect - this.radialEffect)) *
this.elasticity -
this.speed * this.friction
}
set acceleration(value) {
if (typeof value == "number") {
this._acceleration = value
this.speed += this._acceleration * 2
}
}
get acceleration() {
return this._acceleration || 0
}
set speed(value) {
if (typeof value == "number") {
this._speed = value
this.radialEffect += this._speed * 3
}
}
get speed() {
return this._speed || 0
}
set radialEffect(value) {
if (typeof value == "number") {
this._radialEffect = value
}
}
get radialEffect() {
return this._radialEffect || 0
}
get position() {
return {
x:
this.parent.center.x +
this.components.x * (this.parent.radius + this.radialEffect),
y:
this.parent.center.y +
this.components.y * (this.parent.radius + this.radialEffect),
}
}
get components() {
return this._components
}
set elasticity(value) {
if (typeof value === "number") {
this._elasticity = value
}
}
get elasticity() {
return this._elasticity || 0.001
}
set friction(value) {
if (typeof value === "number") {
this._friction = value
}
}
get friction() {
return this._friction || 0.0085
}
}
Any ideas on the why lines 29 and 127 of the Blob_Point.js file are throwing errors?
I attached 2 screens of the developer tools in chrome to show the errors along with the JS its pointing to.
Thanks for any help!
The main issue I can identify is here. I have added comments to the code.
Blob_Point.js
render() {
let canvas = this.canvas // this references the Blob Class (not the Vue instance) and there is no initialised property such as canvas in the class
}
To fix this main issue, you can do something like
Blob_Point.js
export default class Blob {
constructor(color, canvas) {
//the objects setup
// 'this' is a reference to the current class
this.points = []
this._color = color;
this.canvas = canvas
}
}
And then in the .vue file
.Vue
mounted() {
let canvas = document.getElementById("myCanvas");
this.canvas = canvas.getContext("2d");
blob = new Blob("#C09EFF", this.canvas); // now canvas in the Blob Class constructor will refer to the vue instance canvas
blob.canvas = canvas;
blob.init();
blob.render();
},
I have identified another issue here.
set canvas(value) {
if (
value instanceof HTMLElement &&
value.tagName.toLowerCase() === "canvas"
) {
this._canvas = canvas // there is no initialised constructor property as _canvas
this.ctx = this._canvas.getContext("2d") // there is no initialised constructor property such as _canvas
}
}
get canvas() {
return this._canvas // there is no initialised constructor property as _canvas
}

WebGL FPS camera movement along the local axis instead of the world axis with glMatrix.js

I'm trying to make a FPS camera in WebGL.
When I move the camera from the initial position and then rotate, the camera moves along the start position instead of the new position.
The translation and rotation are made with glMatrix.js library.
I have the variables:
var rotateY = 0; // For rotating along the Y axis
var fronBackMovement = 0; // Front and back movement
var sideMovement = 0; // Movement from side to side
Keyboard events:
// Movement
if( key.w == true ){
fronBackMovement += 5;
}
if( key.a == true ){
sideMovement += 5;
}
if( key.s == true ){
fronBackMovement -= 5;
}
if( key.d == true ){
sideMovement -= 5;
}
Mouse movement:
// Rotation
if( mouse.movementX != 0 ){
rotateY += mouse.movementX; // mouse.movementX is screen movement of the cursor
}
Translation and rotation:
camera.matrix = mat4.fromTranslation( mat4.create() ,vec3.fromValues(sideMovement,0,fronBackMovement) )
camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY )
The camera generally looks down the -Z axis so to move forward you just add the camera's Z axis to your position. If you don't want to move vertically then zero out the Y component and normalize. Finally multiply by your desired speed.
The camera's x-axis contains the side movement direction so you can do the same for that.
const cameraPosition = vec3.create();
const tempForwardDirection = vec3.create();
const tempSideDirection = vec3.create();
...
tempForwardDirection[0] = camera.matrix[8];
tempForwardDirection[1] = 0; // camera.matrix[9];
tempForwardDirection[2] = camera.matrix[10];
vec3.normalize(tempForwardDirection, tempForwardDirection)
tempSideDirection[0] = camera.matrix[0];
tempSideDirection[1] = camera.matrix[1];
tempSideDirection[2] = camera.matrix[2];
vec3.scaleAndAdd(
cameraPosition,
cameraPosition,
tempForwardDirection,
-fronBackMovement);
vec3.scaleAndAdd(
cameraPosition,
cameraPosition,
tempSideDirection,
sideMovement)
camera.matrix = mat4.fromTranslation(camera.matrix, cameraPosition);
camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY);
let rotateY = 0; // For rotating along the Y axis
let fronBackMovement = 0; // Front and back movement
let sideMovement = 0; // Movement from side to side
const cameraPosition = vec3.create();
const tempForwardDirection = vec3.create();
const tempSideDirection = vec3.create();
const camera = {
matrix: mat4.create(),
};
const mouse = {
movementX: 0,
};
const gl = document.querySelector("canvas").getContext("webgl");
const vs = `
uniform mat4 u_worldViewProjection;
uniform mat4 u_worldInverseTranspose;
attribute vec4 position;
attribute vec3 normal;
varying vec3 v_normal;
void main() {
gl_Position = u_worldViewProjection * position;
v_normal = (u_worldInverseTranspose * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;
varying vec3 v_normal;
uniform vec3 u_lightDir;
uniform vec4 u_color;
void main() {
vec3 norm = normalize(v_normal);
float light = dot(u_lightDir, norm) * .5 + .5;
gl_FragColor = vec4(u_color.rgb * light, u_color.a);
}
`;
const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);
const projection = mat4.create();
const view = mat4.create();
const viewProjection = mat4.create();
const world = mat4.create();
const worldViewProjection = mat4.create();
const worldInverse = mat4.create();
const worldInverseTranspose = mat4.create();
const fov = degToRad(90);
const zNear = 0.1;
const zFar = 100;
const lightDir = vec3.normalize(vec3.create(), [1, 2, 3]);
const key = {};
let px = 0;
let py = 0;
let pz = 0;
let elev = 0;
let ang = 0;
let roll = 0;
const speed = 1;
const turnSpeed = 90;
let then = 0;
function render(now) {
now *= 0.001; // seconds;
const deltaTime = now - then;
then = now;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.useProgram(progInfo.program);
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
mat4.perspective(projection, fov, aspect, zNear, zFar);
fronBackMovement = 0;
sideMovement = 0;
if( key.w == true ){
fronBackMovement = 5 * deltaTime;
}
if( key.a == true ){
sideMovement = -5 * deltaTime;
}
if( key.s == true ){
fronBackMovement = -5 * deltaTime;
}
if( key.d == true ){
sideMovement = 5 * deltaTime;
}
// Rotation
if( mouse.movementX != 0 ){
rotateY += mouse.movementX / 200; // mouse.movementX is screen movement of the cursor
mouse.movementX = 0;
}
tempForwardDirection[0] = camera.matrix[8];
tempForwardDirection[1] = 0; // camera.matrix[9];
tempForwardDirection[2] = camera.matrix[10];
vec3.normalize(tempForwardDirection, tempForwardDirection)
tempSideDirection[0] = camera.matrix[0];
tempSideDirection[1] = camera.matrix[1];
tempSideDirection[2] = camera.matrix[2];
vec3.scaleAndAdd(
cameraPosition,
cameraPosition,
tempForwardDirection,
-fronBackMovement);
vec3.scaleAndAdd(
cameraPosition,
cameraPosition,
tempSideDirection,
sideMovement)
camera.matrix = mat4.fromTranslation(camera.matrix, cameraPosition);
camera.matrix = mat4.rotateY(camera.matrix,camera.matrix,rotateY);
mat4.invert(view, camera.matrix);
mat4.multiply(viewProjection, projection, view);
for (let z = -1; z <= 1; ++z) {
for (let y = -1; y <= 1; ++y) {
for (let x = -1; x <= 1; ++x) {
if (x === 0 && y === 0 && z === 0) {
continue;
}
mat4.identity(world);
mat4.translate(world, world, [x * 3, y * 3, z * 3]);
mat4.multiply(worldViewProjection, viewProjection, world);
mat4.invert(worldInverse, world);
mat4.transpose(worldInverseTranspose, worldInverse);
twgl.setBuffersAndAttributes(gl, progInfo, bufferInfo);
twgl.setUniforms(progInfo, {
u_worldViewProjection: worldViewProjection,
u_worldInverseTranspose: worldInverseTranspose,
u_color: [(x + 2) / 3, (y + 2) / 3, (z + 2) / 3, 1],
u_lightDir: lightDir,
});
twgl.drawBufferInfo(gl, bufferInfo);
}
}
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
window.addEventListener('keydown', (e) => {
key[e.key] = true;
e.preventDefault();
});
window.addEventListener('keyup', (e) => {
key[e.key] = false;
e.preventDefault();
});
window.addEventListener('mousemove', (e) => {
mouse.movementX = e.movementX;
});
function degToRad(d) {
return d * Math.PI / 180;
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
pre { position: absolute; left: 1em; top: 0; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
<canvas></canvas>
<pre>
A = left
D = right
W = forward
S = down
</pre>

What is the fastest way to create a union of many polygons in turfjs?

I have something like this but with large sets it's awfully slow:
let unionize = (triangles) => {
if(triangles.length == 0) {
return null
}
let ret = triangles[0].feature
triangles.forEach((t, index) => {
if(index > 0) {
ret = turf.union(t, t)
}
})
return ret
}
featureEach tends to be faster than a trivial array forEach although with more features the gain decreases.
<script src="https://cdn.jsdelivr.net/npm/#turf/turf#5.1.6/turf.min.js"></script>
<script>
const generateGrid = (cellSide = 100, units = "kilometers") => {
const bbox = [-95, 30, -85, 40];
return turf.triangleGrid(bbox, cellSide, {
units
});
}
const unionizeForEach = (triangles) => {
console.time('unionizeForEach');
if (triangles.length == 0) {
return null
}
let ret = triangles[0];
triangles.forEach((t, index) => {
if (index > 0) {
ret = turf.union(ret, t)
}
});
console.timeEnd('unionizeForEach');
return ret
}
const unionizeFeatureEach = (triangles) => {
console.time('unionizeFeatureEach');
if (triangles.features.length === 0) {
return null
}
let ret = triangles.features[0];
turf.featureEach(triangles, function (currentFeature, featureIndex) {
if (featureIndex > 0) {
ret = turf.union(ret, currentFeature)
}
});
console.timeEnd('unionizeFeatureEach');
return ret;
}
[100, 50, 10].map(cellSide => {
const triangleGrid = generateGrid(cellSide, 'kilometers');
console.info(`triangleGrid has ${triangleGrid.features.length} features`);
const union_foreach = unionizeForEach(triangleGrid.features);
const union_featureeach = unionizeFeatureEach(triangleGrid);
console.assert(JSON.stringify(union_foreach) === JSON.stringify(union_featureeach));
console.log('\n---\n');
})
</script>