@@ -93,8 +93,217 @@ inline void round_rapidjson(RapidjsonValue &json, double scale, int depth = 1,
9393 } else if (json.IsDouble ()) {
9494 // see round_coords in geojson_helpers
9595 json.SetDouble (std::floor (json.GetDouble () * scale + 0.5 ) / scale);
96- } else if (json.IsFloat ()) {
97- json.SetFloat (std::floor (json.GetFloat () * scale + 0.5 ) / scale);
96+ }
97+ }
98+
99+ inline void round_geojson_non_geometry (RapidjsonValue &json, double scale)
100+ {
101+ if (!json.IsObject ()) {
102+ return ;
103+ }
104+ auto itr = json.FindMember (" type" );
105+ if (itr == json.MemberEnd () || !itr->value .IsString ()) {
106+ return ;
107+ }
108+ const auto type =
109+ std::string (itr->value .GetString (), itr->value .GetStringLength ());
110+ if (type == " Feature" ) {
111+ round_rapidjson (json, scale, INT_MAX, {" geometry" });
112+ } else if (type == " FeatureCollection" ) {
113+ round_rapidjson (json, scale, INT_MAX, {" features" });
114+ for (auto &f : json[" features" ].GetArray ()) {
115+ round_rapidjson (f, scale);
116+ }
117+ } else if (type == " Point" || type == " MultiPoint" ||
118+ type == " LineString" || type == " MultiLineString" ||
119+ type == " Polygon" || type == " MultiPolygon" ) {
120+ round_rapidjson (json, scale, INT_MAX, {" coordinates" });
121+ } else if (type == " GeometryCollection" ) {
122+ round_rapidjson (json, scale, INT_MAX, {" geometries" });
123+ for (auto &g : json[" geometries" ].GetArray ()) {
124+ round_rapidjson (g, scale);
125+ }
126+ }
127+ }
128+
129+ inline void __round_geojson_geometry (RapidjsonValue &json,
130+ const Eigen::Vector3d &scale)
131+ {
132+ if (!json.IsArray () || json.Empty ()) {
133+ return ;
134+ }
135+ if (!json[0 ].IsNumber ()) {
136+ for (auto &e : json.GetArray ()) {
137+ __round_geojson_geometry (e, scale);
138+ }
139+ return ;
140+ }
141+ const int N = std::min (3 , (int )json.Size ());
142+ for (int i = 0 ; i < N; ++i) {
143+ if (json[i].IsDouble ()) {
144+ json[i].SetDouble (std::floor (json[i].GetDouble () * scale[i] + 0.5 ) /
145+ scale[i]);
146+ }
147+ }
148+ }
149+
150+ inline void round_geojson_geometry (RapidjsonValue &json,
151+ const Eigen::Vector3d &scale)
152+ {
153+ if (!json.IsObject ()) {
154+ return ;
155+ }
156+ auto itr = json.FindMember (" type" );
157+ if (itr == json.MemberEnd () || !itr->value .IsString ()) {
158+ return ;
159+ }
160+ const auto type =
161+ std::string (itr->value .GetString (), itr->value .GetStringLength ());
162+ if (type == " Feature" ) {
163+ round_geojson_geometry (json[" geometry" ], scale);
164+ } else if (type == " FeatureCollection" ) {
165+ for (auto &f : json[" features" ].GetArray ()) {
166+ round_geojson_geometry (f[" geometry" ], scale);
167+ }
168+ } else if (type == " Point" || type == " MultiPoint" ||
169+ type == " LineString" || type == " MultiLineString" ||
170+ type == " Polygon" || type == " MultiPolygon" ) {
171+ __round_geojson_geometry (json[" coordinates" ], scale);
172+ } else if (type == " GeometryCollection" ) {
173+ for (auto &g : json[" geometries" ].GetArray ()) {
174+ round_geojson_geometry (g, scale);
175+ }
176+ }
177+ }
178+
179+ inline void denoise_double_0_rapidjson (RapidjsonValue &json)
180+ {
181+ if (json.IsArray ()) {
182+ for (auto &e : json.GetArray ()) {
183+ denoise_double_0_rapidjson (e);
184+ }
185+ } else if (json.IsObject ()) {
186+ auto obj = json.GetObject ();
187+ for (auto &kv : obj) {
188+ denoise_double_0_rapidjson (kv.value );
189+ }
190+ } else if (json.IsDouble ()) {
191+ double d = json.GetDouble ();
192+ if (std::floor (d) == d) {
193+ if (d >= 0 ) {
194+ auto i = static_cast <uint64_t >(d);
195+ if (i == d) {
196+ json.SetUint64 (i);
197+ }
198+ } else {
199+ auto i = static_cast <int64_t >(d);
200+ if (i == d) {
201+ json.SetInt64 (i);
202+ }
203+ }
204+ }
205+ }
206+ }
207+
208+ inline bool __all_is_z0 (RapidjsonValue &json)
209+ {
210+ // [x, y, 0.0], [[x, y, 0.0], ...], [[[x, y, 0.0], ..], ..]
211+ if (!json.IsArray ()) {
212+ return false ;
213+ }
214+ if (json.Empty ()) {
215+ return true ;
216+ }
217+ if (!json[0 ].IsNumber ()) {
218+ for (auto &e : json.GetArray ()) {
219+ if (!__all_is_z0 (e)) {
220+ return false ;
221+ }
222+ }
223+ return true ;
224+ }
225+ if (json.Size () != 3 || !json[2 ].IsNumber ()) {
226+ return false ;
227+ }
228+ return json[2 ].GetDouble () == 0.0 ;
229+ }
230+
231+ inline void __strip_geometry_z_0 (RapidjsonValue &json)
232+ {
233+ if (!json.IsArray () || json.Empty ()) {
234+ return ;
235+ }
236+ if (!json[0 ].IsNumber ()) {
237+ for (auto &e : json.GetArray ()) {
238+ __strip_geometry_z_0 (e);
239+ }
240+ return ;
241+ }
242+ if (json.Size () == 3 ) {
243+ json.PopBack ();
244+ }
245+ }
246+
247+ inline void strip_geometry_z_0 (RapidjsonValue &json)
248+ {
249+ if (json.IsObject ()) {
250+ auto itr = json.FindMember (" type" );
251+ if (itr == json.MemberEnd () || !itr->value .IsString ()) {
252+ return ;
253+ }
254+ const auto type =
255+ std::string (itr->value .GetString (), itr->value .GetStringLength ());
256+ if (type == " Feature" ) {
257+ strip_geometry_z_0 (json[" geometry" ]);
258+ } else if (type == " FeatureCollection" ) {
259+ for (auto &f : json[" features" ].GetArray ()) {
260+ strip_geometry_z_0 (f[" geometry" ]);
261+ }
262+ } else if (type == " Point" || type == " MultiPoint" ||
263+ type == " LineString" || type == " MultiLineString" ||
264+ type == " Polygon" || type == " MultiPolygon" ) {
265+ strip_geometry_z_0 (json[" coordinates" ]);
266+ } else if (type == " GeometryCollection" ) {
267+ for (auto &g : json[" geometries" ].GetArray ()) {
268+ strip_geometry_z_0 (g);
269+ }
270+ }
271+ return ;
272+ }
273+
274+ if (!__all_is_z0 (json)) {
275+ return ;
276+ }
277+ __strip_geometry_z_0 (json);
278+ }
279+
280+ inline void
281+ normalize_json (RapidjsonValue &json, //
282+ bool sort_keys = true , //
283+ std::optional<int > round_geojson_non_geometry = 3 , //
284+ const std::optional<std::array<int , 3 >> &round_geojson_geometry =
285+ std::array<int , 3 >{8 , 8 , 3 }, //
286+ bool denoise_double_0 = true , //
287+ bool strip_geometry_z_0 = true )
288+ {
289+ if (sort_keys) {
290+ sort_keys_inplace (json);
291+ }
292+ if (round_geojson_non_geometry) {
293+ double scale = std::pow (10.0 , *round_geojson_non_geometry);
294+ cubao::round_geojson_non_geometry (json, scale);
295+ }
296+ if (round_geojson_geometry) {
297+ auto &precision = *round_geojson_geometry;
298+ cubao::round_geojson_geometry (json, {std::pow (10.0 , precision[0 ]),
299+ std::pow (10.0 , precision[1 ]),
300+ std::pow (10.0 , precision[2 ])});
301+ }
302+ if (strip_geometry_z_0) {
303+ cubao::strip_geometry_z_0 (json);
304+ }
305+ if (denoise_double_0) {
306+ denoise_double_0_rapidjson (json);
98307 }
99308}
100309
0 commit comments