16 #include "imgui_stdlib.h"
19 #include "polyscope/polyscope.h"
20 #include "polyscope/surface_mesh.h"
32 const std::string polyscopeBackend =
"openGL_mock";
34 const std::string polyscopeBackend =
"";
56 this->isHeadless = isHeadless;
80 if (!(this->isHeadless))
86 std::cout <<
"Headless mode, no polyscope window shown." << std::endl;
100 if (this->isHeadless)
103 if (!meshIn.isready())
105 RSVS3D_ERROR(
"Mesh is not ready, cannot add to polyscope. Call `PrepareForUse` first.");
107 std::vector<std::vector<double>> points;
108 std::vector<std::vector<int>> faces;
109 points.reserve(meshIn.verts.size());
110 faces.reserve(meshIn.surfs.size());
112 for (
size_t i = 0; i < size_t(meshIn.verts.size()); ++i)
114 if (meshIn.verts(i)->coord.size() != 3)
117 (std::string(
"Vertex at position ") + std::to_string(i) +
" has invalid coordinate.").c_str());
120 points.push_back(meshIn.verts(i)->coord);
122 for (
size_t i = 0; i < size_t(meshIn.surfs.size()); ++i)
124 auto faceIndices = meshIn.verts.find_list(meshIn.surfs(i)->OrderedVerts(&meshIn));
125 if (faceIndices.size() < 3)
128 (std::string(
"Surface at position") + std::to_string(i) +
" has less than 3 vertices.").c_str());
130 faces.push_back(faceIndices);
133 polyscope::registerSurfaceMesh(name, points, faces);
143 if (this->isHeadless)
146 this->addMesh(name, snakeIn.snakeconn);
147 std::vector<double> velocities;
148 velocities.reserve(snakeIn.snaxs.size());
149 for (
size_t i = 0; i < size_t(snakeIn.snaxs.size()); ++i)
152 velocities.push_back(snakeIn.snaxs(i)->v);
154 polyscope::getSurfaceMesh(name)->addVertexScalarQuantity(
"velocity", velocities);
167 _3dVectorWrapper(
const std::vector<double> &vec,
double multiplier = 1.0) : vec(vec), multiplier(multiplier)
170 double operator()(
size_t i,
size_t j)
const
172 return vec[i * 3 + j] * this->multiplier;
176 return vec.size() / 3;
180 const std::vector<double> &vec;
181 double multiplier = 1.0;
192 if (this->isHeadless)
195 std::vector<double> properties;
197 auto psMesh = polyscope::getSurfaceMesh(name);
205 psMesh->addVertexVectorQuantity(
"vertex-normal",
_3dVectorWrapper(MeshUnitNormals(surfaceMesh)));
206 psMesh->addVertexVectorQuantity(
"vertex-laplacians-(flipped)",
_3dVectorWrapper(MeshLaplacians(surfaceMesh), -1.0));
221 if (!meshIn.isready())
223 RSVS3D_ERROR(
"Mesh is not ready, cannot add to polyscope. Call `PrepareForUse` first.");
225 std::vector<std::vector<double>> points;
226 std::vector<std::vector<int>> faces;
227 points.reserve(meshIn.verts.size());
228 faces.reserve(meshIn.surfs.size());
229 float outputVolume = 0.0;
232 for (
size_t i = 0; i < size_t(meshIn.verts.size()); ++i)
234 if (meshIn.verts(i)->coord.size() != 3)
237 (std::string(
"Vertex at position ") + std::to_string(i) +
" has invalid coordinate.").c_str());
240 points.push_back(meshIn.verts(i)->coord);
242 std::vector<int> volumePositions;
245 volumePositions = meshIn.volus.find_list(cellIndices);
249 volumePositions = cellIndices;
251 for (
auto volumePosition : volumePositions)
253 if (volumePosition < 0 || volumePosition >= meshIn.volus.size())
255 polyscope::warning(
"Failed to find cell",
"ID : " + std::to_string(volumePosition));
258 std::cout <<
"Display cell " << meshIn.volus(volumePosition)->index <<
" at position [" << volumePosition <<
"]"
260 outputVolume = meshIn.volus(volumePosition)->target;
261 if (this->isHeadless)
263 for (
auto surfaceIndex : meshIn.volus(volumePosition)->surfind)
265 auto faceIndices = meshIn.verts.find_list(meshIn.surfs.isearch(surfaceIndex)->OrderedVerts(&meshIn));
266 if (faceIndices.size() < 3)
269 (std::string(
"Surface ") + std::to_string(surfaceIndex) +
" has less than 3 vertices.").c_str());
271 faces.push_back(faceIndices);
275 polyscope::registerSurfaceMesh(name, points, faces);
291 static int activeEntry;
293 ImGui::InputDouble(
"Snake coarseness", ¶mConf.
snakecoarseness, 0.0, 0.0,
"%.2f");
295 ImGui::InputDouble(
"Bounding box distance", ¶mConf.
distancebox, 0.0, 0.0,
"%.2f");
297 ImGui::InputText(
"Voronoi points file", ¶mConf.
pointfile);
299 if (ImGui::Button(
"Add Voronoi point"))
301 for (
size_t i = 0; i < 4; i++)
313 if (!(activeEntry < nEntries && activeEntry >= 0))
320 ImGui::InputInt((
"Active Point, max ID: " + std::to_string(nEntries)).c_str(), &activeEntry);
321 if (!(activeEntry < nEntries && activeEntry >= 0))
323 polyscope::warning(
"ID to access input point was incorrect.",
"Maximum value is " +
324 std::to_string(nEntries) +
" value was " +
325 std::to_string(activeEntry));
328 ImGui::Text(
"Voronoi point definition - Active ID: %i\n X , Y , Z , Volume fraction", activeEntry);
329 for (
int i = 0; i < 4; ++i)
331 auto fullName = (
"## voropoint setter " + std::to_string(i)).c_str();
332 ImGui::InputDouble(fullName, &(paramConf.
inputpoints[activeEntry * 4 + i]), 0.0, 0.0,
"%.2f");
341 ImGui::InputInt3(
"Snaking grid", paramConf.
gridsizesnake.data());
344 void parameterConfigGui(std::string name, std::array<param::realbounds, 3> ¶mConf)
346 if (ImGui::TreeNode(name.c_str()))
348 for (
int j = 0; j < 2; ++j)
350 for (
int i = 0; i < 3; ++i)
352 auto fullName = (
"##" + name + std::to_string(i) +
"," + std::to_string(j)).c_str();
353 ImGui::InputDouble(fullName, &(paramConf[i][j]), 0.2, 2.0,
"%.2f");
363 if (ImGui::BeginCombo(
"##Grid Style", paramConf.
activegrid.c_str()))
365 for (
auto key : {
"voxel",
"voronoi"})
367 if (ImGui::Selectable(key, paramConf.
activegrid == key))
374 parameterConfigGui(
"Compute domain", paramConf.
domain);
375 parameterConfigGui(
"Physical domain", paramConf.
physdomain);
376 ImGui::SetNextTreeNodeOpen(
false, ImGuiCond_FirstUseEver);
377 if (ImGui::TreeNode(
"Voxel"))
379 parameterConfigGui(paramConf.voxel);
382 ImGui::SetNextTreeNodeOpen(
false, ImGuiCond_FirstUseEver);
383 if (ImGui::TreeNode(
"Voronoi"))
385 parameterConfigGui(paramConf.voronoi);
391 bool change = ImGui::Checkbox(
"Uniform", ¶mConf.
cstfill.active);
392 if (change && paramConf.
cstfill.active)
398 ImGui::InputDouble(
"##Uniform value", ¶mConf.
cstfill.fill, 0.0, 0.0,
"%.2f");
400 change = ImGui::Checkbox(
"File", ¶mConf.
filefill.active);
401 if (change && paramConf.
cstfill.active)
404 paramConf.
cstfill.active =
false;
407 paramConf.
filefill.fill.reserve(2048);
408 ImGui::InputText(
"##File value", ¶mConf.
filefill.fill);
410 change = ImGui::Checkbox(
"Auto", ¶mConf.
makefill.active);
411 if (change && paramConf.
makefill.active)
414 paramConf.
cstfill.active =
false;
417 paramConf.
makefill.fill.reserve(2048);
418 ImGui::InputText(
"##Auto value", ¶mConf.
makefill.fill);
424 ImGui::InputDouble(
"Arrival tolerance", ¶mConf.
arrivaltolerance, 0.0, 0.0,
"%.2e");
425 ImGui::InputDouble(
"Simulataneous arrival tolerance", ¶mConf.
multiarrivaltolerance, 0.0, 0.0,
"%.2e");
426 ImGui::InputDouble(
"Max step distance", ¶mConf.
snaxdiststep, 0.0, 0.0,
"%.2e");
427 ImGui::InputDouble(
"Max step time", ¶mConf.
snaxtimestep, 0.0, 0.0,
"%.2e");
428 ImGui::InputDouble(
"Spawn position", ¶mConf.
spawnposition, 0.0, 0.0,
"%.2e");
429 ImGui::InputInt(
"Initialisation boundary (0/1)", ¶mConf.
initboundary);
433 ImGui::InputInt(
"Logging level [0-7]", ¶mConf.ioout.logginglvl);
434 ImGui::InputText(
"Case name", ¶mConf.ioin.casename);
437 std::ostringstream stream;
438 stream << out.dump(2);
439 ImGui::TextUnformatted(stream.str().c_str());
444 ImGui::InputDouble(
"limitlagrangian", ¶mConf.limitlagrangian, 0.0, 0.0,
"%.2e");
445 ImGui::InputInt(
"mindesvarsparse", ¶mConf.mindesvarsparse);
446 ImGui::InputTextWithHint(
"smoothstepmethod",
"Not sure what appropriate values are", ¶mConf.smoothstepmethod);
447 ImGui::Checkbox(
"snaxDistanceLimit_conserveShape", ¶mConf.snaxDistanceLimit_conserveShape);
448 ImGui::Checkbox(
"surfcentrehessian", ¶mConf.surfcentrehessian);
449 ImGui::Checkbox(
"surfcentrejacobian", ¶mConf.surfcentrejacobian);
451 if (ImGui::TreeNode(
"Smoothing tolerances"))
453 ImGui::InputDouble(
"rsvsmath_automatic_eps_centre2", ¶mConf.rsvsepsilons.rsvsmath_automatic_eps_centre2,
455 ImGui::InputDouble(
"rsvsmath_automatic_eps_centre", ¶mConf.rsvsepsilons.rsvsmath_automatic_eps_centre, 0.0,
457 ImGui::InputDouble(
"rsvsmath_automatic_eps_edge", ¶mConf.rsvsepsilons.rsvsmath_automatic_eps_edge, 0.0, 0.0,
459 ImGui::InputDouble(
"rsvsmath_automatic_eps_surf", ¶mConf.rsvsepsilons.rsvsmath_automatic_eps_surf, 0.0, 0.0,
461 ImGui::InputDouble(
"rsvsmath_automatic_eps_volu", ¶mConf.rsvsepsilons.rsvsmath_automatic_eps_volu, 0.0, 0.0,
469 int fileNameCapacity = 1024;
470 static std::string importFile;
471 static std::string exportFile;
472 static bool flatJsonExport =
false;
474 if (importFile.capacity() <
size_t(fileNameCapacity))
476 importFile.reserve(fileNameCapacity);
478 exportFile.reserve(fileNameCapacity);
479 exportFile =
"interactive-export.json";
483 ImGui::PushItemWidth(200);
484 ImGui::InputTextWithHint(
"##Import-parameter",
"import.json...", &importFile);
485 ImGui::PopItemWidth();
487 if (ImGui::Button(
"Import"))
491 param::io::read(importFile, paramConf);
493 catch (
const std::exception &e)
495 polyscope::error(std::string(
"Could not import parameters from file '") + importFile +
"': " + e.what());
498 ImGui::PushItemWidth(200);
499 ImGui::InputTextWithHint(
"##Export-parameter",
"export.json...", &exportFile);
500 ImGui::PopItemWidth();
502 if (ImGui::Button(
"Export"))
508 param::io::write(exportFile, paramConf);
512 param::io::writeflat(exportFile, paramConf);
515 catch (
const std::exception &e)
517 polyscope::error(std::string(
"Could not export parameters to file '") + exportFile +
"': " + e.what());
521 ImGui::Checkbox(
"Flat JSON format", &flatJsonExport);
526 if (ImGui::CollapsingHeader(
"Parameters"))
528 parameterExportImportGui(paramConf);
530 ImGui::SetNextTreeNodeOpen(
false, ImGuiCond_FirstUseEver);
531 if (ImGui::TreeNode(
"Grid"))
533 parameterConfigGui(paramConf.grid);
536 if (ImGui::TreeNode(
"RSVS"))
538 parameterConfigGui(paramConf.rsvs);
541 if (ImGui::TreeNode(
"Snaking"))
543 parameterConfigGui(paramConf.snak);
546 if (ImGui::TreeNode(
"File setting (view)"))
548 parameterConfigGui(paramConf.files);
551 if (ImGui::TreeNode(
"Development"))
553 parameterConfigGui(paramConf.dev);
562 void UpdateVolume(
integrate::RSVSclass &RSVSobj,
int inspectId,
bool volumeByIndex,
double newVolumeValue)
565 RSVSobj.voluMesh.PrepareForUse();
566 int volumePosition = inspectId;
569 volumePosition = RSVSobj.voluMesh.volus.find(inspectId);
571 if (volumePosition > -1 && volumePosition < RSVSobj.voluMesh.volus.size())
573 RSVSobj.voluMesh.volus[volumePosition].target =
574 newVolumeValue > 0.0 ? (newVolumeValue <= 1.0 ? newVolumeValue : 1.0) : 0.0;
575 RSVSobj.voluMesh.PrepareForUse();
579 polyscope::warning(
"Invalid Cell Position",
"The cell was not found, it is either out of bounds"
580 " or not a valid index.");
585 RSVSobj.voluMesh.PrepareForUse();
586 newVolumeValue = newVolumeValue > 0.0 ? (newVolumeValue <= 1.0 ? newVolumeValue : 1.0) : 0.0;
587 for (
size_t i = 0; i < size_t(RSVSobj.voluMesh.volus.size()); ++i)
589 RSVSobj.voluMesh.volus[i].target = newVolumeValue;
594 static int lineLength = 8;
595 static int vosPrecision = 4;
596 size_t fileNameCapacity = 1024;
597 static std::string importFile;
598 static std::string exportFile;
600 if (importFile.capacity() < fileNameCapacity)
602 importFile.reserve(fileNameCapacity);
604 exportFile.reserve(fileNameCapacity);
605 exportFile =
"interactive-export.fill";
607 if (ImGui::TreeNode(
"Export/Import of Volume fractions"))
610 ImGui::PushItemWidth(200);
611 ImGui::InputTextWithHint(
"##Import-vosfill",
"import.fill...", &importFile);
612 ImGui::PopItemWidth();
614 if (ImGui::Button(
"Import"))
618 RSVSobj.voluMesh.LoadTargetFill(importFile);
620 catch (
const std::exception &e)
622 polyscope::error(std::string(
"Could not import VOS from file '") + importFile +
"': " + e.what());
625 ImGui::PushItemWidth(200);
626 ImGui::InputTextWithHint(
"##Export-vosfill",
"export.fill...", &exportFile);
627 ImGui::PopItemWidth();
629 if (ImGui::Button(
"Export"))
634 std::fstream file(exportFile, std::ios::out);
635 file << std::setprecision(vosPrecision);
636 for (
int i = 0; i < RSVSobj.voluMesh.volus.size(); ++i)
638 file << RSVSobj.voluMesh.volus[i].target <<
" ";
640 if (i % lineLength == lineLength - 1)
646 catch (
const std::exception &e)
648 polyscope::error(std::string(
"Could not export parameters to file '") + exportFile +
"': " + e.what());
653 ImGui::InputInt(
"Items per line", &lineLength);
655 ImGui::InputInt(
"Precision", &vosPrecision);
661 static int inspectId = 1;
662 static bool volumeByIndex =
true;
663 static float newVolumeValue = 0.0;
664 if (ImGui::CollapsingHeader(
"VOS Configuration"))
667 vosExportImportGui(RSVSobj);
668 ImGui::Text(
"\nManual control and viewing Volume fractions");
669 bool cellIdChange = ImGui::InputInt(
"Cell ID", &inspectId);
671 ImGui::Checkbox(
"Use ID (or position)", &volumeByIndex);
672 bool volumeHasChanged = ImGui::InputFloat(
"New volume", &newVolumeValue);
674 bool volumesHaveChanged = ImGui::Button(
"Set All");
675 if (volumeHasChanged)
677 UpdateVolume(RSVSobj, inspectId, volumeByIndex, newVolumeValue);
679 if (volumesHaveChanged)
681 UpdateVolumes(RSVSobj, newVolumeValue);
683 if (cellIdChange || volumeHasChanged || volumesHaveChanged)
685 RSVSobj.voluMesh.PrepareForUse();
686 newVolumeValue = RSVSobj.viewer.
addCells(
"Active Cell", RSVSobj.voluMesh, {inspectId}, volumeByIndex);
687 polyscope::getSurfaceMesh(
"Active Cell")
688 ->setSurfaceColor({1.0 - newVolumeValue, 1.0 - newVolumeValue, 1.0 - newVolumeValue});
713 auto callback = [&] {
714 bool runPreparation =
false;
715 static bool safeToRun =
true;
716 ImGui::PushItemWidth(100);
718 bool viewSurfaces = ImGui::Button(
"View surfaces");
722 if (ImGui::Button(
"Clear GUI Errors"))
728 if (ImGui::CollapsingHeader(
"RSVS Execution"))
730 ImGui::InputInt(
"Number of steps", &RSVSobj.paramconf.snak.
maxsteps);
731 if (ImGui::Button(
"Run"))
735 polyscope::error(
"An error occurred during preparation, try resetting before iteration.");
737 else if (RSVSobj.rsvsSnake.snaxs.size() == 0)
739 polyscope::error(
"There are no snakes on the plane; try resetting before iteration.");
746 iterateInfo = integrate::execute::RSVSiterate(RSVSobj);
748 catch (
const std::invalid_argument &e)
750 std::cerr << e.what() <<
'\n';
751 polyscope::error(e.what());
758 if (ImGui::Button(
"Postprocess"))
761 integrate::execute::PostProcessing(RSVSobj, iterateInfo.timeT, iterateInfo.nVoluZone,
762 iterateInfo.stepNum);
763 integrate::execute::Exporting(RSVSobj);
766 runPreparation = ImGui::Button(
"Reset");
771 integrate::Prepare(RSVSobj);
774 catch (
const std::invalid_argument &e)
776 std::cerr << e.what() <<
'\n';
777 polyscope::error(e.what());
782 RSVSobj.paramconf.snak.engine.reserve(2048);
783 ImGui::InputText(
"Velocity Engine", &RSVSobj.paramconf.snak.engine);
785 if (viewSurfaces || runPreparation)
788 RSVSobj.rsvsSnake.PrepareForUse();
789 RSVSobj.voluMesh.PrepareForUse();
790 integrate::execute::logging::SnakePolyscope(RSVSobj.viewer, RSVSobj.rsvsSnake);
791 this->addMesh(
"Snaking mesh", *RSVSobj.rsvsSnake.snakemesh());
792 this->addMesh(
"Volume mesh", RSVSobj.voluMesh);
794 polyscope::getSurfaceMesh(
"Snaking mesh")->setEnabled(
false);
795 polyscope::getSurfaceMesh(
"Volume mesh")->setTransparency(0.5);
796 auto snakeSurfaceMesh = polyscope::getSurfaceMesh(integrate::constants::polyscopeSnakeName);
797 snakeSurfaceMesh->setEdgeColor({0, 0, 0});
798 snakeSurfaceMesh->setEdgeWidth(1);
799 snakeSurfaceMesh->setBackFacePolicy(polyscope::BackFacePolicy::Identical);
801 vos_ui::vosControlGui(RSVSobj);
802 parameter_ui::parameterConfigGui(RSVSobj.paramconf);
804 ImGui::PopItemWidth();
806 polyscope::state::userCallback = callback;
844 std::array<int, 3> dims = {2, 3, 4};
845 errorOut += BuildBlockGrid(dims, mesh1);
846 mesh1.PrepareForUse();
847 viewer.
addMesh(
"mesh1", mesh1);
Simple class containing all the information needed for the 3D-RSVS execution.
Integration into the full 3 dimensional Restricted Snake Volume of Solid method.
Wrap a vector to allow for (i,j) indexing as if it was a 2D array of coordinates.
Class for development parameters.
Class containing all parameter settings for file operations.
Class for parameters of the grid generation.
std::string activegrid
The type of grid to use either "voxel" or "voronoi" .
std::array< realbounds, 3 > physdomain
Physical domain size for export.
std::array< realbounds, 3 > domain
Domain size in internal coordinates.
Root class for all the parameters.
Parameters related to the Velocity calculation and VOS steps.
filltype< double > cstfill
Fill the VOS values with a constant value.
int solveralgorithm
Algorithm used by Eigen to solve the SQP system.
filltype< std::string > filefill
Fill the VOS values from file filefill.fill.
filltype< std::string > makefill
Fill the VOS values from a run time function accessible from makefill.fill.
Parameters controlling tuning parameters for the stepping of the restricted surface.
double snaxtimestep
maximum snake time step length
int initboundary
Initialisation boundary (either 0 (outer border), 1 (inner border))
int maxsteps
maximum number of steps
double multiarrivaltolerance
Distance along edge at which converging snaxels are considered arrived.
double snaxdiststep
maximum snaxel distance movement
double arrivaltolerance
Distance along edge at which a vertex is considered arrived regardless of "d" and "v".
double spawnposition
Position of spawn.
Class for handling of voronoi VOS meshing parameters.
double distancebox
Distance at which to build the bounding box of the mesh.
double snakecoarseness
The coarseneness level of the snaking mesh that will be generated.
int vorosnakelayers
The number of layers making up the snaking mesh inside each VOS cell [6 6 6] is roughly equal to 2.
std::vector< double > inputpoints
Vector of input points, 4 datums per point.
std::string pointfile
A string pointing to a file containing the set of inputpoints.
Parameters controlling cartesian grid properties.
std::array< int, 3 > gridsizesnake
Size of the Snaking grid on which the snake is defined.
std::array< int, 3 > gridsizebackground
Size of the Background grid on which the VOS is defined.
A structure containing the information about the polyscope display and the RSVS elements to display.
void addMesh(std::string name, const mesh &meshIn)
Add a mesh with a given name to the polyscope window.
float addCells(std::string name, const mesh &meshIn, const std::vector< int > &&cellIndices, bool isIndex=true)
Plot specified volume elements into polyscope.
bool isHeadless
Captures whether the RSVS window is being displayed or not.
PolyScopeRSVS()
Initialize polyscope, creating graphics contexts and constructing a window.
void addSurfaceProperties(std::string name, const mesh &surfaceMesh)
Adds properties of the surface of a snake to it's mesh as scalar quantities.
void show(size_t forFrames=SIZE_MAX)
Show the polyscope window.
void setInteractiveCallback(integrate::RSVSclass &RSVSobj)
Set polyscope's user callback to a lambda which allows control of the RSVSobj.
void addSnake(std::string name, const snake &snakeIn)
PLot a snake with it's velocity in the given polyscope window.
Tools for the mathematical processing of meshes.
std::vector< double > CalculateEdgeCurvature(const mesh &meshin)
Calculates the angles between the surfaces connected at an edge.
std::vector< double > CalculateVertexCurvature(const mesh &meshin, int smoothingSteps)
Calculates the vertex curvature.
std::vector< double > CalculateEdgeLengths(const mesh &meshin)
Calculates the edge lengths.
std::vector< double > CalculateVertexMinEdgeLength(const mesh &meshin)
Calculates the vertex minimum edge length.
std::vector< double > CalculateVertexMeanEdgeLength(const mesh &meshin)
Calculates the vertex mean edge length.
std::vector< double > CalculateVertexMaxEdgeLength(const mesh &meshin)
Calculates the vertex maximum edge length.
Contains overloads of functions for displaying and configuring the parameter structure.
int show()
Should display the polyscope window.
int init()
Should initialise polyscope.
bool TEST_HEADLESS
Boolean controlling wether tests are run in headless mode or not.
int meshShow()
Should display a single small cubic mesh.
Namespace containing interfaces to polyscope for RSVS objects.
bool POLYSCOPE_INITIALISED
Flag controlling wether polyscope has been initialised or not.
Parameters for the integrated 3DRSVS.
Provide an interface between the RSVS process and polyscope.
Interface between the RSVS project and the JSON for Modern C++ library.
Generation of cartesian grids.
#define RSVS3D_ERROR(M)
Throw generic rsvs errors.
#define RSVS3D_ERROR_RANGE(M)
Throw a range_error.