• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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