Point Cloud Library (PCL) 1.13.0
pcl_plotter.h
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2010-2011, Willow Garage, Inc.
6 * Copyright (c) 2012-, Open Perception, Inc.
7 *
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * * Neither the name of the copyright holder(s) nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
38
39#pragma once
40
41#include <iostream>
42#include <vector>
43#include <utility>
44
45#include <pcl/visualization/common/common.h>
46#include <pcl/point_types.h>
47#include <pcl/correspondence.h>
48#include <pcl/point_cloud.h>
49#include <pcl/common/io.h>
50
51#include <vtkContextView.h>
52#include <vtkChartXY.h>
53#include <vtkColorSeries.h>
54#include <vtkSmartPointer.h>
55#include <vtkCommand.h>
56#include <vtkChart.h>
57
58class vtkRenderWindow;
59class vtkRenderWindowInteractor;
60
61namespace pcl
62{
63 namespace visualization
64 {
65 /** \brief PCL Plotter main class. Given point correspondences this class
66 * can be used to plot the data one against the other and display it on the
67 * screen. It also has methods for providing plot for important functions
68 * like histogram etc. Important functions of PCLHistogramVisualizer are
69 * redefined here so that this single class can take responsibility of all
70 * plotting related functionalities.
71 *
72 * \author Kripasindhu Sarkar
73 * \ingroup visualization
74 */
76 {
77 public:
78 using Ptr = shared_ptr<PCLPlotter>;
79 using ConstPtr = shared_ptr<const PCLPlotter>;
80
81 /**\brief A representation of polynomial function. i'th element of the vector denotes the coefficient of x^i of the polynomial in variable x.
82 */
83 using PolynomialFunction = std::vector<double>;
84
85 /**\brief A representation of rational function, defined as the ratio of two polynomial functions. pair::first denotes the numerator and pair::second denotes the denominator of the Rational function.
86 */
87 using RationalFunction = std::pair<PolynomialFunction, PolynomialFunction>;
88
89 /** \brief PCL Plotter constructor.
90 * \param[in] name Name of the window
91 */
92 PCLPlotter (char const * name = "PCL Plotter");
93
94 /** \brief Destructor. */
96
97 /** \brief Adds a plot with correspondences in the arrays arrayX and arrayY
98 * \param[in] array_X X coordinates of point correspondence array
99 * \param[in] array_Y Y coordinates of point correspondence array
100 * \param[in] size length of the array arrayX and arrayY
101 * \param[in] name name of the plot which appears in the legend when toggled on
102 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
103 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
104 */
105 void
106 addPlotData (double const *array_X,
107 double const *array_Y,
108 unsigned long size,
109 char const * name = "Y Axis",
110 int type = vtkChart::LINE ,
111 char const *color=nullptr);
112
113 /** \brief Adds a plot with correspondences in vectors arrayX and arrayY. This is the vector version of the addPlotData function.
114 * \param[in] array_x X coordinates of point correspondence array
115 * \param[in] array_y Y coordinates of point correspondence array
116 * \param[in] name name of the plot which appears in the legend when toggled on
117 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
118 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
119 */
120 void
121 addPlotData (std::vector<double> const &array_x,
122 std::vector<double>const &array_y,
123 char const * name = "Y Axis",
124 int type = vtkChart::LINE,
125 std::vector<char> const &color = std::vector<char> ());
126
127 /** \brief Adds a plot with correspondences in vector of pairs. The the first and second field of the pairs of the vector forms the correspondence.
128 * \param plot_data
129 * \param[in] name name of the plot which appears in the legend when toggled on
130 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
131 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
132 */
133 void
134 addPlotData (std::vector<std::pair<double, double> > const &plot_data,
135 char const * name = "Y Axis",
136 int type = vtkChart::LINE,
137 std::vector<char> const &color = std::vector<char>());
138
139 /** \brief Adds a plot based on the given polynomial function and the range in X axis.
140 * \param[in] p_function A polynomial function which is represented by a vector which stores the coefficients. See description on the typedef.
141 * \param[in] x_min the left boundary of the range for displaying the plot
142 * \param[in] x_max the right boundary of the range for displaying the plot
143 * \param[in] name name of the plot which appears in the legend when toggled on
144 * \param[in] num_points Number of points plotted to show the graph. More this number, more is the resolution.
145 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
146 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
147 */
148 void
149 addPlotData (PolynomialFunction const & p_function,
150 double x_min, double x_max,
151 char const *name = "Y Axis",
152 int num_points = 100,
153 int type = vtkChart::LINE,
154 std::vector<char> const &color = std::vector<char>());
155
156 /** \brief Adds a plot based on the given rational function and the range in X axis.
157 * \param[in] r_function A rational function which is represented by the ratio of two polynomial functions. See description on the typedef for more details.
158 * \param[in] x_min the left boundary of the range for displaying the plot
159 * \param[in] x_max the right boundary of the range for displaying the plot
160 * \param[in] name name of the plot which appears in the legend when toggled on
161 * \param[in] num_points Number of points plotted to show the graph. More this number, more is the resolution.
162 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
163 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
164 */
165 void
166 addPlotData (RationalFunction const & r_function,
167 double x_min, double x_max,
168 char const *name = "Y Axis",
169 int num_points = 100,
170 int type = vtkChart::LINE,
171 std::vector<char> const &color = std::vector<char>());
172
173 /** \brief Adds a plot based on a user defined callback function representing the function to plot
174 * \param[in] function a user defined callback function representing the relation y = function(x)
175 * \param[in] x_min the left boundary of the range for displaying the plot
176 * \param[in] x_max the right boundary of the range for displaying the plot
177 * \param[in] name name of the plot which appears in the legend when toggled on
178 * \param[in] num_points Number of points plotted to show the graph. More this number, more is the resolution.
179 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
180 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or NULL is passed) the plot is colored based on a color scheme
181 */
182 void
183 addPlotData (double (*function)(double),
184 double x_min, double x_max,
185 char const *name = "Y Axis",
186 int num_points = 100,
187 int type = vtkChart::LINE,
188 std::vector<char> const &color = std::vector<char>());
189
190 /** \brief Adds a plot based on a space/tab delimited table provided in a file
191 * \param[in] filename name of the file containing the table. 1st column represents the values of X-Axis. Rest of the columns represent the corresponding values in Y-Axes. First row of the file is considered for naming/labeling of the plot. The plot-names should not contain any space in between.
192 * \param[in] type type of the graph plotted. vtkChart::LINE for line plot, vtkChart::BAR for bar plot, and vtkChart::POINTS for a scattered point plot
193 */
194 void
195 addPlotData (char const * filename,
196 int type = vtkChart::LINE);
197
198 /** \brief Bins the elements in vector data into nbins equally spaced containers and plots the resulted histogram
199 * \param[in] data the raw data
200 * \param[in] nbins the number of bins for the histogram
201 * \param[in] name name of this histogram which will appear on legends if toggled on
202 * \param[in] color a character array of 4 fields denoting the R,G,B and A component of the color of the plot ranging from 0 to 255. If this argument is not passed (or an empty vector is passed) the histogram is colored based on the current color scheme
203 */
204 void
205 addHistogramData (std::vector<double> const & data,
206 int const nbins = 10,
207 char const * name = "Histogram",
208 std::vector<char> const &color = std::vector<char>());
209
210 //##PCLHistogramVisulizer methods##
211 /** \brief Add a histogram feature to screen as a separate window, from a cloud containing a single histogram.
212 * \param[in] cloud the PointCloud dataset containing the histogram
213 * \param[in] hsize the length of the histogram
214 * \param[in] id the point cloud object id (default: cloud)
215 * \param[in] win_width the width of the window
216 * \param[in] win_height the height of the window
217 */
218 template <typename PointT> bool
219 addFeatureHistogram (const pcl::PointCloud<PointT> &cloud,
220 int hsize,
221 const std::string &id = "cloud", int win_width = 640, int win_height = 200);
222
223 /** \brief Add a histogram feature to screen as a separate window from a cloud containing a single histogram.
224 * \param[in] cloud the PointCloud dataset containing the histogram
225 * \param[in] field_name the field name containing the histogram
226 * \param[in] id the point cloud object id (default: cloud)
227 * \param[in] win_width the width of the window
228 * \param[in] win_height the height of the window
229 */
230 bool
232 const std::string &field_name,
233 const std::string &id = "cloud", int win_width = 640, int win_height = 200);
234
235 /** \brief Add a histogram feature to screen as a separate window.
236 * \param[in] cloud the PointCloud dataset containing the histogram
237 * \param[in] field_name the field name containing the histogram
238 * \param[in] index the point index to extract the histogram from
239 * \param[in] id the point cloud object id (default: cloud)
240 * \param[in] win_width the width of the window
241 * \param[in] win_height the height of the window
242 */
243 template <typename PointT> bool
244 addFeatureHistogram (const pcl::PointCloud<PointT> &cloud,
245 const std::string &field_name,
246 const pcl::index_t index,
247 const std::string &id = "cloud", int win_width = 640, int win_height = 200);
248
249 /** \brief Add a histogram feature to screen as a separate window.
250 * \param[in] cloud the PointCloud dataset containing the histogram
251 * \param[in] field_name the field name containing the histogram
252 * \param[in] index the point index to extract the histogram from
253 * \param[in] id the point cloud object id (default: cloud)
254 * \param[in] win_width the width of the window
255 * \param[in] win_height the height of the window
256 */
257 bool
259 const std::string &field_name,
260 const pcl::index_t index,
261 const std::string &id = "cloud", int win_width = 640, int win_height = 200);
262
263 /** \brief Draws all the plots added by addPlotData() or addHistogramData() till now */
264 void
266
267 /** \brief Spins (runs the event loop) the interactor for spin_time amount of time. The name is confusing and will be probably obsolete in the future release with a single overloaded spin()/display() function.
268 * \param[in] spin_time - How long (in ms) should the visualization loop be allowed to run.
269 */
270 void
271 spinOnce (const int spin_time = 1);
272
273 /** \brief Spins (runs the event loop) the interactor indefinitely. Same as plot() - added to retain the similarity between other existing visualization classes. */
274 void
276
277 /** \brief Remove all plots from the window. */
278 void
280
281 /** \brief Set method for the color scheme of the plot. The plots gets autocolored differently based on the color scheme.
282 * \param[in] scheme the color scheme. Possible values are vtkColorSeries::SPECTRUM, vtkColorSeries::WARM, vtkColorSeries::COOL, vtkColorSeries::BLUES, vtkColorSeries::WILD_FLOWER, vtkColorSeries::CITRUS
283 */
284 void
285 setColorScheme (int scheme);
286
287 /** \brief get the currently used color scheme
288 * \return[out] the currently used color scheme. Values include WARM, COOL, BLUES, WILD_FLOWER, CITRUS, CUSTOM
289 */
290 int
292
293 /** \brief set/get method for the viewport's background color.
294 * \param[in] r the red component of the RGB color
295 * \param[in] g the green component of the RGB color
296 * \param[in] b the blue component of the RGB color
297 */
298 void
299 setBackgroundColor (const double r, const double g, const double b);
300
301 /** \brief set/get method for the viewport's background color.
302 * \param [in] color the array containing the 3 component of the RGB color
303 */
304 void
305 setBackgroundColor (const double color[3]);
306
307 /** \brief set/get method for the viewport's background color.
308 * \return [out] color the array containing the 3 component of the RGB color
309 */
310 double *
312
313 /** \brief Set logical range of the X-Axis in plot coordinates
314 * \param[in] min the left boundary of the range
315 * \param[in] max the right boundary of the range
316 */
317 void
318 setXRange (double min, double max);
319
320 /** \brief Set logical range of the Y-Axis in plot coordinates
321 * \param[in] min the left boundary of the range
322 * \param[in] max the right boundary of the range
323 */
324 void
325 setYRange (double min, double max);
326
327 /** \brief Set the main title of the plot
328 * \param[in] title the title to set
329 */
330 void
331 setTitle (const char *title);
332
333 /** \brief Set the title of the X-Axis
334 * \param[in] title the title to set
335 */
336 void
337 setXTitle (const char *title);
338
339 /** \brief Set the title of the Y-Axis
340 * \param[in] title the title to set
341 */
342 void
343 setYTitle (const char *title);
344
345 /** \brief Shows the legend of the graph
346 * \param[in] flag pass flag = true for the display of the legend of the graph
347 */
348 void
349 setShowLegend (bool flag);
350
351 /** \brief set/get method for the window size.
352 * \param[in] w the width of the window
353 * \param[in] h the height of the window
354 */
355 void
356 setWindowSize (int w, int h);
357
358 /** \brief Set the position in screen coordinates.
359 * \param[in] x where to move the window to (X)
360 * \param[in] y where to move the window to (Y)
361 */
362 void
363 setWindowPosition (int x, int y);
364
365 /** \brief Set the visualizer window name.
366 * \param[in] name the name of the window
367 */
368 void
369 setWindowName (const std::string &name);
370
371 /** \brief set/get method for the window size.
372 * \return[in] array containing the width and height of the window
373 */
374 int*
376
377 /** \brief Return a pointer to the underlying VTK RenderWindow used. */
380
381 /** \brief Set the view's interactor. */
382 void
384
385 /** \brief Initialize and Start the view's interactor. */
386 void
388
389 /** \brief Render the vtkWindow once. */
391
392 /** \brief Returns true when the user tried to close the window */
393 bool
394 wasStopped () const;
395
396 /** \brief Stop the interaction and close the visualizaton window. */
397 void
399
400 private:
403 vtkSmartPointer<vtkColorSeries> color_series_; //for automatic coloring
404
405 //extra state variables
406 int current_plot_; //stores the id of the current (most recent) plot, used in automatic coloring and other state change schemes
407 int win_width_, win_height_;
408 int win_x_, win_y_; //window position according to screen coordinate
409 double bkg_color_[3];
410 std::string win_name_;
411
412 //####event callback class####
413 struct ExitMainLoopTimerCallback : public vtkCommand
414 {
415 static ExitMainLoopTimerCallback* New ()
416 {
417 return (new ExitMainLoopTimerCallback);
418 }
419 void
420 Execute (vtkObject*, unsigned long event_id, void* call_data) override;
421
422 int right_timer_id;
423 vtkRenderWindowInteractor *interactor;
424 };
425
426 struct ExitCallback : public vtkCommand
427 {
428 static ExitCallback* New ()
429 {
430 return new ExitCallback;
431 }
432 void
433 Execute (vtkObject*, unsigned long event_id, void*) override;
434
435 PCLPlotter *plotter;
436 };
437
438 /** \brief Set to false if the interaction loop is running. */
439 bool stopped_;
440
441 /** \brief Callback object enabling us to leave the main loop, when a timer fires. */
443 vtkSmartPointer<ExitCallback> exit_callback_;
444
445 ////////////////////////////////////IMPORTANT PRIVATE COMPUTING FUNCTIONS////////////////////////////////////////////////////
446 /** \brief computes the value of the polynomial function at val
447 * \param[in] p_function polynomial function
448 * \param[in] value the value at which the function is to be computed
449 */
450 double
451 compute (PolynomialFunction const & p_function, double val);
452
453 /** \brief computes the value of the rational function at val
454 * \param[in] r_function the rational function
455 * \param[in] value the value at which the function is to be computed
456 */
457 double
458 compute (RationalFunction const & r_function, double val);
459
460 /** \brief bins the elements in vector data into nbins equally spaced containers and returns the histogram form, ie, computes the histogram for 'data'
461 * \param[in] data data who's frequency distribution is to be found
462 * \param[in] nbins number of bins for the histogram
463 * \param[out] histogram vector of pairs containing the histogram. The first field of the pair represent the middle value of the corresponding bin. The second field denotes the frequency of data in that bin.
464 * \note NaN values will be ignored!
465 */
466 void
467 computeHistogram (std::vector<double> const & data, int const nbins, std::vector<std::pair<double, double> > &histogram);
468 };
469 }
470}
471
472#include <pcl/visualization/impl/pcl_plotter.hpp>
PointCloud represents the base class in PCL for storing collections of 3D points.
Definition: point_cloud.h:173
PCL Plotter main class.
Definition: pcl_plotter.h:76
bool addFeatureHistogram(const pcl::PCLPointCloud2 &cloud, const std::string &field_name, const std::string &id="cloud", int win_width=640, int win_height=200)
Add a histogram feature to screen as a separate window from a cloud containing a single histogram.
void setWindowPosition(int x, int y)
Set the position in screen coordinates.
vtkSmartPointer< vtkRenderWindow > getRenderWindow()
Return a pointer to the underlying VTK RenderWindow used.
void addPlotData(std::vector< std::pair< double, double > > const &plot_data, char const *name="Y Axis", int type=vtkChart::LINE, std::vector< char > const &color=std::vector< char >())
Adds a plot with correspondences in vector of pairs.
double * getBackgroundColor()
set/get method for the viewport's background color.
std::pair< PolynomialFunction, PolynomialFunction > RationalFunction
A representation of rational function, defined as the ratio of two polynomial functions.
Definition: pcl_plotter.h:87
void plot()
Draws all the plots added by addPlotData() or addHistogramData() till now.
void startInteractor()
Initialize and Start the view's interactor.
void setColorScheme(int scheme)
Set method for the color scheme of the plot.
bool addFeatureHistogram(const pcl::PCLPointCloud2 &cloud, const std::string &field_name, const pcl::index_t index, const std::string &id="cloud", int win_width=640, int win_height=200)
Add a histogram feature to screen as a separate window.
void setWindowName(const std::string &name)
Set the visualizer window name.
void setYTitle(const char *title)
Set the title of the Y-Axis.
void setBackgroundColor(const double r, const double g, const double b)
set/get method for the viewport's background color.
void addPlotData(PolynomialFunction const &p_function, double x_min, double x_max, char const *name="Y Axis", int num_points=100, int type=vtkChart::LINE, std::vector< char > const &color=std::vector< char >())
Adds a plot based on the given polynomial function and the range in X axis.
void addPlotData(double const *array_X, double const *array_Y, unsigned long size, char const *name="Y Axis", int type=vtkChart::LINE, char const *color=nullptr)
Adds a plot with correspondences in the arrays arrayX and arrayY.
int * getWindowSize() const
set/get method for the window size.
void spinOnce(const int spin_time=1)
Spins (runs the event loop) the interactor for spin_time amount of time.
void renderOnce()
Render the vtkWindow once.
void setWindowSize(int w, int h)
set/get method for the window size.
PCLPlotter(char const *name="PCL Plotter")
PCL Plotter constructor.
void setYRange(double min, double max)
Set logical range of the Y-Axis in plot coordinates.
shared_ptr< PCLPlotter > Ptr
Definition: pcl_plotter.h:78
void setXRange(double min, double max)
Set logical range of the X-Axis in plot coordinates.
void close()
Stop the interaction and close the visualizaton window.
void setBackgroundColor(const double color[3])
set/get method for the viewport's background color.
std::vector< double > PolynomialFunction
A representation of polynomial function.
Definition: pcl_plotter.h:83
void setTitle(const char *title)
Set the main title of the plot.
void addHistogramData(std::vector< double > const &data, int const nbins=10, char const *name="Histogram", std::vector< char > const &color=std::vector< char >())
Bins the elements in vector data into nbins equally spaced containers and plots the resulted histogra...
void addPlotData(RationalFunction const &r_function, double x_min, double x_max, char const *name="Y Axis", int num_points=100, int type=vtkChart::LINE, std::vector< char > const &color=std::vector< char >())
Adds a plot based on the given rational function and the range in X axis.
shared_ptr< const PCLPlotter > ConstPtr
Definition: pcl_plotter.h:79
bool wasStopped() const
Returns true when the user tried to close the window.
void clearPlots()
Remove all plots from the window.
void addPlotData(std::vector< double > const &array_x, std::vector< double >const &array_y, char const *name="Y Axis", int type=vtkChart::LINE, std::vector< char > const &color=std::vector< char >())
Adds a plot with correspondences in vectors arrayX and arrayY.
void setXTitle(const char *title)
Set the title of the X-Axis.
void setViewInteractor(vtkSmartPointer< vtkRenderWindowInteractor > interactor)
Set the view's interactor.
void addPlotData(double(*function)(double), double x_min, double x_max, char const *name="Y Axis", int num_points=100, int type=vtkChart::LINE, std::vector< char > const &color=std::vector< char >())
Adds a plot based on a user defined callback function representing the function to plot.
void spin()
Spins (runs the event loop) the interactor indefinitely.
int getColorScheme()
get the currently used color scheme
void addPlotData(char const *filename, int type=vtkChart::LINE)
Adds a plot based on a space/tab delimited table provided in a file.
void setShowLegend(bool flag)
Shows the legend of the graph.
Defines all the PCL implemented PointT point type structures.
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition: types.h:112
#define PCL_EXPORTS
Definition: pcl_macros.h:323