Allow geometries to use a shared vertex array

The ol.geom.SharedVertices structure represents a flattened array of vertex coordinates.  This is intended to support optimal WebGL rendering.
This commit is contained in:
Tim Schaub
2013-03-02 18:39:24 +01:00
parent bdfa2cc88c
commit b52d283641
23 changed files with 1086 additions and 217 deletions

View File

@@ -0,0 +1,79 @@
goog.provide('ol.test.geom.GeometryCollection');
describe('ol.geom.GeometryCollection', function() {
var outer = [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
inner1 = [[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]],
inner2 = [[8, 8], [9, 8], [9, 9], [8, 9], [8, 8]];
describe('constructor', function() {
it('creates a geometry collection from an array of geometries', function() {
var point = new ol.geom.Point([10, 20]);
var line = new ol.geom.LineString([[10, 20], [30, 40]]);
var poly = new ol.geom.Polygon([outer, inner1, inner2]);
var multi = new ol.geom.GeometryCollection([point, line, poly]);
expect(multi).toBeA(ol.geom.GeometryCollection);
expect(multi).toBeA(ol.geom.Geometry);
});
});
describe('#components', function() {
it('is an array of geometries', function() {
var point = new ol.geom.Point([10, 20]);
var line = new ol.geom.LineString([[10, 20], [30, 40]]);
var poly = new ol.geom.Polygon([outer, inner1, inner2]);
var multi = new ol.geom.GeometryCollection([point, line, poly]);
expect(multi.components.length).toBe(3);
expect(multi.components[0]).toBeA(ol.geom.Point);
expect(multi.components[1]).toBeA(ol.geom.LineString);
expect(multi.components[2]).toBeA(ol.geom.Polygon);
});
});
describe('#dimension', function() {
it('can be 2', function() {
var point = new ol.geom.Point([10, 20]);
var line = new ol.geom.LineString([[10, 20], [30, 40]]);
var poly = new ol.geom.Polygon([outer, inner1, inner2]);
var multi = new ol.geom.GeometryCollection([point, line, poly]);
expect(multi.dimension).toBe(2);
});
it('can be 3', function() {
var multi = new ol.geom.GeometryCollection([
new ol.geom.Point([30, 40, 50])
]);
expect(multi.dimension).toBe(3);
});
});
describe('#getBounds()', function() {
it('returns the bounding extent', function() {
var point = new ol.geom.Point([10, 2]);
var line = new ol.geom.LineString([[1, 20], [30, 40]]);
var multi = new ol.geom.GeometryCollection([point, line]);
var bounds = multi.getBounds();
expect(bounds.minX).toBe(1);
expect(bounds.minY).toBe(2);
expect(bounds.maxX).toBe(30);
expect(bounds.maxY).toBe(40);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryCollection');
goog.require('ol.geom.LineString');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');

View File

@@ -17,20 +17,6 @@ describe('ol.geom.LinearRing', function() {
});
describe('#coordinates', function() {
it('is an array', function() {
var ring = new ol.geom.LinearRing([[10, 20], [30, 40]]);
expect(ring.coordinates.length).toBe(4);
expect(ring.coordinates[0]).toBe(10);
expect(ring.coordinates[1]).toBe(20);
expect(ring.coordinates[2]).toBe(30);
expect(ring.coordinates[3]).toBe(40);
});
});
describe('#dimension', function() {
it('can be 2', function() {
@@ -45,6 +31,14 @@ describe('ol.geom.LinearRing', function() {
});
describe('#getCoordinates()', function() {
it('is an array', function() {
var ring = new ol.geom.LinearRing([[10, 20], [30, 40]]);
expect(ring.getCoordinates()).toEqual([[10, 20], [30, 40]]);
});
});
});

View File

@@ -16,18 +16,12 @@ describe('ol.geom.LineString', function() {
}).toThrow();
});
});
describe('#coordinates', function() {
it('is an array', function() {
var line = new ol.geom.LineString([[10, 20], [30, 40]]);
expect(line.coordinates.length).toBe(4);
expect(line.coordinates[0]).toBe(10);
expect(line.coordinates[1]).toBe(20);
expect(line.coordinates[2]).toBe(30);
expect(line.coordinates[3]).toBe(40);
it('accepts shared vertices', function() {
var vertices = new ol.geom.SharedVertices();
var l1 = new ol.geom.LineString([[10, 20], [30, 40]], vertices);
var l2 = new ol.geom.LineString([[50, 60], [70, 80]], vertices);
expect(l1.getCoordinates()).toEqual([[10, 20], [30, 40]]);
expect(l2.getCoordinates()).toEqual([[50, 60], [70, 80]]);
});
});
@@ -59,8 +53,51 @@ describe('ol.geom.LineString', function() {
});
describe('#getCoordinates', function() {
it('returns an array', function() {
var line = new ol.geom.LineString([[10, 20], [30, 40]]);
expect(line.getCoordinates()).toEqual([[10, 20], [30, 40]]);
});
});
describe('#getSharedId()', function() {
it('returns identifiers', function() {
var vertices = new ol.geom.SharedVertices();
var l1 = new ol.geom.LineString([[10, 20], [30, 40]], vertices);
var l2 = new ol.geom.LineString(
[[50, 60], [70, 80], [90, 100]], vertices);
var id1 = l1.getSharedId();
var id2 = l2.getSharedId();
expect(vertices.coordinates).toEqual(
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
expect(vertices.getStart(id1)).toBe(0);
expect(vertices.getCount(id1)).toBe(2);
expect(vertices.get(id1, 0, 0)).toBe(10);
expect(vertices.get(id1, 0, 1)).toBe(20);
expect(vertices.get(id1, 1, 0)).toBe(30);
expect(vertices.get(id1, 1, 1)).toBe(40);
expect(vertices.getStart(id2)).toBe(4);
expect(vertices.getCount(id2)).toBe(3);
expect(vertices.get(id2, 0, 0)).toBe(50);
expect(vertices.get(id2, 0, 1)).toBe(60);
expect(vertices.get(id2, 1, 0)).toBe(70);
expect(vertices.get(id2, 1, 1)).toBe(80);
expect(vertices.get(id2, 2, 0)).toBe(90);
expect(vertices.get(id2, 2, 1)).toBe(100);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.LineString');
goog.require('ol.geom.SharedVertices');

View File

@@ -68,6 +68,19 @@ describe('ol.geom.MultiLineString', function() {
});
describe('#getCoordinates', function() {
it('returns an array', function() {
var coordinates = [
[[10, 20], [30, 40]],
[[20, 30], [40, 50]]
];
var multi = new ol.geom.MultiLineString(coordinates);
expect(multi.getCoordinates()).toEqual(coordinates);
});
});
});
goog.require('ol.geom.Geometry');

View File

@@ -58,6 +58,15 @@ describe('ol.geom.MultiPoint', function() {
});
describe('#getCoordinates', function() {
it('returns an array', function() {
var multi = new ol.geom.MultiPoint([[10, 20], [30, 40]]);
expect(multi.getCoordinates()).toEqual([[10, 20], [30, 40]]);
});
});
});
goog.require('ol.geom.Geometry');

View File

@@ -71,6 +71,20 @@ describe('ol.geom.MultiPolygon', function() {
});
describe('#getCoordinates', function() {
it('returns an array', function() {
var coordinates = [
[outer1, inner1a, inner1b],
[outer2]
];
var multi = new ol.geom.MultiPolygon(coordinates);
expect(multi.getCoordinates()).toEqual(coordinates);
});
});
});
goog.require('ol.geom.Geometry');

View File

@@ -10,6 +10,16 @@ describe('ol.geom.Point', function() {
expect(point).toBeA(ol.geom.Geometry);
});
it('accepts shared vertices', function() {
var vertices = new ol.geom.SharedVertices();
var p1 = new ol.geom.Point([10, 20], vertices);
var p2 = new ol.geom.Point([30, 40], vertices);
var p3 = new ol.geom.Point([50, 60], vertices);
expect(p1.getCoordinates()).toEqual([10, 20]);
expect(p2.getCoordinates()).toEqual([30, 40]);
expect(p3.getCoordinates()).toEqual([50, 60]);
});
it('throws when given with insufficient dimensions', function() {
expect(function() {
var point = new ol.geom.Point([1]);
@@ -18,19 +28,6 @@ describe('ol.geom.Point', function() {
});
describe('#coordinates', function() {
it('is an array', function() {
var point = new ol.geom.Point([10, 20]);
expect(point.coordinates.length).toBe(2);
expect(point.coordinates[0]).toBe(10);
expect(point.coordinates[1]).toBe(20);
});
});
describe('#dimension', function() {
it('can be 2', function() {
@@ -58,7 +55,52 @@ describe('ol.geom.Point', function() {
});
describe('#getCoordinates()', function() {
it('returns an array', function() {
var point = new ol.geom.Point([10, 20]);
expect(point.getCoordinates()).toEqual([10, 20]);
});
});
describe('#getSharedId()', function() {
it('returns identifiers', function() {
var vertices = new ol.geom.SharedVertices();
var p1 = new ol.geom.Point([10, 20], vertices);
var p2 = new ol.geom.Point([30, 40], vertices);
var p3 = new ol.geom.Point([50, 60], vertices);
var id1 = p1.getSharedId();
var id2 = p2.getSharedId();
var id3 = p3.getSharedId();
expect(vertices.coordinates).toEqual(
[10, 20, 30, 40, 50, 60]);
expect(vertices.getStart(id1)).toBe(0);
expect(vertices.getCount(id1)).toBe(1);
expect(vertices.get(id1, 0, 0)).toBe(10);
expect(vertices.get(id1, 0, 1)).toBe(20);
expect(vertices.getStart(id2)).toBe(2);
expect(vertices.getCount(id2)).toBe(1);
expect(vertices.get(id2, 0, 0)).toBe(30);
expect(vertices.get(id2, 0, 1)).toBe(40);
expect(vertices.getStart(id3)).toBe(4);
expect(vertices.getCount(id3)).toBe(1);
expect(vertices.get(id3, 0, 0)).toBe(50);
expect(vertices.get(id3, 0, 1)).toBe(60);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Point');
goog.require('ol.geom.SharedVertices');

View File

@@ -1,4 +1,4 @@
gooog.require('ol.test.geom.Polygon');
goog.provide('ol.test.geom.Polygon');
describe('ol.geom.Polygon', function() {
@@ -20,6 +20,16 @@ describe('ol.geom.Polygon', function() {
}).toThrow();
});
it('accepts shared vertices', function() {
var vertices = new ol.geom.SharedVertices();
var p1 = new ol.geom.Polygon([outer], vertices);
var p2 = new ol.geom.Polygon([outer, inner1], vertices);
var p3 = new ol.geom.Polygon([outer, inner2], vertices);
expect(p1.getCoordinates()).toEqual([outer]);
expect(p2.getCoordinates()).toEqual([outer, inner1]);
expect(p3.getCoordinates()).toEqual([outer, inner2]);
});
});
describe('#rings', function() {
@@ -62,8 +72,17 @@ describe('ol.geom.Polygon', function() {
});
describe('#getCoordinates()', function() {
it('returns an array', function() {
var poly = new ol.geom.Polygon([outer, inner1, inner2]);
expect(poly.getCoordinates()).toEqual([outer, inner1, inner2]);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Polygon');
goog.require('ol.geom.SharedVertices');

View File

@@ -0,0 +1,195 @@
goog.provide('ol.test.geom.SharedVertices');
describe('ol.geom.SharedVertices', function() {
describe('constructor', function() {
it('creates an instance', function() {
var vertices = new ol.geom.SharedVertices();
expect(vertices).toBeA(ol.geom.SharedVertices);
});
it('accepts options', function() {
var vertices = new ol.geom.SharedVertices({
dimension: 4,
offset: [1, 2, 3, 4]
});
expect(vertices.getDimension()).toBe(4);
expect(vertices.getOffset()).toEqual([1, 2, 3, 4]);
});
});
describe('offset option', function() {
it('offsets the internally stored vertex coordinates', function() {
var vertices = new ol.geom.SharedVertices({offset: [3, -1]});
vertices.add([[3, -1], [0, 0]]);
vertices.add([[10, 20]]);
expect(vertices.coordinates).toEqual([0, 0, -3, 1, 7, 21]);
});
});
describe('#add()', function() {
it('adds vertex arrays to the shared coordinates', function() {
var vertices = new ol.geom.SharedVertices();
expect(vertices.coordinates.length).toBe(0);
vertices.add([[1, 2], [3, 4]]);
expect(vertices.coordinates).toEqual([1, 2, 3, 4]);
vertices.add([[5, 6]]);
expect(vertices.coordinates).toEqual([1, 2, 3, 4, 5, 6]);
});
it('returns an identifier for coordinate access', function() {
var vertices = new ol.geom.SharedVertices();
var id = vertices.add([[1, 2], [3, 4]]);
expect(typeof id).toBe('string');
});
});
describe('#get()', function() {
it('provides access to vertex coordinates', function() {
var vertices = new ol.geom.SharedVertices();
var first = vertices.add([[1, 2], [3, 4]]);
var second = vertices.add([[5, 6]]);
expect(vertices.get(first, 0, 0)).toBe(1);
expect(vertices.get(first, 0, 1)).toBe(2);
expect(vertices.get(first, 1, 0)).toBe(3);
expect(vertices.get(first, 1, 1)).toBe(4);
expect(vertices.get(second, 0, 0)).toBe(5);
expect(vertices.get(second, 0, 1)).toBe(6);
});
it('works for non-2d vertices', function() {
var vertices = new ol.geom.SharedVertices({dimension: 3});
var id = vertices.add([[1, 2, 3], [4, 5, 6]]);
expect(vertices.get(id, 0, 0)).toBe(1);
expect(vertices.get(id, 0, 1)).toBe(2);
expect(vertices.get(id, 0, 2)).toBe(3);
expect(vertices.get(id, 1, 0)).toBe(4);
expect(vertices.get(id, 1, 1)).toBe(5);
expect(vertices.get(id, 1, 2)).toBe(6);
});
it('works when an offset is provided', function() {
var vertices = new ol.geom.SharedVertices({offset: [3, 3]});
var id = vertices.add([[1, 2], [3, 4], [5, 6]]);
expect(vertices.get(id, 0, 0)).toBe(1);
expect(vertices.get(id, 0, 1)).toBe(2);
expect(vertices.get(id, 1, 0)).toBe(3);
expect(vertices.get(id, 1, 1)).toBe(4);
expect(vertices.get(id, 2, 0)).toBe(5);
expect(vertices.get(id, 2, 1)).toBe(6);
});
});
describe('#getCount()', function() {
it('returns the length of an identified vertex array', function() {
var vertices = new ol.geom.SharedVertices();
var first = vertices.add([[2, 3], [3, 4], [4, 5]]);
var second = vertices.add([[5, 6], [6, 6]]);
expect(vertices.getCount(first)).toBe(3);
expect(vertices.getCount(second)).toBe(2);
});
});
describe('#getDimension()', function() {
it('returns 2 by default', function() {
var vertices = new ol.geom.SharedVertices();
expect(vertices.getDimension()).toBe(2);
});
it('returns the dimension provided to the constructor', function() {
var vertices = new ol.geom.SharedVertices({dimension: 10});
expect(vertices.getDimension()).toBe(10);
});
});
describe('#getOffset()', function() {
it('returns null by default', function() {
var vertices = new ol.geom.SharedVertices();
expect(vertices.getOffset()).toBeNull();
});
it('returns the offset provided to the constructor', function() {
var vertices = new ol.geom.SharedVertices({offset: [1, 2]});
expect(vertices.getOffset()).toEqual([1, 2]);
});
});
describe('#getStart()', function() {
it('returns the start of the identified vertex array', function() {
var vertices = new ol.geom.SharedVertices();
var first = vertices.add([[1, 2]]);
var second = vertices.add([[3, 4], [5, 6]]);
var third = vertices.add([[7, 8], [9, 10], [11, 12]]);
expect(vertices.coordinates).toEqual(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
expect(vertices.getStart(first)).toBe(0);
expect(vertices.getStart(second)).toBe(2);
expect(vertices.getStart(third)).toBe(6);
});
});
describe('#remove()', function() {
it('removes a vertex array', function() {
var vertices = new ol.geom.SharedVertices();
var first = vertices.add([[1, 2], [3, 4]]);
var second = vertices.add([[5, 6]]);
var third = vertices.add([[7, 8], [9, 10], [11, 12]]);
expect(vertices.remove(second)).toEqual([[5, 6]]);
expect(vertices.coordinates).toEqual([1, 2, 3, 4, 7, 8, 9, 10, 11, 12]);
expect(vertices.remove(first)).toEqual([[1, 2], [3, 4]]);
expect(vertices.coordinates).toEqual([7, 8, 9, 10, 11, 12]);
expect(vertices.remove(third)).toEqual([[7, 8], [9, 10], [11, 12]]);
expect(vertices.coordinates).toEqual([]);
});
it('adjusts returned vertices by offset', function() {
var vertices = new ol.geom.SharedVertices({offset: [10, 20]});
var first = vertices.add([[1, 2]]);
var second = vertices.add([[3, 4]]);
var third = vertices.add([[5, 6]]);
expect(vertices.remove(second)).toEqual([[3, 4]]);
expect(vertices.coordinates).toEqual([-9, -18, -5, -14]);
expect(vertices.remove(third)).toEqual([[5, 6]]);
expect(vertices.coordinates).toEqual([-9, -18]);
expect(vertices.remove(first)).toEqual([[1, 2]]);
expect(vertices.coordinates).toEqual([]);
});
});
describe('#coordinates', function() {
it('is not reassigned', function() {
var vertices = new ol.geom.SharedVertices();
var first = vertices.add([[1, 2], [3, 4]]);
var coordinates = vertices.coordinates;
var second = vertices.add([[5, 6]]);
expect(vertices.coordinates).toBe(coordinates);
vertices.remove(first);
expect(vertices.coordinates).toBe(coordinates);
vertices.remove(second);
expect(vertices.coordinates).toBe(coordinates);
});
});
});
goog.require('ol.geom.SharedVertices');

View File

@@ -76,8 +76,7 @@ describe('ol.parser.geojson', function() {
var obj = ol.parser.geojson.read(str);
expect(obj).toBeA(ol.geom.Point);
expect(obj.coordinates[0]).toBe(10);
expect(obj.coordinates[1]).toBe(20);
expect(obj.getCoordinates()).toEqual([10, 20]);
});
it('parses linestring', function() {
@@ -88,10 +87,7 @@ describe('ol.parser.geojson', function() {
var obj = ol.parser.geojson.read(str);
expect(obj).toBeA(ol.geom.LineString);
expect(obj.coordinates[0]).toBe(10);
expect(obj.coordinates[1]).toBe(20);
expect(obj.coordinates[2]).toBe(30);
expect(obj.coordinates[3]).toBe(40);
expect(obj.getCoordinates()).toEqual([[10, 20], [30, 40]]);
});
it('parses polygon', function() {