利用百度地图进行城市功能区域划分

本文介绍如何使用百度地图API爬取特定区域内的兴趣点信息,并通过ArcGIS进行地理网格划分,实现城市功能区的定量识别。

记录:

  • 使用百度地图api进行各类兴趣点的划分
  • 将研究区域利用arcgismap进行网格的划分和渔网经纬度范围的导出
  • 将网格的范围与兴趣点坐标进行匹配与计算.
  • 利用所获得的区域的兴趣点的频率进行方格区域功能的判定

百度地图提取兴趣点信息

首先,在百度地图开放平台获取百度地图JavaScript API.这部分可以参考这里

获取到百度地图的唯一服务密钥AK之后,根据百度地图的官方文档,

https://api.map.baidu.com/place/v2/suggestion?query=天安门&region=北京&city_limit=true&output=json&ak=你的ak 

下面是部分参数的解释与属性值:

参数格式备注
query超市搜索兴趣点的关键词
region南京地区范围
coord_typeWGS84采用的坐标的类型
akE4805d16**********707cdc962045开发者访问密钥

下面是使用返回的json文件来获取的自动化脚本

import sys
import requests  #导入requests库,这是一个第三方库,把网页上的内容爬下来用的
import time
ty=sys.getfilesystemencoding()  #这个可以获取文件系统的编码形式
 
## 1. 基本参数设置:
 
lat_1 = 32.010402 # 南京市左下纬度118.711692,32.010402
lon_1 = 118.711692 # 南京市左下经度
lat_2 = 32.099151 # 南京市右上纬度
lon_2 = 118.834149 # 南京市右上经度118.834149,32.099151
 
las = 0.01  # 爬取时划分网格的经纬度间隔
ak='yourak' # 根据自己在百度地图注册平台上申请的AK
place = r'公园' # 爬取的POI类型,可以是学校、政府、超市、商场、小区、餐饮店等等,这里以政府为例
 
 

## 2. POI区域划分,按照经纬度间隔0.01度,将不同URL存入一个列表中
 
print ('*******************{}POI开始获取****************'.format(place))
urls=[] #声明一个数组列表
lat_count=int((lat_2-lat_1)/las+1)
lon_count=int((lon_2-lon_1)/las+1)
for lat_c in range(0,lat_count):
    for lon_c in range(0,lon_count):
        for i in range(0,20):
            page_num=str(i)
            url = 'https://api.map.baidu.com/place/v2/search?query=餐饮店&region=南京&page_size=20&page_num='+str(page_num)+'&output=json&ak=yourak'
            urls.append(url)
print ('url列表读取完成')
 
 
## 3. 为了方便看结果,这里设置了些参数
 
total_before = 0 
total = 0 # 获取总条数
label = 0 # 查看是否获取到数据的标志
count_20 = 0 # 查看每页超过20条的页数
K = 0 # 运行出错的断点数,代表第多少次循环
 
urls = urls[K:] # 防止出现意外,比如在百度地图获取的数据达到上限,就会终止服务,这里的K主要是为了从当前断点处继续爬取,所以需要根据自己程序终止断点设置;
count_xunhuan = len(urls) # 循环次数
count_xunhuan2 = count_xunhuan # 还剩循环次数,主要让自己知道大概有多少循环,每次都打印下,对程序运行时间有个大致了解;
 
 
# 4. 创建文件以及将爬取到的数据读入文件
 
f=open(r'C:\Users\HP\Desktop\result6.csv','a',encoding='gbk') # 根据爬取的POI类型创建文件
print("+++++++++++爬取需循环{}次++++++++++++".format(count_xunhuan))
for url in urls:
    time.sleep(1) # 为了防止并发量报警,设置了一个10秒的休眠。认证后就不需要了
    html = requests.get(url) # 获取网页信息
    data = html.json() # 获取网页信息的json格式数据
    total_before = total
    print(data)
    for item in data['results']: 
        jname = item['name'] # 获取名称
        jlat = item['location']['lat'] # 获取纬度
        jlon = item['location']['lng'] # 获取经度
        jadd = item['address'] # 获取详细地址
        jarea = item['area'] # 获取所在区或县
        j_str = jname + ',' + str(jlat) + ',' + str(jlon) + ',' + jadd + ',' + jarea + '\n' # 以逗号格式,将数据存入一个字符串
        print(j_str)
        f.write(j_str) # 将数据以行的形式写入CSV文件中
        total = total + 1 # 获取的数据记录数
        label = 1 # 表示每个小网格是否爬取到数据,如果为1,则表示获取到数据,执行下面的if语句,如果为0,则表示没有获取到数据;
    count_xunhuan2 = count_xunhuan2 - 1 # 循环次数减一,方便查看了解循环进度
    if label == 1:
        print("需循环{}次, 已循环{}次, 还剩{}次循环结束".format(count_xunhuan, count_xunhuan-count_xunhuan2, count_xunhuan2))
        print('新增{}条数据'.format(total-total_before))
        if total-total_before == 20:
                count_20 = count_20 + 1 # 查看获取到20条数据的页数,因为百度地图限制每页获取20条数据,如果该网格区域超过的话,也是爬取到20条,所以这里设置count_20查看下没有爬取完整的网格数,如果过多,则最好修改las经纬度间隔;
        print("---------已获取{}条数据----------".format(total))
    label = 0
print("每页新增超过20条的页数:{}".format(count_20))
f.close()

利用arcgis进行区域的方格划分

地图要素的采集,使用bbbike的OpenStreet Map划分地图范围,提取范围内的土地利用数据.
使用折线划分所要研究的区域的范围,进行区域的划分,这里使用渔网的功能参考这篇博文

获取的网格经纬度范围与兴趣点坐标进行匹配计算

利用区域划分方格的经纬度范围比较获取的兴趣点的范围,进行区域的功能判定,这里使用的标准是:

注意兴趣点与方格的坐标系相统一.百度api获取的是WGSA-84坐标系.

论文出处见下方
出自:基于空间格网的城市功能区定量识别_骆少华.
使用的自动化脚本如下:

# Package
import numpy as np
import pandas as pd
import csv
Div = pd.read_csv(r'C:\Users\HP\Desktop\grid.csv',encoding='gbk')
Data = pd.read_csv(r'C:\Users\HP\Desktop\result1.csv',encoding='gbk')# Defineing
x_max = Div['Longitude_min']
x_min = Div['Longitude_max']
y_up = Div['Latitude_up']
y_down = Div['Latitude_down']
x = Data['WGS_long']
y = Data['WGS_lat']
# main
num=0
nums=[]
for i in range(420):
    for j in range(3948):
        df = (x[j]>x_min[i])&(x[j]<x_max[i])&(y[j]>y_down[i])&(y[j]<y_up[i])
        if df == True:
            num = num+1
    nums.append(num)
df = pd.DataFrame(nums)
df.to_csv(r'C:\Users\HP\Desktop\hope.csv')
<think>我们之前已经讨论了有限源网格划分的原理、方法及应用,现在用户明确要求了解“使用Java对给定区域进行有限网格划分”。因此,我们将专注于这一具体任务,详细说明在Java中如何实现。 ### 核心步骤 1. **定义网格区域**:确定网格的地理范围(最小/最大经纬度或坐标)和分辨率(网格大小)。 2. **选择插值算法**:如反距离加权(IDW)、克里金(Kriging)等。 3. **数据预处理**:将离散点数据组织成适合计算的结构。 4. **网格计算**:遍历每个网格节点,根据插值算法计算其值。 5. **结果输出**:将网格数据输出为矩阵或文件。 ### Java实现详解 #### 1. 定义网格区域 ```java public class GridArea { private double minX; // 区域最小X坐标 private double maxX; // 区域最大X坐标 private double minY; // 区域最小Y坐标 private double maxY; // 区域最大Y坐标 private int rows; // 网格行数 private int cols; // 网格列数 // 计算网格分辨率 public double getCellWidth() { return (maxX - minX) / cols; } public double getCellHeight() { return (maxY - minY) / rows; } } ``` #### 2. 数据点表示 ```java public class DataPoint { private double x; // X坐标 private double y; // Y坐标 private double value; // 数据值(如温度、高度等) } ``` #### 3. IDW插值实现 ```java import java.util.List; public class GridGenerator { public double[][] generateGrid(GridArea area, List<DataPoint> points, double power) { int rows = area.getRows(); int cols = area.getCols(); double[][] grid = new double[rows][cols]; double cellWidth = area.getCellWidth(); double cellHeight = area.getCellHeight(); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { // 计算当前网格中心点坐标 double gridX = area.getMinX() + (col + 0.5) * cellWidth; double gridY = area.getMinY() + (row + 0.5) * cellHeight; double sumWeights = 0.0; double sumValues = 0.0; for (DataPoint point : points) { double dist = calculateDistance(gridX, gridY, point.getX(), point.getY()); // 避免除零错误 if (dist == 0) { sumWeights = 1.0; sumValues = point.getValue(); break; } double weight = 1 / Math.pow(dist, power); sumWeights += weight; sumValues += point.getValue() * weight; } grid[row][col] = sumValues / sumWeights; } } return grid; } private double calculateDistance(double x1, double y1, double x2, double y2) { return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } } ``` #### 4. 结果可视化(简化) 将生成的网格数据输出为CSV文件,可用Excel或GIS工具可视化: ```java import java.io.FileWriter; import java.io.IOException; public class GridExporter { public static void exportToCSV(double[][] grid, String filename) throws IOException { try (FileWriter writer = new FileWriter(filename)) { for (double[] row : grid) { for (int i = 0; i < row.length; i++) { writer.append(String.format("%.2f", row[i])); if (i < row.length - 1) writer.append(","); } writer.append("\n"); } } } } ``` ### 应用实例:生成温度分布网格 ```java public class Main { public static void main(String[] args) { // 1. 定义区域:经度[100,120],纬度[20,40],划分为100x100网格 GridArea area = new GridArea(100, 120, 20, 40, 100, 100); // 2. 模拟离散温度数据点 List<DataPoint> points = new ArrayList<>(); points.add(new DataPoint(105, 25, 28.5)); points.add(new DataPoint(115, 35, 32.0)); // ... 添加更多点 // 3. 生成网格 GridGenerator generator = new GridGenerator(); double[][] tempGrid = generator.generateGrid(area, points, 2.0); // power=2 // 4. 导出结果 try { GridExporter.exportToCSV(tempGrid, "temperature_grid.csv"); } catch (IOException e) { e.printStackTrace(); } } } ``` ### 性能优化建议 1. **空间索引**:使用四叉树或R树加速邻近点查询,避免全表扫描[^1]。 2. **并行计算**:将网格行分片,用`ForkJoinPool`并行处理: ```java public double[][] parallelIDW(GridArea area, List<DataPoint> points, double power) { double[][] grid = new double[area.getRows()][area.getCols()]; ForkJoinPool pool = new ForkJoinPool(); pool.invoke(new IDWTask(area, points, power, grid, 0, area.getRows())); return grid; } class IDWTask extends RecursiveAction { // 实现细节:划分行范围,递归执行 } ``` 3. **距离计算优化**:对远距离点设置阈值,忽略权重过小的点(如距离>10倍网格宽度)[^1]。 ### 应用场景扩展 - **环境监测**:根据传感器数据生成污染物浓度分布图[^2]。 - **农业规划**:基于土壤采样点划分肥力网格,指导精准施肥[^3]。 --- ### §§相关问题§§ 1. 如何选择IDW插值中的最优幂参数$p$? 2. 在Java中如何实现四叉树空间索引加速网格插值? 3. 网格划分结果如何转换为等高线图? 4. 如何处理网格划分中边缘区域的插值误差? [^1]: 空间索引技术在网格计算中的应用 [^2]: 基于网格插值的城市空气质量监测系统 [^3]: 精准农业中的网格化土壤分析 </think> ### 使用 Java 实现有限网格划分的技术详解 #### 一、核心原理 有限网格划分将连续空间离散化为规则单元,数学表示为: $$ G_{ij} = \left\{ (x,y) \mid x_i \leq x < x_{i+1},\ y_j \leq y < y_{j+1} \right\} $$ 其中 $i=1,2,...,m$, $j=1,2,...,n$ 为网格索引。关键原理包括: 1. **空间离散化**:将区域划分为 $m \times n$ 个矩形单元 2. **数据映射**:将源数据关联到对应网格单元 3. **插值计算**:对无数据网格使用 IDW(反距离加权)等方法填充[^1] #### 二、Java 实现方法 ##### 1. 基础网格生成 ```java public class GridGenerator { private final double minX, maxX, minY, maxY; private final int rows, cols; private final double[][] grid; // 初始化网格区域 public GridGenerator(double minX, double maxX, double minY, double maxY, int rows, int cols) { this.minX = minX; this.maxX = maxX; this.minY = minY; this.maxY = maxY; this.rows = rows; this.cols = cols; this.grid = new double[rows][cols]; } // 计算网格单元宽度/高度 public double getCellWidth() { return (maxX - minX) / cols; } public double getCellHeight() { return (maxY - minY) / rows; } // 坐标到网格索引映射 public int[] getGridIndex(double x, double y) { int col = (int) ((x - minX) / getCellWidth()); int row = (int) ((y - minY) / getCellHeight()); return new int[]{Math.min(Math.max(row, 0), rows-1), Math.min(Math.max(col, 0), cols-1)}; } } ``` ##### 2. 数据点映射与 IDW 插值 ```java public void populateGrid(List<DataPoint> points, double power) { // 初始化网格数据存储 List<List<DataPoint>> cellPoints = new ArrayList<>(rows * cols); for (int i = 0; i < rows * cols; i++) { cellPoints.add(new ArrayList<>()); } // 数据点分配到网格单元 for (DataPoint p : points) { int[] idx = getGridIndex(p.x, p.y); int index = idx[0] * cols + idx[1]; cellPoints.get(index).add(p); } // IDW 插值填充空网格 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { List<DataPoint> cellData = cellPoints.get(i * cols + j); if (!cellData.isEmpty()) { grid[i][j] = cellData.stream() .mapToDouble(p -> p.value) .average() .orElse(0); } else { grid[i][j] = idwInterpolation(i, j, points, power); } } } } // IDW 插值核心算法 private double idwInterpolation(int row, int col, List<DataPoint> points, double power) { double gridX = minX + (col + 0.5) * getCellWidth(); double gridY = minY + (row + 0.5) * getCellHeight(); double sumWeights = 0.0; double sumValues = 0.0; for (DataPoint p : points) { double dist = Math.sqrt(Math.pow(gridX - p.x, 2) + Math.pow(gridY - p.y, 2)); // 避免除零错误 if (dist < 1e-6) return p.value; double weight = 1 / Math.pow(dist, power); sumWeights += weight; sumValues += weight * p.value; } return sumValues / sumWeights; } ``` ##### 3. 性能优化技术 ```java // 四叉树空间索引加速邻近点查询 public class QuadTree { private final int capacity; private final Rectangle boundary; private final List<DataPoint> points = new ArrayList<>(); private QuadTree[] children; public QuadTree(Rectangle boundary, int capacity) { this.boundary = boundary; this.capacity = capacity; } public void insert(DataPoint p) { if (!boundary.contains(p.x, p.y)) return; if (points.size() < capacity) { points.add(p); } else { if (children == null) split(); for (QuadTree child : children) child.insert(p); } } // 范围查询算法 public List<DataPoint> query(Rectangle range) { List<DataPoint> found = new ArrayList<>(); if (!boundary.intersects(range)) return found; for (DataPoint p : points) { if (range.contains(p.x, p.y)) found.add(p); } if (children != null) { for (QuadTree child : children) { found.addAll(child.query(range)); } } return found; } } ``` #### 三、应用案例 1. **城市热力图生成** ```java // 基于网格数据生成热力图 public BufferedImage generateHeatmap() { BufferedImage img = new BufferedImage(cols, rows, BufferedImage.TYPE_INT_ARGB); double maxVal = Arrays.stream(grid).flatMapToDouble(Arrays::stream).max().orElse(1); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { int intensity = (int) (255 * grid[i][j] / maxVal); int rgb = new Color(intensity, 0, 255 - intensity).getRGB(); img.setRGB(j, i, rgb); } } return img; } ``` 2. **路径规划网格** ```java // A*算法中的网格导航 public List<Point> findPath(Point start, Point end) { int[] startIdx = getGridIndex(start.x, start.y); int[] endIdx = getGridIndex(end.x, end.y); // 实现A*算法 PriorityQueue<Node> openSet = new PriorityQueue<>(); double[][] gScore = new double[rows][cols]; // ... 路径搜索实现 ... } ``` #### 四、实际应用场景 1. **智慧城市管理** - 社区划分为 $100m \times 100m$ 网格,每个网格关联人口/设施数据[^2] - 疫情监控:统计各网格病例密度生成风险热力图[^3] 2. **地理信息系统** - 生成高程网格:$z = f(x,y)$ 地形建模 - 气象数据网格化:温度/降水分布可视化[^1] 3. **工业仿真** - 有限元分析前处理:将零件表面划分为三角网格 - 流体动力学模拟:计算网格的流速/压力分布 #### 五、性能优化建议 1. **空间索引**:四叉树/KD树加速邻近点查询 2. **并行计算**:使用 ForkJoinPool 并行处理网格单元 3. **LOD技术**:动态调整网格分辨率 ```java // 基于视距的细节层次 public void render(Graphics g, int zoomLevel) { int renderStep = Math.max(1, 10 - zoomLevel); // 缩放级别控制密度 for (int i = 0; i < rows; i += renderStep) { for (int j = 0; j < cols; j += renderStep) { // 简化绘制 } } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值