From 3a84ad68fc415e61a28e1c4fb6371e22ba76d135 Mon Sep 17 00:00:00 2001 From: Tzanio Kolev Date: Mon, 9 Mar 2026 19:15:27 -0700 Subject: [PATCH 1/5] Added the ability to plot user-provided point line, see -pts and Ctrl+l --- CHANGELOG | 9 +++++ README.md | 1 + glvis.cpp | 37 ++++++++++++++++++-- lib/data_state.cpp | 48 +++++++++++++++++++++++++ lib/data_state.hpp | 7 ++++ lib/script_controller.cpp | 18 ++++++++++ lib/threads.cpp | 56 ++++++++++++++++++++++++++++++ lib/threads.hpp | 4 +++ lib/vsdata.cpp | 73 +++++++++++++++++++++++++++++++++++++-- lib/vsdata.hpp | 9 +++++ lib/vssolution.cpp | 2 ++ lib/vssolution3d.cpp | 2 ++ lib/vsvector.cpp | 2 ++ lib/vsvector3d.cpp | 2 ++ 14 files changed, 265 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 46abcd48..a6e13d2e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 =================================== diff --git a/README.md b/README.md index 2a78818e..e74b1a53 100644 --- a/README.md +++ b/README.md @@ -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. - G – 3D scene export to [glTF format](https://www.khronos.org/gltf) +- Ctrl + l – Toggle point line (see `-pts` option) - Ctrl + p – 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. diff --git a/glvis.cpp b/glvis.cpp index c68418b2..cd9cf7fb 100644 --- a/glvis.cpp +++ b/glvis.cpp @@ -12,6 +12,7 @@ // GLVis - an OpenGL visualization server based on the MFEM library #include +#include #include #include #include @@ -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> point_coords, + bool headless = false) { std::vector current_sessions; string data_type; @@ -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 { @@ -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) @@ -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(); @@ -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 @@ -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 @@ -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); diff --git a/lib/data_state.cpp b/lib/data_state.cpp index 31c222f0..129a3544 100644 --- a/lib/data_state.cpp +++ b/lib/data_state.cpp @@ -10,6 +10,9 @@ // CONTRIBUTING.md for details. #include +#include +#include +#include #include "data_state.hpp" #include "visual.hpp" @@ -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> &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); @@ -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; } diff --git a/lib/data_state.hpp b/lib/data_state.hpp index 18182fc6..418cfeae 100644 --- a/lib/data_state.hpp +++ b/lib/data_state.hpp @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include @@ -139,6 +141,7 @@ struct DataState bool save_coloring{false}; bool keep_attr{false}; double cmplx_phase{0.}; + std::vector> point_coords; // point line (from -pts) DataState() = default; DataState(DataState &&ss) { *this = std::move(ss); } @@ -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> &points, + std::ostream &warn); + #endif // GLVIS_DATA_STATE_HPP diff --git a/lib/script_controller.cpp b/lib/script_controller.cpp index e8bab160..f3e49c22 100644 --- a/lib/script_controller.cpp +++ b/lib/script_controller.cpp @@ -61,6 +61,7 @@ enum class Command Scale, Translate, PlotCaption, + PointLine, Headless, //---------- Max @@ -125,6 +126,7 @@ ScriptCommands::ScriptCommands() (*this)[Command::Scale] = {"scale", "", "Set the scaling factor."}; (*this)[Command::Translate] = {"translate", " ", "Set the translation coordinates."}; (*this)[Command::PlotCaption] = {"plot_caption", "''", "Set the plot caption."}; + (*this)[Command::PointLine] = {"pointline", " ...", "Set point line overlay coordinates."}; (*this)[Command::Headless] = {"headless", "", "Change the session to headless."}; } @@ -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; diff --git a/lib/threads.cpp b/lib/threads.cpp index d6c4690d..7da13693 100644 --- a/lib/threads.cpp +++ b/lib/threads.cpp @@ -240,6 +240,21 @@ int GLVisCommand::ColorbarNumberFormat(string formatting) return 0; } +int GLVisCommand::PointLine(std::vector> 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) @@ -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(); @@ -916,6 +942,7 @@ enum class ThreadCommand AxisLabels, Pause, Autopause, + PointLine, //---------- Max }; @@ -968,6 +995,7 @@ ThreadCommands::ThreadCommands() (*this)[ThreadCommand::AxisLabels] = {"axis_labels", "'' '' ''", "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", " ...", "Set point line overlay coordinates."}; } communication_thread::communication_thread(StreamCollection _is, @@ -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> 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; } diff --git a/lib/threads.hpp b/lib/threads.hpp index 8b3248ef..4217a32a 100644 --- a/lib/threads.hpp +++ b/lib/threads.hpp @@ -12,6 +12,7 @@ #ifndef GLVIS_THREADS_HPP #define GLVIS_THREADS_HPP +#include #include #include #include @@ -62,6 +63,7 @@ class GLVisCommand LEVELLINES, AXIS_NUMBERFORMAT, COLORBAR_NUMBERFORMAT, + POINT_LINE, QUIT }; @@ -97,6 +99,7 @@ class GLVisCommand std::string autopause_mode; std::string axis_formatting; std::string colorbar_formatting; + std::vector> point_coords; // internal variables int autopause; @@ -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> points); int Camera(const double cam[]); int Autopause(const char *mode); int Quit(); diff --git a/lib/vsdata.cpp b/lib/vsdata.cpp index c43d4dc6..cd4207e5 100644 --- a/lib/vsdata.cpp +++ b/lib/vsdata.cpp @@ -700,9 +700,16 @@ void KeyHPressed() cout << vsdata->GetHelpString() << flush; } -void KeylPressed() +void KeylPressed(GLenum state) { - vsdata -> ToggleLight(); + if (state & KMOD_CTRL) + { + vsdata->TogglePointLine(); + } + else + { + vsdata -> ToggleLight(); + } SendExposeEvent(); } @@ -1020,6 +1027,18 @@ void VisualizationSceneScalarData::ToggleRuler() PrepareRuler(); } +void VisualizationSceneScalarData::TogglePointLine() +{ + if (win.data_state.point_coords.empty()) + { + cout << "No points loaded. Use -pts to load coordinates." << endl; + return; + } + show_point_line = !show_point_line; + cout << "Point line: " << (show_point_line ? "ON" : "OFF") << endl; + PreparePointLine(); +} + void VisualizationSceneScalarData::RulerPosition() { cout << "Current ruler position: (" << ruler_x << ',' @@ -1669,6 +1688,56 @@ void VisualizationSceneScalarData::PrepareAxes() updated_bufs.emplace_back(&coord_cross_buf); } +void VisualizationSceneScalarData::PreparePointLine() +{ + point_line_buf.clear(); + if (!show_point_line || win.data_state.point_coords.empty()) + { + return; + } + + const auto& points = win.data_state.point_coords; + // in 2D, elevate the point line above the surface using the value range + // in 3D, use the z-coordinates from the points file. + const bool is_2d = (mesh->SpaceDimension() == 2); + float z_offset = 0.0f; + if (is_2d) + { + const float range = (float)(maxv - minv); + const float dz = (range > 0.0f) ? (0.02f * range) + : (0.02f * (float)std::max(1.0, fabs(maxv))); + z_offset = (float)maxv + dz; + } + + std::vector line_vertices; + line_vertices.reserve((points.size()-1)*2); + for (size_t i = 0; i + 1 < points.size(); i++) + { + float x0 = (float)points[i][0]; + float y0 = (float)points[i][1]; + float x1 = (float)points[i+1][0]; + float y1 = (float)points[i+1][1]; + float z = is_2d ? z_offset : (float)points[i][2]; + float z_next = is_2d ? z_offset : (float)points[i+1][2]; + line_vertices.push_back({x0, y0, z}); + line_vertices.push_back({x1, y1, z_next}); + } + point_line_buf.addLines(line_vertices); + updated_bufs.emplace_back(&point_line_buf); +} + +void VisualizationSceneScalarData::AddPointLineToScene( + gl3::SceneInfo& scene, const gl3::RenderParams& base_params) +{ + if (!show_point_line || win.data_state.point_coords.empty()) { return; } + gl3::RenderParams params = base_params; // use local parameters + params.static_color = {1.0f, 0.0f, 0.0f, 1.0f}; // point line is red + params.use_clip_plane = false; + params.num_pt_lights = 0; + params.contains_translucent = false; + scene.queue.emplace_back(params, &point_line_buf); +} + void VisualizationSceneScalarData::DrawPolygonLevelLines( gl3::GlBuilder& builder, double * point, int n, Array &mesh_level, bool log_vals) diff --git a/lib/vsdata.hpp b/lib/vsdata.hpp index 86fb61fa..d0824db9 100644 --- a/lib/vsdata.hpp +++ b/lib/vsdata.hpp @@ -104,6 +104,7 @@ class VisualizationSceneScalarData : public VisualizationScene gl3::GlDrawable color_bar; gl3::GlDrawable ruler_buf; gl3::GlDrawable caption_buf; + gl3::GlDrawable point_line_buf; int caption_w, caption_h; void Init(); @@ -119,6 +120,7 @@ class VisualizationSceneScalarData : public VisualizationScene Autoscale autoscale; bool logscale; + bool show_point_line{false}; bool LogscaleRange() { return (minv > 0.0 && maxv > minv); } void PrintLogscale(bool warn); @@ -312,6 +314,13 @@ class VisualizationSceneScalarData : public VisualizationScene } } + void PreparePointLine(); + void TogglePointLine(); + void SetPointLineVisible(bool visible) { show_point_line = visible; } + /// Helper for adding point line overlay in derived classes + void AddPointLineToScene(gl3::SceneInfo& scene, + const gl3::RenderParams& params); + void ToggleScaling() { scaling = !scaling; SetNewScalingFromBox(); } diff --git a/lib/vssolution.cpp b/lib/vssolution.cpp index 7d25f38f..ea299d03 100644 --- a/lib/vssolution.cpp +++ b/lib/vssolution.cpp @@ -87,6 +87,7 @@ std::string VisualizationSceneSolution::GetHelpString() const << "| Alt+a - Axes number format |" << endl << "| Alt+c - Colorbar number format |" << endl << "| Alt+n - Numberings method |" << endl + << "| Ctrl+l - Toggle point line |" << endl << "| Ctrl+o - Element ordering curve |" << endl << "| Ctrl+p - Print to a PDF file |" << endl << "+------------------------------------+" << endl @@ -2760,6 +2761,7 @@ gl3::SceneInfo VisualizationSceneSolution::GetSceneObjs() { scene.queue.emplace_back(params, &order_buf); } + AddPointLineToScene(scene, params); // point line overlay ProcessUpdatedBufs(scene); return scene; diff --git a/lib/vssolution3d.cpp b/lib/vssolution3d.cpp index 2383fb3e..91d845d8 100644 --- a/lib/vssolution3d.cpp +++ b/lib/vssolution3d.cpp @@ -87,6 +87,7 @@ std::string VisualizationSceneSolution3d::GetHelpString() const << "| \\ - Set light source position |" << endl << "| Alt+a - Axes number format |" << endl << "| Alt+c - Colorbar number format |" << endl + << "| Ctrl+l - Toggle point line |" << endl << "| Ctrl+o - Element ordering curve |" << endl << "| Ctrl+p - Print to a PDF file |" << endl << "+------------------------------------+" << endl @@ -4284,6 +4285,7 @@ gl3::SceneInfo VisualizationSceneSolution3d::GetSceneObjs() { scene.queue.emplace_back(params, &order_buf); } + AddPointLineToScene(scene, params); // point line overlay ProcessUpdatedBufs(scene); return scene; } diff --git a/lib/vsvector.cpp b/lib/vsvector.cpp index ba006d28..816b6196 100644 --- a/lib/vsvector.cpp +++ b/lib/vsvector.cpp @@ -72,6 +72,7 @@ std::string VisualizationSceneVector::GetHelpString() const << "| \\ - Set light source position |" << endl << "| Alt+a - Axes number format |" << endl << "| Alt+c - Colorbar number format |" << endl + << "| Ctrl+l - Toggle point line |" << endl << "| Ctrl+p - Print to a PDF file |" << endl << "+------------------------------------+" << endl << "| Function keys |" << endl @@ -1131,6 +1132,7 @@ gl3::SceneInfo VisualizationSceneVector::GetSceneObjs() } scene.queue.emplace_back(params, &displine_buf); } + AddPointLineToScene(scene, params); // point line overlay ProcessUpdatedBufs(scene); return scene; diff --git a/lib/vsvector3d.cpp b/lib/vsvector3d.cpp index 244ceb01..759cf3dd 100644 --- a/lib/vsvector3d.cpp +++ b/lib/vsvector3d.cpp @@ -84,6 +84,7 @@ std::string VisualizationSceneVector3d::GetHelpString() const << "| \\ - Set light source position |" << endl << "| Alt+a - Axes number format |" << endl << "| Alt+c - Colorbar number format |" << endl + << "| Ctrl+l - Toggle point line |" << endl << "| Ctrl+p - Print to a PDF file |" << endl << "+------------------------------------+" << endl << "| Function keys |" << endl @@ -1790,6 +1791,7 @@ gl3::SceneInfo VisualizationSceneVector3d::GetSceneObjs() params.use_clip_plane = false; scene.queue.emplace_back(params, &cplines_buf); } + AddPointLineToScene(scene, params); // point line overlay ProcessUpdatedBufs(scene); return scene; } From e58cf27c3c1b52fa61e72e71ed2224dad9daa415 Mon Sep 17 00:00:00 2001 From: Tzanio Kolev Date: Wed, 11 Mar 2026 19:58:51 -0700 Subject: [PATCH 2/5] Update CHANGELOG Co-authored-by: Jan Nikl --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a6e13d2e..492b96e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,7 @@ 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 + 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. From 90a45e2da65548897737665f650c05bcc494df6e Mon Sep 17 00:00:00 2001 From: Tzanio Kolev Date: Thu, 12 Mar 2026 11:45:54 -0700 Subject: [PATCH 3/5] Review comments --- glvis.cpp | 4 ---- lib/data_state.hpp | 1 - 2 files changed, 5 deletions(-) diff --git a/glvis.cpp b/glvis.cpp index cd9cf7fb..57b8c106 100644 --- a/glvis.cpp +++ b/glvis.cpp @@ -207,10 +207,6 @@ 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 { diff --git a/lib/data_state.hpp b/lib/data_state.hpp index 418cfeae..652b76fd 100644 --- a/lib/data_state.hpp +++ b/lib/data_state.hpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include From 4a5a503d920e22a6a3c23d52c00d7da87b478032 Mon Sep 17 00:00:00 2001 From: Tzanio Kolev Date: Thu, 12 Mar 2026 20:27:46 -0700 Subject: [PATCH 4/5] Review comments --- glvis.cpp | 8 ++------ lib/data_state.cpp | 9 +++++---- lib/data_state.hpp | 5 ++++- lib/script_controller.cpp | 7 +------ lib/threads.cpp | 20 +++++++------------- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/glvis.cpp b/glvis.cpp index cd9cf7fb..d55b37ac 100644 --- a/glvis.cpp +++ b/glvis.cpp @@ -632,12 +632,8 @@ int main (int argc, char *argv[]) } 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; + int num_points = ReadPointLine(ifs, win.data_state.point_coords, cerr); + cout << "Loaded " << num_points << " points from " << points_file << endl; } } diff --git a/lib/data_state.cpp b/lib/data_state.cpp index 129a3544..52b62bbe 100644 --- a/lib/data_state.cpp +++ b/lib/data_state.cpp @@ -39,15 +39,16 @@ 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, + +int ReadPointLine(std::istream &in, std::vector> &points, std::ostream &warn) { points.clear(); + int num_points; + in >> num_points; + if (num_points > 0) { points.reserve(num_points); diff --git a/lib/data_state.hpp b/lib/data_state.hpp index 418cfeae..99bdd3c8 100644 --- a/lib/data_state.hpp +++ b/lib/data_state.hpp @@ -281,7 +281,10 @@ struct DataState { if (cgrid_f) { FindComplexValueRange(minv, maxv, vec2scal, scale); } else { minv = maxv = 0.; } } }; -int ReadPointLine(std::istream &in, int num_points, +/// 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> &points, std::ostream &warn); diff --git a/lib/script_controller.cpp b/lib/script_controller.cpp index f3e49c22..e283ac53 100644 --- a/lib/script_controller.cpp +++ b/lib/script_controller.cpp @@ -847,12 +847,7 @@ bool ScriptController::ExecuteScriptCommand() break; case Command::PointLine: { - int num_points; - scr >> num_points; - - num_points = ReadPointLine(scr, num_points, - win.data_state.point_coords, - cerr); + int num_points = ReadPointLine(scr, win.data_state.point_coords, cerr); win.vs->SetPointLineVisible(true); win.vs->PreparePointLine(); diff --git a/lib/threads.cpp b/lib/threads.cpp index 7da13693..e6dd8b6c 100644 --- a/lib/threads.cpp +++ b/lib/threads.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -1625,24 +1626,17 @@ bool communication_thread::execute_one(std::string ident) case ThreadCommand::PointLine: { // in parallel, use the point line data from rank 0 - int num_points; - *is[0] >> num_points; - std::vector> points; - num_points = ReadPointLine(*is[0], num_points, points, cerr); + int num_points = ReadPointLine(*is[0], points, cerr); - // assuming that all ranks have sent point data, reads on the remaining - // ranks to sync parallel streams + // assuming that all ranks have sent the same point data, perform dummy + // reads on the remaining ranks to sync parallel streams + std::vector> dummy_points; + std::ostringstream dummy_stream; 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 - } + ReadPointLine(*is[i], dummy_points, dummy_stream); } glvis_command->PointLine(std::move(points)); From e2d5d885d8385d657a1aaa35a2962083189524ab Mon Sep 17 00:00:00 2001 From: Tzanio Kolev Date: Thu, 12 Mar 2026 20:39:03 -0700 Subject: [PATCH 5/5] Review comments --- lib/vsdata.cpp | 1 + lib/vssolution.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/vsdata.cpp b/lib/vsdata.cpp index cd4207e5..33e05fbe 100644 --- a/lib/vsdata.cpp +++ b/lib/vsdata.cpp @@ -1009,6 +1009,7 @@ void VisualizationSceneScalarData::ToggleLogscale(bool print) SetLevelLines(minv, maxv, nl); UpdateLevelLines(); EventUpdateColors(); + PreparePointLine(); if (print) { PrintLogscale(false); diff --git a/lib/vssolution.cpp b/lib/vssolution.cpp index ea299d03..30e40971 100644 --- a/lib/vssolution.cpp +++ b/lib/vssolution.cpp @@ -2438,6 +2438,7 @@ void VisualizationSceneSolution::UpdateValueRange(bool prepare) bb.z[0] = minv; bb.z[1] = maxv; PrepareAxes(); + PreparePointLine(); if (prepare) { UpdateLevelLines();