[glass] Field2D: Embed standard field images (#5159)

This commit is contained in:
Peter Johnson
2023-05-12 21:31:38 -07:00
committed by GitHub
parent 102e4f2566
commit 27fb47ab10
10 changed files with 154 additions and 30 deletions

View File

@@ -11,6 +11,7 @@
#include <string_view>
#include <utility>
#include <fields/fields.h>
#include <fmt/format.h>
#include <frc/geometry/Pose2d.h>
#include <frc/geometry/Rotation2d.h>
@@ -237,10 +238,12 @@ class FieldInfo {
private:
void Reset();
bool LoadImageImpl(const std::string& fn);
void LoadJson(std::string_view jsonfile);
bool LoadJson(wpi::raw_istream& is, std::string_view filename);
void LoadJsonFile(std::string_view jsonfile);
std::unique_ptr<pfd::open_file> m_fileOpener;
std::string& m_builtin;
std::string& m_filename;
gui::Texture m_texture;
@@ -340,7 +343,8 @@ static bool InputPose(frc::Pose2d* pose) {
}
FieldInfo::FieldInfo(Storage& storage)
: m_filename{storage.GetString("image")},
: m_builtin{storage.GetString("builtin")},
m_filename{storage.GetString("image")},
m_width{storage.GetFloat("width", kDefaultWidth.to<float>())},
m_height{storage.GetFloat("height", kDefaultHeight.to<float>())},
m_top{storage.GetInt("top", 0)},
@@ -349,7 +353,25 @@ FieldInfo::FieldInfo(Storage& storage)
m_right{storage.GetInt("right", -1)} {}
void FieldInfo::DisplaySettings() {
if (ImGui::Button("Choose image...")) {
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10);
if (ImGui::BeginCombo("Image",
m_builtin.empty() ? "Custom" : m_builtin.c_str())) {
if (ImGui::Selectable("Custom", m_builtin.empty())) {
Reset();
}
for (auto&& field : fields::GetFields()) {
bool selected = field.name == m_builtin;
if (ImGui::Selectable(field.name, selected)) {
Reset();
m_builtin = field.name;
}
if (selected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
if (m_builtin.empty() && ImGui::Button("Load image...")) {
m_fileOpener = std::make_unique<pfd::open_file>(
"Choose field image", "",
std::vector<std::string>{"Image File",
@@ -370,6 +392,7 @@ void FieldInfo::DisplaySettings() {
void FieldInfo::Reset() {
m_texture = gui::Texture{};
m_builtin.clear();
m_filename.clear();
m_imageWidth = 0;
m_imageHeight = 0;
@@ -384,7 +407,7 @@ void FieldInfo::LoadImage() {
auto result = m_fileOpener->result();
if (!result.empty()) {
if (wpi::ends_with(result[0], ".json")) {
LoadJson(result[0]);
LoadJsonFile(result[0]);
} else {
LoadImageImpl(result[0].c_str());
m_top = 0;
@@ -395,33 +418,47 @@ void FieldInfo::LoadImage() {
}
m_fileOpener.reset();
}
if (!m_texture && !m_filename.empty()) {
if (!LoadImageImpl(m_filename)) {
m_filename.clear();
if (!m_texture) {
if (!m_builtin.empty()) {
for (auto&& field : fields::GetFields()) {
if (field.name == m_builtin) {
auto jsonstr = field.getJson();
wpi::raw_mem_istream is{jsonstr.data(), jsonstr.size()};
auto imagedata = field.getImage();
auto texture = gui::Texture::CreateFromImage(
reinterpret_cast<const unsigned char*>(imagedata.data()),
imagedata.size());
if (texture && LoadJson(is, {})) {
m_texture = std::move(texture);
m_imageWidth = m_texture.GetWidth();
m_imageHeight = m_texture.GetHeight();
} else {
m_builtin.clear();
}
}
}
} else if (!m_filename.empty()) {
if (!LoadImageImpl(m_filename)) {
m_filename.clear();
}
}
}
}
void FieldInfo::LoadJson(std::string_view jsonfile) {
std::error_code ec;
wpi::raw_fd_istream f(jsonfile, ec);
if (ec) {
std::fputs("GUI: could not open field JSON file\n", stderr);
return;
}
bool FieldInfo::LoadJson(wpi::raw_istream& is, std::string_view filename) {
// parse file
wpi::json j;
try {
j = wpi::json::parse(f);
j = wpi::json::parse(is);
} catch (const wpi::json::parse_error& e) {
fmt::print(stderr, "GUI: JSON: could not parse: {}\n", e.what());
return false;
}
// top level must be an object
if (!j.is_object()) {
std::fputs("GUI: JSON: does not contain a top object\n", stderr);
return;
return false;
}
// image filename
@@ -430,7 +467,7 @@ void FieldInfo::LoadJson(std::string_view jsonfile) {
image = j.at("field-image").get<std::string>();
} catch (const wpi::json::exception& e) {
fmt::print(stderr, "GUI: JSON: could not read field-image: {}\n", e.what());
return;
return false;
}
// corners
@@ -443,7 +480,7 @@ void FieldInfo::LoadJson(std::string_view jsonfile) {
} catch (const wpi::json::exception& e) {
fmt::print(stderr, "GUI: JSON: could not read field-corners: {}\n",
e.what());
return;
return false;
}
// size
@@ -454,7 +491,7 @@ void FieldInfo::LoadJson(std::string_view jsonfile) {
height = j.at("field-size").at(1).get<float>();
} catch (const wpi::json::exception& e) {
fmt::print(stderr, "GUI: JSON: could not read field-size: {}\n", e.what());
return;
return false;
}
// units for size
@@ -463,7 +500,7 @@ void FieldInfo::LoadJson(std::string_view jsonfile) {
unit = j.at("field-unit").get<std::string>();
} catch (const wpi::json::exception& e) {
fmt::print(stderr, "GUI: JSON: could not read field-unit: {}\n", e.what());
return;
return false;
}
// convert size units to meters
@@ -472,22 +509,35 @@ void FieldInfo::LoadJson(std::string_view jsonfile) {
height = units::convert<units::feet, units::meters>(height);
}
// the image filename is relative to the json file
auto pathname = fs::path{jsonfile}.replace_filename(image).string();
if (!filename.empty()) {
// the image filename is relative to the json file
auto pathname = fs::path{filename}.replace_filename(image).string();
// load field image
if (!LoadImageImpl(pathname.c_str())) {
return;
// load field image
if (!LoadImageImpl(pathname.c_str())) {
return false;
}
m_filename = pathname;
}
// save to field info
m_filename = pathname;
m_top = top;
m_left = left;
m_bottom = bottom;
m_right = right;
m_width = width;
m_height = height;
return true;
}
void FieldInfo::LoadJsonFile(std::string_view jsonfile) {
std::error_code ec;
wpi::raw_fd_istream f(jsonfile, ec);
if (ec) {
std::fputs("GUI: could not open field JSON file\n", stderr);
return;
}
LoadJson(f, jsonfile);
}
bool FieldInfo::LoadImageImpl(const std::string& fn) {