Skip to content
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
9 changes: 9 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
https://glvis.org


Version 4.5.1 (development)
===========================
- Added an optional point line overlay (useful e.g. for reference curves), which
can be toggled with 'Ctrl+l'. Points can be loaded from a file with the '-pts'
option, sent via socket with the 'pointline' command, or specified in a GLVis
script. The overlay appears as a red line connecting the given points. The
points line format is: number of points, followed by x y z coordinates.


Version 4.5 released on Feb 6, 2026
===================================

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ Key commands
GLVis will use `SDL` to take screenshots in `bmp` format, which it will then
convert to `png` if ImageMagick's `convert` tool is available.
- <kbd>G</kbd> – 3D scene export to [glTF format](https://www.khronos.org/gltf)
- <kbd>Ctrl</kbd> + <kbd>l</kbd> – Toggle point line (see `-pts` option)
- <kbd>Ctrl</kbd> + <kbd>p</kbd> – Print to a PDF file using `gl2ps`. Other
vector formats (SVG, EPS) are also possible, but keep in mind that the
printing takes a while and the generated files are big.
Expand Down
29 changes: 26 additions & 3 deletions glvis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// GLVis - an OpenGL visualization server based on the MFEM library

#include <limits>
#include <array>
#include <iostream>
#include <fstream>
#include <string>
Expand Down Expand Up @@ -157,7 +158,9 @@ class Session
};

void GLVisServer(int portnum, bool save_stream, bool fix_elem_orient,
bool save_coloring, string plot_caption, bool headless = false)
bool save_coloring, string plot_caption,
std::vector<std::array<double,3>> point_coords,
bool headless = false)
{
std::vector<Session> current_sessions;
string data_type;
Expand Down Expand Up @@ -308,7 +311,7 @@ void GLVisServer(int portnum, bool save_stream, bool fix_elem_orient,
}

Session new_session(fix_elem_orient, save_coloring, plot_caption, headless);

if (!point_coords.empty()) { new_session.GetState().point_coords = point_coords; }
constexpr int tmp_filename_size = 50;
char tmp_file[tmp_filename_size];
if (save_stream)
Expand Down Expand Up @@ -383,6 +386,7 @@ int main (int argc, char *argv[])
const char *palette_name = string_none;
const char *window_title = string_default;
const char *font_name = string_default;
const char *points_file = string_none;
int portnum = 19916;
bool persistent = true;
int multisample = GetMultisample();
Expand Down Expand Up @@ -493,6 +497,8 @@ int main (int argc, char *argv[])
args.AddOption(&enable_hidpi, "-hidpi", "--high-dpi",
"-nohidpi", "--no-high-dpi",
"Enable/disable support for HiDPI at runtime, if supported.");
args.AddOption(&points_file, "-pts", "--points-file",
"Points file: number of points, followed by x y z coordinates.");

cout << endl
<< " _/_/_/ _/ _/ _/ _/" << endl
Expand Down Expand Up @@ -612,6 +618,21 @@ int main (int argc, char *argv[])

GLVisGeometryRefiner.SetType(geom_ref_type);

// Load points file if specified (Ctrl+l to toggle)
if (points_file != string_none)
{
ifstream ifs(points_file);
if (!ifs)
{
cout << "Cannot open points file: " << points_file << endl;
}
else
{
int num_points = ReadPointLine(ifs, win.data_state.point_coords, cerr);
cout << "Loaded " << num_points << " points from " << points_file << endl;
}
}

string data_type;

// check for saved stream file
Expand Down Expand Up @@ -693,7 +714,9 @@ int main (int argc, char *argv[])
std::thread serverThread{GLVisServer, portnum, save_stream,
win.data_state.fix_elem_orient,
win.data_state.save_coloring,
win.plot_caption, win.headless};
win.plot_caption,
std::move(win.data_state.point_coords),
win.headless};

// Start message loop in main thread
MainThreadLoop(win.headless, persistent);
Expand Down
49 changes: 49 additions & 0 deletions lib/data_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
// CONTRIBUTING.md for details.

#include <cstdlib>
#include <istream>
#include <ostream>
#include <string>

#include "data_state.hpp"
#include "visual.hpp"
Expand All @@ -36,6 +39,51 @@ class VectorExtrudeCoefficient : public VectorCoefficient
QuadratureFunction* Extrude1DQuadFunction(Mesh *mesh, Mesh *mesh2d,
QuadratureFunction *qf, int ny);


int ReadPointLine(std::istream &in,
std::vector<std::array<double,3>> &points,
std::ostream &warn)
{
points.clear();

int num_points;
in >> num_points;

if (num_points > 0)
{
points.reserve(num_points);
}

for (int j = 0; num_points < 0 || j < num_points; j++)
{
double x, y, z;
if (in >> x >> y >> z)
{
points.push_back({x, y, z});
}
else
{
warn << "Warning: failed reading point " << j << std::endl;
break;
}
}

const int read_points = (int) points.size();
if (read_points < 2)
{
warn << "Warning: ReadPointLine needs at least 2 points (got "
<< read_points << ")" << std::endl;
}
else if (read_points < num_points)
{
warn << "Warning: ReadPointLine expected " << num_points
<< " (got " << read_points << ")" << std::endl;
}

return read_points;
}


DataState &DataState::operator=(DataState &&ss)
{
internal = std::move(ss.internal);
Expand All @@ -49,6 +97,7 @@ DataState &DataState::operator=(DataState &&ss)
save_coloring = ss.save_coloring;
keep_attr = ss.keep_attr;
cmplx_phase = ss.cmplx_phase;
point_coords = std::move(ss.point_coords);

return *this;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/data_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <map>
#include <string>
#include <memory>
#include <array>
#include <vector>
#include <utility>
#include <functional>
Expand Down Expand Up @@ -139,6 +140,7 @@ struct DataState
bool save_coloring{false};
bool keep_attr{false};
double cmplx_phase{0.};
std::vector<std::array<double,3>> point_coords; // point line (from -pts)

DataState() = default;
DataState(DataState &&ss) { *this = std::move(ss); }
Expand Down Expand Up @@ -278,4 +280,11 @@ struct DataState
{ if (cgrid_f) { FindComplexValueRange(minv, maxv, vec2scal, scale); } else { minv = maxv = 0.; } }
};

/// Helper to read a point line file (num_points, followed by x y z coordinates)
/// that is called in glvis.cpp and the 'pointline' commands in threads.cpp and
/// script_controller.cpp.
int ReadPointLine(std::istream &in,
std::vector<std::array<double,3>> &points,
std::ostream &warn);

#endif // GLVIS_DATA_STATE_HPP
13 changes: 13 additions & 0 deletions lib/script_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ enum class Command
Scale,
Translate,
PlotCaption,
PointLine,
Headless,
//----------
Max
Expand Down Expand Up @@ -125,6 +126,7 @@ ScriptCommands::ScriptCommands()
(*this)[Command::Scale] = {"scale", "<scale>", "Set the scaling factor."};
(*this)[Command::Translate] = {"translate", "<x> <y> <z>", "Set the translation coordinates."};
(*this)[Command::PlotCaption] = {"plot_caption", "'<caption>'", "Set the plot caption."};
(*this)[Command::PointLine] = {"pointline", "<num_points> <x y z>...", "Set point line overlay coordinates."};
(*this)[Command::Headless] = {"headless", "", "Change the session to headless."};
}

Expand Down Expand Up @@ -843,6 +845,17 @@ bool ScriptController::ExecuteScriptCommand()
MyExpose();
}
break;
case Command::PointLine:
{
int num_points = ReadPointLine(scr, win.data_state.point_coords, cerr);

win.vs->SetPointLineVisible(true);
win.vs->PreparePointLine();
MyExpose();

cout << "Script: pointline: " << num_points << " points" << endl;
}
break;
case Command::Headless:
cout << "The session cannot become headless after initialization" << endl;
break;
Expand Down
50 changes: 50 additions & 0 deletions lib/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <array>
#include <algorithm>
#include <sstream>
#include <thread>
#include <vector>

Expand Down Expand Up @@ -240,6 +241,21 @@ int GLVisCommand::ColorbarNumberFormat(string formatting)
return 0;
}

int GLVisCommand::PointLine(std::vector<std::array<double,3>> points)
{
if (lock() < 0)
{
return -1;
}
command = Command::POINT_LINE;
point_coords = std::move(points);
if (signal() < 0)
{
return -2;
}
return 0;
}

int GLVisCommand::Pause()
{
if (lock() < 0)
Expand Down Expand Up @@ -839,6 +855,17 @@ int GLVisCommand::Execute()
break;
}

case Command::POINT_LINE:
{
cout << "Command: pointline: " << point_coords.size()
<< " points" << endl;
win.data_state.point_coords = std::move(point_coords);
win.vs->SetPointLineVisible(true);
win.vs->PreparePointLine();
MyExpose();
break;
}

case Command::QUIT:
{
thread_wnd->signalQuit();
Expand Down Expand Up @@ -916,6 +943,7 @@ enum class ThreadCommand
AxisLabels,
Pause,
Autopause,
PointLine,
//----------
Max
};
Expand Down Expand Up @@ -968,6 +996,7 @@ ThreadCommands::ThreadCommands()
(*this)[ThreadCommand::AxisLabels] = {"axis_labels", "'<x label>' '<y label>' '<z label>'", "Set labels of the axes."};
(*this)[ThreadCommand::Pause] = {"pause", "", "Stop the stream until space is pressed."};
(*this)[ThreadCommand::Autopause] = {"autopause", "<0/off/1/on>", "Turns off or on autopause."};
(*this)[ThreadCommand::PointLine] = {"pointline", "<num_points> <x y z>...", "Set point line overlay coordinates."};
}

communication_thread::communication_thread(StreamCollection _is,
Expand Down Expand Up @@ -1594,6 +1623,27 @@ bool communication_thread::execute_one(std::string ident)
}
}
break;
case ThreadCommand::PointLine:
{
// in parallel, use the point line data from rank 0
std::vector<std::array<double,3>> points;
int num_points = ReadPointLine(*is[0], points, cerr);

// assuming that all ranks have sent the same point data, perform dummy
// reads on the remaining ranks to sync parallel streams
std::vector<std::array<double,3>> dummy_points;
std::ostringstream dummy_stream;
for (size_t i = 1; i < is.size(); i++)
{
*is[i] >> ws >> ident; // 'pointline'
ReadPointLine(*is[i], dummy_points, dummy_stream);
}

glvis_command->PointLine(std::move(points));

cout << "Received " << num_points << " points" << endl;
}
break;
case ThreadCommand::Max: //dummy
break;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/threads.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#ifndef GLVIS_THREADS_HPP
#define GLVIS_THREADS_HPP

#include <array>
#include <mfem.hpp>
#include <thread>
#include <atomic>
Expand Down Expand Up @@ -62,6 +63,7 @@ class GLVisCommand
LEVELLINES,
AXIS_NUMBERFORMAT,
COLORBAR_NUMBERFORMAT,
POINT_LINE,
QUIT
};

Expand Down Expand Up @@ -97,6 +99,7 @@ class GLVisCommand
std::string autopause_mode;
std::string axis_formatting;
std::string colorbar_formatting;
std::vector<std::array<double,3>> point_coords;

// internal variables
int autopause;
Expand Down Expand Up @@ -137,6 +140,7 @@ class GLVisCommand
int Levellines(double minv, double maxv, int number);
int AxisNumberFormat(std::string formatting);
int ColorbarNumberFormat(std::string formatting);
int PointLine(std::vector<std::array<double, 3>> points);
int Camera(const double cam[]);
int Autopause(const char *mode);
int Quit();
Expand Down
Loading
Loading