TowerUtils.java 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package com.qingjian.common.utils;
  2. import cn.hutool.core.io.FileUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.qingjian.common.constants.PathConst;
  5. import com.sun.jna.ptr.DoubleByReference;
  6. import lombok.extern.slf4j.Slf4j;
  7. import java.nio.charset.StandardCharsets;
  8. import java.nio.file.Files;
  9. import java.nio.file.Path;
  10. import java.nio.file.Paths;
  11. import java.util.concurrent.atomic.AtomicBoolean;
  12. /**
  13. * 基站定位工具类
  14. * <p>
  15. * 通过调用动态链接库实现基站信息查询和逆地理编码功能
  16. * 支持将WGS84坐标转换为百度BD09坐标
  17. * </p>
  18. *
  19. * @author cc
  20. */
  21. @Slf4j
  22. public class TowerUtils {
  23. private static final int ADDRESS_BUFFER_SIZE = 2048;
  24. private static final AtomicBoolean FLAG = new AtomicBoolean(false);
  25. /**
  26. * 根据操作系统类型返回对应的动态链接库路径
  27. * Windows系统使用DLL,Linux系统使用SO
  28. *
  29. * @return 动态链接库路径字符串
  30. */
  31. public static String dll() {
  32. return LicenseUtil.isWin() ? PathConst.CELL_TOWER_PATH.toString() : PathConst.CELL_TOWER_PATH_SO.toString();
  33. }
  34. /**
  35. * 初始化基站数据库
  36. * <p>
  37. * 在首次使用前必须调用此方法进行初始化
  38. * 加载基站数据文件到内存中
  39. * </p>
  40. */
  41. public static void init() {
  42. if (FLAG.get()) {
  43. log.info("基站数据库路径已经加载,无需再次初始化!");
  44. return;
  45. }
  46. String cellLocal = SystemConfManager.INSTANCE.getCellLocal();
  47. if (StrUtil.isEmpty(cellLocal)) {
  48. log.info("请先设置基站数据库路径!");
  49. return;
  50. }
  51. Path path = Paths.get(cellLocal);
  52. if (Files.exists(path)) {
  53. String name = FileUtil.getName(path);
  54. if (StrUtil.endWith(name, ".bin")) {
  55. log.info("基站数据库文件名不正确!");
  56. return;
  57. }
  58. CellDll.INSTANCE_DLL.cell_init(cellLocal);
  59. FLAG.set(true);
  60. log.info("基站数据库路径已经加载!");
  61. return;
  62. }
  63. log.info("基站数据库路径不存在!");
  64. }
  65. /**
  66. * 根据基站信息查询位置和地址
  67. * <p>
  68. * 查询流程:
  69. * 1. 调用cell_query获取基站的经纬度信息(WGS84坐标系)
  70. * 2. 将WGS84坐标转换为百度BD09坐标
  71. * 3. 调用regeo_simple进行逆地理编码获取详细地址
  72. * </p>
  73. *
  74. * @param mcc 移动国家代码(Mobile Country Code),中国代码为460
  75. * @param mnc 移动网络代码(Mobile Network Code),0-移动,1-联通,电信对应sid(十进制)
  76. * @param lac 位置区码(Location Area Code),电信对应nid(十进制)
  77. * @param ci 小区标识(Cell Identity),电信对应bid(十进制)
  78. * @return 包含位置信息的数组,格式为:[纬度, 经度, 覆盖半径, 详细地址]
  79. * - obj[0]: 百度纬度(BD09)
  80. * - obj[1]: 百度经度(BD09)
  81. * - obj[2]: 覆盖半径(米)
  82. * - obj[3]: 详细地址描述
  83. * 示例调用:CellUtils.getCells(460, 0, 1, 2)
  84. * getCells(460, 0, 32796, 64265);
  85. * <p>
  86. * 返回示例:[35.994564, 12.468795, 123, "北京市朝阳xxx4号楼;望京街xx163米"]
  87. * </p>
  88. */
  89. public static Object[] getCells(int mcc, int mnc, int lac, int ci) {
  90. Object[] result = new Object[4];
  91. if (!FLAG.get()) {
  92. return result;
  93. }
  94. // 创建用于接收查询结果的引用对象
  95. DoubleByReference latitude = new DoubleByReference(0.0); // WGS84 纬度
  96. DoubleByReference longitude = new DoubleByReference(0.0); // WGS84 经度
  97. byte[] combined = new byte[ADDRESS_BUFFER_SIZE];
  98. // 调用本地库查询基站信息
  99. int queryResult = CellDll.INSTANCE_DLL.cell_query_combined(mcc, mnc, lac, ci,
  100. CellDll.COORD_WGS84, latitude, longitude, combined, combined.length);
  101. // 如果查询失败,返回空数组
  102. if (queryResult != 0) {
  103. return result;
  104. }
  105. double sourceLatitude = latitude.getValue();
  106. double sourceLongitude = longitude.getValue();
  107. // 查询结果的原始坐标来自 WGS84,需要先转换为 BD09 再返回给上层。
  108. //double[] bd09 = CoordinateTransform.transformWGS84ToBD09(sourceLongitude, sourceLatitude);
  109. result[0] = sourceLatitude;
  110. result[1] = sourceLongitude;
  111. result[2] = 0;
  112. // 逆地理编码依旧使用原始 WGS84 坐标,保持与现有 native 接口行为一致。
  113. result[3] = StrUtil.str(combined, StandardCharsets.UTF_8);
  114. return result;
  115. }
  116. }