shench3
2026-03-03 c90dd2da4cfa60c06099c4e66fba6b203bf90b59
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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<OddPointDto> 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<XngpAreaRTreeFbsUtil.LonLat> 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());
        }
    }
}