Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

uber / deck.gl / 13945

20 Sep 2019 - 0:32 coverage decreased (-2.9%) to 79.802%
13945

Pull #3655

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Update layer.md
Pull Request #3655: Update pydeck layer docs

3399 of 4611 branches covered (73.72%)

Branch coverage included in aggregate %.

7024 of 8450 relevant lines covered (83.12%)

5682.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.84
/modules/aggregation-layers/src/utils/gpu-grid-aggregation/grid-aggregation-utils.js
1
import {Matrix4} from 'math.gl';
7×
2
import {fp64 as fp64Utils} from '@luma.gl/core';
3
import {COORDINATE_SYSTEM, log, createIterable, experimental} from '@deck.gl/core';
4
const {count} = experimental;
1×
5
const {fp64LowPart} = fp64Utils;
1×
6

7
const R_EARTH = 6378000;
1×
8

9
function toFinite(n) {
10
  return Number.isFinite(n) ? n : 0;
72×
11
}
12

13
// Takes data and aggregation params and returns aggregated data.
14
export function pointToDensityGridData({
15
  data,
16
  getPosition,
17
  cellSizeMeters,
18
  gpuGridAggregator,
19
  gpuAggregation,
20
  aggregationFlags,
21
  weightParams,
22
  fp64 = false,
Branches [[1, 0]] missed.
23
  coordinateSystem = COORDINATE_SYSTEM.LNGLAT,
24
  viewport = null,
25
  boundingBox = null
26
}) {
27
  let gridData = {};
20×
28
  if (aggregationFlags.dataChanged) {
20×
29
    gridData = parseGridData(data, getPosition, weightParams);
18×
30
    boundingBox = gridData.boundingBox;
18×
31
  }
32
  let cellSize = [cellSizeMeters, cellSizeMeters];
20×
33
  let worldOrigin = [0, 0];
20×
34
  log.assert(
20×
35
    coordinateSystem === COORDINATE_SYSTEM.LNGLAT || coordinateSystem === COORDINATE_SYSTEM.IDENTITY
Branches [[6, 1]] missed.
36
  );
37

38
  switch (coordinateSystem) {
Branches [[7, 2], [7, 3]] missed. 20×
39
    case COORDINATE_SYSTEM.LNGLAT:
40
    case COORDINATE_SYSTEM.LNGLAT_DEPRECATED:
41
      const gridOffset = getGridOffset(boundingBox, cellSizeMeters);
20×
42
      cellSize = [gridOffset.xOffset, gridOffset.yOffset];
20×
43
      worldOrigin = [-180, -90]; // Origin used to define grid cell boundaries
20×
44
      break;
20×
45
    case COORDINATE_SYSTEM.IDENTITY:
UNCOV
46
      const {width, height} = viewport;
!
UNCOV
47
      worldOrigin = [-width / 2, -height / 2]; // Origin used to define grid cell boundaries
!
UNCOV
48
      break;
!
49
    default:
50
      // Currently other coodinate systems not supported/verified.
UNCOV
51
      log.assert(false);
!
52
  }
53

54
  const opts = getGPUAggregationParams({boundingBox, cellSize, worldOrigin});
20×
55

56
  const aggregatedData = gpuGridAggregator.run({
20×
57
    positions: gridData.positions,
58
    positions64xyLow: gridData.positions64xyLow,
59
    weights: gridData.weights,
60
    cellSize,
61
    width: opts.width,
62
    height: opts.height,
63
    gridTransformMatrix: opts.gridTransformMatrix,
64
    useGPU: gpuAggregation,
65
    changeFlags: aggregationFlags,
66
    fp64
67
  });
68

69
  return {
20×
70
    weights: aggregatedData,
71
    gridSize: opts.gridSize,
72
    gridOrigin: opts.gridOrigin,
73
    cellSize,
74
    boundingBox
75
  };
76
}
77

78
// Parse input data to build positions, wights and bounding box.
79
/* eslint-disable max-statements */
80
function parseGridData(data, getPosition, weightParams) {
81
  const pointCount = count(data);
18×
82

83
  // For CPU Aggregation this needs to have full 64 bit precession, hence don't use FLoat32Array
84
  // For GPU Aggregation this will be converted into Float32Array
85
  const positions = new Float64Array(pointCount * 2);
18×
86
  const positions64xyLow = new Float32Array(pointCount * 2);
18×
87

88
  let yMin = Infinity;
18×
89
  let yMax = -Infinity;
18×
90
  let xMin = Infinity;
18×
91
  let xMax = -Infinity;
18×
92
  let y;
93
  let x;
94

95
  const weights = {};
18×
96
  for (const name in weightParams) {
18×
97
    weights[name] = Object.assign({}, weightParams[name], {
28×
98
      values: new Float32Array(pointCount * 3)
99
    });
100
  }
101

102
  const {iterable, objectInfo} = createIterable(data);
18×
103
  for (const object of iterable) {
18×
104
    objectInfo.index++;
5,082×
105
    const position = getPosition(object, objectInfo);
5,082×
106
    const {index} = objectInfo;
5,082×
107
    x = position[0];
5,082×
108
    y = position[1];
5,082×
109
    positions[index * 2] = x;
5,082×
110
    positions[index * 2 + 1] = y;
5,082×
111

112
    positions64xyLow[index * 2] = fp64LowPart(x);
5,082×
113
    positions64xyLow[index * 2 + 1] = fp64LowPart(y);
5,082×
114

115
    for (const name in weightParams) {
5,082×
116
      const weight = weightParams[name].getWeight(object);
5,109×
117

118
      // Aggregator expects each weight is an array of size 3
119
      if (Array.isArray(weight)) {
Branches [[8, 0]] missed. 5,109×
UNCOV
120
        weights[name].values[index * 3] = weight[0];
!
UNCOV
121
        weights[name].values[index * 3 + 1] = weight[1];
!
UNCOV
122
        weights[name].values[index * 3 + 2] = weight[2];
!
123
      } else {
124
        // backward compitability
125
        weights[name].values[index * 3] = weight;
5,109×
126
      }
127
    }
128

129
    if (Number.isFinite(y) && Number.isFinite(x)) {
Branches [[9, 1]] missed. 5,082×
130
      yMin = y < yMin ? y : yMin;
5,082×
131
      yMax = y > yMax ? y : yMax;
5,082×
132

133
      xMin = x < xMin ? x : xMin;
5,082×
134
      xMax = x > xMax ? x : xMax;
5,082×
135
    }
136
  }
137

138
  const boundingBox = {
18×
139
    xMin: toFinite(xMin),
140
    xMax: toFinite(xMax),
141
    yMin: toFinite(yMin),
142
    yMax: toFinite(yMax)
143
  };
144
  return {
18×
145
    positions,
146
    positions64xyLow,
147
    weights,
148
    boundingBox
149
  };
150
}
151
/* eslint-enable max-statements */
152

153
/**
154
 * Based on geometric center of sample points, calculate cellSize in lng/lat (degree) space
155
 * @param {object} gridData - contains bounding box of data
156
 * @param {number} cellSize - grid cell size in meters
157
 * @returns {yOffset, xOffset} - cellSize size lng/lat (degree) space.
158
 */
159

160
function getGridOffset(boundingBox, cellSize) {
161
  const {yMin, yMax} = boundingBox;
20×
162
  const latMin = yMin;
20×
163
  const latMax = yMax;
20×
164
  const centerLat = (latMin + latMax) / 2;
20×
165

166
  return calculateGridLatLonOffset(cellSize, centerLat);
20×
167
}
168

169
/**
170
 * calculate grid layer cell size in lat lon based on world unit size
171
 * and current latitude
172
 * @param {number} cellSize
173
 * @param {number} latitude
174
 * @returns {object} - lat delta and lon delta
175
 */
176
function calculateGridLatLonOffset(cellSize, latitude) {
177
  const yOffset = calculateLatOffset(cellSize);
20×
178
  const xOffset = calculateLonOffset(latitude, cellSize);
20×
179
  return {yOffset, xOffset};
20×
180
}
181

182
/**
183
 * with a given x-km change, calculate the increment of latitude
184
 * based on stackoverflow http://stackoverflow.com/questions/7477003
185
 * @param {number} dy - change in km
186
 * @return {number} - increment in latitude
187
 */
188
function calculateLatOffset(dy) {
189
  return (dy / R_EARTH) * (180 / Math.PI);
20×
190
}
191

192
/**
193
 * with a given x-km change, and current latitude
194
 * calculate the increment of longitude
195
 * based on stackoverflow http://stackoverflow.com/questions/7477003
196
 * @param {number} lat - latitude of current location (based on city)
197
 * @param {number} dx - change in km
198
 * @return {number} - increment in longitude
199
 */
200
function calculateLonOffset(lat, dx) {
201
  return ((dx / R_EARTH) * (180 / Math.PI)) / Math.cos((lat * Math.PI) / 180);
20×
202
}
203

204
// Aligns `inValue` to given `cellSize`
205
export function alignToCell(inValue, cellSize) {
206
  const sign = inValue < 0 ? -1 : 1;
Branches [[15, 0]] missed. 40×
207

208
  let value = sign < 0 ? Math.abs(inValue) + cellSize : Math.abs(inValue);
Branches [[16, 0]] missed. 40×
209

210
  value = Math.floor(value / cellSize) * cellSize;
40×
211

212
  return value * sign;
40×
213
}
214

215
// Calculate grid parameters
216
function getGPUAggregationParams({boundingBox, cellSize, worldOrigin}) {
217
  const {yMin, yMax, xMin, xMax} = boundingBox;
20×
218

219
  // NOTE: this alignment will match grid cell boundaries with existing CPU implementation
220
  // this gurantees identical aggregation results when switching between CPU and GPU aggregation.
221
  // Also gurantees same cell boundaries, when overlapping between two different layers (like ScreenGrid and Contour)
222
  // We first move worldOrigin to [0, 0], align the lower bounding box , then move worldOrigin to its original value.
223
  const originX = alignToCell(xMin - worldOrigin[0], cellSize[0]) + worldOrigin[0];
20×
224
  const originY = alignToCell(yMin - worldOrigin[1], cellSize[1]) + worldOrigin[1];
20×
225

226
  // Setup transformation matrix so that every point is in +ve range
227
  const gridTransformMatrix = new Matrix4().translate([-1 * originX, -1 * originY, 0]);
20×
228

229
  const gridOrigin = [originX, originY];
20×
230
  const width = xMax - xMin + cellSize[0];
20×
231
  const height = yMax - yMin + cellSize[1];
20×
232

233
  const gridSize = [Math.ceil(width / cellSize[0]), Math.ceil(height / cellSize[1])];
20×
234

235
  return {
20×
236
    gridOrigin,
237
    gridSize,
238
    width,
239
    height,
240
    gridTransformMatrix
241
  };
242
}
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2019 Coveralls, LLC