[infra] add script to generate taginfo.json files

Signed-off-by: soshial <soshial@gmail.com>
This commit is contained in:
soshial 2025-02-19 09:48:14 +01:00
parent 84a49920cc
commit f680aaef71
7 changed files with 13447 additions and 0 deletions

1
android/scripts/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,16 @@
plugins {
id 'java-library'
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.json:json:20250107")
}
java {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

View file

@ -0,0 +1,214 @@
package app.organicmaps.scripts;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MapStyleParser {
private static final String GITHUB_BASE_URL = "https://raw.githubusercontent.com/organicmaps/organicmaps/master/data/styles/default/light/symbols/";
public static void main(String[] args) {
List<File> outdoorsInputFilePaths = new ArrayList<>(
Arrays.asList(
Paths.get("..", "data", "styles", "outdoors", "include", "Basemap_label.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "Basemap.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "defaults_new.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "Icons.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "Roads_label.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "Roads.mapcss").toFile(),
Paths.get("..", "data", "styles", "outdoors", "include", "Subways.mapcss").toFile()
)
);
List<File> defaultInputFilePaths = new ArrayList<>(
Arrays.asList(
Paths.get("..", "data", "styles", "default", "include", "Basemap_label.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "Basemap.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "defaults_new.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "Icons.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "Roads_label.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "Roads.mapcss").toFile(),
Paths.get("..", "data", "styles", "default", "include", "Subways.mapcss").toFile()
)
);
try {
JSONArray defaultTags = parseTagsFromFiles(defaultInputFilePaths);
JSONArray outdoorsTags = parseTagsFromFiles(outdoorsInputFilePaths);
outdoorsTags.putAll(defaultTags);
writeJsonToFile(defaultTags, "Organic Maps (default)", "data/styles/default/", "taginfo.json");
writeJsonToFile(outdoorsTags, "Organic Maps (outdoors)", "data/styles/outdoors/", "taginfo.json");
System.out.println("JSON file has been created successfully!");
} catch (JSONException e) {
System.err.println("Error processing files: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error processing files: " + e.getMessage());
}
}
private static void writeJsonToFile(JSONArray tagArray, String styleName, String filePath, String fileName) throws IOException {
JSONObject mainObject = new JSONObject();
mainObject.put("data_format", 1);
mainObject.put("data_url", "https://raw.githubusercontent.com/organicmaps/organicmaps/master/" + filePath + fileName);
mainObject.put("data_updated", DateTimeFormatter.ISO_INSTANT.format(Instant.now()));
JSONObject projectObject = new JSONObject();
projectObject.put("name", styleName);
projectObject.put("description", "Free Android & iOS offline maps app for travelers, tourists, hikers, and cyclists");
projectObject.put("project_url", "https://organicmaps.app");
projectObject.put("doc_url", "https://github.com/organicmaps/organicmaps");
projectObject.put("icon_url", "https://organicmaps.app/logos/green-on-transparent.svg");
projectObject.put("contact_name", "Organic Maps");
projectObject.put("contact_email", "hello@organicmaps.app");
// Add project object to main object
mainObject.put("project", projectObject);
mainObject.put("tags", tagArray);
Path outputPath = Paths.get("..", filePath, fileName);
writeJSON(mainObject, outputPath.toFile());
}
private static JSONArray parseTagsFromFiles(List<File> inputFiles) throws JSONException, IOException {
HashMap<String, ObjectStyle> styleMap = new HashMap<>();
for (File inputFile : inputFiles) {
parseTagsSingleFile(inputFile, styleMap);
}
// Convert to JSON format
JSONArray jsonArray = new JSONArray();
for (Map.Entry<String, ObjectStyle> entry : styleMap.entrySet()) {
ObjectStyle rule = entry.getValue();
JSONObject obj = new JSONObject();
obj.put("key", rule.key);
obj.put("value", rule.value);
if (rule.iconImage != null) {
obj.put("icon_url", GITHUB_BASE_URL + rule.iconImage);
}
JSONArray objectTypes = new JSONArray();
for (ObjectStyle.ObjectType objectType : rule.types) {
objectTypes.put(objectType.displayName);
}
obj.put("object_types", objectTypes);
jsonArray.put(obj);
}
return jsonArray;
}
private static void parseTagsSingleFile(File inputFile, HashMap<String, ObjectStyle> styleMap) throws JSONException, IOException {
String content = readFile(inputFile);
// Split content into style blocks
String[] blocks = content.split("}");
for (String block : blocks) {
String[] lines = block.trim().split("\\n");
String iconImage = null;
List<String> selectors = new ArrayList<>();
for (String line : lines) {
line = line.trim();
if (line.startsWith("node|") || line.startsWith("area|") || line.startsWith("line|") || line.startsWith("relation|")) {
if (line.endsWith(",")) {
line = line.substring(0, line.length() - 1);
}
selectors.add(line);
} else if (line.contains("icon-image:")) {
Pattern pattern = Pattern.compile("icon-image:\\s*([^;]+);?");
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
iconImage = matcher.group(1).trim();
if (iconImage.equals("none")) {
iconImage = null;
}
}
}
}
for (String selector : selectors) {
ObjectStyle newObjectStyle = parseString(selector, iconImage);
if (newObjectStyle != null) {
ObjectStyle existingObjectStyle = styleMap.get(newObjectStyle.tagsSelector);
if (existingObjectStyle == null) {
styleMap.put(newObjectStyle.tagsSelector, newObjectStyle);
} else {
existingObjectStyle.types.addAll(newObjectStyle.types);
if (newObjectStyle.iconImage != null) {
existingObjectStyle.iconImage = newObjectStyle.iconImage;
}
}
}
}
}
}
private static ObjectStyle parseString(String selector, String iconImage) {
Matcher matcher = ObjectStyle.fullPattern.matcher(selector);
if (matcher.find()) {
String type = matcher.group(1);
String zoom = matcher.group(2);
String tagsSelector = matcher.group(3);
Set<ObjectStyle.ObjectType> objectTypes = new HashSet<>();
switch (type) {
case "node":
objectTypes.add(ObjectStyle.ObjectType.NODE);
break;
case "line":
objectTypes.add(ObjectStyle.ObjectType.WAY);
break;
case "area":
objectTypes.add(ObjectStyle.ObjectType.AREA);
break;
case "relation":
objectTypes.add(ObjectStyle.ObjectType.RELATION);
break;
}
Matcher tagsMatcher = ObjectStyle.tagsPattern.matcher(tagsSelector);
if (tagsMatcher.find()) {
String key = tagsMatcher.group(1);
String value = tagsMatcher.group(2);
return new ObjectStyle(tagsSelector, zoom, key, value, iconImage, objectTypes);
}
}
return null;
}
private static String readFile(File filepath) throws IOException {
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
}
return content.toString();
}
private static void writeJSON(JSONObject jsonObject, File path) throws JSONException, IOException {
try (FileWriter writer = new FileWriter(path)) {
writer.write(jsonObject.toString(2));
}
}
}

View file

@ -0,0 +1,55 @@
package app.organicmaps.scripts;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
class ObjectStyle {
String tagsSelector;
String zoom;
String key;
String value;
String iconImage;
Set<ObjectType> types;
enum ObjectType {
NODE("node"),
WAY("way"),
AREA("area"),
RELATION("relation");
final String displayName;
ObjectType(String displayName) {
this.displayName = displayName;
}
}
ObjectStyle(String tagsSelector, String zoom, String key, String value, String iconImage, Set<ObjectType> types) {
this.tagsSelector = tagsSelector;
this.zoom = zoom;
this.key = key;
this.value = value;
this.iconImage = iconImage;
this.types = types;
}
static final Pattern fullPattern = Pattern.compile("(node|area|line|relation)\\|(z.+?)(\\[.*\\])");
static final Pattern tagsPattern = Pattern.compile("\\[(\\w+)=(\\w+)\\]");
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ObjectStyle that = (ObjectStyle) o;
return Objects.equals(key, that.key) &&
Objects.equals(value, that.value) &&
Objects.equals(iconImage, that.iconImage) &&
Objects.equals(types, that.types);
}
@Override
public int hashCode() {
return Objects.hash(key, value, iconImage, types);
}
}

View file

@ -15,3 +15,4 @@ pluginManagement {
//}
rootProject.name = 'Organic Maps'
include ':app'
include ':scripts'

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff