cesium-native 0.43.0
Loading...
Searching...
No Matches
PropertyView.h
1#pragma once
2
3#include "CesiumGltf/ClassProperty.h"
4#include "CesiumGltf/PropertyAttributeProperty.h"
5#include "CesiumGltf/PropertyTableProperty.h"
6#include "CesiumGltf/PropertyTextureProperty.h"
7#include "CesiumGltf/PropertyTypeTraits.h"
8
9#include <cstring>
10#include <optional>
11
12namespace CesiumGltf {
13
17typedef int32_t PropertyViewStatusType;
18
112
119template <typename T>
121validatePropertyType(const ClassProperty& classProperty) {
123 convertStringToPropertyType(classProperty.type)) {
125 }
126
127 PropertyComponentType expectedComponentType =
129
130 if (!classProperty.componentType &&
131 expectedComponentType != PropertyComponentType::None) {
133 }
134
135 if (classProperty.componentType &&
136 expectedComponentType !=
139 }
140
141 if (classProperty.array) {
143 }
144
146}
147
155template <typename T>
158 using ElementType = typename MetadataArrayType<T>::type;
160 convertStringToPropertyType(classProperty.type)) {
162 }
163
164 PropertyComponentType expectedComponentType =
166
167 if (!classProperty.componentType &&
168 expectedComponentType != PropertyComponentType::None) {
170 }
171
172 if (classProperty.componentType &&
173 expectedComponentType !=
176 }
177
178 if (!classProperty.array) {
180 }
181
183}
184
192template <typename T>
193static std::optional<T> getScalar(const CesiumUtility::JsonValue& jsonValue) {
194 return jsonValue.getSafeNumber<T>();
195}
196
206template <typename VecType>
207static std::optional<VecType>
208getVecN(const CesiumUtility::JsonValue& jsonValue) {
209 if (!jsonValue.isArray()) {
210 return std::nullopt;
211 }
212
213 const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
214 constexpr glm::length_t N = VecType::length();
215 if (array.size() != N) {
216 return std::nullopt;
217 }
218
219 using T = typename VecType::value_type;
220
221 VecType result;
222 for (glm::length_t i = 0; i < N; i++) {
223 std::optional<T> value = getScalar<T>(array[i]);
224 if (!value) {
225 return std::nullopt;
226 }
227
228 result[i] = *value;
229 }
230
231 return result;
232}
233
244template <typename MatType>
245static std::optional<MatType>
246getMatN(const CesiumUtility::JsonValue& jsonValue) {
247 if (!jsonValue.isArray()) {
248 return std::nullopt;
249 }
250
251 const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
252 constexpr glm::length_t N = MatType::length();
253 if (array.size() != N * N) {
254 return std::nullopt;
255 }
256
257 using T = typename MatType::value_type;
258
259 MatType result;
260 for (glm::length_t i = 0; i < N; i++) {
261 // Try to parse each value in the column.
262 for (glm::length_t j = 0; j < N; j++) {
263 std::optional<T> value = getScalar<T>(array[i * N + j]);
264 if (!value) {
265 return std::nullopt;
266 }
267
268 result[i][j] = *value;
269 }
270 }
271
272 return result;
273}
274
284template <typename ElementType>
285int64_t getCount(std::optional<std::vector<std::byte>>& buffer) {
286 if (!buffer) {
287 return 0;
288 }
289
290 return static_cast<int64_t>(buffer->size() / sizeof(ElementType));
291}
292
296template <typename ElementType, bool Normalized = false> class PropertyView;
297
310template <typename ElementType> class PropertyView<ElementType, false> {
311public:
316 : _status(PropertyViewStatus::ErrorNonexistentProperty),
317 _name(std::nullopt),
318 _semantic(std::nullopt),
319 _description(std::nullopt),
320 _offset(std::nullopt),
321 _scale(std::nullopt),
322 _max(std::nullopt),
323 _min(std::nullopt),
324 _required(false),
325 _noData(std::nullopt),
326 _defaultValue(std::nullopt) {}
327
331 PropertyView(const ClassProperty& classProperty)
332 : _status(validatePropertyType<ElementType>(classProperty)),
333 _name(classProperty.name),
334 _semantic(classProperty.semantic),
335 _description(classProperty.description),
336 _offset(std::nullopt),
337 _scale(std::nullopt),
338 _max(std::nullopt),
339 _min(std::nullopt),
340 _required(classProperty.required),
341 _noData(std::nullopt),
342 _defaultValue(std::nullopt) {
343 if (_status != PropertyViewStatus::Valid) {
344 return;
345 }
346
347 if (classProperty.normalized) {
348 _status = PropertyViewStatus::ErrorNormalizationMismatch;
349 return;
350 }
351
352 getNumericPropertyValues(classProperty);
353 if (_status != PropertyViewStatus::Valid) {
354 return;
355 }
356
357 if (classProperty.noData) {
358 if (!_required) {
359 // "noData" can only be defined if the property is not required.
360 _noData = getValue(*classProperty.noData);
361 }
362
363 if (!_noData) {
364 // The value was specified but something went wrong.
366 return;
367 }
368 }
369
370 if (classProperty.defaultProperty) {
371 if (!_required) {
372 // "default" can only be defined if the property is not required.
373 _defaultValue = getValue(*classProperty.defaultProperty);
374 }
375
376 if (!_defaultValue) {
377 // The value was specified but something went wrong.
379 return;
380 }
381 }
382 }
383
384protected:
392 : _status(status),
393 _name(std::nullopt),
394 _semantic(std::nullopt),
395 _description(std::nullopt),
396 _offset(std::nullopt),
397 _scale(std::nullopt),
398 _max(std::nullopt),
399 _min(std::nullopt),
400 _required(false),
401 _noData(std::nullopt),
402 _defaultValue(std::nullopt) {}
403
409 const ClassProperty& classProperty,
410 const PropertyTableProperty& property)
411 : PropertyView(classProperty) {
412 if (_status != PropertyViewStatus::Valid) {
413 return;
414 }
415
416 // If the property has its own values, override the class-provided values.
417 getNumericPropertyValues(property);
418 }
419
425 const ClassProperty& classProperty,
426 const PropertyTextureProperty& property)
427 : PropertyView(classProperty) {
428 if (_status != PropertyViewStatus::Valid) {
429 return;
430 }
431
432 // If the property has its own values, override the class-provided values.
433 getNumericPropertyValues(property);
434 }
435
441 const ClassProperty& classProperty,
442 const PropertyAttributeProperty& property)
443 : PropertyView(classProperty) {
444 if (_status != PropertyViewStatus::Valid) {
445 return;
446 }
447
448 // If the property has its own values, override the class-provided values.
449 getNumericPropertyValues(property);
450 }
451
452public:
459 PropertyViewStatusType status() const noexcept { return _status; }
460
465 const std::optional<std::string>& name() const noexcept { return _name; }
466
473 const std::optional<std::string>& semantic() const noexcept {
474 return _semantic;
475 }
476
481 const std::optional<std::string>& description() const noexcept {
482 return _description;
483 }
484
491 int64_t arrayCount() const noexcept { return 0; }
492
496 bool normalized() const noexcept { return false; }
497
505 std::optional<ElementType> offset() const noexcept { return _offset; }
506
514 std::optional<ElementType> scale() const noexcept { return _scale; }
515
525 std::optional<ElementType> max() const noexcept { return _max; }
526
536 std::optional<ElementType> min() const noexcept { return _min; }
537
543 bool required() const noexcept { return _required; }
544
554 std::optional<ElementType> noData() const noexcept { return _noData; }
555
564 std::optional<ElementType> defaultValue() const noexcept {
565 return _defaultValue;
566 }
567
568protected:
571
572private:
573 std::optional<std::string> _name;
574 std::optional<std::string> _semantic;
575 std::optional<std::string> _description;
576
577 std::optional<ElementType> _offset;
578 std::optional<ElementType> _scale;
579 std::optional<ElementType> _max;
580 std::optional<ElementType> _min;
581
582 bool _required;
583 std::optional<ElementType> _noData;
584 std::optional<ElementType> _defaultValue;
585
596 static std::optional<ElementType>
597 getValue(const CesiumUtility::JsonValue& jsonValue) {
599 return getScalar<ElementType>(jsonValue);
600 }
601
603 return getVecN<ElementType>(jsonValue);
604 }
605
607 return getMatN<ElementType>(jsonValue);
608 }
609 }
610
611 using PropertyDefinitionType = std::variant<
616
621 void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
622 std::visit(
623 [this](auto property) {
624 if (property.offset) {
625 // Only floating point types can specify an offset.
627 case PropertyComponentType::Float32:
628 case PropertyComponentType::Float64:
629 this->_offset = getValue(*property.offset);
630 if (this->_offset) {
631 break;
632 }
633 // If it does not break here, something went wrong.
634 [[fallthrough]];
635 default:
636 this->_status = PropertyViewStatus::ErrorInvalidOffset;
637 return;
638 }
639 }
640
641 if (property.scale) {
642 // Only floating point types can specify a scale.
643 switch (TypeToPropertyType<ElementType>::component) {
644 case PropertyComponentType::Float32:
645 case PropertyComponentType::Float64:
646 this->_scale = getValue(*property.scale);
647 if (this->_scale) {
648 break;
649 }
650 // If it does not break here, something went wrong.
651 [[fallthrough]];
652 default:
653 this->_status = PropertyViewStatus::ErrorInvalidScale;
654 return;
655 }
656 }
657
658 if (property.max) {
659 this->_max = getValue(*property.max);
660 if (!this->_max) {
661 // The value was specified but something went wrong.
662 this->_status = PropertyViewStatus::ErrorInvalidMax;
663 return;
664 }
665 }
666
667 if (property.min) {
668 this->_min = getValue(*property.min);
669 if (!this->_min) {
670 // The value was specified but something went wrong.
671 this->_status = PropertyViewStatus::ErrorInvalidMin;
672 return;
673 }
674 }
675 },
676 inProperty);
677 }
678};
679
693template <typename ElementType> class PropertyView<ElementType, true> {
694private:
695 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
696
697public:
702 : _status(PropertyViewStatus::ErrorNonexistentProperty),
703 _name(std::nullopt),
704 _semantic(std::nullopt),
705 _description(std::nullopt),
706 _offset(std::nullopt),
707 _scale(std::nullopt),
708 _max(std::nullopt),
709 _min(std::nullopt),
710 _required(false),
711 _noData(std::nullopt),
712 _defaultValue(std::nullopt) {}
713
717 PropertyView(const ClassProperty& classProperty)
718 : _status(validatePropertyType<ElementType>(classProperty)),
719 _name(classProperty.name),
720 _semantic(classProperty.semantic),
721 _description(classProperty.description),
722 _offset(std::nullopt),
723 _scale(std::nullopt),
724 _max(std::nullopt),
725 _min(std::nullopt),
726 _required(classProperty.required),
727 _noData(std::nullopt),
728 _defaultValue(std::nullopt) {
729 if (_status != PropertyViewStatus::Valid) {
730 return;
731 }
732
733 if (!classProperty.normalized) {
734 _status = PropertyViewStatus::ErrorNormalizationMismatch;
735 }
736
737 getNumericPropertyValues(classProperty);
738 if (_status != PropertyViewStatus::Valid) {
739 return;
740 }
741
742 if (classProperty.noData) {
743 if (!_required) {
744 // "noData" should not be defined if the property is required.
745 _noData = getValue<ElementType>(*classProperty.noData);
746 }
747 if (!_noData) {
748 // The value was specified but something went wrong.
749 _status = PropertyViewStatus::ErrorInvalidNoDataValue;
750 return;
751 }
752 }
753
754 if (classProperty.defaultProperty) {
755 // default value should not be defined if the property is required.
756 if (!_required) {
757 _defaultValue =
758 getValue<NormalizedType>(*classProperty.defaultProperty);
759 }
760 if (!_defaultValue) {
761 // The value was specified but something went wrong.
762 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
763 return;
764 }
765 }
766 }
767
768protected:
775 : _status(status),
776 _name(std::nullopt),
777 _semantic(std::nullopt),
778 _description(std::nullopt),
779 _offset(std::nullopt),
780 _scale(std::nullopt),
781 _max(std::nullopt),
782 _min(std::nullopt),
783 _required(false),
784 _noData(std::nullopt),
785 _defaultValue(std::nullopt) {}
786
792 const ClassProperty& classProperty,
793 const PropertyTableProperty& property)
794 : PropertyView(classProperty) {
795 if (_status != PropertyViewStatus::Valid) {
796 return;
797 }
798
799 // If the property has its own values, override the class-provided values.
800 getNumericPropertyValues(property);
801 }
802
808 const ClassProperty& classProperty,
809 const PropertyTextureProperty& property)
810 : PropertyView(classProperty) {
811 if (_status != PropertyViewStatus::Valid) {
812 return;
813 }
814
815 // If the property has its own values, override the class-provided values.
816 getNumericPropertyValues(property);
817 }
818
824 const ClassProperty& classProperty,
825 const PropertyAttributeProperty& property)
826 : PropertyView(classProperty) {
827 if (_status != PropertyViewStatus::Valid) {
828 return;
829 }
830
831 // If the property has its own values, override the class-provided values.
832 getNumericPropertyValues(property);
833 }
834
835public:
839 PropertyViewStatusType status() const noexcept { return _status; }
840
844 const std::optional<std::string>& name() const noexcept { return _name; }
845
849 const std::optional<std::string>& semantic() const noexcept {
850 return _semantic;
851 }
852
856 const std::optional<std::string>& description() const noexcept {
857 return _description;
858 }
859
863 int64_t arrayCount() const noexcept { return 0; }
864
868 bool normalized() const noexcept { return true; }
869
873 std::optional<NormalizedType> offset() const noexcept { return _offset; }
874
878 std::optional<NormalizedType> scale() const noexcept { return _scale; }
879
883 std::optional<NormalizedType> max() const noexcept { return _max; }
884
888 std::optional<NormalizedType> min() const noexcept { return _min; }
889
893 bool required() const noexcept { return _required; }
894
898 std::optional<ElementType> noData() const noexcept { return _noData; }
899
903 std::optional<NormalizedType> defaultValue() const noexcept {
904 return _defaultValue;
905 }
906
907protected:
910
911private:
912 std::optional<std::string> _name;
913 std::optional<std::string> _semantic;
914 std::optional<std::string> _description;
915
916 std::optional<NormalizedType> _offset;
917 std::optional<NormalizedType> _scale;
918 std::optional<NormalizedType> _max;
919 std::optional<NormalizedType> _min;
920
921 bool _required;
922 std::optional<ElementType> _noData;
923 std::optional<NormalizedType> _defaultValue;
924
934 template <typename T>
935 static std::optional<T> getValue(const CesiumUtility::JsonValue& jsonValue) {
936 if constexpr (IsMetadataScalar<T>::value) {
937 return getScalar<T>(jsonValue);
938 }
939
940 if constexpr (IsMetadataVecN<T>::value) {
941 return getVecN<T>(jsonValue);
942 }
943
944 if constexpr (IsMetadataMatN<T>::value) {
945 return getMatN<T>(jsonValue);
946 }
947 }
948
949 using PropertyDefinitionType = std::variant<
954
959 void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
960 std::visit(
961 [this](auto property) {
962 if (property.offset) {
963 _offset = getValue<NormalizedType>(*property.offset);
964 if (!_offset) {
965 // The value was specified but something went wrong.
966 _status = PropertyViewStatus::ErrorInvalidOffset;
967 return;
968 }
969 }
970
971 if (property.scale) {
972 _scale = getValue<NormalizedType>(*property.scale);
973 if (!_scale) {
974 // The value was specified but something went wrong.
975 _status = PropertyViewStatus::ErrorInvalidScale;
976 return;
977 }
978 }
979
980 if (property.max) {
981 _max = getValue<NormalizedType>(*property.max);
982 if (!_scale) {
983 // The value was specified but something went wrong.
984 _status = PropertyViewStatus::ErrorInvalidMax;
985 return;
986 }
987 }
988
989 if (property.min) {
990 _min = getValue<NormalizedType>(*property.min);
991 if (!_scale) {
992 // The value was specified but something went wrong.
993 _status = PropertyViewStatus::ErrorInvalidMin;
994 return;
995 }
996 }
997 },
998 inProperty);
999 }
1000};
1001
1006template <> class PropertyView<bool> {
1007public:
1012 : _status(PropertyViewStatus::ErrorNonexistentProperty),
1013 _name(std::nullopt),
1014 _semantic(std::nullopt),
1015 _description(std::nullopt),
1016 _required(false),
1017 _defaultValue(std::nullopt) {}
1018
1022 PropertyView(const ClassProperty& classProperty)
1023 : _status(validatePropertyType<bool>(classProperty)),
1024 _name(classProperty.name),
1025 _semantic(classProperty.semantic),
1026 _description(classProperty.description),
1027 _required(classProperty.required),
1028 _defaultValue(std::nullopt) {
1029 if (_status != PropertyViewStatus::Valid) {
1030 return;
1031 }
1032
1033 if (classProperty.defaultProperty) {
1034 if (!_required) {
1035 _defaultValue = getBooleanValue(*classProperty.defaultProperty);
1036 }
1037
1038 if (!_defaultValue) {
1039 // The value was specified but something went wrong.
1040 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1041 return;
1042 }
1043 }
1044 }
1045
1046protected:
1053 : _status(status),
1054 _name(std::nullopt),
1055 _semantic(std::nullopt),
1056 _description(std::nullopt),
1057 _required(false),
1058 _defaultValue(std::nullopt) {}
1059
1065 const ClassProperty& classProperty,
1066 const PropertyTableProperty& /*property*/)
1067 : PropertyView(classProperty) {}
1068
1069public:
1073 PropertyViewStatusType status() const noexcept { return _status; }
1074
1078 const std::optional<std::string>& name() const noexcept { return _name; }
1079
1083 const std::optional<std::string>& semantic() const noexcept {
1084 return _semantic;
1085 }
1086
1090 const std::optional<std::string>& description() const noexcept {
1091 return _description;
1092 }
1093
1097 int64_t arrayCount() const noexcept { return 0; }
1098
1102 bool normalized() const noexcept { return false; }
1103
1107 std::optional<bool> offset() const noexcept { return std::nullopt; }
1108
1112 std::optional<bool> scale() const noexcept { return std::nullopt; }
1113
1117 std::optional<bool> max() const noexcept { return std::nullopt; }
1118
1122 std::optional<bool> min() const noexcept { return std::nullopt; }
1123
1127 bool required() const noexcept { return _required; }
1128
1132 std::optional<bool> noData() const noexcept { return std::nullopt; }
1133
1137 std::optional<bool> defaultValue() const noexcept { return _defaultValue; }
1138
1139protected:
1142
1143private:
1144 std::optional<std::string> _name;
1145 std::optional<std::string> _semantic;
1146 std::optional<std::string> _description;
1147
1148 bool _required;
1149 std::optional<bool> _defaultValue;
1150
1151 static std::optional<bool>
1152 getBooleanValue(const CesiumUtility::JsonValue& value) {
1153 if (!value.isBool()) {
1154 return std::nullopt;
1155 }
1156
1157 return value.getBool();
1158 }
1159};
1160
1165template <> class PropertyView<std::string_view> {
1166public:
1171 : _status(PropertyViewStatus::ErrorNonexistentProperty),
1172 _name(std::nullopt),
1173 _semantic(std::nullopt),
1174 _description(std::nullopt),
1175 _required(false),
1176 _noData(std::nullopt),
1177 _defaultValue(std::nullopt) {}
1178
1182 PropertyView(const ClassProperty& classProperty)
1183 : _status(validatePropertyType<std::string_view>(classProperty)),
1184 _name(classProperty.name),
1185 _semantic(classProperty.semantic),
1186 _description(classProperty.description),
1187 _required(classProperty.required),
1188 _noData(std::nullopt),
1189 _defaultValue(std::nullopt) {
1190 if (_status != PropertyViewStatus::Valid) {
1191 return;
1192 }
1193
1194 if (classProperty.noData) {
1195 if (!_required) {
1196 _noData = getStringValue(*classProperty.noData);
1197 }
1198
1199 if (!_noData) {
1200 // The value was specified but something went wrong.
1201 _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1202 return;
1203 }
1204 }
1205
1206 if (classProperty.defaultProperty) {
1207 if (!_required) {
1208 _defaultValue = getStringValue(*classProperty.defaultProperty);
1209 }
1210
1211 if (!_defaultValue) {
1212 // The value was specified but something went wrong.
1213 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1214 return;
1215 }
1216 }
1217 }
1218
1219protected:
1226 : _status(status),
1227 _name(std::nullopt),
1228 _semantic(std::nullopt),
1229 _description(std::nullopt),
1230 _required(false),
1231 _noData(std::nullopt),
1232 _defaultValue(std::nullopt) {}
1233
1239 const ClassProperty& classProperty,
1240 const PropertyTableProperty& /*property*/)
1241 : PropertyView(classProperty) {}
1242
1243public:
1247 PropertyViewStatusType status() const noexcept { return _status; }
1248
1252 const std::optional<std::string>& name() const noexcept { return _name; }
1253
1257 const std::optional<std::string>& semantic() const noexcept {
1258 return _semantic;
1259 }
1260
1264 const std::optional<std::string>& description() const noexcept {
1265 return _description;
1266 }
1267
1271 int64_t arrayCount() const noexcept { return 0; }
1272
1276 bool normalized() const noexcept { return false; }
1277
1281 std::optional<std::string_view> offset() const noexcept {
1282 return std::nullopt;
1283 }
1284
1288 std::optional<std::string_view> scale() const noexcept {
1289 return std::nullopt;
1290 }
1291
1295 std::optional<std::string_view> max() const noexcept { return std::nullopt; }
1296
1300 std::optional<std::string_view> min() const noexcept { return std::nullopt; }
1301
1305 bool required() const noexcept { return _required; }
1306
1310 std::optional<std::string_view> noData() const noexcept {
1311 if (_noData)
1312 return std::string_view(*_noData);
1313
1314 return std::nullopt;
1315 }
1316
1320 std::optional<std::string_view> defaultValue() const noexcept {
1321 if (_defaultValue)
1322 return std::string_view(*_defaultValue);
1323
1324 return std::nullopt;
1325 }
1326
1327protected:
1330
1331private:
1332 std::optional<std::string> _name;
1333 std::optional<std::string> _semantic;
1334 std::optional<std::string> _description;
1335
1336 bool _required;
1337 std::optional<std::string> _noData;
1338 std::optional<std::string> _defaultValue;
1339
1340 static std::optional<std::string>
1341 getStringValue(const CesiumUtility::JsonValue& value) {
1342 if (!value.isString()) {
1343 return std::nullopt;
1344 }
1345
1346 return std::string(value.getString().c_str());
1347 }
1348};
1349
1363template <typename ElementType>
1364class PropertyView<PropertyArrayView<ElementType>, false> {
1365public:
1370 : _status(PropertyViewStatus::ErrorNonexistentProperty),
1371 _name(std::nullopt),
1372 _semantic(std::nullopt),
1373 _description(std::nullopt),
1374 _count(0),
1375 _offset(std::nullopt),
1376 _scale(std::nullopt),
1377 _max(std::nullopt),
1378 _min(std::nullopt),
1379 _required(false),
1380 _noData(std::nullopt),
1381 _defaultValue(std::nullopt) {}
1382
1386 PropertyView(const ClassProperty& classProperty)
1387 : _status(validateArrayPropertyType<PropertyArrayView<ElementType>>(
1388 classProperty)),
1389 _name(classProperty.name),
1390 _semantic(classProperty.semantic),
1391 _description(classProperty.description),
1392 _count(_count = classProperty.count ? *classProperty.count : 0),
1393 _offset(std::nullopt),
1394 _scale(std::nullopt),
1395 _max(std::nullopt),
1396 _min(std::nullopt),
1397 _required(classProperty.required),
1398 _noData(std::nullopt),
1399 _defaultValue(std::nullopt) {
1400 if (_status != PropertyViewStatus::Valid) {
1401 return;
1402 }
1403
1404 if (classProperty.normalized) {
1405 _status = PropertyViewStatus::ErrorNormalizationMismatch;
1406 return;
1407 }
1408
1409 getNumericPropertyValues(classProperty);
1410 if (_status != PropertyViewStatus::Valid) {
1411 return;
1412 }
1413
1414 if (classProperty.noData) {
1415 if (!_required) {
1416 _noData = getArrayValue(*classProperty.noData);
1417 }
1418
1419 if (!_noData) {
1420 _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1421 return;
1422 }
1423 }
1424
1425 if (classProperty.defaultProperty) {
1426 if (!_required) {
1427 _defaultValue = getArrayValue(*classProperty.defaultProperty);
1428 }
1429
1430 if (!_defaultValue) {
1431 // The value was specified but something went wrong.
1432 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1433 return;
1434 }
1435 }
1436 }
1437
1438protected:
1445 : _status(status),
1446 _name(std::nullopt),
1447 _semantic(std::nullopt),
1448 _description(std::nullopt),
1449 _count(0),
1450 _offset(std::nullopt),
1451 _scale(std::nullopt),
1452 _max(std::nullopt),
1453 _min(std::nullopt),
1454 _required(false),
1455 _noData(std::nullopt),
1456 _defaultValue(std::nullopt) {}
1457
1463 const ClassProperty& classProperty,
1464 const PropertyTableProperty& property)
1465 : PropertyView(classProperty) {
1466 if (_status != PropertyViewStatus::Valid) {
1467 return;
1468 }
1469
1470 // If the property has its own values, override the class-provided values.
1471 getNumericPropertyValues(property);
1472 }
1473
1479 const ClassProperty& classProperty,
1480 const PropertyTextureProperty& property)
1481 : PropertyView(classProperty) {
1482 if (_status != PropertyViewStatus::Valid) {
1483 return;
1484 }
1485
1486 // If the property has its own values, override the class-provided values.
1487 getNumericPropertyValues(property);
1488 }
1489
1490public:
1494 PropertyViewStatusType status() const noexcept { return _status; }
1495
1499 const std::optional<std::string>& name() const noexcept { return _name; }
1500
1504 const std::optional<std::string>& semantic() const noexcept {
1505 return _semantic;
1506 }
1507
1511 const std::optional<std::string>& description() const noexcept {
1512 return _description;
1513 }
1514
1518 int64_t arrayCount() const noexcept { return _count; }
1519
1523 bool normalized() const noexcept { return false; }
1524
1528 std::optional<PropertyArrayView<ElementType>> offset() const noexcept {
1529 if (!_offset) {
1530 return std::nullopt;
1531 }
1532
1534 std::span<const std::byte>(_offset->data(), _offset->size()));
1535 }
1536
1540 std::optional<PropertyArrayView<ElementType>> scale() const noexcept {
1541 if (!_scale) {
1542 return std::nullopt;
1543 }
1544
1546 std::span<const std::byte>(_scale->data(), _scale->size()));
1547 }
1548
1552 std::optional<PropertyArrayView<ElementType>> max() const noexcept {
1553 if (!_max) {
1554 return std::nullopt;
1555 }
1556
1558 std::span<const std::byte>(_max->data(), _max->size()));
1559 }
1560
1564 std::optional<PropertyArrayView<ElementType>> min() const noexcept {
1565 if (!_min) {
1566 return std::nullopt;
1567 }
1568
1570 std::span<const std::byte>(_min->data(), _min->size()));
1571 }
1572
1576 bool required() const noexcept { return _required; }
1577
1581 std::optional<PropertyArrayView<ElementType>> noData() const noexcept {
1582 if (!_noData) {
1583 return std::nullopt;
1584 }
1585
1587 std::span<const std::byte>(_noData->data(), _noData->size()));
1588 }
1589
1593 std::optional<PropertyArrayView<ElementType>> defaultValue() const noexcept {
1594 if (!_defaultValue) {
1595 return std::nullopt;
1596 }
1597
1598 return PropertyArrayView<ElementType>(std::span<const std::byte>(
1599 _defaultValue->data(),
1600 _defaultValue->size()));
1601 }
1602
1603protected:
1606
1607private:
1608 std::optional<std::string> _name;
1609 std::optional<std::string> _semantic;
1610 std::optional<std::string> _description;
1611
1612 int64_t _count;
1613
1614 std::optional<std::vector<std::byte>> _offset;
1615 std::optional<std::vector<std::byte>> _scale;
1616 std::optional<std::vector<std::byte>> _max;
1617 std::optional<std::vector<std::byte>> _min;
1618
1619 bool _required;
1620 std::optional<std::vector<std::byte>> _noData;
1621 std::optional<std::vector<std::byte>> _defaultValue;
1622
1623 using PropertyDefinitionType = std::
1624 variant<ClassProperty, PropertyTableProperty, PropertyTextureProperty>;
1625 void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
1626 std::visit(
1627 [this](auto property) {
1628 if (property.offset) {
1629 // Only floating point types can specify an offset.
1631 case PropertyComponentType::Float32:
1632 case PropertyComponentType::Float64:
1633 if (this->_count > 0) {
1634 this->_offset = getArrayValue(*property.offset);
1635 }
1636 if (this->_offset &&
1637 getCount<ElementType>(this->_offset) == this->_count) {
1638 break;
1639 }
1640 // If it does not break here, something went wrong.
1641 [[fallthrough]];
1642 default:
1643 this->_status = PropertyViewStatus::ErrorInvalidOffset;
1644 return;
1645 }
1646 }
1647
1648 if (property.scale) {
1649 // Only floating point types can specify a scale.
1651 case PropertyComponentType::Float32:
1652 case PropertyComponentType::Float64:
1653 if (_count > 0) {
1654 this->_scale = getArrayValue(*property.scale);
1655 }
1656 if (this->_scale &&
1657 getCount<ElementType>(this->_scale) == this->_count) {
1658 break;
1659 }
1660 // If it does not break here, something went wrong.
1661 [[fallthrough]];
1662 default:
1663 this->_status = PropertyViewStatus::ErrorInvalidScale;
1664 return;
1665 }
1666 }
1667
1668 if (property.max) {
1669 if (this->_count > 0) {
1670 this->_max = getArrayValue(*property.max);
1671 }
1672 if (!this->_max ||
1673 getCount<ElementType>(this->_max) != this->_count) {
1674 // The value was specified but something went wrong.
1675 this->_status = PropertyViewStatus::ErrorInvalidMax;
1676 return;
1677 }
1678 }
1679
1680 if (property.min) {
1681 if (this->_count > 0) {
1682 this->_min = getArrayValue(*property.min);
1683 }
1684 if (!this->_min ||
1685 getCount<ElementType>(this->_min) != this->_count) {
1686 // The value was specified but something went wrong.
1687 this->_status = PropertyViewStatus::ErrorInvalidMin;
1688 return;
1689 }
1690 }
1691 },
1692 inProperty);
1693 }
1694
1695 static std::optional<std::vector<std::byte>>
1696 getArrayValue(const CesiumUtility::JsonValue& jsonValue) {
1697 if (!jsonValue.isArray()) {
1698 return std::nullopt;
1699 }
1700
1701 const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
1702 std::vector<ElementType> values;
1703 values.reserve(array.size());
1704
1705 if constexpr (IsMetadataScalar<ElementType>::value) {
1706 for (size_t i = 0; i < array.size(); i++) {
1707 std::optional<ElementType> element = getScalar<ElementType>(array[i]);
1708 if (!element) {
1709 return std::nullopt;
1710 }
1711
1712 values.push_back(*element);
1713 }
1714 }
1715 if constexpr (IsMetadataVecN<ElementType>::value) {
1716 for (size_t i = 0; i < array.size(); i++) {
1717 std::optional<ElementType> element = getVecN<ElementType>(array[i]);
1718 if (!element) {
1719 return std::nullopt;
1720 }
1721
1722 values.push_back(*element);
1723 }
1724 }
1725
1726 if constexpr (IsMetadataMatN<ElementType>::value) {
1727 for (size_t i = 0; i < array.size(); i++) {
1728 std::optional<ElementType> element = getMatN<ElementType>(array[i]);
1729 if (!element) {
1730 return std::nullopt;
1731 }
1732
1733 values.push_back(*element);
1734 }
1735 }
1736
1737 std::vector<std::byte> result(values.size() * sizeof(ElementType));
1738 std::memcpy(result.data(), values.data(), result.size());
1739
1740 return result;
1741 }
1742};
1743
1757template <typename ElementType>
1758class PropertyView<PropertyArrayView<ElementType>, true> {
1759private:
1760 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
1761
1762public:
1767 : _status(PropertyViewStatus::ErrorNonexistentProperty),
1768 _name(std::nullopt),
1769 _semantic(std::nullopt),
1770 _description(std::nullopt),
1771 _count(0),
1772 _offset(std::nullopt),
1773 _scale(std::nullopt),
1774 _max(std::nullopt),
1775 _min(std::nullopt),
1776 _required(false),
1777 _noData(std::nullopt),
1778 _defaultValue(std::nullopt) {}
1779
1783 PropertyView(const ClassProperty& classProperty)
1784 : _status(validateArrayPropertyType<PropertyArrayView<ElementType>>(
1785 classProperty)),
1786 _name(classProperty.name),
1787 _semantic(classProperty.semantic),
1788 _description(classProperty.description),
1789 _count(_count = classProperty.count ? *classProperty.count : 0),
1790 _offset(std::nullopt),
1791 _scale(std::nullopt),
1792 _max(std::nullopt),
1793 _min(std::nullopt),
1794 _required(classProperty.required),
1795 _noData(std::nullopt),
1796 _defaultValue(std::nullopt) {
1797 if (_status != PropertyViewStatus::Valid) {
1798 return;
1799 }
1800
1801 if (!classProperty.normalized) {
1802 _status = PropertyViewStatus::ErrorNormalizationMismatch;
1803 return;
1804 }
1805
1806 getNumericPropertyValues(classProperty);
1807 if (_status != PropertyViewStatus::Valid) {
1808 return;
1809 }
1810
1811 if (classProperty.noData) {
1812 if (!_required) {
1813 _noData = getArrayValue<ElementType>(*classProperty.noData);
1814 }
1815
1816 if (!_noData) {
1817 _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1818 return;
1819 }
1820 }
1821
1822 if (classProperty.defaultProperty) {
1823 if (!_required) {
1824 _defaultValue =
1825 getArrayValue<NormalizedType>(*classProperty.defaultProperty);
1826 }
1827
1828 if (!_defaultValue) {
1829 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1830 return;
1831 }
1832 }
1833 }
1834
1835protected:
1842 : _status(status),
1843 _name(std::nullopt),
1844 _semantic(std::nullopt),
1845 _description(std::nullopt),
1846 _count(0),
1847 _offset(std::nullopt),
1848 _scale(std::nullopt),
1849 _max(std::nullopt),
1850 _min(std::nullopt),
1851 _required(false),
1852 _noData(std::nullopt),
1853 _defaultValue(std::nullopt) {}
1854
1860 const ClassProperty& classProperty,
1861 const PropertyTableProperty& property)
1862 : PropertyView(classProperty) {
1863 if (_status != PropertyViewStatus::Valid) {
1864 return;
1865 }
1866
1867 // If the property has its own values, override the class-provided values.
1868 getNumericPropertyValues(property);
1869 }
1870
1876 const ClassProperty& classProperty,
1877 const PropertyTextureProperty& property)
1878 : PropertyView(classProperty) {
1879 if (_status != PropertyViewStatus::Valid) {
1880 return;
1881 }
1882
1883 // If the property has its own values, override the class-provided values.
1884 getNumericPropertyValues(property);
1885 }
1886
1887public:
1891 PropertyViewStatusType status() const noexcept { return _status; }
1892
1896 const std::optional<std::string>& name() const noexcept { return _name; }
1897
1901 const std::optional<std::string>& semantic() const noexcept {
1902 return _semantic;
1903 }
1904
1908 const std::optional<std::string>& description() const noexcept {
1909 return _description;
1910 }
1911
1915 int64_t arrayCount() const noexcept { return _count; }
1916
1920 bool normalized() const noexcept { return true; }
1921
1925 std::optional<PropertyArrayView<NormalizedType>> offset() const noexcept {
1926 if (!_offset) {
1927 return std::nullopt;
1928 }
1929
1931 std::span<const std::byte>(_offset->data(), _offset->size()));
1932 }
1933
1937 std::optional<PropertyArrayView<NormalizedType>> scale() const noexcept {
1938 if (!_scale) {
1939 return std::nullopt;
1940 }
1941
1943 std::span<const std::byte>(_scale->data(), _scale->size()));
1944 }
1945
1949 std::optional<PropertyArrayView<NormalizedType>> max() const noexcept {
1950 if (!_max) {
1951 return std::nullopt;
1952 }
1953
1955 std::span<const std::byte>(_max->data(), _max->size()));
1956 }
1957
1961 std::optional<PropertyArrayView<NormalizedType>> min() const noexcept {
1962 if (!_min) {
1963 return std::nullopt;
1964 }
1965
1967 std::span<const std::byte>(_min->data(), _min->size()));
1968 }
1969
1973 bool required() const noexcept { return _required; }
1974
1978 std::optional<PropertyArrayView<ElementType>> noData() const noexcept {
1979 if (!_noData) {
1980 return std::nullopt;
1981 }
1982
1984 std::span<const std::byte>(_noData->data(), _noData->size()));
1985 }
1986
1990 std::optional<PropertyArrayView<NormalizedType>>
1991 defaultValue() const noexcept {
1992 if (!_defaultValue) {
1993 return std::nullopt;
1994 }
1995
1996 return PropertyArrayView<NormalizedType>(std::span<const std::byte>(
1997 _defaultValue->data(),
1998 _defaultValue->size()));
1999 }
2000
2001protected:
2004
2005private:
2006 std::optional<std::string> _name;
2007 std::optional<std::string> _semantic;
2008 std::optional<std::string> _description;
2009
2010 int64_t _count;
2011
2012 std::optional<std::vector<std::byte>> _offset;
2013 std::optional<std::vector<std::byte>> _scale;
2014 std::optional<std::vector<std::byte>> _max;
2015 std::optional<std::vector<std::byte>> _min;
2016
2017 bool _required;
2018 std::optional<std::vector<std::byte>> _noData;
2019 std::optional<std::vector<std::byte>> _defaultValue;
2020
2021 using PropertyDefinitionType = std::
2022 variant<ClassProperty, PropertyTableProperty, PropertyTextureProperty>;
2023 void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
2024 std::visit(
2025 [this](auto property) {
2026 if (property.offset) {
2027 if (_count > 0) {
2028 _offset = getArrayValue<NormalizedType>(*property.offset);
2029 }
2030 if (!_offset || getCount<NormalizedType>(_offset) != _count) {
2031 // The value was specified but something went wrong.
2032 _status = PropertyViewStatus::ErrorInvalidOffset;
2033 return;
2034 }
2035 }
2036
2037 if (property.scale) {
2038 if (_count > 0) {
2039 _scale = getArrayValue<NormalizedType>(*property.scale);
2040 }
2041 if (!_scale || getCount<NormalizedType>(_scale) != _count) {
2042 // The value was specified but something went wrong.
2043 _status = PropertyViewStatus::ErrorInvalidScale;
2044 return;
2045 }
2046 }
2047
2048 if (property.max) {
2049 if (_count > 0) {
2050 _max = getArrayValue<NormalizedType>(*property.max);
2051 }
2052 if (!_max || getCount<NormalizedType>(_max) != _count) {
2053 // The value was specified but something went wrong.
2054 _status = PropertyViewStatus::ErrorInvalidMax;
2055 return;
2056 }
2057 }
2058
2059 if (property.min) {
2060 if (_count > 0) {
2061 _min = getArrayValue<NormalizedType>(*property.min);
2062 }
2063 if (!_min || getCount<NormalizedType>(_min) != _count) {
2064 // The value was specified but something went wrong.
2065 _status = PropertyViewStatus::ErrorInvalidMin;
2066 return;
2067 }
2068 }
2069 },
2070 inProperty);
2071 }
2072
2073 template <typename T>
2074 static std::optional<std::vector<std::byte>>
2075 getArrayValue(const CesiumUtility::JsonValue& jsonValue) {
2076 if (!jsonValue.isArray()) {
2077 return std::nullopt;
2078 }
2079
2080 const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
2081 std::vector<T> values;
2082 values.reserve(array.size());
2083
2084 if constexpr (IsMetadataScalar<T>::value) {
2085 for (size_t i = 0; i < array.size(); i++) {
2086 std::optional<T> element = getScalar<T>(array[i]);
2087 if (!element) {
2088 return std::nullopt;
2089 }
2090
2091 values.push_back(*element);
2092 }
2093 }
2094
2095 if constexpr (IsMetadataVecN<T>::value) {
2096 for (size_t i = 0; i < array.size(); i++) {
2097 std::optional<T> element = getVecN<T>(array[i]);
2098 if (!element) {
2099 return std::nullopt;
2100 }
2101
2102 values.push_back(*element);
2103 }
2104 }
2105
2106 if constexpr (IsMetadataMatN<T>::value) {
2107 for (size_t i = 0; i < array.size(); i++) {
2108 std::optional<T> element = getMatN<T>(array[i]);
2109 if (!element) {
2110 return std::nullopt;
2111 }
2112
2113 values.push_back(*element);
2114 }
2115 }
2116
2117 std::vector<std::byte> result(values.size() * sizeof(T));
2118 std::memcpy(result.data(), values.data(), result.size());
2119
2120 return result;
2121 }
2122};
2123
2128template <> class PropertyView<PropertyArrayView<bool>> {
2129public:
2134 : _status(PropertyViewStatus::ErrorNonexistentProperty),
2135 _name(std::nullopt),
2136 _semantic(std::nullopt),
2137 _description(std::nullopt),
2138 _count(0),
2139 _required(false),
2140 _defaultValue(),
2141 _size(0) {}
2142
2146 PropertyView(const ClassProperty& classProperty)
2147 : _status(
2148 validateArrayPropertyType<PropertyArrayView<bool>>(classProperty)),
2149 _name(classProperty.name),
2150 _semantic(classProperty.semantic),
2151 _description(classProperty.description),
2152 _count(classProperty.count ? *classProperty.count : 0),
2153 _required(classProperty.required),
2154 _defaultValue(),
2155 _size(0) {
2156 if (_status != PropertyViewStatus::Valid) {
2157 return;
2158 }
2159
2160 if (classProperty.defaultProperty) {
2161 if (!_required) {
2162 _defaultValue =
2163 getBooleanArrayValue(*classProperty.defaultProperty, _size);
2164 }
2165
2166 if (_size == 0 || (_count > 0 && _size != _count)) {
2167 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
2168 return;
2169 }
2170 }
2171 }
2172
2173protected:
2180 : _status(status),
2181 _name(std::nullopt),
2182 _semantic(std::nullopt),
2183 _description(std::nullopt),
2184 _count(0),
2185 _required(false),
2186 _defaultValue(),
2187 _size(0) {}
2188
2194 const ClassProperty& classProperty,
2195 const PropertyTableProperty& /*property*/)
2196 : PropertyView(classProperty) {}
2197
2198public:
2202 PropertyViewStatusType status() const noexcept { return _status; }
2203
2207 const std::optional<std::string>& name() const noexcept { return _name; }
2208
2212 const std::optional<std::string>& semantic() const noexcept {
2213 return _semantic;
2214 }
2215
2219 const std::optional<std::string>& description() const noexcept {
2220 return _description;
2221 }
2222
2226 int64_t arrayCount() const noexcept { return _count; }
2227
2231 bool normalized() const noexcept { return false; }
2232
2236 std::optional<PropertyArrayView<bool>> offset() const noexcept {
2237 return std::nullopt;
2238 }
2239
2243 std::optional<PropertyArrayView<bool>> scale() const noexcept {
2244 return std::nullopt;
2245 }
2246
2250 std::optional<PropertyArrayView<bool>> max() const noexcept {
2251 return std::nullopt;
2252 }
2253
2257 std::optional<PropertyArrayView<bool>> min() const noexcept {
2258 return std::nullopt;
2259 }
2260
2264 bool required() const noexcept { return _required; }
2265
2269 std::optional<PropertyArrayView<bool>> noData() const noexcept {
2270 return std::nullopt;
2271 }
2272
2276 std::optional<PropertyArrayView<bool>> defaultValue() const noexcept {
2277 if (_size > 0) {
2279 std::span<const std::byte>(
2280 _defaultValue.data(),
2281 _defaultValue.size()),
2282 /* bitOffset = */ 0,
2283 _size);
2284 }
2285
2286 return std::nullopt;
2287 }
2288
2289protected:
2292
2293private:
2294 std::optional<std::string> _name;
2295 std::optional<std::string> _semantic;
2296 std::optional<std::string> _description;
2297
2298 int64_t _count;
2299 bool _required;
2300
2301 std::vector<std::byte> _defaultValue;
2302 int64_t _size;
2303
2304 static std::vector<std::byte> getBooleanArrayValue(
2305 const CesiumUtility::JsonValue& jsonValue,
2306 int64_t& size) {
2307 if (!jsonValue.isArray()) {
2308 return std::vector<std::byte>();
2309 }
2310
2311 const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
2312 std::vector<std::byte> values;
2313 values.reserve((array.size() / 8) + 1);
2314
2315 size_t byteIndex = 0;
2316 uint8_t bitIndex = 0;
2317
2318 for (size_t i = 0; i < array.size(); i++, size++) {
2319 if (!array[i].isBool()) {
2320 size = 0;
2321 return values;
2322 }
2323
2324 if (values.size() < byteIndex - 1) {
2325 values.push_back(std::byte(0));
2326 }
2327
2328 std::byte value = std::byte(array[i].getBool() ? 1 : 0);
2329 value = value << bitIndex;
2330
2331 values[byteIndex] |= value;
2332
2333 bitIndex++;
2334 if (bitIndex > 7) {
2335 byteIndex++;
2336 bitIndex = 0;
2337 }
2338 }
2339
2340 return values;
2341 }
2342};
2343
2348template <> class PropertyView<PropertyArrayView<std::string_view>> {
2349public:
2354 : _status(PropertyViewStatus::ErrorNonexistentProperty),
2355 _name(std::nullopt),
2356 _semantic(std::nullopt),
2357 _description(std::nullopt),
2358 _count(0),
2359 _required(false),
2360 _noData(),
2361 _defaultValue() {}
2362
2366 PropertyView(const ClassProperty& classProperty)
2367 : _status(validateArrayPropertyType<PropertyArrayView<std::string_view>>(
2368 classProperty)),
2369 _name(classProperty.name),
2370 _semantic(classProperty.semantic),
2371 _description(classProperty.description),
2372 _count(classProperty.count ? *classProperty.count : 0),
2373 _required(classProperty.required),
2374 _noData(),
2375 _defaultValue() {
2376 if (_status != PropertyViewStatus::Valid) {
2377 return;
2378 }
2379
2380 if (classProperty.noData) {
2381 if (!_required) {
2382 _noData = getStringArrayValue(*classProperty.noData);
2383 }
2384
2385 if (_noData.size == 0 || (_count > 0 && _noData.size != _count)) {
2386 _status = PropertyViewStatus::ErrorInvalidNoDataValue;
2387 return;
2388 }
2389 }
2390
2391 if (classProperty.defaultProperty) {
2392 if (!_required) {
2393 _defaultValue = getStringArrayValue(*classProperty.defaultProperty);
2394 }
2395
2396 if (_defaultValue.size == 0 ||
2397 (_count > 0 && _defaultValue.size != _count)) {
2398 // The value was specified but something went wrong.
2399 _status = PropertyViewStatus::ErrorInvalidDefaultValue;
2400 return;
2401 }
2402 }
2403 }
2404
2405protected:
2412 : _status(status),
2413 _name(std::nullopt),
2414 _semantic(std::nullopt),
2415 _description(std::nullopt),
2416 _count(0),
2417 _required(false),
2418 _noData(),
2419 _defaultValue() {}
2420
2426 const ClassProperty& classProperty,
2427 const PropertyTableProperty& /*property*/)
2428 : PropertyView(classProperty) {}
2429
2430public:
2434 PropertyViewStatusType status() const noexcept { return _status; }
2435
2439 const std::optional<std::string>& name() const noexcept { return _name; }
2440
2444 const std::optional<std::string>& semantic() const noexcept {
2445 return _semantic;
2446 }
2447
2451 const std::optional<std::string>& description() const noexcept {
2452 return _description;
2453 }
2454
2458 int64_t arrayCount() const noexcept { return _count; }
2459
2463 bool normalized() const noexcept { return false; }
2464
2468 std::optional<PropertyArrayView<std::string_view>> offset() const noexcept {
2469 return std::nullopt;
2470 }
2471
2475 std::optional<PropertyArrayView<std::string_view>> scale() const noexcept {
2476 return std::nullopt;
2477 }
2478
2482 std::optional<PropertyArrayView<std::string_view>> max() const noexcept {
2483 return std::nullopt;
2484 }
2485
2489 std::optional<PropertyArrayView<std::string_view>> min() const noexcept {
2490 return std::nullopt;
2491 }
2492
2496 bool required() const noexcept { return _required; }
2497
2501 std::optional<PropertyArrayView<std::string_view>> noData() const noexcept {
2502 if (_noData.size > 0) {
2504 std::span<const std::byte>(_noData.data.data(), _noData.data.size()),
2505 std::span<const std::byte>(
2506 _noData.offsets.data(),
2507 _noData.offsets.size()),
2508 _noData.offsetType,
2509 _noData.size);
2510 }
2511
2512 return std::nullopt;
2513 }
2514
2518 std::optional<PropertyArrayView<std::string_view>>
2519 defaultValue() const noexcept {
2520 if (_defaultValue.size > 0) {
2522 std::span<const std::byte>(
2523 _defaultValue.data.data(),
2524 _defaultValue.data.size()),
2525 std::span<const std::byte>(
2526 _defaultValue.offsets.data(),
2527 _defaultValue.offsets.size()),
2528 _defaultValue.offsetType,
2529 _defaultValue.size);
2530 }
2531
2532 return std::nullopt;
2533 }
2534
2535protected:
2538
2539private:
2540 std::optional<std::string> _name;
2541 std::optional<std::string> _semantic;
2542 std::optional<std::string> _description;
2543
2544 int64_t _count;
2545 bool _required;
2546
2547 struct StringArrayValue {
2548 std::vector<std::byte> data;
2549 std::vector<std::byte> offsets;
2550 PropertyComponentType offsetType = PropertyComponentType::None;
2551 int64_t size = 0;
2552 };
2553
2554 StringArrayValue _noData;
2555 StringArrayValue _defaultValue;
2556
2557 static StringArrayValue
2558 getStringArrayValue(const CesiumUtility::JsonValue& jsonValue) {
2559 StringArrayValue result;
2560 if (!jsonValue.isArray()) {
2561 return result;
2562 }
2563
2564 std::vector<std::string> strings;
2565 std::vector<uint64_t> stringOffsets;
2566
2567 const auto array = jsonValue.getArray();
2568 strings.reserve(array.size());
2569 stringOffsets.reserve(array.size() + 1);
2570 stringOffsets.push_back(static_cast<uint64_t>(0));
2571
2572 for (size_t i = 0; i < array.size(); i++) {
2573 if (!array[i].isString()) {
2574 // The entire array is invalidated; return.
2575 return result;
2576 }
2577
2578 const std::string& string = array[i].getString();
2579 strings.push_back(string);
2580 stringOffsets.push_back(stringOffsets[i] + string.size());
2581 }
2582
2583 uint64_t totalLength = stringOffsets.back();
2584 result.data.resize(totalLength);
2585 for (size_t i = 0; i < strings.size(); ++i) {
2586 std::memcpy(
2587 result.data.data() + stringOffsets[i],
2588 strings[i].data(),
2589 strings[i].size());
2590 };
2591
2592 if (totalLength <= std::numeric_limits<uint8_t>::max()) {
2593 result.offsets = narrowOffsetsBuffer<uint8_t>(stringOffsets);
2594 result.offsetType = PropertyComponentType::Uint8;
2595 } else if (totalLength <= std::numeric_limits<uint16_t>::max()) {
2596 result.offsets = narrowOffsetsBuffer<uint16_t>(stringOffsets);
2597 result.offsetType = PropertyComponentType::Uint16;
2598 } else if (totalLength <= std::numeric_limits<uint32_t>::max()) {
2599 result.offsets = narrowOffsetsBuffer<uint32_t>(stringOffsets);
2600 result.offsetType = PropertyComponentType::Uint32;
2601 } else {
2602 result.offsets.resize(stringOffsets.size() * sizeof(uint64_t));
2603 std::memcpy(
2604 result.offsets.data(),
2605 stringOffsets.data(),
2606 result.offsets.size());
2607 result.offsetType = PropertyComponentType::Uint64;
2608 }
2609
2610 result.size = static_cast<int64_t>(strings.size());
2611
2612 return result;
2613 }
2614
2615 template <typename T>
2616 static std::vector<std::byte>
2617 narrowOffsetsBuffer(std::vector<uint64_t> offsets) {
2618 std::vector<std::byte> result(offsets.size() * sizeof(T));
2619 size_t bufferOffset = 0;
2620 for (size_t i = 0; i < offsets.size(); i++, bufferOffset += sizeof(T)) {
2621 T offset = static_cast<T>(offsets[i]);
2622 std::memcpy(result.data() + bufferOffset, &offset, sizeof(T));
2623 }
2624
2625 return result;
2626 }
2627};
2628
2629} // namespace CesiumGltf
A view on an array element of a PropertyTableProperty or PropertyTextureProperty.
Indicates the status of a property view.
static const PropertyViewStatusType ErrorTypeMismatch
This property view's type does not match what is specified in ClassProperty::type.
static const PropertyViewStatusType ErrorInvalidDefaultValue
The property provided an invalid default value.
static const PropertyViewStatusType ErrorInvalidMin
The property provided an invalid minimum value.
static const PropertyViewStatusType ErrorInvalidMax
The property provided an invalid maximum value.
static const PropertyViewStatusType ErrorInvalidOffset
The property provided an invalid offset value.
static const PropertyViewStatusType Valid
This property view is valid and ready to use.
static const PropertyViewStatusType ErrorNonexistentProperty
This property view is trying to view a property that does not exist.
static const PropertyViewStatusType ErrorInvalidNormalization
This property says it is normalized, but it does not have an integer component type.
static const PropertyViewStatusType ErrorArrayTypeMismatch
This property view differs from what is specified in ClassProperty::array.
static const PropertyViewStatusType ErrorInvalidNoDataValue
The property provided an invalid "no data" value.
static const PropertyViewStatusType ErrorNormalizationMismatch
This property view's normalization differs from what is specified in ClassProperty::normalized.
static const PropertyViewStatusType EmptyPropertyWithDefault
This property view does not contain any data, but specifies a default value. This happens when a clas...
static const PropertyViewStatusType ErrorInvalidScale
The property provided an invalid scale value.
static const PropertyViewStatusType ErrorComponentTypeMismatch
This property view's component type does not match what is specified in ClassProperty::componentType.
std::optional< ElementType > offset() const noexcept
Gets the offset to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the...
std::optional< ElementType > scale() const noexcept
Gets the scale to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the ...
bool required() const noexcept
Whether the property must be present in every entity conforming to the class. If not required,...
std::optional< ElementType > defaultValue() const noexcept
Gets the default value to use when encountering a "no data" value or an omitted property....
const std::optional< std::string > & name() const noexcept
Gets the name of the property being viewed. Returns std::nullopt if no name was specified.
PropertyViewStatusType _status
Indicates the status of a property view.
const std::optional< std::string > & semantic() const noexcept
Gets the semantic of the property being viewed. The semantic is an identifier that describes how this...
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
bool normalized() const noexcept
Whether this property has a normalized integer type.
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
int64_t arrayCount() const noexcept
Get the element count of the fixed-length arrays in this property. Only applicable when the property ...
PropertyViewStatusType status() const noexcept
Gets the status of this property view, indicating whether an error occurred.
std::optional< ElementType > noData() const noexcept
Gets the "no data" value, i.e., the value representing missing data in the property wherever it appea...
std::optional< ElementType > min() const noexcept
Gets the minimum allowed value for the property. Only applicable to SCALAR, VECN, and MATN types....
PropertyView(const ClassProperty &classProperty, const PropertyAttributeProperty &property)
Constructs a property instance from a property attribute property and its class definition.
std::optional< ElementType > max() const noexcept
Gets the maximum allowed value for the property. Only applicable to SCALAR, VECN, and MATN types....
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
const std::optional< std::string > & description() const noexcept
Gets the description of the property being viewed. Returns std::nullopt if no description was specifi...
PropertyView()
Constructs an empty property instance.
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
std::optional< ElementType > noData() const noexcept
Constructs an empty property instance. false>noData
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
std::optional< NormalizedType > max() const noexcept
Constructs an empty property instance. false>max
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
PropertyView(const ClassProperty &classProperty, const PropertyAttributeProperty &property)
Constructs a property instance from a property attribute property and its class definition.
PropertyViewStatusType _status
Indicates the status of a property view.
std::optional< NormalizedType > scale() const noexcept
Constructs an empty property instance. false>scale
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
PropertyView()
Constructs an empty property instance.
std::optional< NormalizedType > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
bool required() const noexcept
Constructs an empty property instance. false>required
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
std::optional< NormalizedType > offset() const noexcept
Constructs an empty property instance. false>offset
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
std::optional< NormalizedType > min() const noexcept
Constructs an empty property instance. false>min
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
std::optional< PropertyArrayView< ElementType > > noData() const noexcept
Constructs an empty property instance. false>noData
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
std::optional< PropertyArrayView< ElementType > > offset() const noexcept
Constructs an empty property instance. false>offset
std::optional< PropertyArrayView< ElementType > > max() const noexcept
Constructs an empty property instance. false>max
std::optional< PropertyArrayView< ElementType > > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
std::optional< PropertyArrayView< ElementType > > min() const noexcept
Constructs an empty property instance. false>min
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
bool required() const noexcept
Constructs an empty property instance. false>required
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
std::optional< PropertyArrayView< ElementType > > scale() const noexcept
Constructs an empty property instance. false>scale
PropertyViewStatusType _status
Indicates the status of a property view.
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
std::optional< PropertyArrayView< NormalizedType > > max() const noexcept
Constructs an empty property instance. false>max
PropertyViewStatusType _status
Indicates the status of a property view.
std::optional< PropertyArrayView< NormalizedType > > scale() const noexcept
Constructs an empty property instance. false>scale
std::optional< PropertyArrayView< ElementType > > noData() const noexcept
Constructs an empty property instance. false>noData
std::optional< PropertyArrayView< NormalizedType > > min() const noexcept
Constructs an empty property instance. false>min
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
std::optional< PropertyArrayView< NormalizedType > > offset() const noexcept
Constructs an empty property instance. false>offset
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
std::optional< PropertyArrayView< NormalizedType > > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
bool required() const noexcept
Constructs an empty property instance. false>required
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
std::optional< PropertyArrayView< bool > > min() const noexcept
Constructs an empty property instance. false>min
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
std::optional< PropertyArrayView< bool > > max() const noexcept
Constructs an empty property instance. false>max
std::optional< PropertyArrayView< bool > > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
PropertyView()
Constructs an empty property instance.
PropertyViewStatusType _status
Indicates the status of a property view.
bool required() const noexcept
Constructs an empty property instance. false>required
std::optional< PropertyArrayView< bool > > offset() const noexcept
Constructs an empty property instance. false>offset
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< PropertyArrayView< bool > > scale() const noexcept
Constructs an empty property instance. false>scale
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
std::optional< PropertyArrayView< bool > > noData() const noexcept
Constructs an empty property instance. false>noData
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
std::optional< PropertyArrayView< std::string_view > > max() const noexcept
Constructs an empty property instance. false>max
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
std::optional< PropertyArrayView< std::string_view > > offset() const noexcept
Constructs an empty property instance. false>offset
PropertyViewStatusType _status
Indicates the status of a property view.
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
std::optional< PropertyArrayView< std::string_view > > min() const noexcept
Constructs an empty property instance. false>min
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
std::optional< PropertyArrayView< std::string_view > > noData() const noexcept
Constructs an empty property instance. false>noData
bool required() const noexcept
Constructs an empty property instance. false>required
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< PropertyArrayView< std::string_view > > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
std::optional< PropertyArrayView< std::string_view > > scale() const noexcept
Constructs an empty property instance. false>scale
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
std::optional< bool > min() const noexcept
Constructs an empty property instance. false>min
std::optional< bool > noData() const noexcept
Constructs an empty property instance. false>noData
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
bool required() const noexcept
Constructs an empty property instance. false>required
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
std::optional< bool > scale() const noexcept
Constructs an empty property instance. false>scale
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
PropertyViewStatusType _status
Indicates the status of a property view.
PropertyView()
Constructs an empty property instance.
std::optional< bool > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
std::optional< bool > offset() const noexcept
Constructs an empty property instance. false>offset
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< bool > max() const noexcept
Constructs an empty property instance. false>max
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
bool required() const noexcept
Constructs an empty property instance. false>required
const std::optional< std::string > & name() const noexcept
Constructs an empty property instance. false>name
PropertyView()
Constructs an empty property instance.
std::optional< std::string_view > min() const noexcept
Constructs an empty property instance. false>min
std::optional< std::string_view > offset() const noexcept
Constructs an empty property instance. false>offset
PropertyViewStatusType _status
Indicates the status of a property view.
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
std::optional< std::string_view > scale() const noexcept
Constructs an empty property instance. false>scale
const std::optional< std::string > & description() const noexcept
Constructs an empty property instance. false>description
std::optional< std::string_view > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
int64_t arrayCount() const noexcept
Constructs an empty property instance. false>arrayCount
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< std::string_view > noData() const noexcept
Constructs an empty property instance. false>noData
std::optional< std::string_view > max() const noexcept
Constructs an empty property instance. false>max
const std::optional< std::string > & semantic() const noexcept
Constructs an empty property instance. false>semantic
bool normalized() const noexcept
Constructs an empty property instance. false>normalized
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
Represents a metadata property in EXT_structural_metadata.
A generic implementation of a value in a JSON structure.
Definition JsonValue.h:75
bool getBool() const
Gets the bool from the value.
Definition JsonValue.h:471
const JsonValue::String & getString() const
Gets the string from the value.
Definition JsonValue.h:440
std::vector< JsonValue > Array
The type to represent an Array JSON value.
Definition JsonValue.h:100
bool isBool() const noexcept
Returns whether this value is a Bool value.
Definition JsonValue.h:592
bool isArray() const noexcept
Returns whether this value is an Array value.
Definition JsonValue.h:613
bool isString() const noexcept
Returns whether this value is a String value.
Definition JsonValue.h:599
std::optional< To > getSafeNumber() const
Gets the numerical quantity from the value casted to the To type. This function should be used over g...
Definition JsonValue.h:373
const JsonValue::Array & getArray() const
Gets the array from the value.
Definition JsonValue.h:450
Classes for working with glTF models.
PropertyComponentType
The possible types of a property component.
PropertyComponentType convertStringToPropertyComponentType(const std::string &str)
Converts a string into a PropertyComponentType.
int64_t getCount(std::optional< std::vector< std::byte > > &buffer)
Obtains the number of values of type ElementType that could fit in the buffer.
PropertyViewStatusType validatePropertyType(const ClassProperty &classProperty)
Validates a ClassProperty, checking for any type mismatches.
PropertyType convertStringToPropertyType(const std::string &str)
Converts a string into a PropertyType.
int32_t PropertyViewStatusType
The type used for fields of PropertyViewStatus.
PropertyViewStatusType validateArrayPropertyType(const ClassProperty &classProperty)
Validates a ClassProperty representing an array, checking for any type mismatches.
STL namespace.
bool normalized
Specifies whether integer values are normalized. Only applicable to SCALAR, VECN, and MATN types with...
std::optional< std::string > componentType
The datatype of the element's components. Only applicable to SCALAR, VECN, and MATN types.
bool array
Whether the property is an array. When count is defined the property is a fixed-length array....
std::optional< CesiumUtility::JsonValue > noData
A noData value represents missing data — also known as a sentinel value — wherever it appears....
std::string type
The element type.
std::optional< CesiumUtility::JsonValue > defaultProperty
A default value to use when encountering a noData value or an omitted property. The value is given in...
Check if a C++ type can be represented as a matN type.
Check if a C++ type can be represented as a scalar property type.
Check if a C++ type can be represented as a vecN type.
void type
The component type of this metadata array.
An attribute containing property values.
An array of binary property values.
A texture containing property values.
Convert an integer numeric type to the corresponding representation as a double type....
Convert a C++ type to PropertyType and PropertyComponentType.