"use strict"; const RailingGeometryGame = (function(){ const RailingGeometryGame = function(hollow_bond){ const cache = {}; // Genera un prisma cuadrangular (box) dentro de los buffers de la geometría const append_box = (buffers, min_x, max_x, min_y, max_y, min_z, max_z) => { const { positions, normals, uvs, indices } = buffers; let offset = positions.length / 3; const add_quad = (p1, p2, p3, p4, n) => { positions.push(...p1, ...p2, ...p3, ...p4); normals.push(...n, ...n, ...n, ...n); uvs.push(0, 0, 1, 0, 1, 1, 0, 1); indices.push(offset, offset + 2, offset + 1, offset, offset + 3, offset + 2); offset += 4; }; // Top (+Y) y Bottom (-Y) add_quad([min_x, max_y, max_z], [max_x, max_y, max_z], [max_x, max_y, min_z], [min_x, max_y, min_z], [0, 1, 0]); add_quad([min_x, min_y, min_z], [max_x, min_y, min_z], [max_x, min_y, max_z], [min_x, min_y, max_z], [0, -1, 0]); // North (-Z) y South (+Z) add_quad([max_x, min_y, min_z], [min_x, min_y, min_z], [min_x, max_y, min_z], [max_x, max_y, min_z], [0, 0, -1]); add_quad([min_x, min_y, max_z], [max_x, min_y, max_z], [max_x, max_y, max_z], [min_x, max_y, max_z], [0, 0, 1]); // West (-X) y East (+X) add_quad([min_x, min_y, min_z], [min_x, min_y, max_z], [min_x, max_y, max_z], [min_x, max_y, min_z], [-1, 0, 0]); add_quad([max_x, min_y, max_z], [max_x, min_y, min_z], [max_x, max_y, min_z], [max_x, max_y, max_z], [1, 0, 0]); }; this.get_for_segment = segment => { const is_x = (segment.side === "north" || segment.side === "south"); const length = is_x ? Math.abs(segment.xt - segment.xf) : Math.abs(segment.zt - segment.zf); const height = segment.height || 1.0; const th = segment.thickness || 0.08; const h_th = th * 0.5; const key = `rail_${is_x ? "x" : "z"}_${length.toFixed(2)}`; if(cache[key]){ return cache[key]; } const buffers = { positions: [], normals: [], uvs: [], indices: [] }; const half_len = length * 0.5; // 1. Pasamanos superior (1.0m) y Travesaño medio (0.5m) if(is_x){ append_box(buffers, -half_len, half_len, height - 0.05, height, -h_th, h_th); append_box(buffers, -half_len, half_len, height * 0.5 - 0.02, height * 0.5 + 0.02, -h_th * 0.7, h_th * 0.7); } else { append_box(buffers, -h_th, h_th, height - 0.05, height, -half_len, half_len); append_box(buffers, -h_th * 0.7, h_th * 0.7, height * 0.5 - 0.02, height * 0.5 + 0.02, -half_len, half_len); } // 2. Postes verticales (en los extremos y espaciados cada ~1.0m) const post_count = Math.max(2, Math.round(length / 1.0) + 1); for(let i = 0; i < post_count; i++){ const t = i / (post_count - 1); const pos = (t - 0.5) * length; if(is_x){ append_box(buffers, pos - h_th, pos + h_th, 0, height, -h_th, h_th); } else { append_box(buffers, -h_th, h_th, 0, height, pos - h_th, pos + h_th); } } const geometry = new THREE.BufferGeometry(); geometry.setAttribute("position", new THREE.Float32BufferAttribute(buffers.positions, 3)); geometry.setAttribute("normal", new THREE.Float32BufferAttribute(buffers.normals, 3)); geometry.setAttribute("uv", new THREE.Float32BufferAttribute(buffers.uvs, 2)); geometry.setIndex(buffers.indices); cache[key] = geometry; return geometry; }; this.reset = () => { for(const k in cache){ cache[k].dispose(); delete cache[k]; } }; }; return RailingGeometryGame; })();