1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2013 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 
8 #ifndef CHART_WABSTRACTGRIDDATA_H
9 #define CHART_WABSTRACTGRIDDATA_H
10 
11 #include <Wt/Chart/WAbstractDataSeries3D.h>
12 #include <Wt/Chart/WCartesian3DChart.h>
13 #include <Wt/Chart/WSelection.h>
14 #include <Wt/WPen.h>
15 
16 namespace Wt {
17 class WAbstractItemModel;
18 class WMemoryResource;
19 class WVector3;
20 
21   namespace Chart {
22   class WCartesian3DChart;
23 
24 /*! \brief Enumeration with the possible representations of a WAbstractGridData
25  *
26  * \ingroup charts
27  */
28 enum class Series3DType {
29   Point,   //!< Series rendered as points
30   Surface, //!< Series rendered as a surface
31   Bar      //!< Series rendered as bars
32 };
33 
34 /*! \class WAbstractGridData
35  *  \brief Class representing grid-based data for on a 3D chart.
36  *
37  * General information can be found at WAbstractDataSeries3D. Information on
38  * how the model is structured is provided in the subclasses. GridData can be
39  * represented in three ways. This is indicated by \ref Series3DType and can be
40  * either Series3DType::Point, Series3DType::Surface or Series3DType::Bar. Note that points and
41  * surfaces can only be added to charts of type \ref ChartType::Scatter, while bars
42  * can only be added to charts of type \ref ChartType::Category.
43  *
44  * When the data is shown as a surface, a mesh can be added to the surface.
45  * This draws lines over the surface at the positions of the x- and y-values.
46  * For bar-series data, it is possible to adjust the width of the bars in both
47  * directions.
48  *
49  * The three types of data-representation are illustrated below.
50  *
51  * \image html gridDataTypes.png "The three representation types of grid-based data"
52  *
53  * \ingroup charts
54  */
55 class WT_API WAbstractGridData : public WAbstractDataSeries3D {
56 public:
57   /*! \brief Constructor
58    */
59   WAbstractGridData(std::shared_ptr<WAbstractItemModel> model);
60 
61   virtual ~WAbstractGridData();
62 
63   virtual double minimum(Axis axis) const override = 0;
64 
65   virtual double maximum(Axis axis) const override = 0;
66 
67   /*! \brief Sets the type of representation that will be used for the data.
68    *
69    * All representations in \ref Series3DType are possible for the data. Note
70    * that \ref Series3DType::Point and \ref Series3DType::Surface can only be used on a
71    * chart that is configured as a \ref ChartType::Scatter and \ref Series3DType::Bar can
72    * only be used on a chart that is configured to be a \ref ChartType::Category.
73    *
74    * The default value is Series3DType::Point.
75    */
76   void setType(Series3DType type);
77 
78   /*! \brief Returns the type of representation that will be used for the data.
79    *
80    * \sa setType()
81    */
type()82   virtual Series3DType type() const { return seriesType_; }
83 
84   /*! \brief Enables or disables a mesh for when a surface is drawn.
85    *
86    * The default value is false. This option only takes effect when the type of
87    * this WGridData is \ref Series3DType::Surface. The mesh is drawn at the position
88    * of the x-axis and y-axis values.
89    */
90   void setSurfaceMeshEnabled(bool enabled = true);
91 
92   /*! \brief Returns whether the surface-mesh is enabled for this dataseries.
93    *
94    * \sa setSurfaceMeshEnabled()
95    */
isSurfaceMeshEnabled()96   bool isSurfaceMeshEnabled() { return surfaceMeshEnabled_; }
97 
98   /*! \brief Sets the bar-width.
99    *
100    * This option only takes effect when the type of this WGridData is
101    * Series3DType::Bar. The values provided should be between 0 and 1, where 1 lets
102    * the bars each take up 1/(nb of x/y-values) of the axis.
103    *
104    * The default bar-width is 0.5 in both directions.
105    */
106   void setBarWidth(double xWidth, double yWidth);
107 
108   /*! \brief Returns the bar-width in the X-axis direction.
109    *
110    * \sa setBarWidth()
111    */
barWidthX()112   double barWidthX() { return barWidthX_; }
113 
114   /*! \brief Returns the bar-width in the Y-axis direction.
115    *
116    * \sa setBarWidth()
117    */
barWidthY()118   double barWidthY() { return barWidthY_; }
119 
120   /*! \brief Sets the WPen that is used for drawing the mesh.
121    *
122    * Used when drawing the mesh on a surface or the lines around bars. The
123    * default is a default constructed WPen (black and one pixel wide).
124    *
125    * Note: only the width and color of this WPen are used.
126    *
127    * \sa setSurfaceMeshEnabled()
128    */
129   void setPen(const WPen &pen);
130 
131   /*! \brief Returns the pen that is used for drawing the mesh.
132    *
133    * \sa setPen()
134    */
pen()135   WPen pen() const { return meshPen_; }
136 
137   /*! \brief Find all points on the surface that are projected to the given pixel.
138    *
139    * A ray is cast from the given pixel's x,y position (from the top left of the chart,
140    * in screen coordinates) and every intersection with the surface is returned, along
141    * with its distance from the look point. Note that the coordinates of the intersection
142    * points are interpolated between the data points that make up the surface.
143    */
144   std::vector<WSurfaceSelection> pickSurface(int x, int y) const;
145 
146   /*! \brief Return the bar that is closest to the look point at the given pixel.
147    *
148    * A ray is cast from the given pixel's x,y position (from the top left of the chart,
149    * in screen coordinates), and the closest bar on this WAbstractGridData
150    * is returned, along with its distance from the look point.
151    *
152    * Note that if this WAbstractGridData is hidden, this method still returns the
153    * closest bar as if it was visible. Also, if multiple bars are on the same bar chart,
154    * the bar that is returned may be behind another data series. Use the distance
155    * field of the returned WBarSelection to determine which data series is in front from
156    * the given angle.
157    *
158    * If there is no bar at the given pixel, then a selection with an invalid WModelIndex
159    * is returned. The distance is then set to positive infinity.
160    */
161   WBarSelection pickBar(int x, int y) const;
162 
163   /*! \brief Set isoline levels.
164    *
165    * Isolines are drawn on the top or ground plane of the chart.
166    * Only applies if the type is Series3DType::Surface.
167    *
168    * The isoline levels are set in the coordinate system of the item model.
169    */
170   void setIsoLevels(const std::vector<double> &isoLevels);
171 
172   /*! \brief Get all of the isoline levels.
173    *
174    * \sa addIsoLevel()
175    */
176   const std::vector<double> &isoLevels() const;
177 
178   /*! \brief Set the color map for the isolines.
179    *
180    * When no color map is defined for the isolines, i.e. isoColorMap()
181    * is set to NULL, the color map of this WAbstractGridData will be used.
182    *
183    * The isolines are only drawn if the type is Series3DType::Surface.
184    *
185    * \sa addIsoLevel(), setColorMap()
186    */
187   void setIsoColorMap(const std::shared_ptr<WAbstractColorMap>& colormap);
188 
189   /*! \brief Get the color map for the isolines.
190    *
191    * \sa setIsoColorMap()
192    */
isoColorMap()193   std::shared_ptr<WAbstractColorMap> isoColorMap() const
194     { return isoLineColorMap_; }
195 
196   /*! \brief Set the value below which the data series will be clipped on the given axis.
197    *
198    * This only affects data series whose type is Series3DType::Surface.
199    */
200   void setClippingMin(Axis axis, float v);
201 
202   /*! \brief Gets the value below which the data series will be clipped on the given axis.
203    *
204    * \sa setClippingMin()
205    */
206   float clippingMin(Axis axis) const;
207 
208   /*! \brief JSlot to change the value below which the data series will be clipped on the given axis.
209    *
210    * The JSlot takes one extra argument: the value to clip below.
211    *
212    * The jsRef() of this JSlot is only valid when this WAbstractGridData has been added to
213    * a WCartesian3DChart. If this WAbstractGridData moves to another WCartesian3DChart, the
214    * jsRef() of the JSlot changes.
215    *
216    * \sa setClippingMin()
217    */
218   JSlot &changeClippingMin(Axis axis);
219 
220   /*! \brief Set the value above which the data series will be clipped on the given axis.
221    *
222    * This only affects data series whose type is Series3DType::Surface.
223    */
224   void setClippingMax(Axis axis, float v);
225 
226   /*! \brief Gets the value above which the data series will be clipped on the given axis.
227    *
228    * \sa setClippingMax()
229    */
230   float clippingMax(Axis axis) const;
231 
232   /*! \brief JSlot to change the value above which the data series will be clipped on the given axis.
233    *
234    * The JSlot takes one extra argument: the value to clip below.
235    *
236    * The jsRef() of this JSlot is only valid when this WAbstractGridData has been added to
237    * a WCartesian3DChart. If this WAbstractGridData moves to another WCartesian3DChart, the
238    * jsRef() of the JSlot changes.
239    *
240    * \sa setClippingMax()
241    */
242   JSlot &changeClippingMax(Axis axis);
243 
244   /*! \brief Sets whether clipping lines should be drawn where a surface
245    *         is clipped.
246    *
247    *  Clipping lines are disabled by default. Note that rendering will
248    *  be significantly slower when enabled.
249    */
250   void setClippingLinesEnabled(bool clippingLinesEnabled);
251 
252   /*! \brief Returns whether clipping lines are enabled.
253    *
254    * \sa setClippingLinesEnabled()
255    */
clippingLinesEnabled()256   bool clippingLinesEnabled() const { return clippingLinesEnabled_; }
257 
258   /*! \brief Sets the color of the clipping lines.
259    *
260    * \sa setClippingLinesEnabled()
261    */
262   void setClippingLinesColor(WColor color);
263 
264   /*! \brief Gets the color of the clipping lines.
265    *
266    * \sa setClippingLinesColor(), setClippingLinesEnabled()
267    */
clippingLinesColor()268   WColor clippingLinesColor() const { return clippingLinesColor_; }
269 
270   static const int SURFACE_SIDE_LIMIT = 256; // = sqrt(2^16)
271   static const int BAR_BUFFER_LIMIT = 8190; // = 2^16/8
272 
273   virtual int nbXPoints() const = 0;
274   virtual int nbYPoints() const = 0;
275   virtual WString axisLabel(int u, Axis axis) const = 0;
276   virtual cpp17::any data(int i, int j) const = 0;
277 
278   virtual void setChart(WCartesian3DChart *chart) override;
279 
280   virtual std::vector<cpp17::any> getGlObjects() override;
281 
282   virtual void initializeGL() override;
283   virtual void paintGL() const override;
284   virtual void updateGL() override;
285   virtual void resizeGL() override;
286   virtual void deleteAllGLResources() override;
287 
288 protected:
289   virtual void pointDataFromModel(FloatBuffer& simplePtsArray,
290 				  FloatBuffer& simplePtsSize,
291 				  FloatBuffer& coloredPtsArray,
292 				  FloatBuffer& coloredPtsSize,
293 				  FloatBuffer& coloredPtsColor) const = 0;
294   virtual void surfaceDataFromModel(std::vector<FloatBuffer>& simplePtsArrays) const = 0;
295   virtual void barDataFromModel(std::vector<FloatBuffer>& simplePtsArrays) const = 0;
296   virtual void barDataFromModel(std::vector<FloatBuffer>& simplePtsArrays,
297 				std::vector<FloatBuffer>& coloredPtsArrays,
298 				std::vector<FloatBuffer>& coloredPtsColors) const = 0;
299 
300   // data without color-role
301   virtual int countSimpleData() const = 0;
302   // adds up the value (i, j) for all dataseries, i and j should be specified
303   // without any offsets for axes in the model
304   float stackAllValues(std::vector<WAbstractGridData*> dataseries,
305 		       int i, int j) const;
306 
307   Series3DType seriesType_;
308 
309   bool surfaceMeshEnabled_;
310   bool colorRoleEnabled_;
311 
312   double barWidthX_;
313   double barWidthY_;
314 
315   WPen meshPen_;
316 
317   static const float zeroBarCompensation;
318 
319 private:
320   void initShaders();
321   void initializePointSeriesBuffers();
322   void initializeSurfaceSeriesBuffers();
323   void initializeBarSeriesBuffers();
324   void loadBinaryResource(FloatBuffer&,
325 			  std::vector<WGLWidget::Buffer>& buffers);
326   void barSeriesVertexData(FloatBuffer& verticesIN,
327 			   FloatBuffer& verticesOUT) const;
328   void generateVertexIndices(IntBuffer& indicesOUT,
329 			     int Nx, int Ny, int size = 0) const;
330   void generateMeshIndices(IntBuffer& indicesOUT,
331 			   int Nx, int Ny, int size = 0);
332   void generateTextureCoords(FloatBuffer& coordsOUT,
333 			     const FloatBuffer& dataArray,
334 			     int size);
335 
336   void paintGLIndex(unsigned index) const;
337   void paintGLIndex(unsigned index, double marginX, double marginY, double marginZ) const;
338   void paintGLPositions() const;
339   void paintGLPositions(double marginX, double marginY, double marginZ) const;
340 
341   double rayTriangleIntersect(const WVector3 &re, const WVector3 &rd, const WVector3 &camera, const WVector3 &v0, const WVector3 &v1, const WVector3 &v2, WVector3 &point) const;
342 
343   void drawIsoLines() const;
344   void linesForIsoLevel(double z, std::vector<float> &result) const;
345   WGLWidget::Texture isoLineColorMapTexture();
346 
347   std::vector<int> vertexPosBufferSizes_, vertexPosBuffer2Sizes_;
348   std::vector<int> indexBufferSizes_, lineBufferSizes_;
349   std::vector<int> indexBufferSizes2_, lineBufferSizes2_;
350   std::vector<int> isoLineBufferSizes_;
351 
352   std::vector<double> isoLineHeights_;
353   std::shared_ptr<WAbstractColorMap> isoLineColorMap_;
354 
355   std::vector<WGLWidget::Buffer> vertexPosBuffers_;
356   std::vector<WGLWidget::Buffer> vertexPosBuffers2_;
357   std::vector<WGLWidget::Buffer> vertexSizeBuffers_;
358   std::vector<WGLWidget::Buffer> vertexSizeBuffers2_;
359   std::vector<WGLWidget::Buffer> vertexColorBuffers2_;
360   std::vector<WGLWidget::Buffer> indexBuffers_;
361   std::vector<WGLWidget::Buffer> indexBuffers2_;
362   std::vector<WGLWidget::Buffer> overlayLinesBuffers_;
363   std::vector<WGLWidget::Buffer> overlayLinesBuffers2_;
364   std::vector<WGLWidget::Buffer> colormapTexBuffers_;
365   std::vector<WGLWidget::Buffer> isoLineBuffers_;
366 
367   std::vector<WMemoryResource*> binaryResources_;
368 
369   // Shader program
370   WGLWidget::Shader fragShader_;
371   WGLWidget::Shader colFragShader_;
372   WGLWidget::Shader meshFragShader_;
373   WGLWidget::Shader singleColorFragShader_;
374   WGLWidget::Shader positionFragShader_;
375   WGLWidget::Shader isoLineFragShader_;
376 
377   WGLWidget::Shader vertShader_;
378   WGLWidget::Shader colVertShader_;
379   WGLWidget::Shader meshVertShader_;
380   WGLWidget::Shader isoLineVertexShader_;
381 
382   WGLWidget::Program seriesProgram_;
383   WGLWidget::Program colSeriesProgram_;
384   WGLWidget::Program meshProgram_;
385   WGLWidget::Program singleColorProgram_;
386   WGLWidget::Program positionProgram_;
387   WGLWidget::Program isoLineProgram_;
388 
389   // Shader attributes
390   WGLWidget::AttribLocation vertexPosAttr_;
391   WGLWidget::AttribLocation vertexPosAttr2_;
392   WGLWidget::AttribLocation singleColor_vertexPosAttr_;
393   WGLWidget::AttribLocation position_vertexPosAttr_;
394   WGLWidget::AttribLocation meshVertexPosAttr_;
395   WGLWidget::AttribLocation isoLineVertexPosAttr_;
396 
397   WGLWidget::AttribLocation vertexSizeAttr_;
398   WGLWidget::AttribLocation vertexSizeAttr2_;
399   WGLWidget::AttribLocation vertexColAttr2_;
400 
401   WGLWidget::AttribLocation barTexCoordAttr_;
402 
403   // Shader uniform variables
404   WGLWidget::UniformLocation mvMatrixUniform_;
405   WGLWidget::UniformLocation mvMatrixUniform2_;
406   WGLWidget::UniformLocation singleColor_mvMatrixUniform_;
407   WGLWidget::UniformLocation position_mvMatrixUniform_;
408   WGLWidget::UniformLocation mesh_mvMatrixUniform_;
409   WGLWidget::UniformLocation isoLine_mvMatrixUniform_;
410 
411   WGLWidget::UniformLocation pMatrix_;
412   WGLWidget::UniformLocation pMatrix2_;
413   WGLWidget::UniformLocation singleColor_pMatrix_;
414   WGLWidget::UniformLocation position_pMatrix_;
415   WGLWidget::UniformLocation mesh_pMatrix_;
416   WGLWidget::UniformLocation isoLine_pMatrix_;
417 
418   WGLWidget::UniformLocation cMatrix_;
419   WGLWidget::UniformLocation cMatrix2_;
420   WGLWidget::UniformLocation singleColor_cMatrix_;
421   WGLWidget::UniformLocation position_cMatrix_;
422   WGLWidget::UniformLocation mesh_cMatrix_;
423   WGLWidget::UniformLocation isoLine_cMatrix_;
424 
425   WGLWidget::UniformLocation TexSampler_;
426   WGLWidget::UniformLocation isoLine_TexSampler_;
427   WGLWidget::UniformLocation mesh_colorUniform_;
428 
429   WGLWidget::UniformLocation singleColorUniform_;
430 
431   WGLWidget::UniformLocation pointSpriteUniform_;
432   WGLWidget::UniformLocation pointSpriteUniform2_;
433 
434   WGLWidget::UniformLocation vpHeightUniform_;
435   WGLWidget::UniformLocation vpHeightUniform2_;
436 
437   WGLWidget::UniformLocation offset_;
438   WGLWidget::UniformLocation isoLine_offset_;
439   WGLWidget::UniformLocation scaleFactor_;
440   WGLWidget::UniformLocation isoLine_scaleFactor_;
441 
442   WGLWidget::UniformLocation minPtUniform_;
443   WGLWidget::UniformLocation mesh_minPtUniform_;
444   WGLWidget::UniformLocation singleColor_minPtUniform_;
445   WGLWidget::UniformLocation position_minPtUniform_;
446   WGLWidget::UniformLocation maxPtUniform_;
447   WGLWidget::UniformLocation mesh_maxPtUniform_;
448   WGLWidget::UniformLocation singleColor_maxPtUniform_;
449   WGLWidget::UniformLocation position_maxPtUniform_;
450 
451   WGLWidget::UniformLocation dataMinPtUniform_;
452   WGLWidget::UniformLocation mesh_dataMinPtUniform_;
453   WGLWidget::UniformLocation singleColor_dataMinPtUniform_;
454   WGLWidget::UniformLocation position_dataMinPtUniform_;
455   WGLWidget::UniformLocation dataMaxPtUniform_;
456   WGLWidget::UniformLocation mesh_dataMaxPtUniform_;
457   WGLWidget::UniformLocation singleColor_dataMaxPtUniform_;
458   WGLWidget::UniformLocation position_dataMaxPtUniform_;
459 
460   WGLWidget::UniformLocation singleColor_marginUniform_;
461   WGLWidget::UniformLocation position_marginUniform_;
462 
463   WGLWidget::Texture colormapTexture_;
464   WGLWidget::Texture isoLineColorMapTexture_;
465   WGLWidget::Texture pointSpriteTexture_;
466 
467   std::vector<float> minPt_;
468   std::vector<float> maxPt_;
469   WGLWidget::JavaScriptVector jsMinPt_;
470   WGLWidget::JavaScriptVector jsMaxPt_;
471   bool minPtChanged_;
472   bool maxPtChanged_;
473 
474   JSlot changeClippingMinX_;
475   JSlot changeClippingMaxX_;
476   JSlot changeClippingMinY_;
477   JSlot changeClippingMaxY_;
478   JSlot changeClippingMinZ_;
479   JSlot changeClippingMaxZ_;
480 
481   bool clippingLinesEnabled_;
482   WColor clippingLinesColor_;
483 
484   friend class WCartesian3DChart;
485 };
486 
487   }
488 }
489 
490 #endif
491