1 #include "dynamic_depth/point_cloud.h"
2
3 #include "android-base/logging.h"
4 #include "dynamic_depth/const.h"
5 #include "strings/numbers.h"
6 #include "xmpmeta/base64.h"
7 #include "xmpmeta/xml/utils.h"
8
9 using ::dynamic_depth::xmpmeta::EncodeFloatArrayBase64;
10 using ::dynamic_depth::xmpmeta::xml::Deserializer;
11 using ::dynamic_depth::xmpmeta::xml::Serializer;
12
13 namespace dynamic_depth {
14 namespace {
15
16 const char kPropertyPrefix[] = "PointCloud";
17 const char kPointCount[] = "PointCount";
18 const char kPoints[] = "Points";
19 const char kMetric[] = "Metric";
20
21 const char kNamespaceHref[] = "http://ns.google.com/photos/dd/1.0/pointcloud/";
22
23 } // namespace
24
25 // Private constructor.
PointCloud()26 PointCloud::PointCloud() : metric_(false) {}
27
28 // Public methods.
GetNamespaces(std::unordered_map<string,string> * ns_name_href_map)29 void PointCloud::GetNamespaces(
30 std::unordered_map<string, string>* ns_name_href_map) {
31 if (ns_name_href_map == nullptr) {
32 LOG(ERROR) << "Namespace list or own namespace is null";
33 return;
34 }
35 ns_name_href_map->insert(
36 std::pair<string, string>(kPropertyPrefix, kNamespaceHref));
37 }
38
FromData(const std::vector<float> & points,bool metric)39 std::unique_ptr<PointCloud> PointCloud::FromData(
40 const std::vector<float>& points, bool metric) {
41 if (points.empty()) {
42 LOG(ERROR) << "No point data given";
43 return nullptr;
44 }
45
46 if (points.size() % 4 != 0) {
47 LOG(ERROR) << "Points must be (x, y, z, c) tuples, so the size must be "
48 << "divisible by 4, got " << points.size();
49 return nullptr;
50 }
51
52 std::unique_ptr<PointCloud> point_cloud(new PointCloud());
53 point_cloud->points_ = points;
54 point_cloud->metric_ = metric;
55 return point_cloud;
56 }
57
FromDeserializer(const Deserializer & parent_deserializer)58 std::unique_ptr<PointCloud> PointCloud::FromDeserializer(
59 const Deserializer& parent_deserializer) {
60 std::unique_ptr<Deserializer> deserializer =
61 parent_deserializer.CreateDeserializer(
62 DynamicDepthConst::Namespace(kPropertyPrefix), kPropertyPrefix);
63 if (deserializer == nullptr) {
64 return nullptr;
65 }
66
67 std::unique_ptr<PointCloud> point_cloud(new PointCloud());
68 if (!point_cloud->ParseFields(*deserializer)) {
69 return nullptr;
70 }
71 return point_cloud;
72 }
73
GetPointCount() const74 int PointCloud::GetPointCount() const {
75 return static_cast<int>(points_.size() / 4);
76 }
77
GetPoints() const78 const std::vector<float>& PointCloud::GetPoints() const { return points_; }
GetMetric() const79 bool PointCloud::GetMetric() const { return metric_; }
80
Serialize(Serializer * serializer) const81 bool PointCloud::Serialize(Serializer* serializer) const {
82 if (serializer == nullptr) {
83 LOG(ERROR) << "Serializer is null";
84 return false;
85 }
86
87 if (points_.empty()) {
88 LOG(ERROR) << "No points in the PointCloud to serialize";
89 return false;
90 }
91
92 // No error checking (e.g. points_.size() % 4 == 0), because serialization
93 // shouldn't be blocked by this.
94 string base64_encoded_points;
95 if (!EncodeFloatArrayBase64(points_, &base64_encoded_points)) {
96 LOG(ERROR) << "Points encoding failed";
97 return false;
98 }
99
100 // Write required fields.
101 int point_count = static_cast<int>(points_.size() / 4);
102 if (!serializer->WriteProperty(
103 DynamicDepthConst::PointCloud(), kPointCount,
104 ::dynamic_depth::strings::SimpleItoa(point_count))) {
105 return false;
106 }
107
108 if (!serializer->WriteProperty(DynamicDepthConst::PointCloud(), kPoints,
109 base64_encoded_points)) {
110 return false;
111 }
112
113 // Write optional fields.
114 serializer->WriteBoolProperty(DynamicDepthConst::PointCloud(), kMetric,
115 metric_);
116 return true;
117 }
118
119 // Private methods.
ParseFields(const Deserializer & deserializer)120 bool PointCloud::ParseFields(const Deserializer& deserializer) {
121 // Required fields.
122 std::vector<float> points;
123 if (!deserializer.ParseFloatArrayBase64(DynamicDepthConst::PointCloud(),
124 kPoints, &points)) {
125 return false;
126 }
127
128 int point_count;
129 if (!deserializer.ParseInt(DynamicDepthConst::PointCloud(), kPointCount,
130 &point_count)) {
131 return false;
132 }
133
134 if (points.size() % 4 != 0) {
135 LOG(ERROR) << "Parsed " << points.size() << " values but expected the size "
136 << "to be divisible by 4 for (x, y, z, c) tuple representation";
137 return false;
138 }
139
140 int parsed_points_count = static_cast<int>(points.size() / 4);
141 if (parsed_points_count != point_count) {
142 LOG(ERROR) << "Parsed PointCount = " << point_count << " but "
143 << parsed_points_count << " points were found";
144 return false;
145 }
146
147 // We know that point_count == points.size() now.
148 points_ = points;
149
150 // Optional fields.
151 bool metric;
152 if (!deserializer.ParseBoolean(DynamicDepthConst::PointCloud(), kMetric,
153 &metric)) {
154 // Set it to the default value.
155 metric_ = false;
156 } else {
157 metric_ = metric;
158 }
159
160 return true;
161 }
162
163 } // namespace dynamic_depth
164