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 <pdal/DimDetail.hpp>
38 #include <pdal/DimType.hpp>
39 #include <pdal/Mesh.hpp>
40 #include <pdal/PointContainer.hpp>
41 #include <pdal/PointLayout.hpp>
42 #include <pdal/PointTable.hpp>
43 #include <pdal/PointRef.hpp>
44
45 #include <memory>
46 #include <queue>
47 #include <set>
48 #include <deque>
49
50 //#pragma warning(disable: 4244) // conversion from 'type1' to 'type2', possible loss of data
51
52 namespace pdal
53 {
54 namespace plang
55 {
56 class Invocation;
57 }
58
59 struct PointViewLess;
60 class PointView;
61 class PointViewIter;
62 class KD2Index;
63 class KD3Index;
64 class BOX2D;
65 class BOX3D;
66
67 struct RasterLimits;
68 template <class T> class Raster;
69 using Rasterd = Raster<double>;
70
71 typedef std::shared_ptr<PointView> PointViewPtr;
72 typedef std::set<PointViewPtr, PointViewLess> PointViewSet;
73
74 class PDAL_DLL PointView : public PointContainer
75 {
76 FRIEND_TEST(VoxelTest, center);
77 friend class Stage;
78 friend class plang::Invocation;
79 friend class PointIdxRef;
80 friend struct PointViewLess;
81 public:
82 PointView(const PointView&) = delete;
83 PointView& operator=(const PointView&) = delete;
84 PointView(PointTableRef pointTable);
85 PointView(PointTableRef pointTable, const SpatialReference& srs);
86 virtual ~PointView();
87
88 PointViewIter begin();
89 PointViewIter end();
90
id() const91 int id() const
92 { return m_id; }
93
size() const94 point_count_t size() const
95 { return m_size; }
96
empty() const97 bool empty() const
98 { return m_size == 0; }
99
100 inline void appendPoint(const PointView& buffer, PointId id);
append(const PointView & buf)101 void append(const PointView& buf)
102 {
103 // We use size() instead of the index end because temp points
104 // might have been placed at the end of the buffer.
105 // We're essentially ditching temp points.
106 auto thisEnd = m_index.begin() + size();
107 auto bufEnd = buf.m_index.begin() + buf.size();
108 m_index.insert(thisEnd, buf.m_index.begin(), bufEnd);
109 m_size += buf.size();
110 clearTemps();
111 }
112
113 /// Return a new point view with the same point table as this
114 /// point buffer.
makeNew() const115 PointViewPtr makeNew() const
116 {
117 return PointViewPtr(new PointView(m_pointTable, m_spatialReference));
118 }
119
point(PointId id)120 PointRef point(PointId id)
121 { return PointRef(*this, id); }
122
123 template<class T>
124 T getFieldAs(Dimension::Id dim, PointId pointIndex) const;
125
126 inline void getField(char *pos, Dimension::Id d,
127 Dimension::Type type, PointId id) const;
128
129 template<typename T>
130 void setField(Dimension::Id dim, PointId idx, T val);
131
132 inline void setField(Dimension::Id dim, Dimension::Type type,
133 PointId idx, const void *val);
134
135 template <typename T>
compare(Dimension::Id dim,PointId id1,PointId id2) const136 bool compare(Dimension::Id dim, PointId id1, PointId id2) const
137 {
138 return (getFieldInternal<T>(dim, id1) < getFieldInternal<T>(dim, id2));
139 }
140
compare(Dimension::Id dim,PointId id1,PointId id2) const141 virtual bool compare(Dimension::Id dim, PointId id1, PointId id2) const
142 {
143 const Dimension::Detail *dd = layout()->dimDetail(dim);
144
145 switch (dd->type())
146 {
147 case Dimension::Type::Float:
148 return compare<float>(dim, id1, id2);
149 break;
150 case Dimension::Type::Double:
151 return compare<double>(dim, id1, id2);
152 break;
153 case Dimension::Type::Signed8:
154 return compare<int8_t>(dim, id1, id2);
155 break;
156 case Dimension::Type::Signed16:
157 return compare<int16_t>(dim, id1, id2);
158 break;
159 case Dimension::Type::Signed32:
160 return compare<int32_t>(dim, id1, id2);
161 break;
162 case Dimension::Type::Signed64:
163 return compare<int64_t>(dim, id1, id2);
164 break;
165 case Dimension::Type::Unsigned8:
166 return compare<uint8_t>(dim, id1, id2);
167 break;
168 case Dimension::Type::Unsigned16:
169 return compare<uint16_t>(dim, id1, id2);
170 break;
171 case Dimension::Type::Unsigned32:
172 return compare<uint32_t>(dim, id1, id2);
173 break;
174 case Dimension::Type::Unsigned64:
175 return compare<uint64_t>(dim, id1, id2);
176 break;
177 case Dimension::Type::None:
178 default:
179 return false;
180 break;
181 }
182 }
183
184 /*! @return a cumulated bounds of all points in the PointView.
185 \verbatim embed:rst
186 .. note::
187
188 This method requires that an `X`, `Y`, and `Z` dimension be
189 available, and that it can be casted into a *double* data
190 type using the :cpp:func:`pdal::Dimension::applyScaling`
191 method. Otherwise, an exception will be thrown.
192 \endverbatim
193 */
194 void calculateBounds(BOX2D& box) const;
195 void calculateBounds(BOX3D& box) const;
196
197 void dump(std::ostream& ostr) const;
hasDim(Dimension::Id id) const198 bool hasDim(Dimension::Id id) const
199 { return layout()->hasDim(id); }
dimName(Dimension::Id id) const200 std::string dimName(Dimension::Id id) const
201 { return layout()->dimName(id); }
dims() const202 Dimension::IdList dims() const
203 { return layout()->dims(); }
pointSize() const204 std::size_t pointSize() const
205 { return layout()->pointSize(); }
dimSize(Dimension::Id id) const206 std::size_t dimSize(Dimension::Id id) const
207 { return layout()->dimSize(id); }
dimType(Dimension::Id id) const208 Dimension::Type dimType(Dimension::Id id) const
209 { return layout()->dimType(id);}
dimTypes() const210 DimTypeList dimTypes() const
211 { return layout()->dimTypes(); }
layout() const212 PointLayoutPtr layout() const
213 { return m_layout; }
table() const214 inline PointTableRef table() const
215 { return m_pointTable;}
spatialReference() const216 SpatialReference spatialReference() const
217 { return m_spatialReference; }
218
219 /// Fill a buffer with point data specified by the dimension list.
220 /// \param[in] dims List of dimensions/types to retrieve.
221 /// \param[in] idx Index of point to get.
222 /// \param[in] buf Pointer to buffer to fill.
getPackedPoint(const DimTypeList & dims,PointId idx,char * buf) const223 void getPackedPoint(const DimTypeList& dims, PointId idx, char *buf) const
224 {
225 for (auto di = dims.begin(); di != dims.end(); ++di)
226 {
227 getField(buf, di->m_id, di->m_type, idx);
228 buf += Dimension::size(di->m_type);
229 }
230 }
231
232 /// Load the point buffer from memory whose arrangement is specified
233 /// by the dimension list.
234 /// \param[in] dims Dimension/types of data in packed order
235 /// \param[in] idx Index of point to write.
236 /// \param[in] buf Packed data buffer.
setPackedPoint(const DimTypeList & dims,PointId idx,const char * buf)237 void setPackedPoint(const DimTypeList& dims, PointId idx, const char *buf)
238 {
239 for (auto di = dims.begin(); di != dims.end(); ++di)
240 {
241 setField(di->m_id, di->m_type, idx, (const void *)buf);
242 buf += Dimension::size(di->m_type);
243 }
244 }
245
246 /// Provides access to the memory storing the point data. Though this
247 /// function is public, other access methods are safer and preferred.
getPoint(PointId id)248 char *getPoint(PointId id)
249 { return m_pointTable.getPoint(m_index[id]); }
250
251 /// Provides access to the memory storing the point data. Though this
252 /// function is public, other access methods are safer and preferred.
getOrAddPoint(PointId id)253 char *getOrAddPoint(PointId id)
254 {
255 if (id == size())
256 {
257 m_index.push_back(m_pointTable.addPoint());
258 ++m_size;
259 assert(m_temps.empty());
260 }
261
262 return m_pointTable.getPoint(m_index.at(id));
263 }
264
265 // The standard idiom is swapping with a stack-created empty queue, but
266 // that invokes the ctor and probably allocates. We've probably only got
267 // one or two things in our queue, so just pop until we're empty.
clearTemps()268 void clearTemps()
269 {
270 while (!m_temps.empty())
271 m_temps.pop();
272 }
273 MetadataNode toMetadata() const;
274
275 void invalidateProducts();
276
277 /**
278 Creates a mesh with the specified name.
279
280 \param name Name of the mesh.
281 \return Pointer to the new mesh. Null is returned if the mesh
282 already exists.
283 */
284 TriangularMesh *createMesh(const std::string& name);
285
286 /**
287 Get a pointer to a mesh.
288
289 \param name Name of the mesh.
290 \return New mesh. Null is returned if the mesh already exists.
291 */
292 TriangularMesh *mesh(const std::string& name = "");
293
294 /**
295 Creates a raster with the specified name.
296
297 \param name Name of the raster.
298 \param limits Limits of the raster to create.
299 \return Pointer to the new raster. Null is returned if the raster already exists.
300 */
301 Rasterd *createRaster(const std::string& name, const RasterLimits& limits,
302 double noData = 0);
303
304 /**
305 Get a pointer to a raster.
306
307 \param name Name of the raster.
308 \return Pointer to the New raster. Null
309 */
310 Rasterd *raster(const std::string& name = "");
311
312 KD3Index& build3dIndex();
313 KD2Index& build2dIndex();
314
315 protected:
316 PointTableRef m_pointTable;
317 PointLayoutPtr m_layout;
318 std::deque<PointId> m_index;
319 // The index might be larger than the size to support temporary point
320 // references.
321 point_count_t m_size;
322 int m_id;
323 std::queue<PointId> m_temps;
324 SpatialReference m_spatialReference;
325 std::map<std::string, std::unique_ptr<TriangularMesh>> m_meshes;
326 std::map<std::string, std::unique_ptr<Rasterd>> m_rasters;
327 std::unique_ptr<KD3Index> m_index3;
328 std::unique_ptr<KD2Index> m_index2;
329
330 private:
331 static int m_lastId;
332
333 PointId tableId(PointId idx);
334
335 virtual void setFieldInternal(Dimension::Id dim, PointId idx,
336 const void *buf);
getFieldInternal(Dimension::Id dim,PointId idx,void * buf) const337 virtual void getFieldInternal(Dimension::Id dim, PointId idx,
338 void *buf) const
339 { m_pointTable.getFieldInternal(dim, m_index[idx], buf); }
swapItems(PointId id1,PointId id2)340 virtual void swapItems(PointId id1, PointId id2)
341 {
342 PointId temp = m_index[id2];
343 m_index[id2] = m_index[id1];
344 m_index[id1] = temp;
345 }
setItem(PointId dst,PointId src)346 virtual void setItem(PointId dst, PointId src)
347 {
348 m_index[dst] = m_index[src];
349 }
350
351 template<class T>
352 T getFieldInternal(Dimension::Id dim, PointId pointIndex) const;
353 inline PointId getTemp(PointId id);
freeTemp(PointId id)354 void freeTemp(PointId id)
355 { m_temps.push(id); }
setSpatialReference(const SpatialReference & spatialRef)356 void setSpatialReference(const SpatialReference& spatialRef)
357 { m_spatialReference = spatialRef; }
358
359 // For testing only.
index(PointId id) const360 PointId index(PointId id) const
361 { return m_index[id]; }
362 };
363
364 struct PointViewLess
365 {
operator ()pdal::PointViewLess366 bool operator () (const PointViewPtr& p1, const PointViewPtr& p2) const
367 { return p1->m_id < p2->m_id; }
368 };
369
370 template <class T>
getFieldInternal(Dimension::Id dim,PointId id) const371 T PointView::getFieldInternal(Dimension::Id dim, PointId id) const
372 {
373 T t;
374
375 getFieldInternal(dim, id, &t);
376 return t;
377 }
378
getField(char * pos,Dimension::Id d,Dimension::Type type,PointId id) const379 inline void PointView::getField(char *pos, Dimension::Id d,
380 Dimension::Type type, PointId id) const
381 {
382 Everything e;
383
384 switch (type)
385 {
386 case Dimension::Type::Float:
387 e.f = getFieldAs<float>(d, id);
388 break;
389 case Dimension::Type::Double:
390 e.d = getFieldAs<double>(d, id);
391 break;
392 case Dimension::Type::Signed8:
393 e.s8 = getFieldAs<int8_t>(d, id);
394 break;
395 case Dimension::Type::Signed16:
396 e.s16 = getFieldAs<int16_t>(d, id);
397 break;
398 case Dimension::Type::Signed32:
399 e.s32 = getFieldAs<int32_t>(d, id);
400 break;
401 case Dimension::Type::Signed64:
402 e.s64 = getFieldAs<int64_t>(d, id);
403 break;
404 case Dimension::Type::Unsigned8:
405 e.u8 = getFieldAs<uint8_t>(d, id);
406 break;
407 case Dimension::Type::Unsigned16:
408 e.u16 = getFieldAs<uint16_t>(d, id);
409 break;
410 case Dimension::Type::Unsigned32:
411 e.u32 = getFieldAs<uint32_t>(d, id);
412 break;
413 case Dimension::Type::Unsigned64:
414 e.u64 = getFieldAs<uint64_t>(d, id);
415 break;
416 case Dimension::Type::None:
417 break;
418 }
419 memcpy(pos, &e, Dimension::size(type));
420 }
421
setField(Dimension::Id dim,Dimension::Type type,PointId idx,const void * val)422 inline void PointView::setField(Dimension::Id dim,
423 Dimension::Type type, PointId idx, const void *val)
424 {
425 Everything e;
426
427 memcpy(&e, val, Dimension::size(type));
428 switch (type)
429 {
430 case Dimension::Type::Float:
431 setField(dim, idx, e.f);
432 break;
433 case Dimension::Type::Double:
434 setField(dim, idx, e.d);
435 break;
436 case Dimension::Type::Signed8:
437 setField(dim, idx, e.s8);
438 break;
439 case Dimension::Type::Signed16:
440 setField(dim, idx, e.s16);
441 break;
442 case Dimension::Type::Signed32:
443 setField(dim, idx, e.s32);
444 break;
445 case Dimension::Type::Signed64:
446 setField(dim, idx, e.s64);
447 break;
448 case Dimension::Type::Unsigned8:
449 setField(dim, idx, e.u8);
450 break;
451 case Dimension::Type::Unsigned16:
452 setField(dim, idx, e.u16);
453 break;
454 case Dimension::Type::Unsigned32:
455 setField(dim, idx, e.u32);
456 break;
457 case Dimension::Type::Unsigned64:
458 setField(dim, idx, e.u64);
459 break;
460 case Dimension::Type::None:
461 break;
462 }
463 }
464
465 template <class T>
getFieldAs(Dimension::Id dim,PointId pointIndex) const466 inline T PointView::getFieldAs(Dimension::Id dim,
467 PointId pointIndex) const
468 {
469 assert(pointIndex < m_size);
470 T retval;
471 bool ok = false;
472 const Dimension::Detail *dd = m_layout->dimDetail(dim);
473 Everything e;
474
475 PointId rawIdx = m_index[pointIndex];
476 // Note that getFieldInternal() can't be hoisted out of the switch
477 // because we don't want to call it in the case where the dimension
478 // type isn't known. A separate test could be made, but that *might*
479 // cost and this is an important code path.
480 switch (dd->type())
481 {
482 case Dimension::Type::Float:
483 m_pointTable.getFieldInternal(dim, rawIdx, &e);
484 ok = Utils::numericCast(e.f, retval);
485 break;
486 case Dimension::Type::Double:
487 m_pointTable.getFieldInternal(dim, rawIdx, &e);
488 ok = Utils::numericCast(e.d, retval);
489 break;
490 case Dimension::Type::Signed8:
491 m_pointTable.getFieldInternal(dim, rawIdx, &e);
492 ok = Utils::numericCast(e.s8, retval);
493 break;
494 case Dimension::Type::Signed16:
495 m_pointTable.getFieldInternal(dim, rawIdx, &e);
496 ok = Utils::numericCast(e.s16, retval);
497 break;
498 case Dimension::Type::Signed32:
499 m_pointTable.getFieldInternal(dim, rawIdx, &e);
500 ok = Utils::numericCast(e.s32, retval);
501 break;
502 case Dimension::Type::Signed64:
503 m_pointTable.getFieldInternal(dim, rawIdx, &e);
504 ok = Utils::numericCast(e.s64, retval);
505 break;
506 case Dimension::Type::Unsigned8:
507 m_pointTable.getFieldInternal(dim, rawIdx, &e);
508 ok = Utils::numericCast(e.u8, retval);
509 break;
510 case Dimension::Type::Unsigned16:
511 m_pointTable.getFieldInternal(dim, rawIdx, &e);
512 ok = Utils::numericCast(e.u16, retval);
513 break;
514 case Dimension::Type::Unsigned32:
515 m_pointTable.getFieldInternal(dim, rawIdx, &e);
516 ok = Utils::numericCast(e.u32, retval);
517 break;
518 case Dimension::Type::Unsigned64:
519 m_pointTable.getFieldInternal(dim, rawIdx, &e);
520 ok = Utils::numericCast(e.u64, retval);
521 break;
522 case Dimension::Type::None:
523 default:
524 ok = true;
525 retval = 0;
526 break;
527 } // switch
528
529 if (!ok)
530 {
531 std::ostringstream oss;
532 oss << "Unable to fetch data and convert as requested: ";
533 oss << Dimension::name(dim) << ":" <<
534 Dimension::interpretationName(dd->type()) <<
535 "(" << Utils::toDouble(e, dd->type()) << ") -> " <<
536 Utils::typeidName<T>();
537 throw pdal_error(oss.str());
538 }
539
540 return retval;
541 }
542
543
544 template<typename T>
setField(Dimension::Id dim,PointId idx,T val)545 void PointView::setField(Dimension::Id dim, PointId idx, T val)
546 {
547 const Dimension::Detail *dd = layout()->dimDetail(dim);
548
549 Everything e;
550 bool ok = true;
551 switch (dd->type())
552 {
553 case Dimension::Type::Float:
554 ok = Utils::numericCast(val, e.f);
555 break;
556 case Dimension::Type::Double:
557 ok = Utils::numericCast(val, e.d);
558 break;
559 case Dimension::Type::Signed8:
560 ok = Utils::numericCast(val, e.s8);
561 break;
562 case Dimension::Type::Signed16:
563 ok = Utils::numericCast(val, e.s16);
564 break;
565 case Dimension::Type::Signed32:
566 ok = Utils::numericCast(val, e.s32);
567 break;
568 case Dimension::Type::Signed64:
569 ok = Utils::numericCast(val, e.s64);
570 break;
571 case Dimension::Type::Unsigned8:
572 ok = Utils::numericCast(val, e.u8);
573 break;
574 case Dimension::Type::Unsigned16:
575 ok = Utils::numericCast(val, e.u16);
576 break;
577 case Dimension::Type::Unsigned32:
578 ok = Utils::numericCast(val, e.u32);
579 break;
580 case Dimension::Type::Unsigned64:
581 ok = Utils::numericCast(val, e.u64);
582 break;
583 case Dimension::Type::None:
584 return;
585 }
586 if (ok)
587 m_pointTable.setFieldInternal(dim, tableId(idx), &e);
588 else
589 {
590 std::ostringstream oss;
591 oss << "Unable to set data and convert as requested: ";
592 oss << Dimension::name(dim) << ":" << Utils::typeidName<T>() <<
593 "(" << (double)val << ") -> " <<
594 Dimension::interpretationName(dd->type());
595 throw pdal_error(oss.str());
596 }
597 }
598
appendPoint(const PointView & buffer,PointId id)599 inline void PointView::appendPoint(const PointView& buffer, PointId id)
600 {
601 // Invalid 'id' is a programmer error.
602 PointId rawId = buffer.m_index[id];
603 m_index.push_back(rawId);
604 m_size++;
605 assert(m_temps.empty());
606 }
607
608
609 // Make a temporary copy of a point by adding an entry to the index.
getTemp(PointId id)610 inline PointId PointView::getTemp(PointId id)
611 {
612 PointId newid;
613 if (m_temps.size())
614 {
615 newid = m_temps.front();
616 m_temps.pop();
617 m_index[newid] = m_index[id];
618 }
619 else
620 {
621 newid = (PointId)m_index.size();
622 m_index.push_back(m_index[id]);
623 }
624 return newid;
625 }
626
627 PDAL_DLL std::ostream& operator<<(std::ostream& ostr, const PointView&);
628
629 // PointViewIter
630
631 class PointViewIter
632 {
633 private:
634 PointView *m_view;
635 PointId m_id;
636
637 public:
638 using iterator_category = std::random_access_iterator_tag;
639 using value_type = PointRef;
640 using difference_type = ptrdiff_t;
641 using pointer = PointRef*;
642 using reference = PointRef;
643
PointViewIter()644 PointViewIter()
645 {}
PointViewIter(PointView * view,PointId id)646 PointViewIter(PointView* view, PointId id) : m_view(view), m_id(id)
647 {}
648
operator ++()649 PointViewIter& operator++()
650 { m_id++; return *this; }
operator ++(int)651 PointViewIter operator++(int)
652 { return PointViewIter(m_view, m_id++); }
operator --()653 PointViewIter& operator--()
654 { --m_id; return *this; }
operator --(int)655 PointViewIter operator--(int)
656 { return PointViewIter(m_view, m_id--); }
657
operator +(const difference_type & n) const658 PointViewIter operator+(const difference_type& n) const
659 { return PointViewIter(m_view, m_id + n); }
operator +=(const difference_type & n)660 PointViewIter operator+=(const difference_type& n)
661 { m_id += n; return *this; }
operator -(const difference_type & n) const662 PointViewIter operator-(const difference_type& n) const
663 { return PointViewIter(m_view, m_id - n); }
operator -=(const difference_type & n)664 PointViewIter operator-=(const difference_type& n)
665 { m_id -= n; return *this; }
operator -(const PointViewIter & i) const666 difference_type operator-(const PointViewIter& i) const
667 { return static_cast<difference_type>(m_id - i.m_id); }
668
operator ==(const PointViewIter & i) const669 bool operator==(const PointViewIter& i) const
670 { return m_id == i.m_id; }
operator !=(const PointViewIter & i) const671 bool operator!=(const PointViewIter& i) const
672 { return m_id != i.m_id; }
operator <(const PointViewIter & i) const673 bool operator<(const PointViewIter& i) const
674 { return m_id < i.m_id; }
operator <=(const PointViewIter & i) const675 bool operator<=(const PointViewIter& i) const
676 { return m_id <= i.m_id; }
operator >(const PointViewIter & i) const677 bool operator>(const PointViewIter& i) const
678 { return m_id > i.m_id; }
operator >=(const PointViewIter & i) const679 bool operator>=(const PointViewIter& i) const
680 { return m_id >= i.m_id; }
681
operator *() const682 reference operator*() const
683 { return PointRef(*m_view, m_id); }
operator ->()684 pointer operator->()
685 { return nullptr; }
operator [](const difference_type & n) const686 reference operator[](const difference_type& n) const
687 { return PointRef(*m_view, m_id + n); }
688 };
689
690 } // namespace pdal
691