Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 103 additions & 70 deletions mplot/VisualDataModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T, int glver = mplot::gl::version_4_1>
struct VisualDataModel : public VisualModel<glver>
//! VisualDataModel implementation base class containing common functionality - all the
//! sm::scale objects and methods.
template <typename T, int glver>
struct VisualDataModel_impl_base : public VisualModel<glver>
{
VisualDataModel() : mplot::VisualModel<glver>::VisualModel() {}
VisualDataModel (const sm::vec<float> _offset) : mplot::VisualModel<glver>::VisualModel (_offset) {}
VisualDataModel_impl_base() : mplot::VisualModel<glver>::VisualModel() {}
VisualDataModel_impl_base (const sm::vec<float> _offset) : mplot::VisualModel<glver>::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
Expand All @@ -47,9 +47,6 @@ namespace mplot

void setZScale (const sm::scale<T, float>& zscale) { this->zScale = zscale; }
void setCScale (const sm::scale<T, float>& cscale) { this->colourScale = cscale; }
void setScalarData (const std::vector<T>* _data) { this->scalarData = _data; }
void setVectorData (const std::vector<sm::vec<T>>* _vectors) { this->vectorData = _vectors; }
void setDataCoords (std::vector<sm::vec<float>>* _coords) { this->dataCoords = _coords; }

void updateZScale (const sm::scale<T, float>& zscale)
{
Expand All @@ -75,6 +72,75 @@ namespace mplot
this->cm.setType (_cmt);
}

//! An overridable function to set the colour of rect ri
std::array<float, 3> setColour (uint64_t ri)
{
std::array<float, 3> clr = { 0.0f, 0.0f, 0.0f };
if (this->cm.numDatums() == 3) {
if constexpr (std::is_integral<std::decay_t<T>>::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<float> 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<T, float> colourScale;
//! Scale for second colour (when used with vectorData). This is used if the ColourMap cm is
//! ColourMapType::DuoChrome of ColourMapType::HSV.
sm::scale<T, float> colourScale2;
//! scale for third colour (when used with vectorData). Use if ColourMap cm is
//! ColourMapType::TriChrome.
sm::scale<T, float> 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<T, float> zScale;

//! A scaling function for the vectorData. This will scale the lengths of the
//! vectorData.
sm::scale<sm::vec<T>> 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<float> dcopy;
//! A copy of the scalarData (or first field of vectorData), scaled to be a colour value
sm::vvec<float> dcolour;
//! For the second field of vectorData
sm::vvec<float> dcolour2;
//! For the third field of vectorData
sm::vvec<float> 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 <int32_t ctype = 0, typename T = float, int glver = mplot::gl::version_4_1>
struct VisualDataModel_impl : public VisualDataModel_impl_base<T, glver>
{
void setScalarData (const std::vector<T>* _data) { this->scalarData = _data; }
void setVectorData (const std::vector<sm::vec<T>>* _vectors) { this->vectorData = _vectors; }
void setDataCoords (std::vector<sm::vec<float>>* _coords) { this->dataCoords = _coords; }

//! Update the scalar data
virtual void updateData (const std::vector<T>* _data)
{
Expand Down Expand Up @@ -142,28 +208,6 @@ namespace mplot
this->reinit();
}

sm::vec<float> coordsCentroid() const { return sm::algo::centroid (*this->dataCoords); }

//! An overridable function to set the colour of rect ri
std::array<float, 3> setColour (uint64_t ri)
{
std::array<float, 3> clr = { 0.0f, 0.0f, 0.0f };
if (this->cm.numDatums() == 3) {
if constexpr (std::is_integral<std::decay_t<T>>::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()
{
Expand Down Expand Up @@ -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<float> 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<T, float> colourScale;
//! Scale for second colour (when used with vectorData). This is used if the ColourMap cm is
//! ColourMapType::DuoChrome of ColourMapType::HSV.
sm::scale<T, float> colourScale2;
//! scale for third colour (when used with vectorData). Use if ColourMap cm is
//! ColourMapType::TriChrome.
sm::scale<T, float> 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<T, float> zScale;

//! A scaling function for the vectorData. This will scale the lengths of the
//! vectorData.
sm::scale<sm::vec<T>> vectorScale;

sm::vec<float> 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<T>* scalarData = nullptr;
Expand All @@ -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<sm::vec<float>>* 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<float> dcopy;
//! A copy of the scalarData (or first field of vectorData), scaled to be a colour value
sm::vvec<float> dcolour;
//! For the second field of vectorData
sm::vvec<float> dcolour2;
//! For the third field of vectorData
sm::vvec<float> 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<typename T, int glver>
struct VisualDataModel_impl<1, T, glver> : public VisualDataModel_impl_base<T, glver>
{
// span functions
void setScalarData (std::span<T> _data) { this->scalarData = _data; }
// ...etc

// span attributes instead of the std::vector<>*
std::span<T> scalarData;
std::span<sm::vec<T>> vectorData;
std::span<sm::vec<float>> 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 <typename T, int glver = mplot::gl::version_4_1>
struct VisualDataModel : public VisualDataModel_impl<0, T, glver> {};

} // namespace mplot
Loading