Merge pull request #6653 from MaelRL/AW3-Siggraph_demo-GF

AW3: Visualize and save wrapping iterations
This commit is contained in:
Laurent Rineau 2022-06-15 10:19:00 +02:00
commit 36349f924d
5 changed files with 491 additions and 96 deletions

View File

@ -99,6 +99,32 @@ public:
};
};
struct Wrapping_default_visitor
{
Wrapping_default_visitor() { }
template <typename AlphaWrapper>
void on_alpha_wrapping_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_flood_fill_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper, typename Gate>
void before_facet_treatment(const AlphaWrapper&, const Gate&) { }
template <typename Wrapper, typename Point>
void before_Steiner_point_insertion(const Wrapper&, const Point&) { }
template <typename Wrapper, typename VertexHandle>
void after_Steiner_point_insertion(const Wrapper&, VertexHandle) { }
template <typename AlphaWrapper>
void on_flood_fill_end(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_alpha_wrapping_end(const AlphaWrapper&) { };
};
template <typename Oracle>
class Alpha_wrap_3
{
@ -172,6 +198,9 @@ public:
public:
const Geom_traits& geom_traits() const { return m_dt.geom_traits(); }
Dt& triangulation() { return m_dt; }
const Dt& triangulation() const { return m_dt; }
const Alpha_PQ& queue() const { return m_queue; }
double default_alpha() const
{
@ -216,6 +245,15 @@ public:
OVPM ovpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_property_map(vertex_point, output_mesh));
typedef typename internal_np::Lookup_named_param_def <
internal_np::visitor_t,
NamedParameters,
Wrapping_default_visitor // default
>::reference Visitor;
Wrapping_default_visitor default_visitor;
Visitor visitor = choose_parameter(get_parameter_reference(np, internal_np::visitor), default_visitor);
std::vector<Point_3> no_seeds;
using Seeds = typename internal_np::Lookup_named_param_def<
internal_np::seed_points_t, NamedParameters, std::vector<Point_3> >::reference;
@ -228,6 +266,8 @@ public:
t.start();
#endif
visitor.on_alpha_wrapping_begin(*this);
if(!initialize(alpha, offset, seeds))
return;
@ -237,7 +277,7 @@ public:
CGAL::parameters::vertex_point_map(ovpm).stream_precision(17));
#endif
alpha_flood_fill();
alpha_flood_fill(visitor);
#ifdef CGAL_AW3_TIMER
t.stop();
@ -315,6 +355,8 @@ public:
dump_triangulation_faces("final_dt3.off", false /*only_boundary_faces*/);
#endif
#endif
visitor.on_alpha_wrapping_end(*this);
}
// Convenience overloads
@ -607,11 +649,12 @@ private:
return true;
}
public:
// Manifoldness is tolerated while debugging and extracting at intermediate states
// Not the preferred way because it uses 3*nv storage
template <typename OutputMesh, typename OVPM>
void extract_possibly_non_manifold_surface(OutputMesh& output_mesh,
OVPM ovpm)
OVPM ovpm) const
{
namespace PMP = Polygon_mesh_processing;
@ -696,7 +739,7 @@ private:
template <typename OutputMesh, typename OVPM>
void extract_manifold_surface(OutputMesh& output_mesh,
OVPM ovpm)
OVPM ovpm) const
{
namespace PMP = Polygon_mesh_processing;
@ -748,7 +791,12 @@ private:
if(faces.empty())
return;
CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces));
if(!PMP::is_polygon_soup_a_polygon_mesh(faces))
{
CGAL_warning_msg(false, "Could NOT extract mesh...");
return;
}
PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh,
CGAL::parameters::default_values(),
CGAL::parameters::vertex_point_map(ovpm));
@ -763,7 +811,7 @@ private:
template <typename OutputMesh, typename OVPM>
void extract_surface(OutputMesh& output_mesh,
OVPM ovpm,
const bool tolerate_non_manifoldness = false)
const bool tolerate_non_manifoldness = false) const
{
if(tolerate_non_manifoldness)
extract_possibly_non_manifold_surface(output_mesh, ovpm);
@ -990,12 +1038,15 @@ private:
return initialize_with_cavities(seeds);
}
void alpha_flood_fill()
template <typename Visitor>
void alpha_flood_fill(Visitor& visitor)
{
#ifdef CGAL_AW3_DEBUG
std::cout << "> Flood fill..." << std::endl;
#endif
visitor.on_flood_fill_begin(*this);
// Explore all finite cells that are reachable from one of the initial outside cells.
while(!m_queue.empty())
{
@ -1022,6 +1073,8 @@ private:
std::cout << "Priority: " << gate.priority() << std::endl;
#endif
visitor.before_facet_treatment(*this, gate);
m_queue.pop();
#ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP
@ -1082,10 +1135,14 @@ private:
m_queue.erase(Gate(mf));
}
visitor.before_Steiner_point_insertion(*this, steiner_point);
// Actual insertion of the Steiner point
Vertex_handle vh = m_dt.insert(steiner_point, lt, conflict_cell, li, lj);
vh->info() = DEFAULT;
visitor.after_Steiner_point_insertion(*this, vh);
std::vector<Cell_handle> new_cells;
new_cells.reserve(32);
m_dt.incident_cells(vh, std::back_inserter(new_cells));
@ -1133,6 +1190,8 @@ private:
}
} // while(!queue.empty())
visitor.on_flood_fill_end(*this);
// Check that no useful facet has been ignored
CGAL_postcondition_code(for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) {)
CGAL_postcondition_code( if(fit->first->info().is_outside == fit->first->neighbor(fit->second)->info().is_outside) continue;)

View File

@ -563,6 +563,21 @@ public:
*/
void saveSnapshot();
/*!
* Takes a snapshot without any dialog
*/
void saveSnapshot(const QString& fileName,
const qreal finalWidth,
const qreal finalHeight,
const bool expand = false,
const double oversampling = 1.,
qglviewer::SnapShotBackground background_color = qglviewer::CURRENT_BACKGROUND);
void saveSnapshot(const QString& fileName)
{
return saveSnapshot(fileName, this->width(), this->height());
}
public:
Q_SIGNALS:
/*! Signal emitted by the default init() method.

View File

@ -3761,8 +3761,29 @@ void CGAL::QGLViewer::saveSnapshot()
}
}
CGAL_INLINE_FUNCTION
void CGAL::QGLViewer::saveSnapshot(const QString& fileName,
const qreal finalWidth, const qreal finalHeight,
const bool expand,
const double oversampling,
qglviewer::SnapShotBackground background_color)
{
if(fileName.isEmpty())
return;
QSize finalSize(finalWidth, finalHeight);
QImage* image = takeSnapshot(qglviewer::SnapShotBackground(background_color),
finalSize, oversampling, expand);
if(image)
{
image->save(fileName);
delete image;
}
}
} // namespace CGAL
CGAL_INLINE_FUNCTION
bool CGAL::QGLViewer::isSharing() const
{

View File

@ -12,13 +12,15 @@
#include <CGAL/alpha_wrap_3.h>
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
#include <QElapsedTimer>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include <QString>
#include <QDialog>
#include <QElapsedTimer>
#include <QMainWindow>
#include <QMessageBox>
#include <QTextStream>
#include <QString>
#include <QTranslator>
#include <QtPlugin>
#include <vector>
@ -29,6 +31,183 @@
#include "ui_alpha_wrap_3_dialog.h"
struct Iterative_AW3_visualization_visitor
{
private:
bool m_do_snapshot;
Scene_polygon_soup_item* m_iterative_wrap_item = nullptr;
int sid = 0;
public:
template <typename Scene>
Iterative_AW3_visualization_visitor(Scene* scene,
const bool visualize_iterations,
const bool do_snapshot)
: m_do_snapshot(do_snapshot)
{
if(!visualize_iterations)
return;
m_iterative_wrap_item = new Scene_polygon_soup_item();
m_iterative_wrap_item->setName(QString("Iterative wrap"));
scene->addItem(m_iterative_wrap_item);
}
public:
template <typename AlphaWrapper>
void on_alpha_wrapping_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_flood_fill_begin(const AlphaWrapper&) { }
template <typename AlphaWrapper, typename Facet>
void before_facet_treatment(const AlphaWrapper&,
const Facet&) { }
template <typename AlphaWrapper, typename Point>
void before_Steiner_point_insertion(const AlphaWrapper& wrapper,
const Point& /* p */)
{
if(m_iterative_wrap_item == nullptr)
return;
// If the next top of the queue has vertices on the bbox, don't draw (as to avoid producing
// spikes in the visualization)
// const auto& gate = wrapper.queue().top();
// if(wrapper.triangulation().number_of_vertices() > 500 && gate.is_artificial_facet())
// return;
// Skip some...
if(wrapper.triangulation().number_of_vertices() % 50 != 0)
return;
// Extract the wrap as a triangle soup
using Dt = typename std::decay<decltype(wrapper.triangulation())>::type;
using Vertex_handle = typename Dt::Vertex_handle;
using Facet = typename Dt::Facet;
using Cell_handle = typename Dt::Cell_handle;
std::vector<Kernel::Point_3> points;
std::vector<std::vector<std::size_t> > faces;
std::unordered_map<Vertex_handle, std::size_t> vertex_to_id;
std::size_t nv = 0;
// This is used to compute colors depending on what is old and what is new.
// It is not currently used (a uniform gray color is used), but leaving it as it might be useful.
std::size_t min_time_stamp = -1, max_time_stamp = 0;
for(auto cit=wrapper.triangulation().finite_cells_begin(), cend=wrapper.triangulation().finite_cells_end(); cit!=cend; ++cit)
{
if(cit->time_stamp() > max_time_stamp)
max_time_stamp = cit->time_stamp();
if(cit->time_stamp() < min_time_stamp)
min_time_stamp = cit->time_stamp();
}
std::vector<CGAL::IO::Color> vcolors;
std::vector<CGAL::IO::Color> fcolors;
for(auto fit=wrapper.triangulation().finite_facets_begin(), fend=wrapper.triangulation().finite_facets_end(); fit!=fend; ++fit)
{
Facet f = *fit;
if(!f.first->info().is_outside)
f = wrapper.triangulation().mirror_facet(f);
const Cell_handle c = f.first;
const int s = f.second;
const Cell_handle nh = c->neighbor(s);
if(c->info().is_outside == nh->info().is_outside)
continue;
std::array<std::size_t, 3> ids;
for(int pos=0; pos<3; ++pos)
{
Vertex_handle vh = c->vertex(Dt::vertex_triple_index(s, pos));
auto insertion_res = vertex_to_id.emplace(vh, nv);
if(insertion_res.second) // successful insertion, never-seen-before vertex
{
points.push_back(wrapper.triangulation().point(vh));
vcolors.push_back(CGAL::IO::Color(0, 0, 0));
++nv;
}
ids[pos] = insertion_res.first->second;
}
faces.emplace_back(std::vector<std::size_t>{ids[0], ids[1], ids[2]});
double color_val = double(c->time_stamp() - min_time_stamp) / double(max_time_stamp - min_time_stamp);
color_val = int(256. * color_val);
// fcolors.push_back(CGAL::IO::Color(color_val, 10, 150)); // young is red, old is blue
// fcolors.push_back(CGAL::IO::Color(256 - color_val, 256 - color_val, 256 - color_val)); // young is light, old is dark
fcolors.push_back(CGAL::IO::Color(100, 100, 100)); // uniform darkish gray
}
// Update the wrap item's visualization
m_iterative_wrap_item->load(points, faces, fcolors, vcolors);
m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid));
m_iterative_wrap_item->setAlpha(255 / 2);
m_iterative_wrap_item->invalidateOpenGLBuffers();
m_iterative_wrap_item->redraw();
m_iterative_wrap_item->itemChanged();
// Refresh the view
QApplication::processEvents();
if(m_do_snapshot)
{
std::stringstream oss;
oss << "Wrap_iteration-" << sid << ".png" << std::ends;
QString filename = QString::fromStdString(oss.str().c_str());
CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer();
viewer->saveSnapshot(filename, 1920, 1080, true /*expand*/, 2.0 /*oversampling*/);
}
++sid;
}
template <typename AlphaWrapper, typename VertexHandle>
void after_Steiner_point_insertion(const AlphaWrapper&,
const VertexHandle) { }
template <typename AlphaWrapper>
void on_flood_fill_end(const AlphaWrapper&) { }
template <typename AlphaWrapper>
void on_alpha_wrapping_end(const AlphaWrapper&)
{
if(m_iterative_wrap_item == nullptr)
return;
m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid));
m_iterative_wrap_item->setAlpha(255);
m_iterative_wrap_item->invalidateOpenGLBuffers();
m_iterative_wrap_item->redraw();
m_iterative_wrap_item->itemChanged();
QApplication::processEvents();
if(m_do_snapshot)
{
std::stringstream oss;
oss << "Wrap_iteration-" << sid << ".png" << std::ends;
QString filename = QString::fromStdString(oss.str().c_str());
CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer();
viewer->saveSnapshot(filename);
}
m_iterative_wrap_item->setVisible(false);
// Refresh the view
QApplication::processEvents();
}
};
class Polyhedron_demo_alpha_wrap_3_plugin
: public QObject,
public CGAL::Three::Polyhedron_demo_plugin_helper
@ -90,6 +269,9 @@ private:
connect(ui.wrapEdges, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_faces()));
connect(ui.wrapFaces, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_edges()));
connect(ui.visualizeIterations, SIGNAL(clicked(bool)),
this, SLOT(update_iteration_snapshot_checkbox()));
connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
@ -109,6 +291,11 @@ public Q_SLOTS:
ui.wrapEdges->setChecked(true);
}
void update_iteration_snapshot_checkbox()
{
ui.snapshotIterations->setCheckable(ui.visualizeIterations->isChecked());
}
void on_actionAlpha_wrap_3_triggered()
{
using Triangles = std::vector<Kernel::Triangle_3>;
@ -132,6 +319,8 @@ public Q_SLOTS:
const bool enforce_manifoldness = ui.runManifoldness->isChecked();
double alpha = ui.alphaValue->value();
double offset = ui.offsetValue->value();
const bool visualize_iterations = ui.visualizeIterations->isChecked();
const bool do_snapshot_iterations = ui.snapshotIterations->isChecked();
if(alpha <= 0. || offset <= 0.)
return;
@ -170,6 +359,8 @@ public Q_SLOTS:
get(vpm, source(h, *pMesh)));
}
sm_item->setRenderingMode(Flat);
continue;
}
@ -192,6 +383,8 @@ public Q_SLOTS:
soup_item->points()[p[2]]);
}
soup_item->setRenderingMode(Flat);
continue;
}
@ -287,6 +480,11 @@ public Q_SLOTS:
}
}
std::cout << triangles.size() << " triangles" << std::endl;
std::cout << segments.size() << " edges" << std::endl;
std::cout << points.size() << " points" << std::endl;
std::cout << "do wrap edges/faces: " << wrap_segments << " " << wrap_triangles << std::endl;
if(wrap_triangles)
oracle.add_triangle_soup(triangles);
if(wrap_segments)
@ -314,13 +512,18 @@ public Q_SLOTS:
CGAL::Alpha_wraps_3::internal::Alpha_wrap_3<Oracle> aw3(oracle);
Iterative_AW3_visualization_visitor visitor(scene,
visualize_iterations,
do_snapshot_iterations);
SMesh wrap;
aw3(alpha, offset, wrap,
CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness));
CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness)
.visitor(visitor));
Scene_surface_mesh_item* wrap_item = new Scene_surface_mesh_item(wrap);
wrap_item->setName(tr("Wrap alpha %2 offset %3").arg(alpha).arg(offset));
wrap_item->setColor(Qt::cyan);
wrap_item->setName(tr("Wrap with alpha %2 offset %3").arg(alpha).arg(offset));
wrap_item->setColor(Qt::gray);
scene->addItem(wrap_item);
QApplication::restoreOverrideCursor();

View File

@ -10,31 +10,21 @@
<x>0</x>
<y>0</y>
<width>646</width>
<height>432</height>
<height>673</height>
</rect>
</property>
<property name="windowTitle">
<string>3D Alpha Wrapping</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>3D Alpha Wrapping</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="13" column="1">
<widget class="QCheckBox" name="runManifoldness">
<item row="11" column="1">
<widget class="QCheckBox" name="wrapEdges">
<property name="text">
<string/>
</property>
@ -62,71 +52,21 @@
</property>
</widget>
</item>
<item row="13" column="0">
<item row="15" column="0">
<widget class="QLabel" name="runManifoldness_Label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Enforce 2-manifoldness</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enforce 2-manifold output&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="12" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="relativeOffset">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="wrapEdges">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="relativeAlpha">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="offsetValue_Label">
<property name="text">
<string>Offset value:</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_3">
<item row="18" column="0">
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -148,27 +88,59 @@
</property>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="Line" name="line_2">
<item row="9" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0">
<widget class="QLabel" name="wrapEdges_Label">
<item row="12" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="19" column="0">
<widget class="QLabel" name="visualizeIterations_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap edges&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only extremities of the edges are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>Visualize iterations</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="relativeOffset_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox offset&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;offset := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox offset&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(i.e., value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;offset := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="16" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="offsetValue">
<property name="decimals">
@ -188,8 +160,29 @@
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QCheckBox" name="wrapFaces">
<item row="17" column="0" colspan="2">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="wrapFaces_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap faces&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only edges of the faces are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="wrapEdges_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap edges&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only extremities of the edges are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="relativeAlpha">
<property name="text">
<string/>
</property>
@ -198,17 +191,47 @@
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="wrapFaces_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wrap faces&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;If deactivated, only edges of the faces are taken into account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<item row="7" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="relativeAlpha_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox alpha&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means alpha&lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt; := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use relative-to-bbox alpha&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;As ratio of the length of the bbox's diagonal&lt;br/&gt;(i.e., value &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;x &lt;/span&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;means alpha&lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt; := bbox_diag_l / x)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="21" column="0">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="19" column="1">
<widget class="QCheckBox" name="visualizeIterations">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="wrapFaces">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
@ -225,16 +248,90 @@
</property>
</spacer>
</item>
<item row="7" column="0" colspan="2">
<item row="6" column="1">
<widget class="QCheckBox" name="relativeOffset">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="13" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="offsetValue_Label">
<property name="text">
<string>Offset value:</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QCheckBox" name="runManifoldness">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="14" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="20" column="0">
<widget class="QLabel" name="snapshotIterations_Label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Snapshot iterations&lt;br/&gt;&lt;span style=&quot; font-size:9pt;&quot;&gt;For each iteration, save a snapshot of the viewer &lt;br/&gt;to a file named &lt;/span&gt;&lt;span style=&quot; font-size:9pt; font-style:italic;&quot;&gt;Wrap-iteration_i.png&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="20" column="1">
<widget class="QCheckBox" name="snapshotIterations">
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>