You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
5.9 KiB
JavaScript

/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
import * as THREE from 'three';
import { STLLoader } from 'https://cdn.jsdelivr.net/npm/three@0.136.0/examples/jsm/loaders/STLLoader.js';
import { WindMill } from './windmill.js';
import { Screen } from './screen.js';
import { ArgentinianFlag } from './argentinianflag.js';
import { checkBoard } from './checkboard.js';
window.three = THREE;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({antialias: true});
document.body.appendChild(renderer.domElement);
//renderer.setPixelRatio( window.devicePixelRatio );
function log(s) {
document.getElementById("text").innerHTML = s;
document.getElementById("popup").style.display = "block";
}
class WindSimulation {
constructor(width, height, mills) {
this.width = width;
this.height = height;
this.mills = mills;
this.wms = [];
this.init_windmills();
this.wm = null;
this.simulation = null;
this.xhr = null;
this.checkBoard = checkBoard(width, height);
scene.add(this.checkBoard);
const loader = new STLLoader();
loader.load('assets/MonumentoBandera.stl', (geometry) => {
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
var mesh = new THREE.Mesh(geometry, material);
var scale = 0.0093;
mesh.scale.setScalar(scale);
mesh.rotation.z = -Math.PI / 2;
mesh.position.x = 9.5;
mesh.position.y = 0.3;
scene.add(mesh);
this.monument = mesh;
});
this.flag = new ArgentinianFlag(0.3);
this.flag.position.set(9.5, 0.3, 0.3);
this.flag.rotation.z = Math.PI;
scene.add(this.flag);
}
init_windmills() {
if(!WindMill.isReady()) {
setTimeout(() => { this.init_windmills() }, 100);
return;
}
for(var i = 0; i < this.mills; i++) {
var wm = new WindMill();
wm.position.set(i + 0.5, i + 0.5, 0);
wm.rotation.z = Math.PI;
scene.add(wm);
this.wms.push(wm);
}
this.wm = this.wms[0];
}
move(pos, ended=false) {
if(this.simulation) {
scene.remove(this.simulation);
this.simulation = null;
}
var wm = this.wm;
if(ended) {
if(this.wm != null) this.wm.select(false);
this.wm = null;
}
if(wm == null) return false;
if(pos.x > this.width - 0.5 || pos.x < 0.5 || pos.y > this.height - 0.5 || pos.y < 0.5) return false;
for(var i = 0; i < this.wms.length; i++) {
if(this.wms[i] == wm) continue;
if(pos.clone().sub(this.wms[i].position).length() < 1)
return false;
}
wm.position.x = pos.x;
wm.position.y = pos.y;
return true;
}
animate() {
requestAnimationFrame(() => { this.animate(); });
if(!Screen.isMobile || (Screen.isMobile && screen.clicked)) {
const intersects = screen.raycaster.intersectObjects(this.wms);
var wm = null;
for(var i = 0; i < intersects.length; i++) {
if(intersects[i].object.geometry.constructor.name != "CylinderGeometry") {
wm = intersects[i].object.parent;
break;
}
}
if(!screen.clicked || Screen.isMobile) {
if(this.wm != wm) {
if(this.wm != null) this.wm.select(false);
if(wm != null) wm.select(true);
}
this.wm = wm;
}
}
for(var i = 0; i < this.wms.length; i++) {
this.wms[i].animate();
//this.wms[i].rotation.z += 0.01;
}
//this.flag.rotation.z += 0.01;
this.flag.animate();
renderer.render(scene, camera);
}
simulate() {
if(this.xhr != null)
this.xhr.abort();
var xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.open("POST", "/solver/", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = () => {
if(this.xhr != xhr) return;
if (xhr.readyState === 4 && xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
this.add_simulation(json.ws);
this.xhr = null;
}
};
var pos = [];
for(var i = 0; i < this.wms.length; i++)
pos.push([this.wms[i].position.y, this.wms[i].position.x]);
var data = JSON.stringify({"pos": pos});
xhr.send(data);
}
add_simulation(ws) {
var geometry = new THREE.PlaneGeometry(this.width, this.height, 10 * this.width, 10 * this.height);
var colors = new three.BufferAttribute(new Float32Array(geometry.attributes.position.count * 4), 4);
geometry.setAttribute('color', colors);
const material = new THREE.MeshBasicMaterial({vertexColors: true, transparent: true,});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(this.width / 2, this.height / 2, 90/126);
for(var i = 0; i < colors.count; i++) {
var j = Math.trunc(i / 101);
colors.setXYZW(i, 1 - ws[i % 101][100 - j] / 8, 0, 0, 1 - ws[i % 101][100 - j] / 8);
}
if(this.simulation)
scene.remove(this.simulation);
this.simulation = mesh;
scene.add(mesh);
}
}
var width = 10;
var height = 10;
var ws = new WindSimulation(width, height, 5);
var screen = new Screen(camera, renderer, new THREE.Vector3(width / 2 + 0.5, height / 2, -0.65));
screen.setMoveCallBack((pos, end) => { ws.move(pos, end); });
screen.onResize();
window.ws = ws;
window.screen = screen;
window.scene = scene;
ws.animate();