From dca7cd60bff32f333330915f6355a34a74fccbca Mon Sep 17 00:00:00 2001
From: Jan Burle <jan@c53.be>
Date: Thu, 18 May 2017 16:57:37 +0200
Subject: [PATCH] first cut of a lattice demo

---
 GUI/ba3d/CMakeLists.txt       |   3 +-
 GUI/ba3d/ba3d/model/model.h   |   6 +-
 GUI/ba3d/ba3d/view/canvas.cpp |   4 ++
 GUI/ba3d/ba3d/view/canvas.h   |   1 +
 GUI/ba3d/ba3d/widget.cpp      |   9 +++
 GUI/ba3d/ba3d/widget.h        |   3 +
 GUI/ba3d/demo/CMakeLists.txt  |  17 ++++++
 GUI/ba3d/demo/demo_model.cpp  |  79 ++++++++++++++++++++++++++
 GUI/ba3d/demo/demo_model.h    |  24 ++++++++
 GUI/ba3d/demo/lattice.cpp     | 102 ++++++++++++++++++++++++++++++++++
 GUI/ba3d/demo/lattice.h       |  15 +++++
 GUI/ba3d/demo/main.cpp        |  45 +++++++++++++++
 GUI/ba3d/demo/mainwin.cpp     |  61 ++++++++++++++++++++
 GUI/ba3d/demo/mainwin.h       |  35 ++++++++++++
 14 files changed, 402 insertions(+), 2 deletions(-)
 create mode 100644 GUI/ba3d/demo/CMakeLists.txt
 create mode 100644 GUI/ba3d/demo/demo_model.cpp
 create mode 100644 GUI/ba3d/demo/demo_model.h
 create mode 100644 GUI/ba3d/demo/lattice.cpp
 create mode 100644 GUI/ba3d/demo/lattice.h
 create mode 100644 GUI/ba3d/demo/main.cpp
 create mode 100644 GUI/ba3d/demo/mainwin.cpp
 create mode 100644 GUI/ba3d/demo/mainwin.h

diff --git a/GUI/ba3d/CMakeLists.txt b/GUI/ba3d/CMakeLists.txt
index 92bee32932f..5b53ecb71a4 100644
--- a/GUI/ba3d/CMakeLists.txt
+++ b/GUI/ba3d/CMakeLists.txt
@@ -18,7 +18,8 @@ include_directories(${include_dirs})
 set (CMAKE_AUTOMOC ON)
 
 add_subdirectory (ba3d)
-add_subdirectory (main)
+# add_subdirectory (main)
+add_subdirectory (demo)
 
 set(library_name ba3d)
 set(${library_name}_INCLUDE_DIRS ${include_dirs} PARENT_SCOPE)
diff --git a/GUI/ba3d/ba3d/model/model.h b/GUI/ba3d/ba3d/model/model.h
index b7831eb518b..61cd80e89e6 100644
--- a/GUI/ba3d/ba3d/model/model.h
+++ b/GUI/ba3d/ba3d/model/model.h
@@ -14,7 +14,8 @@ namespace ba3d {
 class Canvas;
 class Object;
 
-class Model {
+class Model : public QObject {
+  Q_OBJECT
   friend class Canvas;
   friend class Object;
 public:
@@ -29,6 +30,9 @@ public:
 
   xyz defEye, defCtr, defUp;  // default camera params
 
+signals:
+  void updated();
+
 private:
   QVector<Object*> objects, objectsBlend;
 
diff --git a/GUI/ba3d/ba3d/view/canvas.cpp b/GUI/ba3d/ba3d/view/canvas.cpp
index 793bb65bd8b..7889304a992 100644
--- a/GUI/ba3d/ba3d/view/canvas.cpp
+++ b/GUI/ba3d/ba3d/view/canvas.cpp
@@ -49,6 +49,10 @@ void Canvas::setModel(Model* m) {
   setCamera(true);
 }
 
+Model* Canvas::getModel() {
+  return model;
+}
+
 void Canvas::setCamera(bool full) {
   if (camera) {
     camera->setAspectRatio(aspectRatio);
diff --git a/GUI/ba3d/ba3d/view/canvas.h b/GUI/ba3d/ba3d/view/canvas.h
index 81a00891406..f388cea594c 100644
--- a/GUI/ba3d/ba3d/view/canvas.h
+++ b/GUI/ba3d/ba3d/view/canvas.h
@@ -30,6 +30,7 @@ public:
   void setCamera(Camera*);
   void setProgram(Program*);
   void setModel(Model*);
+  Model* getModel();
 
 private:
   QRect viewport;
diff --git a/GUI/ba3d/ba3d/widget.cpp b/GUI/ba3d/ba3d/widget.cpp
index 1f3d169daea..4e92772b033 100644
--- a/GUI/ba3d/ba3d/widget.cpp
+++ b/GUI/ba3d/ba3d/widget.cpp
@@ -31,7 +31,16 @@ void Widget3D::setBackground(QColor const& color) {
 }
 
 void Widget3D::setModel(Model* model) {
+  disconnect(modelUpdated);
   canvas->setModel(model);
+
+  connect(model, &Model::updated, [this]() {
+    update();
+  });
+}
+
+Model* Widget3D::getModel() {
+  return canvas->getModel();
 }
 
 void Widget3D::update() {
diff --git a/GUI/ba3d/ba3d/widget.h b/GUI/ba3d/ba3d/widget.h
index db4147204e7..b71368e051b 100644
--- a/GUI/ba3d/ba3d/widget.h
+++ b/GUI/ba3d/ba3d/widget.h
@@ -15,6 +15,7 @@ class Camera;
 class Program;
 
 class Widget3D : public QWidget { BASE(QWidget)
+  Q_OBJECT
 public:
   Widget3D();
  ~Widget3D();
@@ -23,6 +24,7 @@ public:
 
   void setBackground(QColor const&);
   void setModel(Model*); // model owned elsewhere, may be nullptr
+  Model* getModel();
 
   void update();
 
@@ -30,6 +32,7 @@ private:
   Canvas  *canvas;
   Camera  *camera;
   Program *program;
+  QMetaObject::Connection modelUpdated;
 };
 
 //------------------------------------------------------------------------------
diff --git a/GUI/ba3d/demo/CMakeLists.txt b/GUI/ba3d/demo/CMakeLists.txt
new file mode 100644
index 00000000000..a19facd3bb8
--- /dev/null
+++ b/GUI/ba3d/demo/CMakeLists.txt
@@ -0,0 +1,17 @@
+set (app ba3d_app)
+
+find_package (Qt5Core     REQUIRED)
+find_package (Qt5Gui      REQUIRED)
+find_package (Qt5Widgets  REQUIRED)
+find_package (OpenGL)
+
+file (GLOB_RECURSE files *)
+add_executable (${app} ${files})
+
+target_link_libraries (${app}
+  ba3d
+  Qt5::Core Qt5::Gui Qt5::Widgets
+  ${OPENGL_gl_LIBRARY}
+)
+
+# eof
diff --git a/GUI/ba3d/demo/demo_model.cpp b/GUI/ba3d/demo/demo_model.cpp
new file mode 100644
index 00000000000..a8c2ef42f03
--- /dev/null
+++ b/GUI/ba3d/demo/demo_model.cpp
@@ -0,0 +1,79 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#include "demo_model.h"
+#include <ba3d/model/layer.h>
+#include "lattice.h"
+#include <qmath.h>
+
+//------------------------------------------------------------------------------
+
+using namespace ba3d;
+
+DemoModel::DemoModel() {
+  flt const sz = 80; //0;
+  spacing = 20;      // of particles
+
+  defEye = xyz(10, 10, sz);
+  defCtr = xyz(0, 0, -20);
+  defUp  = xyz::_y;
+
+  auto layer = [&](int z1, int z2, QColor color) {
+    flt s2 = sz /2;
+    auto l = new Layer(dxyz(dr(-s2,+s2), dr(-s2,+s2), dr(z1, z2)));
+    color.setAlphaF(.3);
+    l->color = color;
+
+    addBlend(l);
+  };
+
+  layer(  0, -20, Qt::green);
+  layer(-20, -55, Qt::gray);
+
+  n = qFloor(sz / spacing / 2 - 1);
+
+  calc(0);
+}
+
+void DemoModel::calc(float sigma) {
+  auto mesh = squareLattice(n, sigma);
+  for (auto& m: mesh)
+    m = m  * spacing + xyz(0, 0, -20);
+
+  if (ps.empty()) { // first time - init
+    ps.resize(mesh.count());
+    flt R = 6;
+    for (auto& p: ps)
+      add((p = new particle::TruncatedSphere(R, R)));
+  }
+
+  EXPECT (ps.count() == mesh.count())
+
+  if (activeMesh.empty()) {
+    activeMesh = mesh;
+    for (uint i=0; i < ps.count(); ++i)
+      ps.at(i)->transform(xyz::_0, activeMesh.at(i));
+  } else {
+    float const step = .1; bool go = true;
+    while (go) {
+      go = false;
+      for (uint i=0; i < ps.count(); ++i) {
+        auto& p = ps.at(i);
+        auto& newPos = mesh.at(i);
+        auto& pos = activeMesh[i];
+        if (step > (pos - newPos).length())
+          pos = newPos;
+        else {
+          pos = pos + (newPos - pos).normalized() * step;
+          go = true;
+        }
+        p->transform(xyz::_0, pos);
+      }
+//      emit updated(); TODO async
+    }
+  }
+
+  emit updated();
+}
+
+//------------------------------------------------------------------------------
+// eof
diff --git a/GUI/ba3d/demo/demo_model.h b/GUI/ba3d/demo/demo_model.h
new file mode 100644
index 00000000000..93b6276f16c
--- /dev/null
+++ b/GUI/ba3d/demo/demo_model.h
@@ -0,0 +1,24 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#ifndef BA3D_DEMOMODEL_LAYERS_H
+#define BA3D_DEMOMODEL_LAYERS_H
+
+#include <ba3d/model/model.h>
+#include <ba3d/model/particles.h>
+
+//------------------------------------------------------------------------------
+
+class DemoModel : public ba3d::Model {
+public:
+  DemoModel();
+  void calc(float sigma);
+
+private:
+  uint n; float spacing;
+  QVector<ba3d::particle::Particle*> ps;
+  QVector<ba3d::xyz> activeMesh;
+};
+
+//------------------------------------------------------------------------------
+#endif
+// eof
diff --git a/GUI/ba3d/demo/lattice.cpp b/GUI/ba3d/demo/lattice.cpp
new file mode 100644
index 00000000000..48db0fcd1d4
--- /dev/null
+++ b/GUI/ba3d/demo/lattice.cpp
@@ -0,0 +1,102 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#include "lattice.h"
+#include <QtGlobal>
+#include <QTime>
+#include <qmath.h>
+
+//------------------------------------------------------------------------------
+
+QVector<ba3d::xyz> squareLattice(uint n, float sigma) {
+  using flt = ba3d::flt;
+  using xyz = ba3d::xyz;
+
+  auto rand01 = [&]() -> float {
+    static bool seeded = false;
+    if (!seeded) {
+      seeded = true;
+      qsrand(QTime::currentTime().msec());
+    }
+    return qrand() / float(RAND_MAX);
+  };
+
+  auto place00 = [&]() -> xyz {
+    // https://www.taygeta.com/random/gaussian.html
+    float x01, y01, w;
+
+    do {
+      x01 = 2.f * rand01() - 1.f;
+      y01 = 2.f * rand01() - 1.f;
+      w   = x01 * x01 + y01 * y01;
+    } while (w >= 1.f);
+
+    w = sqrt(-2.f * qLn(w) / w);
+    return ba3d::xyz(x01 * w * sigma, y01 * w * sigma, 0);
+  };
+
+  auto placeHere = [&](xyz::rc here) -> xyz {
+    return place00() + here;
+  };
+
+  auto placeXY = [&](flt x, flt y) -> xyz {
+    return placeHere(xyz(x, y, 0));
+  };
+
+  uint nn = (2*n + 1) * (2*n + 1); // total number
+
+  auto mesh = QVector<xyz>(nn);
+
+  auto index = [&](int ix, int iy) -> uint {
+    int nx = n, ny = n;
+    EXPECT (-nx <= ix && ix <= +nx)
+    EXPECT (-ny <= iy && iy <= +ny)
+    uint i = (2*nx + 1) * (iy + ny) + (ix + nx);
+    ENSURE (i < nn)
+    return i;
+  };
+
+  auto get = [&](int ix, int iy) -> xyz::rc {
+    return mesh.at(index(ix, iy));
+  };
+
+  auto isMade = [&](int ix, int iy) -> bool {
+    return xyz::_0 != mesh.at(index(ix, iy));
+  };
+
+  auto put = [&](int ix, int iy) {
+    if (!isMade(ix, iy))
+      mesh[index(ix, iy)] = placeXY(ix, iy);
+  };
+
+  auto growBy1Quadrant = [&](uint n, int mx, int my) {
+    EXPECT (n > 0)
+    EXPECT (1 == qAbs(mx) && 1 == qAbs(my))
+
+    put(0*mx, n*my); put(n*mx, 0*my);
+
+    for (uint i = 1; i < n; ++i) {
+      put(i*mx, n*my); put(n*mx, i*my);
+    }
+
+    put(n*mx, n*my);
+  };
+
+  auto growBy1 = [&](uint n) {
+    EXPECT (n > 0)
+    growBy1Quadrant(n, +1, +1);
+    growBy1Quadrant(n, +1, -1);
+    growBy1Quadrant(n, -1, +1);
+    growBy1Quadrant(n, -1, -1);
+  };
+
+  auto growTo = [&](uint n) {
+    for (uint i = 1; i <= n; ++i)
+      growBy1(i);
+  };
+
+  growTo(n);
+  return mesh;
+};
+
+//------------------------------------------------------------------------------
+// eof
diff --git a/GUI/ba3d/demo/lattice.h b/GUI/ba3d/demo/lattice.h
new file mode 100644
index 00000000000..674b079d281
--- /dev/null
+++ b/GUI/ba3d/demo/lattice.h
@@ -0,0 +1,15 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#ifndef BA3D_LATTICE_H
+#define BA3D_LATTICE_H
+
+#include <ba3d/def.h>
+#include <QVector>
+
+//------------------------------------------------------------------------------
+
+QVector<ba3d::xyz> squareLattice(uint n, float sigma); // n half-size
+
+//------------------------------------------------------------------------------
+#endif
+// eof
diff --git a/GUI/ba3d/demo/main.cpp b/GUI/ba3d/demo/main.cpp
new file mode 100644
index 00000000000..a670b5f60a5
--- /dev/null
+++ b/GUI/ba3d/demo/main.cpp
@@ -0,0 +1,45 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#include <ba3d/def.h>
+#include <ba3d/view/camera.h>
+
+#include "mainwin.h"
+#include "demo_model.h"
+#include <QApplication>
+
+//------------------------------------------------------------------------------
+
+class App : public QApplication { BASE(QApplication)
+public:
+  App(int& argc, char* argv[]);
+ ~App();
+
+  int exec();
+};
+
+App::App(int& argc, char* argv[]) : base(argc, argv) {
+  setOrganizationName("c53");
+  setApplicationName("ba3d");
+}
+
+App::~App() {}
+
+int App::exec() {
+  MainWin win;
+  win.show();
+
+  QScopedPointer<DemoModel> model(new DemoModel);
+
+  win.widg3t().setModel(model.data());
+
+  return base::exec();
+}
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[]) {
+  App(argc, argv).exec();
+}
+
+//------------------------------------------------------------------------------
+// eof
diff --git a/GUI/ba3d/demo/mainwin.cpp b/GUI/ba3d/demo/mainwin.cpp
new file mode 100644
index 00000000000..5fdff9c8847
--- /dev/null
+++ b/GUI/ba3d/demo/mainwin.cpp
@@ -0,0 +1,61 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#include "mainwin.h"
+#include "demo_model.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QSlider>
+#include <QSettings>
+#include <QPushButton>
+
+//------------------------------------------------------------------------------
+
+static QString const MAINWIN_GEOMETRY("MainWin Geometry");
+
+MainWin::MainWin() {
+  setWindowTitle(qApp->applicationName());
+  createLayout();
+
+  QSettings s;
+  restoreGeometry(s.value(MAINWIN_GEOMETRY).toByteArray());
+}
+
+void MainWin::closeEvent(QCloseEvent*) {
+  QSettings s;
+  s.setValue(MAINWIN_GEOMETRY, saveGeometry());
+}
+
+void MainWin::createLayout() {
+  setCentralWidget(new QWidget);
+
+  auto vb = new QVBoxLayout;
+  centralWidget()->setLayout(vb);
+
+  vb->addWidget((w3d = new ba3d::Widget3D));
+  w3d->setBackground(palette().color(QPalette::Background));
+
+  auto hb = new QHBoxLayout;
+  vb->addLayout(hb);
+
+  sigmaSlider  = new QSlider(Qt::Horizontal);
+  auto recalcButton = new QPushButton("Recalc");
+
+  sigmaSlider->setRange(0,30);
+  sigmaSlider->setSingleStep(5);
+  sigmaSlider->setTickInterval(5);
+  sigmaSlider->setTickPosition(QSlider::TicksBelow);
+
+  hb->addStretch();
+  hb->addWidget(sigmaSlider);
+  hb->addWidget(recalcButton);
+
+  connect(recalcButton, &QPushButton::clicked, [this]() {
+    auto model = dynamic_cast<DemoModel*>(w3d->getModel());
+    if (model)
+      model->calc(sigmaSlider->value() / 100.f);
+  });
+}
+
+//------------------------------------------------------------------------------
+// eof
diff --git a/GUI/ba3d/demo/mainwin.h b/GUI/ba3d/demo/mainwin.h
new file mode 100644
index 00000000000..e82fd25cd61
--- /dev/null
+++ b/GUI/ba3d/demo/mainwin.h
@@ -0,0 +1,35 @@
+// GPL3; https://github.com/jburle/ba3d
+
+#ifndef BA3D_MAINWIN_H
+#define BA3D_MAINWIN_H
+
+#include <ba3d/widget.h>
+#include <ba3d/model/particles.h>
+#include <QMainWindow>
+
+//------------------------------------------------------------------------------
+
+class QSlider;
+
+class MainWin : public QMainWindow { BASE(QMainWindow)
+  Q_OBJECT
+public:
+  MainWin();
+
+  ba3d::Widget3D& widg3t() {
+    return *w3d;
+  }
+
+private:
+  void closeEvent(QCloseEvent*);
+
+  ba3d::Widget3D *w3d;
+  QWidget *controls;
+  QSlider *sigmaSlider;
+
+  void createLayout();
+};
+
+//------------------------------------------------------------------------------
+#endif
+// eof
-- 
GitLab