diff --git a/fieldImages/CMakeLists.txt b/fieldImages/CMakeLists.txt index efe6d4d85f..577806debb 100644 --- a/fieldImages/CMakeLists.txt +++ b/fieldImages/CMakeLists.txt @@ -7,6 +7,9 @@ if (WITH_JAVA) find_package(Java REQUIRED) include(UseJava) + file(GLOB JACKSON_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar") + set(CMAKE_JAVA_INCLUDE_PATH fieldImages.jar ${JACKSON_JARS}) + file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java) file(GLOB_RECURSE JAVA_RESOURCES src/main/native/resources/*.json src/main/native/resources/*.png src/main/native/resources/*.jpg) add_jar(field_images_jar SOURCES ${JAVA_SOURCES} RESOURCES NAMESPACE "edu/wpi/first/fields" ${JAVA_RESOURCES} OUTPUT_NAME fieldImages) diff --git a/fieldImages/build.gradle b/fieldImages/build.gradle index 0d1dbb1cfc..369d72a3b3 100644 --- a/fieldImages/build.gradle +++ b/fieldImages/build.gradle @@ -13,6 +13,12 @@ if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxar apply plugin: 'windows-resources' } + dependencies { + implementation "com.fasterxml.jackson.core:jackson-annotations:2.12.4" + implementation "com.fasterxml.jackson.core:jackson-core:2.12.4" + implementation "com.fasterxml.jackson.core:jackson-databind:2.12.4" + } + ext { nativeName = 'fieldImages' baseId = nativeName diff --git a/fieldImages/src/main/java/edu/wpi/fields/FieldConfig.java b/fieldImages/src/main/java/edu/wpi/fields/FieldConfig.java new file mode 100644 index 0000000000..a8dd0874c9 --- /dev/null +++ b/fieldImages/src/main/java/edu/wpi/fields/FieldConfig.java @@ -0,0 +1,90 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.fields; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +public class FieldConfig { + public static class Corners { + @JsonProperty("top-left") + public double[] m_topLeft; + + @JsonProperty("bottom-right") + public double[] m_bottomRight; + } + + @JsonProperty("game") + public String m_game; + + @JsonProperty("field-image") + public String m_fieldImage; + + @JsonProperty("field-corners") + public Corners m_fieldCorners; + + @JsonProperty("field-size") + public double[] m_fieldSize; + + @JsonProperty("field-unit") + public String m_fieldUnit; + + public FieldConfig() {} + + @SuppressWarnings("deprecation") + public URL getImageUrl() { + return getClass().getResource(Fields.kBaseResourceDir + m_fieldImage); + } + + @SuppressWarnings("deprecation") + public InputStream getImageAsStream() { + return getClass().getResourceAsStream(Fields.kBaseResourceDir + m_fieldImage); + } + + /** + * Loads a predefined field configuration from a resource file. + * + * @param field The predefined field + * @return The field configuration + * @throws IOException Throws if the file could not be loaded + */ + public static FieldConfig loadField(Fields field) throws IOException { + return loadFromResource(field.m_resourceFile); + } + + /** + * Loads a field configuration from a file on disk. + * + * @param file The json file to load + * @return The field configuration + * @throws IOException Throws if the file could not be loaded + */ + public static FieldConfig loadFromFile(Path file) throws IOException { + try (BufferedReader reader = Files.newBufferedReader(file)) { + return new ObjectMapper().readerFor(FieldConfig.class).readValue(reader); + } + } + + /** + * Loads a field configuration from a resource file located inside the programs jar file. + * + * @param resourcePath The path to the resource file + * @return The field configuration + * @throws IOException Throws if the resoure could not be loaded + */ + public static FieldConfig loadFromResource(String resourcePath) throws IOException { + try (InputStream stream = FieldConfig.class.getResourceAsStream(resourcePath); + InputStreamReader reader = new InputStreamReader(stream)) { + return new ObjectMapper().readerFor(FieldConfig.class).readValue(reader); + } + } +} diff --git a/fieldImages/src/main/java/edu/wpi/fields/FieldImages.java b/fieldImages/src/main/java/edu/wpi/fields/FieldImages.java deleted file mode 100644 index f482478ed9..0000000000 --- a/fieldImages/src/main/java/edu/wpi/fields/FieldImages.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package edu.wpi.fields; - -public class FieldImages { - public static final String k2018PowerUpFieldConfig = "/edu/wpi/first/fields/2018-powerup.json"; - public static final String k2019DeepSpaceFieldConfig = - "/edu/wpi/first/fields/2019-deepspace.json"; - public static final String k2020InfiniteRechargeFieldConfig = - "/edu/wpi/first/fields/2020-infiniterecharge.json"; - public static final String k2021InfiniteRechargeFieldConfig = - "/edu/wpi/first/fields/2021-infiniterecharge.json"; - public static final String k2021BarrelFieldConfig = - "/edu/wpi/first/fields/2021-barrelracingpath.json"; - public static final String k2021BounceFieldConfig = "/edu/wpi/first/fields/2021-bouncepath.json"; - public static final String k2021GalacticSearchAFieldConfig = - "/edu/wpi/first/fields/2021-galacticsearcha.json"; - public static final String k2021GalacticSearchBFieldConfig = - "/edu/wpi/first/fields/2021-galacticsearchb.json"; - public static final String k2021SlalomFieldConfig = "/edu/wpi/first/fields/2021-slalompath.json"; - public static final String k2022RapidReactFieldConfig = - "/edu/wpi/first/fields/2022-rapidreact.json"; -} diff --git a/fieldImages/src/main/java/edu/wpi/fields/Fields.java b/fieldImages/src/main/java/edu/wpi/fields/Fields.java new file mode 100644 index 0000000000..4fc3508701 --- /dev/null +++ b/fieldImages/src/main/java/edu/wpi/fields/Fields.java @@ -0,0 +1,29 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.fields; + +public enum Fields { + k2018PowerUp("2018-powerup.json"), + k2019DeepSpace("2019-deepspace.json"), + k2020InfiniteRecharge("2020-infiniterecharge.json"), + k2021InfiniteRecharge("2021-infiniterecharge.json"), + k2021Barrel("2021-barrelracingpath.json"), + k2021Bounce("2021-bouncepath.json"), + k2021GalacticSearchA("2021-galacticsearcha.json"), + k2021GalacticSearchB("2021-galacticsearchb.json"), + k2021Slalom("2021-slalompath.json"), + k2022RapidReact("2022-rapidreact.json"); + + public static final String kBaseResourceDir = "/edu/wpi/first/fields/"; + + /** Alias to the current game. */ + public static final Fields kDefaultField = k2022RapidReact; + + public final String m_resourceFile; + + Fields(String resourceFile) { + m_resourceFile = kBaseResourceDir + resourceFile; + } +} diff --git a/fieldImages/src/test/java/edu/wpi/fields/LoadConfigTest.java b/fieldImages/src/test/java/edu/wpi/fields/LoadConfigTest.java new file mode 100644 index 0000000000..f4f162175b --- /dev/null +++ b/fieldImages/src/test/java/edu/wpi/fields/LoadConfigTest.java @@ -0,0 +1,19 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.fields; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class LoadConfigTest { + @ParameterizedTest + @EnumSource(Fields.class) + void testLoad(Fields field) { + FieldConfig config = Assertions.assertDoesNotThrow(() -> FieldConfig.loadField(field)); + + Assertions.assertNotNull(config.getImageUrl()); + } +}