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:
Mael Rouxel-Labbé 2023-06-21 13:15:56 +02:00
parent 0f25ddae73
commit c4f4bc4cac
17 changed files with 3083 additions and 2472 deletions

View File

@ -3,13 +3,17 @@
#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;
if(h >0.8 && h < 0.95) //span of ugly pink, desaturates make it less garish IMO
std::size_t s_max = 255;
if(h > 0.8 && h < 0.95) // span of ugly pink, desaturates make it less garish IMO
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);
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();
const qreal step = (static_cast<qreal>(1)) / nb_of_colors;
qreal h = hue==-1 ? 0
:hue;
for(unsigned i = 0; i < nb_of_colors; ++i) {
if (h!=-1) h += step;
if ( h > 1 ) { h -= 1; }
qreal h = (hue == -1) ? 0 : hue;
for(std::size_t i=0; i<nb_of_colors; ++i)
{
if(h != -1)
h += step;
if(h > 1)
h -= 1;
*out++ = generate_color(h);
}
return out;
}
inline QColor generate_random_color() {
inline QColor generate_random_color()
{
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

View File

@ -1440,7 +1440,7 @@ QList<int> MainWindow::getSelectedSceneItemIndices() const
void MainWindow::selectionChanged()
{
scene->setSelectedItemIndex(getSelectedSceneItemIndex());
scene->setSelectedItemsList(getSelectedSceneItemIndices());
scene->setSelectedItemIndices(getSelectedSceneItemIndices());
CGAL::Three::Scene_item* item = scene->item(getSelectedSceneItemIndex());
Q_FOREACH(CGAL::QGLViewer* vi, CGAL::QGLViewer::QGLViewerPool())
{
@ -2193,7 +2193,7 @@ void MainWindow::on_actionEraseAll_triggered()
QList<int> all_ids;
for(int i = 0; i < scene->numberOfEntries(); ++i)
all_ids.push_back(i);
scene->setSelectedItemsList(all_ids);
scene->setSelectedItemIndices(all_ids);
on_actionErase_triggered();
}

View File

@ -1,11 +1,16 @@
include(polyhedron_demo_macros)
qt5_wrap_ui(display_propertyUI_FILES Display_property.ui)
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
target_link_libraries(display_property_plugin PUBLIC scene_surface_mesh_item
scene_points_with_normal_item
scene_color_ramp)
if(TARGET CGAL::Eigen3_support)
qt5_wrap_ui( display_propertyUI_FILES Display_property.ui )
polyhedron_demo_plugin(display_property_plugin Display_property_plugin ${display_propertyUI_FILES} KEYWORDS Viewer)
target_link_libraries(display_property_plugin
PUBLIC
scene_surface_mesh_item
scene_points_with_normal_item
scene_color_ramp
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
CGAL::Eigen3_support)
endif()

View File

@ -2,26 +2,202 @@
<ui version="4.0">
<class>DisplayPropertyWidget</class>
<widget class="QDockWidget" name="DisplayPropertyWidget">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>292</width>
<height>508</height>
<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 Displaying</string>
<string>Property Display</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>
<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">
<string>Color Item</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="propertyGroup">
<property name="title">
<string>Property</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="propertyBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Smallest Angle Per Face</string>
</property>
</item>
<item>
<property name="text">
<string>Scaled Jacobian</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity (Intrinsic Delaunay)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="ColoringGroup" columnstretch="50,50">
<item row="0" column="0">
<spacer name="verticalSpacer">
<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="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>
@ -30,12 +206,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>127</width>
<height>430</height>
<width>236</width>
<height>397</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<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>
@ -46,206 +222,70 @@
</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">
<bool>false</bool>
</property>
<property name="text">
<string>Delete Group</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="propertyBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Smallest Angle Per Face</string>
</property>
</item>
<item>
<property name="text">
<string>Scaled Jacobian</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity</string>
</property>
</item>
<item>
<property name="text">
<string>Heat Intensity (Intrinsic Delaunay)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="11" column="0">
<widget class="QGroupBox" name="extremeValuesGroup">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="title">
<string>Extreme Values</string>
</property>
</spacer>
<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>
</widget>

View File

@ -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>

View File

@ -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"

View File

@ -217,7 +217,7 @@ void Polyhedron_demo_join_and_split_polyhedra_plugin::on_actionColorConnectedCom
item->computeItemColorVectorAutomatically(true);
item->invalidateOpenGLBuffers();
item->setProperty("NbPatchIds", nb_patch_ids);
scene->itemChanged(item);
scene->itemChanged(item); // @todo emits
}
else
{

View File

@ -7,21 +7,20 @@
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
typedef EPICK::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> SMesh;
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
namespace boost {
template <typename P>
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 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>
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 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 CGAL {
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;
};

View File

@ -172,20 +172,22 @@ Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emi
Scene::Item_id
Scene::erase(Scene::Item_id index)
{
if(index <0 || index >= numberOfEntries())
if(index < 0 || index >= numberOfEntries())
return -1;
CGAL::Three::Scene_item* item = m_entries[index];
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());
}
m_groups.removeAll(index);
if(item->parentGroup()
&& item->parentGroup()->isChildLocked(item))
if(item->parentGroup() && item->parentGroup()->isChildLocked(item))
return -1;
//clears the Scene_view
// clears the Scene_view
clear();
index_map.clear();
if(item->parentGroup())
@ -286,12 +288,12 @@ Scene::erase(QList<int> indices)
void Scene::remove_item_from_groups(Scene_item* item)
{
CGAL::Three::Scene_group_item* group = item->parentGroup();
if(group)
{
group->removeChild(item);
children.push_back(item_id(item));
}
CGAL::Three::Scene_group_item* group = item->parentGroup();
if(group)
{
group->removeChild(item);
children.push_back(item_id(item));
}
}
Scene::~Scene()
{
@ -315,19 +317,19 @@ Scene::~Scene()
CGAL::Three::Scene_item*
Scene::item(Item_id index) const
{
return m_entries.value(index); // QList::value checks bounds
return m_entries.value(index); // QList::value checks bounds
}
Scene::Item_id
Scene::item_id(CGAL::Three::Scene_item* scene_item) const
{
return m_entries.indexOf(scene_item);
return m_entries.indexOf(scene_item);
}
int
Scene::numberOfEntries() const
{
return m_entries.size();
return m_entries.size();
}
// Duplicate a scene item.
@ -335,20 +337,23 @@ Scene::numberOfEntries() const
Scene::Item_id
Scene::duplicate(Item_id index)
{
if(index < 0 || index >= m_entries.size())
return -1;
if(index < 0 || index >= m_entries.size())
return -1;
const CGAL::Three::Scene_item* item = m_entries[index];
CGAL::Three::Scene_item* new_item = item->clone();
if(new_item) {
new_item->setName(tr("%1 (copy)").arg(item->name()));
new_item->setColor(item->color());
new_item->setVisible(item->visible());
addItem(new_item);
return m_entries.size() - 1;
}
else
return -1;
const CGAL::Three::Scene_item* item = m_entries[index];
CGAL::Three::Scene_item* new_item = item->clone();
if(new_item)
{
new_item->setName(tr("%1 (copy)").arg(item->name()));
new_item->setColor(item->color());
new_item->setVisible(item->visible());
addItem(new_item);
return m_entries.size() - 1;
}
else
{
return -1;
}
}
void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
@ -486,33 +491,33 @@ void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
void Scene::s_itemAboutToBeDestroyed(CGAL::Three::Scene_item *rmv_itm)
{
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
{
if(item == rmv_itm)
item->itemAboutToBeDestroyed(item);
}
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
{
if(item == rmv_itm)
item->itemAboutToBeDestroyed(item);
}
}
bool
Scene::keyPressEvent(QKeyEvent* e){
bool res=false;
for (QList<int>::iterator it=selected_items_list.begin(),endit=selected_items_list.end();
it!=endit;++it)
{
CGAL::Three::Scene_item* item=m_entries[*it];
res |= item->keyPressEvent(e);
}
return res;
Scene::keyPressEvent(QKeyEvent* e)
{
bool res = false;
Q_FOREACH(int i, selected_items_list)
{
CGAL::Three::Scene_item* item = m_entries[i];
res |= item->keyPressEvent(e);
}
return res;
}
void
Scene::draw(CGAL::Three::Viewer_interface* viewer)
{
draw_aux(false, viewer);
draw_aux(false, viewer);
}
void
Scene::drawWithNames(CGAL::Three::Viewer_interface* viewer)
{
draw_aux(true, viewer);
draw_aux(true, viewer);
}
bool item_should_be_skipped_in_draw(Scene_item* item) {
@ -615,12 +620,10 @@ void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
viewer->setGlPointSize(2.f);
if(index == selected_item || selected_items_list.contains(index))
{
item.selection_changed(true);
}
else
{
item.selection_changed(false);
}
item.drawEdges(viewer);
@ -1122,12 +1125,14 @@ bool Scene::dropMimeData(const QMimeData * /*data*/,
if(group)
{
Q_FOREACH(int id, selected_items_list)
{
if(group->getChildren().contains(id))
{
one_contained = true;
break;
}
}
}
//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)

View File

@ -195,8 +195,10 @@ public Q_SLOTS:
++i;
}
}
//! 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)
{
@ -206,13 +208,38 @@ public Q_SLOTS:
{
QList<int> list;
Q_FOREACH(Item_id id, group->getChildrenForSelection())
list<<id;
l << setSelectedItemsList(list);
list << id;
l << setSelectedItemIndices(list, false /*do not emit*/);
}
}
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)
@ -249,6 +276,8 @@ Q_SIGNALS:
void selectionChanged(QList<int> is);
//! Used when you don't want to update the selectedItem in the Geometric Objects view.
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.
void restoreCollapsedState();
//! Is emitted when draw() is finished.

View File

@ -1175,11 +1175,11 @@ void* Scene_surface_mesh_item_priv::get_aabb_tree()
void
Scene_surface_mesh_item::select(double orig_x,
double orig_y,
double orig_z,
double dir_x,
double dir_y,
double dir_z)
double orig_y,
double orig_z,
double dir_x,
double dir_y,
double dir_z)
{
SMesh *sm = d->smesh_;
std::size_t vertex_to_emit = 0;
@ -2005,7 +2005,7 @@ void Scene_surface_mesh_item::resetColors()
d->has_feature_edges = false;
}
invalidate(COLORS);
itemChanged();
itemChanged(); // @fixme really shouldn't call something that strong
}
QMenu* Scene_surface_mesh_item::contextMenu()
@ -2387,7 +2387,6 @@ void Scene_surface_mesh_item::computeElements() const
{
d->compute_elements(ALL);
setBuffersFilled(true);
const_cast<Scene_surface_mesh_item*>(this)->itemChanged();
}
void

View File

@ -1,79 +1,96 @@
#ifndef ID_PRINTING_H
#define ID_PRINTING_H
#ifndef CGAL_POLYHEDRON_DEMO_ID_PRINTING_H
#define CGAL_POLYHEDRON_DEMO_ID_PRINTING_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/TextRenderer.h>
#include <CGAL/Three/Three.h>
#include <CGAL/Kernel_traits.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <vector>
#define POINT_SIZE 11
template<class Mesh>
struct VKRingPMAP{
typedef typename boost::graph_traits<Mesh>::vertex_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
struct VKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::vertex_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
VKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(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)];
}
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;
}
};
template<class Mesh>
struct EdgeKRingPMAP{
typedef typename boost::graph_traits<Mesh>::edge_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
struct EdgeKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::edge_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
EdgeKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(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];
}
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;
}
};
template<class Mesh>
struct FKRingPMAP{
typedef typename boost::graph_traits<Mesh>::face_descriptor key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::read_write_property_map_tag category;
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
struct FKRingPMAP
{
using key_type = typename boost::graph_traits<Mesh>::face_descriptor;
using value_type = bool;
using reference = value_type;
using category = boost::read_write_property_map_tag;
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
std::vector<bool>* vec;
Mesh* poly;
IDmap idmap;
FKRingPMAP(std::vector<bool>* vec, Mesh* poly)
:vec(vec), poly(poly)
: vec(vec), poly(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){
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;
}
};
@ -91,26 +110,28 @@ void deleteIds(CGAL::Three::Viewer_interface* viewer,
TextListItem* fitems,
std::vector<TextItem*>* targeted_ids)
{
TextRenderer *renderer = viewer->textRenderer();
TextRenderer* renderer = viewer->textRenderer();
for(TextItem* it : vitems->textList())
delete it;
delete it;
for(TextItem* it : eitems->textList())
delete it;
delete it;
for(TextItem* it : fitems->textList())
delete it;
delete it;
vitems->clear();
renderer->removeTextList(vitems);
eitems->clear();
renderer->removeTextList(eitems);
fitems->clear();
renderer->removeTextList(fitems);
targeted_ids->clear();
viewer->update();
}
template<typename Handle, typename Point, typename Tree>
bool find_primitive_id(const QPoint& point,
Tree* aabb_tree,
@ -118,12 +139,13 @@ bool find_primitive_id(const QPoint& point,
Handle& selected_fh,
Point& pt_under)
{
typedef typename CGAL::Kernel_traits<Point>::Kernel Traits;
using Traits = typename CGAL::Kernel_traits<Point>::Kernel;
bool found = false;
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();
//find clicked facet
// find clicked facet
CGAL::qglviewer::Vec dir;
Point ray_origin;
if(viewer->camera()->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
@ -151,38 +173,39 @@ bool find_primitive_id(const QPoint& point,
if(intersections.empty())
return false;
typename Intersections::iterator closest = intersections.begin();
const Point* closest_point =
boost::get<Point>(&closest->first);
for(typename Intersections::iterator
it = boost::next(intersections.begin()),
end = intersections.end();
it != end; ++it)
const Point* closest_point = boost::get<Point>(&closest->first);
for(typename Intersections::iterator it = boost::next(intersections.begin()),
end = intersections.end(); it != end; ++it)
{
if(! closest_point) {
if(! closest_point)
{
closest = it;
}
else {
const Point* it_point =
boost::get<Point>(&it->first);
if(it_point &&
(ray_dir * (*it_point - *closest_point)) < 0)
else
{
const Point* it_point = boost::get<Point>(&it->first);
if(it_point && (ray_dir * (*it_point - *closest_point)) < 0)
{
closest = it;
closest_point = it_point;
}
}
}
if(!closest_point)
return false;
pt_under = Point(point_under.x, point_under.y, point_under.z);
selected_fh = closest->second;
return true;
}
template<typename Mesh, typename Point >
template<typename Mesh, typename Point>
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 Point& pt_under,
const CGAL::qglviewer::Vec& offset,
@ -191,21 +214,21 @@ void compute_displayed_ids(Mesh& mesh,
TextListItem* fitems,
std::vector<TextItem*>* targeted_ids)
{
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
using vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
using halfedge_descriptor = typename boost::graph_traits<Mesh>::halfedge_descriptor;
using edge_descriptor = typename boost::graph_traits<Mesh>::edge_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);
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);
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);
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);
QFont font;
@ -214,70 +237,77 @@ void compute_displayed_ids(Mesh& mesh,
std::vector<vertex_descriptor> displayed_vertices;
std::vector<edge_descriptor> displayed_edges;
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)();
// test the vertices of the closest face
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
{
Point test=Point(get(ppmap, vh).x()+offset.x,
get(ppmap, vh).y()+offset.y,
get(ppmap, vh).z()+offset.z);
Point test=Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if( dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_vertices.push_back(vh);
}
}
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]).z() + offset.z));
//test if we want to erase or not
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]).z() + offset.z));
// test if we want to erase or not
for(TextItem* text_item : *targeted_ids)
{
if(text_item->position() == point)
{
//hide and stop
// hide and stop
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
return;
}
}
deleteIds(viewer, vitems, eitems, fitems, targeted_ids);
// test the midpoint of edges of the closest face
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.y()+offset.y,
test.z()+offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if(dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_edges.clear();
displayed_edges.push_back(edge(e, mesh));
}
}
// test the centroid of the closest face
double x(0), y(0), z(0);
int total(0);
for(vertex_descriptor vh : vertices_around_face(halfedge(selected_fh, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
Point test(x/total+offset.x,
y/total+offset.y,
z/total+offset.z);
Point test(x / total+offset.x,
y / total+offset.y,
z / total+offset.z);
double dist = CGAL::squared_distance(test, pt_under);
if(dist < min_dist){
if(dist < min_dist)
{
min_dist = dist;
displayed_vertices.clear();
displayed_edges.clear();
@ -293,23 +323,21 @@ void compute_displayed_ids(Mesh& mesh,
if(f != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f);
}
for(halfedge_descriptor h : CGAL::halfedges_around_target(halfedge(displayed_vertices[0], mesh), mesh))
{
displayed_edges.push_back(edge(h, mesh));
}
}
else if(!displayed_edges.empty())
{
displayed_vertices.push_back(target(halfedge(displayed_edges[0], mesh), mesh));
displayed_vertices.push_back(target(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
face_descriptor f1(face(halfedge(displayed_edges[0], mesh),mesh)),
f2(face(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
f2(face(opposite(halfedge(displayed_edges[0], mesh), mesh),mesh));
if(f1 != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f1);
if(f2 != boost::graph_traits<Mesh>::null_face())
displayed_faces.push_back(f2);
}
else if(!displayed_faces.empty())
{
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));
}
}
//fill TextItems
// fill TextItems
std::vector<bool> vertex_selection(false);
vertex_selection.resize(num_vertices(mesh));
VKRingPMAP<Mesh> vpmap(&vertex_selection, &mesh);
@ -345,9 +374,7 @@ void compute_displayed_ids(Mesh& mesh,
face_selection.resize(num_faces(mesh));
FKRingPMAP<Mesh> fpmap(&face_selection, &mesh);
for(face_descriptor f_h : displayed_faces)
{
put(fpmap, f_h, true);
}
put(fpmap, f_h, true);
CGAL::expand_face_selection(displayed_faces,
mesh,
1,
@ -356,9 +383,9 @@ void compute_displayed_ids(Mesh& mesh,
for(vertex_descriptor vh : displayed_vertices)
{
Point pos=Point(get(ppmap, vh).x()+offset.x,
get(ppmap, vh).y()+offset.y,
get(ppmap, vh).z()+offset.z);
Point pos = Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
float(pos.z()),
@ -366,13 +393,14 @@ void compute_displayed_ids(Mesh& mesh,
vitems->append(text_item);
targeted_ids->push_back(text_item);
}
for(edge_descriptor e : displayed_edges)
{
halfedge_descriptor h(halfedge(e, mesh));
Point pos=CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
pos = Point(pos.x()+offset.x,
pos.y()+offset.y,
pos.z()+offset.z);
halfedge_descriptor h(halfedge(e, mesh));
Point pos = CGAL::midpoint(get(ppmap, source(h, mesh)),get(ppmap, target(h, mesh)));
pos = Point(pos.x() + offset.x,
pos.y() + offset.y,
pos.z() + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
@ -387,15 +415,15 @@ void compute_displayed_ids(Mesh& mesh,
int total(0);
for(vertex_descriptor vh :vertices_around_face(halfedge(f, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
Point pos(x/total+offset.x,
y/total+offset.y,
z/total+offset.z);
Point pos(x/total + offset.x,
y/total + offset.y,
z/total + offset.z);
TextItem* text_item = new TextItem(float(pos.x()),
float(pos.y()),
float(pos.z()),
@ -408,18 +436,20 @@ template<class Mesh>
bool printVertexIds(const Mesh& mesh,
TextListItem* vitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
typedef typename boost::property_map<Mesh, boost::vertex_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using Point = typename boost::property_traits<Ppmap>::value_type;
using IDmap = typename boost::property_map<Mesh, boost::vertex_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::vertex_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
//fills textItems
// fills textItems
for(typename boost::graph_traits<Mesh>::vertex_descriptor vh : vertices(mesh))
{
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));
}
//add the QList to the render's pool
// add the QList to the render's pool
bool res = true;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -437,10 +468,9 @@ bool printVertexIds(const Mesh& mesh,
renderer->addTextList(vitems);
v->update();
if(vitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -448,13 +478,15 @@ template<class Mesh>
bool printEdgeIds(const Mesh& mesh,
TextListItem* eitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
typedef typename boost::property_map<Mesh, boost::halfedge_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using Point = typename boost::property_traits<Ppmap>::value_type;
using IDmap = typename boost::property_map<Mesh, boost::halfedge_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::halfedge_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
@ -468,7 +500,8 @@ bool printEdgeIds(const Mesh& mesh,
float((p1.z() + p2.z()) / 2 + offset.z),
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;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -476,10 +509,9 @@ bool printEdgeIds(const Mesh& mesh,
renderer->addTextList(eitems);
v->update();
if(eitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -487,15 +519,18 @@ template<class Mesh>
bool printFaceIds(const Mesh& mesh,
TextListItem* fitems)
{
typedef typename boost::property_map<Mesh, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_map<Mesh, boost::face_index_t>::type IDmap;
using Ppmap = typename boost::property_map<Mesh, boost::vertex_point_t>::const_type;
using IDmap = typename boost::property_map<Mesh, boost::face_index_t>::type;
Ppmap ppmap = get(boost::vertex_point, mesh);
IDmap idmap = get(boost::face_index, mesh);
const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
QFont font;
font.setBold(true);
font.setPointSize(POINT_SIZE);
for(typename boost::graph_traits<Mesh>::face_descriptor fh : faces(mesh))
{
double x(0), y(0), z(0);
@ -513,7 +548,8 @@ bool printFaceIds(const Mesh& mesh,
float(z / total + offset.z),
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;
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
{
@ -521,9 +557,7 @@ bool printFaceIds(const Mesh& mesh,
renderer->addTextList(fitems);
v->update();
if(fitems->size() > static_cast<std::size_t>(renderer->getMax_textItems()))
{
res = false;
}
}
return res;
}
@ -535,14 +569,15 @@ int zoomToId(const Mesh& mesh,
typename boost::graph_traits<Mesh>::face_descriptor& selected_fh,
Point& p)
{
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<Mesh>::vertex_descriptor vertex_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 vertex_descriptor = typename boost::graph_traits<Mesh>::vertex_descriptor;
using face_descriptor = typename boost::graph_traits<Mesh>::face_descriptor;
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);
VIDmap vidmap = get(boost::vertex_index, mesh);
@ -555,10 +590,11 @@ int zoomToId(const Mesh& mesh,
if((first != QString("v") &&
first != QString("e") &&
first != QString("f")) ||
!is_int)
!is_int)
{
return 1; //("Input must be of the form [v/e/f][int]"
}
const CGAL::qglviewer::Vec offset = viewer->offset();
typename Traits::Vector_3 normal;
if(first == QString("v"))
@ -567,26 +603,25 @@ int zoomToId(const Mesh& mesh,
for(vertex_descriptor vh : vertices(mesh))
{
std::size_t cur_id = get(vidmap, vh);
if( cur_id == id)
if(cur_id == id)
{
p = Point(get(ppmap, vh).x() + offset.x,
get(ppmap, vh).y() + offset.y,
get(ppmap, vh).z() + offset.z);
typename boost::graph_traits<Mesh>::halfedge_descriptor hf = halfedge(vh, mesh);
if(CGAL::is_border(hf, mesh))
{
hf = opposite(hf, mesh);
}
selected_fh = face(hf, mesh);
normal = CGAL::Polygon_mesh_processing::compute_vertex_normal(vh, mesh);
found = true;
break;
}
}
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"))
{
@ -604,10 +639,10 @@ int zoomToId(const Mesh& mesh,
typename Traits::Vector_3 normal1(0,0,0);
if(!is_border(hf, mesh))
{
normal1= CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh),
mesh);
normal1 = CGAL::Polygon_mesh_processing::compute_face_normal(face(hf,mesh), mesh);
selected_fh = face(hf, mesh);
}
typename Traits::Vector_3 normal2(0,0,0);
if(!is_border(opposite(hf, mesh), mesh))
{
@ -615,15 +650,15 @@ int zoomToId(const Mesh& mesh,
mesh);
selected_fh = face(hf, mesh);
}
normal = 0.5*normal1+0.5*normal2;
normal = 0.5*normal1 + 0.5*normal2;
found = true;
break;
}
}
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"))
{
@ -634,30 +669,30 @@ int zoomToId(const Mesh& mesh,
{
if(get(fidmap, fh) != id)
continue;
for(vertex_descriptor vh : vertices_around_face(halfedge(fh, mesh), mesh))
{
x+=get(ppmap, vh).x();
y+=get(ppmap, vh).y();
z+=get(ppmap, vh).z();
x += get(ppmap, vh).x();
y += get(ppmap, vh).y();
z += get(ppmap, vh).z();
++total;
}
p = Point(x/total + offset.x,
y/total + offset.y,
z/total + offset.z);
normal = CGAL::Polygon_mesh_processing::compute_face_normal(
fh,
mesh);
y/total + offset.y,
z/total + offset.z);
normal = CGAL::Polygon_mesh_processing::compute_face_normal(fh, mesh);
selected_fh = fh;
found = true;
break;
}
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::Vec(-normal.x(), -normal.y(), -normal.z()));
CGAL::qglviewer::Vec(-normal.x(), -normal.y(), -normal.z()));
Point new_pos = p +
0.25*CGAL::qglviewer::Vec(
viewer->camera()->position().x - viewer->camera()->pivotPoint().x,
@ -665,19 +700,69 @@ int zoomToId(const Mesh& mesh,
viewer->camera()->position().z - viewer->camera()->pivotPoint().z)
.norm() * normal ;
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(),
p.y(),
p.z()));
viewer->camera()->setPivotPoint(CGAL::qglviewer::Vec(p.x(), p.y(), p.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]));
.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; //all clear;
}
#endif // ID_PRINTING_H
return 0; // all clear;
}
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

View File

@ -1,234 +1,246 @@
#ifndef TRIANGULATE_PRIMITIVE
#define TRIANGULATE_PRIMITIVE
#ifndef CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
#define CGAL_DEMO_TRIANGULATE_PRIMITIVE_H
#include <CGAL/Three/Scene_item.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Projection_traits_3.h>
#include <CGAL/Three/Scene_item.h>
#include <queue>
#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>
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
{
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
bool is_external;
};
typedef CGAL::Projection_traits_3<Traits> P_traits;
using Vb = CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor, P_traits>;
using Fbb = CGAL::Triangulation_face_base_with_info_2<Face_info, P_traits>;
using Fb = CGAL::Constrained_triangulation_face_base_2<P_traits, Fbb>;
using TDS = CGAL::Triangulation_data_structure_2<Vb, Fb>;
using Itag = CGAL::Exact_predicates_tag;
using CDT = CGAL::Constrained_Delaunay_triangulation_2<P_traits, TDS, Itag>;
typedef CGAL::Triangulation_vertex_base_with_info_2<halfedge_descriptor,
P_traits> Vb;
using Vertex_handle = typename CDT::Vertex_handle;
using Face_handle = typename CDT::Face_handle;
struct Face_info {
typename boost::graph_traits<Mesh>::halfedge_descriptor e[3];
bool is_external;
};
typedef CGAL::Triangulation_face_base_with_info_2<Face_info,
P_traits> Fb1;
typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::Exact_predicates_tag Itag;
struct PointAndId
{
Point point;
Index_type id;
PointAndId() = default;
PointAndId(const Point& point, const Index_type id) : point(point), id(id) { }
};
public:
struct PointAndId {
typename Kernel::Point_3 point;
Index_type id;
};
CDT* cdt;
CGAL::Unique_hash_map<Vertex_handle, Index_type> v2v;
typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits,
TDS,
Itag> CDT;
CDT *cdt;
CGAL::Unique_hash_map<typename CDT::Vertex_handle, Index_type> v2v;
//Constructor
FacetTriangulator(typename boost::graph_traits<Mesh>::face_descriptor fd,
public:
// Constructor
FacetTriangulator(face_descriptor fd,
const Vector& normal,
Mesh *poly,
Mesh* poly,
Vector offset = Vector(0,0,0))
{
std::vector<PointAndId> idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
{
PointAndId idPoint;
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
idPoint.id = source(he_circ, *poly);
idPoints.push_back(idPoint);
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,
source(he_circ, *poly));
}
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,
Mesh *poly,
Mesh* poly,
Vector offset = Vector(0,0,0))
{
std::vector<PointAndId> idPoints;
for(halfedge_descriptor he_circ : halfedges_around_face( halfedge(fd, *poly), *poly))
{
PointAndId idPoint;
idPoint.point = get(boost::vertex_point,*poly,source(he_circ, *poly))+offset;
idPoint.id = source(he_circ, *poly);
idPoints.push_back(idPoint);
std::vector<PointAndId> idPoints;
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,
source(he_circ, *poly));
}
if(!triangulate_with_points(idPoints,more_points, normal))
std::cerr<<"Facet not displayed"<<std::endl;
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr << "Facet not displayed" << std::endl;
}
FacetTriangulator(std::vector<PointAndId > &idPoints,
const Vector& normal)
{
if(!triangulate(idPoints, normal))
std::cerr<<"Facet not displayed"<<std::endl;
}
FacetTriangulator(std::vector<PointAndId > &idPoints,
const std::vector<typename Kernel::Point_3>& more_points,
FacetTriangulator(std::vector<PointAndId>& idPoints,
const Vector& normal)
{
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr<<"Facet not displayed"<<std::endl;
if(!triangulate(idPoints, normal))
std::cerr << "Facet not displayed" << std::endl;
}
FacetTriangulator(std::vector<PointAndId>& idPoints,
const std::vector<Point>& more_points,
const Vector& normal)
{
if(!triangulate_with_points(idPoints, more_points, normal))
std::cerr << "Facet not displayed" << std::endl;
}
~FacetTriangulator()
{
if (cdt )
delete cdt;
if(cdt)
delete cdt;
}
private:
bool triangulate( std::vector<PointAndId > &idPoints,
const Vector& normal )
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;
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)
for(const 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;
}
y += idPoint.point.y();
z += idPoint.point.z();
bool triangulate_with_points( std::vector<PointAndId > &idPoints,
const std::vector<typename Kernel::Point_3>& more_points,
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
for(PointAndId idPoint : idPoints)
{
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())
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 == typename CDT::Vertex_handle()) {
if(first == Vertex_handle())
first = vh;
}
if(previous != nullptr && previous != vh) {
if(previous != nullptr && previous != vh)
{
cdt->insert_constraint(previous, vh);
last_inserted = previous;
}
previous = vh;
previous = vh;
}
}
if(last_inserted == typename CDT::Vertex_handle())
return false;
cdt->insert_constraint(previous, first);
for(typename Kernel::Point_3 point : more_points)
{
cdt->insert(point);
}
// 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;
}
if(last_inserted == Vertex_handle())
return false;
if(previous != first)
cdt->insert_constraint(previous, first);
// 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;
}
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;
}
};
#endif // TRIANGULATE_PRIMITIVE
#endif // CGAL_DEMO_TRIANGULATE_PRIMITIVE_H

View File

@ -58,7 +58,6 @@ namespace Three{
* */
class Scene_interface {
public:
//!A bounding box is a box with each face corresponding to an extremum of its contents.
typedef CGAL::Bbox_3 Bbox;

View File

@ -81,7 +81,7 @@ public:
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_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.
};
typedef CGAL::Bbox_3 Bbox;

View File

@ -70,7 +70,7 @@ public:
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_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
NB_OF_PROGRAMS //! Holds the number of different programs in this enum.
};