511 lines
16 KiB
C++
511 lines
16 KiB
C++
#include "CesiumGeoJsonObject.h"
|
|
|
|
#include "CesiumGeospatial/Cartographic.h"
|
|
#include "Dom/JsonObject.h"
|
|
#include "VecMath.h"
|
|
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
FCesiumGeoJsonFeature::FCesiumGeoJsonFeature()
|
|
: _pDocument(nullptr), _pFeature(nullptr) {}
|
|
|
|
FCesiumGeoJsonFeature::FCesiumGeoJsonFeature(
|
|
const std::shared_ptr<CesiumVectorData::GeoJsonDocument>& document,
|
|
const CesiumVectorData::GeoJsonFeature* feature)
|
|
: _pDocument(document), _pFeature(feature) {}
|
|
|
|
ECesiumGeoJsonFeatureIdType UCesiumGeoJsonFeatureBlueprintLibrary::GetIdType(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
if (!InFeature._pDocument || !InFeature._pFeature ||
|
|
std::holds_alternative<std::monostate>(InFeature._pFeature->id)) {
|
|
return ECesiumGeoJsonFeatureIdType::None;
|
|
}
|
|
|
|
return std::holds_alternative<int64_t>(InFeature._pFeature->id)
|
|
? ECesiumGeoJsonFeatureIdType::Integer
|
|
: ECesiumGeoJsonFeatureIdType::String;
|
|
}
|
|
|
|
int64 UCesiumGeoJsonFeatureBlueprintLibrary::GetIdAsInteger(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
if (!InFeature._pDocument || !InFeature._pFeature) {
|
|
return -1;
|
|
}
|
|
const int64_t* pId = std::get_if<int64_t>(&InFeature._pFeature->id);
|
|
if (!pId) {
|
|
return -1;
|
|
}
|
|
|
|
return *pId;
|
|
}
|
|
|
|
FString UCesiumGeoJsonFeatureBlueprintLibrary::GetIdAsString(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
if (!InFeature._pDocument || !InFeature._pFeature) {
|
|
return {};
|
|
}
|
|
struct GetIdVisitor {
|
|
FString operator()(const int64_t& id) { return FString::FromInt(id); }
|
|
FString operator()(const std::string& id) {
|
|
return UTF8_TO_TCHAR(id.c_str());
|
|
}
|
|
FString operator()(const std::monostate& id) { return {}; }
|
|
};
|
|
|
|
return std::visit(GetIdVisitor{}, InFeature._pFeature->id);
|
|
}
|
|
|
|
namespace {
|
|
TSharedPtr<FJsonValue>
|
|
jsonValueToUnrealJsonValue(const CesiumUtility::JsonValue& value) {
|
|
struct JsonValueVisitor {
|
|
TSharedPtr<FJsonValue> operator()(const CesiumUtility::JsonValue::Null&) {
|
|
return MakeShared<FJsonValueNull>();
|
|
}
|
|
TSharedPtr<FJsonValue>
|
|
operator()(const CesiumUtility::JsonValue::Bool& value) {
|
|
return MakeShared<FJsonValueBoolean>(value);
|
|
}
|
|
TSharedPtr<FJsonValue> operator()(const std::string& value) {
|
|
return MakeShared<FJsonValueString>(UTF8_TO_TCHAR(value.c_str()));
|
|
}
|
|
TSharedPtr<FJsonValue> operator()(const double& value) {
|
|
return MakeShared<FJsonValueNumber>(value);
|
|
}
|
|
TSharedPtr<FJsonValue> operator()(const std::uint64_t& value) {
|
|
// If this value will fit into a double losslessly, we return it as a JSON
|
|
// number.
|
|
const std::optional<double> doubleOpt =
|
|
CesiumUtility::losslessNarrow<double, std::uint64_t>(value);
|
|
if (doubleOpt) {
|
|
return MakeShared<FJsonValueNumber>(*doubleOpt);
|
|
}
|
|
|
|
// Otherwise, we return it as a number string.
|
|
return MakeShared<FJsonValueNumberString>(FString::FromInt(value));
|
|
}
|
|
TSharedPtr<FJsonValue> operator()(const std::int64_t& value) {
|
|
// If this value will fit into a double losslessly, we return it as a JSON
|
|
// number.
|
|
const std::optional<double> doubleOpt =
|
|
CesiumUtility::losslessNarrow<double, std::int64_t>(value);
|
|
if (doubleOpt) {
|
|
return MakeShared<FJsonValueNumber>(*doubleOpt);
|
|
}
|
|
|
|
// Otherwise, we return it as a number string.
|
|
return MakeShared<FJsonValueNumberString>(FString::FromInt(value));
|
|
}
|
|
TSharedPtr<FJsonValue>
|
|
operator()(const CesiumUtility::JsonValue::Array& value) {
|
|
TArray<TSharedPtr<FJsonValue>> values;
|
|
values.Reserve(value.size());
|
|
for (const CesiumUtility::JsonValue& v : value) {
|
|
values.Emplace(jsonValueToUnrealJsonValue(v));
|
|
}
|
|
return MakeShared<FJsonValueArray>(MoveTemp(values));
|
|
}
|
|
TSharedPtr<FJsonValue>
|
|
operator()(const CesiumUtility::JsonValue::Object& value) {
|
|
TSharedPtr<FJsonObject> obj = MakeShared<FJsonObject>();
|
|
for (const auto& [k, v] : value) {
|
|
obj->SetField(UTF8_TO_TCHAR(k.c_str()), jsonValueToUnrealJsonValue(v));
|
|
}
|
|
return MakeShared<FJsonValueObject>(MoveTemp(obj));
|
|
};
|
|
};
|
|
|
|
return std::visit(JsonValueVisitor{}, value.value);
|
|
}
|
|
} // namespace
|
|
|
|
FJsonObjectWrapper UCesiumGeoJsonFeatureBlueprintLibrary::GetProperties(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
if (!InFeature._pDocument || !InFeature._pFeature) {
|
|
return {};
|
|
}
|
|
TSharedPtr<FJsonObject> object = MakeShared<FJsonObject>();
|
|
if (InFeature._pFeature->properties) {
|
|
for (const auto& [k, v] : *InFeature._pFeature->properties) {
|
|
object->SetField(UTF8_TO_TCHAR(k.c_str()), jsonValueToUnrealJsonValue(v));
|
|
}
|
|
}
|
|
|
|
FJsonObjectWrapper wrapper;
|
|
wrapper.JsonObject = MoveTemp(object);
|
|
return wrapper;
|
|
}
|
|
|
|
FCesiumGeoJsonObject UCesiumGeoJsonFeatureBlueprintLibrary::GetGeometry(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
if (!InFeature._pDocument || !InFeature._pFeature ||
|
|
!InFeature._pFeature->geometry) {
|
|
return {};
|
|
}
|
|
|
|
return FCesiumGeoJsonObject(
|
|
InFeature._pDocument,
|
|
InFeature._pFeature->geometry.get());
|
|
}
|
|
|
|
bool UCesiumGeoJsonFeatureBlueprintLibrary::IsValid(
|
|
const FCesiumGeoJsonFeature& InFeature) {
|
|
return InFeature._pDocument != nullptr && InFeature._pFeature != nullptr;
|
|
}
|
|
|
|
bool UCesiumGeoJsonObjectBlueprintLibrary::IsValid(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
return InObject._pDocument != nullptr && InObject._pObject != nullptr;
|
|
}
|
|
|
|
ECesiumGeoJsonObjectType UCesiumGeoJsonObjectBlueprintLibrary::GetObjectType(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
// Assert that enums are equivalent.
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::Point ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::Point);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::MultiPoint ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::MultiPoint);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::LineString ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::LineString);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::MultiLineString ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::MultiLineString);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::Polygon ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::Polygon);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::MultiPolygon ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::MultiPolygon);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::GeometryCollection ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::GeometryCollection);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::Feature ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::Feature);
|
|
static_assert(
|
|
(uint32_t)CesiumVectorData::GeoJsonObjectType::FeatureCollection ==
|
|
(uint32_t)ECesiumGeoJsonObjectType::FeatureCollection);
|
|
|
|
return (ECesiumGeoJsonObjectType)InObject._pObject->getType();
|
|
}
|
|
|
|
FBox UCesiumGeoJsonObjectBlueprintLibrary::GetBoundingBox(
|
|
const FCesiumGeoJsonObject& InObject,
|
|
EHasValue& Branches) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
Branches = EHasValue::NoValue;
|
|
return {};
|
|
}
|
|
|
|
const std::optional<CesiumGeometry::AxisAlignedBox>& boundingBox =
|
|
InObject._pObject->getBoundingBox();
|
|
if (boundingBox) {
|
|
Branches = EHasValue::HasValue;
|
|
return FBox(
|
|
FVector(
|
|
boundingBox->minimumX,
|
|
boundingBox->minimumY,
|
|
boundingBox->minimumZ),
|
|
FVector(
|
|
boundingBox->maximumX,
|
|
boundingBox->maximumY,
|
|
boundingBox->maximumZ));
|
|
}
|
|
|
|
Branches = EHasValue::NoValue;
|
|
return {};
|
|
}
|
|
|
|
FJsonObjectWrapper UCesiumGeoJsonObjectBlueprintLibrary::GetForeignMembers(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
TSharedPtr<FJsonObject> object = MakeShared<FJsonObject>();
|
|
for (const auto& [k, v] : InObject._pObject->getForeignMembers()) {
|
|
object->SetField(UTF8_TO_TCHAR(k.c_str()), jsonValueToUnrealJsonValue(v));
|
|
}
|
|
|
|
FJsonObjectWrapper wrapper;
|
|
wrapper.JsonObject = MoveTemp(object);
|
|
return wrapper;
|
|
}
|
|
|
|
FVector UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsPoint(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonPoint* pPoint =
|
|
std::get_if<CesiumVectorData::GeoJsonPoint>(&InObject._pObject->value);
|
|
|
|
if (!pPoint) {
|
|
return FVector::ZeroVector;
|
|
}
|
|
|
|
return VecMath::createVector(pPoint->coordinates);
|
|
}
|
|
|
|
TArray<FVector> UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsMultiPoint(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonMultiPoint* pMultiPoint =
|
|
std::get_if<CesiumVectorData::GeoJsonMultiPoint>(
|
|
&InObject._pObject->value);
|
|
|
|
if (!pMultiPoint) {
|
|
return TArray<FVector>();
|
|
}
|
|
|
|
TArray<FVector> Points;
|
|
Points.Reserve(pMultiPoint->coordinates.size());
|
|
|
|
for (size_t i = 0; i < pMultiPoint->coordinates.size(); i++) {
|
|
Points.Emplace(VecMath::createVector(pMultiPoint->coordinates[i]));
|
|
}
|
|
|
|
return Points;
|
|
}
|
|
|
|
FCesiumGeoJsonLineString
|
|
UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsLineString(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonLineString* pLineString =
|
|
std::get_if<CesiumVectorData::GeoJsonLineString>(
|
|
&InObject._pObject->value);
|
|
|
|
if (!pLineString) {
|
|
return TArray<FVector>();
|
|
}
|
|
|
|
TArray<FVector> Points;
|
|
Points.Reserve(pLineString->coordinates.size());
|
|
|
|
for (size_t i = 0; i < pLineString->coordinates.size(); i++) {
|
|
Points.Emplace(VecMath::createVector(pLineString->coordinates[i]));
|
|
}
|
|
|
|
return FCesiumGeoJsonLineString(MoveTemp(Points));
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonLineString>
|
|
UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsMultiLineString(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonMultiLineString* pMultiLineString =
|
|
std::get_if<CesiumVectorData::GeoJsonMultiLineString>(
|
|
&InObject._pObject->value);
|
|
|
|
if (!pMultiLineString) {
|
|
return TArray<FCesiumGeoJsonLineString>();
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonLineString> Lines;
|
|
Lines.Reserve(pMultiLineString->coordinates.size());
|
|
for (size_t i = 0; i < pMultiLineString->coordinates[i].size(); i++) {
|
|
|
|
TArray<FVector> Points;
|
|
Points.Reserve(pMultiLineString->coordinates[i].size());
|
|
|
|
for (size_t j = 0; j < pMultiLineString->coordinates[i].size(); j++) {
|
|
Points.Emplace(
|
|
VecMath::createVector(pMultiLineString->coordinates[i][j]));
|
|
}
|
|
|
|
Lines.Emplace(MoveTemp(Points));
|
|
}
|
|
|
|
return Lines;
|
|
}
|
|
|
|
FCesiumGeoJsonPolygon UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsPolygon(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonPolygon* pPolygon =
|
|
std::get_if<CesiumVectorData::GeoJsonPolygon>(&InObject._pObject->value);
|
|
|
|
if (!pPolygon) {
|
|
return FCesiumGeoJsonPolygon();
|
|
}
|
|
|
|
return FCesiumGeoJsonPolygon(InObject._pDocument, &pPolygon->coordinates);
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonPolygon>
|
|
UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsMultiPolygon(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonMultiPolygon* pMultiPolygon =
|
|
std::get_if<CesiumVectorData::GeoJsonMultiPolygon>(
|
|
&InObject._pObject->value);
|
|
|
|
if (!pMultiPolygon) {
|
|
return TArray<FCesiumGeoJsonPolygon>();
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonPolygon> Polygons;
|
|
Polygons.Reserve(pMultiPolygon->coordinates.size());
|
|
|
|
for (size_t i = 0; i < pMultiPolygon->coordinates.size(); i++) {
|
|
Polygons.Emplace(InObject._pDocument, &pMultiPolygon->coordinates[i]);
|
|
}
|
|
|
|
return Polygons;
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonObject>
|
|
UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsGeometryCollection(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonGeometryCollection* pGeometryCollection =
|
|
std::get_if<CesiumVectorData::GeoJsonGeometryCollection>(
|
|
&InObject._pObject->value);
|
|
|
|
if (!pGeometryCollection) {
|
|
|
|
return TArray<FCesiumGeoJsonObject>();
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonObject> Geometries;
|
|
Geometries.Reserve(pGeometryCollection->geometries.size());
|
|
|
|
for (size_t i = 0; i < pGeometryCollection->geometries.size(); i++) {
|
|
Geometries.Emplace(FCesiumGeoJsonObject(
|
|
InObject._pDocument,
|
|
&pGeometryCollection->geometries[i]));
|
|
}
|
|
|
|
return Geometries;
|
|
}
|
|
|
|
FCesiumGeoJsonFeature UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsFeature(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonFeature* pFeature =
|
|
std::get_if<CesiumVectorData::GeoJsonFeature>(&InObject._pObject->value);
|
|
|
|
if (!pFeature) {
|
|
return FCesiumGeoJsonFeature();
|
|
}
|
|
|
|
return FCesiumGeoJsonFeature(InObject._pDocument, pFeature);
|
|
}
|
|
|
|
TArray<FCesiumGeoJsonFeature>
|
|
UCesiumGeoJsonObjectBlueprintLibrary::GetObjectAsFeatureCollection(
|
|
const FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return {};
|
|
}
|
|
|
|
const CesiumVectorData::GeoJsonFeatureCollection* pFeatureCollection =
|
|
std::get_if<CesiumVectorData::GeoJsonFeatureCollection>(
|
|
&InObject._pObject->value);
|
|
|
|
TArray<FCesiumGeoJsonFeature> Features;
|
|
Features.Reserve(pFeatureCollection->features.size());
|
|
|
|
for (size_t i = 0; i < pFeatureCollection->features.size(); i++) {
|
|
const CesiumVectorData::GeoJsonFeature* pFeature =
|
|
pFeatureCollection->features[i]
|
|
.getIf<CesiumVectorData::GeoJsonFeature>();
|
|
if (pFeature == nullptr) {
|
|
continue;
|
|
}
|
|
Features.Emplace(FCesiumGeoJsonFeature(InObject._pDocument, pFeature));
|
|
}
|
|
|
|
return Features;
|
|
}
|
|
|
|
FCesiumVectorStyle UCesiumGeoJsonObjectBlueprintLibrary::GetStyle(
|
|
const FCesiumGeoJsonObject& InObject,
|
|
EHasValue& Branches) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
Branches = EHasValue::NoValue;
|
|
return FCesiumVectorStyle();
|
|
}
|
|
|
|
const std::optional<CesiumVectorData::VectorStyle> style =
|
|
InObject._pObject->getStyle();
|
|
Branches = style ? EHasValue::HasValue : EHasValue::NoValue;
|
|
return style ? FCesiumVectorStyle::fromNative(*style) : FCesiumVectorStyle();
|
|
}
|
|
|
|
void UCesiumGeoJsonObjectBlueprintLibrary::SetStyle(
|
|
UPARAM(Ref) FCesiumGeoJsonObject& InObject,
|
|
const FCesiumVectorStyle& InStyle) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return;
|
|
}
|
|
|
|
const_cast<CesiumVectorData::GeoJsonObject*>(InObject._pObject)->getStyle() =
|
|
InStyle.toNative();
|
|
}
|
|
|
|
void UCesiumGeoJsonObjectBlueprintLibrary::ClearStyle(
|
|
UPARAM(Ref) FCesiumGeoJsonObject& InObject) {
|
|
if (!InObject._pDocument || !InObject._pObject) {
|
|
return;
|
|
}
|
|
|
|
const_cast<CesiumVectorData::GeoJsonObject*>(InObject._pObject)->getStyle() =
|
|
std::nullopt;
|
|
}
|
|
|
|
FCesiumGeoJsonLineString::FCesiumGeoJsonLineString(TArray<FVector>&& InPoints)
|
|
: Points(MoveTemp(InPoints)) {}
|
|
|
|
TArray<FCesiumGeoJsonLineString>
|
|
UCesiumGeoJsonPolygonBlueprintFunctionLibrary::GetPolygonRings(
|
|
const FCesiumGeoJsonPolygon& InPolygon) {
|
|
TArray<FCesiumGeoJsonLineString> Rings;
|
|
Rings.Reserve(InPolygon._rings->size());
|
|
|
|
for (size_t i = 0; i < InPolygon._rings->size(); i++) {
|
|
TArray<FVector> Points;
|
|
Points.Reserve((*InPolygon._rings)[i].size());
|
|
|
|
for (size_t j = 0; j < (*InPolygon._rings)[i].size(); j++) {
|
|
Points.Emplace(VecMath::createVector((*InPolygon._rings)[i][j]));
|
|
}
|
|
|
|
Rings.Emplace(MoveTemp(Points));
|
|
}
|
|
|
|
return Rings;
|
|
}
|