Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
scripts. 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
37 changes: 34 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 @@ -204,6 +207,10 @@ void GLVisServer(int portnum, bool save_stream, bool fix_elem_orient,
if (server.good())
{
cout << "Waiting for data on port " << portnum << " ..." << endl;
if (!point_coords.empty())
{
cout << point_coords.size() << " points loaded (Ctrl+l to toggle)" << endl;
}
}
else
{
Expand Down Expand Up @@ -308,7 +315,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 +390,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 +501,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 +622,25 @@ 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;
ifs >> num_points;
num_points = ReadPointLine(ifs, num_points,
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 +722,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
48 changes: 48 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,50 @@ class VectorExtrudeCoefficient : public VectorCoefficient
QuadratureFunction* Extrude1DQuadFunction(Mesh *mesh, Mesh *mesh2d,
QuadratureFunction *qf, int ny);

/// 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, int num_points,
std::vector<std::array<double,3>> &points,
std::ostream &warn)
{
points.clear();

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 +96,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
7 changes: 7 additions & 0 deletions lib/data_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
#include <map>
#include <string>
#include <memory>
#include <array>
#include <vector>
#include <iosfwd>
#include <utility>
#include <functional>

Expand Down Expand Up @@ -139,6 +141,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 +281,8 @@ struct DataState
{ if (cgrid_f) { FindComplexValueRange(minv, maxv, vec2scal, scale); } else { minv = maxv = 0.; } }
};

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

#endif // GLVIS_DATA_STATE_HPP
18 changes: 18 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,22 @@ bool ScriptController::ExecuteScriptCommand()
MyExpose();
}
break;
case Command::PointLine:
{
int num_points;
scr >> num_points;

num_points = ReadPointLine(scr, num_points,
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
56 changes: 56 additions & 0 deletions lib/threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,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 +854,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 +942,7 @@ enum class ThreadCommand
AxisLabels,
Pause,
Autopause,
PointLine,
//----------
Max
};
Expand Down Expand Up @@ -968,6 +995,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 +1622,34 @@ bool communication_thread::execute_one(std::string ident)
}
}
break;
case ThreadCommand::PointLine:
{
// in parallel, use the point line data from rank 0
int num_points;
*is[0] >> num_points;

std::vector<std::array<double,3>> points;
num_points = ReadPointLine(*is[0], num_points, points, cerr);

// assuming that all ranks have sent point data, reads on the remaining
// ranks to sync parallel streams
for (size_t i = 1; i < is.size(); i++)
{
*is[i] >> ws >> ident; // 'pointline'
int np;
*is[i] >> np;
for (int j = 0; j < np; j++)
{
double x, y, z;
*is[i] >> x >> y >> z; // ignore
}
}

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