-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathVisualDataModel.cppm
More file actions
314 lines (271 loc) · 13.7 KB
/
Copy pathVisualDataModel.cppm
File metadata and controls
314 lines (271 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/*!
* VisualModels which have data.
*/
module;
#include <vector>
#include <cstdint>
export module mplot.visualdatamodel;
export import sm.vec;
export import sm.vvec;
export import sm.scale;
import sm.centroid;
export import mplot.visualmodel;
export import mplot.colourmap;
export import mplot.gl.version;
export namespace mplot
{
//! VisualDataModel implementation base class containing common functionality - all the
//! sm::scale objects and methods.
template <typename T, std::int32_t glver>
struct VisualDataModel_impl_base : public VisualModel<glver>
{
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_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
//! do_autoscale set true).
void clearAutoscale()
{
if (this->zScale.do_autoscale == true) { this->zScale.reset(); }
if (this->colourScale.do_autoscale == true) { this->colourScale.reset(); }
if (this->colourScale2.do_autoscale == true) { this->colourScale2.reset(); }
if (this->colourScale3.do_autoscale == true) { this->colourScale3.reset(); }
if (this->vectorScale.do_autoscale == true) { this->vectorScale.reset(); }
}
void clearAutoscaleZ() { if (this->zScale.do_autoscale == true) { this->zScale.reset(); } }
void clearAutoscaleColour()
{
if (this->colourScale.do_autoscale == true) { this->colourScale.reset(); }
if (this->colourScale2.do_autoscale == true) { this->colourScale2.reset(); }
if (this->colourScale3.do_autoscale == true) { this->colourScale3.reset(); }
}
void clearAutoscaleVector() { if (this->vectorScale.do_autoscale == true) { this->vectorScale.reset(); } }
void setZScale (const sm::scale<T, float>& zscale) { this->zScale = zscale; }
void setCScale (const sm::scale<T, float>& cscale) { this->colourScale = cscale; }
void updateZScale (const sm::scale<T, float>& zscale)
{
this->zScale = zscale;
this->reinit();
}
void updateCScale (const sm::scale<T, float>& cscale)
{
this->colourScale = cscale;
this->reinit();
}
void setVectorScale (const sm::scale<sm::vec<T>>& vscale)
{
this->vectorScale = vscale;
this->reinit();
}
void setColourMap (ColourMapType _cmt, const float _hue = 0.0f)
{
this->cm.setHue (_hue);
this->cm.setType (_cmt);
}
//! An overridable function to set the colour of rect ri
std::array<float, 3> setColour (std::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.
std::uint32_t datasize = 0;
};
//! VisualDataModel implementation that deals with std::vector pointers to scalar/vector data
template <std::int32_t ctype = 0, typename T = float, std::int32_t 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)
{
this->scalarData = _data;
this->reinit();
}
//! Update the scalar data with an associated z-scaling
void updateData (const std::vector<T>* _data, const sm::scale<T, float>& zscale)
{
this->scalarData = _data;
this->zScale = zscale;
this->reinit();
}
//! Update the scalar data, along with both the z-scaling and the colour-scaling
void updateData (const std::vector<T>* _data, const sm::scale<T, float>& zscale, const sm::scale<T, float>& cscale)
{
this->scalarData = _data;
this->zScale = zscale;
this->colourScale = cscale;
this->reinit();
}
//! Update coordinate data and scalar data along with z-scaling for scalar data
virtual void updateData (std::vector<sm::vec<float>>* _coords, const std::vector<T>* _data,
const sm::scale<T, float>& zscale)
{
this->dataCoords = _coords;
this->scalarData = _data;
this->zScale = zscale;
this->reinit();
}
//! Update coordinate data and scalar data along with z- and colour-scaling for scalar data
virtual void updateData (std::vector<sm::vec<float>>* _coords, const std::vector<T>* _data,
const sm::scale<T, float>& zscale, const sm::scale<T, float>& cscale)
{
this->dataCoords = _coords;
this->scalarData = _data;
this->zScale = zscale;
this->colourScale = cscale;
this->reinit();
}
//! Update just the coordinate data
virtual void updateCoords (std::vector<sm::vec<float>>* _coords)
{
this->dataCoords = _coords;
this->reinit();
}
//! Update the vector data (for plotting quiver plots)
void updateData (const std::vector<sm::vec<T>>* _vectors)
{
this->vectorData = _vectors;
this->reinit();
}
//! Update both coordinate and vector data
void updateData (std::vector<sm::vec<float>>* _coords, const std::vector<sm::vec<T>>* _vectors)
{
this->dataCoords = _coords;
this->vectorData = _vectors;
this->reinit();
}
//! Find datasize
void determine_datasize()
{
this->datasize = 0;
if (this->vectorData != nullptr && !this->vectorData->empty()) {
this->datasize = this->vectorData->size();
} else if (this->scalarData != nullptr && !this->scalarData->empty()) {
this->datasize = this->scalarData->size();
} // else datasize remains 0
}
// Common function for setting up the z and colour scaling
void setupScaling()
{
this->dcopy.resize (this->datasize, 0);
this->dcolour.resize (this->datasize);
if (this->scalarData != nullptr) {
// What do these scaling operations do to any NaNs in scalarData? They should remain
// NaN. Then in dcopy, might want to make them 0.
this->zScale.transform (*(this->scalarData), this->dcopy);
this->dcopy.replace_nan_with (this->zScale.transform_one(0.0f));
this->colourScale.transform (*(this->scalarData), this->dcolour);
} else if (this->vectorData != nullptr) {
this->dcolour2.resize (this->datasize);
this->dcolour3.resize (this->datasize);
sm::vvec<float> veclens(this->dcopy);
for (std::uint32_t i = 0; i < this->datasize; ++i) {
veclens[i] = (*this->vectorData)[i].length();
this->dcolour[i] = (*this->vectorData)[i][0];
this->dcolour2[i] = (*this->vectorData)[i][1];
// Could also extract a third colour for Trichrome vs Duochrome (or for raw RGB signal)
this->dcolour3[i] = (*this->vectorData)[i][2];
}
this->zScale.transform (veclens, this->dcopy);
// Handle case where this->cm.getType() == mplot::ColourMapType::RGB and there is
// exactly one colour. ColourMapType::RGB (and RGBMono/Grey) assumes R/G/B data all
// in range 0->1 ALREADY and therefore they don't need to be re-scaled with
// this->colourScale.
if (this->cm.getType() != mplot::ColourMapType::RGB
&& this->cm.getType() != mplot::ColourMapType::RGBMono
&& this->cm.getType() != mplot::ColourMapType::RGBGrey) {
this->colourScale.transform (this->dcolour, this->dcolour);
// Dual axis colour maps like Duochrome and HSV will need to use colourScale2 to
// transform their second colour/axis,
this->colourScale2.transform (this->dcolour2, this->dcolour2);
// Similarly for Triple axis maps
this->colourScale3.transform (this->dcolour3, this->dcolour3);
} // else assume dcolour/dcolour2/dcolour3 are all in range 0->1 (or 0-255) already
}
}
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;
//! A container for vector data to visualize. Can also be used for colour of the
//! hexes.
const std::vector<sm::vec<T>>* vectorData = nullptr;
//! The coordinates at which to visualize data, if appropriate (e.g. scatter
//! 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;
};
#if 0 // We could add another implementation here, in which the data are provided as std::span
//! VisualDataModel implementation that deals with std::spans to scalar/vector data
template<typename T, std::int32_t 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, std::int32_t glver = mplot::gl::version_4_1>
struct VisualDataModel : public VisualDataModel_impl<0, T, glver> {};
} // namespace mplot