diff --git a/mplot/VisualDataModel.h b/mplot/VisualDataModel.h index 72ceadd0..fe3d7abd 100644 --- a/mplot/VisualDataModel.h +++ b/mplot/VisualDataModel.h @@ -14,15 +14,15 @@ namespace mplot { - //! Class for VisualModels that visualize data of type T. T is probably float or - //! double, but may be integer types, too. - template - struct VisualDataModel : public VisualModel + //! VisualDataModel implementation base class containing common functionality - all the + //! sm::scale objects and methods. + template + struct VisualDataModel_impl_base : public VisualModel { - VisualDataModel() : mplot::VisualModel::VisualModel() {} - VisualDataModel (const sm::vec _offset) : mplot::VisualModel::VisualModel (_offset) {} + VisualDataModel_impl_base() : mplot::VisualModel::VisualModel() {} + VisualDataModel_impl_base (const sm::vec _offset) : mplot::VisualModel::VisualModel (_offset) {} //! Deconstructor should *not* deallocate data - client code should do that - ~VisualDataModel() {} + ~VisualDataModel_impl_base() {} //! Reset the autoscaled flags so that the next time data is transformed by //! the Scale objects they will autoscale again (assuming they have @@ -47,9 +47,6 @@ namespace mplot void setZScale (const sm::scale& zscale) { this->zScale = zscale; } void setCScale (const sm::scale& cscale) { this->colourScale = cscale; } - void setScalarData (const std::vector* _data) { this->scalarData = _data; } - void setVectorData (const std::vector>* _vectors) { this->vectorData = _vectors; } - void setDataCoords (std::vector>* _coords) { this->dataCoords = _coords; } void updateZScale (const sm::scale& zscale) { @@ -75,6 +72,75 @@ namespace mplot this->cm.setType (_cmt); } + //! An overridable function to set the colour of rect ri + std::array setColour (uint64_t ri) + { + std::array clr = { 0.0f, 0.0f, 0.0f }; + if (this->cm.numDatums() == 3) { + if constexpr (std::is_integral>::value) { + // Differs from above as we divide by 255 to get value in range 0-1 + clr = this->cm.convert (this->dcolour[ri]/255.0f, this->dcolour2[ri]/255.0f, this->dcolour3[ri]/255.0f); + } else { + clr = this->cm.convert (this->dcolour[ri], this->dcolour2[ri], this->dcolour3[ri]); + } + } else if (this->cm.numDatums() == 2) { + // Use vectorData + clr = this->cm.convert (this->dcolour[ri], this->dcolour2[ri]); + } else { + clr = this->cm.convert (this->dcolour[ri]); + } + return clr; + } + + //! All data models use a a colour map. Change the type/hue of this colour map + //! object to generate different types of map. + ColourMap cm; + + //! A Scaling function for the colour map. Perhaps a scale class contains a + //! colour map? If not, then this scale might well be autoscaled. Applied to scalarData. + sm::scale colourScale; + //! Scale for second colour (when used with vectorData). This is used if the ColourMap cm is + //! ColourMapType::DuoChrome of ColourMapType::HSV. + sm::scale colourScale2; + //! scale for third colour (when used with vectorData). Use if ColourMap cm is + //! ColourMapType::TriChrome. + sm::scale colourScale3; + + //! A scale to scale (or autoscale) scalarData. This might be used to set z + //! locations of data coordinates based on scalarData. The scaling may + sm::scale zScale; + + //! A scaling function for the vectorData. This will scale the lengths of the + //! vectorData. + sm::scale> vectorScale; + + /* + * Scaled data. Used in GridVisual classes and PolarVisual or anywhere else where scalarData + * or vectorData are scaled to be z values or colours. + */ + + //! A copy of the scalarData which can be transformed suitably to be the z value of the surface + sm::vvec dcopy; + //! A copy of the scalarData (or first field of vectorData), scaled to be a colour value + sm::vvec dcolour; + //! For the second field of vectorData + sm::vvec dcolour2; + //! For the third field of vectorData + sm::vvec dcolour3; + + //! The length of the data structure that will be visualized. May be length of + //! this->scalarData or of this->vectorData. + unsigned int datasize = 0; + }; + + //! VisualDataModel implementation that deals with std::vector pointers to scalar/vector data + template + struct VisualDataModel_impl : public VisualDataModel_impl_base + { + void setScalarData (const std::vector* _data) { this->scalarData = _data; } + void setVectorData (const std::vector>* _vectors) { this->vectorData = _vectors; } + void setDataCoords (std::vector>* _coords) { this->dataCoords = _coords; } + //! Update the scalar data virtual void updateData (const std::vector* _data) { @@ -142,28 +208,6 @@ namespace mplot this->reinit(); } - sm::vec coordsCentroid() const { return sm::algo::centroid (*this->dataCoords); } - - //! An overridable function to set the colour of rect ri - std::array setColour (uint64_t ri) - { - std::array clr = { 0.0f, 0.0f, 0.0f }; - if (this->cm.numDatums() == 3) { - if constexpr (std::is_integral>::value) { - // Differs from above as we divide by 255 to get value in range 0-1 - clr = this->cm.convert (this->dcolour[ri]/255.0f, this->dcolour2[ri]/255.0f, this->dcolour3[ri]/255.0f); - } else { - clr = this->cm.convert (this->dcolour[ri], this->dcolour2[ri], this->dcolour3[ri]); - } - } else if (this->cm.numDatums() == 2) { - // Use vectorData - clr = this->cm.convert (this->dcolour[ri], this->dcolour2[ri]); - } else { - clr = this->cm.convert (this->dcolour[ri]); - } - return clr; - } - //! Find datasize void determine_datasize() { @@ -219,28 +263,7 @@ namespace mplot } } - //! All data models use a a colour map. Change the type/hue of this colour map - //! object to generate different types of map. - ColourMap cm; - - //! A Scaling function for the colour map. Perhaps a scale class contains a - //! colour map? If not, then this scale might well be autoscaled. Applied to scalarData. - sm::scale colourScale; - //! Scale for second colour (when used with vectorData). This is used if the ColourMap cm is - //! ColourMapType::DuoChrome of ColourMapType::HSV. - sm::scale colourScale2; - //! scale for third colour (when used with vectorData). Use if ColourMap cm is - //! ColourMapType::TriChrome. - sm::scale colourScale3; - - //! A scale to scale (or autoscale) scalarData. This might be used to set z - //! locations of data coordinates based on scalarData. The scaling may - sm::scale zScale; - - //! A scaling function for the vectorData. This will scale the lengths of the - //! vectorData. - sm::scale> vectorScale; - + sm::vec coordsCentroid() const { return sm::algo::centroid (*this->dataCoords); } //! The data to visualize. T may simply be float or double, or, if the //! visualization is of directional information, such as in a quiver plot, const std::vector* scalarData = nullptr; @@ -253,24 +276,34 @@ namespace mplot //! graph, quiver plot). Note fixed type of float, which is suitable for //! OpenGL coordinates. Not const as child code may resize or update content. std::vector>* dataCoords = nullptr; + }; - /* - * Scaled data. Used in GridVisual classes and PolarVisual or anywhere else where scalarData - * or vectorData are scaled to be z values or colours. - */ - - //! A copy of the scalarData which can be transformed suitably to be the z value of the surface - sm::vvec dcopy; - //! A copy of the scalarData (or first field of vectorData), scaled to be a colour value - sm::vvec dcolour; - //! For the second field of vectorData - sm::vvec dcolour2; - //! For the third field of vectorData - sm::vvec dcolour3; +#if 0 // We could add another implementation here, in which the data are provided as std::span - //! The length of the data structure that will be visualized. May be length of - //! this->scalarData or of this->vectorData. - unsigned int datasize = 0; + //! VisualDataModel implementation that deals with std::spans to scalar/vector data + template + struct VisualDataModel_impl<1, T, glver> : public VisualDataModel_impl_base + { + // span functions + void setScalarData (std::span _data) { this->scalarData = _data; } + // ...etc + + // span attributes instead of the std::vector<>* + std::span scalarData; + std::span> vectorData; + std::span> dataCoords; }; +#endif + + /*! + * VisualDataModel is an optional 'data layer' for VisualModels. It is used in several of the + * built-in VisualModels such as HexGridVisual, GridVisual and ScatterVisual. It provides a way + * to refer to the data (such as using std::vector<> pointers) and all the scaling functions + * that are useful for turning the data into colours and positions in the scene. It is not + * necessary to use VisualDataModel as your base class; you can derive directly from VisualModel + * (for an example see InstancedScatterVisual) + */ + template + struct VisualDataModel : public VisualDataModel_impl<0, T, glver> {}; } // namespace mplot