Ios 谷歌地图热地图颜色平均重量

Ios 谷歌地图热地图颜色平均重量,ios,objective-c,google-maps,heatmap,Ios,Objective C,Google Maps,Heatmap,Google Maps iOS SDK的热图(更具体地说是)主要通过计算区域中点的密度来决定渲染区域的颜色 但是,我想根据该区域点的平均重量或强度来选择颜色 据我所知,这种行为不是内置的(但谁知道呢——文档有点糟糕)。决定颜色选择的文件是我认为在/src/Heatmap/GMUHeatmapTileLayer.m中这是一个相对较短的文件,但我对Objective-C不是很精通,所以我很难弄清楚是什么做的。我认为-tileForX:y:zoom:inGMUHeatmapTileLayer.m是重要

Google Maps iOS SDK的热图(更具体地说是)主要通过计算区域中点的密度来决定渲染区域的颜色

但是,我想根据该区域点的平均重量或强度来选择颜色

据我所知,这种行为不是内置的(但谁知道呢——文档有点糟糕)。决定颜色选择的文件是我认为在
/src/Heatmap/GMUHeatmapTileLayer.m
中这是一个相对较短的文件,但我对Objective-C不是很精通,所以我很难弄清楚是什么做的。我认为
-tileForX:y:zoom:
in
GMUHeatmapTileLayer.m
是重要的功能,但我不确定,即使是这样,我也不知道如何修改它。在该方法的末尾,数据先水平“卷积”,然后垂直“卷积”。我想这就是实际计算强度的地方。不幸的是,我不知道它到底在做什么,我害怕改变事情,因为我在obj-c很烂。此方法的卷积部分如下所示:

- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {

  // ...

  // Convolve data.
  int lowerLimit = (int)data->_radius;
  int upperLimit = paddedTileSize - (int)data->_radius - 1;
  // Convolve horizontally first.
  float *intermediate = calloc(paddedTileSize * paddedTileSize, sizeof(float));
  for (int y = 0; y < paddedTileSize; y++) {
    for (int x = 0; x < paddedTileSize; x++) {
      float value = intensity[y * paddedTileSize + x];
      if (value != 0) {
        // convolve to x +/- radius bounded by the limit we care about.
        int start = MAX(lowerLimit, x - (int)data->_radius);
        int end = MIN(upperLimit, x + (int)data->_radius);
        for (int x2 = start; x2 <= end; x2++) {
          float scaledKernel = value * [data->_kernel[x2 - x + data->_radius] floatValue];
          // I THINK THIS IS WHERE I NEED TO MAKE THE CHANGE
          intermediate[y * paddedTileSize + x2] += scaledKernel;
          // ^
        }
      }
    }
  }
  free(intensity);
  // Convole vertically to get final intensity.
  float *finalIntensity = calloc(kGMUTileSize * kGMUTileSize, sizeof(float));
  for (int x = lowerLimit; x <= upperLimit; x++) {
    for (int y = 0; y < paddedTileSize; y++) {
      float value = intermediate[y * paddedTileSize + x];
      if (value != 0) {
        int start = MAX(lowerLimit, y - (int)data->_radius);
        int end = MIN(upperLimit, y + (int)data->_radius);
        for (int y2 = start; y2 <= end; y2++) {
          float scaledKernel = value * [data->_kernel[y2 - y + data->_radius] floatValue];
          // I THINK THIS IS WHERE I NEED TO MAKE THE CHANGE
          finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
          // ^
        }
      }
    }
  }
  free(intermediate);

  // ...

}
-(UIImage*)tileForX:(NSUInteger)x y:(NSUInteger)y缩放:(NSUInteger)缩放{
// ...
//卷积数据。
int lowerLimit=(int)数据->半径;
int上限=填充文件大小-(int)数据->半径-1;
//先水平卷积。
float*mediate=calloc(paddedTileSize*paddedTileSize,sizeof(float));
对于(int y=0;y半径);
int end=最小值(上限,x+(int)数据->半径);
对于(intx2=start;x2_内核[x2-x+data->_半径]floatValue];
//我想这是我需要改变的地方
中间[y*填充文件大小+x2]+=scaledKernel;
// ^
}
}
}
}
自由(强度);
//垂直旋转以获得最终强度。
float*finalIntensity=calloc(kGMUTileSize*kGMUTileSize,sizeof(float));
对于(int x=下限;x_半径);
int end=最小值(上限,y+(int)数据->半径);
for(int y2=start;y2_内核[y2-y+data->_半径]floatValue];
//我想这是我需要改变的地方
最终密度[(y2-lowerLimit)*kGMUTileSize+x-lowerLimit]+=scaledKernel;
// ^
}
}
}
}
免费(中级);
// ...
}
这就是每次迭代计算强度的方法,对吗?如果是这样,我如何改变它以达到我想要的效果(平均,而不是总结性的颜色,我认为这与强度成正比)


那么:如何通过修改框架来计算平均强度而不是求和强度?

我认为您的思路是正确的。要计算平均强度,请将点和除以点计数。由于您已经计算了总和,我认为一个简单的解决方案是还保存每个点的计数。如果我理解正确,这这是你必须做的

为总和分配内存时,也为计数分配内存

// At this place
float *intermediate = calloc(paddedTileSize * paddedTileSize, sizeof(float));
// Add this line, calloc will initialize them to zero
int *counts = calloc(paddedTileSize * paddedTileSize, sizeof(int));
然后增加每个循环中的计数

// Below this line (first loop)
intermediate[y * paddedTileSize + x2] += scaledKernel;
// Add this
counts[y * paddedTileSize + x2]++;

// And below this line (second loop)
finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
// Add this
counts[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit]++;
在两个循环之后,你应该有两个数组,一个是你的总和
finalIntensity
,另一个是你的计数
counts

for (int y = 0; y < paddedTileSize; y++) {
    for (int x = 0; x < paddedTileSize; x++) {
        int n = y * paddedTileSize + x;
        if (counts[n] != 0)
            finalIntensity[n] = finalIntensity[n] / counts[n];
    }
}
free(counts);
for(int y=0;y
finalIntensity
现在应该包含您的平均值

for (int y = 0; y < paddedTileSize; y++) {
    for (int x = 0; x < paddedTileSize; x++) {
        int n = y * paddedTileSize + x;
        if (counts[n] != 0)
            finalIntensity[n] = finalIntensity[n] / counts[n];
    }
}
free(counts);

如果您愿意,并且代码的其余部分允许,您可以跳过最后一个循环,在使用最终强度值时进行除法。只需将任何后续的
finalIntensity[n]
更改为
counts[n]==0?finalIntensity[n]:finalIntensity[n]/counts[n]

我可能刚刚解决了java版本的相同问题

我的问题是有12个不同值的自定义渐变。 但我的实际加权数据并不一定包含从1到12的所有强度值

问题是,最高强度值会映射到最高颜色。 同样,10个接近强度为1的数据点将获得与强度为12的单个点相同的颜色

因此,创建磁贴的函数是一个很好的起点:

爪哇:

对于C:

// Generate coloring
// ...
float max = [data->_maxIntensities[zoom] floatValue];
max = _gradient.startPoints.count;
我用Java实现了这一点,它对我来说很有效,但不确定C代码

你必须处理半径,你甚至可以编辑内核。因为我发现当我有很多同质数据(即强度变化很小,或者通常有很多数据)时,热图会退化为单色叠加,因为边缘上的梯度会越来越小

但希望这能有所帮助


//Erik

通常最好将
calloc()和
free()配对
。由于
计数
只是临时使用,因此在达到其目的后可以释放。不这样做会导致每次运行代码片段时内存泄漏。但是,如果您确定
paddedTitleSize
在应用程序的生命周期内不会更改,您当然可以执行
calloc()
有一次,当应用程序启动时,永远不要释放它。这可能会给你一个小的速度提升。你知道如何或者是否可以利用它以两种不同的颜色显示像“是”和“否”这样的投票吗?我曾想过按原样使用强度,但现在我意识到每个点都包含e
// Convolve it ("smoothen" it out)
double[][] convolved = convolve(intensity, mKernel, mMaxAverage);

// the mMaxAverage gets set here:
public void setWeightedData(Collection<WeightedLatLng> data) {
// ...
    // Add points to quad tree
    for (WeightedLatLng l : mData) {
        mTree.add(l);
        mMaxAverage = Math.max(l.getIntensity(), mMaxAverage);
    }
// ...
// And finally the convolve method:
static double[][] convolve(double[][] grid, double[] kernel, double max) {
// ...
    intermediate[x2][y] += val * kernel[x2 - (x - radius)];
    if (intermediate[x2][y] > max) intermediate[x2][y] = max;
// ...
    outputGrid[x - radius][y2 - radius] += val * kernel[y2 - (y - radius)];
    if (outputGrid[x - radius][y2 - radius] > max ) outputGrid[x - radius][y2 - radius] = max;
// To get the maximum average you could do that here:
- (void)setWeightedData:(NSArray<GMUWeightedLatLng *> *)weightedData {
    _weightedData = [weightedData copy];
    for (GMUWeightedLatLng *dataPoint in _weightedData)
        _maxAverage = Math.max(dataPoint.intensity, _maxAverage)
// ...
// And then simply in the convolve section
    intermediate[y * paddedTileSize + x2] += scaledKernel;
    if (intermediate[y * paddedTileSize + x2] > _maxAverage) 
        intermediate[y * paddedTileSize + x2] = _maxAverage;
// ...
   finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] += scaledKernel;
   if (finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] > _maxAverage)
       finalIntensity[(y2 - lowerLimit) * kGMUTileSize + x - lowerLimit] = _maxAverage;
// The maximum intensity is simply the size of my gradient colors array (or the starting points) 
Bitmap bitmap = colorize(convolved, mColorMap, mGradient.mStartPoints.length);
// Generate coloring
// ...
float max = [data->_maxIntensities[zoom] floatValue];
max = _gradient.startPoints.count;