-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fill-extrude-height and fill-extrude-base properties. (#3223)
🎉 🏗 🆙
- Loading branch information
Lauren Budorick
authored
Oct 8, 2016
1 parent
5994bc3
commit c8cbb9d
Showing
15 changed files
with
848 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
'use strict'; | ||
|
||
var Bucket = require('../bucket'); | ||
var util = require('../../util/util'); | ||
var loadGeometry = require('../load_geometry'); | ||
var earcut = require('earcut'); | ||
var classifyRings = require('../../util/classify_rings'); | ||
var Point = require('point-geometry'); | ||
var EARCUT_MAX_RINGS = 500; | ||
|
||
module.exports = FillExtrusionBucket; | ||
|
||
function FillExtrusionBucket() { | ||
Bucket.apply(this, arguments); | ||
} | ||
|
||
FillExtrusionBucket.prototype = util.inherit(Bucket, {}); | ||
|
||
FillExtrusionBucket.prototype.programInterfaces = { | ||
fillextrusion: { | ||
layoutVertexArrayType: new Bucket.VertexArrayType([{ | ||
name: 'a_pos', | ||
components: 2, | ||
type: 'Int16' | ||
}, { | ||
name: 'a_normal', | ||
components: 3, | ||
type: 'Int16' | ||
}, { | ||
name: 'a_edgedistance', | ||
components: 1, | ||
type: 'Int16' | ||
}]), | ||
elementArrayType: new Bucket.ElementArrayType(3), | ||
|
||
paintAttributes: [{ | ||
name: 'a_minH', | ||
components: 1, | ||
type: 'Uint16', | ||
getValue: function(layer, globalProperties, featureProperties) { | ||
return [layer.getPaintValue("fill-extrude-base", globalProperties, featureProperties)]; | ||
}, | ||
multiplier: 1, | ||
paintProperty: 'fill-extrude-base' | ||
}, { | ||
name: 'a_maxH', | ||
components: 1, | ||
type: 'Uint16', | ||
getValue: function(layer, globalProperties, featureProperties) { | ||
return [layer.getPaintValue("fill-extrude-height", globalProperties, featureProperties)]; | ||
}, | ||
multiplier: 1, | ||
paintProperty: 'fill-extrude-height' | ||
}, { | ||
name: 'a_color', | ||
components: 4, | ||
type: 'Uint8', | ||
getValue: function(layer, globalProperties, featureProperties) { | ||
var color = layer.getPaintValue("fill-color", globalProperties, featureProperties); | ||
color[3] = 1.0; | ||
return color; | ||
}, | ||
multiplier: 255, | ||
paintProperty: 'fill-color' | ||
}] | ||
} | ||
}; | ||
|
||
FillExtrusionBucket.prototype.addVertex = function(vertexArray, x, y, nx, ny, nz, t, e) { | ||
return vertexArray.emplaceBack( | ||
// a_pos | ||
x, | ||
y, | ||
// a_normal | ||
Math.floor(nx * this.factor) * 2 + t, | ||
ny * this.factor * 2, | ||
nz * this.factor * 2, | ||
|
||
// a_edgedistance | ||
Math.round(e) | ||
); | ||
}; | ||
|
||
FillExtrusionBucket.prototype.addFeature = function(feature) { | ||
var lines = loadGeometry(feature); | ||
var polygons = convertCoords(classifyRings(lines, EARCUT_MAX_RINGS)); | ||
|
||
this.factor = Math.pow(2, 13); | ||
|
||
var startGroup = this.prepareArrayGroup('fillextrusion', 0); | ||
var startIndex = startGroup.layoutVertexArray.length; | ||
|
||
for (var i = 0; i < polygons.length; i++) { | ||
this.addPolygon(polygons[i]); | ||
} | ||
|
||
this.populatePaintArrays('fillextrusion', {zoom: this.zoom}, feature.properties, startGroup, startIndex); | ||
}; | ||
|
||
FillExtrusionBucket.prototype.addPolygon = function(polygon) { | ||
var numVertices = 0; | ||
for (var k = 0; k < polygon.length; k++) { | ||
numVertices += polygon[k].length; | ||
} | ||
numVertices *= 5; | ||
|
||
var group = this.prepareArrayGroup('fillextrusion', numVertices); | ||
var flattened = []; | ||
var holeIndices = []; | ||
|
||
var indices = []; | ||
|
||
for (var r = 0; r < polygon.length; r++) { | ||
var ring = polygon[r]; | ||
|
||
if (r > 0) holeIndices.push(flattened.length / 2); | ||
|
||
var edgeDistance = 0; | ||
|
||
for (var v = 0; v < ring.length; v++) { | ||
var v1 = ring[v]; | ||
|
||
var index = this.addVertex(group.layoutVertexArray, v1[0], v1[1], 0, 0, 1, 1, 0); | ||
indices.push(index); | ||
|
||
if (v >= 1) { | ||
var v2 = ring[v - 1]; | ||
|
||
if (!isBoundaryEdge(v1, v2)) { | ||
var perp = Point.convert(v1)._sub(Point.convert(v2))._perp()._unit(); | ||
|
||
var bottomRight = this.addVertex(group.layoutVertexArray, v1[0], v1[1], perp.x, perp.y, 0, 0, edgeDistance); | ||
this.addVertex(group.layoutVertexArray, v1[0], v1[1], perp.x, perp.y, 0, 1, edgeDistance); | ||
|
||
edgeDistance += Point.convert(v2).dist(Point.convert(v1)); | ||
|
||
this.addVertex(group.layoutVertexArray, v2[0], v2[1], perp.x, perp.y, 0, 0, edgeDistance); | ||
this.addVertex(group.layoutVertexArray, v2[0], v2[1], perp.x, perp.y, 0, 1, edgeDistance); | ||
|
||
group.elementArray.emplaceBack(bottomRight, bottomRight + 1, bottomRight + 2); | ||
group.elementArray.emplaceBack(bottomRight + 1, bottomRight + 2, bottomRight + 3); | ||
} | ||
} | ||
|
||
// convert to format used by earcut | ||
flattened.push(v1[0]); | ||
flattened.push(v1[1]); | ||
} | ||
} | ||
|
||
var triangleIndices = earcut(flattened, holeIndices); | ||
|
||
for (var j = 0; j < triangleIndices.length - 2; j += 3) { | ||
group.elementArray.emplaceBack(indices[triangleIndices[j]], | ||
indices[triangleIndices[j + 1]], | ||
indices[triangleIndices[j + 2]]); | ||
} | ||
}; | ||
|
||
function convertCoords(rings) { | ||
if (rings instanceof Point) return [rings.x, rings.y]; | ||
return rings.map(convertCoords); | ||
} | ||
|
||
function isBoundaryEdge(v1, v2) { | ||
return v1.some(function(a, i) { | ||
return isOutside(v2[i]) && v2[i] === a; | ||
}); | ||
} | ||
|
||
function isOutside(coord) { | ||
return coord < 0 || coord > Bucket.EXTENT; | ||
} |
Oops, something went wrong.