diff --git a/README.md b/README.md index 05eb06646e70e82007271bc5b6c29410fd6b565f..b2c499452d78f443fc4a3d03b8dab4dde3ed0b54 100644 --- a/README.md +++ b/README.md @@ -267,8 +267,10 @@ View.assignProgram(program) ## Immediately -- go for generic ui class like remote hardware: subscribes etc - +- nice work on generic ui classes / ui.thing.call('function', arg) +- finish robot flow: offsets, ok, 100ms updates, ok + - forward transform object -> three.js canvas + - do key-binding ui for robot jogging, write video - three robot canvas - set module display width diff --git a/client/client.js b/client/client.js index 445c6a8d3a9d95b8c7d310cb8792c7d6d98c3930..e06abe46a0067037ba568cf943702eb44de7b627 100644 --- a/client/client.js +++ b/client/client.js @@ -32,7 +32,7 @@ var wrapper = {} var nav = {} var verbose = false -var verboseComs = false +var verboseComs = false /* @@ -98,7 +98,7 @@ function socketSend(type, data) { type: type, data: data } - if(verboseComs) console.log('SEND', msg) + if (verboseComs) console.log('SEND', msg) sckt.send(JSON.stringify(msg)) } @@ -106,7 +106,7 @@ function socketRecv(evt) { var recv = JSON.parse(evt.data) var type = recv.type var data = recv.data - if(verboseComs) console.log('RECV', recv) + if (verboseComs) console.log('RECV', recv) // tree banger switch (type) { case 'console': @@ -171,6 +171,9 @@ function heapSendsNewProgram(prgm) { // whole hearted replace // hello for bugs when we lay this on top of something else program = prgm + if (program.description.view != null) { + writeTransformToPage(program.description.view) + } // 1st we want to git rm old files ... // when adding links, we'll have to add all and then draw links if (verbose) console.log('LOAD PROGRAM', program) @@ -397,6 +400,21 @@ function getCurrentTransform() { }) } +function writeTransformToPage(trns) { + // console.log('writing transform', trns) + /* transform is like { + scale: number, + translate: [x, y], + origin: [x, y] + } + */ + document.body.style.transform = `scale(${trns.scale}) translate(${trns.translate[0]}px, ${trns.translate[1]}px)` + document.body.style.transformOrigin = `${trns.origin[0]}px ${trns.origin[1]}px` + // opposite for nav + nav.style.transformOrigin = `${trns.origin[0]}px ${trns.origin[1]}px` + nav.style.transform = `scale(${1/trns.scale}) translate(${-trns.translate[0]*trns.scale}px,${-trns.translate[1]*trns.scale}px)` +} + function elementIsNotModule(element) { if ((element.tagName == 'HTML') || (element.tagName == 'BODY') || (element.tagName == 'svg')) { return true @@ -420,6 +438,11 @@ onwheel = function(evt) { var ty = cT.ty + (evt.pageY - cT.oy) * (1 - 1 / cT.s) // body + writeTransformToPage({ + scale: scale, + translate: [tx, ty], + origin: [evt.pageX, evt.pageY] + }) document.body.style.transform = `scale(${scale}) translate(${tx}px,${ty}px)` document.body.style.transformOrigin = `${evt.pageX}px ${evt.pageY}px` diff --git a/client/divtools.js b/client/divtools.js index dc8f3cd2c965ca8680c149b77b0488231e6ee7a0..9f811c3155ede6935adfed5901c2af66c8a622dc 100644 --- a/client/divtools.js +++ b/client/divtools.js @@ -3,11 +3,17 @@ function addRepToView(rep) { // a div to locate it var domElem = document.createElement('div') + + if(rep.description.isBigBlock){ + domElem.className = 'bigblock' + } else { + domElem.className = 'block' + } // dif. color for hardwares ? - domElem.className = 'block' if (rep.description.isHardware) { domElem.classList.add('hardware') } + domElem.style.left = lastPos.x + 'px' domElem.style.top = lastPos.y + 'px' diff --git a/client/style.css b/client/style.css index e6045c5d8b252eba98e3ce76eea2a4fe82d11779..d891d8440c5c5f2d73a39c3b2d3192cef2768871 100644 --- a/client/style.css +++ b/client/style.css @@ -18,6 +18,14 @@ body { background-color: #303030; } +.bigblock { + width: 800px; + position: absolute; + padding: 0px; + padding-bottom: 23px; + background-color: #303030; +} + .hardware { background-color: #4d4c4c; } diff --git a/client/ui/libs/three.js b/client/ui/libs/three.js index 8e95e397869be9918769ee422af2a4d0c03053cd..2bdb579138f257b0a0b4546088c36942016f2e82 100644 --- a/client/ui/libs/three.js +++ b/client/ui/libs/three.js @@ -48754,3 +48754,490 @@ Object.defineProperties( THREE.OrbitControls.prototype, { } } ); + +;(function() { + +"use strict"; + +var root = this + +var has_require = typeof require !== 'undefined' + +var THREE = root.THREE || has_require && require('three') +if( !THREE ) + throw new Error( 'MeshLine requires three.js' ) + +function MeshLine() { + + this.positions = []; + + this.previous = []; + this.next = []; + this.side = []; + this.width = []; + this.indices_array = []; + this.uvs = []; + this.counters = []; + this.geometry = new THREE.BufferGeometry(); + + this.widthCallback = null; + +} + +MeshLine.prototype.setGeometry = function( g, c ) { + + this.widthCallback = c; + + this.positions = []; + this.counters = []; + + if( g instanceof THREE.Geometry ) { + for( var j = 0; j < g.vertices.length; j++ ) { + var v = g.vertices[ j ]; + var c = j/g.vertices.length; + this.positions.push( v.x, v.y, v.z ); + this.positions.push( v.x, v.y, v.z ); + this.counters.push(c); + this.counters.push(c); + } + } + + if( g instanceof THREE.BufferGeometry ) { + // read attribute positions ? + } + + if( g instanceof Float32Array || g instanceof Array ) { + for( var j = 0; j < g.length; j += 3 ) { + var c = j/g.length; + this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); + this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); + this.counters.push(c); + this.counters.push(c); + } + } + + this.process(); + +} + +MeshLine.prototype.compareV3 = function( a, b ) { + + var aa = a * 6; + var ab = b * 6; + return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] ); + +} + +MeshLine.prototype.copyV3 = function( a ) { + + var aa = a * 6; + return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ]; + +} + +MeshLine.prototype.process = function() { + + var l = this.positions.length / 6; + + this.previous = []; + this.next = []; + this.side = []; + this.width = []; + this.indices_array = []; + this.uvs = []; + + for( var j = 0; j < l; j++ ) { + this.side.push( 1 ); + this.side.push( -1 ); + } + + var w; + for( var j = 0; j < l; j++ ) { + if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) ); + else w = 1; + this.width.push( w ); + this.width.push( w ); + } + + for( var j = 0; j < l; j++ ) { + this.uvs.push( j / ( l - 1 ), 0 ); + this.uvs.push( j / ( l - 1 ), 1 ); + } + + var v; + + if( this.compareV3( 0, l - 1 ) ){ + v = this.copyV3( l - 2 ); + } else { + v = this.copyV3( 0 ); + } + this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + for( var j = 0; j < l - 1; j++ ) { + v = this.copyV3( j ); + this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + } + + for( var j = 1; j < l; j++ ) { + v = this.copyV3( j ); + this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + } + + if( this.compareV3( l - 1, 0 ) ){ + v = this.copyV3( 1 ); + } else { + v = this.copyV3( l - 1 ); + } + this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); + + for( var j = 0; j < l - 1; j++ ) { + var n = j * 2; + this.indices_array.push( n, n + 1, n + 2 ); + this.indices_array.push( n + 2, n + 1, n + 3 ); + } + + if (!this.attributes) { + this.attributes = { + position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ), + previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ), + next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ), + side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ), + width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ), + uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ), + index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 ), + counters: new THREE.BufferAttribute( new Float32Array( this.counters ), 1 ) + } + } else { + this.attributes.position.copyArray(new Float32Array(this.positions)); + this.attributes.position.needsUpdate = true; + this.attributes.previous.copyArray(new Float32Array(this.previous)); + this.attributes.previous.needsUpdate = true; + this.attributes.next.copyArray(new Float32Array(this.next)); + this.attributes.next.needsUpdate = true; + this.attributes.side.copyArray(new Float32Array(this.side)); + this.attributes.side.needsUpdate = true; + this.attributes.width.copyArray(new Float32Array(this.width)); + this.attributes.width.needsUpdate = true; + this.attributes.uv.copyArray(new Float32Array(this.uvs)); + this.attributes.uv.needsUpdate = true; + this.attributes.index.copyArray(new Uint16Array(this.indices_array)); + this.attributes.index.needsUpdate = true; + } + + this.geometry.addAttribute( 'position', this.attributes.position ); + this.geometry.addAttribute( 'previous', this.attributes.previous ); + this.geometry.addAttribute( 'next', this.attributes.next ); + this.geometry.addAttribute( 'side', this.attributes.side ); + this.geometry.addAttribute( 'width', this.attributes.width ); + this.geometry.addAttribute( 'uv', this.attributes.uv ); + this.geometry.addAttribute( 'counters', this.attributes.counters ); + + this.geometry.setIndex( this.attributes.index ); + +} + +function memcpy (src, srcOffset, dst, dstOffset, length) { + var i + + src = src.subarray || src.slice ? src : src.buffer + dst = dst.subarray || dst.slice ? dst : dst.buffer + + src = srcOffset ? src.subarray ? + src.subarray(srcOffset, length && srcOffset + length) : + src.slice(srcOffset, length && srcOffset + length) : src + + if (dst.set) { + dst.set(src, dstOffset) + } else { + for (i=0; i<src.length; i++) { + dst[i + dstOffset] = src[i] + } + } + + return dst +} + +/** + * Fast method to advance the line by one position. The oldest position is removed. + * @param position + */ +MeshLine.prototype.advance = function(position) { + + var positions = this.attributes.position.array; + var previous = this.attributes.previous.array; + var next = this.attributes.next.array; + var l = positions.length; + + // PREVIOUS + memcpy( positions, 0, previous, 0, l ); + + // POSITIONS + memcpy( positions, 6, positions, 0, l - 6 ); + + positions[l - 6] = position.x; + positions[l - 5] = position.y; + positions[l - 4] = position.z; + positions[l - 3] = position.x; + positions[l - 2] = position.y; + positions[l - 1] = position.z; + + // NEXT + memcpy( positions, 6, next, 0, l - 6 ); + + next[l - 6] = position.x; + next[l - 5] = position.y; + next[l - 4] = position.z; + next[l - 3] = position.x; + next[l - 2] = position.y; + next[l - 1] = position.z; + + this.attributes.position.needsUpdate = true; + this.attributes.previous.needsUpdate = true; + this.attributes.next.needsUpdate = true; + +}; + +function MeshLineMaterial( parameters ) { + + var vertexShaderSource = [ +'precision highp float;', +'', +'attribute vec3 position;', +'attribute vec3 previous;', +'attribute vec3 next;', +'attribute float side;', +'attribute float width;', +'attribute vec2 uv;', +'attribute float counters;', +'', +'uniform mat4 projectionMatrix;', +'uniform mat4 modelViewMatrix;', +'uniform vec2 resolution;', +'uniform float lineWidth;', +'uniform vec3 color;', +'uniform float opacity;', +'uniform float near;', +'uniform float far;', +'uniform float sizeAttenuation;', +'', +'varying vec2 vUV;', +'varying vec4 vColor;', +'varying float vCounters;', +'', +'vec2 fix( vec4 i, float aspect ) {', +'', +' vec2 res = i.xy / i.w;', +' res.x *= aspect;', +' vCounters = counters;', +' return res;', +'', +'}', +'', +'void main() {', +'', +' float aspect = resolution.x / resolution.y;', +' float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);', +'', +' vColor = vec4( color, opacity );', +' vUV = uv;', +'', +' mat4 m = projectionMatrix * modelViewMatrix;', +' vec4 finalPosition = m * vec4( position, 1.0 );', +' vec4 prevPos = m * vec4( previous, 1.0 );', +' vec4 nextPos = m * vec4( next, 1.0 );', +'', +' vec2 currentP = fix( finalPosition, aspect );', +' vec2 prevP = fix( prevPos, aspect );', +' vec2 nextP = fix( nextPos, aspect );', +'', +' float pixelWidth = finalPosition.w * pixelWidthRatio;', +' float w = 1.8 * pixelWidth * lineWidth * width;', +'', +' if( sizeAttenuation == 1. ) {', +' w = 1.8 * lineWidth * width;', +' }', +'', +' vec2 dir;', +' if( nextP == currentP ) dir = normalize( currentP - prevP );', +' else if( prevP == currentP ) dir = normalize( nextP - currentP );', +' else {', +' vec2 dir1 = normalize( currentP - prevP );', +' vec2 dir2 = normalize( nextP - currentP );', +' dir = normalize( dir1 + dir2 );', +'', +' vec2 perp = vec2( -dir1.y, dir1.x );', +' vec2 miter = vec2( -dir.y, dir.x );', +' //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );', +'', +' }', +'', +' //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;', +' vec2 normal = vec2( -dir.y, dir.x );', +' normal.x /= aspect;', +' normal *= .5 * w;', +'', +' vec4 offset = vec4( normal * side, 0.0, 1.0 );', +' finalPosition.xy += offset.xy;', +'', +' gl_Position = finalPosition;', +'', +'}' ]; + + var fragmentShaderSource = [ + '#extension GL_OES_standard_derivatives : enable', +'precision mediump float;', +'', +'uniform sampler2D map;', +'uniform sampler2D alphaMap;', +'uniform float useMap;', +'uniform float useAlphaMap;', +'uniform float useDash;', +'uniform float dashArray;', +'uniform float dashOffset;', +'uniform float dashRatio;', +'uniform float visibility;', +'uniform float alphaTest;', +'uniform vec2 repeat;', +'', +'varying vec2 vUV;', +'varying vec4 vColor;', +'varying float vCounters;', +'', +'void main() {', +'', +' vec4 c = vColor;', +' if( useMap == 1. ) c *= texture2D( map, vUV * repeat );', +' if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a;', +' if( c.a < alphaTest ) discard;', +' if( useDash == 1. ){', +' c.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio));', +' }', +' gl_FragColor = c;', +' gl_FragColor.a *= step(vCounters, visibility);', +'}' ]; + + function check( v, d ) { + if( v === undefined ) return d; + return v; + } + + THREE.Material.call( this ); + + parameters = parameters || {}; + + this.lineWidth = check( parameters.lineWidth, 1 ); + this.map = check( parameters.map, null ); + this.useMap = check( parameters.useMap, 0 ); + this.alphaMap = check( parameters.alphaMap, null ); + this.useAlphaMap = check( parameters.useAlphaMap, 0 ); + this.color = check( parameters.color, new THREE.Color( 0xffffff ) ); + this.opacity = check( parameters.opacity, 1 ); + this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) ); + this.sizeAttenuation = check( parameters.sizeAttenuation, 1 ); + this.near = check( parameters.near, 1 ); + this.far = check( parameters.far, 1 ); + this.dashArray = check( parameters.dashArray, 0 ); + this.dashOffset = check( parameters.dashOffset, 0 ); + this.dashRatio = check( parameters.dashRatio, 0.5 ); + this.useDash = ( this.dashArray !== 0 ) ? 1 : 0; + this.visibility = check( parameters.visibility, 1 ); + this.alphaTest = check( parameters.alphaTest, 0 ); + this.repeat = check( parameters.repeat, new THREE.Vector2( 1, 1 ) ); + + var material = new THREE.RawShaderMaterial( { + uniforms:{ + lineWidth: { type: 'f', value: this.lineWidth }, + map: { type: 't', value: this.map }, + useMap: { type: 'f', value: this.useMap }, + alphaMap: { type: 't', value: this.alphaMap }, + useAlphaMap: { type: 'f', value: this.useAlphaMap }, + color: { type: 'c', value: this.color }, + opacity: { type: 'f', value: this.opacity }, + resolution: { type: 'v2', value: this.resolution }, + sizeAttenuation: { type: 'f', value: this.sizeAttenuation }, + near: { type: 'f', value: this.near }, + far: { type: 'f', value: this.far }, + dashArray: { type: 'f', value: this.dashArray }, + dashOffset: { type: 'f', value: this.dashOffset }, + dashRatio: { type: 'f', value: this.dashRatio }, + useDash: { type: 'f', value: this.useDash }, + visibility: {type: 'f', value: this.visibility}, + alphaTest: {type: 'f', value: this.alphaTest}, + repeat: { type: 'v2', value: this.repeat } + }, + vertexShader: vertexShaderSource.join( '\r\n' ), + fragmentShader: fragmentShaderSource.join( '\r\n' ) + }); + + delete parameters.lineWidth; + delete parameters.map; + delete parameters.useMap; + delete parameters.alphaMap; + delete parameters.useAlphaMap; + delete parameters.color; + delete parameters.opacity; + delete parameters.resolution; + delete parameters.sizeAttenuation; + delete parameters.near; + delete parameters.far; + delete parameters.dashArray; + delete parameters.dashOffset; + delete parameters.dashRatio; + delete parameters.visibility; + delete parameters.alphaTest; + delete parameters.repeat; + + material.type = 'MeshLineMaterial'; + + material.setValues( parameters ); + + return material; + +}; + +MeshLineMaterial.prototype = Object.create( THREE.Material.prototype ); +MeshLineMaterial.prototype.constructor = MeshLineMaterial; + +MeshLineMaterial.prototype.copy = function ( source ) { + + THREE.Material.prototype.copy.call( this, source ); + + this.lineWidth = source.lineWidth; + this.map = source.map; + this.useMap = source.useMap; + this.alphaMap = source.alphaMap; + this.useAlphaMap = source.useAlphaMap; + this.color.copy( source.color ); + this.opacity = source.opacity; + this.resolution.copy( source.resolution ); + this.sizeAttenuation = source.sizeAttenuation; + this.near = source.near; + this.far = source.far; + this.dashArray.copy( source.dashArray ); + this.dashOffset.copy( source.dashOffset ); + this.dashRatio.copy( source.dashRatio ); + this.useDash = source.useDash; + this.visibility = source.visibility; + this.alphaTest = source.alphaTest; + this.repeat.copy( source.repeat ); + + return this; + +}; + +if( typeof exports !== 'undefined' ) { + if( typeof module !== 'undefined' && module.exports ) { + exports = module.exports = { MeshLine: MeshLine, MeshLineMaterial: MeshLineMaterial }; + } + exports.MeshLine = MeshLine; + exports.MeshLineMaterial = MeshLineMaterial; +} +else { + root.MeshLine = MeshLine; + root.MeshLineMaterial = MeshLineMaterial; +} + +}).call(this); diff --git a/client/ui/robotRepresentation.js b/client/ui/robotRepresentation.js new file mode 100644 index 0000000000000000000000000000000000000000..2664eb18f8523a8e2d91b1b4a234462f82986be9 --- /dev/null +++ b/client/ui/robotRepresentation.js @@ -0,0 +1,125 @@ +(function() { + // generic / example three.js canvas + /* KRITICAL STEP */ + // this is our object, that we will later append + // to the .lump position + var threeCanvas = {} + + var verbose = false + + // now three stuff + var container = document.createElement('div') + var scene = new THREE.Scene() + scene.background = new THREE.Color(0xd6d6d6) + var camera = new THREE.PerspectiveCamera(75, 1, 0.01, 1000) + camera.up.set(0, 0, 1) + var renderer = new THREE.WebGLRenderer() + renderer.setSize(696, 796) + container.appendChild(renderer.domElement) + + // axes + var axesHelper = new THREE.AxesHelper(0.1) + scene.add(axesHelper) + + // grid + /* + var gridHelper = new THREE.GridHelper(10, 100) + gridHelper.translateOnAxis(new THREE.Vector3(0, 0, 1), -0.01) + gridHelper.rotateX(-Math.PI / 2) + scene.add(gridHelper) + */ + + // one line + var material = new THREE.LineBasicMaterial({ color: 0x000000 }) + var geometry = new THREE.Geometry() + geometry.vertices.push(new THREE.Vector3(0, 0, 0)) + geometry.vertices.push(new THREE.Vector3(0.5, 0, 0.5)) + geometry.vertices.push(new THREE.Vector3(1, 0, 0.5)) + var meshline = new MeshLine() + meshline.setGeometry(geometry, function(p) { return 3 }) + var material = new MeshLineMaterial({ + useMap: false, + color: new THREE.Color(0x50514f), + opacity: 1, + sizeAttenuation: true, + lineWidth: 0.01, + near: camera.near, + far: camera.far + }) + var mesh = new THREE.Mesh(meshline.geometry, material) + scene.add(mesh) + + var controls = new THREE.OrbitControls(camera, container) + + camera.position.set(0.5, -1, 0.5) + controls.update() + + var animate = function() { + requestAnimationFrame(animate) + /* + line.geometry.vertices[1].x += 0.01 + line.geometry.verticesNeedUpdate = true + */ + controls.update() + + renderer.render(scene, camera) + } + // kickstart + animate() + + // set class, etc, put canvas in class, etc + // and then + /* KRITICAL STEP */ + // we have to give our 'lump' object a .domElem, this + // will be referenced upstream to append to the right module + // append it to the dom so that it can be appended on init + threeCanvas.domElem = container + + /* KRITICAL STEP */ + // whatever is posted to .lump will receive messages through + // .onMessage, so if we don't write one, we'll cause errors + // upstream, and besides, wouldn't be able to get anything from + // the server + threeCanvas.onMessage = function(msg) { + //console.log('got message in client side ui object', msg) + if (msg.calls == 'updateXY1') { + if(verbose) console.log('updateXY1', msg.argument) + geometry.vertices[0].set(msg.argument[0], msg.argument[1], msg.argument[2]) + meshline.setGeometry(geometry, function(p) { return 3 }) + geometry.verticesNeedUpdate = true + } else if (msg.calls == 'updateXY2') { + if(verbose) console.log('updateXY2', msg.argument) + geometry.vertices[1].set(msg.argument[0], msg.argument[1], msg.argument[2]) + meshline.setGeometry(geometry, function(p) { return 3 }) + geometry.verticesNeedUpdate = true + } else if (msg.calls == 'updateXY3') { + if(verbose) console.log('updateXY3', msg.argument) + geometry.vertices[2].set(msg.argument[0], msg.argument[1], msg.argument[2]) + meshline.setGeometry(geometry, function(p) { return 3 }) + geometry.verticesNeedUpdate = true + } else { + console.log('default msg because none from sys at threejs clientside') + console.log(msg) + } + } + + /* KRITICAL STEP */ + // expect this to only be used once + // it's basically our init function + // and gets called once the module is loaded + window.registerNewModule = function(id, key) { + threeCanvas.parentId = id + threeCanvas.key = key + // affectionately named lump of code, insert ourselves here + program.modules[id].ui[key].lump = threeCanvas + // and call-back to do onload things + var data = { + id: threeCanvas.parentId, + key: threeCanvas.key, + msg: { + key: 'onload' + } + } + socketSend('put ui change', data) + } +})() \ No newline at end of file diff --git a/client/ui/threeCanvas.js b/client/ui/threeCanvas.js index 0beeaf0855c01b038898df89c59563137fa0858c..9da96fe9ef7810c975d8df26f2cc8ddb2894eed6 100644 --- a/client/ui/threeCanvas.js +++ b/client/ui/threeCanvas.js @@ -1,4 +1,5 @@ (function() { + // generic / example three.js canvas /* KRITICAL STEP */ // this is our object, that we will later append // to the .lump position diff --git a/modules/robot/forwardTransform.js b/modules/robot/forwardTransform.js index 33894b71719bcd3b0378537ce5ef0374564b1ab0..2cdd66b9166ec5060c59ffc16212f4437b7bd3cc 100644 --- a/modules/robot/forwardTransform.js +++ b/modules/robot/forwardTransform.js @@ -7,9 +7,6 @@ let Output = JSUnit.Output let State = JSUnit.State function forwardTransform() { - var theta1 = 0 - var theta2 = 0 - var forwardTransform = { description: { name: 'forwardTransform Parser', @@ -24,73 +21,68 @@ function forwardTransform() { // or they don't get getter / settered when we do forwardTransform.state = State() var state = forwardTransform.state - state.l1 = 0.4 - state.l2 = 0.2 + state.tA = 0 + state.tB = 0 + state.tC = 0 + state.lA = 0.4 + state.lB = 0.2 + state.onUiChange('tA', () => { + doForwardTransform() + }) forwardTransform.inputs = { - theta1: Input('any', intakeTheta1), - theta2: Input('any', intakeTheta2), - l1: Input('any', intakeL1), - l2: Input('any', intakeL2) + theta_A: Input('any', (num) => { + state.tA = num + doForwardTransform() + }), + theta_B: Input('any', (num) => { + state.tB = num + doForwardTransform() + }), + theta_C: Input('number', (num) => { + state.tC = num + doForwardTransform() + }), + len_A: Input('any', (num) => { + state.lA = num + doForwardTransform() + }), + len_B: Input('any', (num) => { + state.lB = num + doForwardTransform() + }) } forwardTransform.outputs = { - originpt: Output('array'), - jointpt: Output('array'), - touchpt: Output('array') - } - - function intakeTheta1(num){ - theta1 = num - var points = parseforwardTransform() - forwardTransform.outputs.originpt.emit(points.originpt) - forwardTransform.outputs.jointpt.emit(points.jointpt) - forwardTransform.outputs.touchpt.emit(points.touchpt) - - } - - function intakeTheta2(num){ - theta2 = num - var points = parseforwardTransform() - forwardTransform.outputs.originpt.emit(points.originpt) - forwardTransform.outputs.jointpt.emit(points.jointpt) - forwardTransform.outputs.touchpt.emit(points.touchpt) - //console.log('theta2 input') - } - - function intakeL1(num){ - state.l1 = num - var points = parseforwardTransform() - forwardTransform.outputs.originpt.emit(points.originpt) - forwardTransform.outputs.jointpt.emit(points.jointpt) - forwardTransform.outputs.touchpt.emit(points.touchpt) - //console.log('state.l1 input') - } - - function intakeL2(num){ - state.l2 = num - var points = parseforwardTransform() - forwardTransform.outputs.originpt.emit(points.originpt) - forwardTransform.outputs.jointpt.emit(points.jointpt) - forwardTransform.outputs.touchpt.emit(points.touchpt) - //console.log('state.l2 input') + ptA: Output('array'), + ptB: Output('array'), + ptC: Output('array') } // TODO: test, can we link global vars to ui objects ... // forwardTransform.ui.mode.value = var ? no bc set / get etc // more like var = forwardTransform.ui.mode.value ? is this referential? - function parseforwardTransform() { - var points = { - originpt: [0,0], - jointpt: [0,0], - touchpt: [0,0] - } - - points.jointpt = [state.l1*Math.cos(theta1), state.l1*Math.sin(theta1)] - points.touchpt = [state.l1*Math.cos(theta1)+state.l2*Math.cos(theta2+theta1), state.l1*Math.sin(theta1)+state.l2*Math.sin(theta2+ theta1)] - - return points + function doForwardTransform() { + var lenA = state.lA*Math.cos(state.tB) + var lenB = state.lB*Math.cos(state.tB + state.tC) + + var knuckle = [ lenA*Math.cos(state.tA), + lenA*Math.sin(state.tA), + state.lA*Math.sin(state.tB)] + + var tip = [ knuckle[0] + lenB*Math.cos(state.tA), + knuckle[1] + lenB*Math.sin(state.tA), + knuckle[2] + state.lB*Math.sin(state.tB + state.tC)] + /* + [ state.lA*Math.cos(state.tA) + state.lB*Math.cos(state.tA + state.tB), + state.lA*Math.sin(state.tA) + state.lB*Math.sin(state.tA + state.tB), + state.lA*Math.sin(state.tB) + state.lB*Math.sin(state.tA + state.tB)] + */ + + forwardTransform.outputs.ptA.emit([0,0,0]) + forwardTransform.outputs.ptB.emit(knuckle) + forwardTransform.outputs.ptC.emit(tip) } return forwardTransform diff --git a/modules/ui/robotCanvas.js b/modules/ui/robotCanvas.js index 1250f4bc2bba95b04af7fc27612acbb995839a55..28b0d7c47d86c766013d738b906094eeece12bd8 100644 --- a/modules/ui/robotCanvas.js +++ b/modules/ui/robotCanvas.js @@ -14,8 +14,9 @@ function RobotCanvas() { var rbtCanvas = { // descriptions are used in UI description: { - name: 'ThreeJS-Canvas', - alt: 'graphix' + name: 'RobotArm-Canvas', + alt: 'graphix', + isBigBlock: true } } @@ -26,7 +27,7 @@ function RobotCanvas() { rbtCanvas.inputs = { xy1: Input('array', onNewXY1), xy2: Input('array', onNewXY2), - // do some canvas stuff + xy3: Input('array', onNewXY3) } rbtCanvas.outputs = { @@ -35,30 +36,34 @@ function RobotCanvas() { rbtCanvas.ui = UI() var ui = rbtCanvas.ui - ui.addElement('threeCanvas', 'ui/threeCanvas.js') + ui.addElement('canvas', 'ui/robotRepresentation.js') // add bonus lib path - ui.threeCanvas.libPath = 'ui/libs/three.js' - ui.threeCanvas.subscribe('onload', function(msg){ + ui.canvas.libPath = 'ui/libs/three.js' + ui.canvas.subscribe('onload', function(msg){ console.log('catch canvas load', msg) + onNewXY1([0,0,0]) + onNewXY2([0.3,0.3,0.6]) + onNewXY3([0.6,0.6,0.3]) }) - - /* - ui.threeCanvas.onload = function() { - console.log('canvas is loaded') - } - */ function onNewXY1(array) { - ui.threeCanvas.send({ + ui.canvas.send({ calls: "updateXY1", - argument: [array[0], 0, array[1]] + argument: array }) } function onNewXY2(array){ - ui.threeCanavs.send({ + ui.canvas.send({ calls: "updateXY2", - argument: [array[0], 0, array[1]] + argument: array + }) + } + + function onNewXY3(array){ + ui.canvas.send({ + calls: "updateXY3", + argument: array }) } diff --git a/modules/util/gate.js b/modules/util/gate.js index d4e5f174e8a6bca94c5f9fb7c328b48f8aa93ae9..cf3af9bb6a422f53678535c9b80726f22729f7d8 100644 --- a/modules/util/gate.js +++ b/modules/util/gate.js @@ -28,7 +28,7 @@ function Gate() { gate.ui = UI() var ui = gate.ui ui.addElement('openButton', 'ui/uiButton.js') - ui.openButton.subscribe('onload', function(msg){ + ui.openButton.subscribe('onload', function(msg) { ui.openButton.send({ calls: 'setText', argument: 'click to open gate' @@ -51,11 +51,17 @@ function Gate() { if (gate.isOpen) { gate.isOpen = false state.message = 'closed' - ui.openButton.setText('click to open gate') + ui.openButton.send({ + calls: 'setText', + argument: 'click to open gate' + }) } else { gate.isOpen = true state.message = 'open' - ui.openButton.setText('click to close gate') + ui.openButton.send({ + calls: 'setText', + argument: 'click to close gate' + }) } } diff --git a/modules/util/log.js b/modules/util/log.js index eb9ad295a1f96feb084b940eab3769be72ddec5b..9dff8924aebba38f92756b5f62c12060f9a81f1b 100644 --- a/modules/util/log.js +++ b/modules/util/log.js @@ -17,10 +17,11 @@ function Logger() { logger.state = State() // alias ! - var state = logger.state + var state = logger.state state.prefix = 'LOGGER:' state.message = '---' + state.logToggle = true logger.inputs = { thru: Input('any', onInput) // makes anything into '1' event @@ -30,9 +31,11 @@ function Logger() { throughput: Output('any') } - function onInput(input){ - state.message = input.toString() - console.log(state.prefix, input) + function onInput(input) { + if (state.logToggle) { + state.message = input.toString() + console.log(state.prefix, input) + } } return logger diff --git a/programs.js b/programs.js index fef3606d80fe22884d8ac8fe05ee15115246d434..8285824f367790420181ab9b1e99d088390bdb21 100644 --- a/programs.js +++ b/programs.js @@ -305,6 +305,10 @@ function SetUI(module, left, top){ module.description.position.top = top } +function SetView(program, transform){ + program.description.view = transform +} + module.exports = { new: newProgram, open: openProgram, @@ -312,5 +316,6 @@ module.exports = { loadModuleFromSource: loadModuleFromSource, removeModule: removeModuleFromProgram, assignSocket: assignSocket, - setUI: SetUI + setUI: SetUI, + setView: SetView } \ No newline at end of file diff --git a/robot.js b/robot.js index e33085da118b33b9cca4a677033c6d761ed88fac..77c9b52372f352fcd8678a316e2cf675a155f541 100644 --- a/robot.js +++ b/robot.js @@ -22,19 +22,34 @@ var program = Programs.new('new program') var link = Programs.loadModuleFromSource(program, './modules/hardware/atkseriallink.js') link.startUp() link.state.log = false -Programs.setUI(link, 1050, 50) +Programs.setUI(link, 1050, 150) var mrbotone = Programs.loadModuleFromSource(program, './modules/hardware/atkmrobot.js') +mrbotone.route.route = '0,0' +mrbotone.state.enc_reverse = true +mrbotone.state.enc_offset = 8875 Programs.setUI(mrbotone, 600, 50) + var mrbottwo = Programs.loadModuleFromSource(program, './modules/hardware/atkmrobot.js') +mrbottwo.state.enc_reverse = true +mrbottwo.state.enc_offset = 4000 +mrbottwo.route.route = '0,1' Programs.setUI(mrbottwo, 600, 550) + var mrbotthree = Programs.loadModuleFromSource(program, './modules/hardware/atkmrobot.js') +mrbotthree.route.route = '0,2' +mrbotthree.state.enc_reverse = false +mrbotthree.state.enc_offset = 1700 Programs.setUI(mrbotthree, 600, 1050) var rbtcanvas = Programs.loadModuleFromSource(program, './modules/ui/robotCanvas.js') -Programs.setUI(rbtcanvas, 1200, 50) +Programs.setUI(rbtcanvas, 1500, 1050) -/* +Programs.setView(program, { + scale: 0.5, + translate: [-160, -30], + origin: [200, 120] +}) var button = Programs.loadModuleFromSource(program, './modules/ui/button.js') var delay = Programs.loadModuleFromSource(program, './modules/util/delay.js') @@ -46,17 +61,38 @@ Programs.setUI(delay, 90, 250) Programs.setUI(gate, 90, 400) button.outputs.whammy.attach(mrbotone.inputs.get_pos) +button.outputs.whammy.attach(mrbottwo.inputs.get_pos) +button.outputs.whammy.attach(mrbotthree.inputs.get_pos) button.outputs.whammy.attach(delay.inputs.thru) delay.outputs.out.attach(gate.inputs.thru) gate.outputs.out.attach(button.inputs.thru) -var log = Programs.loadModuleFromSource(program, './modules/util/log.js') -log.state.prefix = "jnt1:" -Programs.setUI(log, 1050, 520) -mrbotone.outputs.pos.attach(log.inputs.thru) +var transform = Programs.loadModuleFromSource(program, './modules/robot/forwardTransform.js') +Programs.setUI(transform, 1225, 650) + +var log1 = Programs.loadModuleFromSource(program, './modules/util/log.js') +log1.state.prefix = "jnt1:" +Programs.setUI(log1, 1500, 50) +mrbotone.outputs.pos.attach(log1.inputs.thru) +mrbotone.outputs.pos.attach(transform.inputs.theta_A) -var canvas = Programs.loadModuleFromSource(program, './modules/ui/threeCanvas.js') -Programs.setUI(canvas, 1500, 650) +var log2= Programs.loadModuleFromSource(program, './modules/util/log.js') +log2.state.prefix = "jnt2:" +Programs.setUI(log2, 1500, 250) +mrbottwo.outputs.pos.attach(log2.inputs.thru) +mrbottwo.outputs.pos.attach(transform.inputs.theta_B) + +var log3 = Programs.loadModuleFromSource(program, './modules/util/log.js') +log3.state.prefix = "jnt3:" +Programs.setUI(log3, 1500, 450) +mrbotthree.outputs.pos.attach(log3.inputs.thru) +mrbotthree.outputs.pos.attach(transform.inputs.theta_C) + +transform.outputs.ptA.attach(rbtcanvas.inputs.xy1) +transform.outputs.ptB.attach(rbtcanvas.inputs.xy2) +transform.outputs.ptC.attach(rbtcanvas.inputs.xy3) + +/* var collector = Programs.loadModuleFromSource(program, './modules/util/collector.js') Programs.setUI(collector, 1050, 800) @@ -70,7 +106,7 @@ Programs.setUI(gateCounter, 600, 850) var stest = Programs.loadModuleFromSource(program, './modules/ui/stest.js') var rep = Reps.makeFromModule(stest) -console.log('rep', rep) +console.log1('rep', rep) /* example program-like-an-api // load some modules diff --git a/views.js b/views.js index b1efc2d8b77779634f59e7d3130cc9085357edc9..43b447d01de379b71187c70368c5fda0366a6f56 100644 --- a/views.js +++ b/views.js @@ -163,6 +163,9 @@ function uiRequestCurrentProgram() { }, modules: {} } + if(program.description.view != null){ + prgRep.description.view = program.description.view + } for (mdlName in program.modules) { var mdlRep = Reps.makeFromModule(program.modules[mdlName]) prgRep.modules[mdlName] = mdlRep