diff --git a/.travis.yml b/.travis.yml index 8adb1b96de6f..ec667489fa72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: sudo: false addons: chrome: stable + firefox: latest before_script: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start @@ -19,7 +20,7 @@ script: - echo 'test webgl-stub' && echo -en 'travis_fold:start:script.test\\r' - npm run build - - npm run test -- --browsers ChromeCI --webgl-stub --failTaskOnError --suppressPassed + - npm run test -- --browsers FirefoxHeadless --webgl-stub --failTaskOnError --suppressPassed - echo -en 'travis_fold:end:script.test\\r' - echo 'makeZipFile' && echo -en 'travis_fold:start:script.makeZipFile\\r' diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ll.b3dm b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ll.b3dm index 98b2b469bda1..df79fe32f39e 100644 Binary files a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ll.b3dm and b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ll.b3dm differ diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/lr.b3dm b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/lr.b3dm index ebb24758d31f..e273cb03a764 100644 Binary files a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/lr.b3dm and b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/lr.b3dm differ diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/parent.b3dm b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/parent.b3dm index 8f6c2012861e..8cb958955234 100644 Binary files a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/parent.b3dm and b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/parent.b3dm differ diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json index d7baf1670f0e..2874634d6112 100644 --- a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json +++ b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/tileset.json @@ -3,6 +3,9 @@ "version": "1.0", "tilesetVersion": "1.2.3" }, + "extras": { + "name": "Sample Tileset" + }, "properties": { "id": { "minimum": 0, @@ -79,6 +82,9 @@ "geometricError": 0, "content": { "uri": "lr.b3dm" + }, + "extras": { + "id": "Special Tile" } }, { diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ul.b3dm b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ul.b3dm index ecd600aba825..b7a4c162220c 100644 Binary files a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ul.b3dm and b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ul.b3dm differ diff --git a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ur.b3dm b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ur.b3dm index 7dd42a0fdf4b..9ae74c7b0534 100644 Binary files a/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ur.b3dm and b/Apps/SampleData/Cesium3DTiles/Tilesets/Tileset/ur.b3dm differ diff --git a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html index ac80ea828e44..a2d7a1c8a274 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html +++ b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html @@ -2,7 +2,7 @@ - + @@ -10,10 +10,12 @@ @@ -45,7 +47,6 @@ function startup(Cesium) { 'use strict'; //Sandcastle_Begin - // Add a clipping plane, a plane geometry to show the representation of the // plane, and control the magnitude of the plane distance with the mouse. @@ -66,6 +67,7 @@ var targetY = 0.0; var planeEntities = []; var selectedPlane; +var clippingPlanes; // Select plane when mouse down var downHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); @@ -112,16 +114,16 @@ var tileset; function loadTileset(url) { - var clippingPlanes = [ - new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) - ]; + clippingPlanes = new Cesium.ClippingPlaneCollection({ + planes : [ + new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) + ], + edgeWidth : viewModel.edgeStylingEnabled ? 1.0 : 0.0 + }); tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url : url, - clippingPlanes : new Cesium.ClippingPlaneCollection({ - planes : clippingPlanes, - edgeWidth : viewModel.edgeStylingEnabled ? 1.0 : 0.0 - }) + clippingPlanes : clippingPlanes })); tileset.debugShowBoundingVolume = viewModel.debugBoundingVolumesEnabled; @@ -132,7 +134,7 @@ viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0.5, -0.2, radius * 4.0)); for (var i = 0; i < clippingPlanes.length; ++i) { - var plane = clippingPlanes[i]; + var plane = clippingPlanes.get(i); var planeEntity = viewer.entities.add({ position : boundingSphere.center, plane : { @@ -152,21 +154,14 @@ }); } -var modelEntityClippingPlanes; function loadModel(url) { - var clippingPlanes = [ - new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) - ]; - - modelEntityClippingPlanes = new Cesium.ClippingPlaneCollection({ - planes : clippingPlanes, + clippingPlanes = new Cesium.ClippingPlaneCollection({ + planes : [ + new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -1.0), -100.0) + ], edgeWidth : viewModel.edgeStylingEnabled ? 1.0 : 0.0 }); - function updateClippingPlanes() { - return modelEntityClippingPlanes; - } - var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 100.0); var heading = Cesium.Math.toRadians(135.0); var pitch = 0.0; @@ -181,14 +176,14 @@ uri : url, scale : 8, minimumPixelSize : 100.0, - clippingPlanes : new Cesium.CallbackProperty(updateClippingPlanes, false) + clippingPlanes : clippingPlanes } }); viewer.trackedEntity = entity; for (var i = 0; i < clippingPlanes.length; ++i) { - var plane = clippingPlanes[i]; + var plane = clippingPlanes.get(i); var planeEntity = viewer.entities.add({ position : position, plane : { @@ -244,13 +239,7 @@ Cesium.knockout.getObservable(viewModel, 'edgeStylingEnabled').subscribe(function(value) { var edgeWidth = value ? 1.0 : 0.0; - if (Cesium.defined(tileset)) { - tileset.clippingPlanes.edgeWidth = edgeWidth; - } - - if (Cesium.defined(modelEntityClippingPlanes)) { - modelEntityClippingPlanes.edgeWidth = edgeWidth; - } + clippingPlanes.edgeWidth = edgeWidth; }); function reset() { @@ -262,7 +251,7 @@ } //Sandcastle_End -Sandcastle.finishedLoading(); + Sandcastle.finishedLoading(); } if (typeof Cesium !== 'undefined') { startup(Cesium); diff --git a/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html b/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html index 406ce45146c4..63d3e1177858 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html +++ b/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html @@ -28,7 +28,7 @@ 'use strict'; //Sandcastle_Begin // A demo of interactive 3D Tiles styling -// Styling language Documentation: https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling +// Styling language Documentation: https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling // Building data courtesy of NYC OpenData portal: http://www1.nyc.gov/site/doitt/initiatives/3d-building.page var viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() diff --git a/Apps/Sandcastle/gallery/3D Tiles Interactivity.html b/Apps/Sandcastle/gallery/3D Tiles Interactivity.html index 90277d6b5669..901dc56a001f 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Interactivity.html +++ b/Apps/Sandcastle/gallery/3D Tiles Interactivity.html @@ -145,7 +145,7 @@ } // Evaluate feature description - console.log('Description : ' + tileset.style.meta.description.evaluate(scene.frameState, feature)); + console.log('Description : ' + tileset.style.meta.description.evaluate(feature)); } function zoom(movement, feature) { diff --git a/Apps/Sandcastle/gallery/3D Tiles Photogrammetry Classification.html b/Apps/Sandcastle/gallery/3D Tiles Photogrammetry Classification.html index 1d0e6f276c60..71091168a3b1 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Photogrammetry Classification.html +++ b/Apps/Sandcastle/gallery/3D Tiles Photogrammetry Classification.html @@ -34,7 +34,7 @@ // A normal b3dm tileset of photogrammetry var tileset = new Cesium.Cesium3DTileset({ - url: Cesium.IonResource.fromAssetId(5712) + url: Cesium.IonResource.fromAssetId(6074) }); viewer.scene.primitives.add(tileset); viewer.zoomTo(tileset); diff --git a/Apps/Sandcastle/gallery/3D Tiles Photogrammetry.html b/Apps/Sandcastle/gallery/3D Tiles Photogrammetry.html index 21c34c89d36f..655dfa67f97f 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Photogrammetry.html +++ b/Apps/Sandcastle/gallery/3D Tiles Photogrammetry.html @@ -31,7 +31,7 @@ }); var tileset = new Cesium.Cesium3DTileset({ - url: Cesium.IonResource.fromAssetId(5712) + url: Cesium.IonResource.fromAssetId(6074) }); viewer.scene.primitives.add(tileset); diff --git a/Apps/Sandcastle/gallery/Cardboard.html b/Apps/Sandcastle/gallery/Cardboard.html index 67606e73c971..1523ee468e23 100644 --- a/Apps/Sandcastle/gallery/Cardboard.html +++ b/Apps/Sandcastle/gallery/Cardboard.html @@ -59,7 +59,7 @@ var radians = Cesium.Math.toRadians(i); var timeIncrement = i - startAngle; var time = Cesium.JulianDate.addSeconds(start, timeIncrement, new Cesium.JulianDate()); - var position = Cesium.Cartesian3.fromDegrees(lon + (radius * 1.5 * Math.cos(radians)), lat + (radius * Math.sin(radians)), Cesium.Math.nextRandomNumber() * 500 + 1750); + var position = Cesium.Cartesian3.fromDegrees(lon + (radius * 1.5 * Math.cos(radians)), lat + (radius * Math.sin(radians)), Cesium.Math.nextRandomNumber() * 500 + 1800); property.addSample(time, position); } return property; diff --git a/Apps/Sandcastle/gallery/Classification Types.html b/Apps/Sandcastle/gallery/Classification Types.html index cdc9551797aa..a874c9a8a687 100644 --- a/Apps/Sandcastle/gallery/Classification Types.html +++ b/Apps/Sandcastle/gallery/Classification Types.html @@ -32,7 +32,7 @@ }); viewer.scene.globe.depthTestAgainstTerrain = false; -var tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(5712) }); +var tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(6074) }); viewer.scene.primitives.add(tileset); tileset.readyPromise.then(function(){ diff --git a/Apps/Sandcastle/gallery/Classification.html b/Apps/Sandcastle/gallery/Classification.html index d2cac1b6a4ea..d92986a1c0e5 100644 --- a/Apps/Sandcastle/gallery/Classification.html +++ b/Apps/Sandcastle/gallery/Classification.html @@ -198,7 +198,7 @@ scene.invertClassificationColor.alpha = parseFloat(value); } -var tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(5712) }); +var tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(6074) }); scene.primitives.add(tileset); var viewModel = { diff --git a/Apps/Sandcastle/gallery/Geometry Height Reference.html b/Apps/Sandcastle/gallery/Geometry Height Reference.html index d3202f476d38..76b33542fcf2 100644 --- a/Apps/Sandcastle/gallery/Geometry Height Reference.html +++ b/Apps/Sandcastle/gallery/Geometry Height Reference.html @@ -4,7 +4,7 @@ - + Cesium Demo @@ -41,6 +41,20 @@ // instead of showing through it from underground viewer.scene.globe.depthTestAgainstTerrain = true; +Sandcastle.addToolbarMenu([{ + text : 'Polygons', + onselect : function() { + viewer.entities.removeAll(); + addPolygons(); + } +}, { + text : 'Boxes, Cylinders and Ellipsoids', + onselect : function() { + viewer.entities.removeAll(); + addGeometries(); + } +}]); + Sandcastle.addToolbarMenu([{ text : 'Terrain Enabled', onselect : function() { @@ -53,11 +67,57 @@ } }]); -var longitude = 6.850615989890521; -var latitude = 45.89546589994886; +var longitude = 6.950615989890521; +var latitude = 45.79546589994886; var delta = 0.001; -function addEntity(i, j) { +function addGeometry(i, j) { + var west = longitude + delta * i; + var north = latitude + delta * j + delta; + + var type = Math.floor(Math.random() * 3); + if (type === 0) { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + box : { + dimensions : new Cesium.Cartesian3(40.0, 30.0, 50.0), + material : Cesium.Color.fromRandom({alpha : 1.0}), + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } else if (type === 1) { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + cylinder : { + length :50.0, + topRadius : 20.0, + bottomRadius : 20.0, + material : Cesium.Color.fromRandom({alpha : 1.0}), + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } else { + viewer.entities.add({ + position: Cesium.Cartesian3.fromDegrees(west, north, 0.0), + ellipsoid : { + radii : new Cesium.Cartesian3(20.0, 15.0, 25.0), + material : Cesium.Color.fromRandom({alpha : 1.0}), + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND + } + }); + } +} + +function addGeometries(){ + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + addGeometry(i, j); + } + } + viewer.zoomTo(viewer.entities); +} + +function addPolygon(i, j) { var west = longitude + delta * i; var east = longitude + delta * i + delta; @@ -81,15 +141,17 @@ }); } -// create 16 polygons that are side-by-side -for (var i = 0; i < 4; i++) { - for (var j = 0; j < 4; j++) { - addEntity(i, j); +function addPolygons() { + // create 16 polygons that are side-by-side + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { + addPolygon(i, j); + } } + viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(longitude, latitude, 1500), new Cesium.HeadingPitchRange(-Cesium.Math.PI/2, -Cesium.Math.PI_OVER_FOUR, 2000)); + viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); } - -viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(longitude, latitude, 500), new Cesium.HeadingPitchRange(Cesium.Math.PI, -Cesium.Math.PI_OVER_FOUR, 2000)); -viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);//Sandcastle_End +//Sandcastle_End Sandcastle.finishedLoading(); } if (typeof Cesium !== 'undefined') { diff --git a/Apps/Sandcastle/gallery/Materials.html b/Apps/Sandcastle/gallery/Materials.html index 105bc9c7dd4d..b19aacc0068f 100644 --- a/Apps/Sandcastle/gallery/Materials.html +++ b/Apps/Sandcastle/gallery/Materials.html @@ -176,7 +176,7 @@ type : 'Water', uniforms : { specularMap: '../images/earthspec1k.jpg', - normalMap: require.toUrl('Assets/Textures/waterNormals.jpg'), + normalMap: Cesium.buildModuleUrl('Assets/Textures/waterNormals.jpg'), frequency: 10000.0, animationSpeed: 0.01, amplitude: 1.0 diff --git a/Apps/Sandcastle/gallery/Plane.jpg b/Apps/Sandcastle/gallery/Plane.jpg index 4fcb0355e641..ef4197ef5a5e 100644 Binary files a/Apps/Sandcastle/gallery/Plane.jpg and b/Apps/Sandcastle/gallery/Plane.jpg differ diff --git a/Apps/Sandcastle/gallery/Scene Rendering Performance.html b/Apps/Sandcastle/gallery/Scene Rendering Performance.html index 2fe9f269456f..e0191886bc46 100644 --- a/Apps/Sandcastle/gallery/Scene Rendering Performance.html +++ b/Apps/Sandcastle/gallery/Scene Rendering Performance.html @@ -147,7 +147,7 @@

Max delta time

function loadTilesetScenario() { resetScene(); - tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(5712) }); + tileset = new Cesium.Cesium3DTileset({ url: Cesium.IonResource.fromAssetId(6074) }); viewer.scene.primitives.add(tileset); viewer.zoomTo(tileset); } diff --git a/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.html b/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.html new file mode 100644 index 000000000000..a14220d8a2c8 --- /dev/null +++ b/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.html @@ -0,0 +1,209 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.jpg b/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.jpg new file mode 100644 index 000000000000..e510b2284a66 Binary files /dev/null and b/Apps/Sandcastle/gallery/development/Geometry Offset Attribute box cylinder ellipsoid.jpg differ diff --git a/Apps/Sandcastle/gallery/development/Ground Primitive Materials.html b/Apps/Sandcastle/gallery/development/Ground Primitive Materials.html index 0b6ba374679c..e45e3c891bbe 100644 --- a/Apps/Sandcastle/gallery/development/Ground Primitive Materials.html +++ b/Apps/Sandcastle/gallery/development/Ground Primitive Materials.html @@ -190,7 +190,7 @@ type : 'Water', uniforms : { specularMap: '../images/earthspec1k.jpg', - normalMap: require.toUrl('Assets/Textures/waterNormals.jpg'), + normalMap: Cesium.buildModuleUrl('Assets/Textures/waterNormals.jpg'), frequency: 10000.0, animationSpeed: 0.01, amplitude: 1.0 diff --git a/Apps/Sandcastle/gallery/development/Many Clipping Planes.html b/Apps/Sandcastle/gallery/development/Many Clipping Planes.html index 0aee98bb3275..46cb523a11e2 100644 --- a/Apps/Sandcastle/gallery/development/Many Clipping Planes.html +++ b/Apps/Sandcastle/gallery/development/Many Clipping Planes.html @@ -152,7 +152,7 @@ } var modelUrl = '../../SampleData/models/CesiumAir/Cesium_Air.glb'; -var agiHqUrl = Cesium.IonResource.fromAssetId(5712); +var agiHqUrl = Cesium.IonResource.fromAssetId(6074); var instancedUrl = '../../SampleData/Cesium3DTiles/Instanced/InstancedOrientation/tileset.json'; var pointCloudUrl = Cesium.IonResource.fromAssetId(5713); diff --git a/CHANGES.md b/CHANGES.md index 4fe6de43324d..d1fb853b1431 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,56 @@ Change Log ========== +### 1.49 - 2018-09-04 + +##### Breaking Changes :mega: +* Removed `ClippingPlaneCollection.clone`. [#6872](https://github.com/AnalyticalGraphicsInc/cesium/pull/6872) +* Changed `Globe.pick` to return a position in ECEF coordinates regardless of the current scene mode. This will only effect you if you were working around a bug to make `Globe.pick` work in 2D and Columbus View. Use `Globe.pickWorldCoordinates` to get the position in world coordinates that correlate to the current scene mode. [#6859](https://github.com/AnalyticalGraphicsInc/cesium/pull/6859) +* Removed the unused `frameState` parameter in `evaluate` and `evaluateColor` functions in `Expression`, `StyleExpression`, `ConditionsExpression` and all other places that call the functions. [#6890](https://github.com/AnalyticalGraphicsInc/cesium/pull/6890) +* Removed `PostProcessStageLibrary.createLensFlarStage`. Use `PostProcessStageLibrary.createLensFlareStage` instead. [#6972](https://github.com/AnalyticalGraphicsInc/cesium/pull/6972) +* Removed `Scene.fxaa`. Use `Scene.postProcessStages.fxaa.enabled` instead. [#6980](https://github.com/AnalyticalGraphicsInc/cesium/pull/6980) + +##### Additions :tada: +* Added `heightReference` to `BoxGraphics`, `CylinderGraphics` and `EllipsoidGraphics`, which can be used to clamp these entity types to terrain. [#6932](https://github.com/AnalyticalGraphicsInc/cesium/pull/6932) +* Added `GeocoderViewModel.destinationFound` for specifying a function that is called upon a successful geocode. The default behavior is to fly to the destination found by the geocoder. [#6915](https://github.com/AnalyticalGraphicsInc/cesium/pull/6915 +* Added `ClippingPlaneCollection.planeAdded` and `ClippingPlaneCollection.planeRemoved` events. `planeAdded` is raised when a new plane is added to the collection and `planeRemoved` is raised when a plane is removed. [#6875](https://github.com/AnalyticalGraphicsInc/cesium/pull/6875) +* Added `Matrix4.setScale` for setting the scale on an affine transformation matrix [#6888](https://github.com/AnalyticalGraphicsInc/cesium/pull/6888) +) +* Added optional `width` and `height` to `Scene.drillPick` for specifying a search area. [#6922](https://github.com/AnalyticalGraphicsInc/cesium/pull/6922) +* Added `Cesium3DTileset.root` for getting the root tile of a tileset. [#6944](https://github.com/AnalyticalGraphicsInc/cesium/pull/6944) +* Added `Cesium3DTileset.extras` and `Cesium3DTile.extras` for getting application specific metadata from 3D Tiles. [#6974](https://github.com/AnalyticalGraphicsInc/cesium/pull/6974) + +##### Fixes :wrench: +* Several performance improvements and fixes to the 3D Tiles traversal code. [#6390](https://github.com/AnalyticalGraphicsInc/cesium/pull/6390) + * Improved load performance when `skipLevelOfDetail` is false. + * Fixed a bug that caused some skipped tiles to load when `skipLevelOfDetail` is true. + * Fixed pick statistics in the 3D Tiles Inspector. + * Fixed drawing of debug labels for external tilesets. + * Fixed drawing of debug outlines for empty tiles. +* The Geocoder widget now takes terrain altitude into account when calculating its final destination. [#6876](https://github.com/AnalyticalGraphicsInc/cesium/pull/6876) +* The Viewer widget now takes terrain altitude into account when zooming or flying to imagery layers. [#6895](https://github.com/AnalyticalGraphicsInc/cesium/pull/6895) +* Fixed Firefox camera control issues with mouse and touch events. [#6372](https://github.com/AnalyticalGraphicsInc/cesium/issues/6372) +* Fixed `getPickRay` in 2D. [#2480](https://github.com/AnalyticalGraphicsInc/cesium/issues/2480) +* Fixed `Globe.pick` for 2D and Columbus View. [#6859](https://github.com/AnalyticalGraphicsInc/cesium/pull/6859) +* Fixed imagery layer feature picking in 2D and Columbus view. [#6859](https://github.com/AnalyticalGraphicsInc/cesium/pull/6859) +* Fixed intermittent ground clamping issues for all entity types that use a height reference. [#6930](https://github.com/AnalyticalGraphicsInc/cesium/pull/6930) +* Fixed bug that caused a new `ClippingPlaneCollection` to be created every frame when used with a model entity. [#6872](https://github.com/AnalyticalGraphicsInc/cesium/pull/6872) +* Improved `Plane` entities so they are better aligned with the globe surface. [#6887](https://github.com/AnalyticalGraphicsInc/cesium/pull/6887) +* Fixed crash when rendering translucent objects when all shadow maps in the scene set `fromLightSource` to false. [#6883](https://github.com/AnalyticalGraphicsInc/cesium/pull/6883) +* Fixed night shading in 2D and Columbus view. [#4122](https://github.com/AnalyticalGraphicsInc/cesium/issues/4122) +* Fixed model loading failure when a glTF 2.0 primitive does not have a material. [6906](https://github.com/AnalyticalGraphicsInc/cesium/pull/6906) +* Fixed a crash when setting show to `false` on a polyline clamped to the ground. [#6912](https://github.com/AnalyticalGraphicsInc/cesium/issues/6912) +* Fixed a bug where `Cesium3DTileset` wasn't using the correct `tilesetVersion`. [#6933](https://github.com/AnalyticalGraphicsInc/cesium/pull/6933) +* Fixed crash that happened when calling `scene.pick` after setting a new terrain provider. [#6918](https://github.com/AnalyticalGraphicsInc/cesium/pull/6918) +* Fixed an issue that caused the browser to hang when using `drillPick` on a polyline clamped to the ground. [6907](https://github.com/AnalyticalGraphicsInc/cesium/issues/6907) +* Fixed an issue where color wasn't updated properly for polylines clamped to ground. [#6927](https://github.com/AnalyticalGraphicsInc/cesium/pull/6927) +* Fixed an excessive memory use bug that occurred when a data URI was used to specify a glTF model. [#6928](https://github.com/AnalyticalGraphicsInc/cesium/issues/6928) +* Fixed an issue where switching from 2D to 3D could cause a crash. [#6929](https://github.com/AnalyticalGraphicsInc/cesium/issues/6929) +* Fixed an issue where point primitives behind the camera would appear in view. [#6904](https://github.com/AnalyticalGraphicsInc/cesium/issues/6904) +* The `createGroundPolylineGeometry` web worker no longer depends on `GroundPolylinePrimitive`, making the worker smaller and potentially avoiding a hanging build in some webpack configurations. [#6946](https://github.com/AnalyticalGraphicsInc/cesium/pull/6946) +* Fixed an issue that cause terrain entities (entities with unspecified `height`) and `GroundPrimitives` to fail when crossing the international date line. [#6951](https://github.com/AnalyticalGraphicsInc/cesium/issues/6951) +* Fixed normal calculation for `CylinderGeometry` when the top radius is not equal to the bottom radius [#6863](https://github.com/AnalyticalGraphicsInc/cesium/pull/6863) + ### 1.48 - 2018-08-01 ##### Additions :tada: @@ -13,10 +63,10 @@ Change Log ##### Deprecated :hourglass_flowing_sand: * Support for 3D Tiles `content.url` is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use `content.uri instead`. Support for `content.url` will remain for backwards compatibility. [#6744](https://github.com/AnalyticalGraphicsInc/cesium/pull/6744) -* Support for the 3D Tiles pre-version 1.0 Batch Table Hierarchy is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use the [`3DTILES_batch_table_hierarchy`](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/1.0/extensions/3DTILES_batch_table_hierarchy) extension instead. Support for the deprecated batch table hierarchy will remain for backwards compatibility. [#6780](https://github.com/AnalyticalGraphicsInc/cesium/pull/6780) +* Support for the 3D Tiles pre-version 1.0 Batch Table Hierarchy is deprecated to reflect updates to the [3D Tiles spec](https://github.com/AnalyticalGraphicsInc/3d-tiles/pull/301). Use the [`3DTILES_batch_table_hierarchy`](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy) extension instead. Support for the deprecated batch table hierarchy will remain for backwards compatibility. [#6780](https://github.com/AnalyticalGraphicsInc/cesium/pull/6780) * `PostProcessStageLibrary.createLensFlarStage` is deprecated due to misspelling and will be removed in Cesium 1.49. Use `PostProcessStageLibrary.createLensFlareStage` instead. -#### Fixes :wrench: +##### Fixes :wrench: * Fixed a bug where 3D Tilesets using the `region` bounding volume don't get transformed when the tileset's `modelMatrix` changes. [#6755](https://github.com/AnalyticalGraphicsInc/cesium/pull/6755) * Fixed a bug that caused eye dome lighting for point clouds to fail in Safari on macOS and Edge on Windows by removing the dependency on floating point color textures. [#6792](https://github.com/AnalyticalGraphicsInc/cesium/issues/6792) * Fixed a bug that caused polylines on terrain to render incorrectly in 2D and Columbus View with a `WebMercatorProjection`. [#6809](https://github.com/AnalyticalGraphicsInc/cesium/issues/6809) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9a84f5ec1ec8..37aec21b64e0 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -49,6 +49,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Josh Lawrence](https://github.com/loshjawrence) * [Omar Shehata](https://github.com/OmarShehata) * [Matt Petry](https://github.com/MattPetry) + * [Michael Squires](https://github.com/mksquires) * [NICTA](http://www.nicta.com.au/) * [Chris Cooper](https://github.com/chris-cooper) * [Kevin Ring](https://github.com/kring) @@ -186,3 +187,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu * [Jonathan Puckey](https://github.com/puckey) * [Mark Erikson](https://github.com/markerikson) * [Hannah Bollar](https://github.com/hanbollar) +* [Felix Palmer](https://github.com/felixpalmer) diff --git a/Documentation/Contributors/PresentersGuide/README.md b/Documentation/Contributors/PresentersGuide/README.md index 3023540f1cd3..7ca86031dbe3 100644 --- a/Documentation/Contributors/PresentersGuide/README.md +++ b/Documentation/Contributors/PresentersGuide/README.md @@ -45,7 +45,7 @@ Focus less on details, and instead **focus on providing context**, especially at Your audience loves stories. Tell one. -Early in a presentation, **a story will help build context**. For example, see Slides 2-6 of [3D Tiles](http://cesiumjs.org/presentations/SIGGRAPH2015/Cesium3DTiles.pdf). +Early in a presentation, **a story will help build context**. For example, see Slides 2-6 of [3D Tiles](https://cesium.com/presentations/files/SIGGRAPH2015/Cesium3DTiles.pdf). Stories will help you connect with your audience. It will make them more likely to [engage you](#engage-the-audience). And it will make them more likely to remember your talk later. diff --git a/Source/Core/ApproximateTerrainHeights.js b/Source/Core/ApproximateTerrainHeights.js index 2f20a806afa3..39fabe916bab 100644 --- a/Source/Core/ApproximateTerrainHeights.js +++ b/Source/Core/ApproximateTerrainHeights.js @@ -2,6 +2,7 @@ define([ './buildModuleUrl', './defaultValue', './defined', + './defineProperties', './BoundingSphere', './Cartesian2', './Cartesian3', @@ -16,6 +17,7 @@ define([ buildModuleUrl, defaultValue, defined, + defineProperties, BoundingSphere, Cartesian2, Cartesian3, @@ -199,5 +201,20 @@ define([ ApproximateTerrainHeights._terrainHeights = undefined; ApproximateTerrainHeights._initPromise = undefined; + defineProperties(ApproximateTerrainHeights, { + /** + * Determines if the terrain heights are initialized and ready to use. To initialize the terrain heights, + * call {@link ApproximateTerrainHeights#initialize} and wait for the returned promise to resolve. + * @type {Boolean} + * @readonly + * @memberof ApproximateTerrainHeights + */ + initialized: { + get: function() { + return defined(ApproximateTerrainHeights._terrainHeights); + } + } + }); + return ApproximateTerrainHeights; }); diff --git a/Source/Core/BoxGeometry.js b/Source/Core/BoxGeometry.js index 801531017474..13f9eb5b1da2 100644 --- a/Source/Core/BoxGeometry.js +++ b/Source/Core/BoxGeometry.js @@ -1,25 +1,31 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian3', './Check', './ComponentDatatype', './defaultValue', './defined', + './DeveloperError', './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './PrimitiveType', './VertexFormat' ], function( + arrayFill, BoundingSphere, Cartesian3, Check, ComponentDatatype, defaultValue, defined, + DeveloperError, Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, PrimitiveType, VertexFormat) { 'use strict'; @@ -60,6 +66,9 @@ define([ //>>includeStart('debug', pragmas.debug); Check.typeOf.object('min', min); Check.typeOf.object('max', max); + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); var vertexFormat = defaultValue(options.vertexFormat, VertexFormat.DEFAULT); @@ -67,6 +76,7 @@ define([ this._minimum = Cartesian3.clone(min); this._maximum = Cartesian3.clone(max); this._vertexFormat = vertexFormat; + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createBoxGeometry'; } @@ -106,7 +116,8 @@ define([ return new BoxGeometry({ minimum : Cartesian3.negate(corner, new Cartesian3()), maximum : corner, - vertexFormat : options.vertexFormat + vertexFormat : options.vertexFormat, + offsetAttribute: options.offsetAttribute }); }; @@ -145,7 +156,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - BoxGeometry.packedLength = 2 * Cartesian3.packedLength + VertexFormat.packedLength; + BoxGeometry.packedLength = 2 * Cartesian3.packedLength + VertexFormat.packedLength + 1; /** * Stores the provided instance into the provided array. @@ -167,6 +178,7 @@ define([ Cartesian3.pack(value._minimum, array, startingIndex); Cartesian3.pack(value._maximum, array, startingIndex + Cartesian3.packedLength); VertexFormat.pack(value._vertexFormat, array, startingIndex + 2 * Cartesian3.packedLength); + array[startingIndex + 2 * Cartesian3.packedLength + VertexFormat.packedLength] = defaultValue(value._offsetAttribute, -1); return array; }; @@ -177,7 +189,8 @@ define([ var scratchOptions = { minimum: scratchMin, maximum: scratchMax, - vertexFormat: scratchVertexFormat + vertexFormat: scratchVertexFormat, + offsetAttribute : undefined }; /** @@ -198,14 +211,17 @@ define([ var min = Cartesian3.unpack(array, startingIndex, scratchMin); var max = Cartesian3.unpack(array, startingIndex + Cartesian3.packedLength, scratchMax); var vertexFormat = VertexFormat.unpack(array, startingIndex + 2 * Cartesian3.packedLength, scratchVertexFormat); + var offsetAttribute = array[startingIndex + 2 * Cartesian3.packedLength + VertexFormat.packedLength]; if (!defined(result)) { + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new BoxGeometry(scratchOptions); } result._minimum = Cartesian3.clone(min, result._minimum); result._maximum = Cartesian3.clone(max, result._maximum); result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat); + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -818,11 +834,24 @@ define([ var diff = Cartesian3.subtract(max, min, diffScratch); var radius = Cartesian3.magnitude(diff) * 0.5; + if (defined(boxGeometry._offsetAttribute)) { + var length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = boxGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + return new Geometry({ attributes : attributes, indices : indices, primitiveType : PrimitiveType.TRIANGLES, - boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius) + boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius), + offsetAttribute : boxGeometry._offsetAttribute }); }; diff --git a/Source/Core/BoxOutlineGeometry.js b/Source/Core/BoxOutlineGeometry.js index c44aee0630a2..c5d568754f2a 100644 --- a/Source/Core/BoxOutlineGeometry.js +++ b/Source/Core/BoxOutlineGeometry.js @@ -1,24 +1,30 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian3', './Check', './ComponentDatatype', './defaultValue', './defined', + './DeveloperError', './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './PrimitiveType' ], function( + arrayFill, BoundingSphere, Cartesian3, Check, ComponentDatatype, defaultValue, defined, + DeveloperError, Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, PrimitiveType) { 'use strict'; @@ -54,10 +60,14 @@ define([ //>>includeStart('debug', pragmas.debug); Check.typeOf.object('min', min); Check.typeOf.object('max', max); + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); this._min = Cartesian3.clone(min); this._max = Cartesian3.clone(max); + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createBoxOutlineGeometry'; } @@ -94,7 +104,8 @@ define([ return new BoxOutlineGeometry({ minimum : Cartesian3.negate(corner, new Cartesian3()), - maximum : corner + maximum : corner, + offsetAttribute: options.offsetAttribute }); }; @@ -133,7 +144,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - BoxOutlineGeometry.packedLength = 2 * Cartesian3.packedLength; + BoxOutlineGeometry.packedLength = 2 * Cartesian3.packedLength + 1; /** * Stores the provided instance into the provided array. @@ -154,6 +165,8 @@ define([ Cartesian3.pack(value._min, array, startingIndex); Cartesian3.pack(value._max, array, startingIndex + Cartesian3.packedLength); + array[startingIndex + (Cartesian3.packedLength * 2)] = defaultValue(value._offsetAttribute, -1); + return array; }; @@ -161,7 +174,8 @@ define([ var scratchMax = new Cartesian3(); var scratchOptions = { minimum : scratchMin, - maximum : scratchMax + maximum : scratchMax, + offsetAttribute : undefined }; /** @@ -181,13 +195,16 @@ define([ var min = Cartesian3.unpack(array, startingIndex, scratchMin); var max = Cartesian3.unpack(array, startingIndex + Cartesian3.packedLength, scratchMax); + var offsetAttribute = array[startingIndex + Cartesian3.packedLength * 2]; if (!defined(result)) { + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new BoxOutlineGeometry(scratchOptions); } result._min = Cartesian3.clone(min, result._min); result._max = Cartesian3.clone(max, result._max); + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -277,11 +294,24 @@ define([ var diff = Cartesian3.subtract(max, min, diffScratch); var radius = Cartesian3.magnitude(diff) * 0.5; + if (defined(boxGeometry._offsetAttribute)) { + var length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = boxGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + return new Geometry({ attributes : attributes, indices : indices, primitiveType : PrimitiveType.LINES, - boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius) + boundingSphere : new BoundingSphere(Cartesian3.ZERO, radius), + offsetAttribute : boxGeometry._offsetAttribute }); }; diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js index 6418e649a3c9..adaeae231362 100644 --- a/Source/Core/CesiumTerrainProvider.js +++ b/Source/Core/CesiumTerrainProvider.js @@ -61,8 +61,7 @@ define([ /** * A {@link TerrainProvider} that accesses terrain data in a Cesium terrain format. - * The format is described on the - * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Cesium-Terrain-Server|Cesium wiki}. + * The supported formats are described on the {@link https://cesiumjs.org/data-and-assets/terrain/formats/|Terrain Formats page}. * * @alias CesiumTerrainProvider * @constructor @@ -81,7 +80,7 @@ define([ * terrainProvider : new Cesium.CesiumTerrainProvider({ * url : Cesium.IonResource.fromAssetId(3956), * requestVertexNormals : true - * }); + * }) * }); * * @see createWorldTerrain @@ -157,11 +156,11 @@ define([ var uri = new Uri(metadataResource.url); if (uri.authority === 'assets.agi.com') { - var deprecationText = 'The STK World Terrain tileset is deprecated and will be available until September 1, 2018.'; - var deprecationLinkText = 'Check out the new high-resolution Cesium World Terrain'; + var deprecationText = 'The STK World Terrain tileset is end-of-life and will shut down on October 1, 2018.'; + var deprecationLinkText = 'Check out the new high-resolution Cesium World Terrain for migration instructions.'; var deprecationLink = 'https://cesium.com/blog/2018/03/01/introducing-cesium-world-terrain/'; that._tileCredits = [ - new Credit('' + deprecationText + ' ' + deprecationLinkText + '', true) + new Credit('' + deprecationText + ' ' + deprecationLinkText + '', true) ]; deprecationWarning('assets.agi.com', deprecationText + ' ' + deprecationLinkText + ' ' + deprecationLink); } else { @@ -320,12 +319,14 @@ define([ } } - var layerJsonCredit = new Credit(attribution); + if (attribution.length > 0) { + var layerJsonCredit = new Credit(attribution); - if (defined(that._tileCredits)) { - that._tileCredits.push(layerJsonCredit); - } else { - that._tileCredits = [layerJsonCredit]; + if (defined(that._tileCredits)) { + that._tileCredits.push(layerJsonCredit); + } else { + that._tileCredits = [layerJsonCredit]; + } } that._ready = true; diff --git a/Source/Core/CylinderGeometry.js b/Source/Core/CylinderGeometry.js index 99f8d5a11f8d..ba4a4eb0bbb4 100644 --- a/Source/Core/CylinderGeometry.js +++ b/Source/Core/CylinderGeometry.js @@ -1,4 +1,5 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian2', './Cartesian3', @@ -10,11 +11,13 @@ define([ './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './IndexDatatype', './Math', './PrimitiveType', './VertexFormat' ], function( + arrayFill, BoundingSphere, Cartesian2, Cartesian3, @@ -26,6 +29,7 @@ define([ Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, IndexDatatype, CesiumMath, PrimitiveType, @@ -86,6 +90,9 @@ define([ if (slices < 3) { throw new DeveloperError('options.slices must be greater than or equal to 3.'); } + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); this._length = length; @@ -93,6 +100,7 @@ define([ this._bottomRadius = bottomRadius; this._vertexFormat = VertexFormat.clone(vertexFormat); this._slices = slices; + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createCylinderGeometry'; } @@ -100,7 +108,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - CylinderGeometry.packedLength = VertexFormat.packedLength + 4; + CylinderGeometry.packedLength = VertexFormat.packedLength + 5; /** * Stores the provided instance into the provided array. @@ -129,7 +137,8 @@ define([ array[startingIndex++] = value._length; array[startingIndex++] = value._topRadius; array[startingIndex++] = value._bottomRadius; - array[startingIndex] = value._slices; + array[startingIndex++] = value._slices; + array[startingIndex] = defaultValue(value._offsetAttribute, -1); return array; }; @@ -140,7 +149,8 @@ define([ length : undefined, topRadius : undefined, bottomRadius : undefined, - slices : undefined + slices : undefined, + offsetAttribute : undefined }; /** @@ -166,13 +176,15 @@ define([ var length = array[startingIndex++]; var topRadius = array[startingIndex++]; var bottomRadius = array[startingIndex++]; - var slices = array[startingIndex]; + var slices = array[startingIndex++]; + var offsetAttribute = array[startingIndex]; if (!defined(result)) { scratchOptions.length = length; scratchOptions.topRadius = topRadius; scratchOptions.bottomRadius = bottomRadius; scratchOptions.slices = slices; + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new CylinderGeometry(scratchOptions); } @@ -181,6 +193,7 @@ define([ result._topRadius = topRadius; result._bottomRadius = bottomRadius; result._slices = slices; + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -223,15 +236,17 @@ define([ var tangentIndex = 0; var bitangentIndex = 0; + var theta = Math.atan2(bottomRadius - topRadius, length); var normal = normalScratch; - normal.z = 0; + normal.z = Math.sin(theta); + var normalScale = Math.cos(theta); var tangent = tangentScratch; var bitangent = bitangentScratch; for (i = 0; i < slices; i++) { var angle = i / slices * CesiumMath.TWO_PI; - var x = Math.cos(angle); - var y = Math.sin(angle); + var x = normalScale * Math.cos(angle); + var y = normalScale * Math.sin(angle); if (computeNormal) { normal.x = x; normal.y = y; @@ -241,12 +256,12 @@ define([ } if (vertexFormat.normal) { - normals[normalIndex++] = x; - normals[normalIndex++] = y; - normals[normalIndex++] = 0; - normals[normalIndex++] = x; - normals[normalIndex++] = y; - normals[normalIndex++] = 0; + normals[normalIndex++] = normal.x; + normals[normalIndex++] = normal.y; + normals[normalIndex++] = normal.z; + normals[normalIndex++] = normal.x; + normals[normalIndex++] = normal.y; + normals[normalIndex++] = normal.z; } if (vertexFormat.tangent) { @@ -398,11 +413,24 @@ define([ var boundingSphere = new BoundingSphere(Cartesian3.ZERO, Cartesian2.magnitude(radiusScratch)); + if (defined(cylinderGeometry._offsetAttribute)) { + length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = cylinderGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + return new Geometry({ attributes : attributes, indices : indices, primitiveType : PrimitiveType.TRIANGLES, - boundingSphere : boundingSphere + boundingSphere : boundingSphere, + offsetAttribute : cylinderGeometry._offsetAttribute }); }; diff --git a/Source/Core/CylinderOutlineGeometry.js b/Source/Core/CylinderOutlineGeometry.js index 5722e1bbdd90..cfcb92dbc679 100644 --- a/Source/Core/CylinderOutlineGeometry.js +++ b/Source/Core/CylinderOutlineGeometry.js @@ -1,5 +1,6 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian2', './Cartesian3', @@ -8,12 +9,15 @@ define([ './CylinderGeometryLibrary', './defaultValue', './defined', + './DeveloperError', './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './IndexDatatype', './PrimitiveType' ], function( + arrayFill, BoundingSphere, Cartesian2, Cartesian3, @@ -22,9 +26,11 @@ define([ CylinderGeometryLibrary, defaultValue, defined, + DeveloperError, Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, IndexDatatype, PrimitiveType) { 'use strict'; @@ -75,6 +81,9 @@ define([ Check.typeOf.number('options.topRadius', topRadius); Check.typeOf.number('options.bottomRadius', bottomRadius); Check.typeOf.number.greaterThanOrEquals('options.slices', slices, 3); + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); this._length = length; @@ -82,6 +91,7 @@ define([ this._bottomRadius = bottomRadius; this._slices = slices; this._numberOfVerticalLines = numberOfVerticalLines; + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createCylinderOutlineGeometry'; } @@ -89,7 +99,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - CylinderOutlineGeometry.packedLength = 5; + CylinderOutlineGeometry.packedLength = 6; /** * Stores the provided instance into the provided array. @@ -112,7 +122,8 @@ define([ array[startingIndex++] = value._topRadius; array[startingIndex++] = value._bottomRadius; array[startingIndex++] = value._slices; - array[startingIndex] = value._numberOfVerticalLines; + array[startingIndex++] = value._numberOfVerticalLines; + array[startingIndex] = defaultValue(value._offsetAttribute, -1); return array; }; @@ -122,7 +133,8 @@ define([ topRadius : undefined, bottomRadius : undefined, slices : undefined, - numberOfVerticalLines : undefined + numberOfVerticalLines : undefined, + offsetAttribute : undefined }; /** @@ -144,7 +156,8 @@ define([ var topRadius = array[startingIndex++]; var bottomRadius = array[startingIndex++]; var slices = array[startingIndex++]; - var numberOfVerticalLines = array[startingIndex]; + var numberOfVerticalLines = array[startingIndex++]; + var offsetAttribute = array[startingIndex]; if (!defined(result)) { scratchOptions.length = length; @@ -152,6 +165,7 @@ define([ scratchOptions.bottomRadius = bottomRadius; scratchOptions.slices = slices; scratchOptions.numberOfVerticalLines = numberOfVerticalLines; + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new CylinderOutlineGeometry(scratchOptions); } @@ -160,6 +174,7 @@ define([ result._bottomRadius = bottomRadius; result._slices = slices; result._numberOfVerticalLines = numberOfVerticalLines; + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -226,11 +241,24 @@ define([ var boundingSphere = new BoundingSphere(Cartesian3.ZERO, Cartesian2.magnitude(radiusScratch)); + if (defined(cylinderGeometry._offsetAttribute)) { + length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = cylinderGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + return new Geometry({ attributes : attributes, indices : indices, primitiveType : PrimitiveType.LINES, - boundingSphere : boundingSphere + boundingSphere : boundingSphere, + offsetAttribute : cylinderGeometry._offsetAttribute }); }; diff --git a/Source/Core/EllipsoidGeometry.js b/Source/Core/EllipsoidGeometry.js index d60e4253b3a5..5209f15fa507 100644 --- a/Source/Core/EllipsoidGeometry.js +++ b/Source/Core/EllipsoidGeometry.js @@ -1,4 +1,5 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian2', './Cartesian3', @@ -10,11 +11,13 @@ define([ './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './IndexDatatype', './Math', './PrimitiveType', './VertexFormat' ], function( + arrayFill, BoundingSphere, Cartesian2, Cartesian3, @@ -26,6 +29,7 @@ define([ Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, IndexDatatype, CesiumMath, PrimitiveType, @@ -81,12 +85,16 @@ define([ if (stackPartitions < 3) { throw new DeveloperError('options.stackPartitions cannot be less than three.'); } + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); this._radii = Cartesian3.clone(radii); this._stackPartitions = stackPartitions; this._slicePartitions = slicePartitions; this._vertexFormat = VertexFormat.clone(vertexFormat); + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createEllipsoidGeometry'; } @@ -94,7 +102,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - EllipsoidGeometry.packedLength = Cartesian3.packedLength + VertexFormat.packedLength + 2; + EllipsoidGeometry.packedLength = Cartesian3.packedLength + VertexFormat.packedLength + 3; /** * Stores the provided instance into the provided array. @@ -124,7 +132,8 @@ define([ startingIndex += VertexFormat.packedLength; array[startingIndex++] = value._stackPartitions; - array[startingIndex] = value._slicePartitions; + array[startingIndex++] = value._slicePartitions; + array[startingIndex] = defaultValue(value._offsetAttribute, -1); return array; }; @@ -135,7 +144,8 @@ define([ radii : scratchRadii, vertexFormat : scratchVertexFormat, stackPartitions : undefined, - slicePartitions : undefined + slicePartitions : undefined, + offsetAttribute : undefined }; /** @@ -162,11 +172,13 @@ define([ startingIndex += VertexFormat.packedLength; var stackPartitions = array[startingIndex++]; - var slicePartitions = array[startingIndex]; + var slicePartitions = array[startingIndex++]; + var offsetAttribute = array[startingIndex]; if (!defined(result)) { scratchOptions.stackPartitions = stackPartitions; scratchOptions.slicePartitions = slicePartitions; + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new EllipsoidGeometry(scratchOptions); } @@ -174,6 +186,7 @@ define([ result._vertexFormat = VertexFormat.clone(vertexFormat, result._vertexFormat); result._stackPartitions = stackPartitions; result._slicePartitions = slicePartitions; + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -358,6 +371,18 @@ define([ } } + if (defined(ellipsoidGeometry._offsetAttribute)) { + var length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = ellipsoidGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + index = 0; for (j = 0; j < slicePartitions - 1; j++) { indices[index++] = slicePartitions + j; @@ -396,7 +421,8 @@ define([ attributes : attributes, indices : indices, primitiveType : PrimitiveType.TRIANGLES, - boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid) + boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid), + offsetAttribute : ellipsoidGeometry._offsetAttribute }); }; diff --git a/Source/Core/EllipsoidOutlineGeometry.js b/Source/Core/EllipsoidOutlineGeometry.js index 888a700442b3..bd064ba684af 100644 --- a/Source/Core/EllipsoidOutlineGeometry.js +++ b/Source/Core/EllipsoidOutlineGeometry.js @@ -1,4 +1,5 @@ define([ + './arrayFill', './BoundingSphere', './Cartesian3', './ComponentDatatype', @@ -9,10 +10,12 @@ define([ './Geometry', './GeometryAttribute', './GeometryAttributes', + './GeometryOffsetAttribute', './IndexDatatype', './Math', './PrimitiveType' ], function( + arrayFill, BoundingSphere, Cartesian3, ComponentDatatype, @@ -23,6 +26,7 @@ define([ Geometry, GeometryAttribute, GeometryAttributes, + GeometryOffsetAttribute, IndexDatatype, CesiumMath, PrimitiveType) { @@ -74,12 +78,16 @@ define([ if (subdivisions < 0) { throw new DeveloperError('options.subdivisions must be greater than or equal to zero.'); } + if (defined(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute.TOP) { + throw new DeveloperError('GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry.'); + } //>>includeEnd('debug'); this._radii = Cartesian3.clone(radii); this._stackPartitions = stackPartitions; this._slicePartitions = slicePartitions; this._subdivisions = subdivisions; + this._offsetAttribute = options.offsetAttribute; this._workerName = 'createEllipsoidOutlineGeometry'; } @@ -87,7 +95,7 @@ define([ * The number of elements used to pack the object into an array. * @type {Number} */ - EllipsoidOutlineGeometry.packedLength = Cartesian3.packedLength + 3; + EllipsoidOutlineGeometry.packedLength = Cartesian3.packedLength + 4; /** * Stores the provided instance into the provided array. @@ -115,7 +123,8 @@ define([ array[startingIndex++] = value._stackPartitions; array[startingIndex++] = value._slicePartitions; - array[startingIndex] = value._subdivisions; + array[startingIndex++] = value._subdivisions; + array[startingIndex] = defaultValue(value._offsetAttribute, -1); return array; }; @@ -125,7 +134,8 @@ define([ radii : scratchRadii, stackPartitions : undefined, slicePartitions : undefined, - subdivisions : undefined + subdivisions : undefined, + offsetAttribute : undefined }; /** @@ -151,11 +161,13 @@ define([ var stackPartitions = array[startingIndex++]; var slicePartitions = array[startingIndex++]; var subdivisions = array[startingIndex++]; + var offsetAttribute = array[startingIndex]; if (!defined(result)) { scratchOptions.stackPartitions = stackPartitions; scratchOptions.slicePartitions = slicePartitions; scratchOptions.subdivisions = subdivisions; + scratchOptions.offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return new EllipsoidOutlineGeometry(scratchOptions); } @@ -163,6 +175,7 @@ define([ result._stackPartitions = stackPartitions; result._slicePartitions = slicePartitions; result._subdivisions = subdivisions; + result._offsetAttribute = offsetAttribute === -1 ? undefined : offsetAttribute; return result; }; @@ -291,11 +304,24 @@ define([ }) }); + if (defined(ellipsoidGeometry._offsetAttribute)) { + var length = positions.length; + var applyOffset = new Uint8Array(length / 3); + var offsetValue = ellipsoidGeometry._offsetAttribute === GeometryOffsetAttribute.NONE ? 0 : 1; + arrayFill(applyOffset, offsetValue); + attributes.applyOffset = new GeometryAttribute({ + componentDatatype : ComponentDatatype.UNSIGNED_BYTE, + componentsPerAttribute : 1, + values: applyOffset + }); + } + return new Geometry({ attributes : attributes, indices : indices, primitiveType : PrimitiveType.LINES, - boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid) + boundingSphere : BoundingSphere.fromEllipsoid(ellipsoid), + offsetAttribute : ellipsoidGeometry._offsetAttribute }); }; diff --git a/Source/Core/FeatureDetection.js b/Source/Core/FeatureDetection.js index 8f34384c782a..32b7e8ec7356 100644 --- a/Source/Core/FeatureDetection.js +++ b/Source/Core/FeatureDetection.js @@ -170,7 +170,9 @@ define([ //we still need to use it if it exists in order to support browsers //that rely on it, such as the Windows WebBrowser control which defines //PointerEvent but sets navigator.pointerEnabled to false. - hasPointerEvents = typeof PointerEvent !== 'undefined' && (!defined(theNavigator.pointerEnabled) || theNavigator.pointerEnabled); + + //Firefox disabled because of https://github.com/AnalyticalGraphicsInc/cesium/issues/6372 + hasPointerEvents = !isFirefox() && typeof PointerEvent !== 'undefined' && (!defined(theNavigator.pointerEnabled) || theNavigator.pointerEnabled); } return hasPointerEvents; } diff --git a/Source/Core/Ion.js b/Source/Core/Ion.js index 07de777b0ff1..2a67d34a8345 100644 --- a/Source/Core/Ion.js +++ b/Source/Core/Ion.js @@ -9,7 +9,7 @@ define([ 'use strict'; var defaultTokenCredit; - var defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0NDViM2NkNi0xYTE2LTRlZTUtODBlNy05M2Q4ODg4M2NmMTQiLCJpZCI6MjU5LCJpYXQiOjE1MTgxOTc4MDh9.sld5jPORDf_lWavMEsugh6vHPnjR6j3qd1aBkQTswNM'; + var defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkZGM5ZDhhNi00MTEzLTQ3YzUtOGQ1Zi0xZjE3MGM0NDYzNWEiLCJpZCI6MjU5LCJpYXQiOjE1MzU3MjQyMjh9.pIEOyZPuF4xHRzAQFnDgZJwgpLXDtS7vGMwha6fCs2g'; /** * Default settings for accessing the Cesium ion API. diff --git a/Source/Core/ManagedArray.js b/Source/Core/ManagedArray.js index fed116228452..8c63178ed689 100644 --- a/Source/Core/ManagedArray.js +++ b/Source/Core/ManagedArray.js @@ -74,9 +74,9 @@ define([ * Sets the element at an index. Resizes the array if index is greater than the length of the array. * * @param {Number} index The index to set. - * @param {*} value The value to set at index. + * @param {*} element The element to set at index. */ - ManagedArray.prototype.set = function(index, value) { + ManagedArray.prototype.set = function(index, element) { //>>includeStart('debug', pragmas.debug); Check.typeOf.number('index', index); //>>includeEnd('debug'); @@ -84,11 +84,22 @@ define([ if (index >= this.length) { this.length = index + 1; } - this._array[index] = value; + this._array[index] = element; + }; + + /** + * Returns the last element in the array without modifying the array. + * + * @returns {*} The last element in the array. + */ + ManagedArray.prototype.peek = function() { + return this._array[this._length - 1]; }; /** * Push an element into the array. + * + * @param {*} element The element to push. */ ManagedArray.prototype.push = function(element) { var index = this.length++; diff --git a/Source/Core/Matrix4.js b/Source/Core/Matrix4.js index 9e2eba17b6e4..5d1fd4809f10 100644 --- a/Source/Core/Matrix4.js +++ b/Source/Core/Matrix4.js @@ -1090,7 +1090,7 @@ define([ * * @param {Matrix4} matrix The matrix to use. * @param {Cartesian3} translation The translation that replaces the translation of the provided matrix. - * @param {Cartesian4} result The object onto which to store the result. + * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ Matrix4.setTranslation = function(matrix, translation, result) { @@ -1123,6 +1123,27 @@ define([ return result; }; + var scaleScratch = new Cartesian3(); + /** + * Computes a new matrix that replaces the scale with the provided scale. This assumes the matrix is an affine transformation + * + * @param {Matrix4} matrix The matrix to use. + * @param {Cartesian3} scale The scale that replaces the scale of the provided matrix. + * @param {Matrix4} result The object onto which to store the result. + * @returns {Matrix4} The modified result parameter. + */ + Matrix4.setScale = function(matrix, scale, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('matrix', matrix); + Check.typeOf.object('scale', scale); + Check.typeOf.object('result', result); + //>>includeEnd('debug'); + + var existingScale = Matrix4.getScale(matrix, scaleScratch); + var newScale = Cartesian3.divideComponents(scale, existingScale, scaleScratch); + return Matrix4.multiplyByScale(matrix, newScale, result); + }; + /** * Retrieves a copy of the matrix row at the provided index as a Cartesian4 instance. * diff --git a/Source/Core/PeliasGeocoderService.js b/Source/Core/PeliasGeocoderService.js index 8d8a4832f4c5..42857d93feda 100644 --- a/Source/Core/PeliasGeocoderService.js +++ b/Source/Core/PeliasGeocoderService.js @@ -1,4 +1,5 @@ define([ + './Cartesian3', './Check', './defined', './defineProperties', @@ -6,6 +7,7 @@ define([ './Rectangle', './Resource' ], function ( + Cartesian3, Check, defined, defineProperties, @@ -77,24 +79,20 @@ define([ return resource.fetchJson() .then(function (results) { return results.features.map(function (resultObject) { + var destination; var bboxDegrees = resultObject.bbox; - // Pelias does not always provide bounding information - // so just expand the location slightly. - if (!defined(bboxDegrees)) { + if (defined(bboxDegrees)) { + destination = Rectangle.fromDegrees(bboxDegrees[0], bboxDegrees[1], bboxDegrees[2], bboxDegrees[3]); + } else { var lon = resultObject.geometry.coordinates[0]; var lat = resultObject.geometry.coordinates[1]; - bboxDegrees = [ - lon - 0.001, - lat - 0.001, - lon + 0.001, - lat + 0.001 - ]; + destination = Cartesian3.fromDegrees(lon, lat); } return { displayName: resultObject.properties.label, - destination: Rectangle.fromDegrees(bboxDegrees[0], bboxDegrees[1], bboxDegrees[2], bboxDegrees[3]) + destination: destination }; }); }); diff --git a/Source/DataSources/BoxGeometryUpdater.js b/Source/DataSources/BoxGeometryUpdater.js index 65fc33687cb0..40b807d927d9 100644 --- a/Source/DataSources/BoxGeometryUpdater.js +++ b/Source/DataSources/BoxGeometryUpdater.js @@ -6,13 +6,18 @@ define([ '../Core/Color', '../Core/ColorGeometryInstanceAttribute', '../Core/defined', + '../Core/defineProperties', '../Core/DeveloperError', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -25,19 +30,27 @@ define([ Color, ColorGeometryInstanceAttribute, defined, + defineProperties, DeveloperError, DistanceDisplayConditionGeometryInstanceAttribute, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, Property) { 'use strict'; + var defaultOffset = Cartesian3.ZERO; + + var offsetScratch = new Cartesian3(); var positionScratch = new Cartesian3(); var scratchColor = new Color(); @@ -45,6 +58,7 @@ define([ this.id = entity; this.vertexFormat = undefined; this.dimensions = undefined; + this.offsetAttribute = undefined; } /** @@ -73,6 +87,20 @@ define([ BoxGeometryUpdater.prototype.constructor = BoxGeometryUpdater; } + defineProperties(BoxGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof BoxGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -93,12 +121,16 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - - var color; var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -107,23 +139,16 @@ define([ if (!defined(currentColor)) { currentColor = Color.WHITE; } - color = ColorGeometryInstanceAttribute.fromColor(currentColor); - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute, - color : color - }; - } else { - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute - }; + attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor); + } + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); } return new GeometryInstance({ id : entity, geometry : BoxGeometry.fromDimensions(this._options), - modelMatrix : entity.computeModelMatrix(time), + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.mapProjection.ellipsoid), attributes : attributes }); }; @@ -150,18 +175,28 @@ define([ var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); + var attributes = { + show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), + color : ColorGeometryInstanceAttribute.fromColor(outlineColor), + distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition), + offset : undefined + }; + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); + } + return new GeometryInstance({ id : entity, geometry : BoxOutlineGeometry.fromDimensions(this._options), - modelMatrix : entity.computeModelMatrix(time), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.mapProjection.ellipsoid), + attributes : attributes }); }; + BoxGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + BoxGeometryUpdater.prototype._isHidden = function(entity, box) { return !defined(box.dimensions) || !defined(entity.position) || GeometryUpdater.prototype._isHidden.call(this, entity, box); }; @@ -171,13 +206,16 @@ define([ }; BoxGeometryUpdater.prototype._setStaticOptions = function(entity, box) { - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; + var heightReference = Property.getValueOrDefault(box.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); var options = this._options; - options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; + options.vertexFormat = this._materialProperty instanceof ColorMaterialProperty ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; options.dimensions = box.dimensions.getValue(Iso8601.MINIMUM_VALUE, options.dimensions); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + BoxGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + BoxGeometryUpdater.DynamicGeometryUpdater = DynamicBoxGeometryUpdater; /** @@ -199,7 +237,10 @@ define([ }; DynamicBoxGeometryUpdater.prototype._setOptions = function(entity, box, time) { - this._options.dimensions = Property.getValueOrUndefined(box.dimensions, time, this._options.dimensions); + var heightReference = Property.getValueOrDefault(box.heightReference, time, HeightReference.NONE); + var options = this._options; + options.dimensions = Property.getValueOrUndefined(box.dimensions, time, options.dimensions); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; return BoxGeometryUpdater; diff --git a/Source/DataSources/BoxGraphics.js b/Source/DataSources/BoxGraphics.js index dd63aee52e21..d9b96a63f493 100644 --- a/Source/DataSources/BoxGraphics.js +++ b/Source/DataSources/BoxGraphics.js @@ -23,6 +23,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.dimensions] A {@link Cartesian3} Property specifying the length, width, and height of the box. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the box. * @param {Property} [options.fill=true] A boolean Property specifying whether the box is filled with the provided material. @@ -36,6 +37,7 @@ define([ * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Box.html|Cesium Sandcastle Box Demo} */ function BoxGraphics(options) { + this._heightReference = undefined; this._dimensions = undefined; this._dimensionsSubscription = undefined; this._show = undefined; @@ -72,6 +74,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof BoxGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the boolean Property specifying the visibility of the box. * @memberof BoxGraphics.prototype @@ -154,6 +164,7 @@ define([ if (!defined(result)) { return new BoxGraphics(this); } + result.heightReference = this.heightReference; result.dimensions = this.dimensions; result.show = this.show; result.material = this.material; @@ -179,6 +190,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.dimensions = defaultValue(this.dimensions, source.dimensions); this.show = defaultValue(this.show, source.show); this.material = defaultValue(this.material, source.material); diff --git a/Source/DataSources/CylinderGeometryUpdater.js b/Source/DataSources/CylinderGeometryUpdater.js index 90c863049ce3..0d5aad66a628 100644 --- a/Source/DataSources/CylinderGeometryUpdater.js +++ b/Source/DataSources/CylinderGeometryUpdater.js @@ -6,13 +6,18 @@ define([ '../Core/CylinderGeometry', '../Core/CylinderOutlineGeometry', '../Core/defined', + '../Core/defineProperties', '../Core/DeveloperError', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -25,19 +30,27 @@ define([ CylinderGeometry, CylinderOutlineGeometry, defined, + defineProperties, DeveloperError, DistanceDisplayConditionGeometryInstanceAttribute, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, Property) { 'use strict'; + var defaultOffset = Cartesian3.ZERO; + + var offsetScratch = new Cartesian3(); var positionScratch = new Cartesian3(); var scratchColor = new Color(); @@ -49,6 +62,7 @@ define([ this.bottomRadius = undefined; this.slices = undefined; this.numberOfVerticalLines = undefined; + this.offsetAttribute = undefined; } /** @@ -77,6 +91,20 @@ define([ CylinderGeometryUpdater.prototype.constructor = CylinderGeometryUpdater; } + defineProperties(CylinderGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof CylinderGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -97,12 +125,16 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - - var color; var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -111,23 +143,17 @@ define([ if (!defined(currentColor)) { currentColor = Color.WHITE; } - color = ColorGeometryInstanceAttribute.fromColor(currentColor); - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute, - color : color - }; - } else { - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute - }; + attributes.color = ColorGeometryInstanceAttribute.fromColor(currentColor); + } + + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); } return new GeometryInstance({ id : entity, geometry : new CylinderGeometry(this._options), - modelMatrix : entity.computeModelMatrix(time), + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.cylinder.heightReference, this._options.length * 0.5, this._scene.mapProjection.ellipsoid), attributes : attributes }); }; @@ -154,18 +180,28 @@ define([ var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); + var attributes = { + show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), + color : ColorGeometryInstanceAttribute.fromColor(outlineColor), + distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition), + offset : undefined + }; + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); + } + return new GeometryInstance({ id : entity, geometry : new CylinderOutlineGeometry(this._options), - modelMatrix : entity.computeModelMatrix(time), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : entity.computeModelMatrixForHeightReference(time, entity.cylinder.heightReference, this._options.length * 0.5, this._scene.mapProjection.ellipsoid), + attributes : attributes }); }; + CylinderGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + CylinderGeometryUpdater.prototype._isHidden = function(entity, cylinder) { return !defined(entity.position) || !defined(cylinder.length) || !defined(cylinder.topRadius) || !defined(cylinder.bottomRadius) || GeometryUpdater.prototype._isHidden.call(this, entity, cylinder); }; @@ -182,19 +218,19 @@ define([ }; CylinderGeometryUpdater.prototype._setStaticOptions = function(entity, cylinder) { - var slices = cylinder.slices; - var numberOfVerticalLines = cylinder.numberOfVerticalLines; - + var heightReference = Property.getValueOrDefault(cylinder.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); var options = this._options; - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; - options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; + options.vertexFormat = this._materialProperty instanceof ColorMaterialProperty ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; options.length = cylinder.length.getValue(Iso8601.MINIMUM_VALUE); options.topRadius = cylinder.topRadius.getValue(Iso8601.MINIMUM_VALUE); options.bottomRadius = cylinder.bottomRadius.getValue(Iso8601.MINIMUM_VALUE); - options.slices = defined(slices) ? slices.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.numberOfVerticalLines = defined(numberOfVerticalLines) ? numberOfVerticalLines.getValue(Iso8601.MINIMUM_VALUE) : undefined; + options.slices = Property.getValueOrUndefined(cylinder.slices, Iso8601.MINIMUM_VALUE); + options.numberOfVerticalLines = Property.getValueOrUndefined(cylinder.numberOfVerticalLines, Iso8601.MINIMUM_VALUE); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + CylinderGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + CylinderGeometryUpdater.DynamicGeometryUpdater = DynamicCylinderGeometryUpdater; /** @@ -217,12 +253,14 @@ define([ }; DynamicCylinderGeometryUpdater.prototype._setOptions = function(entity, cylinder, time) { + var heightReference = Property.getValueOrDefault(cylinder.heightReference, time, HeightReference.NONE); var options = this._options; options.length = Property.getValueOrUndefined(cylinder.length, time); options.topRadius = Property.getValueOrUndefined(cylinder.topRadius, time); options.bottomRadius = Property.getValueOrUndefined(cylinder.bottomRadius, time); options.slices = Property.getValueOrUndefined(cylinder.slices, time); options.numberOfVerticalLines = Property.getValueOrUndefined(cylinder.numberOfVerticalLines, time); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; return CylinderGeometryUpdater; diff --git a/Source/DataSources/CylinderGraphics.js b/Source/DataSources/CylinderGraphics.js index 3b0deba5cedd..fb74a8ff0cb3 100644 --- a/Source/DataSources/CylinderGraphics.js +++ b/Source/DataSources/CylinderGraphics.js @@ -24,6 +24,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.length] A numeric Property specifying the length of the cylinder. * @param {Property} [options.topRadius] A numeric Property specifying the radius of the top of the cylinder. * @param {Property} [options.bottomRadius] A numeric Property specifying the radius of the bottom of the cylinder. @@ -39,6 +40,7 @@ define([ * @param {Property} [options.distanceDisplayCondition] A Property specifying at what distance from the camera that this cylinder will be displayed. */ function CylinderGraphics(options) { + this._heightReference = undefined; this._length = undefined; this._lengthSubscription = undefined; this._topRadius = undefined; @@ -84,6 +86,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof CylinderGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the numeric Property specifying the length of the cylinder. * @memberof CylinderGraphics.prototype @@ -196,6 +206,7 @@ define([ if (!defined(result)) { return new CylinderGraphics(this); } + result.heightReference = this.heightReference; result.bottomRadius = this.bottomRadius; result.length = this.length; result.topRadius = this.topRadius; @@ -225,6 +236,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.bottomRadius = defaultValue(this.bottomRadius, source.bottomRadius); this.length = defaultValue(this.length, source.length); this.topRadius = defaultValue(this.topRadius, source.topRadius); diff --git a/Source/DataSources/DataSourceDisplay.js b/Source/DataSources/DataSourceDisplay.js index ccbfd229f16f..3477bfb878af 100644 --- a/Source/DataSources/DataSourceDisplay.js +++ b/Source/DataSources/DataSourceDisplay.js @@ -1,4 +1,5 @@ define([ + '../Core/ApproximateTerrainHeights', '../Core/BoundingSphere', '../Core/Check', '../Core/defaultValue', @@ -20,6 +21,7 @@ define([ './PointVisualizer', './PolylineVisualizer' ], function( + ApproximateTerrainHeights, BoundingSphere, Check, defaultValue, @@ -245,7 +247,7 @@ define([ Check.defined('time', time); //>>includeEnd('debug'); - if (!GroundPrimitive._initialized) { + if (!ApproximateTerrainHeights.initialized) { this._ready = false; return false; } diff --git a/Source/DataSources/EllipsoidGeometryUpdater.js b/Source/DataSources/EllipsoidGeometryUpdater.js index 41f6b4052e27..52b1facb8fd1 100644 --- a/Source/DataSources/EllipsoidGeometryUpdater.js +++ b/Source/DataSources/EllipsoidGeometryUpdater.js @@ -5,18 +5,23 @@ define([ '../Core/ColorGeometryInstanceAttribute', '../Core/defaultValue', '../Core/defined', + '../Core/defineProperties', '../Core/DistanceDisplayCondition', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/EllipsoidGeometry', '../Core/EllipsoidOutlineGeometry', '../Core/GeometryInstance', + '../Core/GeometryOffsetAttribute', '../Core/Iso8601', + '../Core/OffsetGeometryInstanceAttribute', '../Core/Matrix4', '../Core/ShowGeometryInstanceAttribute', + '../Scene/HeightReference', '../Scene/MaterialAppearance', '../Scene/PerInstanceColorAppearance', '../Scene/Primitive', '../Scene/SceneMode', + './heightReferenceOnEntityPropertyChanged', './ColorMaterialProperty', './DynamicGeometryUpdater', './GeometryUpdater', @@ -29,18 +34,23 @@ define([ ColorGeometryInstanceAttribute, defaultValue, defined, + defineProperties, DistanceDisplayCondition, DistanceDisplayConditionGeometryInstanceAttribute, EllipsoidGeometry, EllipsoidOutlineGeometry, GeometryInstance, + GeometryOffsetAttribute, Iso8601, + OffsetGeometryInstanceAttribute, Matrix4, ShowGeometryInstanceAttribute, + HeightReference, MaterialAppearance, PerInstanceColorAppearance, Primitive, SceneMode, + heightReferenceOnEntityPropertyChanged, ColorMaterialProperty, DynamicGeometryUpdater, GeometryUpdater, @@ -49,7 +59,9 @@ define([ 'use strict'; var defaultMaterial = new ColorMaterialProperty(Color.WHITE); + var defaultOffset = Cartesian3.ZERO; + var offsetScratch = new Cartesian3(); var radiiScratch = new Cartesian3(); var scratchColor = new Color(); var unitSphere = new Cartesian3(1, 1, 1); @@ -61,6 +73,7 @@ define([ this.stackPartitions = undefined; this.slicePartitions = undefined; this.subdivisions = undefined; + this.offsetAttribute = undefined; } /** @@ -89,6 +102,20 @@ define([ EllipsoidGeometryUpdater.prototype.constructor = EllipsoidGeometryUpdater; } + defineProperties(EllipsoidGeometryUpdater.prototype, { + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof EllipsoidGeometryUpdater.prototype + * @readonly + */ + terrainOffsetProperty: { + get: function() { + return this._terrainOffsetProperty; + } + } + }); + /** * Creates the geometry instance which represents the fill of the geometry. * @@ -107,12 +134,18 @@ define([ var entity = this._entity; var isAvailable = entity.isAvailable(time); - var attributes; - var color; var show = new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time)); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); var distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition); + + var attributes = { + show : show, + distanceDisplayCondition : distanceDisplayConditionAttribute, + color : undefined, + offset: undefined + }; + if (this._materialProperty instanceof ColorMaterialProperty) { var currentColor; if (defined(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { @@ -122,22 +155,16 @@ define([ currentColor = Color.WHITE; } color = ColorGeometryInstanceAttribute.fromColor(currentColor); - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute, - color : color - }; - } else { - attributes = { - show : show, - distanceDisplayCondition : distanceDisplayConditionAttribute - }; + attributes.color = color; + } + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); } return new GeometryInstance({ id : entity, geometry : new EllipsoidGeometry(this._options), - modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrix(time, modelMatrixResult), + modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrixForHeightReference(time, entity.ellipsoid.heightReference, this._options.radii.z * 0.5, this._scene.mapProjection.ellipsoid, modelMatrixResult), attributes : attributes }); }; @@ -163,18 +190,28 @@ define([ var outlineColor = Property.getValueOrDefault(this._outlineColorProperty, time, Color.BLACK, scratchColor); var distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); + var attributes = { + show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), + color : ColorGeometryInstanceAttribute.fromColor(outlineColor), + distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition), + offset : undefined + }; + if (defined(this._options.offsetAttribute)) { + attributes.offset = OffsetGeometryInstanceAttribute.fromCartesian3(Property.getValueOrDefault(this._terrainOffsetProperty, time, defaultOffset, offsetScratch)); + } + return new GeometryInstance({ id : entity, geometry : new EllipsoidOutlineGeometry(this._options), - modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrix(time, modelMatrixResult), - attributes : { - show : new ShowGeometryInstanceAttribute(isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time)), - color : ColorGeometryInstanceAttribute.fromColor(outlineColor), - distanceDisplayCondition : DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition(distanceDisplayCondition) - } + modelMatrix : skipModelMatrix ? undefined : entity.computeModelMatrixForHeightReference(time, entity.ellipsoid.heightReference, this._options.radii.z * 0.5, this._scene.mapProjection.ellipsoid, modelMatrixResult), + attributes : attributes }); }; + EllipsoidGeometryUpdater.prototype._computeCenter = function(time, result) { + return Property.getValueOrUndefined(this._entity.position, time, result); + }; + EllipsoidGeometryUpdater.prototype._isHidden = function(entity, ellipsoid) { return !defined(entity.position) || !defined(ellipsoid.radii) || GeometryUpdater.prototype._isHidden.call(this, entity, ellipsoid); }; @@ -190,19 +227,18 @@ define([ }; EllipsoidGeometryUpdater.prototype._setStaticOptions = function(entity, ellipsoid) { - var stackPartitions = ellipsoid.stackPartitions; - var slicePartitions = ellipsoid.slicePartitions; - var subdivisions = ellipsoid.subdivisions; - var isColorMaterial = this._materialProperty instanceof ColorMaterialProperty; - + var heightReference = Property.getValueOrDefault(ellipsoid.heightReference, Iso8601.MINIMUM_VALUE, HeightReference.NONE); var options = this._options; - options.vertexFormat = isColorMaterial ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; + options.vertexFormat = this._materialProperty instanceof ColorMaterialProperty ? PerInstanceColorAppearance.VERTEX_FORMAT : MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat; options.radii = ellipsoid.radii.getValue(Iso8601.MINIMUM_VALUE, options.radii); - options.stackPartitions = defined(stackPartitions) ? stackPartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.slicePartitions = defined(slicePartitions) ? slicePartitions.getValue(Iso8601.MINIMUM_VALUE) : undefined; - options.subdivisions = defined(subdivisions) ? subdivisions.getValue(Iso8601.MINIMUM_VALUE) : undefined; + options.stackPartitions = Property.getValueOrUndefined(ellipsoid.stackPartitions, Iso8601.MINIMUM_VALUE); + options.slicePartitions = Property.getValueOrUndefined(ellipsoid.slicePartitions, Iso8601.MINIMUM_VALUE); + options.subdivisions = Property.getValueOrUndefined(ellipsoid.subdivisions, Iso8601.MINIMUM_VALUE); + options.offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; }; + EllipsoidGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged; + EllipsoidGeometryUpdater.DynamicGeometryUpdater = DynamicEllipsoidGeometryUpdater; /** @@ -220,6 +256,7 @@ define([ this._lastOutlineShow = undefined; this._lastOutlineWidth = undefined; this._lastOutlineColor = undefined; + this._lastOffset = new Cartesian3(); this._material = {}; } @@ -247,7 +284,7 @@ define([ } var radii = Property.getValueOrUndefined(ellipsoid.radii, time, radiiScratch); - var modelMatrix = entity.computeModelMatrix(time, this._modelMatrix); + var modelMatrix = defined(radii) ? entity.computeModelMatrixForHeightReference(time, ellipsoid.heightReference, radii.z * 0.5, this._scene.mapProjection.ellipsoid, this._modelMatrix) : undefined; if (!defined(modelMatrix) || !defined(radii)) { if (defined(this._primitive)) { this._primitive.show = false; @@ -270,10 +307,13 @@ define([ var slicePartitions = Property.getValueOrUndefined(ellipsoid.slicePartitions, time); var subdivisions = Property.getValueOrUndefined(ellipsoid.subdivisions, time); var outlineWidth = Property.getValueOrDefault(ellipsoid.outlineWidth, time, 1.0); + var heightReference = Property.getValueOrDefault(ellipsoid.heightReference, time, HeightReference.NONE); + var offsetAttribute = heightReference !== HeightReference.NONE ? GeometryOffsetAttribute.ALL : undefined; //In 3D we use a fast path by modifying Primitive.modelMatrix instead of regenerating the primitive every frame. + //Also check for height reference because this method doesn't work when the height is relative to terrain. var sceneMode = this._scene.mode; - var in3D = sceneMode === SceneMode.SCENE3D; + var in3D = sceneMode === SceneMode.SCENE3D && heightReference === HeightReference.NONE; var options = this._options; @@ -282,11 +322,13 @@ define([ var distanceDisplayConditionProperty = this._geometryUpdater.distanceDisplayConditionProperty; var distanceDisplayCondition = distanceDisplayConditionProperty.getValue(time); + var offset = Property.getValueOrDefault(this._geometryUpdater.terrainOffsetProperty, time, defaultOffset, offsetScratch); + //We only rebuild the primitive if something other than the radii has changed //For the radii, we use unit sphere and then deform it with a scale matrix. var rebuildPrimitives = !in3D || this._lastSceneMode !== sceneMode || !defined(this._primitive) || // options.stackPartitions !== stackPartitions || options.slicePartitions !== slicePartitions || // - options.subdivisions !== subdivisions || this._lastOutlineWidth !== outlineWidth; + options.subdivisions !== subdivisions || this._lastOutlineWidth !== outlineWidth || options.offsetAttribute !== offsetAttribute; if (rebuildPrimitives) { var primitives = this._primitives; @@ -300,6 +342,7 @@ define([ options.stackPartitions = stackPartitions; options.slicePartitions = slicePartitions; options.subdivisions = subdivisions; + options.offsetAttribute = offsetAttribute; options.radii = in3D ? unitSphere : radii; var appearance = new MaterialAppearance({ @@ -336,6 +379,7 @@ define([ this._lastOutlineShow = showOutline; this._lastOutlineColor = Color.clone(outlineColor, this._lastOutlineColor); this._lastDistanceDisplayCondition = distanceDisplayCondition; + this._lastOffset = Cartesian3.clone(offset, this._lastOffset); } else if (this._primitive.ready) { //Update attributes only. var primitive = this._primitive; @@ -377,6 +421,12 @@ define([ outlineAttributes.distanceDisplayCondition = DistanceDisplayConditionGeometryInstanceAttribute.toValue(distanceDisplayCondition, outlineAttributes.distanceDisplayCondition); DistanceDisplayCondition.clone(distanceDisplayCondition, this._lastDistanceDisplayCondition); } + + if (!Cartesian3.equals(offset, this._lastOffset)) { + attributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset); + outlineAttributes.offset = OffsetGeometryInstanceAttribute.toValue(offset, attributes.offset); + Cartesian3.clone(offset, this._lastOffset); + } } if (in3D) { diff --git a/Source/DataSources/EllipsoidGraphics.js b/Source/DataSources/EllipsoidGraphics.js index 2199c61dec41..9f2894b09eed 100644 --- a/Source/DataSources/EllipsoidGraphics.js +++ b/Source/DataSources/EllipsoidGraphics.js @@ -23,6 +23,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: + * @param {Property} [options.heightReference] A Property specifying what the height from the entity position is relative to. * @param {Property} [options.radii] A {@link Cartesian3} Property specifying the radii of the ellipsoid. * @param {Property} [options.show=true] A boolean Property specifying the visibility of the ellipsoid. * @param {Property} [options.fill=true] A boolean Property specifying whether the ellipsoid is filled with the provided material. @@ -39,6 +40,7 @@ define([ * @demo {@link https://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Spheres%20and%20Ellipsoids.html|Cesium Sandcastle Spheres and Ellipsoids Demo} */ function EllipsoidGraphics(options) { + this._heightReference = undefined; this._show = undefined; this._showSubscription = undefined; this._radii = undefined; @@ -82,6 +84,14 @@ define([ } }, + /** + * Gets or sets the Property specifying the {@link HeightReference}. + * @memberof EllipsoidGraphics.prototype + * @type {Property} + * @default HeightReference.NONE + */ + heightReference : createPropertyDescriptor('heightReference'), + /** * Gets or sets the boolean Property specifying the visibility of the ellipsoid. * @memberof EllipsoidGraphics.prototype @@ -188,6 +198,7 @@ define([ if (!defined(result)) { return new EllipsoidGraphics(this); } + result.heightReference = this.heightReference; result.show = this.show; result.radii = this.radii; result.material = this.material; @@ -217,6 +228,7 @@ define([ } //>>includeEnd('debug'); + this.heightReference = defaultValue(this.heightReference, source.heightReference); this.show = defaultValue(this.show, source.show); this.radii = defaultValue(this.radii, source.radii); this.material = defaultValue(this.material, source.material); diff --git a/Source/DataSources/Entity.js b/Source/DataSources/Entity.js index 1996c6791872..b5170a14fa46 100644 --- a/Source/DataSources/Entity.js +++ b/Source/DataSources/Entity.js @@ -1,5 +1,6 @@ define([ '../Core/Cartesian3', + '../Core/Cartographic', '../Core/Check', '../Core/createGuid', '../Core/defaultValue', @@ -7,10 +8,12 @@ define([ '../Core/defineProperties', '../Core/DeveloperError', '../Core/Event', + '../Core/Math', '../Core/Matrix3', '../Core/Matrix4', '../Core/Quaternion', '../Core/Transforms', + '../Scene/HeightReference', '../Scene/GroundPrimitive', '../Scene/GroundPolylinePrimitive', './BillboardGraphics', @@ -36,6 +39,7 @@ define([ './WallGraphics' ], function( Cartesian3, + Cartographic, Check, createGuid, defaultValue, @@ -43,10 +47,12 @@ define([ defineProperties, DeveloperError, Event, + CesiumMath, Matrix3, Matrix4, Quaternion, Transforms, + HeightReference, GroundPrimitive, GroundPolylinePrimitive, BillboardGraphics, @@ -72,6 +78,8 @@ define([ WallGraphics) { 'use strict'; + var cartoScratch = new Cartographic(); + function createConstantPositionProperty(value) { return new ConstantPositionProperty(value); } @@ -608,11 +616,44 @@ define([ * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. Result is undefined if position or orientation are undefined. */ Entity.prototype.computeModelMatrix = function(time, result) { + //>>includeStart('debug', pragmas.debug); Check.typeOf.object('time', time); + //>>includeEnd('debug'); var position = Property.getValueOrUndefined(this._position, time, positionScratch); if (!defined(position)) { return undefined; } + + var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch); + if (!defined(orientation)) { + result = Transforms.eastNorthUpToFixedFrame(position, undefined, result); + } else { + result = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result); + } + return result; + }; + + /** + * @private + */ + Entity.prototype.computeModelMatrixForHeightReference = function(time, heightReferenceProperty, heightOffset, ellipsoid, result) { + //>>includeStart('debug', pragmas.debug); + Check.typeOf.object('time', time); + //>>includeEnd('debug'); + var heightReference = Property.getValueOrDefault(heightReferenceProperty, time, HeightReference.NONE); + var position = Property.getValueOrUndefined(this._position, time, positionScratch); + if (heightReference === HeightReference.NONE || !defined(position) || Cartesian3.equalsEpsilon(position, Cartesian3.ZERO, CesiumMath.EPSILON8)) { + return this.computeModelMatrix(time, result); + } + + var carto = ellipsoid.cartesianToCartographic(position, cartoScratch); + if (heightReference === HeightReference.CLAMP_TO_GROUND) { + carto.height = heightOffset; + } else { + carto.height += heightOffset; + } + position = ellipsoid.cartographicToCartesian(carto, position); + var orientation = Property.getValueOrUndefined(this._orientation, time, orientationScratch); if (!defined(orientation)) { result = Transforms.eastNorthUpToFixedFrame(position, undefined, result); diff --git a/Source/DataSources/GroundGeometryUpdater.js b/Source/DataSources/GroundGeometryUpdater.js index 76c2c7b1810e..bcc22dd6b8b0 100644 --- a/Source/DataSources/GroundGeometryUpdater.js +++ b/Source/DataSources/GroundGeometryUpdater.js @@ -72,6 +72,12 @@ define([ } }, + /** + * Gets the terrain offset property + * @type {TerrainOffsetProperty} + * @memberof GroundGeometryUpdater.prototype + * @readonly + */ terrainOffsetProperty: { get: function() { return this._terrainOffsetProperty; @@ -107,7 +113,7 @@ define([ if (defined(heightReferenceProperty) || defined(extrudedHeightReferenceProperty)) { var centerPosition = new CallbackProperty(this._computeCenter.bind(this), !this._dynamic); - this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, heightReferenceProperty, extrudedHeightReferenceProperty, centerPosition); + this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, centerPosition, heightReferenceProperty, extrudedHeightReferenceProperty); } }; diff --git a/Source/DataSources/PlaneGeometryUpdater.js b/Source/DataSources/PlaneGeometryUpdater.js index 5c70bd1e38a2..811d23952ac6 100644 --- a/Source/DataSources/PlaneGeometryUpdater.js +++ b/Source/DataSources/PlaneGeometryUpdater.js @@ -9,6 +9,8 @@ define([ '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/GeometryInstance', '../Core/Iso8601', + '../Core/Math', + '../Core/Matrix3', '../Core/Matrix4', '../Core/PlaneGeometry', '../Core/PlaneOutlineGeometry', @@ -31,6 +33,8 @@ define([ DistanceDisplayConditionGeometryInstanceAttribute, GeometryInstance, Iso8601, + CesiumMath, + Matrix3, Matrix4, PlaneGeometry, PlaneOutlineGeometry, @@ -136,7 +140,7 @@ define([ options.plane = plane; options.dimensions = dimensions; - modelMatrix = createPrimitiveMatrix(plane, dimensions, modelMatrix, modelMatrix); + modelMatrix = createPrimitiveMatrix(plane, dimensions, modelMatrix, this._scene.mapProjection.ellipsoid, modelMatrix); return new GeometryInstance({ id : entity, @@ -177,7 +181,7 @@ define([ options.plane = plane; options.dimensions = dimensions; - modelMatrix = createPrimitiveMatrix(plane, dimensions, modelMatrix, modelMatrix); + modelMatrix = createPrimitiveMatrix(plane, dimensions, modelMatrix, this._scene.mapProjection.ellipsoid, modelMatrix); return new GeometryInstance({ id : entity, @@ -242,30 +246,38 @@ define([ options.dimensions = Property.getValueOrUndefined(plane.dimensions, time, options.dimensions); }; + var scratchAxis = new Cartesian3(); + var scratchAxis2 = new Cartesian3(); var scratchTranslation = new Cartesian3(); var scratchNormal = new Cartesian3(); var scratchScale = new Cartesian3(); - function createPrimitiveMatrix (plane, dimensions, modelMatrix, result) { - var normal; - var distance; - if (defined(plane)) { - normal = plane.normal; - distance = plane.distance; - } else { - normal = Cartesian3.clone(Cartesian3.UNIT_X, scratchNormal); - distance = 0.0; - } - - if (!defined(dimensions)) { - dimensions = new Cartesian2(1.0, 1.0); - } + var scratchQuaternion = new Quaternion(); + var scratchMatrix3 = new Matrix3(); + function createPrimitiveMatrix(plane, dimensions, transform, ellipsoid, result) { + var normal = plane.normal; + var distance = plane.distance; var translation = Cartesian3.multiplyByScalar(normal, -distance, scratchTranslation); - translation = Matrix4.multiplyByPoint(modelMatrix, translation, translation); + translation = Matrix4.multiplyByPoint(transform, translation, translation); - var transformedNormal = Matrix4.multiplyByPointAsVector(modelMatrix, normal, scratchNormal); + var transformedNormal = Matrix4.multiplyByPointAsVector(transform, normal, scratchNormal); Cartesian3.normalize(transformedNormal, transformedNormal); - var rotation = getRotationMatrix(transformedNormal, Cartesian3.UNIT_Z); + + var up = ellipsoid.geodeticSurfaceNormal(translation, scratchAxis2); + if (CesiumMath.equalsEpsilon(Math.abs(Cartesian3.dot(up, transformedNormal)), 1.0, CesiumMath.EPSILON8)) { + up = Cartesian3.clone(Cartesian3.UNIT_Z, up); + } + + var left = Cartesian3.cross(up, transformedNormal, scratchAxis); + up = Cartesian3.cross(transformedNormal, left, up); + Cartesian3.normalize(left, left); + Cartesian3.normalize(up, up); + + var rotationMatrix = scratchMatrix3; + Matrix3.setColumn(rotationMatrix, 0, left, rotationMatrix); + Matrix3.setColumn(rotationMatrix, 1, up, rotationMatrix); + Matrix3.setColumn(rotationMatrix, 2, transformedNormal, rotationMatrix); + var rotation = Quaternion.fromRotationMatrix(rotationMatrix, scratchQuaternion); var scale = Cartesian2.clone(dimensions, scratchScale); scale.z = 1.0; @@ -273,18 +285,10 @@ define([ return Matrix4.fromTranslationQuaternionRotationScale(translation, rotation, scale, result); } - // get a rotation according to a normal - var scratchAxis = new Cartesian3(); - var scratchQuaternion = new Quaternion(); - function getRotationMatrix(direction, up) { - var angle = Cartesian3.angleBetween(direction, up); - if (angle === 0.0) { - return Quaternion.clone(Quaternion.IDENTITY, scratchQuaternion); - } - - var axis = Cartesian3.cross(up, direction, scratchAxis); - return Quaternion.fromAxisAngle(axis, angle, scratchQuaternion); - } + /** + * @private + */ + PlaneGeometryUpdater.createPrimitiveMatrix = createPrimitiveMatrix; return PlaneGeometryUpdater; }); diff --git a/Source/DataSources/PolylineVisualizer.js b/Source/DataSources/PolylineVisualizer.js index a4bfc58c8ae5..7bf86fc489ae 100644 --- a/Source/DataSources/PolylineVisualizer.js +++ b/Source/DataSources/PolylineVisualizer.js @@ -51,7 +51,7 @@ define([ return; } - if (updater.clampToGround) { // Also checks for support + if (updater.clampToGround && updater.fillEnabled) { // Also checks for support that._groundBatch.add(time, updater); return; } diff --git a/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js b/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js index c3da5fdcae14..f5df9d4d540e 100644 --- a/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js +++ b/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js @@ -1,5 +1,7 @@ define([ '../Core/AssociativeArray', + '../Core/Color', + '../Core/ColorGeometryInstanceAttribute', '../Core/defined', '../Core/DistanceDisplayCondition', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', @@ -13,6 +15,8 @@ define([ './Property' ], function( AssociativeArray, + Color, + ColorGeometryInstanceAttribute, defined, DistanceDisplayCondition, DistanceDisplayConditionGeometryInstanceAttribute, @@ -26,6 +30,7 @@ define([ Property) { 'use strict'; + var scratchColor = new Color(); var distanceDisplayConditionScratch = new DistanceDisplayCondition(); var defaultDistanceDisplayCondition = new DistanceDisplayCondition(); @@ -195,6 +200,15 @@ define([ this.attributes.set(instance.id.id, attributes); } + if (!updater.fillMaterialProperty.isConstant) { + var colorProperty = updater.fillMaterialProperty.color; + var resultColor = Property.getValueOrDefault(colorProperty, time, Color.WHITE, scratchColor); + if (!Color.equals(attributes._lastColor, resultColor)) { + attributes._lastColor = Color.clone(resultColor, attributes._lastColor); + attributes.color = ColorGeometryInstanceAttribute.toValue(resultColor, attributes.color); + } + } + var show = entity.isShowing && (updater.hasConstantFill || updater.isFilled(time)); var currentShow = attributes.show[0] === 1; if (show !== currentShow) { diff --git a/Source/DataSources/TerrainOffsetProperty.js b/Source/DataSources/TerrainOffsetProperty.js index 7f9f740cf7d7..b7683f047778 100644 --- a/Source/DataSources/TerrainOffsetProperty.js +++ b/Source/DataSources/TerrainOffsetProperty.js @@ -32,7 +32,7 @@ define([ /** * @private */ - function TerrainOffsetProperty(scene, heightReferenceProperty, extrudedHeightReferenceProperty, positionProperty) { + function TerrainOffsetProperty(scene, positionProperty, heightReferenceProperty, extrudedHeightReferenceProperty) { //>>includeStart('debug', pragmas.debug); Check.defined('scene', scene); Check.defined('positionProperty', positionProperty); diff --git a/Source/DataSources/heightReferenceOnEntityPropertyChanged.js b/Source/DataSources/heightReferenceOnEntityPropertyChanged.js new file mode 100644 index 000000000000..95fae99fa390 --- /dev/null +++ b/Source/DataSources/heightReferenceOnEntityPropertyChanged.js @@ -0,0 +1,40 @@ +define([ + '../Core/defaultValue', + '../Core/defined', + './CallbackProperty', + './GeometryUpdater', + './TerrainOffsetProperty' + ], function( + defaultValue, + defined, + CallbackProperty, + GeometryUpdater, + TerrainOffsetProperty) { + 'use strict'; + + function heightReferenceOnEntityPropertyChanged(entity, propertyName, newValue, oldValue) { + GeometryUpdater.prototype._onEntityPropertyChanged.call(this, entity, propertyName, newValue, oldValue); + if (this._observedPropertyNames.indexOf(propertyName) === -1) { + return; + } + + var geometry = this._entity[this._geometryPropertyName]; + if (!defined(geometry)) { + return; + } + + if (defined(this._terrainOffsetProperty)) { + this._terrainOffsetProperty.destroy(); + this._terrainOffsetProperty = undefined; + } + + var heightReferenceProperty = geometry.heightReference; + + if (defined(heightReferenceProperty)) { + var centerPosition = new CallbackProperty(this._computeCenter.bind(this), !this._dynamic); + this._terrainOffsetProperty = new TerrainOffsetProperty(this._scene, centerPosition, heightReferenceProperty); + } + } + + return heightReferenceOnEntityPropertyChanged; +}); diff --git a/Source/Scene/Batched3DModel3DTileContent.js b/Source/Scene/Batched3DModel3DTileContent.js index b89874f33998..f3e291eaaa40 100644 --- a/Source/Scene/Batched3DModel3DTileContent.js +++ b/Source/Scene/Batched3DModel3DTileContent.js @@ -56,8 +56,8 @@ define([ /** * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md|Batched 3D Model} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Batched3DModel|Batched 3D Model} + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset. *

* Implements the {@link Cesium3DTileContent} interface. *

@@ -276,7 +276,7 @@ define([ batchTableBinaryByteLength = 0; featureTableJsonByteLength = 0; featureTableBinaryByteLength = 0; - Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); + Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchLength] [batchTableByteLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Batched3DModel.'); } else if (batchTableBinaryByteLength >= 570425344) { // Second legacy check byteOffset -= sizeOfUint32; @@ -285,7 +285,7 @@ define([ batchTableBinaryByteLength = featureTableBinaryByteLength; featureTableJsonByteLength = 0; featureTableBinaryByteLength = 0; - Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Batched3DModel/README.md.'); + Batched3DModel3DTileContent._deprecationWarning('b3dm-legacy-header', 'This b3dm header is using the legacy format [batchTableJsonByteLength] [batchTableBinaryByteLength] [batchLength]. The new format is [featureTableJsonByteLength] [featureTableBinaryByteLength] [batchTableJsonByteLength] [batchTableBinaryByteLength] from https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Batched3DModel.'); } var featureTableJson; @@ -444,8 +444,8 @@ define([ } }; - Batched3DModel3DTileContent.prototype.applyStyle = function(frameState, style) { - this._batchTable.applyStyle(frameState, style); + Batched3DModel3DTileContent.prototype.applyStyle = function(style) { + this._batchTable.applyStyle(style); }; Batched3DModel3DTileContent.prototype.update = function(tileset, frameState) { @@ -482,8 +482,7 @@ define([ // If any commands were pushed, add derived commands var commandEnd = frameState.commandList.length; if ((commandStart < commandEnd) && (frameState.passes.render || frameState.passes.pick) && !defined(tileset.classificationType)) { - var finalResolution = this._tile._finalResolution; - this._batchTable.addDerivedCommands(frameState, commandStart, finalResolution); + this._batchTable.addDerivedCommands(frameState, commandStart); } }; diff --git a/Source/Scene/BingMapsImageryProvider.js b/Source/Scene/BingMapsImageryProvider.js index 6e31778486bd..a403bd1338de 100644 --- a/Source/Scene/BingMapsImageryProvider.js +++ b/Source/Scene/BingMapsImageryProvider.js @@ -52,11 +52,7 @@ define([ * @param {Resource|String} options.url The url of the Bing Maps server hosting the imagery. * @param {String} [options.key] The Bing Maps key for your application, which can be * created at {@link https://www.bingmapsportal.com/}. - * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used. - * If {@link BingMapsApi.defaultKey} is undefined as well, a message is - * written to the console reminding you that you must create and supply a Bing Maps - * key as soon as possible. Please do not deploy an application that uses - * Bing Maps imagery without creating a separate key for your application. + * If this parameter is not provided, {@link BingMapsApi.defaultKey} is used, which is undefined by default. * @param {String} [options.tileProtocol] The protocol to use when loading tiles, e.g. 'http:' or 'https:'. * By default, tiles are loaded using the same protocol as the page. * @param {BingMapsStyle} [options.mapStyle=BingMapsStyle.AERIAL] The type of Bing Maps imagery to load. diff --git a/Source/Scene/Camera.js b/Source/Scene/Camera.js index 50b48178c9d3..353d0ae73088 100644 --- a/Source/Scene/Camera.js +++ b/Source/Scene/Camera.js @@ -958,7 +958,10 @@ define([ if (this._suspendTerrainAdjustment) { this._suspendTerrainAdjustment = !globeFinishedUpdating; } - this._adjustHeightForTerrain(); + + if (globeFinishedUpdating) { + this._adjustHeightForTerrain(); + } }; var setTransformPosition = new Cartesian3(); @@ -1013,7 +1016,7 @@ define([ mousePosition.y = scene.drawingBufferHeight / 2.0; var ray = this.getPickRay(mousePosition, pickGlobeScratchRay); - rayIntersection = globe.pick(ray, scene, scratchRayIntersection); + rayIntersection = globe.pickWorldCoordinates(ray, scene, scratchRayIntersection); if (scene.pickPositionSupported) { depthIntersection = scene.pickPositionWorldCoordinates(mousePosition, scratchDepthIntersection); @@ -2414,7 +2417,7 @@ define([ function pickMap2D(camera, windowPosition, projection, result) { var ray = camera.getPickRay(windowPosition, pickEllipsoid2DRay); var position = ray.origin; - position.z = 0.0; + position = Cartesian3.fromElements(position.y, position.z, 0.0, position); var cart = projection.unproject(position); if (cart.latitude < -CesiumMath.PI_OVER_TWO || cart.latitude > CesiumMath.PI_OVER_TWO) { @@ -2536,7 +2539,7 @@ define([ Cartesian3.clone(camera.directionWC, result.direction); - if (camera._mode === SceneMode.COLUMBUS_VIEW) { + if (camera._mode === SceneMode.COLUMBUS_VIEW || camera._mode === SceneMode.SCENE2D) { Cartesian3.fromElements(result.origin.z, result.origin.x, result.origin.y, result.origin); } diff --git a/Source/Scene/Cesium3DTile.js b/Source/Scene/Cesium3DTile.js index c01c67cc1f68..2e24ba16c617 100644 --- a/Source/Scene/Cesium3DTile.js +++ b/Source/Scene/Cesium3DTile.js @@ -2,6 +2,7 @@ define([ '../Core/BoundingSphere', '../Core/Cartesian3', '../Core/Color', + '../Core/ColorGeometryInstanceAttribute', '../Core/CullingVolume', '../Core/defaultValue', '../Core/defined', @@ -24,7 +25,6 @@ define([ '../Core/Resource', '../Core/RuntimeError', '../ThirdParty/when', - './Cesium3DTileChildrenVisibility', './Cesium3DTileContentFactory', './Cesium3DTileContentState', './Cesium3DTileOptimizationHint', @@ -38,6 +38,7 @@ define([ BoundingSphere, Cartesian3, Color, + ColorGeometryInstanceAttribute, CullingVolume, defaultValue, defined, @@ -60,7 +61,6 @@ define([ Resource, RuntimeError, when, - Cesium3DTileChildrenVisibility, Cesium3DTileContentFactory, Cesium3DTileContentState, Cesium3DTileOptimizationHint, @@ -88,7 +88,7 @@ define([ var contentHeader = header.content; /** - * The local transform of this tile + * The local transform of this tile. * @type {Matrix4} */ this.transform = defined(header.transform) ? Matrix4.unpack(header.transform) : Matrix4.clone(Matrix4.IDENTITY); @@ -100,7 +100,7 @@ define([ this._initialTransform = Matrix4.multiply(parentInitialTransform, this.transform, new Matrix4()); /** - * The final computed transform of this tile + * The final computed transform of this tile. * @type {Matrix4} * @readonly */ @@ -200,10 +200,6 @@ define([ contentHeaderUri = contentHeader.url; } - if (tileset._brokenUrlWorkaround && contentHeaderUri.length > 0 && (contentHeaderUri[0] === '/')) { - contentHeaderUri = contentHeader.uri = contentHeaderUri.substring(1); - } - hasEmptyContent = false; contentState = Cesium3DTileContentState.UNLOADED; contentResource = baseResource.getDerivedResource({ @@ -235,19 +231,6 @@ define([ */ this.hasEmptyContent = hasEmptyContent; - /** - * When true, the tile's content is renderable. - *

- * This is false until the tile's content is loaded. - *

- * - * @type {Boolean} - * @readonly - * - * @private - */ - this.hasRenderableContent = false; - /** * When true, the tile's content points to an external tileset. *

@@ -262,14 +245,16 @@ define([ this.hasTilesetContent = false; /** - * The corresponding node in the cache replacement list. + * The node in the tileset's LRU cache, used to determine when to unload a tile's content. + * + * See {@link Cesium3DTilesetCache} * * @type {DoublyLinkedListNode} * @readonly * * @private */ - this.replacementNode = undefined; + this.cacheNode = undefined; var expire = header.expire; var expireDuration; @@ -295,15 +280,6 @@ define([ */ this.expireDate = expireDate; - /** - * Marks if the tile is selected this frame. - * - * @type {Boolean} - * - * @private - */ - this.selected = false; - /** * The time when a style was last applied to this tile. * @@ -334,22 +310,27 @@ define([ // Members that are updated every frame for tree traversal and rendering optimizations: this._distanceToCamera = 0; - this._visibilityPlaneMask = 0; - this._childrenVisibility = Cesium3DTileChildrenVisibility.VISIBLE; - this._lastSelectedFrameNumber = -1; + this._centerZDepth = 0; this._screenSpaceError = 0; - this._screenSpaceErrorComputedFrame = -1; + this._visibilityPlaneMask = 0; + this._visible = false; + this._inRequestVolume = false; + this._finalResolution = true; this._depth = 0; - this._centerZDepth = 0; this._stackLength = 0; - this._selectedFrame = -1; this._selectionDepth = 0; - this._lastSelectionDepth = undefined; - this._requestedFrame = undefined; - this._lastVisitedFrame = undefined; + + this._updatedVisibilityFrame = 0; + this._touchedFrame = 0; + this._visitedFrame = 0; + this._selectedFrame = 0; + this._requestedFrame = 0; this._ancestorWithContent = undefined; - this._ancestorWithLoadedContent = undefined; + this._ancestorWithContentAvailable = undefined; + this._refines = false; + this._shouldSelect = false; + this._priority = 0.0; this._isClipped = true; this._clippingPlanesState = 0; // encapsulates (_isClipped, clippingPlanes.enabled) and number/function @@ -398,6 +379,21 @@ define([ } }, + /** + * Get the tile's bounding volume. + * + * @memberof Cesium3DTile.prototype + * + * @type {TileBoundingVolume} + * @readonly + * @private + */ + boundingVolume : { + get : function() { + return this._boundingVolume; + } + }, + /** * Get the bounding volume of the tile's contents. This defaults to the * tile's bounding volume when the content's bounding volume is @@ -429,6 +425,22 @@ define([ } }, + /** + * Returns the extras property in the tileset JSON for this tile, which contains application specific metadata. + * Returns undefined if extras does not exist. + * + * @memberof Cesium3DTile.prototype + * + * @type {*} + * @readonly + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#specifying-extensions-and-application-specific-extras|Extras in the 3D Tiles specification.} + */ + extras : { + get : function() { + return this._header.extras; + } + }, + /** * Gets or sets the tile's highlight color. * @@ -467,13 +479,13 @@ define([ */ contentAvailable : { get : function() { - return this.contentReady || (defined(this._expiredContent) && this._contentState !== Cesium3DTileContentState.FAILED); + return (this.contentReady && !this.hasEmptyContent && !this.hasTilesetContent) || (defined(this._expiredContent) && !this.contentFailed); } }, /** - * Determines if the tile is ready to render. true if the tile - * is ready to render; otherwise, false. + * Determines if the tile's content is ready. This is automatically true for + * tile's with empty content. * * @memberof Cesium3DTile.prototype * @@ -522,6 +534,23 @@ define([ } }, + /** + * Determines if the tile's content failed to load. true if the tile's + * content failed to load; otherwise, false. + * + * @memberof Cesium3DTile.prototype + * + * @type {Boolean} + * @readonly + * + * @private + */ + contentFailed : { + get : function() { + return this._contentState === Cesium3DTileContentState.FAILED; + } + }, + /** * Gets the promise that will be resolved when the tile's content is ready to process. * This happens after the content is downloaded but before the content is ready @@ -618,7 +647,7 @@ define([ function createPriorityFunction(tile) { return function() { - return tile._distanceToCamera; + return tile._priority; }; } @@ -690,7 +719,6 @@ define([ if (defined(contentFactory)) { content = contentFactory(tileset, that, that._contentResource, arrayBuffer, 0); - that.hasRenderableContent = true; } else { // The content may be json instead content = Cesium3DTileContentFactory.json(tileset, that, that._contentResource, arrayBuffer, 0); @@ -710,6 +738,7 @@ define([ updateExpireDate(that); // Refresh style for expired content + that._selectedFrame = 0; that.lastStyleTime = 0; that._contentState = Cesium3DTileContentState.READY; @@ -735,7 +764,7 @@ define([ * @private */ Cesium3DTile.prototype.unloadContent = function() { - if (!this.hasRenderableContent) { + if (this.hasEmptyContent || this.hasTilesetContent) { return; } @@ -744,8 +773,6 @@ define([ this._contentReadyToProcessPromise = undefined; this._contentReadyPromise = undefined; - this.replacementNode = undefined; - this.lastStyleTime = 0; this.clippingPlanesDirty = (this._clippingPlanesState === 0); this._clippingPlanesState = 0; @@ -794,7 +821,7 @@ define([ var tileset = this._tileset; var clippingPlanes = tileset.clippingPlanes; if (defined(clippingPlanes) && clippingPlanes.enabled) { - var tileTransform = tileset._root.computedTransform; + var tileTransform = tileset.root.computedTransform; var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform); this._isClipped = intersection !== Intersect.INSIDE; if (intersection === Intersect.OUTSIDE) { @@ -829,7 +856,7 @@ define([ var tileset = this._tileset; var clippingPlanes = tileset.clippingPlanes; if (defined(clippingPlanes) && clippingPlanes.enabled) { - var tileTransform = tileset._root.computedTransform; + var tileTransform = tileset.root.computedTransform; var intersection = clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume, tileTransform); this._isClipped = intersection !== Intersect.INSIDE; if (intersection === Intersect.OUTSIDE) { @@ -859,7 +886,7 @@ define([ * Computes the distance from the center of the tile's bounding volume to the camera. * * @param {FrameState} frameState The frame state. - * @returns {Number} The distance, in meters, or zero if the camera is inside the bounding volume. + * @returns {Number} The distance, in meters. * * @private */ @@ -1032,14 +1059,24 @@ define([ function applyDebugSettings(tile, tileset, frameState) { var hasContentBoundingVolume = defined(tile._header.content) && defined(tile._header.content.boundingVolume); + var empty = tile.hasEmptyContent || tile.hasTilesetContent; var showVolume = tileset.debugShowBoundingVolume || (tileset.debugShowContentBoundingVolume && !hasContentBoundingVolume); if (showVolume) { + var color; + if (!tile._finalResolution) { + color = Color.YELLOW; + } else if (empty) { + color = Color.DARKGRAY; + } else { + color = Color.WHITE; + } if (!defined(tile._debugBoundingVolume)) { - var color = tile._finalResolution ? (hasContentBoundingVolume ? Color.WHITE : Color.RED) : Color.YELLOW; tile._debugBoundingVolume = tile._boundingVolume.createDebugVolume(color); } tile._debugBoundingVolume.update(frameState); + var attributes = tile._debugBoundingVolume.getGeometryInstanceAttributes('outline'); + attributes.color = ColorGeometryInstanceAttribute.toValue(color, attributes.color); } else if (!showVolume && defined(tile._debugBoundingVolume)) { tile._debugBoundingVolume = tile._debugBoundingVolume.destroy(); } diff --git a/Source/Scene/Cesium3DTileBatchTable.js b/Source/Scene/Cesium3DTileBatchTable.js index 9750aaada61d..e4885fac3e9a 100644 --- a/Source/Scene/Cesium3DTileBatchTable.js +++ b/Source/Scene/Cesium3DTileBatchTable.js @@ -544,7 +544,7 @@ define([ var scratchColor = new Color(); - Cesium3DTileBatchTable.prototype.applyStyle = function(frameState, style) { + Cesium3DTileBatchTable.prototype.applyStyle = function(style) { if (!defined(style)) { this.setAllColor(DEFAULT_COLOR_VALUE); this.setAllShow(true); @@ -555,8 +555,8 @@ define([ var length = this.featuresLength; for (var i = 0; i < length; ++i) { var feature = content.getFeature(i); - var color = defined(style.color) ? style.color.evaluateColor(frameState, feature, scratchColor) : DEFAULT_COLOR_VALUE; - var show = defined(style.show) ? style.show.evaluate(frameState, feature) : DEFAULT_SHOW_VALUE; + var color = defined(style.color) ? style.color.evaluateColor(feature, scratchColor) : DEFAULT_COLOR_VALUE; + var show = defined(style.show) ? style.show.evaluate(feature) : DEFAULT_SHOW_VALUE; this.setColor(i, color); this.setShow(i, show); } @@ -1181,7 +1181,7 @@ define([ }; function getColorBlend(batchTable) { - var tileset = batchTable._content._tileset; + var tileset = batchTable._content.tileset; var colorBlendMode = tileset.colorBlendMode; var colorBlendAmount = tileset.colorBlendAmount; if (colorBlendMode === Cesium3DTileColorBlendMode.HIGHLIGHT) { @@ -1241,11 +1241,12 @@ define([ OPAQUE_AND_TRANSLUCENT : 2 }; - Cesium3DTileBatchTable.prototype.addDerivedCommands = function(frameState, commandStart, finalResolution) { + Cesium3DTileBatchTable.prototype.addDerivedCommands = function(frameState, commandStart) { var commandList = frameState.commandList; var commandEnd = commandList.length; var tile = this._content._tile; - var tileset = tile._tileset; + var finalResolution = tile._finalResolution; + var tileset = tile.tileset; var bivariateVisibilityTest = tileset._skipLevelOfDetail && tileset._hasMixedContent && frameState.context.stencilBuffer; var styleCommandsNeeded = getStyleCommandsNeeded(this); @@ -1276,9 +1277,8 @@ define([ } tileset._backfaceCommands.push(derivedCommands.zback); } - if (!defined(derivedCommands.stencil) || tile._selectionDepth !== tile._lastSelectionDepth) { + if (!defined(derivedCommands.stencil) || tile._selectionDepth !== getLastSelectionDepth(derivedCommands.stencil)) { derivedCommands.stencil = deriveStencilCommand(derivedCommands.originalCommand, tile._selectionDepth); - tile._lastSelectionDepth = tile._selectionDepth; } updateDerivedCommand(derivedCommands.stencil, command); } @@ -1423,6 +1423,10 @@ define([ return derivedCommand; } + function getLastSelectionDepth(stencilCommand) { + return stencilCommand.renderState.stencilTest.reference >>> 4; + } + function getTranslucentRenderState(renderState) { var rs = clone(renderState, true); rs.cull.enabled = false; @@ -1479,7 +1483,7 @@ define([ } batchTable._pickTexture = createTexture(batchTable, context, bytes); - content._tileset._statistics.batchTableByteLength += batchTable._pickTexture.sizeInBytes; + content.tileset._statistics.batchTableByteLength += batchTable._pickTexture.sizeInBytes; } } diff --git a/Source/Scene/Cesium3DTileChildrenVisibility.js b/Source/Scene/Cesium3DTileChildrenVisibility.js deleted file mode 100644 index ddfd279b147d..000000000000 --- a/Source/Scene/Cesium3DTileChildrenVisibility.js +++ /dev/null @@ -1,19 +0,0 @@ -define([ - '../Core/freezeObject' - ], function( - freezeObject) { - 'use strict'; - - /** - * @private - */ - var Cesium3DTileChildrenVisibility = { - NONE : 0, // No children visible - VISIBLE : 1, // At least one child visible - IN_REQUEST_VOLUME : 2, // At least one child in viewer request volume - VISIBLE_IN_REQUEST_VOLUME : 4, // At least one child both visible and in viewer request volume - VISIBLE_NOT_IN_REQUEST_VOLUME : 8 // At least one child visible but not in viewer request volume - }; - - return freezeObject(Cesium3DTileChildrenVisibility); -}); diff --git a/Source/Scene/Cesium3DTileContent.js b/Source/Scene/Cesium3DTileContent.js index cd5106b7e246..c812b804e42c 100644 --- a/Source/Scene/Cesium3DTileContent.js +++ b/Source/Scene/Cesium3DTileContent.js @@ -57,7 +57,7 @@ define([ * equals the number of groups of points as distinguished by the BATCH_ID feature table semantic. *

* - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/PointCloud/README.md#batched-points} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/PointCloud#batched-points} * * @memberof Cesium3DTileContent.prototype * @@ -130,7 +130,7 @@ define([ * Gets the array of {@link Cesium3DTileContent} objects that represent the * content a composite's inner tiles, which can also be composites. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Composite/README.md} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Composite} * * @memberof Cesium3DTileContent.prototype * @@ -237,7 +237,7 @@ define([ * Features in a tile are ordered by batchId, an index used to retrieve their metadata from the batch table. *

* - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable}. + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/BatchTable}. * * @param {Number} batchId The batchId for the feature. * @returns {Cesium3DTileFeature} The corresponding {@link Cesium3DTileFeature} object. @@ -271,12 +271,11 @@ define([ * not part of the public Cesium API. *

* - * @param {FrameSate} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * * @private */ - Cesium3DTileContent.prototype.applyStyle = function(frameState, style) { + Cesium3DTileContent.prototype.applyStyle = function(style) { DeveloperError.throwInstantiationError(); }; diff --git a/Source/Scene/Cesium3DTileFeature.js b/Source/Scene/Cesium3DTileFeature.js index 3aa53b38796b..fadd5ba604e8 100644 --- a/Source/Scene/Cesium3DTileFeature.js +++ b/Source/Scene/Cesium3DTileFeature.js @@ -153,7 +153,7 @@ define([ * Returns whether the feature contains this property. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String} name The case-sensitive name of the property. * @returns {Boolean} Whether the feature contains this property. @@ -166,7 +166,7 @@ define([ * Returns an array of property names for the feature. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String[]} results An array into which to store the results. * @returns {String[]} The names of the feature's properties. @@ -179,7 +179,7 @@ define([ * Returns a copy of the value of the feature's property with the given name. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String} name The case-sensitive name of the property. * @returns {*} The value of the property or undefined if the property does not exist. diff --git a/Source/Scene/Cesium3DTileOptimizations.js b/Source/Scene/Cesium3DTileOptimizations.js index d3e08593f9a3..1b644d6c00be 100644 --- a/Source/Scene/Cesium3DTileOptimizations.js +++ b/Source/Scene/Cesium3DTileOptimizations.js @@ -44,7 +44,7 @@ define([ var length = children.length; // Check if the parent has an oriented bounding box. - var boundingVolume = tile._boundingVolume; + var boundingVolume = tile.boundingVolume; if (boundingVolume instanceof TileOrientedBoundingBox || boundingVolume instanceof TileBoundingRegion) { var orientedBoundingBox = boundingVolume._orientedBoundingBox; tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.USE_OPTIMIZATION; @@ -52,7 +52,7 @@ define([ var child = children[i]; // Check if the child has an oriented bounding box. - var childBoundingVolume = child._boundingVolume; + var childBoundingVolume = child.boundingVolume; if (!(childBoundingVolume instanceof TileOrientedBoundingBox || childBoundingVolume instanceof TileBoundingRegion)) { // Do not support if the parent and child both do not have oriented bounding boxes. tile._optimChildrenWithinParent = Cesium3DTileOptimizationHint.SKIP_OPTIMIZATION; diff --git a/Source/Scene/Cesium3DTilePointFeature.js b/Source/Scene/Cesium3DTilePointFeature.js index ed852e538130..546572e2881e 100644 --- a/Source/Scene/Cesium3DTilePointFeature.js +++ b/Source/Scene/Cesium3DTilePointFeature.js @@ -681,7 +681,7 @@ define([ * Returns whether the feature contains this property. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String} name The case-sensitive name of the property. * @returns {Boolean} Whether the feature contains this property. @@ -694,7 +694,7 @@ define([ * Returns an array of property names for the feature. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String[]} results An array into which to store the results. * @returns {String[]} The names of the feature's properties. @@ -707,7 +707,7 @@ define([ * Returns a copy of the value of the feature's property with the given name. This includes properties from this feature's * class and inherited classes when using a batch table hierarchy. * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/TileFormats/BatchTable#batch-table-hierarchy} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/extensions/3DTILES_batch_table_hierarchy} * * @param {String} name The case-sensitive name of the property. * @returns {*} The value of the property or undefined if the property does not exist. diff --git a/Source/Scene/Cesium3DTileRefine.js b/Source/Scene/Cesium3DTileRefine.js index b72832f10903..79feafa40c3b 100644 --- a/Source/Scene/Cesium3DTileRefine.js +++ b/Source/Scene/Cesium3DTileRefine.js @@ -7,7 +7,7 @@ define([ /** * The refinement approach for a tile. *

- * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/schema/tile.schema.json|tile schema} + * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#refinement|Refinement} * in the 3D Tiles spec. *

* diff --git a/Source/Scene/Cesium3DTileStyle.js b/Source/Scene/Cesium3DTileStyle.js index 0c8068dab1b7..f6b2ed67949c 100644 --- a/Source/Scene/Cesium3DTileStyle.js +++ b/Source/Scene/Cesium3DTileStyle.js @@ -24,7 +24,7 @@ define([ * A style that is applied to a {@link Cesium3DTileset}. *

* Evaluates an expression defined using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}. *

* * @alias Cesium3DTileStyle @@ -53,7 +53,7 @@ define([ * pointSize : '${Temperature} * 2.0' * }); * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} */ function Cesium3DTileStyle(style) { this._style = undefined; @@ -176,7 +176,7 @@ define([ defineProperties(Cesium3DTileStyle.prototype, { /** * Gets the object defining the style using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}. * * @memberof Cesium3DTileStyle.prototype * @@ -250,13 +250,13 @@ define([ * var style = new Cesium3DTileStyle({ * show : '(regExp("^Chest").test(${County})) && (${YearBuilt} >= 1970)' * }); - * style.show.evaluate(frameState, feature); // returns true or false depending on the feature's properties + * style.show.evaluate(feature); // returns true or false depending on the feature's properties * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override show expression with a custom function * style.show = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return true; * } * }; @@ -319,13 +319,13 @@ define([ * var style = new Cesium3DTileStyle({ * color : '(${Temperature} > 90) ? color("red") : color("white")' * }); - * style.color.evaluateColor(frameState, feature, result); // returns a Cesium.Color object + * style.color.evaluateColor(feature, result); // returns a Cesium.Color object * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override color expression with a custom function * style.color = { - * evaluateColor : function(frameState, feature, result) { + * evaluateColor : function(feature, result) { * return Cesium.Color.clone(Cesium.Color.WHITE, result); * } * }; @@ -381,13 +381,13 @@ define([ * var style = new Cesium3DTileStyle({ * pointSize : '(${Temperature} > 90) ? 2.0 : 1.0' * }); - * style.pointSize.evaluate(frameState, feature); // returns a Number + * style.pointSize.evaluate(feature); // returns a Number * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override pointSize expression with a custom function * style.pointSize = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return 1.0; * } * }; @@ -690,13 +690,13 @@ define([ * var style = new Cesium3DTileStyle({ * font : '(${Temperature} > 90) ? "30px Helvetica" : "24px Helvetica"' * }); - * style.font.evaluate(frameState, feature); // returns a String + * style.font.evaluate(feature); // returns a String * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override font expression with a custom function * style.font = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return '24px Helvetica'; * } * }; @@ -738,13 +738,13 @@ define([ * var style = new Cesium3DTileStyle({ * labelStyle : '(${Temperature} > 90) ? ' + LabelStyle.FILL_AND_OUTLINE + ' : ' + LabelStyle.FILL * }); - * style.labelStyle.evaluate(frameState, feature); // returns a LabelStyle + * style.labelStyle.evaluate(feature); // returns a LabelStyle * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override labelStyle expression with a custom function * style.labelStyle = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return LabelStyle.FILL; * } * }; @@ -786,13 +786,13 @@ define([ * var style = new Cesium3DTileStyle({ * labelText : '(${Temperature} > 90) ? ">90" : "<=90"' * }); - * style.labelText.evaluate(frameState, feature); // returns a String + * style.labelText.evaluate(feature); // returns a String * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override labelText expression with a custom function * style.labelText = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return 'Example label text'; * } * }; @@ -882,7 +882,7 @@ define([ * var style = new Cesium.Cesium3DTileStyle(); * // Override backgroundPadding expression with a string * style.backgroundPadding = 'vec2(5.0, 7.0)'; - * style.backgroundPadding.evaluate(frameState, feature); // returns a Cartesian2 + * style.backgroundPadding.evaluate(feature); // returns a Cartesian2 */ backgroundPadding : { get : function() { @@ -969,7 +969,7 @@ define([ * var style = new Cesium.Cesium3DTileStyle(); * // Override scaleByDistance expression with a string * style.scaleByDistance = 'vec4(1.5e2, 2.0, 1.5e7, 0.5)'; - * style.scaleByDistance.evaluate(frameState, feature); // returns a Cartesian4 + * style.scaleByDistance.evaluate(feature); // returns a Cartesian4 */ scaleByDistance : { get : function() { @@ -1008,7 +1008,7 @@ define([ * var style = new Cesium.Cesium3DTileStyle(); * // Override translucencyByDistance expression with a string * style.translucencyByDistance = 'vec4(1.5e2, 1.0, 1.5e7, 0.2)'; - * style.translucencyByDistance.evaluate(frameState, feature); // returns a Cartesian4 + * style.translucencyByDistance.evaluate(feature); // returns a Cartesian4 */ translucencyByDistance : { get : function() { @@ -1047,7 +1047,7 @@ define([ * var style = new Cesium.Cesium3DTileStyle(); * // Override distanceDisplayCondition expression with a string * style.distanceDisplayCondition = 'vec2(0.0, 5.5e6)'; - * style.distanceDisplayCondition.evaluate(frameState, feature); // returns a Cartesian2 + * style.distanceDisplayCondition.evaluate(feature); // returns a Cartesian2 */ distanceDisplayCondition : { get : function() { @@ -1230,13 +1230,13 @@ define([ * var style = new Cesium3DTileStyle({ * image : '(${Temperature} > 90) ? "/url/to/image1" : "/url/to/image2"' * }); - * style.image.evaluate(frameState, feature); // returns a String + * style.image.evaluate(feature); // returns a String * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override image expression with a custom function * style.image = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return '/url/to/image'; * } * }; @@ -1278,7 +1278,7 @@ define([ * var style = new Cesium.Cesium3DTileStyle(); * // Override disableDepthTestDistance expression with a string * style.disableDepthTestDistance = '1000.0'; - * style.disableDepthTestDistance.evaluate(frameState, feature); // returns a Number + * style.disableDepthTestDistance.evaluate(feature); // returns a Number */ disableDepthTestDistance : { get : function() { @@ -1317,13 +1317,13 @@ define([ * var style = new Cesium3DTileStyle({ * horizontalOrigin : HorizontalOrigin.LEFT * }); - * style.horizontalOrigin.evaluate(frameState, feature); // returns a HorizontalOrigin + * style.horizontalOrigin.evaluate(feature); // returns a HorizontalOrigin * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override horizontalOrigin expression with a custom function * style.horizontalOrigin = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return HorizontalOrigin.CENTER; * } * }; @@ -1365,13 +1365,13 @@ define([ * var style = new Cesium3DTileStyle({ * verticalOrigin : VerticalOrigin.TOP * }); - * style.verticalOrigin.evaluate(frameState, feature); // returns a VerticalOrigin + * style.verticalOrigin.evaluate(feature); // returns a VerticalOrigin * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override verticalOrigin expression with a custom function * style.verticalOrigin = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return VerticalOrigin.CENTER; * } * }; @@ -1413,13 +1413,13 @@ define([ * var style = new Cesium3DTileStyle({ * labelHorizontalOrigin : HorizontalOrigin.LEFT * }); - * style.labelHorizontalOrigin.evaluate(frameState, feature); // returns a HorizontalOrigin + * style.labelHorizontalOrigin.evaluate(feature); // returns a HorizontalOrigin * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override labelHorizontalOrigin expression with a custom function * style.labelHorizontalOrigin = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return HorizontalOrigin.CENTER; * } * }; @@ -1461,13 +1461,13 @@ define([ * var style = new Cesium3DTileStyle({ * labelVerticalOrigin : VerticalOrigin.TOP * }); - * style.labelVerticalOrigin.evaluate(frameState, feature); // returns a VerticalOrigin + * style.labelVerticalOrigin.evaluate(feature); // returns a VerticalOrigin * * @example * var style = new Cesium.Cesium3DTileStyle(); * // Override labelVerticalOrigin expression with a custom function * style.labelVerticalOrigin = { - * evaluate : function(frameState, feature) { + * evaluate : function(feature) { * return VerticalOrigin.CENTER; * } * }; @@ -1503,7 +1503,7 @@ define([ * description : '"Building id ${id} has height ${Height}."' * } * }); - * style.meta.description.evaluate(frameState, feature); // returns a String with the substituted variables + * style.meta.description.evaluate(feature); // returns a String with the substituted variables */ meta : { get : function() { diff --git a/Source/Scene/Cesium3DTileStyleEngine.js b/Source/Scene/Cesium3DTileStyleEngine.js index 07ac449b0e52..36d4c3fb0ab6 100644 --- a/Source/Scene/Cesium3DTileStyleEngine.js +++ b/Source/Scene/Cesium3DTileStyleEngine.js @@ -65,13 +65,13 @@ define([ var length = tiles.length; for (var i = 0; i < length; ++i) { var tile = tiles[i]; - if (tile.selected && (tile.lastStyleTime !== lastStyleTime)) { + if (tile.lastStyleTime !== lastStyleTime) { // Apply the style to this tile if it wasn't already applied because: // 1) the user assigned a new style to the tileset // 2) this tile is now visible, but it wasn't visible when the style was first assigned var content = tile.content; tile.lastStyleTime = lastStyleTime; - content.applyStyle(frameState, this._style); + content.applyStyle(this._style); statistics.numberOfFeaturesStyled += content.featuresLength; ++statistics.numberOfTilesStyled; } diff --git a/Source/Scene/Cesium3DTileset.js b/Source/Scene/Cesium3DTileset.js index 162757d56c5a..604742192531 100644 --- a/Source/Scene/Cesium3DTileset.js +++ b/Source/Scene/Cesium3DTileset.js @@ -12,7 +12,6 @@ define([ '../Core/DoublyLinkedList', '../Core/Ellipsoid', '../Core/Event', - '../Core/getMagic', '../Core/JulianDate', '../Core/ManagedArray', '../Core/Math', @@ -27,6 +26,8 @@ define([ './Cesium3DTileColorBlendMode', './Cesium3DTileContentState', './Cesium3DTileOptimizations', + './Cesium3DTileRefine', + './Cesium3DTilesetCache', './Cesium3DTilesetStatistics', './Cesium3DTilesetTraversal', './Cesium3DTileStyleEngine', @@ -53,7 +54,6 @@ define([ DoublyLinkedList, Ellipsoid, Event, - getMagic, JulianDate, ManagedArray, CesiumMath, @@ -68,6 +68,8 @@ define([ Cesium3DTileColorBlendMode, Cesium3DTileContentState, Cesium3DTileOptimizations, + Cesium3DTileRefine, + Cesium3DTilesetCache, Cesium3DTilesetStatistics, Cesium3DTilesetTraversal, Cesium3DTileStyleEngine, @@ -83,7 +85,7 @@ define([ 'use strict'; /** - * A {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles tileset}, + * A {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles tileset}, * used for streaming massive heterogeneous 3D geospatial datasets. * * @alias Cesium3DTileset @@ -122,7 +124,7 @@ define([ * @param {Boolean} [options.debugShowMemoryUsage=false] For debugging only. When true, draws labels to indicate the texture and geometry memory in megabytes used by each tile. * @param {Boolean} [options.debugShowUrl=false] For debugging only. When true, draws labels to indicate the url of each tile. * - * @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0. See {@link https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status} + * @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0. * * @example * var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({ @@ -152,7 +154,7 @@ define([ * dynamicScreenSpaceErrorHeightFalloff : 0.25 * })); * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles specification} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles specification} */ function Cesium3DTileset(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); @@ -169,31 +171,21 @@ define([ this._geometricError = undefined; // Geometric error when the tree is not rendered at all this._extensionsUsed = undefined; this._gltfUpAxis = undefined; + this._cache = new Cesium3DTilesetCache(); this._processingQueue = []; this._selectedTiles = []; + this._emptyTiles = []; this._requestedTiles = []; - this._desiredTiles = new ManagedArray(); this._selectedTilesToStyle = []; this._loadTimestamp = undefined; this._timeSinceLoad = 0.0; - - var replacementList = new DoublyLinkedList(); - - // [head, sentinel) -> tiles that weren't selected this frame and may be replaced - // (sentinel, tail] -> tiles that were selected this frame - this._replacementList = replacementList; // Tiles with content loaded. For cache management. - this._replacementSentinel = replacementList.add(); - this._trimTiles = false; + this._extras = undefined; this._cullWithChildrenBounds = defaultValue(options.cullWithChildrenBounds, true); + this._allTilesAdditive = true; this._hasMixedContent = false; - this._baseTraversal = new Cesium3DTilesetTraversal.BaseTraversal(); - this._skipTraversal = new Cesium3DTilesetTraversal.SkipTraversal({ - selectionHeuristic : selectionHeuristic - }); - this._backfaceCommands = new ManagedArray(); this._maximumScreenSpaceError = defaultValue(options.maximumScreenSpaceError, 16); @@ -593,7 +585,7 @@ define([ * This property is for debugging only; it is not optimized for production use. *

* When true, renders the bounding volume for each visible tile. The bounding volume is - * white if the tile has a content bounding volume; otherwise, it is red. Tiles that don't meet the + * white if the tile has a content bounding volume or is empty; otherwise, it is red. Tiles that don't meet the * screen space error and are still refining to their descendants are yellow. *

* @@ -673,12 +665,6 @@ define([ * @default false */ this.debugShowUrl = defaultValue(options.debugShowUrl, false); - - // A bunch of tilesets were generated that have a leading / in front of all URLs in the tileset JSON file. If the tiles aren't - // at the root of the domain they will not load anymore. If we find a b3dm file with a leading slash, we test load a tile. - // If it succeeds we continue on. If it fails, we set this to true so we know to strip the slash when loading tiles. - this._brokenUrlWorkaround = false; - this._credits = undefined; var that = this; @@ -700,17 +686,9 @@ define([ that._url = resource.url; that._basePath = basePath; - // We don't know the distance of the tileset until tileset JSON file is loaded, so use the default distance for now return Cesium3DTileset.loadJson(resource); }) .then(function(tilesetJson) { - return detectBrokenUrlWorkaround(that, resource, tilesetJson); - }) - .then(function(tilesetJson) { - if (that._brokenUrlWorkaround) { - deprecationWarning('Cesium3DTileset.leadingSlash', 'Having a leading slash in a tile URL that is actually relative to the tileset JSON file is deprecated.'); - } - that._root = that.loadTileset(resource, tilesetJson); var gltfUpAxis = defined(tilesetJson.asset.gltfUpAxis) ? Axis.fromName(tilesetJson.asset.gltfUpAxis) : Axis.Y; that._asset = tilesetJson.asset; @@ -718,71 +696,18 @@ define([ that._geometricError = tilesetJson.geometricError; that._extensionsUsed = tilesetJson.extensionsUsed; that._gltfUpAxis = gltfUpAxis; + that._extras = tilesetJson.extras; that._readyPromise.resolve(that); }).otherwise(function(error) { that._readyPromise.reject(error); }); } - function detectBrokenUrlWorkaround(tileset, resource, tilesetJson) { - var testUrl = findBrokenUrl(tilesetJson.root); - - // If it's an empty string, we are good to load the tileset. - if (!defined(testUrl) || (testUrl.length === 0)) { - return tilesetJson; - } - - var testResource = resource.getDerivedResource({ - url : testUrl - }); - - return testResource.fetchArrayBuffer() - .then(function(buffer) { - var uint8Array = new Uint8Array(buffer); - var magic = getMagic(uint8Array); - - // If its not a b3dm file, then use workaround - // This accounts for servers that return an error page with a 200 status code - tileset._brokenUrlWorkaround = (magic !== 'b3dm'); - - return tilesetJson; - }) - .otherwise(function() { - // Tile failed to load, so use the workaround - tileset._brokenUrlWorkaround = true; - return tilesetJson; - }); - } - - var brokenUrlRegex = /^\/.+\.b3dm$/; - - function findBrokenUrl(node) { - var content = node.content; - if (defined(content) && defined(content.url)) { - if (brokenUrlRegex.test(content.url)) { - return content.url; - } - - return ''; - } - - var children = node.children; - if (defined(children)) { - var count = children.length; - for (var i = 0; i < count; ++i) { - var result = findBrokenUrl(children[i]); - if (defined(result)) { - return result; - } - } - } - } - defineProperties(Cesium3DTileset.prototype, { /** * Gets the tileset's asset object property, which contains metadata about the tileset. *

- * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/schema/asset.schema.json|asset schema} + * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#reference-asset|asset schema reference} * in the 3D Tiles spec for the full set of properties. *

* @@ -823,7 +748,7 @@ define([ /** * Gets the tileset's properties dictionary object, which contains metadata about per-feature properties. *

- * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/schema/properties.schema.json|properties schema} + * See the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#reference-properties|properties schema reference} * in the 3D Tiles spec for the full set of properties. *

* @@ -949,7 +874,7 @@ define([ /** * The style, defined using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}, + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}, * applied to each feature in the tileset. *

* Assign undefined to remove the style, which will restore the visual @@ -983,7 +908,7 @@ define([ * } * }); * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} */ style : { get : function() { @@ -1067,6 +992,28 @@ define([ } }, + /** + * The root tile. + * + * @memberOf Cesium3DTileset.prototype + * + * @type {Cesium3DTile} + * @readonly + * + * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true. + */ + root : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.'); + } + //>>includeEnd('debug'); + + return this._root; + } + }, + /** * The tileset's bounding sphere. * @@ -1095,6 +1042,7 @@ define([ } //>>includeEnd('debug'); + this._root.updateTransform(this._modelMatrix); return this._root.boundingSphere; } }, @@ -1123,11 +1071,6 @@ define([ }, set : function(value) { this._modelMatrix = Matrix4.clone(value, this._modelMatrix); - if (defined(this._root)) { - // Update the root transform right away instead of waiting for the next update loop. - // Useful, for example, when setting the modelMatrix and then having the camera view the tileset. - this._root.updateTransform(this._modelMatrix); - } } }, @@ -1227,6 +1170,31 @@ define([ get : function() { return this._ellipsoid; } + }, + + /** + * Returns the extras property at the top-level of the tileset JSON, which contains application specific metadata. + * Returns undefined if extras does not exist. + * + * @memberof Cesium3DTileset.prototype + * + * @exception {DeveloperError} The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true. + * + * @type {*} + * @readonly + * + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification#specifying-extensions-and-application-specific-extras|Extras in the 3D Tiles specification.} + */ + extras : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('The tileset is not loaded. Use Cesium3DTileset.readyPromise or wait for Cesium3DTileset.ready to be true.'); + } + //>>includeEnd('debug'); + + return this._extras; + } } }); @@ -1260,18 +1228,18 @@ define([ throw new RuntimeError('Tileset must have an asset property.'); } if (asset.version !== '0.0' && asset.version !== '1.0') { - throw new RuntimeError('The tileset must be 3D Tiles version 0.0 or 1.0. See https://github.com/AnalyticalGraphicsInc/3d-tiles#spec-status'); + throw new RuntimeError('The tileset must be 3D Tiles version 0.0 or 1.0.'); } var statistics = this._statistics; - // Append the tileset version to the resource - if (!defined(resource.queryParameters.v)) { - var versionQuery = { - v: defaultValue(asset.tilesetVersion, '0.0') - }; - this._basePath += '?v=' + versionQuery.v; - resource.setQueryParameters(versionQuery); + var tilesetVersion = asset.tilesetVersion; + if (defined(tilesetVersion)) { + // Append the tileset version to the resource + this._basePath += '?v=' + tilesetVersion; + resource.setQueryParameters({ v: tilesetVersion }); + } else { + delete resource.queryParameters.v; } // A tileset JSON file referenced from a tile may exist in a different directory than the root tileset. @@ -1285,35 +1253,27 @@ define([ rootTile._depth = parentTile._depth + 1; } - ++statistics.numberOfTilesTotal; - var stack = []; - stack.push({ - header : tilesetJson.root, - tile3D : rootTile - }); + stack.push(rootTile); while (stack.length > 0) { var tile = stack.pop(); - var tile3D = tile.tile3D; - var children = tile.header.children; + ++statistics.numberOfTilesTotal; + this._allTilesAdditive = this._allTilesAdditive && (tile.refine === Cesium3DTileRefine.ADD); + var children = tile._header.children; if (defined(children)) { var length = children.length; for (var i = 0; i < length; ++i) { var childHeader = children[i]; - var childTile = new Cesium3DTile(this, resource, childHeader, tile3D); - tile3D.children.push(childTile); - childTile._depth = tile3D._depth + 1; - ++statistics.numberOfTilesTotal; - stack.push({ - header : childHeader, - tile3D : childTile - }); + var childTile = new Cesium3DTile(this, resource, childHeader, tile); + tile.children.push(childTile); + childTile._depth = tile._depth + 1; + stack.push(childTile); } } if (this._cullWithChildrenBounds) { - Cesium3DTileOptimizations.checkChildrenWithinParent(tile3D); + Cesium3DTileOptimizations.checkChildrenWithinParent(tile); } } @@ -1399,15 +1359,6 @@ define([ tileset._dynamicScreenSpaceErrorComputedDensity = density; } - function selectionHeuristic(tileset, ancestor, tile) { - var skipLevels = tileset._skipLevelOfDetail ? tileset.skipLevels : 0; - var skipScreenSpaceErrorFactor = tileset._skipLevelOfDetail ? tileset.skipScreenSpaceErrorFactor : 1.0; - - return (ancestor !== tile && !tile.hasEmptyContent && !tileset.immediatelyLoadDesiredLevelOfDetail) && - (tile._screenSpaceError < ancestor._screenSpaceError / skipScreenSpaceErrorFactor) && - (tile._depth > ancestor._depth + skipLevels); - } - /////////////////////////////////////////////////////////////////////////// function requestContent(tileset, tile) { @@ -1425,11 +1376,11 @@ define([ } if (expired) { - if (tile.hasRenderableContent) { + if (tile.hasTilesetContent) { + destroySubtree(tileset, tile); + } else { statistics.decrementLoadCounts(tile.content); --tileset._statistics.numberOfTilesWithContentReady; - } else if (tile.hasTilesetContent) { - destroySubtree(tileset, tile); } } @@ -1439,12 +1390,16 @@ define([ tile.contentReadyPromise.then(handleTileSuccess(tileset, tile)).otherwise(handleTileFailure(tileset, tile)); } - function requestTiles(tileset, outOfCore) { - if (!outOfCore) { - return; - } + function sortRequestByPriority(a, b) { + return a._priority - b._priority; + } + + function requestTiles(tileset) { + // Sort requests by priority before making any requests. + // This makes it less likely that requests will be cancelled after being issued. var requestedTiles = tileset._requestedTiles; var length = requestedTiles.length; + requestedTiles.sort(sortRequestByPriority); for (var i = 0; i < length; ++i) { requestContent(tileset, requestedTiles[i]); } @@ -1487,16 +1442,14 @@ define([ return function() { --tileset._statistics.numberOfTilesProcessing; - if (tile.hasRenderableContent) { + if (!tile.hasTilesetContent) { // RESEARCH_IDEA: ability to unload tiles (without content) for an // external tileset when all the tiles are unloaded. tileset._statistics.incrementLoadCounts(tile.content); ++tileset._statistics.numberOfTilesWithContentReady; - // Add to the tile cache. Previously expired tiles are already in the cache. - if (!defined(tile.replacementNode)) { - tile.replacementNode = tileset._replacementList.add(tile); - } + // Add to the tile cache. Previously expired tiles are already in the cache and won't get re-added. + tileset._cache.add(tile); } tileset.tileLoad.raiseEvent(tile); @@ -1549,7 +1502,7 @@ define([ } function computeTileLabelPosition(tile) { - var boundingVolume = tile._boundingVolume.boundingVolume; + var boundingVolume = tile.boundingVolume.boundingVolume; var halfAxes = boundingVolume.halfAxes; var radius = boundingVolume.radius; @@ -1619,8 +1572,12 @@ define([ } function updateTileDebugLabels(tileset, frameState) { + var i; + var tile; var selectedTiles = tileset._selectedTiles; - var length = selectedTiles.length; + var selectedLength = selectedTiles.length; + var emptyTiles = tileset._emptyTiles; + var emptyLength = emptyTiles.length; tileset._tileDebugLabels.removeAll(); if (tileset.debugPickedTileLabelOnly) { @@ -1630,10 +1587,16 @@ define([ label.pixelOffset = new Cartesian2(15, -15); // Offset to avoid picking the label. } } else { - for (var i = 0; i < length; ++i) { - var tile = selectedTiles[i]; + for (i = 0; i < selectedLength; ++i) { + tile = selectedTiles[i]; addTileDebugLabel(tile, tileset, computeTileLabelPosition(tile)); } + for (i = 0; i < emptyLength; ++i) { + tile = emptyTiles[i]; + if (tile.hasTilesetContent) { + addTileDebugLabel(tile, tileset, computeTileLabelPosition(tile)); + } + } } tileset._tileDebugLabels.update(frameState); } @@ -1650,11 +1613,14 @@ define([ var commandList = frameState.commandList; var numberOfInitialCommands = commandList.length; var selectedTiles = tileset._selectedTiles; - var length = selectedTiles.length; + var selectedLength = selectedTiles.length; + var emptyTiles = tileset._emptyTiles; + var emptyLength = emptyTiles.length; var tileVisible = tileset.tileVisible; var i; + var tile; - var bivariateVisibilityTest = tileset._skipLevelOfDetail && tileset._hasMixedContent && frameState.context.stencilBuffer && length > 0; + var bivariateVisibilityTest = tileset._skipLevelOfDetail && tileset._hasMixedContent && frameState.context.stencilBuffer && selectedLength > 0; tileset._backfaceCommands.length = 0; @@ -1663,18 +1629,20 @@ define([ } var lengthBeforeUpdate = commandList.length; - for (i = 0; i < length; ++i) { - var tile = selectedTiles[i]; - // tiles may get unloaded and destroyed between selection and update - if (tile.selected) { - // Raise the tileVisible event before update in case the tileVisible event - // handler makes changes that update needs to apply to WebGL resources - tileVisible.raiseEvent(tile); - tile.update(tileset, frameState); - statistics.incrementSelectionCounts(tile.content); - ++statistics.selected; - } + for (i = 0; i < selectedLength; ++i) { + tile = selectedTiles[i]; + // Raise the tileVisible event before update in case the tileVisible event + // handler makes changes that update needs to apply to WebGL resources + tileVisible.raiseEvent(tile); + tile.update(tileset, frameState); + statistics.incrementSelectionCounts(tile.content); + ++statistics.selected; + } + for (i = 0; i < emptyLength; ++i) { + tile = emptyTiles[i]; + tile.update(tileset, frameState); } + var lengthAfterUpdate = commandList.length; var addedCommandsLength = lengthAfterUpdate - lengthBeforeUpdate; @@ -1756,52 +1724,27 @@ define([ stack.push(children[i]); } if (tile !== root) { - unloadTileFromCache(tileset, tile); - tile.destroy(); + destroyTile(tileset, tile); --statistics.numberOfTilesTotal; } } root.children = []; } - function unloadTileFromCache(tileset, tile) { - var node = tile.replacementNode; - if (!defined(node)) { - return; - } - - var statistics = tileset._statistics; - var replacementList = tileset._replacementList; - var tileUnload = tileset.tileUnload; + function unloadTile(tileset, tile) { + tileset.tileUnload.raiseEvent(tile); + tileset._statistics.decrementLoadCounts(tile.content); + --tileset._statistics.numberOfTilesWithContentReady; + tile.unloadContent(); + } - tileUnload.raiseEvent(tile); - replacementList.remove(node); - statistics.decrementLoadCounts(tile.content); - --statistics.numberOfTilesWithContentReady; + function destroyTile(tileset, tile) { + tileset._cache.unloadTile(tileset, tile, unloadTile); + tile.destroy(); } function unloadTiles(tileset) { - var trimTiles = tileset._trimTiles; - tileset._trimTiles = false; - - var replacementList = tileset._replacementList; - - var totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes; - var maximumMemoryUsageInBytes = tileset._maximumMemoryUsage * 1024 * 1024; - - // Traverse the list only to the sentinel since tiles/nodes to the - // right of the sentinel were used this frame. - // - // The sub-list to the left of the sentinel is ordered from LRU to MRU. - var sentinel = tileset._replacementSentinel; - var node = replacementList.head; - while ((node !== sentinel) && ((totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) { - var tile = node.item; - node = node.next; - unloadTileFromCache(tileset, tile); - tile.unloadContent(); - totalMemoryUsageInBytes = tileset.totalMemoryUsageInBytes; - } + tileset._cache.unloadTiles(tileset, unloadTile); } /** @@ -1814,8 +1757,7 @@ define([ *

*/ Cesium3DTileset.prototype.trimLoadedTiles = function() { - // Defer to next frame so WebGL delete calls happen inside the render loop - this._trimTiles = true; + this._cache.trim(); }; /////////////////////////////////////////////////////////////////////////// @@ -1871,27 +1813,34 @@ define([ this._timeSinceLoad = Math.max(JulianDate.secondsDifference(frameState.time, this._loadTimestamp) * 1000, 0.0); - this._skipLevelOfDetail = this.skipLevelOfDetail && !defined(this._classificationType) && !this._disableSkipLevelOfDetail; + this._skipLevelOfDetail = this.skipLevelOfDetail && !defined(this._classificationType) && !this._disableSkipLevelOfDetail && !this._allTilesAdditive; // Do not do out-of-core operations (new content requests, cache removal, // process new tiles) during the pick pass. var passes = frameState.passes; - var isPick = (passes.pick && !passes.render); - var outOfCore = !isPick; + var isRender = passes.render; + var isPick = passes.pick; + var outOfCore = isRender; var statistics = this._statistics; statistics.clear(); + if (this.dynamicScreenSpaceError) { + updateDynamicScreenSpaceError(this, frameState); + } + if (outOfCore) { - processTiles(this, frameState); + this._cache.reset(); } - if (this.dynamicScreenSpaceError) { - updateDynamicScreenSpaceError(this, frameState); + this._requestedTiles.length = 0; + Cesium3DTilesetTraversal.selectTiles(this, frameState); + + if (outOfCore) { + requestTiles(this); + processTiles(this, frameState); } - Cesium3DTilesetTraversal.selectTiles(this, frameState, outOfCore); - requestTiles(this, outOfCore); updateTiles(this, frameState); if (outOfCore) { diff --git a/Source/Scene/Cesium3DTilesetCache.js b/Source/Scene/Cesium3DTilesetCache.js new file mode 100644 index 000000000000..848a41da2529 --- /dev/null +++ b/Source/Scene/Cesium3DTilesetCache.js @@ -0,0 +1,79 @@ +define([ + '../Core/defined', + '../Core/DoublyLinkedList' + ], function( + defined, + DoublyLinkedList) { + 'use strict'; + + /** + * Stores tiles with content loaded. + * + * @private + */ + function Cesium3DTilesetCache() { + // [head, sentinel) -> tiles that weren't selected this frame and may be removed from the cache + // (sentinel, tail] -> tiles that were selected this frame + this._list = new DoublyLinkedList(); + this._sentinel = this._list.add(); + this._trimTiles = false; + } + + Cesium3DTilesetCache.prototype.reset = function() { + // Move sentinel node to the tail so, at the start of the frame, all tiles + // may be potentially replaced. Tiles are moved to the right of the sentinel + // when they are selected so they will not be replaced. + this._list.splice(this._list.tail, this._sentinel); + }; + + Cesium3DTilesetCache.prototype.touch = function(tile) { + var node = tile.cacheNode; + if (defined(node)) { + this._list.splice(this._sentinel, node); + } + }; + + Cesium3DTilesetCache.prototype.add = function(tile) { + if (!defined(tile.cacheNode)) { + tile.cacheNode = this._list.add(tile); + } + }; + + Cesium3DTilesetCache.prototype.unloadTile = function(tileset, tile, unloadCallback) { + var node = tile.cacheNode; + if (!defined(node)) { + return; + } + + this._list.remove(node); + tile.cacheNode = undefined; + unloadCallback(tileset, tile); + }; + + Cesium3DTilesetCache.prototype.unloadTiles = function(tileset, unloadCallback) { + var trimTiles = this._trimTiles; + this._trimTiles = false; + + var list = this._list; + + var maximumMemoryUsageInBytes = tileset.maximumMemoryUsage * 1024 * 1024; + + // Traverse the list only to the sentinel since tiles/nodes to the + // right of the sentinel were used this frame. + // + // The sub-list to the left of the sentinel is ordered from LRU to MRU. + var sentinel = this._sentinel; + var node = list.head; + while ((node !== sentinel) && ((tileset.totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) { + var tile = node.item; + node = node.next; + this.unloadTile(tileset, tile, unloadCallback); + } + }; + + Cesium3DTilesetCache.prototype.trim = function() { + this._trimTiles = true; + }; + + return Cesium3DTilesetCache; +}); diff --git a/Source/Scene/Cesium3DTilesetTraversal.js b/Source/Scene/Cesium3DTilesetTraversal.js index 3052b00ddb79..ef5eaff01521 100644 --- a/Source/Scene/Cesium3DTilesetTraversal.js +++ b/Source/Scene/Cesium3DTilesetTraversal.js @@ -1,23 +1,25 @@ define([ '../Core/CullingVolume', + '../Core/defaultValue', '../Core/defined', '../Core/freezeObject', '../Core/Intersect', '../Core/ManagedArray', '../Core/Math', '../Core/OrthographicFrustum', - './Cesium3DTileChildrenVisibility', + './Cesium3DTileOptimizationHint', './Cesium3DTileRefine', './SceneMode' ], function( CullingVolume, + defaultValue, defined, freezeObject, Intersect, ManagedArray, CesiumMath, OrthographicFrustum, - Cesium3DTileChildrenVisibility, + Cesium3DTileOptimizationHint, Cesium3DTileRefine, SceneMode) { 'use strict'; @@ -25,832 +27,609 @@ define([ /** * @private */ - var Cesium3DTilesetTraversal = {}; + function Cesium3DTilesetTraversal() { + } - function selectTiles(tileset, frameState, outOfCore) { - if (tileset.debugFreezeFrame) { - return; - } + function isVisible(tile) { + return tile._visible && tile._inRequestVolume; + } - var maximumScreenSpaceError = tileset._maximumScreenSpaceError; + var traversal = { + stack : new ManagedArray(), + stackMaximumLength : 0 + }; - tileset._desiredTiles.length = 0; - tileset._selectedTiles.length = 0; - tileset._requestedTiles.length = 0; - tileset._selectedTilesToStyle.length = 0; - tileset._hasMixedContent = false; + var emptyTraversal = { + stack : new ManagedArray(), + stackMaximumLength : 0 + }; + + var descendantTraversal = { + stack : new ManagedArray(), + stackMaximumLength : 0 + }; - // Move sentinel node to the tail so, at the start of the frame, all tiles - // may be potentially replaced. Tiles are moved to the right of the sentinel - // when they are selected so they will not be replaced. - var replacementList = tileset._replacementList; - replacementList.splice(replacementList.tail, tileset._replacementSentinel); + var selectionTraversal = { + stack : new ManagedArray(), + stackMaximumLength : 0, + ancestorStack : new ManagedArray(), + ancestorStackMaximumLength : 0 + }; - var root = tileset._root; - root.updateTransform(tileset._modelMatrix); + var descendantSelectionDepth = 2; - if (!root.insideViewerRequestVolume(frameState)) { + Cesium3DTilesetTraversal.selectTiles = function(tileset, frameState) { + if (tileset.debugFreezeFrame) { return; } - root._distanceToCamera = root.distanceToTile(frameState); + tileset._selectedTiles.length = 0; + tileset._selectedTilesToStyle.length = 0; + tileset._emptyTiles.length = 0; + tileset._hasMixedContent = false; + + var root = tileset.root; + updateTile(tileset, root, frameState); - if (getScreenSpaceError(tileset, tileset._geometricError, root, frameState) <= maximumScreenSpaceError) { - // The SSE of not rendering the tree is small enough that the tree does not need to be rendered + // The root tile is not visible + if (!isVisible(root)) { return; } - root._visibilityPlaneMask = root.visibility(frameState, CullingVolume.MASK_INDETERMINATE); - if (root._visibilityPlaneMask === CullingVolume.MASK_OUTSIDE) { + // The tileset doesn't meet the SSE requirement, therefore the tree does not need to be rendered + if (getScreenSpaceError(tileset, tileset._geometricError, root, frameState) <= tileset._maximumScreenSpaceError) { return; } - loadTile(tileset, root, frameState, true); - - if (!tileset._skipLevelOfDetail) { - // just execute base traversal and add tiles to _desiredTiles - tileset._baseTraversal.execute(tileset, root, maximumScreenSpaceError, frameState, outOfCore); - var leaves = tileset._baseTraversal.leaves; - var length = leaves.length; - for (var i = 0; i < length; ++i) { - tileset._desiredTiles.push(leaves.get(i)); - } + if (!skipLevelOfDetail(tileset)) { + executeBaseTraversal(tileset, root, frameState); } else if (tileset.immediatelyLoadDesiredLevelOfDetail) { - tileset._skipTraversal.execute(tileset, root, frameState, outOfCore); + executeSkipTraversal(tileset, root, frameState); } else { - // leaves of the base traversal is where we start the skip traversal - tileset._baseTraversal.leaves = tileset._skipTraversal.queue1; - - // load and select tiles without skipping up to tileset.baseScreenSpaceError - tileset._baseTraversal.execute(tileset, root, tileset.baseScreenSpaceError, frameState, outOfCore); - - // skip traversal starts from a prepopulated queue from the base traversal - tileset._skipTraversal.execute(tileset, undefined, frameState, outOfCore); + executeBaseAndSkipTraversal(tileset, root, frameState); } - // mark tiles for selection or their nearest loaded ancestor - markLoadedTilesForSelection(tileset, frameState, outOfCore); - - // sort selected tiles by distance to camera and call selectTile on each - // set tile._selectionDepth on all tiles - traverseAndSelect(tileset, root, frameState); + traversal.stack.trim(traversal.stackMaximumLength); + emptyTraversal.stack.trim(emptyTraversal.stackMaximumLength); + descendantTraversal.stack.trim(descendantTraversal.stackMaximumLength); + selectionTraversal.stack.trim(selectionTraversal.stackMaximumLength); + selectionTraversal.ancestorStack.trim(selectionTraversal.ancestorStackMaximumLength); + }; - tileset._desiredTiles.trim(); + function executeBaseTraversal(tileset, root, frameState) { + var baseScreenSpaceError = tileset._maximumScreenSpaceError; + var maximumScreenSpaceError = tileset._maximumScreenSpaceError; + executeTraversal(tileset, root, baseScreenSpaceError, maximumScreenSpaceError, frameState); } - var descendantStack = []; - - function markLoadedTilesForSelection(tileset, frameState, outOfCore) { - var tiles = tileset._desiredTiles; - var length = tiles.length; - for (var i = 0; i < length; ++i) { - var original = tiles.get(i); - - if (hasAdditiveContent(original)) { - original.selected = true; - original._selectedFrame = frameState.frameNumber; - continue; - } - - var loadedTile = original._ancestorWithLoadedContent; - if (original.hasRenderableContent && original.contentAvailable) { - loadedTile = original; - } - - if (defined(loadedTile)) { - loadedTile.selected = true; - loadedTile._selectedFrame = frameState.frameNumber; - } else { - // if no ancestors are ready, traverse down and select ready tiles to minimize empty regions - descendantStack.push(original); - while (descendantStack.length > 0) { - var tile = descendantStack.pop(); - var children = tile.children; - var childrenLength = children.length; - for (var j = 0; j < childrenLength; ++j) { - var child = children[j]; - touch(tileset, child, outOfCore); - if (child.contentAvailable) { - child.selected = true; - child._finalResolution = true; - child._selectedFrame = frameState.frameNumber; - } - if (child._depth - original._depth < 2) { // prevent traversing too far - if (!child.contentAvailable || child.refine === Cesium3DTileRefine.ADD) { - descendantStack.push(child); - } - } - } - } - } - } + function executeSkipTraversal(tileset, root, frameState) { + var baseScreenSpaceError = Number.MAX_VALUE; + var maximumScreenSpaceError = tileset._maximumScreenSpaceError; + executeTraversal(tileset, root, baseScreenSpaceError, maximumScreenSpaceError, frameState); + traverseAndSelect(tileset, root, frameState); } - var scratchStack = []; - var scratchStack2 = []; - - /** - * Traverse the tree while tiles are visible and check if their selected frame is the current frame. - * If so, add it to a selection queue. - * Tiles are sorted near to far so we can take advantage of early Z. - * Furthermore, this is a preorder traversal so children tiles are selected before ancestor tiles. - * - * The reason for the preorder traversal is so that tiles can easily be marked with their - * selection depth. A tile's _selectionDepth is its depth in the tree where all non-selected tiles are removed. - * This property is important for use in the stencil test because we want to render deeper tiles on top of their - * ancestors. If a tileset is very deep, the depth is unlikely to fit into the stencil buffer. - * - * We want to select children before their ancestors because there is no guarantee on the relationship between - * the children's z-depth and the ancestor's z-depth. We cannot rely on Z because we want the child to appear on top - * of ancestor regardless of true depth. The stencil tests used require children to be drawn first. @see {@link updateTiles} - * - * NOTE: this will no longer work when there is a chain of selected tiles that is longer than the size of the - * stencil buffer (usually 8 bits). In other words, the subset of the tree containing only selected tiles must be - * no deeper than 255. It is very, very unlikely this will cause a problem. - * - * NOTE: when the scene has inverted classification enabled, the stencil buffer will be masked to 4 bits. So, the - * selected tiles must be no deeper than 15. This is still very unlikely. - */ - function traverseAndSelect(tileset, root, frameState) { - var stack = scratchStack; - var ancestorStack = scratchStack2; - - var lastAncestor; - stack.push(root); - while (stack.length > 0 || ancestorStack.length > 0) { - if (ancestorStack.length > 0) { - var waitingTile = ancestorStack[ancestorStack.length - 1]; - if (waitingTile._stackLength === stack.length) { - ancestorStack.pop(); - if (waitingTile === lastAncestor) { - waitingTile._finalResolution = true; - } - selectTile(tileset, waitingTile, frameState); - continue; - } - } - - var tile = stack.pop(); - if (!defined(tile) || !isVisited(tile, frameState)) { - continue; - } - - var shouldSelect = tile.selected && tile._selectedFrame === frameState.frameNumber && tile.hasRenderableContent; - - var children = tile.children; - var childrenLength = children.length; - - children.sort(sortChildrenByDistanceToCamera); - - if (shouldSelect) { - if (tile.refine === Cesium3DTileRefine.ADD) { - tile._finalResolution = true; - selectTile(tileset, tile, frameState); - } else { - tile._selectionDepth = ancestorStack.length; - - if (tile._selectionDepth > 0) { - tileset._hasMixedContent = true; - } - - lastAncestor = tile; + function executeBaseAndSkipTraversal(tileset, root, frameState) { + var baseScreenSpaceError = Math.max(tileset.baseScreenSpaceError, tileset.maximumScreenSpaceError); + var maximumScreenSpaceError = tileset.maximumScreenSpaceError; + executeTraversal(tileset, root, baseScreenSpaceError, maximumScreenSpaceError, frameState); + traverseAndSelect(tileset, root, frameState); + } - if (childrenLength === 0) { - tile._finalResolution = true; - selectTile(tileset, tile, frameState); - continue; - } + function skipLevelOfDetail(tileset) { + return tileset._skipLevelOfDetail; + } - ancestorStack.push(tile); - tile._stackLength = stack.length; - } - } + function addEmptyTile(tileset, tile) { + tileset._emptyTiles.push(tile); + } - for (var i = 0; i < childrenLength; ++i) { - var child = children[i]; - stack.push(child); - } - } + function contentVisible(tile, frameState) { + return (tile._visibilityPlaneMask === CullingVolume.MASK_INSIDE) || + (tile.contentVisibility(frameState) !== Intersect.OUTSIDE); } function selectTile(tileset, tile, frameState) { - // There may also be a tight box around just the tile's contents, e.g., for a city, we may be - // zoomed into a neighborhood and can cull the skyscrapers in the root tile. - if (tile.contentAvailable && ( - (tile._visibilityPlaneMask === CullingVolume.MASK_INSIDE) || - (tile.contentVisibility(frameState) !== Intersect.OUTSIDE) - )) { - tileset._selectedTiles.push(tile); - + if (contentVisible(tile, frameState)) { var tileContent = tile.content; if (tileContent.featurePropertiesDirty) { // A feature's property in this tile changed, the tile needs to be re-styled. tileContent.featurePropertiesDirty = false; tile.lastStyleTime = 0; // Force applying the style to this tile tileset._selectedTilesToStyle.push(tile); - } else if ((tile._lastSelectedFrameNumber !== frameState.frameNumber - 1) || tile.lastStyleTime === 0) { + } else if ((tile._selectedFrame < frameState.frameNumber - 1)) { // Tile is newly selected; it is selected this frame, but was not selected last frame. tileset._selectedTilesToStyle.push(tile); } - tile._lastSelectedFrameNumber = frameState.frameNumber; + tile._selectedFrame = frameState.frameNumber; + tileset._selectedTiles.push(tile); } } - // PERFORMANCE_IDEA: is it worth exploiting frame-to-frame coherence in the sort, i.e., the - // list of children are probably fully or mostly sorted unless the camera moved significantly? - function sortChildrenByDistanceToCamera(a, b) { - // Sort by farthest child first since this is going on a stack - if (b._distanceToCamera === 0 && a._distanceToCamera === 0) { - return b._centerZDepth - a._centerZDepth; + function selectDescendants(tileset, root, frameState) { + var stack = descendantTraversal.stack; + stack.push(root); + while (stack.length > 0) { + descendantTraversal.stackMaximumLength = Math.max(descendantTraversal.stackMaximumLength, stack.length); + var tile = stack.pop(); + var children = tile.children; + var childrenLength = children.length; + for (var i = 0; i < childrenLength; ++i) { + var child = children[i]; + if (child.contentAvailable) { + updateTile(tileset, child, frameState); + touchTile(tileset, child, frameState); + selectTile(tileset, child, frameState); + } else if (child._depth - root._depth < descendantSelectionDepth) { + // Continue traversing, but not too far + stack.push(child); + } + } } - - return b._distanceToCamera - a._distanceToCamera; } - var emptyArray = freezeObject([]); - - function BaseTraversal() { - this.tileset = undefined; - this.frameState = undefined; - this.outOfCore = undefined; - this.stack = new ManagedArray(); - this.leaves = new ManagedArray(); - this.baseScreenSpaceError = undefined; - this.internalDFS = new InternalBaseTraversal(); - } - - BaseTraversal.prototype.execute = function(tileset, root, baseScreenSpaceError, frameState, outOfCore) { - this.tileset = tileset; - this.frameState = frameState; - this.outOfCore = outOfCore; - this.leaves.length = 0; - this.baseScreenSpaceError = Math.max(baseScreenSpaceError, this.tileset._maximumScreenSpaceError); - this.internalDFS.tileset = this.tileset; - this.internalDFS.frameState = this.frameState; - this.internalDFS.outOfCore = this.outOfCore; - this.internalDFS.baseScreenSpaceError = this.baseScreenSpaceError; - depthFirstSearch(root, this); - }; - - BaseTraversal.prototype.visitStart = function(tile) { - if (!isVisited(tile, this.frameState)) { - visitTile(this.tileset, tile, this.frameState, this.outOfCore); - } - }; - - BaseTraversal.prototype.visitEnd = function(tile) { - tile._lastVisitedFrame = this.frameState.frameNumber; - }; - - BaseTraversal.prototype.getChildren = function(tile) { - var tileset = this.tileset; - var outOfCore = this.outOfCore; - var frameState = this.frameState; - if (!baseUpdateAndCheckChildren(tileset, tile, this.baseScreenSpaceError, frameState)) { - return emptyArray; - } - - var children = tile.children; - var childrenLength = children.length; - var allReady = true; - var replacementWithContent = tile.refine === Cesium3DTileRefine.REPLACE && tile.hasRenderableContent; - for (var i = 0; i < childrenLength; ++i) { - var child = children[i]; - loadTile(tileset, child, frameState, true); - touch(tileset, child, outOfCore); - - // content cannot be replaced until all of the nearest descendants with content are all loaded - if (replacementWithContent) { - if (!child.hasEmptyContent) { - allReady = allReady && child.contentAvailable; - } else { - allReady = allReady && this.internalDFS.execute(child); - } + function selectDesiredTile(tileset, tile, frameState) { + if (!skipLevelOfDetail(tileset)) { + if (tile.contentAvailable) { + // The tile can be selected right away and does not require traverseAndSelect + selectTile(tileset, tile, frameState); } + return; } - if (allReady) { - return children; + // If this tile is not loaded attempt to select its ancestor instead + var loadedTile = tile.contentAvailable ? tile : tile._ancestorWithContentAvailable; + if (defined(loadedTile)) { + // Tiles will actually be selected in traverseAndSelect + loadedTile._shouldSelect = true; + } else { + // If no ancestors are ready traverse down and select tiles to minimize empty regions. + // This happens often for immediatelyLoadDesiredLevelOfDetail where parent tiles are not necessarily loaded before zooming out. + selectDescendants(tileset, tile, frameState); } + } - return emptyArray; - }; + function visitTile(tileset, tile, frameState) { + ++tileset._statistics.visited; + tile._visitedFrame = frameState.frameNumber; + } - function baseUpdateAndCheckChildren(tileset, tile, baseScreenSpaceError, frameState) { - if (hasAdditiveContent(tile)) { - tileset._desiredTiles.push(tile); + function touchTile(tileset, tile, frameState) { + if (tile._touchedFrame === frameState.frameNumber) { + // Prevents another pass from touching the frame again + return; } + tileset._cache.touch(tile); + tile._touchedFrame = frameState.frameNumber; + } - // Stop traversal on the subtree since it will be destroyed - if (tile.hasTilesetContent && tile.contentExpired) { - return false; + function getPriority(tileset, tile) { + // If skipLevelOfDetail is off try to load child tiles as soon as possible so that their parent can refine sooner. + // Additive tiles are prioritized by distance because it subjectively looks better. + // Replacement tiles are prioritized by screen space error. + // A tileset that has both additive and replacement tiles may not prioritize tiles as effectively since SSE and distance + // are different types of values. Maybe all priorities need to be normalized to 0-1 range. + if (tile.refine === Cesium3DTileRefine.ADD) { + return tile._distanceToCamera; } + var parent = tile.parent; + var useParentScreenSpaceError = defined(parent) && (!skipLevelOfDetail(tileset) || (tile._screenSpaceError === 0.0)); + var screenSpaceError = useParentScreenSpaceError ? parent._screenSpaceError : tile._screenSpaceError; + var rootScreenSpaceError = tileset.root._screenSpaceError; + return rootScreenSpaceError - screenSpaceError; // Map higher SSE to lower values (e.g. root tile is highest priority) + } - // stop traversal when we've attained the desired level of error - if (tile._screenSpaceError <= baseScreenSpaceError && !tile.hasTilesetContent) { - // update children so the leaf handler can check if any are visible for the children union bound optimization - updateChildren(tile, frameState); - return false; + function loadTile(tileset, tile, frameState) { + if (hasUnloadedContent(tile) || tile.contentExpired) { + tile._requestedFrame = frameState.frameNumber; + tile._priority = getPriority(tileset, tile); + tileset._requestedTiles.push(tile); } + } - var childrenVisibility = updateChildren(tile, frameState); - var showAdditive = tile.refine === Cesium3DTileRefine.ADD; - var showReplacement = tile.refine === Cesium3DTileRefine.REPLACE && (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE_IN_REQUEST_VOLUME) !== 0; + function getScreenSpaceError(tileset, geometricError, tile, frameState) { + if (geometricError === 0.0) { + // Leaf tiles do not have any error so save the computation + return 0.0; + } - return showAdditive || showReplacement || tile.hasTilesetContent || !defined(tile._ancestorWithContent); - } + var camera = frameState.camera; + var frustum = camera.frustum; + var context = frameState.context; + var height = context.drawingBufferHeight; - BaseTraversal.prototype.shouldVisit = function(tile) { - return isVisible(tile._visibilityPlaneMask); - }; + var error; + if (frameState.mode === SceneMode.SCENE2D || frustum instanceof OrthographicFrustum) { + if (defined(frustum._offCenterFrustum)) { + frustum = frustum._offCenterFrustum; + } + var width = context.drawingBufferWidth; + var pixelSize = Math.max(frustum.top - frustum.bottom, frustum.right - frustum.left) / Math.max(width, height); + error = geometricError / pixelSize; + } else { + // Avoid divide by zero when viewer is inside the tile + var distance = Math.max(tile._distanceToCamera, CesiumMath.EPSILON7); + var sseDenominator = camera.frustum.sseDenominator; + error = (geometricError * height) / (distance * sseDenominator); - BaseTraversal.prototype.leafHandler = function(tile) { - // if skipLevelOfDetail is off, leaves of the base traversal get pushed to tileset._desiredTiles. additive tiles have already been pushed - if (this.tileset._skipLevelOfDetail || !hasAdditiveContent(tile)) { - if (tile.refine === Cesium3DTileRefine.REPLACE && !childrenAreVisible(tile)) { - ++this.tileset._statistics.numberOfTilesCulledWithChildrenUnion; - return; + if (tileset.dynamicScreenSpaceError) { + var density = tileset._dynamicScreenSpaceErrorComputedDensity; + var factor = tileset.dynamicScreenSpaceErrorFactor; + var dynamicError = CesiumMath.fog(distance, density) * factor; + error -= dynamicError; } - this.leaves.push(tile); } - }; - function InternalBaseTraversal() { - this.tileset = undefined; - this.frameState = undefined; - this.outOfCore = undefined; - this.baseScreenSpaceError = undefined; - this.stack = new ManagedArray(); - this.allLoaded = undefined; + return error; } - InternalBaseTraversal.prototype.execute = function(root) { - this.allLoaded = true; - depthFirstSearch(root, this); - return this.allLoaded; - }; - - InternalBaseTraversal.prototype.visitStart = function(tile) { - if (!isVisited(tile, this.frameState)) { - visitTile(this.tileset, tile, this.frameState, this.outOfCore); + function updateVisibility(tileset, tile, frameState) { + if (tile._updatedVisibilityFrame === frameState.frameNumber) { + // Return early if visibility has already been checked during the traversal. + // The visibility may have already been checked if the cullWithChildrenBounds optimization is used. + return; } - }; - InternalBaseTraversal.prototype.visitEnd = BaseTraversal.prototype.visitEnd; - - // Continue traversing until we have renderable content. We want the first descendants with content of the root to load - InternalBaseTraversal.prototype.shouldVisit = function(tile) { - return !tile.hasRenderableContent && isVisible(tile._visibilityPlaneMask); - }; - - InternalBaseTraversal.prototype.getChildren = function(tile) { - var tileset = this.tileset; - var frameState = this.frameState; - var outOfCore = this.outOfCore; - - if (!baseUpdateAndCheckChildren(tileset, tile, this.baseScreenSpaceError, frameState)) { - return emptyArray; - } + var parent = tile.parent; + var parentTransform = defined(parent) ? parent.computedTransform : tileset._modelMatrix; + var parentVisibilityPlaneMask = defined(parent) ? parent._visibilityPlaneMask : CullingVolume.MASK_INDETERMINATE; + + tile.updateTransform(parentTransform); + tile._distanceToCamera = tile.distanceToTile(frameState); + tile._centerZDepth = tile.distanceToTileCenter(frameState); + tile._screenSpaceError = getScreenSpaceError(tileset, tile.geometricError, tile, frameState); + tile._visibilityPlaneMask = tile.visibility(frameState, parentVisibilityPlaneMask); // Use parent's plane mask to speed up visibility test + tile._visible = tile._visibilityPlaneMask !== CullingVolume.MASK_OUTSIDE; + tile._inRequestVolume = tile.insideViewerRequestVolume(frameState); + tile._updatedVisibilityFrame = frameState.frameNumber; + } + function anyChildrenVisible(tileset, tile, frameState) { + var anyVisible = false; var children = tile.children; - var childrenLength = children.length; - for (var i = 0; i < childrenLength; ++i) { + var length = children.length; + for (var i = 0; i < length; ++i) { var child = children[i]; - loadTile(tileset, child, frameState, true); - touch(tileset, child, outOfCore); - if (!tile.contentAvailable) { - this.allLoaded = false; - } + updateVisibility(tileset, child, frameState); + anyVisible = anyVisible || isVisible(child); } - return children; - }; - - InternalBaseTraversal.prototype.updateAndCheckChildren = BaseTraversal.prototype.updateAndCheckChildren; - - function SkipTraversal(options) { - this.tileset = undefined; - this.frameState = undefined; - this.outOfCore = undefined; - this.queue1 = new ManagedArray(); - this.queue2 = new ManagedArray(); - this.internalDFS = new InternalSkipTraversal(options.selectionHeuristic); - this.maxChildrenLength = 0; - this.scratchQueue = new ManagedArray(); + return anyVisible; } - SkipTraversal.prototype.execute = function(tileset, root, frameState, outOfCore) { - this.tileset = tileset; - this.frameState = frameState; - this.outOfCore = outOfCore; - this.internalDFS.frameState = frameState; - this.internalDFS.outOfCore = outOfCore; - - this.maxChildrenLength = 0; - breadthFirstSearch(root, this); - this.queue1.length = 0; - this.queue2.length = 0; - this.scratchQueue.length = 0; - this.scratchQueue.trim(this.maxChildrenLength); - }; + function updateTileVisibility(tileset, tile, frameState) { + updateVisibility(tileset, tile, frameState); - SkipTraversal.prototype.visitStart = function(tile) { - if (!isVisited(tile, this.frameState)) { - visitTile(this.tileset, tile, this.frameState, this.outOfCore); + if (!isVisible(tile)) { + return; } - }; - - SkipTraversal.prototype.visitEnd = BaseTraversal.prototype.visitEnd; - SkipTraversal.prototype.getChildren = function(tile) { - this.scratchQueue.length = 0; - this.internalDFS.execute(tile, this.scratchQueue); - this.maxChildrenLength = Math.max(this.maxChildrenLength, this.scratchQueue.length); - return this.scratchQueue; - }; - - SkipTraversal.prototype.leafHandler = function(tile) { - // additive tiles have already been pushed - if (!hasAdditiveContent(tile) && !isVisited(tile, this.frameState)) { - this.tileset._desiredTiles.push(tile); + // Use parent's geometric error with child's box to see if the tile already meet the SSE + var parent = tile.parent; + if (defined(parent) && (parent.refine === Cesium3DTileRefine.ADD) && getScreenSpaceError(tileset, parent.geometricError, tile, frameState) <= tileset._maximumScreenSpaceError) { + tile._visible = false; + return; } - }; - - function InternalSkipTraversal(selectionHeuristic) { - this.selectionHeuristic = selectionHeuristic; - this.tileset = undefined; - this.frameState = undefined; - this.outOfCore = undefined; - this.root = undefined; - this.queue = undefined; - this.stack = new ManagedArray(); - } - - InternalSkipTraversal.prototype.execute = function(root, queue) { - this.tileset = root._tileset; - this.root = root; - this.queue = queue; - depthFirstSearch(root, this); - }; - InternalSkipTraversal.prototype.visitStart = function(tile) { - if (!isVisited(tile, this.frameState)) { - visitTile(this.tileset, tile, this.frameState, this.outOfCore); + // Optimization - if none of the tile's children are visible then this tile isn't visible + var replace = tile.refine === Cesium3DTileRefine.REPLACE; + var useOptimization = tile._optimChildrenWithinParent === Cesium3DTileOptimizationHint.USE_OPTIMIZATION; + var hasChildren = tile.children.length > 0; + if (replace && useOptimization && hasChildren) { + if (!anyChildrenVisible(tileset, tile, frameState)) { + ++tileset._statistics.numberOfTilesCulledWithChildrenUnion; + tile._visible = false; + return; + } } - }; + } - InternalSkipTraversal.prototype.visitEnd = BaseTraversal.prototype.visitEnd; + function updateTile(tileset, tile, frameState) { + updateTileVisibility(tileset, tile, frameState); + tile.updateExpiration(); - InternalSkipTraversal.prototype.getChildren = function(tile) { - var tileset = this.tileset; - var maximumScreenSpaceError = tileset._maximumScreenSpaceError; + tile._shouldSelect = false; + tile._finalResolution = true; + tile._ancestorWithContent = undefined; + tile._ancestorWithContentAvailable = undefined; - // Stop traversal on the subtree since it will be destroyed - if (tile.hasTilesetContent && tile.contentExpired) { - return emptyArray; + var parent = tile.parent; + if (defined(parent)) { + // ancestorWithContent is an ancestor that has content or has the potential to have + // content. Used in conjunction with tileset.skipLevels to know when to skip a tile. + // ancestorWithContentAvailable is an ancestor that is rendered if a desired tile is not loaded. + var hasContent = !hasUnloadedContent(parent) || (parent._requestedFrame === frameState.frameNumber); + tile._ancestorWithContent = hasContent ? parent : parent._ancestorWithContent; + tile._ancestorWithContentAvailable = parent.contentAvailable ? parent : parent._ancestorWithContentAvailable; } + } - if (!tile.hasTilesetContent) { - if (tile.refine === Cesium3DTileRefine.ADD) { - // Always load additive tiles - loadTile(tileset, tile, this.frameState, true); - if (hasAdditiveContent(tile)) { - tileset._desiredTiles.push(tile); - } - } + function hasEmptyContent(tile) { + return tile.hasEmptyContent || tile.hasTilesetContent; + } - // stop traversal when we've attained the desired level of error - if (tile._screenSpaceError <= maximumScreenSpaceError) { - updateChildren(tile, this.frameState); - return emptyArray; - } + function hasUnloadedContent(tile) { + return !hasEmptyContent(tile) && tile.contentUnloaded; + } - // if we have reached the skipping threshold without any loaded ancestors, return empty so this tile is loaded - if ( - (!tile.hasEmptyContent && tile.contentUnloaded) && - defined(tile._ancestorWithLoadedContent) && - this.selectionHeuristic(tileset, tile._ancestorWithLoadedContent, tile)) { - updateChildren(tile, this.frameState); - return emptyArray; - } + function reachedSkippingThreshold(tileset, tile) { + var ancestor = tile._ancestorWithContent; + return !tileset.immediatelyLoadDesiredLevelOfDetail && + defined(ancestor) && + (tile._screenSpaceError < (ancestor._screenSpaceError / tileset.skipScreenSpaceErrorFactor)) && + (tile._depth > (ancestor._depth + tileset.skipLevels)); + } + + function sortChildrenByDistanceToCamera(a, b) { + // Sort by farthest child first since this is going on a stack + if (b._distanceToCamera === 0 && a._distanceToCamera === 0) { + return b._centerZDepth - a._centerZDepth; } - var childrenVisibility = updateChildren(tile, this.frameState); - var showAdditive = tile.refine === Cesium3DTileRefine.ADD && tile._screenSpaceError > maximumScreenSpaceError; - var showReplacement = tile.refine === Cesium3DTileRefine.REPLACE && (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE_IN_REQUEST_VOLUME) !== 0; + return b._distanceToCamera - a._distanceToCamera; + } - // at least one child is visible, but is not in request volume. the parent must be selected - if (childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE_NOT_IN_REQUEST_VOLUME && tile.refine === Cesium3DTileRefine.REPLACE) { - this.tileset._desiredTiles.push(tile); - } + function updateAndPushChildren(tileset, tile, stack, frameState) { + var i; + var replace = tile.refine === Cesium3DTileRefine.REPLACE; + var children = tile.children; + var length = children.length; - if (showAdditive || showReplacement || tile.hasTilesetContent) { - var children = tile.children; - var childrenLength = children.length; - for (var i = 0; i < childrenLength; ++i) { - touch(tileset, children[i], this.outOfCore); - } - return children; + for (i = 0; i < length; ++i) { + updateTile(tileset, children[i], frameState); } - return emptyArray; - }; + // Sort by distance to take advantage of early Z and reduce artifacts for skipLevelOfDetail + children.sort(sortChildrenByDistanceToCamera); - InternalSkipTraversal.prototype.shouldVisit = function(tile) { - return isVisibleAndMeetsSSE(this.tileset, tile, this.frameState); - }; + // For traditional replacement refinement only refine if all children are loaded. + // Empty tiles are exempt since it looks better if children stream in as they are loaded to fill the empty space. + var checkRefines = !skipLevelOfDetail(tileset) && replace && !hasEmptyContent(tile); + var refines = true; - InternalSkipTraversal.prototype.leafHandler = function(tile) { - if (tile !== this.root) { - if (tile.refine === Cesium3DTileRefine.REPLACE && !childrenAreVisible(tile)) { - ++this.tileset._statistics.numberOfTilesCulledWithChildrenUnion; - return; + var anyChildrenVisible = false; + for (i = 0; i < length; ++i) { + var child = children[i]; + if (isVisible(child)) { + stack.push(child); + anyChildrenVisible = true; + } else if (checkRefines || tileset.loadSiblings) { + // Keep non-visible children loaded since they are still needed before the parent can refine. + // Or loadSiblings is true so always load tiles regardless of visibility. + loadTile(tileset, child, frameState); + touchTile(tileset, child, frameState); } - if (!tile.hasEmptyContent) { - if (this.tileset.loadSiblings) { - var parent = tile.parent; - var tiles = parent.children; - var length = tiles.length; - for (var i = 0; i < length; ++i) { - loadTile(this.tileset, tiles[i], this.frameState, false); - touch(this.tileset, tiles[i], this.outOfCore); - } + if (checkRefines) { + var childRefines; + if (!child._inRequestVolume) { + childRefines = false; + } else if (hasEmptyContent(child)) { + childRefines = executeEmptyTraversal(tileset, child, frameState); } else { - loadTile(this.tileset, tile, this.frameState, true); - touch(this.tileset, tile, this.outOfCore); + childRefines = child.contentAvailable; } + refines = refines && childRefines; } - this.queue.push(tile); - } else if (!hasAdditiveContent(tile)) { - // additive tiles have already been pushed - this.tileset._desiredTiles.push(tile); } - }; - function updateChildren(tile, frameState) { - if (isVisited(tile, frameState)) { - return tile._childrenVisibility; + if (!anyChildrenVisible) { + refines = false; } - var children = tile.children; - - updateTransforms(children, tile.computedTransform); - computeDistanceToCamera(children, frameState); - - return computeChildrenVisibility(tile, frameState); - } - - function isVisited(tile, frameState) { - // because the leaves of one tree traversal are the root of the subsequent traversal, avoid double visitation - return tile._lastVisitedFrame === frameState.frameNumber; - } - - function visitTile(tileset, tile, frameState, outOfCore) { - ++tileset._statistics.visited; - tile.selected = false; - tile._finalResolution = false; - computeSSE(tile, frameState); - touch(tileset, tile, outOfCore); - tile.updateExpiration(); - tile._ancestorWithContent = undefined; - tile._ancestorWithLoadedContent = undefined; - var parent = tile.parent; - if (defined(parent)) { - var replace = parent.refine === Cesium3DTileRefine.REPLACE; - tile._ancestorWithContent = (replace && parent.hasRenderableContent) ? parent : parent._ancestorWithContent; - tile._ancestorWithLoadedContent = (replace && parent.hasRenderableContent && parent.contentAvailable) ? parent : parent._ancestorWithLoadedContent; - } + return refines; } - function touch(tileset, tile, outOfCore) { - if (!outOfCore) { - return; + function inBaseTraversal(tileset, tile, baseScreenSpaceError) { + if (!skipLevelOfDetail(tileset)) { + return true; } - var node = tile.replacementNode; - if (defined(node)) { - tileset._replacementList.splice(tileset._replacementSentinel, node); + if (tileset.immediatelyLoadDesiredLevelOfDetail) { + return false; } - } - - function computeSSE(tile, frameState) { - if (tile._screenSpaceErrorComputedFrame !== frameState.frameNumber) { - tile._screenSpaceErrorComputedFrame = frameState.frameNumber; - tile._screenSpaceError = getScreenSpaceError(tile._tileset, tile.geometricError, tile, frameState); + if (!defined(tile._ancestorWithContent)) { + // Include root or near-root tiles in the base traversal so there is something to select up to + return true; } - } - - function checkAdditiveVisibility(tileset, tile, frameState) { - if (defined(tile.parent) && (tile.parent.refine === Cesium3DTileRefine.ADD)) { - return isVisibleAndMeetsSSE(tileset, tile, frameState); + if (tile._screenSpaceError === 0.0) { + // If a leaf, use parent's SSE + return tile.parent._screenSpaceError > baseScreenSpaceError; } - return true; + return tile._screenSpaceError > baseScreenSpaceError; } - function loadTile(tileset, tile, frameState, checkVisibility) { - if ((tile.contentUnloaded || tile.contentExpired) && tile._requestedFrame !== frameState.frameNumber) { - if (!checkVisibility || checkAdditiveVisibility(tileset, tile, frameState)) { - tile._requestedFrame = frameState.frameNumber; - tileset._requestedTiles.push(tile); - } - } - } + function executeTraversal(tileset, root, baseScreenSpaceError, maximumScreenSpaceError, frameState) { + // Depth-first traversal that traverses all visible tiles and marks tiles for selection. + // If skipLevelOfDetail is off then a tile does not refine until all children are loaded. + // This is the traditional replacement refinement approach and is called the base traversal. + // Tiles that have a greater screen space error than the base screen space error are part of the base traversal, + // all other tiles are part of the skip traversal. The skip traversal allows for skipping levels of the tree + // and rendering children and parent tiles simultaneously. + var stack = traversal.stack; + stack.push(root); - function computeChildrenVisibility(tile, frameState) { - var flag = Cesium3DTileChildrenVisibility.NONE; - var children = tile.children; - var childrenLength = children.length; - var visibilityPlaneMask = tile._visibilityPlaneMask; - for (var k = 0; k < childrenLength; ++k) { - var child = children[k]; + while (stack.length > 0) { + traversal.stackMaximumLength = Math.max(traversal.stackMaximumLength, stack.length); - var visibilityMask = child.visibility(frameState, visibilityPlaneMask); + var tile = stack.pop(); + var baseTraversal = inBaseTraversal(tileset, tile, baseScreenSpaceError); + var add = tile.refine === Cesium3DTileRefine.ADD; + var replace = tile.refine === Cesium3DTileRefine.REPLACE; + var children = tile.children; + var childrenLength = children.length; + var parent = tile.parent; + var parentRefines = !defined(parent) || parent._refines; + var traverse = (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError); + var refines = false; + + if (tile.hasTilesetContent && tile.contentExpired) { + // Don't traverse expired subtree because it will be destroyed + traverse = false; + } - if (isVisible(visibilityMask)) { - flag |= Cesium3DTileChildrenVisibility.VISIBLE; + if (traverse) { + refines = updateAndPushChildren(tileset, tile, stack, frameState) && parentRefines; } - if (!child.insideViewerRequestVolume(frameState)) { - if (isVisible(visibilityMask)) { - flag |= Cesium3DTileChildrenVisibility.VISIBLE_NOT_IN_REQUEST_VOLUME; - } - visibilityMask = CullingVolume.MASK_OUTSIDE; - } else { - flag |= Cesium3DTileChildrenVisibility.IN_REQUEST_VOLUME; - if (isVisible(visibilityMask)) { - flag |= Cesium3DTileChildrenVisibility.VISIBLE_IN_REQUEST_VOLUME; + if (hasEmptyContent(tile)) { + // Add empty tile just to show its debug bounding volume + // If the tile has tileset content load the external tileset + addEmptyTile(tileset, tile, frameState); + loadTile(tileset, tile, frameState); + } else if (add) { + // Additive tiles are always loaded and selected + selectDesiredTile(tileset, tile, frameState); + loadTile(tileset, tile, frameState); + } else if (replace) { + if (baseTraversal) { + // Always load tiles in the base traversal + // Select tiles that can't refine further + loadTile(tileset, tile, frameState); + if (!refines && parentRefines) { + selectDesiredTile(tileset, tile, frameState); + } + } else { + // Load tiles that are not skipped or can't refine further. In practice roughly half the tiles stay unloaded. + // Select tiles that can't refine further. If the tile doesn't have loaded content it will try to select an ancestor with loaded content instead. + if (!refines) { // eslint-disable-line + selectDesiredTile(tileset, tile, frameState); + loadTile(tileset, tile, frameState); + } else if (reachedSkippingThreshold(tileset, tile)) { + loadTile(tileset, tile, frameState); + } } } - child._visibilityPlaneMask = visibilityMask; + visitTile(tileset, tile, frameState); + touchTile(tileset, tile, frameState); + tile._refines = refines; + tile._updatedVisibilityFrame = 0; // Reset so visibility is checked during the next pass } + } - tile._childrenVisibility = flag; + function executeEmptyTraversal(tileset, root, frameState) { + // Depth-first traversal that checks if all nearest descendants with content are loaded. Ignores visibility. + var allDescendantsLoaded = true; + var maximumScreenSpaceError = tileset._maximumScreenSpaceError; + var stack = emptyTraversal.stack; + stack.push(root); - return flag; - } + while (stack.length > 0) { + emptyTraversal.stackMaximumLength = Math.max(emptyTraversal.stackMaximumLength, stack.length); - function getScreenSpaceError(tileset, geometricError, tile, frameState) { - if (geometricError === 0.0) { - // Leaf tiles do not have any error so save the computation - return 0.0; - } + var tile = stack.pop(); + var children = tile.children; + var childrenLength = children.length; - // Avoid divide by zero when viewer is inside the tile - var camera = frameState.camera; - var frustum = camera.frustum; - var context = frameState.context; - var height = context.drawingBufferHeight; + // Only traverse if the tile is empty - traversal stop at descendants with content + var traverse = hasEmptyContent(tile) && (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError); - var error; - if (frameState.mode === SceneMode.SCENE2D || frustum instanceof OrthographicFrustum) { - if (defined(frustum._offCenterFrustum)) { - frustum = frustum._offCenterFrustum; + // Traversal stops but the tile does not have content yet. + // There will be holes if the parent tries to refine to its children, so don't refine. + if (!traverse && !tile.contentAvailable) { + allDescendantsLoaded = false; } - var width = context.drawingBufferWidth; - var pixelSize = Math.max(frustum.top - frustum.bottom, frustum.right - frustum.left) / Math.max(width, height); - error = geometricError / pixelSize; - } else { - var distance = Math.max(tile._distanceToCamera, CesiumMath.EPSILON7); - var sseDenominator = camera.frustum.sseDenominator; - error = (geometricError * height) / (distance * sseDenominator); - if (tileset.dynamicScreenSpaceError) { - var density = tileset._dynamicScreenSpaceErrorComputedDensity; - var factor = tileset.dynamicScreenSpaceErrorFactor; - var dynamicError = CesiumMath.fog(distance, density) * factor; - error -= dynamicError; + updateTile(tileset, tile, frameState); + if (!isVisible(tile)) { + // Load tiles that aren't visible since they are still needed for the parent to refine + loadTile(tileset, tile, frameState); + touchTile(tileset, tile, frameState); } - } - return error; - } - - function computeDistanceToCamera(children, frameState) { - var length = children.length; - for (var i = 0; i < length; ++i) { - var child = children[i]; - child._distanceToCamera = child.distanceToTile(frameState); - child._centerZDepth = child.distanceToTileCenter(frameState); - } - } - - function updateTransforms(children, parentTransform) { - var length = children.length; - for (var i = 0; i < length; ++i) { - var child = children[i]; - child.updateTransform(parentTransform); + if (traverse) { + for (var i = 0; i < childrenLength; ++i) { + var child = children[i]; + stack.push(child); + } + } } - } - function isVisible(visibilityPlaneMask) { - return visibilityPlaneMask !== CullingVolume.MASK_OUTSIDE; + return allDescendantsLoaded; } - function isVisibleAndMeetsSSE(tileset, tile, frameState) { + /** + * Traverse the tree and check if their selected frame is the current frame. If so, add it to a selection queue. + * This is a preorder traversal so children tiles are selected before ancestor tiles. + * + * The reason for the preorder traversal is so that tiles can easily be marked with their + * selection depth. A tile's _selectionDepth is its depth in the tree where all non-selected tiles are removed. + * This property is important for use in the stencil test because we want to render deeper tiles on top of their + * ancestors. If a tileset is very deep, the depth is unlikely to fit into the stencil buffer. + * + * We want to select children before their ancestors because there is no guarantee on the relationship between + * the children's z-depth and the ancestor's z-depth. We cannot rely on Z because we want the child to appear on top + * of ancestor regardless of true depth. The stencil tests used require children to be drawn first. + * + * NOTE: this will no longer work when there is a chain of selected tiles that is longer than the size of the + * stencil buffer (usually 8 bits). In other words, the subset of the tree containing only selected tiles must be + * no deeper than 255. It is very, very unlikely this will cause a problem. + * + * NOTE: when the scene has inverted classification enabled, the stencil buffer will be masked to 4 bits. So, the + * selected tiles must be no deeper than 15. This is still very unlikely. + */ + function traverseAndSelect(tileset, root, frameState) { var maximumScreenSpaceError = tileset._maximumScreenSpaceError; - var parent = tile.parent; - if (!defined(parent)) { - return isVisible(tile._visibilityPlaneMask); - } - var showAdditive = parent.refine === Cesium3DTileRefine.ADD && parent._screenSpaceError > maximumScreenSpaceError; - - return isVisible(tile._visibilityPlaneMask) && (!showAdditive || getScreenSpaceError(tileset, parent.geometricError, tile, frameState) > maximumScreenSpaceError); - } - - function childrenAreVisible(tile) { - // optimization does not apply for additive refinement - return tile.refine === Cesium3DTileRefine.ADD || tile.children.length === 0 || tile._childrenVisibility & Cesium3DTileChildrenVisibility.VISIBLE !== 0; - } - - function hasAdditiveContent(tile) { - return tile.refine === Cesium3DTileRefine.ADD && tile.hasRenderableContent; - } - - function depthFirstSearch(root, options) { - var stack = options.stack; + var stack = selectionTraversal.stack; + var ancestorStack = selectionTraversal.ancestorStack; + var lastAncestor; - if (defined(root) && (!defined(options.shouldVisit) || options.shouldVisit(root))) { - stack.push(root); - } + stack.push(root); - var maxLength = 0; - while (stack.length > 0) { - maxLength = Math.max(maxLength, stack.length); + while (stack.length > 0 || ancestorStack.length > 0) { + selectionTraversal.stackMaximumLength = Math.max(selectionTraversal.stackMaximumLength, stack.length); + selectionTraversal.ancestorStackMaximumLength = Math.max(selectionTraversal.ancestorStackMaximumLength, ancestorStack.length); - var tile = stack.pop(); - options.visitStart(tile); - var children = options.getChildren(tile); - var isNativeArray = !defined(children.get); - var length = children.length; - for (var i = 0; i < length; ++i) { - var child = isNativeArray ? children[i] : children.get(i); - - if (!defined(options.shouldVisit) || options.shouldVisit(child)) { - stack.push(child); + if (ancestorStack.length > 0) { + var waitingTile = ancestorStack.peek(); + if (waitingTile._stackLength === stack.length) { + ancestorStack.pop(); + if (waitingTile !== lastAncestor) { + waitingTile._finalResolution = false; + } + selectTile(tileset, waitingTile, frameState); + continue; } } - if (length === 0 && defined(options.leafHandler)) { - options.leafHandler(tile); + var tile = stack.pop(); + if (!defined(tile)) { + // stack is empty but ancestorStack isn't + continue; } - options.visitEnd(tile); - } - - stack.trim(maxLength); - } - - function breadthFirstSearch(root, options) { - var queue1 = options.queue1; - var queue2 = options.queue2; - if (defined(root) && (!defined(options.shouldVisit) || options.shouldVisit(root))) { - queue1.push(root); - } + var add = tile.refine === Cesium3DTileRefine.ADD; + var shouldSelect = tile._shouldSelect; + var children = tile.children; + var childrenLength = children.length; + var traverse = (childrenLength > 0) && (tile._screenSpaceError > maximumScreenSpaceError); - var maxLength = 0; - while (queue1.length > 0) { - var length = queue1.length; - maxLength = Math.max(maxLength, length); - - for (var i = 0; i < length; ++i) { - var tile = queue1.get(i); - options.visitStart(tile); - var children = options.getChildren(tile); - var isNativeArray = !defined(children.get); - var childrenLength = children.length; - for (var j = 0; j < childrenLength; ++j) { - var child = isNativeArray ? children[j] : children.get(j); - - if (!defined(options.shouldVisit) || options.shouldVisit(child)) { - queue2.push(child); + if (shouldSelect) { + if (add) { + selectTile(tileset, tile, frameState); + } else { + tile._selectionDepth = ancestorStack.length; + if (tile._selectionDepth > 0) { + tileset._hasMixedContent = true; } + lastAncestor = tile; + if (!traverse) { + selectTile(tileset, tile, frameState); + continue; + } + ancestorStack.push(tile); + tile._stackLength = stack.length; } + } - if (childrenLength === 0 && defined(options.leafHandler)) { - options.leafHandler(tile); + if (traverse) { + for (var i = 0; i < childrenLength; ++i) { + var child = children[i]; + if (isVisible(child)) { + stack.push(child); + } } - options.visitEnd(tile); } - - queue1.length = 0; - var temp = queue1; - queue1 = queue2; - queue2 = temp; - options.queue1 = queue1; - options.queue2 = queue2; } - - queue1.length = 0; - queue2.length = 0; - - queue1.trim(maxLength); - queue2.trim(maxLength); } - Cesium3DTilesetTraversal.selectTiles = selectTiles; - - Cesium3DTilesetTraversal.BaseTraversal = BaseTraversal; - - Cesium3DTilesetTraversal.SkipTraversal = SkipTraversal; - return Cesium3DTilesetTraversal; }); diff --git a/Source/Scene/ClassificationPrimitive.js b/Source/Scene/ClassificationPrimitive.js index 675e2f9d5ef5..aa7f6d06ab3e 100644 --- a/Source/Scene/ClassificationPrimitive.js +++ b/Source/Scene/ClassificationPrimitive.js @@ -589,7 +589,7 @@ define([ vsPick = Primitive._updatePickColorAttribute(vsPick); var pickFS3D = shadowVolumeAppearance.createPickFragmentShader(false); - var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false); + var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false, frameState.mapProjection); classificationPrimitive._spPick = ShaderProgram.replaceCache({ context : context, @@ -605,7 +605,7 @@ define([ var pickProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spPick, '2dPick'); if (!defined(pickProgram2D)) { var pickFS2D = shadowVolumeAppearance.createPickFragmentShader(true); - var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true); + var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true, frameState.mapProjection); pickProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spPick, '2dPick', { vertexShaderSource : pickVS2D, @@ -640,7 +640,7 @@ define([ // Create a fragment shader that computes only required material hookups using screen space techniques var fsColorSource = shadowVolumeAppearance.createFragmentShader(false); - var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false); + var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false, frameState.mapProjection); classificationPrimitive._spColor = ShaderProgram.replaceCache({ context : context, @@ -657,7 +657,7 @@ define([ var colorProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spColor, '2dColor'); if (!defined(colorProgram2D)) { var fsColorSource2D = shadowVolumeAppearance.createFragmentShader(true); - var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true); + var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true, frameState.mapProjection); colorProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spColor, '2dColor', { vertexShaderSource : vsColorSource2D, diff --git a/Source/Scene/ClippingPlaneCollection.js b/Source/Scene/ClippingPlaneCollection.js index bcb7e0e44da3..01a3d88dac1e 100644 --- a/Source/Scene/ClippingPlaneCollection.js +++ b/Source/Scene/ClippingPlaneCollection.js @@ -11,6 +11,7 @@ define([ '../Core/deprecationWarning', '../Core/destroyObject', '../Core/DeveloperError', + '../Core/Event', '../Core/Intersect', '../Core/Matrix4', '../Core/PixelFormat', @@ -36,6 +37,7 @@ define([ deprecationWarning, destroyObject, DeveloperError, + Event, Intersect, Matrix4, PixelFormat, @@ -75,15 +77,6 @@ define([ this._dirtyIndex = -1; this._multipleDirtyPlanes = false; - // Add each ClippingPlane object. - var planes = options.planes; - if (defined(planes)) { - var planesLength = planes.length; - for (var i = 0; i < planesLength; ++i) { - this.add(planes[i]); - } - } - this._enabled = defaultValue(options.enabled, true); /** @@ -111,6 +104,22 @@ define([ */ this.edgeWidth = defaultValue(options.edgeWidth, 0.0); + /** + * An event triggered when a new clipping plane is added to the collection. Event handlers + * are passed the new plane and the index at which it was added. + * @type {Event} + * @default Event() + */ + this.planeAdded = new Event(); + + /** + * An event triggered when a new clipping plane is removed from the collection. Event handlers + * are passed the new plane and the index from which it was removed. + * @type {Event} + * @default Event() + */ + this.planeRemoved = new Event(); + // If this ClippingPlaneCollection has an owner, only its owner should update or destroy it. // This is because in a Cesium3DTileset multiple models may reference the tileset's ClippingPlaneCollection. this._owner = undefined; @@ -123,6 +132,15 @@ define([ this._float32View = undefined; this._clippingPlanesTexture = undefined; + + // Add each ClippingPlane object. + var planes = options.planes; + if (defined(planes)) { + var planesLength = planes.length; + for (var i = 0; i < planesLength; ++i) { + this.add(planes[i]); + } + } } function unionIntersectFunction(value) { @@ -263,6 +281,7 @@ define([ setIndexDirty(this, newPlaneIndex); this._planes.push(plane); + this.planeAdded.raiseEvent(plane, newPlaneIndex); }; /** @@ -346,6 +365,8 @@ define([ this._multipleDirtyPlanes = true; planes.length = length; + this.planeRemoved.raiseEvent(clippingPlane, index); + return true; }; @@ -365,6 +386,7 @@ define([ plane.onChangeCallback = undefined; plane.index = -1; } + this.planeRemoved.raiseEvent(plane, i); } this._multipleDirtyPlanes = true; this._planes = []; @@ -546,47 +568,6 @@ define([ this._dirtyIndex = -1; }; - /** - * Duplicates this ClippingPlaneCollection instance. - * - * @param {ClippingPlaneCollection} [result] The object onto which to store the result. - * @returns {ClippingPlaneCollection} The modified result parameter or a new ClippingPlaneCollection instance if one was not provided. - */ - ClippingPlaneCollection.prototype.clone = function(result) { - if (!defined(result)) { - result = new ClippingPlaneCollection(); - } - - var length = this.length; - var i; - if (result.length !== length) { - var planes = result._planes; - var index = planes.length; - - planes.length = length; - for (i = index; i < length; ++i) { - result._planes[i] = new ClippingPlane(Cartesian3.UNIT_X, 0.0); - } - } - - for (i = 0; i < length; ++i) { - var resultPlane = result._planes[i]; - resultPlane.index = i; - resultPlane.onChangeCallback = function(index) { - setIndexDirty(result, index); - }; - ClippingPlane.clone(this._planes[i], resultPlane); - } - - result.enabled = this.enabled; - Matrix4.clone(this.modelMatrix, result.modelMatrix); - result.unionClippingRegions = this.unionClippingRegions; - Color.clone(this.edgeColor, result.edgeColor); - result.edgeWidth = this.edgeWidth; - - return result; - }; - var scratchMatrix = new Matrix4(); var scratchPlane = new Plane(Cartesian3.UNIT_X, 0.0); /** diff --git a/Source/Scene/Composite3DTileContent.js b/Source/Scene/Composite3DTileContent.js index 91d9bd51b1b8..4847f27c6639 100644 --- a/Source/Scene/Composite3DTileContent.js +++ b/Source/Scene/Composite3DTileContent.js @@ -26,8 +26,8 @@ define([ /** * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Composite/README.md|Composite} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Composite|Composite} + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset. *

* Implements the {@link Cesium3DTileContent} interface. *

@@ -250,11 +250,11 @@ define([ } }; - Composite3DTileContent.prototype.applyStyle = function(frameState, style) { + Composite3DTileContent.prototype.applyStyle = function(style) { var contents = this._contents; var length = contents.length; for (var i = 0; i < length; ++i) { - contents[i].applyStyle(frameState, style); + contents[i].applyStyle(style); } }; diff --git a/Source/Scene/ConditionsExpression.js b/Source/Scene/ConditionsExpression.js index 1bc5d32d74c0..093f380c5b91 100644 --- a/Source/Scene/ConditionsExpression.js +++ b/Source/Scene/ConditionsExpression.js @@ -14,7 +14,7 @@ define([ * An expression for a style applied to a {@link Cesium3DTileset}. *

* Evaluates a conditions expression defined using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}. *

*

* Implements the {@link StyleExpression} interface. @@ -34,7 +34,7 @@ define([ * ['true', 'color("#FFFFFF")'] * ] * }); - * expression.evaluateColor(frameState, feature, result); // returns a Cesium.Color object + * expression.evaluateColor(feature, result); // returns a Cesium.Color object */ function ConditionsExpression(conditionsExpression, defines) { this._conditionsExpression = clone(conditionsExpression, true); @@ -89,19 +89,18 @@ define([ /** * Evaluates the result of an expression, optionally using the provided feature's properties. If the result of * the expression in the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} * is of type Boolean, Number, or String, the corresponding JavaScript * primitive type will be returned. If the result is a RegExp, a Javascript RegExp * object will be returned. If the result is a Cartesian2, Cartesian3, or Cartesian4, * a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} object will be returned. If the result argument is * a {@link Color}, the {@link Cartesian4} value is converted to a {@link Color} and then returned. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Object} [result] The object onto which to store the result. * @returns {Boolean|Number|String|RegExp|Cartesian2|Cartesian3|Cartesian4|Color} The result of evaluating the expression. */ - ConditionsExpression.prototype.evaluate = function(frameState, feature, result) { + ConditionsExpression.prototype.evaluate = function(feature, result) { var conditions = this._runtimeConditions; if (!defined(conditions)) { return undefined; @@ -109,8 +108,8 @@ define([ var length = conditions.length; for (var i = 0; i < length; ++i) { var statement = conditions[i]; - if (statement.condition.evaluate(frameState, feature)) { - return statement.expression.evaluate(frameState, feature, result); + if (statement.condition.evaluate(feature)) { + return statement.expression.evaluate(feature, result); } } }; @@ -120,12 +119,11 @@ define([ *

* This is equivalent to {@link ConditionsExpression#evaluate} but always returns a {@link Color} object. *

- * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Color} [result] The object in which to store the result * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ - ConditionsExpression.prototype.evaluateColor = function(frameState, feature, result) { + ConditionsExpression.prototype.evaluateColor = function(feature, result) { var conditions = this._runtimeConditions; if (!defined(conditions)) { return undefined; @@ -133,8 +131,8 @@ define([ var length = conditions.length; for (var i = 0; i < length; ++i) { var statement = conditions[i]; - if (statement.condition.evaluate(frameState, feature)) { - return statement.expression.evaluateColor(frameState, feature, result); + if (statement.condition.evaluate(feature)) { + return statement.expression.evaluateColor(feature, result); } } }; diff --git a/Source/Scene/Empty3DTileContent.js b/Source/Scene/Empty3DTileContent.js index 354c51db82b3..d5c49f35cad0 100644 --- a/Source/Scene/Empty3DTileContent.js +++ b/Source/Scene/Empty3DTileContent.js @@ -8,7 +8,7 @@ define([ /** * Represents empty content for tiles in a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset that + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset that * do not have content, e.g., because they are used to optimize hierarchical culling. *

* Implements the {@link Cesium3DTileContent} interface. @@ -119,7 +119,7 @@ define([ Empty3DTileContent.prototype.applyDebugSettings = function(enabled, color) { }; - Empty3DTileContent.prototype.applyStyle = function(frameState, style) { + Empty3DTileContent.prototype.applyStyle = function(style) { }; Empty3DTileContent.prototype.update = function(tileset, frameState) { diff --git a/Source/Scene/Expression.js b/Source/Scene/Expression.js index 223e177a3070..1ecd0f1b2378 100644 --- a/Source/Scene/Expression.js +++ b/Source/Scene/Expression.js @@ -32,7 +32,7 @@ define([ * An expression for a style applied to a {@link Cesium3DTileset}. *

* Evaluates an expression defined using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}. *

*

* Implements the {@link StyleExpression} interface. @@ -46,11 +46,11 @@ define([ * * @example * var expression = new Cesium.Expression('(regExp("^Chest").test(${County})) && (${YearBuilt} >= 1970)'); - * expression.evaluate(frameState, feature); // returns true or false depending on the feature's properties + * expression.evaluate(feature); // returns true or false depending on the feature's properties * * @example * var expression = new Cesium.Expression('(${Temperature} > 90) ? color("red") : color("white")'); - * expression.evaluateColor(frameState, feature, result); // returns a Cesium.Color object + * expression.evaluateColor(feature, result); // returns a Cesium.Color object */ function Expression(expression, defines) { //>>includeStart('debug', pragmas.debug); @@ -141,21 +141,20 @@ define([ /** * Evaluates the result of an expression, optionally using the provided feature's properties. If the result of * the expression in the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} * is of type Boolean, Number, or String, the corresponding JavaScript * primitive type will be returned. If the result is a RegExp, a Javascript RegExp * object will be returned. If the result is a Cartesian2, Cartesian3, or Cartesian4, * a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} object will be returned. If the result argument is * a {@link Color}, the {@link Cartesian4} value is converted to a {@link Color} and then returned. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Object} [result] The object onto which to store the result. * @returns {Boolean|Number|String|RegExp|Cartesian2|Cartesian3|Cartesian4|Color} The result of evaluating the expression. */ - Expression.prototype.evaluate = function(frameState, feature, result) { + Expression.prototype.evaluate = function(feature, result) { scratchStorage.reset(); - var value = this._runtimeAst.evaluate(frameState, feature); + var value = this._runtimeAst.evaluate(feature); if ((result instanceof Color) && (value instanceof Cartesian4)) { return Color.fromCartesian4(value, result); } @@ -171,14 +170,13 @@ define([ * This is equivalent to {@link Expression#evaluate} but always returns a {@link Color} object. *

* - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Color} [result] The object in which to store the result * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ - Expression.prototype.evaluateColor = function(frameState, feature, result) { + Expression.prototype.evaluateColor = function(feature, result) { scratchStorage.reset(); - var color = this._runtimeAst.evaluate(frameState, feature); + var color = this._runtimeAst.evaluate(feature); return Color.fromCartesian4(color, result); }; @@ -256,18 +254,18 @@ define([ }; var binaryFunctions = { - atan2 : getEvaluateBinaryCommponentwise(Math.atan2, false), - pow : getEvaluateBinaryCommponentwise(Math.pow, false), - min : getEvaluateBinaryCommponentwise(Math.min, true), - max : getEvaluateBinaryCommponentwise(Math.max, true), + atan2 : getEvaluateBinaryComponentwise(Math.atan2, false), + pow : getEvaluateBinaryComponentwise(Math.pow, false), + min : getEvaluateBinaryComponentwise(Math.min, true), + max : getEvaluateBinaryComponentwise(Math.max, true), distance : distance, dot : dot, cross : cross }; var ternaryFunctions = { - clamp : getEvaluateTernaryCommponentwise(CesiumMath.clamp, true), - mix : getEvaluateTernaryCommponentwise(CesiumMath.lerp, true) + clamp : getEvaluateTernaryComponentwise(CesiumMath.clamp, true), + mix : getEvaluateTernaryComponentwise(CesiumMath.lerp, true) }; function fract(number) { @@ -297,7 +295,7 @@ define([ }; } - function getEvaluateBinaryCommponentwise(operation, allowScalar) { + function getEvaluateBinaryComponentwise(operation, allowScalar) { return function(call, left, right) { if (allowScalar && typeof right === 'number') { if (typeof left === 'number') { @@ -325,7 +323,7 @@ define([ }; } - function getEvaluateTernaryCommponentwise(operation, allowScalar) { + function getEvaluateTernaryComponentwise(operation, allowScalar) { return function(call, left, right, test) { if (allowScalar && typeof test === 'number') { if (typeof left === 'number' && typeof right === 'number') { @@ -901,85 +899,85 @@ define([ } } - function evaluateTilesetTime(frameState, feature) { + function evaluateTilesetTime(feature) { return feature.content.tileset.timeSinceLoad; } function getEvaluateUnaryFunction(call) { var evaluate = unaryFunctions[call]; - return function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + return function(feature) { + var left = this._left.evaluate(feature); return evaluate(call, left); }; } function getEvaluateBinaryFunction(call) { var evaluate = binaryFunctions[call]; - return function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + return function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); return evaluate(call, left, right); }; } function getEvaluateTernaryFunction(call) { var evaluate = ternaryFunctions[call]; - return function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); - var test = this._test.evaluate(frameState, feature); + return function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); + var test = this._test.evaluate(feature); return evaluate(call, left, right, test); }; } - Node.prototype._evaluateLiteral = function(frameState, feature) { + Node.prototype._evaluateLiteral = function() { return this._value; }; - Node.prototype._evaluateLiteralColor = function(frameState, feature) { + Node.prototype._evaluateLiteralColor = function(feature) { var color = scratchColor; var args = this._left; if (this._value === 'color') { if (!defined(args)) { Color.fromBytes(255, 255, 255, 255, color); } else if (args.length > 1) { - Color.fromCssColorString(args[0].evaluate(frameState, feature), color); - color.alpha = args[1].evaluate(frameState, feature); + Color.fromCssColorString(args[0].evaluate(feature), color); + color.alpha = args[1].evaluate(feature); } else { - Color.fromCssColorString(args[0].evaluate(frameState, feature), color); + Color.fromCssColorString(args[0].evaluate(feature), color); } } else if (this._value === 'rgb') { Color.fromBytes( - args[0].evaluate(frameState, feature), - args[1].evaluate(frameState, feature), - args[2].evaluate(frameState, feature), + args[0].evaluate(feature), + args[1].evaluate(feature), + args[2].evaluate(feature), 255, color); } else if (this._value === 'rgba') { // convert between css alpha (0 to 1) and cesium alpha (0 to 255) - var a = args[3].evaluate(frameState, feature) * 255; + var a = args[3].evaluate(feature) * 255; Color.fromBytes( - args[0].evaluate(frameState, feature), - args[1].evaluate(frameState, feature), - args[2].evaluate(frameState, feature), + args[0].evaluate(feature), + args[1].evaluate(feature), + args[2].evaluate(feature), a, color); } else if (this._value === 'hsl') { Color.fromHsl( - args[0].evaluate(frameState, feature), - args[1].evaluate(frameState, feature), - args[2].evaluate(frameState, feature), + args[0].evaluate(feature), + args[1].evaluate(feature), + args[2].evaluate(feature), 1.0, color); } else if (this._value === 'hsla') { Color.fromHsl( - args[0].evaluate(frameState, feature), - args[1].evaluate(frameState, feature), - args[2].evaluate(frameState, feature), - args[3].evaluate(frameState, feature), + args[0].evaluate(feature), + args[1].evaluate(feature), + args[2].evaluate(feature), + args[3].evaluate(feature), color); } return Cartesian4.fromColor(color, scratchStorage.getCartesian4()); }; - Node.prototype._evaluateLiteralVector = function(frameState, feature) { + Node.prototype._evaluateLiteralVector = function(feature) { // Gather the components that make up the vector, which includes components from interior vectors. // For example vec3(1, 2, 3) or vec3(vec2(1, 2), 3) are both valid. // @@ -998,7 +996,7 @@ define([ var args = this._left; var argsLength = args.length; for (var i = 0; i < argsLength; ++i) { - var value = args[i].evaluate(frameState, feature); + var value = args[i].evaluate(feature); if (typeof value === 'number') { components.push(value); } else if (value instanceof Cartesian2) { @@ -1038,11 +1036,11 @@ define([ } }; - Node.prototype._evaluateLiteralString = function(frameState, feature) { + Node.prototype._evaluateLiteralString = function() { return this._value; }; - Node.prototype._evaluateVariableString = function(frameState, feature) { + Node.prototype._evaluateVariableString = function(feature) { var result = this._value; var match = variableRegex.exec(result); while (match !== null) { @@ -1058,7 +1056,7 @@ define([ return result; }; - Node.prototype._evaluateVariable = function(frameState, feature) { + Node.prototype._evaluateVariable = function(feature) { // evaluates to undefined if the property name is not defined for that feature return feature.getProperty(this._value); }; @@ -1068,16 +1066,16 @@ define([ } // PERFORMANCE_IDEA: Determine if parent property needs to be computed before runtime - Node.prototype._evaluateMemberDot = function(frameState, feature) { + Node.prototype._evaluateMemberDot = function(feature) { if (checkFeature(this._left)) { - return feature.getProperty(this._right.evaluate(frameState, feature)); + return feature.getProperty(this._right.evaluate(feature)); } - var property = this._left.evaluate(frameState, feature); + var property = this._left.evaluate(feature); if (!defined(property)) { return undefined; } - var member = this._right.evaluate(frameState, feature); + var member = this._right.evaluate(feature); if ((property instanceof Cartesian2) || (property instanceof Cartesian3) || (property instanceof Cartesian4)) { // Vector components may be accessed with .r, .g, .b, .a and implicitly with .x, .y, .z, .w if (member === 'r') { @@ -1093,16 +1091,16 @@ define([ return property[member]; }; - Node.prototype._evaluateMemberBrackets = function(frameState, feature) { + Node.prototype._evaluateMemberBrackets = function(feature) { if (checkFeature(this._left)) { - return feature.getProperty(this._right.evaluate(frameState, feature)); + return feature.getProperty(this._right.evaluate(feature)); } - var property = this._left.evaluate(frameState, feature); + var property = this._left.evaluate(feature); if (!defined(property)) { return undefined; } - var member = this._right.evaluate(frameState, feature); + var member = this._right.evaluate(feature); if ((property instanceof Cartesian2) || (property instanceof Cartesian3) || (property instanceof Cartesian4)) { // Vector components may be accessed with [0][1][2][3], ['r']['g']['b']['a'] and implicitly with ['x']['y']['z']['w'] // For Cartesian2 and Cartesian3 out-of-range components will just return undefined @@ -1119,10 +1117,10 @@ define([ return property[member]; }; - Node.prototype._evaluateArray = function(frameState, feature) { + Node.prototype._evaluateArray = function(feature) { var array = []; for (var i = 0; i < this._value.length; i++) { - array[i] = this._value[i].evaluate(frameState, feature); + array[i] = this._value[i].evaluate(feature); } return array; }; @@ -1130,16 +1128,16 @@ define([ // PERFORMANCE_IDEA: Have "fast path" functions that deal only with specific types // that we can assign if we know the types before runtime - Node.prototype._evaluateNot = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluateNot = function(feature) { + var left = this._left.evaluate(feature); if (typeof left !== 'boolean') { throw new RuntimeError('Operator "!" requires a boolean argument. Argument is ' + left + '.'); } return !left; }; - Node.prototype._evaluateNegative = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluateNegative = function(feature) { + var left = this._left.evaluate(feature); if (left instanceof Cartesian2) { return Cartesian2.negate(left, scratchStorage.getCartesian2()); } else if (left instanceof Cartesian3) { @@ -1153,8 +1151,8 @@ define([ throw new RuntimeError('Operator "-" requires a vector or number argument. Argument is ' + left + '.'); }; - Node.prototype._evaluatePositive = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluatePositive = function(feature) { + var left = this._left.evaluate(feature); if (!((left instanceof Cartesian2) || (left instanceof Cartesian3) || (left instanceof Cartesian4) || (typeof left === 'number'))) { throw new RuntimeError('Operator "+" requires a vector or number argument. Argument is ' + left + '.'); @@ -1163,9 +1161,9 @@ define([ return left; }; - Node.prototype._evaluateLessThan = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateLessThan = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((typeof left !== 'number') || (typeof right !== 'number')) { throw new RuntimeError('Operator "<" requires number arguments. Arguments are ' + left + ' and ' + right + '.'); @@ -1174,9 +1172,9 @@ define([ return left < right; }; - Node.prototype._evaluateLessThanOrEquals = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateLessThanOrEquals = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((typeof left !== 'number') || (typeof right !== 'number')) { throw new RuntimeError('Operator "<=" requires number arguments. Arguments are ' + left + ' and ' + right + '.'); @@ -1185,9 +1183,9 @@ define([ return left <= right; }; - Node.prototype._evaluateGreaterThan = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateGreaterThan = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((typeof left !== 'number') || (typeof right !== 'number')) { throw new RuntimeError('Operator ">" requires number arguments. Arguments are ' + left + ' and ' + right + '.'); @@ -1196,9 +1194,9 @@ define([ return left > right; }; - Node.prototype._evaluateGreaterThanOrEquals = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateGreaterThanOrEquals = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((typeof left !== 'number') || (typeof right !== 'number')) { throw new RuntimeError('Operator ">=" requires number arguments. Arguments are ' + left + ' and ' + right + '.'); @@ -1207,8 +1205,8 @@ define([ return left >= right; }; - Node.prototype._evaluateOr = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluateOr = function(feature) { + var left = this._left.evaluate(feature); if (typeof left !== 'boolean') { throw new RuntimeError('Operator "||" requires boolean arguments. First argument is ' + left + '.'); } @@ -1218,7 +1216,7 @@ define([ return true; } - var right = this._right.evaluate(frameState, feature); + var right = this._right.evaluate(feature); if (typeof right !== 'boolean') { throw new RuntimeError('Operator "||" requires boolean arguments. Second argument is ' + right + '.'); } @@ -1226,8 +1224,8 @@ define([ return left || right; }; - Node.prototype._evaluateAnd = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluateAnd = function(feature) { + var left = this._left.evaluate(feature); if (typeof left !== 'boolean') { throw new RuntimeError('Operator "&&" requires boolean arguments. First argument is ' + left + '.'); } @@ -1237,7 +1235,7 @@ define([ return false; } - var right = this._right.evaluate(frameState, feature); + var right = this._right.evaluate(feature); if (typeof right !== 'boolean') { throw new RuntimeError('Operator "&&" requires boolean arguments. Second argument is ' + right + '.'); } @@ -1245,9 +1243,9 @@ define([ return left && right; }; - Node.prototype._evaluatePlus = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluatePlus = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) { return Cartesian2.add(left, right, scratchStorage.getCartesian2()); } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) { @@ -1264,9 +1262,9 @@ define([ throw new RuntimeError('Operator "+" requires vector or number arguments of matching types, or at least one string argument. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateMinus = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateMinus = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) { return Cartesian2.subtract(left, right, scratchStorage.getCartesian2()); } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) { @@ -1280,9 +1278,9 @@ define([ throw new RuntimeError('Operator "-" requires vector or number arguments of matching types. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateTimes = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateTimes = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) { return Cartesian2.multiplyComponents(left, right, scratchStorage.getCartesian2()); } else if ((right instanceof Cartesian2) && (typeof left === 'number')) { @@ -1308,9 +1306,9 @@ define([ throw new RuntimeError('Operator "*" requires vector or number arguments. If both arguments are vectors they must be matching types. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateDivide = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateDivide = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) { return Cartesian2.divideComponents(left, right, scratchStorage.getCartesian2()); } else if ((left instanceof Cartesian2) && (typeof right === 'number')) { @@ -1330,9 +1328,9 @@ define([ throw new RuntimeError('Operator "/" requires vector or number arguments of matching types, or a number as the second argument. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateMod = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateMod = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2)) { return Cartesian2.fromElements(left.x % right.x, left.y % right.y, scratchStorage.getCartesian2()); } else if ((right instanceof Cartesian3) && (left instanceof Cartesian3)) { @@ -1346,9 +1344,9 @@ define([ throw new RuntimeError('Operator "%" requires vector or number arguments of matching types. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateEqualsStrict = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateEqualsStrict = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2) || (right instanceof Cartesian3) && (left instanceof Cartesian3) || (right instanceof Cartesian4) && (left instanceof Cartesian4)) { @@ -1357,9 +1355,9 @@ define([ return left === right; }; - Node.prototype._evaluateNotEqualsStrict = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateNotEqualsStrict = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((right instanceof Cartesian2) && (left instanceof Cartesian2) || (right instanceof Cartesian3) && (left instanceof Cartesian3) || (right instanceof Cartesian4) && (left instanceof Cartesian4)) { @@ -1368,57 +1366,57 @@ define([ return left !== right; }; - Node.prototype._evaluateConditional = function(frameState, feature) { - var test = this._test.evaluate(frameState, feature); + Node.prototype._evaluateConditional = function(feature) { + var test = this._test.evaluate(feature); if (typeof test !== 'boolean') { throw new RuntimeError('Conditional argument of conditional expression must be a boolean. Argument is ' + test + '.'); } if (test) { - return this._left.evaluate(frameState, feature); + return this._left.evaluate(feature); } - return this._right.evaluate(frameState, feature); + return this._right.evaluate(feature); }; - Node.prototype._evaluateNaN = function(frameState, feature) { - return isNaN(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateNaN = function(feature) { + return isNaN(this._left.evaluate(feature)); }; - Node.prototype._evaluateIsFinite = function(frameState, feature) { - return isFinite(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateIsFinite = function(feature) { + return isFinite(this._left.evaluate(feature)); }; - Node.prototype._evaluateIsExactClass = function(frameState, feature) { - return feature.isExactClass(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateIsExactClass = function(feature) { + return feature.isExactClass(this._left.evaluate(feature)); }; - Node.prototype._evaluateIsClass = function(frameState, feature) { - return feature.isClass(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateIsClass = function(feature) { + return feature.isClass(this._left.evaluate(feature)); }; - Node.prototype._evaluategetExactClassName = function(frameState, feature) { + Node.prototype._evaluategetExactClassName = function(feature) { return feature.getExactClassName(); }; - Node.prototype._evaluateBooleanConversion = function(frameState, feature) { - return Boolean(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateBooleanConversion = function(feature) { + return Boolean(this._left.evaluate(feature)); }; - Node.prototype._evaluateNumberConversion = function(frameState, feature) { - return Number(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateNumberConversion = function(feature) { + return Number(this._left.evaluate(feature)); }; - Node.prototype._evaluateStringConversion = function(frameState, feature) { - return String(this._left.evaluate(frameState, feature)); + Node.prototype._evaluateStringConversion = function(feature) { + return String(this._left.evaluate(feature)); }; - Node.prototype._evaluateRegExp = function(frameState, feature) { - var pattern = this._value.evaluate(frameState, feature); + Node.prototype._evaluateRegExp = function(feature) { + var pattern = this._value.evaluate(feature); var flags = ''; if (defined(this._left)) { - flags = this._left.evaluate(frameState, feature); + flags = this._left.evaluate(feature); } var exp; @@ -1430,9 +1428,9 @@ define([ return exp; }; - Node.prototype._evaluateRegExpTest = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateRegExpTest = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if (!((left instanceof RegExp) && (typeof right === 'string'))) { throw new RuntimeError('RegExp.test requires the first argument to be a RegExp and the second argument to be a string. Arguments are ' + left + ' and ' + right + '.'); @@ -1441,9 +1439,9 @@ define([ return left.test(right); }; - Node.prototype._evaluateRegExpMatch = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateRegExpMatch = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((left instanceof RegExp) && (typeof right === 'string')) { return left.test(right); @@ -1454,9 +1452,9 @@ define([ throw new RuntimeError('Operator "=~" requires one RegExp argument and one string argument. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateRegExpNotMatch = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateRegExpNotMatch = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if ((left instanceof RegExp) && (typeof right === 'string')) { return !(left.test(right)); @@ -1467,9 +1465,9 @@ define([ throw new RuntimeError('Operator "!~" requires one RegExp argument and one string argument. Arguments are ' + left + ' and ' + right + '.'); }; - Node.prototype._evaluateRegExpExec = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); - var right = this._right.evaluate(frameState, feature); + Node.prototype._evaluateRegExpExec = function(feature) { + var left = this._left.evaluate(feature); + var right = this._right.evaluate(feature); if (!((left instanceof RegExp) && (typeof right === 'string'))) { throw new RuntimeError('RegExp.exec requires the first argument to be a RegExp and the second argument to be a string. Arguments are ' + left + ' and ' + right + '.'); @@ -1482,8 +1480,8 @@ define([ return exec[1]; }; - Node.prototype._evaluateToString = function(frameState, feature) { - var left = this._left.evaluate(frameState, feature); + Node.prototype._evaluateToString = function(feature) { + var left = this._left.evaluate(feature); if ((left instanceof RegExp) || (left instanceof Cartesian2) || (left instanceof Cartesian3) || (left instanceof Cartesian4)) { return String(left); } diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index d463cf162201..6d0c3d8da2b3 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -239,6 +239,12 @@ define([ */ shadowsEnabled : true, + /** + * Whether there are any active shadow maps that originate from light sources. Does not + * include shadow maps that are used for analytical purposes. + */ + lightShadowsEnabled : true, + /** * All shadow maps that are enabled this frame. */ diff --git a/Source/Scene/Geometry3DTileContent.js b/Source/Scene/Geometry3DTileContent.js index 62473e75ca5e..ff4f949e83c6 100644 --- a/Source/Scene/Geometry3DTileContent.js +++ b/Source/Scene/Geometry3DTileContent.js @@ -317,7 +317,7 @@ define([ return; } - var modelMatrix = content._tile.computedTransform; + var modelMatrix = content.tile.computedTransform; var center; if (defined(featureTableJson.RTC_CENTER)) { @@ -365,7 +365,7 @@ define([ center : center, modelMatrix : modelMatrix, batchTable : batchTable, - boundingVolume : content._tile._boundingVolume.boundingVolume + boundingVolume : content.tile.boundingVolume.boundingVolume }); } } @@ -403,10 +403,10 @@ define([ } }; - Geometry3DTileContent.prototype.applyStyle = function(frameState, style) { + Geometry3DTileContent.prototype.applyStyle = function(style) { createFeatures(this); if (defined(this._geometries)) { - this._geometries.applyStyle(frameState, style, this._features); + this._geometries.applyStyle(style, this._features); } }; diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js index 29b77bbac8f5..5acc74e2413f 100644 --- a/Source/Scene/Globe.js +++ b/Source/Scene/Globe.js @@ -407,14 +407,11 @@ define([ * @param {Ray} ray The ray to test for intersection. * @param {Scene} scene The scene. * @param {Cartesian3} [result] The object onto which to store the result. - * @returns {Cartesian3|undefined} The intersection or undefined if none was found. + * @returns {Cartesian3|undefined} The intersection or undefined if none was found. The returned position is in projected coordinates for 2D and Columbus View. * - * @example - * // find intersection of ray through a pixel and the globe - * var ray = viewer.camera.getPickRay(windowCoordinates); - * var intersection = globe.pick(ray, scene); + * @private */ - Globe.prototype.pick = function(ray, scene, result) { + Globe.prototype.pickWorldCoordinates = function(ray, scene, result) { //>>includeStart('debug', pragmas.debug); if (!defined(ray)) { throw new DeveloperError('ray is required'); @@ -472,6 +469,31 @@ define([ return intersection; }; + var cartoScratch = new Cartographic(); + /** + * Find an intersection between a ray and the globe surface that was rendered. The ray must be given in world coordinates. + * + * @param {Ray} ray The ray to test for intersection. + * @param {Scene} scene The scene. + * @param {Cartesian3} [result] The object onto which to store the result. + * @returns {Cartesian3|undefined} The intersection or undefined if none was found. + * + * @example + * // find intersection of ray through a pixel and the globe + * var ray = viewer.camera.getPickRay(windowCoordinates); + * var intersection = globe.pick(ray, scene); + */ + Globe.prototype.pick = function(ray, scene, result) { + result = this.pickWorldCoordinates(ray, scene, result); + if (defined(result) && scene.mode !== SceneMode.SCENE3D) { + result = Cartesian3.fromElements(result.y, result.z, result.x, result); + var carto = scene.mapProjection.unproject(result, cartoScratch); + result = scene.globe.ellipsoid.cartographicToCartesian(carto, result); + } + + return result; + }; + var scratchGetHeightCartesian = new Cartesian3(); var scratchGetHeightIntersection = new Cartesian3(); var scratchGetHeightCartographic = new Cartographic(); diff --git a/Source/Scene/GroundPolylinePrimitive.js b/Source/Scene/GroundPolylinePrimitive.js index f5c5ca0ef9c5..7d052e567843 100644 --- a/Source/Scene/GroundPolylinePrimitive.js +++ b/Source/Scene/GroundPolylinePrimitive.js @@ -343,9 +343,6 @@ define([ } }); - GroundPolylinePrimitive._initialized = false; - GroundPolylinePrimitive._initPromise = undefined; - /** * Initializes the minimum and maximum terrain heights. This only needs to be called if you are creating the * GroundPolylinePrimitive synchronously. @@ -353,17 +350,7 @@ define([ * @returns {Promise} A promise that will resolve once the terrain heights have been loaded. */ GroundPolylinePrimitive.initializeTerrainHeights = function() { - var initPromise = GroundPolylinePrimitive._initPromise; - if (defined(initPromise)) { - return initPromise; - } - - GroundPolylinePrimitive._initPromise = ApproximateTerrainHeights.initialize() - .then(function() { - GroundPolylinePrimitive._initialized = true; - }); - - return GroundPolylinePrimitive._initPromise; + return ApproximateTerrainHeights.initialize(); }; function createShaderProgram(groundPolylinePrimitive, frameState, appearance) { @@ -582,7 +569,7 @@ define([ return; } - if (!GroundPolylinePrimitive._initialized) { + if (!ApproximateTerrainHeights.initialized) { //>>includeStart('debug', pragmas.debug); if (!this.asynchronous) { throw new DeveloperError('For synchronous GroundPolylinePrimitives, you must call GroundPolylinePrimitives.initializeTerrainHeights() and wait for the returned promise to resolve.'); @@ -639,7 +626,8 @@ define([ groundInstances[i] = new GeometryInstance({ geometry : geometryInstance.geometry, attributes : attributes, - id : geometryInstance.id + id : geometryInstance.id, + pickPrimitive : that }); } diff --git a/Source/Scene/GroundPrimitive.js b/Source/Scene/GroundPrimitive.js index de6c371b6f71..2df59183af5a 100644 --- a/Source/Scene/GroundPrimitive.js +++ b/Source/Scene/GroundPrimitive.js @@ -614,9 +614,6 @@ define([ } } - GroundPrimitive._initialized = false; - GroundPrimitive._initPromise = undefined; - /** * Initializes the minimum and maximum terrain heights. This only needs to be called if you are creating the * GroundPrimitive synchronously. @@ -625,17 +622,7 @@ define([ * */ GroundPrimitive.initializeTerrainHeights = function() { - var initPromise = GroundPrimitive._initPromise; - if (defined(initPromise)) { - return initPromise; - } - - GroundPrimitive._initPromise = ApproximateTerrainHeights.initialize() - .then(function() { - GroundPrimitive._initialized = true; - }); - - return GroundPrimitive._initPromise; + return ApproximateTerrainHeights.initialize(); }; /** @@ -655,7 +642,7 @@ define([ return; } - if (!GroundPrimitive._initialized) { + if (!ApproximateTerrainHeights.initialized) { //>>includeStart('debug', pragmas.debug); if (!this.asynchronous) { throw new DeveloperError('For synchronous GroundPrimitives, you must call GroundPrimitive.initializeTerrainHeights() and wait for the returned promise to resolve.'); diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index b50ff303b065..96a8711e1559 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -64,8 +64,8 @@ define([ /** * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/Instanced3DModel/README.md|Instanced 3D Model} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Instanced3DModel|Instanced 3D Model} + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset. *

* Implements the {@link Cesium3DTileContent} interface. *

@@ -451,8 +451,8 @@ define([ this._batchTable.setAllColor(color); }; - Instanced3DModel3DTileContent.prototype.applyStyle = function(frameState, style) { - this._batchTable.applyStyle(frameState, style); + Instanced3DModel3DTileContent.prototype.applyStyle = function(style) { + this._batchTable.applyStyle(style); }; Instanced3DModel3DTileContent.prototype.update = function(tileset, frameState) { diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js index fd055aea88f0..891783cb02df 100644 --- a/Source/Scene/Model.js +++ b/Source/Scene/Model.js @@ -6,6 +6,7 @@ define([ '../Core/clone', '../Core/Color', '../Core/combine', + '../Core/createGuid', '../Core/defaultValue', '../Core/defined', '../Core/defineProperties', @@ -79,6 +80,7 @@ define([ clone, Color, combine, + createGuid, defaultValue, defined, defineProperties, @@ -206,7 +208,7 @@ define([ }; var gltfCache = {}; - + var uriToGuid = {}; /////////////////////////////////////////////////////////////////////////// /** @@ -1195,9 +1197,14 @@ define([ var basePath = defaultValue(options.basePath, modelResource.clone()); var resource = Resource.createIfNeeded(basePath); - // If no cache key is provided, use the absolute URL, since two URLs with - // different relative paths could point to the same model. - var cacheKey = defaultValue(options.cacheKey, getAbsoluteUri(modelResource.url)); + // If no cache key is provided, use a GUID. + // Check using a URI to GUID dictionary that we have not already added this model. + var cacheKey = defaultValue(options.cacheKey, uriToGuid[getAbsoluteUri(modelResource.url)]); + if (!defined(cacheKey)) { + cacheKey = createGuid(); + uriToGuid[getAbsoluteUri(modelResource.url)] = cacheKey; + } + if (defined(options.basePath) && !defined(options.cacheKey)) { cacheKey += resource.url; } diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js index 1326d8e95bd9..57e083efe409 100644 --- a/Source/Scene/OIT.js +++ b/Source/Scene/OIT.js @@ -540,7 +540,7 @@ define([ var framebuffer = passState.framebuffer; var length = commands.length; - var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled; + var lightShadowsEnabled = scene.frameState.shadowHints.lightShadowsEnabled; passState.framebuffer = oit._adjustTranslucentFBO; oit._adjustTranslucentCommand.execute(context, passState); @@ -553,14 +553,14 @@ define([ for (j = 0; j < length; ++j) { command = commands[j]; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } if (defined(invertClassification)) { command = invertClassification.unclassifiedCommand; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } @@ -569,14 +569,14 @@ define([ for (j = 0; j < length; ++j) { command = commands[j]; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } if (defined(invertClassification)) { command = invertClassification.unclassifiedCommand; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.alphaCommand : command.derivedCommands.oit.alphaCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } @@ -588,7 +588,7 @@ define([ var framebuffer = passState.framebuffer; var length = commands.length; - var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled; + var lightShadowsEnabled = scene.frameState.shadowHints.lightShadowsEnabled; passState.framebuffer = oit._adjustTranslucentFBO; oit._adjustTranslucentCommand.execute(context, passState); @@ -602,14 +602,14 @@ define([ for (var j = 0; j < length; ++j) { command = commands[j]; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } if (defined(invertClassification)) { command = invertClassification.unclassifiedCommand; command = defined(command.derivedCommands.logDepth) ? command.derivedCommands.logDepth.command : command; - derivedCommand = (shadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; + derivedCommand = (lightShadowsEnabled && command.receiveShadows) ? command.derivedCommands.oit.shadows.translucentCommand : command.derivedCommands.oit.translucentCommand; executeFunction(derivedCommand, scene, context, passState, debugFramebuffer); } diff --git a/Source/Scene/PointCloud.js b/Source/Scene/PointCloud.js index b581622b3f33..6623383bcf69 100644 --- a/Source/Scene/PointCloud.js +++ b/Source/Scene/PointCloud.js @@ -97,7 +97,7 @@ define([ /** * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/PointCloud/README.md|Point Cloud} + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/PointCloud|Point Cloud} * tile. Used internally by {@link PointCloud3DTileContent} and {@link TimeDynamicPointCloud}. * * @alias PointCloud diff --git a/Source/Scene/PointCloud3DTileContent.js b/Source/Scene/PointCloud3DTileContent.js index 61b6196c62ab..83e929963023 100644 --- a/Source/Scene/PointCloud3DTileContent.js +++ b/Source/Scene/PointCloud3DTileContent.js @@ -34,8 +34,8 @@ define([ /** * Represents the contents of a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/TileFormats/PointCloud/README.md|Point Cloud} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/PointCloud|Point Cloud} + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset. *

* Implements the {@link Cesium3DTileContent} interface. *

@@ -260,9 +260,9 @@ define([ this._pointCloud.color = enabled ? color : Color.WHITE; }; - PointCloud3DTileContent.prototype.applyStyle = function(frameState, style) { + PointCloud3DTileContent.prototype.applyStyle = function(style) { if (defined(this._batchTable)) { - this._batchTable.applyStyle(frameState, style); + this._batchTable.applyStyle(style); } else { this._styleDirty = true; } diff --git a/Source/Scene/PostProcessStageLibrary.js b/Source/Scene/PostProcessStageLibrary.js index babb7abfdffe..35a42473c6ac 100644 --- a/Source/Scene/PostProcessStageLibrary.js +++ b/Source/Scene/PostProcessStageLibrary.js @@ -776,18 +776,5 @@ define([ }); }; - /** - * Renaming createLensFlarStage to createLensFlareStage would lead to breaking change - * @deprecated - * @private - */ - PostProcessStageLibrary.createLensFlarStage = function() { - deprecationWarning( - 'PostProcessStageLibrary.createLensFlarStage', - 'createLensFlarStage has been deprecated and will be removed in Cesium 1.49. Use createLensFlareStage instead' - ); - return PostProcessStageLibrary.createLensFlareStage(); - }; - return PostProcessStageLibrary; }); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 9ed7a6ce0aeb..39ec5703e3d3 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -300,6 +300,11 @@ define([ return; } + if (this._tilesInvalidated) { + invalidateAllTiles(this); + this._tilesInvalidated = false; + } + // Gets commands for any texture re-projections this._tileProvider.initialize(frameState); @@ -376,16 +381,10 @@ define([ return; } - if (this._tilesInvalidated) { - invalidateAllTiles(this); - } - // Load/create resources for terrain and imagery. Prepare texture re-projections for the next frame. processTileLoadQueue(this, frameState); updateHeights(this, frameState); updateTileLoadProgress(this, frameState); - - this._tilesInvalidated = false; }; /** @@ -771,8 +770,11 @@ define([ var scratchRay = new Ray(); var scratchCartographic = new Cartographic(); var scratchPosition = new Cartesian3(); + var scratchArray = []; function updateHeights(primitive, frameState) { + var tryNextFrame = scratchArray; + tryNextFrame.length = 0; var tilesToUpdateHeights = primitive._tileToUpdateHeights; var terrainProvider = primitive._tileProvider.terrainProvider; @@ -783,14 +785,20 @@ define([ var mode = frameState.mode; var projection = frameState.mapProjection; var ellipsoid = projection.ellipsoid; + var i; while (tilesToUpdateHeights.length > 0) { var tile = tilesToUpdateHeights[0]; + if (tile.state !== QuadtreeTileLoadState.DONE) { + tryNextFrame.push(tile); + tilesToUpdateHeights.shift(); + primitive._lastTileIndex = 0; + continue; + } var customData = tile.customData; var customDataLength = customData.length; var timeSliceMax = false; - var i; for (i = primitive._lastTileIndex; i < customDataLength; ++i) { var data = customData[i]; @@ -870,6 +878,9 @@ define([ tilesToUpdateHeights.shift(); } } + for (i = 0; i < tryNextFrame.length; i++) { + tilesToUpdateHeights.push(tryNextFrame[i]); + } } function createRenderCommandsForSelectedTiles(primitive, frameState) { diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index 4340e5100f03..68242abcacd9 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -1430,25 +1430,6 @@ define([ } }, - /** - * When true, enables Fast Approximate Anti-aliasing even when order independent translucency - * is unsupported. - * @memberof Scene.prototype - * @type {Boolean} - * @default true - * @deprecated - */ - fxaa : { - get : function() { - deprecationWarning('Scene.fxaa', 'The Scene.fxaa property has been deprecated. Use Scene.postProcessStages.fxaa.'); - return this.postProcessStages.fxaa.enabled; - }, - set : function(value) { - deprecationWarning('Scene.fxaa', 'The Scene.fxaa property has been deprecated. Use Scene.postProcessStages.fxaa.'); - this.postProcessStages.fxaa.enabled = value; - } - }, - /** * @private */ @@ -1498,7 +1479,7 @@ define([ var shadowsEnabled = frameState.shadowHints.shadowsEnabled; var shadowMaps = frameState.shadowHints.shadowMaps; var lightShadowMaps = frameState.shadowHints.lightShadowMaps; - var lightShadowsEnabled = shadowsEnabled && (lightShadowMaps.length > 0); + var lightShadowsEnabled = frameState.shadowHints.lightShadowsEnabled; // Update derived commands when any shadow maps become dirty var shadowsDirty = false; @@ -2082,10 +2063,7 @@ define([ return; } - var shadowsEnabled = scene.frameState.shadowHints.shadowsEnabled; - var lightShadowsEnabled = shadowsEnabled && (scene.frameState.shadowHints.lightShadowMaps.length > 0); - - if (lightShadowsEnabled && command.receiveShadows && defined(command.derivedCommands.shadows)) { + if (frameState.shadowHints.lightShadowsEnabled && command.receiveShadows && defined(command.derivedCommands.shadows)) { // If the command receives shadows, execute the derived shadows command. // Some commands, such as OIT derived commands, do not have derived shadow commands themselves // and instead shadowing is built-in. In this case execute the command regularly below. @@ -2940,6 +2918,8 @@ define([ frameState.shadowHints.shadowsEnabled = shadowsEnabled; } + frameState.shadowHints.lightShadowsEnabled = false; + if (!shadowsEnabled) { return; } @@ -2964,6 +2944,7 @@ define([ if (shadowMap.fromLightSource) { frameState.shadowHints.lightShadowMaps.push(shadowMap); + frameState.shadowHints.lightShadowsEnabled = true; } if (shadowMap.dirty) { @@ -3751,14 +3732,19 @@ define([ * * @param {Cartesian2} windowPosition Window coordinates to perform picking on. * @param {Number} [limit] If supplied, stop drilling after collecting this many picks. + * @param {Number} [width=3] Width of the pick rectangle. + * @param {Number} [height=3] Height of the pick rectangle. * @returns {Object[]} Array of objects, each containing 1 picked primitives. * * @exception {DeveloperError} windowPosition is undefined. * * @example * var pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0)); + * + * @see Scene#pick + * */ - Scene.prototype.drillPick = function(windowPosition, limit) { + Scene.prototype.drillPick = function(windowPosition, limit, width, height) { // PERFORMANCE_IDEA: This function calls each primitive's update for each pass. Instead // we could update the primitive once, and then just execute their commands for each pass, // and cull commands for picked primitives. e.g., base on the command's owner. @@ -3778,7 +3764,7 @@ define([ limit = Number.MAX_VALUE; } - var pickedResult = this.pick(windowPosition); + var pickedResult = this.pick(windowPosition, width, height); while (defined(pickedResult) && defined(pickedResult.primitive)) { result.push(pickedResult); if (0 >= --limit) { @@ -3806,7 +3792,7 @@ define([ pickedPrimitives.push(primitive); } - pickedResult = this.pick(windowPosition); + pickedResult = this.pick(windowPosition, width, height); } // unhide everything we hid while drill picking @@ -3945,26 +3931,22 @@ define([ this.sun = this.sun && this.sun.destroy(); this._sunPostProcess = this._sunPostProcess && this._sunPostProcess.destroy(); this._depthPlane = this._depthPlane && this._depthPlane.destroy(); - this._transitioner.destroy(); + this._transitioner = this._transitioner && this._transitioner.destroy(); this._debugFrustumPlanes = this._debugFrustumPlanes && this._debugFrustumPlanes.destroy(); this._brdfLutGenerator = this._brdfLutGenerator && this._brdfLutGenerator.destroy(); + this._globeDepth = this._globeDepth && this._globeDepth.destroy(); + this._oit = this._oit && this._oit.destroy(); - if (defined(this._globeDepth)) { - this._globeDepth.destroy(); - } if (this._removeCreditContainer) { this._canvas.parentNode.removeChild(this._creditContainer); } - if (defined(this._oit)) { - this._oit.destroy(); - } - this._sceneFramebuffer = this._sceneFramebuffer && this._sceneFramebuffer.destroy(); this.postProcessStages = this.postProcessStages && this.postProcessStages.destroy(); this._context = this._context && this._context.destroy(); - this._frameState.creditDisplay.destroy(); + this._frameState.creditDisplay = this._frameState.creditDisplay && this._frameState.creditDisplay.destroy(); + if (defined(this._performanceDisplay)){ this._performanceDisplay = this._performanceDisplay && this._performanceDisplay.destroy(); this._performanceContainer.parentNode.removeChild(this._performanceContainer); diff --git a/Source/Scene/SceneTransitioner.js b/Source/Scene/SceneTransitioner.js index b69d36c93c8d..52d8e934eee8 100644 --- a/Source/Scene/SceneTransitioner.js +++ b/Source/Scene/SceneTransitioner.js @@ -285,6 +285,7 @@ define([ var completeMorph = function() { transitioner._morphCancelled = true; + transitioner._scene.camera.cancelFlight(); completeMorphFunction(transitioner); }; transitioner._completeMorph = completeMorph; @@ -530,7 +531,7 @@ define([ var globe = scene.globe; if (defined(globe)) { - var pickPos = globe.pick(ray, scene, scratchCVTo2DPickPos); + var pickPos = globe.pickWorldCoordinates(ray, scene, scratchCVTo2DPickPos); if (defined(pickPos)) { Matrix4.multiplyByPoint(Camera.TRANSFORM_2D_INVERSE, pickPos, endPos); endPos.z += Cartesian3.distance(startPos, endPos); @@ -634,7 +635,7 @@ define([ var globe = scene.globe; if (defined(globe)) { - var pickedPos = globe.pick(ray, scene, scratch3DTo2DPickPosition); + var pickedPos = globe.pickWorldCoordinates(ray, scene, scratch3DTo2DPickPosition); if (defined(pickedPos)) { var height = Cartesian3.distance(camera2D.position2D, pickedPos); pickedPos.x += height; diff --git a/Source/Scene/ScreenSpaceCameraController.js b/Source/Scene/ScreenSpaceCameraController.js index 02037bbbb2e7..3e8600ce0c06 100644 --- a/Source/Scene/ScreenSpaceCameraController.js +++ b/Source/Scene/ScreenSpaceCameraController.js @@ -512,7 +512,12 @@ define([ object._zoomMouseStart = Cartesian2.clone(startPosition, object._zoomMouseStart); if (defined(object._globe)) { - pickedPosition = mode !== SceneMode.SCENE2D ? pickGlobe(object, startPosition, scratchPickCartesian) : camera.getPickRay(startPosition, scratchZoomPickRay).origin; + if (mode === SceneMode.SCENE2D) { + pickedPosition = camera.getPickRay(startPosition, scratchZoomPickRay).origin; + pickedPosition = Cartesian3.fromElements(pickedPosition.y, pickedPosition.z, pickedPosition.x); + } else { + pickedPosition = pickGlobe(object, startPosition, scratchPickCartesian); + } } if (defined(pickedPosition)) { object._useZoomWorldPosition = true; @@ -552,6 +557,7 @@ define([ if ((camera.position.x < 0.0 && savedX > 0.0) || (camera.position.x > 0.0 && savedX < 0.0)) { pickedPosition = camera.getPickRay(startPosition, scratchZoomPickRay).origin; + pickedPosition = Cartesian3.fromElements(pickedPosition.y, pickedPosition.z, pickedPosition.x); object._zoomWorldPosition = Cartesian3.clone(pickedPosition, object._zoomWorldPosition); } } @@ -692,7 +698,7 @@ define([ } var rayDirection = ray.direction; - if (mode === SceneMode.COLUMBUS_VIEW) { + if (mode === SceneMode.COLUMBUS_VIEW || mode === SceneMode.SCENE2D) { Cartesian3.fromElements(rayDirection.y, rayDirection.z, rayDirection.x, rayDirection); } @@ -716,6 +722,9 @@ define([ var start = camera.getPickRay(movement.startPosition, translate2DStart).origin; var end = camera.getPickRay(movement.endPosition, translate2DEnd).origin; + start = Cartesian3.fromElements(start.y, start.z, start.x, start); + end = Cartesian3.fromElements(end.y, end.z, end.x, end); + var direction = Cartesian3.subtract(start, end, scratchTranslateP0); var distance = Cartesian3.magnitude(direction); @@ -832,7 +841,7 @@ define([ } var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay); - var rayIntersection = globe.pick(ray, scene, scratchRayIntersection); + var rayIntersection = globe.pickWorldCoordinates(ray, scene, scratchRayIntersection); var pickDistance = defined(depthIntersection) ? Cartesian3.distance(depthIntersection, camera.positionWC) : Number.POSITIVE_INFINITY; var rayDistance = defined(rayIntersection) ? Cartesian3.distance(rayIntersection, camera.positionWC) : Number.POSITIVE_INFINITY; diff --git a/Source/Scene/ShadowVolumeAppearance.js b/Source/Scene/ShadowVolumeAppearance.js index e18161cbc253..42adc5d7e093 100644 --- a/Source/Scene/ShadowVolumeAppearance.js +++ b/Source/Scene/ShadowVolumeAppearance.js @@ -36,6 +36,13 @@ define([ ShadowVolumeAppearanceFS) { 'use strict'; + var projectionExtentDefines = { + eastMostYhighDefine : '', + eastMostYlowDefine : '', + westMostYhighDefine : '', + westMostYlowDefine : '' + }; + /** * Creates shaders for a ClassificationPrimitive to use a given Appearance, as well as for picking. * @@ -183,15 +190,17 @@ define([ * @param {String[]} defines External defines to pass to the vertex shader. * @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position. * @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D. + * @param {MapProjection} mapProjection Current scene's map projection. * @returns {String} Shader source for the vertex shader. */ - ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D) { + ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { //>>includeStart('debug', pragmas.debug); Check.defined('defines', defines); Check.typeOf.string('vertexShaderSource', vertexShaderSource); Check.typeOf.bool('columbusView2D', columbusView2D); + Check.defined('mapProjection', mapProjection); //>>includeEnd('debug'); - return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance); + return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance, mapProjection); }; /** @@ -200,20 +209,55 @@ define([ * @param {String[]} defines External defines to pass to the vertex shader. * @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position and picking. * @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D. + * @param {MapProjection} mapProjection Current scene's map projection. * @returns {String} Shader source for the vertex shader. */ - ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D) { + ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { //>>includeStart('debug', pragmas.debug); Check.defined('defines', defines); Check.typeOf.string('vertexShaderSource', vertexShaderSource); Check.typeOf.bool('columbusView2D', columbusView2D); + Check.defined('mapProjection', mapProjection); //>>includeEnd('debug'); - return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource); + return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, undefined, mapProjection); }; - function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance) { + var longitudeExtentsCartesianScratch = new Cartesian3(); + var longitudeExtentsCartographicScratch = new Cartographic(); + var longitudeExtentsEncodeScratch = { + high : 0.0, + low : 0.0 + }; + function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance, mapProjection) { var allDefines = defines.slice(); + if (projectionExtentDefines.eastMostYhighDefine === '') { + var eastMostCartographic = longitudeExtentsCartographicScratch; + eastMostCartographic.longitude = CesiumMath.PI; + eastMostCartographic.latitude = 0.0; + eastMostCartographic.height = 0.0; + var eastMostCartesian = mapProjection.project(eastMostCartographic, longitudeExtentsCartesianScratch); + var encoded = EncodedCartesian3.encode(eastMostCartesian.x, longitudeExtentsEncodeScratch); + projectionExtentDefines.eastMostYhighDefine = 'EAST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + projectionExtentDefines.eastMostYlowDefine = 'EAST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + + var westMostCartographic = longitudeExtentsCartographicScratch; + westMostCartographic.longitude = -CesiumMath.PI; + westMostCartographic.latitude = 0.0; + westMostCartographic.height = 0.0; + var westMostCartesian = mapProjection.project(westMostCartographic, longitudeExtentsCartesianScratch); + encoded = EncodedCartesian3.encode(westMostCartesian.x, longitudeExtentsEncodeScratch); + projectionExtentDefines.westMostYhighDefine = 'WEST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + projectionExtentDefines.westMostYlowDefine = 'WEST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + } + + if (columbusView2D) { + allDefines.push(projectionExtentDefines.eastMostYhighDefine); + allDefines.push(projectionExtentDefines.eastMostYlowDefine); + allDefines.push(projectionExtentDefines.westMostYhighDefine); + allDefines.push(projectionExtentDefines.westMostYlowDefine); + } + if (defined(appearance) && appearance instanceof PerInstanceColorAppearance) { allDefines.push('PER_INSTANCE_COLOR'); } @@ -636,13 +680,27 @@ define([ // rectangle cartographic coords !== spherical because it's on an ellipsoid var southWestExtents = latLongToSpherical(boundingRectangle.south, boundingRectangle.west, ellipsoid, sphericalScratch); - // Slightly pad extents to avoid floating point error when fragment culling at edges. - var south = southWestExtents.x - CesiumMath.EPSILON5; - var west = southWestExtents.y - CesiumMath.EPSILON5; + var south = southWestExtents.x; + var west = southWestExtents.y; var northEastExtents = latLongToSpherical(boundingRectangle.north, boundingRectangle.east, ellipsoid, sphericalScratch); - var north = northEastExtents.x + CesiumMath.EPSILON5; - var east = northEastExtents.y + CesiumMath.EPSILON5; + var north = northEastExtents.x; + var east = northEastExtents.y; + + // If the bounding rectangle crosses the IDL, rotate the spherical extents so the cross no longer happens. + // This rotation must happen in the shader too. + var rotationRadians = 0.0; + if (west > east) { + rotationRadians = CesiumMath.PI - west; + west = -CesiumMath.PI; + east += rotationRadians; + } + + // Slightly pad extents to avoid floating point error when fragment culling at edges. + south -= CesiumMath.EPSILON5; + west -= CesiumMath.EPSILON5; + north += CesiumMath.EPSILON5; + east += CesiumMath.EPSILON5; var longitudeRangeInverse = 1.0 / (east - west); var latitudeRangeInverse = 1.0 / (north - south); @@ -653,6 +711,12 @@ define([ componentsPerAttribute: 4, normalize: false, value : [south, west, latitudeRangeInverse, longitudeRangeInverse] + }), + longitudeRotation : new GeometryInstanceAttribute({ + componentDatatype: ComponentDatatype.FLOAT, + componentsPerAttribute: 1, + normalize: false, + value : [rotationRadians] }) }; @@ -669,7 +733,7 @@ define([ }; ShadowVolumeAppearance.hasAttributesForSphericalExtents = function(attributes) { - return defined(attributes.sphericalExtents) && + return defined(attributes.sphericalExtents) && defined(attributes.longitudeRotation) && defined(attributes.planes2D_HIGH) && defined(attributes.planes2D_LOW) && defined(attributes.uMaxVmax) && defined(attributes.uvMinAndExtents); }; diff --git a/Source/Scene/StyleExpression.js b/Source/Scene/StyleExpression.js index 3bb72e05ecb2..81e6b8bcdb26 100644 --- a/Source/Scene/StyleExpression.js +++ b/Source/Scene/StyleExpression.js @@ -8,7 +8,7 @@ define([ * An expression for a style applied to a {@link Cesium3DTileset}. *

* Derived classes of this interface evaluate expressions in the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}. + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}. *

*

* This type describes an interface and is not intended to be instantiated directly. @@ -26,19 +26,18 @@ define([ /** * Evaluates the result of an expression, optionally using the provided feature's properties. If the result of * the expression in the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} * is of type Boolean, Number, or String, the corresponding JavaScript * primitive type will be returned. If the result is a RegExp, a Javascript RegExp * object will be returned. If the result is a Cartesian2, Cartesian3, or Cartesian4, * a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} object will be returned. If the result argument is * a {@link Color}, the {@link Cartesian4} value is converted to a {@link Color} and then returned. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Object} [result] The object onto which to store the result. * @returns {Boolean|Number|String|RegExp|Cartesian2|Cartesian3|Cartesian4|Color} The result of evaluating the expression. */ - StyleExpression.prototype.evaluate = function(frameState, feature, result) { + StyleExpression.prototype.evaluate = function(feature, result) { DeveloperError.throwInstantiationError(); }; @@ -48,12 +47,11 @@ define([ * This is equivalent to {@link StyleExpression#evaluate} but always returns a {@link Color} object. *

* - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileFeature} feature The feature whose properties may be used as variables in the expression. * @param {Color} [result] The object in which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ - StyleExpression.prototype.evaluateColor = function(frameState, feature, result) { + StyleExpression.prototype.evaluateColor = function(feature, result) { DeveloperError.throwInstantiationError(); }; diff --git a/Source/Scene/TileBoundingRegion.js b/Source/Scene/TileBoundingRegion.js index 48ac2003f723..52686d5a3d88 100644 --- a/Source/Scene/TileBoundingRegion.js +++ b/Source/Scene/TileBoundingRegion.js @@ -352,6 +352,7 @@ define([ }); var instance = new GeometryInstance({ geometry : geometry, + id : 'outline', modelMatrix : modelMatrix, attributes : { color : ColorGeometryInstanceAttribute.fromColor(color) diff --git a/Source/Scene/TileBoundingSphere.js b/Source/Scene/TileBoundingSphere.js index ffc98d1245ad..278e11ad8a51 100644 --- a/Source/Scene/TileBoundingSphere.js +++ b/Source/Scene/TileBoundingSphere.js @@ -151,6 +151,7 @@ define([ var modelMatrix = Matrix4.fromTranslation(this.center, new Matrix4.clone(Matrix4.IDENTITY)); var instance = new GeometryInstance({ geometry : geometry, + id : 'outline', modelMatrix : modelMatrix, attributes : { color : ColorGeometryInstanceAttribute.fromColor(color) diff --git a/Source/Scene/TileOrientedBoundingBox.js b/Source/Scene/TileOrientedBoundingBox.js index bf09771654a6..c1f0ef277694 100644 --- a/Source/Scene/TileOrientedBoundingBox.js +++ b/Source/Scene/TileOrientedBoundingBox.js @@ -134,6 +134,7 @@ define([ var modelMatrix = Matrix4.fromRotationTranslation(this.boundingVolume.halfAxes, this.boundingVolume.center); var instance = new GeometryInstance({ geometry : geometry, + id : 'outline', modelMatrix : modelMatrix, attributes : { color : ColorGeometryInstanceAttribute.fromColor(color) diff --git a/Source/Scene/Tileset3DTileContent.js b/Source/Scene/Tileset3DTileContent.js index 65af2b76b7d6..015db00a4ab5 100644 --- a/Source/Scene/Tileset3DTileContent.js +++ b/Source/Scene/Tileset3DTileContent.js @@ -16,7 +16,7 @@ define([ /** * Represents content for a tile in a - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset whose + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset whose * content points to another 3D Tiles tileset. *

* Implements the {@link Cesium3DTileContent} interface. @@ -148,7 +148,7 @@ define([ Tileset3DTileContent.prototype.applyDebugSettings = function(enabled, color) { }; - Tileset3DTileContent.prototype.applyStyle = function(frameState, style) { + Tileset3DTileContent.prototype.applyStyle = function(style) { }; Tileset3DTileContent.prototype.update = function(tileset, frameState) { diff --git a/Source/Scene/TimeDynamicPointCloud.js b/Source/Scene/TimeDynamicPointCloud.js index 684223ac3046..5ee29f81670f 100644 --- a/Source/Scene/TimeDynamicPointCloud.js +++ b/Source/Scene/TimeDynamicPointCloud.js @@ -61,7 +61,7 @@ define([ * @param {ShadowMode} [options.shadows=ShadowMode.ENABLED] Determines whether the point cloud casts or receives shadows from each light source. * @param {Number} [options.maximumMemoryUsage=256] The maximum amount of memory in MB that can be used by the point cloud. * @param {Object} [options.shading] Options for constructing a {@link PointCloudShading} object to control point attenuation and eye dome lighting. - * @param {Cesium3DTileStyle} [options.style] The style, defined using the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}, applied to each point in the point cloud. + * @param {Cesium3DTileStyle} [options.style] The style, defined using the {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}, applied to each point in the point cloud. * @param {ClippingPlaneCollection} [options.clippingPlanes] The {@link ClippingPlaneCollection} used to selectively disable rendering the point cloud. */ function TimeDynamicPointCloud(options) { @@ -126,7 +126,7 @@ define([ /** * The style, defined using the - * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language}, + * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language}, * applied to each point in the point cloud. *

* Assign undefined to remove the style, which will restore the visual @@ -147,7 +147,7 @@ define([ * show : '${Classification} !== 2' * }); * - * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/Styling|3D Tiles Styling language} + * @see {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/Styling|3D Tiles Styling language} */ this.style = options.style; diff --git a/Source/Scene/Vector3DTileContent.js b/Source/Scene/Vector3DTileContent.js index c8bb89e5271f..4db34f4c8e2f 100644 --- a/Source/Scene/Vector3DTileContent.js +++ b/Source/Scene/Vector3DTileContent.js @@ -49,7 +49,7 @@ define([ /** * Represents the contents of a * {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/3d-tiles-next/TileFormats/VectorData|Vector} - * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/blob/master/README.md|3D Tiles} tileset. + * tile in a {@link https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification|3D Tiles} tileset. *

* Implements the {@link Cesium3DTileContent} interface. *

@@ -396,7 +396,7 @@ define([ polygonMaximumHeights : polygonMaximumHeights, center : center, rectangle : rectangle, - boundingVolume : content._tile._boundingVolume.boundingVolume, + boundingVolume : content.tile.boundingVolume.boundingVolume, batchTable : batchTable, batchIds : batchIds.polygons, modelMatrix : modelMatrix @@ -430,7 +430,7 @@ define([ maximumHeight : maxHeight, center : center, rectangle : rectangle, - boundingVolume : content._tile._boundingVolume.boundingVolume, + boundingVolume : content.tile.boundingVolume.boundingVolume, batchTable : batchTable }); } @@ -494,16 +494,16 @@ define([ } }; - Vector3DTileContent.prototype.applyStyle = function(frameState, style) { + Vector3DTileContent.prototype.applyStyle = function(style) { createFeatures(this); if (defined(this._polygons)) { - this._polygons.applyStyle(frameState, style, this._features); + this._polygons.applyStyle(style, this._features); } if (defined(this._polylines)) { - this._polylines.applyStyle(frameState, style, this._features); + this._polylines.applyStyle(style, this._features); } if (defined(this._points)) { - this._points.applyStyle(frameState, style, this._features); + this._points.applyStyle(style, this._features); } }; diff --git a/Source/Scene/Vector3DTileGeometry.js b/Source/Scene/Vector3DTileGeometry.js index 762b543d7767..bb1e7e2e7084 100644 --- a/Source/Scene/Vector3DTileGeometry.js +++ b/Source/Scene/Vector3DTileGeometry.js @@ -408,12 +408,11 @@ define([ /** * Apply a style to the content. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The array of features. */ - Vector3DTileGeometry.prototype.applyStyle = function(frameState, style, features) { - this._primitive.applyStyle(frameState, style, features); + Vector3DTileGeometry.prototype.applyStyle = function(style, features) { + this._primitive.applyStyle(style, features); }; /** diff --git a/Source/Scene/Vector3DTilePoints.js b/Source/Scene/Vector3DTilePoints.js index 9a3e2938ad57..2416197ee2f0 100644 --- a/Source/Scene/Vector3DTilePoints.js +++ b/Source/Scene/Vector3DTilePoints.js @@ -309,11 +309,10 @@ define([ /** * Apply a style to the content. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The array of features. */ - Vector3DTilePoints.prototype.applyStyle = function(frameState, style, features) { + Vector3DTilePoints.prototype.applyStyle = function(style, features) { if (!defined(style)) { clearStyle(this, features); return; @@ -326,65 +325,65 @@ define([ var feature = features[batchId]; if (defined(style.show)) { - feature.show = style.show.evaluate(frameState, feature); + feature.show = style.show.evaluate(feature); } if (defined(style.pointSize)) { - feature.pointSize = style.pointSize.evaluate(frameState, feature); + feature.pointSize = style.pointSize.evaluate(feature); } if (defined(style.color)) { - feature.color = style.color.evaluateColor(frameState, feature, scratchColor); + feature.color = style.color.evaluateColor(feature, scratchColor); } if (defined(style.pointOutlineColor)) { - feature.pointOutlineColor = style.pointOutlineColor.evaluateColor(frameState, feature, scratchColor2); + feature.pointOutlineColor = style.pointOutlineColor.evaluateColor(feature, scratchColor2); } if (defined(style.pointOutlineWidth)) { - feature.pointOutlineWidth = style.pointOutlineWidth.evaluate(frameState, feature); + feature.pointOutlineWidth = style.pointOutlineWidth.evaluate(feature); } if (defined(style.labelColor)) { - feature.labelColor = style.labelColor.evaluateColor(frameState, feature, scratchColor3); + feature.labelColor = style.labelColor.evaluateColor(feature, scratchColor3); } if (defined(style.labelOutlineColor)) { - feature.labelOutlineColor = style.labelOutlineColor.evaluateColor(frameState, feature, scratchColor4); + feature.labelOutlineColor = style.labelOutlineColor.evaluateColor(feature, scratchColor4); } if (defined(style.labelOutlineWidth)) { - feature.labelOutlineWidth = style.labelOutlineWidth.evaluate(frameState, feature); + feature.labelOutlineWidth = style.labelOutlineWidth.evaluate(feature); } if (defined(style.font)) { - feature.font = style.font.evaluate(frameState, feature); + feature.font = style.font.evaluate(feature); } if (defined(style.labelStyle)) { - feature.labelStyle = style.labelStyle.evaluate(frameState, feature); + feature.labelStyle = style.labelStyle.evaluate(feature); } if (defined(style.labelText)) { - feature.labelText = style.labelText.evaluate(frameState, feature); + feature.labelText = style.labelText.evaluate(feature); } else { feature.labelText = undefined; } if (defined(style.backgroundColor)) { - feature.backgroundColor = style.backgroundColor.evaluateColor(frameState, feature, scratchColor5); + feature.backgroundColor = style.backgroundColor.evaluateColor(feature, scratchColor5); } if (defined(style.backgroundPadding)) { - feature.backgroundPadding = style.backgroundPadding.evaluate(frameState, feature); + feature.backgroundPadding = style.backgroundPadding.evaluate(feature); } if (defined(style.backgroundEnabled)) { - feature.backgroundEnabled = style.backgroundEnabled.evaluate(frameState, feature); + feature.backgroundEnabled = style.backgroundEnabled.evaluate(feature); } if (defined(style.scaleByDistance)) { - var scaleByDistanceCart4 = style.scaleByDistance.evaluate(frameState, feature); + var scaleByDistanceCart4 = style.scaleByDistance.evaluate(feature); scratchScaleByDistance.near = scaleByDistanceCart4.x; scratchScaleByDistance.nearValue = scaleByDistanceCart4.y; scratchScaleByDistance.far = scaleByDistanceCart4.z; @@ -395,7 +394,7 @@ define([ } if (defined(style.translucencyByDistance)) { - var translucencyByDistanceCart4 = style.translucencyByDistance.evaluate(frameState, feature); + var translucencyByDistanceCart4 = style.translucencyByDistance.evaluate(feature); scratchTranslucencyByDistance.near = translucencyByDistanceCart4.x; scratchTranslucencyByDistance.nearValue = translucencyByDistanceCart4.y; scratchTranslucencyByDistance.far = translucencyByDistanceCart4.z; @@ -406,7 +405,7 @@ define([ } if (defined(style.distanceDisplayCondition)) { - var distanceDisplayConditionCart2 = style.distanceDisplayCondition.evaluate(frameState, feature); + var distanceDisplayConditionCart2 = style.distanceDisplayCondition.evaluate(feature); scratchDistanceDisplayCondition.near = distanceDisplayConditionCart2.x; scratchDistanceDisplayCondition.far = distanceDisplayConditionCart2.y; feature.distanceDisplayCondition = scratchDistanceDisplayCondition; @@ -415,41 +414,41 @@ define([ } if (defined(style.heightOffset)) { - feature.heightOffset = style.heightOffset.evaluate(frameState, feature); + feature.heightOffset = style.heightOffset.evaluate(feature); } if (defined(style.anchorLineEnabled)) { - feature.anchorLineEnabled = style.anchorLineEnabled.evaluate(frameState, feature); + feature.anchorLineEnabled = style.anchorLineEnabled.evaluate(feature); } if (defined(style.anchorLineColor)) { - feature.anchorLineColor = style.anchorLineColor.evaluateColor(frameState, feature, scratchColor6); + feature.anchorLineColor = style.anchorLineColor.evaluateColor(feature, scratchColor6); } if (defined(style.image)) { - feature.image = style.image.evaluate(frameState, feature); + feature.image = style.image.evaluate(feature); } else { feature.image = undefined; } if (defined(style.disableDepthTestDistance)) { - feature.disableDepthTestDistance = style.disableDepthTestDistance.evaluate(frameState, feature); + feature.disableDepthTestDistance = style.disableDepthTestDistance.evaluate(feature); } if (defined(style.horizontalOrigin)) { - feature.horizontalOrigin = style.horizontalOrigin.evaluate(frameState, feature); + feature.horizontalOrigin = style.horizontalOrigin.evaluate(feature); } if (defined(style.verticalOrigin)) { - feature.verticalOrigin = style.verticalOrigin.evaluate(frameState, feature); + feature.verticalOrigin = style.verticalOrigin.evaluate(feature); } if (defined(style.labelHorizontalOrigin)) { - feature.labelHorizontalOrigin = style.labelHorizontalOrigin.evaluate(frameState, feature); + feature.labelHorizontalOrigin = style.labelHorizontalOrigin.evaluate(feature); } if (defined(style.labelVerticalOrigin)) { - feature.labelVerticalOrigin = style.labelVerticalOrigin.evaluate(frameState, feature); + feature.labelVerticalOrigin = style.labelVerticalOrigin.evaluate(feature); } } }; diff --git a/Source/Scene/Vector3DTilePolygons.js b/Source/Scene/Vector3DTilePolygons.js index 3fc2387759f5..dd1dce43fba2 100644 --- a/Source/Scene/Vector3DTilePolygons.js +++ b/Source/Scene/Vector3DTilePolygons.js @@ -384,12 +384,11 @@ define([ /** * Apply a style to the content. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The array of features. */ - Vector3DTilePolygons.prototype.applyStyle = function(frameState, style, features) { - this._primitive.applyStyle(frameState, style, features); + Vector3DTilePolygons.prototype.applyStyle = function(style, features) { + this._primitive.applyStyle(style, features); }; /** diff --git a/Source/Scene/Vector3DTilePolylines.js b/Source/Scene/Vector3DTilePolylines.js index cd4f4f72a36b..b233f641dcdd 100644 --- a/Source/Scene/Vector3DTilePolylines.js +++ b/Source/Scene/Vector3DTilePolylines.js @@ -489,11 +489,10 @@ define([ /** * Apply a style to the content. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The array of features. */ - Vector3DTilePolylines.prototype.applyStyle = function(frameState, style, features) { + Vector3DTilePolylines.prototype.applyStyle = function(style, features) { if (!defined(style)) { clearStyle(this, features); return; @@ -505,8 +504,8 @@ define([ var batchId = batchIds[i]; var feature = features[batchId]; - feature.color = defined(style.color) ? style.color.evaluateColor(frameState, feature, scratchColor) : DEFAULT_COLOR_VALUE; - feature.show = defined(style.show) ? style.show.evaluate(frameState, feature) : DEFAULT_SHOW_VALUE; + feature.color = defined(style.color) ? style.color.evaluateColor(feature, scratchColor) : DEFAULT_COLOR_VALUE; + feature.show = defined(style.show) ? style.show.evaluate(feature) : DEFAULT_SHOW_VALUE; } }; diff --git a/Source/Scene/Vector3DTilePrimitive.js b/Source/Scene/Vector3DTilePrimitive.js index 7ee1aa55150b..91cee93c9a62 100644 --- a/Source/Scene/Vector3DTilePrimitive.js +++ b/Source/Scene/Vector3DTilePrimitive.js @@ -929,11 +929,10 @@ define([ /** * Apply a style to the content. * - * @param {FrameState} frameState The frame state. * @param {Cesium3DTileStyle} style The style. * @param {Cesium3DTileFeature[]} features The array of features. */ - Vector3DTilePrimitive.prototype.applyStyle = function(frameState, style, features) { + Vector3DTilePrimitive.prototype.applyStyle = function(style, features) { if (!defined(style)) { clearStyle(this, features); return; @@ -951,8 +950,8 @@ define([ var batchId = batchIds[i]; var feature = features[batchId]; - feature.color = defined(style.color) ? style.color.evaluateColor(frameState, feature, scratchColor) : DEFAULT_COLOR_VALUE; - feature.show = defined(style.show) ? style.show.evaluate(frameState, feature) : DEFAULT_SHOW_VALUE; + feature.color = defined(style.color) ? style.color.evaluateColor(feature, scratchColor) : DEFAULT_COLOR_VALUE; + feature.show = defined(style.show) ? style.show.evaluate(feature) : DEFAULT_SHOW_VALUE; } if (isSimpleStyle) { diff --git a/Source/Scene/computeFlyToLocationForRectangle.js b/Source/Scene/computeFlyToLocationForRectangle.js new file mode 100644 index 000000000000..64149dc12a46 --- /dev/null +++ b/Source/Scene/computeFlyToLocationForRectangle.js @@ -0,0 +1,75 @@ +define([ + '../Core/defined', + '../Core/Rectangle', + '../Core/sampleTerrainMostDetailed', + './SceneMode', + '../ThirdParty/when' +], function( + defined, + Rectangle, + sampleTerrainMostDetailed, + SceneMode, + when) { +'use strict'; + + /** + * Computes the final camera location to view a rectangle adjusted for terrain. + * + * @param {Rectangle} rectangle The rectangle being zoomed to. + * @param {Scene} scene The scene being used. + * + * @returns {Cartographic|Rectangle} The location to place the camera or the original rectangle if terrain does not have availability. + * + * @private + */ + function computeFlyToLocationForRectangle(rectangle, scene) { + var terrainProvider = scene.terrainProvider; + + if (!defined(terrainProvider)) { + return when.resolve(rectangle); + } + + return terrainProvider.readyPromise.then(function() { + var availability = terrainProvider.availability; + + if (!defined(availability) || scene.mode === SceneMode.SCENE2D) { + return rectangle; + } + + var cartographics = [ + Rectangle.center(rectangle), + Rectangle.southeast(rectangle), + Rectangle.southwest(rectangle), + Rectangle.northeast(rectangle), + Rectangle.northwest(rectangle) + ]; + + return computeFlyToLocationForRectangle._sampleTerrainMostDetailed(terrainProvider, cartographics) + .then(function(positionsOnTerrain) { + var maxHeight = positionsOnTerrain.reduce(function(currentMax, item) { + return Math.max(item.height, currentMax); + }, -Number.MAX_VALUE); + + var finalPosition; + + var camera = scene.camera; + var mapProjection = scene.mapProjection; + var ellipsoid = mapProjection.ellipsoid; + var tmp = camera.getRectangleCameraCoordinates(rectangle); + if (scene.mode === SceneMode.SCENE3D) { + finalPosition = ellipsoid.cartesianToCartographic(tmp); + } else { + finalPosition = mapProjection.unproject(tmp); + } + + finalPosition.height += maxHeight; + return finalPosition; + }); + }); + } + + //Exposed for testing. + computeFlyToLocationForRectangle._sampleTerrainMostDetailed = sampleTerrainMostDetailed; + + return computeFlyToLocationForRectangle; +}); diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 8364c94ad007..cb7eb85310c4 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -214,9 +214,27 @@ void main() vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a); #elif defined(ENABLE_DAYNIGHT_SHADING) float diffuseIntensity = clamp(czm_getLambertDiffuse(czm_sunDirectionEC, normalEC) * 5.0 + 0.3, 0.0, 1.0); - float cameraDist = length(czm_view[3]); + float cameraDist; + if (czm_sceneMode == czm_sceneMode2D) + { + cameraDist = max(czm_frustumPlanes.x - czm_frustumPlanes.y, czm_frustumPlanes.w - czm_frustumPlanes.z) * 0.5; + } + else if (czm_sceneMode == czm_sceneModeColumbusView) + { + cameraDist = -czm_view[3].z; + } + else + { + cameraDist = length(czm_view[3]); + } float fadeOutDist = u_lightingFadeDistance.x; float fadeInDist = u_lightingFadeDistance.y; + if (czm_sceneMode != czm_sceneMode3D) { + vec3 radii = czm_getWgs84EllipsoidEC().radii; + float maxRadii = max(radii.x, max(radii.y, radii.z)); + fadeOutDist -= maxRadii; + fadeInDist -= maxRadii; + } float t = clamp((cameraDist - fadeOutDist) / (fadeInDist - fadeOutDist), 0.0, 1.0); diffuseIntensity = mix(1.0, diffuseIntensity, t); vec4 finalColor = vec4(color.rgb * diffuseIntensity, color.a); diff --git a/Source/Shaders/PointPrimitiveCollectionVS.glsl b/Source/Shaders/PointPrimitiveCollectionVS.glsl index 2bc8608f5d7e..0fbd81f1bbcd 100644 --- a/Source/Shaders/PointPrimitiveCollectionVS.glsl +++ b/Source/Shaders/PointPrimitiveCollectionVS.glsl @@ -140,12 +140,8 @@ void main() } #endif -#ifdef LOG_DEPTH - czm_vertexLogDepth(czm_projection * positionEC); -#endif - - vec4 positionWC = czm_eyeToWindowCoordinates(positionEC); - gl_Position = czm_viewportOrthographic * vec4(positionWC.xy, -positionWC.z, 1.0); + gl_Position = czm_projection * positionEC; + czm_vertexLogDepth(); #ifdef DISABLE_DEPTH_DISTANCE float disableDepthTestDistance = distanceDisplayConditionAndDisableDepth.z; diff --git a/Source/Shaders/ShadowVolumeAppearanceFS.glsl b/Source/Shaders/ShadowVolumeAppearanceFS.glsl index 5fb3f7c4f049..6b78c130eac9 100644 --- a/Source/Shaders/ShadowVolumeAppearanceFS.glsl +++ b/Source/Shaders/ShadowVolumeAppearanceFS.glsl @@ -10,7 +10,7 @@ varying vec2 v_inversePlaneExtents; varying vec4 v_westPlane; varying vec4 v_southPlane; #endif // SPHERICAL -varying vec2 v_uvMin; +varying vec3 v_uvMinAndSphericalLongitudeRotation; varying vec3 v_uMaxAndInverseDistance; varying vec3 v_vMaxAndInverseDistance; #endif // TEXTURE_COORDINATES @@ -58,6 +58,8 @@ void main(void) #ifdef SPHERICAL // Treat world coords as a sphere normal for spherical coordinates vec2 sphericalLatLong = czm_approximateSphericalCoordinates(worldCoordinate); + sphericalLatLong.y += v_uvMinAndSphericalLongitudeRotation.z; + sphericalLatLong.y = czm_branchFreeTernary(sphericalLatLong.y < czm_pi, sphericalLatLong.y, sphericalLatLong.y - czm_twoPi); uv.x = (sphericalLatLong.y - v_sphericalExtents.y) * v_sphericalExtents.w; uv.y = (sphericalLatLong.x - v_sphericalExtents.x) * v_sphericalExtents.z; #else // SPHERICAL @@ -131,8 +133,8 @@ void main(void) // Remap texture coordinates from computed (approximately aligned with cartographic space) to the desired // texture coordinate system, which typically forms a tight oriented bounding box around the geometry. // Shader is provided a set of reference points for remapping. - materialInput.st.x = czm_lineDistance(v_uvMin, v_uMaxAndInverseDistance.xy, uv) * v_uMaxAndInverseDistance.z; - materialInput.st.y = czm_lineDistance(v_uvMin, v_vMaxAndInverseDistance.xy, uv) * v_vMaxAndInverseDistance.z; + materialInput.st.x = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_uMaxAndInverseDistance.xy, uv) * v_uMaxAndInverseDistance.z; + materialInput.st.y = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_vMaxAndInverseDistance.xy, uv) * v_vMaxAndInverseDistance.z; #endif czm_material material = czm_getMaterial(materialInput); diff --git a/Source/Shaders/ShadowVolumeAppearanceVS.glsl b/Source/Shaders/ShadowVolumeAppearanceVS.glsl index d15f79cd25dc..0f2b1c456a3b 100644 --- a/Source/Shaders/ShadowVolumeAppearanceVS.glsl +++ b/Source/Shaders/ShadowVolumeAppearanceVS.glsl @@ -20,7 +20,7 @@ varying vec2 v_inversePlaneExtents; varying vec4 v_westPlane; varying vec4 v_southPlane; #endif // SPHERICAL -varying vec2 v_uvMin; +varying vec3 v_uvMinAndSphericalLongitudeRotation; varying vec3 v_uMaxAndInverseDistance; varying vec3 v_vMaxAndInverseDistance; #endif // TEXTURE_COORDINATES @@ -40,10 +40,29 @@ void main() #ifdef TEXTURE_COORDINATES #ifdef SPHERICAL v_sphericalExtents = czm_batchTable_sphericalExtents(batchId); + v_uvMinAndSphericalLongitudeRotation.z = czm_batchTable_longitudeRotation(batchId); #else // SPHERICAL #ifdef COLUMBUS_VIEW_2D vec4 planes2D_high = czm_batchTable_planes2D_HIGH(batchId); vec4 planes2D_low = czm_batchTable_planes2D_LOW(batchId); + + // If the primitive is split across the IDL (planes2D_high.x > planes2D_high.w): + // - If this vertex is on the east side of the IDL (position3DLow.y > 0.0, comparison with position3DHigh may produce artifacts) + // - existing "east" is on the wrong side of the world, far away (planes2D_high/low.w) + // - so set "east" as beyond the eastmost extent of the projection (idlSplitNewPlaneHiLow) + vec2 idlSplitNewPlaneHiLow = vec2(EAST_MOST_X_HIGH - (WEST_MOST_X_HIGH - planes2D_high.w), EAST_MOST_X_LOW - (WEST_MOST_X_LOW - planes2D_low.w)); + bool idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y > 0.0; + planes2D_high.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.w); + planes2D_low.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.w); + + // - else, if this vertex is on the west side of the IDL (position3DLow.y < 0.0) + // - existing "west" is on the wrong side of the world, far away (planes2D_high/low.x) + // - so set "west" as beyond the westmost extent of the projection (idlSplitNewPlaneHiLow) + idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y < 0.0; + idlSplitNewPlaneHiLow = vec2(WEST_MOST_X_HIGH - (EAST_MOST_X_HIGH - planes2D_high.x), WEST_MOST_X_LOW - (EAST_MOST_X_LOW - planes2D_low.x)); + planes2D_high.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.x); + planes2D_low.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.x); + vec3 southWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.xy), vec3(0.0, planes2D_low.xy))).xyz; vec3 northWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.x, planes2D_high.z), vec3(0.0, planes2D_low.x, planes2D_low.z))).xyz; vec3 southEastCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.w, planes2D_high.y), vec3(0.0, planes2D_low.w, planes2D_low.y))).xyz; @@ -71,7 +90,7 @@ void main() v_uMaxAndInverseDistance = vec3(uMaxVmax.xy, uvMinAndExtents.z); v_vMaxAndInverseDistance = vec3(uMaxVmax.zw, uvMinAndExtents.w); - v_uvMin = uvMinAndExtents.xy; + v_uvMinAndSphericalLongitudeRotation.xy = uvMinAndExtents.xy; #endif // TEXTURE_COORDINATES #ifdef PER_INSTANCE_COLOR diff --git a/Source/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspectorViewModel.js b/Source/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspectorViewModel.js index a5217060ae77..d80ba01ddb0e 100644 --- a/Source/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspectorViewModel.js +++ b/Source/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspectorViewModel.js @@ -71,7 +71,7 @@ define([ return ''; } - var statistics = tileset.statistics; + var statistics = isPick ? tileset._statisticsLastPick : tileset._statisticsLastColor; // Since the pick pass uses a smaller frustum around the pixel of interest, // the statistics will be different than the normal render pass. @@ -81,7 +81,7 @@ define([ '
  • Visited: ' + statistics.visited.toLocaleString() + '
  • ' + // Number of commands returned is likely to be higher than the number of tiles selected // because of tiles that create multiple commands. - '
  • Selected: ' + tileset._selectedTiles.length.toLocaleString() + '
  • ' + + '
  • Selected: ' + statistics.selected.toLocaleString() + '
  • ' + // Number of commands executed is likely to be higher because of commands overlapping // multiple frustums. '
  • Commands: ' + statistics.numberOfCommands.toLocaleString() + '
  • '; @@ -1193,9 +1193,8 @@ define([ var currentFeature = this._feature; if (defined(currentFeature) && !currentFeature.content.isDestroyed()) { // Restore original color to feature that is no longer selected - var frameState = this._scene.frameState; if (!this.colorize && defined(this._style)) { - currentFeature.color = defined(this._style.color) ? this._style.color.evaluateColor(frameState, currentFeature, scratchColor) : Color.WHITE; + currentFeature.color = defined(this._style.color) ? this._style.color.evaluateColor(currentFeature, scratchColor) : Color.WHITE; } else { currentFeature.color = oldColor; } diff --git a/Source/Widgets/CesiumInspector/CesiumInspector.js b/Source/Widgets/CesiumInspector/CesiumInspector.js index 81909eb47f48..8072c3696e2a 100644 --- a/Source/Widgets/CesiumInspector/CesiumInspector.js +++ b/Source/Widgets/CesiumInspector/CesiumInspector.js @@ -40,6 +40,18 @@ define([ container = getElement(container); + function createCheckBox(checkboxBinding, labelText) { + var checkboxContainer = document.createElement('div'); + var checkboxLabel = document.createElement('label'); + var checkboxInput = document.createElement('input'); + checkboxInput.type = 'checkbox'; + checkboxInput.setAttribute('data-bind', checkboxBinding); + checkboxLabel.appendChild(checkboxInput); + checkboxLabel.appendChild(document.createTextNode(labelText)); + checkboxContainer.appendChild(checkboxLabel); + return checkboxContainer; + } + var performanceContainer = document.createElement('div'); var viewModel = new CesiumInspectorViewModel(scene, performanceContainer); @@ -77,33 +89,15 @@ define([ generalSection.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : generalVisible, "cesium-cesiumInspector-hide" : !generalVisible}'); panel.appendChild(generalSection); - var debugShowFrustums = document.createElement('div'); - generalSection.appendChild(debugShowFrustums); + var debugShowFrustums = createCheckBox('checked: frustums', 'Show Frustums'); var frustumStatistics = document.createElement('div'); frustumStatistics.className = 'cesium-cesiumInspector-frustumStatistics'; frustumStatistics.setAttribute('data-bind', 'css: {"cesium-cesiumInspector-show" : frustums, "cesium-cesiumInspector-hide" : !frustums}, html: frustumStatisticText'); - var frustumsCheckbox = document.createElement('input'); - frustumsCheckbox.type = 'checkbox'; - frustumsCheckbox.setAttribute('data-bind', 'checked: frustums'); - debugShowFrustums.appendChild(frustumsCheckbox); - debugShowFrustums.appendChild(document.createTextNode('Show Frustums')); debugShowFrustums.appendChild(frustumStatistics); + generalSection.appendChild(debugShowFrustums); - var debugShowFrustumPlanes = document.createElement('div'); - generalSection.appendChild(debugShowFrustumPlanes); - var frustumPlanesCheckbox = document.createElement('input'); - frustumPlanesCheckbox.type = 'checkbox'; - frustumPlanesCheckbox.setAttribute('data-bind', 'checked: frustumPlanes'); - debugShowFrustumPlanes.appendChild(frustumPlanesCheckbox); - debugShowFrustumPlanes.appendChild(document.createTextNode('Show Frustum Planes')); - - var performanceDisplay = document.createElement('div'); - generalSection.appendChild(performanceDisplay); - var pdCheckbox = document.createElement('input'); - pdCheckbox.type = 'checkbox'; - pdCheckbox.setAttribute('data-bind', 'checked: performance'); - performanceDisplay.appendChild(pdCheckbox); - performanceDisplay.appendChild(document.createTextNode('Performance Display')); + generalSection.appendChild(createCheckBox('checked: frustumPlanes', 'Show Frustum Planes')); + generalSection.appendChild(createCheckBox('checked: performance', 'Performance Display')); performanceContainer.className = 'cesium-cesiumInspector-performanceDisplay'; generalSection.appendChild(performanceContainer); @@ -113,24 +107,13 @@ define([ shaderCacheDisplay.setAttribute('data-bind', 'html: shaderCacheText'); generalSection.appendChild(shaderCacheDisplay); - var globeDepth = document.createElement('div'); + var globeDepth = createCheckBox('checked: globeDepth', 'Show globe depth'); generalSection.appendChild(globeDepth); - var gCheckbox = document.createElement('input'); - gCheckbox.type = 'checkbox'; - gCheckbox.setAttribute('data-bind', 'checked: globeDepth'); - globeDepth.appendChild(gCheckbox); - globeDepth.appendChild(document.createTextNode('Show globe depth')); var globeDepthFrustum = document.createElement('div'); globeDepth.appendChild(globeDepthFrustum); - var pickDepth = document.createElement('div'); - generalSection.appendChild(pickDepth); - var pCheckbox = document.createElement('input'); - pCheckbox.type = 'checkbox'; - pCheckbox.setAttribute('data-bind', 'checked: pickDepth'); - pickDepth.appendChild(pCheckbox); - pickDepth.appendChild(document.createTextNode('Show pick depth')); + generalSection.appendChild(createCheckBox('checked: pickDepth', 'Show pick depth')); var depthFrustum = document.createElement('div'); generalSection.appendChild(depthFrustum); @@ -186,30 +169,11 @@ define([ buttonWrap.appendChild(pickPrimitiveButton); pickPrimRequired.appendChild(buttonWrap); - var debugSphere = document.createElement('div'); - pickPrimRequired.appendChild(debugSphere); - var bsCheckbox = document.createElement('input'); - bsCheckbox.type = 'checkbox'; - bsCheckbox.setAttribute('data-bind', 'checked: primitiveBoundingSphere, enable: hasPickedPrimitive'); - debugSphere.appendChild(bsCheckbox); - debugSphere.appendChild(document.createTextNode('Show bounding sphere')); - - var refFrame = document.createElement('div'); - pickPrimRequired.appendChild(refFrame); - var rfCheckbox = document.createElement('input'); - rfCheckbox.type = 'checkbox'; - rfCheckbox.setAttribute('data-bind', 'checked: primitiveReferenceFrame, enable: hasPickedPrimitive'); - refFrame.appendChild(rfCheckbox); - refFrame.appendChild(document.createTextNode('Show reference frame')); - - var primitiveOnly = document.createElement('div'); - this._primitiveOnly = primitiveOnly; - pickPrimRequired.appendChild(primitiveOnly); - var primitiveOnlyCheckbox = document.createElement('input'); - primitiveOnlyCheckbox.type = 'checkbox'; - primitiveOnlyCheckbox.setAttribute('data-bind', 'checked: filterPrimitive, enable: hasPickedPrimitive'); - primitiveOnly.appendChild(primitiveOnlyCheckbox); - primitiveOnly.appendChild(document.createTextNode('Show only selected')); + pickPrimRequired.appendChild(createCheckBox('checked: primitiveBoundingSphere, enable: hasPickedPrimitive', 'Show bounding sphere')); + pickPrimRequired.appendChild(createCheckBox('checked: primitiveReferenceFrame, enable: hasPickedPrimitive', 'Show reference frame')); + + this._primitiveOnly = createCheckBox('checked: filterPrimitive, enable: hasPickedPrimitive', 'Show only selected'); + pickPrimRequired.appendChild(this._primitiveOnly); // Terrain var terrain = document.createElement('div'); @@ -302,45 +266,12 @@ define([ tileInfo.appendChild(table); - var tileBoundingSphere = document.createElement('div'); - pickTileRequired.appendChild(tileBoundingSphere); - var tbsCheck = document.createElement('input'); - tbsCheck.type = 'checkbox'; - tbsCheck.setAttribute('data-bind', 'checked: tileBoundingSphere, enable: hasPickedTile'); - tileBoundingSphere.appendChild(tbsCheck); - tileBoundingSphere.appendChild(document.createTextNode('Show bounding volume')); - - var renderTile = document.createElement('div'); - pickTileRequired.appendChild(renderTile); - var rCheck = document.createElement('input'); - rCheck.type = 'checkbox'; - rCheck.setAttribute('data-bind', 'checked: filterTile, enable: hasPickedTile'); - renderTile.appendChild(rCheck); - renderTile.appendChild(document.createTextNode('Show only selected')); - - var wireframe = document.createElement('div'); - terrainSection.appendChild(wireframe); - var wCheckbox = document.createElement('input'); - wCheckbox.type = 'checkbox'; - wCheckbox.setAttribute('data-bind', 'checked: wireframe'); - wireframe.appendChild(wCheckbox); - wireframe.appendChild(document.createTextNode('Wireframe')); - - var suspendUpdates = document.createElement('div'); - terrainSection.appendChild(suspendUpdates); - var upCheckbox = document.createElement('input'); - upCheckbox.type = 'checkbox'; - upCheckbox.setAttribute('data-bind', 'checked: suspendUpdates'); - suspendUpdates.appendChild(upCheckbox); - suspendUpdates.appendChild(document.createTextNode('Suspend LOD update')); - - var tileCoords = document.createElement('div'); - terrainSection.appendChild(tileCoords); - var coordCheck = document.createElement('input'); - coordCheck.type = 'checkbox'; - coordCheck.setAttribute('data-bind', 'checked: tileCoordinates'); - tileCoords.appendChild(coordCheck); - tileCoords.appendChild(document.createTextNode('Show tile coordinates')); + pickTileRequired.appendChild(createCheckBox('checked: tileBoundingSphere, enable: hasPickedTile', 'Show bounding volume')); + pickTileRequired.appendChild(createCheckBox('checked: filterTile, enable: hasPickedTile', 'Show only selected')); + + terrainSection.appendChild(createCheckBox('checked: wireframe', 'Wireframe')); + terrainSection.appendChild(createCheckBox('checked: suspendUpdates', 'Suspend LOD update')); + terrainSection.appendChild(createCheckBox('checked: tileCoordinates', 'Show tile coordinates')); knockout.applyBindings(viewModel, this._element); } diff --git a/Source/Widgets/Geocoder/Geocoder.js b/Source/Widgets/Geocoder/Geocoder.js index 7926cf53b489..09385f39f271 100644 --- a/Source/Widgets/Geocoder/Geocoder.js +++ b/Source/Widgets/Geocoder/Geocoder.js @@ -34,6 +34,7 @@ define([ * @param {GeocoderService[]} [options.geocoderServices] The geocoder services to be used * @param {Boolean} [options.autoComplete = true] True if the geocoder should query as the user types to autocomplete * @param {Number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds. + * @param {Geocoder~DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode. If not supplied, the default behavior is to fly the camera to the result destination. */ function Geocoder(options) { //>>includeStart('debug', pragmas.debug); @@ -210,5 +211,12 @@ css: { active: $data === $parent._selectedSuggestion }'); return destroyObject(this); }; + /** + * A function that handles the result of a successful geocode. + * @callback Geocoder~DestinationFoundFunction + * @param {GeocoderViewModel} viewModel The view model. + * @param {Cartesian3|Rectangle} destination The destination result of the geocode. + */ + return Geocoder; }); diff --git a/Source/Widgets/Geocoder/GeocoderViewModel.js b/Source/Widgets/Geocoder/GeocoderViewModel.js index e65c1ab09370..b1ab192bb84b 100644 --- a/Source/Widgets/Geocoder/GeocoderViewModel.js +++ b/Source/Widgets/Geocoder/GeocoderViewModel.js @@ -7,7 +7,11 @@ define([ '../../Core/DeveloperError', '../../Core/Event', '../../Core/GeocodeType', + '../../Core/Math', '../../Core/Matrix4', + '../../Core/Rectangle', + '../../Core/sampleTerrainMostDetailed', + '../../Scene/computeFlyToLocationForRectangle', '../../ThirdParty/knockout', '../../ThirdParty/when', '../createCommand', @@ -21,13 +25,20 @@ define([ DeveloperError, Event, GeocodeType, + CesiumMath, Matrix4, + Rectangle, + sampleTerrainMostDetailed, + computeFlyToLocationForRectangle, knockout, when, createCommand, getElement) { 'use strict'; + // The height we use if geocoding to a specific point instead of an rectangle. + var DEFAULT_HEIGHT = 1000; + /** * The view model for the {@link Geocoder} widget. * @alias GeocoderViewModel @@ -39,6 +50,7 @@ define([ * If more than one are supplied, suggestions will be gathered for the geocoders that support it, * and if no suggestion is selected the result from the first geocoder service wil be used. * @param {Number} [options.flightDuration] The duration of the camera flight to an entered location, in seconds. + * @param {Geocoder~DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode. If not supplied, the default behavior is to fly the camera to the result destination. */ function GeocoderViewModel(options) { //>>includeStart('debug', pragmas.debug); @@ -66,9 +78,7 @@ define([ this._suggestions = []; this._selectedSuggestion = undefined; this._showSuggestions = true; - this._updateCamera = updateCamera; - this._adjustSuggestionsScroll = adjustSuggestionsScroll; - this._updateSearchSuggestions = updateSearchSuggestions; + this._handleArrowDown = handleArrowDown; this._handleArrowUp = handleArrowUp; @@ -129,7 +139,7 @@ define([ that._searchText = data.displayName; var destination = data.destination; clearSuggestions(that); - updateCamera(that, destination); + that.destinationFound(that, destination); }; this.hideSuggestions = function () { @@ -162,6 +172,12 @@ define([ */ this.autoComplete = defaultValue(options.autocomplete, true); + /** + * Gets and sets the command called when a geocode destination is found + * @type {Geocoder~DestinationFoundFunction} + */ + this.destinationFound = defaultValue(options.destinationFound, GeocoderViewModel.flyToDestination); + this._focusTextbox = false; knockout.track(this, ['_searchText', '_isSearchInProgress', 'keepExpanded', '_suggestions', '_selectedSuggestion', '_showSuggestions', '_focusTextbox']); @@ -169,7 +185,7 @@ define([ var searchTextObservable = knockout.getObservable(this, '_searchText'); searchTextObservable.extend({ rateLimit: { timeout: 500 } }); this._suggestionSubscription = searchTextObservable.subscribe(function() { - updateSearchSuggestions(that); + GeocoderViewModel._updateSearchSuggestions(that); }); /** * Gets a value indicating whether a search is currently in progress. This property is observable. @@ -315,7 +331,7 @@ define([ } next = currentIndex - 1; viewModel._selectedSuggestion = viewModel._suggestions[next]; - adjustSuggestionsScroll(viewModel, next); + GeocoderViewModel._adjustSuggestionsScroll(viewModel, next); } function handleArrowDown(viewModel) { @@ -327,18 +343,67 @@ define([ var next = (currentIndex + 1) % numberOfSuggestions; viewModel._selectedSuggestion = viewModel._suggestions[next]; - adjustSuggestionsScroll(viewModel, next); + GeocoderViewModel._adjustSuggestionsScroll(viewModel, next); } - function updateCamera(viewModel, destination) { - viewModel._scene.camera.flyTo({ - destination : destination, - complete: function() { - viewModel._complete.raiseEvent(); - }, - duration : viewModel._flightDuration, - endTransform : Matrix4.IDENTITY - }); + function computeFlyToLocationForCartographic(cartographic, terrainProvider) { + var availability = defined(terrainProvider) ? terrainProvider.availability : undefined; + + if (!defined(availability)) { + cartographic.height += DEFAULT_HEIGHT; + return when.resolve(cartographic); + } + + return sampleTerrainMostDetailed(terrainProvider, [cartographic]) + .then(function(positionOnTerrain) { + cartographic = positionOnTerrain[0]; + cartographic.height += DEFAULT_HEIGHT; + return cartographic; + }); + } + + function flyToDestination(viewModel, destination) { + var scene = viewModel._scene; + var mapProjection = scene.mapProjection; + var ellipsoid = mapProjection.ellipsoid; + + var camera = scene.camera; + var terrainProvider = scene.terrainProvider; + var finalDestination = destination; + + var promise; + if (destination instanceof Rectangle) { + // Some geocoders return a Rectangle of zero width/height, treat it like a point instead. + if (CesiumMath.equalsEpsilon(destination.south, destination.north, CesiumMath.EPSILON7) && + CesiumMath.equalsEpsilon(destination.east, destination.west, CesiumMath.EPSILON7)) { + // destination is now a Cartographic + destination = Rectangle.center(destination); + } else { + promise = computeFlyToLocationForRectangle(destination, scene); + } + } else { // destination is a Cartesian3 + destination = ellipsoid.cartesianToCartographic(destination); + } + + if (!defined(promise)) { + promise = computeFlyToLocationForCartographic(destination, terrainProvider); + } + + promise + .then(function(result) { + finalDestination = ellipsoid.cartographicToCartesian(result); + }) + .always(function() { + // Whether terrain querying succeeded or not, fly to the destination. + camera.flyTo({ + destination: finalDestination, + complete: function() { + viewModel._complete.raiseEvent(); + }, + duration: viewModel._flightDuration, + endTransform: Matrix4.IDENTITY + }); + }); } function chainPromise(promise, geocoderService, query, geocodeType) { @@ -385,7 +450,7 @@ define([ var geocoderResults = result.value; if (result.state === 'fulfilled' && defined(geocoderResults) && geocoderResults.length > 0) { viewModel._searchText = geocoderResults[0].displayName; - updateCamera(viewModel, geocoderResults[0].destination); + viewModel.destinationFound(viewModel, geocoderResults[0].destination); return; } viewModel._searchText = query + ' (not found)'; @@ -461,5 +526,15 @@ define([ }); } + /** + * A function to fly to the destination found by a successful geocode. + * @type {Geocoder~DestinationFoundFunction} + */ + GeocoderViewModel.flyToDestination = flyToDestination; + + //exposed for testing + GeocoderViewModel._updateSearchSuggestions = updateSearchSuggestions; + GeocoderViewModel._adjustSuggestionsScroll = adjustSuggestionsScroll; + return GeocoderViewModel; }); diff --git a/Source/Widgets/Viewer/Viewer.js b/Source/Widgets/Viewer/Viewer.js index b55c5b124afb..57419cdd78d0 100644 --- a/Source/Widgets/Viewer/Viewer.js +++ b/Source/Widgets/Viewer/Viewer.js @@ -1,6 +1,7 @@ define([ '../../Core/BoundingSphere', '../../Core/Cartesian3', + '../../Core/Cartographic', '../../Core/Clock', '../../Core/defaultValue', '../../Core/defined', @@ -22,6 +23,7 @@ define([ '../../DataSources/EntityView', '../../DataSources/Property', '../../Scene/Cesium3DTileset', + '../../Scene/computeFlyToLocationForRectangle', '../../Scene/ImageryLayer', '../../Scene/SceneMode', '../../Scene/TimeDynamicPointCloud', @@ -49,6 +51,7 @@ define([ ], function( BoundingSphere, Cartesian3, + Cartographic, Clock, defaultValue, defined, @@ -70,6 +73,7 @@ define([ EntityView, Property, Cesium3DTileset, + computeFlyToLocationForRectangle, ImageryLayer, SceneMode, TimeDynamicPointCloud, @@ -1810,9 +1814,11 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to //If the zoom target is a rectangular imagery in an ImageLayer if (zoomTarget instanceof ImageryLayer) { zoomTarget.getViewableRectangle().then(function(rectangle) { + return computeFlyToLocationForRectangle(rectangle, that.scene); + }).then(function(position) { //Only perform the zoom if it wasn't cancelled before the promise was resolved if (that._zoomPromise === zoomPromise) { - that._zoomTarget = rectangle; + that._zoomTarget = position; } }); return; @@ -1976,9 +1982,14 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to } // If zoomTarget was an ImageryLayer - if (target instanceof Rectangle) { + var isCartographic = target instanceof Cartographic; + if (target instanceof Rectangle || isCartographic) { + var destination = target; + if (isCartographic) { + destination = scene.mapProjection.ellipsoid.cartographicToCartesian(destination); + } options = { - destination : target, + destination : destination, duration : zoomOptions.duration, maximumHeight : zoomOptions.maximumHeight, complete : function() { diff --git a/Source/Workers/createGroundPolylineGeometry.js b/Source/Workers/createGroundPolylineGeometry.js index aabe28475686..02f31149fb01 100644 --- a/Source/Workers/createGroundPolylineGeometry.js +++ b/Source/Workers/createGroundPolylineGeometry.js @@ -1,15 +1,15 @@ define([ + '../Core/ApproximateTerrainHeights', '../Core/defined', - '../Core/GroundPolylineGeometry', - '../Scene/GroundPolylinePrimitive' + '../Core/GroundPolylineGeometry' ], function( + ApproximateTerrainHeights, defined, - GroundPolylineGeometry, - GroundPolylinePrimitive) { + GroundPolylineGeometry) { 'use strict'; function createGroundPolylineGeometry(groundPolylineGeometry, offset) { - return GroundPolylinePrimitive.initializeTerrainHeights() + return ApproximateTerrainHeights.initialize() .then(function() { if (defined(offset)) { groundPolylineGeometry = GroundPolylineGeometry.unpack(groundPolylineGeometry, offset); diff --git a/Specs/Cesium3DTilesTester.js b/Specs/Cesium3DTilesTester.js index 7180ee1a0a05..ab7b62618e7c 100644 --- a/Specs/Cesium3DTilesTester.js +++ b/Specs/Cesium3DTilesTester.js @@ -97,6 +97,7 @@ define([ scene.renderForSpecs(); return tileset.tilesLoaded; }).then(function() { + scene.renderForSpecs(); return tileset; }); }; @@ -162,7 +163,7 @@ define([ Cesium3DTilesTester.resolvesReadyPromise = function(scene, url) { return Cesium3DTilesTester.loadTileset(scene, url).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; return content.readyPromise.then(function(content) { expect(content).toBeDefined(); }); @@ -171,7 +172,7 @@ define([ Cesium3DTilesTester.tileDestroys = function(scene, url) { return Cesium3DTilesTester.loadTileset(scene, url).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.isDestroyed()).toEqual(false); scene.primitives.remove(tileset); expect(content.isDestroyed()).toEqual(true); diff --git a/Specs/Core/BoxGeometrySpec.js b/Specs/Core/BoxGeometrySpec.js index 8bf3c8788df1..6f8e4cdd70e8 100644 --- a/Specs/Core/BoxGeometrySpec.js +++ b/Specs/Core/BoxGeometrySpec.js @@ -1,13 +1,17 @@ defineSuite([ 'Core/BoxGeometry', + 'Core/arrayFill', 'Core/AxisAlignedBoundingBox', 'Core/Cartesian3', + 'Core/GeometryOffsetAttribute', 'Core/VertexFormat', 'Specs/createPackableSpecs' ], function( BoxGeometry, + arrayFill, AxisAlignedBoundingBox, Cartesian3, + GeometryOffsetAttribute, VertexFormat, createPackableSpecs) { 'use strict'; @@ -62,6 +66,24 @@ defineSuite([ expect(m.boundingSphere.radius).toEqual(Cartesian3.magnitude(maximumCorner) * 0.5); }); + it('computes offset attribute', function() { + var m = BoxGeometry.createGeometry(new BoxGeometry({ + minimum : new Cartesian3(-1, -2, -3), + maximum : new Cartesian3(1, 2, 3), + vertexFormat : VertexFormat.POSITION_ONLY, + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 8; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('fromDimensions throws without dimensions', function() { expect(function() { return BoxGeometry.fromDimensions(); @@ -116,5 +138,5 @@ defineSuite([ minimum : new Cartesian3(1.0, 2.0, 3.0), maximum : new Cartesian3(4.0, 5.0, 6.0), vertexFormat : VertexFormat.POSITION_AND_NORMAL - }), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0]); + }), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0]); }); diff --git a/Specs/Core/BoxOutlineGeometrySpec.js b/Specs/Core/BoxOutlineGeometrySpec.js index 7c251f5ce34a..d5a8e34d1631 100644 --- a/Specs/Core/BoxOutlineGeometrySpec.js +++ b/Specs/Core/BoxOutlineGeometrySpec.js @@ -1,12 +1,16 @@ defineSuite([ 'Core/BoxOutlineGeometry', + 'Core/arrayFill', 'Core/AxisAlignedBoundingBox', 'Core/Cartesian3', + 'Core/GeometryOffsetAttribute', 'Specs/createPackableSpecs' ], function( BoxOutlineGeometry, + arrayFill, AxisAlignedBoundingBox, Cartesian3, + GeometryOffsetAttribute, createPackableSpecs) { 'use strict'; @@ -36,6 +40,23 @@ defineSuite([ expect(m.indices.length).toEqual(12 * 2); }); + it('computes offset attribute', function() { + var m = BoxOutlineGeometry.createGeometry(new BoxOutlineGeometry({ + minimum : new Cartesian3(-1, -2, -3), + maximum : new Cartesian3(1, 2, 3), + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 8; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('fromDimensions throws without dimensions', function() { expect(function() { return BoxOutlineGeometry.fromDimensions(); @@ -87,5 +108,5 @@ defineSuite([ createPackableSpecs(BoxOutlineGeometry, new BoxOutlineGeometry({ minimum : new Cartesian3(1.0, 2.0, 3.0), maximum : new Cartesian3(4.0, 5.0, 6.0) - }), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); + }), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, -1.0]); }); diff --git a/Specs/Core/CesiumTerrainProviderSpec.js b/Specs/Core/CesiumTerrainProviderSpec.js index 7b44e32baa88..944f5e5fc1b9 100644 --- a/Specs/Core/CesiumTerrainProviderSpec.js +++ b/Specs/Core/CesiumTerrainProviderSpec.js @@ -461,6 +461,20 @@ defineSuite([ }); }); + it('do not add blank attribution if layer.json does not have one', function() { + returnTileJson('Data/CesiumTerrainTileJson/WaterMask.tile.json'); + + var provider = new CesiumTerrainProvider({ + url : 'made/up/url' + }); + + return pollToPromise(function() { + return provider.ready; + }).then(function() { + expect(provider._tileCredit).toBeUndefined(); + }); + }); + describe('requestTileGeometry', function() { it('uses multiple urls specified in layer.json', function() { diff --git a/Specs/Core/CylinderGeometrySpec.js b/Specs/Core/CylinderGeometrySpec.js index 267326b2863f..3db2ed5350ba 100644 --- a/Specs/Core/CylinderGeometrySpec.js +++ b/Specs/Core/CylinderGeometrySpec.js @@ -1,9 +1,13 @@ defineSuite([ 'Core/CylinderGeometry', + 'Core/arrayFill', + 'Core/GeometryOffsetAttribute', 'Core/VertexFormat', 'Specs/createPackableSpecs' ], function( CylinderGeometry, + arrayFill, + GeometryOffsetAttribute, VertexFormat, createPackableSpecs) { 'use strict'; @@ -57,6 +61,26 @@ defineSuite([ expect(m.indices.length).toEqual(numTriangles * 3); }); + it('computes offset attribute', function() { + var m = CylinderGeometry.createGeometry(new CylinderGeometry({ + vertexFormat : VertexFormat.POSITION_ONLY, + length: 1, + topRadius: 1, + bottomRadius: 1, + slices: 3, + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 12; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('compute all vertex attributes', function() { var m = CylinderGeometry.createGeometry(new CylinderGeometry({ vertexFormat : VertexFormat.ALL, @@ -154,6 +178,6 @@ defineSuite([ bottomRadius: 0, slices: 3 }); - var packedInstance = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 3.0]; + var packedInstance = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 3.0, -1.0]; createPackableSpecs(CylinderGeometry, cylinder, packedInstance); }); diff --git a/Specs/Core/CylinderOutlineGeometrySpec.js b/Specs/Core/CylinderOutlineGeometrySpec.js index 0aefe556725d..36d9803593aa 100644 --- a/Specs/Core/CylinderOutlineGeometrySpec.js +++ b/Specs/Core/CylinderOutlineGeometrySpec.js @@ -1,8 +1,12 @@ defineSuite([ 'Core/CylinderOutlineGeometry', + 'Core/arrayFill', + 'Core/GeometryOffsetAttribute', 'Specs/createPackableSpecs' ], function( CylinderOutlineGeometry, + arrayFill, + GeometryOffsetAttribute, createPackableSpecs) { 'use strict'; @@ -52,6 +56,25 @@ defineSuite([ expect(m.indices.length).toEqual(9 * 2); // 3 top + 3 bottom + 3 sides }); + it('computes offset attribute', function() { + var m = CylinderOutlineGeometry.createGeometry(new CylinderOutlineGeometry({ + length: 1, + topRadius: 1, + bottomRadius: 1, + slices: 3, + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 6; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('computes positions with no lines along the length', function() { var m = CylinderOutlineGeometry.createGeometry(new CylinderOutlineGeometry({ length: 1, @@ -115,6 +138,6 @@ defineSuite([ slices: 3, numberOfVerticalLines: 0 }); - var packedInstance = [1.0, 1.0, 0.0, 3.0, 0.0]; + var packedInstance = [1.0, 1.0, 0.0, 3.0, 0.0, -1.0]; createPackableSpecs(CylinderOutlineGeometry, cylinder, packedInstance); }); diff --git a/Specs/Core/EllipsoidGeometrySpec.js b/Specs/Core/EllipsoidGeometrySpec.js index 0bbc97a8d55f..0fcbdb8cf3dd 100644 --- a/Specs/Core/EllipsoidGeometrySpec.js +++ b/Specs/Core/EllipsoidGeometrySpec.js @@ -1,12 +1,16 @@ defineSuite([ 'Core/EllipsoidGeometry', + 'Core/arrayFill', 'Core/Cartesian3', + 'Core/GeometryOffsetAttribute', 'Core/Math', 'Core/VertexFormat', 'Specs/createPackableSpecs' ], function( EllipsoidGeometry, + arrayFill, Cartesian3, + GeometryOffsetAttribute, CesiumMath, VertexFormat, createPackableSpecs) { @@ -58,6 +62,24 @@ defineSuite([ expect(m.boundingSphere.radius).toEqual(1); }); + it('computes offset attribute', function() { + var m = EllipsoidGeometry.createGeometry(new EllipsoidGeometry({ + vertexFormat : VertexFormat.POSITION_ONLY, + slicePartitions: 3, + stackPartitions: 3, + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 16; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('compute all vertex attributes', function() { var m = EllipsoidGeometry.createGeometry(new EllipsoidGeometry({ vertexFormat : VertexFormat.ALL, @@ -147,6 +169,6 @@ defineSuite([ slicePartitions: 3, stackPartitions: 3 }); - var packedInstance = [1.0, 2.0, 3.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0]; + var packedInstance = [1.0, 2.0, 3.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0, -1.0]; createPackableSpecs(EllipsoidGeometry, ellipsoidgeometry, packedInstance); }); diff --git a/Specs/Core/EllipsoidOutlineGeometrySpec.js b/Specs/Core/EllipsoidOutlineGeometrySpec.js index d3d64b571173..b1954b656966 100644 --- a/Specs/Core/EllipsoidOutlineGeometrySpec.js +++ b/Specs/Core/EllipsoidOutlineGeometrySpec.js @@ -1,10 +1,14 @@ defineSuite([ 'Core/EllipsoidOutlineGeometry', + 'Core/arrayFill', 'Core/Cartesian3', + 'Core/GeometryOffsetAttribute', 'Specs/createPackableSpecs' ], function( EllipsoidOutlineGeometry, + arrayFill, Cartesian3, + GeometryOffsetAttribute, createPackableSpecs) { 'use strict'; @@ -71,6 +75,24 @@ defineSuite([ expect(m.boundingSphere.radius).toEqual(1); }); + it('computes offset attribute', function() { + var m = EllipsoidOutlineGeometry.createGeometry(new EllipsoidOutlineGeometry({ + stackPartitions : 3, + slicePartitions: 3, + subdivisions: 3, + offsetAttribute: GeometryOffsetAttribute.ALL + })); + + var numVertices = 14; + expect(m.attributes.position.values.length).toEqual(numVertices * 3); + + var offset = m.attributes.applyOffset.values; + expect(offset.length).toEqual(numVertices); + var expected = new Array(offset.length); + expected = arrayFill(expected, 1); + expect(offset).toEqual(expected); + }); + it('undefined is returned if the x, y, or z radii are equal or less than zero', function() { var ellipsoidOutline0 = new EllipsoidOutlineGeometry({ radii : new Cartesian3(0.0, 500000.0, 500000.0) @@ -112,6 +134,6 @@ defineSuite([ stackPartitions: 3, subdivisions: 3 }); - var packedInstance = [1.0, 2.0, 3.0, 3.0, 3.0, 3.0]; + var packedInstance = [1.0, 2.0, 3.0, 3.0, 3.0, 3.0, -1.0]; createPackableSpecs(EllipsoidOutlineGeometry, ellipsoidgeometry, packedInstance); }); diff --git a/Specs/Core/ManagedArraySpec.js b/Specs/Core/ManagedArraySpec.js index 94c1c5b32a38..c050bb8f6013 100644 --- a/Specs/Core/ManagedArraySpec.js +++ b/Specs/Core/ManagedArraySpec.js @@ -55,6 +55,16 @@ defineSuite([ expect(array.length).toEqual(6); }); + it('peeks at the last element of the array', function() { + var array = new ManagedArray(); + expect(array.peek()).toBeUndefined(); + array.push(0); + expect(array.peek()).toBe(0); + array.push(1); + array.push(2); + expect(array.peek()).toBe(2); + }); + it('can push values', function() { var array = new ManagedArray(); var length = 10; diff --git a/Specs/Core/Matrix4Spec.js b/Specs/Core/Matrix4Spec.js index 450ae97a54ea..2086c403e390 100644 --- a/Specs/Core/Matrix4Spec.js +++ b/Specs/Core/Matrix4Spec.js @@ -476,6 +476,19 @@ defineSuite([ expect(result).toEqual(expected); }); + it('setScale works', function() { + var matrix = Matrix4.clone(Matrix4.IDENTITY); + var result = new Matrix4(); + var newScale = new Cartesian3(1.0, 2.0, 3.0); + + expect(Matrix4.getScale(matrix, new Cartesian3())).toEqual(new Cartesian3(1.0, 1.0, 1.0)); + + var returnedResult = Matrix4.setScale(matrix, newScale, result); + + expect(Matrix4.getScale(returnedResult, new Cartesian3())).toEqual(newScale); + expect(result).toBe(returnedResult); + }); + it('getRow works for each row', function() { var matrix = new Matrix4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0); var expectedRow0 = new Cartesian4(1.0, 2.0, 3.0, 4.0); diff --git a/Specs/Core/PeliasGeocoderServiceSpec.js b/Specs/Core/PeliasGeocoderServiceSpec.js index e3b8117e8e70..67b7594f7156 100644 --- a/Specs/Core/PeliasGeocoderServiceSpec.js +++ b/Specs/Core/PeliasGeocoderServiceSpec.js @@ -1,13 +1,13 @@ defineSuite([ 'Core/PeliasGeocoderService', 'Core/GeocodeType', - 'Core/Rectangle', + 'Core/Cartesian3', 'Core/Resource', 'ThirdParty/when' ], function( PeliasGeocoderService, GeocodeType, - Rectangle, + Cartesian3, Resource, when) { 'use strict'; @@ -40,7 +40,7 @@ defineSuite([ .then(function(results) { expect(results.length).toEqual(1); expect(results[0].displayName).toEqual(data.features[0].properties.label); - expect(results[0].destination).toBeInstanceOf(Rectangle); + expect(results[0].destination).toBeInstanceOf(Cartesian3); }); }); diff --git a/Specs/Core/ScreenSpaceEventHandlerSpec.js b/Specs/Core/ScreenSpaceEventHandlerSpec.js index 8566563bce92..3b5766bf58c9 100644 --- a/Specs/Core/ScreenSpaceEventHandlerSpec.js +++ b/Specs/Core/ScreenSpaceEventHandlerSpec.js @@ -20,7 +20,7 @@ defineSuite([ DomEventSimulator) { 'use strict'; - var usePointerEvents = FeatureDetection.supportsPointerEvents(); + var usePointerEvents; var element; var handler; @@ -63,6 +63,10 @@ defineSuite([ event.preventDefault(); } + beforeAll(function(){ + usePointerEvents = FeatureDetection.supportsPointerEvents(); + }); + beforeEach(function() { // ignore events that bubble up to the document. // this prevents triggering the browser's "middle click to scroll" behavior diff --git a/Specs/Core/SphereGeometrySpec.js b/Specs/Core/SphereGeometrySpec.js index 57815a50a14e..4c8590922a4d 100644 --- a/Specs/Core/SphereGeometrySpec.js +++ b/Specs/Core/SphereGeometrySpec.js @@ -102,6 +102,6 @@ defineSuite([ stackPartitions : 3, slicePartitions: 3 }); - var packedInstance = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0]; + var packedInstance = [1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 3.0, -1.0]; createPackableSpecs(SphereGeometry, sphere, packedInstance); }); diff --git a/Specs/Core/SphereOutlineGeometrySpec.js b/Specs/Core/SphereOutlineGeometrySpec.js index b857e93dfc2a..43d5f7851d84 100644 --- a/Specs/Core/SphereOutlineGeometrySpec.js +++ b/Specs/Core/SphereOutlineGeometrySpec.js @@ -58,6 +58,6 @@ defineSuite([ slicePartitions: 3, subdivisions: 2 }); - var packedInstance = [1.0, 1.0, 1.0, 3.0, 3.0, 2.0]; + var packedInstance = [1.0, 1.0, 1.0, 3.0, 3.0, 2.0, -1.0]; createPackableSpecs(SphereOutlineGeometry, sphere, packedInstance); }); diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm index 98b2b469bda1..df79fe32f39e 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ll.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm index ebb24758d31f..e273cb03a764 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/lr.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm index 8f6c2012861e..8cb958955234 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/parent.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json index d7baf1670f0e..2874634d6112 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/tileset.json @@ -3,6 +3,9 @@ "version": "1.0", "tilesetVersion": "1.2.3" }, + "extras": { + "name": "Sample Tileset" + }, "properties": { "id": { "minimum": 0, @@ -79,6 +82,9 @@ "geometricError": 0, "content": { "uri": "lr.b3dm" + }, + "extras": { + "id": "Special Tile" } }, { diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm index ecd600aba825..b7a4c162220c 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ul.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm index 7dd42a0fdf4b..9ae74c7b0534 100644 Binary files a/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm and b/Specs/Data/Cesium3DTiles/Tilesets/Tileset/ur.b3dm differ diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json index 1bd6cad42407..ec20e19e4225 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset.json @@ -1,6 +1,7 @@ { "asset": { - "version": "1.0" + "version": "1.0", + "tilesetVersion": "1.2.3" }, "properties": { "id": { diff --git a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithExternalResources/tileset2/tileset2.json b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithExternalResources/tileset2/tileset2.json index 9fe64e6eee72..eab61b02cfb5 100644 --- a/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithExternalResources/tileset2/tileset2.json +++ b/Specs/Data/Cesium3DTiles/Tilesets/TilesetWithExternalResources/tileset2/tileset2.json @@ -1,6 +1,7 @@ { "asset": { - "version": "1.0" + "version": "1.0", + "tilesetVersion": "1.2.3" }, "geometricError": 70, "root": { diff --git a/Specs/DataSources/BoxGeometryUpdaterSpec.js b/Specs/DataSources/BoxGeometryUpdaterSpec.js index 1a59fa76d025..c7e5dc8d09c3 100644 --- a/Specs/DataSources/BoxGeometryUpdaterSpec.js +++ b/Specs/DataSources/BoxGeometryUpdaterSpec.js @@ -1,12 +1,15 @@ defineSuite([ 'DataSources/BoxGeometryUpdater', 'Core/Cartesian3', + 'Core/Color', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/TimeIntervalCollection', 'DataSources/BoxGraphics', 'DataSources/ConstantPositionProperty', 'DataSources/ConstantProperty', 'DataSources/Entity', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -15,12 +18,15 @@ defineSuite([ ], function( BoxGeometryUpdater, Cartesian3, + Color, + GeometryOffsetAttribute, JulianDate, TimeIntervalCollection, BoxGraphics, ConstantPositionProperty, ConstantProperty, Entity, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -79,10 +85,51 @@ defineSuite([ instance = updater.createFillGeometryInstance(time); geometry = instance.geometry; expect(geometry._maximum).toEqual(Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3())); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; expect(geometry._max).toEqual(Cartesian3.multiplyByScalar(dimensions, 0.5, new Cartesian3())); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicBox(); + var graphics = entity.box; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new BoxGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + + graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'box'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); }); it('dynamic updater sets properties', function() { @@ -93,6 +140,7 @@ defineSuite([ dynamicUpdater.update(JulianDate.now()); expect(dynamicUpdater._options.dimensions).toEqual(entity.box.dimensions.getValue()); + expect(dynamicUpdater._options.offsetAttribute).toBeUndefined(); }); it('geometryChanged event is raised when expected', function() { @@ -123,6 +171,13 @@ defineSuite([ expect(listener.calls.count()).toEqual(3); }); + it('computes center', function() { + var entity = createBasicBox(); + var updater = new BoxGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); + }); + function getScene() { return scene; } diff --git a/Specs/DataSources/CylinderGeometryUpdaterSpec.js b/Specs/DataSources/CylinderGeometryUpdaterSpec.js index df9e36764088..07dcd008431e 100644 --- a/Specs/DataSources/CylinderGeometryUpdaterSpec.js +++ b/Specs/DataSources/CylinderGeometryUpdaterSpec.js @@ -1,6 +1,8 @@ defineSuite([ 'DataSources/CylinderGeometryUpdater', 'Core/Cartesian3', + 'Core/Color', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/Quaternion', 'Core/TimeIntervalCollection', @@ -10,6 +12,7 @@ defineSuite([ 'DataSources/Entity', 'DataSources/SampledPositionProperty', 'DataSources/SampledProperty', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -18,6 +21,8 @@ defineSuite([ ], function( CylinderGeometryUpdater, Cartesian3, + Color, + GeometryOffsetAttribute, JulianDate, Quaternion, TimeIntervalCollection, @@ -27,6 +32,7 @@ defineSuite([ Entity, SampledPositionProperty, SampledProperty, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -164,6 +170,7 @@ defineSuite([ expect(geometry._topRadius).toEqual(options.topRadius); expect(geometry._bottomRadius).toEqual(options.bottomRadius); expect(geometry._length).toEqual(options.length); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; @@ -171,6 +178,46 @@ defineSuite([ expect(geometry._bottomRadius).toEqual(options.bottomRadius); expect(geometry._length).toEqual(options.length); expect(geometry._numberOfVerticalLines).toEqual(options.numberOfVerticalLines); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicCylinder(); + var graphics = entity.cylinder; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new CylinderGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + + graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'cylinder'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); }); it('dynamic updater sets properties', function() { @@ -191,6 +238,7 @@ defineSuite([ expect(options.topRadius).toEqual(cylinder.topRadius.getValue()); expect(options.bottomRadius).toEqual(cylinder.bottomRadius.getValue()); expect(options.length).toEqual(cylinder.length.getValue()); + expect(options.offsetAttribute).toBeUndefined(); }); it('geometryChanged event is raised when expected', function() { @@ -230,6 +278,13 @@ defineSuite([ expect(listener.calls.count()).toEqual(5); }); + it('computes center', function() { + var entity = createBasicCylinder(); + var updater = new CylinderGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); + }); + function getScene() { return scene; } diff --git a/Specs/DataSources/DataSourceDisplaySpec.js b/Specs/DataSources/DataSourceDisplaySpec.js index 47c06fd08c93..a628b49e8886 100644 --- a/Specs/DataSources/DataSourceDisplaySpec.js +++ b/Specs/DataSources/DataSourceDisplaySpec.js @@ -42,10 +42,6 @@ defineSuite([ scene.destroyForSpecs(); // Leave ground primitive uninitialized - GroundPrimitive._initialized = false; - GroundPrimitive._initPromise = undefined; - GroundPolylinePrimitive._initialized = false; - GroundPolylinePrimitive._initPromise = undefined; ApproximateTerrainHeights._initPromise = undefined; ApproximateTerrainHeights._terrainHeights = undefined; }); @@ -365,8 +361,6 @@ defineSuite([ }); it('verify update returns false till terrain heights are initialized', function() { - GroundPrimitive._initialized = false; - GroundPrimitive._initPromise = undefined; ApproximateTerrainHeights._initPromise = undefined; ApproximateTerrainHeights._terrainHeights = undefined; diff --git a/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js b/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js index e149aeadb9eb..828536582552 100644 --- a/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js +++ b/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js @@ -3,6 +3,7 @@ defineSuite([ 'Core/Cartesian3', 'Core/Color', 'Core/ColorGeometryInstanceAttribute', + 'Core/GeometryOffsetAttribute', 'Core/JulianDate', 'Core/Math', 'Core/Quaternion', @@ -14,6 +15,7 @@ defineSuite([ 'DataSources/Entity', 'DataSources/SampledPositionProperty', 'DataSources/SampledProperty', + 'Scene/HeightReference', 'Scene/PrimitiveCollection', 'Specs/createDynamicGeometryUpdaterSpecs', 'Specs/createDynamicProperty', @@ -24,6 +26,7 @@ defineSuite([ Cartesian3, Color, ColorGeometryInstanceAttribute, + GeometryOffsetAttribute, JulianDate, CesiumMath, Quaternion, @@ -35,6 +38,7 @@ defineSuite([ Entity, SampledPositionProperty, SampledProperty, + HeightReference, PrimitiveCollection, createDynamicGeometryUpdaterSpecs, createDynamicProperty, @@ -160,6 +164,7 @@ defineSuite([ expect(geometry._radii).toEqual(options.radii); expect(geometry._stackPartitions).toEqual(options.stackPartitions); expect(geometry._slicePartitions).toEqual(options.slicePartitions); + expect(geometry._offsetAttribute).toBeUndefined(); instance = updater.createOutlineGeometryInstance(time); geometry = instance.geometry; @@ -168,6 +173,53 @@ defineSuite([ expect(geometry._stackPartitions).toEqual(options.stackPartitions); expect(geometry._slicePartitions).toEqual(options.slicePartitions); expect(geometry._subdivisions).toEqual(options.subdivisions); + expect(geometry._offsetAttribute).toBeUndefined(); + }); + + it('Creates geometry with expected offsetAttribute', function() { + var entity = createBasicEllipsoid(); + var graphics = entity.ellipsoid; + graphics.outline = true; + graphics.outlineColor = Color.BLACK; + graphics.height = new ConstantProperty(20.0); + graphics.extrudedHeight = new ConstantProperty(0.0); + var updater = new EllipsoidGeometryUpdater(entity, getScene()); + + var instance; + + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.NONE); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toBeUndefined(); + + graphics.heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + + graphics.heightReference = new ConstantProperty(HeightReference.RELATIVE_TO_GROUND); + updater._onEntityPropertyChanged(entity, 'ellipsoid'); + instance = updater.createFillGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + instance = updater.createOutlineGeometryInstance(time); + expect(instance.geometry._offsetAttribute).toEqual(GeometryOffsetAttribute.ALL); + }); + + it('computes center', function() { + var entity = createBasicEllipsoid(); + var updater = new EllipsoidGeometryUpdater(entity, scene); + + expect(updater._computeCenter(time)).toEqual(entity.position.getValue(time)); }); it('dynamic ellipsoid creates and updates', function() { diff --git a/Specs/DataSources/PolylineVisualizerSpec.js b/Specs/DataSources/PolylineVisualizerSpec.js index 78ac465f8c74..34722cf0a608 100644 --- a/Specs/DataSources/PolylineVisualizerSpec.js +++ b/Specs/DataSources/PolylineVisualizerSpec.js @@ -712,4 +712,51 @@ defineSuite([ visualizer.destroy(); }); }); + + it('Sets static geometry primitive show attribute when clamped to ground', function() { + if (!Entity.supportsPolylinesOnTerrain(scene)) { + return; + } + + var objects = new EntityCollection(); + var visualizer = new PolylineVisualizer(scene, objects, scene.groundPrimitives); + + var polyline = new PolylineGraphics(); + polyline.positions = new ConstantProperty([Cartesian3.fromDegrees(0.0, 0.0), Cartesian3.fromDegrees(0.0, 1.0)]); + polyline.material = new ColorMaterialProperty(); + polyline.clampToGround = new ConstantProperty(true); + + var entity = new Entity(); + entity.polyline = polyline; + objects.add(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }).then(function() { + var primitive = scene.groundPrimitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes).toBeDefined(); + expect(attributes.show).toEqual(ShowGeometryInstanceAttribute.toValue(true)); + expect(attributes.color).toEqual(ColorGeometryInstanceAttribute.toValue(Color.WHITE)); + expect(primitive.appearance).toBeInstanceOf(PolylineColorAppearance); + expect(primitive.appearance.closed).toBe(false); + + entity.polyline.show = false; + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }); + }).then(function() { + expect(scene.primitives.length).toEqual(0); + + objects.remove(entity); + visualizer.destroy(); + }); + }); }, 'WebGL'); diff --git a/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js b/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js index 8dfed1d1f9b8..a8270facff08 100644 --- a/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js +++ b/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js @@ -10,6 +10,7 @@ defineSuite([ 'Core/TimeInterval', 'Core/TimeIntervalCollection', 'DataSources/BoundingSphereState', + 'DataSources/ColorMaterialProperty', 'DataSources/ConstantProperty', 'DataSources/Entity', 'DataSources/PolylineOutlineMaterialProperty', @@ -32,6 +33,7 @@ defineSuite([ TimeInterval, TimeIntervalCollection, BoundingSphereState, + ColorMaterialProperty, ConstantProperty, Entity, PolylineOutlineMaterialProperty, @@ -122,6 +124,52 @@ defineSuite([ }); }); + it('updates with sampled color out of range', function() { + if (!GroundPolylinePrimitive.isSupported(scene)) { + // Don't fail if GroundPolylinePrimitive is not supported + return; + } + + var validTime = JulianDate.fromIso8601('2018-02-14T04:10:00+1100'); + var color = new TimeIntervalCollectionProperty(); + color.intervals.addInterval(TimeInterval.fromIso8601({ + iso8601: '2018-02-14T04:00:00+1100/2018-02-14T04:15:00+1100', + data: Color.RED + })); + var polyline = createGroundPolyline(); + polyline.material = new ColorMaterialProperty(color); + var entity = new Entity({ + availability: new TimeIntervalCollection([TimeInterval.fromIso8601({iso8601: '2018-02-14T04:00:00+1100/2018-02-14T04:30:00+1100'})]), + polyline: polyline + }); + + var batch = new StaticGroundPolylinePerMaterialBatch(scene.groundPrimitives); + + var updater = new PolylineGeometryUpdater(entity, scene); + batch.add(validTime, updater); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = batch.update(validTime); + scene.render(validTime); + return isUpdated; + }).then(function() { + expect(scene.groundPrimitives.length).toEqual(1); + var primitive = scene.groundPrimitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes.color).toEqual([255, 0, 0, 255]); + + batch.update(time); + scene.render(time); + + primitive = scene.groundPrimitives.get(0); + attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes.color).toEqual([255, 255, 255, 255]); + + batch.removeAllPrimitives(); + }); + }); + it('updates with sampled distance display condition out of range', function() { if (!GroundPolylinePrimitive.isSupported(scene)) { // Don't fail if GroundPolylinePrimitive is not supported diff --git a/Specs/DataSources/TerrainOffsetPropertySpec.js b/Specs/DataSources/TerrainOffsetPropertySpec.js index 9a0b060c5e4f..671434a11126 100644 --- a/Specs/DataSources/TerrainOffsetPropertySpec.js +++ b/Specs/DataSources/TerrainOffsetPropertySpec.js @@ -37,7 +37,7 @@ defineSuite([ var position = new CallbackProperty(jasmine.createSpy(), false); var height = new ConstantProperty(30); var extrudedHeight = new ConstantProperty(0); - var property = new TerrainOffsetProperty(scene, height, extrudedHeight, position); + var property = new TerrainOffsetProperty(scene, position, height, extrudedHeight); expect(property.isConstant).toBe(false); expect(property.getValue(time)).toEqual(Cartesian3.ZERO); property.destroy(); @@ -49,7 +49,7 @@ defineSuite([ var height = new ConstantProperty(30); var extrudedHeight = new ConstantProperty(0); expect(function() { - return new TerrainOffsetProperty(undefined, height, extrudedHeight, position); + return new TerrainOffsetProperty(undefined, position, height, extrudedHeight); }).toThrowDeveloperError(); }); @@ -57,7 +57,7 @@ defineSuite([ var height = new ConstantProperty(30); var extrudedHeight = new ConstantProperty(0); expect(function() { - return new TerrainOffsetProperty(scene, height, extrudedHeight, undefined); + return new TerrainOffsetProperty(scene, undefined, height, extrudedHeight); }).toThrowDeveloperError(); }); }); diff --git a/Specs/Scene/Batched3DModel3DTileContentSpec.js b/Specs/Scene/Batched3DModel3DTileContentSpec.js index 272a81666bfb..73c1647a69a7 100644 --- a/Specs/Scene/Batched3DModel3DTileContentSpec.js +++ b/Specs/Scene/Batched3DModel3DTileContentSpec.js @@ -80,7 +80,7 @@ defineSuite([ .then(function(tileset) { expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled(); Cesium3DTilesTester.expectRenderTileset(scene, tileset); - var batchTable = tileset._root._content.batchTable; + var batchTable = tileset.root.content.batchTable; expect(batchTable._properties).toBeDefined(); }); }); @@ -90,7 +90,7 @@ defineSuite([ .then(function(tileset) { expect(Batched3DModel3DTileContent._deprecationWarning).toHaveBeenCalled(); Cesium3DTilesTester.expectRenderTileset(scene, tileset); - var batchTable = tileset._root._content.batchTable; + var batchTable = tileset.root.content.batchTable; expect(batchTable._properties).toBeDefined(); }); }); @@ -160,7 +160,7 @@ defineSuite([ var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, newHPR); // Update tile transform - tileset._root.transform = newTransform; + tileset.root.transform = newTransform; scene.renderForSpecs(); // Move the camera to the new location @@ -183,7 +183,7 @@ defineSuite([ it('picks with batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; tileset.show = false; expect(scene).toPickPrimitive(undefined); tileset.show = true; @@ -197,7 +197,7 @@ defineSuite([ it('picks without batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; tileset.show = false; expect(scene).toPickPrimitive(undefined); tileset.show = true; @@ -211,7 +211,7 @@ defineSuite([ it('can get features and properties', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(10); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'id')).toBe(true); @@ -221,7 +221,7 @@ defineSuite([ it('throws when calling getFeature with invalid index', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(function(){ content.getFeature(-1); }).toThrowDeveloperError(); @@ -236,7 +236,7 @@ defineSuite([ it('gets memory usage', function() { return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // 10 buildings, 36 ushort indices and 24 vertices per building, 8 float components (position, normal, uv) and 1 uint component (batchId) per vertex. // 10 * ((24 * (8 * 4 + 1 * 4)) + (36 * 2)) = 9360 @@ -271,7 +271,7 @@ defineSuite([ it('Links model to tileset clipping planes based on bounding volume clipping', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var content = tile.content; var model = content._model; @@ -298,7 +298,7 @@ defineSuite([ it('Links model to tileset clipping planes if tileset clipping planes are reassigned', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var model = tile.content._model; expect(model.clippingPlanes).toBeUndefined(); @@ -333,7 +333,7 @@ defineSuite([ spyOn(Model, '_getClippingFunction').and.callThrough(); return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var clippingPlaneCollection = new ClippingPlaneCollection({ planes : [ @@ -352,12 +352,12 @@ defineSuite([ return Cesium3DTilesTester.loadTileset(scene, withRtcCenterUrl).then(function(tileset) { Cesium3DTilesTester.expectRenderTileset(scene, tileset); - var rtcTransform = tileset._root._content._rtcCenterTransform; + var rtcTransform = tileset.root.content._rtcCenterTransform; expect(rtcTransform).toEqual(Matrix4.fromTranslation(new Cartesian3(0.1, 0.2, 0.3))); - var expectedModelTransform = Matrix4.multiply(tileset._root.transform, rtcTransform, new Matrix4()); - expect(tileset._root._content._contentModelMatrix).toEqual(expectedModelTransform); - expect(tileset._root._content._model._modelMatrix).toEqual(expectedModelTransform); + var expectedModelTransform = Matrix4.multiply(tileset.root.transform, rtcTransform, new Matrix4()); + expect(tileset.root.content._contentModelMatrix).toEqual(expectedModelTransform); + expect(tileset.root.content._model._modelMatrix).toEqual(expectedModelTransform); // Update tile transform var newLongitude = -1.31962; @@ -365,12 +365,12 @@ defineSuite([ var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude, 0.0); var newHPR = new HeadingPitchRoll(); var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, newHPR); - tileset._root.transform = newTransform; + tileset.root.transform = newTransform; scene.camera.lookAt(newCenter, new HeadingPitchRange(0.0, 0.0, 15.0)); scene.renderForSpecs(); - expectedModelTransform = Matrix4.multiply(tileset._root.computedTransform, rtcTransform, expectedModelTransform); - expect(tileset._root._content._model._modelMatrix).toEqual(expectedModelTransform); + expectedModelTransform = Matrix4.multiply(tileset.root.computedTransform, rtcTransform, expectedModelTransform); + expect(tileset.root.content._model._modelMatrix).toEqual(expectedModelTransform); }); }); diff --git a/Specs/Scene/CameraEventAggregatorSpec.js b/Specs/Scene/CameraEventAggregatorSpec.js index 9654527c7187..0b05de3ed19b 100644 --- a/Specs/Scene/CameraEventAggregatorSpec.js +++ b/Specs/Scene/CameraEventAggregatorSpec.js @@ -18,12 +18,13 @@ defineSuite([ DomEventSimulator) { 'use strict'; - var usePointerEvents = FeatureDetection.supportsPointerEvents(); + var usePointerEvents; var canvas; var handler; var handler2; beforeAll(function() { + usePointerEvents = FeatureDetection.supportsPointerEvents(); canvas = createCanvas(1024, 768); }); diff --git a/Specs/Scene/CameraSpec.js b/Specs/Scene/CameraSpec.js index 535eb9188f4a..819ba609bf02 100644 --- a/Specs/Scene/CameraSpec.js +++ b/Specs/Scene/CameraSpec.js @@ -2261,7 +2261,7 @@ defineSuite([ var ray = camera.getPickRay(windowCoord); var cameraPosition = camera.position; - var expectedPosition = new Cartesian3(cameraPosition.x + 2.0, cameraPosition.y + 2, cameraPosition.z); + var expectedPosition = new Cartesian3(cameraPosition.z, cameraPosition.x + 2.0, cameraPosition.y + 2.0); expect(ray.origin).toEqualEpsilon(expectedPosition, CesiumMath.EPSILON14); expect(ray.direction).toEqual(camera.directionWC); }); diff --git a/Specs/Scene/Cesium3DTileBatchTableSpec.js b/Specs/Scene/Cesium3DTileBatchTableSpec.js index 65028807093b..43b9dd330d93 100644 --- a/Specs/Scene/Cesium3DTileBatchTableSpec.js +++ b/Specs/Scene/Cesium3DTileBatchTableSpec.js @@ -550,7 +550,7 @@ defineSuite([ it('renders tileset with batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // Each feature in the b3dm file has an id property from 0 to 9, // check that the 2nd resource has an id of 2 @@ -568,7 +568,7 @@ defineSuite([ it('renders tileset without batch table', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.getFeature(2).getProperty('id')).toBeUndefined(); @@ -595,7 +595,7 @@ defineSuite([ ContextLimits._maximumTextureSize = 4; return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBeGreaterThan(ContextLimits._maximumTextureSize); Cesium3DTilesTester.expectRenderTileset(scene, tileset); @@ -616,7 +616,7 @@ defineSuite([ }); function expectRenderTranslucent(tileset) { - var batchTable = tileset._root.content.batchTable; + var batchTable = tileset.root.content.batchTable; // Get initial color var opaqueColor; @@ -799,7 +799,7 @@ defineSuite([ function checkHierarchyProperties(tileset, multipleParents) { // Check isExactClass, isClass, and getExactClassName in Cesium3DTileFeature - var content = tileset._root.content; + var content = tileset.root.content; var batchTable = content.batchTable; var hierarchy = batchTable._batchTableHierarchy; @@ -861,7 +861,7 @@ defineSuite([ function checkHierarchyPropertiesNoParents(tileset) { // Check isExactClass, isClass, and getExactClassName in Cesium3DTileFeature - var content = tileset._root.content; + var content = tileset.root.content; var doorFeature = content.getFeature(4); expect(doorFeature.isExactClass('door')).toBe(true); expect(doorFeature.isExactClass('doorknob')).toBe(false); @@ -1111,7 +1111,7 @@ defineSuite([ it('destroys', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; var batchTable = content.batchTable; expect(batchTable.isDestroyed()).toEqual(false); scene.primitives.remove(tileset); diff --git a/Specs/Scene/Cesium3DTileSpec.js b/Specs/Scene/Cesium3DTileSpec.js index a0699cedf8fd..cd5661d1fd2d 100644 --- a/Specs/Scene/Cesium3DTileSpec.js +++ b/Specs/Scene/Cesium3DTileSpec.js @@ -180,12 +180,18 @@ defineSuite([ }); describe('bounding volumes', function() { + it('returns the tile bounding volume if the content bounding volume is undefined', function() { + var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined); + expect(tile.boundingVolume).toBeDefined(); + expect(tile.contentBoundingVolume).toBe(tile.boundingVolume); + }); + it('can have a bounding sphere', function() { var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined); var radius = tileWithBoundingSphere.boundingVolume.sphere[3]; - expect(tile.contentBoundingVolume).toBeDefined(); - expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(radius); - expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(Cartesian3.ZERO); + expect(tile.boundingVolume).toBeDefined(); + expect(tile.boundingVolume.boundingVolume.radius).toEqual(radius); + expect(tile.boundingVolume.boundingVolume.center).toEqual(Cartesian3.ZERO); }); it('can have a content bounding sphere', function() { @@ -203,30 +209,30 @@ defineSuite([ var maximumHeight = tileWithBoundingRegion.boundingVolume.region[5]; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined); var tbr = new TileBoundingRegion({rectangle: rectangle, minimumHeight: minimumHeight, maximumHeight: maximumHeight}); - expect(tile.contentBoundingVolume).toBeDefined(); - expect(tile.contentBoundingVolume).toEqual(tbr); + expect(tile.boundingVolume).toBeDefined(); + expect(tile.boundingVolume).toEqual(tbr); }); it('can have a content bounding region', function() { var region = tileWithContentBoundingRegion.content.boundingVolume.region; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingRegion, undefined); - expect(tile._contentBoundingVolume).toBeDefined(); + expect(tile.contentBoundingVolume).toBeDefined(); var tbb = new TileBoundingRegion({ rectangle: new Rectangle(region[0], region[1], region[2], region[3]), minimumHeight: region[4], maximumHeight: region[5] }); - expect(tile._contentBoundingVolume).toEqual(tbb); + expect(tile.contentBoundingVolume).toEqual(tbb); }); it('can have an oriented bounding box', function() { var box = tileWithBoundingBox.boundingVolume.box; var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined); - expect(tile.contentBoundingVolume).toBeDefined(); + expect(tile.boundingVolume).toBeDefined(); var center = new Cartesian3(box[0], box[1], box[2]); var halfAxes = Matrix3.fromArray(box, 3); var obb = new TileOrientedBoundingBox(center, halfAxes); - expect(tile.contentBoundingVolume).toEqual(obb); + expect(tile.boundingVolume).toEqual(obb); }); it('can have a content oriented bounding box', function() { @@ -243,8 +249,8 @@ defineSuite([ var header = clone(tileWithContentBoundingSphere, true); header.transform = getTileTransform(centerLongitude, centerLatitude); var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); - var boundingSphere = tile._boundingVolume.boundingVolume; - var contentBoundingSphere = tile._contentBoundingVolume.boundingVolume; + var boundingSphere = tile.boundingVolume.boundingVolume; + var contentBoundingSphere = tile.contentBoundingVolume.boundingVolume; var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0); expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4); @@ -258,8 +264,8 @@ defineSuite([ var header = clone(tileWithContentBoundingBox, true); header.transform = getTileTransform(centerLongitude, centerLatitude); var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); - var boundingBox = tile._boundingVolume.boundingVolume; - var contentBoundingBox = tile._contentBoundingVolume.boundingVolume; + var boundingBox = tile.boundingVolume.boundingVolume; + var contentBoundingBox = tile.contentBoundingVolume.boundingVolume; var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0); expect(boundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7); @@ -270,8 +276,8 @@ defineSuite([ var header = clone(tileWithContentBoundingRegion, true); header.transform = getTileTransform(centerLongitude, centerLatitude); var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); - var boundingRegion = tile._boundingVolume; - var contentBoundingRegion = tile._contentBoundingVolume; + var boundingRegion = tile.boundingVolume; + var contentBoundingRegion = tile.contentBoundingVolume; var region = header.boundingVolume.region; var rectangle = Rectangle.unpack(region); @@ -295,7 +301,7 @@ defineSuite([ var header = clone(tileWithBoundingSphere, true); header.transform = getTileTransform(centerLongitude, centerLatitude); var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined); - var boundingSphere = tile._boundingVolume.boundingVolume; + var boundingSphere = tile.boundingVolume.boundingVolume; // Check the original transform var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude); @@ -317,6 +323,7 @@ defineSuite([ var scene; beforeEach(function() { scene = createScene(); + scene.frameState.passes.render = true; }); afterEach(function() { diff --git a/Specs/Scene/Cesium3DTileStyleSpec.js b/Specs/Scene/Cesium3DTileStyleSpec.js index b5d486f59d30..3f477c4255b4 100644 --- a/Specs/Scene/Cesium3DTileStyleSpec.js +++ b/Specs/Scene/Cesium3DTileStyleSpec.js @@ -12,8 +12,6 @@ defineSuite([ Expression) { 'use strict'; - var frameState = {}; - function MockFeature() { this._properties = {}; } @@ -2512,7 +2510,7 @@ defineSuite([ description : '"Hello, ${name}"' } }); - expect(style.meta.description.evaluate(frameState, feature1)).toEqual('Hello, Hello'); + expect(style.meta.description.evaluate(feature1)).toEqual('Hello, Hello'); style = new Cesium3DTileStyle({ meta : { @@ -2520,8 +2518,8 @@ defineSuite([ volume : '${Height} * ${Width} * ${Depth}' } }); - expect(style.meta.featureColor.evaluateColor(frameState, feature1)).toEqual(Color.fromBytes(38, 255, 82)); - expect(style.meta.volume.evaluate(frameState, feature1)).toEqual(20 * 20 * 100); + expect(style.meta.featureColor.evaluateColor(feature1)).toEqual(Color.fromBytes(38, 255, 82)); + expect(style.meta.volume.evaluate(feature1)).toEqual(20 * 20 * 100); }); it('default meta has no properties', function() { @@ -2562,9 +2560,9 @@ defineSuite([ 'pointSize' : '1.0' }); - expect(style.show.evaluate(frameState, undefined)).toEqual(true); - expect(style.color.evaluateColor(frameState, undefined)).toEqual(Color.WHITE); - expect(style.pointSize.evaluate(frameState, undefined)).toEqual(1.0); + expect(style.show.evaluate(undefined)).toEqual(true); + expect(style.color.evaluateColor(undefined)).toEqual(Color.WHITE); + expect(style.pointSize.evaluate(undefined)).toEqual(1.0); }); it('applies show style with variable', function() { @@ -2572,8 +2570,8 @@ defineSuite([ 'show' : "${ZipCode} === '19341'" }); - expect(style.show.evaluate(frameState, feature1)).toEqual(true); - expect(style.show.evaluate(frameState, feature2)).toEqual(false); + expect(style.show.evaluate(feature1)).toEqual(true); + expect(style.show.evaluate(feature2)).toEqual(false); }); it('applies show style with regexp and variables', function() { @@ -2581,8 +2579,8 @@ defineSuite([ 'show' : "(regExp('^Chest').test(${County})) && (${YearBuilt} >= 1970)" }); - expect(style.show.evaluate(frameState, feature1)).toEqual(true); - expect(style.show.evaluate(frameState, feature2)).toEqual(false); + expect(style.show.evaluate(feature1)).toEqual(true); + expect(style.show.evaluate(feature2)).toEqual(false); }); it('applies show style with conditional', function() { @@ -2598,24 +2596,24 @@ defineSuite([ ] } }); - expect(style.show.evaluate(frameState, feature1)).toEqual(false); - expect(style.show.evaluate(frameState, feature2)).toEqual(true); + expect(style.show.evaluate(feature1)).toEqual(false); + expect(style.show.evaluate(feature2)).toEqual(true); }); it('applies color style variables', function() { var style = new Cesium3DTileStyle({ 'color' : "(${Temperature} > 90) ? color('red') : color('white')" }); - expect(style.color.evaluateColor(frameState, feature1)).toEqual(Color.WHITE); - expect(style.color.evaluateColor(frameState, feature2)).toEqual(Color.RED); + expect(style.color.evaluateColor(feature1)).toEqual(Color.WHITE); + expect(style.color.evaluateColor(feature2)).toEqual(Color.RED); }); it('applies color style with new color', function() { var style = new Cesium3DTileStyle({ 'color' : 'rgba(${red}, ${green}, ${blue}, (${volume} > 100 ? 0.5 : 1.0))' }); - expect(style.color.evaluateColor(frameState, feature1)).toEqual(new Color(38/255, 255/255, 82/255, 0.5)); - expect(style.color.evaluateColor(frameState, feature2)).toEqual(new Color(255/255, 30/255, 30/255, 1.0)); + expect(style.color.evaluateColor(feature1)).toEqual(new Color(38/255, 255/255, 82/255, 0.5)); + expect(style.color.evaluateColor(feature2)).toEqual(new Color(255/255, 30/255, 30/255, 1.0)); }); it('applies color style that maps id to color', function() { @@ -2631,8 +2629,8 @@ defineSuite([ ] } }); - expect(style.color.evaluateColor(frameState, feature1)).toEqual(Color.RED); - expect(style.color.evaluateColor(frameState, feature2)).toEqual(Color.LIME); + expect(style.color.evaluateColor(feature1)).toEqual(Color.RED); + expect(style.color.evaluateColor(feature2)).toEqual(Color.LIME); }); it('applies color style with conditional', function() { @@ -2648,8 +2646,8 @@ defineSuite([ ] } }); - expect(style.color.evaluateColor(frameState, feature1)).toEqual(Color.BLUE); - expect(style.color.evaluateColor(frameState, feature2)).toEqual(Color.YELLOW); + expect(style.color.evaluateColor(feature1)).toEqual(Color.BLUE); + expect(style.color.evaluateColor(feature2)).toEqual(Color.YELLOW); }); it('applies pointSize style with variable', function() { @@ -2657,8 +2655,8 @@ defineSuite([ 'pointSize' : '${Temperature} / 10.0' }); - expect(style.pointSize.evaluate(frameState, feature1)).toEqual(7.8); - expect(style.pointSize.evaluate(frameState, feature2)).toEqual(9.2); + expect(style.pointSize.evaluate(feature1)).toEqual(7.8); + expect(style.pointSize.evaluate(feature2)).toEqual(9.2); }); it('applies pointSize style with regexp and variables', function() { @@ -2666,8 +2664,8 @@ defineSuite([ 'pointSize' : "(regExp('^Chest').test(${County})) ? 2.0 : 1.0" }); - expect(style.pointSize.evaluate(frameState, feature1)).toEqual(2.0); - expect(style.pointSize.evaluate(frameState, feature2)).toEqual(1.0); + expect(style.pointSize.evaluate(feature1)).toEqual(2.0); + expect(style.pointSize.evaluate(feature2)).toEqual(1.0); }); it('applies pointSize style with conditional', function() { @@ -2683,8 +2681,8 @@ defineSuite([ ] } }); - expect(style.pointSize.evaluate(frameState, feature1)).toEqual(6); - expect(style.pointSize.evaluate(frameState, feature2)).toEqual(3); + expect(style.pointSize.evaluate(feature1)).toEqual(6); + expect(style.pointSize.evaluate(feature2)).toEqual(3); }); it('applies with defines', function() { @@ -2707,14 +2705,14 @@ defineSuite([ } }); - expect(style.color.evaluateColor(frameState, feature1)).toEqual(Color.RED); - expect(style.color.evaluateColor(frameState, feature2)).toEqual(Color.BLUE); - expect(style.show.evaluate(frameState, feature1)).toEqual(true); - expect(style.show.evaluate(frameState, feature2)).toEqual(false); - expect(style.pointSize.evaluate(frameState, feature1)).toEqual(114); - expect(style.pointSize.evaluate(frameState, feature2)).toEqual(44); - expect(style.meta.description.evaluate(frameState, feature1)).toEqual('Half height is 50'); - expect(style.meta.description.evaluate(frameState, feature2)).toEqual('Half height is 19'); + expect(style.color.evaluateColor(feature1)).toEqual(Color.RED); + expect(style.color.evaluateColor(feature2)).toEqual(Color.BLUE); + expect(style.show.evaluate(feature1)).toEqual(true); + expect(style.show.evaluate(feature2)).toEqual(false); + expect(style.pointSize.evaluate(feature1)).toEqual(114); + expect(style.pointSize.evaluate(feature2)).toEqual(44); + expect(style.meta.description.evaluate(feature1)).toEqual('Half height is 50'); + expect(style.meta.description.evaluate(feature2)).toEqual('Half height is 19'); }); it('return undefined shader functions when the style is empty', function() { diff --git a/Specs/Scene/Cesium3DTilesetSpec.js b/Specs/Scene/Cesium3DTilesetSpec.js index 6965e41a5301..4fde0ab601c6 100644 --- a/Specs/Scene/Cesium3DTilesetSpec.js +++ b/Specs/Scene/Cesium3DTilesetSpec.js @@ -2,6 +2,7 @@ defineSuite([ 'Scene/Cesium3DTileset', 'Core/Cartesian3', 'Core/Color', + 'Core/defined', 'Core/CullingVolume', 'Core/getAbsoluteUri', 'Core/getStringFromTypedArray', @@ -32,6 +33,7 @@ defineSuite([ Cesium3DTileset, Cartesian3, Color, + defined, CullingVolume, getAbsoluteUri, getStringFromTypedArray, @@ -185,12 +187,6 @@ defineSuite([ scene.camera.moveDown(200.0); } - function viewBottomRight() { - viewAllTiles(); - scene.camera.moveRight(200.0); - scene.camera.moveDown(200.0); - } - function viewInstances() { setZoom(30.0); } @@ -199,6 +195,10 @@ defineSuite([ setZoom(5.0); } + function isSelected(tileset, tile) { + return tileset._selectedTiles.indexOf(tile) > -1; + } + it('throws with undefined url', function() { expect(function() { return new Cesium3DTileset(); @@ -353,11 +353,41 @@ defineSuite([ expect(properties.id.maximum).toEqual(9); expect(tileset._geometricError).toEqual(240.0); - expect(tileset._root).toBeDefined(); + expect(tileset.root).toBeDefined(); expect(tileset.url).toEqual(tilesetUrl); }); }); + it('loads tileset with extras', function() { + return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { + expect(tileset.extras).toEqual({ 'name': 'Sample Tileset' }); + expect(tileset.root.extras).toBeUndefined(); + + var length = tileset.root.children.length; + var taggedChildren = 0; + for (var i = 0; i < length; ++i) { + if (defined(tileset.root.children[i].extras)) { + expect(tileset.root.children[i].extras).toEqual({ 'id': 'Special Tile' }); + ++taggedChildren; + } + } + + expect(taggedChildren).toEqual(1); + }); + }); + + it('gets root tile', function() { + var tileset = scene.primitives.add(new Cesium3DTileset({ + url : tilesetUrl + })); + expect(function() { + return tileset.root; + }).toThrowDeveloperError(); + return tileset.readyPromise.then(function() { + expect(tileset.root).toBeDefined(); + }); + }); + it('hasExtension returns true if the tileset JSON file uses the specified extension', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableHierarchyUrl).then(function(tileset) { expect(tileset.hasExtension('3DTILES_batch_table_hierarchy')).toBe(true); @@ -367,7 +397,7 @@ defineSuite([ it('passes version in query string to tiles', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - expect(tileset._root.content._resource.url).toEqual(getAbsoluteUri(tilesetUrl.replace('tileset.json','parent.b3dm?v=1.2.3'))); + expect(tileset.root.content._resource.url).toEqual(getAbsoluteUri(tilesetUrl.replace('tileset.json','parent.b3dm?v=1.2.3'))); }); }); @@ -413,6 +443,15 @@ defineSuite([ }).toThrowDeveloperError(); }); + it('throws when getting extras and tileset is not ready', function() { + var tileset = new Cesium3DTileset({ + url : tilesetUrl + }); + expect(function() { + return tileset.extras; + }).toThrowDeveloperError(); + }); + it('requests tile with invalid magic', function() { var invalidMagicBuffer = Cesium3DTilesTester.generateBatchedTileBuffer({ magic : [120, 120, 120, 120] @@ -426,7 +465,7 @@ defineSuite([ deferred.resolve(invalidMagicBuffer); }); scene.renderForSpecs(); // Request root - var root = tileset._root; + var root = tileset.root; return root.contentReadyPromise.then(function() { fail('should not resolve'); }).otherwise(function(error) { @@ -447,7 +486,7 @@ defineSuite([ deferred.reject(); }); scene.renderForSpecs(); // Request root - var root = tileset._root; + var root = tileset.root; return root.contentReadyPromise.then(function() { fail('should not resolve'); }).otherwise(function(error) { @@ -474,7 +513,7 @@ defineSuite([ })); }); scene.renderForSpecs(); // Request root - var root = tileset._root; + var root = tileset.root; return root.contentReadyPromise.then(function() { fail('should not resolve'); }).otherwise(function(error) { @@ -701,7 +740,7 @@ defineSuite([ expect(statistics.batchTableByteLength).toEqual(0); // One feature colored, the batch table memory is now higher - tileset._root.content.getFeature(0).color = Color.RED; + tileset.root.content.getFeature(0).color = Color.RED; scene.renderForSpecs(); expect(statistics.geometryByteLength).toEqual(singleTileGeometryMemory * tilesLength); expect(statistics.texturesByteLength).toEqual(singleTileTextureMemory * tilesLength); @@ -781,7 +820,7 @@ defineSuite([ scene.renderForSpecs(); expect(statistics.visited).toEqual(0); expect(statistics.numberOfCommands).toEqual(0); - expect(tileset._root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).toEqual(CullingVolume.MASK_OUTSIDE); + expect(tileset.root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).toEqual(CullingVolume.MASK_OUTSIDE); }); }); @@ -805,10 +844,10 @@ defineSuite([ scene.renderForSpecs(); expect(statistics.visited).toEqual(2); // Visits root, but does not render it expect(statistics.numberOfCommands).toEqual(1); - expect(tileset._selectedTiles[0]).not.toBe(tileset._root); + expect(tileset._selectedTiles[0]).not.toBe(tileset.root); // Set contents box to undefined, and now root won't be culled - tileset._root._contentBoundingVolume = undefined; + tileset.root._contentBoundingVolume = undefined; scene.renderForSpecs(); expect(statistics.visited).toEqual(2); expect(statistics.numberOfCommands).toEqual(2); @@ -837,7 +876,7 @@ defineSuite([ scene.camera.moveDown(0.5); scene.renderForSpecs(); - var root = tileset._root; + var root = tileset.root; var llTile = findTileByUrl(root.children, 'll.b3dm'); var lrTile = findTileByUrl(root.children, 'lr.b3dm'); var urTile = findTileByUrl(root.children, 'ur.b3dm'); @@ -961,7 +1000,7 @@ defineSuite([ it('replacement refinement - selects root when sse is met', function() { viewRootOnly(); return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - tileset._root.refine = Cesium3DTileRefine.REPLACE; + tileset.root.refine = Cesium3DTileRefine.REPLACE; // Meets screen space error, only root tile is rendered scene.renderForSpecs(); @@ -974,7 +1013,7 @@ defineSuite([ it('replacement refinement - selects children when sse is not met', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - tileset._root.refine = Cesium3DTileRefine.REPLACE; + tileset.root.refine = Cesium3DTileRefine.REPLACE; // Does not meet screen space error, child tiles replace root tile scene.renderForSpecs(); @@ -986,11 +1025,9 @@ defineSuite([ }); it('replacement refinement - selects root when sse is not met and children are not ready', function() { - // Set view so that only root tile is loaded initially viewRootOnly(); - return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; root.refine = Cesium3DTileRefine.REPLACE; // Set zoom to start loading child tiles @@ -1008,26 +1045,28 @@ defineSuite([ }); it('replacement refinement - selects tile when inside viewer request volume', function() { - return Cesium3DTilesTester.loadTileset(scene, tilesetWithViewerRequestVolumeUrl).then(function(tileset) { + var options = { + skipLevelOfDetail : false + }; + return Cesium3DTilesTester.loadTileset(scene, tilesetWithViewerRequestVolumeUrl, options).then(function(tileset) { var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; root.refine = Cesium3DTileRefine.REPLACE; - // Force root tile to always not meet SSE since this is just checking the request volume - tileset.maximumScreenSpaceError = 0.0; + root.hasEmptyContent = false; // mock content + tileset.maximumScreenSpaceError = 0.0; // Force root tile to always not meet SSE since this is just checking the request volume // Renders all 5 tiles setZoom(20.0); scene.renderForSpecs(); expect(statistics.numberOfCommands).toEqual(5); - expect(root.selected).toBe(false); + expect(isSelected(tileset, root)).toBe(false); // No longer renders the tile with a request volume setZoom(1500.0); - root.hasRenderableContent = true; // mock content scene.renderForSpecs(); expect(statistics.numberOfCommands).toEqual(4); - expect(root.selected).toBe(true); // one child is no longer selected. root is chosen instead + expect(isSelected(tileset, root)).toBe(true); // one child is no longer selected. root is chosen instead }); }); @@ -1038,24 +1077,23 @@ defineSuite([ // E E // C C C C // - viewRootOnly(); return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement1Url).then(function(tileset) { + tileset.skipLevelOfDetail = false; viewAllTiles(); scene.renderForSpecs(); var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; - return when.join(root.children[0].contentReadyPromise, root.children[1].contentReadyPromise).then(function() { - // Even though root's children are loaded, the grandchildren need to be loaded before it becomes refinable - expect(numberOfChildrenWithoutContent(root)).toEqual(0); // Children are loaded - expect(statistics.numberOfCommands).toEqual(1); // No stencil or backface commands; no mixed content - expect(statistics.numberOfPendingRequests).toEqual(4); // Loading grandchildren + // Even though root's children are loaded, the grandchildren need to be loaded before it becomes refinable + expect(numberOfChildrenWithoutContent(root)).toEqual(0); // Children are loaded + expect(statistics.numberOfCommands).toEqual(1); // No stencil or backface commands; no mixed content + expect(statistics.numberOfPendingRequests).toEqual(4); // Loading grandchildren - return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { - expect(statistics.numberOfCommands).toEqual(4); // Render children - }); + return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { + scene.renderForSpecs(); + expect(statistics.numberOfCommands).toEqual(4); // Render children }); }); }); @@ -1071,6 +1109,7 @@ defineSuite([ viewRootOnly(); return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement2Url).then(function(tileset) { + tileset.skipLevelOfDetail = false; var statistics = tileset._statistics; return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { expect(statistics.numberOfCommands).toEqual(1); @@ -1096,8 +1135,9 @@ defineSuite([ viewRootOnly(); return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url).then(function(tileset) { + tileset.skipLevelOfDetail = false; var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; expect(statistics.numberOfCommands).toEqual(1); viewAllTiles(); @@ -1109,7 +1149,7 @@ defineSuite([ expect(statistics.numberOfPendingRequests).toEqual(4); // Loading child content tiles return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { - expect(root.selected).toEqual(false); + expect(isSelected(tileset, root)).toEqual(false); expect(statistics.numberOfCommands).toEqual(4); // Render child content tiles }); }); @@ -1134,7 +1174,7 @@ defineSuite([ var center = Cartesian3.fromRadians(centerLongitude, centerLatitude, 22.0); scene.camera.lookAt(center, new HeadingPitchRange(0.0, 1.57, 1.0)); - var root = tileset._root; + var root = tileset.root; var childRoot = root.children[0]; scene.renderForSpecs(); @@ -1147,13 +1187,13 @@ defineSuite([ expect(childRoot.children[3].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).toEqual(CullingVolume.MASK_OUTSIDE); expect(tileset._selectedTiles.length).toEqual(0); - expect(childRoot.selected).toBe(false); + expect(isSelected(tileset, childRoot)).toBe(false); }); }); it('does not select visible tiles not meeting SSE with visible children', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacementWithViewerRequestVolumeUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; var childRoot = root.children[0]; childRoot.geometricError = 240; @@ -1166,13 +1206,13 @@ defineSuite([ expect(childRoot.children[2].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(childRoot.children[3].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); - expect(childRoot.selected).toBe(false); + expect(isSelected(tileset, childRoot)).toBe(false); }); }); it('does select visible tiles meeting SSE with visible children', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacementWithViewerRequestVolumeUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; var childRoot = root.children[0]; childRoot.geometricError = 0; // child root should meet SSE and children should not be drawn @@ -1186,15 +1226,18 @@ defineSuite([ expect(childRoot.children[2].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(childRoot.children[3].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); - expect(childRoot.selected).toBe(true); + expect(isSelected(tileset, childRoot)).toBe(true); }); }); }); - it('does select visibile tiles with visible children failing request volumes', function() { + it('does select visible tiles with visible children failing request volumes', function() { + var options = { + cullWithChildrenBounds : false + }; viewRootOnly(); - return Cesium3DTilesTester.loadTileset(scene, tilesetReplacementWithViewerRequestVolumeUrl).then(function(tileset) { - var root = tileset._root; + return Cesium3DTilesTester.loadTileset(scene, tilesetReplacementWithViewerRequestVolumeUrl, options).then(function(tileset) { + var root = tileset.root; var childRoot = root.children[0]; expect(childRoot.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); @@ -1205,13 +1248,13 @@ defineSuite([ expect(childRoot.children[3].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(tileset._selectedTiles.length).toEqual(1); - expect(childRoot.selected).toBe(true); + expect(isSelected(tileset, childRoot)).toBe(true); }); }); - it('does select visibile tiles with visible children passing request volumes', function() { + it('does select visible tiles with visible children passing request volumes', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacementWithViewerRequestVolumeUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; var childRoot = root.children[0]; childRoot.geometricError = 0; @@ -1225,12 +1268,12 @@ defineSuite([ expect(childRoot.children[3].visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(tileset._selectedTiles.length).toEqual(1); - expect(childRoot.selected).toBe(true); + expect(isSelected(tileset, childRoot)).toBe(true); childRoot.geometricError = 200; scene.renderForSpecs(); expect(tileset._selectedTiles.length).toEqual(4); - expect(childRoot.selected).toBe(false); + expect(isSelected(tileset, childRoot)).toBe(false); }); }); }); @@ -1242,7 +1285,7 @@ defineSuite([ return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) { // Root points to an external tileset JSON file and has no children until it is requested - var root = tileset._root; + var root = tileset.root; expect(root.children.length).toEqual(0); // Set view so that root's content is requested @@ -1285,11 +1328,10 @@ defineSuite([ viewRootOnly(); scene.renderForSpecs(); - return tileset._root.contentReadyPromise; + return tileset.root.contentReadyPromise; }).then(function() { - //Make sure tileset2.json was requested with query parameters and version - var queryParamsWithVersion = 'v=0.0&' + queryParams; - expectedUrl = getAbsoluteUri('Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset2.json?' + queryParamsWithVersion); + //Make sure tileset2.json was requested with query parameters and does not use parent tilesetVersion + expectedUrl = getAbsoluteUri('Data/Cesium3DTiles/Tilesets/TilesetOfTilesets/tileset2.json?v=1.2.3&' + queryParams); expect(Resource._Implementations.loadWithXhr.calls.argsFor(0)[0]).toEqual(expectedUrl); }); }); @@ -1311,7 +1353,7 @@ defineSuite([ }); // Check for color - tileset._root.color = Color.RED; + tileset.root.color = Color.RED; Cesium3DTilesTester.expectRender(scene, tileset, function(rgba) { expect(rgba).not.toEqual(color); }); @@ -1456,7 +1498,7 @@ defineSuite([ expect(tileset._tileDebugLabels).toBeDefined(); expect(tileset._tileDebugLabels.length).toEqual(5); - var root = tileset._root; + var root = tileset.root; expect(tileset._tileDebugLabels._labels[0].text).toEqual('Geometric error: ' + root.geometricError); expect(tileset._tileDebugLabels._labels[1].text).toEqual('Geometric error: ' + root.children[0].geometricError); expect(tileset._tileDebugLabels._labels[2].text).toEqual('Geometric error: ' + root.children[1].geometricError); @@ -1477,7 +1519,7 @@ defineSuite([ expect(tileset._tileDebugLabels).toBeDefined(); expect(tileset._tileDebugLabels.length).toEqual(2); - var root = tileset._root; + var root = tileset.root; expect(tileset._tileDebugLabels._labels[0].text).toEqual('Geometric error: ' + root.geometricError); expect(tileset._tileDebugLabels._labels[1].text).toEqual('Geometric error: ' + root.children[0].geometricError); @@ -1516,8 +1558,8 @@ defineSuite([ expect(tileset._tileDebugLabels).toBeDefined(); expect(tileset._tileDebugLabels.length).toEqual(1); - var content = tileset._root.content; - var expected = 'Commands: ' + tileset._root.commandsLength + '\n' + + var content = tileset.root.content; + var expected = 'Commands: ' + tileset.root.commandsLength + '\n' + 'Triangles: ' + content.trianglesLength + '\n' + 'Features: ' + content.featuresLength; @@ -1588,7 +1630,7 @@ defineSuite([ tileset.debugPickedTileLabelOnly = true; var scratchPosition = new Cartesian3(1.0, 1.0, 1.0); - tileset.debugPickedTile = tileset._root; + tileset.debugPickedTile = tileset.root; tileset.debugPickPosition = scratchPosition; scene.renderForSpecs(); @@ -1629,7 +1671,7 @@ defineSuite([ viewRootOnly(); scene.renderForSpecs(); // Request root expect(tileset._statistics.numberOfPendingRequests).toEqual(1); - return tileset._root.contentReadyToProcessPromise.then(function() { + return tileset.root.contentReadyToProcessPromise.then(function() { scene.pickForSpecs(); expect(spy).not.toHaveBeenCalled(); scene.renderForSpecs(); @@ -1714,9 +1756,9 @@ defineSuite([ var spyUpdate = jasmine.createSpy('listener'); tileset.tileVisible.addEventListener(spyUpdate); scene.renderForSpecs(); - expect(tileset._root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); + expect(tileset.root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(spyUpdate.calls.count()).toEqual(1); - expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset._root); + expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset.root); }); }); @@ -1730,7 +1772,7 @@ defineSuite([ return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { // Root is loaded expect(spyUpdate.calls.count()).toEqual(1); - expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset._root); + expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset.root); spyUpdate.calls.reset(); // Unload from cache @@ -1742,7 +1784,7 @@ defineSuite([ viewRootOnly(); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function() { expect(spyUpdate.calls.count()).toEqual(1); - expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset._root); + expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset.root); }); }); }); @@ -1771,7 +1813,7 @@ defineSuite([ it('destroys', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; expect(tileset.isDestroyed()).toEqual(false); scene.primitives.remove(tileset); expect(tileset.isDestroyed()).toEqual(true); @@ -1788,7 +1830,7 @@ defineSuite([ it('destroys before external tileset JSON file finishes loading', function() { viewNothing(); return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; viewRootOnly(); scene.renderForSpecs(); // Request external tileset JSON file @@ -1812,7 +1854,7 @@ defineSuite([ url : tilesetUrl })); return tileset.readyPromise.then(function(tileset) { - var root = tileset._root; + var root = tileset.root; scene.renderForSpecs(); // Request root scene.primitives.remove(tileset); @@ -1918,7 +1960,7 @@ defineSuite([ expect(scene).notToRender([0, 0, 0, 255]); // Change feature ids so the show expression will evaluate to false - var content = tileset._root.content; + var content = tileset.root.content; var length = content.featuresLength; var i; var feature; @@ -1937,6 +1979,48 @@ defineSuite([ }); }); + it('applies style when tile is selected after new style is applied', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { + var feature = tileset.root.content.getFeature(0); + tileset.style = new Cesium3DTileStyle({color: 'color("red")'}); + scene.renderForSpecs(); + expect(feature.color).toEqual(Color.RED); + + tileset.style = new Cesium3DTileStyle({color: 'color("blue")'}); + scene.renderForSpecs(); + expect(feature.color).toEqual(Color.BLUE); + + viewNothing(); + tileset.style = new Cesium3DTileStyle({color: 'color("lime")'}); + scene.renderForSpecs(); + expect(feature.color).toEqual(Color.BLUE); // Hasn't been selected yet + + viewAllTiles(); + scene.renderForSpecs(); + expect(feature.color).toEqual(Color.LIME); + + // Feature's show property is preserved if the style hasn't changed and the feature is newly selected + feature.show = false; + scene.renderForSpecs(); + expect(feature.show).toBe(false); + viewNothing(); + scene.renderForSpecs(); + expect(feature.show).toBe(false); + viewAllTiles(); + expect(feature.show).toBe(false); + }); + }); + + it('does not reapply style during pick pass', function() { + return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { + tileset.style = new Cesium3DTileStyle({color: 'color("red")'}); + scene.renderForSpecs(); + expect(tileset.statistics.numberOfTilesStyled).toBe(1); + scene.pickForSpecs(); + expect(tileset.statistics.numberOfTilesStyled).toBe(0); + }); + }); + it('applies style with complex color expression to a tileset', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { // Each feature in the b3dm file has an id property from 0 to 9 @@ -2016,13 +2100,13 @@ defineSuite([ it('applies custom style to a tileset', function() { var style = new Cesium3DTileStyle(); style.show = { - evaluate : function(frameState, feature) { + evaluate : function(feature) { return this._value; }, _value : false }; style.color = { - evaluateColor : function(frameState, feature, result) { + evaluateColor : function(feature, result) { return Color.clone(Color.WHITE, result); } }; @@ -2303,14 +2387,14 @@ defineSuite([ it('Unloads cached tiles in a tileset with external tileset JSON file using maximumMemoryUsage', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) { var statistics = tileset._statistics; - var replacementList = tileset._replacementList; + var cacheList = tileset._cache._list; tileset.maximumMemoryUsage = 0.02; scene.renderForSpecs(); expect(statistics.numberOfCommands).toEqual(5); expect(statistics.numberOfTilesWithContentReady).toEqual(5); - expect(replacementList.length - 1).toEqual(5); // Only tiles with content are on the replacement list. -1 for sentinel. + expect(cacheList.length - 1).toEqual(5); // Only tiles with content are on the replacement list. -1 for sentinel. // Zoom out so only root tile is needed to meet SSE. This unloads // all tiles except the root and one of the b3dm children @@ -2319,7 +2403,7 @@ defineSuite([ expect(statistics.numberOfCommands).toEqual(1); expect(statistics.numberOfTilesWithContentReady).toEqual(2); - expect(replacementList.length - 1).toEqual(2); + expect(cacheList.length - 1).toEqual(2); // Reset camera so all tiles are reloaded viewAllTiles(); @@ -2328,7 +2412,7 @@ defineSuite([ expect(statistics.numberOfCommands).toEqual(5); expect(statistics.numberOfTilesWithContentReady).toEqual(5); - expect(replacementList.length - 1).toEqual(5); + expect(cacheList.length - 1).toEqual(5); }); }); }); @@ -2443,12 +2527,12 @@ defineSuite([ tileset.tileUnload.addEventListener(spyUpdate); scene.renderForSpecs(); - expect(tileset._root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); + expect(tileset.root.visibility(scene.frameState, CullingVolume.MASK_INDETERMINATE)).not.toEqual(CullingVolume.MASK_OUTSIDE); expect(spyUpdate.calls.count()).toEqual(4); - expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset._root.children[0]); - expect(spyUpdate.calls.argsFor(1)[0]).toBe(tileset._root.children[1]); - expect(spyUpdate.calls.argsFor(2)[0]).toBe(tileset._root.children[2]); - expect(spyUpdate.calls.argsFor(3)[0]).toBe(tileset._root.children[3]); + expect(spyUpdate.calls.argsFor(0)[0]).toBe(tileset.root.children[0]); + expect(spyUpdate.calls.argsFor(1)[0]).toBe(tileset.root.children[1]); + expect(spyUpdate.calls.argsFor(2)[0]).toBe(tileset.root.children[2]); + expect(spyUpdate.calls.argsFor(3)[0]).toBe(tileset.root.children[3]); }); }); @@ -2476,7 +2560,7 @@ defineSuite([ var totalCommands = b3dmCommands + i3dmCommands; return Cesium3DTilesTester.loadTileset(scene, tilesetWithTransformsUrl).then(function(tileset) { var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; var rootTransform = Matrix4.unpack(root._header.transform); var child = root.children[0]; @@ -2535,17 +2619,17 @@ defineSuite([ return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url).then(function(tileset) { var statistics = tileset._statistics; - tileset._root.children[0].children[0].children[0].unloadContent(); - tileset._root.children[0].children[0].children[1].unloadContent(); - tileset._root.children[0].children[0].children[2].unloadContent(); + tileset.root.children[0].children[0].children[0].unloadContent(); + tileset.root.children[0].children[0].children[1].unloadContent(); + tileset.root.children[0].children[0].children[2].unloadContent(); statistics.numberOfTilesWithContentReady -= 3; scene.renderForSpecs(); expect(tileset._hasMixedContent).toBe(true); expect(statistics.numberOfTilesWithContentReady).toEqual(2); - expect(tileset._root.children[0].children[0].children[3]._selectionDepth).toEqual(1); - expect(tileset._root._selectionDepth).toEqual(0); + expect(tileset.root.children[0].children[0].children[3]._selectionDepth).toEqual(1); + expect(tileset.root._selectionDepth).toEqual(0); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) { expect(statistics.numberOfTilesWithContentReady).toEqual(5); @@ -2556,10 +2640,9 @@ defineSuite([ it('adds stencil clear command first when unresolved', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url).then(function(tileset) { - - tileset._root.children[0].children[0].children[0].unloadContent(); - tileset._root.children[0].children[0].children[1].unloadContent(); - tileset._root.children[0].children[0].children[2].unloadContent(); + tileset.root.children[0].children[0].children[0].unloadContent(); + tileset.root.children[0].children[0].children[1].unloadContent(); + tileset.root.children[0].children[0].children[2].unloadContent(); scene.renderForSpecs(); var commandList = scene.frameState.commandList; @@ -2570,22 +2653,21 @@ defineSuite([ it('creates duplicate backface commands', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url).then(function(tileset) { - var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; - tileset._root.children[0].children[0].children[0].unloadContent(); - tileset._root.children[0].children[0].children[1].unloadContent(); - tileset._root.children[0].children[0].children[2].unloadContent(); + tileset.root.children[0].children[0].children[0].unloadContent(); + tileset.root.children[0].children[0].children[1].unloadContent(); + tileset.root.children[0].children[0].children[2].unloadContent(); scene.renderForSpecs(); // 2 for root tile, 1 for child, 1 for stencil clear // Tiles that are marked as finalResolution, including leaves, do not create back face commands expect(statistics.numberOfCommands).toEqual(4); - expect(root.selected).toBe(true); + expect(isSelected(tileset, root)).toBe(true); expect(root._finalResolution).toBe(false); - expect(root.children[0].children[0].children[3].selected).toBe(true); + expect(isSelected(tileset, root.children[0].children[0].children[3])).toBe(true); expect(root.children[0].children[0].children[3]._finalResolution).toBe(true); expect(tileset._hasMixedContent).toBe(true); @@ -2600,23 +2682,23 @@ defineSuite([ it('does not create duplicate backface commands if no selected descendants', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url).then(function(tileset) { var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; - tileset._root.children[0].children[0].children[0].unloadContent(); - tileset._root.children[0].children[0].children[1].unloadContent(); - tileset._root.children[0].children[0].children[2].unloadContent(); - tileset._root.children[0].children[0].children[3].unloadContent(); + tileset.root.children[0].children[0].children[0].unloadContent(); + tileset.root.children[0].children[0].children[1].unloadContent(); + tileset.root.children[0].children[0].children[2].unloadContent(); + tileset.root.children[0].children[0].children[3].unloadContent(); scene.renderForSpecs(); // 2 for root tile, 1 for child, 1 for stencil clear expect(statistics.numberOfCommands).toEqual(1); - expect(root.selected).toBe(true); + expect(isSelected(tileset, root)).toBe(true); expect(root._finalResolution).toBe(true); - expect(root.children[0].children[0].children[0].selected).toBe(false); - expect(root.children[0].children[0].children[1].selected).toBe(false); - expect(root.children[0].children[0].children[2].selected).toBe(false); - expect(root.children[0].children[0].children[3].selected).toBe(false); + expect(isSelected(tileset, root.children[0].children[0].children[0])).toBe(false); + expect(isSelected(tileset, root.children[0].children[0].children[1])).toBe(false); + expect(isSelected(tileset, root.children[0].children[0].children[2])).toBe(false); + expect(isSelected(tileset, root.children[0].children[0].children[3])).toBe(false); expect(tileset._hasMixedContent).toBe(false); }); }); @@ -2650,8 +2732,7 @@ defineSuite([ it('loadSiblings', function() { viewBottomLeft(); return Cesium3DTilesTester.loadTileset(scene, tilesetReplacement3Url, { - loadSiblings : false, - baseScreenSpaceError: 1000000000 + loadSiblings : false }).then(function(tileset) { var statistics = tileset._statistics; expect(statistics.numberOfTilesWithContentReady).toBe(2); @@ -2663,20 +2744,30 @@ defineSuite([ }); }); - xit('immediatelyLoadDesiredLevelOfDetail', function() { - viewBottomRight(); + it('immediatelyLoadDesiredLevelOfDetail', function() { + viewBottomLeft(); var tileset = scene.primitives.add(new Cesium3DTileset({ url : tilesetOfTilesetsUrl, immediatelyLoadDesiredLevelOfDetail : true })); return Cesium3DTilesTester.waitForReady(scene, tileset).then(function(tileset) { scene.renderForSpecs(); - return tileset._root.contentReadyPromise.then(function() { - tileset._root.refine = Cesium3DTileRefine.REPLACE; - tileset._root.children[0].refine = Cesium3DTileRefine.REPLACE; + return tileset.root.contentReadyPromise.then(function() { + tileset.root.refine = Cesium3DTileRefine.REPLACE; + tileset.root.children[0].refine = Cesium3DTileRefine.REPLACE; + tileset._allTilesAdditive = false; return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) { var statistics = tileset._statistics; expect(statistics.numberOfTilesWithContentReady).toBe(1); + // Renders child while parent loads + viewRootOnly(); + scene.renderForSpecs(); + expect(isSelected(tileset, tileset.root.children[0])); + expect(!isSelected(tileset, tileset.root)); + return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then(function(tileset) { + expect(!isSelected(tileset, tileset.root.children[0])); + expect(isSelected(tileset, tileset.root)); + }); }); }); }); @@ -2685,7 +2776,7 @@ defineSuite([ it('selects children if no ancestors available', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) { var statistics = tileset._statistics; - var parent = tileset._root.children[0]; + var parent = tileset.root.children[0]; var child = parent.children[3].children[0]; parent.refine = Cesium3DTileRefine.REPLACE; parent.unloadContent(); @@ -2695,8 +2786,8 @@ defineSuite([ expect(child.contentReady).toBe(true); expect(parent.contentReady).toBe(false); - expect(child.selected).toBe(true); - expect(parent.selected).toBe(false); + expect(isSelected(tileset, child)).toBe(true); + expect(isSelected(tileset, parent)).toBe(false); expect(statistics.numberOfCommands).toEqual(1); }); }); @@ -2707,7 +2798,7 @@ defineSuite([ spyOn(Resource._Implementations, 'loadWithXhr').and.callFake(function(url, responseType, method, data, headers, deferred, overrideMimeType) { Resource._DefaultImplementations.loadWithXhr(batchedColorsB3dmUrl, responseType, method, data, headers, deferred, overrideMimeType); }); - var tile = tileset._root; + var tile = tileset.root; var statistics = tileset._statistics; var expiredContent; tileset.style = new Cesium3DTileStyle({ @@ -2808,7 +2899,7 @@ defineSuite([ }); }); - var subtreeRoot = tileset._root.children[0]; + var subtreeRoot = tileset.root.children[0]; var subtreeChildren = subtreeRoot.children[0].children; var childrenLength = subtreeChildren.length; var statistics = tileset._statistics; @@ -2855,7 +2946,7 @@ defineSuite([ spyOn(Resource._Implementations, 'loadWithXhr').and.callFake(function(url, responseType, method, data, headers, deferred, overrideMimeType) { deferred.reject(); }); - var tile = tileset._root; + var tile = tileset.root; var statistics = tileset._statistics; // Trigger expiration to happen next frame @@ -2877,13 +2968,17 @@ defineSuite([ it('tile expiration date', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; // Trigger expiration to happen next frame tile.expireDate = JulianDate.addSeconds(JulianDate.now(), -1.0, new JulianDate()); // Stays in the expired state until the request goes through + var originalMaxmimumRequests = RequestScheduler.maximumRequests; + RequestScheduler.maximumRequests = 0; // Artificially limit Request Scheduler so the request won't go through scene.renderForSpecs(); + RequestScheduler.maximumRequests = originalMaxmimumRequests; + expect(tile.contentExpired).toBe(true); return pollToPromise(function() { @@ -2950,7 +3045,7 @@ defineSuite([ it('clipping planes cull hidden tiles', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - var visibility = tileset._root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); + var visibility = tileset.root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); expect(visibility).not.toBe(CullingVolume.MASK_OUTSIDE); @@ -2961,12 +3056,12 @@ defineSuite([ ] }); - visibility = tileset._root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); + visibility = tileset.root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); expect(visibility).toBe(CullingVolume.MASK_OUTSIDE); plane.distance = 0.0; - visibility = tileset._root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); + visibility = tileset.root.visibility(scene.frameState, CullingVolume.MASK_INSIDE); expect(visibility).not.toBe(CullingVolume.MASK_OUTSIDE); }); @@ -2974,7 +3069,7 @@ defineSuite([ it('clipping planes cull hidden content', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { - var visibility = tileset._root.contentVisibility(scene.frameState); + var visibility = tileset.root.contentVisibility(scene.frameState); expect(visibility).not.toBe(Intersect.OUTSIDE); @@ -2985,12 +3080,12 @@ defineSuite([ ] }); - visibility = tileset._root.contentVisibility(scene.frameState); + visibility = tileset.root.contentVisibility(scene.frameState); expect(visibility).toBe(Intersect.OUTSIDE); plane.distance = 0.0; - visibility = tileset._root.contentVisibility(scene.frameState); + visibility = tileset.root.contentVisibility(scene.frameState); expect(visibility).not.toBe(Intersect.OUTSIDE); }); @@ -2999,7 +3094,7 @@ defineSuite([ it('clipping planes cull tiles completely inside clipping region', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetUrl).then(function(tileset) { var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; scene.renderForSpecs(); @@ -3041,7 +3136,7 @@ defineSuite([ it('clipping planes cull tiles completely inside clipping region for i3dm', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetWithExternalResourcesUrl).then(function(tileset) { var statistics = tileset._statistics; - var root = tileset._root; + var root = tileset.root; scene.renderForSpecs(); diff --git a/Specs/Scene/ClassificationPrimitiveSpec.js b/Specs/Scene/ClassificationPrimitiveSpec.js index ba2dcdef2c2a..e3c278aa3470 100644 --- a/Specs/Scene/ClassificationPrimitiveSpec.js +++ b/Specs/Scene/ClassificationPrimitiveSpec.js @@ -58,7 +58,7 @@ defineSuite([ beforeAll(function() { scene = createScene(); - scene.fxaa = false; + scene.postProcessStages.fxaa.enabled = false; ellipsoid = Ellipsoid.WGS84; }); diff --git a/Specs/Scene/ClippingPlaneCollectionSpec.js b/Specs/Scene/ClippingPlaneCollectionSpec.js index bd6717110818..dc8a6c66fa32 100644 --- a/Specs/Scene/ClippingPlaneCollectionSpec.js +++ b/Specs/Scene/ClippingPlaneCollectionSpec.js @@ -95,6 +95,14 @@ defineSuite([ expect(clippingPlanes._planes[0]).toBe(planes[0]); }); + it('fires the planeAdded event when a plane is added', function() { + clippingPlanes = new ClippingPlaneCollection(); + var spy = jasmine.createSpy(); + clippingPlanes.planeAdded.addEventListener(spy); + clippingPlanes.add(planes[0]); + expect(spy).toHaveBeenCalled(); + }); + it('gets the plane at an index', function() { clippingPlanes = new ClippingPlaneCollection({ planes : planes @@ -138,6 +146,43 @@ defineSuite([ expect(result).toBe(false); }); + it('remove fires planeRemoved event', function() { + clippingPlanes = new ClippingPlaneCollection({ + planes : planes + }); + + var spy = jasmine.createSpy(); + clippingPlanes.planeRemoved.addEventListener(spy); + + clippingPlanes.remove(planes[0]); + expect(spy).toHaveBeenCalled(); + }); + + it('removeAll removes all of the planes in the collection', function() { + clippingPlanes = new ClippingPlaneCollection({ + planes : planes + }); + + expect(clippingPlanes.length).toEqual(planes.length); + + clippingPlanes.removeAll(); + + expect(clippingPlanes.length).toBe(0); + }); + + it('removeAll fires planeRemoved event', function() { + clippingPlanes = new ClippingPlaneCollection({ + planes : planes + }); + + var spy = jasmine.createSpy(); + clippingPlanes.planeRemoved.addEventListener(spy); + + clippingPlanes.removeAll(); + + expect(spy).toHaveBeenCalled(); + }); + describe('uint8 texture mode', function() { beforeEach(function() { spyOn(ClippingPlaneCollection, 'useFloatTexture').and.returnValue(false); @@ -576,56 +621,6 @@ defineSuite([ }).toThrowDeveloperError(); }); - it('clone without a result parameter returns new copy', function() { - clippingPlanes = new ClippingPlaneCollection({ - planes : planes, - enabled : false, - edgeColor : Color.RED, - modelMatrix : transform - }); - - var result = clippingPlanes.clone(); - expect(result).not.toBe(clippingPlanes); - expect(Cartesian3.equals(result._planes[0].normal, planes[0].normal)).toBe(true); - expect(result._planes[0].distance).toEqual(planes[0].distance); - expect(Cartesian3.equals(result._planes[1].normal, planes[1].normal)).toBe(true); - expect(result._planes[1].distance).toEqual(planes[1].distance); - expect(result.enabled).toEqual(false); - expect(result.modelMatrix).toEqual(transform); - expect(result.edgeColor).toEqual(Color.RED); - expect(result.edgeWidth).toEqual(0.0); - expect(result.unionClippingRegions).toEqual(false); - expect(result._testIntersection).not.toBeUndefined(); - }); - - it('clone stores copy in result parameter', function() { - clippingPlanes = new ClippingPlaneCollection({ - planes : planes, - enabled : false, - edgeColor : Color.RED, - modelMatrix : transform - }); - var result = new ClippingPlaneCollection(); - var copy = clippingPlanes.clone(result); - expect(copy).toBe(result); - expect(result._planes).not.toBe(planes); - expect(Cartesian3.equals(result._planes[0].normal, planes[0].normal)).toBe(true); - expect(result._planes[0].distance).toEqual(planes[0].distance); - expect(Cartesian3.equals(result._planes[1].normal, planes[1].normal)).toBe(true); - expect(result._planes[1].distance).toEqual(planes[1].distance); - expect(result.enabled).toEqual(false); - expect(result.modelMatrix).toEqual(transform); - expect(result.edgeColor).toEqual(Color.RED); - expect(result.edgeWidth).toEqual(0.0); - expect(result.unionClippingRegions).toEqual(false); - expect(result._testIntersection).not.toBeUndefined(); - - // Only allocate a new array if needed - var previousPlanes = result._planes; - clippingPlanes.clone(result); - expect(result._planes).toBe(previousPlanes); - }); - it('setting unionClippingRegions updates testIntersection function', function() { clippingPlanes = new ClippingPlaneCollection(); var originalIntersectFunction = clippingPlanes._testIntersection; diff --git a/Specs/Scene/ConditionsExpressionSpec.js b/Specs/Scene/ConditionsExpressionSpec.js index 5c3bf2bc547d..2647d8de3aaf 100644 --- a/Specs/Scene/ConditionsExpressionSpec.js +++ b/Specs/Scene/ConditionsExpressionSpec.js @@ -8,8 +8,6 @@ defineSuite([ Color) { 'use strict'; - var frameState = {}; - function MockFeature(value) { this._value = value; } @@ -46,22 +44,22 @@ defineSuite([ it('evaluates conditional', function() { var expression = new ConditionsExpression(jsonExp); - expect(expression.evaluateColor(frameState, new MockFeature(101))).toEqual(Color.BLUE); - expect(expression.evaluateColor(frameState, new MockFeature(52))).toEqual(Color.RED); - expect(expression.evaluateColor(frameState, new MockFeature(3))).toEqual(Color.LIME); + expect(expression.evaluateColor(new MockFeature(101))).toEqual(Color.BLUE); + expect(expression.evaluateColor(new MockFeature(52))).toEqual(Color.RED); + expect(expression.evaluateColor(new MockFeature(3))).toEqual(Color.LIME); }); it('evaluates conditional with defines', function() { var expression = new ConditionsExpression(jsonExpWithDefines, defines); - expect(expression.evaluateColor(frameState, new MockFeature(101))).toEqual(Color.BLUE); - expect(expression.evaluateColor(frameState, new MockFeature(52))).toEqual(Color.LIME); - expect(expression.evaluateColor(frameState, new MockFeature(3))).toEqual(Color.LIME); + expect(expression.evaluateColor(new MockFeature(101))).toEqual(Color.BLUE); + expect(expression.evaluateColor(new MockFeature(52))).toEqual(Color.LIME); + expect(expression.evaluateColor(new MockFeature(3))).toEqual(Color.LIME); }); it('evaluate takes result argument', function() { var result = new Cartesian4(); var expression = new ConditionsExpression(jsonExpWithDefines, defines, result); - var value = expression.evaluate(frameState, new MockFeature(101), result); + var value = expression.evaluate(new MockFeature(101), result); expect(value).toEqual(new Cartesian4(0.0, 0.0, 1.0, 1.0)); expect(value).toBe(result); }); @@ -69,7 +67,7 @@ defineSuite([ it('evaluate takes a color result argument', function() { var result = new Color(); var expression = new ConditionsExpression(jsonExpWithDefines, defines, result); - var value = expression.evaluate(frameState, new MockFeature(101), result); + var value = expression.evaluate(new MockFeature(101), result); expect(value).toEqual(Color.BLUE); expect(value).toBe(result); }); @@ -79,17 +77,17 @@ defineSuite([ 'conditions' : [] }); expect(expression._conditions).toEqual([]); - expect(expression.evaluate(frameState, new MockFeature(101))).toEqual(undefined); - expect(expression.evaluate(frameState, new MockFeature(52))).toEqual(undefined); - expect(expression.evaluate(frameState, new MockFeature(3))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(101))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(52))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(3))).toEqual(undefined); }); it('constructs and evaluates empty', function() { var expression = new ConditionsExpression([]); expect(expression._conditions).toEqual(undefined); - expect(expression.evaluate(frameState, new MockFeature(101))).toEqual(undefined); - expect(expression.evaluate(frameState, new MockFeature(52))).toEqual(undefined); - expect(expression.evaluate(frameState, new MockFeature(3))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(101))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(52))).toEqual(undefined); + expect(expression.evaluate(new MockFeature(3))).toEqual(undefined); }); it('gets shader function', function() { diff --git a/Specs/Scene/ExpressionSpec.js b/Specs/Scene/ExpressionSpec.js index 5ad608d8e2c4..6918b9dd1bdc 100644 --- a/Specs/Scene/ExpressionSpec.js +++ b/Specs/Scene/ExpressionSpec.js @@ -16,8 +16,6 @@ defineSuite([ ExpressionNodeType) { 'use strict'; - var frameState = {}; - function MockFeature() { this._properties = {}; this._className = undefined; @@ -59,7 +57,7 @@ defineSuite([ it('parses backslashes', function() { var expression = new Expression('"\\he\\\\\\ll\\\\o"'); - expect(expression.evaluate(frameState, undefined)).toEqual('\\he\\\\\\ll\\\\o'); + expect(expression.evaluate(undefined)).toEqual('\\he\\\\\\ll\\\\o'); }); it('evaluates variable', function() { @@ -73,55 +71,55 @@ defineSuite([ feature.addProperty('undefined', undefined); var expression = new Expression('${height}'); - expect(expression.evaluate(frameState, feature)).toEqual(10); + expect(expression.evaluate(feature)).toEqual(10); expression = new Expression('\'${height}\''); - expect(expression.evaluate(frameState, feature)).toEqual('10'); + expect(expression.evaluate(feature)).toEqual('10'); expression = new Expression('${height}/${width}'); - expect(expression.evaluate(frameState, feature)).toEqual(2); + expect(expression.evaluate(feature)).toEqual(2); expression = new Expression('${string}'); - expect(expression.evaluate(frameState, feature)).toEqual('hello'); + expect(expression.evaluate(feature)).toEqual('hello'); expression = new Expression('\'replace ${string}\''); - expect(expression.evaluate(frameState, feature)).toEqual('replace hello'); + expect(expression.evaluate(feature)).toEqual('replace hello'); expression = new Expression('\'replace ${string} multiple ${height}\''); - expect(expression.evaluate(frameState, feature)).toEqual('replace hello multiple 10'); + expect(expression.evaluate(feature)).toEqual('replace hello multiple 10'); expression = new Expression('"replace ${string}"'); - expect(expression.evaluate(frameState, feature)).toEqual('replace hello'); + expect(expression.evaluate(feature)).toEqual('replace hello'); expression = new Expression('\'replace ${string\''); - expect(expression.evaluate(frameState, feature)).toEqual('replace ${string'); + expect(expression.evaluate(feature)).toEqual('replace ${string'); expression = new Expression('${boolean}'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); expression = new Expression('\'${boolean}\''); - expect(expression.evaluate(frameState, feature)).toEqual('true'); + expect(expression.evaluate(feature)).toEqual('true'); expression = new Expression('${vector}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian3.UNIT_X); + expect(expression.evaluate(feature)).toEqual(Cartesian3.UNIT_X); expression = new Expression('\'${vector}\''); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian3.UNIT_X.toString()); + expect(expression.evaluate(feature)).toEqual(Cartesian3.UNIT_X.toString()); expression = new Expression('${null}'); - expect(expression.evaluate(frameState, feature)).toEqual(null); + expect(expression.evaluate(feature)).toEqual(null); expression = new Expression('\'${null}\''); - expect(expression.evaluate(frameState, feature)).toEqual(''); + expect(expression.evaluate(feature)).toEqual(''); expression = new Expression('${undefined}'); - expect(expression.evaluate(frameState, feature)).toEqual(undefined); + expect(expression.evaluate(feature)).toEqual(undefined); expression = new Expression('\'${undefined}\''); - expect(expression.evaluate(frameState, feature)).toEqual(''); + expect(expression.evaluate(feature)).toEqual(''); expression = new Expression('abs(-${height}) + max(${height}, ${width}) + clamp(${height}, 0, 2)'); - expect(expression.evaluate(frameState, feature)).toEqual(22); + expect(expression.evaluate(feature)).toEqual(22); expect(function() { return new Expression('${height'); @@ -136,7 +134,7 @@ defineSuite([ feature.addProperty('Height', 10); var expression = new Expression('${halfHeight}', defines); - expect(expression.evaluate(frameState, feature)).toEqual(5); + expect(expression.evaluate(feature)).toEqual(5); }); it('evaluates with defines, honoring order of operations', function() { @@ -144,13 +142,13 @@ defineSuite([ value: '1 + 2' }; var expression = new Expression('5.0 * ${value}', defines); - expect(expression.evaluate(frameState, undefined)).toEqual(15); + expect(expression.evaluate(undefined)).toEqual(15); }); it('evaluate takes result argument', function() { var expression = new Expression('vec3(1.0)'); var result = new Cartesian3(); - var value = expression.evaluate(frameState, undefined, result); + var value = expression.evaluate(undefined, result); expect(value).toEqual(new Cartesian3(1.0, 1.0, 1.0)); expect(value).toBe(result); }); @@ -158,7 +156,7 @@ defineSuite([ it('evaluate takes a color result argument', function() { var expression = new Expression('color("red")'); var result = new Color(); - var value = expression.evaluate(frameState, undefined, result); + var value = expression.evaluate(undefined, result); expect(value).toEqual(Color.RED); expect(value).toBe(result); }); @@ -249,180 +247,180 @@ defineSuite([ it('evaluates literal null', function() { var expression = new Expression('null'); - expect(expression.evaluate(frameState, undefined)).toEqual(null); + expect(expression.evaluate(undefined)).toEqual(null); }); it('evaluates literal undefined', function() { var expression = new Expression('undefined'); - expect(expression.evaluate(frameState, undefined)).toEqual(undefined); + expect(expression.evaluate(undefined)).toEqual(undefined); }); it('evaluates literal boolean', function() { var expression = new Expression('true'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('false'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('converts to literal boolean', function() { var expression = new Expression('Boolean()'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('Boolean(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('Boolean("true")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('evaluates literal number', function() { var expression = new Expression('1'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('0'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('NaN'); - expect(expression.evaluate(frameState, undefined)).toEqual(NaN); + expect(expression.evaluate(undefined)).toEqual(NaN); expression = new Expression('Infinity'); - expect(expression.evaluate(frameState, undefined)).toEqual(Infinity); + expect(expression.evaluate(undefined)).toEqual(Infinity); }); it('evaluates math constants', function() { var expression = new Expression('Math.PI'); - expect(expression.evaluate(frameState, undefined)).toEqual(Math.PI); + expect(expression.evaluate(undefined)).toEqual(Math.PI); expression = new Expression('Math.E'); - expect(expression.evaluate(frameState, undefined)).toEqual(Math.E); + expect(expression.evaluate(undefined)).toEqual(Math.E); }); it('evaluates number constants', function() { var expression = new Expression('Number.POSITIVE_INFINITY'); - expect(expression.evaluate(frameState, undefined)).toEqual(Number.POSITIVE_INFINITY); + expect(expression.evaluate(undefined)).toEqual(Number.POSITIVE_INFINITY); }); it('converts to literal number', function() { var expression = new Expression('Number()'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('Number("1")'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('Number(true)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); }); it('evaluates literal string', function() { var expression = new Expression('\'hello\''); - expect(expression.evaluate(frameState, undefined)).toEqual('hello'); + expect(expression.evaluate(undefined)).toEqual('hello'); expression = new Expression('\'Cesium\''); - expect(expression.evaluate(frameState, undefined)).toEqual('Cesium'); + expect(expression.evaluate(undefined)).toEqual('Cesium'); expression = new Expression('"Cesium"'); - expect(expression.evaluate(frameState, undefined)).toEqual('Cesium'); + expect(expression.evaluate(undefined)).toEqual('Cesium'); }); it('converts to literal string', function() { var expression = new Expression('String()'); - expect(expression.evaluate(frameState, undefined)).toEqual(''); + expect(expression.evaluate(undefined)).toEqual(''); expression = new Expression('String(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual('1'); + expect(expression.evaluate(undefined)).toEqual('1'); expression = new Expression('String(true)'); - expect(expression.evaluate(frameState, undefined)).toEqual('true'); + expect(expression.evaluate(undefined)).toEqual('true'); }); it('evaluates literal color', function() { var expression = new Expression('color(\'#ffffff\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(\'#00FFFF\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); expression = new Expression('color(\'#fff\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(\'#0FF\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); expression = new Expression('color(\'white\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(\'cyan\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.CYAN)); expression = new Expression('color(\'white\', 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromAlpha(Color.WHITE, 0.5))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromAlpha(Color.WHITE, 0.5))); expression = new Expression('rgb(255, 255, 255)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('rgb(100, 255, 190)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 255, 190))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 255, 190))); expression = new Expression('hsl(0, 0, 1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('hsl(1.0, 0.6, 0.7)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromHsl(1.0, 0.6, 0.7))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromHsl(1.0, 0.6, 0.7))); expression = new Expression('rgba(255, 255, 255, 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromAlpha(Color.WHITE, 0.5))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromAlpha(Color.WHITE, 0.5))); expression = new Expression('rgba(100, 255, 190, 0.25)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 255, 190, 0.25 * 255))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 255, 190, 0.25 * 255))); expression = new Expression('hsla(0, 0, 1, 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(new Color(1.0, 1.0, 1.0, 0.5))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(new Color(1.0, 1.0, 1.0, 0.5))); expression = new Expression('hsla(1.0, 0.6, 0.7, 0.75)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.fromHsl(1.0, 0.6, 0.7, 0.75))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.fromHsl(1.0, 0.6, 0.7, 0.75))); expression = new Expression('color()'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); }); it('evaluates literal color with result parameter', function() { var color = new Color(); var expression = new Expression('color(\'#0000ff\')'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.BLUE); + expect(expression.evaluate(undefined, color)).toEqual(Color.BLUE); expect(color).toEqual(Color.BLUE); expression = new Expression('color(\'#f00\')'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.RED); + expect(expression.evaluate(undefined, color)).toEqual(Color.RED); expect(color).toEqual(Color.RED); expression = new Expression('color(\'cyan\')'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.CYAN); + expect(expression.evaluate(undefined, color)).toEqual(Color.CYAN); expect(color).toEqual(Color.CYAN); expression = new Expression('color(\'white\', 0.5)'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); + expect(expression.evaluate(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); expression = new Expression('rgb(0, 0, 0)'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.BLACK); + expect(expression.evaluate(undefined, color)).toEqual(Color.BLACK); expect(color).toEqual(Color.BLACK); expression = new Expression('hsl(0, 0, 1)'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.WHITE); + expect(expression.evaluate(undefined, color)).toEqual(Color.WHITE); expect(color).toEqual(Color.WHITE); expression = new Expression('rgba(255, 0, 255, 0.5)'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(new Color(1.0, 0, 1.0, 0.5)); + expect(expression.evaluate(undefined, color)).toEqual(new Color(1.0, 0, 1.0, 0.5)); expect(color).toEqual(new Color(1.0, 0, 1.0, 0.5)); expression = new Expression('hsla(0, 0, 1, 0.5)'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); + expect(expression.evaluate(undefined, color)).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); expect(color).toEqual(new Color(1.0, 1.0, 1.0, 0.5)); expression = new Expression('color()'); - expect(expression.evaluate(frameState, undefined, color)).toEqual(Color.WHITE); + expect(expression.evaluate(undefined, color)).toEqual(Color.WHITE); expect(color).toEqual(Color.WHITE); }); @@ -434,19 +432,19 @@ defineSuite([ feature.addProperty('alpha', 0.2); var expression = new Expression('color(${hex6})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(${hex3})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(${keyword})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('color(${keyword}, ${alpha} + 0.6)'); - expect(expression.evaluate(frameState, feature).x).toEqual(1.0); - expect(expression.evaluate(frameState, feature).y).toEqual(1.0); - expect(expression.evaluate(frameState, feature).z).toEqual(1.0); - expect(expression.evaluate(frameState, feature).w).toEqual(0.8); + expect(expression.evaluate(feature).x).toEqual(1.0); + expect(expression.evaluate(feature).y).toEqual(1.0); + expect(expression.evaluate(feature).z).toEqual(1.0); + expect(expression.evaluate(feature).w).toEqual(0.8); }); it('evaluates rgb with expressions as arguments', function() { @@ -456,10 +454,10 @@ defineSuite([ feature.addProperty('blue', 255); var expression = new Expression('rgb(${red}, ${green}, ${blue})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255))); expression = new Expression('rgb(${red}/2, ${green}/2, ${blue})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255))); }); it('evaluates hsl with expressions as arguments', function() { @@ -469,10 +467,10 @@ defineSuite([ feature.addProperty('l', 1.0); var expression = new Expression('hsl(${h}, ${s}, ${l})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('hsl(${h} + 0.2, ${s} + 1.0, ${l} - 0.5)'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromHsl(0.2, 1.0, 0.5))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromHsl(0.2, 1.0, 0.5))); }); it('evaluates rgba with expressions as arguments', function() { @@ -483,10 +481,10 @@ defineSuite([ feature.addProperty('a', 0.3); var expression = new Expression('rgba(${red}, ${green}, ${blue}, ${a})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255, 0.3*255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255, 0.3*255))); expression = new Expression('rgba(${red}/2, ${green}/2, ${blue}, ${a} * 2)'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255, 0.6*255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255, 0.6*255))); }); it('evaluates hsla with expressions as arguments', function() { @@ -497,10 +495,10 @@ defineSuite([ feature.addProperty('a', 1.0); var expression = new Expression('hsla(${h}, ${s}, ${l}, ${a})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('hsla(${h} + 0.2, ${s} + 1.0, ${l} - 0.5, ${a} / 4)'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromHsl(0.2, 1.0, 0.5, 0.25))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromHsl(0.2, 1.0, 0.5, 0.25))); }); it('evaluates rgba with expressions as arguments', function() { @@ -511,10 +509,10 @@ defineSuite([ feature.addProperty('alpha', 0.5); var expression = new Expression('rgba(${red}, ${green}, ${blue}, ${alpha})'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255, 0.5 * 255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(100, 200, 255, 0.5 * 255))); expression = new Expression('rgba(${red}/2, ${green}/2, ${blue}, ${alpha} + 0.1)'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255, 0.6 * 255))); + expect(expression.evaluate(feature)).toEqual(Cartesian4.fromColor(Color.fromBytes(50, 100, 255, 0.6 * 255))); }); it('color constructors throw with wrong number of arguments', function() { @@ -537,226 +535,226 @@ defineSuite([ it('evaluates color properties (r, g, b, a)', function() { var expression = new Expression('color(\'#ffffff\').r'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgb(255, 255, 0).g'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('color("cyan").b'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgba(255, 255, 0, 0.5).a'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); }); it('evaluates color properties (x, y, z, w)', function() { var expression = new Expression('color(\'#ffffff\').x'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgb(255, 255, 0).y'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('color("cyan").z'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgba(255, 255, 0, 0.5).w'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); }); it('evaluates color properties ([0], [1], [2]. [3])', function() { var expression = new Expression('color(\'#ffffff\')[0]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgb(255, 255, 0)[1]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('color("cyan")[2]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgba(255, 255, 0, 0.5)[3]'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); }); it('evaluates color properties (["r"], ["g"], ["b"], ["a"])', function() { var expression = new Expression('color(\'#ffffff\')["r"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgb(255, 255, 0)["g"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('color("cyan")["b"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgba(255, 255, 0, 0.5)["a"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); }); it('evaluates color properties (["x"], ["y"], ["z"], ["w"])', function() { var expression = new Expression('color(\'#ffffff\')["x"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgb(255, 255, 0)["y"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('color("cyan")["z"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('rgba(255, 255, 0, 0.5)["w"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); }); it('evaluates vec2', function() { var expression = new Expression('vec2(2.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(2.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(2.0, 2.0)); expression = new Expression('vec2(3.0, 4.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3.0, 4.0)); expression = new Expression('vec2(vec2(3.0, 4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3.0, 4.0)); expression = new Expression('vec2(vec3(3.0, 4.0, 5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3.0, 4.0)); expression = new Expression('vec2(vec4(3.0, 4.0, 5.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3.0, 4.0)); }); it('throws if vec2 has invalid number of arguments', function() { var expression = new Expression('vec2()'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec2(3.0, 4.0, 5.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec2(vec2(3.0, 4.0), 5.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('throws if vec2 has invalid argument', function() { var expression = new Expression('vec2("1")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates vec3', function() { var expression = new Expression('vec3(2.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(2.0, 2.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(2.0, 2.0, 2.0)); expression = new Expression('vec3(3.0, 4.0, 5.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); expression = new Expression('vec3(vec2(3.0, 4.0), 5.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); expression = new Expression('vec3(3.0, vec2(4.0, 5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); expression = new Expression('vec3(vec3(3.0, 4.0, 5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); expression = new Expression('vec3(vec4(3.0, 4.0, 5.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, 4.0, 5.0)); }); it ('throws if vec3 has invalid number of arguments', function() { var expression = new Expression('vec3()'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec3(3.0, 4.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec3(3.0, 4.0, 5.0, 6.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec3(vec2(3.0, 4.0), vec2(5.0, 6.0))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec3(vec4(3.0, 4.0, 5.0, 6.0), 1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('throws if vec3 has invalid argument', function() { var expression = new Expression('vec3(1.0, "1.0", 2.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates vec4', function() { var expression = new Expression('vec4(2.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2.0, 2.0, 2.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(2.0, 2.0, 2.0, 2.0)); expression = new Expression('vec4(3.0, 4.0, 5.0, 6.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(vec2(3.0, 4.0), 5.0, 6.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(3.0, vec2(4.0, 5.0), 6.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(3.0, 4.0, vec2(5.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(vec3(3.0, 4.0, 5.0), 6.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(3.0, vec3(4.0, 5.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); expression = new Expression('vec4(vec4(3.0, 4.0, 5.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3.0, 4.0, 5.0, 6.0)); }); it ('throws if vec4 has invalid number of arguments', function() { var expression = new Expression('vec4()'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec4(3.0, 4.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec4(3.0, 4.0, 5.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec4(3.0, 4.0, 5.0, 6.0, 7.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec4(vec3(3.0, 4.0, 5.0))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('throws if vec4 has invalid argument', function() { var expression = new Expression('vec4(1.0, "2.0", 3.0, 4.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -768,653 +766,653 @@ defineSuite([ feature.addProperty('scale', 1); var expression = new Expression('vec4(${height}, ${width}, ${depth}, ${scale})'); - expect(expression.evaluate(frameState, feature)).toEqual(new Cartesian4(2.0, 4.0, 3.0, 1.0)); + expect(expression.evaluate(feature)).toEqual(new Cartesian4(2.0, 4.0, 3.0, 1.0)); }); it('evaluates expression with multiple nested vectors', function() { var expression = new Expression('vec4(vec2(1, 2)[vec3(6, 1, 5).y], 2, vec4(1.0).w, 5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2.0, 2.0, 1.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(2.0, 2.0, 1.0, 5.0)); }); it('evaluates vector properties (x, y, z, w)', function() { var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).x'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).y'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).z'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).w'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); }); it('evaluates vector properties (r, g, b, a)', function() { var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).r'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).g'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).b'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0).a'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); }); it('evaluates vector properties ([0], [1], [2], [3])', function() { var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[0]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[1]'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[2]'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)[3]'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); }); it('evaluates vector properties (["x"], ["y"], ["z"]. ["w"])', function() { var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["x"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["y"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["z"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["w"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); }); it('evaluates vector properties (["r"], ["g"], ["b"]. ["a"])', function() { var expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["r"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["g"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["b"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('vec4(1.0, 2.0, 3.0, 4.0)["a"]'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); }); it('evaluates unary not', function() { var expression = new Expression('!true'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('!!true'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('throws if unary not takes invalid argument', function() { var expression = new Expression('!"true"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates unary negative', function() { var expression = new Expression('-5'); - expect(expression.evaluate(frameState, undefined)).toEqual(-5); + expect(expression.evaluate(undefined)).toEqual(-5); expression = new Expression('-(-5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(5); + expect(expression.evaluate(undefined)).toEqual(5); }); it('throws if unary negative takes invalid argument', function() { var expression = new Expression('-"56"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates unary positive', function() { var expression = new Expression('+5'); - expect(expression.evaluate(frameState, undefined)).toEqual(5); + expect(expression.evaluate(undefined)).toEqual(5); }); it('throws if unary positive takes invalid argument', function() { var expression = new Expression('+"56"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary addition', function() { var expression = new Expression('1 + 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(3); + expect(expression.evaluate(undefined)).toEqual(3); expression = new Expression('1 + 2 + 3 + 4'); - expect(expression.evaluate(frameState, undefined)).toEqual(10); + expect(expression.evaluate(undefined)).toEqual(10); }); it('evaluates binary addition with strings', function() { var expression = new Expression('1 + "10"'); - expect(expression.evaluate(frameState, undefined)).toEqual('110'); + expect(expression.evaluate(undefined)).toEqual('110'); expression = new Expression('"10" + 1'); - expect(expression.evaluate(frameState, undefined)).toEqual('101'); + expect(expression.evaluate(undefined)).toEqual('101'); expression = new Expression('"name_" + "building"'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_building'); + expect(expression.evaluate(undefined)).toEqual('name_building'); expression = new Expression('"name_" + true'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_true'); + expect(expression.evaluate(undefined)).toEqual('name_true'); expression = new Expression('"name_" + null'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_null'); + expect(expression.evaluate(undefined)).toEqual('name_null'); expression = new Expression('"name_" + undefined'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_undefined'); + expect(expression.evaluate(undefined)).toEqual('name_undefined'); expression = new Expression('"name_" + vec2(1.1)'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_(1.1, 1.1)'); + expect(expression.evaluate(undefined)).toEqual('name_(1.1, 1.1)'); expression = new Expression('"name_" + vec3(1.1)'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_(1.1, 1.1, 1.1)'); + expect(expression.evaluate(undefined)).toEqual('name_(1.1, 1.1, 1.1)'); expression = new Expression('"name_" + vec4(1.1)'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_(1.1, 1.1, 1.1, 1.1)'); + expect(expression.evaluate(undefined)).toEqual('name_(1.1, 1.1, 1.1, 1.1)'); expression = new Expression('"name_" + regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual('name_/a/'); + expect(expression.evaluate(undefined)).toEqual('name_/a/'); }); it('throws if binary addition takes invalid arguments', function() { var expression = new Expression('vec2(1.0) + vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 + vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary subtraction', function() { var expression = new Expression('2 - 1'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('4 - 3 - 2 - 1'); - expect(expression.evaluate(frameState, undefined)).toEqual(-2); + expect(expression.evaluate(undefined)).toEqual(-2); }); it('throws if binary subtraction takes invalid arguments', function() { var expression = new Expression('vec2(1.0) - vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 - vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('"name1" - "name2"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary multiplication', function() { var expression = new Expression('1 * 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(2); + expect(expression.evaluate(undefined)).toEqual(2); expression = new Expression('1 * 2 * 3 * 4'); - expect(expression.evaluate(frameState, undefined)).toEqual(24); + expect(expression.evaluate(undefined)).toEqual(24); }); it('throws if binary multiplication takes invalid arguments', function() { var expression = new Expression('vec2(1.0) * vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec2(1.0) * "name"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary division', function() { var expression = new Expression('2 / 1'); - expect(expression.evaluate(frameState, undefined)).toEqual(2); + expect(expression.evaluate(undefined)).toEqual(2); expression = new Expression('1/2'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.5); + expect(expression.evaluate(undefined)).toEqual(0.5); expression = new Expression('24 / -4 / 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(-3); + expect(expression.evaluate(undefined)).toEqual(-3); }); it('throws if binary division takes invalid arguments', function() { var expression = new Expression('vec2(1.0) / vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec2(1.0) / "2.0"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 / vec4(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary modulus', function() { var expression = new Expression('2 % 1'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('6 % 4 % 3'); - expect(expression.evaluate(frameState, undefined)).toEqual(2); + expect(expression.evaluate(undefined)).toEqual(2); }); it('throws if binary modulus takes invalid arguments', function() { var expression = new Expression('vec2(1.0) % vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('vec2(1.0) % "2.0"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 % vec4(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary equals strict', function() { var expression = new Expression('\'hello\' === \'hello\''); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('1 === 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('false === true === false'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('1 === "1"'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('evaluates binary not equals strict', function() { var expression = new Expression('\'hello\' !== \'hello\''); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('1 !== 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('false !== true !== false'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('1 !== "1"'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('evaluates binary less than', function() { var expression = new Expression('2 < 3'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('2 < 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('3 < 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('throws if binary less than takes invalid arguments', function() { var expression = new Expression('vec2(1.0) < vec2(2.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 < vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('true < false'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('color(\'blue\') < 10'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary less than or equals', function() { var expression = new Expression('2 <= 3'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('2 <= 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('3 <= 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('throws if binary less than or equals takes invalid arguments', function() { var expression = new Expression('vec2(1.0) <= vec2(2.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 <= vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 <= "5"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('true <= false'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('color(\'blue\') <= 10'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary greater than', function() { var expression = new Expression('2 > 3'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('2 > 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('3 > 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('throws if binary greater than takes invalid arguments', function() { var expression = new Expression('vec2(1.0) > vec2(2.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 > vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 > "5"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('true > false'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('color(\'blue\') > 10'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates binary greater than or equals', function() { var expression = new Expression('2 >= 3'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('2 >= 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('3 >= 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('throws if binary greater than or equals takes invalid arguments', function() { var expression = new Expression('vec2(1.0) >= vec2(2.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 >= vec3(1.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1.0 >= "5"'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('true >= false'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('color(\'blue\') >= 10'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates logical and', function() { var expression = new Expression('false && false'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('false && true'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('true && true'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('2 && color(\'red\')'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('throws with invalid and operands', function() { var expression = new Expression('2 && true'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('true && color(\'red\')'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates logical or', function() { var expression = new Expression('false || false'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('false || true'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('true || true'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('throws with invalid or operands', function() { var expression = new Expression('2 || false'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('false || color(\'red\')'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates color operations', function() { var expression = new Expression('+rgba(255, 0, 0, 1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.RED)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.RED)); expression = new Expression('rgba(255, 0, 0, 0.5) + rgba(0, 0, 255, 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.MAGENTA)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.MAGENTA)); expression = new Expression('rgba(0, 255, 255, 1.0) - rgba(0, 255, 0, 0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.BLUE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.BLUE)); expression = new Expression('rgba(255, 255, 255, 1.0) * rgba(255, 0, 0, 1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.RED)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.RED)); expression = new Expression('rgba(255, 255, 0, 1.0) * 1.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.YELLOW)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.YELLOW)); expression = new Expression('1 * rgba(255, 255, 0, 1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.YELLOW)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.YELLOW)); expression = new Expression('rgba(255, 255, 255, 1.0) / rgba(255, 255, 255, 1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(Color.WHITE)); expression = new Expression('rgba(255, 255, 255, 1.0) / 2'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(new Color(0.5, 0.5, 0.5, 0.5))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(new Color(0.5, 0.5, 0.5, 0.5))); expression = new Expression('rgba(255, 255, 255, 1.0) % rgba(255, 255, 255, 1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(Cartesian4.fromColor(new Color(0, 0, 0, 0))); + expect(expression.evaluate(undefined)).toEqual(Cartesian4.fromColor(new Color(0, 0, 0, 0))); expression = new Expression('color(\'green\') === color(\'green\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('color(\'green\') !== color(\'green\')'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('evaluates vector operations', function() { var expression = new Expression('+vec2(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1, 2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1, 2)); expression = new Expression('+vec3(1, 2, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1, 2, 3)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1, 2, 3)); expression = new Expression('+vec4(1, 2, 3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1, 2, 3, 4)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1, 2, 3, 4)); expression = new Expression('-vec2(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-1, -2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(-1, -2)); expression = new Expression('-vec3(1, 2, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(-1, -2, -3)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(-1, -2, -3)); expression = new Expression('-vec4(1, 2, 3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-1, -2, -3, -4)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(-1, -2, -3, -4)); expression = new Expression('vec2(1, 2) + vec2(3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(4, 6)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(4, 6)); expression = new Expression('vec3(1, 2, 3) + vec3(3, 4, 5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(4, 6, 8)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(4, 6, 8)); expression = new Expression('vec4(1, 2, 3, 4) + vec4(3, 4, 5, 6)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(4, 6, 8, 10)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(4, 6, 8, 10)); expression = new Expression('vec2(1, 2) - vec2(3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-2, -2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(-2, -2)); expression = new Expression('vec3(1, 2, 3) - vec3(3, 4, 5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(-2, -2, -2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(-2, -2, -2)); expression = new Expression('vec4(1, 2, 3, 4) - vec4(3, 4, 5, 6)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-2, -2, -2, -2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(-2, -2, -2, -2)); expression = new Expression('vec2(1, 2) * vec2(3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 8)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3, 8)); expression = new Expression('vec2(1, 2) * 3.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 6)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3, 6)); expression = new Expression('3.0 * vec2(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(3, 6)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(3, 6)); expression = new Expression('vec3(1, 2, 3) * vec3(3, 4, 5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 8, 15)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3, 8, 15)); expression = new Expression('vec3(1, 2, 3) * 3.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 6, 9)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3, 6, 9)); expression = new Expression('3.0 * vec3(1, 2, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3, 6, 9)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3, 6, 9)); expression = new Expression('vec4(1, 2, 3, 4) * vec4(3, 4, 5, 6)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 8, 15, 24)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3, 8, 15, 24)); expression = new Expression('vec4(1, 2, 3, 4) * 3.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 6, 9, 12)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3, 6, 9, 12)); expression = new Expression('3.0 * vec4(1, 2, 3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(3, 6, 9, 12)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(3, 6, 9, 12)); expression = new Expression('vec2(1, 2) / vec2(2, 5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.5, 0.4)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.5, 0.4)); expression = new Expression('vec2(1, 2) / 2.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.5, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.5, 1.0)); expression = new Expression('vec3(1, 2, 3) / vec3(2, 5, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.5, 0.4, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.5, 0.4, 1.0)); expression = new Expression('vec3(1, 2, 3) / 2.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.5, 1.0, 1.5)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.5, 1.0, 1.5)); expression = new Expression('vec4(1, 2, 3, 4) / vec4(2, 5, 3, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.5, 0.4, 1.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0.5, 0.4, 1.0, 2.0)); expression = new Expression('vec4(1, 2, 3, 4) / 2.0'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.5, 1.0, 1.5, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0.5, 1.0, 1.5, 2.0)); expression = new Expression('vec2(2, 3) % vec2(3, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(2, 0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(2, 0)); expression = new Expression('vec3(2, 3, 4) % vec3(3, 3, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(2, 0, 1)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(2, 0, 1)); expression = new Expression('vec4(2, 3, 4, 5) % vec4(3, 3, 3, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2, 0, 1, 1)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(2, 0, 1, 1)); expression = new Expression('vec2(1, 2) === vec2(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('vec3(1, 2, 3) === vec3(1, 2, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('vec4(1, 2, 3, 4) === vec4(1, 2, 3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('vec2(1, 2) !== vec2(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('vec3(1, 2, 3) !== vec3(1, 2, 3)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('vec4(1, 2, 3, 4) !== vec4(1, 2, 3, 4)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('evaluates color toString function', function() { var expression = new Expression('color("red").toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('(1, 0, 0, 1)'); + expect(expression.evaluate(undefined)).toEqual('(1, 0, 0, 1)'); expression = new Expression('rgba(0, 0, 255, 0.5).toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('(0, 0, 1, 0.5)'); + expect(expression.evaluate(undefined)).toEqual('(0, 0, 1, 0.5)'); }); it('evaluates vector toString function', function() { @@ -1422,68 +1420,68 @@ defineSuite([ feature.addProperty('property', new Cartesian4(1, 2, 3, 4)); var expression = new Expression('vec2(1, 2).toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2)'); + expect(expression.evaluate(undefined)).toEqual('(1, 2)'); expression = new Expression('vec3(1, 2, 3).toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2, 3)'); + expect(expression.evaluate(undefined)).toEqual('(1, 2, 3)'); expression = new Expression('vec4(1, 2, 3, 4).toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('(1, 2, 3, 4)'); + expect(expression.evaluate(undefined)).toEqual('(1, 2, 3, 4)'); expression = new Expression('${property}.toString()'); - expect(expression.evaluate(frameState, feature)).toEqual('(1, 2, 3, 4)'); + expect(expression.evaluate(feature)).toEqual('(1, 2, 3, 4)'); }); it('evaluates isNaN function', function() { var expression = new Expression('isNaN()'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isNaN(NaN)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isNaN(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isNaN(Infinity)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isNaN(null)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isNaN(true)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isNaN("hello")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isNaN(color("white"))'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); }); it('evaluates isFinite function', function() { var expression = new Expression('isFinite()'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isFinite(NaN)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isFinite(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isFinite(Infinity)'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isFinite(null)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isFinite(true)'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('isFinite("hello")'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('isFinite(color("white"))'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); }); it('evaluates isExactClass function', function() { @@ -1491,10 +1489,10 @@ defineSuite([ feature.setClass('door'); var expression = new Expression('isExactClass("door")'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); expression = new Expression('isExactClass("roof")'); - expect(expression.evaluate(frameState, feature)).toEqual(false); + expect(expression.evaluate(feature)).toEqual(false); }); it('throws if isExactClass takes an invalid number of arguments', function() { @@ -1514,7 +1512,7 @@ defineSuite([ feature.setInheritedClass('building'); var expression = new Expression('isClass("door") && isClass("building")'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); }); it('throws if isClass takes an invalid number of arguments', function() { @@ -1531,7 +1529,7 @@ defineSuite([ var feature = new MockFeature(); feature.setClass('door'); var expression = new Expression('getExactClassName()'); - expect(expression.evaluate(frameState, feature)).toEqual('door'); + expect(expression.evaluate(feature)).toEqual('door'); }); it('throws if getExactClassName takes an invalid number of arguments', function() { @@ -1544,25 +1542,25 @@ defineSuite([ // Argument must be a number or vector var expression = new Expression('abs("-1")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates abs function', function() { var expression = new Expression('abs(-1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('abs(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('abs(vec2(-1.0, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, 1.0)); expression = new Expression('abs(vec3(-1.0, 1.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1.0, 1.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1.0, 1.0, 0.0)); expression = new Expression('abs(vec4(-1.0, 1.0, 0.0, -1.2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1.0, 1.0, 0.0, 1.2)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1.0, 1.0, 0.0, 1.2)); }); it('throws if abs function takes an invalid number of arguments', function() { @@ -1577,16 +1575,16 @@ defineSuite([ it('evaluates cos function', function() { var expression = new Expression('cos(0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('cos(vec2(0, Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(1.0, -1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(1.0, -1.0), CesiumMath.EPSILON7); expression = new Expression('cos(vec3(0, Math.PI, -Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(1.0, -1.0, -1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(1.0, -1.0, -1.0), CesiumMath.EPSILON7); expression = new Expression('cos(vec4(0, Math.PI, -Math.PI, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(1.0, -1.0, -1.0, 1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(1.0, -1.0, -1.0, 1.0), CesiumMath.EPSILON7); }); it('throws if cos function takes an invalid number of arguments', function() { @@ -1601,16 +1599,16 @@ defineSuite([ it('evaluates sin function', function() { var expression = new Expression('sin(0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('sin(vec2(0, Math.PI/2))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(0.0, 1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(0.0, 1.0), CesiumMath.EPSILON7); expression = new Expression('sin(vec3(0, Math.PI/2, -Math.PI/2))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(0.0, 1.0, -1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(0.0, 1.0, -1.0), CesiumMath.EPSILON7); expression = new Expression('sin(vec4(0, Math.PI/2, -Math.PI/2, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(0.0, 1.0, -1.0, 0.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(0.0, 1.0, -1.0, 0.0), CesiumMath.EPSILON7); }); it('throws if sin function takes an invalid number of arguments', function() { @@ -1625,16 +1623,16 @@ defineSuite([ it('evaluates tan function', function() { var expression = new Expression('tan(0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('tan(vec2(0, Math.PI/4))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(0.0, 1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(0.0, 1.0), CesiumMath.EPSILON7); expression = new Expression('tan(vec3(0, Math.PI/4, Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(0.0, 1.0, 0.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(0.0, 1.0, 0.0), CesiumMath.EPSILON7); expression = new Expression('tan(vec4(0, Math.PI/4, Math.PI, -Math.PI/4))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(0.0, 1.0, 0.0, -1.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(0.0, 1.0, 0.0, -1.0), CesiumMath.EPSILON7); }); it('throws if tan function takes an invalid number of arguments', function() { @@ -1649,16 +1647,16 @@ defineSuite([ it('evaluates acos function', function() { var expression = new Expression('acos(1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('acos(vec2(1, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); expression = new Expression('acos(vec3(1, 0, 1))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); expression = new Expression('acos(vec4(1, 0, 1, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO, 0.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO, 0.0), CesiumMath.EPSILON7); }); it('throws if acos function takes an invalid number of arguments', function() { @@ -1673,16 +1671,16 @@ defineSuite([ it('evaluates asin function', function() { var expression = new Expression('asin(0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('asin(vec2(0, 1))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); expression = new Expression('asin(vec3(0, 1, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); expression = new Expression('asin(vec4(0, 1, 0, 1))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO, 0.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_TWO, 0.0, CesiumMath.PI_OVER_TWO, 0.0), CesiumMath.EPSILON7); }); it('throws if asin function takes an invalid number of arguments', function() { @@ -1697,16 +1695,16 @@ defineSuite([ it('evaluates atan function', function() { var expression = new Expression('atan(0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('atan(vec2(0, 1))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_FOUR), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(0.0, CesiumMath.PI_OVER_FOUR), CesiumMath.EPSILON7); expression = new Expression('atan(vec3(0, 1, 0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_FOUR, 0.0, CesiumMath.PI_OVER_FOUR), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(0.0, CesiumMath.PI_OVER_FOUR, 0.0, CesiumMath.PI_OVER_FOUR), CesiumMath.EPSILON7); expression = new Expression('atan(vec4(0, 1, 0, 1))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_FOUR, 0.0, CesiumMath.PI_OVER_FOUR, 0.0), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(0.0, CesiumMath.PI_OVER_FOUR, 0.0, CesiumMath.PI_OVER_FOUR, 0.0), CesiumMath.EPSILON7); }); it('throws if atan function takes an invalid number of arguments', function() { @@ -1721,16 +1719,16 @@ defineSuite([ it('evaluates radians function', function() { var expression = new Expression('radians(180)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(Math.PI, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(Math.PI, CesiumMath.EPSILON10); expression = new Expression('radians(vec2(180, 90))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(Math.PI, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(Math.PI, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); expression = new Expression('radians(vec3(180, 90, 180))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(Math.PI, CesiumMath.PI_OVER_TWO, Math.PI), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(Math.PI, CesiumMath.PI_OVER_TWO, Math.PI), CesiumMath.EPSILON7); expression = new Expression('radians(vec4(180, 90, 180, 90))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(Math.PI, CesiumMath.PI_OVER_TWO, Math.PI, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(Math.PI, CesiumMath.PI_OVER_TWO, Math.PI, CesiumMath.PI_OVER_TWO), CesiumMath.EPSILON7); }); it('throws if radians function takes an invalid number of arguments', function() { @@ -1745,16 +1743,16 @@ defineSuite([ it('evaluates degrees function', function() { var expression = new Expression('degrees(2 * Math.PI)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(360, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(360, CesiumMath.EPSILON10); expression = new Expression('degrees(vec2(2 * Math.PI, Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(360, 180), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(360, 180), CesiumMath.EPSILON7); expression = new Expression('degrees(vec3(2 * Math.PI, Math.PI, 2 * Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(360, 180, 360), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(360, 180, 360), CesiumMath.EPSILON7); expression = new Expression('degrees(vec4(2 * Math.PI, Math.PI, 2 * Math.PI, Math.PI))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(360, 180, 360, 180), CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(360, 180, 360, 180), CesiumMath.EPSILON7); }); it('throws if degrees function takes an invalid number of arguments', function() { @@ -1769,22 +1767,22 @@ defineSuite([ it('evaluates sqrt function', function() { var expression = new Expression('sqrt(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('sqrt(4.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('sqrt(-1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(NaN); + expect(expression.evaluate(undefined)).toEqual(NaN); expression = new Expression('sqrt(vec2(1.0, 4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, 2.0)); expression = new Expression('sqrt(vec3(1.0, 4.0, 9.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1.0, 2.0, 3.0)); expression = new Expression('sqrt(vec4(1.0, 4.0, 9.0, 16.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1.0, 2.0, 3.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1.0, 2.0, 3.0, 4.0)); }); it('throws if sqrt function takes an invalid number of arguments', function() { @@ -1799,22 +1797,22 @@ defineSuite([ it('evaluates sign function', function() { var expression = new Expression('sign(5.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('sign(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('sign(-5.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(-1.0); + expect(expression.evaluate(undefined)).toEqual(-1.0); expression = new Expression('sign(vec2(5.0, -5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, -1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, -1.0)); expression = new Expression('sign(vec3(5.0, -5.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1.0, -1.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1.0, -1.0, 0.0)); expression = new Expression('sign(vec4(5.0, -5.0, 0.0, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1.0, -1.0, 0.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1.0, -1.0, 0.0, 1.0)); }); it('throws if sign function takes an invalid number of arguments', function() { @@ -1829,22 +1827,22 @@ defineSuite([ it('evaluates floor function', function() { var expression = new Expression('floor(5.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(5.0); + expect(expression.evaluate(undefined)).toEqual(5.0); expression = new Expression('floor(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('floor(-1.2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(-2.0); + expect(expression.evaluate(undefined)).toEqual(-2.0); expression = new Expression('floor(vec2(5.5, -1.2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(5.0, -2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(5.0, -2.0)); expression = new Expression('floor(vec3(5.5, -1.2, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(5.0, -2.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(5.0, -2.0, 0.0)); expression = new Expression('floor(vec4(5.5, -1.2, 0.0, -2.9))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(5.0, -2.0, 0.0, -3.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(5.0, -2.0, 0.0, -3.0)); }); it('throws if floor function takes an invalid number of arguments', function() { @@ -1859,22 +1857,22 @@ defineSuite([ it('evaluates ceil function', function() { var expression = new Expression('ceil(5.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(6.0); + expect(expression.evaluate(undefined)).toEqual(6.0); expression = new Expression('ceil(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('ceil(-1.2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(-1.0); + expect(expression.evaluate(undefined)).toEqual(-1.0); expression = new Expression('ceil(vec2(5.5, -1.2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(6.0, -1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(6.0, -1.0)); expression = new Expression('ceil(vec3(5.5, -1.2, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(6.0, -1.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(6.0, -1.0, 0.0)); expression = new Expression('ceil(vec4(5.5, -1.2, 0.0, -2.9))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(6.0, -1.0, 0.0, -2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(6.0, -1.0, 0.0, -2.0)); }); it('throws if ceil function takes an invalid number of arguments', function() { @@ -1889,22 +1887,22 @@ defineSuite([ it('evaluates round function', function() { var expression = new Expression('round(5.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(6); + expect(expression.evaluate(undefined)).toEqual(6); expression = new Expression('round(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0); + expect(expression.evaluate(undefined)).toEqual(0); expression = new Expression('round(1.2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1); + expect(expression.evaluate(undefined)).toEqual(1); expression = new Expression('round(vec2(5.5, -1.2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(6.0, -1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(6.0, -1.0)); expression = new Expression('round(vec3(5.5, -1.2, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(6.0, -1.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(6.0, -1.0, 0.0)); expression = new Expression('round(vec4(5.5, -1.2, 0.0, -2.9))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(6.0, -1.0, 0.0, -3.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(6.0, -1.0, 0.0, -3.0)); }); it('throws if round function takes an invalid number of arguments', function() { @@ -1919,19 +1917,19 @@ defineSuite([ it('evaluates exp function', function() { var expression = new Expression('exp(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(Math.E, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(Math.E, CesiumMath.EPSILON10); expression = new Expression('exp(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(1.0, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(1.0, CesiumMath.EPSILON10); expression = new Expression('exp(vec2(1.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian2(Math.E, 1.0), CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian2(Math.E, 1.0), CesiumMath.EPSILON10); expression = new Expression('exp(vec3(1.0, 0.0, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(Math.E, 1.0, Math.E), CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(Math.E, 1.0, Math.E), CesiumMath.EPSILON10); expression = new Expression('exp(vec4(1.0, 0.0, 1.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian4(Math.E, 1.0, Math.E, 1.0), CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian4(Math.E, 1.0, Math.E, 1.0), CesiumMath.EPSILON10); }); it('throws if exp function takes an invalid number of arguments', function() { @@ -1946,22 +1944,22 @@ defineSuite([ it('evaluates exp2 function', function() { var expression = new Expression('exp2(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('exp2(0.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('exp2(2.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); expression = new Expression('exp2(vec2(1.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(2.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(2.0, 1.0)); expression = new Expression('exp2(vec3(1.0, 0.0, 2.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(2.0, 1.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(2.0, 1.0, 4.0)); expression = new Expression('exp2(vec4(1.0, 0.0, 2.0, 3.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(2.0, 1.0, 4.0, 8.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(2.0, 1.0, 4.0, 8.0)); }); it('throws if exp2 function takes an invalid number of arguments', function() { @@ -1976,19 +1974,19 @@ defineSuite([ it('evaluates log function', function() { var expression = new Expression('log(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('log(10.0)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(2.302585092994046, CesiumMath.EPSILON7); + expect(expression.evaluate(undefined)).toEqualEpsilon(2.302585092994046, CesiumMath.EPSILON7); expression = new Expression('log(vec2(1.0, Math.E))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.0, 1.0)); expression = new Expression('log(vec3(1.0, Math.E, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.0, 1.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.0, 1.0, 0.0)); expression = new Expression('log(vec4(1.0, Math.E, 1.0, Math.E))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.0, 1.0, 0.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0.0, 1.0, 0.0, 1.0)); }); it('throws if log function takes an invalid number of arguments', function() { @@ -2003,22 +2001,22 @@ defineSuite([ it('evaluates log2 function', function() { var expression = new Expression('log2(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('log2(2.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('log2(4.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('log2(vec2(1.0, 2.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.0, 1.0)); expression = new Expression('log2(vec3(1.0, 2.0, 4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.0, 1.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.0, 1.0, 2.0)); expression = new Expression('log2(vec4(1.0, 2.0, 4.0, 8.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.0, 1.0, 2.0, 3.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0.0, 1.0, 2.0, 3.0)); }); it('throws if log2 function takes an invalid number of arguments', function() { @@ -2033,22 +2031,22 @@ defineSuite([ it('evaluates fract function', function() { var expression = new Expression('fract(1.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('fract(2.25)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.25); + expect(expression.evaluate(undefined)).toEqual(0.25); expression = new Expression('fract(-2.25)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.75); + expect(expression.evaluate(undefined)).toEqual(0.75); expression = new Expression('fract(vec2(1.0, 2.25))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.0, 0.25)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.0, 0.25)); expression = new Expression('fract(vec3(1.0, 2.25, -2.25))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.0, 0.25, 0.75)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.0, 0.25, 0.75)); expression = new Expression('fract(vec4(1.0, 2.25, -2.25, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0.0, 0.25, 0.75, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0.0, 0.25, 0.75, 0.0)); }); it('throws if fract function takes an invalid number of arguments', function() { @@ -2063,16 +2061,16 @@ defineSuite([ it('evaluates length function', function() { var expression = new Expression('length(-3.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('length(vec2(-3.0, 4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(5.0); + expect(expression.evaluate(undefined)).toEqual(5.0); expression = new Expression('length(vec3(2.0, 3.0, 6.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(7.0); + expect(expression.evaluate(undefined)).toEqual(7.0); expression = new Expression('length(vec4(2.0, 4.0, 7.0, 10.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(13.0); + expect(expression.evaluate(undefined)).toEqual(13.0); }); it('throws if length function takes an invalid number of arguments', function() { @@ -2087,18 +2085,18 @@ defineSuite([ it('evaluates normalize function', function() { var expression = new Expression('normalize(5.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('normalize(vec2(3.0, 4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0.6, 0.8)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0.6, 0.8)); expression = new Expression('normalize(vec3(2.0, 3.0, -4.0))'); var length = Math.sqrt(2 * 2 + 3 * 3 + 4 * 4); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(new Cartesian3(2.0 / length, 3.0 / length, -4.0 / length), CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(new Cartesian3(2.0 / length, 3.0 / length, -4.0 / length), CesiumMath.EPSILON10); expression = new Expression('normalize(vec4(-2.0, 3.0, -4.0, 5.0))'); length = Math.sqrt(2 * 2 + 3 * 3 + 4 * 4 + 5 * 5); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-2.0 / length, 3.0 / length, -4.0 / length, 5.0/length), CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(-2.0 / length, 3.0 / length, -4.0 / length, 5.0/length), CesiumMath.EPSILON10); }); it('throws if normalize function takes an invalid number of arguments', function() { @@ -2113,25 +2111,25 @@ defineSuite([ it('evaluates clamp function', function() { var expression = new Expression('clamp(50.0, 0.0, 100.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(50.0); + expect(expression.evaluate(undefined)).toEqual(50.0); expression = new Expression('clamp(50.0, 0.0, 25.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(25.0); + expect(expression.evaluate(undefined)).toEqual(25.0); expression = new Expression('clamp(50.0, 75.0, 100.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(75.0); + expect(expression.evaluate(undefined)).toEqual(75.0); expression = new Expression('clamp(vec2(50.0,50.0), vec2(0.0,75.0), 100.0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(50.0, 75.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(50.0, 75.0)); expression = new Expression('clamp(vec2(50.0,50.0), vec2(0.0,75.0), vec2(25.0,100.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(25.0, 75.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(25.0, 75.0)); expression = new Expression('clamp(vec3(50.0, 50.0, 50.0), vec3(0.0, 0.0, 75.0), vec3(100.0, 25.0, 100.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(50.0, 25.0, 75.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(50.0, 25.0, 75.0)); expression = new Expression('clamp(vec4(50.0, 50.0, 50.0, 100.0), vec4(0.0, 0.0, 75.0, 75.0), vec4(100.0, 25.0, 100.0, 85.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(50.0, 25.0, 75.0, 85.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(50.0, 25.0, 75.0, 85.0)); }); it('throws if clamp function takes an invalid number of arguments', function() { @@ -2155,51 +2153,51 @@ defineSuite([ it('throws if clamp function takes mismatching types', function() { var expression = new Expression('clamp(0.0,vec2(0,1),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('clamp(vec2(0,1),vec3(0,1,2),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('clamp(vec2(0,1),vec2(0,1), vec3(1,2,3))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates mix function', function() { var expression = new Expression('mix(0.0, 2.0, 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('mix(vec2(0.0,1.0), vec2(2.0,3.0), 0.5)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, 2.0)); expression = new Expression('mix(vec2(0.0,1.0), vec2(2.0,3.0), vec2(0.5,4.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, 9.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, 9.0)); expression = new Expression('mix(vec3(0.0,1.0,2.0), vec3(2.0,3.0,4.0), vec3(0.5,4.0,5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1.0, 9.0, 12.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1.0, 9.0, 12.0)); expression = new Expression('mix(vec4(0.0,1.0,2.0,1.5), vec4(2.0,3.0,4.0,2.5), vec4(0.5,4.0,5.0,3.5))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1.0, 9.0, 12.0, 5.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1.0, 9.0, 12.0, 5.0)); }); it('throws if mix function takes mismatching types', function() { var expression = new Expression('mix(0.0,vec2(0,1),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('mix(vec2(0,1),vec3(0,1,2),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('mix(vec2(0,1),vec2(0,1), vec3(1,2,3))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -2223,21 +2221,21 @@ defineSuite([ it('evaluates atan2 function', function() { var expression = new Expression('atan2(0,1)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(0.0, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(0.0, CesiumMath.EPSILON10); expression = new Expression('atan2(1,0)'); - expect(expression.evaluate(frameState, undefined)).toEqualEpsilon(0.5 * Math.PI, CesiumMath.EPSILON10); + expect(expression.evaluate(undefined)).toEqualEpsilon(0.5 * Math.PI, CesiumMath.EPSILON10); expression = new Expression('atan2(vec2(0,1),vec2(1,0))'); - expect(expression.evaluate(frameState, undefined)) + expect(expression.evaluate(undefined)) .toEqualEpsilon(new Cartesian2(0.0, 0.5 * Math.PI), CesiumMath.EPSILON10); expression = new Expression('atan2(vec3(0,1,0.5),vec3(1,0,0.5))'); - expect(expression.evaluate(frameState, undefined)) + expect(expression.evaluate(undefined)) .toEqualEpsilon(new Cartesian3(0.0, 0.5 * Math.PI, 0.25 * Math.PI), CesiumMath.EPSILON10); expression = new Expression('atan2(vec4(0,1,0.5,1),vec4(1,0,0.5,0))'); - expect(expression.evaluate(frameState, undefined)) + expect(expression.evaluate(undefined)) .toEqualEpsilon(new Cartesian4(0.0, 0.5 * Math.PI, 0.25 * Math.PI, 0.5 * Math.PI), CesiumMath.EPSILON10); }); @@ -2254,35 +2252,35 @@ defineSuite([ it('throws if atan2 function takes mismatching types', function() { var expression = new Expression('atan2(0.0,vec2(0,1))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('atan2(vec2(0,1),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('atan2(vec2(0,1),vec3(0,1,2))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates pow function', function() { var expression = new Expression('pow(5,0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('pow(4,2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(16.0); + expect(expression.evaluate(undefined)).toEqual(16.0); expression = new Expression('pow(vec2(5,4),vec2(0,2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(1.0, 16.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(1.0, 16.0)); expression = new Expression('pow(vec3(5,4,3),vec3(0,2,3))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(1.0, 16.0, 27.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(1.0, 16.0, 27.0)); expression = new Expression('pow(vec4(5,4,3,2),vec4(0,2,3,5))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(1.0, 16.0, 27.0, 32.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(1.0, 16.0, 27.0, 32.0)); }); it('throws if pow function takes an invalid number of arguments', function() { @@ -2298,38 +2296,38 @@ defineSuite([ it('throws if pow function takes mismatching types', function() { var expression = new Expression('pow(0.0, vec2(0,1))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('pow(vec2(0,1),0.0)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('pow(vec2(0,1),vec3(0,1,2))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates min function', function() { var expression = new Expression('min(0,1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('min(-1,0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(-1.0); + expect(expression.evaluate(undefined)).toEqual(-1.0); expression = new Expression('min(vec2(-1,1),0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-1.0, 0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(-1.0, 0)); expression = new Expression('min(vec2(-1,2),vec2(0,1))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(-1.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(-1.0, 1.0)); expression = new Expression('min(vec3(-1,2,1),vec3(0,1,2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(-1.0, 1.0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(-1.0, 1.0, 1.0)); expression = new Expression('min(vec4(-1,2,1,4),vec4(0,1,2,3))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(-1.0, 1.0, 1.0, 3.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(-1.0, 1.0, 1.0, 3.0)); }); it('throws if min function takes an invalid number of arguments', function() { @@ -2345,33 +2343,33 @@ defineSuite([ it('throws if min function takes mismatching types', function() { var expression = new Expression('min(0.0, vec2(0,1))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('min(vec2(0,1),vec3(0,1,2))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates max function', function() { var expression = new Expression('max(0,1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('max(-1,0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(0.0); + expect(expression.evaluate(undefined)).toEqual(0.0); expression = new Expression('max(vec2(-1,1),0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0, 1.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0, 1.0)); expression = new Expression('max(vec2(-1,2),vec2(0,1))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian2(0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian2(0, 2.0)); expression = new Expression('max(vec3(-1,2,1),vec3(0,1,2))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0, 2.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0, 2.0, 2.0)); expression = new Expression('max(vec4(-1,2,1,4),vec4(0,1,2,3))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian4(0, 2.0, 2.0, 4.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian4(0, 2.0, 2.0, 4.0)); }); it('throws if max function takes an invalid number of arguments', function() { @@ -2387,27 +2385,27 @@ defineSuite([ it('throws if max function takes mismatching types', function() { var expression = new Expression('max(0.0, vec2(0,1))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('max(vec2(0,1),vec3(0,1,2))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates the distance function', function() { var expression = new Expression('distance(0, 1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('distance(vec2(1.0, 0.0), vec2(0.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(1.0); + expect(expression.evaluate(undefined)).toEqual(1.0); expression = new Expression('distance(vec3(3.0, 2.0, 1.0), vec3(1.0, 0.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(3.0); + expect(expression.evaluate(undefined)).toEqual(3.0); expression = new Expression('distance(vec4(5.0, 5.0, 5.0, 5.0), vec4(0.0, 0.0, 0.0, 0.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(10.0); + expect(expression.evaluate(undefined)).toEqual(10.0); }); it('throws if distance function takes an invalid number of arguments', function() { @@ -2422,26 +2420,26 @@ defineSuite([ it('throws if distance function takes mismatching types of arguments', function() { expect(function() { - return new Expression('distance(1, vec2(3.0, 2.0)').evaluate(frameState, undefined); + return new Expression('distance(1, vec2(3.0, 2.0)').evaluate(undefined); }).toThrowRuntimeError(); expect(function() { - return new Expression('distance(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(frameState, undefined); + return new Expression('distance(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates the dot function', function() { var expression = new Expression('dot(1, 2)'); - expect(expression.evaluate(frameState, undefined)).toEqual(2.0); + expect(expression.evaluate(undefined)).toEqual(2.0); expression = new Expression('dot(vec2(1.0, 1.0), vec2(2.0, 2.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(4.0); + expect(expression.evaluate(undefined)).toEqual(4.0); expression = new Expression('dot(vec3(1.0, 2.0, 3.0), vec3(2.0, 2.0, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(9.0); + expect(expression.evaluate(undefined)).toEqual(9.0); expression = new Expression('dot(vec4(5.0, 5.0, 2.0, 3.0), vec4(1.0, 2.0, 1.0, 1.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(20.0); + expect(expression.evaluate(undefined)).toEqual(20.0); }); it('throws if dot function takes an invalid number of arguments', function() { @@ -2456,23 +2454,23 @@ defineSuite([ it('throws if dot function takes mismatching types of arguments', function() { expect(function() { - return new Expression('dot(1, vec2(3.0, 2.0)').evaluate(frameState, undefined); + return new Expression('dot(1, vec2(3.0, 2.0)').evaluate(undefined); }).toThrowRuntimeError(); expect(function() { - return new Expression('dot(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(frameState, undefined); + return new Expression('dot(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates the cross function', function() { var expression = new Expression('cross(vec3(1.0, 1.0, 1.0), vec3(2.0, 2.0, 2.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(0.0, 0.0, 0.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(0.0, 0.0, 0.0)); expression = new Expression('cross(vec3(-1.0, -1.0, -1.0), vec3(0.0, -2.0, -5.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(3.0, -5.0, 2.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(3.0, -5.0, 2.0)); expression = new Expression('cross(vec3(5.0, -2.0, 1.0), vec3(-2.0, -6.0, -8.0))'); - expect(expression.evaluate(frameState, undefined)).toEqual(new Cartesian3(22.0, 38.0, -34.0)); + expect(expression.evaluate(undefined)).toEqual(new Cartesian3(22.0, 38.0, -34.0)); }); it('throws if cross function takes an invalid number of arguments', function() { @@ -2487,23 +2485,23 @@ defineSuite([ it('throws if cross function does not take vec3 arguments', function() { expect(function() { - return new Expression('cross(vec2(1.0, 2.0), vec2(3.0, 2.0)').evaluate(frameState, undefined); + return new Expression('cross(vec2(1.0, 2.0), vec2(3.0, 2.0)').evaluate(undefined); }).toThrowRuntimeError(); expect(function() { - return new Expression('cross(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(frameState, undefined); + return new Expression('cross(vec4(5.0, 2.0, 3.0, 1.0), vec3(4.0, 4.0, 4.0))').evaluate(undefined); }).toThrowRuntimeError(); }); it('evaluates ternary conditional', function() { var expression = new Expression('true ? "first" : "second"'); - expect(expression.evaluate(frameState, undefined)).toEqual('first'); + expect(expression.evaluate(undefined)).toEqual('first'); expression = new Expression('false ? "first" : "second"'); - expect(expression.evaluate(frameState, undefined)).toEqual('second'); + expect(expression.evaluate(undefined)).toEqual('second'); expression = new Expression('(!(1 + 2 > 3)) ? (2 > 1 ? 1 + 1 : 0) : (2 > 1 ? -1 + -1 : 0)'); - expect(expression.evaluate(frameState, undefined)).toEqual(2); + expect(expression.evaluate(undefined)).toEqual(2); }); it('evaluates member expression with dot', function() { @@ -2526,36 +2524,36 @@ defineSuite([ }); var expression = new Expression('${vector.x}'); - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); expression = new Expression('${vector.z}'); - expect(expression.evaluate(frameState, feature)).toEqual(0.0); + expect(expression.evaluate(feature)).toEqual(0.0); expression = new Expression('${height.z}'); - expect(expression.evaluate(frameState, feature)).toEqual(undefined); + expect(expression.evaluate(feature)).toEqual(undefined); expression = new Expression('${undefined.z}'); - expect(expression.evaluate(frameState, feature)).toEqual(undefined); + expect(expression.evaluate(feature)).toEqual(undefined); expression = new Expression('${feature}'); - expect(expression.evaluate(frameState, feature)).toEqual({ + expect(expression.evaluate(feature)).toEqual({ vector : Cartesian4.UNIT_Z }); expression = new Expression('${feature.vector}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_X); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_X); expression = new Expression('${feature.feature.vector}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Z); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Z); expression = new Expression('${feature.vector.x}'); - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); expression = new Expression('${address.street}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example Street'); + expect(expression.evaluate(feature)).toEqual('Example Street'); expression = new Expression('${address.city}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example City'); + expect(expression.evaluate(feature)).toEqual('Example City'); }); it('evaluates member expression with brackets', function() { @@ -2579,52 +2577,52 @@ defineSuite([ }); var expression = new Expression('${vector["x"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); expression = new Expression('${vector["z"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(0.0); + expect(expression.evaluate(feature)).toEqual(0.0); expression = new Expression('${height["z"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(undefined); + expect(expression.evaluate(feature)).toEqual(undefined); expression = new Expression('${undefined["z"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(undefined); + expect(expression.evaluate(feature)).toEqual(undefined); expression = new Expression('${feature["vector"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_X); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_X); expression = new Expression('${feature.vector["x"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); expression = new Expression('${feature["vector"].x}'); - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); expression = new Expression('${feature["vector.x"]}'); - expect(expression.evaluate(frameState, feature)).toEqual('something else'); + expect(expression.evaluate(feature)).toEqual('something else'); expression = new Expression('${feature.feature["vector"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Z); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Z); expression = new Expression('${feature["feature.vector"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Y); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Y); expression = new Expression('${address.street}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example Street'); + expect(expression.evaluate(feature)).toEqual('Example Street'); expression = new Expression('${feature.address.street}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example Street'); + expect(expression.evaluate(feature)).toEqual('Example Street'); expression = new Expression('${feature["address"].street}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example Street'); + expect(expression.evaluate(feature)).toEqual('Example Street'); expression = new Expression('${feature["address.street"]}'); - expect(expression.evaluate(frameState, feature)).toEqual('Other Street'); + expect(expression.evaluate(feature)).toEqual('Other Street'); expression = new Expression('${address["street"]}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example Street'); + expect(expression.evaluate(feature)).toEqual('Example Street'); expression = new Expression('${address["city"]}'); - expect(expression.evaluate(frameState, feature)).toEqual('Example City'); + expect(expression.evaluate(feature)).toEqual('Example City'); }); it('member expressions throw without variable notation', function() { @@ -2654,12 +2652,12 @@ defineSuite([ }); var expression = new Expression('${feature}'); - expect(expression.evaluate(frameState, feature)).toEqual({ + expect(expression.evaluate(feature)).toEqual({ vector : Cartesian4.UNIT_X }); expression = new Expression('${feature} === ${feature.feature}'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); }); it('constructs regex', function() { @@ -2667,44 +2665,44 @@ defineSuite([ feature.addProperty('pattern', '[abc]'); var expression = new Expression('regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual(/a/); + expect(expression.evaluate(undefined)).toEqual(/a/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.LITERAL_REGEX); expression = new Expression('regExp("\\w")'); - expect(expression.evaluate(frameState, undefined)).toEqual(/\w/); + expect(expression.evaluate(undefined)).toEqual(/\w/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.LITERAL_REGEX); expression = new Expression('regExp(1 + 1)'); - expect(expression.evaluate(frameState, undefined)).toEqual(/2/); + expect(expression.evaluate(undefined)).toEqual(/2/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.REGEX); expression = new Expression('regExp(true)'); - expect(expression.evaluate(frameState, undefined)).toEqual(/true/); + expect(expression.evaluate(undefined)).toEqual(/true/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.LITERAL_REGEX); expression = new Expression('regExp()'); - expect(expression.evaluate(frameState, undefined)).toEqual(/(?:)/); + expect(expression.evaluate(undefined)).toEqual(/(?:)/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.LITERAL_REGEX); expression = new Expression('regExp(${pattern})'); - expect(expression.evaluate(frameState, feature)).toEqual(/[abc]/); + expect(expression.evaluate(feature)).toEqual(/[abc]/); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.REGEX); }); it ('constructs regex with flags', function() { var expression = new Expression('regExp("a", "i")'); - expect(expression.evaluate(frameState, undefined)).toEqual(/a/i); + expect(expression.evaluate(undefined)).toEqual(/a/i); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.LITERAL_REGEX); expression = new Expression('regExp("a", "m" + "g")'); - expect(expression.evaluate(frameState, undefined)).toEqual(/a/mg); + expect(expression.evaluate(undefined)).toEqual(/a/mg); expect(expression._runtimeAst._type).toEqual(ExpressionNodeType.REGEX); }); it('does not throw SyntaxError if regex constructor has invalid pattern', function() { var expression = new Expression('regExp("(?<=\\s)" + ".")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).not.toThrowSyntaxError(); expect(function() { @@ -2715,7 +2713,7 @@ defineSuite([ it('throws if regex constructor has invalid flags', function() { var expression = new Expression('regExp("a" + "b", "q")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expect(function() { @@ -2728,30 +2726,30 @@ defineSuite([ feature.addProperty('property', 'abc'); var expression = new Expression('regExp("a").test("abc")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('regExp("a").test("bcd")'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('regExp("quick\\s(brown).+?(jumps)", "ig").test("The Quick Brown Fox Jumps Over The Lazy Dog")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('regExp("a").test()'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('regExp(${property}).test(${property})'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); }); it('throws if regex test function has invalid arguments', function() { var expression = new Expression('regExp("1").test(1)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('regExp("a").test(regExp("b"))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -2761,33 +2759,33 @@ defineSuite([ feature.addProperty('Name', 'Building 1'); var expression = new Expression('regExp("a(.)", "i").exec("Abc")'); - expect(expression.evaluate(frameState, undefined)).toEqual('b'); + expect(expression.evaluate(undefined)).toEqual('b'); expression = new Expression('regExp("a(.)").exec("qbc")'); - expect(expression.evaluate(frameState, undefined)).toEqual(null); + expect(expression.evaluate(undefined)).toEqual(null); expression = new Expression('regExp("a(.)").exec()'); - expect(expression.evaluate(frameState, undefined)).toEqual(null); + expect(expression.evaluate(undefined)).toEqual(null); expression = new Expression('regExp("quick\\s(b.*n).+?(jumps)", "ig").exec("The Quick Brown Fox Jumps Over The Lazy Dog")'); - expect(expression.evaluate(frameState, undefined)).toEqual('Brown'); + expect(expression.evaluate(undefined)).toEqual('Brown'); expression = new Expression('regExp("(" + ${property} + ")").exec(${property})'); - expect(expression.evaluate(frameState, feature)).toEqual('abc'); + expect(expression.evaluate(feature)).toEqual('abc'); expression = new Expression('regExp("Building\\s(\\d)").exec(${Name})'); - expect(expression.evaluate(frameState, feature)).toEqual('1'); + expect(expression.evaluate(feature)).toEqual('1'); }); it('throws if regex exec function has invalid arguments', function() { var expression = new Expression('regExp("1").exec(1)'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('regExp("a").exec(regExp("b"))'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -2796,22 +2794,22 @@ defineSuite([ feature.addProperty('property', 'abc'); var expression = new Expression('regExp("a") =~ "abc"'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('"abc" =~ regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('regExp("a") =~ "bcd"'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('"bcd" =~ regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('regExp("quick\\s(brown).+?(jumps)", "ig") =~ "The Quick Brown Fox Jumps Over The Lazy Dog"'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('regExp(${property}) =~ ${property}'); - expect(expression.evaluate(frameState, feature)).toEqual(true); + expect(expression.evaluate(feature)).toEqual(true); }); it('throws if regex match operator has invalid arguments', function() { @@ -2820,17 +2818,17 @@ defineSuite([ var expression = new Expression('regExp("a") =~ 1'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 =~ regExp("a")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 =~ 1'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -2839,38 +2837,38 @@ defineSuite([ feature.addProperty('property', 'abc'); var expression = new Expression('regExp("a") !~ "abc"'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('"abc" !~ regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('regExp("a") !~ "bcd"'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('"bcd" !~ regExp("a")'); - expect(expression.evaluate(frameState, undefined)).toEqual(true); + expect(expression.evaluate(undefined)).toEqual(true); expression = new Expression('regExp("quick\\s(brown).+?(jumps)", "ig") !~ "The Quick Brown Fox Jumps Over The Lazy Dog"'); - expect(expression.evaluate(frameState, undefined)).toEqual(false); + expect(expression.evaluate(undefined)).toEqual(false); expression = new Expression('regExp(${property}) !~ ${property}'); - expect(expression.evaluate(frameState, feature)).toEqual(false); + expect(expression.evaluate(feature)).toEqual(false); }); it('throws if regex not match operator has invalid arguments', function() { var expression = new Expression('regExp("a") !~ 1'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 !~ regExp("a")'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); expression = new Expression('1 !~ 1'); expect(function() { - expression.evaluate(frameState, undefined); + expression.evaluate(undefined); }).toThrowRuntimeError(); }); @@ -2889,13 +2887,13 @@ defineSuite([ feature.addProperty('property', 'abc'); var expression = new Expression('regExp().toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('/(?:)/'); + expect(expression.evaluate(undefined)).toEqual('/(?:)/'); expression = new Expression('regExp("\\d\\s\\d", "ig").toString()'); - expect(expression.evaluate(frameState, undefined)).toEqual('/\\d\\s\\d/gi'); + expect(expression.evaluate(undefined)).toEqual('/\\d\\s\\d/gi'); expression = new Expression('regExp(${property}).toString()'); - expect(expression.evaluate(frameState, feature)).toEqual('/abc/'); + expect(expression.evaluate(feature)).toEqual('/abc/'); }); it('throws when using toString on other type', function() { @@ -2904,7 +2902,7 @@ defineSuite([ var expression = new Expression('${property}.toString()'); expect(function() { - return expression.evaluate(frameState, feature); + return expression.evaluate(feature); }).toThrowRuntimeError(); }); @@ -2925,36 +2923,36 @@ defineSuite([ }); var expression = new Expression('[1, 2, 3]'); - expect(expression.evaluate(frameState, undefined)).toEqual([1, 2, 3]); + expect(expression.evaluate(undefined)).toEqual([1, 2, 3]); expression = new Expression('[1+2, "hello", 2 < 3, color("blue"), ${property}]'); - expect(expression.evaluate(frameState, feature)).toEqual([3, 'hello', true, Cartesian4.fromColor(Color.BLUE), 'value']); + expect(expression.evaluate(feature)).toEqual([3, 'hello', true, Cartesian4.fromColor(Color.BLUE), 'value']); expression = new Expression('${array[1]}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Y); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Y); expression = new Expression('${complicatedArray[1].subproperty}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Z); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Z); expression = new Expression('${complicatedArray[0]["anotherproperty"]}'); - expect(expression.evaluate(frameState, feature)).toEqual(Cartesian4.UNIT_Y); + expect(expression.evaluate(feature)).toEqual(Cartesian4.UNIT_Y); expression = new Expression('${temperatures["scale"]}'); - expect(expression.evaluate(frameState, feature)).toEqual('fahrenheit'); + expect(expression.evaluate(feature)).toEqual('fahrenheit'); expression = new Expression('${temperatures.values[0]}'); - expect(expression.evaluate(frameState, feature)).toEqual(70); + expect(expression.evaluate(feature)).toEqual(70); expression = new Expression('${temperatures["values"][0]}'); - expect(expression.evaluate(frameState, feature)).toEqual(70); + expect(expression.evaluate(feature)).toEqual(70); }); it('evaluates tiles3d_tileset_time expression', function() { var feature = new MockFeature(); var expression = new Expression('${tiles3d_tileset_time}'); - expect(expression.evaluate(frameState, feature)).toEqual(0.0); + expect(expression.evaluate(feature)).toEqual(0.0); feature.content.tileset.timeSinceLoad = 1.0; - expect(expression.evaluate(frameState, feature)).toEqual(1.0); + expect(expression.evaluate(feature)).toEqual(1.0); }); it('gets shader function', function() { diff --git a/Specs/Scene/Geometry3DTileContentSpec.js b/Specs/Scene/Geometry3DTileContentSpec.js index 55eaba37fde7..dae01c33c3cc 100644 --- a/Specs/Scene/Geometry3DTileContentSpec.js +++ b/Specs/Scene/Geometry3DTileContentSpec.js @@ -552,7 +552,7 @@ defineSuite([ url : geometryBoxesWithBatchTable })); return loadTileset(tileset).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(1); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'name')).toBe(true); @@ -565,7 +565,7 @@ defineSuite([ url : geometryBoxesWithBatchTable })); return loadTileset(tileset).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(function(){ content.getFeature(-1); }).toThrowDeveloperError(); diff --git a/Specs/Scene/GlobeSurfaceTileProviderSpec.js b/Specs/Scene/GlobeSurfaceTileProviderSpec.js index c287014611dd..00919c6f7c80 100644 --- a/Specs/Scene/GlobeSurfaceTileProviderSpec.js +++ b/Specs/Scene/GlobeSurfaceTileProviderSpec.js @@ -674,12 +674,14 @@ defineSuite([ var surface = scene.globe._surface; var replacementQueue = surface._tileReplacementQueue; expect(replacementQueue.count).toBeGreaterThan(0); + var oldTile = replacementQueue.head; surface.tileProvider.terrainProvider = new EllipsoidTerrainProvider(); scene.renderForSpecs(); - expect(replacementQueue.count).toBe(0); + expect(replacementQueue.count).toBeGreaterThan(0); + expect(replacementQueue.head).not.toBe(oldTile); }); }); diff --git a/Specs/Scene/GroundPolylinePrimitiveSpec.js b/Specs/Scene/GroundPolylinePrimitiveSpec.js index 9d8c0c61cc95..e0f5777b13b6 100644 --- a/Specs/Scene/GroundPolylinePrimitiveSpec.js +++ b/Specs/Scene/GroundPolylinePrimitiveSpec.js @@ -76,8 +76,6 @@ defineSuite([ scene.destroyForSpecs(); // Leave ground primitive uninitialized - GroundPolylinePrimitive._initialized = false; - GroundPolylinePrimitive._initPromise = undefined; ApproximateTerrainHeights._initPromise = undefined; ApproximateTerrainHeights._terrainHeights = undefined; }); @@ -688,6 +686,7 @@ defineSuite([ verifyGroundPolylinePrimitiveRender(groundPolylinePrimitive, polylineColor); expect(scene).toPickAndCall(function(result) { + expect(result.primitive).toEqual(groundPolylinePrimitive); expect(result.id).toEqual('polyline on terrain'); }); }); @@ -707,6 +706,7 @@ defineSuite([ verifyGroundPolylinePrimitiveRender(groundPolylinePrimitive, polylineColor); expect(scene).toPickAndCall(function(result) { + expect(result.primitive).toEqual(groundPolylinePrimitive); expect(result.id).toEqual('polyline on terrain'); }); }); @@ -726,6 +726,7 @@ defineSuite([ verifyGroundPolylinePrimitiveRender(groundPolylinePrimitive, polylineColor); expect(scene).toPickAndCall(function(result) { + expect(result.primitive).toEqual(groundPolylinePrimitive); expect(result.id).toEqual('polyline on terrain'); }); }); @@ -764,6 +765,7 @@ defineSuite([ verifyGroundPolylinePrimitiveRender(groundPolylinePrimitive, polylineColor); expect(scene).toPickAndCall(function(result) { + expect(result.primitive).toEqual(groundPolylinePrimitive); expect(result.id).toEqual('big polyline on terrain'); }); scene.completeMorph(); @@ -936,9 +938,10 @@ defineSuite([ it('creating a synchronous primitive throws if initializeTerrainHeights wasn\'t called', function() { // Make it seem like initializeTerrainHeights was never called - var initPromise = GroundPolylinePrimitive._initPromise; - GroundPolylinePrimitive._initPromise = undefined; - GroundPolylinePrimitive._initialized = false; + var initPromise = ApproximateTerrainHeights._initPromise; + var terrainHeights = ApproximateTerrainHeights._terrainHeights; + ApproximateTerrainHeights._initPromise = undefined; + ApproximateTerrainHeights._terrainHeights = undefined; groundPolylinePrimitive = new GroundPolylinePrimitive({ geometryInstances : groundPolylineInstance, @@ -952,7 +955,7 @@ defineSuite([ } // Set back to initialized state - GroundPolylinePrimitive._initPromise = initPromise; - GroundPolylinePrimitive._initialized = true; + ApproximateTerrainHeights._initPromise = initPromise; + ApproximateTerrainHeights._terrainHeights = terrainHeights; }); }, 'WebGL'); diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js index b63c4f56f553..07895570f9dd 100644 --- a/Specs/Scene/GroundPrimitiveSpec.js +++ b/Specs/Scene/GroundPrimitiveSpec.js @@ -65,7 +65,7 @@ defineSuite([ beforeAll(function() { scene = createScene(); - scene.fxaa = false; + scene.postProcessStages.fxaa.enabled = false; context = scene.context; @@ -77,9 +77,6 @@ defineSuite([ scene.destroyForSpecs(); // Leave ground primitive uninitialized - GroundPrimitive._initialized = false; - GroundPrimitive._initPromise = undefined; - ApproximateTerrainHeights._initPromise = undefined; ApproximateTerrainHeights._terrainHeights = undefined; }); @@ -121,7 +118,7 @@ defineSuite([ geometryInstances : new GeometryInstance({ geometry : new RectangleGeometry({ ellipsoid : ellipsoid, - rectangle : rectangle + rectangle : Rectangle.fromDegrees(-180 + CesiumMath.EPSILON4, -90 + CesiumMath.EPSILON4, 180 - CesiumMath.EPSILON4, 90 - CesiumMath.EPSILON4) }), id : 'depth rectangle', attributes : { @@ -365,6 +362,76 @@ defineSuite([ verifyGroundPrimitiveRender(primitive, rectColor); }); + it('renders GroundPrimitives with spherical texture coordinates across the IDL in 3D', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + var rectColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(1.0, 1.0, 0.0, 1.0)); + var bigIdlRectangle = Rectangle.fromDegrees(176.0, 30.0, -176.0, 34.0); + var bigIdlRectangleInstance = new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : bigIdlRectangle + }), + id : 'rectangle', + attributes : { + color : rectColorAttribute + } + }); + + primitive = new GroundPrimitive({ + geometryInstances : bigIdlRectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : bigIdlRectangle }); + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRenderAndCall(function(rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + expect(rgba[0]).toEqual(0); + }); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + }); + + it('renders GroundPrimitives with planar texture coordinates across the IDL in 3D', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + var rectColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(1.0, 1.0, 0.0, 1.0)); + var smallIdlRectangle = Rectangle.fromDegrees(179.6, 30.0, -179.6, 30.9); + var smallIdlRectangleInstance = new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : smallIdlRectangle + }), + id : 'rectangle', + attributes : { + color : rectColorAttribute + } + }); + + primitive = new GroundPrimitive({ + geometryInstances : smallIdlRectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : smallIdlRectangle }); + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRenderAndCall(function(rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + expect(rgba[0]).toEqual(0); + }); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + }); + it('renders in Columbus view when scene3DOnly is false', function() { if (!GroundPrimitive.isSupported(scene)) { return; @@ -400,14 +467,14 @@ defineSuite([ }); largeScene.render(); - largeScene.fxaa = false; + largeScene.postProcessStages.fxaa.enabled = false; largeScene.camera.setView({ destination : destination }); var largeSceneDepthPrimitive = new MockGlobePrimitive(new Primitive({ geometryInstances : new GeometryInstance({ geometry : new RectangleGeometry({ ellipsoid : ellipsoid, - rectangle : rectangle + rectangle : Rectangle.fromDegrees(-180 + CesiumMath.EPSILON4, -90 + CesiumMath.EPSILON4, 180 - CesiumMath.EPSILON4, 90 - CesiumMath.EPSILON4) }), id : 'depth rectangle', attributes : { @@ -533,6 +600,36 @@ defineSuite([ verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle); }); + it('renders GeometryInstances with texture classifying terrain across the IDL', function() { + if (!GroundPrimitive.isSupported(scene) || !GroundPrimitive.supportsMaterials(scene)) { + return; + } + + var whiteImageMaterial = Material.fromType(Material.DiffuseMapType); + whiteImageMaterial.uniforms.image = './Data/Images/White.png'; + + var largeRectangle = Rectangle.fromDegrees(179.0, 30.0, -179.0, 31.0); + var largeRectanglePrimitive = new GroundPrimitive({ + geometryInstances : new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : largeRectangle + }) + }), + id : 'largeRectangle', + appearance : new EllipsoidSurfaceAppearance({ + aboveGround : false, + flat : true, + material : whiteImageMaterial + }), + asynchronous : false, + classificationType : ClassificationType.TERRAIN + }); + + scene.morphToColumbusView(0); + verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle); + }); + it('renders with invert classification and an opaque color', function() { if (!GroundPrimitive.isSupported(scene)) { return; @@ -1260,9 +1357,10 @@ defineSuite([ it('creating a synchronous primitive throws if initializeTerrainHeights wasn\'t called', function() { // Make it seem like initializeTerrainHeights was never called - var initPromise = GroundPrimitive._initPromise; - GroundPrimitive._initPromise = undefined; - GroundPrimitive._initialized = false; + var initPromise = ApproximateTerrainHeights._initPromise; + var terrainHeights = ApproximateTerrainHeights._terrainHeights; + ApproximateTerrainHeights._initPromise = undefined; + ApproximateTerrainHeights._terrainHeights = undefined; primitive = new GroundPrimitive({ geometryInstances : rectangleInstance, @@ -1276,7 +1374,7 @@ defineSuite([ } // Set back to initialized state - GroundPrimitive._initPromise = initPromise; - GroundPrimitive._initialized = true; + ApproximateTerrainHeights._initPromise = initPromise; + ApproximateTerrainHeights._terrainHeights = terrainHeights; }); }, 'WebGL'); diff --git a/Specs/Scene/Instanced3DModel3DTileContentSpec.js b/Specs/Scene/Instanced3DModel3DTileContentSpec.js index 75fca2f18e88..bf7254ed943d 100644 --- a/Specs/Scene/Instanced3DModel3DTileContentSpec.js +++ b/Specs/Scene/Instanced3DModel3DTileContentSpec.js @@ -183,7 +183,7 @@ defineSuite([ var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, new HeadingPitchRoll()); // Update tile transform - tileset._root.transform = newTransform; + tileset.root.transform = newTransform; // Move the camera to the new location setCamera(newLongitude, newLatitude); @@ -245,7 +245,7 @@ defineSuite([ it('throws when calling getFeature with invalid index', function() { return Cesium3DTilesTester.loadTileset(scene, withoutBatchTableUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(function(){ content.getFeature(-1); }).toThrowDeveloperError(); @@ -260,7 +260,7 @@ defineSuite([ it('gets memory usage', function() { return Cesium3DTilesTester.loadTileset(scene, texturedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // Box model - 36 ushort indices and 24 vertices per building, 8 float components (position, normal, uv) per vertex. // (24 * 8 * 4) + (36 * 2) = 840 @@ -295,7 +295,7 @@ defineSuite([ it('Links model to tileset clipping planes based on bounding volume clipping', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var content = tile.content; var model = content._modelInstanceCollection._model; @@ -322,7 +322,7 @@ defineSuite([ it('Links model to tileset clipping planes if tileset clipping planes are reassigned', function() { return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var model = tile.content._modelInstanceCollection._model; expect(model.clippingPlanes).toBeUndefined(); @@ -357,7 +357,7 @@ defineSuite([ spyOn(Model, '_getClippingFunction').and.callThrough(); return Cesium3DTilesTester.loadTileset(scene, withBatchTableUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var content = tile.content; var clippingPlaneCollection = new ClippingPlaneCollection({ planes : [ diff --git a/Specs/Scene/ModelSpec.js b/Specs/Scene/ModelSpec.js index 1b44abe81fb0..43dd98bdd943 100644 --- a/Specs/Scene/ModelSpec.js +++ b/Specs/Scene/ModelSpec.js @@ -266,7 +266,8 @@ defineSuite([ expect(texturedBoxModel.ready).toEqual(true); expect(texturedBoxModel.asynchronous).toEqual(true); expect(texturedBoxModel.releaseGltfJson).toEqual(false); - expect(texturedBoxModel.cacheKey).toEndWith('Data/Models/Box-Textured/CesiumTexturedBoxTest.gltf'); + expect(texturedBoxModel.cacheKey).toBeDefined(); + expect(texturedBoxModel.cacheKey).not.toContain('Data/Models/Box-Textured/CesiumTexturedBoxTest.gltf'); expect(texturedBoxModel.debugShowBoundingVolume).toEqual(false); expect(texturedBoxModel.debugWireframe).toEqual(false); expect(texturedBoxModel.distanceDisplayCondition).toBeUndefined(); diff --git a/Specs/Scene/PickSpec.js b/Specs/Scene/PickSpec.js index 638b8e51b7f7..73fb644f65a0 100644 --- a/Specs/Scene/PickSpec.js +++ b/Specs/Scene/PickSpec.js @@ -114,6 +114,22 @@ defineSuite([ expect(scene).notToPick(7, 7, 3); }); + it('drill picks a primitive with a modified pick search area', function() { + if (FeatureDetection.isInternetExplorer()) { + // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. + return; + } + + camera.setView({ + destination : Rectangle.fromDegrees(-10.0, -10.0, 10.0, 10.0) + }); + + var rectangle = createRectangle(); + + expect(scene).toDrillPickPrimitive(rectangle, 7, 7, 5); + expect(scene).notToDrillPick(7, 7, 3); + }); + it('does not pick primitives when show is false', function() { var rectangle = createRectangle(); rectangle.show = false; diff --git a/Specs/Scene/PointCloud3DTileContentSpec.js b/Specs/Scene/PointCloud3DTileContentSpec.js index 7fd70f1518e5..6197cf410e64 100644 --- a/Specs/Scene/PointCloud3DTileContentSpec.js +++ b/Specs/Scene/PointCloud3DTileContentSpec.js @@ -184,8 +184,8 @@ defineSuite([ it('gets tileset properties', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { - var root = tileset._root; - var content = root._content; + var root = tileset.root; + var content = root.content; expect(content.tileset).toBe(tileset); expect(content.tile).toBe(root); expect(content.url.indexOf(root._header.content.uri) > -1).toBe(true); @@ -284,7 +284,7 @@ defineSuite([ var decoder = DracoLoader._getDecoderTaskProcessor(); spyOn(decoder, 'scheduleTask').and.returnValue(when.reject({message : 'my error'})); return Cesium3DTilesTester.loadTileset(scene, pointCloudDracoUrl).then(function(tileset) { - var root = tileset._root; + var root = tileset.root; return root.contentReadyPromise.then(function() { fail('should not resolve'); }).otherwise(function(error) { @@ -323,7 +323,7 @@ defineSuite([ var newTransform = Transforms.headingPitchRollToFixedFrame(newCenter, newHPR); // Update tile transform - tileset._root.transform = newTransform; + tileset.root.transform = newTransform; // Move the camera to the new location setCamera(newLongitude, newLatitude); @@ -363,7 +363,7 @@ defineSuite([ it('picks', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; tileset.show = false; expect(scene).toPickPrimitive(undefined); tileset.show = true; @@ -404,7 +404,7 @@ defineSuite([ it('point cloud without batch table works', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(0); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'name')).toBe(false); @@ -414,7 +414,7 @@ defineSuite([ it('batched point cloud works', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(8); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'name')).toBe(true); @@ -427,7 +427,7 @@ defineSuite([ // created. There is no per-point show/color/pickId because the overhead is too high. Instead points are styled // based on their properties, and these are not accessible from the API. return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(0); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'name')).toBe(false); @@ -437,7 +437,7 @@ defineSuite([ it('throws when calling getFeature with invalid index', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(function(){ content.getFeature(-1); }).toThrowDeveloperError(); @@ -452,7 +452,7 @@ defineSuite([ it('Supports back face culling when there are per-point normals', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // Get the number of picked sections with back face culling on var pickedCountCulling = 0; @@ -512,7 +512,7 @@ defineSuite([ noAttenuationPixelCount = scene.logarithmicDepthBuffer ? 20 : 16; var center = new Cartesian3.fromRadians(centerLongitude, centerLatitude, 5.0); scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, 5.0)); - scene.fxaa = false; + scene.postProcessStages.fxaa.enabled = false; scene.camera.zoomIn(6); return Cesium3DTilesTester.loadTileset(scene, pointCloudNoColorUrl).then(function(tileset) { @@ -605,7 +605,7 @@ defineSuite([ it('applies shader style', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudWithPerPointPropertiesUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // Solid red color tileset.style = new Cesium3DTileStyle({ @@ -797,7 +797,7 @@ defineSuite([ it('does not apply shader style if the point cloud has a batch table', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; var shaderProgram = content._pointCloud._drawCommand.shaderProgram; tileset.style = new Cesium3DTileStyle({ color:'color("red")' @@ -840,7 +840,7 @@ defineSuite([ return when.all(promises).then(function(tilesets) { var length = tilesets.length; for (var i = 0; i < length; ++i) { - var content = tilesets[i]._root.content; + var content = tilesets[i].root.content; expect(content.geometryByteLength).toEqual(expectedGeometryMemory[i]); expect(content.texturesByteLength).toEqual(0); } @@ -849,7 +849,7 @@ defineSuite([ it('gets memory usage for batch point cloud', function() { return Cesium3DTilesTester.loadTileset(scene, pointCloudBatchedUrl).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; // Point cloud consists of positions, colors, normals, and batchIds // 3 floats (xyz), 3 floats (normal), 1 byte (batchId) @@ -881,7 +881,7 @@ defineSuite([ it('rebuilds shaders when clipping planes are enabled, change between union and intersection, or change count', function () { return Cesium3DTilesTester.loadTileset(scene, pointCloudRGBUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; tile._isClipped = true; var content = tile.content; diff --git a/Specs/Scene/SceneSpec.js b/Specs/Scene/SceneSpec.js index 3faf61d56441..6027f800c13b 100644 --- a/Specs/Scene/SceneSpec.js +++ b/Specs/Scene/SceneSpec.js @@ -111,7 +111,7 @@ defineSuite([ afterEach(function() { scene.backgroundColor = new Color(0.0, 0.0, 0.0, 0.0); scene.debugCommandFilter = undefined; - scene.fxaa = false; + scene.postProcessStages.fxaa.enabled = false; scene.primitives.removeAll(); scene.morphTo3D(0.0); @@ -418,7 +418,7 @@ defineSuite([ primitives.add(rectanglePrimitive); scene.camera.setView({ destination : rectangle }); - scene.fxaa = false; + scene.postProcessStages.fxaa.enabled = false; expect(scene).toRenderAndCall(function(rgba) { expect(rgba[0]).not.toEqual(0); expect(rgba[1]).toEqual(0); @@ -465,7 +465,7 @@ defineSuite([ s._oit._translucentMultipassSupport = false; } - s.fxaa = true; + s.postProcessStages.fxaa.enabled = false; var rectangle = Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0); diff --git a/Specs/Scene/ScreenSpaceCameraControllerSpec.js b/Specs/Scene/ScreenSpaceCameraControllerSpec.js index 6b71846515ae..a0521bcabdea 100644 --- a/Specs/Scene/ScreenSpaceCameraControllerSpec.js +++ b/Specs/Scene/ScreenSpaceCameraControllerSpec.js @@ -44,7 +44,7 @@ defineSuite([ DomEventSimulator) { 'use strict'; - var usePointerEvents = FeatureDetection.supportsPointerEvents(); + var usePointerEvents; var scene; var canvas; var camera; @@ -64,7 +64,7 @@ defineSuite([ this.getHeight = function(cartographic) { return 0.0; }; - this.pick = function() { + this.pickWorldCoordinates = function() { return new Cartesian3(0.0, 0.0, 1.0); }; this._surface = { @@ -80,6 +80,7 @@ defineSuite([ }; } beforeAll(function() { + usePointerEvents = FeatureDetection.supportsPointerEvents(); canvas = createCanvas(1024, 768); }); diff --git a/Specs/Scene/ShadowMapSpec.js b/Specs/Scene/ShadowMapSpec.js index 1546688f390d..06ea1505f331 100644 --- a/Specs/Scene/ShadowMapSpec.js +++ b/Specs/Scene/ShadowMapSpec.js @@ -1134,6 +1134,28 @@ defineSuite([ floor.show = false; }); + it('does not receive shadows if fromLightSource is false', function() { + box.show = true; + floorTranslucent.show = true; + createCascadedShadowMap(); + scene.shadowMap.fromLightSource = false; + + // Render without shadows + scene.shadowMap.enabled = false; + var unshadowedColor; + renderAndCall(function(rgba) { + unshadowedColor = rgba; + expect(rgba).not.toEqual(backgroundColor); + }); + + // Render with shadows + scene.shadowMap.enabled = true; + renderAndCall(function(rgba) { + expect(rgba).not.toEqual(backgroundColor); + expect(rgba).toEqual(unshadowedColor); + }); + }); + it('tweaking shadow bias parameters works', function() { box.show = true; floor.show = true; diff --git a/Specs/Scene/ShadowVolumeAppearanceSpec.js b/Specs/Scene/ShadowVolumeAppearanceSpec.js index 773b341710ed..8f08ce10f26f 100644 --- a/Specs/Scene/ShadowVolumeAppearanceSpec.js +++ b/Specs/Scene/ShadowVolumeAppearanceSpec.js @@ -5,6 +5,7 @@ defineSuite([ 'Core/Math', 'Core/ComponentDatatype', 'Core/Ellipsoid', + 'Core/EncodedCartesian3', 'Core/Matrix4', 'Core/WebMercatorProjection', 'Core/Rectangle', @@ -19,6 +20,7 @@ defineSuite([ CesiumMath, ComponentDatatype, Ellipsoid, + EncodedCartesian3, Matrix4, WebMercatorProjection, Rectangle, @@ -69,6 +71,29 @@ defineSuite([ flat :true }); + // Defines for projection extents + var eastMostCartographic = new Cartographic(); + var longitudeExtentsEncodeScratch = { + high : 0.0, + low : 0.0 + }; + eastMostCartographic.longitude = CesiumMath.PI; + eastMostCartographic.latitude = 0.0; + eastMostCartographic.height = 0.0; + var eastMostCartesian = projection.project(eastMostCartographic); + var encoded = EncodedCartesian3.encode(eastMostCartesian.x, longitudeExtentsEncodeScratch); + var eastMostYhighDefine = 'EAST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + var eastMostYlowDefine = 'EAST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + + var westMostCartographic = new Cartographic(); + westMostCartographic.longitude = -CesiumMath.PI; + westMostCartographic.latitude = 0.0; + westMostCartographic.height = 0.0; + var westMostCartesian = projection.project(westMostCartographic); + encoded = EncodedCartesian3.encode(westMostCartesian.x, longitudeExtentsEncodeScratch); + var westMostYhighDefine = 'WEST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + var westMostYlowDefine = 'WEST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + it('provides attributes for computing texture coordinates from Spherical extents', function() { var attributes = largeRectangleAttributes; @@ -81,6 +106,13 @@ defineSuite([ expect(value[1]).toEqualEpsilon(-CesiumMath.PI_OVER_FOUR, CesiumMath.EPSILON4); expect(value[2]).toEqualEpsilon(1.0 / CesiumMath.PI_OVER_TWO, CesiumMath.EPSILON4); expect(value[3]).toEqualEpsilon(1.0 / CesiumMath.PI_OVER_TWO, CesiumMath.EPSILON4); + + var longitudeRotation = attributes.longitudeRotation; + expect(longitudeRotation.componentDatatype).toEqual(ComponentDatatype.FLOAT); + expect(longitudeRotation.componentsPerAttribute).toEqual(1); + expect(longitudeRotation.normalize).toEqual(false); + value = longitudeRotation.value; + expect(value[0]).toEqualEpsilon(0.0, CesiumMath.EPSILON4); }); function checkGeometryInstanceAttributeVec3(attribute) { @@ -214,82 +246,116 @@ defineSuite([ it('creates vertex shaders for color', function() { // Check defines var sphericalTexturedAppearance = new ShadowVolumeAppearance(true, false, textureMaterialAppearance); - var shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, false); + var shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, false, projection); var defines = shaderSource.defines; expect(defines.length).toEqual(2); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('SPHERICAL')).not.toEqual(-1); // 2D variant - shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, true); + shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(2); + expect(defines.length).toEqual(6); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + // Unculled color appearance - no texcoords at all var sphericalUnculledColorAppearance = new ShadowVolumeAppearance(false, false, perInstanceColorMaterialAppearance); - shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, false); + shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(1); expect(defines.indexOf('PER_INSTANCE_COLOR')).not.toEqual(-1); // 2D variant - shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, true); + shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(1); + expect(defines.length).toEqual(5); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf('PER_INSTANCE_COLOR')).not.toEqual(-1); // Planar textured, without culling var planarTexturedAppearance = new ShadowVolumeAppearance(false, true, textureMaterialAppearance); - shaderSource = planarTexturedAppearance.createVertexShader([], testVs, false); + shaderSource = planarTexturedAppearance.createVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.length).toEqual(1); - shaderSource = planarTexturedAppearance.createVertexShader([], testVs, true); + shaderSource = planarTexturedAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); - expect(defines.length).toEqual(2); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(6); }); it('creates vertex shaders for pick', function() { // Check defines var sphericalTexturedAppearance = new ShadowVolumeAppearance(true, false, textureMaterialAppearance); - var shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, false); + var shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, false, projection); var defines = shaderSource.defines; expect(defines.length).toEqual(2); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('SPHERICAL')).not.toEqual(-1); // 2D variant - shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, true); + shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(2); + expect(defines.length).toEqual(6); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + // Unculled color appearance - no texcoords at all var sphericalUnculledColorAppearance = new ShadowVolumeAppearance(false, false, perInstanceColorMaterialAppearance); - shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, false); + shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(0); // 2D variant - shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, true); + shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(0); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(4); // Planar textured, without culling var planarTexturedAppearance = new ShadowVolumeAppearance(false, true, textureMaterialAppearance); - shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, false); + shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(0); - shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, true); + shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(0); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(4); }); it('creates fragment shaders for color and pick', function() { diff --git a/Specs/Scene/StyleExpressionSpec.js b/Specs/Scene/StyleExpressionSpec.js index 4b47f35a6b27..b046ffd8e2c3 100644 --- a/Specs/Scene/StyleExpressionSpec.js +++ b/Specs/Scene/StyleExpressionSpec.js @@ -4,8 +4,6 @@ defineSuite([ StyleExpression) { 'use strict'; - var frameState = {}; - function MockFeature() { } @@ -18,11 +16,11 @@ defineSuite([ var feature = new MockFeature(); expect(function() { - return expression.evaluate(frameState, feature); + return expression.evaluate(feature); }).toThrowDeveloperError(); expect(function() { - return expression.evaluateColor(frameState, feature); + return expression.evaluateColor(feature); }).toThrowDeveloperError(); }); }); diff --git a/Specs/Scene/Tileset3DTileContentSpec.js b/Specs/Scene/Tileset3DTileContentSpec.js index 72d493898efd..7ed264900d93 100644 --- a/Specs/Scene/Tileset3DTileContentSpec.js +++ b/Specs/Scene/Tileset3DTileContentSpec.js @@ -42,7 +42,7 @@ defineSuite([ it('gets properties', function() { return Cesium3DTilesTester.loadTileset(scene, tilesetOfTilesetsUrl).then(function(tileset) { - var tile = tileset._root; + var tile = tileset.root; var content = tile.content; expect(content.featuresLength).toBe(0); expect(content.pointsLength).toBe(0); diff --git a/Specs/Scene/TimeDynamicPointCloudSpec.js b/Specs/Scene/TimeDynamicPointCloudSpec.js index 5fb55156a379..a2526529db31 100644 --- a/Specs/Scene/TimeDynamicPointCloudSpec.js +++ b/Specs/Scene/TimeDynamicPointCloudSpec.js @@ -678,20 +678,22 @@ defineSuite([ it('frames not loaded in sequential updates do not impact average load time', function() { var pointCloud = createTimeDynamicPointCloud(); - var initialAverageLoadTime = pointCloud._getAverageLoadTime(); + expect(pointCloud._runningAverage).toBe(0.0); return loadFrame(pointCloud).then(function() { - var firstFrameLoadTime = pointCloud._getAverageLoadTime(); - expect(firstFrameLoadTime).not.toBe(initialAverageLoadTime); - expect(firstFrameLoadTime).toBeGreaterThan(0.0); + expect(pointCloud._frames[0].sequential).toBe(true); + expect(pointCloud._runningLength).toBe(1); + expect(pointCloud._runningAverage).toBeGreaterThan(0.0); goToFrame(2); // Start loading frame 2, but don't finish loading it now scene.renderForSpecs(); return loadFrame(pointCloud, 1).then(function() { - var averageLoadTime = pointCloud._getAverageLoadTime(); - expect(averageLoadTime).not.toBe(firstFrameLoadTime); - expect(averageLoadTime).toBeGreaterThan(0.0); + var twoFrameAverage = pointCloud._runningAverage; + expect(pointCloud._frames[1].sequential).toBe(true); + expect(pointCloud._runningLength).toBe(2); + expect(pointCloud._runningAverage).toBeGreaterThan(0.0); return loadFrame(pointCloud, 2).then(function() { expect(pointCloud._frames[2].sequential).toBe(false); - expect(pointCloud._getAverageLoadTime()).toBe(averageLoadTime); + expect(pointCloud._runningLength).toBe(2); // No update + expect(pointCloud._runningAverage).toBe(twoFrameAverage); // No update }); }); }); diff --git a/Specs/Scene/Vector3DTileContentSpec.js b/Specs/Scene/Vector3DTileContentSpec.js index e53d39c78258..e4f2cbc69257 100644 --- a/Specs/Scene/Vector3DTileContentSpec.js +++ b/Specs/Scene/Vector3DTileContentSpec.js @@ -646,7 +646,7 @@ defineSuite([ url : vectorPolygonsWithBatchTable })); return loadTileset(tileset).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(content.featuresLength).toBe(1); expect(content.innerContents).toBeUndefined(); expect(content.hasProperty(0, 'name')).toBe(true); @@ -659,7 +659,7 @@ defineSuite([ url : vectorPolygonsWithBatchTable })); return loadTileset(tileset).then(function(tileset) { - var content = tileset._root.content; + var content = tileset.root.content; expect(function(){ content.getFeature(-1); }).toThrowDeveloperError(); diff --git a/Specs/Scene/Vector3DTileGeometrySpec.js b/Specs/Scene/Vector3DTileGeometrySpec.js index e9043896c4c4..233317192880 100644 --- a/Specs/Scene/Vector3DTileGeometrySpec.js +++ b/Specs/Scene/Vector3DTileGeometrySpec.js @@ -74,7 +74,7 @@ defineSuite([ _statistics : { texturesByteLength : 0 }, - _tileset : { + tileset : { _statistics : { batchTableByteLength : 0 }, diff --git a/Specs/Scene/Vector3DTilePointsSpec.js b/Specs/Scene/Vector3DTilePointsSpec.js index 5de05c9ff612..057edb4fabea 100644 --- a/Specs/Scene/Vector3DTilePointsSpec.js +++ b/Specs/Scene/Vector3DTilePointsSpec.js @@ -60,13 +60,11 @@ defineSuite([ _statistics : { texturesByteLength : 0 }, - _tileset : { + tileset : { _statistics : { batchTableByteLength : 0 }, - colorBlendMode : ColorBlendMode.HIGHLIGHT - }, - tileset : { + colorBlendMode : ColorBlendMode.HIGHLIGHT, ellipsoid : Ellipsoid.WGS84 }, getFeature : function(id) { return { batchId : id }; } @@ -154,7 +152,7 @@ defineSuite([ return loadPoints(points).then(function() { var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, undefined, features); + points.applyStyle(undefined, features); scene.camera.lookAt(Cartesian3.fromDegrees(0.0, 0.0, 10.0), new Cartesian3(0.0, 0.0, 50.0)); expect(scene).toRender([255, 255, 255, 255]); @@ -188,7 +186,7 @@ defineSuite([ return loadPoints(points).then(function() { var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, style, features); + points.applyStyle(style, features); for (var i = 0; i < cartoPositions.length; ++i) { var position = ellipsoid.cartographicToCartesian(cartoPositions[i]); @@ -224,7 +222,7 @@ defineSuite([ var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, undefined, features); + points.applyStyle(undefined, features); var getFeature = mockTileset.getFeature; mockTileset.getFeature = function(index) { @@ -297,7 +295,7 @@ defineSuite([ return loadPoints(points).then(function() { var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, style, features); + points.applyStyle(style, features); var i; for (i = 0; i < features.length; ++i) { @@ -367,7 +365,7 @@ defineSuite([ return loadPoints(points).then(function() { var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, style, features); + points.applyStyle(style, features); var collection = points._billboardCollection; expect(collection.length).toEqual(1); @@ -413,7 +411,7 @@ defineSuite([ return loadPoints(points).then(function() { var features = []; points.createFeatures(mockTileset, features); - points.applyStyle(scene.frameState, style, features); + points.applyStyle(style, features); points.applyDebugSettings(true, Color.YELLOW); var i; diff --git a/Specs/Scene/Vector3DTilePolygonsSpec.js b/Specs/Scene/Vector3DTilePolygonsSpec.js index e728b2dc6f32..d7f9d0b28598 100644 --- a/Specs/Scene/Vector3DTilePolygonsSpec.js +++ b/Specs/Scene/Vector3DTilePolygonsSpec.js @@ -76,7 +76,7 @@ defineSuite([ _statistics : { texturesByteLength : 0 }, - _tileset : { + tileset : { _statistics : { batchTableByteLength : 0 }, diff --git a/Specs/Scene/Vector3DTilePolylinesSpec.js b/Specs/Scene/Vector3DTilePolylinesSpec.js index 3ccedcd9447a..eea85b35e1d2 100644 --- a/Specs/Scene/Vector3DTilePolylinesSpec.js +++ b/Specs/Scene/Vector3DTilePolylinesSpec.js @@ -46,7 +46,7 @@ defineSuite([ _statistics : { texturesByteLength : 0 }, - _tileset : { + tileset : { _statistics : { batchTableByteLength : 0 }, diff --git a/Specs/Scene/computeFlyToLocationForRectangleSpec.js b/Specs/Scene/computeFlyToLocationForRectangleSpec.js new file mode 100644 index 000000000000..f60ef778a6a3 --- /dev/null +++ b/Specs/Scene/computeFlyToLocationForRectangleSpec.js @@ -0,0 +1,145 @@ +defineSuite([ + 'Scene/computeFlyToLocationForRectangle', + 'Core/EllipsoidTerrainProvider', + 'Core/Rectangle', + 'Scene/Globe', + 'Scene/SceneMode', + 'Specs/createScene', + 'ThirdParty/when' + ], function( + computeFlyToLocationForRectangle, + EllipsoidTerrainProvider, + Rectangle, + Globe, + SceneMode, + createScene, + when) { + 'use strict'; + + var scene; + + beforeEach(function() { + scene = createScene(); + }); + + afterEach(function() { + scene.destroyForSpecs(); + }); + + function sampleTest(sceneMode){ + //Pretend we have terrain with availability. + var terrainProvider = new EllipsoidTerrainProvider(); + terrainProvider.availability = {}; + + scene.globe = new Globe(); + scene.terrainProvider = terrainProvider; + scene.mode = sceneMode; + + var rectangle = new Rectangle(0.2, 0.4, 0.6, 0.8); + var cartographics = [ + Rectangle.center(rectangle), + Rectangle.southeast(rectangle), + Rectangle.southwest(rectangle), + Rectangle.northeast(rectangle), + Rectangle.northwest(rectangle) + ]; + + // Mock sampleTerrainMostDetailed with same positions but with heights. + var maxHeight = 1234; + var sampledResults = [ + Rectangle.center(rectangle), + Rectangle.southeast(rectangle), + Rectangle.southwest(rectangle), + Rectangle.northeast(rectangle), + Rectangle.northwest(rectangle) + ]; + sampledResults[0].height = 145; + sampledResults[1].height = 1211; + sampledResults[2].height = -123; + sampledResults[3].height = maxHeight; + + spyOn(computeFlyToLocationForRectangle, '_sampleTerrainMostDetailed').and.returnValue(when.resolve(sampledResults)); + + // Basically do the computation ourselves with our known values; + var expectedResult; + if (sceneMode === SceneMode.SCENE3D) { + expectedResult = scene.mapProjection.ellipsoid.cartesianToCartographic(scene.camera.getRectangleCameraCoordinates(rectangle)); + } else { + expectedResult = scene.mapProjection.unproject(scene.camera.getRectangleCameraCoordinates(rectangle)); + } + expectedResult.height += maxHeight; + + return computeFlyToLocationForRectangle(rectangle, scene) + .then(function(result) { + expect(result).toEqual(expectedResult); + expect(computeFlyToLocationForRectangle._sampleTerrainMostDetailed).toHaveBeenCalledWith(terrainProvider, cartographics); + }); + } + + it('samples terrain and returns expected result in 3D', function() { + return sampleTest(SceneMode.SCENE3D); + }); + + it('samples terrain and returns expected result in CV', function() { + return sampleTest(SceneMode.COLUMBUS_VIEW); + }); + + it('returns original rectangle in 2D', function() { + var terrainProvider = new EllipsoidTerrainProvider(); + terrainProvider.availability = {}; + + scene.globe = new Globe(); + scene.terrainProvider = terrainProvider; + scene.mode = SceneMode.SCENE2D; + + var rectangle = new Rectangle(0.2, 0.4, 0.6, 0.8); + spyOn(computeFlyToLocationForRectangle, '_sampleTerrainMostDetailed'); + + return computeFlyToLocationForRectangle(rectangle, scene) + .then(function(result) { + expect(result).toBe(rectangle); + expect(computeFlyToLocationForRectangle._sampleTerrainMostDetailed).not.toHaveBeenCalled(); + }); + }); + + it('returns original rectangle when terrain not available', function() { + scene.globe = new Globe(); + scene.terrainProvider = new EllipsoidTerrainProvider(); + + var rectangle = new Rectangle(0.2, 0.4, 0.6, 0.8); + spyOn(computeFlyToLocationForRectangle, '_sampleTerrainMostDetailed'); + + return computeFlyToLocationForRectangle(rectangle, scene) + .then(function(result) { + expect(result).toBe(rectangle); + expect(computeFlyToLocationForRectangle._sampleTerrainMostDetailed).not.toHaveBeenCalled(); + }); + }); + + it('waits for terrain to become ready', function() { + var terrainProvider = new EllipsoidTerrainProvider(); + spyOn(terrainProvider.readyPromise, 'then').and.callThrough(); + + scene.globe = new Globe(); + scene.terrainProvider = terrainProvider; + + var rectangle = new Rectangle(0.2, 0.4, 0.6, 0.8); + return computeFlyToLocationForRectangle(rectangle, scene) + .then(function(result) { + expect(result).toBe(rectangle); + expect(terrainProvider.readyPromise.then).toHaveBeenCalled(); + }); + }); + + it('returns original rectangle when terrain undefined', function() { + scene.terrainProvider = undefined; + var rectangle = new Rectangle(0.2, 0.4, 0.6, 0.8); + spyOn(computeFlyToLocationForRectangle, '_sampleTerrainMostDetailed'); + + return computeFlyToLocationForRectangle(rectangle, scene) + .then(function(result) { + expect(result).toBe(rectangle); + expect(computeFlyToLocationForRectangle._sampleTerrainMostDetailed).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/Specs/Widgets/Geocoder/GeocoderSpec.js b/Specs/Widgets/Geocoder/GeocoderSpec.js index ba723f2c2fa4..d5eb07e6828d 100644 --- a/Specs/Widgets/Geocoder/GeocoderSpec.js +++ b/Specs/Widgets/Geocoder/GeocoderSpec.js @@ -12,24 +12,6 @@ defineSuite([ var scene; - var mockDestination = new Cartesian3(1.0, 2.0, 3.0); - var geocoderResults = [{ - displayName: 'a', - destination: mockDestination - }, { - displayName: 'b', - destination: mockDestination - }, { - displayName: 'c', - destination: mockDestination - }]; - - var customGeocoderOptions = { - autoComplete : true, - geocode : function (input) { - return when.resolve(geocoderResults); - } - }; beforeEach(function() { scene = createScene(); }); @@ -40,16 +22,19 @@ defineSuite([ it('constructor sets expected properties', function() { var flightDuration = 1234; + var destinationFound = jasmine.createSpy(); var geocoder = new Geocoder({ container : document.body, scene : scene, - flightDuration : flightDuration + flightDuration : flightDuration, + destinationFound : destinationFound }); var viewModel = geocoder.viewModel; expect(viewModel.scene).toBe(scene); expect(viewModel.flightDuration).toBe(flightDuration); + expect(viewModel.destinationFound).toBe(destinationFound); geocoder.destroy(); }); @@ -96,34 +81,4 @@ defineSuite([ }); }).toThrowDeveloperError(); }); - - it('automatic suggestions can be navigated by arrow up/down keys', function() { - var container = document.createElement('div'); - container.id = 'testContainer'; - document.body.appendChild(container); - var geocoder = new Geocoder({ - container : 'testContainer', - scene : scene, - geocoderServices : [customGeocoderOptions] - }); - var viewModel = geocoder._viewModel; - viewModel._searchText = 'some_text'; - viewModel._updateSearchSuggestions(viewModel); - - expect(viewModel._selectedSuggestion).toEqual(undefined); - viewModel._handleArrowDown(viewModel); - expect(viewModel._selectedSuggestion.displayName).toEqual('a'); - viewModel._handleArrowDown(viewModel); - viewModel._handleArrowDown(viewModel); - expect(viewModel._selectedSuggestion.displayName).toEqual('c'); - viewModel._handleArrowDown(viewModel); - expect(viewModel._selectedSuggestion.displayName).toEqual('a'); - viewModel._handleArrowDown(viewModel); - viewModel._handleArrowUp(viewModel); - expect(viewModel._selectedSuggestion.displayName).toEqual('a'); - viewModel._handleArrowUp(viewModel); - expect(viewModel._selectedSuggestion).toBeUndefined(); - document.body.removeChild(container); - }); - }, 'WebGL'); diff --git a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js index a21421012b3a..17a35fc6ce18 100644 --- a/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js +++ b/Specs/Widgets/Geocoder/GeocoderViewModelSpec.js @@ -1,12 +1,14 @@ defineSuite([ 'Widgets/Geocoder/GeocoderViewModel', 'Core/Cartesian3', + 'Core/Rectangle', 'Specs/createScene', 'Specs/pollToPromise', 'ThirdParty/when' ], function( GeocoderViewModel, Cartesian3, + Rectangle, createScene, pollToPromise, when) { @@ -21,6 +23,9 @@ defineSuite([ }, { displayName: 'b', destination: mockDestination + }, { + displayName: 'c', + destination: mockDestination }]; var customGeocoderOptions = { autoComplete: true, @@ -156,8 +161,8 @@ defineSuite([ geocoderServices : [customGeocoderOptions] }); geocoder._searchText = 'some_text'; - geocoder._updateSearchSuggestions(geocoder); - expect(geocoder._suggestions.length).toEqual(2); + GeocoderViewModel._updateSearchSuggestions(geocoder); + expect(geocoder._suggestions.length).toEqual(3); }); it('update search suggestions results in empty list if the query is empty', function() { @@ -166,35 +171,38 @@ defineSuite([ geocoderServices : [customGeocoderOptions] }); geocoder._searchText = ''; - spyOn(geocoder, '_adjustSuggestionsScroll'); - geocoder._updateSearchSuggestions(geocoder); + + GeocoderViewModel._updateSearchSuggestions(geocoder); expect(geocoder._suggestions.length).toEqual(0); }); it('can activate selected search suggestion', function () { + spyOn(GeocoderViewModel, 'flyToDestination'); + var destination = new Rectangle(0.0, -0.1, 0.1, 0.1); var geocoder = new GeocoderViewModel({ scene : scene, geocoderServices : [customGeocoderOptions] }); - spyOn(geocoder, '_updateCamera'); - spyOn(geocoder, '_adjustSuggestionsScroll'); - var suggestion = {displayName: 'a', destination: {west: 0.0, east: 0.1, north: 0.1, south: -0.1}}; + var suggestion = { displayName: 'a', destination: destination }; geocoder._selectedSuggestion = suggestion; geocoder.activateSuggestion(suggestion); expect(geocoder._searchText).toEqual('a'); + expect(GeocoderViewModel.flyToDestination).toHaveBeenCalledWith(geocoder, destination); }); it('if more than one geocoder service is provided, use first result from first geocode in array order', function () { + spyOn(GeocoderViewModel, 'flyToDestination'); + var geocoder = new GeocoderViewModel({ scene : scene, geocoderServices : [noResultsGeocoder, customGeocoderOptions2] }); geocoder._searchText = 'sthsnth'; // an empty query will prevent geocoding - spyOn(geocoder, '_updateCamera'); - spyOn(geocoder, '_adjustSuggestionsScroll'); + geocoder.search(); expect(geocoder._searchText).toEqual(geocoderResults2[0].displayName); + expect(GeocoderViewModel.flyToDestination).toHaveBeenCalledWith(geocoder, mockDestination); }); it('can update autoComplete suggestions list using multiple geocoders', function () { @@ -203,10 +211,48 @@ defineSuite([ geocoderServices : [customGeocoderOptions, customGeocoderOptions2] }); geocoder._searchText = 'sthsnth'; // an empty query will prevent geocoding - spyOn(geocoder, '_updateCamera'); - spyOn(geocoder, '_adjustSuggestionsScroll'); - geocoder._updateSearchSuggestions(geocoder); + GeocoderViewModel._updateSearchSuggestions(geocoder); expect(geocoder._suggestions.length).toEqual(geocoderResults1.length + geocoderResults2.length); }); + it('uses custom destination found callback', function () { + spyOn(GeocoderViewModel, 'flyToDestination'); + + var destinationFound = jasmine.createSpy(); + var geocoder = new GeocoderViewModel({ + scene : scene, + geocoderServices : [noResultsGeocoder, customGeocoderOptions2], + destinationFound: destinationFound + }); + geocoder._searchText = 'sthsnth'; // an empty query will prevent geocoding + geocoder.search(); + + expect(geocoder._searchText).toEqual(geocoderResults2[0].displayName); + expect(GeocoderViewModel.flyToDestination).not.toHaveBeenCalled(); + expect(destinationFound).toHaveBeenCalledWith(geocoder, mockDestination); + }); + + it('automatic suggestions can be navigated by arrow up/down keys', function() { + spyOn(GeocoderViewModel, '_adjustSuggestionsScroll'); + var viewModel = new GeocoderViewModel({ + scene : scene, + geocoderServices : [customGeocoderOptions] + }); + viewModel._searchText = 'some_text'; + GeocoderViewModel._updateSearchSuggestions(viewModel); + + expect(viewModel._selectedSuggestion).toEqual(undefined); + viewModel._handleArrowDown(viewModel); + expect(viewModel._selectedSuggestion.displayName).toEqual('a'); + viewModel._handleArrowDown(viewModel); + viewModel._handleArrowDown(viewModel); + expect(viewModel._selectedSuggestion.displayName).toEqual('c'); + viewModel._handleArrowDown(viewModel); + expect(viewModel._selectedSuggestion.displayName).toEqual('a'); + viewModel._handleArrowDown(viewModel); + viewModel._handleArrowUp(viewModel); + expect(viewModel._selectedSuggestion.displayName).toEqual('a'); + viewModel._handleArrowUp(viewModel); + expect(viewModel._selectedSuggestion).toBeUndefined(); + }); }, 'WebGL'); diff --git a/Specs/addDefaultMatchers.js b/Specs/addDefaultMatchers.js index 775b3f3e996e..9903852787d9 100644 --- a/Specs/addDefaultMatchers.js +++ b/Specs/addDefaultMatchers.js @@ -297,6 +297,22 @@ define([ }; }, + toDrillPickPrimitive : function(util, customEqualityTesters) { + return { + compare : function(actual, expected, x, y, width, height) { + return drillPickPrimitiveEquals(actual, 1, x, y, width, height); + } + }; + }, + + notToDrillPick : function(util, customEqualityTesters) { + return { + compare : function(actual, expected, x, y, width, height) { + return drillPickPrimitiveEquals(actual, 0, x, y, width, height); + } + }; + }, + toPickAndCall : function(util, customEqualityTesters) { return { compare : function(actual, expected) { @@ -532,6 +548,36 @@ define([ }; } + function drillPickPrimitiveEquals(actual, expected, x, y, width, height) { + var scene = actual; + var windowPosition = new Cartesian2(x, y); + var result = scene.drillPick(windowPosition, undefined, width, height); + + if (!!window.webglStub) { + return { + pass : true + }; + } + + var pass = true; + var message; + + if (defined(expected)) { + pass = (result.length === expected); + } else { + pass = !defined(result); + } + + if (!pass) { + message = 'Expected to pick ' + expected + ', but picked: ' + result; + } + + return { + pass : pass, + message : message + }; + } + function expectContextToRender(actual, expected, expectEqual) { var options = actual; var context = options.context; diff --git a/gulpfile.js b/gulpfile.js index 27f1d69dd6bf..296ce6f724ed 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -26,7 +26,7 @@ var Promise = require('bluebird'); var requirejs = require('requirejs'); var Karma = require('karma').Server; var yargs = require('yargs'); -var aws = require('aws-sdk'); +var AWS = require('aws-sdk'); var mime = require('mime'); var compressible = require('compressible'); @@ -338,15 +338,14 @@ gulp.task('deploy-s3', function(done) { function deployCesium(bucketName, uploadDirectory, cacheControl, done) { var readFile = Promise.promisify(fs.readFile); var gzip = Promise.promisify(zlib.gzip); - var getCredentials = Promise.promisify(aws.config.getCredentials, {context: aws.config}); var concurrencyLimit = 2000; - var s3 = new Promise.promisifyAll(new aws.S3({ + var s3 = new AWS.S3({ maxRetries : 10, retryDelayOptions : { base : 500 } - })); + }); var existingBlobs = []; var totalFiles = 0; @@ -354,10 +353,8 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { var skipped = 0; var errors = []; - return getCredentials() - .then(function() { - var prefix = uploadDirectory + '/'; - return listAll(s3, bucketName, prefix, existingBlobs) + var prefix = uploadDirectory + '/'; + return listAll(s3, bucketName, prefix, existingBlobs) .then(function() { return globby([ 'Apps/**', @@ -377,8 +374,7 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { ], { dot : true // include hidden files }); - }) - .then(function(files) { + }).then(function(files) { return Promise.map(files, function(file) { var blobName = uploadDirectory + '/' + file; var mimeLookup = getMimeType(blobName); @@ -407,25 +403,24 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { existingBlobs.splice(index, 1); // get file info - return s3.headObjectAsync({ - Bucket : bucketName, - Key : blobName - }) - .then(function(data) { - if (data.ETag !== ('"' + hash + '"') || - data.CacheControl !== cacheControl || - data.ContentType !== contentType || - data.ContentEncoding !== contentEncoding) { - return content; - } - - // We don't need to upload this file again - skipped++; - return undefined; - }) - .catch(function(error) { - errors.push(error); - }); + return s3.headObject({ + Bucket: bucketName, + Key: blobName + }).promise().then(function(data) { + if (data.ETag !== ('"' + hash + '"') || + data.CacheControl !== cacheControl || + data.ContentType !== contentType || + data.ContentEncoding !== contentEncoding) { + return content; + } + + // We don't need to upload this file again + skipped++; + return undefined; + }) + .catch(function(error) { + errors.push(error); + }); }) .then(function(content) { if (!content) { @@ -443,16 +438,16 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { CacheControl : cacheControl }; - return s3.putObjectAsync(params).then(function() { - uploaded++; - }) - .catch(function(error) { - errors.push(error); - }); + return s3.putObject(params).promise() + .then(function() { + uploaded++; + }) + .catch(function(error) { + errors.push(error); + }); }); }, {concurrency : concurrencyLimit}); - }) - .then(function() { + }).then(function() { console.log('Skipped ' + skipped + ' files and successfully uploaded ' + uploaded + ' files of ' + (totalFiles - skipped) + ' files.'); if (existingBlobs.length === 0) { return; @@ -477,22 +472,19 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { batches.push(objectsToDelete); return Promise.map(batches, function(objects) { - return s3.deleteObjectsAsync({ - Bucket : bucketName, - Delete : { - Objects : objects + return s3.deleteObjects({ + Bucket: bucketName, + Delete: { + Objects: objects } - }) - .then(function() { + }).promise().then(function() { console.log('Cleaned ' + objects.length + ' files.'); }); }, {concurrency : concurrency}); } - }) - .catch(function(error) { + }).catch(function(error) { errors.push(error); - }) - .then(function() { + }).then(function() { if (errors.length === 0) { done(); return; @@ -504,11 +496,6 @@ function deployCesium(bucketName, uploadDirectory, cacheControl, done) { }); done(1); }); - }) - .catch(function(error) { - console.log('Error: Could not load S3 credentials.'); - done(); - }); } function getMimeType(filename) { @@ -534,13 +521,12 @@ function getMimeType(filename) { // get all files currently in bucket asynchronously function listAll(s3, bucketName, prefix, files, marker) { - return s3.listObjectsAsync({ - Bucket : bucketName, - MaxKeys : 1000, - Prefix : prefix, - Marker : marker - }) - .then(function(data) { + return s3.listObjects({ + Bucket: bucketName, + MaxKeys: 1000, + Prefix: prefix, + Marker: marker + }).promise().then(function(data) { var items = data.Contents; for (var i = 0; i < items.length; i++) { files.push(items[i].Key); diff --git a/package.json b/package.json index d5fbf45fb6c7..5c39846022e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "1.48.0", + "version": "1.49.0", "description": "CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "homepage": "http://cesiumjs.org", "license": "Apache-2.0",