Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support cube non rectangle #216

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions demos/cube-generated/SolidColorSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(" ");
};
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions demos/cube-generated/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
83 changes: 23 additions & 60 deletions src/geometries/Cube.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to change the CubeTile#neighbors method. Currently, the logic assumes that an edge tile never meets more than one tile in the other face; this is no longer true with residual tiles.

Consider, for example, the non-residual tile at the top left of the down face. This tile meets two different tiles in the left face: the residual tile at the bottom right of the left face, and the non-residual tile immediately to the left.

A similar situation happens with some of the other corners of the cube. A strategy that might work is to have a lookup table indicating whether a particular corner is "special" or not ("special" meaning that a residual tile meets a non-residual one at that corner). Then add the additional tile to the neighbor set in the cases where the corner is "special".

}


Expand All @@ -138,32 +140,46 @@ CubeTile.prototype.rotY = function() {


CubeTile.prototype.centerX = function() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be expressed more succinctly as

var levelWidth = this._level.width();
var tileWidth = this._level.tileWidth();
return (this.x * tileWidth + 0.5 * this.width()) / levelWidth - 0.5;

which is the same logic as in FlatView.

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() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise as above.

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();
};


Expand Down Expand Up @@ -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);
Expand All @@ -488,47 +499,6 @@ CubeLevel.prototype.tileHeight = function() {
};


CubeLevel.prototype._validateWithParentLevel = function(parentLevel) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still want to validate that each tile has at most one parent tile in the previous level (i.e., the tile width must be a submultiple of the parent width, and the same for height). Otherwise, CubeTile#parent and CubeTile#children no longer work correctly.

If you're up for it, you can lift this restriction afterwards (but please make it a separate PR, to keep each change small).


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
Expand All @@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add

- The tile width (respectively, height) for a level must be a submultiple of the tile width (respectively, height) for the parent level.

per the discussion above.

*
* @param {Object[]} levelPropertiesList Level description
* @param {number} levelPropertiesList[].size Cube face size in pixels
Expand All @@ -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);
Expand Down
28 changes: 0 additions & 28 deletions test/suite/geometries/Cube.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down