Skip to content

Commit 745eb68

Browse files
joa-quimclaude
andcommitted
fix: test-hook window leak crash; track point-cloud view
Test hooks borrowing a window (dgt, landmask, movie, scene_adopt) now give it back when it closes (testBorrowScene): a closed window left in the test dll's g_scenes was read by linkPartnerWindows -> bad_alloc / SIGSEGV on Linux and macOS CI. gmtvtk_scene_borrowed_test + checks. MB-System navigation tracks (and their group) get "Show point-cloud": the soundings of their swath file(s), same view as a line area's (one shared openSubCloud). That view keeps CUBE filter and Gridding. Okada test updated for _grid_dims refusing inconsistent grids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8f84b42 commit 745eb68

14 files changed

Lines changed: 264 additions & 46 deletions

‎deps/src/10_geometry.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,12 +959,14 @@ static std::vector<std::pair<std::string, int>> lineGroupMbFiles(Scene *s, const
959959
// A line area's "Show point-cloud" (90_c_api.cpp): the window's swath soundings inside `ring` in a view of
960960
// their own, with their own 3D Soundings
961961
static void mbShowAreaCloud(Scene *s, const std::vector<std::array<double, 3>> &ring);
962+
// ...and a navigation track's (or a group of tracks'): the soundings of those swath files, the same view
963+
static void mbShowFilesCloud(Scene *s, const QStringList &files);
962964
#endif
963965
// A point cloud's Scene Objects menus (50_scene.cpp): its master handle and its "Points" row
964966
static void cloudObjectMenu(Scene *s, const QPoint &gp);
965967
static void cloudPointsMenu(Scene *s, const QPoint &gp);
966968
static void addMbSystemMenu(QMenu &m, const std::vector<std::string> &navs, QWidget *parent = nullptr,
967-
const std::vector<std::pair<std::string, int>> &own = {});
969+
const std::vector<std::pair<std::string, int>> &own = {}, Scene *s = nullptr);
968970
static void overlayBuildFill(Overlay &ov); // filled overlay's triangles (50_scene.cpp)
969971
static bool overlayActorFilled(Scene *s, vtkActor *a); // ...is this actor one? (50_scene.cpp)
970972
static void vwSaveProduct(Scene *s, const std::string &key); // Vector Wizard product -> SVG/EPS/PDF (50_scene.cpp)

‎deps/src/50_scene.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3251,7 +3251,7 @@ static void rebuildSceneObjects(Scene *s) {
32513251
QAction *aCpt = nullptr, *aBlack = nullptr;
32523252
// A group of MB-System navigation tracks: mbgrdviz's Action menu editors, on every track
32533253
// of the group (each submenu item does its own work, so `pick` matches nothing below).
3254-
addMbSystemMenu(m, lineGroupMbNavs(s, gn), s->win, lineGroupMbFiles(s, gn));
3254+
addMbSystemMenu(m, lineGroupMbNavs(s, gn), s->win, lineGroupMbFiles(s, gn), s);
32553255
QAction *aVw = vwKey.empty() ? nullptr : m.addAction("Save as SVG / EPS / PDF…");
32563256
if (aVw) m.addSeparator();
32573257
if (cptable) {

‎deps/src/55_lineprops.cpp‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,8 +1261,13 @@ static std::vector<std::string> lineGroupMbNavs(Scene *s, const std::string &gna
12611261
#ifdef GMTVTK_MBGRDVIZ
12621262
static MbGrdVizHost mbgrdvizViewerHost(); // 90_c_api.cpp
12631263
#endif
1264+
//
1265+
// "Show point-cloud" goes in the same submenu, for tracks whose swath file is part of window `s`'s point
1266+
// cloud (a dropped swath file's navigation): the soundings of THAT file in the view a line area's
1267+
// "Show point-cloud" opens. Built here, the one place the submenu is made, so a single track and its
1268+
// group's handle both get it.
12641269
static void addMbSystemMenu(QMenu &m, const std::vector<std::string> &navs, QWidget *parent,
1265-
const std::vector<std::pair<std::string, int>> &own) {
1270+
const std::vector<std::pair<std::string, int>> &own, Scene *s) {
12661271
#ifdef GMTVTK_MBGRDVIZ
12671272
std::vector<std::string> known;
12681273
for (const std::string &n : navs)
@@ -1285,9 +1290,17 @@ static void addMbSystemMenu(QMenu &m, const std::vector<std::string> &navs, QWid
12851290
mbRunNavEditor(mbgrdvizViewerHost(), parent, which, files, formats);
12861291
});
12871292
}
1293+
#ifdef GMTVTK_MBEDITVIZ
1294+
QStringList ownFiles;
1295+
for (const auto &f : own) ownFiles << QString::fromStdString(f.first);
1296+
if (s && !ownFiles.isEmpty() && mb3dsdgHasCloudFiles(s, ownFiles)) {
1297+
mb->addSeparator();
1298+
mb->addAction("Show point-cloud", [s, ownFiles]() { mbShowFilesCloud(s, ownFiles); });
1299+
}
1300+
#endif
12881301
m.addSeparator();
12891302
#else
1290-
(void)m; (void)navs; (void)parent; (void)own;
1303+
(void)m; (void)navs; (void)parent; (void)own; (void)s;
12911304
#endif
12921305
}
12931306

@@ -1363,7 +1376,7 @@ static void popupLineObjectMenu(Scene *s, const LineRef &lr, const QString &name
13631376
std::vector<std::pair<std::string, int>> own;
13641377
if (!ovp->mbFile.empty())
13651378
own.push_back({ovp->mbFile, ovp->mbFormat});
1366-
addMbSystemMenu(m, { ovp->mbNav }, s->win, own);
1379+
addMbSystemMenu(m, { ovp->mbNav }, s->win, own, s);
13671380
}
13681381

13691382
// EVERY nested rectangle carries the nesting actions at the TOP of the menu, so the chain can

‎deps/src/90_c_api.cpp‎

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2585,17 +2585,11 @@ GMTVTK_API int gmtvtk_mb_tag_cloud_grid_h(void *handle, const char *name) {
25852585
// A line area's "Show point-cloud": the window's swath soundings inside the area, in a NEW point-cloud
25862586
// window (gmtvtk_view_points, the window every point cloud gets) with its own 3D Soundings pane
25872587
// (mb3dsdgOpenAreaCloud). Closing that window is its pane's Discard.
2588-
static void mbShowAreaCloud(Scene *s, const std::vector<std::array<double, 3>> &ring) {
2589-
if (!sceneAlive(s) || ring.size() < 4)
2590-
return;
2591-
std::vector<double> xy;
2592-
const size_t n = (ring.front() == ring.back()) ? ring.size() - 1 : ring.size(); // the closing duplicate
2593-
for (size_t i = 0; i < n; i++) {
2594-
xy.push_back(ring[i][0]);
2595-
xy.push_back(ring[i][1]);
2596-
}
2588+
// The window a sub-cloud view (an area's, a track's) opens in: gmtvtk_view_points, the window every
2589+
// point cloud gets, framed on the soundings it is given. ONE maker and ONE closer for both views.
2590+
static std::function<void *(const double *, int, const QString &)> mbSubCloudWindowMaker(Scene *s) {
25972591
const int geog = s->baseGeog ? 1 : 0;
2598-
auto makeWindow = [geog](const double *xyz, int np, const QString &title) -> void * {
2592+
return [geog](const double *xyz, int np, const QString &title) -> void * {
25992593
double x0 = xyz[0], x1 = xyz[0], y0 = xyz[1], y1 = xyz[1];
26002594
for (int i = 1; i < np; i++) {
26012595
x0 = std::min(x0, xyz[3 * i]); x1 = std::max(x1, xyz[3 * i]);
@@ -2604,11 +2598,40 @@ static void mbShowAreaCloud(Scene *s, const std::vector<std::array<double, 3>> &
26042598
return gmtvtk_view_points(xyz, np, nullptr, nullptr, 0, x0, x1, y0, y1, geog, 3.0, 1.0, 0.0, 0.0,
26052599
title.toUtf8().constData());
26062600
};
2607-
auto closeWin = [](void *w) { if (sceneAlive(static_cast<Scene *>(w))) gmtvtk_close(w); };
2601+
}
2602+
static void mbSubCloudWindowClose(void *w) { if (sceneAlive(static_cast<Scene *>(w))) gmtvtk_close(w); }
2603+
2604+
static void mbShowAreaCloud(Scene *s, const std::vector<std::array<double, 3>> &ring) {
2605+
if (!sceneAlive(s) || ring.size() < 4)
2606+
return;
2607+
std::vector<double> xy;
2608+
const size_t n = (ring.front() == ring.back()) ? ring.size() - 1 : ring.size(); // the closing duplicate
2609+
for (size_t i = 0; i < n; i++) {
2610+
xy.push_back(ring[i][0]);
2611+
xy.push_back(ring[i][1]);
2612+
}
26082613
QApplication::setOverrideCursor(Qt::WaitCursor);
2609-
mb3dsdgOpenAreaCloud(s, xy.data(), int(xy.size() / 2), makeWindow, closeWin);
2614+
mb3dsdgOpenAreaCloud(s, xy.data(), int(xy.size() / 2), mbSubCloudWindowMaker(s), mbSubCloudWindowClose);
26102615
QApplication::restoreOverrideCursor();
26112616
}
2617+
2618+
// A navigation track's "Show point-cloud" (its "MB-System" submenu, addMbSystemMenu): the soundings of
2619+
// its swath file(s), in the same view an area gets. Accept / Discard / the parent's pane: the same.
2620+
static void mbShowFilesCloud(Scene *s, const QStringList &files) {
2621+
if (!sceneAlive(s) || files.isEmpty())
2622+
return;
2623+
QApplication::setOverrideCursor(Qt::WaitCursor);
2624+
mb3dsdgOpenFileCloud(s, files, mbSubCloudWindowMaker(s), mbSubCloudWindowClose);
2625+
QApplication::restoreOverrideCursor();
2626+
}
2627+
// The same from the host: window `handle`'s cloud, the soundings of the swath file `file`. 1 = opened
2628+
GMTVTK_API int gmtvtk_mb_file_cloud_h(void *handle, const char *file) {
2629+
Scene *s = static_cast<Scene *>(handle);
2630+
if (!sceneAlive(s) || !file || !*file)
2631+
return 0;
2632+
mbShowFilesCloud(s, QStringList{ QString::fromUtf8(file) });
2633+
return mb3dsdgAreaOpen() ? 1 : 0;
2634+
}
26122635
// The same "Show point-cloud" from coordinates: the soundings of window `handle`'s swath cloud inside the
26132636
// polygon of n x,y vertices (true coords). 1 = the area window and its pane opened
26142637
GMTVTK_API int gmtvtk_mb_area_cloud_h(void *handle, const double *xy, int n) {
@@ -2626,6 +2649,11 @@ GMTVTK_API int gmtvtk_mb_area_cloud_h(void *handle, const double *xy, int n) {
26262649
GMTVTK_API int gmtvtk_mb_soundings_counts(int *out) {
26272650
return (out && mb3dsdgCounts(&out[0], &out[1], &out[2])) ? 1 : 0;
26282651
}
2652+
// The open 3D Soundings pane's buttons that are shown: bit 0 CUBE filter, bit 1 Gridding, bit 2 Discard
2653+
// (an area / track view). -1 = no pane
2654+
GMTVTK_API int gmtvtk_mb_pane_buttons() {
2655+
return mb3dsdgPaneButtons();
2656+
}
26292657
// View > Show flagged of the open 3D Soundings view, through its menu entry. 1 = done
26302658
GMTVTK_API int gmtvtk_mb_soundings_show_flagged(int on) {
26312659
return mb3dsdgSetShowFlagged(on != 0) ? 1 : 0;
@@ -3092,7 +3120,7 @@ GMTVTK_API int gmtvtk_mbgrdviz_track_menu_test(void *handle, const char *element
30923120
break;
30933121
}
30943122
QMenu m;
3095-
addMbSystemMenu(m, navs, s->win, own);
3123+
addMbSystemMenu(m, navs, s->win, own, s);
30963124
std::string items;
30973125
int n = 0;
30983126
for (QAction *a : m.actions())
@@ -7402,10 +7430,16 @@ GMTVTK_API int gmtvtk_ecmwf_dialog_test(void *handle, const char *path) {
74027430
// out here for a scene that is perfectly alive. The Scene struct is byte-identical between the two
74037431
// dlls (same source, same compiler), so adopting the pointer is the same mirroring the callback
74047432
// registrations already do.
7433+
static void testBorrowScene(Scene *s); // below: borrow, given back when the window goes
7434+
// Does THIS dll still count `scene` as a live window? Pointer comparison only -- safe to ask about a
7435+
// window that is already gone, which is the point: after its window closes the answer must be 0.
7436+
GMTVTK_API int gmtvtk_scene_borrowed_test(void *scene) {
7437+
return g_scenes.count(static_cast<Scene *>(scene)) ? 1 : 0;
7438+
}
74057439
GMTVTK_API int gmtvtk_scene_adopt_test(void *scene) {
74067440
Scene *s = static_cast<Scene *>(scene);
74077441
if (!s) return 0;
7408-
g_scenes.insert(s);
7442+
testBorrowScene(s);
74097443
return 1;
74107444
}
74117445

@@ -8040,6 +8074,20 @@ GMTVTK_API void *gmtvtk_open_empty(const char *title); // defined below; forwa
80408074
//
80418075
// ONE function does the borrowing, for every hook, so no site can forget the giving-back half. A
80428076
// repeat open on the same dialog just connects again — the handler is idempotent.
8077+
// The borrowing for a hook that has no dialog slot to tie it to (a scene adopted as it is, or a dialog
8078+
// kept in a per-window registry rather than a g_*TestDlg pointer): the borrowed Scene is given back when
8079+
// its WINDOW is destroyed. Without this a closed window stays "alive" here for ever, and the next thing
8080+
// in this dll that walks g_scenes -- rebuildSceneObjects -> swipeRefreshAvailability ->
8081+
// linkPartnerWindows -- reads the freed Scene: std::bad_alloc / SIGSEGV on Linux and macOS (2026-10-07,
8082+
// the grdlandmask parking test right after the DGT one), silently "fine" on Windows.
8083+
static void testBorrowScene(Scene *s) {
8084+
if (!s) return;
8085+
g_scenes.insert(s);
8086+
static std::unordered_set<Scene *> wired; // one give-back per window, however often borrowed
8087+
if (s->win && wired.insert(s).second)
8088+
QObject::connect(s->win, &QObject::destroyed, [s]() { g_scenes.erase(s); wired.erase(s); });
8089+
}
8090+
80438091
template <class T>
80448092
static void testBorrowWindow(Scene *s, T **slot) {
80458093
if (!s) return;
@@ -8672,7 +8720,7 @@ GMTVTK_API int gmtvtk_movie_open_dialog_test(void *handle) {
86728720
ensureApp();
86738721
Scene *s = static_cast<Scene *>(handle);
86748722
if (!s || !s->win) return 0;
8675-
g_scenes.insert(s);
8723+
testBorrowScene(s);
86768724
return gmtvtk_open_movie_dialog_h(s);
86778725
}
86788726
// The X, driven the way a user drives it.
@@ -8712,7 +8760,7 @@ GMTVTK_API int gmtvtk_dgt_open_dialog_test(void *handle) {
87128760
ensureApp();
87138761
Scene *s = static_cast<Scene *>(handle);
87148762
if (!s || !s->win) return 0;
8715-
g_scenes.insert(s);
8763+
testBorrowScene(s);
87168764
DgtLidarDialog *w = dgtTestDlg(handle);
87178765
if (w) w->unpark();
87188766
else {
@@ -8783,7 +8831,7 @@ GMTVTK_API int gmtvtk_landmask_open_dialog_test(void *handle) {
87838831
ensureApp();
87848832
Scene *s = static_cast<Scene *>(handle);
87858833
if (!s || !s->win) return 0;
8786-
g_scenes.insert(s);
8834+
testBorrowScene(s);
87878835
const int ok = openGrdLandmaskDialog(s->win, s);
87888836
QApplication::processEvents();
87898837
return ok;

‎deps/src/mbeditviz/mb3dsoundings_cloud.cpp‎

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "mb3dsoundings_window.h"
99
#include "mbeditviz.h"
1010

11+
#include <QDir>
1112
#include <QFileInfo>
1213
#include <QMessageBox>
1314
#include <QTimer>
@@ -348,23 +349,19 @@ int mb3dsdgEsfFlag(const MbEditHost &host, const QStringList &files, const doubl
348349
return failed.isEmpty() ? n : -1;
349350
}
350351

351-
bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
352-
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
353-
const std::function<void(void *)> &closeWin) {
352+
// THE sub-cloud view, whatever picks its soundings: a line area's "Show point-cloud" (the soundings
353+
// inside it) and a navigation track's (the soundings of its file). `keep` says which of the parent's
354+
// soundings go; everything else -- the window, the pane, Accept / Discard, the parent stepping aside --
355+
// is this one function, so the two views cannot drift apart. `none` is said when nothing is kept.
356+
static bool openSubCloud(void *parentScene, const std::function<bool(const mb3dsoundings_sounding_struct &)> &keep,
357+
const QString &suffix, const QString &none,
358+
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
359+
const std::function<void(void *)> &closeWin) {
354360
Cloud *p = g_cloud;
355-
if (!p || p->scene != parentScene || !ring || nring < 3 || !makeWindow)
361+
if (!p || p->scene != parentScene || !keep || !makeWindow)
356362
return false;
357-
auto inside = [ring, nring](double x, double y) { // even-odd rule over the ring (x,y pairs)
358-
bool in = false;
359-
for (int i = 0, j = nring - 1; i < nring; j = i++) {
360-
const double xi = ring[2 * i], yi = ring[2 * i + 1], xj = ring[2 * j], yj = ring[2 * j + 1];
361-
if ((yi > y) != (yj > y) && x < (xj - xi) * (y - yi) / (yj - yi) + xi)
362-
in = !in;
363-
}
364-
return in;
365-
};
366-
// the parent's soundings inside the area, on the parent's own ping x beam frame (so every sounding
367-
// keeps its identity), flagged ones carried as mbgetdata carries them (shifted by the flag offset)
363+
// the parent's soundings kept, on the parent's own ping x beam frame (so every sounding keeps its
364+
// identity), flagged ones carried as mbgetdata carries them (shifted by the flag offset)
368365
const int nping = int(p->pingTime.size());
369366
int nbeam = 0;
370367
for (const auto &s : p->s)
@@ -374,7 +371,7 @@ bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
374371
const size_t nn = size_t(nping) * size_t(nbeam);
375372
std::vector<double> lon(nn, NAN), lat(nn, NAN), z(nn, NAN), good;
376373
for (const auto &s : p->s) {
377-
if (!inside(s.x, s.y))
374+
if (!keep(s))
378375
continue;
379376
const size_t k = size_t(s.ibeam) * size_t(nping) + size_t(s.iping);
380377
lon[k] = s.x;
@@ -388,10 +385,10 @@ bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
388385
}
389386
}
390387
if (good.empty()) {
391-
QMessageBox::information(nullptr, "Show point-cloud", "No good sounding of " + p->name + " lies inside this area.");
388+
QMessageBox::information(nullptr, "Show point-cloud", QString(none).arg(p->name));
392389
return false;
393390
}
394-
const QString title = p->name + " (area)";
391+
const QString title = p->name + " (" + suffix + ")";
395392
// the parent waits: its soundings and edits stay, only its pane goes (one 3-D sounding editor at a time)
396393
g_cloud = nullptr;
397394
if (mb3dsdgIsOpen())
@@ -417,6 +414,76 @@ bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
417414
return false;
418415
}
419416

417+
bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
418+
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
419+
const std::function<void(void *)> &closeWin) {
420+
if (!ring || nring < 3)
421+
return false;
422+
auto inside = [ring, nring](const mb3dsoundings_sounding_struct &s) { // even-odd rule over the ring
423+
bool in = false;
424+
for (int i = 0, j = nring - 1; i < nring; j = i++) {
425+
const double xi = ring[2 * i], yi = ring[2 * i + 1], xj = ring[2 * j], yj = ring[2 * j + 1];
426+
if ((yi > s.y) != (yj > s.y) && s.x < (xj - xi) * (s.y - yi) / (yj - yi) + xi)
427+
in = !in;
428+
}
429+
return in;
430+
};
431+
return openSubCloud(parentScene, inside, "area", "No good sounding of %1 lies inside this area.",
432+
makeWindow, closeWin);
433+
}
434+
435+
// Is `path` one of the swath files of `parentScene`'s cloud? Paths compared as the OS does: separators
436+
// normalised, and case-blind on Windows.
437+
static int cloudFileIndex(const Cloud *p, const QString &path) {
438+
const QString want = QDir::cleanPath(QDir::fromNativeSeparators(path));
439+
for (int i = 0; i < p->files.size(); i++) {
440+
const QString have = QDir::cleanPath(QDir::fromNativeSeparators(p->files[i]));
441+
#ifdef _WIN32
442+
if (have.compare(want, Qt::CaseInsensitive) == 0) return i;
443+
#else
444+
if (have == want) return i;
445+
#endif
446+
}
447+
return -1;
448+
}
449+
450+
bool mb3dsdgHasCloudFiles(void *parentScene, const QStringList &files) {
451+
const Cloud *p = g_cloud;
452+
if (!p || p->scene != parentScene)
453+
return false;
454+
for (const QString &f : files)
455+
if (cloudFileIndex(p, f) >= 0)
456+
return true;
457+
return false;
458+
}
459+
460+
bool mb3dsdgOpenFileCloud(void *parentScene, const QStringList &files,
461+
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
462+
const std::function<void(void *)> &closeWin) {
463+
const Cloud *p = g_cloud;
464+
if (!p || p->scene != parentScene)
465+
return false;
466+
std::vector<char> take(size_t(p->files.size()), 0);
467+
QStringList names;
468+
for (const QString &f : files) {
469+
const int i = cloudFileIndex(p, f);
470+
if (i < 0 || take[size_t(i)])
471+
continue;
472+
take[size_t(i)] = 1;
473+
names << QFileInfo(f).completeBaseName();
474+
}
475+
if (names.isEmpty())
476+
return false;
477+
const std::vector<int> &pf = p->pingFile;
478+
auto ofTrack = [&take, &pf](const mb3dsoundings_sounding_struct &s) {
479+
return s.iping >= 0 && s.iping < int(pf.size()) && pf[size_t(s.iping)] >= 0 &&
480+
pf[size_t(s.iping)] < int(take.size()) && take[size_t(pf[size_t(s.iping)])];
481+
};
482+
const QString suffix = names.size() == 1 ? names.front() : QString("%1 tracks").arg(names.size());
483+
return openSubCloud(parentScene, ofTrack, suffix, "No good sounding of %1 belongs to this track.",
484+
makeWindow, closeWin);
485+
}
486+
420487
bool mb3dsdgAreaOpen() {
421488
return g_cloud && g_cloud->parent;
422489
}

‎deps/src/mbeditviz/mb3dsoundings_cloud.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,18 @@ int mb3dsdgEsfFlag(const MbEditHost &host, const QStringList &files, const doubl
4444
bool mb3dsdgOpenAreaCloud(void *parentScene, const double *ring, int nring,
4545
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
4646
const std::function<void(void *)> &closeWin);
47+
// A navigation track's "Show point-cloud": the same view (the same function underneath), its soundings
48+
// being those of `parentScene`'s cloud that came from the swath file(s) `files` -- a track, or a group of
49+
// them. False when nothing opened.
50+
bool mb3dsdgOpenFileCloud(void *parentScene, const QStringList &files,
51+
const std::function<void *(const double *xyz, int n, const QString &title)> &makeWindow,
52+
const std::function<void(void *)> &closeWin);
53+
// Does `parentScene`'s swath cloud hold any of `files`? (what offers a track's "Show point-cloud")
54+
bool mb3dsdgHasCloudFiles(void *parentScene, const QStringList &files);
4755
// The open 3D Soundings view (mb3dsoundings_window.h): points it draws, good / flagged counts; and View >
4856
// Show flagged through its menu entry
4957
bool mb3dsdgCounts(int *drawn, int *good, int *flagged);
58+
int mb3dsdgPaneButtons(); // shown buttons: bit 0 CUBE filter, bit 1 Gridding, bit 2 Discard; -1 none
5059
bool mb3dsdgSetShowFlagged(bool on);
5160
// An area pane is the open one (its parent waiting); its Accept (true) or Discard (false), as its buttons
5261
bool mb3dsdgAreaOpen();

0 commit comments

Comments
 (0)