osb/source/core/StarJsonExtra.cpp
2024-03-20 01:53:34 +11:00

474 lines
13 KiB
C++

#include "StarJsonExtra.hpp"
#include "StarLogging.hpp"
#include "StarRandom.hpp"
namespace Star {
size_t jsonToSize(Json const& v) {
if (v.isNull())
return NPos;
if (!v.canConvert(Json::Type::Int))
throw JsonException("Json not an int in jsonToSize");
return v.toUInt();
}
Json jsonFromSize(size_t s) {
if (s == NPos)
return Json();
return Json(s);
}
Vec2D jsonToVec2D(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 2)
throw JsonException("Json not an array of size 2 in jsonToVec2D");
return Vec2D(v.getDouble(0), v.getDouble(1));
}
Vec2F jsonToVec2F(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 2)
throw JsonException("Json not an array of size 2 in jsonToVec2F");
return Vec2F(v.getFloat(0), v.getFloat(1));
}
Json jsonFromVec2F(Vec2F const& v) {
return JsonArray{v[0], v[1]};
}
Vec2I jsonToVec2I(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 2)
throw JsonException("Json not an array of size 2 in jsonToVec2I");
return Vec2I(v.getInt(0), v.getInt(1));
}
Json jsonFromVec2I(Vec2I const& v) {
return JsonArray{v[0], v[1]};
}
Vec2U jsonToVec2U(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 2)
throw JsonException("Json not an array of size 2 in jsonToVec2I");
return Vec2U(v.getInt(0), v.getInt(1));
}
Json jsonFromVec2U(Vec2U const& v) {
return JsonArray{v[0], v[1]};
}
Vec2B jsonToVec2B(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 2)
throw JsonException("Json not an array of size 2 in jsonToVec2B");
return Vec2B(v.getInt(0), v.getInt(1));
}
Json jsonFromVec2B(Vec2B const& v) {
return JsonArray{v[0], v[1]};
}
Vec3D jsonToVec3D(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 3)
throw JsonException("Json not an array of size size 3 in jsonToVec3D");
return Vec3D(v.getDouble(0), v.getDouble(1), v.getDouble(2));
}
Vec3F jsonToVec3F(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 3)
throw JsonException("Json not an array of size 3 in jsonToVec3D");
return Vec3F(v.getFloat(0), v.getFloat(1), v.getFloat(2));
}
Json jsonFromVec3F(Vec3F const& v) {
return JsonArray{v[0], v[1], v[2]};
}
Vec3I jsonToVec3I(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 3)
throw JsonException("Json not an array of size 3 in jsonToVec3I");
return Vec3I(v.getInt(0), v.getInt(1), v.getInt(2));
}
Json jsonFromVec3I(Vec3I const& v) {
JsonArray result;
result.append(v[0]);
result.append(v[1]);
result.append(v[2]);
return result;
}
Vec3B jsonToVec3B(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 3)
throw JsonException("Json not an array of size 3 in jsonToVec3B");
return Vec3B(v.getInt(0), v.getInt(1), v.getInt(2));
}
Vec4B jsonToVec4B(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 4)
throw JsonException("Json not an array of size 4 in jsonToVec4B");
return Vec4B(v.getInt(0), v.getInt(1), v.getInt(2), v.getInt(3));
}
Vec4I jsonToVec4I(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 4)
throw JsonException("Json not an array of size 4 in jsonToVec4B");
return Vec4I(v.getInt(0), v.getInt(1), v.getInt(2), v.getInt(3));
}
Vec4F jsonToVec4F(Json const& v) {
if (v.type() != Json::Type::Array || v.size() != 4)
throw JsonException("Json not an array of size 4 in jsonToVec4B");
return Vec4F(v.getFloat(0), v.getFloat(1), v.getFloat(2), v.getFloat(3));
}
RectD jsonToRectD(Json const& v) {
if (v.type() != Json::Type::Array)
throw JsonException("Json not an array in jsonToRectD");
if (v.size() != 4 && v.size() != 2)
throw JsonException("Json not an array of proper size in jsonToRectD");
if (v.size() == 4)
return RectD(v.getDouble(0), v.getDouble(1), v.getDouble(2), v.getDouble(3));
try {
auto lowerLeft = jsonToVec2D(v.get(0));
auto upperRight = jsonToVec2D(v.get(1));
return RectD(lowerLeft, upperRight);
} catch (JsonException const& e) {
throw JsonException(strf("Inner position not well formed in jsonToRectD: {}", outputException(e, true)));
}
}
Json jsonFromRectD(RectD const& rect) {
return JsonArray{rect.xMin(), rect.yMin(), rect.xMax(), rect.yMax()};
}
RectF jsonToRectF(Json const& v) {
return RectF(jsonToRectD(v));
}
Json jsonFromRectF(RectF const& rect) {
return JsonArray{rect.xMin(), rect.yMin(), rect.xMax(), rect.yMax()};
}
RectI jsonToRectI(Json const& v) {
if (v.type() != Json::Type::Array)
throw JsonException("Json not an array in jsonToRectI");
if (v.size() != 4 && v.size() != 2)
throw JsonException("Json not an array of proper size in jsonToRectI");
if (v.size() == 4)
return RectI(v.getInt(0), v.getInt(1), v.getInt(2), v.getInt(3));
try {
auto lowerLeft = jsonToVec2I(v.get(0));
auto upperRight = jsonToVec2I(v.get(1));
return RectI(lowerLeft, upperRight);
} catch (JsonException const& e) {
throw JsonException(strf("Inner position not well formed in jsonToRectI: {}", outputException(e, true)));
}
}
Json jsonFromRectI(RectI const& rect) {
return JsonArray{rect.xMin(), rect.yMin(), rect.xMax(), rect.yMax()};
}
RectU jsonToRectU(Json const& v) {
if (v.type() != Json::Type::Array)
throw JsonException("Json not an array in jsonToRectU");
if (v.size() != 4 && v.size() != 2)
throw JsonException("Json not an array of proper size in jsonToRectU");
if (v.size() == 4)
return RectU(v.getInt(0), v.getUInt(1), v.getUInt(2), v.getUInt(3));
try {
auto lowerLeft = jsonToVec2U(v.get(0));
auto upperRight = jsonToVec2U(v.get(1));
return RectU(lowerLeft, upperRight);
} catch (JsonException const& e) {
throw JsonException(strf("Inner position not well formed in jsonToRectU: {}", outputException(e, true)));
}
}
Json jsonFromRectU(RectU const& rect) {
return JsonArray{rect.xMin(), rect.yMin(), rect.xMax(), rect.yMax()};
}
Color jsonToColor(Json const& v) {
if (v.type() == Json::Type::Array) {
if (v.type() != Json::Type::Array || (v.size() != 3 && v.size() != 4))
throw JsonException("Json not an array of size 3 or 4 in jsonToColor");
Color c = Color::rgba(0, 0, 0, 255);
c.setRedF((float)v.getInt(0) / 255.f);
c.setGreenF((float)v.getInt(1) / 255.f);
c.setBlueF((float)v.getInt(2) / 255.f);
if (v.size() == 4)
c.setAlphaF((float)v.getInt(3) / 255.f);
return c;
} else if (v.type() == Json::Type::String) {
return Color(v.toString());
} else {
throw JsonException(strf("Json of type {} cannot be converted to color", v.typeName()));
}
}
Json jsonFromColor(Color const& color) {
JsonArray result;
result.push_back(color.redF() * 255.f);
result.push_back(color.greenF() * 255.f);
result.push_back(color.blueF() * 255.f);
if (color.alphaF() < 255.f) {
result.push_back(color.alphaF() * 255.f);
}
return result;
}
PolyD jsonToPolyD(Json const& v) {
PolyD poly;
for (Json const& vertex : v.iterateArray())
poly.add(jsonToVec2D(vertex));
return fixInsideOutPoly(poly);
}
PolyF jsonToPolyF(Json const& v) {
PolyF poly;
for (Json const& vertex : v.iterateArray())
poly.add(jsonToVec2F(vertex));
return fixInsideOutPoly(poly);
}
PolyI jsonToPolyI(Json const& v) {
PolyI poly;
for (Json const& vertex : v.iterateArray())
poly.add(jsonToVec2I(vertex));
return fixInsideOutPoly(poly);
}
Json jsonFromPolyF(PolyF const& poly) {
JsonArray vertexList;
for (auto const& vertex : poly.vertexes())
vertexList.append(JsonArray{vertex[0], vertex[1]});
return vertexList;
}
Line2F jsonToLine2F(Json const& v) {
return Line2F(jsonToVec2F(v.get(0)), jsonToVec2F(v.get(1)));
}
Json jsonFromLine2F(Line2F const& line) {
return JsonArray{jsonFromVec2F(line.min()), jsonFromVec2F(line.max())};
}
Mat3F jsonToMat3F(Json const& v) {
return Mat3F(jsonToVec3F(v.get(0)), jsonToVec3F(v.get(1)), jsonToVec3F(v.get(2)));
}
Json jsonFromMat3F(Mat3F const& v) {
return JsonArray{jsonFromVec3F(v[0]), jsonFromVec3F(v[1]), jsonFromVec3F(v[2])};
}
StringList jsonToStringList(Json const& v) {
StringList result;
for (auto const& entry : v.iterateArray())
result.push_back(entry.toString());
return result;
}
Json jsonFromStringList(List<String> const& v) {
JsonArray result;
for (auto& e : v)
result.push_back(e);
return result;
}
List<float> jsonToFloatList(Json const& v) {
List<float> result;
for (auto const& entry : v.iterateArray())
result.push_back(entry.toFloat());
return result;
}
StringSet jsonToStringSet(Json const& v) {
StringSet result;
for (auto const& entry : v.iterateArray())
result.add(entry.toString());
return result;
}
Json jsonFromStringSet(StringSet const& v) {
JsonArray result;
for (auto& e : v)
result.push_back(e);
return result;
}
List<int> jsonToIntList(Json const& v) {
List<int> result;
for (auto const& entry : v.iterateArray())
result.push_back(entry.toInt());
return result;
}
List<Vec2I> jsonToVec2IList(Json const& v) {
List<Vec2I> result;
for (auto const& entry : v.iterateArray())
result.append(jsonToVec2I(entry));
return result;
}
List<Vec2U> jsonToVec2UList(Json const& v) {
List<Vec2U> result;
for (auto const& entry : v.iterateArray())
result.append(jsonToVec2U(entry));
return result;
}
List<Vec2F> jsonToVec2FList(Json const& v) {
List<Vec2F> result;
for (auto const& entry : v.iterateArray())
result.append(jsonToVec2F(entry));
return result;
}
List<Vec4B> jsonToVec4BList(Json const& v) {
List<Vec4B> result;
for (auto const& entry : v.iterateArray())
result.append(jsonToVec4B(entry));
return result;
}
List<Color> jsonToColorList(Json const& v) {
List<Color> result;
for (auto const& entry : v.iterateArray())
result.append(jsonToColor(entry));
return result;
}
List<Directives> jsonToDirectivesList(Json const& v) {
List<Directives> result;
for (auto const& entry : v.iterateArray())
result.append(entry.toString());
return result;
}
Json jsonFromDirectivesList(List<Directives> const& v) {
JsonArray result;
for (auto& e : v) {
if (e)
result.push_back(*e.stringPtr());
}
return result;
}
Json weightedChoiceFromJson(Json const& source, Json const& default_) {
if (source.isNull())
return default_;
if (source.type() != Json::Type::Array)
throw StarException("Json of array type expected.");
List<pair<float, Json>> options;
float sum = 0;
size_t idx = 0;
while (idx < source.size()) {
float weight = 1;
Json entry = source.get(idx);
if (entry.type() == Json::Type::Int || entry.type() == Json::Type::Float) {
weight = entry.toDouble();
idx++;
if (idx >= source.size())
throw StarException("Weighted companion cube cannot cry.");
sum += weight;
options.append(pair<float, Json>{weight, source.get(idx)});
} else {
sum += weight;
options.append(pair<float, Json>{weight, entry});
}
idx++;
}
if (!options.size())
return default_;
float choice = Random::randf() * sum;
idx = 0;
while (idx < options.size()) {
auto const& entry = options[idx];
if (entry.first >= choice)
return entry.second;
choice -= entry.first;
idx++;
}
return options[options.size() - 1].second;
}
Json binnedChoiceFromJson(Json const& bins, float target, Json const& def) {
JsonArray binList = bins.toArray();
sortByComputedValue(binList, [](Json const& pair) { return -pair.getFloat(0); });
Json result = def;
for (auto const& pair : binList) {
if (pair.getFloat(0) <= target) {
result = pair.get(1);
break;
}
}
return result;
}
template <>
WeightedPool<int> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<int>(source, [](Json const& v) { return v.toInt(); });
}
template <>
WeightedPool<unsigned> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<unsigned>(source, [](Json const& v) { return v.toUInt(); });
}
template <>
WeightedPool<float> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<float>(source, [](Json const& v) { return v.toFloat(); });
}
template <>
WeightedPool<double> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<double>(source, [](Json const& v) { return v.toDouble(); });
}
template <>
WeightedPool<String> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<String>(source, [](Json const& v) { return v.toString(); });
}
template <>
WeightedPool<JsonArray> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<JsonArray>(source, [](Json const& v) { return v.toArray(); });
}
template <>
WeightedPool<JsonObject> jsonToWeightedPool(Json const& source) {
return jsonToWeightedPool<JsonObject>(source, [](Json const& v) { return v.toObject(); });
}
}