1 /******************************************************************************
2 * Copyright (c) 2014, Hobu Inc.
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 #pragma once
36 
37 #include <algorithm>
38 #include <list>
39 #include <vector>
40 
41 #include "pdal/SpatialReference.hpp"
42 #include "pdal/Dimension.hpp"
43 #include "pdal/PointContainer.hpp"
44 #include "pdal/PointLayout.hpp"
45 #include "pdal/Metadata.hpp"
46 
47 namespace pdal
48 {
49 
50 class ArtifactManager;
51 
52 class PDAL_DLL BasePointTable : public PointContainer
53 {
54     FRIEND_TEST(PointTable, srs);
55     friend class PointView;
56 
57 protected:
58     BasePointTable(PointLayout& layout);
59 
60 public:
61     virtual ~BasePointTable();
62 
63     // Layout operations.
layout() const64     virtual PointLayoutPtr layout() const
65         { return &m_layoutRef; }
66 
67     // Metadata operations.
metadata()68     MetadataNode metadata()
69         { return m_metadata->getNode(); }
finalize()70     virtual void finalize()
71         { m_layoutRef.finalize(); }
setSpatialReference(const SpatialReference & srs)72     void setSpatialReference(const SpatialReference& srs)
73     {
74         clearSpatialReferences();
75         addSpatialReference(srs);
76     }
clearSpatialReferences()77     void clearSpatialReferences()
78         { m_spatialRefs.clear(); }
79     void addSpatialReference(const SpatialReference& srs);
spatialReferenceUnique() const80     bool spatialReferenceUnique() const
81         { return m_spatialRefs.size() <= 1; }
spatialReference() const82     SpatialReference spatialReference() const
83     {
84         return spatialReferenceUnique() ? anySpatialReference() :
85             SpatialReference();
86     }
anySpatialReference() const87     SpatialReference anySpatialReference() const
88     {
89         return m_spatialRefs.size() ?
90             *m_spatialRefs.begin() : SpatialReference();
91     }
supportsView() const92     virtual bool supportsView() const
93         { return false; }
94     MetadataNode privateMetadata(const std::string& name);
95     MetadataNode toMetadata() const;
96     ArtifactManager& artifactManager();
97 
98 private:
99     // Point data operations.
100     virtual PointId addPoint() = 0;
101     virtual char *getDimension(const Dimension::Detail *d, PointId idx) = 0;
102 
103 protected:
104     virtual char *getPoint(PointId idx) = 0;
105 
106 protected:
107     MetadataPtr m_metadata;
108     std::list<SpatialReference> m_spatialRefs;
109     PointLayout& m_layoutRef;
110     std::unique_ptr<ArtifactManager> m_artifactManager;
111 };
112 typedef BasePointTable& PointTableRef;
113 typedef BasePointTable const & ConstPointTableRef;
114 
115 class PDAL_DLL SimplePointTable : public BasePointTable
116 {
117 
118 protected:
SimplePointTable(PointLayout & layout)119     SimplePointTable(PointLayout& layout) : BasePointTable(layout)
120         {}
121 
122 protected:
pointsToBytes(point_count_t numPts) const123     std::size_t pointsToBytes(point_count_t numPts) const
124         { return m_layoutRef.pointSize() * numPts; }
125 
126 private:
127     virtual void setFieldInternal(Dimension::Id id, PointId idx,
128         const void *value);
129     virtual void getFieldInternal(Dimension::Id id, PointId idx,
130         void *value) const;
131 
getDimension(const Dimension::Detail * d,PointId idx)132     char *getDimension(const Dimension::Detail *d, PointId idx)
133         { return getPoint(idx) + d->offset(); }
134 
getDimension(const Dimension::Detail * d,PointId idx) const135     const char *getDimension(const Dimension::Detail *d, PointId idx) const
136     {
137         SimplePointTable *ncThis = const_cast<SimplePointTable *>(this);
138         return ncThis->getPoint(idx) + d->offset();
139     }
140 };
141 
142 // This provides a context for processing a set of points and allows the library
143 // to be used to process multiple point sets simultaneously.
144 class PDAL_DLL RowPointTable : public SimplePointTable
145 {
146 private:
147     // Point storage.
148     std::vector<char *> m_blocks;
149     point_count_t m_numPts;
150 
151     // Make sure this is power-of-2 to facilitate fast div and mod ops.
152     static const point_count_t m_blockPtCnt = 65536;
153 
154 public:
RowPointTable()155     RowPointTable() : SimplePointTable(m_layout), m_numPts(0)
156         {}
157     virtual ~RowPointTable();
supportsView() const158     virtual bool supportsView() const
159         { return true; }
160 
161 protected:
162     virtual char *getPoint(PointId idx);
163 
164 private:
165     // Point data operations.
166     virtual PointId addPoint();
167 
168     PointLayout m_layout;
169 };
170 using PointTable = RowPointTable;
171 
172 // This provides a context for processing a set of points and allows the library
173 // to be used to process multiple point sets simultaneously.
174 class PDAL_DLL ColumnPointTable : public SimplePointTable
175 {
176 private:
177     // Point storage.
178     using DimBlockList = std::vector<char *>;
179     using MemBlocks = std::vector<DimBlockList>;
180 
181     // List of dimension memory block lists.
182     MemBlocks m_blocks;
183     point_count_t m_numPts;
184 
185     // Make sure this is power-of-2 to facilitate fast div and mod ops.
186     static const point_count_t m_blockPtCnt = 16384;
187 
188 public:
ColumnPointTable()189     ColumnPointTable() : SimplePointTable(m_layout), m_numPts(0)
190         {}
191     virtual ~ColumnPointTable();
supportsView() const192     virtual bool supportsView() const
193         { return true; }
194     virtual void finalize();
getPoint(PointId idx)195     virtual char *getPoint(PointId idx)
196         { return nullptr; }
197 
198 private:
199     virtual void setFieldInternal(Dimension::Id id, PointId idx,
200         const void *value);
201     virtual void getFieldInternal(Dimension::Id id, PointId idx,
202         void *value) const;
203 
204     virtual PointId addPoint();
205 
206     // Hide base class calls for now.
207     const char *getDimension(const Dimension::Detail *d, PointId idx) const;
208     char *getDimension(const Dimension::Detail *d, PointId idx);
209 
210     PointLayout m_layout;
211 };
212 
213 /// A StreamPointTable must provide storage for point data up to its capacity.
214 /// It must implement getPoint() which returns a pointer to a buffer of
215 /// sufficient size to contain a point's data.  The minimum size required
216 /// is constant and can be determined by calling pointsToBytes(1) in the
217 /// finalize() method.
218 class PDAL_DLL StreamPointTable : public SimplePointTable
219 {
220 protected:
StreamPointTable(PointLayout & layout,point_count_t capacity)221     StreamPointTable(PointLayout& layout, point_count_t capacity)
222         : SimplePointTable(layout)
223         , m_capacity(capacity)
224         , m_numPoints(0)
225         , m_skips(m_capacity, false)
226     {}
227 
228 public:
229     /// Called when a new point should be added.  Probably a no-op for
230     /// streaming.
addPoint()231     virtual PointId addPoint()
232         { return 0; }
233 
234     /// Called when execute() is started.  Typically used to set buffer size
235     /// when all dimensions are known.
finalize()236     virtual void finalize()
237         {}
238 
clear(point_count_t count)239     void clear(point_count_t count)
240     {
241         if (!count)
242             return;
243 
244         m_numPoints = count;
245         reset();
246         std::fill(m_skips.begin(), m_skips.end(), false);
247     }
248 
249     /// Returns true if a point in the table was filtered out and should be
250     /// considered omitted.
skip(PointId n) const251     bool skip(PointId n) const
252         { return m_skips[n]; }
setSkip(PointId n)253     void setSkip(PointId n)
254         { m_skips[n] = true; }
255 
capacity() const256     point_count_t capacity() const
257         { return m_capacity; }
258 
259     /// During a given call to reset(), this indicates the number of points
260     /// populated in the table.  This value will always be less then or equal
261     /// to capacity(), and also includes skipped points.
numPoints() const262     point_count_t numPoints() const
263         { return m_numPoints; }
264 
265 protected:
266     /// Called when the contents of StreamPointTable have been consumed and
267     /// the point data will be potentially overwritten.
reset()268     virtual void reset()
269     {}
270 
271 private:
272     point_count_t m_capacity;
273     point_count_t m_numPoints;
274     std::vector<bool> m_skips;
275 };
276 
277 class PDAL_DLL FixedPointTable : public StreamPointTable
278 {
279 public:
FixedPointTable(point_count_t capacity)280     FixedPointTable(point_count_t capacity)
281         : StreamPointTable(m_layout, capacity)
282     {}
283 
finalize()284     virtual void finalize()
285     {
286         if (!m_layout.finalized())
287         {
288             BasePointTable::finalize();
289             m_buf.resize(pointsToBytes(capacity() + 1));
290         }
291     }
292 
293 protected:
reset()294     virtual void reset()
295         { std::fill(m_buf.begin(), m_buf.end(), 0); }
296 
getPoint(PointId idx)297     virtual char *getPoint(PointId idx)
298         { return m_buf.data() + pointsToBytes(idx); }
299 
300 private:
301     std::vector<char> m_buf;
302     PointLayout m_layout;
303 };
304 
305 } //namespace
306 
307