diff --git a/package.json b/package.json index 59d4588..a5cae80 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "jest": "^27.0.4", "prettier": "^2.3.1", "rollup": "^3.2.3", + "rollup-cache": "^2.0.0", "three": "^0.160.1", "ts-jest": "^27.0.3", "ts-node": "^10.0.0", diff --git a/resources/openbim-clay.js b/resources/openbim-clay.js index 2316bb6..86c297b 100644 --- a/resources/openbim-clay.js +++ b/resources/openbim-clay.js @@ -77042,12 +77042,6 @@ function rng() { return getRandomValues(rnds8); } -var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; - -function validate(uuid) { - return typeof uuid === 'string' && REGEX.test(uuid); -} - /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -77065,318 +77059,6 @@ function unsafeStringify(arr, offset = 0) { return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; } -function parse(uuid) { - if (!validate(uuid)) { - throw TypeError('Invalid UUID'); - } - - let v; - const arr = new Uint8Array(16); // Parse ########-....-....-....-............ - - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ - - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ - - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ - - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) - - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; -} - -function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape - - const bytes = []; - - for (let i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); - } - - return bytes; -} - -const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; -const URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; -function v35(name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - var _namespace; - - if (typeof value === 'string') { - value = stringToBytes(value); - } - - if (typeof namespace === 'string') { - namespace = parse(namespace); - } - - if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` - - - let bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; - - if (buf) { - offset = offset || 0; - - for (let i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } - - return buf; - } - - return unsafeStringify(bytes); - } // Function#name is not settable on some platforms (#270) - - - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL$1; - return generateUUID; -} - -/* - * Browser-compatible JavaScript MD5 - * - * Modification of JavaScript MD5 - * https://github.com/blueimp/JavaScript-MD5 - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - * - * Based on - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ -function md5(bytes) { - if (typeof bytes === 'string') { - const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape - - bytes = new Uint8Array(msg.length); - - for (let i = 0; i < msg.length; ++i) { - bytes[i] = msg.charCodeAt(i); - } - } - - return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); -} -/* - * Convert an array of little-endian words to an array of bytes - */ - - -function md5ToHexEncodedArray(input) { - const output = []; - const length32 = input.length * 32; - const hexTab = '0123456789abcdef'; - - for (let i = 0; i < length32; i += 8) { - const x = input[i >> 5] >>> i % 32 & 0xff; - const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); - output.push(hex); - } - - return output; -} -/** - * Calculate output length with padding and bit length - */ - - -function getOutputLength(inputLength8) { - return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; -} -/* - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ - - -function wordsToMd5(x, len) { - /* append padding */ - x[len >> 5] |= 0x80 << len % 32; - x[getOutputLength(len) - 1] = len; - let a = 1732584193; - let b = -271733879; - let c = -1732584194; - let d = 271733878; - - for (let i = 0; i < x.length; i += 16) { - const olda = a; - const oldb = b; - const oldc = c; - const oldd = d; - a = md5ff(a, b, c, d, x[i], 7, -680876936); - d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); - c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); - b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); - a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); - d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); - c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); - b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); - a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); - d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); - c = md5ff(c, d, a, b, x[i + 10], 17, -42063); - b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); - a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); - d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); - c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); - b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); - a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); - d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); - c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); - b = md5gg(b, c, d, a, x[i], 20, -373897302); - a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); - d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); - c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); - b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); - a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); - d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); - c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); - b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); - a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); - d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); - c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); - b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); - a = md5hh(a, b, c, d, x[i + 5], 4, -378558); - d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); - c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); - b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); - a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); - d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); - c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); - b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); - a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); - d = md5hh(d, a, b, c, x[i], 11, -358537222); - c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); - b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); - a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); - d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); - c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); - b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); - a = md5ii(a, b, c, d, x[i], 6, -198630844); - d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); - c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); - b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); - a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); - d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); - c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); - b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); - a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); - d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); - c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); - b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); - a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); - d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); - c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); - b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); - a = safeAdd(a, olda); - b = safeAdd(b, oldb); - c = safeAdd(c, oldc); - d = safeAdd(d, oldd); - } - - return [a, b, c, d]; -} -/* - * Convert an array bytes to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ - - -function bytesToWords(input) { - if (input.length === 0) { - return []; - } - - const length8 = input.length * 8; - const output = new Uint32Array(getOutputLength(length8)); - - for (let i = 0; i < length8; i += 8) { - output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; - } - - return output; -} -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - - -function safeAdd(x, y) { - const lsw = (x & 0xffff) + (y & 0xffff); - const msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return msw << 16 | lsw & 0xffff; -} -/* - * Bitwise rotate a 32-bit number to the left. - */ - - -function bitRotateLeft(num, cnt) { - return num << cnt | num >>> 32 - cnt; -} -/* - * These functions implement the four basic operations the algorithm uses. - */ - - -function md5cmn(q, a, b, x, s, t) { - return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); -} - -function md5ff(a, b, c, d, x, s, t) { - return md5cmn(b & c | ~b & d, a, b, x, s, t); -} - -function md5gg(a, b, c, d, x, s, t) { - return md5cmn(b & d | c & ~d, a, b, x, s, t); -} - -function md5hh(a, b, c, d, x, s, t) { - return md5cmn(b ^ c ^ d, a, b, x, s, t); -} - -function md5ii(a, b, c, d, x, s, t) { - return md5cmn(c ^ (b | ~d), a, b, x, s, t); -} - -v35('v3', 0x30, md5); - const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); var native = { randomUUID @@ -77406,103 +77088,6 @@ function v4(options, buf, offset) { return unsafeStringify(rnds); } -// Adapted from Chris Veness' SHA1 code at -// http://www.movable-type.co.uk/scripts/sha1.html -function f(s, x, y, z) { - switch (s) { - case 0: - return x & y ^ ~x & z; - - case 1: - return x ^ y ^ z; - - case 2: - return x & y ^ x & z ^ y & z; - - case 3: - return x ^ y ^ z; - } -} - -function ROTL(x, n) { - return x << n | x >>> 32 - n; -} - -function sha1(bytes) { - const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; - const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; - - if (typeof bytes === 'string') { - const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape - - bytes = []; - - for (let i = 0; i < msg.length; ++i) { - bytes.push(msg.charCodeAt(i)); - } - } else if (!Array.isArray(bytes)) { - // Convert Array-like to Array - bytes = Array.prototype.slice.call(bytes); - } - - bytes.push(0x80); - const l = bytes.length / 4 + 2; - const N = Math.ceil(l / 16); - const M = new Array(N); - - for (let i = 0; i < N; ++i) { - const arr = new Uint32Array(16); - - for (let j = 0; j < 16; ++j) { - arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3]; - } - - M[i] = arr; - } - - M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); - M[N - 1][14] = Math.floor(M[N - 1][14]); - M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; - - for (let i = 0; i < N; ++i) { - const W = new Uint32Array(80); - - for (let t = 0; t < 16; ++t) { - W[t] = M[i][t]; - } - - for (let t = 16; t < 80; ++t) { - W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); - } - - let a = H[0]; - let b = H[1]; - let c = H[2]; - let d = H[3]; - let e = H[4]; - - for (let t = 0; t < 80; ++t) { - const s = Math.floor(t / 20); - const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0; - e = d; - d = c; - c = ROTL(b, 30) >>> 0; - b = a; - a = T; - } - - H[0] = H[0] + a >>> 0; - H[1] = H[1] + b >>> 0; - H[2] = H[2] + c >>> 0; - H[3] = H[3] + d >>> 0; - H[4] = H[4] + e >>> 0; - } - - return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; -} - -v35('v5', 0x50, sha1); - class FragmentMesh extends THREE.InstancedMesh { constructor(geometry, material, count, fragment) { super(geometry, material, count); @@ -84319,6 +83904,7 @@ class SimpleWall extends Element { this.endPoint = new THREE.Vector3(1, 0, 0); this._openings = new Map(); this._corners = new Map(); + this._halfSpaces = new Map(); this.type = type; const profile = new RectangleProfile(model); this.body = new Extrusion(model, profile); @@ -84332,7 +83918,7 @@ class SimpleWall extends Element { this.attributes = new IFC4X3.IfcWall(new IFC4X3.IfcGloballyUniqueId(v4()), null, null, null, null, placement, shape, null, null); this.model.set(this.attributes); } - update(updateGeometry = false) { + update(updateGeometry = false, updateCorners = false) { this.updateAllOpenings(); const profile = this.body.profile; profile.dimension.x = this.length; @@ -84349,7 +83935,8 @@ class SimpleWall extends Element { this.model.set(reps); this.updateGeometryID(); super.update(updateGeometry); - // this.updateAllCorners(); + if (updateCorners) + this.updateAllCorners(); } extend(wall, atTheEndPoint = true) { const zDirection = new THREE.Vector3(0, 0, 1); @@ -84358,59 +83945,121 @@ class SimpleWall extends Element { const coplanarPoint = new THREE.Vector3(wall.startPoint.x, wall.startPoint.z, wall.startPoint.y * -1); const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(correctedNormalVector, coplanarPoint); const correctedDirection = new THREE.Vector3(this.direction.x * -1, this.direction.z, this.direction.y); - if (atTheEndPoint) { + if (atTheEndPoint) correctedDirection.negate(); - } - const origin = atTheEndPoint ? this.endPoint : this.startPoint; - const sign = atTheEndPoint ? -1 : 1; - const rayOriginPoint = new THREE.Vector3(origin.x, origin.z, origin.y * sign); + const origin = atTheEndPoint ? this.startPoint : this.endPoint; + const rayOriginPoint = new THREE.Vector3(origin.x, origin.z, origin.y * -1); const rayAxisWall1 = new THREE.Ray(rayOriginPoint, correctedDirection); const intersectionPoint = rayAxisWall1.intersectPlane(plane, new THREE.Vector3()); if (intersectionPoint) { const correctedIntersectionPoint = new THREE.Vector3(intersectionPoint === null || intersectionPoint === void 0 ? void 0 : intersectionPoint.x, (intersectionPoint === null || intersectionPoint === void 0 ? void 0 : intersectionPoint.z) * -1, intersectionPoint === null || intersectionPoint === void 0 ? void 0 : intersectionPoint.y); - if (atTheEndPoint) { - this.endPoint = correctedIntersectionPoint; - } - else { - this.startPoint = correctedIntersectionPoint; - } wall.update(true); + this.update(true); return correctedIntersectionPoint; } return null; } + calculateDistances(wall, atTheEndPoint, intersectionPoint) { + const distance1 = this.midPoint.distanceTo(intersectionPoint); + const distance2 = wall.midPoint.distanceTo(intersectionPoint); + const distance3 = this.startPoint.distanceTo(this.midPoint); + const distance4 = this.startPoint.distanceTo(intersectionPoint); + const distance5 = wall.startPoint.distanceTo(wall.midPoint); + const distance6 = wall.startPoint.distanceTo(intersectionPoint); + let sign1 = 1; + let sign2 = 1; + if (distance3 <= distance4 && distance5 <= distance6) { + sign1 = atTheEndPoint ? 1 : -1; + sign2 = atTheEndPoint ? 1 : -1; + } + else if (distance3 >= distance4 && distance5 >= distance6) { + sign1 = -1; + sign2 = -1; + } + else if (distance3 >= distance4 && distance5 <= distance6) { + sign1 = 1; + sign2 = -1; + } + else if (distance3 < distance4 && distance5 > distance6) { + sign1 = -1; + sign2 = 1; + } + const sign3 = atTheEndPoint ? 1 : -1; + return { + distance1, + distance2, + sign1, + sign2, + sign3, + }; + } + updateAllCorners() { + for (const [_id, { wall, atTheEndPoint }] of this._corners) { + const intersectionPoint = this.extend(wall, atTheEndPoint); + if (!intersectionPoint) + return; + const angle = wall.rotation.z - this.rotation.z; + const width1 = this.type.width; + const width2 = wall.type.width; + const { distance1, distance2, sign1, sign2, sign3 } = this.calculateDistances(wall, atTheEndPoint, intersectionPoint); + for (const [_id, { halfSpace }] of wall._halfSpaces) { + halfSpace.position.x = + sign2 * distance1 + width1 / (2 * Math.sin(angle)); + halfSpace.rotation.y = sign3 * angle; + halfSpace.rotation.x = (sign3 * Math.PI) / 2; + halfSpace.update(); + } + for (const [_id, { halfSpace }] of this._halfSpaces) { + halfSpace.position.x = + sign1 * distance2 + width2 / (2 * Math.sin(angle)); + halfSpace.rotation.y = angle; + halfSpace.rotation.x = -Math.PI / 2; + halfSpace.update(); + } + wall.update(true); + } + this.update(true); + } addCorner(wall, atTheEndPoint = true) { const intersectionPoint = this.extend(wall, atTheEndPoint); if (!intersectionPoint) return; const angle = wall.rotation.z - this.rotation.z; - const theta = this.direction.dot(wall.direction) / - (this.direction.length() * wall.direction.length()); - let sign = 1; - if ((Math.asin(theta) < 0 && atTheEndPoint) || - (Math.asin(theta) > 0 && !atTheEndPoint)) { - sign = -1; - } const width1 = this.type.width; const width2 = wall.type.width; - const distance1 = this.midPoint.distanceTo(intersectionPoint); - const distance2 = wall.midPoint.distanceTo(intersectionPoint); - const hsInteriorWall2 = new HalfSpace(this.model); - hsInteriorWall2.position.x = distance1 - width2 / (2 * Math.sin(angle)); - hsInteriorWall2.rotation.y = angle; - hsInteriorWall2.rotation.x = Math.PI / 2; - hsInteriorWall2.update(); + const { distance1, distance2, sign1, sign2, sign3 } = this.calculateDistances(wall, atTheEndPoint, intersectionPoint); const hsExteriorWall1 = new HalfSpace(this.model); hsExteriorWall1.position.x = - sign * distance2 + width1 / (2 * Math.sin(angle)); + sign1 * distance2 + width2 / (2 * Math.sin(angle)); hsExteriorWall1.rotation.y = angle; hsExteriorWall1.rotation.x = -Math.PI / 2; hsExteriorWall1.update(); + const hsInteriorWall2 = new HalfSpace(this.model); + hsInteriorWall2.position.x = + sign2 * distance1 + width1 / (2 * Math.sin(angle)); + hsInteriorWall2.rotation.y = sign3 * angle; + hsInteriorWall2.rotation.x = (sign3 * Math.PI) / 2; + hsInteriorWall2.update(); this.body.addSubtraction(hsInteriorWall2); wall.body.addSubtraction(hsExteriorWall1); wall.update(true); - const id = wall.attributes.expressID; - this._corners.set(id, { wall, atTheEndPoint }); + this.update(true); + this._corners.set(wall.attributes.expressID, { + wall, + atTheEndPoint, + }); + wall._corners.set(this.attributes.expressID, { + wall: this, + atTheEndPoint, + }); + const hsInteriorWall2Id = hsInteriorWall2.attributes.expressID; + const hsExteriorWall1Id = hsExteriorWall1.attributes.expressID; + wall._halfSpaces.set(hsInteriorWall2Id, { + halfSpace: hsInteriorWall2, + }); + this._halfSpaces.set(hsExteriorWall1Id, { + halfSpace: hsExteriorWall1, + }); } addOpening(opening) { super.addOpening(opening); diff --git a/resources/rollup.config.mjs b/resources/rollup.config.mjs index 788e7c4..45134f5 100644 --- a/resources/rollup.config.mjs +++ b/resources/rollup.config.mjs @@ -1,20 +1,26 @@ import { nodeResolve } from "@rollup/plugin-node-resolve"; -import extensions from './rollup-extensions.mjs'; +import extensions from "./rollup-extensions.mjs"; import commonjs from "@rollup/plugin-commonjs"; -// This creates the bundle used by the examples -export default { - input: "dist/src/index.js", - output: { - file: "./resources/openbim-clay.js", - format: "esm", - }, - external: ["three"], // so it's not included - plugins: [ - extensions({ - extensions: [ '.js' ], - }), - nodeResolve(), - commonjs() - ], +import { cacheBuild } from "rollup-cache"; + +const cacheConfig = { + name: "clay", }; + +// This creates the bundle used by the examples +export default cacheBuild(cacheConfig, { + input: "dist/src/index.js", + output: { + file: "./resources/openbim-clay.js", + format: "esm", + }, + external: ["three"], // so it's not included + plugins: [ + extensions({ + extensions: [".js"], + }), + nodeResolve(), + commonjs(), + ], +}); diff --git a/src/elements/Walls/SimpleWall/index.html b/src/elements/Walls/SimpleWall/index.html index cc4376d..3758685 100644 --- a/src/elements/Walls/SimpleWall/index.html +++ b/src/elements/Walls/SimpleWall/index.html @@ -108,16 +108,16 @@ // wall.addOpening(opening); // wall.update(true); - wall.startPoint.x = -5; - wall.startPoint.y = 0; + wall.startPoint.x = 0; + wall.startPoint.y = -15; wall.endPoint.x = 0; - wall.endPoint.y = 10; + wall.endPoint.y = 20; wall.update(true); - wall2.startPoint.x = 30; - wall2.startPoint.y = 20; - wall2.endPoint.x = -30; - wall2.endPoint.y = 20; + wall2.startPoint.x = 35; + wall2.startPoint.y = 15; + wall2.endPoint.x = -35; + wall2.endPoint.y = 15; wall2.update(true); wall.addCorner(wall2, true); //at the end point => true @@ -135,41 +135,41 @@ gui .add(wall.startPoint, "x") .name("Start X") - .min(-5) - .max(5) + .min(-15) + .max(15) .step(0.1) .onChange(() => { - wall.update(true); + wall.update(true, true); }); gui .add(wall.startPoint, "y") .name("Start Y") - .min(-5) - .max(5) + .min(-15) + .max(15) .step(0.1) .onChange(() => { - wall.update(true); + wall.update(true, true); }); gui .add(wall.endPoint, "x") .name("End X") - .min(-5) - .max(5) + .min(-15) + .max(15) .step(0.1) .onChange(() => { - wall.update(true); + wall.update(true, true); }); gui .add(wall.endPoint, "y") .name("End Y") - .min(-5) - .max(5) + .min(-15) + .max(15) .step(0.1) .onChange(() => { - wall.update(true); + wall.update(true, true); }); gui @@ -190,6 +190,7 @@ .step(0.05) .onChange(() => { simpleWallType.update(true); + wall.update(false, true); }); gui diff --git a/src/elements/Walls/SimpleWall/src/index.ts b/src/elements/Walls/SimpleWall/src/index.ts index 85cce16..62ac870 100644 --- a/src/elements/Walls/SimpleWall/src/index.ts +++ b/src/elements/Walls/SimpleWall/src/index.ts @@ -33,6 +33,8 @@ export class SimpleWall extends Element { { wall: SimpleWall; atTheEndPoint: boolean } >(); + _halfSpaces = new Map(); + get length() { return this.startPoint.distanceTo(this.endPoint); } @@ -82,7 +84,7 @@ export class SimpleWall extends Element { this.model.set(this.attributes); } - update(updateGeometry: boolean = false) { + update(updateGeometry: boolean = false, updateCorners = false) { this.updateAllOpenings(); const profile = this.body.profile; @@ -101,9 +103,11 @@ export class SimpleWall extends Element { const reps = this.model.get(shape.Representations[0]); reps.Items = [this.body.attributes]; this.model.set(reps); + this.updateGeometryID(); super.update(updateGeometry); - // this.updateAllCorners(); + + if (updateCorners) this.updateAllCorners(); } extend(wall: SimpleWall, atTheEndPoint = true) { @@ -132,21 +136,13 @@ export class SimpleWall extends Element { this.direction.y ); - if (atTheEndPoint) { - correctedDirection.negate(); - } + if (atTheEndPoint) correctedDirection.negate(); - const origin = atTheEndPoint ? this.endPoint : this.startPoint; - const sign = atTheEndPoint ? -1 : 1; + const origin = atTheEndPoint ? this.startPoint : this.endPoint; - const rayOriginPoint = new THREE.Vector3( - origin.x, - origin.z, - origin.y * sign - ); + const rayOriginPoint = new THREE.Vector3(origin.x, origin.z, origin.y * -1); const rayAxisWall1 = new THREE.Ray(rayOriginPoint, correctedDirection); - const intersectionPoint = rayAxisWall1.intersectPlane( plane, new THREE.Vector3() @@ -159,61 +155,143 @@ export class SimpleWall extends Element { intersectionPoint?.y ); - if (atTheEndPoint) { - this.endPoint = correctedIntersectionPoint; - } else { - this.startPoint = correctedIntersectionPoint; - } - wall.update(true); + this.update(true); return correctedIntersectionPoint; } return null; } + private calculateDistances( + wall: SimpleWall, + atTheEndPoint: boolean, + intersectionPoint: THREE.Vector3 + ) { + const distance1 = this.midPoint.distanceTo(intersectionPoint); + const distance2 = wall.midPoint.distanceTo(intersectionPoint); + + const distance3 = this.startPoint.distanceTo(this.midPoint); + const distance4 = this.startPoint.distanceTo(intersectionPoint); + + const distance5 = wall.startPoint.distanceTo(wall.midPoint); + const distance6 = wall.startPoint.distanceTo(intersectionPoint); + + let sign1 = 1; + let sign2 = 1; + + if (distance3 <= distance4 && distance5 <= distance6) { + sign1 = atTheEndPoint ? 1 : -1; + sign2 = atTheEndPoint ? 1 : -1; + } else if (distance3 >= distance4 && distance5 >= distance6) { + sign1 = -1; + sign2 = -1; + } else if (distance3 >= distance4 && distance5 <= distance6) { + sign1 = 1; + sign2 = -1; + } else if (distance3 < distance4 && distance5 > distance6) { + sign1 = -1; + sign2 = 1; + } + + const sign3 = atTheEndPoint ? 1 : -1; + + return { + distance1, + distance2, + sign1, + sign2, + sign3, + }; + } + + private updateAllCorners() { + for (const [_id, { wall, atTheEndPoint }] of this._corners) { + const intersectionPoint = this.extend(wall, atTheEndPoint); + if (!intersectionPoint) return; + + const angle = wall.rotation.z - this.rotation.z; + + const width1 = this.type.width; + const width2 = wall.type.width; + + const { distance1, distance2, sign1, sign2, sign3 } = + this.calculateDistances(wall, atTheEndPoint, intersectionPoint); + + for (const [_id, { halfSpace }] of wall._halfSpaces) { + halfSpace.position.x = + sign2 * distance1 + width1 / (2 * Math.sin(angle)); + halfSpace.rotation.y = sign3 * angle; + halfSpace.rotation.x = (sign3 * Math.PI) / 2; + halfSpace.update(); + } + + for (const [_id, { halfSpace }] of this._halfSpaces) { + halfSpace.position.x = + sign1 * distance2 + width2 / (2 * Math.sin(angle)); + halfSpace.rotation.y = angle; + halfSpace.rotation.x = -Math.PI / 2; + halfSpace.update(); + } + + wall.update(true); + } + this.update(true); + } + addCorner(wall: SimpleWall, atTheEndPoint = true) { const intersectionPoint = this.extend(wall, atTheEndPoint); + if (!intersectionPoint) return; const angle = wall.rotation.z - this.rotation.z; - const theta = - this.direction.dot(wall.direction) / - (this.direction.length() * wall.direction.length()); - - let sign = 1; - if ( - (Math.asin(theta) < 0 && atTheEndPoint) || - (Math.asin(theta) > 0 && !atTheEndPoint) - ) { - sign = -1; - } - const width1 = this.type.width; const width2 = wall.type.width; - const distance1 = this.midPoint.distanceTo(intersectionPoint); - const distance2 = wall.midPoint.distanceTo(intersectionPoint); - const hsInteriorWall2 = new HalfSpace(this.model); - hsInteriorWall2.position.x = distance1 - width2 / (2 * Math.sin(angle)); - hsInteriorWall2.rotation.y = angle; - hsInteriorWall2.rotation.x = Math.PI / 2; - hsInteriorWall2.update(); + const { distance1, distance2, sign1, sign2, sign3 } = + this.calculateDistances(wall, atTheEndPoint, intersectionPoint); const hsExteriorWall1 = new HalfSpace(this.model); hsExteriorWall1.position.x = - sign * distance2 + width1 / (2 * Math.sin(angle)); + sign1 * distance2 + width2 / (2 * Math.sin(angle)); hsExteriorWall1.rotation.y = angle; hsExteriorWall1.rotation.x = -Math.PI / 2; hsExteriorWall1.update(); + const hsInteriorWall2 = new HalfSpace(this.model); + hsInteriorWall2.position.x = + sign2 * distance1 + width1 / (2 * Math.sin(angle)); + hsInteriorWall2.rotation.y = sign3 * angle; + hsInteriorWall2.rotation.x = (sign3 * Math.PI) / 2; + hsInteriorWall2.update(); + this.body.addSubtraction(hsInteriorWall2); wall.body.addSubtraction(hsExteriorWall1); + wall.update(true); + this.update(true); + + this._corners.set(wall.attributes.expressID, { + wall, + atTheEndPoint, + }); - const id = wall.attributes.expressID; - this._corners.set(id, { wall, atTheEndPoint }); + wall._corners.set(this.attributes.expressID, { + wall: this, + atTheEndPoint, + }); + + const hsInteriorWall2Id = hsInteriorWall2.attributes.expressID; + const hsExteriorWall1Id = hsExteriorWall1.attributes.expressID; + + wall._halfSpaces.set(hsInteriorWall2Id, { + halfSpace: hsInteriorWall2, + }); + + this._halfSpaces.set(hsExteriorWall1Id, { + halfSpace: hsExteriorWall1, + }); } addOpening(opening: SimpleOpening) { diff --git a/tsconfig.json b/tsconfig.json index e76b269..c3ad4e0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,20 +3,20 @@ /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "incremental": true /* Enable incremental compilation */, + "target": "ES2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, // "lib": [], /* Specify library files to be included in the compilation. */ - "allowJs": false, /* Allow javascript files to be compiled. */ + "allowJs": false /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ + "sourceMap": true /* Generates corresponding '.map' file. */, // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist", /* Redirect output structure to the directory. */ + "outDir": "./dist" /* Redirect output structure to the directory. */, // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - "composite": true, /* Enable project compilation */ + "composite": true /* Enable project compilation */, // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "removeComments": true, /* Do not emit comments to output. */ // "noEmit": true, /* Do not emit outputs. */ @@ -25,7 +25,7 @@ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ @@ -35,22 +35,22 @@ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ - "noUnusedLocals": true, /* Report errors on unused locals. */ - "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noUnusedLocals": true /* Report errors on unused locals. */, + "noUnusedParameters": true /* Report errors on unused parameters. */, // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ - "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, // "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ - "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + "preserveSymlinks": true /* Do not resolve the real path of symlinks. */, // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ /* Source Map Options */ @@ -64,8 +64,8 @@ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ /* Advanced Options */ - "skipLibCheck": true, /* Skip type checking of declaration files. */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ }, "typedocOptions": { "entryPoints": ["src/index.ts"], @@ -77,8 +77,6 @@ "excludeProtected": true, "excludeReferences": true }, - "include": [ - "src/**/*" - ], + "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } diff --git a/yarn.lock b/yarn.lock index 176bbc7..18033db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -730,7 +730,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.14": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -849,6 +849,25 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-commonjs@npm:^25.0.2": + version: 25.0.7 + resolution: "@rollup/plugin-commonjs@npm:25.0.7" + dependencies: + "@rollup/pluginutils": ^5.0.1 + commondir: ^1.0.1 + estree-walker: ^2.0.2 + glob: ^8.0.3 + is-reference: 1.2.1 + magic-string: ^0.30.3 + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 052e11839a9edc556eda5dcc759ab816dcc57e9f0f905a1e6e14fff954eaa6b1e2d0d544f5bd18d863993c5eba43d8ac9c19d9bb53b1c3b1213f32cfc9d50b2e + languageName: node + linkType: hard + "@rollup/plugin-node-resolve@npm:15.1.0": version: 15.1.0 resolution: "@rollup/plugin-node-resolve@npm:15.1.0" @@ -868,6 +887,40 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-node-resolve@npm:^15.1.0": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" + dependencies: + "@rollup/pluginutils": ^5.0.1 + "@types/resolve": 1.20.2 + deepmerge: ^4.2.2 + is-builtin-module: ^3.2.1 + is-module: ^1.0.0 + resolve: ^1.22.1 + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 730f32c2f8fdddff07cf0fca86a5dac7c475605fb96930197a868c066e62eb6388c557545e4f7d99b7a283411754c9fbf98944ab086b6074e04fc1292e234aa8 + languageName: node + linkType: hard + +"@rollup/plugin-replace@npm:^5.0.2": + version: 5.0.5 + resolution: "@rollup/plugin-replace@npm:5.0.5" + dependencies: + "@rollup/pluginutils": ^5.0.1 + magic-string: ^0.30.3 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 5559b48fa098a842ddb3a25b23d9902d75496bed807d4cabac304bb7e75b06374ad4a44f7871ddcd1bfcf23e6015a0274d44564b42af54c722af0a514c247ec1 + languageName: node + linkType: hard + "@rollup/pluginutils@npm:^5.0.1": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" @@ -5037,6 +5090,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.3": + version: 0.30.8 + resolution: "magic-string@npm:0.30.8" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.15 + checksum: 79922f4500d3932bb587a04440d98d040170decf432edc0f91c0bf8d41db16d364189bf800e334170ac740918feda62cd39dcc170c337dc18050cfcf00a5f232 + languageName: node + linkType: hard + "make-dir@npm:^3.0.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" @@ -5653,6 +5715,7 @@ __metadata: jest: ^27.0.4 prettier: ^2.3.1 rollup: ^3.2.3 + rollup-cache: ^2.0.0 three: ^0.160.1 three-mesh-bvh: 0.7.0 ts-jest: ^27.0.3 @@ -6244,7 +6307,19 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.2.3": +"rollup-cache@npm:^2.0.0": + version: 2.0.0 + resolution: "rollup-cache@npm:2.0.0" + dependencies: + "@rollup/plugin-commonjs": ^25.0.2 + "@rollup/plugin-node-resolve": ^15.1.0 + "@rollup/plugin-replace": ^5.0.2 + rollup: ^3.25.1 + checksum: 2bf0ffc45373b81b8c75a63c7c80f9f2fa5e5b50be0e58b9eff5f232aa3dfb93dd0171e66140324e28c3aa1471078fb3a93c8309c96b40566527512d1209d1ef + languageName: node + linkType: hard + +"rollup@npm:^3.2.3, rollup@npm:^3.25.1": version: 3.29.4 resolution: "rollup@npm:3.29.4" dependencies: