mirror of https://github.com/CGAL/cgal
Work on display property plugin (+ heat method)
- separated property display and Heat method into two independent plugins - redesigned UIs - added "Largest Angle per face" and "face areas" to the display properties - enable using a selection item to select heat method's source vertices - fixed smallest angle computation - fixed storing wrong display values - fixed applicable() returning true too often - fixed zoom not working for property maps other than the plugin's - fixed zoom not working for simplices other than faces - fixed zoom not working for point sets - fixed color map ignoring the user's color choice - fixed property combobox resetting on pretty much other action - fixed not resetting colors when items are modified - fixed broken connections in the heat method plugin - fixed not actually emitting anything when a list selection is changed - much more stuff
This commit is contained in:
parent
0f25ddae73
commit
c4f4bc4cac
|
|
@ -3,13 +3,17 @@
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
inline QColor generate_color(double h, double s_min = 0.35)
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
inline QColor generate_color(double h,
|
||||||
|
double s_min = 0.35)
|
||||||
{
|
{
|
||||||
std::size_t s_max=255;
|
std::size_t s_max = 255;
|
||||||
if(h >0.8 && h < 0.95) //span of ugly pink, desaturates make it less garish IMO
|
if(h > 0.8 && h < 0.95) // span of ugly pink, desaturates make it less garish IMO
|
||||||
s_max = 160;
|
s_max = 160;
|
||||||
std::size_t s = std::rand() % (s_max-static_cast<std::size_t>(s_min*255)) + static_cast<int>(s_min*255);
|
std::size_t s = std::rand() % (s_max-static_cast<std::size_t>(s_min*255)) + static_cast<int>(s_min*255);
|
||||||
return QColor::fromHsvF(h,s/255.0,1.0);
|
return QColor::fromHsvF(h, s/255.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,19 +26,23 @@ compute_color_map(QColor base_color,
|
||||||
qreal hue = base_color.hueF();
|
qreal hue = base_color.hueF();
|
||||||
const qreal step = (static_cast<qreal>(1)) / nb_of_colors;
|
const qreal step = (static_cast<qreal>(1)) / nb_of_colors;
|
||||||
|
|
||||||
qreal h = hue==-1 ? 0
|
qreal h = (hue == -1) ? 0 : hue;
|
||||||
:hue;
|
for(std::size_t i=0; i<nb_of_colors; ++i)
|
||||||
for(unsigned i = 0; i < nb_of_colors; ++i) {
|
{
|
||||||
if (h!=-1) h += step;
|
if(h != -1)
|
||||||
if ( h > 1 ) { h -= 1; }
|
h += step;
|
||||||
|
if(h > 1)
|
||||||
|
h -= 1;
|
||||||
*out++ = generate_color(h);
|
*out++ = generate_color(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QColor generate_random_color() {
|
inline QColor generate_random_color()
|
||||||
|
{
|
||||||
std::size_t h = static_cast<std::size_t>(std::rand() % 360);
|
std::size_t h = static_cast<std::size_t>(std::rand() % 360);
|
||||||
return generate_color(h/359.0);
|
return generate_color(h / 359.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // _COLOR_MAP_H
|
||||||
|
|
|
||||||
|
|
@ -1440,7 +1440,7 @@ QList<int> MainWindow::getSelectedSceneItemIndices() const
|
||||||
void MainWindow::selectionChanged()
|
void MainWindow::selectionChanged()
|
||||||
{
|
{
|
||||||
scene->setSelectedItemIndex(getSelectedSceneItemIndex());
|
scene->setSelectedItemIndex(getSelectedSceneItemIndex());
|
||||||
scene->setSelectedItemsList(getSelectedSceneItemIndices());
|
scene->setSelectedItemIndices(getSelectedSceneItemIndices());
|
||||||
CGAL::Three::Scene_item* item = scene->item(getSelectedSceneItemIndex());
|
CGAL::Three::Scene_item* item = scene->item(getSelectedSceneItemIndex());
|
||||||
Q_FOREACH(CGAL::QGLViewer* vi, CGAL::QGLViewer::QGLViewerPool())
|
Q_FOREACH(CGAL::QGLViewer* vi, CGAL::QGLViewer::QGLViewerPool())
|
||||||
{
|
{
|
||||||
|
|
@ -2193,7 +2193,7 @@ void MainWindow::on_actionEraseAll_triggered()
|
||||||
QList<int> all_ids;
|
QList<int> all_ids;
|
||||||
for(int i = 0; i < scene->numberOfEntries(); ++i)
|
for(int i = 0; i < scene->numberOfEntries(); ++i)
|
||||||
all_ids.push_back(i);
|
all_ids.push_back(i);
|
||||||
scene->setSelectedItemsList(all_ids);
|
scene->setSelectedItemIndices(all_ids);
|
||||||
on_actionErase_triggered();
|
on_actionErase_triggered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
include(polyhedron_demo_macros)
|
include(polyhedron_demo_macros)
|
||||||
if(TARGET CGAL::Eigen3_support)
|
|
||||||
qt5_wrap_ui( display_propertyUI_FILES Display_property.ui )
|
qt5_wrap_ui(display_propertyUI_FILES Display_property.ui)
|
||||||
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
|
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
|
||||||
target_link_libraries(display_property_plugin
|
target_link_libraries(display_property_plugin PUBLIC scene_surface_mesh_item
|
||||||
PUBLIC
|
|
||||||
scene_surface_mesh_item
|
|
||||||
scene_points_with_normal_item
|
scene_points_with_normal_item
|
||||||
|
scene_color_ramp)
|
||||||
|
|
||||||
|
if(TARGET CGAL::Eigen3_support)
|
||||||
|
qt5_wrap_ui(heat_methodUI_FILES Heat_method.ui)
|
||||||
|
polyhedron_demo_plugin(heat_method_plugin Heat_method_plugin ${heat_methodUI_FILES} KEYWORDS Viewer)
|
||||||
|
target_link_libraries(heat_method_plugin PUBLIC scene_surface_mesh_item
|
||||||
|
scene_selection_item
|
||||||
scene_color_ramp
|
scene_color_ramp
|
||||||
CGAL::Eigen3_support)
|
CGAL::Eigen3_support)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -2,209 +2,59 @@
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>DisplayPropertyWidget</class>
|
<class>DisplayPropertyWidget</class>
|
||||||
<widget class="QDockWidget" name="DisplayPropertyWidget">
|
<widget class="QDockWidget" name="DisplayPropertyWidget">
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>292</width>
|
|
||||||
<height>508</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Property Displaying</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0">
|
|
||||||
<item>
|
|
||||||
<widget class="QScrollArea" name="scrollArea">
|
|
||||||
<property name="horizontalScrollBarPolicy">
|
|
||||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
|
||||||
</property>
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>127</width>
|
|
||||||
<height>430</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="legendLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>RAMP DISPLAYING</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QPushButton" name="colorizeButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Colorize</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QTabWidget" name="colorChoiceWidget">
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="ramp_tab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Ramp</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
|
||||||
<property name="title">
|
|
||||||
<string>Ramp Colors</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="minColorButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Color Min...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="maxColorButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Color Max...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="map_tab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Map</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="initColorButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Initial Color...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<widget class="QPushButton" name="sourcePointsButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Select Source Points</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Zoom </string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="zoomToMinButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Zoom to min</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="zoomToMaxButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Zoom to max</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Ramp Extrema</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="DoubleEdit" name="minBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>0.00</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="DoubleEdit" name="maxBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>2.00</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="1">
|
|
||||||
<widget class="QPushButton" name="deleteButton">
|
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>514</width>
|
||||||
|
<height>695</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>514</width>
|
||||||
|
<height>695</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Property Display</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="9" column="0" colspan="2">
|
||||||
|
<widget class="QPushButton" name="colorizeButton">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Cantarell</family>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Delete Group</string>
|
<string>Color Item</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="0" column="0" colspan="2">
|
||||||
</item>
|
<widget class="QGroupBox" name="propertyGroup">
|
||||||
</layout>
|
<property name="title">
|
||||||
</item>
|
<string>Property</string>
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<size>
|
<property name="leftMargin">
|
||||||
<width>40</width>
|
<number>6</number>
|
||||||
<height>20</height>
|
</property>
|
||||||
</size>
|
<property name="topMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>6</number>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="propertyBox">
|
<widget class="QComboBox" name="propertyBox">
|
||||||
<property name="sizeAdjustPolicy">
|
<property name="sizeAdjustPolicy">
|
||||||
|
|
@ -233,8 +83,11 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="0">
|
||||||
|
<layout class="QGridLayout" name="ColoringGroup" columnstretch="50,50">
|
||||||
|
<item row="0" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
|
@ -247,6 +100,193 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="coloringChoiceGroup">
|
||||||
|
<property name="title">
|
||||||
|
<string>Color Visualization</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2" columnstretch="50,50">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QRadioButton" name="randomColorsRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Random colors</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QPushButton" name="minColorButton">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0">
|
||||||
|
<widget class="QLabel" name="initColorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>First color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="maxColorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QRadioButton" name="colorRampRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Color Ramp</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QPushButton" name="initColorButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QPushButton" name="maxColorButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="minColorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Min color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" 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="0" column="1" rowspan="3">
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>236</width>
|
||||||
|
<height>397</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="legendLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>RAMP DISPLAYING</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
|
<widget class="QGroupBox" name="extremeValuesGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Extreme Values</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="extremeValuesMinLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Min Value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="extremeValuesMaxLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max Value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="DoubleEdit" name="maxBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>2.00</string>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QPushButton" name="zoomToMaxButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom to max value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QPushButton" name="zoomToMinButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom to min value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="DoubleEdit" name="minBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>0.00</string>
|
||||||
|
</property>
|
||||||
|
<property name="frame">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,294 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>HeatMethodWidget</class>
|
||||||
|
<widget class="QDockWidget" name="HeatMethodWidget">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>365</width>
|
||||||
|
<height>708</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>365</width>
|
||||||
|
<height>708</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Heat Method</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="3" column="0">
|
||||||
|
<layout class="QGridLayout" name="coloringGroup" columnstretch="50,50">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<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="0" column="1" rowspan="3">
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>161</width>
|
||||||
|
<height>371</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0" alignment="Qt::AlignHCenter">
|
||||||
|
<widget class="QLabel" name="legendLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>RAMP DISPLAYING</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="coloringChoiceGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Color Ramp</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2" columnstretch="50,50">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="minColorLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Min color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="minColorButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="maxColorLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Max color</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QPushButton" name="maxColorButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QGroupBox" name="methodGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Method</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="methodBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="0">
|
||||||
|
<widget class="QGroupBox" name="extremeValueGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Extreme Value</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="zoomToMaxButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom to max value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="extremeValueMaxLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Max Value</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="DoubleEdit" name="maxBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>0</string>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0" colspan="2">
|
||||||
|
<widget class="QPushButton" name="estimateDistancesButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Cantarell</family>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Estimate Geodesic Distances</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QGroupBox" name="sourcesGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Source Vertices</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPushButton" name="createSourceVerticesButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string extracomment="Use 'Shift + Left Click'"/>
|
||||||
|
</property>
|
||||||
|
<property name="toolTipDuration">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Create Source Vertices Selection Item</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>DoubleEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>CGAL_double_edit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
|
|
@ -0,0 +1,822 @@
|
||||||
|
#include "ui_Heat_method.h"
|
||||||
|
|
||||||
|
#include "Color_ramp.h"
|
||||||
|
#include "id_printing.h"
|
||||||
|
#include "Messages_interface.h"
|
||||||
|
#include "triangulate_primitive.h"
|
||||||
|
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Scene_polyhedron_selection_item.h"
|
||||||
|
#include "Scene_surface_mesh_item.h"
|
||||||
|
|
||||||
|
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||||
|
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
||||||
|
#include <CGAL/Three/Three.h>
|
||||||
|
#include <CGAL/Three/Triangle_container.h>
|
||||||
|
#include <CGAL/Buffer_for_vao.h>
|
||||||
|
|
||||||
|
#include <CGAL/boost/bimap.hpp>
|
||||||
|
#include <CGAL/boost/graph/helpers.h>
|
||||||
|
#include <CGAL/Dynamic_property_map.h>
|
||||||
|
#include <CGAL/Heat_method_3/Surface_mesh_geodesic_distances_3.h>
|
||||||
|
|
||||||
|
#include <QAbstractItemView>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QColorDialog>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QStyleFactory>
|
||||||
|
|
||||||
|
// @fixme multiple selection items are broken, so don't create a selection item if there is already one
|
||||||
|
|
||||||
|
using namespace CGAL::Three;
|
||||||
|
|
||||||
|
Viewer_interface* (&getActiveViewer)() = Three::activeViewer;
|
||||||
|
|
||||||
|
class Scene_heat_item
|
||||||
|
: public Scene_item_rendering_helper
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene_surface_mesh_item* parent;
|
||||||
|
SMesh* sm;
|
||||||
|
|
||||||
|
mutable std::vector<float> verts;
|
||||||
|
mutable std::vector<float> normals;
|
||||||
|
mutable std::vector<unsigned int> idx;
|
||||||
|
mutable std::vector<float> colors;
|
||||||
|
mutable std::vector<float> heat_values;
|
||||||
|
mutable std::size_t nb_idx;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Scene_heat_item(Scene_surface_mesh_item* item)
|
||||||
|
: parent(item), sm(item->face_graph())
|
||||||
|
{
|
||||||
|
CGAL_precondition(is_triangle_mesh(*sm));
|
||||||
|
|
||||||
|
setTriangleContainer(0, new Triangle_container(Viewer_interface::PROGRAM_HEAT_INTENSITY, true));
|
||||||
|
setRenderingMode(Gouraud);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Scene_heat_item(){}
|
||||||
|
|
||||||
|
Scene_item* clone() const Q_DECL_OVERRIDE { return nullptr; }
|
||||||
|
QString toolTip() const Q_DECL_OVERRIDE{ return QString(); }
|
||||||
|
Scene_surface_mesh_item* getParent() { return parent; }
|
||||||
|
bool isEmpty() const Q_DECL_OVERRIDE { return false; }
|
||||||
|
|
||||||
|
SMesh* face_graph() { return sm; }
|
||||||
|
|
||||||
|
void initializeBuffers(Viewer_interface *viewer) const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
getTriangleContainer(0)->initializeBuffers(viewer);
|
||||||
|
getTriangleContainer(0)->setIdxSize(nb_idx);
|
||||||
|
|
||||||
|
verts.resize(0);
|
||||||
|
verts.shrink_to_fit();
|
||||||
|
normals.resize(0);
|
||||||
|
normals.shrink_to_fit();
|
||||||
|
colors.resize(0);
|
||||||
|
colors.shrink_to_fit();
|
||||||
|
idx.clear();
|
||||||
|
idx.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Viewer_interface *viewer) const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
if(!visible())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!isInit(viewer))
|
||||||
|
initGL(viewer);
|
||||||
|
|
||||||
|
if(getBuffersFilled() && !getBuffersInit(viewer))
|
||||||
|
{
|
||||||
|
initializeBuffers(viewer);
|
||||||
|
setBuffersInit(viewer, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!getBuffersFilled())
|
||||||
|
{
|
||||||
|
computeElements();
|
||||||
|
initializeBuffers(viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTriangleContainer(0)->setAlpha(1.0f);
|
||||||
|
getTriangleContainer(0)->draw(viewer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compute_bbox() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
setBbox(parent->bbox());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool supportsRenderingMode(RenderingMode m) const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
return (m == Gouraud);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void invalidateOpenGLBuffers() Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
setBuffersFilled(false);
|
||||||
|
compute_bbox();
|
||||||
|
getTriangleContainer(0)->reset_vbos(NOT_INSTANCED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeElements() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
typedef CGAL::Buffer_for_vao<float, unsigned int> CPF;
|
||||||
|
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
|
auto vpm = CGAL::get(CGAL::vertex_point, *sm);
|
||||||
|
auto vnormals = sm->property_map<vertex_descriptor, EPICK::Vector_3>("v:normal").first;
|
||||||
|
auto fnormals = sm->property_map<face_descriptor, EPICK::Vector_3>("f:normal").first;
|
||||||
|
|
||||||
|
auto [vcolors, vcolors_found] = sm->property_map<vertex_descriptor, CGAL::IO::Color>("v:color");
|
||||||
|
CGAL_assertion(vcolors_found);
|
||||||
|
auto [vdist, vdist_found] = sm->property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity");
|
||||||
|
CGAL_assertion(vdist_found);
|
||||||
|
|
||||||
|
verts.clear();
|
||||||
|
normals.clear();
|
||||||
|
idx.clear();
|
||||||
|
colors.clear();
|
||||||
|
|
||||||
|
idx.reserve(3 * num_faces(*sm));
|
||||||
|
for(face_descriptor fd : faces(*sm))
|
||||||
|
{
|
||||||
|
for(halfedge_descriptor hd : halfedges_around_face(halfedge(fd, *sm),*sm))
|
||||||
|
idx.push_back(source(hd, *sm));
|
||||||
|
}
|
||||||
|
|
||||||
|
const CGAL::qglviewer::Vec& o = static_cast<Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
||||||
|
EPICK::Vector_3 offset(o.x, o.y, o.z);
|
||||||
|
|
||||||
|
for(vertex_descriptor vd : vertices(*sm))
|
||||||
|
{
|
||||||
|
const CGAL::IO::Color& c = vcolors[vd];
|
||||||
|
colors.push_back(float(c.red()) / 255);
|
||||||
|
colors.push_back(float(c.green()) / 255);
|
||||||
|
colors.push_back(float(c.blue()) / 255);
|
||||||
|
|
||||||
|
const EPICK::Point_3& p = get(vpm, vd) + offset;
|
||||||
|
CPF::add_point_in_buffer(p, verts);
|
||||||
|
|
||||||
|
const EPICK::Vector_3& n = vnormals[vd];
|
||||||
|
CPF::add_normal_in_buffer(n, normals);
|
||||||
|
|
||||||
|
heat_values.push_back(vdist[vd]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_idx = idx.size();
|
||||||
|
getTriangleContainer(0)->allocate(Triangle_container::Vertex_indices, idx.data(),
|
||||||
|
static_cast<int>(idx.size()*sizeof(unsigned int)));
|
||||||
|
getTriangleContainer(0)->allocate(Triangle_container::Smooth_vertices, verts.data(),
|
||||||
|
static_cast<int>(num_vertices(*sm)*3*sizeof(float)));
|
||||||
|
getTriangleContainer(0)->allocate(Triangle_container::Smooth_normals, normals.data(),
|
||||||
|
static_cast<int>(num_vertices(*sm)*3*sizeof(float)));
|
||||||
|
getTriangleContainer(0)->allocate(Triangle_container::VColors, colors.data(),
|
||||||
|
static_cast<int>(colors.size()*sizeof(float)));
|
||||||
|
getTriangleContainer(0)->allocate(Triangle_container::Distances, heat_values.data(),
|
||||||
|
static_cast<int>(heat_values.size()*sizeof(float)));
|
||||||
|
|
||||||
|
compute_bbox();
|
||||||
|
setBuffersFilled(true);
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
}; // class Scene_heat_item
|
||||||
|
|
||||||
|
class DockWidget
|
||||||
|
: public QDockWidget,
|
||||||
|
public Ui::HeatMethodWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DockWidget(const QString& name, QWidget *parent)
|
||||||
|
: QDockWidget(name, parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Heat_method_plugin
|
||||||
|
: public QObject,
|
||||||
|
public Polyhedron_demo_plugin_helper
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
||||||
|
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
||||||
|
|
||||||
|
using Vertex_distance_map = SMesh::Property_map<vertex_descriptor, double>;
|
||||||
|
using Heat_method = CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<SMesh>;
|
||||||
|
using Heat_method_idt = CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<SMesh, CGAL::Heat_method_3::Intrinsic_Delaunay>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QAction* actionHeatMethod;
|
||||||
|
|
||||||
|
DockWidget* dock_widget;
|
||||||
|
|
||||||
|
// coloring choice and legend
|
||||||
|
double rm = 1.;
|
||||||
|
double gm = 0.;
|
||||||
|
double bm = 0.;
|
||||||
|
double rM = 0.;
|
||||||
|
double gM = 1.;
|
||||||
|
double bM = 0.;
|
||||||
|
|
||||||
|
Color_ramp color_ramp;
|
||||||
|
QPixmap legend;
|
||||||
|
|
||||||
|
// tracking which scene items have which sources, and which heat method builders
|
||||||
|
boost::bimap<boost::bimaps::set_of<Scene_surface_mesh_item*>,
|
||||||
|
boost::bimaps::set_of<Scene_polyhedron_selection_item*> > item_source_vertices;
|
||||||
|
|
||||||
|
// the point of storing this is that in the Heat Method(s), a number of computations are only
|
||||||
|
// dependent on the mesh, and not the sources, and such can be performed just once.
|
||||||
|
std::unordered_map<Scene_surface_mesh_item*, Heat_method*> heat_methods;
|
||||||
|
std::unordered_map<Scene_surface_mesh_item*, Heat_method_idt*> idt_heat_methods;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool applicable(QAction*) const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
// Single item => it must be a mesh and the selection item will be created through the plugin's button
|
||||||
|
if(scene->selectionIndices().size() == 1)
|
||||||
|
{
|
||||||
|
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||||
|
return qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
}
|
||||||
|
// Two items => it must be a surface mesh and a selection item (in any order)
|
||||||
|
else if(scene->selectionIndices().size() == 2)
|
||||||
|
{
|
||||||
|
Scene_item* item1 = scene->item(scene->selectionIndices().front());
|
||||||
|
Scene_item* item2 = scene->item(scene->selectionIndices().back());
|
||||||
|
return ((qobject_cast<Scene_surface_mesh_item*>(item1) &&
|
||||||
|
qobject_cast<Scene_polyhedron_selection_item*>(item2)) ||
|
||||||
|
(qobject_cast<Scene_polyhedron_selection_item*>(item1) &&
|
||||||
|
qobject_cast<Scene_surface_mesh_item*>(item2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QAction*> actions() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
return QList<QAction*>() << actionHeatMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(QMainWindow* mw,
|
||||||
|
Scene_interface* sc,
|
||||||
|
Messages_interface*) Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
this->scene = sc;
|
||||||
|
this->mw = mw;
|
||||||
|
|
||||||
|
actionHeatMethod = new QAction(QString("Heat Method"), mw);
|
||||||
|
actionHeatMethod->setProperty("submenuName", "Color");
|
||||||
|
|
||||||
|
connect(actionHeatMethod, SIGNAL(triggered()),
|
||||||
|
this, SLOT(openDialog()));
|
||||||
|
|
||||||
|
Scene* scene_item = static_cast<Scene*>(scene);
|
||||||
|
connect(scene_item, SIGNAL(itemIndicesSelected(QList<int>)),
|
||||||
|
this, SLOT(onItemIndicesSelected(QList<int>)));
|
||||||
|
|
||||||
|
// Dock Widget
|
||||||
|
dock_widget = new DockWidget("Heat Method", mw);
|
||||||
|
addDockWidget(dock_widget);
|
||||||
|
dock_widget->setVisible(false);
|
||||||
|
|
||||||
|
connect(dock_widget->methodBox, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(onNewMethodSelected(int)));
|
||||||
|
|
||||||
|
dock_widget->methodBox->addItems({"Heat Method",
|
||||||
|
"Heat Method (Intrinsic Delaunay)"});
|
||||||
|
|
||||||
|
connect(dock_widget->createSourceVerticesButton, SIGNAL(clicked()),
|
||||||
|
this, SLOT(createSourceVerticesSelectionItem()));
|
||||||
|
|
||||||
|
QPalette palette(Qt::red);
|
||||||
|
dock_widget->minColorButton->setPalette(palette);
|
||||||
|
dock_widget->minColorButton->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
dock_widget->minColorButton->update();
|
||||||
|
|
||||||
|
palette = QPalette(Qt::green);
|
||||||
|
dock_widget->maxColorButton->setPalette(palette);
|
||||||
|
dock_widget->maxColorButton->setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
dock_widget->maxColorButton->update();
|
||||||
|
|
||||||
|
// lambda to generate the three connect(), for each color button (min, max, map)
|
||||||
|
auto connect_color_buttons = [this](QPushButton* colorButton,
|
||||||
|
double& r, double& g, double& b)
|
||||||
|
{
|
||||||
|
connect(colorButton, &QPushButton::pressed,
|
||||||
|
this, [this, colorButton, &r, &g, &b]()
|
||||||
|
{
|
||||||
|
QColor color = QColorDialog::getColor();
|
||||||
|
if(!color.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
r = color.redF();
|
||||||
|
g = color.greenF();
|
||||||
|
b = color.blueF();
|
||||||
|
|
||||||
|
QPalette palette(color);
|
||||||
|
colorButton->setPalette(palette);
|
||||||
|
colorButton->update();
|
||||||
|
|
||||||
|
displayRampLegend();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
connect_color_buttons(dock_widget->minColorButton, rm, gm, bm);
|
||||||
|
connect_color_buttons(dock_widget->maxColorButton, rM, gM, bM);
|
||||||
|
|
||||||
|
// Main action connection
|
||||||
|
connect(dock_widget->estimateDistancesButton, SIGNAL(clicked(bool)),
|
||||||
|
this, SLOT(estimateDistances()));
|
||||||
|
|
||||||
|
// Post coloring connection
|
||||||
|
connect(dock_widget->zoomToMaxButton, &QPushButton::pressed,
|
||||||
|
this, &Heat_method_plugin::on_zoomToMaxButton_pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void openDialog()
|
||||||
|
{
|
||||||
|
if(!dock_widget->isVisible())
|
||||||
|
dock_widget->show();
|
||||||
|
dock_widget->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void closure() Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
dock_widget->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void disableExtremeValue()
|
||||||
|
{
|
||||||
|
dock_widget->extremeValueGroup->setEnabled(false);
|
||||||
|
dock_widget->zoomToMaxButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableExtremeValue()
|
||||||
|
{
|
||||||
|
dock_widget->extremeValueGroup->setEnabled(true);
|
||||||
|
dock_widget->zoomToMaxButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetExtremeValue()
|
||||||
|
{
|
||||||
|
dock_widget->maxBox->setRange(0, 99999999);
|
||||||
|
dock_widget->maxBox->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayRampLegend()
|
||||||
|
{
|
||||||
|
color_ramp = Color_ramp(rm, rM, gm, gM, bm, bM);
|
||||||
|
|
||||||
|
const int height = 256;
|
||||||
|
const int width = 140;
|
||||||
|
const int cell_width = width / 3;
|
||||||
|
const int top_margin = 5;
|
||||||
|
const int left_margin = 5;
|
||||||
|
const int drawing_height = height - 2*top_margin;
|
||||||
|
const int text_height = 20;
|
||||||
|
|
||||||
|
legend = QPixmap(width, height + text_height);
|
||||||
|
legend.fill(QColor(200, 200, 200));
|
||||||
|
|
||||||
|
QPainter painter(&legend);
|
||||||
|
painter.setPen(Qt::black);
|
||||||
|
painter.setBrush(QColor(200, 200, 200));
|
||||||
|
|
||||||
|
const double min_value = 0;
|
||||||
|
const double max_value = dock_widget->maxBox->value();
|
||||||
|
|
||||||
|
// Build legend data
|
||||||
|
std::vector<double> graduations(100);
|
||||||
|
for(int i=0; i<100; ++i)
|
||||||
|
graduations[i] = i / 100.0;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(std::vector<double>::iterator it = graduations.begin(), end = graduations.end(); it != end; ++it, i+=2)
|
||||||
|
{
|
||||||
|
QColor color(255 * color_ramp.r(*it),
|
||||||
|
255 * color_ramp.g(*it),
|
||||||
|
255 * color_ramp.b(*it));
|
||||||
|
painter.fillRect(left_margin, drawing_height - top_margin - i, cell_width, 2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw right vertical line
|
||||||
|
painter.setPen(Qt::blue);
|
||||||
|
painter.drawLine(QPoint(left_margin + cell_width + 10,
|
||||||
|
drawing_height - top_margin + 2),
|
||||||
|
QPoint(left_margin + cell_width + 10,
|
||||||
|
drawing_height - top_margin - static_cast<int>(graduations.size())*2 + 2));
|
||||||
|
|
||||||
|
// draw min value and max value
|
||||||
|
painter.setPen(Qt::blue);
|
||||||
|
QRect min_text_rect(left_margin + cell_width + 10,
|
||||||
|
drawing_height - top_margin, 100, text_height);
|
||||||
|
painter.drawText(min_text_rect, Qt::AlignCenter, QObject::tr("%1").arg(min_value, 0, 'f', 3));
|
||||||
|
|
||||||
|
QRect max_text_rect(left_margin + cell_width + 10,
|
||||||
|
drawing_height - top_margin - 200, 100, text_height);
|
||||||
|
painter.drawText(max_text_rect, Qt::AlignCenter, QObject::tr("%1").arg(max_value, 0, 'f', 3));
|
||||||
|
|
||||||
|
dock_widget->legendLabel->setPixmap(legend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
// Called when new geometric objects are selected in the scene
|
||||||
|
void onItemIndicesSelected(QList<int> selected_items)
|
||||||
|
{
|
||||||
|
resetExtremeValue();
|
||||||
|
dock_widget->setEnabled(false);
|
||||||
|
|
||||||
|
Scene_surface_mesh_item* sm_item = nullptr;
|
||||||
|
Scene_polyhedron_selection_item* source_vertices = nullptr;
|
||||||
|
|
||||||
|
if(selected_items.size() == 1)
|
||||||
|
{
|
||||||
|
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item);
|
||||||
|
if(source_vertices)
|
||||||
|
{
|
||||||
|
// While selecting a selection item, enable coloring if the selection item is linked to a sm_item
|
||||||
|
if(item_source_vertices.right.count(source_vertices) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dock_widget->setEnabled(true);
|
||||||
|
dock_widget->createSourceVerticesButton->setEnabled(false);
|
||||||
|
dock_widget->estimateDistancesButton->setEnabled(true);
|
||||||
|
disableExtremeValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(qobject_cast<Scene_heat_item*>(item))
|
||||||
|
{
|
||||||
|
dock_widget->setEnabled(true);
|
||||||
|
dock_widget->createSourceVerticesButton->setEnabled(false);
|
||||||
|
dock_widget->estimateDistancesButton->setEnabled(false);
|
||||||
|
disableExtremeValue();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
}
|
||||||
|
else if(selected_items.size() == 2)
|
||||||
|
{
|
||||||
|
Scene_item* item1 = scene->item(selected_items.front());
|
||||||
|
Scene_item* item2 = scene->item(selected_items.back());
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item2);
|
||||||
|
if(!sm_item)
|
||||||
|
{
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!sm_item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dock_widget->setEnabled(true);
|
||||||
|
const bool has_sources = (source_vertices || item_source_vertices.left.count(sm_item) != 0);
|
||||||
|
dock_widget->estimateDistancesButton->setEnabled(has_sources);
|
||||||
|
dock_widget->createSourceVerticesButton->setEnabled(!has_sources);
|
||||||
|
disableExtremeValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is only called if the index actually changed (doesn't trigger
|
||||||
|
// if you click again the item)
|
||||||
|
void onNewMethodSelected(int method_index)
|
||||||
|
{
|
||||||
|
resetExtremeValue(); // reset extreme value before the legend to get the proper values
|
||||||
|
displayRampLegend();
|
||||||
|
|
||||||
|
if(method_index >= 0 && method_index < dock_widget->methodBox->count()) // valid method
|
||||||
|
{
|
||||||
|
dock_widget->setEnabled(true);
|
||||||
|
disableExtremeValue(); // only available after displaying geodesic distances
|
||||||
|
}
|
||||||
|
else // no or broken method?
|
||||||
|
{
|
||||||
|
dock_widget->setEnabled(false);
|
||||||
|
dock_widget->methodBox->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool displayHeatIntensity(Scene_surface_mesh_item* sm_item,
|
||||||
|
Scene_polyhedron_selection_item* source_vertices,
|
||||||
|
const bool use_iDT = false)
|
||||||
|
{
|
||||||
|
SMesh& mesh = *sm_item->face_graph();
|
||||||
|
|
||||||
|
SMesh::Property_map<vertex_descriptor, double> heat_intensity =
|
||||||
|
mesh.add_property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity", 0).first;
|
||||||
|
|
||||||
|
auto initialize_hm_map = [this, sm_item, &mesh] (auto*& hm_ptr, auto& hm_map) -> void
|
||||||
|
{
|
||||||
|
using Method = std::decay_t<decltype(*hm_ptr)>;
|
||||||
|
|
||||||
|
auto it = hm_map.find(sm_item);
|
||||||
|
if(it != hm_map.end()) // method already exists
|
||||||
|
{
|
||||||
|
hm_ptr = it->second;
|
||||||
|
|
||||||
|
for(vertex_descriptor v : vertices(mesh))
|
||||||
|
hm_ptr->remove_source(v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hm_ptr = new Method(mesh);
|
||||||
|
hm_map[sm_item] = hm_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sm_item, &Scene_surface_mesh_item::aboutToBeDestroyed,
|
||||||
|
this, [this, sm_item, &hm_map]()
|
||||||
|
{
|
||||||
|
item_source_vertices.left.erase(sm_item);
|
||||||
|
|
||||||
|
auto it = hm_map.find(sm_item);
|
||||||
|
if(it == hm_map.end())
|
||||||
|
return;
|
||||||
|
delete it->second;
|
||||||
|
hm_map.erase(it);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Heat_method* hm = nullptr;
|
||||||
|
Heat_method_idt* hm_idt = nullptr;
|
||||||
|
|
||||||
|
if(use_iDT)
|
||||||
|
initialize_hm_map(hm_idt, idt_heat_methods);
|
||||||
|
else
|
||||||
|
initialize_hm_map(hm, heat_methods);
|
||||||
|
|
||||||
|
for(auto v : source_vertices->selected_vertices)
|
||||||
|
{
|
||||||
|
if(use_iDT)
|
||||||
|
hm_idt->add_source(v);
|
||||||
|
else
|
||||||
|
hm->add_source(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(use_iDT)
|
||||||
|
hm_idt->estimate_geodesic_distances(heat_intensity);
|
||||||
|
else
|
||||||
|
hm->estimate_geodesic_distances(heat_intensity);
|
||||||
|
|
||||||
|
// Post treatment
|
||||||
|
double max = 0;
|
||||||
|
for(vertex_descriptor v : vertices(mesh))
|
||||||
|
{
|
||||||
|
double hi = heat_intensity[v];
|
||||||
|
if(hi > max)
|
||||||
|
max = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayRampLegend();
|
||||||
|
|
||||||
|
auto [vcolors, vcolors_added] = mesh.add_property_map<vertex_descriptor, CGAL::IO::Color >("v:color", CGAL::IO::Color());
|
||||||
|
for(vertex_descriptor v : vertices(mesh))
|
||||||
|
{
|
||||||
|
double h = heat_intensity[v] / max;
|
||||||
|
CGAL::IO::Color color(255 * color_ramp.r(h),
|
||||||
|
255 * color_ramp.g(h),
|
||||||
|
255 * color_ramp.b(h));
|
||||||
|
vcolors[v] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the colored item
|
||||||
|
Scene_heat_item* heat_item = new Scene_heat_item(sm_item);
|
||||||
|
heat_item->setName(tr("%1 (distance isolines)").arg(sm_item->name()));
|
||||||
|
heat_item->setVisible(false);
|
||||||
|
|
||||||
|
sm_item->invalidateOpenGLBuffers();
|
||||||
|
sm_item->setRenderingMode(GouraudPlusEdges);
|
||||||
|
sm_item->redraw();
|
||||||
|
|
||||||
|
scene->addItem(heat_item);
|
||||||
|
scene->setSelectedItem(scene->item_id(sm_item));
|
||||||
|
|
||||||
|
// any change of sm_item destroys everything
|
||||||
|
connect(sm_item, &Scene_surface_mesh_item::itemChanged,
|
||||||
|
this, [this, sm_item, heat_item]()
|
||||||
|
{
|
||||||
|
sm_item->resetColors();
|
||||||
|
removePluginProperties(sm_item);
|
||||||
|
scene->erase(scene->item_id(heat_item));
|
||||||
|
onItemIndicesSelected(scene->selectionIndices());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(sm_item, &Scene_surface_mesh_item::aboutToBeDestroyed,
|
||||||
|
this, [this, heat_item]()
|
||||||
|
{
|
||||||
|
scene->erase(scene->item_id(heat_item));
|
||||||
|
onItemIndicesSelected(scene->selectionIndices());
|
||||||
|
});
|
||||||
|
|
||||||
|
// here because if it's put above, the setSelectedItem() might reset the value
|
||||||
|
dock_widget->maxBox->setValue(max);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void estimateDistances()
|
||||||
|
{
|
||||||
|
// Get the mesh and source vertices items
|
||||||
|
Scene_surface_mesh_item* sm_item = nullptr;
|
||||||
|
Scene_polyhedron_selection_item* source_vertices = nullptr;
|
||||||
|
|
||||||
|
if(scene->selectionIndices().size() == 1)
|
||||||
|
{
|
||||||
|
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
if(sm_item)
|
||||||
|
{
|
||||||
|
// a surface mesh item is selected, an existing associated selection item must exist
|
||||||
|
source_vertices = item_source_vertices.left.at(sm_item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// a selection item is selected, an existing associated mesh item must exist
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item);
|
||||||
|
if(source_vertices)
|
||||||
|
sm_item = item_source_vertices.right.at(source_vertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(scene->selectionIndices().size() == 2)
|
||||||
|
{
|
||||||
|
// two items, for (possibly unlinked) sm_item and its associated selection
|
||||||
|
Scene_item* item1 = scene->item(scene->selectionIndices().front());
|
||||||
|
Scene_item* item2 = scene->item(scene->selectionIndices().back());
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item2);
|
||||||
|
if(!sm_item)
|
||||||
|
{
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
|
||||||
|
source_vertices = qobject_cast<Scene_polyhedron_selection_item*>(item1);
|
||||||
|
}
|
||||||
|
|
||||||
|
link_mesh_and_selection(sm_item, source_vertices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::critical(mw, "Error","Unsupported selection of items.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGAL_assertion(sm_item && source_vertices);
|
||||||
|
|
||||||
|
if(!is_triangle_mesh(*sm_item->face_graph()))
|
||||||
|
{
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
QMessageBox::critical(mw, "Error","The mesh must be triangulated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source_vertices->selected_vertices.empty())
|
||||||
|
{
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
QMessageBox::critical(mw, "Error","At least one source vertex is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
|
enableExtremeValue();
|
||||||
|
|
||||||
|
const std::string& method_name = dock_widget->methodBox->currentText().toStdString();
|
||||||
|
if(method_name == "Heat Method")
|
||||||
|
displayHeatIntensity(sm_item, source_vertices);
|
||||||
|
else if(method_name == "Heat Method (Intrinsic Delaunay)")
|
||||||
|
displayHeatIntensity(sm_item, source_vertices, true /*use IDT*/);
|
||||||
|
|
||||||
|
// @todo emit a new SIGNAL on successful coloring, something like "colorChanged()"
|
||||||
|
// itemChanged is too strong and would conflict with the connection below
|
||||||
|
sm_item->invalidateOpenGLBuffers();
|
||||||
|
sm_item->redraw();
|
||||||
|
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void removePluginProperty(Scene_item* item,
|
||||||
|
const std::string& property_name)
|
||||||
|
{
|
||||||
|
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
if(!sm_item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SMesh* sm = sm_item->face_graph();
|
||||||
|
if(sm == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Here we only target the property maps added by this plugin, so 'double' is fine
|
||||||
|
SMesh::Property_map<face_descriptor, double> property;
|
||||||
|
bool found;
|
||||||
|
std::tie(property, found) = sm->property_map<face_descriptor, double>(property_name);
|
||||||
|
if(found)
|
||||||
|
sm->remove_property_map(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removePluginProperties(Scene_item* item)
|
||||||
|
{
|
||||||
|
removePluginProperty(item, "v:HM_Plugin_heat_intensity");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
// deletion of the selection item removes the pair from the map
|
||||||
|
void link_mesh_and_selection(Scene_surface_mesh_item* sm_item,
|
||||||
|
Scene_polyhedron_selection_item* source_vertices)
|
||||||
|
{
|
||||||
|
item_source_vertices.left.insert(std::make_pair(sm_item, source_vertices));
|
||||||
|
|
||||||
|
connect(source_vertices, &Scene_polyhedron_selection_item::aboutToBeDestroyed,
|
||||||
|
this, [this, sm_item]()
|
||||||
|
{
|
||||||
|
item_source_vertices.left.erase(sm_item);
|
||||||
|
onItemIndicesSelected(scene->selectionIndices());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSourceVerticesSelectionItem()
|
||||||
|
{
|
||||||
|
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||||
|
Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
if(!sm_item)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(mw, "Warning", "Select a surface mesh to add source vertices");
|
||||||
|
dock_widget->createSourceVerticesButton->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGAL_assertion(item_source_vertices.left.count(sm_item) == 0);
|
||||||
|
|
||||||
|
Scene_polyhedron_selection_item* source_vertices = new Scene_polyhedron_selection_item(sm_item, mw);
|
||||||
|
source_vertices->setName(tr("%1 (source vertices)").arg(sm_item->name()));
|
||||||
|
scene->addItem(source_vertices);
|
||||||
|
|
||||||
|
link_mesh_and_selection(sm_item, source_vertices);
|
||||||
|
|
||||||
|
dock_widget->createSourceVerticesButton->setEnabled(false);
|
||||||
|
dock_widget->estimateDistancesButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void on_zoomToMaxButton_pressed()
|
||||||
|
{
|
||||||
|
Scene_surface_mesh_item* sm_item = nullptr;
|
||||||
|
if(scene->selectionIndices().size() == 1)
|
||||||
|
{
|
||||||
|
Scene_item* item = scene->item(scene->mainSelectionIndex());
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
|
||||||
|
}
|
||||||
|
else if(scene->selectionIndices().size() == 2)
|
||||||
|
{
|
||||||
|
Scene_item* item1 = scene->item(scene->selectionIndices().front());
|
||||||
|
Scene_item* item2 = scene->item(scene->selectionIndices().back());
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item1);
|
||||||
|
if(!sm_item)
|
||||||
|
sm_item = qobject_cast<Scene_surface_mesh_item*>(item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SMesh& mesh = *(sm_item->face_graph());
|
||||||
|
|
||||||
|
auto [heat_intensity, found] = mesh.property_map<vertex_descriptor, double>("v:HM_Plugin_heat_intensity");
|
||||||
|
CGAL_assertion(found);
|
||||||
|
|
||||||
|
double max = 0;
|
||||||
|
vertex_descriptor max_v = boost::graph_traits<SMesh>::null_vertex();
|
||||||
|
for(vertex_descriptor v : vertices(mesh))
|
||||||
|
{
|
||||||
|
if(heat_intensity[v] > max)
|
||||||
|
{
|
||||||
|
max = heat_intensity[v];
|
||||||
|
max_v = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGAL_assertion(max_v != boost::graph_traits<SMesh>::null_vertex());
|
||||||
|
|
||||||
|
face_descriptor unused_fd;
|
||||||
|
Point_3 unused_p;
|
||||||
|
::zoomToId(mesh,
|
||||||
|
QString("v%1").arg(max_v),
|
||||||
|
getActiveViewer(),
|
||||||
|
unused_fd, unused_p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "Heat_method_plugin.moc"
|
||||||
|
|
@ -217,7 +217,7 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionColorConnectedCom
|
||||||
item->computeItemColorVectorAutomatically(true);
|
item->computeItemColorVectorAutomatically(true);
|
||||||
item->invalidateOpenGLBuffers();
|
item->invalidateOpenGLBuffers();
|
||||||
item->setProperty("NbPatchIds", nb_patch_ids);
|
item->setProperty("NbPatchIds", nb_patch_ids);
|
||||||
scene->itemChanged(item);
|
scene->itemChanged(item); // @todo emits
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,20 @@
|
||||||
#include <CGAL/boost/graph/properties.h>
|
#include <CGAL/boost/graph/properties.h>
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
|
||||||
typedef EPICK::Point_3 Point_3;
|
typedef EPICK::Point_3 Point_3;
|
||||||
|
|
||||||
typedef CGAL::Surface_mesh<Point_3> SMesh;
|
typedef CGAL::Surface_mesh<Point_3> SMesh;
|
||||||
|
|
||||||
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
|
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
|
||||||
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
|
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
|
||||||
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
struct property_map<CGAL::Surface_mesh<P>, CGAL::vertex_selection_t>
|
struct property_map<CGAL::Surface_mesh<P>, CGAL::vertex_selection_t>
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::vertex_descriptor vertex_descriptor;
|
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::vertex_descriptor vertex_descriptor;
|
||||||
|
|
||||||
typedef typename CGAL::Surface_mesh<P>::template Property_map<vertex_descriptor, int> type;
|
typedef typename CGAL::Surface_mesh<P>::template Property_map<vertex_descriptor, int> type;
|
||||||
|
|
@ -32,7 +31,6 @@ struct property_map<CGAL::Surface_mesh<P>, CGAL::vertex_selection_t>
|
||||||
template <typename P>
|
template <typename P>
|
||||||
struct property_map<CGAL::Surface_mesh<P>, CGAL::face_selection_t>
|
struct property_map<CGAL::Surface_mesh<P>, CGAL::face_selection_t>
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::face_descriptor face_descriptor;
|
typedef typename boost::graph_traits<CGAL::Surface_mesh<P> >::face_descriptor face_descriptor;
|
||||||
|
|
||||||
typedef typename CGAL::Surface_mesh<P>::template Property_map<face_descriptor, int> type;
|
typedef typename CGAL::Surface_mesh<P>::template Property_map<face_descriptor, int> type;
|
||||||
|
|
@ -41,11 +39,11 @@ struct property_map<CGAL::Surface_mesh<P>, CGAL::face_selection_t>
|
||||||
|
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
template <typename P, typename Property_tag>
|
template <typename P, typename Property_tag>
|
||||||
struct Get_pmap_of_surface_mesh_ {
|
struct Get_pmap_of_surface_mesh_
|
||||||
|
{
|
||||||
typedef typename boost::property_map<Surface_mesh<P>, Property_tag >::type type;
|
typedef typename boost::property_map<Surface_mesh<P>, Property_tag >::type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,20 +172,22 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi
|
||||||
Scene::Item_id
|
Scene::Item_id
|
||||||
Scene::erase(Scene::Item_id index)
|
Scene::erase(Scene::Item_id index)
|
||||||
{
|
{
|
||||||
if(index <0 || index >= numberOfEntries())
|
if(index < 0 || index >= numberOfEntries())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
CGAL::Three::Scene_item* item = m_entries[index];
|
CGAL::Three::Scene_item* item = m_entries[index];
|
||||||
|
|
||||||
if(qobject_cast<Scene_group_item*>(item))
|
if(qobject_cast<Scene_group_item*>(item))
|
||||||
{
|
{
|
||||||
setSelectedItemsList(QList<Scene_interface::Item_id>()<<item_id(item));
|
setSelectedItemIndices(QList<Scene_interface::Item_id>() << item_id(item));
|
||||||
return erase(selectionIndices());
|
return erase(selectionIndices());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_groups.removeAll(index);
|
m_groups.removeAll(index);
|
||||||
if(item->parentGroup()
|
if(item->parentGroup() && item->parentGroup()->isChildLocked(item))
|
||||||
&& item->parentGroup()->isChildLocked(item))
|
|
||||||
return -1;
|
return -1;
|
||||||
//clears the Scene_view
|
|
||||||
|
// clears the Scene_view
|
||||||
clear();
|
clear();
|
||||||
index_map.clear();
|
index_map.clear();
|
||||||
if(item->parentGroup())
|
if(item->parentGroup())
|
||||||
|
|
@ -340,7 +342,8 @@ Scene::duplicate(Item_id index)
|
||||||
|
|
||||||
const CGAL::Three::Scene_item* item = m_entries[index];
|
const CGAL::Three::Scene_item* item = m_entries[index];
|
||||||
CGAL::Three::Scene_item* new_item = item->clone();
|
CGAL::Three::Scene_item* new_item = item->clone();
|
||||||
if(new_item) {
|
if(new_item)
|
||||||
|
{
|
||||||
new_item->setName(tr("%1 (copy)").arg(item->name()));
|
new_item->setName(tr("%1 (copy)").arg(item->name()));
|
||||||
new_item->setColor(item->color());
|
new_item->setColor(item->color());
|
||||||
new_item->setVisible(item->visible());
|
new_item->setVisible(item->visible());
|
||||||
|
|
@ -348,7 +351,9 @@ Scene::duplicate(Item_id index)
|
||||||
return m_entries.size() - 1;
|
return m_entries.size() - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
|
void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
|
||||||
|
|
@ -493,12 +498,12 @@ void Scene::s_itemAboutToBeDestroyed(CGAL::Three::Scene_item *rmv_itm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
Scene::keyPressEvent(QKeyEvent* e){
|
Scene::keyPressEvent(QKeyEvent* e)
|
||||||
bool res=false;
|
{
|
||||||
for (QList<int>::iterator it=selected_items_list.begin(),endit=selected_items_list.end();
|
bool res = false;
|
||||||
it!=endit;++it)
|
Q_FOREACH(int i, selected_items_list)
|
||||||
{
|
{
|
||||||
CGAL::Three::Scene_item* item=m_entries[*it];
|
CGAL::Three::Scene_item* item = m_entries[i];
|
||||||
res |= item->keyPressEvent(e);
|
res |= item->keyPressEvent(e);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -615,12 +620,10 @@ void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
|
||||||
viewer->setGlPointSize(2.f);
|
viewer->setGlPointSize(2.f);
|
||||||
if(index == selected_item || selected_items_list.contains(index))
|
if(index == selected_item || selected_items_list.contains(index))
|
||||||
{
|
{
|
||||||
|
|
||||||
item.selection_changed(true);
|
item.selection_changed(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
item.selection_changed(false);
|
item.selection_changed(false);
|
||||||
}
|
}
|
||||||
item.drawEdges(viewer);
|
item.drawEdges(viewer);
|
||||||
|
|
@ -1122,6 +1125,7 @@ bool Scene::dropMimeData(const QMimeData * /*data*/,
|
||||||
if(group)
|
if(group)
|
||||||
{
|
{
|
||||||
Q_FOREACH(int id, selected_items_list)
|
Q_FOREACH(int id, selected_items_list)
|
||||||
|
{
|
||||||
if(group->getChildren().contains(id))
|
if(group->getChildren().contains(id))
|
||||||
{
|
{
|
||||||
one_contained = true;
|
one_contained = true;
|
||||||
|
|
@ -1129,6 +1133,7 @@ bool Scene::dropMimeData(const QMimeData * /*data*/,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//if the drop item is not a group_item or if it already contains the item, then the drop action must be ignored
|
//if the drop item is not a group_item or if it already contains the item, then the drop action must be ignored
|
||||||
if(!group ||one_contained)
|
if(!group ||one_contained)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -195,8 +195,10 @@ public Q_SLOTS:
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the target list of indices as the selected indices.
|
//! Sets the target list of indices as the selected indices.
|
||||||
QList<int> setSelectedItemsList(QList<int> l )
|
const QList<int>& setSelectedItemIndices(QList<int> l,
|
||||||
|
const bool do_emit = true)
|
||||||
{
|
{
|
||||||
Q_FOREACH(int i,l)
|
Q_FOREACH(int i,l)
|
||||||
{
|
{
|
||||||
|
|
@ -206,13 +208,38 @@ public Q_SLOTS:
|
||||||
{
|
{
|
||||||
QList<int> list;
|
QList<int> list;
|
||||||
Q_FOREACH(Item_id id, group->getChildrenForSelection())
|
Q_FOREACH(Item_id id, group->getChildrenForSelection())
|
||||||
list<<id;
|
list << id;
|
||||||
l << setSelectedItemsList(list);
|
l << setSelectedItemIndices(list, false /*do not emit*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
selected_items_list = l;
|
selected_items_list = l;
|
||||||
return l;
|
if(do_emit)
|
||||||
|
Q_EMIT itemIndicesSelected(selected_items_list);
|
||||||
|
return selected_items_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Sets the target list of indices as the selected indices.
|
||||||
|
const QList<int>& setSelectedItemList(QList<int> l,
|
||||||
|
const bool do_emit = true)
|
||||||
|
{
|
||||||
|
Q_FOREACH(int i,l)
|
||||||
|
{
|
||||||
|
CGAL::Three::Scene_group_item* group =
|
||||||
|
qobject_cast<CGAL::Three::Scene_group_item*>(item(i));
|
||||||
|
if(group)
|
||||||
|
{
|
||||||
|
QList<int> list;
|
||||||
|
Q_FOREACH(Item_id id, group->getChildrenForSelection())
|
||||||
|
list << id;
|
||||||
|
l << setSelectedItemList(list, false /*do not emit*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selected_items_list = l;
|
||||||
|
if(do_emit)
|
||||||
|
Q_EMIT selectionChanged(selected_items_list);
|
||||||
|
return selected_items_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors (setters)
|
// Accessors (setters)
|
||||||
|
|
@ -249,6 +276,8 @@ Q_SIGNALS:
|
||||||
void selectionChanged(QList<int> is);
|
void selectionChanged(QList<int> is);
|
||||||
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
|
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
|
||||||
void itemIndexSelected(int i);
|
void itemIndexSelected(int i);
|
||||||
|
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
|
||||||
|
void itemIndicesSelected(QList<int> is);
|
||||||
//! Emit this to reset the collapsed state of all groups after the Geometric Objects view has been redrawn.
|
//! Emit this to reset the collapsed state of all groups after the Geometric Objects view has been redrawn.
|
||||||
void restoreCollapsedState();
|
void restoreCollapsedState();
|
||||||
//! Is emitted when draw() is finished.
|
//! Is emitted when draw() is finished.
|
||||||
|
|
|
||||||
|
|
@ -2005,7 +2005,7 @@ void Scene_surface_mesh_item::resetColors()
|
||||||
d->has_feature_edges = false;
|
d->has_feature_edges = false;
|
||||||
}
|
}
|
||||||
invalidate(COLORS);
|
invalidate(COLORS);
|
||||||
itemChanged();
|
itemChanged(); // @fixme really shouldn't call something that strong
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu* Scene_surface_mesh_item::contextMenu()
|
QMenu* Scene_surface_mesh_item::contextMenu()
|
||||||
|
|
@ -2387,7 +2387,6 @@ void Scene_surface_mesh_item::computeElements() const
|
||||||
{
|
{
|
||||||
d->compute_elements(ALL);
|
d->compute_elements(ALL);
|
||||||
setBuffersFilled(true);
|
setBuffersFilled(true);
|
||||||
const_cast<Scene_surface_mesh_item*>(this)->itemChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,96 @@
|
||||||
#ifndef ID_PRINTING_H
|
#ifndef CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
|
||||||
#define ID_PRINTING_H
|
#define CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
|
||||||
|
|
||||||
#include <CGAL/boost/graph/selection.h>
|
#include <CGAL/boost/graph/selection.h>
|
||||||
|
#include <CGAL/Kernel_traits.h>
|
||||||
|
#include <CGAL/Kernel/global_functions.h>
|
||||||
|
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||||
|
|
||||||
#include <CGAL/Three/Viewer_interface.h>
|
#include <CGAL/Three/Viewer_interface.h>
|
||||||
#include <CGAL/Three/TextRenderer.h>
|
#include <CGAL/Three/TextRenderer.h>
|
||||||
#include <CGAL/Three/Three.h>
|
#include <CGAL/Three/Three.h>
|
||||||
#include <CGAL/Kernel_traits.h>
|
|
||||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define POINT_SIZE 11
|
#define POINT_SIZE 11
|
||||||
|
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
struct VKRingPMAP{
|
struct VKRingPMAP
|
||||||
typedef typename boost::graph_traits<Mesh>::vertex_descriptor key_type;
|
{
|
||||||
typedef bool value_type;
|
using key_type = typename boost::graph_traits<Mesh>::vertex_descriptor;
|
||||||
typedef value_type reference;
|
using value_type = bool;
|
||||||
typedef boost::read_write_property_map_tag category;
|
using reference = value_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
|
using category = boost::read_write_property_map_tag;
|
||||||
|
|
||||||
|
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
|
||||||
|
|
||||||
std::vector<bool>* vec;
|
std::vector<bool>* vec;
|
||||||
Mesh* poly;
|
Mesh* poly;
|
||||||
IDmap idmap;
|
IDmap idmap;
|
||||||
|
|
||||||
VKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
VKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
||||||
:vec(vec), poly(poly)
|
: vec(vec), poly(poly)
|
||||||
{
|
{
|
||||||
idmap = get(boost::vertex_index, *poly);
|
idmap = get(boost::vertex_index, *poly);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend value_type get(const VKRingPMAP<Mesh>& map, const key_type& v){
|
friend value_type get(const VKRingPMAP<Mesh>& map, const key_type& v)
|
||||||
|
{
|
||||||
return (*map.vec)[get(map.idmap, v)];
|
return (*map.vec)[get(map.idmap, v)];
|
||||||
}
|
}
|
||||||
friend void put(VKRingPMAP<Mesh>& map, const key_type& v, const value_type i){
|
|
||||||
|
friend void put(VKRingPMAP<Mesh>& map, const key_type& v, const value_type i)
|
||||||
|
{
|
||||||
(*map.vec)[get(map.idmap, v)] = i;
|
(*map.vec)[get(map.idmap, v)] = i;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
struct EdgeKRingPMAP{
|
struct EdgeKRingPMAP
|
||||||
typedef typename boost::graph_traits<Mesh>::edge_descriptor key_type;
|
{
|
||||||
typedef bool value_type;
|
using key_type = typename boost::graph_traits<Mesh>::edge_descriptor;
|
||||||
typedef value_type reference;
|
using value_type = bool;
|
||||||
typedef boost::read_write_property_map_tag category;
|
using reference = value_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
|
using category = boost::read_write_property_map_tag;
|
||||||
|
|
||||||
|
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
|
||||||
|
|
||||||
std::vector<bool>* vec;
|
std::vector<bool>* vec;
|
||||||
Mesh* poly;
|
Mesh* poly;
|
||||||
IDmap idmap;
|
IDmap idmap;
|
||||||
|
|
||||||
EdgeKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
EdgeKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
||||||
:vec(vec), poly(poly)
|
: vec(vec), poly(poly)
|
||||||
{
|
{
|
||||||
idmap = get(boost::halfedge_index, *poly);
|
idmap = get(boost::halfedge_index, *poly);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend value_type get(const EdgeKRingPMAP<Mesh>& map, const key_type& e){
|
friend value_type get(const EdgeKRingPMAP<Mesh>& map, const key_type& e)
|
||||||
|
{
|
||||||
return (*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2];
|
return (*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2];
|
||||||
}
|
}
|
||||||
friend void put(EdgeKRingPMAP<Mesh>& map, const key_type& e, const value_type i){
|
|
||||||
|
friend void put(EdgeKRingPMAP<Mesh>& map, const key_type& e, const value_type i)
|
||||||
|
{
|
||||||
(*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2] = i;
|
(*map.vec)[get(map.idmap, halfedge(e, *map.poly))/2] = i;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
struct FKRingPMAP{
|
struct FKRingPMAP
|
||||||
typedef typename boost::graph_traits<Mesh>::face_descriptor key_type;
|
{
|
||||||
typedef bool value_type;
|
using key_type = typename boost::graph_traits<Mesh>::face_descriptor;
|
||||||
typedef value_type reference;
|
using value_type = bool;
|
||||||
typedef boost::read_write_property_map_tag category;
|
using reference = value_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
|
using category = boost::read_write_property_map_tag;
|
||||||
|
|
||||||
|
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
|
||||||
|
|
||||||
std::vector<bool>* vec;
|
std::vector<bool>* vec;
|
||||||
Mesh* poly;
|
Mesh* poly;
|
||||||
IDmap idmap;
|
IDmap idmap;
|
||||||
|
|
||||||
FKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
FKRingPMAP(std::vector<bool>* vec, Mesh* poly)
|
||||||
:vec(vec), poly(poly)
|
: vec(vec), poly(poly)
|
||||||
{
|
{
|
||||||
idmap = get(boost::face_index, *poly);
|
idmap = get(boost::face_index, *poly);
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +98,9 @@ struct FKRingPMAP{
|
||||||
friend value_type get(const FKRingPMAP<Mesh>& map, const key_type& f){
|
friend value_type get(const FKRingPMAP<Mesh>& map, const key_type& f){
|
||||||
return (*map.vec)[get(map.idmap, f)];
|
return (*map.vec)[get(map.idmap, f)];
|
||||||
}
|
}
|
||||||
friend void put(FKRingPMAP<Mesh>& map, const key_type& f, const value_type i){
|
|
||||||
|
friend void put(FKRingPMAP<Mesh>& map, const key_type& f, const value_type i)
|
||||||
|
{
|
||||||
(*map.vec)[get(map.idmap, f)] = i;
|
(*map.vec)[get(map.idmap, f)] = i;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -91,26 +110,28 @@ void deleteIds(CGAL::Three::Viewer_interface* viewer,
|
||||||
TextListItem* fitems,
|
TextListItem* fitems,
|
||||||
std::vector<TextItem*>* targeted_ids)
|
std::vector<TextItem*>* targeted_ids)
|
||||||
{
|
{
|
||||||
TextRenderer *renderer = viewer->textRenderer();
|
TextRenderer* renderer = viewer->textRenderer();
|
||||||
|
|
||||||
for(TextItem* it : vitems->textList())
|
for(TextItem* it : vitems->textList())
|
||||||
delete it;
|
delete it;
|
||||||
for(TextItem* it : eitems->textList())
|
for(TextItem* it : eitems->textList())
|
||||||
delete it;
|
delete it;
|
||||||
for(TextItem* it : fitems->textList())
|
for(TextItem* it : fitems->textList())
|
||||||
delete it;
|
delete it;
|
||||||
|
|
||||||
vitems->clear();
|
vitems->clear();
|
||||||
renderer->removeTextList(vitems);
|
renderer->removeTextList(vitems);
|
||||||
|
|
||||||
eitems->clear();
|
eitems->clear();
|
||||||
renderer->removeTextList(eitems);
|
renderer->removeTextList(eitems);
|
||||||
|
|
||||||
fitems->clear();
|
fitems->clear();
|
||||||
renderer->removeTextList(fitems);
|
renderer->removeTextList(fitems);
|
||||||
|
|
||||||
targeted_ids->clear();
|
targeted_ids->clear();
|
||||||
viewer->update();
|
viewer->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Handle, typename Point, typename Tree>
|
template<typename Handle, typename Point, typename Tree>
|
||||||
bool find_primitive_id(const QPoint& point,
|
bool find_primitive_id(const QPoint& point,
|
||||||
Tree* aabb_tree,
|
Tree* aabb_tree,
|
||||||
|
|
@ -118,12 +139,13 @@ bool find_primitive_id(const QPoint& point,
|
||||||
Handle& selected_fh,
|
Handle& selected_fh,
|
||||||
Point& pt_under)
|
Point& pt_under)
|
||||||
{
|
{
|
||||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Traits;
|
using Traits = typename CGAL::Kernel_traits<Point>::Kernel;
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
CGAL::qglviewer::Vec point_under = viewer->camera()->pointUnderPixel(point,found);
|
CGAL::qglviewer::Vec point_under = viewer->camera()->pointUnderPixel(point,found);
|
||||||
const CGAL::qglviewer::Vec offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
const CGAL::qglviewer::Vec offset = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
||||||
|
|
||||||
//find clicked facet
|
// find clicked facet
|
||||||
CGAL::qglviewer::Vec dir;
|
CGAL::qglviewer::Vec dir;
|
||||||
Point ray_origin;
|
Point ray_origin;
|
||||||
if(viewer->camera()->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
|
if(viewer->camera()->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
|
||||||
|
|
@ -151,38 +173,39 @@ bool find_primitive_id(const QPoint& point,
|
||||||
|
|
||||||
if(intersections.empty())
|
if(intersections.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
typename Intersections::iterator closest = intersections.begin();
|
typename Intersections::iterator closest = intersections.begin();
|
||||||
const Point* closest_point =
|
const Point* closest_point = boost::get<Point>(&closest->first);
|
||||||
boost::get<Point>(&closest->first);
|
for(typename Intersections::iterator it = boost::next(intersections.begin()),
|
||||||
for(typename Intersections::iterator
|
end = intersections.end(); it != end; ++it)
|
||||||
it = boost::next(intersections.begin()),
|
{
|
||||||
end = intersections.end();
|
if(! closest_point)
|
||||||
it != end; ++it)
|
|
||||||
{
|
{
|
||||||
if(! closest_point) {
|
|
||||||
closest = it;
|
closest = it;
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
const Point* it_point =
|
{
|
||||||
boost::get<Point>(&it->first);
|
const Point* it_point = boost::get<Point>(&it->first);
|
||||||
if(it_point &&
|
if(it_point && (ray_dir * (*it_point - *closest_point)) < 0)
|
||||||
(ray_dir * (*it_point - *closest_point)) < 0)
|
|
||||||
{
|
{
|
||||||
closest = it;
|
closest = it;
|
||||||
closest_point = it_point;
|
closest_point = it_point;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!closest_point)
|
if(!closest_point)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pt_under = Point(point_under.x, point_under.y, point_under.z);
|
pt_under = Point(point_under.x, point_under.y, point_under.z);
|
||||||
selected_fh = closest->second;
|
selected_fh = closest->second;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Mesh, typename Point >
|
template<typename Mesh, typename Point>
|
||||||
void compute_displayed_ids(Mesh& mesh,
|
void compute_displayed_ids(Mesh& mesh,
|
||||||
CGAL::Three::Viewer_interface *viewer,
|
CGAL::Three::Viewer_interface* viewer,
|
||||||
const typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
|
const typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
|
||||||
const Point& pt_under,
|
const Point& pt_under,
|
||||||
const CGAL::qglviewer::Vec& offset,
|
const CGAL::qglviewer::Vec& offset,
|
||||||
|
|
@ -191,21 +214,21 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
TextListItem* fitems,
|
TextListItem* fitems,
|
||||||
std::vector<TextItem*>* targeted_ids)
|
std::vector<TextItem*>* targeted_ids)
|
||||||
{
|
{
|
||||||
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
using vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
|
||||||
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
|
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
|
||||||
typedef typename boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
|
using edge_descriptor = typename boost::graph_traits<Mesh>::edge_descriptor;
|
||||||
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
|
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
|
||||||
|
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::type Ppmap;
|
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::type;
|
||||||
Ppmap ppmap = get(boost::vertex_point, mesh);
|
Ppmap ppmap = get(boost::vertex_point, mesh);
|
||||||
|
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type VIDmap;
|
using VIDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
|
||||||
VIDmap vidmap = get(boost::vertex_index, mesh);
|
VIDmap vidmap = get(boost::vertex_index, mesh);
|
||||||
|
|
||||||
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type HIDmap;
|
using HIDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
|
||||||
HIDmap hidmap = get(boost::halfedge_index, mesh);
|
HIDmap hidmap = get(boost::halfedge_index, mesh);
|
||||||
|
|
||||||
typedef typename boost::property_map<Mesh, boost::face_index_t>::type FIDmap;
|
using FIDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
|
||||||
FIDmap fidmap = get(boost::face_index, mesh);
|
FIDmap fidmap = get(boost::face_index, mesh);
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
|
|
@ -214,70 +237,77 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
std::vector<vertex_descriptor> displayed_vertices;
|
std::vector<vertex_descriptor> displayed_vertices;
|
||||||
std::vector<edge_descriptor> displayed_edges;
|
std::vector<edge_descriptor> displayed_edges;
|
||||||
std::vector<face_descriptor> displayed_faces;
|
std::vector<face_descriptor> displayed_faces;
|
||||||
//Test spots around facet to find the closest to point
|
// Test spots around facet to find the closest to point
|
||||||
|
|
||||||
double min_dist = (std::numeric_limits<double>::max)();
|
double min_dist = (std::numeric_limits<double>::max)();
|
||||||
|
|
||||||
// test the vertices of the closest face
|
// test the vertices of the closest face
|
||||||
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
|
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
|
||||||
{
|
{
|
||||||
Point test=Point(get(ppmap, vh).x()+offset.x,
|
Point test=Point(get(ppmap, vh).x() + offset.x,
|
||||||
get(ppmap, vh).y()+offset.y,
|
get(ppmap, vh).y() + offset.y,
|
||||||
get(ppmap, vh).z()+offset.z);
|
get(ppmap, vh).z() + offset.z);
|
||||||
double dist = CGAL::squared_distance(test, pt_under);
|
double dist = CGAL::squared_distance(test, pt_under);
|
||||||
if( dist < min_dist){
|
if(dist < min_dist)
|
||||||
|
{
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
displayed_vertices.clear();
|
displayed_vertices.clear();
|
||||||
displayed_vertices.push_back(vh);
|
displayed_vertices.push_back(vh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QVector3D point(
|
|
||||||
float(get(ppmap, displayed_vertices[0]).x() + offset.x),
|
QVector3D point(float(get(ppmap, displayed_vertices[0]).x() + offset.x),
|
||||||
float(get(ppmap, displayed_vertices[0]).y() + offset.y),
|
float(get(ppmap, displayed_vertices[0]).y() + offset.y),
|
||||||
float(get(ppmap, displayed_vertices[0]).z() + offset.z));
|
float(get(ppmap, displayed_vertices[0]).z() + offset.z));
|
||||||
|
|
||||||
//test if we want to erase or not
|
// test if we want to erase or not
|
||||||
for(TextItem* text_item : *targeted_ids)
|
for(TextItem* text_item : *targeted_ids)
|
||||||
{
|
{
|
||||||
if(text_item->position() == point)
|
if(text_item->position() == point)
|
||||||
{
|
{
|
||||||
//hide and stop
|
// hide and stop
|
||||||
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
|
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
|
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
|
||||||
|
|
||||||
// test the midpoint of edges of the closest face
|
// test the midpoint of edges of the closest face
|
||||||
for(halfedge_descriptor e : halfedges_around_face(halfedge(selected_fh, mesh), mesh))
|
for(halfedge_descriptor e : halfedges_around_face(halfedge(selected_fh, mesh), mesh))
|
||||||
{
|
{
|
||||||
Point test=CGAL::midpoint(get(ppmap, source(e, mesh)),get(ppmap, target(e, mesh)));
|
Point test = CGAL::midpoint(get(ppmap, source(e, mesh)),get(ppmap, target(e, mesh)));
|
||||||
test = Point(test.x()+offset.x,
|
test = Point(test.x()+offset.x,
|
||||||
test.y()+offset.y,
|
test.y()+offset.y,
|
||||||
test.z()+offset.z);
|
test.z()+offset.z);
|
||||||
double dist = CGAL::squared_distance(test, pt_under);
|
double dist = CGAL::squared_distance(test, pt_under);
|
||||||
if(dist < min_dist){
|
if(dist < min_dist)
|
||||||
|
{
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
displayed_vertices.clear();
|
displayed_vertices.clear();
|
||||||
displayed_edges.clear();
|
displayed_edges.clear();
|
||||||
displayed_edges.push_back(edge(e, mesh));
|
displayed_edges.push_back(edge(e, mesh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test the centroid of the closest face
|
// test the centroid of the closest face
|
||||||
double x(0), y(0), z(0);
|
double x(0), y(0), z(0);
|
||||||
int total(0);
|
int total(0);
|
||||||
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
|
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
|
||||||
{
|
{
|
||||||
x+=get(ppmap, vh).x();
|
x += get(ppmap, vh).x();
|
||||||
y+=get(ppmap, vh).y();
|
y += get(ppmap, vh).y();
|
||||||
z+=get(ppmap, vh).z();
|
z += get(ppmap, vh).z();
|
||||||
++total;
|
++total;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point test(x/total+offset.x,
|
Point test(x / total+offset.x,
|
||||||
y/total+offset.y,
|
y / total+offset.y,
|
||||||
z/total+offset.z);
|
z / total+offset.z);
|
||||||
|
|
||||||
double dist = CGAL::squared_distance(test, pt_under);
|
double dist = CGAL::squared_distance(test, pt_under);
|
||||||
if(dist < min_dist){
|
if(dist < min_dist)
|
||||||
|
{
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
displayed_vertices.clear();
|
displayed_vertices.clear();
|
||||||
displayed_edges.clear();
|
displayed_edges.clear();
|
||||||
|
|
@ -293,11 +323,10 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
if(f != boost::graph_traits<Mesh>::null_face())
|
if(f != boost::graph_traits<Mesh>::null_face())
|
||||||
displayed_faces.push_back(f);
|
displayed_faces.push_back(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(halfedge_descriptor h : CGAL::halfedges_around_target(halfedge(displayed_vertices[0], mesh), mesh))
|
for(halfedge_descriptor h : CGAL::halfedges_around_target(halfedge(displayed_vertices[0], mesh), mesh))
|
||||||
{
|
|
||||||
displayed_edges.push_back(edge(h, mesh));
|
displayed_edges.push_back(edge(h, mesh));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if(!displayed_edges.empty())
|
else if(!displayed_edges.empty())
|
||||||
{
|
{
|
||||||
displayed_vertices.push_back(target(halfedge(displayed_edges[0], mesh), mesh));
|
displayed_vertices.push_back(target(halfedge(displayed_edges[0], mesh), mesh));
|
||||||
|
|
@ -309,7 +338,6 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
if(f2 != boost::graph_traits<Mesh>::null_face())
|
if(f2 != boost::graph_traits<Mesh>::null_face())
|
||||||
displayed_faces.push_back(f2);
|
displayed_faces.push_back(f2);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(!displayed_faces.empty())
|
else if(!displayed_faces.empty())
|
||||||
{
|
{
|
||||||
for(halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(displayed_faces[0], mesh), mesh))
|
for(halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(displayed_faces[0], mesh), mesh))
|
||||||
|
|
@ -318,7 +346,8 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
displayed_vertices.push_back(target(h, mesh));
|
displayed_vertices.push_back(target(h, mesh));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fill TextItems
|
|
||||||
|
// fill TextItems
|
||||||
std::vector<bool> vertex_selection(false);
|
std::vector<bool> vertex_selection(false);
|
||||||
vertex_selection.resize(num_vertices(mesh));
|
vertex_selection.resize(num_vertices(mesh));
|
||||||
VKRingPMAP<Mesh> vpmap(&vertex_selection, &mesh);
|
VKRingPMAP<Mesh> vpmap(&vertex_selection, &mesh);
|
||||||
|
|
@ -345,9 +374,7 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
face_selection.resize(num_faces(mesh));
|
face_selection.resize(num_faces(mesh));
|
||||||
FKRingPMAP<Mesh> fpmap(&face_selection, &mesh);
|
FKRingPMAP<Mesh> fpmap(&face_selection, &mesh);
|
||||||
for(face_descriptor f_h : displayed_faces)
|
for(face_descriptor f_h : displayed_faces)
|
||||||
{
|
|
||||||
put(fpmap, f_h, true);
|
put(fpmap, f_h, true);
|
||||||
}
|
|
||||||
CGAL::expand_face_selection(displayed_faces,
|
CGAL::expand_face_selection(displayed_faces,
|
||||||
mesh,
|
mesh,
|
||||||
1,
|
1,
|
||||||
|
|
@ -356,9 +383,9 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
|
|
||||||
for(vertex_descriptor vh : displayed_vertices)
|
for(vertex_descriptor vh : displayed_vertices)
|
||||||
{
|
{
|
||||||
Point pos=Point(get(ppmap, vh).x()+offset.x,
|
Point pos = Point(get(ppmap, vh).x() + offset.x,
|
||||||
get(ppmap, vh).y()+offset.y,
|
get(ppmap, vh).y() + offset.y,
|
||||||
get(ppmap, vh).z()+offset.z);
|
get(ppmap, vh).z() + offset.z);
|
||||||
TextItem* text_item = new TextItem(float(pos.x()),
|
TextItem* text_item = new TextItem(float(pos.x()),
|
||||||
float(pos.y()),
|
float(pos.y()),
|
||||||
float(pos.z()),
|
float(pos.z()),
|
||||||
|
|
@ -366,13 +393,14 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
vitems->append(text_item);
|
vitems->append(text_item);
|
||||||
targeted_ids->push_back(text_item);
|
targeted_ids->push_back(text_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(edge_descriptor e : displayed_edges)
|
for(edge_descriptor e : displayed_edges)
|
||||||
{
|
{
|
||||||
halfedge_descriptor h(halfedge(e, mesh));
|
halfedge_descriptor h(halfedge(e, mesh));
|
||||||
Point pos=CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
|
Point pos = CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
|
||||||
pos = Point(pos.x()+offset.x,
|
pos = Point(pos.x() + offset.x,
|
||||||
pos.y()+offset.y,
|
pos.y() + offset.y,
|
||||||
pos.z()+offset.z);
|
pos.z() + offset.z);
|
||||||
|
|
||||||
TextItem* text_item = new TextItem(float(pos.x()),
|
TextItem* text_item = new TextItem(float(pos.x()),
|
||||||
float(pos.y()),
|
float(pos.y()),
|
||||||
|
|
@ -387,15 +415,15 @@ void compute_displayed_ids(Mesh& mesh,
|
||||||
int total(0);
|
int total(0);
|
||||||
for(vertex_descriptor vh :vertices_around_face(halfedge(f, mesh), mesh))
|
for(vertex_descriptor vh :vertices_around_face(halfedge(f, mesh), mesh))
|
||||||
{
|
{
|
||||||
x+=get(ppmap, vh).x();
|
x += get(ppmap, vh).x();
|
||||||
y+=get(ppmap, vh).y();
|
y += get(ppmap, vh).y();
|
||||||
z+=get(ppmap, vh).z();
|
z += get(ppmap, vh).z();
|
||||||
++total;
|
++total;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point pos(x/total+offset.x,
|
Point pos(x/total + offset.x,
|
||||||
y/total+offset.y,
|
y/total + offset.y,
|
||||||
z/total+offset.z);
|
z/total + offset.z);
|
||||||
TextItem* text_item = new TextItem(float(pos.x()),
|
TextItem* text_item = new TextItem(float(pos.x()),
|
||||||
float(pos.y()),
|
float(pos.y()),
|
||||||
float(pos.z()),
|
float(pos.z()),
|
||||||
|
|
@ -408,18 +436,20 @@ template<class Mesh>
|
||||||
bool printVertexIds(const Mesh& mesh,
|
bool printVertexIds(const Mesh& mesh,
|
||||||
TextListItem* vitems)
|
TextListItem* vitems)
|
||||||
{
|
{
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
|
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
|
||||||
typedef typename boost::property_traits<Ppmap>::value_type Point;
|
using Point = typename boost::property_traits<Ppmap>::value_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
|
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
|
||||||
|
|
||||||
Ppmap ppmap = get(boost::vertex_point, mesh);
|
Ppmap ppmap = get(boost::vertex_point, mesh);
|
||||||
IDmap idmap = get(boost::vertex_index, mesh);
|
IDmap idmap = get(boost::vertex_index, mesh);
|
||||||
|
|
||||||
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
font.setPointSize(POINT_SIZE);
|
font.setPointSize(POINT_SIZE);
|
||||||
|
|
||||||
//fills textItems
|
// fills textItems
|
||||||
for(typename boost::graph_traits<Mesh>::vertex_descriptor vh : vertices(mesh))
|
for(typename boost::graph_traits<Mesh>::vertex_descriptor vh : vertices(mesh))
|
||||||
{
|
{
|
||||||
const Point& p = get(ppmap, vh);
|
const Point& p = get(ppmap, vh);
|
||||||
|
|
@ -429,7 +459,8 @@ bool printVertexIds(const Mesh& mesh,
|
||||||
QString("%1").arg(get(idmap, vh)), true, font, Qt::red));
|
QString("%1").arg(get(idmap, vh)), true, font, Qt::red));
|
||||||
|
|
||||||
}
|
}
|
||||||
//add the QList to the render's pool
|
|
||||||
|
// add the QList to the render's pool
|
||||||
bool res = true;
|
bool res = true;
|
||||||
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
||||||
{
|
{
|
||||||
|
|
@ -437,10 +468,9 @@ bool printVertexIds(const Mesh& mesh,
|
||||||
renderer->addTextList(vitems);
|
renderer->addTextList(vitems);
|
||||||
v->update();
|
v->update();
|
||||||
if(vitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
if(vitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
||||||
{
|
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -448,13 +478,15 @@ template<class Mesh>
|
||||||
bool printEdgeIds(const Mesh& mesh,
|
bool printEdgeIds(const Mesh& mesh,
|
||||||
TextListItem* eitems)
|
TextListItem* eitems)
|
||||||
{
|
{
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
|
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
|
||||||
typedef typename boost::property_traits<Ppmap>::value_type Point;
|
using Point = typename boost::property_traits<Ppmap>::value_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
|
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
|
||||||
|
|
||||||
Ppmap ppmap = get(boost::vertex_point, mesh);
|
Ppmap ppmap = get(boost::vertex_point, mesh);
|
||||||
IDmap idmap = get(boost::halfedge_index, mesh);
|
IDmap idmap = get(boost::halfedge_index, mesh);
|
||||||
|
|
||||||
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
font.setPointSize(POINT_SIZE);
|
font.setPointSize(POINT_SIZE);
|
||||||
|
|
@ -468,7 +500,8 @@ bool printEdgeIds(const Mesh& mesh,
|
||||||
float((p1.z() + p2.z()) / 2 + offset.z),
|
float((p1.z() + p2.z()) / 2 + offset.z),
|
||||||
QString("%1").arg(get(idmap, halfedge(e, mesh)) / 2), true, font, Qt::green));
|
QString("%1").arg(get(idmap, halfedge(e, mesh)) / 2), true, font, Qt::green));
|
||||||
}
|
}
|
||||||
//add the QList to the render's pool
|
|
||||||
|
// add the QList to the render's pool
|
||||||
bool res = true;
|
bool res = true;
|
||||||
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
||||||
{
|
{
|
||||||
|
|
@ -476,10 +509,9 @@ bool printEdgeIds(const Mesh& mesh,
|
||||||
renderer->addTextList(eitems);
|
renderer->addTextList(eitems);
|
||||||
v->update();
|
v->update();
|
||||||
if(eitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
if(eitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
||||||
{
|
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -487,15 +519,18 @@ template<class Mesh>
|
||||||
bool printFaceIds(const Mesh& mesh,
|
bool printFaceIds(const Mesh& mesh,
|
||||||
TextListItem* fitems)
|
TextListItem* fitems)
|
||||||
{
|
{
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
|
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
|
||||||
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
|
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
|
||||||
|
|
||||||
Ppmap ppmap = get(boost::vertex_point, mesh);
|
Ppmap ppmap = get(boost::vertex_point, mesh);
|
||||||
IDmap idmap = get(boost::face_index, mesh);
|
IDmap idmap = get(boost::face_index, mesh);
|
||||||
|
|
||||||
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
font.setPointSize(POINT_SIZE);
|
font.setPointSize(POINT_SIZE);
|
||||||
|
|
||||||
for(typename boost::graph_traits<Mesh>::face_descriptor fh : faces(mesh))
|
for(typename boost::graph_traits<Mesh>::face_descriptor fh : faces(mesh))
|
||||||
{
|
{
|
||||||
double x(0), y(0), z(0);
|
double x(0), y(0), z(0);
|
||||||
|
|
@ -513,7 +548,8 @@ bool printFaceIds(const Mesh& mesh,
|
||||||
float(z / total + offset.z),
|
float(z / total + offset.z),
|
||||||
QString("%1").arg(get(idmap, fh)), true, font, Qt::blue));
|
QString("%1").arg(get(idmap, fh)), true, font, Qt::blue));
|
||||||
}
|
}
|
||||||
//add the QList to the render's pool
|
|
||||||
|
// add the QList to the render's pool
|
||||||
bool res = true;
|
bool res = true;
|
||||||
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
||||||
{
|
{
|
||||||
|
|
@ -521,10 +557,8 @@ bool printFaceIds(const Mesh& mesh,
|
||||||
renderer->addTextList(fitems);
|
renderer->addTextList(fitems);
|
||||||
v->update();
|
v->update();
|
||||||
if(fitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
if(fitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
|
||||||
{
|
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,14 +569,15 @@ int zoomToId(const Mesh& mesh,
|
||||||
typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
|
typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
|
||||||
Point& p)
|
Point& p)
|
||||||
{
|
{
|
||||||
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
using vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
|
||||||
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
|
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
|
|
||||||
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type VIDmap;
|
|
||||||
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type EIDmap;
|
|
||||||
typedef typename boost::property_map<Mesh, boost::face_index_t>::type FIDmap;
|
|
||||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Traits;
|
|
||||||
|
|
||||||
|
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
|
||||||
|
using VIDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
|
||||||
|
using EIDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
|
||||||
|
using FIDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
|
||||||
|
|
||||||
|
using Traits = typename CGAL::Kernel_traits<Point>::Kernel;
|
||||||
|
|
||||||
Ppmap ppmap = get(boost::vertex_point, mesh);
|
Ppmap ppmap = get(boost::vertex_point, mesh);
|
||||||
VIDmap vidmap = get(boost::vertex_index, mesh);
|
VIDmap vidmap = get(boost::vertex_index, mesh);
|
||||||
|
|
@ -559,6 +594,7 @@ int zoomToId(const Mesh& mesh,
|
||||||
{
|
{
|
||||||
return 1; //("Input must be of the form [v/e/f][int]"
|
return 1; //("Input must be of the form [v/e/f][int]"
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGAL::qglviewer::Vec offset = viewer->offset();
|
const CGAL::qglviewer::Vec offset = viewer->offset();
|
||||||
typename Traits::Vector_3 normal;
|
typename Traits::Vector_3 normal;
|
||||||
if(first == QString("v"))
|
if(first == QString("v"))
|
||||||
|
|
@ -567,26 +603,25 @@ int zoomToId(const Mesh& mesh,
|
||||||
for(vertex_descriptor vh : vertices(mesh))
|
for(vertex_descriptor vh : vertices(mesh))
|
||||||
{
|
{
|
||||||
std::size_t cur_id = get(vidmap, vh);
|
std::size_t cur_id = get(vidmap, vh);
|
||||||
if( cur_id == id)
|
if(cur_id == id)
|
||||||
{
|
{
|
||||||
p = Point(get(ppmap, vh).x() + offset.x,
|
p = Point(get(ppmap, vh).x() + offset.x,
|
||||||
get(ppmap, vh).y() + offset.y,
|
get(ppmap, vh).y() + offset.y,
|
||||||
get(ppmap, vh).z() + offset.z);
|
get(ppmap, vh).z() + offset.z);
|
||||||
|
|
||||||
typename boost::graph_traits<Mesh>::halfedge_descriptor hf = halfedge(vh, mesh);
|
typename boost::graph_traits<Mesh>::halfedge_descriptor hf = halfedge(vh, mesh);
|
||||||
if(CGAL::is_border(hf, mesh))
|
if(CGAL::is_border(hf, mesh))
|
||||||
{
|
|
||||||
hf = opposite(hf, mesh);
|
hf = opposite(hf, mesh);
|
||||||
}
|
|
||||||
selected_fh = face(hf, mesh);
|
selected_fh = face(hf, mesh);
|
||||||
normal = CGAL::Polygon_mesh_processing::compute_vertex_normal(vh, mesh);
|
normal = CGAL::Polygon_mesh_processing::compute_vertex_normal(vh, mesh);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found)
|
if(!found)
|
||||||
{
|
return 2; // "No vertex with id %1").arg(id)
|
||||||
return 2;//"No vertex with id %1").arg(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(first == QString("e"))
|
else if(first == QString("e"))
|
||||||
{
|
{
|
||||||
|
|
@ -604,10 +639,10 @@ int zoomToId(const Mesh& mesh,
|
||||||
typename Traits::Vector_3 normal1(0,0,0);
|
typename Traits::Vector_3 normal1(0,0,0);
|
||||||
if(!is_border(hf, mesh))
|
if(!is_border(hf, mesh))
|
||||||
{
|
{
|
||||||
normal1= CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh),
|
normal1 = CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh), mesh);
|
||||||
mesh);
|
|
||||||
selected_fh = face(hf, mesh);
|
selected_fh = face(hf, mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
typename Traits::Vector_3 normal2(0,0,0);
|
typename Traits::Vector_3 normal2(0,0,0);
|
||||||
if(!is_border(opposite(hf, mesh), mesh))
|
if(!is_border(opposite(hf, mesh), mesh))
|
||||||
{
|
{
|
||||||
|
|
@ -615,15 +650,15 @@ int zoomToId(const Mesh& mesh,
|
||||||
mesh);
|
mesh);
|
||||||
selected_fh = face(hf, mesh);
|
selected_fh = face(hf, mesh);
|
||||||
}
|
}
|
||||||
normal = 0.5*normal1+0.5*normal2;
|
|
||||||
|
normal = 0.5*normal1 + 0.5*normal2;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found)
|
if(!found)
|
||||||
{
|
return 3; // "No edge with id %1").arg(id)
|
||||||
return 3;//"No edge with id %1").arg(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(first == QString("f"))
|
else if(first == QString("f"))
|
||||||
{
|
{
|
||||||
|
|
@ -634,28 +669,28 @@ int zoomToId(const Mesh& mesh,
|
||||||
{
|
{
|
||||||
if(get(fidmap, fh) != id)
|
if(get(fidmap, fh) != id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(vertex_descriptor vh : vertices_around_face(halfedge(fh, mesh), mesh))
|
for(vertex_descriptor vh : vertices_around_face(halfedge(fh, mesh), mesh))
|
||||||
{
|
{
|
||||||
x+=get(ppmap, vh).x();
|
x += get(ppmap, vh).x();
|
||||||
y+=get(ppmap, vh).y();
|
y += get(ppmap, vh).y();
|
||||||
z+=get(ppmap, vh).z();
|
z += get(ppmap, vh).z();
|
||||||
++total;
|
++total;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = Point(x/total + offset.x,
|
p = Point(x/total + offset.x,
|
||||||
y/total + offset.y,
|
y/total + offset.y,
|
||||||
z/total + offset.z);
|
z/total + offset.z);
|
||||||
normal = CGAL::Polygon_mesh_processing::compute_face_normal(
|
normal = CGAL::Polygon_mesh_processing::compute_face_normal(fh, mesh);
|
||||||
fh,
|
|
||||||
mesh);
|
|
||||||
selected_fh = fh;
|
selected_fh = fh;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found)
|
if(!found)
|
||||||
{
|
return 4; // "No face with id %1").arg(id)
|
||||||
return 4; //"No face with id %1").arg(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CGAL::qglviewer::Quaternion new_orientation(CGAL::qglviewer::Vec(0,0,-1),
|
CGAL::qglviewer::Quaternion new_orientation(CGAL::qglviewer::Vec(0,0,-1),
|
||||||
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
|
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
|
||||||
Point new_pos = p +
|
Point new_pos = p +
|
||||||
|
|
@ -665,9 +700,7 @@ int zoomToId(const Mesh& mesh,
|
||||||
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
|
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
|
||||||
.norm() * normal ;
|
.norm() * normal ;
|
||||||
|
|
||||||
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(),
|
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(), p.y(), p.z()));
|
||||||
p.y(),
|
|
||||||
p.z()));
|
|
||||||
|
|
||||||
viewer->moveCameraToCoordinates(QString("%1 %2 %3 %4 %5 %6 %7").arg(new_pos.x())
|
viewer->moveCameraToCoordinates(QString("%1 %2 %3 %4 %5 %6 %7").arg(new_pos.x())
|
||||||
.arg(new_pos.y())
|
.arg(new_pos.y())
|
||||||
|
|
@ -677,7 +710,59 @@ int zoomToId(const Mesh& mesh,
|
||||||
.arg(new_orientation[2])
|
.arg(new_orientation[2])
|
||||||
.arg(new_orientation[3]));
|
.arg(new_orientation[3]));
|
||||||
viewer->update();
|
viewer->update();
|
||||||
return 0; //all clear;
|
|
||||||
}
|
return 0; // all clear;
|
||||||
#endif // ID_PRINTING_H
|
}
|
||||||
|
|
||||||
|
template<class PointSet>
|
||||||
|
int zoomToPoint(const PointSet& ps,
|
||||||
|
const typename PointSet::Index& index,
|
||||||
|
CGAL::Three::Viewer_interface* viewer,
|
||||||
|
typename PointSet::Point_3& p)
|
||||||
|
{
|
||||||
|
const CGAL::qglviewer::Vec offset = viewer->offset();
|
||||||
|
|
||||||
|
using Point_3 = typename PointSet::Point_3;
|
||||||
|
using Vector_3 = typename PointSet::Vector_3;
|
||||||
|
|
||||||
|
const Point_3& op = ps.point(index);
|
||||||
|
|
||||||
|
p = Point_3(op.x() + offset.x,
|
||||||
|
op.y() + offset.y,
|
||||||
|
op.z() + offset.z);
|
||||||
|
|
||||||
|
Vector_3 normal;
|
||||||
|
if(ps.has_normal_map())
|
||||||
|
normal = ps.normal(index);
|
||||||
|
else
|
||||||
|
normal = { viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
|
||||||
|
viewer->camera()->position().y - viewer->camera()->pivotPoint().y,
|
||||||
|
viewer->camera()->position().z - viewer->camera()->pivotPoint().z };
|
||||||
|
|
||||||
|
Point_3 new_pos = p +
|
||||||
|
0.25 * CGAL::qglviewer::Vec(
|
||||||
|
viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
|
||||||
|
viewer->camera()->position().y - viewer->camera()->pivotPoint().y,
|
||||||
|
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
|
||||||
|
.norm() * normal ;
|
||||||
|
|
||||||
|
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(), p.y(), p.z()));
|
||||||
|
|
||||||
|
CGAL::qglviewer::Quaternion new_orientation(CGAL::qglviewer::Vec(0,0,-1),
|
||||||
|
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
|
||||||
|
|
||||||
|
viewer->moveCameraToCoordinates(QString("%1 %2 %3 %4 %5 %6 %7").arg(new_pos.x())
|
||||||
|
.arg(new_pos.y())
|
||||||
|
.arg(new_pos.z())
|
||||||
|
.arg(new_orientation[0])
|
||||||
|
.arg(new_orientation[1])
|
||||||
|
.arg(new_orientation[2])
|
||||||
|
.arg(new_orientation[3]));
|
||||||
|
|
||||||
|
viewer->update();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,234 +1,246 @@
|
||||||
#ifndef TRIANGULATE_PRIMITIVE
|
#ifndef CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
||||||
#define TRIANGULATE_PRIMITIVE
|
#define CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
||||||
|
|
||||||
|
#include <CGAL/Three/Scene_item.h>
|
||||||
|
|
||||||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||||
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
||||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||||
|
|
||||||
#include <CGAL/Projection_traits_3.h>
|
#include <CGAL/Projection_traits_3.h>
|
||||||
#include <CGAL/Three/Scene_item.h>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
//Make sure all the facets are triangles
|
#include <CGAL/boost/graph/properties.h>
|
||||||
|
#include <boost/graph/graph_traits.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <queue>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Ensure that all the facets are triangles
|
||||||
|
// @todo just use PMP::triangulate_face()...?
|
||||||
|
// or at least mark_faces_in_domain()
|
||||||
|
|
||||||
template<class Mesh, typename Kernel, typename Index_type>
|
template<class Mesh, typename Kernel, typename Index_type>
|
||||||
class FacetTriangulator
|
class FacetTriangulator
|
||||||
{
|
{
|
||||||
typedef Kernel Traits;
|
public:
|
||||||
|
using Traits = Kernel;
|
||||||
|
using Point = typename Kernel::Point_3;
|
||||||
|
using Vector = typename Kernel::Vector_3;
|
||||||
|
|
||||||
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
|
using P_traits = CGAL::Projection_traits_3<Traits>;
|
||||||
|
|
||||||
typedef typename Kernel::Vector_3 Vector;
|
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
|
||||||
|
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
|
||||||
|
|
||||||
|
struct Face_info
|
||||||
typedef CGAL::Projection_traits_3<Traits> P_traits;
|
{
|
||||||
|
|
||||||
typedef CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor,
|
|
||||||
P_traits> Vb;
|
|
||||||
|
|
||||||
struct Face_info {
|
|
||||||
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
|
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
|
||||||
bool is_external;
|
bool is_external;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CGAL::Triangulation_face_base_with_info_2<Face_info,
|
using Vb = CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor, P_traits>;
|
||||||
P_traits> Fb1;
|
using Fbb = CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits>;
|
||||||
typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1> Fb;
|
using Fb = CGAL::Constrained_triangulation_face_base_2<P_traits, Fbb>;
|
||||||
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
|
using TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>;
|
||||||
typedef CGAL::Exact_predicates_tag Itag;
|
using Itag = CGAL::Exact_predicates_tag;
|
||||||
|
using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, Itag>;
|
||||||
|
|
||||||
public:
|
using Vertex_handle = typename CDT::Vertex_handle;
|
||||||
struct PointAndId {
|
using Face_handle = typename CDT::Face_handle;
|
||||||
typename Kernel::Point_3 point;
|
|
||||||
|
struct PointAndId
|
||||||
|
{
|
||||||
|
Point point;
|
||||||
Index_type id;
|
Index_type id;
|
||||||
|
PointAndId() = default;
|
||||||
|
PointAndId(const Point& point, const Index_type id) : point(point), id(id) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits,
|
public:
|
||||||
TDS,
|
CDT* cdt;
|
||||||
Itag> CDT;
|
CGAL::Unique_hash_map<Vertex_handle, Index_type> v2v;
|
||||||
CDT *cdt;
|
|
||||||
CGAL::Unique_hash_map<typename CDT::Vertex_handle, Index_type> v2v;
|
|
||||||
|
|
||||||
//Constructor
|
public:
|
||||||
FacetTriangulator(typename boost::graph_traits<Mesh>::face_descriptor fd,
|
// Constructor
|
||||||
|
FacetTriangulator(face_descriptor fd,
|
||||||
const Vector& normal,
|
const Vector& normal,
|
||||||
Mesh *poly,
|
Mesh* poly,
|
||||||
Vector offset = Vector(0,0,0))
|
Vector offset = Vector(0,0,0))
|
||||||
{
|
{
|
||||||
std::vector<PointAndId> idPoints;
|
std::vector<PointAndId> idPoints;
|
||||||
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
|
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
|
||||||
{
|
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
|
||||||
PointAndId idPoint;
|
source(he_circ, *poly));
|
||||||
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
|
|
||||||
idPoint.id = source(he_circ, *poly);
|
|
||||||
idPoints.push_back(idPoint);
|
|
||||||
|
|
||||||
}
|
|
||||||
if(!triangulate(idPoints, normal))
|
if(!triangulate(idPoints, normal))
|
||||||
std::cerr<<"Facet not displayed"<<std::endl;
|
std::cerr << "Facet not displayed" << std::endl;
|
||||||
}
|
}
|
||||||
FacetTriangulator(typename boost::graph_traits<Mesh>::face_descriptor fd,
|
|
||||||
const std::vector<typename Kernel::Point_3>& more_points,
|
FacetTriangulator(face_descriptor fd,
|
||||||
|
const std::vector<Point>& more_points,
|
||||||
const Vector& normal,
|
const Vector& normal,
|
||||||
Mesh *poly,
|
Mesh* poly,
|
||||||
Vector offset = Vector(0,0,0))
|
Vector offset = Vector(0,0,0))
|
||||||
{
|
{
|
||||||
std::vector<PointAndId> idPoints;
|
std::vector<PointAndId> idPoints;
|
||||||
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
|
for(halfedge_descriptor he_circ : halfedges_around_face(halfedge(fd, *poly), *poly))
|
||||||
{
|
idPoints.emplace_back(get(CGAL::vertex_point, *poly, source(he_circ, *poly)) + offset,
|
||||||
PointAndId idPoint;
|
source(he_circ, *poly));
|
||||||
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
|
|
||||||
idPoint.id = source(he_circ, *poly);
|
|
||||||
idPoints.push_back(idPoint);
|
|
||||||
|
|
||||||
}
|
if(!triangulate_with_points(idPoints, more_points, normal))
|
||||||
if(!triangulate_with_points(idPoints,more_points, normal))
|
std::cerr << "Facet not displayed" << std::endl;
|
||||||
std::cerr<<"Facet not displayed"<<std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FacetTriangulator(std::vector<PointAndId > &idPoints,
|
FacetTriangulator(std::vector<PointAndId>& idPoints,
|
||||||
const Vector& normal)
|
const Vector& normal)
|
||||||
{
|
{
|
||||||
if(!triangulate(idPoints, normal))
|
if(!triangulate(idPoints, normal))
|
||||||
std::cerr<<"Facet not displayed"<<std::endl;
|
std::cerr << "Facet not displayed" << std::endl;
|
||||||
}
|
}
|
||||||
FacetTriangulator(std::vector<PointAndId > &idPoints,
|
FacetTriangulator(std::vector<PointAndId>& idPoints,
|
||||||
const std::vector<typename Kernel::Point_3>& more_points,
|
const std::vector<Point>& more_points,
|
||||||
const Vector& normal)
|
const Vector& normal)
|
||||||
{
|
{
|
||||||
if(!triangulate_with_points(idPoints, more_points, normal))
|
if(!triangulate_with_points(idPoints, more_points, normal))
|
||||||
std::cerr<<"Facet not displayed"<<std::endl;
|
std::cerr << "Facet not displayed" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~FacetTriangulator()
|
~FacetTriangulator()
|
||||||
{
|
{
|
||||||
if (cdt )
|
if(cdt)
|
||||||
delete cdt;
|
delete cdt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool triangulate( std::vector<PointAndId > &idPoints,
|
bool triangulate(std::vector<PointAndId>& idPoints,
|
||||||
const Vector& normal )
|
|
||||||
{
|
|
||||||
P_traits cdt_traits(normal);
|
|
||||||
cdt = new CDT(cdt_traits);
|
|
||||||
typename CDT::Vertex_handle previous, first, last_inserted;
|
|
||||||
|
|
||||||
// Iterate the points of the facet and decide if they must be inserted in the CDT
|
|
||||||
typename Kernel::FT x(0), y(0), z(0);
|
|
||||||
|
|
||||||
for(PointAndId idPoint : idPoints)
|
|
||||||
{
|
|
||||||
|
|
||||||
x += idPoint.point.x();
|
|
||||||
y += idPoint.point.y();
|
|
||||||
z += idPoint.point.z();
|
|
||||||
typename CDT::Vertex_handle vh;
|
|
||||||
//Always insert the first point, then only insert
|
|
||||||
// if the distance with the previous is reasonable.
|
|
||||||
if(first == typename CDT::Vertex_handle() || idPoint.point != previous->point())
|
|
||||||
{
|
|
||||||
vh = cdt->insert(idPoint.point);
|
|
||||||
v2v[vh] = idPoint.id;
|
|
||||||
if(first == typename CDT::Vertex_handle()) {
|
|
||||||
first = vh;
|
|
||||||
}
|
|
||||||
if(previous != nullptr && previous != vh) {
|
|
||||||
cdt->insert_constraint(previous, vh);
|
|
||||||
last_inserted = previous;
|
|
||||||
}
|
|
||||||
previous = vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(last_inserted == typename CDT::Vertex_handle())
|
|
||||||
return false;
|
|
||||||
if(previous != first)
|
|
||||||
cdt->insert_constraint(previous, first);
|
|
||||||
// sets mark is_external
|
|
||||||
for(typename CDT::All_faces_iterator
|
|
||||||
fit2 = cdt->all_faces_begin(),
|
|
||||||
end = cdt->all_faces_end();
|
|
||||||
fit2 != end; ++fit2)
|
|
||||||
{
|
|
||||||
fit2->info().is_external = false;
|
|
||||||
}
|
|
||||||
//check if the facet is external or internal
|
|
||||||
std::queue<typename CDT::Face_handle> face_queue;
|
|
||||||
face_queue.push(cdt->infinite_vertex()->face());
|
|
||||||
while(! face_queue.empty() ) {
|
|
||||||
typename CDT::Face_handle fh = face_queue.front();
|
|
||||||
face_queue.pop();
|
|
||||||
if(fh->info().is_external) continue;
|
|
||||||
fh->info().is_external = true;
|
|
||||||
for(int i = 0; i <3; ++i) {
|
|
||||||
if(!cdt->is_constrained(std::make_pair(fh, i)))
|
|
||||||
{
|
|
||||||
face_queue.push(fh->neighbor(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool triangulate_with_points( std::vector<PointAndId > &idPoints,
|
|
||||||
const std::vector<typename Kernel::Point_3>& more_points,
|
|
||||||
const Vector& normal)
|
const Vector& normal)
|
||||||
{
|
{
|
||||||
P_traits cdt_traits(normal);
|
P_traits cdt_traits(normal);
|
||||||
cdt = new CDT(cdt_traits);
|
cdt = new CDT(cdt_traits);
|
||||||
typename CDT::Vertex_handle previous, first, last_inserted;
|
|
||||||
|
Vertex_handle previous, first, last_inserted;
|
||||||
|
|
||||||
// Iterate the points of the facet and decide if they must be inserted in the CDT
|
// Iterate the points of the facet and decide if they must be inserted in the CDT
|
||||||
for(PointAndId idPoint : idPoints)
|
typename Kernel::FT x(0), y(0), z(0);
|
||||||
|
|
||||||
|
for(const PointAndId& idPoint : idPoints)
|
||||||
{
|
{
|
||||||
typename CDT::Vertex_handle vh;
|
x += idPoint.point.x();
|
||||||
//Always insert the first point, then only insert
|
y += idPoint.point.y();
|
||||||
// if the distance with the previous is reasonable.
|
z += idPoint.point.z();
|
||||||
if(first == typename CDT::Vertex_handle() || idPoint.point != previous->point())
|
|
||||||
|
Vertex_handle vh;
|
||||||
|
// Always insert the first point, then only insert if the distance with the previous is reasonable.
|
||||||
|
if(first == Vertex_handle() || idPoint.point != previous->point())
|
||||||
{
|
{
|
||||||
vh = cdt->insert(idPoint.point);
|
vh = cdt->insert(idPoint.point);
|
||||||
v2v[vh] = idPoint.id;
|
v2v[vh] = idPoint.id;
|
||||||
if(first == typename CDT::Vertex_handle()) {
|
if(first == Vertex_handle())
|
||||||
first = vh;
|
first = vh;
|
||||||
}
|
|
||||||
if(previous != nullptr && previous != vh) {
|
if(previous != nullptr && previous != vh)
|
||||||
|
{
|
||||||
cdt->insert_constraint(previous, vh);
|
cdt->insert_constraint(previous, vh);
|
||||||
last_inserted = previous;
|
last_inserted = previous;
|
||||||
}
|
}
|
||||||
previous = vh;
|
previous = vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(last_inserted == typename CDT::Vertex_handle())
|
|
||||||
|
if(last_inserted == Vertex_handle())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if(previous != first)
|
||||||
cdt->insert_constraint(previous, first);
|
cdt->insert_constraint(previous, first);
|
||||||
for(typename Kernel::Point_3 point : more_points)
|
|
||||||
{
|
|
||||||
cdt->insert(point);
|
|
||||||
}
|
|
||||||
// sets mark is_external
|
// sets mark is_external
|
||||||
for(typename CDT::All_faces_iterator
|
for(Face_handle f2 : cdt->all_face_handles())
|
||||||
fit2 = cdt->all_faces_begin(),
|
f2->info().is_external = false;
|
||||||
end = cdt->all_faces_end();
|
|
||||||
fit2 != end; ++fit2)
|
// check if the facet is external or internal
|
||||||
{
|
|
||||||
fit2->info().is_external = false;
|
|
||||||
}
|
|
||||||
//check if the facet is external or internal
|
|
||||||
std::queue<typename CDT::Face_handle> face_queue;
|
std::queue<typename CDT::Face_handle> face_queue;
|
||||||
face_queue.push(cdt->infinite_vertex()->face());
|
face_queue.push(cdt->infinite_vertex()->face());
|
||||||
while(! face_queue.empty() ) {
|
while(! face_queue.empty())
|
||||||
|
{
|
||||||
typename CDT::Face_handle fh = face_queue.front();
|
typename CDT::Face_handle fh = face_queue.front();
|
||||||
face_queue.pop();
|
face_queue.pop();
|
||||||
if(fh->info().is_external) continue;
|
if(fh->info().is_external)
|
||||||
|
continue;
|
||||||
|
|
||||||
fh->info().is_external = true;
|
fh->info().is_external = true;
|
||||||
for(int i = 0; i <3; ++i) {
|
for(int i = 0; i <3; ++i)
|
||||||
if(!cdt->is_constrained(std::make_pair(fh, i)))
|
|
||||||
{
|
{
|
||||||
|
if(!cdt->is_constrained(std::make_pair(fh, i)))
|
||||||
face_queue.push(fh->neighbor(i));
|
face_queue.push(fh->neighbor(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool triangulate_with_points(std::vector<PointAndId >& idPoints,
|
||||||
|
const std::vector<Point>& more_points,
|
||||||
|
const Vector& normal)
|
||||||
|
{
|
||||||
|
P_traits cdt_traits(normal);
|
||||||
|
cdt = new CDT(cdt_traits);
|
||||||
|
|
||||||
|
// Iterate the points of the facet and decide if they must be inserted in the CDT
|
||||||
|
Vertex_handle previous, first, last_inserted;
|
||||||
|
for(const PointAndId& idPoint : idPoints)
|
||||||
|
{
|
||||||
|
Vertex_handle vh;
|
||||||
|
// Always insert the first point, then only insert if the distance with the previous is reasonable.
|
||||||
|
if(first == Vertex_handle() || idPoint.point != previous->point())
|
||||||
|
{
|
||||||
|
vh = cdt->insert(idPoint.point);
|
||||||
|
v2v[vh] = idPoint.id;
|
||||||
|
if(first == Vertex_handle())
|
||||||
|
first = vh;
|
||||||
|
|
||||||
|
if(previous != nullptr && previous != vh)
|
||||||
|
{
|
||||||
|
cdt->insert_constraint(previous, vh);
|
||||||
|
last_inserted = previous;
|
||||||
|
}
|
||||||
|
previous = vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(last_inserted == Vertex_handle())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cdt->insert_constraint(previous, first);
|
||||||
|
for(const Point& point : more_points)
|
||||||
|
cdt->insert(point);
|
||||||
|
|
||||||
|
// sets mark is_external
|
||||||
|
for(Face_handle f2 : cdt->all_face_handles())
|
||||||
|
f2->info().is_external = false;
|
||||||
|
|
||||||
|
// check if the facet is external or internal
|
||||||
|
std::queue<typename CDT::Face_handle> face_queue;
|
||||||
|
face_queue.push(cdt->infinite_vertex()->face());
|
||||||
|
while(!face_queue.empty())
|
||||||
|
{
|
||||||
|
typename CDT::Face_handle fh = face_queue.front();
|
||||||
|
face_queue.pop();
|
||||||
|
if(fh->info().is_external)
|
||||||
|
continue;
|
||||||
|
fh->info().is_external = true;
|
||||||
|
for(int i = 0; i <3; ++i)
|
||||||
|
{
|
||||||
|
if(!cdt->is_constrained(std::make_pair(fh, i)))
|
||||||
|
face_queue.push(fh->neighbor(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRIANGULATE_PRIMITIVE
|
#endif // CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ namespace Three{
|
||||||
* */
|
* */
|
||||||
class Scene_interface {
|
class Scene_interface {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//!A bounding box is a box with each face corresponding to an extremum of its contents.
|
//!A bounding box is a box with each face corresponding to an extremum of its contents.
|
||||||
|
|
||||||
typedef CGAL::Bbox_3 Bbox;
|
typedef CGAL::Bbox_3 Bbox;
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ public:
|
||||||
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
|
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
|
||||||
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
|
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
|
||||||
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
|
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
|
||||||
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Display_property_plugin
|
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Heat_method_plugin
|
||||||
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
|
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
|
||||||
};
|
};
|
||||||
typedef CGAL::Bbox_3 Bbox;
|
typedef CGAL::Bbox_3 Bbox;
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ public:
|
||||||
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
|
PROGRAM_OLD_FLAT, /** Used to render flat shading without pre computing normals without geometry shader*/
|
||||||
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
|
PROGRAM_SOLID_WIREFRAME, //! Used to render edges with width superior to 1.
|
||||||
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
|
PROGRAM_NO_INTERPOLATION, //! Used to render faces without interpolating their color.
|
||||||
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Display_property_plugin
|
PROGRAM_HEAT_INTENSITY, //! Used to render special item in Heat_method_plugin
|
||||||
PROGRAM_TETRA_FILTERING, //! Used in Scene_tetrahedra_item with Tetrahedra_filtering_plugin
|
PROGRAM_TETRA_FILTERING, //! Used in Scene_tetrahedra_item with Tetrahedra_filtering_plugin
|
||||||
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
|
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue