Update for jart/json.cpp change

This commit is contained in:
Peter Johnson
2026-03-29 15:38:18 -07:00
parent de3e211fdb
commit 9ca93fa190
120 changed files with 1240 additions and 1087 deletions

View File

@@ -70,9 +70,6 @@ void Analyzer::UpdateFeedforwardGains() {
} catch (const AnalysisManager::FileReadingError& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
} catch (const wpi::util::json::exception& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
} catch (const std::exception& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
@@ -298,9 +295,6 @@ void Analyzer::PrepareData() {
} catch (const AnalysisManager::FileReadingError& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
} catch (const wpi::util::json::exception& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());
} catch (const std::exception& e) {
m_state = AnalyzerState::kFileError;
HandleError(e.what());

View File

@@ -3,7 +3,6 @@
// the WPILib BSD license file in the root directory of this project.
#include <filesystem>
#include <fstream>
#include <map>
#include <memory>
#include <optional>
@@ -27,7 +26,10 @@
#include "wpi/gui/wpigui.hpp"
#include "wpi/gui/wpigui_openurl.hpp"
#include "wpi/math/util/MathUtil.hpp"
#include "wpi/util/MemoryBuffer.hpp"
#include "wpi/util/fs.hpp"
#include "wpi/util/json.hpp"
#include "wpi/util/raw_ostream.hpp"
namespace gui = wpi::gui;
@@ -175,14 +177,26 @@ void CameraCalibrationSelectorButton(const char* text,
if (selector && selector->ready(0)) {
auto selectedFiles = selector->result();
if (!selectedFiles.empty()) {
auto fileBuffer = wpi::util::MemoryBuffer::GetFile(selectedFiles[0]);
if (!fileBuffer) {
goto err;
}
auto buffer = fileBuffer.value()->GetCharBuffer();
auto j = wpi::util::json::parse({buffer.data(), buffer.size()});
if (!j) {
goto err;
}
try {
cameraModel = wpi::util::json::parse(std::ifstream(selectedFiles[0]))
.get<wpical::CameraModel>();
cameraModel = j->get<wpical::CameraModel>();
} catch (...) {
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("Camera Calibration Loading Error");
goto err;
}
}
goto done;
err:
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("Camera Calibration Loading Error");
done:
selector.reset();
}
}
@@ -199,15 +213,29 @@ void FieldSelectorButton(const char* text,
auto selectedFiles = selector->result();
if (!selectedFiles.empty()) {
std::string idealLayoutPath = selectedFiles[0];
auto fileBuffer = wpi::util::MemoryBuffer::GetFile(idealLayoutPath);
if (!fileBuffer) {
gInvalidLayoutPath = idealLayoutPath;
goto err;
}
auto buffer = fileBuffer.value()->GetCharBuffer();
auto j = wpi::util::json::parse({buffer.data(), buffer.size()});
if (!j) {
gInvalidLayoutPath = idealLayoutPath;
goto err;
}
try {
layout = wpi::util::json::parse(std::ifstream(idealLayoutPath))
.get<wpi::apriltag::AprilTagFieldLayout>();
layout = j->get<wpi::apriltag::AprilTagFieldLayout>();
} catch (...) {
gInvalidLayoutPath = idealLayoutPath;
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("AprilTag Field Layout Loading Error");
goto err;
}
}
goto done;
err:
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("AprilTag Field Layout Loading Error");
done:
selector.reset();
}
if (layout.GetTags().size() > 0) {
@@ -226,11 +254,18 @@ void SaveCalibratedField(const wpi::apriltag::AprilTagFieldLayout& field,
static std::string saveDir;
ProcessDirectorySelector(saveDirSelector, saveDir);
if (!saveDir.empty()) {
std::ofstream out(saveDir + "/" + outputName + ".json");
out << wpi::util::json{field}.dump(4);
std::error_code ec;
wpi::util::raw_fd_ostream out(saveDir + "/" + outputName + ".json", ec,
fs::OF_Text);
if (!ec) {
wpi::util::json{field}.marshal(out, true, 4);
}
std::ofstream fmap(saveDir + "/" + outputName + ".fmap");
fmap << wpi::util::json{fmap::Fieldmap(field)}.dump(4);
wpi::util::raw_fd_ostream fmap(saveDir + "/" + outputName + ".fmap", ec,
fs::OF_Text);
if (!ec) {
wpi::util::json{fmap::Fieldmap(field)}.marshal(fmap, true, 4);
}
saveDir.clear();
}
@@ -286,8 +321,12 @@ void CalibrateCamera() {
std::filesystem::path myPath(cameraVideoPath);
auto outputPath = myPath.parent_path() / "cameracalibration.json";
std::ofstream output_file(outputPath);
output_file << wpi::util::json(gCameraModel).dump(4) << std::endl;
std::error_code ec;
wpi::util::raw_fd_ostream output_file(outputPath.string(), ec,
fs::OF_Text);
if (!ec) {
wpi::util::json{gCameraModel}.marshal(output_file, true, 4);
}
ImGui::CloseCurrentPopup();
calibrating = false;
} else if (!videoProcessor->IsFinished()) {
@@ -350,16 +389,30 @@ void CombineCalibrations() {
if (!selectedFiles.empty()) {
std::map<std::string, wpi::apriltag::AprilTagFieldLayout> fieldLayouts;
for (auto& path : selectedFiles) {
auto fileBuffer = wpi::util::MemoryBuffer::GetFile(path);
if (!fileBuffer) {
gInvalidLayoutPath = path;
goto err;
}
auto buffer = fileBuffer.value()->GetCharBuffer();
auto j = wpi::util::json::parse({buffer.data(), buffer.size()});
if (!j) {
gInvalidLayoutPath = path;
goto err;
}
try {
fieldLayouts.emplace(
path, wpi::util::json::parse(std::ifstream(path))
.get<wpi::apriltag::AprilTagFieldLayout>());
fieldLayouts.emplace(path,
j->get<wpi::apriltag::AprilTagFieldLayout>());
} catch (...) {
gInvalidLayoutPath = path;
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("AprilTag Field Layout Loading Error");
goto err;
}
}
goto good;
err:
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("AprilTag Field Layout Loading Error");
good:
calibratedFieldLayouts = fieldLayouts;
}
calibratedFieldLayoutMultiselector.reset();

View File

@@ -306,47 +306,71 @@ void to_json(wpi::util::json& json, const CameraModel& cameraModel) {
cameraModel.distortionCoefficients.data(),
cameraModel.distortionCoefficients.data() +
cameraModel.distortionCoefficients.size());
json = {{"camera_matrix", cameraMatrix},
{"distortion_coefficients", distortionCoefficients},
{"avg_reprojection_error", cameraModel.avgReprojectionError}};
json = wpi::util::json::object();
json["camera_matrix"] = cameraMatrix;
json["distortion_coefficients"] = distortionCoefficients;
json["avg_reprojection_error"] = cameraModel.avgReprojectionError;
}
void from_json(const wpi::util::json& json, CameraModel& cameraModel) {
bool isCalibdb = json.contains("camera");
Eigen::Matrix3d cameraMatrix;
std::vector<double> distortionCoeffs;
auto mat = json.at("camera_matrix");
auto distortionCoefficients = json.at("distortion_coefficients");
auto jmat = json.at("camera_matrix");
auto jdistortionCoefficients = json.at("distortion_coefficients");
if (isCalibdb) {
// OpenCV format has data key
if (mat.contains("data")) {
auto data = mat.at("data").get<std::vector<double>>();
if (auto jdata = jmat.lookup("data")) {
auto& arr = jdata->get_array();
std::vector<double> data;
data.reserve(arr.size());
for (const auto& item : arr) {
data.push_back(item.get_number());
}
cameraMatrix = Eigen::Matrix<double, 3, 3, Eigen::RowMajor>{data.data()};
} else {
for (int i = 0; i < cameraMatrix.rows(); i++) {
auto& jcols = jmat.at(i);
for (int j = 0; j < cameraMatrix.cols(); j++) {
cameraMatrix(i, j) = mat[i][j];
cameraMatrix(i, j) = jcols.at(j).get_number();
}
}
}
// OpenCV format has data key
if (distortionCoefficients.contains("data")) {
distortionCoeffs =
distortionCoefficients.at("data").get<std::vector<double>>();
wpi::util::json::array_t* arr;
if (auto jdata = jdistortionCoefficients.lookup("data")) {
arr = &jdata->get_array();
} else {
distortionCoeffs = distortionCoefficients.get<std::vector<double>>();
arr = &jdistortionCoefficients.get_array();
}
distortionCoeffs.reserve(arr->size());
for (const auto& item : *arr) {
distortionCoeffs.push_back(item.get_number());
}
} else {
cameraMatrix = Eigen::Matrix<double, 3, 3, Eigen::RowMajor>{
mat.get<std::vector<double>>().data()};
distortionCoeffs = distortionCoefficients.get<std::vector<double>>();
{
auto& arr = jmat.get_array();
std::vector<double> data;
data.reserve(arr.size());
for (const auto& item : arr) {
data.push_back(item.get_number());
}
cameraMatrix = Eigen::Matrix<double, 3, 3, Eigen::RowMajor>{data.data()};
}
{
auto& arr = jdistortionCoefficients.get_array();
distortionCoeffs.reserve(arr.size());
for (const auto& item : arr) {
distortionCoeffs.push_back(item.get_number());
}
}
}
// CalibDB generates JSONs with 5 values. Just zero out the remaining 3 to get
// it to 8
distortionCoeffs.resize(8, 0);
cameraModel = {cameraMatrix,
Eigen::Matrix<double, 8, 1>{distortionCoeffs.data()},
json.at("avg_reprojection_error")};
json.at("avg_reprojection_error").get_number()};
}
} // namespace wpical

View File

@@ -29,25 +29,39 @@ Fieldmap::Fieldmap(const wpi::apriltag::AprilTagFieldLayout& layout)
}
void fmap::to_json(wpi::util::json& json, const Fiducial& layout) {
json = {{"family", layout.family},
{"id", layout.id},
{"size", layout.size},
{"transform", std::vector<double>{layout.transform.data(),
layout.transform.data() +
layout.transform.size()}},
{"unique", layout.unique}};
json = wpi::util::json::object();
json["family"] = layout.family;
json["id"] = layout.id;
json["size"] = layout.size;
json["transform"] =
std::vector<double>{layout.transform.data(),
layout.transform.data() + layout.transform.size()};
json["unique"] = layout.unique;
}
void fmap::from_json(const wpi::util::json& json, Fiducial& layout) {
auto vec = json.at("transform").get<std::vector<double>>();
layout = {json.at("family"), json.at("id"), json.at("size"),
Eigen::Matrix4d{vec.data()}, json.at("unique")};
auto& arr = json.at("transform").get_array();
std::vector<double> vec;
vec.reserve(arr.size());
for (auto& elem : arr) {
vec.push_back(elem.get_number());
}
layout = {json.at("family").get_string(),
static_cast<int>(json.at("id").get_int()),
json.at("size").get_number(), Eigen::Matrix4d{vec.data()},
static_cast<int>(json.at("unique").get_int())};
}
void fmap::to_json(wpi::util::json& json, const Fieldmap& layout) {
json = {{"type", "frc"}, {"fiducials", layout.fiducials}};
json = wpi::util::json::object("type", "frc", "fiducials", layout.fiducials);
}
void fmap::from_json(const wpi::util::json& json, Fieldmap& layout) {
layout = {json.at("type"), json.at("fiducials")};
auto& arr = json.at("fiducials").get_array();
std::vector<Fiducial> fiducials;
fiducials.reserve(arr.size());
for (auto& elem : arr) {
fiducials.emplace_back(elem.get<Fiducial>());
}
layout = {json.at("type").get_string(), fiducials};
}

View File

@@ -2,7 +2,6 @@
// 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.
#include <fstream>
#include <optional>
#include <string>
@@ -13,7 +12,10 @@
#include "path_lookup.hpp"
#include "wpi/apriltag/AprilTagFieldLayout.hpp"
#include "wpi/apriltag/AprilTagFields.hpp"
#include "wpi/util/MemoryBuffer.hpp"
#include "wpi/util/fs.hpp"
#include "wpi/util/json.hpp"
#include "wpi/util/raw_ostream.hpp"
const std::string projectRootPath = PROJECT_ROOT_PATH;
@@ -42,8 +44,10 @@ TEST(CameraCalibrationTest, Typical) {
}
auto ret = calibrator.GetCameraModel();
EXPECT_NE(ret, std::nullopt);
std::ofstream output_file(calSavePath + "/cameracalibration.json");
output_file << wpi::util::json(ret.value()).dump(4) << std::endl;
std::error_code ec;
wpi::util::raw_fd_ostream output_file(calSavePath + "/cameracalibration.json",
ec, fs::OF_Text);
wpi::util::json(ret.value()).marshal(output_file, true, 4);
}
TEST(CameraCalibrationTest, Atypical) {
@@ -58,8 +62,10 @@ TEST(CameraCalibrationTest, Atypical) {
}
TEST(FieldCalibrationTest, Typical) {
auto model = wpi::util::json::parse(
std::ifstream(calSavePath + "/cameracalibration.json"))
auto buffer =
wpi::util::MemoryBuffer::GetFile(calSavePath + "/cameracalibration.json");
auto buf = buffer.value()->GetCharBuffer();
auto model = wpi::util::json::parse_or_throw({buf.data(), buf.size()})
.get<wpical::CameraModel>();
auto ret =
wpical::calibrate(LookupPath(projectRootPath + videoLocation), model,
@@ -80,8 +86,10 @@ TEST(FieldCalibrationTest, Atypical_Bad_Camera_Model) {
}
TEST(FieldCalibrationTest, Atypical_Bad_Field_Layout) {
auto model = wpi::util::json::parse(
std::ifstream(calSavePath + "/cameracalibration.json"))
auto buffer =
wpi::util::MemoryBuffer::GetFile(calSavePath + "/cameracalibration.json");
auto buf = buffer.value()->GetCharBuffer();
auto model = wpi::util::json::parse_or_throw({buf.data(), buf.size()})
.get<wpical::CameraModel>();
auto ret =
wpical::calibrate(LookupPath(projectRootPath + videoLocation), model,
@@ -90,8 +98,10 @@ TEST(FieldCalibrationTest, Atypical_Bad_Field_Layout) {
}
TEST(FieldCalibrationTest, Atypical_Bad_Input_Directory) {
auto model = wpi::util::json::parse(
std::ifstream(calSavePath + "/cameracalibration.json"))
auto buffer =
wpi::util::MemoryBuffer::GetFile(calSavePath + "/cameracalibration.json");
auto buf = buffer.value()->GetCharBuffer();
auto model = wpi::util::json::parse_or_throw({buf.data(), buf.size()})
.get<wpical::CameraModel>();
auto ret =
wpical::calibrate(LookupPath(projectRootPath), model,
@@ -102,8 +112,10 @@ TEST(FieldCalibrationTest, Atypical_Bad_Input_Directory) {
}
TEST(FieldCalibrationTest, Atypical_Bad_Pinned_Tag) {
auto model = wpi::util::json::parse(
std::ifstream(calSavePath + "/cameracalibration.json"))
auto buffer =
wpi::util::MemoryBuffer::GetFile(calSavePath + "/cameracalibration.json");
auto buf = buffer.value()->GetCharBuffer();
auto model = wpi::util::json::parse_or_throw({buf.data(), buf.size()})
.get<wpical::CameraModel>();
auto ret =
wpical::calibrate(LookupPath(projectRootPath + videoLocation), model,
@@ -114,8 +126,10 @@ TEST(FieldCalibrationTest, Atypical_Bad_Pinned_Tag) {
}
TEST(FieldCalibrationTest, Atypical_Bad_Pinned_Tag_Negative) {
auto model = wpi::util::json::parse(
std::ifstream(calSavePath + "/cameracalibration.json"))
auto buffer =
wpi::util::MemoryBuffer::GetFile(calSavePath + "/cameracalibration.json");
auto buf = buffer.value()->GetCharBuffer();
auto model = wpi::util::json::parse_or_throw({buf.data(), buf.size()})
.get<wpical::CameraModel>();
auto ret =
wpical::calibrate(LookupPath(projectRootPath + videoLocation), model,