1 ///
2 /// Copyright (c) 2012, Texas A&M University
3 /// All rights reserved.
4 ///
5 /// Redistribution and use in source and binary forms, with or without
6 /// modification, are permitted provided that the following conditions
7 /// are met:
8 ///
9 ///  * Redistributions of source code must retain the above copyright
10 ///    notice, this list of conditions and the following disclaimer.
11 ///  * Redistributions in binary form must reproduce the above
12 ///    copyright notice, this list of conditions and the following
13 ///    disclaimer in the documentation and/or other materials provided
14 ///    with the distribution.
15 ///  * Neither the name of Texas A&M University nor the names of its
16 ///    contributors may be used to endorse or promote products derived
17 ///    from this software without specific prior written permission.
18 ///
19 /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 /// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 /// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 /// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 /// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 /// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 /// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 /// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 /// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 /// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 /// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 /// POSSIBILITY OF SUCH DAMAGE.
31 ///
32 /// The following software was written as part of a collaboration with the
33 /// University of South Carolina, Interdisciplinary Mathematics Institute.
34 ///
35 /// @file   cloud.h
36 /// @details The declaration of the class representing the cloud data structure.
37 /// A cloud represents a single 3D set of points and associated attributes.
38 /// This class allows for the basic manipulation of the cloud as well as its
39 /// display.
40 /// @author  Yue Li and Matthew Hielsberg
41 
42 #pragma once
43 
44 #include <QtGui/QColor>
45 #include <pcl/apps/point_cloud_editor/localTypes.h>
46 #include <pcl/apps/point_cloud_editor/statistics.h>
47 
48 #include <pcl/memory.h>  // for pcl::weak_ptr
49 
50 #ifdef OPENGL_IS_A_FRAMEWORK
51 # include <OpenGL/gl.h>
52 # include <OpenGL/glu.h>
53 #else
54 #ifdef _WIN32
55 // Need this to pull in APIENTRY, etc.
56 #include "windows.h"
57 #endif
58 # include <GL/gl.h>
59 # include <GL/glu.h>
60 #endif
61 
62 /// @brief A wrapper which allows to use any implementation of cloud provided by
63 /// a third-party library.
64 /// @details This wrapper attempts to create a simple interface for displaying
65 /// and modifying point clouds.  It is common for point clouds to have
66 /// coordinate values that are exceptionally large, especially when dealing
67 /// with the GIS community.  As such this class shifts the stored point cloud
68 /// according to the minimum in each of the coordinate directions.  The
69 /// interface presented by this class then serves the shifted points in order to
70 /// reduce any precision errors that may occur due to sums of large values.
71 /// Functions also exist for accessing the unshifted versions of the points,
72 /// however most operations performed on the cloud will expect it to live near
73 /// the origin.
74 // XXX - handle shifting upon setting of a Cloud3D
75 // XXX - add functions for retrieving an unshifted Cloud3D
76 // XXX - add functions for retrieving unshifted points by index
77 // XXX - mark access functions below as returning shifted values
78 class Cloud : public Statistics
79 {
80   public:
81     /// The type for shared pointer pointing to a selection buffer
82     using SelectionPtr = pcl::shared_ptr<Selection>;
83 
84     /// The type for weak pointer pointing to a selection buffer
85     using SelectionWeakPtr = pcl::weak_ptr<Selection>;
86 
87     /// @brief Default Constructor
88     Cloud ();
89 
90     /// @brief Copy Constructor
91     /// @details This constructor creates a copy of the passed cloud. The
92     /// values of the member variables of the passed cloud are deep copied.
93     /// @param copy The cloud object to be used to initialize this cloud object.
94     Cloud (const Cloud& copy);
95 
96     /// @brief Construct a cloud from a Cloud3D.
97     /// @details This constructor creates a cloud object with the passed
98     /// cloud object stored with the internal representation. The member
99     /// variables of this object are initialized but not set.
100     Cloud (const Cloud3D& cloud, bool register_stats=false);
101 
102     /// @brief Equal Operator
103     /// @details Deep copies all the state of the passed cloud to this cloud.
104     /// @param cloud The cloud object whose status to be copied to this object
105     /// @return A reference to this cloud containing the new values.
106     Cloud&
107     operator= (const Cloud& cloud);
108 
109     /// @brief Subscript Operator
110     /// @details This operator returns a reference to the point with the
111     /// passed index in this cloud object.
112     /// @pre The index passed is expected to be within the limits of the cloud.
113     /// For debugging this is currently checked by an assert.
114     /// @param index The index of the point to be returned.
115     /// @return A reference to the indexed point.
116     Point3D&
117     operator[] (unsigned int index);
118 
119     /// @brief Subscript Operator
120     /// @details This operator returns a const reference to the point with the
121     /// passed index in this cloud object.
122     /// @pre The index passed is expected to be within the limits of the cloud.
123     /// For debugging this is currently checked by an assert.
124     /// @param index The index of the point to be returned.
125     /// @return A const reference to the indexed point.
126     const Point3D&
127     operator[] (unsigned int index) const;
128 
129     /// @brief Returns the center of the point cloud
130     /// @param x The x coordinate of the center (computed as the average point).
131     /// @param y The y coordinate of the center (computed as the average point).
132     /// @param z The z coordinate of the center (computed as the average point).
133     inline
134     void
getCenter(float & x,float & y,float & z)135     getCenter (float &x, float &y, float &z) const
136     {
137       x = center_xyz_[X]; y = center_xyz_[Y]; z = center_xyz_[Z];
138     }
139 
140     /// @brief Returns the scaling factor for the point cloud
141     /// @return The scaling factor
142     inline
143     float
getScalingFactor()144     getScalingFactor() const
145     {
146       return (display_scale_);
147     }
148 
149     /// @brief Gets the transform matrix.
150     /// @details The returned matrix is used to transform the cloud for
151     /// rendering only and does not affect the values of the points stored.
152     /// @return A 1-D array representing (4 x 4) matrix in
153     /// using OpenGL's column-major format.
154     inline
155     const float*
getMatrix()156     getMatrix () const
157     {
158       return (cloud_matrix_);
159     }
160 
161     /// @brief Sets the transform matrix for the cloud.
162     /// @details The passed matrix is used to transform the cloud for
163     /// rendering only and does not affect the values of the points stored.
164     /// @pre The passed pointer represents a matrix having valid memory of at
165     /// least MATRIX_SIZE elements.
166     /// @param matrix a 1-D array representing (4 x 4) matrix in
167     /// using OpenGL's column-major format.
168     void
169     loadMatrix (const float* matrix);
170 
171     /// @brief Right multiplies the cloud matrix with the passed matrix
172     /// @details The application of this matrix effectively transforms the
173     /// cloud from its current state.  The passed matrix is used for display
174     /// only and does not affect the values of the points stored.
175     /// @pre The passed pointer represents a matrix having valid memory of at
176     /// least MATRIX_SIZE elements.
177     /// @param matrix a 1-D array representing (4 x 4) matrix in
178     /// using OpenGL's column-major format.
179     void
180     multMatrix (const float* matrix);
181 
182     /// @brief Sets the selection transform matrix to the one passed.
183     /// @details The selection matrix represents the local transformations
184     /// applied to the selected points. The matrix is used relative to the
185     /// cloud's state after the application of its own matrices  which can be
186     /// modified by loadMatrix and multMatrix functions.
187     /// @pre The passed pointer represents a matrix having valid memory of at
188     /// least MATRIX_SIZE elements.
189     /// @param matrix a 1-D array representing (4 x 4) matrix in
190     /// using OpenGL's column-major format.
191     /// @sa loadMatrix multMatrix
192     void
193     setSelectionRotation (const float* matrix);
194 
195     void
196     setSelectionTranslation (float dx, float dy, float dz);
197 
198     /// @brief Sets the selected points.
199     /// @details The cloud object is responsible for its display. As we have
200     /// tried to adopt a lazy approach in the application of modifications to
201     /// the cloud, the cloud must be notified of the selected points.  This is
202     /// required as the user may move the selected points and we do not wish for
203     /// the selected points to be drawn twice, once in the user-updated position
204     /// and another in the points original location.
205     /// @pre Assumes that the selection stores the selected indices of the
206     /// points sorted.
207     /// @param A pointer pointing to a selection object.
208     /// @remarks This has been implemented using a weak pointer to allow a lazy
209     /// update to occur.  When a selection is destroyed we can switch to
210     /// a faster rendering mode; this also occurs if the selection object is
211     /// empty.
212     void
213     setSelection (const SelectionPtr& selection_ptr);
214 
215     /// @brief Sets the RGB values for coloring points in COLOR_BY_PURE mode.
216     /// @param r the value for red color
217     /// @param g the value for the green color
218     /// @param b the value for the blue color
219     void
220     setRGB (float r, float g, float b);
221 
222     /// @brief Sets the RGB values used for highlighting the selected points.
223     /// @param r the value for red color
224     /// @param g the value for the green color
225     /// @param b the value for the blue color
226     void
227     setHighlightColor (float r, float g, float b);
228 
229     /// @brief Renders the cloud and highlights any selected points.
230     /// @param disableHighlight Defaults to false.  If true the selected points
231     /// will not be drawn.
232     /// @sa setColorRampAxis, setColorRamp
233     void
234     draw (bool disable_highlight = false) const;
235 
236     /// @brief Renders the cloud and highlights any selected points.
237     /// @details The colors of the non-selected points come from a 1D texture
238     /// which is implemented by a color ramp.
239     void
240     drawWithTexture () const;
241 
242     /// @brief Renders the cloud and highlights any selected points.
243     /// @details The colors of the non-selected points uses the native color
244     /// of the original points
245     /// @pre The cloud should be originally colored.
246     void
247     drawWithRGB () const;
248 
249     /// @brief Renders the cloud and highlights any selected points.
250     /// @details The non-selected points are in a single color
251     void
252     drawWithPureColor () const;
253 
254     /// @brief Renders the cloud with the color used for highlighting the
255     /// selected points.
256     void
257     drawWithHighlightColor () const;
258 
259     /// @brief Sets the axis along which the displayed points should have the
260     /// color ramp applied.
261     /// @param a The axis id describing which direction the ramp should be
262     /// applied.
263     inline
264     void
setColorRampAxis(Axis a)265     setColorRampAxis(Axis a)
266     {
267       color_ramp_axis_ = a;
268     }
269 
270     /// @brief Enables/Disables the use of the color ramp in display.
271     /// @details The color ramp aids in the visualization of the displayed
272     /// points by varying the color according to a linear ramp along one of the
273     /// axes.
274     /// @param onOff True enables the use of the color ramp and false disables.
275     inline
276     void
setColorRamp(bool on_off)277     setColorRamp(bool on_off)
278     {
279       use_color_ramp_ = on_off;
280     }
281 
282     /// @brief Appends a new 3D point to the cloud.
283     /// @param point the new point to be added.
284     void
285     append (const Point3D& point);
286 
287     /// @brief Appends the points of the passed cloud to this cloud.
288     /// @param cloud the cloud to be appended to this cloud.
289     void
290     append (const Cloud& cloud);
291 
292     /// @brief Removes the points in selection from the cloud.
293     /// @details Each indexed point in the selection will be removed from this
294     /// container.
295     /// @pre The index of each point in the selection is expected to be within
296     /// the limits of the cloud.  For debugging this is currently checked by an
297     /// assert.  Also, it is expected that the selection indices are sorted.
298     /// @param selection a selection object which stores the indices of the
299     /// selected points.
300     /// @remarks This function requires the use of Selection::isSelected and its
301     /// complexity can vary based on the implementation of that function.
302     void
303     remove (const Selection& selection);
304 
305     /// @brief Gets the size of the cloud
306     inline
307     unsigned int
size()308     size () const
309     {
310       return (cloud_.size());
311     }
312 
313     /// @brief Sets the size of the cloud of this object to the passed new size
314     /// @details If the size is smaller than the current size, only the first
315     /// new_size points will be kept, the rest being dropped. If new_size is
316     /// larger than the current size, the new points required to fill the
317     /// extended region are created with its default constructor.
318     /// @param new_size the new size of the cloud.
319     void
320     resize (unsigned int new_size);
321 
322     /// @brief Removes all points from the cloud and resets the object
323     void
324     clear ();
325 
326     /// @brief Set the sizes used for rendering the unselected points.
327     /// @param size The size, in pixels, used for rendering the points.
328     void
329     setPointSize (int size);
330 
331     /// @brief Set the sizes used for rendering the selected points.
332     /// @param size The size, in pixels, used for rendering the points.
333     void
334     setHighlightPointSize (int size);
335 
336     /// @brief Compute the transformed coordinates of the indexed point in the
337     /// cloud according to the object transform.
338     /// @details This applies the object rotation and translation of the
339     /// indexed point according to the user transforms.
340     /// @param index The index of the point whose coordinates are
341     /// transformed.
342     /// @return The transformed point.
343     Point3D
344     getObjectSpacePoint (unsigned int index) const;
345 
346     /// @brief Compute the transformed coordinates of the indexed point in the
347     /// cloud to match the display.
348     /// @details To save on computation, the points in the display are not
349     /// transformed on the cpu side, instead the gpu is allowed to manipulate
350     /// them for display.  This function performs the same manipulation and
351     /// returns the transformed point.
352     /// @param index The index of the point whose coordinates are
353     /// transformed according to the display.
354     /// @return The transformed point.
355     Point3D
356     getDisplaySpacePoint (unsigned int index) const;
357 
358     /// @brief Compute the transformed coordinates of the all the points in the
359     /// cloud to match the display.
360     /// @details To save on computation, the points in the display are not
361     /// transformed on the cpu side, instead the gpu is allowed to manipulate
362     /// them for display.  This function performs the same manipulation and
363     /// returns the transformed points.
364     /// @param pts a vector used to store the points whose coordinates are
365     /// transformed.
366     void
367     getDisplaySpacePoints (Point3DVector& pts) const;
368 
369     /// @brief Returns a const reference to the internal representation of this
370     /// object.
371     const Cloud3D&
372     getInternalCloud () const;
373 
374     /// @brief Places the points in the copy buffer into the cloud according
375     /// to the indices in the selection.
376     void
377     restore (const CopyBuffer& copy_buffer, const Selection& selection);
378 
379     /// @brief Get statistics of the selected points in string.
380     std::string
381     getStat () const override;
382 
383     /// Default Point Size
384     static const float DEFAULT_POINT_DISPLAY_SIZE_;
385     /// Default Highlight Point Size
386     static const float DEFAULT_POINT_HIGHLIGHT_SIZE_;
387     /// Default Point Color - Red component
388     static const float DEFAULT_POINT_DISPLAY_COLOR_RED_;
389     /// Default Point Color - Green component
390     static const float DEFAULT_POINT_DISPLAY_COLOR_GREEN_;
391     /// Default Point Color - Blue component
392     static const float DEFAULT_POINT_DISPLAY_COLOR_BLUE_;
393     /// Default Point Highlight Color - Red component
394     static const float DEFAULT_POINT_HIGHLIGHT_COLOR_RED_;
395     /// Default Point Highlight Color - Green component
396     static const float DEFAULT_POINT_HIGHLIGHT_COLOR_GREEN_;
397     /// Default Point Highlight Color - Blue component
398     static const float DEFAULT_POINT_HIGHLIGHT_COLOR_BLUE_;
399 
400   private:
401     /// @brief Computes the point cloud related members.
402     /// @details The cloud keeps track of certain values related to the points
403     /// in the cloud.  These include the minimum coordinates and the ranges in
404     /// the coordinate directions.
405     /// @pre Assumes that there is at least one dimension of the point cloud
406     /// that has non-zero range.
407     void
408     updateCloudMembers ();
409 
410     /// @brief Enable the texture used for rendering the cloud
411     void
412     enableTexture () const;
413 
414     /// @brief Disable the texture used for rendering the cloud
415     void
416     disableTexture() const;
417 
418     /// The internal representation of the cloud
419     Cloud3D cloud_;
420 
421     /// @brief A weak pointer pointing to the selection object.
422     /// @details This implementation uses the weak pointer to allow for a lazy
423     /// update of the cloud if the selection object is destroyed.
424     SelectionWeakPtr selection_wk_ptr_;
425 
426     /// Flag that indicates whether a color ramp should be used (true) or not
427     /// (false) when displaying the cloud
428     bool use_color_ramp_;
429 
430     /// The axis which the color ramp is to be applied when drawing the cloud
431     Axis color_ramp_axis_;
432 
433     /// A scale value used to normalize the display of clouds.  This is simply
434     /// one over the maximum of the range in each coordinate direction
435     float display_scale_;
436 
437     /// The center coordinate values in the point cloud.  This is used for
438     /// display.
439     float center_xyz_[XYZ_SIZE];
440 
441     /// The minimum coordinate values in the point cloud.  This is used for
442     /// display.
443     float min_xyz_[XYZ_SIZE];
444 
445     /// The maximum coordinate values in the point cloud.  This is used for
446     /// display.
447     float max_xyz_[XYZ_SIZE];
448 
449     /// A (4x4) OpenGL transform matrix for rendering the cloud
450     float cloud_matrix_[MATRIX_SIZE];
451 
452     /// A (4x4) OpenGL transform matrix specifying the relative transformations
453     /// that are applied to the selected points in the cloud when drawing them
454     /// as highlighted.
455     float select_matrix_[MATRIX_SIZE];
456 
457     /// A vector of indices for every point in the cloud.  This vector is used
458     /// when a selection is set and sorted such that the selected indices
459     /// appear first in the vector.  This is used during display to allow for
460     /// separate indexed drawing of the selection and the point cloud.  Note
461     /// that this vector is partitioned according to selected and not-selected.
462     IndexVector partitioned_indices_;
463 
464     /// The size used for rendering the unselected points in the cloud
465     float point_size_;
466 
467     /// The size used for rendering the selected points in the cloud
468     float selected_point_size_;
469 
470     /// The R, G, B values used for coloring each points when the current
471     /// color scheme is COLOR_BY_PURE.
472     float color_[RGB];
473 
474     /// The R, G, B values used for highlighting the selected points.
475     float highlight_color_[RGB];
476 
477     /// The translations on x, y, and z axis on the selected points.
478     float select_translate_x_, select_translate_y_, select_translate_z_;
479 };
480