cesium-native  0.41.0
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 
12 namespace CesiumGltf {
13 
14 typedef int32_t PropertyViewStatusType;
15 
28 public:
32  static const PropertyViewStatusType Valid = 0;
33 
41  static const PropertyViewStatusType EmptyPropertyWithDefault = 1;
42 
47  static const PropertyViewStatusType ErrorNonexistentProperty = 2;
48 
53  static const PropertyViewStatusType ErrorTypeMismatch = 3;
54 
59  static const PropertyViewStatusType ErrorComponentTypeMismatch = 4;
60 
65  static const PropertyViewStatusType ErrorArrayTypeMismatch = 5;
66 
71  static const PropertyViewStatusType ErrorInvalidNormalization = 6;
72 
77  static const PropertyViewStatusType ErrorNormalizationMismatch = 7;
78 
82  static const PropertyViewStatusType ErrorInvalidOffset = 8;
83 
87  static const PropertyViewStatusType ErrorInvalidScale = 9;
88 
92  static const PropertyViewStatusType ErrorInvalidMax = 10;
93 
97  static const PropertyViewStatusType ErrorInvalidMin = 11;
98 
102  static const PropertyViewStatusType ErrorInvalidNoDataValue = 12;
103 
107  static const PropertyViewStatusType ErrorInvalidDefaultValue = 13;
108 };
109 
110 template <typename T>
111 PropertyViewStatusType
112 validatePropertyType(const ClassProperty& classProperty) {
114  convertStringToPropertyType(classProperty.type)) {
116  }
117 
118  PropertyComponentType expectedComponentType =
119  TypeToPropertyType<T>::component;
120 
121  if (!classProperty.componentType &&
122  expectedComponentType != PropertyComponentType::None) {
124  }
125 
126  if (classProperty.componentType &&
127  expectedComponentType !=
128  convertStringToPropertyComponentType(*classProperty.componentType)) {
130  }
131 
132  if (classProperty.array) {
134  }
135 
137 }
138 
139 template <typename T>
140 PropertyViewStatusType
141 validateArrayPropertyType(const ClassProperty& classProperty) {
142  using ElementType = typename MetadataArrayType<T>::type;
143  if (TypeToPropertyType<ElementType>::value !=
144  convertStringToPropertyType(classProperty.type)) {
146  }
147 
148  PropertyComponentType expectedComponentType =
149  TypeToPropertyType<ElementType>::component;
150 
151  if (!classProperty.componentType &&
152  expectedComponentType != PropertyComponentType::None) {
154  }
155 
156  if (classProperty.componentType &&
157  expectedComponentType !=
158  convertStringToPropertyComponentType(*classProperty.componentType)) {
160  }
161 
162  if (!classProperty.array) {
164  }
165 
167 }
168 
169 template <typename T>
170 static std::optional<T> getScalar(const CesiumUtility::JsonValue& jsonValue) {
171  try {
172  return jsonValue.getSafeNumber<T>();
173  } catch (const CesiumUtility::JsonValueNotRealValue& /*error*/) {
174  return std::nullopt;
175  } catch (const gsl::narrowing_error& /*error*/) {
176  return std::nullopt;
177  }
178 }
179 
180 template <typename VecType>
181 static std::optional<VecType>
182 getVecN(const CesiumUtility::JsonValue& jsonValue) {
183  if (!jsonValue.isArray()) {
184  return std::nullopt;
185  }
186 
187  const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
188  constexpr glm::length_t N = VecType::length();
189  if (array.size() != N) {
190  return std::nullopt;
191  }
192 
193  using T = typename VecType::value_type;
194 
195  VecType result;
196  for (glm::length_t i = 0; i < N; i++) {
197  std::optional<T> value = getScalar<T>(array[i]);
198  if (!value) {
199  return std::nullopt;
200  }
201 
202  result[i] = *value;
203  }
204 
205  return result;
206 }
207 
208 template <typename MatType>
209 static std::optional<MatType>
210 getMatN(const CesiumUtility::JsonValue& jsonValue) {
211  if (!jsonValue.isArray()) {
212  return std::nullopt;
213  }
214 
215  const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
216  constexpr glm::length_t N = MatType::length();
217  if (array.size() != N * N) {
218  return std::nullopt;
219  }
220 
221  using T = typename MatType::value_type;
222 
223  MatType result;
224  for (glm::length_t i = 0; i < N; i++) {
225  // Try to parse each value in the column.
226  for (glm::length_t j = 0; j < N; j++) {
227  std::optional<T> value = getScalar<T>(array[i * N + j]);
228  if (!value) {
229  return std::nullopt;
230  }
231 
232  result[i][j] = *value;
233  }
234  }
235 
236  return result;
237 }
238 
239 template <typename ElementType>
240 int64_t getCount(std::optional<std::vector<std::byte>>& buffer) {
241  if (!buffer) {
242  return 0;
243  }
244 
245  return static_cast<int64_t>(buffer->size() / sizeof(ElementType));
246 }
247 
251 template <typename ElementType, bool Normalized = false> class PropertyView;
252 
265 template <typename ElementType> class PropertyView<ElementType, false> {
266 public:
271  : _status(PropertyViewStatus::ErrorNonexistentProperty),
272  _name(std::nullopt),
273  _semantic(std::nullopt),
274  _description(std::nullopt),
275  _offset(std::nullopt),
276  _scale(std::nullopt),
277  _max(std::nullopt),
278  _min(std::nullopt),
279  _required(false),
280  _noData(std::nullopt),
281  _defaultValue(std::nullopt) {}
282 
286  PropertyView(const ClassProperty& classProperty)
287  : _status(validatePropertyType<ElementType>(classProperty)),
288  _name(classProperty.name),
289  _semantic(classProperty.semantic),
290  _description(classProperty.description),
291  _offset(std::nullopt),
292  _scale(std::nullopt),
293  _max(std::nullopt),
294  _min(std::nullopt),
295  _required(classProperty.required),
296  _noData(std::nullopt),
297  _defaultValue(std::nullopt) {
298  if (_status != PropertyViewStatus::Valid) {
299  return;
300  }
301 
302  if (classProperty.normalized) {
304  return;
305  }
306 
307  getNumericPropertyValues(classProperty);
308  if (_status != PropertyViewStatus::Valid) {
309  return;
310  }
311 
312  if (classProperty.noData) {
313  if (!_required) {
314  // "noData" can only be defined if the property is not required.
315  _noData = getValue(*classProperty.noData);
316  }
317 
318  if (!_noData) {
319  // The value was specified but something went wrong.
321  return;
322  }
323  }
324 
325  if (classProperty.defaultProperty) {
326  if (!_required) {
327  // "default" can only be defined if the property is not required.
328  _defaultValue = getValue(*classProperty.defaultProperty);
329  }
330 
331  if (!_defaultValue) {
332  // The value was specified but something went wrong.
334  return;
335  }
336  }
337  }
338 
339 protected:
346  PropertyView(PropertyViewStatusType status)
347  : _status(status),
348  _name(std::nullopt),
349  _semantic(std::nullopt),
350  _description(std::nullopt),
351  _offset(std::nullopt),
352  _scale(std::nullopt),
353  _max(std::nullopt),
354  _min(std::nullopt),
355  _required(false),
356  _noData(std::nullopt),
357  _defaultValue(std::nullopt) {}
358 
364  const ClassProperty& classProperty,
365  const PropertyTableProperty& property)
366  : PropertyView(classProperty) {
367  if (_status != PropertyViewStatus::Valid) {
368  return;
369  }
370 
371  // If the property has its own values, override the class-provided values.
372  getNumericPropertyValues(property);
373  }
374 
380  const ClassProperty& classProperty,
381  const PropertyTextureProperty& property)
382  : PropertyView(classProperty) {
383  if (_status != PropertyViewStatus::Valid) {
384  return;
385  }
386 
387  // If the property has its own values, override the class-provided values.
388  getNumericPropertyValues(property);
389  }
390 
396  const ClassProperty& classProperty,
397  const PropertyAttributeProperty& property)
398  : PropertyView(classProperty) {
399  if (_status != PropertyViewStatus::Valid) {
400  return;
401  }
402 
403  // If the property has its own values, override the class-provided values.
404  getNumericPropertyValues(property);
405  }
406 
407 public:
414  PropertyViewStatusType status() const noexcept { return _status; }
415 
420  const std::optional<std::string>& name() const noexcept { return _name; }
421 
428  const std::optional<std::string>& semantic() const noexcept {
429  return _semantic;
430  }
431 
436  const std::optional<std::string>& description() const noexcept {
437  return _description;
438  }
439 
446  int64_t arrayCount() const noexcept { return 0; }
447 
451  bool normalized() const noexcept { return false; }
452 
460  std::optional<ElementType> offset() const noexcept { return _offset; }
461 
469  std::optional<ElementType> scale() const noexcept { return _scale; }
470 
480  std::optional<ElementType> max() const noexcept { return _max; }
481 
491  std::optional<ElementType> min() const noexcept { return _min; }
492 
498  bool required() const noexcept { return _required; }
499 
509  std::optional<ElementType> noData() const noexcept { return _noData; }
510 
519  std::optional<ElementType> defaultValue() const noexcept {
520  return _defaultValue;
521  }
522 
523 protected:
524  PropertyViewStatusType _status;
525 
526 private:
527  std::optional<std::string> _name;
528  std::optional<std::string> _semantic;
529  std::optional<std::string> _description;
530 
531  std::optional<ElementType> _offset;
532  std::optional<ElementType> _scale;
533  std::optional<ElementType> _max;
534  std::optional<ElementType> _min;
535 
536  bool _required;
537  std::optional<ElementType> _noData;
538  std::optional<ElementType> _defaultValue;
539 
550  static std::optional<ElementType>
551  getValue(const CesiumUtility::JsonValue& jsonValue) {
552  if constexpr (IsMetadataScalar<ElementType>::value) {
553  return getScalar<ElementType>(jsonValue);
554  }
555 
556  if constexpr (IsMetadataVecN<ElementType>::value) {
557  return getVecN<ElementType>(jsonValue);
558  }
559 
560  if constexpr (IsMetadataMatN<ElementType>::value) {
561  return getMatN<ElementType>(jsonValue);
562  }
563  }
564 
565  using PropertyDefinitionType = std::variant<
566  ClassProperty,
567  PropertyTableProperty,
568  PropertyTextureProperty,
569  PropertyAttributeProperty>;
570 
575  void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
576  std::visit(
577  [this](auto property) {
578  if (property.offset) {
579  // Only floating point types can specify an offset.
580  switch (TypeToPropertyType<ElementType>::component) {
581  case PropertyComponentType::Float32:
582  case PropertyComponentType::Float64:
583  this->_offset = getValue(*property.offset);
584  if (this->_offset) {
585  break;
586  }
587  // If it does not break here, something went wrong.
588  [[fallthrough]];
589  default:
590  this->_status = PropertyViewStatus::ErrorInvalidOffset;
591  return;
592  }
593  }
594 
595  if (property.scale) {
596  // Only floating point types can specify a scale.
597  switch (TypeToPropertyType<ElementType>::component) {
598  case PropertyComponentType::Float32:
599  case PropertyComponentType::Float64:
600  this->_scale = getValue(*property.scale);
601  if (this->_scale) {
602  break;
603  }
604  // If it does not break here, something went wrong.
605  [[fallthrough]];
606  default:
607  this->_status = PropertyViewStatus::ErrorInvalidScale;
608  return;
609  }
610  }
611 
612  if (property.max) {
613  this->_max = getValue(*property.max);
614  if (!this->_max) {
615  // The value was specified but something went wrong.
616  this->_status = PropertyViewStatus::ErrorInvalidMax;
617  return;
618  }
619  }
620 
621  if (property.min) {
622  this->_min = getValue(*property.min);
623  if (!this->_min) {
624  // The value was specified but something went wrong.
625  this->_status = PropertyViewStatus::ErrorInvalidMin;
626  return;
627  }
628  }
629  },
630  inProperty);
631  }
632 };
633 
647 template <typename ElementType> class PropertyView<ElementType, true> {
648 private:
649  using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
650 
651 public:
656  : _status(PropertyViewStatus::ErrorNonexistentProperty),
657  _name(std::nullopt),
658  _semantic(std::nullopt),
659  _description(std::nullopt),
660  _offset(std::nullopt),
661  _scale(std::nullopt),
662  _max(std::nullopt),
663  _min(std::nullopt),
664  _required(false),
665  _noData(std::nullopt),
666  _defaultValue(std::nullopt) {}
667 
671  PropertyView(const ClassProperty& classProperty)
672  : _status(validatePropertyType<ElementType>(classProperty)),
673  _name(classProperty.name),
674  _semantic(classProperty.semantic),
675  _description(classProperty.description),
676  _offset(std::nullopt),
677  _scale(std::nullopt),
678  _max(std::nullopt),
679  _min(std::nullopt),
680  _required(classProperty.required),
681  _noData(std::nullopt),
682  _defaultValue(std::nullopt) {
683  if (_status != PropertyViewStatus::Valid) {
684  return;
685  }
686 
687  if (!classProperty.normalized) {
688  _status = PropertyViewStatus::ErrorNormalizationMismatch;
689  }
690 
691  getNumericPropertyValues(classProperty);
692  if (_status != PropertyViewStatus::Valid) {
693  return;
694  }
695 
696  if (classProperty.noData) {
697  if (!_required) {
698  // "noData" should not be defined if the property is required.
699  _noData = getValue<ElementType>(*classProperty.noData);
700  }
701  if (!_noData) {
702  // The value was specified but something went wrong.
703  _status = PropertyViewStatus::ErrorInvalidNoDataValue;
704  return;
705  }
706  }
707 
708  if (classProperty.defaultProperty) {
709  // default value should not be defined if the property is required.
710  if (!_required) {
711  _defaultValue =
712  getValue<NormalizedType>(*classProperty.defaultProperty);
713  }
714  if (!_defaultValue) {
715  // The value was specified but something went wrong.
716  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
717  return;
718  }
719  }
720  }
721 
722 protected:
728  PropertyView(PropertyViewStatusType status)
729  : _status(status),
730  _name(std::nullopt),
731  _semantic(std::nullopt),
732  _description(std::nullopt),
733  _offset(std::nullopt),
734  _scale(std::nullopt),
735  _max(std::nullopt),
736  _min(std::nullopt),
737  _required(false),
738  _noData(std::nullopt),
739  _defaultValue(std::nullopt) {}
740 
746  const ClassProperty& classProperty,
747  const PropertyTableProperty& property)
748  : PropertyView(classProperty) {
749  if (_status != PropertyViewStatus::Valid) {
750  return;
751  }
752 
753  // If the property has its own values, override the class-provided values.
754  getNumericPropertyValues(property);
755  }
756 
762  const ClassProperty& classProperty,
763  const PropertyTextureProperty& property)
764  : PropertyView(classProperty) {
765  if (_status != PropertyViewStatus::Valid) {
766  return;
767  }
768 
769  // If the property has its own values, override the class-provided values.
770  getNumericPropertyValues(property);
771  }
772 
778  const ClassProperty& classProperty,
779  const PropertyAttributeProperty& property)
780  : PropertyView(classProperty) {
781  if (_status != PropertyViewStatus::Valid) {
782  return;
783  }
784 
785  // If the property has its own values, override the class-provided values.
786  getNumericPropertyValues(property);
787  }
788 
789 public:
793  PropertyViewStatusType status() const noexcept { return _status; }
794 
798  const std::optional<std::string>& name() const noexcept { return _name; }
799 
803  const std::optional<std::string>& semantic() const noexcept {
804  return _semantic;
805  }
806 
810  const std::optional<std::string>& description() const noexcept {
811  return _description;
812  }
813 
817  int64_t arrayCount() const noexcept { return 0; }
818 
822  bool normalized() const noexcept { return true; }
823 
827  std::optional<NormalizedType> offset() const noexcept { return _offset; }
828 
832  std::optional<NormalizedType> scale() const noexcept { return _scale; }
833 
837  std::optional<NormalizedType> max() const noexcept { return _max; }
838 
842  std::optional<NormalizedType> min() const noexcept { return _min; }
843 
847  bool required() const noexcept { return _required; }
848 
852  std::optional<ElementType> noData() const noexcept { return _noData; }
853 
857  std::optional<NormalizedType> defaultValue() const noexcept {
858  return _defaultValue;
859  }
860 
861 protected:
862  PropertyViewStatusType _status;
863 
864 private:
865  std::optional<std::string> _name;
866  std::optional<std::string> _semantic;
867  std::optional<std::string> _description;
868 
869  std::optional<NormalizedType> _offset;
870  std::optional<NormalizedType> _scale;
871  std::optional<NormalizedType> _max;
872  std::optional<NormalizedType> _min;
873 
874  bool _required;
875  std::optional<ElementType> _noData;
876  std::optional<NormalizedType> _defaultValue;
877 
887  template <typename T>
888  static std::optional<T> getValue(const CesiumUtility::JsonValue& jsonValue) {
889  if constexpr (IsMetadataScalar<T>::value) {
890  return getScalar<T>(jsonValue);
891  }
892 
893  if constexpr (IsMetadataVecN<T>::value) {
894  return getVecN<T>(jsonValue);
895  }
896 
897  if constexpr (IsMetadataMatN<T>::value) {
898  return getMatN<T>(jsonValue);
899  }
900  }
901 
902  using PropertyDefinitionType = std::variant<
903  ClassProperty,
904  PropertyTableProperty,
905  PropertyTextureProperty,
906  PropertyAttributeProperty>;
907 
912  void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
913  std::visit(
914  [this](auto property) {
915  if (property.offset) {
916  _offset = getValue<NormalizedType>(*property.offset);
917  if (!_offset) {
918  // The value was specified but something went wrong.
919  _status = PropertyViewStatus::ErrorInvalidOffset;
920  return;
921  }
922  }
923 
924  if (property.scale) {
925  _scale = getValue<NormalizedType>(*property.scale);
926  if (!_scale) {
927  // The value was specified but something went wrong.
928  _status = PropertyViewStatus::ErrorInvalidScale;
929  return;
930  }
931  }
932 
933  if (property.max) {
934  _max = getValue<NormalizedType>(*property.max);
935  if (!_scale) {
936  // The value was specified but something went wrong.
937  _status = PropertyViewStatus::ErrorInvalidMax;
938  return;
939  }
940  }
941 
942  if (property.min) {
943  _min = getValue<NormalizedType>(*property.min);
944  if (!_scale) {
945  // The value was specified but something went wrong.
946  _status = PropertyViewStatus::ErrorInvalidMin;
947  return;
948  }
949  }
950  },
951  inProperty);
952  }
953 };
954 
959 template <> class PropertyView<bool> {
960 public:
965  : _status(PropertyViewStatus::ErrorNonexistentProperty),
966  _name(std::nullopt),
967  _semantic(std::nullopt),
968  _description(std::nullopt),
969  _required(false),
970  _defaultValue(std::nullopt) {}
971 
975  PropertyView(const ClassProperty& classProperty)
976  : _status(validatePropertyType<bool>(classProperty)),
977  _name(classProperty.name),
978  _semantic(classProperty.semantic),
979  _description(classProperty.description),
980  _required(classProperty.required),
981  _defaultValue(std::nullopt) {
982  if (_status != PropertyViewStatus::Valid) {
983  return;
984  }
985 
986  if (classProperty.defaultProperty) {
987  if (!_required) {
988  _defaultValue = getBooleanValue(*classProperty.defaultProperty);
989  }
990 
991  if (!_defaultValue) {
992  // The value was specified but something went wrong.
993  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
994  return;
995  }
996  }
997  }
998 
999 protected:
1005  PropertyView(PropertyViewStatusType status)
1006  : _status(status),
1007  _name(std::nullopt),
1008  _semantic(std::nullopt),
1009  _description(std::nullopt),
1010  _required(false),
1011  _defaultValue(std::nullopt) {}
1012 
1018  const ClassProperty& classProperty,
1019  const PropertyTableProperty& /*property*/)
1020  : PropertyView(classProperty) {}
1021 
1022 public:
1026  PropertyViewStatusType status() const noexcept { return _status; }
1027 
1031  const std::optional<std::string>& name() const noexcept { return _name; }
1032 
1036  const std::optional<std::string>& semantic() const noexcept {
1037  return _semantic;
1038  }
1039 
1043  const std::optional<std::string>& description() const noexcept {
1044  return _description;
1045  }
1046 
1050  int64_t arrayCount() const noexcept { return 0; }
1051 
1055  bool normalized() const noexcept { return false; }
1056 
1060  std::optional<bool> offset() const noexcept { return std::nullopt; }
1061 
1065  std::optional<bool> scale() const noexcept { return std::nullopt; }
1066 
1070  std::optional<bool> max() const noexcept { return std::nullopt; }
1071 
1075  std::optional<bool> min() const noexcept { return std::nullopt; }
1076 
1080  bool required() const noexcept { return _required; }
1081 
1085  std::optional<bool> noData() const noexcept { return std::nullopt; }
1086 
1090  std::optional<bool> defaultValue() const noexcept { return _defaultValue; }
1091 
1092 protected:
1093  PropertyViewStatusType _status;
1094 
1095 private:
1096  std::optional<std::string> _name;
1097  std::optional<std::string> _semantic;
1098  std::optional<std::string> _description;
1099 
1100  bool _required;
1101  std::optional<bool> _defaultValue;
1102 
1103  static std::optional<bool>
1104  getBooleanValue(const CesiumUtility::JsonValue& value) {
1105  if (!value.isBool()) {
1106  return std::nullopt;
1107  }
1108 
1109  return value.getBool();
1110  }
1111 };
1112 
1117 template <> class PropertyView<std::string_view> {
1118 public:
1123  : _status(PropertyViewStatus::ErrorNonexistentProperty),
1124  _name(std::nullopt),
1125  _semantic(std::nullopt),
1126  _description(std::nullopt),
1127  _required(false),
1128  _noData(std::nullopt),
1129  _defaultValue(std::nullopt) {}
1130 
1134  PropertyView(const ClassProperty& classProperty)
1135  : _status(validatePropertyType<std::string_view>(classProperty)),
1136  _name(classProperty.name),
1137  _semantic(classProperty.semantic),
1138  _description(classProperty.description),
1139  _required(classProperty.required),
1140  _noData(std::nullopt),
1141  _defaultValue(std::nullopt) {
1142  if (_status != PropertyViewStatus::Valid) {
1143  return;
1144  }
1145 
1146  if (classProperty.noData) {
1147  if (!_required) {
1148  _noData = getStringValue(*classProperty.noData);
1149  }
1150 
1151  if (!_noData) {
1152  // The value was specified but something went wrong.
1153  _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1154  return;
1155  }
1156  }
1157 
1158  if (classProperty.defaultProperty) {
1159  if (!_required) {
1160  _defaultValue = getStringValue(*classProperty.defaultProperty);
1161  }
1162 
1163  if (!_defaultValue) {
1164  // The value was specified but something went wrong.
1165  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1166  return;
1167  }
1168  }
1169  }
1170 
1171 protected:
1177  PropertyView(PropertyViewStatusType status)
1178  : _status(status),
1179  _name(std::nullopt),
1180  _semantic(std::nullopt),
1181  _description(std::nullopt),
1182  _required(false),
1183  _noData(std::nullopt),
1184  _defaultValue(std::nullopt) {}
1185 
1191  const ClassProperty& classProperty,
1192  const PropertyTableProperty& /*property*/)
1193  : PropertyView(classProperty) {}
1194 
1195 public:
1199  PropertyViewStatusType status() const noexcept { return _status; }
1200 
1204  const std::optional<std::string>& name() const noexcept { return _name; }
1205 
1209  const std::optional<std::string>& semantic() const noexcept {
1210  return _semantic;
1211  }
1212 
1216  const std::optional<std::string>& description() const noexcept {
1217  return _description;
1218  }
1219 
1223  int64_t arrayCount() const noexcept { return 0; }
1224 
1228  bool normalized() const noexcept { return false; }
1229 
1233  std::optional<std::string_view> offset() const noexcept {
1234  return std::nullopt;
1235  }
1236 
1240  std::optional<std::string_view> scale() const noexcept {
1241  return std::nullopt;
1242  }
1243 
1247  std::optional<std::string_view> max() const noexcept { return std::nullopt; }
1248 
1252  std::optional<std::string_view> min() const noexcept { return std::nullopt; }
1253 
1257  bool required() const noexcept { return _required; }
1258 
1262  std::optional<std::string_view> noData() const noexcept {
1263  if (_noData)
1264  return std::string_view(*_noData);
1265 
1266  return std::nullopt;
1267  }
1268 
1272  std::optional<std::string_view> defaultValue() const noexcept {
1273  if (_defaultValue)
1274  return std::string_view(*_defaultValue);
1275 
1276  return std::nullopt;
1277  }
1278 
1279 protected:
1280  PropertyViewStatusType _status;
1281 
1282 private:
1283  std::optional<std::string> _name;
1284  std::optional<std::string> _semantic;
1285  std::optional<std::string> _description;
1286 
1287  bool _required;
1288  std::optional<std::string> _noData;
1289  std::optional<std::string> _defaultValue;
1290 
1291  static std::optional<std::string>
1292  getStringValue(const CesiumUtility::JsonValue& value) {
1293  if (!value.isString()) {
1294  return std::nullopt;
1295  }
1296 
1297  return std::string(value.getString().c_str());
1298  }
1299 };
1300 
1314 template <typename ElementType>
1315 class PropertyView<PropertyArrayView<ElementType>, false> {
1316 public:
1321  : _status(PropertyViewStatus::ErrorNonexistentProperty),
1322  _name(std::nullopt),
1323  _semantic(std::nullopt),
1324  _description(std::nullopt),
1325  _count(0),
1326  _offset(std::nullopt),
1327  _scale(std::nullopt),
1328  _max(std::nullopt),
1329  _min(std::nullopt),
1330  _required(false),
1331  _noData(std::nullopt),
1332  _defaultValue(std::nullopt) {}
1333 
1337  PropertyView(const ClassProperty& classProperty)
1338  : _status(validateArrayPropertyType<PropertyArrayView<ElementType>>(
1339  classProperty)),
1340  _name(classProperty.name),
1341  _semantic(classProperty.semantic),
1342  _description(classProperty.description),
1343  _count(_count = classProperty.count ? *classProperty.count : 0),
1344  _offset(std::nullopt),
1345  _scale(std::nullopt),
1346  _max(std::nullopt),
1347  _min(std::nullopt),
1348  _required(classProperty.required),
1349  _noData(std::nullopt),
1350  _defaultValue(std::nullopt) {
1351  if (_status != PropertyViewStatus::Valid) {
1352  return;
1353  }
1354 
1355  if (classProperty.normalized) {
1356  _status = PropertyViewStatus::ErrorNormalizationMismatch;
1357  return;
1358  }
1359 
1360  getNumericPropertyValues(classProperty);
1361  if (_status != PropertyViewStatus::Valid) {
1362  return;
1363  }
1364 
1365  if (classProperty.noData) {
1366  if (!_required) {
1367  _noData = getArrayValue(*classProperty.noData);
1368  }
1369 
1370  if (!_noData) {
1371  _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1372  return;
1373  }
1374  }
1375 
1376  if (classProperty.defaultProperty) {
1377  if (!_required) {
1378  _defaultValue = getArrayValue(*classProperty.defaultProperty);
1379  }
1380 
1381  if (!_defaultValue) {
1382  // The value was specified but something went wrong.
1383  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1384  return;
1385  }
1386  }
1387  }
1388 
1389 protected:
1395  PropertyView(PropertyViewStatusType status)
1396  : _status(status),
1397  _name(std::nullopt),
1398  _semantic(std::nullopt),
1399  _description(std::nullopt),
1400  _count(0),
1401  _offset(std::nullopt),
1402  _scale(std::nullopt),
1403  _max(std::nullopt),
1404  _min(std::nullopt),
1405  _required(false),
1406  _noData(std::nullopt),
1407  _defaultValue(std::nullopt) {}
1408 
1414  const ClassProperty& classProperty,
1415  const PropertyTableProperty& property)
1416  : PropertyView(classProperty) {
1417  if (_status != PropertyViewStatus::Valid) {
1418  return;
1419  }
1420 
1421  // If the property has its own values, override the class-provided values.
1422  getNumericPropertyValues(property);
1423  }
1424 
1430  const ClassProperty& classProperty,
1431  const PropertyTextureProperty& property)
1432  : PropertyView(classProperty) {
1433  if (_status != PropertyViewStatus::Valid) {
1434  return;
1435  }
1436 
1437  // If the property has its own values, override the class-provided values.
1438  getNumericPropertyValues(property);
1439  }
1440 
1441 public:
1445  PropertyViewStatusType status() const noexcept { return _status; }
1446 
1450  const std::optional<std::string>& name() const noexcept { return _name; }
1451 
1455  const std::optional<std::string>& semantic() const noexcept {
1456  return _semantic;
1457  }
1458 
1462  const std::optional<std::string>& description() const noexcept {
1463  return _description;
1464  }
1465 
1469  int64_t arrayCount() const noexcept { return _count; }
1470 
1474  bool normalized() const noexcept { return false; }
1475 
1479  std::optional<PropertyArrayView<ElementType>> offset() const noexcept {
1480  if (!_offset) {
1481  return std::nullopt;
1482  }
1483 
1485  gsl::span<const std::byte>(_offset->data(), _offset->size()));
1486  }
1487 
1491  std::optional<PropertyArrayView<ElementType>> scale() const noexcept {
1492  if (!_scale) {
1493  return std::nullopt;
1494  }
1495 
1497  gsl::span<const std::byte>(_scale->data(), _scale->size()));
1498  }
1499 
1503  std::optional<PropertyArrayView<ElementType>> max() const noexcept {
1504  if (!_max) {
1505  return std::nullopt;
1506  }
1507 
1509  gsl::span<const std::byte>(_max->data(), _max->size()));
1510  }
1511 
1515  std::optional<PropertyArrayView<ElementType>> min() const noexcept {
1516  if (!_min) {
1517  return std::nullopt;
1518  }
1519 
1521  gsl::span<const std::byte>(_min->data(), _min->size()));
1522  }
1523 
1527  bool required() const noexcept { return _required; }
1528 
1532  std::optional<PropertyArrayView<ElementType>> noData() const noexcept {
1533  if (!_noData) {
1534  return std::nullopt;
1535  }
1536 
1538  gsl::span<const std::byte>(_noData->data(), _noData->size()));
1539  }
1540 
1544  std::optional<PropertyArrayView<ElementType>> defaultValue() const noexcept {
1545  if (!_defaultValue) {
1546  return std::nullopt;
1547  }
1548 
1549  return PropertyArrayView<ElementType>(gsl::span<const std::byte>(
1550  _defaultValue->data(),
1551  _defaultValue->size()));
1552  }
1553 
1554 protected:
1555  PropertyViewStatusType _status;
1556 
1557 private:
1558  std::optional<std::string> _name;
1559  std::optional<std::string> _semantic;
1560  std::optional<std::string> _description;
1561 
1562  int64_t _count;
1563 
1564  std::optional<std::vector<std::byte>> _offset;
1565  std::optional<std::vector<std::byte>> _scale;
1566  std::optional<std::vector<std::byte>> _max;
1567  std::optional<std::vector<std::byte>> _min;
1568 
1569  bool _required;
1570  std::optional<std::vector<std::byte>> _noData;
1571  std::optional<std::vector<std::byte>> _defaultValue;
1572 
1573  using PropertyDefinitionType = std::
1574  variant<ClassProperty, PropertyTableProperty, PropertyTextureProperty>;
1575  void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
1576  std::visit(
1577  [this](auto property) {
1578  if (property.offset) {
1579  // Only floating point types can specify an offset.
1580  switch (TypeToPropertyType<ElementType>::component) {
1581  case PropertyComponentType::Float32:
1582  case PropertyComponentType::Float64:
1583  if (this->_count > 0) {
1584  this->_offset = getArrayValue(*property.offset);
1585  }
1586  if (this->_offset &&
1587  getCount<ElementType>(this->_offset) == this->_count) {
1588  break;
1589  }
1590  // If it does not break here, something went wrong.
1591  [[fallthrough]];
1592  default:
1593  this->_status = PropertyViewStatus::ErrorInvalidOffset;
1594  return;
1595  }
1596  }
1597 
1598  if (property.scale) {
1599  // Only floating point types can specify a scale.
1600  switch (TypeToPropertyType<ElementType>::component) {
1601  case PropertyComponentType::Float32:
1602  case PropertyComponentType::Float64:
1603  if (_count > 0) {
1604  this->_scale = getArrayValue(*property.scale);
1605  }
1606  if (this->_scale &&
1607  getCount<ElementType>(this->_scale) == this->_count) {
1608  break;
1609  }
1610  // If it does not break here, something went wrong.
1611  [[fallthrough]];
1612  default:
1613  this->_status = PropertyViewStatus::ErrorInvalidScale;
1614  return;
1615  }
1616  }
1617 
1618  if (property.max) {
1619  if (this->_count > 0) {
1620  this->_max = getArrayValue(*property.max);
1621  }
1622  if (!this->_max ||
1623  getCount<ElementType>(this->_max) != this->_count) {
1624  // The value was specified but something went wrong.
1625  this->_status = PropertyViewStatus::ErrorInvalidMax;
1626  return;
1627  }
1628  }
1629 
1630  if (property.min) {
1631  if (this->_count > 0) {
1632  this->_min = getArrayValue(*property.min);
1633  }
1634  if (!this->_min ||
1635  getCount<ElementType>(this->_min) != this->_count) {
1636  // The value was specified but something went wrong.
1637  this->_status = PropertyViewStatus::ErrorInvalidMin;
1638  return;
1639  }
1640  }
1641  },
1642  inProperty);
1643  }
1644 
1645  static std::optional<std::vector<std::byte>>
1646  getArrayValue(const CesiumUtility::JsonValue& jsonValue) {
1647  if (!jsonValue.isArray()) {
1648  return std::nullopt;
1649  }
1650 
1651  const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
1652  std::vector<ElementType> values;
1653  values.reserve(array.size());
1654 
1655  if constexpr (IsMetadataScalar<ElementType>::value) {
1656  for (size_t i = 0; i < array.size(); i++) {
1657  std::optional<ElementType> element = getScalar<ElementType>(array[i]);
1658  if (!element) {
1659  return std::nullopt;
1660  }
1661 
1662  values.push_back(*element);
1663  }
1664  }
1665  if constexpr (IsMetadataVecN<ElementType>::value) {
1666  for (size_t i = 0; i < array.size(); i++) {
1667  std::optional<ElementType> element = getVecN<ElementType>(array[i]);
1668  if (!element) {
1669  return std::nullopt;
1670  }
1671 
1672  values.push_back(*element);
1673  }
1674  }
1675 
1676  if constexpr (IsMetadataMatN<ElementType>::value) {
1677  for (size_t i = 0; i < array.size(); i++) {
1678  std::optional<ElementType> element = getMatN<ElementType>(array[i]);
1679  if (!element) {
1680  return std::nullopt;
1681  }
1682 
1683  values.push_back(*element);
1684  }
1685  }
1686 
1687  std::vector<std::byte> result(values.size() * sizeof(ElementType));
1688  std::memcpy(result.data(), values.data(), result.size());
1689 
1690  return result;
1691  }
1692 };
1693 
1707 template <typename ElementType>
1708 class PropertyView<PropertyArrayView<ElementType>, true> {
1709 private:
1710  using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
1711 
1712 public:
1717  : _status(PropertyViewStatus::ErrorNonexistentProperty),
1718  _name(std::nullopt),
1719  _semantic(std::nullopt),
1720  _description(std::nullopt),
1721  _count(0),
1722  _offset(std::nullopt),
1723  _scale(std::nullopt),
1724  _max(std::nullopt),
1725  _min(std::nullopt),
1726  _required(false),
1727  _noData(std::nullopt),
1728  _defaultValue(std::nullopt) {}
1729 
1733  PropertyView(const ClassProperty& classProperty)
1734  : _status(validateArrayPropertyType<PropertyArrayView<ElementType>>(
1735  classProperty)),
1736  _name(classProperty.name),
1737  _semantic(classProperty.semantic),
1738  _description(classProperty.description),
1739  _count(_count = classProperty.count ? *classProperty.count : 0),
1740  _offset(std::nullopt),
1741  _scale(std::nullopt),
1742  _max(std::nullopt),
1743  _min(std::nullopt),
1744  _required(classProperty.required),
1745  _noData(std::nullopt),
1746  _defaultValue(std::nullopt) {
1747  if (_status != PropertyViewStatus::Valid) {
1748  return;
1749  }
1750 
1751  if (!classProperty.normalized) {
1752  _status = PropertyViewStatus::ErrorNormalizationMismatch;
1753  return;
1754  }
1755 
1756  getNumericPropertyValues(classProperty);
1757  if (_status != PropertyViewStatus::Valid) {
1758  return;
1759  }
1760 
1761  if (classProperty.noData) {
1762  if (!_required) {
1763  _noData = getArrayValue<ElementType>(*classProperty.noData);
1764  }
1765 
1766  if (!_noData) {
1767  _status = PropertyViewStatus::ErrorInvalidNoDataValue;
1768  return;
1769  }
1770  }
1771 
1772  if (classProperty.defaultProperty) {
1773  if (!_required) {
1774  _defaultValue =
1775  getArrayValue<NormalizedType>(*classProperty.defaultProperty);
1776  }
1777 
1778  if (!_defaultValue) {
1779  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
1780  return;
1781  }
1782  }
1783  }
1784 
1785 protected:
1791  PropertyView(PropertyViewStatusType status)
1792  : _status(status),
1793  _name(std::nullopt),
1794  _semantic(std::nullopt),
1795  _description(std::nullopt),
1796  _count(0),
1797  _offset(std::nullopt),
1798  _scale(std::nullopt),
1799  _max(std::nullopt),
1800  _min(std::nullopt),
1801  _required(false),
1802  _noData(std::nullopt),
1803  _defaultValue(std::nullopt) {}
1804 
1810  const ClassProperty& classProperty,
1811  const PropertyTableProperty& property)
1812  : PropertyView(classProperty) {
1813  if (_status != PropertyViewStatus::Valid) {
1814  return;
1815  }
1816 
1817  // If the property has its own values, override the class-provided values.
1818  getNumericPropertyValues(property);
1819  }
1820 
1826  const ClassProperty& classProperty,
1827  const PropertyTextureProperty& property)
1828  : PropertyView(classProperty) {
1829  if (_status != PropertyViewStatus::Valid) {
1830  return;
1831  }
1832 
1833  // If the property has its own values, override the class-provided values.
1834  getNumericPropertyValues(property);
1835  }
1836 
1837 public:
1841  PropertyViewStatusType status() const noexcept { return _status; }
1842 
1846  const std::optional<std::string>& name() const noexcept { return _name; }
1847 
1851  const std::optional<std::string>& semantic() const noexcept {
1852  return _semantic;
1853  }
1854 
1858  const std::optional<std::string>& description() const noexcept {
1859  return _description;
1860  }
1861 
1865  int64_t arrayCount() const noexcept { return _count; }
1866 
1870  bool normalized() const noexcept { return true; }
1871 
1875  std::optional<PropertyArrayView<NormalizedType>> offset() const noexcept {
1876  if (!_offset) {
1877  return std::nullopt;
1878  }
1879 
1881  gsl::span<const std::byte>(_offset->data(), _offset->size()));
1882  }
1883 
1887  std::optional<PropertyArrayView<NormalizedType>> scale() const noexcept {
1888  if (!_scale) {
1889  return std::nullopt;
1890  }
1891 
1893  gsl::span<const std::byte>(_scale->data(), _scale->size()));
1894  }
1895 
1899  std::optional<PropertyArrayView<NormalizedType>> max() const noexcept {
1900  if (!_max) {
1901  return std::nullopt;
1902  }
1903 
1905  gsl::span<const std::byte>(_max->data(), _max->size()));
1906  }
1907 
1911  std::optional<PropertyArrayView<NormalizedType>> min() const noexcept {
1912  if (!_min) {
1913  return std::nullopt;
1914  }
1915 
1917  gsl::span<const std::byte>(_min->data(), _min->size()));
1918  }
1919 
1923  bool required() const noexcept { return _required; }
1924 
1928  std::optional<PropertyArrayView<ElementType>> noData() const noexcept {
1929  if (!_noData) {
1930  return std::nullopt;
1931  }
1932 
1934  gsl::span<const std::byte>(_noData->data(), _noData->size()));
1935  }
1936 
1940  std::optional<PropertyArrayView<NormalizedType>>
1941  defaultValue() const noexcept {
1942  if (!_defaultValue) {
1943  return std::nullopt;
1944  }
1945 
1946  return PropertyArrayView<NormalizedType>(gsl::span<const std::byte>(
1947  _defaultValue->data(),
1948  _defaultValue->size()));
1949  }
1950 
1951 protected:
1952  PropertyViewStatusType _status;
1953 
1954 private:
1955  std::optional<std::string> _name;
1956  std::optional<std::string> _semantic;
1957  std::optional<std::string> _description;
1958 
1959  int64_t _count;
1960 
1961  std::optional<std::vector<std::byte>> _offset;
1962  std::optional<std::vector<std::byte>> _scale;
1963  std::optional<std::vector<std::byte>> _max;
1964  std::optional<std::vector<std::byte>> _min;
1965 
1966  bool _required;
1967  std::optional<std::vector<std::byte>> _noData;
1968  std::optional<std::vector<std::byte>> _defaultValue;
1969 
1970  using PropertyDefinitionType = std::
1971  variant<ClassProperty, PropertyTableProperty, PropertyTextureProperty>;
1972  void getNumericPropertyValues(const PropertyDefinitionType& inProperty) {
1973  std::visit(
1974  [this](auto property) {
1975  if (property.offset) {
1976  if (_count > 0) {
1977  _offset = getArrayValue<NormalizedType>(*property.offset);
1978  }
1979  if (!_offset || getCount<NormalizedType>(_offset) != _count) {
1980  // The value was specified but something went wrong.
1981  _status = PropertyViewStatus::ErrorInvalidOffset;
1982  return;
1983  }
1984  }
1985 
1986  if (property.scale) {
1987  if (_count > 0) {
1988  _scale = getArrayValue<NormalizedType>(*property.scale);
1989  }
1990  if (!_scale || getCount<NormalizedType>(_scale) != _count) {
1991  // The value was specified but something went wrong.
1992  _status = PropertyViewStatus::ErrorInvalidScale;
1993  return;
1994  }
1995  }
1996 
1997  if (property.max) {
1998  if (_count > 0) {
1999  _max = getArrayValue<NormalizedType>(*property.max);
2000  }
2001  if (!_max || getCount<NormalizedType>(_max) != _count) {
2002  // The value was specified but something went wrong.
2003  _status = PropertyViewStatus::ErrorInvalidMax;
2004  return;
2005  }
2006  }
2007 
2008  if (property.min) {
2009  if (_count > 0) {
2010  _min = getArrayValue<NormalizedType>(*property.min);
2011  }
2012  if (!_min || getCount<NormalizedType>(_min) != _count) {
2013  // The value was specified but something went wrong.
2014  _status = PropertyViewStatus::ErrorInvalidMin;
2015  return;
2016  }
2017  }
2018  },
2019  inProperty);
2020  }
2021 
2022  template <typename T>
2023  static std::optional<std::vector<std::byte>>
2024  getArrayValue(const CesiumUtility::JsonValue& jsonValue) {
2025  if (!jsonValue.isArray()) {
2026  return std::nullopt;
2027  }
2028 
2029  const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
2030  std::vector<T> values;
2031  values.reserve(array.size());
2032 
2033  if constexpr (IsMetadataScalar<T>::value) {
2034  for (size_t i = 0; i < array.size(); i++) {
2035  std::optional<T> element = getScalar<T>(array[i]);
2036  if (!element) {
2037  return std::nullopt;
2038  }
2039 
2040  values.push_back(*element);
2041  }
2042  }
2043 
2044  if constexpr (IsMetadataVecN<T>::value) {
2045  for (size_t i = 0; i < array.size(); i++) {
2046  std::optional<T> element = getVecN<T>(array[i]);
2047  if (!element) {
2048  return std::nullopt;
2049  }
2050 
2051  values.push_back(*element);
2052  }
2053  }
2054 
2055  if constexpr (IsMetadataMatN<T>::value) {
2056  for (size_t i = 0; i < array.size(); i++) {
2057  std::optional<T> element = getMatN<T>(array[i]);
2058  if (!element) {
2059  return std::nullopt;
2060  }
2061 
2062  values.push_back(*element);
2063  }
2064  }
2065 
2066  std::vector<std::byte> result(values.size() * sizeof(T));
2067  std::memcpy(result.data(), values.data(), result.size());
2068 
2069  return result;
2070  }
2071 };
2072 
2077 template <> class PropertyView<PropertyArrayView<bool>> {
2078 public:
2083  : _status(PropertyViewStatus::ErrorNonexistentProperty),
2084  _name(std::nullopt),
2085  _semantic(std::nullopt),
2086  _description(std::nullopt),
2087  _count(0),
2088  _required(false),
2089  _defaultValue(),
2090  _size(0) {}
2091 
2095  PropertyView(const ClassProperty& classProperty)
2096  : _status(
2097  validateArrayPropertyType<PropertyArrayView<bool>>(classProperty)),
2098  _name(classProperty.name),
2099  _semantic(classProperty.semantic),
2100  _description(classProperty.description),
2101  _count(classProperty.count ? *classProperty.count : 0),
2102  _required(classProperty.required),
2103  _defaultValue(),
2104  _size(0) {
2105  if (_status != PropertyViewStatus::Valid) {
2106  return;
2107  }
2108 
2109  if (classProperty.defaultProperty) {
2110  if (!_required) {
2111  _defaultValue =
2112  getBooleanArrayValue(*classProperty.defaultProperty, _size);
2113  }
2114 
2115  if (_size == 0 || (_count > 0 && _size != _count)) {
2116  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
2117  return;
2118  }
2119  }
2120  }
2121 
2122 protected:
2128  PropertyView(PropertyViewStatusType status)
2129  : _status(status),
2130  _name(std::nullopt),
2131  _semantic(std::nullopt),
2132  _description(std::nullopt),
2133  _count(0),
2134  _required(false),
2135  _defaultValue(),
2136  _size(0) {}
2137 
2143  const ClassProperty& classProperty,
2144  const PropertyTableProperty& /*property*/)
2145  : PropertyView(classProperty) {}
2146 
2147 public:
2151  PropertyViewStatusType status() const noexcept { return _status; }
2152 
2156  const std::optional<std::string>& name() const noexcept { return _name; }
2157 
2161  const std::optional<std::string>& semantic() const noexcept {
2162  return _semantic;
2163  }
2164 
2168  const std::optional<std::string>& description() const noexcept {
2169  return _description;
2170  }
2171 
2175  int64_t arrayCount() const noexcept { return _count; }
2176 
2180  bool normalized() const noexcept { return false; }
2181 
2185  std::optional<PropertyArrayView<bool>> offset() const noexcept {
2186  return std::nullopt;
2187  }
2188 
2192  std::optional<PropertyArrayView<bool>> scale() const noexcept {
2193  return std::nullopt;
2194  }
2195 
2199  std::optional<PropertyArrayView<bool>> max() const noexcept {
2200  return std::nullopt;
2201  }
2202 
2206  std::optional<PropertyArrayView<bool>> min() const noexcept {
2207  return std::nullopt;
2208  }
2209 
2213  bool required() const noexcept { return _required; }
2214 
2218  std::optional<PropertyArrayView<bool>> noData() const noexcept {
2219  return std::nullopt;
2220  }
2221 
2225  std::optional<PropertyArrayView<bool>> defaultValue() const noexcept {
2226  if (_size > 0) {
2227  return PropertyArrayView<bool>(
2228  gsl::span<const std::byte>(
2229  _defaultValue.data(),
2230  _defaultValue.size()),
2231  /* bitOffset = */ 0,
2232  _size);
2233  }
2234 
2235  return std::nullopt;
2236  }
2237 
2238 protected:
2239  PropertyViewStatusType _status;
2240 
2241 private:
2242  std::optional<std::string> _name;
2243  std::optional<std::string> _semantic;
2244  std::optional<std::string> _description;
2245 
2246  int64_t _count;
2247  bool _required;
2248 
2249  std::vector<std::byte> _defaultValue;
2250  int64_t _size;
2251 
2252  static std::vector<std::byte> getBooleanArrayValue(
2253  const CesiumUtility::JsonValue& jsonValue,
2254  int64_t& size) {
2255  if (!jsonValue.isArray()) {
2256  return std::vector<std::byte>();
2257  }
2258 
2259  const CesiumUtility::JsonValue::Array& array = jsonValue.getArray();
2260  std::vector<std::byte> values;
2261  values.reserve((array.size() / 8) + 1);
2262 
2263  size_t byteIndex = 0;
2264  uint8_t bitIndex = 0;
2265 
2266  for (size_t i = 0; i < array.size(); i++, size++) {
2267  if (!array[i].isBool()) {
2268  size = 0;
2269  return values;
2270  }
2271 
2272  if (values.size() < byteIndex - 1) {
2273  values.push_back(std::byte(0));
2274  }
2275 
2276  std::byte value = std::byte(array[i].getBool() ? 1 : 0);
2277  value = value << bitIndex;
2278 
2279  values[byteIndex] |= value;
2280 
2281  bitIndex++;
2282  if (bitIndex > 7) {
2283  byteIndex++;
2284  bitIndex = 0;
2285  }
2286  }
2287 
2288  return values;
2289  }
2290 };
2291 
2296 template <> class PropertyView<PropertyArrayView<std::string_view>> {
2297 public:
2302  : _status(PropertyViewStatus::ErrorNonexistentProperty),
2303  _name(std::nullopt),
2304  _semantic(std::nullopt),
2305  _description(std::nullopt),
2306  _count(0),
2307  _required(false),
2308  _noData(),
2309  _defaultValue() {}
2310 
2314  PropertyView(const ClassProperty& classProperty)
2315  : _status(validateArrayPropertyType<PropertyArrayView<std::string_view>>(
2316  classProperty)),
2317  _name(classProperty.name),
2318  _semantic(classProperty.semantic),
2319  _description(classProperty.description),
2320  _count(classProperty.count ? *classProperty.count : 0),
2321  _required(classProperty.required),
2322  _noData(),
2323  _defaultValue() {
2324  if (_status != PropertyViewStatus::Valid) {
2325  return;
2326  }
2327 
2328  if (classProperty.noData) {
2329  if (!_required) {
2330  _noData = getStringArrayValue(*classProperty.noData);
2331  }
2332 
2333  if (_noData.size == 0 || (_count > 0 && _noData.size != _count)) {
2334  _status = PropertyViewStatus::ErrorInvalidNoDataValue;
2335  return;
2336  }
2337  }
2338 
2339  if (classProperty.defaultProperty) {
2340  if (!_required) {
2341  _defaultValue = getStringArrayValue(*classProperty.defaultProperty);
2342  }
2343 
2344  if (_defaultValue.size == 0 ||
2345  (_count > 0 && _defaultValue.size != _count)) {
2346  // The value was specified but something went wrong.
2347  _status = PropertyViewStatus::ErrorInvalidDefaultValue;
2348  return;
2349  }
2350  }
2351  }
2352 
2353 protected:
2359  PropertyView(PropertyViewStatusType status)
2360  : _status(status),
2361  _name(std::nullopt),
2362  _semantic(std::nullopt),
2363  _description(std::nullopt),
2364  _count(0),
2365  _required(false),
2366  _noData(),
2367  _defaultValue() {}
2368 
2374  const ClassProperty& classProperty,
2375  const PropertyTableProperty& /*property*/)
2376  : PropertyView(classProperty) {}
2377 
2378 public:
2382  PropertyViewStatusType status() const noexcept { return _status; }
2383 
2387  const std::optional<std::string>& name() const noexcept { return _name; }
2388 
2392  const std::optional<std::string>& semantic() const noexcept {
2393  return _semantic;
2394  }
2395 
2399  const std::optional<std::string>& description() const noexcept {
2400  return _description;
2401  }
2402 
2406  int64_t arrayCount() const noexcept { return _count; }
2407 
2411  bool normalized() const noexcept { return false; }
2412 
2416  std::optional<PropertyArrayView<std::string_view>> offset() const noexcept {
2417  return std::nullopt;
2418  }
2419 
2423  std::optional<PropertyArrayView<std::string_view>> scale() const noexcept {
2424  return std::nullopt;
2425  }
2426 
2430  std::optional<PropertyArrayView<std::string_view>> max() const noexcept {
2431  return std::nullopt;
2432  }
2433 
2437  std::optional<PropertyArrayView<std::string_view>> min() const noexcept {
2438  return std::nullopt;
2439  }
2440 
2444  bool required() const noexcept { return _required; }
2445 
2449  std::optional<PropertyArrayView<std::string_view>> noData() const noexcept {
2450  if (_noData.size > 0) {
2452  gsl::span<const std::byte>(_noData.data.data(), _noData.data.size()),
2453  gsl::span<const std::byte>(
2454  _noData.offsets.data(),
2455  _noData.offsets.size()),
2456  _noData.offsetType,
2457  _noData.size);
2458  }
2459 
2460  return std::nullopt;
2461  }
2462 
2466  std::optional<PropertyArrayView<std::string_view>>
2467  defaultValue() const noexcept {
2468  if (_defaultValue.size > 0) {
2470  gsl::span<const std::byte>(
2471  _defaultValue.data.data(),
2472  _defaultValue.data.size()),
2473  gsl::span<const std::byte>(
2474  _defaultValue.offsets.data(),
2475  _defaultValue.offsets.size()),
2476  _defaultValue.offsetType,
2477  _defaultValue.size);
2478  }
2479 
2480  return std::nullopt;
2481  }
2482 
2483 protected:
2484  PropertyViewStatusType _status;
2485 
2486 private:
2487  std::optional<std::string> _name;
2488  std::optional<std::string> _semantic;
2489  std::optional<std::string> _description;
2490 
2491  int64_t _count;
2492  bool _required;
2493 
2494  struct StringArrayValue {
2495  std::vector<std::byte> data;
2496  std::vector<std::byte> offsets;
2497  PropertyComponentType offsetType = PropertyComponentType::None;
2498  int64_t size = 0;
2499  };
2500 
2501  StringArrayValue _noData;
2502  StringArrayValue _defaultValue;
2503 
2504  static StringArrayValue
2505  getStringArrayValue(const CesiumUtility::JsonValue& jsonValue) {
2506  StringArrayValue result;
2507  if (!jsonValue.isArray()) {
2508  return result;
2509  }
2510 
2511  std::vector<std::string> strings;
2512  std::vector<uint64_t> stringOffsets;
2513 
2514  const auto array = jsonValue.getArray();
2515  strings.reserve(array.size());
2516  stringOffsets.reserve(array.size() + 1);
2517  stringOffsets.push_back(static_cast<uint64_t>(0));
2518 
2519  for (size_t i = 0; i < array.size(); i++) {
2520  if (!array[i].isString()) {
2521  // The entire array is invalidated; return.
2522  return result;
2523  }
2524 
2525  const std::string& string = array[i].getString();
2526  strings.push_back(string);
2527  stringOffsets.push_back(stringOffsets[i] + string.size());
2528  }
2529 
2530  uint64_t totalLength = stringOffsets.back();
2531  result.data.resize(totalLength);
2532  for (size_t i = 0; i < strings.size(); ++i) {
2533  std::memcpy(
2534  result.data.data() + stringOffsets[i],
2535  strings[i].data(),
2536  strings[i].size());
2537  };
2538 
2539  if (totalLength <= std::numeric_limits<uint8_t>::max()) {
2540  result.offsets = narrowOffsetsBuffer<uint8_t>(stringOffsets);
2541  result.offsetType = PropertyComponentType::Uint8;
2542  } else if (totalLength <= std::numeric_limits<uint16_t>::max()) {
2543  result.offsets = narrowOffsetsBuffer<uint16_t>(stringOffsets);
2544  result.offsetType = PropertyComponentType::Uint16;
2545  } else if (totalLength <= std::numeric_limits<uint32_t>::max()) {
2546  result.offsets = narrowOffsetsBuffer<uint32_t>(stringOffsets);
2547  result.offsetType = PropertyComponentType::Uint32;
2548  } else {
2549  result.offsets.resize(stringOffsets.size() * sizeof(uint64_t));
2550  std::memcpy(
2551  result.offsets.data(),
2552  stringOffsets.data(),
2553  result.offsets.size());
2554  result.offsetType = PropertyComponentType::Uint64;
2555  }
2556 
2557  result.size = static_cast<int64_t>(strings.size());
2558 
2559  return result;
2560  }
2561 
2562  template <typename T>
2563  static std::vector<std::byte>
2564  narrowOffsetsBuffer(std::vector<uint64_t> offsets) {
2565  std::vector<std::byte> result(offsets.size() * sizeof(T));
2566  size_t bufferOffset = 0;
2567  for (size_t i = 0; i < offsets.size(); i++, bufferOffset += sizeof(T)) {
2568  T offset = static_cast<T>(offsets[i]);
2569  std::memcpy(result.data() + bufferOffset, &offset, sizeof(T));
2570  }
2571 
2572  return result;
2573  }
2574 };
2575 
2576 } // namespace CesiumGltf
A view on an array element of a PropertyTableProperty or PropertyTextureProperty.
Indicates the status of a property view.
Definition: PropertyView.h:27
static const PropertyViewStatusType ErrorTypeMismatch
This property view's type does not match what is specified in ClassProperty::type.
Definition: PropertyView.h:53
static const PropertyViewStatusType ErrorInvalidDefaultValue
The property provided an invalid default value.
Definition: PropertyView.h:107
static const PropertyViewStatusType ErrorInvalidMin
The property provided an invalid minimum value.
Definition: PropertyView.h:97
static const PropertyViewStatusType ErrorInvalidMax
The property provided an invalid maximum value.
Definition: PropertyView.h:92
static const PropertyViewStatusType ErrorInvalidOffset
The property provided an invalid offset value.
Definition: PropertyView.h:82
static const PropertyViewStatusType Valid
This property view is valid and ready to use.
Definition: PropertyView.h:32
static const PropertyViewStatusType ErrorNonexistentProperty
This property view is trying to view a property that does not exist.
Definition: PropertyView.h:47
static const PropertyViewStatusType ErrorInvalidNormalization
This property says it is normalized, but it does not have an integer component type.
Definition: PropertyView.h:71
static const PropertyViewStatusType ErrorArrayTypeMismatch
This property view differs from what is specified in ClassProperty::array.
Definition: PropertyView.h:65
static const PropertyViewStatusType ErrorInvalidNoDataValue
The property provided an invalid "no data" value.
Definition: PropertyView.h:102
static const PropertyViewStatusType ErrorNormalizationMismatch
This property view's normalization differs from what is specified in ClassProperty::normalized.
Definition: PropertyView.h:77
static const PropertyViewStatusType EmptyPropertyWithDefault
This property view does not contain any data, but specifies a default value. This happens when a clas...
Definition: PropertyView.h:41
static const PropertyViewStatusType ErrorInvalidScale
The property provided an invalid scale value.
Definition: PropertyView.h:87
static const PropertyViewStatusType ErrorComponentTypeMismatch
This property view's component type does not match what is specified in ClassProperty::componentType.
Definition: PropertyView.h:59
std::optional< ElementType > offset() const noexcept
Gets the offset to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the...
Definition: PropertyView.h:460
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...
Definition: PropertyView.h:428
bool required() const noexcept
Whether the property must be present in every entity conforming to the class. If not required,...
Definition: PropertyView.h:498
std::optional< ElementType > noData() const noexcept
Gets the "no data" value, i.e., the value representing missing data in the property wherever it appea...
Definition: PropertyView.h:509
const std::optional< std::string > & description() const noexcept
Gets the description of the property being viewed. Returns std::nullopt if no description was specifi...
Definition: PropertyView.h:436
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
Definition: PropertyView.h:363
std::optional< ElementType > defaultValue() const noexcept
Gets the default value to use when encountering a "no data" value or an omitted property....
Definition: PropertyView.h:519
std::optional< ElementType > scale() const noexcept
Gets the scale to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the ...
Definition: PropertyView.h:469
bool normalized() const noexcept
Whether this property has a normalized integer type.
Definition: PropertyView.h:451
std::optional< ElementType > min() const noexcept
Gets the minimum allowed value for the property. Only applicable to SCALAR, VECN, and MATN types....
Definition: PropertyView.h:491
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
Definition: PropertyView.h:286
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
Definition: PropertyView.h:379
int64_t arrayCount() const noexcept
Get the element count of the fixed-length arrays in this property. Only applicable when the property ...
Definition: PropertyView.h:446
PropertyViewStatusType status() const noexcept
Gets the status of this property view, indicating whether an error occurred.
Definition: PropertyView.h:414
const std::optional< std::string > & name() const noexcept
Gets the name of the property being viewed. Returns std::nullopt if no name was specified.
Definition: PropertyView.h:420
PropertyView(const ClassProperty &classProperty, const PropertyAttributeProperty &property)
Constructs a property instance from a property attribute property and its class definition.
Definition: PropertyView.h:395
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
Definition: PropertyView.h:346
std::optional< ElementType > max() const noexcept
Gets the maximum allowed value for the property. Only applicable to SCALAR, VECN, and MATN types....
Definition: PropertyView.h:480
PropertyView()
Constructs an empty property instance.
Definition: PropertyView.h:270
const std::optional< std::string > & description() const noexcept
Definition: PropertyView.h:810
std::optional< NormalizedType > scale() const noexcept
Definition: PropertyView.h:832
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
Definition: PropertyView.h:745
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
Definition: PropertyView.h:728
const std::optional< std::string > & semantic() const noexcept
Definition: PropertyView.h:803
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
Definition: PropertyView.h:761
PropertyView(const ClassProperty &classProperty, const PropertyAttributeProperty &property)
Constructs a property instance from a property attribute property and its class definition.
Definition: PropertyView.h:777
std::optional< NormalizedType > defaultValue() const noexcept
Definition: PropertyView.h:857
std::optional< NormalizedType > min() const noexcept
Definition: PropertyView.h:842
PropertyView()
Constructs an empty property instance.
Definition: PropertyView.h:655
std::optional< NormalizedType > offset() const noexcept
Definition: PropertyView.h:827
std::optional< NormalizedType > max() const noexcept
Definition: PropertyView.h:837
PropertyViewStatusType status() const noexcept
Definition: PropertyView.h:793
const std::optional< std::string > & name() const noexcept
Definition: PropertyView.h:798
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
Definition: PropertyView.h:671
std::optional< ElementType > noData() const noexcept
Definition: PropertyView.h:852
const std::optional< std::string > & semantic() const noexcept
const std::optional< std::string > & description() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
std::optional< PropertyArrayView< ElementType > > offset() const noexcept
std::optional< PropertyArrayView< ElementType > > max() const noexcept
std::optional< PropertyArrayView< ElementType > > scale() const noexcept
std::optional< PropertyArrayView< ElementType > > min() const noexcept
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< PropertyArrayView< ElementType > > noData() const noexcept
std::optional< PropertyArrayView< ElementType > > defaultValue() const noexcept
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
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &property)
Constructs a property instance from a property table property and its class definition.
std::optional< PropertyArrayView< NormalizedType > > defaultValue() const noexcept
const std::optional< std::string > & semantic() const noexcept
std::optional< PropertyArrayView< NormalizedType > > min() const noexcept
PropertyView(const ClassProperty &classProperty, const PropertyTextureProperty &property)
Constructs a property instance from a property texture property and its class definition.
std::optional< PropertyArrayView< NormalizedType > > max() const noexcept
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.
std::optional< PropertyArrayView< NormalizedType > > scale() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
std::optional< PropertyArrayView< ElementType > > noData() const noexcept
const std::optional< std::string > & description() const noexcept
std::optional< PropertyArrayView< NormalizedType > > offset() const noexcept
const std::optional< std::string > & name() const noexcept
std::optional< PropertyArrayView< bool > > defaultValue() const noexcept
std::optional< PropertyArrayView< bool > > max() const noexcept
const std::optional< std::string > & description() const noexcept
const std::optional< std::string > & semantic() const noexcept
PropertyView()
Constructs an empty property instance.
std::optional< PropertyArrayView< bool > > noData() const noexcept
const std::optional< std::string > & name() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
std::optional< PropertyArrayView< bool > > offset() const noexcept
PropertyViewStatusType status() const noexcept
std::optional< PropertyArrayView< bool > > min() const noexcept
std::optional< PropertyArrayView< bool > > scale() const noexcept
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
const std::optional< std::string > & semantic() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
const std::optional< std::string > & name() const noexcept
const std::optional< std::string > & description() const noexcept
std::optional< PropertyArrayView< std::string_view > > defaultValue() const noexcept
std::optional< PropertyArrayView< std::string_view > > min() const noexcept
std::optional< PropertyArrayView< std::string_view > > noData() const noexcept
std::optional< PropertyArrayView< std::string_view > > offset() const noexcept
std::optional< PropertyArrayView< std::string_view > > max() const noexcept
std::optional< PropertyArrayView< std::string_view > > scale() const noexcept
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
PropertyViewStatusType status() const noexcept
const std::optional< std::string > & semantic() const noexcept
bool required() const noexcept
int64_t arrayCount() const noexcept
std::optional< bool > defaultValue() const noexcept
std::optional< bool > max() const noexcept
const std::optional< std::string > & name() const noexcept
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
std::optional< bool > noData() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
Definition: PropertyView.h:975
const std::optional< std::string > & description() const noexcept
bool normalized() const noexcept
std::optional< bool > offset() const noexcept
PropertyView()
Constructs an empty property instance.
Definition: PropertyView.h:964
std::optional< bool > scale() const noexcept
std::optional< bool > min() const noexcept
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
PropertyView(const ClassProperty &classProperty, const PropertyTableProperty &)
Constructs a property instance from a property table property and its class definition.
const std::optional< std::string > & name() const noexcept
PropertyView()
Constructs an empty property instance.
std::optional< std::string_view > defaultValue() const noexcept
std::optional< std::string_view > noData() const noexcept
std::optional< std::string_view > max() const noexcept
PropertyView(const ClassProperty &classProperty)
Constructs a property instance from a class definition only.
const std::optional< std::string > & semantic() const noexcept
PropertyView(PropertyViewStatusType status)
Constructs an invalid instance for an erroneous property.
std::optional< std::string_view > offset() const noexcept
const std::optional< std::string > & description() const noexcept
PropertyViewStatusType status() const noexcept
std::optional< std::string_view > min() const noexcept
std::optional< std::string_view > scale() const noexcept
Represents a metadata property in EXT_structural_metadata.
Definition: PropertyView.h:251
A generic implementation of a value in a JSON structure.
Definition: JsonValue.h:67
bool getBool() const
Gets the bool from the value.
Definition: JsonValue.h:456
std::vector< JsonValue > Array
The type to represent an Array JSON value.
Definition: JsonValue.h:92
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:358
bool isBool() const noexcept
Returns whether this value is a Bool value.
Definition: JsonValue.h:577
const JsonValue::String & getString() const
Gets the string from the value.
Definition: JsonValue.h:425
bool isArray() const noexcept
Returns whether this value is an Array value.
Definition: JsonValue.h:598
bool isString() const noexcept
Returns whether this value is a String value.
Definition: JsonValue.h:584
const JsonValue::Array & getArray() const
Gets the array from the value.
Definition: JsonValue.h:435
Classes for working with glTF models.
A class property.
Definition: ClassProperty.h:19
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.
Definition: ClassProperty.h:98
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.
Definition: ClassProperty.h:89
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 scalar property type.
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.