From ef25663edc659ef537811d1b8534eb878e89d3eb Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Mon, 24 Jun 2024 20:51:33 -0400 Subject: [PATCH 01/13] separate intersection component code --- src/components/intersection.js | 353 ++++++++++++++++++++++++++++++++ src/index.js | 354 +-------------------------------- 2 files changed, 354 insertions(+), 353 deletions(-) create mode 100644 src/components/intersection.js diff --git a/src/components/intersection.js b/src/components/intersection.js new file mode 100644 index 000000000..93cf057fe --- /dev/null +++ b/src/components/intersection.js @@ -0,0 +1,353 @@ +/* global AFRAME */ +AFRAME.registerComponent('intersection', { + schema: { + dimensions: { type: 'string', default: '20 20' }, + sidewalk: { type: 'string', default: '0 0 0 0' }, + northeastcurb: { type: 'string', default: '0 0' }, + southwestcurb: { type: 'string', default: '0 0' }, + southeastcurb: { type: 'string', default: '0 0' }, + northwestcurb: { type: 'string', default: '0 0' }, + stopsign: { type: 'string', default: '0 0 0 0' }, + trafficsignal: { type: 'string', default: '0 0 0 0' }, + crosswalk: { type: 'string', default: '0 0 0 0' } + }, + init: function () { + var data = this.data; + var el = this.el; + + // remove all child nodes if exists + while (el.firstChild) { + el.removeChild(el.lastChild); + } + const dimensionsArray = data.dimensions.split(' ').map((i) => Number(i)); + const positionArray = [ + this.el.getAttribute('position').x, + this.el.getAttribute('position').y, + this.el.getAttribute('position').z + ]; + const sidewalkArray = data.sidewalk.split(' ').map((i) => Number(i)); + const northeastcurbArray = data.northeastcurb + .split(' ') + .map((i) => Number(i)); + const southwestcurbArray = data.southwestcurb + .split(' ') + .map((i) => Number(i)); + const southeastcurbArray = data.southeastcurb + .split(' ') + .map((i) => Number(i)); + const northwestcurbArray = data.northwestcurb + .split(' ') + .map((i) => Number(i)); + const stopsignArray = data.stopsign.split(' ').map((i) => Number(i)); + const trafficsignalArray = data.trafficsignal + .split(' ') + .map((i) => Number(i)); + const crosswalklArray = data.crosswalk.split(' ').map((i) => Number(i)); + + const intersectWidth = dimensionsArray[0]; + const intersectDepth = dimensionsArray[1]; + + this.el.setAttribute( + 'geometry', + `primitive:box; width: ${intersectWidth}; height: ${intersectDepth}; depth:0.2` + ); + this.el.setAttribute('position', { + x: positionArray[0], + y: -0.1, + z: positionArray[2] + }); + this.el.setAttribute('rotation', '-90 0 0'); + this.el.setAttribute( + 'material', + 'src: #asphalt-texture; repeat:5 5; roughness:1' + ); + + function createSidewalkElem({ + length, + width, + positionVec, + scaleVec = { x: 1, y: 1, z: 1 }, + rotationVec + }) { + const sd = document.createElement('a-entity'); + const repeatCountInter = []; + repeatCountInter[0] = width / 2; + // every 2 meters repeat sidewalk texture + repeatCountInter[1] = parseInt(length / 2); + + sd.setAttribute('geometry', 'primitive', 'box'); + sd.setAttribute('geometry', 'height: 0.4'); + sd.setAttribute('position', positionVec); + sd.setAttribute('scale', scaleVec); + sd.setAttribute('geometry', 'depth', length); + sd.setAttribute('geometry', 'width', width); + sd.setAttribute('rotation', rotationVec); + sd.setAttribute('mixin', 'sidewalk'); + sd.setAttribute( + 'material', + `repeat: ${repeatCountInter[0]} ${repeatCountInter[1]}` + ); + el.appendChild(sd); + } + + // describe sidewalk parameters + const sidewalkParams = { + west: { + positionVec: { x: intersectWidth / 2 - sidewalkArray[0] / 2, z: 0.1 }, + rotationVec: { x: 90, y: 0, z: 0 }, + length: intersectDepth, + width: sidewalkArray[0] + }, + east: { + positionVec: { x: -intersectWidth / 2 + sidewalkArray[1] / 2, z: 0.1 }, + rotationVec: { x: 90, y: 0, z: 0 }, + length: intersectDepth, + width: sidewalkArray[1] + }, + north: { + positionVec: { + y: -intersectDepth / 2 + sidewalkArray[2] / 2, + // add x offset to avoid sidewalk's element overlap + x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + // minus the width of the crossing sidewalk + length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], + width: sidewalkArray[2] + }, + south: { + positionVec: { + y: intersectDepth / 2 - sidewalkArray[3] / 2, + // add x offset to avoid sidewalk's element overlap + x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + // minus the width of the crossing sidewalk + length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], + width: sidewalkArray[3] + } + }; + + // create sidewalks if they are given in sidewalkArray + const selectedSidewalks = Object.keys(sidewalkParams).filter( + (el, ind) => sidewalkArray[ind] + ); + + selectedSidewalks.forEach((sidewalkName, ind) => { + const params = sidewalkParams[sidewalkName]; + createSidewalkElem(params); + }); + + // describe curb parameters + const curbParams = { + northeast: { + positionVec: { + x: intersectWidth / 2 - northeastcurbArray[0] / 2, + y: intersectDepth / 2 - northeastcurbArray[1] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + length: northeastcurbArray[0], + width: northeastcurbArray[1] + }, + southwest: { + positionVec: { + x: -intersectWidth / 2 + southwestcurbArray[0] / 2, + y: -intersectDepth / 2 + southwestcurbArray[1] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + length: southwestcurbArray[0], + width: southwestcurbArray[1] + }, + southeast: { + positionVec: { + x: intersectWidth / 2 - southeastcurbArray[0] / 2, + y: -intersectDepth / 2 + southeastcurbArray[1] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + length: southeastcurbArray[0], + width: southeastcurbArray[1] + }, + northwest: { + positionVec: { + x: -intersectWidth / 2 + northwestcurbArray[0] / 2, + y: intersectDepth / 2 - northwestcurbArray[1] / 2, + z: 0.1 + }, + rotationVec: { x: 0, y: 90, z: -90 }, + length: northwestcurbArray[0], + width: northwestcurbArray[1] + } + }; + + // create curbs if they are given + for (const [curbName, params] of Object.entries(curbParams)) { + if (data[`${curbName}curb`] !== '0 0') { + createSidewalkElem(params); + } + } + + if (stopsignArray[0]) { + const ss1 = document.createElement('a-entity'); + ss1.setAttribute('position', { + x: intersectWidth / 2, + y: intersectDepth / 3, + z: 0.1 + }); + ss1.setAttribute('rotation', { x: 0, y: 90, z: 90 }); + ss1.setAttribute('mixin', 'stop_sign'); + el.appendChild(ss1); + } + if (stopsignArray[1]) { + const ss2 = document.createElement('a-entity'); + ss2.setAttribute('position', { + x: -intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.1 + }); + ss2.setAttribute('rotation', { x: 0, y: -90, z: -90 }); + ss2.setAttribute('mixin', 'stop_sign'); + el.appendChild(ss2); + } + if (stopsignArray[2]) { + const ss3 = document.createElement('a-entity'); + ss3.setAttribute('position', { + x: -intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }); + ss3.setAttribute('rotation', { x: -90, y: 90, z: 90 }); + ss3.setAttribute('mixin', 'stop_sign'); + el.appendChild(ss3); + } + if (stopsignArray[3]) { + const ss4 = document.createElement('a-entity'); + ss4.setAttribute('position', { + x: intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }); + ss4.setAttribute('rotation', { x: 90, y: -90, z: -90 }); + ss4.setAttribute('mixin', 'stop_sign'); + el.appendChild(ss4); + } + + if (trafficsignalArray[0]) { + const ts1 = document.createElement('a-entity'); + ts1.setAttribute('position', { + x: intersectWidth / 2, + y: intersectDepth / 3, + z: 0.3 + }); + ts1.setAttribute('rotation', { x: 210, y: 90, z: 90 }); + ts1.setAttribute('mixin', 'signal_left'); + el.appendChild(ts1); + const ts2 = document.createElement('a-entity'); + ts2.setAttribute('position', { + x: intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.3 + }); + ts2.setAttribute('rotation', { x: 180, y: 90, z: 90 }); + ts2.setAttribute('mixin', 'signal_right'); + el.appendChild(ts2); + } + if (trafficsignalArray[1]) { + const ts3 = document.createElement('a-entity'); + ts3.setAttribute('position', { + x: -intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.3 + }); + ts3.setAttribute('rotation', { x: 30, y: 90, z: 90 }); + ts3.setAttribute('mixin', 'signal_left'); + el.appendChild(ts3); + const ts4 = document.createElement('a-entity'); + ts4.setAttribute('position', { + x: -intersectWidth / 2, + y: intersectDepth / 3, + z: 0.3 + }); + ts4.setAttribute('rotation', { x: 0, y: 90, z: 90 }); + ts4.setAttribute('mixin', 'signal_right'); + el.appendChild(ts4); + } + if (trafficsignalArray[2]) { + const ts5 = document.createElement('a-entity'); + ts5.setAttribute('position', { + x: -intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }); + ts5.setAttribute('rotation', { x: 120, y: 90, z: 90 }); + ts5.setAttribute('mixin', 'signal_left'); + el.appendChild(ts5); + const ts6 = document.createElement('a-entity'); + ts6.setAttribute('position', { + x: intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }); + ts6.setAttribute('rotation', { x: 90, y: 90, z: 90 }); + ts6.setAttribute('mixin', 'signal_right'); + el.appendChild(ts6); + } + if (trafficsignalArray[3]) { + const ts7 = document.createElement('a-entity'); + ts7.setAttribute('position', { + x: intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }); + ts7.setAttribute('rotation', { x: -60, y: 90, z: 90 }); + ts7.setAttribute('mixin', 'signal_left'); + el.appendChild(ts7); + const ts8 = document.createElement('a-entity'); + ts8.setAttribute('position', { + x: -intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }); + ts8.setAttribute('rotation', { x: -90, y: 90, z: 90 }); + ts8.setAttribute('mixin', 'signal_right'); + el.appendChild(ts8); + } + + if (crosswalklArray[0]) { + const cw1 = document.createElement('a-entity'); + cw1.setAttribute('position', { x: intersectWidth / 2 - 2, z: 0.11 }); + cw1.setAttribute('rotation', { x: 0, y: 0, z: 180 }); + cw1.setAttribute('scale', { y: intersectDepth / 12 }); + cw1.setAttribute('mixin', 'markings crosswalk-zebra'); + el.appendChild(cw1); + } + if (crosswalklArray[1]) { + const cw2 = document.createElement('a-entity'); + cw2.setAttribute('position', { x: -intersectWidth / 2 + 2, z: 0.11 }); + cw2.setAttribute('rotation', { x: 0, y: 0, z: 180 }); + cw2.setAttribute('scale', { y: intersectDepth / 12 }); + cw2.setAttribute('mixin', 'markings crosswalk-zebra'); + el.appendChild(cw2); + } + if (crosswalklArray[2]) { + const cw3 = document.createElement('a-entity'); + cw3.setAttribute('position', { y: -intersectDepth / 2 + 2, z: 0.11 }); + cw3.setAttribute('rotation', { x: 0, y: 0, z: 90 }); + cw3.setAttribute('scale', { y: intersectWidth / 12 }); + cw3.setAttribute('mixin', 'markings crosswalk-zebra'); + el.appendChild(cw3); + } + if (crosswalklArray[3]) { + const cw4 = document.createElement('a-entity'); + cw4.setAttribute('position', { y: intersectDepth / 2 - 2, z: 0.11 }); + cw4.setAttribute('rotation', { x: 0, y: 0, z: 90 }); + cw4.setAttribute('scale', { y: intersectWidth / 12 }); + cw4.setAttribute('mixin', 'markings crosswalk-zebra'); + el.appendChild(cw4); + } + } +}); diff --git a/src/index.js b/src/index.js index 02e83ddb5..d5d60118d 100644 --- a/src/index.js +++ b/src/index.js @@ -21,6 +21,7 @@ require('aframe-atlas-uvs-component'); require('./components/streetplan-loader'); require('./components/street-geo.js'); require('./components/street-environment.js'); +require('./components/intersection.js'); AFRAME.registerComponent('street', { schema: { @@ -204,359 +205,6 @@ AFRAME.registerComponent('streetmix-loader', { } }); -AFRAME.registerComponent('intersection', { - schema: { - dimensions: { type: 'string', default: '20 20' }, - sidewalk: { type: 'string', default: '0 0 0 0' }, - northeastcurb: { type: 'string', default: '0 0' }, - southwestcurb: { type: 'string', default: '0 0' }, - southeastcurb: { type: 'string', default: '0 0' }, - northwestcurb: { type: 'string', default: '0 0' }, - stopsign: { type: 'string', default: '0 0 0 0' }, - trafficsignal: { type: 'string', default: '0 0 0 0' }, - crosswalk: { type: 'string', default: '0 0 0 0' } - }, - init: function () { - var data = this.data; - var el = this.el; - - // remove all child nodes if exists - while (el.firstChild) { - el.removeChild(el.lastChild); - } - const dimensionsArray = data.dimensions.split(' ').map((i) => Number(i)); - const positionArray = [ - this.el.getAttribute('position').x, - this.el.getAttribute('position').y, - this.el.getAttribute('position').z - ]; - const sidewalkArray = data.sidewalk.split(' ').map((i) => Number(i)); - const northeastcurbArray = data.northeastcurb - .split(' ') - .map((i) => Number(i)); - const southwestcurbArray = data.southwestcurb - .split(' ') - .map((i) => Number(i)); - const southeastcurbArray = data.southeastcurb - .split(' ') - .map((i) => Number(i)); - const northwestcurbArray = data.northwestcurb - .split(' ') - .map((i) => Number(i)); - const stopsignArray = data.stopsign.split(' ').map((i) => Number(i)); - const trafficsignalArray = data.trafficsignal - .split(' ') - .map((i) => Number(i)); - const crosswalklArray = data.crosswalk.split(' ').map((i) => Number(i)); - - const intersectWidth = dimensionsArray[0]; - const intersectDepth = dimensionsArray[1]; - - this.el.setAttribute( - 'geometry', - `primitive:box; width: ${intersectWidth}; height: ${intersectDepth}; depth:0.2` - ); - this.el.setAttribute('position', { - x: positionArray[0], - y: -0.1, - z: positionArray[2] - }); - this.el.setAttribute('rotation', '-90 0 0'); - this.el.setAttribute( - 'material', - 'src: #asphalt-texture; repeat:5 5; roughness:1' - ); - - function createSidewalkElem({ - length, - width, - positionVec, - scaleVec = { x: 1, y: 1, z: 1 }, - rotationVec - }) { - const sd = document.createElement('a-entity'); - const repeatCountInter = []; - repeatCountInter[0] = width / 2; - // every 2 meters repeat sidewalk texture - repeatCountInter[1] = parseInt(length / 2); - - sd.setAttribute('geometry', 'primitive', 'box'); - sd.setAttribute('geometry', 'height: 0.4'); - sd.setAttribute('position', positionVec); - sd.setAttribute('scale', scaleVec); - sd.setAttribute('geometry', 'depth', length); - sd.setAttribute('geometry', 'width', width); - sd.setAttribute('rotation', rotationVec); - sd.setAttribute('mixin', 'sidewalk'); - sd.setAttribute( - 'material', - `repeat: ${repeatCountInter[0]} ${repeatCountInter[1]}` - ); - el.appendChild(sd); - } - - // describe sidewalk parameters - const sidewalkParams = { - west: { - positionVec: { x: intersectWidth / 2 - sidewalkArray[0] / 2, z: 0.1 }, - rotationVec: { x: 90, y: 0, z: 0 }, - length: intersectDepth, - width: sidewalkArray[0] - }, - east: { - positionVec: { x: -intersectWidth / 2 + sidewalkArray[1] / 2, z: 0.1 }, - rotationVec: { x: 90, y: 0, z: 0 }, - length: intersectDepth, - width: sidewalkArray[1] - }, - north: { - positionVec: { - y: -intersectDepth / 2 + sidewalkArray[2] / 2, - // add x offset to avoid sidewalk's element overlap - x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - // minus the width of the crossing sidewalk - length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[2] - }, - south: { - positionVec: { - y: intersectDepth / 2 - sidewalkArray[3] / 2, - // add x offset to avoid sidewalk's element overlap - x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - // minus the width of the crossing sidewalk - length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[3] - } - }; - - // create sidewalks if they are given in sidewalkArray - const selectedSidewalks = Object.keys(sidewalkParams).filter( - (el, ind) => sidewalkArray[ind] - ); - - selectedSidewalks.forEach((sidewalkName, ind) => { - const params = sidewalkParams[sidewalkName]; - createSidewalkElem(params); - }); - - // describe curb parameters - const curbParams = { - northeast: { - positionVec: { - x: intersectWidth / 2 - northeastcurbArray[0] / 2, - y: intersectDepth / 2 - northeastcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: northeastcurbArray[0], - width: northeastcurbArray[1] - }, - southwest: { - positionVec: { - x: -intersectWidth / 2 + southwestcurbArray[0] / 2, - y: -intersectDepth / 2 + southwestcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: southwestcurbArray[0], - width: southwestcurbArray[1] - }, - southeast: { - positionVec: { - x: intersectWidth / 2 - southeastcurbArray[0] / 2, - y: -intersectDepth / 2 + southeastcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: southeastcurbArray[0], - width: southeastcurbArray[1] - }, - northwest: { - positionVec: { - x: -intersectWidth / 2 + northwestcurbArray[0] / 2, - y: intersectDepth / 2 - northwestcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: northwestcurbArray[0], - width: northwestcurbArray[1] - } - }; - - // create curbs if they are given - for (const [curbName, params] of Object.entries(curbParams)) { - if (data[`${curbName}curb`] !== '0 0') { - createSidewalkElem(params); - } - } - - if (stopsignArray[0]) { - const ss1 = document.createElement('a-entity'); - ss1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.1 - }); - ss1.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ss1.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss1); - } - if (stopsignArray[1]) { - const ss2 = document.createElement('a-entity'); - ss2.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.1 - }); - ss2.setAttribute('rotation', { x: 0, y: -90, z: -90 }); - ss2.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss2); - } - if (stopsignArray[2]) { - const ss3 = document.createElement('a-entity'); - ss3.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ss3.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ss3.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss3); - } - if (stopsignArray[3]) { - const ss4 = document.createElement('a-entity'); - ss4.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ss4.setAttribute('rotation', { x: 90, y: -90, z: -90 }); - ss4.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss4); - } - - if (trafficsignalArray[0]) { - const ts1 = document.createElement('a-entity'); - ts1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts1.setAttribute('rotation', { x: 210, y: 90, z: 90 }); - ts1.setAttribute('mixin', 'signal_left'); - el.appendChild(ts1); - const ts2 = document.createElement('a-entity'); - ts2.setAttribute('position', { - x: intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts2.setAttribute('rotation', { x: 180, y: 90, z: 90 }); - ts2.setAttribute('mixin', 'signal_right'); - el.appendChild(ts2); - } - if (trafficsignalArray[1]) { - const ts3 = document.createElement('a-entity'); - ts3.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts3.setAttribute('rotation', { x: 30, y: 90, z: 90 }); - ts3.setAttribute('mixin', 'signal_left'); - el.appendChild(ts3); - const ts4 = document.createElement('a-entity'); - ts4.setAttribute('position', { - x: -intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts4.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ts4.setAttribute('mixin', 'signal_right'); - el.appendChild(ts4); - } - if (trafficsignalArray[2]) { - const ts5 = document.createElement('a-entity'); - ts5.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts5.setAttribute('rotation', { x: 120, y: 90, z: 90 }); - ts5.setAttribute('mixin', 'signal_left'); - el.appendChild(ts5); - const ts6 = document.createElement('a-entity'); - ts6.setAttribute('position', { - x: intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts6.setAttribute('rotation', { x: 90, y: 90, z: 90 }); - ts6.setAttribute('mixin', 'signal_right'); - el.appendChild(ts6); - } - if (trafficsignalArray[3]) { - const ts7 = document.createElement('a-entity'); - ts7.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ts7.setAttribute('rotation', { x: -60, y: 90, z: 90 }); - ts7.setAttribute('mixin', 'signal_left'); - el.appendChild(ts7); - const ts8 = document.createElement('a-entity'); - ts8.setAttribute('position', { - x: -intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ts8.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ts8.setAttribute('mixin', 'signal_right'); - el.appendChild(ts8); - } - - if (crosswalklArray[0]) { - const cw1 = document.createElement('a-entity'); - cw1.setAttribute('position', { x: intersectWidth / 2 - 2, z: 0.11 }); - cw1.setAttribute('rotation', { x: 0, y: 0, z: 180 }); - cw1.setAttribute('scale', { y: intersectDepth / 12 }); - cw1.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw1); - } - if (crosswalklArray[1]) { - const cw2 = document.createElement('a-entity'); - cw2.setAttribute('position', { x: -intersectWidth / 2 + 2, z: 0.11 }); - cw2.setAttribute('rotation', { x: 0, y: 0, z: 180 }); - cw2.setAttribute('scale', { y: intersectDepth / 12 }); - cw2.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw2); - } - if (crosswalklArray[2]) { - const cw3 = document.createElement('a-entity'); - cw3.setAttribute('position', { y: -intersectDepth / 2 + 2, z: 0.11 }); - cw3.setAttribute('rotation', { x: 0, y: 0, z: 90 }); - cw3.setAttribute('scale', { y: intersectWidth / 12 }); - cw3.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw3); - } - if (crosswalklArray[3]) { - const cw4 = document.createElement('a-entity'); - cw4.setAttribute('position', { y: intersectDepth / 2 - 2, z: 0.11 }); - cw4.setAttribute('rotation', { x: 0, y: 0, z: 90 }); - cw4.setAttribute('scale', { y: intersectWidth / 12 }); - cw4.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw4); - } - } -}); - // Vehicle wheel Animation AFRAME.registerComponent('wheel', { schema: { From 332a0e3806d69db95183d8ec6ca1254a13f764a7 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Mon, 24 Jun 2024 21:25:43 -0400 Subject: [PATCH 02/13] move layersData in separate file --- .../AddLayerPanel/AddLayerPanel.component.jsx | 74 +------------------ .../components/AddLayerPanel/layersData.js | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+), 73 deletions(-) create mode 100644 src/editor/components/components/AddLayerPanel/layersData.js diff --git a/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx b/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx index dc734b4b9..0ad0e48a9 100644 --- a/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx +++ b/src/editor/components/components/AddLayerPanel/AddLayerPanel.component.jsx @@ -9,17 +9,9 @@ import { Dropdown } from '../Dropdown'; import CardPlaceholder from '../../../../../ui_assets/card-placeholder.svg'; import LockedCard from '../../../../../ui_assets/locked-card.svg'; +import { layersData } from './layersData.js'; import { LayersOptions } from './LayersOptions.js'; import posthog from 'posthog-js'; - -import { - createSvgExtrudedEntity, - createMapbox, - createStreetmixStreet, - create3DTiles, - createCustomModel, - createPrimitiveGeometry -} from './createLayerFunctions'; import Events from '../../../lib/Events'; const AddLayerPanel = ({ onClose, isAddLayerPanelOpen }) => { @@ -70,70 +62,6 @@ const AddLayerPanel = ({ onClose, isAddLayerPanelOpen }) => { return groupedArray; }; - // data for layers cards - const layersData = [ - { - name: 'Mapbox 2D Aerial', - img: 'ui_assets/cards/mapbox2d.jpg', - icon: 'ui_assets/cards/icons/mapbox24.png', - requiresPro: true, - description: - 'Create entity with mapbox component, that accepts a long / lat and renders a plane with dimensions that (should be) at a correct scale.', - id: 1, - handlerFunction: createMapbox - }, - { - name: 'Street from Streetmix URL', - img: 'ui_assets/cards/streetmix.jpg', - icon: 'ui_assets/cards/icons/streetmix24.png', - requiresPro: true, - description: - 'Create an additional Streetmix street in your 3DStreet scene without replacing any existing streets.', - id: 2, - handlerFunction: createStreetmixStreet - }, - { - name: 'Entity from extruded SVG', - img: '', - icon: '', - requiresPro: true, - description: - 'Create entity with svg-extruder component, that accepts a svgString and creates a new entity with geometry extruded from the svg and applies the default mixin material grass.', - id: 3, - handlerFunction: createSvgExtrudedEntity - }, - { - name: 'Google Maps 3D Tiles', - img: 'ui_assets/cards/google3d.jpg', - icon: 'ui_assets/cards/icons/google24.png', - requiresPro: true, - description: - 'Adds an entity to load and display 3d tiles from Google Maps Tiles API 3D Tiles endpoint. This will break your scene and you cannot save it yet, so beware before testing.', - id: 4, - handlerFunction: create3DTiles - }, - { - name: 'glTF model from URL', - img: '', - requiresPro: true, - icon: '', - description: - 'Create entity with model from path for a glTF (or Glb) file hosted on any publicly accessible HTTP server.', - id: 5, - handlerFunction: createCustomModel - }, - { - name: 'Create primitive geometry', - img: '', - requiresPro: true, - icon: '', - description: - 'Create entity with A-Frame primitive geometry. Geometry type could be changed in properties panel.', - id: 6, - handlerFunction: createPrimitiveGeometry - } - ]; - // get array with objects data (cardsData) from mixinGroups of selectedOption const getSelectedMixinCards = (selectedOption) => { if (!selectedOption) return []; diff --git a/src/editor/components/components/AddLayerPanel/layersData.js b/src/editor/components/components/AddLayerPanel/layersData.js new file mode 100644 index 000000000..790fbaacd --- /dev/null +++ b/src/editor/components/components/AddLayerPanel/layersData.js @@ -0,0 +1,74 @@ +import { + createSvgExtrudedEntity, + createMapbox, + createStreetmixStreet, + create3DTiles, + createCustomModel, + createPrimitiveGeometry +} from './createLayerFunctions'; + +// data for PRO layers cards +const layersData = [ + { + name: 'Mapbox 2D Aerial', + img: 'ui_assets/cards/mapbox2d.jpg', + icon: 'ui_assets/cards/icons/mapbox24.png', + requiresPro: true, + description: + 'Create entity with mapbox component, that accepts a long / lat and renders a plane with dimensions that (should be) at a correct scale.', + id: 1, + handlerFunction: createMapbox + }, + { + name: 'Street from Streetmix URL', + img: 'ui_assets/cards/streetmix.jpg', + icon: 'ui_assets/cards/icons/streetmix24.png', + requiresPro: true, + description: + 'Create an additional Streetmix street in your 3DStreet scene without replacing any existing streets.', + id: 2, + handlerFunction: createStreetmixStreet + }, + { + name: 'Entity from extruded SVG', + img: '', + icon: '', + requiresPro: true, + description: + 'Create entity with svg-extruder component, that accepts a svgString and creates a new entity with geometry extruded from the svg and applies the default mixin material grass.', + id: 3, + handlerFunction: createSvgExtrudedEntity + }, + { + name: 'Google Maps 3D Tiles', + img: 'ui_assets/cards/google3d.jpg', + icon: 'ui_assets/cards/icons/google24.png', + requiresPro: true, + description: + 'Adds an entity to load and display 3d tiles from Google Maps Tiles API 3D Tiles endpoint. This will break your scene and you cannot save it yet, so beware before testing.', + id: 4, + handlerFunction: create3DTiles + }, + { + name: 'glTF model from URL', + img: '', + requiresPro: true, + icon: '', + description: + 'Create entity with model from path for a glTF (or Glb) file hosted on any publicly accessible HTTP server.', + id: 5, + handlerFunction: createCustomModel + }, + { + name: 'Create primitive geometry', + img: '', + requiresPro: true, + icon: '', + description: + 'Create entity with A-Frame primitive geometry. Geometry type could be changed in properties panel.', + id: 6, + handlerFunction: createPrimitiveGeometry + } +]; + +export { layersData }; From a3f9dd04ecd3b28fe85397d98637ea0ea3362b37 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Mon, 24 Jun 2024 22:06:59 -0400 Subject: [PATCH 03/13] add intersection layer, first version --- .../AddLayerPanel/createLayerFunctions.js | 13 ++++++++++++- .../components/AddLayerPanel/layersData.js | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js index 56884464a..fbb25a669 100644 --- a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js +++ b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js @@ -149,11 +149,22 @@ function createPrimitiveGeometry() { Events.emit('entitycreated', newEl); } +function createIntersection() { + const newEl = document.createElement('a-entity'); + newEl.setAttribute('intersection', ''); + newEl.setAttribute('data-layer-name', 'Street intersection'); + const parentEl = document.querySelector('#street-container'); + parentEl.appendChild(newEl); + // update sceneGraph + Events.emit('entitycreated', newEl); +} + export { createSvgExtrudedEntity, createMapbox, createStreetmixStreet, create3DTiles, createCustomModel, - createPrimitiveGeometry + createPrimitiveGeometry, + createIntersection }; diff --git a/src/editor/components/components/AddLayerPanel/layersData.js b/src/editor/components/components/AddLayerPanel/layersData.js index 790fbaacd..6605c8953 100644 --- a/src/editor/components/components/AddLayerPanel/layersData.js +++ b/src/editor/components/components/AddLayerPanel/layersData.js @@ -4,7 +4,8 @@ import { createStreetmixStreet, create3DTiles, createCustomModel, - createPrimitiveGeometry + createPrimitiveGeometry, + createIntersection } from './createLayerFunctions'; // data for PRO layers cards @@ -68,6 +69,16 @@ const layersData = [ 'Create entity with A-Frame primitive geometry. Geometry type could be changed in properties panel.', id: 6, handlerFunction: createPrimitiveGeometry + }, + { + name: 'Create intersection', + img: '', + requiresPro: true, + icon: '', + description: + 'Create intersection entity. Parameters of intersection component could be changed in properties panel.', + id: 7, + handlerFunction: createIntersection } ]; From 1c728a5aac7b11869f75596774a4e3d47e82b4f4 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Mon, 24 Jun 2024 22:29:47 -0400 Subject: [PATCH 04/13] made live update for intersection component --- src/components/intersection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/intersection.js b/src/components/intersection.js index 93cf057fe..dabae80a9 100644 --- a/src/components/intersection.js +++ b/src/components/intersection.js @@ -11,7 +11,7 @@ AFRAME.registerComponent('intersection', { trafficsignal: { type: 'string', default: '0 0 0 0' }, crosswalk: { type: 'string', default: '0 0 0 0' } }, - init: function () { + update: function () { var data = this.data; var el = this.el; From fd09d2feda6ebdb62dbc41bb8845c746f9197de0 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Tue, 25 Jun 2024 21:28:41 -0400 Subject: [PATCH 05/13] refactor some code --- src/components/intersection.js | 292 +++++++++++++++++---------------- 1 file changed, 152 insertions(+), 140 deletions(-) diff --git a/src/components/intersection.js b/src/components/intersection.js index dabae80a9..442228de6 100644 --- a/src/components/intersection.js +++ b/src/components/intersection.js @@ -2,6 +2,7 @@ AFRAME.registerComponent('intersection', { schema: { dimensions: { type: 'string', default: '20 20' }, + // cardinal direction order for sidewalk, stopsign, crosswalk: west, east, north, south sidewalk: { type: 'string', default: '0 0 0 0' }, northeastcurb: { type: 'string', default: '0 0' }, southwestcurb: { type: 'string', default: '0 0' }, @@ -14,17 +15,13 @@ AFRAME.registerComponent('intersection', { update: function () { var data = this.data; var el = this.el; + const directionOrder = ['west', 'east', 'north', 'south']; // remove all child nodes if exists while (el.firstChild) { el.removeChild(el.lastChild); } const dimensionsArray = data.dimensions.split(' ').map((i) => Number(i)); - const positionArray = [ - this.el.getAttribute('position').x, - this.el.getAttribute('position').y, - this.el.getAttribute('position').z - ]; const sidewalkArray = data.sidewalk.split(' ').map((i) => Number(i)); const northeastcurbArray = data.northeastcurb .split(' ') @@ -51,11 +48,7 @@ AFRAME.registerComponent('intersection', { 'geometry', `primitive:box; width: ${intersectWidth}; height: ${intersectDepth}; depth:0.2` ); - this.el.setAttribute('position', { - x: positionArray[0], - y: -0.1, - z: positionArray[2] - }); + this.el.object3D.position.setY(-0.1); this.el.setAttribute('rotation', '-90 0 0'); this.el.setAttribute( 'material', @@ -70,17 +63,15 @@ AFRAME.registerComponent('intersection', { rotationVec }) { const sd = document.createElement('a-entity'); - const repeatCountInter = []; - repeatCountInter[0] = width / 2; // every 2 meters repeat sidewalk texture - repeatCountInter[1] = parseInt(length / 2); + const repeatCountInter = [width / 2, parseInt(length / 2)]; - sd.setAttribute('geometry', 'primitive', 'box'); - sd.setAttribute('geometry', 'height: 0.4'); + sd.setAttribute( + 'geometry', + `primitive:box; depth: ${length}; width: ${width}; height: 0.4` + ); sd.setAttribute('position', positionVec); sd.setAttribute('scale', scaleVec); - sd.setAttribute('geometry', 'depth', length); - sd.setAttribute('geometry', 'width', width); sd.setAttribute('rotation', rotationVec); sd.setAttribute('mixin', 'sidewalk'); sd.setAttribute( @@ -106,9 +97,9 @@ AFRAME.registerComponent('intersection', { }, north: { positionVec: { - y: -intersectDepth / 2 + sidewalkArray[2] / 2, // add x offset to avoid sidewalk's element overlap x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, + y: -intersectDepth / 2 + sidewalkArray[2] / 2, z: 0.1 }, rotationVec: { x: 0, y: 90, z: -90 }, @@ -118,9 +109,9 @@ AFRAME.registerComponent('intersection', { }, south: { positionVec: { - y: intersectDepth / 2 - sidewalkArray[3] / 2, // add x offset to avoid sidewalk's element overlap x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, + y: intersectDepth / 2 - sidewalkArray[3] / 2, z: 0.1 }, rotationVec: { x: 0, y: 90, z: -90 }, @@ -191,132 +182,153 @@ AFRAME.registerComponent('intersection', { } } - if (stopsignArray[0]) { - const ss1 = document.createElement('a-entity'); - ss1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.1 - }); - ss1.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ss1.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss1); - } - if (stopsignArray[1]) { - const ss2 = document.createElement('a-entity'); - ss2.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.1 - }); - ss2.setAttribute('rotation', { x: 0, y: -90, z: -90 }); - ss2.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss2); - } - if (stopsignArray[2]) { - const ss3 = document.createElement('a-entity'); - ss3.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ss3.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ss3.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss3); - } - if (stopsignArray[3]) { - const ss4 = document.createElement('a-entity'); - ss4.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ss4.setAttribute('rotation', { x: 90, y: -90, z: -90 }); - ss4.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss4); - } + // describe stop signals parameters + const stopsignals = { + west: { + position: { + x: intersectWidth / 2, + y: intersectDepth / 3, + z: 0.1 + }, + rotation: { x: 0, y: 90, z: 90 } + }, + east: { + position: { + x: -intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.1 + }, + rotation: { x: 0, y: -90, z: -90 } + }, + north: { + position: { + x: -intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }, + rotation: { x: -90, y: 90, z: 90 } + }, + south: { + position: { + x: intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }, + rotation: { x: 90, y: -90, z: -90 } + } + }; - if (trafficsignalArray[0]) { - const ts1 = document.createElement('a-entity'); - ts1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts1.setAttribute('rotation', { x: 210, y: 90, z: 90 }); - ts1.setAttribute('mixin', 'signal_left'); - el.appendChild(ts1); - const ts2 = document.createElement('a-entity'); - ts2.setAttribute('position', { - x: intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts2.setAttribute('rotation', { x: 180, y: 90, z: 90 }); - ts2.setAttribute('mixin', 'signal_right'); - el.appendChild(ts2); - } - if (trafficsignalArray[1]) { - const ts3 = document.createElement('a-entity'); - ts3.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts3.setAttribute('rotation', { x: 30, y: 90, z: 90 }); - ts3.setAttribute('mixin', 'signal_left'); - el.appendChild(ts3); - const ts4 = document.createElement('a-entity'); - ts4.setAttribute('position', { - x: -intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts4.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ts4.setAttribute('mixin', 'signal_right'); - el.appendChild(ts4); - } - if (trafficsignalArray[2]) { - const ts5 = document.createElement('a-entity'); - ts5.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts5.setAttribute('rotation', { x: 120, y: 90, z: 90 }); - ts5.setAttribute('mixin', 'signal_left'); - el.appendChild(ts5); - const ts6 = document.createElement('a-entity'); - ts6.setAttribute('position', { - x: intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts6.setAttribute('rotation', { x: 90, y: 90, z: 90 }); - ts6.setAttribute('mixin', 'signal_right'); - el.appendChild(ts6); + function createStopSignal(direction) { + const stopSignEl = document.createElement('a-entity'); + const params = stopsignals[direction]; + stopSignEl.setAttribute('position', params['position']); + stopSignEl.setAttribute('rotation', params['rotation']); + stopSignEl.setAttribute('mixin', 'stop_sign'); + return stopSignEl; } - if (trafficsignalArray[3]) { - const ts7 = document.createElement('a-entity'); - ts7.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ts7.setAttribute('rotation', { x: -60, y: 90, z: 90 }); - ts7.setAttribute('mixin', 'signal_left'); - el.appendChild(ts7); - const ts8 = document.createElement('a-entity'); - ts8.setAttribute('position', { - x: -intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 + + // create stop signals + directionOrder.forEach((direction, index) => { + if (stopsignArray[index]) { + const stopSignEl = createStopSignal(direction); + el.appendChild(stopSignEl); + } + }); + + // describe traffic signals parameters + const trafficSignals = { + west: { + left: { + position: { + x: intersectWidth / 2, + y: intersectDepth / 3, + z: 0.3 + }, + rotation: { x: 210, y: 90, z: 90 } + }, + right: { + position: { + x: intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.3 + }, + rotation: { x: 180, y: 90, z: 90 } + } + }, + east: { + left: { + position: { + x: -intersectWidth / 2, + y: -intersectDepth / 3, + z: 0.3 + }, + rotation: { x: 210, y: 90, z: 90 } + }, + right: { + position: { + x: -intersectWidth / 2, + y: intersectDepth / 3, + z: 0.3 + }, + rotation: { x: 0, y: 90, z: 90 } + } + }, + north: { + left: { + position: { + x: -intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }, + rotation: { x: 120, y: 90, z: 90 } + }, + right: { + position: { + x: intersectWidth / 3, + y: intersectDepth / 2, + z: 0.1 + }, + rotation: { x: 90, y: 90, z: 90 } + } + }, + south: { + left: { + position: { + x: intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }, + rotation: { x: -60, y: 90, z: 90 } + }, + right: { + position: { + x: -intersectWidth / 3, + y: -intersectDepth / 2, + z: 0.1 + }, + rotation: { x: -90, y: 90, z: 90 } + } + } + }; + + function createTrafficSignals(direction) { + const params = trafficSignals[direction]; + ['left', 'right'].forEach((side) => { + const trafficSignalEl = document.createElement('a-entity'); + trafficSignalEl.setAttribute('position', params[side].position); + trafficSignalEl.setAttribute('rotation', params[side].rotation); + trafficSignalEl.setAttribute('mixin', `signal_${side}`); + el.appendChild(trafficSignalEl); }); - ts8.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ts8.setAttribute('mixin', 'signal_right'); - el.appendChild(ts8); } + // create traffic signals + directionOrder.forEach((direction, index) => { + if (trafficsignalArray[index]) { + createTrafficSignals(direction); + } + }); + if (crosswalklArray[0]) { const cw1 = document.createElement('a-entity'); cw1.setAttribute('position', { x: intersectWidth / 2 - 2, z: 0.11 }); From bafced93555ae64c8585c602d909b5997e931bd5 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Fri, 28 Jun 2024 21:29:40 -0400 Subject: [PATCH 06/13] add splat layer and updated version of aframe-gaussian-splatting-component lib --- .../AddLayerPanel/createLayerFunctions.js | 38 ++++++- .../components/AddLayerPanel/layersData.js | 13 ++- ...aframe-gaussian-splatting-component.min.js | 104 ++++++++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/lib/aframe-gaussian-splatting-component.min.js diff --git a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js index fbb25a669..99a1bfbc2 100644 --- a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js +++ b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js @@ -159,6 +159,41 @@ function createIntersection() { Events.emit('entitycreated', newEl); } +function createSplatObject() { + // accepts a path for a .splat file hosted on any publicly accessible HTTP server. + // Then create entity with model from that path by using gaussian_splatting component + const modelUrl = prompt( + 'Please enter a URL to custom Splat model', + 'https://cdn.glitch.me/f80a77a3-62a6-4024-9bef-a6b523d1abc0/gs_Bioswale3_treat.splat' + ); + const createSplatElement = () => { + if (modelUrl && modelUrl !== '') { + const newEl = document.createElement('a-entity'); + newEl.classList.add('splat-model'); + newEl.setAttribute('data-no-pause', ''); + newEl.setAttribute('gaussian_splatting', `src: ${modelUrl}`); + newEl.setAttribute('data-layer-name', 'Splat Model • My Custom Object'); + newEl.play(); + const parentEl = document.querySelector('#street-container'); + parentEl.appendChild(newEl); + // update sceneGraph + Events.emit('entitycreated', newEl); + } + }; + + if (AFRAME.components['gaussian_splatting']) { + createSplatElement(); + } else { + loadScript( + new URL( + '/src/lib/aframe-gaussian-splatting-component.min.js', + import.meta.url + ), + createSplatElement + ); + } +} + export { createSvgExtrudedEntity, createMapbox, @@ -166,5 +201,6 @@ export { create3DTiles, createCustomModel, createPrimitiveGeometry, - createIntersection + createIntersection, + createSplatObject }; diff --git a/src/editor/components/components/AddLayerPanel/layersData.js b/src/editor/components/components/AddLayerPanel/layersData.js index 6605c8953..8755b3945 100644 --- a/src/editor/components/components/AddLayerPanel/layersData.js +++ b/src/editor/components/components/AddLayerPanel/layersData.js @@ -5,7 +5,8 @@ import { create3DTiles, createCustomModel, createPrimitiveGeometry, - createIntersection + createIntersection, + createSplatObject } from './createLayerFunctions'; // data for PRO layers cards @@ -79,6 +80,16 @@ const layersData = [ 'Create intersection entity. Parameters of intersection component could be changed in properties panel.', id: 7, handlerFunction: createIntersection + }, + { + name: 'Splat model from URL', + img: '', + requiresPro: true, + icon: '', + description: + 'Create entity with model from path for a Splat (.splat) file hosted on any publicly accessible HTTP server.', + id: 8, + handlerFunction: createSplatObject } ]; diff --git a/src/lib/aframe-gaussian-splatting-component.min.js b/src/lib/aframe-gaussian-splatting-component.min.js new file mode 100644 index 000000000..2cb3a16b9 --- /dev/null +++ b/src/lib/aframe-gaussian-splatting-component.min.js @@ -0,0 +1,104 @@ +AFRAME.registerComponent("gaussian_splatting",{schema:{src:{type:"string",default:"train.splat"},cutoutEntity:{type:"selector"},pixelRatio:{type:"number",default:1},xrPixelRatio:{type:"number",default:.5},depthWrite:{type:"boolean",default:!1},discardFilter:{type:"number",default:0}},init:function(){0{this.initLoadProcess()})},initLoadProcess(){this.loadData(this.el.sceneEl.camera,this.el.object3D,this.el.sceneEl.renderer,this.data.src),this.data.cutoutEntity&&(this.cutout=this.data.cutoutEntity.object3D),this.el.isPlaying||this.el.play()},initGL:async function(numVertexes){console.log("initGL",numVertexes),this.object.frustumCulled=!1;var gl=this.renderer.getContext(),gl=gl.getParameter(gl.MAX_TEXTURE_SIZE),gl=(this.maxVertexes=gl*gl,numVertexes>this.maxVertexes&&(console.log("numVertexes limited to ",this.maxVertexes,numVertexes),numVertexes=this.maxVertexes),this.bufferTextureWidth=gl,this.bufferTextureHeight=Math.floor((numVertexes-1)/gl)+1,this.centerAndScaleData=new Float32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.covAndColorData=new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight*4),this.centerAndScaleTexture=new THREE.DataTexture(this.centerAndScaleData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBA,THREE.FloatType),this.centerAndScaleTexture.needsUpdate=!0,this.covAndColorTexture=new THREE.DataTexture(this.covAndColorData,this.bufferTextureWidth,this.bufferTextureHeight,THREE.RGBAIntegerFormat,THREE.UnsignedIntType),this.covAndColorTexture.internalFormat="RGBA32UI",this.covAndColorTexture.needsUpdate=!0,new Uint32Array(this.bufferTextureWidth*this.bufferTextureHeight)),gl=new THREE.InstancedBufferAttribute(gl,1,!1),baseGeometry=(gl.setUsage(THREE.DynamicDrawUsage),new THREE.BufferGeometry),positionsArray=new Float32Array(18),positionsArray=new THREE.BufferAttribute(positionsArray,3),positionsArray=(baseGeometry.setAttribute("position",positionsArray),positionsArray.setXYZ(2,-2,2,0),positionsArray.setXYZ(1,2,2,0),positionsArray.setXYZ(0,-2,-2,0),positionsArray.setXYZ(5,-2,-2,0),positionsArray.setXYZ(4,2,2,0),positionsArray.setXYZ(3,2,-2,0),positionsArray.needsUpdate=!0,(new THREE.InstancedBufferGeometry).copy(baseGeometry));positionsArray.setAttribute("splatIndex",gl),positionsArray.instanceCount=1;let material=new THREE.ShaderMaterial({uniforms:{viewport:{value:new Float32Array([1980,1080])},focal:{value:1e3},centerAndScaleTexture:{value:this.centerAndScaleTexture},covAndColorTexture:{value:this.covAndColorTexture},gsProjectionMatrix:{value:this.getProjectionMatrix()},gsModelViewMatrix:{value:this.getModelViewMatrix()},discardFilter:{value:this.data.discardFilter}},vertexShader:` + precision highp sampler2D; + precision highp usampler2D; + + out vec4 vColor; + out vec2 vPosition; + out float fDF; + uniform vec2 viewport; + uniform float focal; + uniform mat4 gsProjectionMatrix; + uniform mat4 gsModelViewMatrix; + uniform float discardFilter; + + attribute uint splatIndex; + uniform sampler2D centerAndScaleTexture; + uniform usampler2D covAndColorTexture; + + vec2 unpackInt16(in uint value) { + int v = int(value); + int v0 = v >> 16; + int v1 = (v & 0xFFFF); + if((v & 0x8000) != 0) + v1 |= 0xFFFF0000; + return vec2(float(v1), float(v0)); + } + + void main () { + ivec2 texSize = textureSize(centerAndScaleTexture, 0); + ivec2 texPos = ivec2(splatIndex%uint(texSize.x), splatIndex/uint(texSize.x)); + vec4 centerAndScaleData = texelFetch(centerAndScaleTexture, texPos, 0); + + vec4 center = vec4(centerAndScaleData.xyz, 1); + vec4 camspace = gsModelViewMatrix * center; + vec4 pos2d = gsProjectionMatrix * camspace; + + float bounds = 1.2 * pos2d.w; + if (pos2d.z < -pos2d.w || pos2d.x < -bounds || pos2d.x > bounds + || pos2d.y < -bounds || pos2d.y > bounds) { + gl_Position = vec4(0.0, 0.0, 2.0, 1.0); + return; + } + + uvec4 covAndColorData = texelFetch(covAndColorTexture, texPos, 0); + vec2 cov3D_M11_M12 = unpackInt16(covAndColorData.x) * centerAndScaleData.w; + vec2 cov3D_M13_M22 = unpackInt16(covAndColorData.y) * centerAndScaleData.w; + vec2 cov3D_M23_M33 = unpackInt16(covAndColorData.z) * centerAndScaleData.w; + mat3 Vrk = mat3( + cov3D_M11_M12.x, cov3D_M11_M12.y, cov3D_M13_M22.x, + cov3D_M11_M12.y, cov3D_M13_M22.y, cov3D_M23_M33.x, + cov3D_M13_M22.x, cov3D_M23_M33.x, cov3D_M23_M33.y + ); + + mat3 J = mat3( + focal / camspace.z, 0., -(focal * camspace.x) / (camspace.z * camspace.z), + 0., -focal / camspace.z, (focal * camspace.y) / (camspace.z * camspace.z), + 0., 0., 0. + ); + + mat3 W = transpose(mat3(gsModelViewMatrix)); + mat3 T = W * J; + mat3 cov = transpose(T) * Vrk * T; + + vec2 vCenter = vec2(pos2d) / pos2d.w; + + float diagonal1 = cov[0][0] + 0.3; + float offDiagonal = cov[0][1]; + float diagonal2 = cov[1][1] + 0.3; + + float mid = 0.5 * (diagonal1 + diagonal2); + float radius = length(vec2((diagonal1 - diagonal2) / 2.0, offDiagonal)); + float lambda1 = mid + radius; + float lambda2 = max(mid - radius, 0.1); + vec2 diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1)); + vec2 v1 = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector; + vec2 v2 = min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x); + + uint colorUint = covAndColorData.w; + vColor = vec4( + float(colorUint & uint(0xFF)) / 255.0, + float((colorUint >> uint(8)) & uint(0xFF)) / 255.0, + float((colorUint >> uint(16)) & uint(0xFF)) / 255.0, + float(colorUint >> uint(24)) / 255.0 + ); + vPosition = position.xy; + fDF = discardFilter; + + gl_Position = vec4( + vCenter + + position.x * v2 / viewport * 2.0 + + position.y * v1 / viewport * 2.0, pos2d.z / pos2d.w, 1.0); + } + `,fragmentShader:` + in vec4 vColor; + in vec2 vPosition; + in float fDF; + + void main () { + float A = -dot(vPosition, vPosition); + if (A < -4.0) discard; + float B = exp(A) * vColor.a; + if(B < fDF) discard; + gl_FragColor = vec4(vColor.rgb, B); + } + `,blending:THREE.CustomBlending,blendSrcAlpha:THREE.OneFactor,depthTest:!0,depthWrite:this.data.depthWrite,transparent:!0}),mesh=(material.onBeforeRender=(renderer,scene,camera,geometry,object,group)=>{var projectionMatrix=this.getProjectionMatrix(camera),viewport=(mesh.material.uniforms.gsProjectionMatrix.value=projectionMatrix,mesh.material.uniforms.gsModelViewMatrix.value=this.getModelViewMatrix(camera),new THREE.Vector4),projectionMatrix=(renderer.getCurrentViewport(viewport),viewport.w/2*Math.abs(projectionMatrix.elements[5]));material.uniforms.viewport.value[0]=viewport.z,material.uniforms.viewport.value[1]=viewport.w,material.uniforms.focal.value=projectionMatrix},new THREE.Mesh(positionsArray,material));for(mesh.frustumCulled=!1,this.object.add(mesh),this.worker.onmessage=e=>{var indexes=new Uint32Array(e.data.sortedIndexes);mesh.geometry.attributes.splatIndex.set(indexes),mesh.geometry.attributes.splatIndex.needsUpdate=!0,mesh.geometry.instanceCount=indexes.length,this.sortReady=!0};;){var centerAndScaleTextureProperties=this.renderer.properties.get(this.centerAndScaleTexture),covAndColorTextureProperties=this.renderer.properties.get(this.covAndColorTexture);if(centerAndScaleTextureProperties&¢erAndScaleTextureProperties.__webglTexture&&covAndColorTextureProperties&¢erAndScaleTextureProperties.__webglTexture)break;await new Promise(resolve=>setTimeout(resolve,10))}this.sortReady=!0},loadData:async function(camera,object,renderer,src){this.camera=camera,this.object=object,this.renderer=renderer,this.loadedVertexCount=0,this.rowLength=32,this.worker=new Worker(URL.createObjectURL(new Blob(["(",this.createWorker.toString(),")(self)"],{type:"application/javascript"}))),this.worker.postMessage({method:"clear"});try{for(;;){if((data=await fetch(src)).ok)break;console.log("retry",src),await new Promise(resolve=>setTimeout(resolve,1e3))}this.parseData(data,src)}catch(error){console.error(error)}},parseData:async function(data,src){var reader=data.body.getReader();let glInitialized=!1,bytesDownloaded=0,bytesProcesses=0;var _totalDownloadBytes=data.headers.get("Content-Length"),totalDownloadBytes=_totalDownloadBytes?parseInt(_totalDownloadBytes):void 0,chunks=(null!=totalDownloadBytes&&(_totalDownloadBytes=Math.floor(totalDownloadBytes/this.rowLength),await this.initGL(_totalDownloadBytes),glInitialized=!0),[]),start=Date.now();let lastReportedProgress=0;for(var isPly=src.endsWith(".ply");;)try{var mbps,percent,{value,done}=await reader.read();if(done){console.log("Completed download.");break}bytesDownloaded+=value.length,null!=totalDownloadBytes?(mbps=bytesDownloaded/1024/1024/((Date.now()-start)/1e3),1<(percent=bytesDownloaded/totalDownloadBytes*100)-lastReportedProgress&&(console.log("download progress:",percent.toFixed(2)+"%",mbps.toFixed(2)+" Mbps"),lastReportedProgress=percent)):console.log("download progress:",bytesDownloaded,", unknown total"),chunks.push(value);var bytesRemains=bytesDownloaded-bytesProcesses;if(!isPly&&null!=totalDownloadBytes&&bytesRemains>this.rowLength){var chunk,extra_data,vertexCount=Math.floor(bytesRemains/this.rowLength),concatenatedChunksbuffer=new Uint8Array(bytesRemains);let offset=0;for(chunk of chunks)concatenatedChunksbuffer.set(chunk,offset),offset+=chunk.length;chunks.length=0,bytesRemains>vertexCount*this.rowLength&&((extra_data=new Uint8Array(bytesRemains-vertexCount*this.rowLength)).set(concatenatedChunksbuffer.subarray(bytesRemains-extra_data.length,bytesRemains),0),chunks.push(extra_data));var buffer=new Uint8Array(vertexCount*this.rowLength);buffer.set(concatenatedChunksbuffer.subarray(0,buffer.byteLength),0),this.pushDataBuffer(buffer.buffer,vertexCount),bytesProcesses+=vertexCount*this.rowLength}}catch(error){console.error(error);break}if(0acc+chunk.length,0)),offset=0;for(let chunk of chunks)concatenatedChunks.set(chunk,offset),offset+=chunk.length;isPly&&(concatenatedChunks=new Uint8Array(this.processPlyBuffer(concatenatedChunks.buffer)));let numVertexes=Math.floor(concatenatedChunks.byteLength/this.rowLength);glInitialized||(await this.initGL(numVertexes),glInitialized=!0),this.pushDataBuffer(concatenatedChunks.buffer,numVertexes)}},pushDataBuffer:function(buffer,vertexCount){if(this.loadedVertexCount+vertexCount>this.maxVertexes&&(console.log("vertexCount limited to ",this.maxVertexes,vertexCount),vertexCount=this.maxVertexes-this.loadedVertexCount),!(vertexCount<=0)){var u_buffer=new Uint8Array(buffer),f_buffer=new Float32Array(buffer),matrices=new Float32Array(16*vertexCount),covAndColorData_uint8=new Uint8Array(this.covAndColorData.buffer),covAndColorData_int16=new Int16Array(this.covAndColorData.buffer);for(let i=0;imax_value&&(max_value=Math.abs(mtx.elements[cov_indexes[j]]));let destOffset=4*this.loadedVertexCount+4*i;this.centerAndScaleData[destOffset+0]=center.x,this.centerAndScaleData[destOffset+1]=center.y,this.centerAndScaleData[destOffset+2]=center.z,this.centerAndScaleData[destOffset+3]=max_value/32767,destOffset=8*this.loadedVertexCount+4*i*2;for(let j=0;j-1e-4*depth&&cutoutArea&&(depthList[validCount]=depth,validIndexList[validCount]=i,validCount++,depth>maxDepth&&(maxDepth=depth),depth{if("clear"==e.data.method&&(matrices=void 0),"push"==e.data.method&&(new_matrices=new Float32Array(e.data.matrices),matrices=void 0===matrices?new_matrices:((resized=new Float32Array(matrices.length+new_matrices.length)).set(matrices),resized.set(new_matrices,matrices.length),resized)),"sort"==e.data.method)if(void 0===matrices){var new_matrices=new Uint32Array(1);self.postMessage({sortedIndexes:new_matrices},[new_matrices.buffer])}else{var new_matrices=new Float32Array(e.data.view),cutout=void 0!==e.data.cutout?new Float32Array(e.data.cutout):void 0;let sortedIndexes=sortSplats(matrices,new_matrices,cutout);self.postMessage({sortedIndexes:sortedIndexes},[sortedIndexes.buffer])}}},processPlyBuffer:function(inputBuffer){var ubuf=new Uint8Array(inputBuffer),ubuf=(new TextDecoder).decode(ubuf.slice(0,10240)),header_end_index=ubuf.indexOf("end_header\n");if(header_end_index<0)throw new Error("Unable to read .ply file header");var vertexCount=parseInt(/element vertex (\d+)\n/.exec(ubuf)[1]);console.log("Vertex Count",vertexCount);let row_offset=0,offsets={},types={};var prop,TYPE_MAP={double:"getFloat64",int:"getInt32",uint:"getUint32",float:"getFloat32",short:"getInt16",ushort:"getUint16",uchar:"getUint8"};for(prop of ubuf.slice(0,header_end_index).split("\n").filter(k=>k.startsWith("property "))){var[,type,name]=prop.split(" "),type=TYPE_MAP[type]||"getInt8";types[name]=type,offsets[name]=row_offset,row_offset+=parseInt(type.replace(/[^\d]/g,""))/8}console.log("Bytes per row",row_offset,types,offsets);let dataView=new DataView(inputBuffer,header_end_index+"end_header\n".length),row=0;var attrs=new Proxy({},{get(target,prop){if(types[prop])return dataView[types[prop]](row*row_offset+offsets[prop],!0);throw new Error(prop+" not found")}});console.time("calculate importance");let sizeList=new Float32Array(vertexCount);var size,opacity,sizeIndex=new Uint32Array(vertexCount);for(row=0;rowsizeList[a]-sizeList[b]),console.timeEnd("sort");var buffer=new ArrayBuffer(32*vertexCount);console.time("build buffer");for(let j=0;j Date: Wed, 3 Jul 2024 21:41:10 -0400 Subject: [PATCH 07/13] load aframe-gaussian-splatting-component in index.js instead of dynamic loading --- .../AddLayerPanel/createLayerFunctions.js | 35 ++++++------------- src/index.js | 1 + 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js index 99a1bfbc2..611f4df1b 100644 --- a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js +++ b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js @@ -166,31 +166,18 @@ function createSplatObject() { 'Please enter a URL to custom Splat model', 'https://cdn.glitch.me/f80a77a3-62a6-4024-9bef-a6b523d1abc0/gs_Bioswale3_treat.splat' ); - const createSplatElement = () => { - if (modelUrl && modelUrl !== '') { - const newEl = document.createElement('a-entity'); - newEl.classList.add('splat-model'); - newEl.setAttribute('data-no-pause', ''); - newEl.setAttribute('gaussian_splatting', `src: ${modelUrl}`); - newEl.setAttribute('data-layer-name', 'Splat Model • My Custom Object'); - newEl.play(); - const parentEl = document.querySelector('#street-container'); - parentEl.appendChild(newEl); - // update sceneGraph - Events.emit('entitycreated', newEl); - } - }; - if (AFRAME.components['gaussian_splatting']) { - createSplatElement(); - } else { - loadScript( - new URL( - '/src/lib/aframe-gaussian-splatting-component.min.js', - import.meta.url - ), - createSplatElement - ); + if (modelUrl && modelUrl !== '') { + const newEl = document.createElement('a-entity'); + newEl.classList.add('splat-model'); + newEl.setAttribute('data-no-pause', ''); + newEl.setAttribute('gaussian_splatting', `src: ${modelUrl}`); + newEl.setAttribute('data-layer-name', 'Splat Model • My Custom Object'); + newEl.play(); + const parentEl = document.querySelector('#street-container'); + parentEl.appendChild(newEl); + // update sceneGraph + Events.emit('entitycreated', newEl); } } diff --git a/src/index.js b/src/index.js index c3078128c..1396c9683 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,7 @@ require('./components/ocean'); require('./components/svg-extruder.js'); require('./lib/aframe-cursor-teleport-component.min.js'); require('./lib/animation-mixer.js'); +require('./lib/aframe-gaussian-splatting-component.min.js'); require('./assets.js'); require('./components/notify.js'); require('./components/create-from-json'); From a1f2fa321cf01b8c86dd615d16b53a97a4ab8a06 Mon Sep 17 00:00:00 2001 From: Alexander Goryushkin Date: Wed, 3 Jul 2024 22:09:34 -0400 Subject: [PATCH 08/13] add autocreated class to all child elements in intersection --- src/components/intersection.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/intersection.js b/src/components/intersection.js index 442228de6..3264c0d68 100644 --- a/src/components/intersection.js +++ b/src/components/intersection.js @@ -74,6 +74,7 @@ AFRAME.registerComponent('intersection', { sd.setAttribute('scale', scaleVec); sd.setAttribute('rotation', rotationVec); sd.setAttribute('mixin', 'sidewalk'); + sd.classList.add('autocreated'); sd.setAttribute( 'material', `repeat: ${repeatCountInter[0]} ${repeatCountInter[1]}` @@ -224,6 +225,7 @@ AFRAME.registerComponent('intersection', { stopSignEl.setAttribute('position', params['position']); stopSignEl.setAttribute('rotation', params['rotation']); stopSignEl.setAttribute('mixin', 'stop_sign'); + stopSignEl.classList.add('autocreated'); return stopSignEl; } @@ -318,6 +320,7 @@ AFRAME.registerComponent('intersection', { trafficSignalEl.setAttribute('position', params[side].position); trafficSignalEl.setAttribute('rotation', params[side].rotation); trafficSignalEl.setAttribute('mixin', `signal_${side}`); + trafficSignalEl.classList.add('autocreated'); el.appendChild(trafficSignalEl); }); } @@ -335,6 +338,7 @@ AFRAME.registerComponent('intersection', { cw1.setAttribute('rotation', { x: 0, y: 0, z: 180 }); cw1.setAttribute('scale', { y: intersectDepth / 12 }); cw1.setAttribute('mixin', 'markings crosswalk-zebra'); + cw1.classList.add('autocreated'); el.appendChild(cw1); } if (crosswalklArray[1]) { @@ -343,6 +347,7 @@ AFRAME.registerComponent('intersection', { cw2.setAttribute('rotation', { x: 0, y: 0, z: 180 }); cw2.setAttribute('scale', { y: intersectDepth / 12 }); cw2.setAttribute('mixin', 'markings crosswalk-zebra'); + cw2.classList.add('autocreated'); el.appendChild(cw2); } if (crosswalklArray[2]) { @@ -351,6 +356,7 @@ AFRAME.registerComponent('intersection', { cw3.setAttribute('rotation', { x: 0, y: 0, z: 90 }); cw3.setAttribute('scale', { y: intersectWidth / 12 }); cw3.setAttribute('mixin', 'markings crosswalk-zebra'); + cw3.classList.add('autocreated'); el.appendChild(cw3); } if (crosswalklArray[3]) { @@ -359,6 +365,7 @@ AFRAME.registerComponent('intersection', { cw4.setAttribute('rotation', { x: 0, y: 0, z: 90 }); cw4.setAttribute('scale', { y: intersectWidth / 12 }); cw4.setAttribute('mixin', 'markings crosswalk-zebra'); + cw4.classList.add('autocreated'); el.appendChild(cw4); } } From fbce62f772a1756766fdd62a1215784a6ecac975 Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Tue, 9 Jul 2024 20:19:22 -0700 Subject: [PATCH 09/13] remove old intersection component --- src/index.js | 353 --------------------------------------------------- 1 file changed, 353 deletions(-) diff --git a/src/index.js b/src/index.js index b903c86a4..097870577 100644 --- a/src/index.js +++ b/src/index.js @@ -248,359 +248,6 @@ AFRAME.registerComponent('streetmix-loader', { } }); -AFRAME.registerComponent('intersection', { - schema: { - dimensions: { type: 'string', default: '20 20' }, - sidewalk: { type: 'string', default: '0 0 0 0' }, - northeastcurb: { type: 'string', default: '0 0' }, - southwestcurb: { type: 'string', default: '0 0' }, - southeastcurb: { type: 'string', default: '0 0' }, - northwestcurb: { type: 'string', default: '0 0' }, - stopsign: { type: 'string', default: '0 0 0 0' }, - trafficsignal: { type: 'string', default: '0 0 0 0' }, - crosswalk: { type: 'string', default: '0 0 0 0' } - }, - init: function () { - var data = this.data; - var el = this.el; - - // remove all child nodes if exists - while (el.firstChild) { - el.removeChild(el.lastChild); - } - const dimensionsArray = data.dimensions.split(' ').map((i) => Number(i)); - const positionArray = [ - this.el.getAttribute('position').x, - this.el.getAttribute('position').y, - this.el.getAttribute('position').z - ]; - const sidewalkArray = data.sidewalk.split(' ').map((i) => Number(i)); - const northeastcurbArray = data.northeastcurb - .split(' ') - .map((i) => Number(i)); - const southwestcurbArray = data.southwestcurb - .split(' ') - .map((i) => Number(i)); - const southeastcurbArray = data.southeastcurb - .split(' ') - .map((i) => Number(i)); - const northwestcurbArray = data.northwestcurb - .split(' ') - .map((i) => Number(i)); - const stopsignArray = data.stopsign.split(' ').map((i) => Number(i)); - const trafficsignalArray = data.trafficsignal - .split(' ') - .map((i) => Number(i)); - const crosswalklArray = data.crosswalk.split(' ').map((i) => Number(i)); - - const intersectWidth = dimensionsArray[0]; - const intersectDepth = dimensionsArray[1]; - - this.el.setAttribute( - 'geometry', - `primitive:box; width: ${intersectWidth}; height: ${intersectDepth}; depth:0.2` - ); - this.el.setAttribute('position', { - x: positionArray[0], - y: -0.1, - z: positionArray[2] - }); - this.el.setAttribute('rotation', '-90 0 0'); - this.el.setAttribute( - 'material', - 'src: #asphalt-texture; repeat:5 5; roughness:1' - ); - - function createSidewalkElem({ - length, - width, - positionVec, - scaleVec = { x: 1, y: 1, z: 1 }, - rotationVec - }) { - const sd = document.createElement('a-entity'); - const repeatCountInter = []; - repeatCountInter[0] = width / 2; - // every 2 meters repeat sidewalk texture - repeatCountInter[1] = parseInt(length / 2); - - sd.setAttribute('geometry', 'primitive', 'box'); - sd.setAttribute('geometry', 'height: 0.4'); - sd.setAttribute('position', positionVec); - sd.setAttribute('scale', scaleVec); - sd.setAttribute('geometry', 'depth', length); - sd.setAttribute('geometry', 'width', width); - sd.setAttribute('rotation', rotationVec); - sd.setAttribute('mixin', 'sidewalk'); - sd.setAttribute( - 'material', - `repeat: ${repeatCountInter[0]} ${repeatCountInter[1]}` - ); - el.appendChild(sd); - } - - // describe sidewalk parameters - const sidewalkParams = { - west: { - positionVec: { x: intersectWidth / 2 - sidewalkArray[0] / 2, z: 0.1 }, - rotationVec: { x: 90, y: 0, z: 0 }, - length: intersectDepth, - width: sidewalkArray[0] - }, - east: { - positionVec: { x: -intersectWidth / 2 + sidewalkArray[1] / 2, z: 0.1 }, - rotationVec: { x: 90, y: 0, z: 0 }, - length: intersectDepth, - width: sidewalkArray[1] - }, - north: { - positionVec: { - y: -intersectDepth / 2 + sidewalkArray[2] / 2, - // add x offset to avoid sidewalk's element overlap - x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - // minus the width of the crossing sidewalk - length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[2] - }, - south: { - positionVec: { - y: intersectDepth / 2 - sidewalkArray[3] / 2, - // add x offset to avoid sidewalk's element overlap - x: sidewalkArray[1] / 2 - sidewalkArray[0] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - // minus the width of the crossing sidewalk - length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[3] - } - }; - - // create sidewalks if they are given in sidewalkArray - const selectedSidewalks = Object.keys(sidewalkParams).filter( - (el, ind) => sidewalkArray[ind] - ); - - selectedSidewalks.forEach((sidewalkName, ind) => { - const params = sidewalkParams[sidewalkName]; - createSidewalkElem(params); - }); - - // describe curb parameters - const curbParams = { - northeast: { - positionVec: { - x: intersectWidth / 2 - northeastcurbArray[0] / 2, - y: intersectDepth / 2 - northeastcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: northeastcurbArray[0], - width: northeastcurbArray[1] - }, - southwest: { - positionVec: { - x: -intersectWidth / 2 + southwestcurbArray[0] / 2, - y: -intersectDepth / 2 + southwestcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: southwestcurbArray[0], - width: southwestcurbArray[1] - }, - southeast: { - positionVec: { - x: intersectWidth / 2 - southeastcurbArray[0] / 2, - y: -intersectDepth / 2 + southeastcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: southeastcurbArray[0], - width: southeastcurbArray[1] - }, - northwest: { - positionVec: { - x: -intersectWidth / 2 + northwestcurbArray[0] / 2, - y: intersectDepth / 2 - northwestcurbArray[1] / 2, - z: 0.1 - }, - rotationVec: { x: 0, y: 90, z: -90 }, - length: northwestcurbArray[0], - width: northwestcurbArray[1] - } - }; - - // create curbs if they are given - for (const [curbName, params] of Object.entries(curbParams)) { - if (data[`${curbName}curb`] !== '0 0') { - createSidewalkElem(params); - } - } - - if (stopsignArray[0]) { - const ss1 = document.createElement('a-entity'); - ss1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.1 - }); - ss1.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ss1.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss1); - } - if (stopsignArray[1]) { - const ss2 = document.createElement('a-entity'); - ss2.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.1 - }); - ss2.setAttribute('rotation', { x: 0, y: -90, z: -90 }); - ss2.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss2); - } - if (stopsignArray[2]) { - const ss3 = document.createElement('a-entity'); - ss3.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ss3.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ss3.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss3); - } - if (stopsignArray[3]) { - const ss4 = document.createElement('a-entity'); - ss4.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ss4.setAttribute('rotation', { x: 90, y: -90, z: -90 }); - ss4.setAttribute('mixin', 'stop_sign'); - el.appendChild(ss4); - } - - if (trafficsignalArray[0]) { - const ts1 = document.createElement('a-entity'); - ts1.setAttribute('position', { - x: intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts1.setAttribute('rotation', { x: 210, y: 90, z: 90 }); - ts1.setAttribute('mixin', 'signal_left'); - el.appendChild(ts1); - const ts2 = document.createElement('a-entity'); - ts2.setAttribute('position', { - x: intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts2.setAttribute('rotation', { x: 180, y: 90, z: 90 }); - ts2.setAttribute('mixin', 'signal_right'); - el.appendChild(ts2); - } - if (trafficsignalArray[1]) { - const ts3 = document.createElement('a-entity'); - ts3.setAttribute('position', { - x: -intersectWidth / 2, - y: -intersectDepth / 3, - z: 0.3 - }); - ts3.setAttribute('rotation', { x: 30, y: 90, z: 90 }); - ts3.setAttribute('mixin', 'signal_left'); - el.appendChild(ts3); - const ts4 = document.createElement('a-entity'); - ts4.setAttribute('position', { - x: -intersectWidth / 2, - y: intersectDepth / 3, - z: 0.3 - }); - ts4.setAttribute('rotation', { x: 0, y: 90, z: 90 }); - ts4.setAttribute('mixin', 'signal_right'); - el.appendChild(ts4); - } - if (trafficsignalArray[2]) { - const ts5 = document.createElement('a-entity'); - ts5.setAttribute('position', { - x: -intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts5.setAttribute('rotation', { x: 120, y: 90, z: 90 }); - ts5.setAttribute('mixin', 'signal_left'); - el.appendChild(ts5); - const ts6 = document.createElement('a-entity'); - ts6.setAttribute('position', { - x: intersectWidth / 3, - y: intersectDepth / 2, - z: 0.1 - }); - ts6.setAttribute('rotation', { x: 90, y: 90, z: 90 }); - ts6.setAttribute('mixin', 'signal_right'); - el.appendChild(ts6); - } - if (trafficsignalArray[3]) { - const ts7 = document.createElement('a-entity'); - ts7.setAttribute('position', { - x: intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ts7.setAttribute('rotation', { x: -60, y: 90, z: 90 }); - ts7.setAttribute('mixin', 'signal_left'); - el.appendChild(ts7); - const ts8 = document.createElement('a-entity'); - ts8.setAttribute('position', { - x: -intersectWidth / 3, - y: -intersectDepth / 2, - z: 0.1 - }); - ts8.setAttribute('rotation', { x: -90, y: 90, z: 90 }); - ts8.setAttribute('mixin', 'signal_right'); - el.appendChild(ts8); - } - - if (crosswalklArray[0]) { - const cw1 = document.createElement('a-entity'); - cw1.setAttribute('position', { x: intersectWidth / 2 - 2, z: 0.11 }); - cw1.setAttribute('rotation', { x: 0, y: 0, z: 180 }); - cw1.setAttribute('scale', { y: intersectDepth / 12 }); - cw1.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw1); - } - if (crosswalklArray[1]) { - const cw2 = document.createElement('a-entity'); - cw2.setAttribute('position', { x: -intersectWidth / 2 + 2, z: 0.11 }); - cw2.setAttribute('rotation', { x: 0, y: 0, z: 180 }); - cw2.setAttribute('scale', { y: intersectDepth / 12 }); - cw2.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw2); - } - if (crosswalklArray[2]) { - const cw3 = document.createElement('a-entity'); - cw3.setAttribute('position', { y: -intersectDepth / 2 + 2, z: 0.11 }); - cw3.setAttribute('rotation', { x: 0, y: 0, z: 90 }); - cw3.setAttribute('scale', { y: intersectWidth / 12 }); - cw3.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw3); - } - if (crosswalklArray[3]) { - const cw4 = document.createElement('a-entity'); - cw4.setAttribute('position', { y: intersectDepth / 2 - 2, z: 0.11 }); - cw4.setAttribute('rotation', { x: 0, y: 0, z: 90 }); - cw4.setAttribute('scale', { y: intersectWidth / 12 }); - cw4.setAttribute('mixin', 'markings crosswalk-zebra'); - el.appendChild(cw4); - } - } -}); - // Vehicle wheel Animation AFRAME.registerComponent('wheel', { schema: { From edb1c3779e2258f5d953afb7ed010b562c5aeba6 Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Tue, 9 Jul 2024 21:29:16 -0700 Subject: [PATCH 10/13] fix rotation to match google tiles --- .../components/components/AddLayerPanel/createLayerFunctions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js index 611f4df1b..49c417200 100644 --- a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js +++ b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js @@ -137,7 +137,7 @@ function createCustomModel() { function createPrimitiveGeometry() { const newEl = document.createElement('a-entity'); newEl.setAttribute('geometry', 'primitive: circle; radius: 50;'); - newEl.setAttribute('rotation', '-90 0 0'); + newEl.setAttribute('rotation', '-90 -90 0'); newEl.setAttribute( 'data-layer-name', 'Plane Geometry • Traffic Circle Asphalt' From a944e95be435fcb0b08e5efb97f8e2fb32fe1add Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Tue, 9 Jul 2024 21:29:30 -0700 Subject: [PATCH 11/13] add display names to match google tiles rotation --- src/components/intersection.js | 37 +++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/components/intersection.js b/src/components/intersection.js index 3264c0d68..657b4bf7b 100644 --- a/src/components/intersection.js +++ b/src/components/intersection.js @@ -60,7 +60,8 @@ AFRAME.registerComponent('intersection', { width, positionVec, scaleVec = { x: 1, y: 1, z: 1 }, - rotationVec + rotationVec, + displayName }) { const sd = document.createElement('a-entity'); // every 2 meters repeat sidewalk texture @@ -79,6 +80,7 @@ AFRAME.registerComponent('intersection', { 'material', `repeat: ${repeatCountInter[0]} ${repeatCountInter[1]}` ); + sd.setAttribute('data-layer-name', 'Sidewalk • ' + displayName); el.appendChild(sd); } @@ -88,13 +90,15 @@ AFRAME.registerComponent('intersection', { positionVec: { x: intersectWidth / 2 - sidewalkArray[0] / 2, z: 0.1 }, rotationVec: { x: 90, y: 0, z: 0 }, length: intersectDepth, - width: sidewalkArray[0] + width: sidewalkArray[0], + displayName: 'West' }, east: { positionVec: { x: -intersectWidth / 2 + sidewalkArray[1] / 2, z: 0.1 }, rotationVec: { x: 90, y: 0, z: 0 }, length: intersectDepth, - width: sidewalkArray[1] + width: sidewalkArray[1], + displayName: 'East' }, north: { positionVec: { @@ -106,7 +110,8 @@ AFRAME.registerComponent('intersection', { rotationVec: { x: 0, y: 90, z: -90 }, // minus the width of the crossing sidewalk length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[2] + width: sidewalkArray[2], + displayName: 'North' }, south: { positionVec: { @@ -118,7 +123,8 @@ AFRAME.registerComponent('intersection', { rotationVec: { x: 0, y: 90, z: -90 }, // minus the width of the crossing sidewalk length: intersectWidth - sidewalkArray[1] - sidewalkArray[0], - width: sidewalkArray[3] + width: sidewalkArray[3], + displayName: 'South' } }; @@ -142,7 +148,8 @@ AFRAME.registerComponent('intersection', { }, rotationVec: { x: 0, y: 90, z: -90 }, length: northeastcurbArray[0], - width: northeastcurbArray[1] + width: northeastcurbArray[1], + displayName: 'Northeast' }, southwest: { positionVec: { @@ -152,7 +159,8 @@ AFRAME.registerComponent('intersection', { }, rotationVec: { x: 0, y: 90, z: -90 }, length: southwestcurbArray[0], - width: southwestcurbArray[1] + width: southwestcurbArray[1], + displayName: 'Southwest' }, southeast: { positionVec: { @@ -162,7 +170,8 @@ AFRAME.registerComponent('intersection', { }, rotationVec: { x: 0, y: 90, z: -90 }, length: southeastcurbArray[0], - width: southeastcurbArray[1] + width: southeastcurbArray[1], + displayName: 'Southeast' }, northwest: { positionVec: { @@ -172,7 +181,8 @@ AFRAME.registerComponent('intersection', { }, rotationVec: { x: 0, y: 90, z: -90 }, length: northwestcurbArray[0], - width: northwestcurbArray[1] + width: northwestcurbArray[1], + displayName: 'Northwest' } }; @@ -226,6 +236,7 @@ AFRAME.registerComponent('intersection', { stopSignEl.setAttribute('rotation', params['rotation']); stopSignEl.setAttribute('mixin', 'stop_sign'); stopSignEl.classList.add('autocreated'); + stopSignEl.setAttribute('data-layer-name', 'Traffic Control • Stop Sign'); return stopSignEl; } @@ -321,6 +332,10 @@ AFRAME.registerComponent('intersection', { trafficSignalEl.setAttribute('rotation', params[side].rotation); trafficSignalEl.setAttribute('mixin', `signal_${side}`); trafficSignalEl.classList.add('autocreated'); + trafficSignalEl.setAttribute( + 'data-layer-name', + 'Traffic Signal • ' + direction + ' ' + side + ); el.appendChild(trafficSignalEl); }); } @@ -338,6 +353,7 @@ AFRAME.registerComponent('intersection', { cw1.setAttribute('rotation', { x: 0, y: 0, z: 180 }); cw1.setAttribute('scale', { y: intersectDepth / 12 }); cw1.setAttribute('mixin', 'markings crosswalk-zebra'); + cw1.setAttribute('data-layer-name', 'Crosswalk • East'); cw1.classList.add('autocreated'); el.appendChild(cw1); } @@ -347,6 +363,7 @@ AFRAME.registerComponent('intersection', { cw2.setAttribute('rotation', { x: 0, y: 0, z: 180 }); cw2.setAttribute('scale', { y: intersectDepth / 12 }); cw2.setAttribute('mixin', 'markings crosswalk-zebra'); + cw2.setAttribute('data-layer-name', 'Crosswalk • West'); cw2.classList.add('autocreated'); el.appendChild(cw2); } @@ -356,12 +373,14 @@ AFRAME.registerComponent('intersection', { cw3.setAttribute('rotation', { x: 0, y: 0, z: 90 }); cw3.setAttribute('scale', { y: intersectWidth / 12 }); cw3.setAttribute('mixin', 'markings crosswalk-zebra'); + cw3.setAttribute('data-layer-name', 'Crosswalk • Zebra (Continental)'); cw3.classList.add('autocreated'); el.appendChild(cw3); } if (crosswalklArray[3]) { const cw4 = document.createElement('a-entity'); cw4.setAttribute('position', { y: intersectDepth / 2 - 2, z: 0.11 }); + cw4.setAttribute('data-layer-name', 'Crosswalk • Zebra (Continental)'); cw4.setAttribute('rotation', { x: 0, y: 0, z: 90 }); cw4.setAttribute('scale', { y: intersectWidth / 12 }); cw4.setAttribute('mixin', 'markings crosswalk-zebra'); From 7de97157cd27da6fa4e6c34a401f58c45734a077 Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Tue, 9 Jul 2024 23:21:59 -0700 Subject: [PATCH 12/13] update intersection defaults --- src/components/intersection.js | 14 ++++++-------- .../AddLayerPanel/createLayerFunctions.js | 3 ++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/intersection.js b/src/components/intersection.js index 657b4bf7b..3decd5764 100644 --- a/src/components/intersection.js +++ b/src/components/intersection.js @@ -4,13 +4,13 @@ AFRAME.registerComponent('intersection', { dimensions: { type: 'string', default: '20 20' }, // cardinal direction order for sidewalk, stopsign, crosswalk: west, east, north, south sidewalk: { type: 'string', default: '0 0 0 0' }, - northeastcurb: { type: 'string', default: '0 0' }, - southwestcurb: { type: 'string', default: '0 0' }, - southeastcurb: { type: 'string', default: '0 0' }, - northwestcurb: { type: 'string', default: '0 0' }, + northeastcurb: { type: 'string', default: '4 4' }, + southwestcurb: { type: 'string', default: '4 4' }, + southeastcurb: { type: 'string', default: '4 4' }, + northwestcurb: { type: 'string', default: '4 4' }, stopsign: { type: 'string', default: '0 0 0 0' }, - trafficsignal: { type: 'string', default: '0 0 0 0' }, - crosswalk: { type: 'string', default: '0 0 0 0' } + trafficsignal: { type: 'string', default: '1 1 1 1' }, + crosswalk: { type: 'string', default: '2 2 2 2' } }, update: function () { var data = this.data; @@ -48,8 +48,6 @@ AFRAME.registerComponent('intersection', { 'geometry', `primitive:box; width: ${intersectWidth}; height: ${intersectDepth}; depth:0.2` ); - this.el.object3D.position.setY(-0.1); - this.el.setAttribute('rotation', '-90 0 0'); this.el.setAttribute( 'material', 'src: #asphalt-texture; repeat:5 5; roughness:1' diff --git a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js index 49c417200..043abb800 100644 --- a/src/editor/components/components/AddLayerPanel/createLayerFunctions.js +++ b/src/editor/components/components/AddLayerPanel/createLayerFunctions.js @@ -152,7 +152,8 @@ function createPrimitiveGeometry() { function createIntersection() { const newEl = document.createElement('a-entity'); newEl.setAttribute('intersection', ''); - newEl.setAttribute('data-layer-name', 'Street intersection'); + newEl.setAttribute('data-layer-name', 'Street • Intersection 90º'); + newEl.setAttribute('rotation', '-90 -90 0'); const parentEl = document.querySelector('#street-container'); parentEl.appendChild(newEl); // update sceneGraph From d572cca794585037fd11f5ca3e412d8f5caf347e Mon Sep 17 00:00:00 2001 From: Kieran Farr Date: Fri, 12 Jul 2024 11:25:43 -0700 Subject: [PATCH 13/13] remove splats for now doesn't work with log depth buffer --- .../components/AddLayerPanel/layersData.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/editor/components/components/AddLayerPanel/layersData.js b/src/editor/components/components/AddLayerPanel/layersData.js index 8755b3945..6605c8953 100644 --- a/src/editor/components/components/AddLayerPanel/layersData.js +++ b/src/editor/components/components/AddLayerPanel/layersData.js @@ -5,8 +5,7 @@ import { create3DTiles, createCustomModel, createPrimitiveGeometry, - createIntersection, - createSplatObject + createIntersection } from './createLayerFunctions'; // data for PRO layers cards @@ -80,16 +79,6 @@ const layersData = [ 'Create intersection entity. Parameters of intersection component could be changed in properties panel.', id: 7, handlerFunction: createIntersection - }, - { - name: 'Splat model from URL', - img: '', - requiresPro: true, - icon: '', - description: - 'Create entity with model from path for a Splat (.splat) file hosted on any publicly accessible HTTP server.', - id: 8, - handlerFunction: createSplatObject } ];