Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GridVisual selected pixels border enhancements #306

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ if(ARMADILLO_FOUND)
target_link_libraries(grid_border GLEW::GLEW)
endif()

add_executable(grid_border2 grid_border2.cpp)
target_link_libraries(grid_border2 OpenGL::GL glfw Freetype::Freetype)
if(USE_GLEW)
target_link_libraries(grid_border2 GLEW::GLEW)
endif()


# Like HexGrid::resampleImage, this one uses an omp call that only works on Mac with
# libomp, so avoid compiling this example on a Mac.
Expand Down
64 changes: 64 additions & 0 deletions examples/grid_border2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* An example morph::Visual scene, containing a Grid, and using GridVisual. This is for
* debugging/demonstrating grid borders. see aso grid_border.cpp
*/

#include <iostream>
#include <vector>
#include <cmath>
#include <chrono>

#include <morph/mathconst.h>
#include <morph/vec.h>
#include <morph/Visual.h>
#include <morph/VisualDataModel.h>
#include <morph/GridVisual.h>
#include <morph/Grid.h>

int main()
{
morph::Visual v(1600, 1000, "GridVisual borders");

// Create a grid to show in the scene
constexpr unsigned int Nside = 4; // You can change this
constexpr morph::vec<float, 2> grid_spacing = {0.5f, 0.5f};
morph::Grid grid(Nside, Nside, grid_spacing);
std::cout << "Number of pixels in grid:" << grid.n() << std::endl;

// Make some dummy data (a sine wave) to make an interesting surface
std::vector<float> data(grid.n(), 0.0);

// Set data
constexpr float length = morph::mathconst<float>::pi_over_4;
for (unsigned int ri=0; ri<grid.n(); ++ri) {
auto coord = grid[ri];
data[ri] = std::sin(length * coord[0]) * std::sin(0.5f * length * coord[1]) ; // Range 0->1
}

float step = 0.6f;
// Add a GridVisual to display the Grid within the morph::Visual scene
morph::vec<float, 3> offset = { -step * grid.width(), -step * grid.width(), 0.0f };

auto gv = std::make_unique<morph::GridVisual<float>>(&grid, offset);
v.bindmodel (gv);
gv->gridVisMode = morph::GridVisMode::RectInterp;
gv->setScalarData (&data);
gv->cm.setType (morph::ColourMapType::Cork);
gv->zScale.do_autoscale = false;
gv->zScale.setParams (0, 0);
gv->colourScale.do_autoscale = false;
gv->colourScale.compute_scaling (-1, 1);

// Border specific parameters
gv->showborder = true;
gv->border_thickness = 0.15f; // of a pixel
gv->border_z_offset = 0.0f;
gv->border_colour = morph::colour::black;

gv->finalize();
v.addVisualModel (gv);

v.keepOpen();

return 0;
}
141 changes: 103 additions & 38 deletions morph/GridVisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,12 @@ namespace morph {
morph::vec<float, 4> cg_extents = this->grid->extents(); // {xmin, xmax, ymin, ymax}
morph::vec<float, 2> dx = this->grid->get_dx();
float bthick = this->border_thickness_fixed ? this->border_thickness_fixed : dx[0] * this->border_thickness;
float bz = 0.02f;
float left = cg_extents[0] - (dx[0]/2.0f) + this->centering_offset[0];
float right = cg_extents[1] + (dx[0]/2.0f) + this->centering_offset[0];
float bot = cg_extents[2] - (dx[1]/2.0f) + this->centering_offset[1];
float top = cg_extents[3] + (dx[1]/2.0f) + this->centering_offset[1];
morph::vec<float> lb = {{left, bot, bz}}; // z?
morph::vec<float> lt = {{left, top, bz}};
morph::vec<float> rt = {{right, top, bz}};
morph::vec<float> rb = {{right, bot, bz}};

this->computeFlatLine(lb, lt, rb, rt, this->uz, this->border_colour, bthick);
this->computeFlatLine(lt, rt, lb, rb, this->uz, this->border_colour, bthick);
this->computeFlatLine(rt, rb, lt, lb, this->uz, this->border_colour, bthick);
this->computeFlatLine(rb, lb, rt, lt, this->uz, this->border_colour, bthick);
morph::vec<float, 4> r_extents = { left, right, bot, top };
this->rectangularBorder (r_extents, this->border_z_offset, bthick, this->border_colour);
}

//! function to draw the grid (border around each pixel)
Expand Down Expand Up @@ -152,46 +144,104 @@ namespace morph {
// Draw around all pixels
morph::vec<float, 4> cg_extents = this->grid->extents(); // {xmin, xmax, ymin, ymax}
morph::vec<float, 2> dx = this->grid->get_dx();
float gridthick = this->grid_thickness_fixed ? this->grid_thickness_fixed : dx[0] * this->grid_thickness;
float bz = 0.05f;
float gridthick = this->grid_thickness_fixed ? this->grid_thickness_fixed : dx[0] * this->grid_thickness;

unsigned int pix_width = static_cast<unsigned int>(std::round((cg_extents[1] - cg_extents[0] + dx[0])/dx[0]));

// check if the size of selected_pix_border_colour is the same as the size of selected_pix_indexes
if (selected_pix_indexes.size()>selected_pix_border_colour.size()){
std::cerr << "[GridVisual::drawSelectedPixBorder] the number of pixel indices is higher than the number of colours,"
<< " the last color will be used for the remaining pixels" << std::endl;
while(selected_pix_border_colour.size() < selected_pix_indexes.size()) {
selected_pix_border_colour.push_back(selected_pix_border_colour.back());
}
// If user has NOT resized and populated selected_pix_border_colour AND
// selected_pix_indexes, resize and default the colour here.
if (this->selected_pix_border_colour.size() < this->selected_pix_indexes.size()) {
this->selected_pix_border_colour.resize (this->selected_pix_indexes.size(), this->border_colour);
}

float grid_left = cg_extents[0] - (dx[0]/2.0f) + this->centering_offset[0];
float grid_bot = cg_extents[2] - (dx[1]/2.0f) + this->centering_offset[1];

// loop through each pixel
for (unsigned int i=0; i < selected_pix_indexes.size(); ++i ) {
for (std::size_t i=0; i < selected_pix_indexes.size(); ++i ) {
unsigned int r = selected_pix_indexes[i] % pix_width;
unsigned int c = selected_pix_indexes[i] / pix_width;
// {xmin, xmax, ymin, ymax}
morph::vec<float, 4> r_extents = { (grid_left + r * dx[0]), (grid_left + (r+1) * dx[0]), (grid_bot + c * dx[1]), (grid_bot + (c+1) * dx[1]) };
this->rectangularBorder (r_extents, this->grid_z_offset, gridthick, this->selected_pix_border_colour[i]);
}
}

// Draw a GridVisual border
// r_extents: rectangular extents of the Grid
void rectangularBorder (const morph::vec<float, 4>& r_extents,
const float bz, const float linethickness,
const std::array<float, 3>& clr)
{
morph::vec<float> lb = { r_extents[0], r_extents[2], bz };
morph::vec<float> lt = { r_extents[0], r_extents[3], bz };
morph::vec<float> rt = { r_extents[1], r_extents[3], bz };
morph::vec<float> rb = { r_extents[1], r_extents[2], bz };
#if 1
morph::vec<float> lbout = { r_extents[0] - linethickness, r_extents[2] - linethickness, bz };
morph::vec<float> ltout = { r_extents[0] - linethickness, r_extents[3] + linethickness, bz };
morph::vec<float> rtout = { r_extents[1] + linethickness, r_extents[3] + linethickness, bz };
morph::vec<float> rbout = { r_extents[1] + linethickness, r_extents[2] - linethickness, bz };

this->computeFlatQuad (lbout, ltout, lt, lb, clr);
this->computeFlatQuad (lt, ltout, rtout, rt, clr);
this->computeFlatQuad (rt, rtout, rbout, rb, clr);
this->computeFlatQuad (rb, rbout, lbout, lb, clr);
#else
// draw the vertical from bottom left to top left
this->computeFlatLine(lb, lt, rb, rt, this->uz, clr, linethickness);
// draw the horizontal from bottom left to bottom right
this->computeFlatLine(rb, lb, rt, lt, this->uz, clr, linethickness);
// draw the vertical from bottom right to top right
this->computeFlatLine(rt, rb, lt, lb, this->uz, clr, linethickness);
// draw the horizontal from top left to top right
this->computeFlatLine(lt, rt, lb, rb, this->uz, clr, linethickness);
#endif
}

//! Draw a border around the selected pixels, using the first selected pix colour
void drawSelectedPixBorderEnclosing()
{
// Draw around all pixels
morph::vec<float, 4> cg_extents = this->grid->extents(); // {xmin, xmax, ymin, ymax}
morph::vec<float, 2> dx = this->grid->get_dx();
float gridthick = this->grid_thickness_fixed ? this->grid_thickness_fixed : dx[0] * this->grid_thickness;

unsigned int pix_width = static_cast<unsigned int>(std::round((cg_extents[1] - cg_extents[0] + dx[0])/dx[0]));

if (this->selected_pix_border_colour.empty()) {
this->selected_pix_border_colour.push_back (this->border_colour);
}

float grid_left = cg_extents[0] - (dx[0]/2.0f) + this->centering_offset[0];
float grid_bot = cg_extents[2] - (dx[1]/2.0f) + this->centering_offset[1];

morph::range<float> l_r; // left extent range
l_r.search_init();
morph::range<float> r_r;
r_r.search_init();
morph::range<float> b_r;
b_r.search_init();
morph::range<float> t_r;
t_r.search_init();

// Find extents of our selected pixels
for (std::size_t i = 0; i < this->selected_pix_indexes.size(); ++i) {
I r = this->selected_pix_indexes[i] % pix_width;
I c = this->selected_pix_indexes[i] / pix_width;
float left = grid_left + (r * dx[0]);
float right = left + dx[0];
float bot = grid_bot + (c * dx[1]);
float top = bot + dx[1];
morph::vec<float> lb = {{left, bot, bz}}; // z?
morph::vec<float> lt = {{left, top, bz}};
morph::vec<float> rt = {{right, top, bz}};
morph::vec<float> rb = {{right, bot, bz}};

// draw the vertical from bottom left to top left
this->computeFlatLine(lb, lt, rb, rt, this->uz, this->selected_pix_border_colour[i], gridthick);
// draw the horizontal from bottom left to bottom right
this->computeFlatLine(rb, lb, rt, lt, this->uz, this->selected_pix_border_colour[i], gridthick);
// draw the vertical from bottom right to top right
this->computeFlatLine(rt, rb, lt, lb, this->uz, this->selected_pix_border_colour[i], gridthick);
// draw the horizontal from top left to top right
this->computeFlatLine(lt, rt, lb, rb, this->uz, this->selected_pix_border_colour[i], gridthick);
l_r.update (left);
r_r.update (right);
b_r.update (bot);
t_r.update (top);
}

// xmin xmax ymin ymax
morph::vec<float, 4> r_extents = { l_r.min, r_r.max, b_r.min, t_r.max };
this->rectangularBorder (r_extents, this->grid_z_offset, gridthick, this->selected_pix_border_colour[0]);
}

// Common function to setup scaling. Called by all initializeVertices subroutines. Also
Expand Down Expand Up @@ -286,7 +336,10 @@ namespace morph {
this->drawGrid();
}
if (this->showselectedpixborder == true) {
this->drawSelectedPixBorder();
this->drawSelectedPixBorder();
}
if (this->showselectedpixborder_enclosing == true) {
this->drawSelectedPixBorderEnclosing();
}
if (this->showorigin == true) {
this->computeSphere (morph::vec<float>{0, 0, 0}, morph::colour::crimson, 0.25f * this->grid->get_dx()[0]);
Expand Down Expand Up @@ -807,6 +860,9 @@ namespace morph {
//! If you need to override the pixels-relationship to the grid thickness, set it here
float grid_thickness_fixed = 0.0f;

//! How far in z to locate the grid lines?
float grid_z_offset = 0.02f;

//! Set true to draw a border around the outside
bool showborder = false;

Expand All @@ -819,16 +875,25 @@ namespace morph {
//! If you need to override the pixels-relationship to the border thickness, set it here
float border_thickness_fixed = 0.0f;

//! new option for border around selected pixels
//! Where in z to locate the border lines?
float border_z_offset = 0.02f;

/*!
* If true, draw a border around selected pixels (with a full border around each selected
* pixel). The selected pixels are chosen by the client code, which should populate
* selected_pix_indexes.
*/
bool showselectedpixborder = false;

//! list of the pixel to have a border
std::vector<unsigned int> selected_pix_indexes;
//! If true, draw a rectangular border enclosing the selected pixels
bool showselectedpixborder_enclosing = false;

//! list of those pixel indices that should be drawn with a border
std::vector<I> selected_pix_indexes;

//! The colour for the border
std::vector<std::array<float, 3>> selected_pix_border_colour;


// If true, interpolate the colour of the sides of columns on a column grid
bool interpolate_colour_sides = false;

Expand Down
Loading