UNPKG

c8y-openlayer

Version:

This module is designed to help integrate Openlayer with Cumulocity IoT

685 lines (582 loc) 23.2 kB
import _ol_ from '../../index.js'; import _ol_array_ from '../../array.js'; import _ol_color_ from '../../color.js'; import _ol_extent_ from '../../extent.js'; import _ol_geom_flat_orient_ from '../../geom/flat/orient.js'; import _ol_geom_flat_transform_ from '../../geom/flat/transform.js'; import _ol_geom_flat_topology_ from '../../geom/flat/topology.js'; import _ol_obj_ from '../../obj.js'; import _ol_render_webgl_ from '../webgl.js'; import _ol_render_webgl_Replay_ from '../webgl/replay.js'; import _ol_render_webgl_linestringreplay_defaultshader_ from '../webgl/linestringreplay/defaultshader.js'; import _ol_render_webgl_linestringreplay_defaultshader_Locations_ from '../webgl/linestringreplay/defaultshader/locations.js'; import _ol_webgl_ from '../../webgl.js'; import _ol_webgl_Buffer_ from '../../webgl/buffer.js'; /** * @constructor * @extends {ol.render.webgl.Replay} * @param {number} tolerance Tolerance. * @param {ol.Extent} maxExtent Max extent. * @struct */ var _ol_render_webgl_LineStringReplay_ = function(tolerance, maxExtent) { _ol_render_webgl_Replay_.call(this, tolerance, maxExtent); /** * @private * @type {ol.render.webgl.linestringreplay.defaultshader.Locations} */ this.defaultLocations_ = null; /** * @private * @type {Array.<Array.<?>>} */ this.styles_ = []; /** * @private * @type {Array.<number>} */ this.styleIndices_ = []; /** * @private * @type {{strokeColor: (Array.<number>|null), * lineCap: (string|undefined), * lineDash: Array.<number>, * lineDashOffset: (number|undefined), * lineJoin: (string|undefined), * lineWidth: (number|undefined), * miterLimit: (number|undefined), * changed: boolean}|null} */ this.state_ = { strokeColor: null, lineCap: undefined, lineDash: null, lineDashOffset: undefined, lineJoin: undefined, lineWidth: undefined, miterLimit: undefined, changed: false }; }; _ol_.inherits(_ol_render_webgl_LineStringReplay_, _ol_render_webgl_Replay_); /** * Draw one segment. * @private * @param {Array.<number>} flatCoordinates Flat coordinates. * @param {number} offset Offset. * @param {number} end End. * @param {number} stride Stride. */ _ol_render_webgl_LineStringReplay_.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { var i, ii; var numVertices = this.vertices.length; var numIndices = this.indices.length; //To save a vertex, the direction of a point is a product of the sign (1 or -1), a prime from //ol.render.webgl.LineStringReplay.Instruction_, and a rounding factor (1 or 2). If the product is even, //we round it. If it is odd, we don't. var lineJoin = this.state_.lineJoin === 'bevel' ? 0 : this.state_.lineJoin === 'miter' ? 1 : 2; var lineCap = this.state_.lineCap === 'butt' ? 0 : this.state_.lineCap === 'square' ? 1 : 2; var closed = _ol_geom_flat_topology_.lineStringIsClosed(flatCoordinates, offset, end, stride); var startCoords, sign, n; var lastIndex = numIndices; var lastSign = 1; //We need the adjacent vertices to define normals in joins. p0 = last, p1 = current, p2 = next. var p0, p1, p2; for (i = offset, ii = end; i < ii; i += stride) { n = numVertices / 7; p0 = p1; p1 = p2 || [flatCoordinates[i], flatCoordinates[i + 1]]; //First vertex. if (i === offset) { p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]]; if (end - offset === stride * 2 && _ol_array_.equals(p1, p2)) { break; } if (closed) { //A closed line! Complete the circle. p0 = [flatCoordinates[end - stride * 2], flatCoordinates[end - stride * 2 + 1]]; startCoords = p2; } else { //Add the first two/four vertices. if (lineCap) { numVertices = this.addVertices_([0, 0], p1, p2, lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.BEGIN_LINE_CAP * lineCap, numVertices); numVertices = this.addVertices_([0, 0], p1, p2, -lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.BEGIN_LINE_CAP * lineCap, numVertices); this.indices[numIndices++] = n + 2; this.indices[numIndices++] = n; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n + 3; this.indices[numIndices++] = n + 2; } numVertices = this.addVertices_([0, 0], p1, p2, lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.BEGIN_LINE * (lineCap || 1), numVertices); numVertices = this.addVertices_([0, 0], p1, p2, -lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.BEGIN_LINE * (lineCap || 1), numVertices); lastIndex = numVertices / 7 - 1; continue; } } else if (i === end - stride) { //Last vertex. if (closed) { //Same as the first vertex. p2 = startCoords; break; } else { p0 = p0 || [0, 0]; numVertices = this.addVertices_(p0, p1, [0, 0], lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.END_LINE * (lineCap || 1), numVertices); numVertices = this.addVertices_(p0, p1, [0, 0], -lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.END_LINE * (lineCap || 1), numVertices); this.indices[numIndices++] = n; this.indices[numIndices++] = lastIndex - 1; this.indices[numIndices++] = lastIndex; this.indices[numIndices++] = lastIndex; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n; if (lineCap) { numVertices = this.addVertices_(p0, p1, [0, 0], lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.END_LINE_CAP * lineCap, numVertices); numVertices = this.addVertices_(p0, p1, [0, 0], -lastSign * _ol_render_webgl_LineStringReplay_.Instruction_.END_LINE_CAP * lineCap, numVertices); this.indices[numIndices++] = n + 2; this.indices[numIndices++] = n; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n + 3; this.indices[numIndices++] = n + 2; } break; } } else { p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]]; } // We group CW and straight lines, thus the not so inituitive CCW checking function. sign = _ol_render_webgl_.triangleIsCounterClockwise(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]) ? -1 : 1; numVertices = this.addVertices_(p0, p1, p2, sign * _ol_render_webgl_LineStringReplay_.Instruction_.BEVEL_FIRST * (lineJoin || 1), numVertices); numVertices = this.addVertices_(p0, p1, p2, sign * _ol_render_webgl_LineStringReplay_.Instruction_.BEVEL_SECOND * (lineJoin || 1), numVertices); numVertices = this.addVertices_(p0, p1, p2, -sign * _ol_render_webgl_LineStringReplay_.Instruction_.MITER_BOTTOM * (lineJoin || 1), numVertices); if (i > offset) { this.indices[numIndices++] = n; this.indices[numIndices++] = lastIndex - 1; this.indices[numIndices++] = lastIndex; this.indices[numIndices++] = n + 2; this.indices[numIndices++] = n; this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1; } this.indices[numIndices++] = n; this.indices[numIndices++] = n + 2; this.indices[numIndices++] = n + 1; lastIndex = n + 2; lastSign = sign; //Add miter if (lineJoin) { numVertices = this.addVertices_(p0, p1, p2, sign * _ol_render_webgl_LineStringReplay_.Instruction_.MITER_TOP * lineJoin, numVertices); this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n + 3; this.indices[numIndices++] = n; } } if (closed) { n = n || numVertices / 7; sign = _ol_geom_flat_orient_.linearRingIsClockwise([p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]], 0, 6, 2) ? 1 : -1; numVertices = this.addVertices_(p0, p1, p2, sign * _ol_render_webgl_LineStringReplay_.Instruction_.BEVEL_FIRST * (lineJoin || 1), numVertices); numVertices = this.addVertices_(p0, p1, p2, -sign * _ol_render_webgl_LineStringReplay_.Instruction_.MITER_BOTTOM * (lineJoin || 1), numVertices); this.indices[numIndices++] = n; this.indices[numIndices++] = lastIndex - 1; this.indices[numIndices++] = lastIndex; this.indices[numIndices++] = n + 1; this.indices[numIndices++] = n; this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1; } }; /** * @param {Array.<number>} p0 Last coordinates. * @param {Array.<number>} p1 Current coordinates. * @param {Array.<number>} p2 Next coordinates. * @param {number} product Sign, instruction, and rounding product. * @param {number} numVertices Vertex counter. * @return {number} Vertex counter. * @private */ _ol_render_webgl_LineStringReplay_.prototype.addVertices_ = function(p0, p1, p2, product, numVertices) { this.vertices[numVertices++] = p0[0]; this.vertices[numVertices++] = p0[1]; this.vertices[numVertices++] = p1[0]; this.vertices[numVertices++] = p1[1]; this.vertices[numVertices++] = p2[0]; this.vertices[numVertices++] = p2[1]; this.vertices[numVertices++] = product; return numVertices; }; /** * Check if the linestring can be drawn (i. e. valid). * @param {Array.<number>} flatCoordinates Flat coordinates. * @param {number} offset Offset. * @param {number} end End. * @param {number} stride Stride. * @return {boolean} The linestring can be drawn. * @private */ _ol_render_webgl_LineStringReplay_.prototype.isValid_ = function(flatCoordinates, offset, end, stride) { var range = end - offset; if (range < stride * 2) { return false; } else if (range === stride * 2) { var firstP = [flatCoordinates[offset], flatCoordinates[offset + 1]]; var lastP = [flatCoordinates[offset + stride], flatCoordinates[offset + stride + 1]]; return !_ol_array_.equals(firstP, lastP); } return true; }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.drawLineString = function(lineStringGeometry, feature) { var flatCoordinates = lineStringGeometry.getFlatCoordinates(); var stride = lineStringGeometry.getStride(); if (this.isValid_(flatCoordinates, 0, flatCoordinates.length, stride)) { flatCoordinates = _ol_geom_flat_transform_.translate(flatCoordinates, 0, flatCoordinates.length, stride, -this.origin[0], -this.origin[1]); if (this.state_.changed) { this.styleIndices_.push(this.indices.length); this.state_.changed = false; } this.startIndices.push(this.indices.length); this.startIndicesFeature.push(feature); this.drawCoordinates_( flatCoordinates, 0, flatCoordinates.length, stride); } }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) { var indexCount = this.indices.length; var ends = multiLineStringGeometry.getEnds(); ends.unshift(0); var flatCoordinates = multiLineStringGeometry.getFlatCoordinates(); var stride = multiLineStringGeometry.getStride(); var i, ii; if (ends.length > 1) { for (i = 1, ii = ends.length; i < ii; ++i) { if (this.isValid_(flatCoordinates, ends[i - 1], ends[i], stride)) { var lineString = _ol_geom_flat_transform_.translate(flatCoordinates, ends[i - 1], ends[i], stride, -this.origin[0], -this.origin[1]); this.drawCoordinates_( lineString, 0, lineString.length, stride); } } } if (this.indices.length > indexCount) { this.startIndices.push(indexCount); this.startIndicesFeature.push(feature); if (this.state_.changed) { this.styleIndices_.push(indexCount); this.state_.changed = false; } } }; /** * @param {Array.<number>} flatCoordinates Flat coordinates. * @param {Array.<Array.<number>>} holeFlatCoordinates Hole flat coordinates. * @param {number} stride Stride. */ _ol_render_webgl_LineStringReplay_.prototype.drawPolygonCoordinates = function( flatCoordinates, holeFlatCoordinates, stride) { if (!_ol_geom_flat_topology_.lineStringIsClosed(flatCoordinates, 0, flatCoordinates.length, stride)) { flatCoordinates.push(flatCoordinates[0]); flatCoordinates.push(flatCoordinates[1]); } this.drawCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride); if (holeFlatCoordinates.length) { var i, ii; for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) { if (!_ol_geom_flat_topology_.lineStringIsClosed(holeFlatCoordinates[i], 0, holeFlatCoordinates[i].length, stride)) { holeFlatCoordinates[i].push(holeFlatCoordinates[i][0]); holeFlatCoordinates[i].push(holeFlatCoordinates[i][1]); } this.drawCoordinates_(holeFlatCoordinates[i], 0, holeFlatCoordinates[i].length, stride); } } }; /** * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {number=} opt_index Index count. */ _ol_render_webgl_LineStringReplay_.prototype.setPolygonStyle = function(feature, opt_index) { var index = opt_index === undefined ? this.indices.length : opt_index; this.startIndices.push(index); this.startIndicesFeature.push(feature); if (this.state_.changed) { this.styleIndices_.push(index); this.state_.changed = false; } }; /** * @return {number} Current index. */ _ol_render_webgl_LineStringReplay_.prototype.getCurrentIndex = function() { return this.indices.length; }; /** * @inheritDoc **/ _ol_render_webgl_LineStringReplay_.prototype.finish = function(context) { // create, bind, and populate the vertices buffer this.verticesBuffer = new _ol_webgl_Buffer_(this.vertices); // create, bind, and populate the indices buffer this.indicesBuffer = new _ol_webgl_Buffer_(this.indices); this.startIndices.push(this.indices.length); //Clean up, if there is nothing to draw if (this.styleIndices_.length === 0 && this.styles_.length > 0) { this.styles_ = []; } this.vertices = null; this.indices = null; }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.getDeleteResourcesFunction = function(context) { var verticesBuffer = this.verticesBuffer; var indicesBuffer = this.indicesBuffer; return function() { context.deleteBuffer(verticesBuffer); context.deleteBuffer(indicesBuffer); }; }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.setUpProgram = function(gl, context, size, pixelRatio) { // get the program var fragmentShader, vertexShader; fragmentShader = _ol_render_webgl_linestringreplay_defaultshader_.fragment; vertexShader = _ol_render_webgl_linestringreplay_defaultshader_.vertex; var program = context.getProgram(fragmentShader, vertexShader); // get the locations var locations; if (!this.defaultLocations_) { locations = new _ol_render_webgl_linestringreplay_defaultshader_Locations_(gl, program); this.defaultLocations_ = locations; } else { locations = this.defaultLocations_; } context.useProgram(program); // enable the vertex attrib arrays gl.enableVertexAttribArray(locations.a_lastPos); gl.vertexAttribPointer(locations.a_lastPos, 2, _ol_webgl_.FLOAT, false, 28, 0); gl.enableVertexAttribArray(locations.a_position); gl.vertexAttribPointer(locations.a_position, 2, _ol_webgl_.FLOAT, false, 28, 8); gl.enableVertexAttribArray(locations.a_nextPos); gl.vertexAttribPointer(locations.a_nextPos, 2, _ol_webgl_.FLOAT, false, 28, 16); gl.enableVertexAttribArray(locations.a_direction); gl.vertexAttribPointer(locations.a_direction, 1, _ol_webgl_.FLOAT, false, 28, 24); // Enable renderer specific uniforms. gl.uniform2fv(locations.u_size, size); gl.uniform1f(locations.u_pixelRatio, pixelRatio); return locations; }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.shutDownProgram = function(gl, locations) { gl.disableVertexAttribArray(locations.a_lastPos); gl.disableVertexAttribArray(locations.a_position); gl.disableVertexAttribArray(locations.a_nextPos); gl.disableVertexAttribArray(locations.a_direction); }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) { //Save GL parameters. var tmpDepthFunc = /** @type {number} */ (gl.getParameter(gl.DEPTH_FUNC)); var tmpDepthMask = /** @type {boolean} */ (gl.getParameter(gl.DEPTH_WRITEMASK)); if (!hitDetection) { gl.enable(gl.DEPTH_TEST); gl.depthMask(true); gl.depthFunc(gl.NOTEQUAL); } if (!_ol_obj_.isEmpty(skippedFeaturesHash)) { this.drawReplaySkipping_(gl, context, skippedFeaturesHash); } else { //Draw by style groups to minimize drawElements() calls. var i, start, end, nextStyle; end = this.startIndices[this.startIndices.length - 1]; for (i = this.styleIndices_.length - 1; i >= 0; --i) { start = this.styleIndices_[i]; nextStyle = this.styles_[i]; this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]); this.drawElements(gl, context, start, end); gl.clear(gl.DEPTH_BUFFER_BIT); end = start; } } if (!hitDetection) { gl.disable(gl.DEPTH_TEST); gl.clear(gl.DEPTH_BUFFER_BIT); //Restore GL parameters. gl.depthMask(tmpDepthMask); gl.depthFunc(tmpDepthFunc); } }; /** * @private * @param {WebGLRenderingContext} gl gl. * @param {ol.webgl.Context} context Context. * @param {Object} skippedFeaturesHash Ids of features to skip. */ _ol_render_webgl_LineStringReplay_.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) { var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart; featureIndex = this.startIndices.length - 2; end = start = this.startIndices[featureIndex + 1]; for (i = this.styleIndices_.length - 1; i >= 0; --i) { nextStyle = this.styles_[i]; this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]); groupStart = this.styleIndices_[i]; while (featureIndex >= 0 && this.startIndices[featureIndex] >= groupStart) { featureStart = this.startIndices[featureIndex]; feature = this.startIndicesFeature[featureIndex]; featureUid = _ol_.getUid(feature).toString(); if (skippedFeaturesHash[featureUid]) { if (start !== end) { this.drawElements(gl, context, start, end); gl.clear(gl.DEPTH_BUFFER_BIT); } end = featureStart; } featureIndex--; start = featureStart; } if (start !== end) { this.drawElements(gl, context, start, end); gl.clear(gl.DEPTH_BUFFER_BIT); } start = end = groupStart; } }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) { var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex; featureIndex = this.startIndices.length - 2; end = this.startIndices[featureIndex + 1]; for (i = this.styleIndices_.length - 1; i >= 0; --i) { nextStyle = this.styles_[i]; this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]); groupStart = this.styleIndices_[i]; while (featureIndex >= 0 && this.startIndices[featureIndex] >= groupStart) { start = this.startIndices[featureIndex]; feature = this.startIndicesFeature[featureIndex]; featureUid = _ol_.getUid(feature).toString(); if (skippedFeaturesHash[featureUid] === undefined && feature.getGeometry() && (opt_hitExtent === undefined || _ol_extent_.intersects( /** @type {Array<number>} */ (opt_hitExtent), feature.getGeometry().getExtent()))) { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); this.drawElements(gl, context, start, end); var result = featureCallback(feature); if (result) { return result; } } featureIndex--; end = start; } } return undefined; }; /** * @private * @param {WebGLRenderingContext} gl gl. * @param {Array.<number>} color Color. * @param {number} lineWidth Line width. * @param {number} miterLimit Miter limit. */ _ol_render_webgl_LineStringReplay_.prototype.setStrokeStyle_ = function(gl, color, lineWidth, miterLimit) { gl.uniform4fv(this.defaultLocations_.u_color, color); gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth); gl.uniform1f(this.defaultLocations_.u_miterLimit, miterLimit); }; /** * @inheritDoc */ _ol_render_webgl_LineStringReplay_.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) { var strokeStyleLineCap = strokeStyle.getLineCap(); this.state_.lineCap = strokeStyleLineCap !== undefined ? strokeStyleLineCap : _ol_render_webgl_.defaultLineCap; var strokeStyleLineDash = strokeStyle.getLineDash(); this.state_.lineDash = strokeStyleLineDash ? strokeStyleLineDash : _ol_render_webgl_.defaultLineDash; var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset(); this.state_.lineDashOffset = strokeStyleLineDashOffset ? strokeStyleLineDashOffset : _ol_render_webgl_.defaultLineDashOffset; var strokeStyleLineJoin = strokeStyle.getLineJoin(); this.state_.lineJoin = strokeStyleLineJoin !== undefined ? strokeStyleLineJoin : _ol_render_webgl_.defaultLineJoin; var strokeStyleColor = strokeStyle.getColor(); if (!(strokeStyleColor instanceof CanvasGradient) && !(strokeStyleColor instanceof CanvasPattern)) { strokeStyleColor = _ol_color_.asArray(strokeStyleColor).map(function(c, i) { return i != 3 ? c / 255 : c; }) || _ol_render_webgl_.defaultStrokeStyle; } else { strokeStyleColor = _ol_render_webgl_.defaultStrokeStyle; } var strokeStyleWidth = strokeStyle.getWidth(); strokeStyleWidth = strokeStyleWidth !== undefined ? strokeStyleWidth : _ol_render_webgl_.defaultLineWidth; var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); strokeStyleMiterLimit = strokeStyleMiterLimit !== undefined ? strokeStyleMiterLimit : _ol_render_webgl_.defaultMiterLimit; if (!this.state_.strokeColor || !_ol_array_.equals(this.state_.strokeColor, strokeStyleColor) || this.state_.lineWidth !== strokeStyleWidth || this.state_.miterLimit !== strokeStyleMiterLimit) { this.state_.changed = true; this.state_.strokeColor = strokeStyleColor; this.state_.lineWidth = strokeStyleWidth; this.state_.miterLimit = strokeStyleMiterLimit; this.styles_.push([strokeStyleColor, strokeStyleWidth, strokeStyleMiterLimit]); } }; /** * @enum {number} * @private */ _ol_render_webgl_LineStringReplay_.Instruction_ = { ROUND: 2, BEGIN_LINE: 3, END_LINE: 5, BEGIN_LINE_CAP: 7, END_LINE_CAP: 11, BEVEL_FIRST: 13, BEVEL_SECOND: 17, MITER_BOTTOM: 19, MITER_TOP: 23 }; export default _ol_render_webgl_LineStringReplay_;