abhishekvp / cesium-lg Goto Github PK
View Code? Open in Web Editor NEWLiquid Galaxy GSoC 2016 Project: Enabling Cesium for Liquid Galaxy
Liquid Galaxy GSoC 2016 Project: Enabling Cesium for Liquid Galaxy
add this to slaves to account for vertical fov.
this is my shortcut for 16:9 galaxy screens, but really the browser document width and height should be queried and used for this.
var displayAspectRatio = 16/9; // height/width - query dom for this
viewer.camera.frustum.fov = toRadians(CONFIG.slaveHorizFOV * displayAspectRatio);
this will also need to be reset on browser window size change.
The slave default field of view should be set from config.js
eg. viewer.camera.frustum.fov = toRadians(CONFIG.SlaveFOV);
document titles should not be Hello World
"Master Cesium" and "Slave Cesium" or something like that
neaten up the line breaks and formatting so it's easier to read.
change the intro comment.
//Rename this file to config.js and replace BingMapsKey with your key
var CONFIG = {
wsURI : 'ws://10.237.10.1:8081',
BingMapsKey : 'YOUR BING MAPS API KEY',
camSigFigures : 10e6,
slaveHorizFOV : 25,
masterFOV : 25
NODE_SERVER_IP: 'localhost',
NODE_SERVER_PORT: 8081,
UDP_PORT:21567,
UDP_HOST: 'localhost'
};
Add UDP packet listening and sending to the nodejs relay service, so it can send & respond to Google Earth viewsync UDP packets.
And translate between Cesium ViewSync and Earth ViewSync formats. In the first instance, I'd like to try using a Google Earth master to control Cesium slaves and get a better idea how responsive the slaves are.
In the Slave viewer setup app the AGI terrain provider...
terrainProvider : new Cesium.CesiumTerrainProvider({
url:'http://assets.agi.com/stk-terrain/world',
requestWaterMask: true })
At some point we'll need to handle switching between different terrain providers (ellipisoid, VTK) as well.
But start by getting one in there to start with.
Hi, another layer to add..
var bingMapsAerialWithLabels = new Cesium.BingMapsImageryProvider({
url: 'http://dev.virtualearth.net',
mapStyle: Cesium.BingMapsStyle.AERIAL_WITH_LABELS
});
config.js
Master & Slave html
Hi, check that npm packages.json is up to date and doesn't have extraneous packages in it.
Thanks.
I think Message is a bit too generic, maube something like...
var CesiumSync = ProtoBuf.loadProtoFile("cesiumsync.proto").build("CesiumSync");
maybe also rename the 'msg' vars to 'sync' or something?
For the message type need come up with some message type identifier that isn't a string.
At the moment "ge-cam" or "state" appears as literal string in the packet. I was hoping protobuf would encode this more efficiently. At the moment it still takes up a bunch of bytes when it should be less than 1.
Using some constants would be fine. TYPE.cam = 0; TYPE.status = 1; TYPE.gecam=2 ?
Or another idea?
tcpdump output...
18:25:04.232393 IP 10.237.10.1.8081 > 10.237.10.71.50687: Flags [P.], ack 1, win 123, length 76
0x0000: 4500 0074 4284 4000 4006 cdde 0aed 0a01 E..tB.@.@.......
0x0010: 0aed 0a47 1f91 c5ff 089e d0d5 75fd cdd1 ...G........u...
0x0020: 5018 007b 2a88 0000 c24a 003e 00c1 ff0a P..{*....J.>....
0x0030: 0667 652d 6361 6d11 4680 20bd 05bb 6540 .ge-cam.F.....e@
0x0040: 1985 63ca 050c aa43 c021 5200 fd50 096b ..c....C.!R..P.k
0x0050: a240 29e3 88a1 f9b4 0bf6 3f31 0370 ddcd .@).......?1.p..
0x0060: 4ce7 c6bf 396b 3ce6 78f6 892f 3f00 0000 L...9k<.x../?...
0x0070: ffff 0200
In server.js wsServer.on() maintain count of active client count. So I can tell if I have the right number of slaves connected...
var clientWSCount = 0, activeWSClientCount = 0;
var wsClients = {};
wsServer.on("connection", function(socket) { // Port 8081
//Keep count of all connected clients
var id = clientWSCount++;
activeWSClientCount++;
//Store connection object for each of the clients
wsClients[id] = socket;
console.log((new Date()) + ' Connection accepted [' + id + '], Active clients '+ activeWSClientCount);
...
socket.on("close", function(reasonCode, description) {
delete wsClients[id];
activeWSClientCount--;
console.log((new Date()) + ' Peer ' + id + ' disconnected. Still have '+activeWSClientCount+' clients');
})
Before getting to stuck into UI designs, i suggest using the simple dat.gui for master UI.
dat.gui is a common library for basic html user interfaces and would be fine to use in this project.
https://github.com/dataarts/dat.gui
https://workshop.chromeexperiments.com/examples/gui/
It may be worthwhile looking at syncing dat.gui 'state' from the master to slaves?
Passing the dat structure to slaves when there's a change.
there's some radian conversion stuff going on in server.js pull utils.js and use toRadians()
Hi, sending the current camera pose as heartbeat every second would be useful.
Particularly when Slave Cesiums restart and we want them to quickly re-sync to the current camera pose... they may restart when there are no camera updates happening.
I'm not sure whether to do this from the Cesium Master or from the server.js relay.
If the camera pose comes from Google Earth viewsync then it makes more sense for the nodejs relay to send the heartbeat.
Heartbeart time should be a CONFIG setting
CONFIG.cameraSyncHeartBeat = 1000; // (in milliseconds)
If we settle on using lat,long,alt,heading,pitch,roll for camera pose then we have a single handler for camera, rather than the two at the moment.
In Cesium Master we'll use camera.positionCartographic['longitude'], etc.
Leave the Cesium camera.position.x,y,z code in there, just commented out?
I'm not sure what the camera.position.xyz values are more or less useful than lat,long,alt?
var server = app.listen(argv.port, argv.public ? undefined : NODE_SERVER_IP, function() {
console.log('Cesium development server running on '+server.address().address+':'+ server.address().port);
if (argv.public) {
console.log('Be aware this server is listening on all interfaces');
}
});
Want to be able to toggle this on the slaves from the master dat.ui...
viewer.scene.debugShowFramesPerSecond = true;
Hi, we can cache http:// requests but not https:// feeds, so check the data providers are using http:// URI's.
eg. http://dev.virtualearth.net rather than https://dev.virtualearth.net
Hi, with the 'Home' icon position can we set it to a lower altitude?
It's far far away from Earth!
On the Cesium Master add UI elements for toggling the state of some things we can use to test that slaves are following.
eg.
TerrainProviders - there's a selection see first Cesiumjs.org demo
Fog - viewer.fog.enabled = true/false
Lighting - viewer.scene.enableLighting = true/false
WaterMasks - flag for terrain loading
Terrain Shadowing -
I'll add more as I find or think of them.
Hi, the git history still contains all the Cesium source.
Making the repo 80Mb in size when it really should be 8Kb :)
Thanks.
We'll need map sync to work when Cesium is in 2D projection mode as well in 3D.
I think these are called SceneModes in Cesium.
I'm not sure why you need to check for greatest common divisor?
With 16:9 screen.width is still the horizontal and screen.height the vertical.
This worked...
function getAspectRatio() {
return screen.height / screen.width;
}
hmm... probably should be width / height, and then divide the HorizFov in the clients.
I think a more complex protobuf will be needed...
eg.
message CesiumSync {
required int32 msgtype =1;
optional CameraPose pose = 2;
optional State state = 3;
message CameraPose {
required sint32 lon;
... lat, alt, heading, pitch, roll all required
}
message State { // viewer state
optional boolean fog = 1;
optional boolean lighting = 2;
optional string ImageryProvider = 3; // "Bing.ROAD"
optional string TerrainProvider = 4; // "STK"
optional boolean showDebugFPS = 5;
...
}
}
this...
UDPserver.on('message', function (message, remote) {
var msgArray = String(message).split(',');
var lat = msgArray[1];
var lon = msgArray[2];
var alt = msgArray[3];
var hdg = msgArray[4]*Math.PI/180;
var pitch = (msgArray[5] - 90)*Math.PI/180;
var roll = msgArray[6]*Math.PI/180;
var wsMesg = '{"msg-type":"ge-cam", "lon":'+lon+',"lat":'+lat+',"ht":'+alt+',"heading":'+hdg+',"pitch":'+pitch+',"roll":'+roll+'}
';
for(var i in wsClients){
wsClients[i].send(wsMesg);
}
Hi, this seems to work for me when switching back to the using reconnectingws library...
var ws = new ReconnectingWebSocket(CONFIG.wsURI, null, { binaryType: 'arraybuffer' } );
// ws.binaryType = "arraybuffer";
Let's start with a simple state share for the Imagery choice from the master to slaves.
So if the Master switches to Roadmap the Slaves also switch.
From the master we also want to remotely 'reload' the slave clients, helps with debugging or when things go weird.
The master UI will need a 'reload slaves' button, and then send a message that makes the clients do "location.reload();"
Check line 135 you have ws.onMessage defined for no reason!
move the map API key into config.js
We should be clear about which field of view we are using here!
do this for slave and master.
If not, core at least part of server.js with a good demo app!
Minimal would be camera pose
Actually the 'server.js' will be more like 'bridge.js' :)
Master Cesium > [websocket] > node server.js > [udp broadcast] > slaves node server.js > [websocket] > Slave Cesium
This is becasue the camera pose updates are time critical, and sending them as TCP websocket in a loop one at a time is introducing jitter. We can eliminate that jitter by sending a SINGLE UDP broadcast from the Master which will be picked up by the slaves.
This is going to need to be on a different port to Google Earth.
Hi, going from 3D > 2D > 3D the yaw offset of the slaves appears to get messed up.
In server.js in the UDP GoogleEarth cam function, save 'msgToWSClients' and check that it is different from the last GE message. We don't need to transmit duplicate camera poses.
This will be a bit like the 'lastCamStr' in the Master.
server.js:
UDPserver.on('message', function(message, remote) {
var viewsync = String(message).split(',');
var s = new CesiumSync();
s.msgtype = 2;
s.lat = Math.round(parseFloat(viewsync[1]) * 10e5);
s.lon = Math.round(parseFloat(viewsync[2]) * 10e5);
s.alt = Math.round(parseFloat(viewsync[3]) * 100);
s.heading = Math.round(util.toRadians(parseFloat(viewsync[4])) * 10e4);
s.pitch = Math.round(util.toRadians((parseFloat(viewsync[5]) - 90)) * 10e4);
s.roll = Math.round(util.toRadians(parseFloat(viewsync[6])) * 10e3);
var thisSync = s.toBuffer();
if (thisSync != lastGESync) {
lastGESync = thisSync;
for (var i in wsClients) {
wsClients[i].send(thisSync);
}
// UDPclient.send(thisSync,0,thisSync.length,CONFIG.CesiumSyncPort,CONFIG.CesiumSyncHost);
}
});
cesiumsync.proto:
message CesiumSync {
required int32 msgtype = 1;
optional sint32 lon = 2;
optional sint32 lat = 3;
optional sint32 alt = 4;
optional sint32 heading = 5;
optional sint32 pitch = 6;
optional sint32 roll = 7;
optional bool lighting = 8;
}
updates to Slave-Client.html:
function handleGECam(camVals) {
var px = camVals.lon / 10e5,
py = camVals.lat / 10e5,
pz = camVals.alt / 100,
heading = camVals.heading / 10e4,
pitch = camVals.pitch / 10e4,
roll = camVals.roll / 10e3;
...
There is no reason to create the client message every iteration. It's the same message.
Do it once before the loop and then just send it to each client.
See code in the previous issue that was closed.
for(var i in wsClients){
//if(clients[i]!=connection)
var lat = msgArray[1];
var lon = msgArray[2];
var alt = msgArray[3];
var heading = msgArray[4]_Math.PI/180;
var pitch = (msgArray[5] - 90)_Math.PI/180;
var roll = msgArray[6]*Math.PI/180;
wsClients[i].send('{"msg-type":"ge-cam", "lon":'+lon+',"lat":'+lat+',"ht":'+alt+',"heading":'+heading+',"pitch":'+pitch+',"roll":'+roll+'}');
}
Space Nav camera control is critical for Liquid Galaxy.
There's some prior work here that can be incorporated into the Master.
Also I realise you don't have a SpaceNav to test this, so I'll work on this part a bit.
"clients[]" as a var name is too generic, use "wsClients[]" short for websocket clients.
To help with setup take the network settings into server.config file or allow command line options to override each.
NODE_SERVER_IP, NODE_SERVER_PORT, UDP_PORT, UDP_HOST;
I'm not using localhost, so I need to change this each time I pull your code.
To make the websocket messaging more efficient we need to move away from sending stringified JSON objects and only transmit the minimal information needed and in the most effective manner we can think of (given gsoc time!).
I suggest investigating google protobuf or javascript arraybuffers.
I'm not sure using the same config for both nodejs and browser js clients is working very well.
Need a better way of doing a shared config, or give up and have separate config.
The cesium client have this warning...
ReferenceError: module is not defined
common useful routines like fix360() and toRads() can be pulled into a separate js.
Change the echo server to act as a relay.
Most the camera sync messages there's no reason to send a packet BACK to the master, it just adds latency.
You can use a particular URI path like /relay/ for this
or have the master send a message like 'IAmMaster' to switch off echo for that client.
(low priority)
Take the Cesium Master camera pose and broadcast it as UDP in viewsync format.
Just camera pose to start with, don't worry about timers.
Will need config for network address to send on, also config for whether this is a unicast send or broadcast (i think).
Will need config for udp socket number
Hi, add GridImagery provider it's a nice low data imagery provider.
var GridImageryProvider = new Cesium.GridImageryProvider({cells:8, glowWidth:0});
Hi, no need to hide the configs in the js folder a new user shouldn't have to go digging.
Move *-config.js files up to root.
Thanks.
By default the slave doesn't need a geocoder UI.
The default Slave UI should be empty, just a cesium globe.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.