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