diff --git a/examples/hexgrid.cpp b/examples/hexgrid.cpp index 3c250489..f013d2e5 100644 --- a/examples/hexgrid.cpp +++ b/examples/hexgrid.cpp @@ -77,6 +77,9 @@ int main() hgv2->setScalarData (&data2); hgv2->hexVisMode = visMode; hgv2->zScale.null_scaling(); + // You can transform the view of the hexgrid in HexGridVisual (transforms may also be applied to the underlying hexgrid) + // This applies a scaling first, and then a reflection. + //hgv2->tfm = sm::mat::reflection (sm::vec::ux()) * sm::mat::identity() * 0.5f; hgv2->addLabel ("hexalign::flat_up", sm::vec<>{ -hg1.width()/2.6f, -hg1.width()/1.6f }, mplot::TextFeatures(0.02f)); hgv2->finalize(); diff --git a/examples/hexgrid_fft.cpp b/examples/hexgrid_fft.cpp index 2c40063c..f0c724b9 100644 --- a/examples/hexgrid_fft.cpp +++ b/examples/hexgrid_fft.cpp @@ -173,7 +173,7 @@ int main() // Real part of hexgrid FFT auto fhgv = std::make_unique>(hfft.hgf.get(), sm::vec{3.0f, 0.0f}); fhgv->set_parent (v.get_id()); - fhgv->zoom = (hfft.Uscale); + fhgv->set_zoom (hfft.Uscale); fhgv->zScale.null_scaling(); fhgv->setScalarData (&fft_r); fhgv->cm.setType (mplot::ColourMapType::GreyscaleInv); diff --git a/examples/hexgrid_image_fft.cpp b/examples/hexgrid_image_fft.cpp index a35e6bb3..8777b10a 100644 --- a/examples/hexgrid_image_fft.cpp +++ b/examples/hexgrid_image_fft.cpp @@ -104,7 +104,7 @@ int main (int argc, char** argv) // Show the real part of FFT on a hexgrid auto fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_r); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); @@ -116,7 +116,7 @@ int main (int argc, char** argv) // Show the imaginary part of FFT on a hexgrid fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, -fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_i); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); @@ -173,7 +173,7 @@ int main (int argc, char** argv) // real fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, -hgw * 1.5f + fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_r); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); @@ -184,7 +184,7 @@ int main (int argc, char** argv) // imag fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, -hgw * 1.5f - fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_i); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); @@ -206,7 +206,7 @@ int main (int argc, char** argv) // real fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, -hgw * 3.0f + fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_r); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); @@ -217,7 +217,7 @@ int main (int argc, char** argv) // image fhgv = std::make_unique>(hfft.hgf.get(), o + sm::vec{ hgw, -hgw * 3.0f - fhgw * 0.6f }); fhgv->set_parent (v.get_id()); - fhgv->zoom = myUscale; + fhgv->set_zoom (myUscale); fhgv->setScalarData (&fft_i); fhgv->colourScale.compute_scaling (-1200, 1200); fhgv->cm.setType (mplot::ColourMapType::CET_D13); diff --git a/mplot/HexGridVisual.cppm b/mplot/HexGridVisual.cppm index 8f20dfb8..866b6126 100644 --- a/mplot/HexGridVisual.cppm +++ b/mplot/HexGridVisual.cppm @@ -52,8 +52,18 @@ export namespace mplot //! something, so that it is visible. void markHex (std::uint32_t hi) { this->markedHexes.insert(hi); } - //! Zoom factor - float zoom = 1.0f; + void set_zoom (const float factor) + { + this->tfm = (sm::mat::identity() * factor) * this->tfm; + } + + void reflect_lr() + { + this->tfm = sm::mat::reflection(sm::vec::ux()) * this->tfm; + } + + //! scalar 'zoom' has been replaced with a transform matrix to allow zoom, but also flip or rotate + sm::mat tfm; //! Show a set of hexes at the zero? bool zerogrid = false; @@ -246,18 +256,21 @@ export namespace mplot // If dataCoords has been populated, use these for hex positions, allowing for // mapping of the 2D hexgrid onto a 3D manifold. if (this->dataCoords == nullptr) { + sm::vec crd = { this->hg->d_x[hi], this->hg->d_y[hi], this->dcopy[hi] }; + sm::vec p = this->tfm * crd.template as(); if (update == false) { - this->vertexPositions[hi * 3] = this->zoom * this->hg->d_x[hi]; - this->vertexPositions[hi * 3 + 1] = this->zoom * this->hg->d_y[hi]; + this->vertexPositions[hi * 3] = p[0]; + this->vertexPositions[hi * 3 + 1] = p[1]; } - this->vertexPositions[hi * 3 + 2] = this->zoom * this->dcopy[hi]; + this->vertexPositions[hi * 3 + 2] = p[2]; } else { // Otherwise use the positions directly in the hexgrid: + sm::vec p = this->tfm * (*this->dataCoords)[hi]; // sm::vec{ (*this->dataCoords)[hi][0], (*this->dataCoords)[hi][1], (*this->dataCoords)[hi][2] }; if (update == false) { - this->vertexPositions[hi * 3] = (*this->dataCoords)[hi][0]; - this->vertexPositions[hi * 3 + 1] = (*this->dataCoords)[hi][1]; + this->vertexPositions[hi * 3] = p[0]; + this->vertexPositions[hi * 3 + 1] = p[1]; } - this->vertexPositions[hi * 3 + 2] = (*this->dataCoords)[hi][2]; + this->vertexPositions[hi * 3 + 2] = p[2]; } if (this->markedHexes.count(hi)) { this->vertexColors[hi * 3] = blkclr[0]; @@ -353,6 +366,9 @@ export namespace mplot sm::vec coordN4 = {}; sm::vec coordN5 = {}; + // The rotation from the transformation in the hexgrid (if any) + sm::mat lt (this->hg->tfm.template as()); + for (std::uint32_t hi = 0; hi < nhex; ++hi) { if (this->dataCoords == nullptr) { @@ -403,10 +419,7 @@ export namespace mplot // Use the centre position as the first location for finding the normal vector vtx_0 = this->dataCoords == nullptr ? sm::vec{ _x, _y, datumC } : coordC; - this->vertex_push (this->zoom * vtx_0, this->vertexPositions); - - // The rotation from the transformation in the hexgrid (if any) - sm::mat lt (this->hg->tfm.template as()); + this->vertex_push ((this->tfm * vtx_0), this->vertexPositions); // A hexagon corner/vertex position sm::vec crnr = {}; @@ -447,7 +460,7 @@ export namespace mplot vtx_1 = coordC; } } - this->vertex_push (this->zoom * vtx_1, this->vertexPositions); + this->vertex_push (this->tfm * vtx_1, this->vertexPositions); // SE vertex @@ -482,7 +495,7 @@ export namespace mplot vtx_2 = coordC; } } - this->vertex_push (this->zoom * vtx_2, this->vertexPositions); + this->vertex_push (this->tfm * vtx_2, this->vertexPositions); // S @@ -517,7 +530,7 @@ export namespace mplot vtx_tmp = coordC; } } - this->vertex_push (this->zoom * vtx_tmp, this->vertexPositions); + this->vertex_push (this->tfm * vtx_tmp, this->vertexPositions); // SW if (this->dataCoords == nullptr) { @@ -551,7 +564,7 @@ export namespace mplot vtx_tmp = coordC; } } - this->vertex_push (this->zoom * vtx_tmp, this->vertexPositions); + this->vertex_push (this->tfm * vtx_tmp, this->vertexPositions); // NW if (this->dataCoords == nullptr) { @@ -585,7 +598,7 @@ export namespace mplot vtx_tmp = coordC; } } - this->vertex_push (this->zoom * vtx_tmp, this->vertexPositions); + this->vertex_push (this->tfm * vtx_tmp, this->vertexPositions); // N if (this->dataCoords == nullptr) { @@ -619,7 +632,7 @@ export namespace mplot vtx_tmp = coordC; } } - this->vertex_push (this->zoom * vtx_tmp, this->vertexPositions); + this->vertex_push (this->tfm * vtx_tmp, this->vertexPositions); // From vtx_0,1,2 compute normal. This sets the correct normal, but note // that there is only one 'layer' of vertices; the back of the