package com.xiaopeng.map.utils; import com.google.protobuf.CodedOutputStream; import com.xiaopeng.map.dto.MapAreaDataDto; import com.xiaopeng.map.dto.OddAreaDto; import com.xiaopeng.map.dto.OddPointDto; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.List; /** * 将 MapAreaDataDto 序列化为与 map_area_data.proto 兼容的 Protobuf 二进制格式。 */ public final class MapAreaDataProtoWriter { private MapAreaDataProtoWriter() { } public static void writeTo(MapAreaDataDto data, OutputStream out) throws IOException { byte[] bytes = toByteArray(data); out.write(bytes); } public static byte[] toByteArray(MapAreaDataDto data) throws IOException { int size = computeSize(data); byte[] buf = new byte[size]; CodedOutputStream cos = CodedOutputStream.newInstance(buf); writeMapAreaData(cos, data); cos.checkNoSpaceLeft(); return buf; } private static int computeSize(MapAreaDataDto data) { int size = 0; if (data.getVersion() != 0) { size += CodedOutputStream.computeUInt32Size(1, data.getVersion()); } for (OddAreaDto area : data.getOddAreas()) { int areaSize = computeOddAreaSize(area); size += CodedOutputStream.computeTagSize(2) + CodedOutputStream.computeRawVarint32Size(areaSize) + areaSize; } return size; } private static int computeOddAreaSize(OddAreaDto area) { int size = 0; if (area.getOddId() != 0) { size += CodedOutputStream.computeUInt32Size(1, area.getOddId()); } for (OddPointDto pt : area.getOddPoints()) { int ptSize = computeOddPointSize(pt); size += CodedOutputStream.computeTagSize(2) + CodedOutputStream.computeRawVarint32Size(ptSize) + ptSize; } if (area.isBlacklist()) { size += CodedOutputStream.computeBoolSize(3, true); } return size; } private static int computeOddPointSize(OddPointDto pt) { int size = 0; if (pt.getLatitude() != 0.0) { size += CodedOutputStream.computeDoubleSize(1, pt.getLatitude()); } if (pt.getLongitude() != 0.0) { size += CodedOutputStream.computeDoubleSize(2, pt.getLongitude()); } return size; } private static void writeMapAreaData(CodedOutputStream cos, MapAreaDataDto data) throws IOException { cos.writeUInt32(1, data.getVersion()); for (OddAreaDto area : data.getOddAreas()) { cos.writeTag(2, 2); // field 2, wire type length-delimited int areaSize = computeOddAreaSize(area); cos.writeRawVarint32(areaSize); writeOddArea(cos, area); } } private static void writeOddArea(CodedOutputStream cos, OddAreaDto area) throws IOException { cos.writeUInt32(1, area.getOddId()); List points = area.getOddPoints(); for (OddPointDto pt : points) { cos.writeTag(2, 2); int ptSize = computeOddPointSize(pt); cos.writeRawVarint32(ptSize); writeOddPoint(cos, pt); } if (area.isBlacklist()) { cos.writeBool(3, true); } } private static void writeOddPoint(CodedOutputStream cos, OddPointDto pt) throws IOException { cos.writeDouble(1, pt.getLatitude()); cos.writeDouble(2, pt.getLongitude()); } /** * 测试入口:使用 XngpAreaRTreeFbsUtil 的示例 GCL 数据生成 map_area_data 文件。 */ public static void main(String[] args) { String gcl = "104.06249657558965_30.583221674855963," + "104.06244328689024_30.58049965528362," + "104.06640444191817_30.580606702069797," + "104.06496563619123_30.58420035984882," + "104.06249657558965_30.583221674855963"; List points = XngpAreaRTreeFbsUtil.parseGcl(gcl); if (points.isEmpty()) { System.err.println("parseGcl failed: no points"); return; } OddAreaDto oddArea = OddAreaDto.builder() .oddId(1) .isBlacklist(false) .build(); for (XngpAreaRTreeFbsUtil.LonLat p : points) { oddArea.getOddPoints().add(OddPointDto.builder() .latitude(p.getLat()) .longitude(p.getLon()) .build()); } MapAreaDataDto data = MapAreaDataDto.builder() .version(1) .oddAreas(java.util.Collections.singletonList(oddArea)) .build(); String outFile = "map_area_data_test.bin"; try (FileOutputStream fos = new FileOutputStream(outFile)) { MapAreaDataProtoWriter.writeTo(data, fos); System.out.println("MapAreaDataProtoWriter success, outFile=" + outFile); } catch (IOException e) { System.err.println("MapAreaDataProtoWriter failed: " + e.getMessage()); } } }