From dd47e52d2b323df98035e3147dc9cecaeee95d79 Mon Sep 17 00:00:00 2001 From: Justinidlerz Date: Wed, 30 Jan 2019 16:39:34 +0800 Subject: [PATCH 1/2] feat: (script) Support cube tile non rectangle when in the last row or column position --- demos/cube-generated/SolidColorSource.js | 28 ++++++-- demos/cube-generated/index.js | 4 +- src/geometries/Cube.js | 83 +++++++----------------- test/suite/geometries/Cube.js | 28 -------- 4 files changed, 47 insertions(+), 96 deletions(-) diff --git a/demos/cube-generated/SolidColorSource.js b/demos/cube-generated/SolidColorSource.js index e46824b48..abbbc0208 100644 --- a/demos/cube-generated/SolidColorSource.js +++ b/demos/cube-generated/SolidColorSource.js @@ -16,18 +16,21 @@ 'use strict'; // Custom tile source for procedurally generated solid color tiles. -function SolidColorSource(width, height) { +function SolidColorSource(width, height, tileSize) { this._width = width; this._height = height; + this._tileSize = tileSize; } -SolidColorSource.prototype._tileText = function(tile) { +SolidColorSource.prototype._tileText = function(tile, width, height) { var components = []; if (tile.face) { components.push("face:" + tile.face); } components.push("x:" + tile.x); components.push("y:" + tile.y); + components.push("width:" + width); + components.push("height:" + height); components.push("zoom:" + tile.z); return components.join(" "); }; @@ -45,11 +48,24 @@ SolidColorSource.prototype._tileColor = function(tile) { }; SolidColorSource.prototype.loadAsset = function(stage, tile, done) { - var width = this._width; - var height = this._height; - var text = this._tileText(tile); + var _width = this._width * (tile.z + 1); + var _height = this._height * (tile.z + 1); + var width; + // Compute tile x remainder + if (this._tileSize * (tile.x + 1) > _width) { + width = (_width / this._tileSize - tile.x) * this._tileSize; + } else { + width = this._tileSize; + } + var height; + // Compute tile y remainder + if (this._tileSize * (tile.y + 1) > _height) { + height = (_height / this._tileSize - tile.y) * this._tileSize; + } else { + height = this._tileSize; + } + var text = this._tileText(tile, width, height); var color = this._tileColor(tile); - // Create the canvas element. var element = document.createElement("canvas"); element.width = width; diff --git a/demos/cube-generated/index.js b/demos/cube-generated/index.js index 59cba30c6..263cc8827 100644 --- a/demos/cube-generated/index.js +++ b/demos/cube-generated/index.js @@ -19,12 +19,12 @@ var viewer = new Marzipano.Viewer(document.getElementById('pano')); // Create procedurally-generated single-color tile source. -var source = new SolidColorSource(512, 512); +var source = new SolidColorSource(1600, 1600, 512); // Create geometry with a very large number of levels. var levels = []; for(var i = 0; i < 32; i++) { - levels.push({ tileSize: 512, size: 512 * Math.pow(2,i) }); + levels.push({ tileSize: 512, size: 800 * Math.pow(2,i) }); } var geometry = new Marzipano.CubeGeometry(levels); diff --git a/src/geometries/Cube.js b/src/geometries/Cube.js index 4308b1131..26b7062d8 100644 --- a/src/geometries/Cube.js +++ b/src/geometries/Cube.js @@ -124,6 +124,8 @@ function CubeTile(face, x, y, z, geometry) { this.z = z; this._geometry = geometry; this._level = geometry.levelList[z]; + // Pre compute last tile size, when all is square, it's 0 + this._tileResidue = this._level.width() % this._level.tileWidth(); } @@ -138,32 +140,46 @@ CubeTile.prototype.rotY = function() { CubeTile.prototype.centerX = function() { - return (this.x + 0.5) / this._level.numHorizontalTiles() - 0.5; + var foreWidth = this._level.tileWidth() * this.x; + var partOfWidth = this.width() / 2; + // Compute tile centerX of face + return (foreWidth + partOfWidth + 0.5) / this._level.width() - 0.5; }; CubeTile.prototype.centerY = function() { - return 0.5 - (this.y + 0.5) / this._level.numVerticalTiles(); + var foreWidth = this._level.tileWidth() * this.y; + var partOfWidth = this.height() / 2; + // Compute tile centerY of face + return 0.5 - (foreWidth + partOfWidth + 0.5) / this._level.width(); }; CubeTile.prototype.scaleX = function() { - return 1 / this._level.numHorizontalTiles(); + return this.width() / this._level.width(); }; CubeTile.prototype.scaleY = function() { - return 1 / this._level.numVerticalTiles(); + return this.height() / this._level.width(); }; CubeTile.prototype.width = function() { + // Return remainder when it's edge and the tile has residue + if (this.atRightEdge() && this._tileResidue !== 0) { + return this._tileResidue; + } return this._level.tileWidth(); }; CubeTile.prototype.height = function() { - return this._level.tileHeight(); + // Return remainder when it's edge and the tile has residue + if (this.atBottomEdge() && this._tileResidue !== 0) { + return this._tileResidue; + } + return this._level.tileWidth(); }; @@ -458,11 +474,6 @@ function CubeLevel(levelProperties) { this._size = levelProperties.size; this._tileSize = levelProperties.tileSize; - - if (this._size % this._tileSize !== 0) { - throw new Error('Level size is not multiple of tile size: ' + - this._size + ' ' + this._tileSize); - } } inherits(CubeLevel, Level); @@ -488,47 +499,6 @@ CubeLevel.prototype.tileHeight = function() { }; -CubeLevel.prototype._validateWithParentLevel = function(parentLevel) { - - var width = this.width(); - var height = this.height(); - var tileWidth = this.tileWidth(); - var tileHeight = this.tileHeight(); - var numHorizontal = this.numHorizontalTiles(); - var numVertical = this.numVerticalTiles(); - - var parentWidth = parentLevel.width(); - var parentHeight = parentLevel.height(); - var parentTileWidth = parentLevel.tileWidth(); - var parentTileHeight = parentLevel.tileHeight(); - var parentNumHorizontal = parentLevel.numHorizontalTiles(); - var parentNumVertical = parentLevel.numVerticalTiles(); - - if (width % parentWidth !== 0) { - throw new Error('Level width must be multiple of parent level: ' + - width + ' vs. ' + parentWidth); - } - - if (height % parentHeight !== 0) { - throw new Error('Level height must be multiple of parent level: ' + - height + ' vs. ' + parentHeight); - } - - if (numHorizontal % parentNumHorizontal !== 0) { - throw new Error('Number of horizontal tiles must be multiple of parent level: ' + - numHorizontal + " (" + width + '/' + tileWidth + ')' + " vs. " + - parentNumHorizontal + " (" + parentWidth + '/' + parentTileWidth + ')'); - } - - if (numVertical % parentNumVertical !== 0) { - throw new Error('Number of vertical tiles must be multiple of parent level: ' + - numVertical + " (" + height + '/' + tileHeight + ')' + " vs. " + - parentNumVertical + " (" + parentHeight + '/' + parentTileHeight + ')'); - } - -}; - - /** * @class CubeGeometry * @implements Geometry @@ -538,11 +508,8 @@ CubeLevel.prototype._validateWithParentLevel = function(parentLevel) { * multiple resolution levels. * * The following restrictions apply: - * - All tiles in a level must be square and form a rectangular grid; - * - The size of a level must be a multiple of the tile size; - * - The size of a level must be a multiple of the parent level size; - * - The number of tiles in a level must be a multiple of the number of tiles - * in the parent level. + * - All tiles must be square, except when in the last row or column position, + * and must form a rectangular grid; * * @param {Object[]} levelPropertiesList Level description * @param {number} levelPropertiesList[].size Cube face size in pixels @@ -556,10 +523,6 @@ function CubeGeometry(levelPropertiesList) { this.levelList = makeLevelList(levelPropertiesList, CubeLevel); this.selectableLevelList = makeSelectableLevelList(this.levelList); - for (var i = 1; i < this.levelList.length; i++) { - this.levelList[i]._validateWithParentLevel(this.levelList[i-1]); - } - this._tileSearcher = new TileSearcher(this); this._neighborsCache = new LruMap(CubeTile.equals, CubeTile.hash, 64); diff --git a/test/suite/geometries/Cube.js b/test/suite/geometries/Cube.js index 55d28575b..0e7e2056f 100644 --- a/test/suite/geometries/Cube.js +++ b/test/suite/geometries/Cube.js @@ -31,34 +31,6 @@ suite('CubeGeometry', function() { return false; } - suite('malformed levels', function() { - - test('level size must not be smaller than parent level', function() { - assert.throws(function() { - new Cube([{ tileSize: 512, size: 512 }, { tileSize: 512, size: 500 }]); - }); - }); - - test('level size must be multiple of parent level', function() { - assert.throws(function() { - new Cube([{ tileSize: 512, size: 512 }, { tileSize: 512, size: 1000 }]); - }); - }); - - test('number of tiles in level must not be smaller than parent level', function() { - assert.throws(function() { - new Cube([{ tileSize: 128, size: 512 }, { tileSize: 512, size: 1024 }]); - }); - }); - - test('number of tiles in level must be multiple of parent level', function() { - assert.throws(function() { - new Cube([{ tileSize: 256, size: 512 }, { tileSize: 512, size: 512*3 }]); - }); - }); - - }); - suite('levels with constant tile size', function() { var cube = null; From 1b74cd3508097ed62404f15ea8d9d3f462b7da0d Mon Sep 17 00:00:00 2001 From: Justinidlerz Date: Thu, 14 Feb 2019 18:08:49 +0800 Subject: [PATCH 2/2] feat: (script) rollback verify function --- src/geometries/Cube.js | 62 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/src/geometries/Cube.js b/src/geometries/Cube.js index 26b7062d8..d1f469b27 100644 --- a/src/geometries/Cube.js +++ b/src/geometries/Cube.js @@ -140,18 +140,16 @@ CubeTile.prototype.rotY = function() { CubeTile.prototype.centerX = function() { - var foreWidth = this._level.tileWidth() * this.x; - var partOfWidth = this.width() / 2; - // Compute tile centerX of face - return (foreWidth + partOfWidth + 0.5) / this._level.width() - 0.5; + var levelWidth = this._level.width(); + var tileWidth = this._level.tileWidth(); + return (this.x * tileWidth + 0.5 * this.width()) / levelWidth - 0.5; }; CubeTile.prototype.centerY = function() { - var foreWidth = this._level.tileWidth() * this.y; - var partOfWidth = this.height() / 2; - // Compute tile centerY of face - return 0.5 - (foreWidth + partOfWidth + 0.5) / this._level.width(); + var levelHeight = this._level.height(); + var tileHeight = this._level.tileHeight(); + return 0.5 - (this.y * tileHeight + 0.5 * this.height()) / levelHeight; }; @@ -499,6 +497,47 @@ CubeLevel.prototype.tileHeight = function() { }; +CubeLevel.prototype._validateWithParentLevel = function(parentLevel) { + + var width = this.width(); + var height = this.height(); + var tileWidth = this.tileWidth(); + var tileHeight = this.tileHeight(); + var numHorizontal = this.numHorizontalTiles(); + var numVertical = this.numVerticalTiles(); + + var parentWidth = parentLevel.width(); + var parentHeight = parentLevel.height(); + var parentTileWidth = parentLevel.tileWidth(); + var parentTileHeight = parentLevel.tileHeight(); + var parentNumHorizontal = parentLevel.numHorizontalTiles(); + var parentNumVertical = parentLevel.numVerticalTiles(); + + if (width % parentWidth !== 0) { + throw new Error('Level width must be multiple of parent level: ' + + width + ' vs. ' + parentWidth); + } + + if (height % parentHeight !== 0) { + throw new Error('Level height must be multiple of parent level: ' + + height + ' vs. ' + parentHeight); + } + + if (numHorizontal % parentNumHorizontal !== 0) { + throw new Error('Number of horizontal tiles must be multiple of parent level: ' + + numHorizontal + " (" + width + '/' + tileWidth + ')' + " vs. " + + parentNumHorizontal + " (" + parentWidth + '/' + parentTileWidth + ')'); + } + + if (numVertical % parentNumVertical !== 0) { + throw new Error('Number of vertical tiles must be multiple of parent level: ' + + numVertical + " (" + height + '/' + tileHeight + ')' + " vs. " + + parentNumVertical + " (" + parentHeight + '/' + parentTileHeight + ')'); + } + +}; + + /** * @class CubeGeometry * @implements Geometry @@ -510,6 +549,9 @@ CubeLevel.prototype.tileHeight = function() { * The following restrictions apply: * - All tiles must be square, except when in the last row or column position, * and must form a rectangular grid; + * - The size of a level must be a multiple of the parent level size; + * - The tile width (respectively, height) for a level must be a submultiple + * of the tile width (respectively, height) for the parent level. * * @param {Object[]} levelPropertiesList Level description * @param {number} levelPropertiesList[].size Cube face size in pixels @@ -523,6 +565,10 @@ function CubeGeometry(levelPropertiesList) { this.levelList = makeLevelList(levelPropertiesList, CubeLevel); this.selectableLevelList = makeSelectableLevelList(this.levelList); + for (var i = 1; i < this.levelList.length; i++) { + this.levelList[i]._validateWithParentLevel(this.levelList[i-1]); + } + this._tileSearcher = new TileSearcher(this); this._neighborsCache = new LruMap(CubeTile.equals, CubeTile.hash, 64);