Merge branch 'old/gsoc2014-Polyhedron_shortest_path-skiazyk' into gsoc2014-Polyhedron_shortest_path-skiazyk
Conflicts: Documentation/biblio/geom.bib Documentation/doc/Documentation/Doxyfile.in Documentation/doc/Documentation/dependencies Documentation/doc/Documentation/packages.txt Documentation/scripts/generate_how_to_cite.py Polyhedron/demo/Polyhedron/CMakeLists.txt
|
|
@ -60,4 +60,19 @@ public:
|
|||
|
||||
/// @}
|
||||
}; /* end Polyhedron_items_with_id_3 */
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLHelper
|
||||
|
||||
Given a `CGAL::Polyhedron_3` or more generally a model of `HalfedgeDS`,
|
||||
for each simplex type (vertex, halfedge, facet) associates an index from
|
||||
0 to the number of simplices minus 1 to each simplex of `hds`.
|
||||
All simplex types must provide an `id()` method return a reference to a variable
|
||||
that can be assigned a `std::size_t`. For the `Polyhedron_3` type, an item class
|
||||
suited for this use is `CGAL::Polyhedron_items_with_id_3`.
|
||||
*/
|
||||
template<class HalfedgeDS_with_id>
|
||||
void set_halfedgeds_items_id ( HalfedgeDS_with_id& hds );
|
||||
|
||||
} /* end namespace CGAL */
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ user might encounter.
|
|||
- `CGAL::HalfedgeDS_halfedge_max_base_with_id`
|
||||
- `CGAL::HalfedgeDS_face_max_base_with_id`
|
||||
- `CGAL::Polyhedron_items_with_id_3`
|
||||
- `CGAL::set_halfedgeds_items_id()`
|
||||
|
||||
## Helper Functions ##
|
||||
- `CGAL::is_border()`
|
||||
|
|
|
|||
|
|
@ -1396,7 +1396,7 @@ EXTRA_SEARCH_MAPPINGS =
|
|||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_LATEX = YES
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
|
|
|
|||
|
|
@ -151902,3 +151902,25 @@ pages = {179--189}
|
|||
, year = "2014"
|
||||
, url = "http://hal.inria.fr/hal-00943409"
|
||||
}
|
||||
|
||||
@article{XinWang2009improvingchenandhan,
|
||||
author = {Xin, Shi-Qing and Wang, Guo-Jin},
|
||||
title = {Improving Chen and Han's Algorithm on the Discrete Geodesic Problem},
|
||||
journal = {ACM Trans. Graph.},
|
||||
issue_date = {August 2009},
|
||||
volume = {28},
|
||||
number = {4},
|
||||
month = sep,
|
||||
year = {2009},
|
||||
issn = {0730-0301},
|
||||
pages = {104:1--104:8},
|
||||
articleno = {104},
|
||||
numpages = {8},
|
||||
url = {http://doi.acm.org/10.1145/1559755.1559761},
|
||||
doi = {10.1145/1559755.1559761},
|
||||
acmid = {1559761},
|
||||
publisher = {ACM},
|
||||
address = {New York, NY, USA},
|
||||
keywords = {Design and analysis of algorithms, computational geometry, shortest path problems},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,3 +119,4 @@ IMAGE_PATH = ${CMAKE_SOURCE_DIR}/Documentation/doc/Documentation/fig \
|
|||
${CMAKE_SOURCE_DIR}/Stream_support/doc/Stream_support/fig \
|
||||
${CMAKE_SOURCE_DIR}/Surface_modeling/doc/Surface_modeling/fig \
|
||||
${CMAKE_SOURCE_DIR}/Barycentric_coordinates_2/doc/Barycentric_coordinates_2/fig \
|
||||
${CMAKE_SOURCE_DIR}/Surface_mesh_shortest_path/doc/Surface_mesh_shortest_path/fig \
|
||||
|
|
|
|||
|
|
@ -85,4 +85,5 @@ Stream_support
|
|||
Surface_modeling
|
||||
Barycentric_coordinates_2
|
||||
Surface_mesh
|
||||
Surface_mesh_shortest_path
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ h1 {
|
|||
\package_listing{Surface_mesh_simplification}
|
||||
\package_listing{Surface_modeling}
|
||||
\package_listing{Surface_mesh_parameterization}
|
||||
\package_listing{Surface_mesh_shortest_path}
|
||||
\package_listing{Ridges_3}
|
||||
\package_listing{Jet_fitting_3}
|
||||
\package_listing{Point_set_processing_3}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ def protect_upper_case(title):
|
|||
return title.replace("dD","{dD}").replace("2D","{2D}").replace("3D","{3D}").replace("CGAL","{CGAL}").replace("Qt","{Qt}").replace("Boost","{Boost}")
|
||||
|
||||
def protect_accentuated_letters(authors):
|
||||
res=authors.replace(u"é",r"{\'e}").replace(u"ä",r"{\"a}").replace(u"ö",r"{\"o}").replace(u"ñ",r"{\~n}").replace(u"ã",r"{\~a}").replace(u"ë",r"{\"e}").replace("%","")
|
||||
res=authors.replace(u"é",r"{\'e}").replace(u"è",r"{\`e}").replace(u"É",r"{\'E}").replace(u"ä",r"{\"a}").replace(u"ö",r"{\"o}").replace(u"ñ",r"{\~n}").replace(u"ã",r"{\~a}").replace(u"ë",r"{\"e}").replace("%","")
|
||||
try:
|
||||
res.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
|
|
|
|||
|
|
@ -118,6 +118,18 @@ and <code>src/</code> directories).
|
|||
|
||||
<!-- Installation (and general changes) -->
|
||||
<!-- New packages -->
|
||||
<h3>Triangulated Surface Mesh Shortest Paths (new package)</h3>
|
||||
<ul>
|
||||
<li>
|
||||
The package provides methods for computing shortest path on
|
||||
triangulated surface meshes. Given a set of source points
|
||||
on the surface, this package provides a data structure that
|
||||
can efficiently provides the shortest path from any point on
|
||||
the surface to the sources points.
|
||||
There is no restriction on the genus or the number of connnected
|
||||
components of the mesh.
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Major and breaking changes -->
|
||||
<!-- Arithmetic and Algebra -->
|
||||
<!-- Combinatorial Algorithms -->
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
qt4_wrap_ui( segmentationUI_FILES Mesh_segmentation_widget.ui)
|
||||
qt4_wrap_ui( selectionUI_FILES Selection_widget.ui)
|
||||
qt4_wrap_ui( funcUI_FILES Function_dialog.ui )
|
||||
qt4_wrap_ui( shortestPathUI_FILES Shortest_path_widget.ui )
|
||||
|
||||
qt4_generate_moc( "MainWindow.h" "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp" )
|
||||
qt4_generate_moc( "File_loader_dialog.h" "${CMAKE_CURRENT_BINARY_DIR}/File_loader_dialog_moc.cpp" )
|
||||
|
|
@ -137,6 +138,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
Scene_polyhedron_item_decorator.cpp
|
||||
Scene_polyhedron_selection_item.cpp
|
||||
Scene_polyhedron_item_k_ring_selection.cpp
|
||||
Scene_polyhedron_shortest_path_item.cpp
|
||||
)
|
||||
qt4_automoc( Scene_implicit_function_item.cpp )
|
||||
|
||||
|
|
@ -209,6 +211,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
add_item(scene_polyhedron_selection_item Scene_polyhedron_selection_item.cpp Scene_polyhedron_selection_item.moc)
|
||||
target_link_libraries(scene_polyhedron_selection_item scene_polyhedron_item_decorator scene_polyhedron_item_k_ring_selection)
|
||||
|
||||
add_item(scene_polyhedron_shortest_path_item Scene_polyhedron_shortest_path_item.cpp Scene_polyhedron_shortest_path_item.moc)
|
||||
target_link_libraries(scene_polyhedron_shortest_path_item scene_polyhedron_item_decorator scene_polyhedron_item scene_polylines_item)
|
||||
|
||||
if(EIGEN3_FOUND )
|
||||
add_item(scene_textured_polyhedron_item Scene_textured_polyhedron_item.cpp texture.cpp Scene_textured_polyhedron_item.moc)
|
||||
endif()
|
||||
|
|
@ -456,6 +461,9 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
|
|||
|
||||
polyhedron_demo_plugin(selection_plugin Polyhedron_demo_selection_plugin ${selectionUI_FILES})
|
||||
target_link_libraries(selection_plugin scene_polyhedron_selection_item scene_points_with_normal_item scene_polylines_item)
|
||||
|
||||
polyhedron_demo_plugin(shortest_path_plugin Polyhedron_demo_shortest_path_plugin ${shortestPathUI_FILES})
|
||||
target_link_libraries(shortest_path_plugin scene_polyhedron_item scene_polylines_item scene_polyhedron_selection_item scene_polyhedron_shortest_path_item scene_basic_objects)
|
||||
#
|
||||
# Exporting
|
||||
#
|
||||
|
|
|
|||
|
|
@ -0,0 +1,305 @@
|
|||
#include "Polyhedron_demo_plugin_helper.h"
|
||||
#include "Polyhedron_demo_plugin_interface.h"
|
||||
|
||||
#include "Messages_interface.h"
|
||||
#include "Scene_polyhedron_item.h"
|
||||
#include "Scene_polylines_item.h"
|
||||
#include "Scene_polyhedron_selection_item.h"
|
||||
#include "Scene_polyhedron_shortest_path_item.h"
|
||||
#include "Polyhedron_type.h"
|
||||
#include "Scene.h"
|
||||
#include "ui_Shortest_path_widget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QInputDialog>
|
||||
#include <QTime>
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QDockWidget>
|
||||
//#include <QtConcurrentRun>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
class Polyhedron_demo_shortest_path_plugin :
|
||||
public QObject,
|
||||
public Polyhedron_demo_plugin_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(Polyhedron_demo_plugin_interface)
|
||||
private:
|
||||
|
||||
typedef boost::property_map<Polyhedron, boost::vertex_index_t>::type VertexIndexMap;
|
||||
typedef boost::property_map<Polyhedron, CGAL::halfedge_index_t>::type HalfedgeIndexMap;
|
||||
typedef boost::property_map<Polyhedron, CGAL::face_index_t>::type FaceIndexMap;
|
||||
typedef boost::property_map<Polyhedron, CGAL::vertex_point_t>::type VertexPointMap;
|
||||
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron> Surface_mesh_shortest_path_traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Surface_mesh_shortest_path_traits, VertexIndexMap, HalfedgeIndexMap, FaceIndexMap, VertexPointMap> Surface_mesh_shortest_path;
|
||||
|
||||
struct ShortestPathsPointsVisitor
|
||||
{
|
||||
typedef std::vector<Surface_mesh_shortest_path::Point_3> Container;
|
||||
Container& m_container;
|
||||
|
||||
ShortestPathsPointsVisitor(Container& container)
|
||||
: m_container(container)
|
||||
{
|
||||
}
|
||||
|
||||
void point(const Surface_mesh_shortest_path::Point_3& point)
|
||||
{
|
||||
std::cout << point << std::endl;
|
||||
m_container.push_back(point);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<Scene_polyhedron_item*, Scene_polyhedron_shortest_path_item* > Shortest_paths_map;
|
||||
|
||||
public:
|
||||
|
||||
QList<QAction*> actions() const
|
||||
{
|
||||
return QList<QAction*>() << actionMakeShortestPaths;
|
||||
}
|
||||
|
||||
bool applicable(QAction*) const
|
||||
{
|
||||
return qobject_cast<Scene_polyhedron_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
}
|
||||
|
||||
void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface* messages)
|
||||
{
|
||||
this->scene = scene_interface;
|
||||
this->mw = mainWindow;
|
||||
this->m_messages = messages;
|
||||
|
||||
dock_widget = new QDockWidget("Shortest path", mw);
|
||||
dock_widget->setVisible(false);
|
||||
|
||||
ui_widget.setupUi(dock_widget);
|
||||
add_dock_widget(dock_widget);
|
||||
|
||||
connect(ui_widget.Selection_type_combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(on_Selection_type_combo_box_changed(int)));
|
||||
connect(ui_widget.Primitives_type_combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(on_Primitives_type_combo_box_changed(int)));
|
||||
|
||||
actionMakeShortestPaths = new QAction("Make Shortest Path", this->mw);
|
||||
|
||||
connect(actionMakeShortestPaths, SIGNAL(triggered()), this, SLOT(on_actionMakeShortestPaths_triggered()));
|
||||
|
||||
Scene* trueScene = dynamic_cast<Scene*>(scene_interface);
|
||||
// This is for later
|
||||
if(trueScene) {
|
||||
connect(trueScene, SIGNAL(itemAboutToBeDestroyed(Scene_item*)), this, SLOT(item_about_to_be_destroyed(Scene_item*)));
|
||||
connect(trueScene, SIGNAL(newItem(int)), this, SLOT(new_item(int)));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Selection_mode get_selection_mode() const;
|
||||
Scene_polyhedron_shortest_path_item::Primitives_mode get_primitives_mode() const;
|
||||
|
||||
void check_and_set_ids(Polyhedron* polyhedron);
|
||||
|
||||
public Q_SLOTS:
|
||||
void on_actionMakeShortestPaths_triggered();
|
||||
void on_Selection_type_combo_box_changed(int index);
|
||||
void on_Primitives_type_combo_box_changed(int index);
|
||||
void new_item(int index);
|
||||
void item_about_to_be_destroyed(Scene_item* scene_item);
|
||||
|
||||
private:
|
||||
Shortest_paths_map m_shortestPathsMap;
|
||||
|
||||
Messages_interface* m_messages;
|
||||
QAction* actionComputeShortestPath;
|
||||
QAction* actionMakeShortestPaths;
|
||||
QDockWidget* dock_widget;
|
||||
Ui::Shortest_path ui_widget;
|
||||
};
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Selection_mode Polyhedron_demo_shortest_path_plugin::get_selection_mode() const
|
||||
{
|
||||
return (Scene_polyhedron_shortest_path_item::Selection_mode) ui_widget.Selection_type_combo_box->currentIndex();
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Primitives_mode Polyhedron_demo_shortest_path_plugin::get_primitives_mode() const
|
||||
{
|
||||
return (Scene_polyhedron_shortest_path_item::Primitives_mode) ui_widget.Primitives_type_combo_box->currentIndex();
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::item_about_to_be_destroyed(Scene_item* sceneItem)
|
||||
{
|
||||
// if polyhedron item
|
||||
Scene_polyhedron_item* polyhedronItem = qobject_cast<Scene_polyhedron_item*>(sceneItem);
|
||||
if(polyhedronItem)
|
||||
{
|
||||
Shortest_paths_map::iterator found = m_shortestPathsMap.find(polyhedronItem);
|
||||
|
||||
if (found != m_shortestPathsMap.end())
|
||||
{
|
||||
Scene_polyhedron_shortest_path_item* shortestPathItem = found->second;
|
||||
m_shortestPathsMap.erase(found);
|
||||
scene->erase(scene->item_id(shortestPathItem));
|
||||
}
|
||||
}
|
||||
|
||||
// if polyhedron selection item
|
||||
Scene_polyhedron_shortest_path_item* shortestPathItem = qobject_cast<Scene_polyhedron_shortest_path_item*>(sceneItem);
|
||||
if(shortestPathItem)
|
||||
{
|
||||
Scene_polyhedron_item* polyhedronItem = shortestPathItem->polyhedron_item();
|
||||
Shortest_paths_map::iterator found = m_shortestPathsMap.find(polyhedronItem);
|
||||
|
||||
if (found != m_shortestPathsMap.end())
|
||||
{
|
||||
m_shortestPathsMap.erase(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::new_item(int itemIndex)
|
||||
{
|
||||
Scene_polyhedron_shortest_path_item* item = qobject_cast<Scene_polyhedron_shortest_path_item*>(scene->item(itemIndex));
|
||||
|
||||
if (!item)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(item->polyhedron_item() == NULL)
|
||||
{
|
||||
Scene_polyhedron_item* polyhedronItem = get_selected_item<Scene_polyhedron_item>();
|
||||
|
||||
if(!polyhedronItem)
|
||||
{
|
||||
CGAL_assertion(item->polyhedron_item() == NULL); // which means it is coming from selection_io loader
|
||||
this->m_messages->information(tr("Error: please select corresponding polyhedron item from Geometric Objects list."));
|
||||
scene->erase(itemIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!item->deferred_load(polyhedronItem, this->scene, this->m_messages, this->mw))
|
||||
{
|
||||
this->m_messages->information("Error: loading selection item is not successful!");
|
||||
scene->erase(itemIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
check_and_set_ids(item->polyhedron_item()->polyhedron());
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Selection_mode selectionMode = get_selection_mode(); // Scene_polyhedron_shortest_path_item::INSERT_POINTS_MODE;
|
||||
|
||||
std::cout << "Selection mode: " << selectionMode << std::endl;
|
||||
|
||||
item->set_selection_mode(selectionMode);
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Primitives_mode primitivesMode = get_primitives_mode(); // Scene_polyhedron_shortest_path_item::FACE_MODE;
|
||||
|
||||
std::cout << "Primitives mode: " << primitivesMode << std::endl;
|
||||
|
||||
item->set_primitives_mode(primitivesMode);
|
||||
|
||||
item->setRenderingMode(Flat);
|
||||
|
||||
if(item->name() == "unamed")
|
||||
{
|
||||
item->setName(tr("%1 (shortest path computation item)").arg(item->polyhedron_item()->name()));
|
||||
}
|
||||
|
||||
m_shortestPathsMap.insert(std::make_pair(item->polyhedron_item(), item));
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::on_actionMakeShortestPaths_triggered()
|
||||
{
|
||||
Scene_polyhedron_item* polyhedronItem = get_selected_item<Scene_polyhedron_item>();
|
||||
|
||||
if (polyhedronItem)
|
||||
{
|
||||
if (m_shortestPathsMap.find(polyhedronItem) == m_shortestPathsMap.end())
|
||||
{
|
||||
dock_widget->show();
|
||||
dock_widget->raise();
|
||||
// The other parts of initialization will be handled by the 'new_item' callback
|
||||
scene->addItem(new Scene_polyhedron_shortest_path_item(polyhedronItem, this->scene, this->m_messages, this->mw));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_messages->warning(tr("A shortest path item for this polyhedron already exists (only one allowed per for now)"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_messages->warning("No polyhedron selected.");
|
||||
}
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::on_Selection_type_combo_box_changed(int index)
|
||||
{
|
||||
std::cout << "Selection mode changed: " << index << std::endl;
|
||||
|
||||
for (Shortest_paths_map::iterator it = m_shortestPathsMap.begin(); it != m_shortestPathsMap.end(); ++it)
|
||||
{
|
||||
it->second->set_selection_mode(get_selection_mode());
|
||||
}
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::on_Primitives_type_combo_box_changed(int index)
|
||||
{
|
||||
std::cout << "Primitives mode changed: " << index << std::endl;
|
||||
|
||||
for (Shortest_paths_map::iterator it = m_shortestPathsMap.begin(); it != m_shortestPathsMap.end(); ++it)
|
||||
{
|
||||
it->second->set_primitives_mode(get_primitives_mode());
|
||||
}
|
||||
}
|
||||
|
||||
void Polyhedron_demo_shortest_path_plugin::check_and_set_ids(Polyhedron* polyhedron)
|
||||
{
|
||||
Polyhedron::Vertex_iterator testVertex1 = polyhedron->vertices_begin();
|
||||
Polyhedron::Vertex_iterator testVertex2 = ++polyhedron->vertices_begin();
|
||||
|
||||
if(testVertex1->id() == testVertex2->id())
|
||||
{
|
||||
std::size_t vertexId = 0;
|
||||
for(Polyhedron::Vertex_iterator currentVertex = polyhedron->vertices_begin();
|
||||
currentVertex != polyhedron->vertices_end(); ++currentVertex, ++vertexId)
|
||||
{
|
||||
currentVertex->id() = vertexId;
|
||||
}
|
||||
}
|
||||
|
||||
Polyhedron::Halfedge_iterator testHalfedge1 = polyhedron->halfedges_begin();
|
||||
Polyhedron::Halfedge_iterator testHalfedge2 = ++polyhedron->halfedges_begin();
|
||||
|
||||
if (testHalfedge1->id() == testHalfedge2->id())
|
||||
{
|
||||
std::size_t halfedgeId = 0;
|
||||
for(Polyhedron::Halfedge_iterator currentHalfedge = polyhedron->halfedges_begin();
|
||||
currentHalfedge != polyhedron->halfedges_end(); ++currentHalfedge, ++halfedgeId)
|
||||
{
|
||||
currentHalfedge->id() = halfedgeId;
|
||||
}
|
||||
}
|
||||
|
||||
Polyhedron::Facet_iterator testFacet1 = polyhedron->facets_begin();
|
||||
Polyhedron::Facet_iterator testFacet2 = ++polyhedron->facets_begin();
|
||||
|
||||
if (testFacet1->id() == testFacet2->id())
|
||||
{
|
||||
std::size_t facetId = 0;
|
||||
for(Polyhedron::Facet_iterator currentFacet = polyhedron->facets_begin();
|
||||
currentFacet != polyhedron->facets_end(); ++currentFacet, ++facetId)
|
||||
{
|
||||
currentFacet->id() = facetId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(Polyhedron_demo_shortest_path_plugin, Polyhedron_demo_shortest_path_plugin)
|
||||
|
||||
#include "Polyhedron_demo_shortest_path_plugin.moc"
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
#include "Scene_polyhedron_shortest_path_item.h"
|
||||
|
||||
#include "Scene_polylines_item.h"
|
||||
|
||||
#include <vector>
|
||||
#include <Qt>
|
||||
#include <QKeySequence>
|
||||
#include <fstream>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/function_objects.h>
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Scene_polyhedron_shortest_path_item()
|
||||
: Scene_polyhedron_item_decorator(NULL, false)
|
||||
, m_shortestPaths(NULL)
|
||||
, m_isTreeCached(false)
|
||||
, m_shiftHeld(false)
|
||||
{
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Scene_polyhedron_shortest_path_item(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow)
|
||||
: Scene_polyhedron_item_decorator(polyhedronItem, false)
|
||||
, m_shortestPaths(NULL)
|
||||
, m_isTreeCached(false)
|
||||
, m_shiftHeld(false)
|
||||
{
|
||||
initialize(polyhedronItem, sceneInterface, messages, mainWindow);
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::~Scene_polyhedron_shortest_path_item()
|
||||
{
|
||||
deinitialize();
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::supportsRenderingMode(RenderingMode m) const
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case Points:
|
||||
return true;
|
||||
case PointsPlusNormals:
|
||||
return true;
|
||||
case Wireframe:
|
||||
return true;
|
||||
case Flat:
|
||||
return true;
|
||||
case FlatPlusEdges:
|
||||
return true;
|
||||
case Gouraud:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::draw() const
|
||||
{
|
||||
if (supportsRenderingMode(renderingMode()))
|
||||
{
|
||||
draw_points();
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::draw(Viewer_interface*) const
|
||||
{
|
||||
draw();
|
||||
}
|
||||
|
||||
// Wireframe OpenGL drawing
|
||||
void Scene_polyhedron_shortest_path_item::draw_edges() const
|
||||
{
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::draw_edges(Viewer_interface*) const
|
||||
{
|
||||
draw_edges();
|
||||
}
|
||||
// Points OpenGL drawing
|
||||
void Scene_polyhedron_shortest_path_item::draw_points() const
|
||||
{
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
CGAL::GL::Point_size point_size;
|
||||
point_size.set_point_size(5);
|
||||
CGALglcolor(Qt::green);
|
||||
|
||||
::glBegin(GL_POINTS);
|
||||
|
||||
for(Surface_mesh_shortest_path::Source_point_iterator it = m_shortestPaths->source_points_begin(); it != m_shortestPaths->source_points_end(); ++it)
|
||||
{
|
||||
const Point_3& p = m_shortestPaths->point(it->first, it->second);
|
||||
::glVertex3d(p.x(), p.y(), p.z());
|
||||
}
|
||||
|
||||
::glEnd();
|
||||
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::draw_points(Viewer_interface*) const
|
||||
{
|
||||
draw_points();
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item* Scene_polyhedron_shortest_path_item::clone() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::set_selection_mode(Selection_mode mode)
|
||||
{
|
||||
m_selectionMode = mode;
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Selection_mode Scene_polyhedron_shortest_path_item::get_selection_mode() const
|
||||
{
|
||||
return m_selectionMode;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::set_primitives_mode(Primitives_mode mode)
|
||||
{
|
||||
m_primitivesMode = mode;
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Primitives_mode Scene_polyhedron_shortest_path_item::get_primitives_mode() const
|
||||
{
|
||||
return m_primitivesMode;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::recreate_shortest_path_object()
|
||||
{
|
||||
if (m_shortestPaths)
|
||||
{
|
||||
delete m_shortestPaths;
|
||||
}
|
||||
|
||||
m_shortestPaths = new Surface_mesh_shortest_path(*polyhedron(),
|
||||
CGAL::get(boost::vertex_index, *polyhedron()),
|
||||
CGAL::get(CGAL::halfedge_index, *polyhedron()),
|
||||
CGAL::get(CGAL::face_index, *polyhedron()),
|
||||
CGAL::get(CGAL::vertex_point, *polyhedron()));
|
||||
|
||||
//m_shortestPaths->m_debugOutput = true;
|
||||
|
||||
m_isTreeCached = false;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::ensure_aabb_object()
|
||||
{
|
||||
if (!m_isTreeCached)
|
||||
{
|
||||
m_shortestPaths->build_aabb_tree(m_aabbTree);
|
||||
m_isTreeCached = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::ensure_shortest_paths_tree()
|
||||
{
|
||||
if (!m_shortestPaths->changed_since_last_build())
|
||||
{
|
||||
m_messages->information(tr("Recomputing shortest paths tree..."));
|
||||
m_shortestPaths->build_sequence_tree();
|
||||
m_messages->information(tr("Done."));
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::poly_item_changed()
|
||||
{
|
||||
recreate_shortest_path_object();
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::changed()
|
||||
{
|
||||
// Supposedly, this is not the correct 'changed' callback to use
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::get_mouse_ray(QMouseEvent* mouseEvent, Ray_3& outRay)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin();
|
||||
qglviewer::Camera* camera = viewer->camera();
|
||||
const qglviewer::Vec point = camera->pointUnderPixel(mouseEvent->pos(), found);
|
||||
|
||||
if(found)
|
||||
{
|
||||
const qglviewer::Vec orig = camera->position();
|
||||
outRay = Ray_3(Point_3(orig.x, orig.y, orig.z), Point_3(point.x, point.y, point.z));
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::remove_nearest_point(const Face_location& faceLocation)
|
||||
{
|
||||
Surface_mesh_shortest_path_traits::Compute_squared_distance_3 computeSquaredDistance3;
|
||||
|
||||
const Point_3 pickLocation = m_shortestPaths->point(faceLocation.first, faceLocation.second);
|
||||
|
||||
Surface_mesh_shortest_path::Source_point_iterator found = m_shortestPaths->source_points_end();
|
||||
FT minDistance(0.0);
|
||||
const FT thresholdDistance = FT(0.4);
|
||||
|
||||
for (Surface_mesh_shortest_path::Source_point_iterator it = m_shortestPaths->source_points_begin(); it != m_shortestPaths->source_points_end(); ++it)
|
||||
{
|
||||
Point_3 sourceLocation = m_shortestPaths->point(it->first, it->second);
|
||||
FT distance = computeSquaredDistance3(sourceLocation, pickLocation);
|
||||
|
||||
if ((found == m_shortestPaths->source_points_end() && distance <= thresholdDistance) || distance < minDistance)
|
||||
{
|
||||
found = it;
|
||||
minDistance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != m_shortestPaths->source_points_end())
|
||||
{
|
||||
m_shortestPaths->remove_source_point(found);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::get_as_edge_point(Scene_polyhedron_shortest_path_item::Face_location& inOutLocation)
|
||||
{
|
||||
size_t minIndex = 0;
|
||||
FT minCoord(inOutLocation.second[0]);
|
||||
|
||||
for (size_t i = 1; i < 3; ++i)
|
||||
{
|
||||
if (minCoord > inOutLocation.second[i])
|
||||
{
|
||||
minIndex = i;
|
||||
minCoord = inOutLocation.second[i];
|
||||
}
|
||||
}
|
||||
|
||||
// The nearest edge is that of the two non-minimal barycentric coordinates
|
||||
size_t nearestEdge[2];
|
||||
size_t current = 0;
|
||||
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
if (i != minIndex)
|
||||
{
|
||||
nearestEdge[current] = i;
|
||||
++current;
|
||||
}
|
||||
}
|
||||
|
||||
Construct_barycentric_coordinate construct_barycentric_coordinate;
|
||||
|
||||
Point_3 trianglePoints[3] = {
|
||||
m_shortestPaths->point(inOutLocation.first, construct_barycentric_coordinate(FT(1.0), FT(0.0), FT(0.0))),
|
||||
m_shortestPaths->point(inOutLocation.first, construct_barycentric_coordinate(FT(0.0), FT(1.0), FT(0.0))),
|
||||
m_shortestPaths->point(inOutLocation.first, construct_barycentric_coordinate(FT(0.0), FT(0.0), FT(1.0))),
|
||||
};
|
||||
|
||||
CGAL::Surface_mesh_shortest_paths_3::Parametric_distance_along_segment_3<Surface_mesh_shortest_path_traits> parametricDistanceSegment3;
|
||||
|
||||
Point_3 trianglePoint = m_shortestPaths->point(inOutLocation.first, inOutLocation.second);
|
||||
|
||||
FT distanceAlongSegment = parametricDistanceSegment3(trianglePoints[nearestEdge[0]], trianglePoints[nearestEdge[1]], trianglePoint);
|
||||
|
||||
FT coords[3] = { FT(0.0), FT(0.0), FT(0.0), };
|
||||
|
||||
coords[nearestEdge[1]] = distanceAlongSegment;
|
||||
coords[nearestEdge[0]] = FT(1.0) - distanceAlongSegment;
|
||||
|
||||
inOutLocation.second = construct_barycentric_coordinate(coords[0], coords[1], coords[2]);
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::get_as_vertex_point(Scene_polyhedron_shortest_path_item::Face_location& inOutLocation)
|
||||
{
|
||||
size_t maxIndex = 0;
|
||||
FT maxCoord(inOutLocation.second[0]);
|
||||
|
||||
for (size_t i = 1; i < 3; ++i)
|
||||
{
|
||||
if (inOutLocation.second[i] > maxCoord)
|
||||
{
|
||||
maxIndex = i;
|
||||
maxCoord = inOutLocation.second[i];
|
||||
}
|
||||
}
|
||||
|
||||
FT coords[3] = { FT(0.0), FT(0.0), FT(0.0), };
|
||||
coords[maxIndex] = FT(1.0);
|
||||
|
||||
Construct_barycentric_coordinate construct_barycentric_coordinate;
|
||||
inOutLocation.second = construct_barycentric_coordinate(coords[0], coords[1], coords[2]);
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::run_point_select(const Ray_3& ray)
|
||||
{
|
||||
ensure_aabb_object();
|
||||
|
||||
Face_location faceLocation = m_shortestPaths->locate(ray, m_aabbTree);
|
||||
|
||||
if (faceLocation.first == GraphTraits::null_face())
|
||||
{
|
||||
m_messages->information(tr("Shortest Paths: No face under cursor."));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_messages->information(tr("Shortest Paths: Selected Face: %1; Barycentric coordinates: %2 %3 %4")
|
||||
.arg(faceLocation.first->id())
|
||||
.arg(double(faceLocation.second[0]))
|
||||
.arg(double(faceLocation.second[1]))
|
||||
.arg(double(faceLocation.second[2])));
|
||||
switch (m_selectionMode)
|
||||
{
|
||||
case INSERT_POINTS_MODE:
|
||||
switch (m_primitivesMode)
|
||||
{
|
||||
case VERTEX_MODE:
|
||||
get_as_vertex_point(faceLocation);
|
||||
m_shortestPaths->add_source_point(faceLocation.first, faceLocation.second);
|
||||
break;
|
||||
case EDGE_MODE:
|
||||
get_as_edge_point(faceLocation);
|
||||
m_shortestPaths->add_source_point(faceLocation.first, faceLocation.second);
|
||||
break;
|
||||
case FACE_MODE:
|
||||
m_shortestPaths->add_source_point(faceLocation.first, faceLocation.second);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case REMOVE_POINTS_MODE:
|
||||
remove_nearest_point(faceLocation);
|
||||
break;
|
||||
case SHORTEST_PATH_MODE:
|
||||
switch (m_primitivesMode)
|
||||
{
|
||||
case VERTEX_MODE:
|
||||
get_as_vertex_point(faceLocation);
|
||||
break;
|
||||
case EDGE_MODE:
|
||||
get_as_edge_point(faceLocation);
|
||||
break;
|
||||
case FACE_MODE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_shortestPaths->number_of_source_points() > 0)
|
||||
{
|
||||
ensure_shortest_paths_tree();
|
||||
|
||||
Scene_polylines_item* polylines = new Scene_polylines_item();
|
||||
|
||||
polylines->polylines.push_back(Scene_polylines_item::Polyline());
|
||||
|
||||
m_messages->information(tr("Computing shortest path polyline..."));
|
||||
|
||||
QTime time;
|
||||
time.start();
|
||||
//~ m_shortestPaths->m_debugOutput=true;
|
||||
m_shortestPaths->shortest_path_points_to_source_points(faceLocation.first, faceLocation.second, std::back_inserter(polylines->polylines.back()));
|
||||
std::cout << "ok (" << time.elapsed() << " ms)" << std::endl;
|
||||
|
||||
polylines->setName(tr("%1 (shortest path)").arg(polyhedron_item()->name()));
|
||||
polylines->setColor(Qt::red);
|
||||
|
||||
this->m_sceneInterface->addItem(polylines);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_messages->warning(tr("No source points to compute shortest paths from."));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::eventFilter(QObject* /*target*/, QEvent* event)
|
||||
{
|
||||
if(event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
|
||||
{
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
||||
Qt::KeyboardModifiers modifiers = keyEvent->modifiers();
|
||||
m_shiftHeld = modifiers.testFlag(Qt::ShiftModifier);
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress && m_shiftHeld)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if(mouseEvent->button() == Qt::LeftButton)
|
||||
{
|
||||
Ray_3 mouseRay;
|
||||
|
||||
if (get_mouse_ray(mouseEvent, mouseRay))
|
||||
{
|
||||
if (run_point_select(mouseRay))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::load(const std::string& file_name)
|
||||
{
|
||||
m_deferredLoadFilename = file_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::deferred_load(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow)
|
||||
{
|
||||
initialize(polyhedronItem, sceneInterface, messages, mainWindow);
|
||||
|
||||
std::ifstream inFile(m_deferredLoadFilename.c_str());
|
||||
|
||||
if (!inFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_shortestPaths->clear();
|
||||
|
||||
std::vector<face_descriptor> listOfFaces;
|
||||
listOfFaces.reserve(CGAL::num_faces(*polyhedron()));
|
||||
face_iterator current, end;
|
||||
for (boost::tie(current, end) = CGAL::faces(*polyhedron()); current != end; ++current)
|
||||
{
|
||||
listOfFaces.push_back(*current);
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::size_t faceId;
|
||||
Barycentric_coordinate location;
|
||||
Construct_barycentric_coordinate construct_barycentric_coordinate;
|
||||
|
||||
while (std::getline(inFile, line))
|
||||
{
|
||||
std::istringstream lineStream(line);
|
||||
FT coords[3];
|
||||
lineStream >> faceId >> coords[0] >> coords[1] >> coords[2];
|
||||
|
||||
location = construct_barycentric_coordinate(coords[0], coords[1], coords[2]);
|
||||
|
||||
// std::cout << "Read in face: " << faceId << " , " << location << std::endl;
|
||||
|
||||
m_shortestPaths->add_source_point(listOfFaces[faceId], location);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::save(const std::string& file_name) const
|
||||
{
|
||||
std::ofstream out(file_name.c_str());
|
||||
|
||||
if (!out)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(Surface_mesh_shortest_path::Source_point_iterator it = m_shortestPaths->source_points_begin(); it != m_shortestPaths->source_points_end(); ++it)
|
||||
{
|
||||
// std::cout << "Output face location: " << it->first->id() << " , " << it->second << std::endl;
|
||||
out << it->first->id() << " " << it->second[0] << " " << it->second[1] << " " << it->second[3] << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::initialize(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow)
|
||||
{
|
||||
this->m_mainWindow = mainWindow;
|
||||
this->m_messages = messages;
|
||||
this->poly_item = polyhedronItem;
|
||||
this->m_sceneInterface = sceneInterface;
|
||||
|
||||
connect(polyhedronItem, SIGNAL(item_is_about_to_be_changed()), this, SLOT(poly_item_changed()));
|
||||
|
||||
QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin();
|
||||
viewer->installEventFilter(this);
|
||||
m_mainWindow->installEventFilter(this);
|
||||
|
||||
recreate_shortest_path_object();
|
||||
}
|
||||
|
||||
void Scene_polyhedron_shortest_path_item::deinitialize()
|
||||
{
|
||||
if (m_shortestPaths)
|
||||
{
|
||||
delete m_shortestPaths;
|
||||
}
|
||||
|
||||
this->poly_item = NULL;
|
||||
this->m_sceneInterface = NULL;
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::isFinite() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Scene_polyhedron_shortest_path_item::isEmpty() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Scene_polyhedron_shortest_path_item::Bbox Scene_polyhedron_shortest_path_item::bbox() const
|
||||
{
|
||||
return polyhedron_item()->bbox();
|
||||
}
|
||||
|
||||
QString Scene_polyhedron_shortest_path_item::toolTip() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
#include "Scene_polyhedron_shortest_path_item.moc"
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
#ifndef SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_H
|
||||
#define SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_H
|
||||
|
||||
#include "Scene_polyhedron_shortest_path_item_config.h"
|
||||
#include "Scene_polyhedron_item_decorator.h"
|
||||
#include "Scene_interface.h"
|
||||
#include "Messages_interface.h"
|
||||
|
||||
#include "Polyhedron_type.h"
|
||||
#include "Kernel_type.h"
|
||||
|
||||
#include "opengl_tools.h"
|
||||
#include <CGAL/gl_render.h>
|
||||
|
||||
#include <QGLViewer/qglviewer.h>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QMainWindow>
|
||||
#include <QObject>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <CGAL/Surface_mesh_shortest_path.h>
|
||||
#endif
|
||||
|
||||
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_tree.h>
|
||||
|
||||
#include <boost/current_function.hpp>
|
||||
|
||||
class SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_EXPORT Scene_polyhedron_shortest_path_item : public Scene_polyhedron_item_decorator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Polyhedron_demo_shortest_path_plugin;
|
||||
|
||||
public:
|
||||
typedef Scene_interface::Bbox Bbox;
|
||||
|
||||
typedef boost::property_map<Polyhedron, CGAL::vertex_point_t>::type VertexPointMap;
|
||||
|
||||
typedef boost::graph_traits<Polyhedron> GraphTraits;
|
||||
typedef GraphTraits::face_descriptor face_descriptor;
|
||||
typedef GraphTraits::face_iterator face_iterator;
|
||||
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron> Surface_mesh_shortest_path_traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Surface_mesh_shortest_path_traits> Surface_mesh_shortest_path;
|
||||
typedef Surface_mesh_shortest_path::Face_location Face_location;
|
||||
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron, VertexPointMap> AABB_face_graph_primitive;
|
||||
typedef CGAL::AABB_traits<Kernel, AABB_face_graph_primitive> AABB_face_graph_traits;
|
||||
typedef CGAL::AABB_tree<AABB_face_graph_traits> AABB_face_graph_tree;
|
||||
|
||||
typedef Surface_mesh_shortest_path_traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef Surface_mesh_shortest_path_traits::Construct_barycentric_coordinate Construct_barycentric_coordinate;
|
||||
typedef Surface_mesh_shortest_path_traits::Ray_3 Ray_3;
|
||||
typedef Surface_mesh_shortest_path_traits::Point_3 Point_3;
|
||||
typedef Surface_mesh_shortest_path_traits::FT FT;
|
||||
|
||||
enum Selection_mode
|
||||
{
|
||||
INSERT_POINTS_MODE = 0,
|
||||
REMOVE_POINTS_MODE = 1,
|
||||
SHORTEST_PATH_MODE = 2
|
||||
};
|
||||
|
||||
enum Primitives_mode
|
||||
{
|
||||
VERTEX_MODE = 0,
|
||||
EDGE_MODE = 1,
|
||||
FACE_MODE = 2
|
||||
};
|
||||
|
||||
private:
|
||||
Messages_interface* m_messages;
|
||||
QMainWindow* m_mainWindow;
|
||||
Scene_interface* m_sceneInterface;
|
||||
Surface_mesh_shortest_path* m_shortestPaths;
|
||||
AABB_face_graph_tree m_aabbTree;
|
||||
|
||||
std::string m_deferredLoadFilename;
|
||||
|
||||
Selection_mode m_selectionMode;
|
||||
Primitives_mode m_primitivesMode;
|
||||
|
||||
bool m_isTreeCached;
|
||||
|
||||
bool m_shiftHeld;
|
||||
|
||||
private:
|
||||
bool get_mouse_ray(QMouseEvent* mouseEvent, Kernel::Ray_3&);
|
||||
|
||||
void recreate_shortest_path_object();
|
||||
void ensure_aabb_object();
|
||||
void ensure_shortest_paths_tree();
|
||||
|
||||
bool run_point_select(const Kernel::Ray_3&);
|
||||
void remove_nearest_point(const Face_location& ray);
|
||||
void get_as_edge_point(Face_location& inOutLocation);
|
||||
void get_as_vertex_point(Face_location& inOutLocation);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Scene_polyhedron_shortest_path_item();
|
||||
Scene_polyhedron_shortest_path_item(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow);
|
||||
~Scene_polyhedron_shortest_path_item();
|
||||
|
||||
void set_selection_mode(Selection_mode mode);
|
||||
Selection_mode get_selection_mode() const;
|
||||
void set_primitives_mode(Primitives_mode mode);
|
||||
Primitives_mode get_primitives_mode() const;
|
||||
|
||||
virtual bool supportsRenderingMode(RenderingMode m) const;
|
||||
virtual void draw() const;
|
||||
virtual void draw(Viewer_interface*) const;
|
||||
// Wireframe OpenGL drawing
|
||||
virtual void draw_edges() const;
|
||||
virtual void draw_edges(Viewer_interface*) const;
|
||||
// Points OpenGL drawing
|
||||
virtual void draw_points() const;
|
||||
virtual void draw_points(Viewer_interface*) const;
|
||||
|
||||
virtual Scene_polyhedron_shortest_path_item* clone() const;
|
||||
|
||||
bool deferred_load(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow);
|
||||
virtual bool load(const std::string& file_name);
|
||||
virtual bool save(const std::string& file_name) const;
|
||||
|
||||
protected:
|
||||
void initialize(Scene_polyhedron_item* polyhedronItem, Scene_interface* sceneInterface, Messages_interface* messages, QMainWindow* mainWindow);
|
||||
void deinitialize();
|
||||
|
||||
virtual bool isFinite() const;
|
||||
virtual bool isEmpty() const;
|
||||
virtual Bbox bbox() const;
|
||||
virtual QString toolTip() const;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* /*target*/, QEvent * gen_event);
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void poly_item_changed();
|
||||
virtual void changed();
|
||||
};
|
||||
|
||||
#endif // SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_H
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_CONFIG_H
|
||||
#define SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_CONFIG_H
|
||||
|
||||
#ifdef scene_polyhedron_shortest_path_item_EXPORTS
|
||||
# define SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // SCENE_POLYHEDRON_SHORTEST_PATH_ITEM_CONFIG_H
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Shortest_path</class>
|
||||
<widget class="QDockWidget" name="Shortest_path">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>334</width>
|
||||
<height>402</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Shortest_path</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Shortest_path &Type:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>Selection_type_combo_box</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="Selection_type_combo_box">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Insertion</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Removal</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Compute Path</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="Primitives_type_combo_box">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Vertex</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Edge</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Face</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -162,6 +162,7 @@ else
|
|||
p_klein_function_plugin \
|
||||
p_sphere_function_plugin \
|
||||
p_tanglecube_function_plugin \
|
||||
shortest_path_plugin \
|
||||
all
|
||||
do
|
||||
if ${MAKE_CMD} -f Makefile help | grep "$target" > /dev/null; then
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ int main(int argc, char** argv )
|
|||
else
|
||||
OpenMesh::IO::read_mesh(mesh, "data/cactus.off");
|
||||
|
||||
std::cout << "#F : " << num_faces(mesh) << std::endl;
|
||||
std::cout << "#H : " << num_halfedges(mesh) << std::endl;
|
||||
std::cout << "#V : " << num_vertices(mesh) << std::endl;
|
||||
|
||||
// create a property-map for SDF values
|
||||
typedef std::map<face_descriptor, double> Facet_double_map;
|
||||
Facet_double_map internal_sdf_map;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
import subprocess;
|
||||
import sys;
|
||||
|
||||
class TestConfig:
|
||||
"""
|
||||
Describes a benchmark test case to run over a set of models
|
||||
"""
|
||||
|
||||
def __init__(self, testName, testModels, numTrials, numSources, numQueries, randSeed, kernel="epick"):
|
||||
"""
|
||||
testName - the name of the test as it should appear in the documentation file
|
||||
testModels - a list of .off model files to run the test on
|
||||
numTrials - the number of times the full test should be repeated on each mesh
|
||||
numSources - the number of source points to use in each trial
|
||||
numQueries - the number of query points to use in each trial
|
||||
rand - a python random number generator, used to pass a random key to the tests
|
||||
"""
|
||||
self.testName = testName;
|
||||
self.testModels = testModels;
|
||||
self.numTrials = numTrials;
|
||||
self.numSources = numSources;
|
||||
self.numQueries = numQueries;
|
||||
self.randSeed = randSeed;
|
||||
self.kernel = kernel;
|
||||
|
||||
def __str__(self):
|
||||
return "%s : Kernel = %s #Trials = %d, #Sources = %d, #Queries = %d" % (self.testName, self.kernel, self.numTrials, self.numSources, self.numQueries);
|
||||
|
||||
def read_all_lines(file):
|
||||
f = open(file, "r");
|
||||
lines = list(map(lambda l: l.strip(), f.readlines()));
|
||||
f.close();
|
||||
return lines;
|
||||
|
||||
def read_test_config(line):
|
||||
toks = line.strip().split(',');
|
||||
return TestConfig(toks[0], read_all_lines(toks[1]), int(toks[2]), int(toks[3]), int(toks[4]), int(toks[5]));
|
||||
|
||||
def prepare_program():
|
||||
"""
|
||||
Call cmake for the benchmark program in the current directory. Specifies O2 to ensure optimized build, but Debug to allow NDEBUG sections to be included (for memory benchmarking for example)
|
||||
"""
|
||||
cmakeCall = subprocess.call(['cmake', '-DCMAKE_CXX_FLAGS=-O3 -Wall -DCGAL_NDEBUG', '-DCMAKE_BUILD_TYPE=Debug', '.']);
|
||||
if cmakeCall != 0:
|
||||
return False;
|
||||
makeCall = subprocess.call(['make']);
|
||||
if makeCall != 0:
|
||||
return False;
|
||||
return True;
|
||||
|
||||
def run_benchmarks(testConfig, outputFile):
|
||||
"""
|
||||
Executes the benchmarks program for the given configuration.
|
||||
"""
|
||||
print("Config: " + str(testConfig));
|
||||
for model in testConfig.testModels:
|
||||
sys.stdout.write("Model = %s ... " % model);
|
||||
sys.stdout.flush();
|
||||
result = subprocess.call(['./benchmark_shortest_paths.exe', '-k', testConfig.kernel, '-p', model.strip(), '-r', str(testConfig.randSeed), '-t', str(testConfig.numTrials), '-n', str(testConfig.numSources), '-q', str(testConfig.numQueries)], stdout=outputFile);
|
||||
if result == 0:
|
||||
sys.stdout.write("Done.\n");
|
||||
else:
|
||||
sys.stdout.write("Error.\n");
|
||||
return True;
|
||||
|
||||
def process_file(file, infoset):
|
||||
"""
|
||||
Processes the benchmark output into a dictionary
|
||||
"""
|
||||
currentFile = None;
|
||||
for line in file:
|
||||
if line.strip():
|
||||
tokens = list(map(lambda x: x.strip(), line.strip().split('|')));
|
||||
if len(tokens) >= 2:
|
||||
if tokens[0].lower() == "filename":
|
||||
currentFile = tokens[1];
|
||||
if currentFile not in infoset:
|
||||
infoset[currentFile] = {};
|
||||
else:
|
||||
infoset[currentFile][tokens[0].lower()] = tokens[1]
|
||||
else:
|
||||
print(line);
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <exception>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path_traits.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h>
|
||||
|
||||
#define UNUSED(X) (void)sizeof(X)
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
typedef boost::timer::nanosecond_type nanosecond_type;
|
||||
|
||||
enum Kernel_type
|
||||
{
|
||||
KERNEL_UNKNOWN,
|
||||
KERNEL_IPICK,
|
||||
KERNEL_EPICK,
|
||||
KERNEL_EPECK,
|
||||
};
|
||||
|
||||
template <class IntType>
|
||||
class SampledValue
|
||||
{
|
||||
private:
|
||||
IntType m_minimum;
|
||||
IntType m_maximum;
|
||||
IntType m_sum;
|
||||
IntType m_numSamples;
|
||||
|
||||
public:
|
||||
SampledValue()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_minimum = IntType(0);
|
||||
m_maximum = IntType(0);
|
||||
m_sum = IntType(0);
|
||||
m_numSamples = IntType(0);
|
||||
}
|
||||
|
||||
IntType minimum() const
|
||||
{
|
||||
return m_minimum;
|
||||
}
|
||||
|
||||
IntType maximum() const
|
||||
{
|
||||
return m_maximum;
|
||||
}
|
||||
|
||||
IntType sum() const
|
||||
{
|
||||
return m_sum;
|
||||
}
|
||||
|
||||
IntType average_integer() const
|
||||
{
|
||||
return m_sum / m_numSamples;
|
||||
}
|
||||
|
||||
IntType average_remainder() const
|
||||
{
|
||||
return m_sum % m_numSamples;
|
||||
}
|
||||
|
||||
double average_float() const
|
||||
{
|
||||
return double(average_integer()) + (double(average_remainder()) / double(m_numSamples));
|
||||
}
|
||||
|
||||
void add_sample(IntType sample)
|
||||
{
|
||||
if (m_numSamples == 0)
|
||||
{
|
||||
m_minimum = sample;
|
||||
m_maximum = sample;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minimum = std::min(m_minimum, sample);
|
||||
m_maximum = std::max(m_maximum, sample);
|
||||
}
|
||||
m_sum += sample;
|
||||
++m_numSamples;
|
||||
}
|
||||
};
|
||||
|
||||
struct Benchmark_data
|
||||
{
|
||||
size_t numVertices;
|
||||
size_t numFaces;
|
||||
size_t numEdges;
|
||||
|
||||
SampledValue<boost::timer::nanosecond_type> constructionTime;
|
||||
SampledValue<boost::timer::nanosecond_type> queryTime;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
SampledValue<size_t> peakMemoryUsage;
|
||||
#endif
|
||||
|
||||
void reset()
|
||||
{
|
||||
numVertices = 0;
|
||||
numEdges = 0;
|
||||
numFaces = 0;
|
||||
constructionTime.reset();
|
||||
queryTime.reset();
|
||||
#if !defined(NDEBUG)
|
||||
peakMemoryUsage.reset();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
void print_results(std::ostream& stream, const std::string& filename, const Benchmark_data& outData)
|
||||
{
|
||||
stream << "Filename | " << filename << std::endl;
|
||||
stream << "Num Vertices | " << outData.numVertices << std::endl;
|
||||
stream << "Num Edges | " << outData.numEdges << std::endl;
|
||||
stream << "Num Faces | " << outData.numFaces << std::endl;
|
||||
|
||||
stream << "Construction | " << outData.constructionTime.average_float() / 1.0e9 << " | " << double(outData.constructionTime.minimum()) / 1.0e9 << " | " << double(outData.constructionTime.maximum()) / 1.0e9 << " |" << std::endl;
|
||||
stream << "Query | " << 1.0 / (outData.queryTime.average_float() / 1.0e9) << " | " << double(outData.queryTime.minimum()) / 1.0e9 << " | " << double(outData.queryTime.maximum()) / 1.0e9 << " |" << std::endl;
|
||||
#if !defined(NDEBUG)
|
||||
stream << "Memory (Peak) | " << outData.peakMemoryUsage.average_float() / 1.0e6 << " | " << double(outData.peakMemoryUsage.minimum()) / 1.0e6 << " | " << double(outData.peakMemoryUsage.maximum()) / 1.0e6 << " |" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::Barycentric_coordinate random_coordinate(CGAL::Random& rand)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typename Traits::Construct_barycentric_coordinate construct_barycentric_coordinate;
|
||||
FT u = rand.uniform_real(FT(0.0), FT(1.0));
|
||||
FT v = rand.uniform_real(FT(0.0), FT(1.0) - u);
|
||||
return construct_barycentric_coordinate(u, v, FT(1.0) - u - v);
|
||||
}
|
||||
|
||||
template <class Kernel>
|
||||
void run_benchmarks(CGAL::Random& rand, size_t numTrials, size_t numSources, size_t numQueries, const std::string& polyhedronFile, Benchmark_data& outData)
|
||||
{
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef typename Traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef typename Surface_mesh_shortest_path::Face_location Face_location;
|
||||
typedef typename Surface_mesh_shortest_path::FT FT;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::face_iterator face_iterator;
|
||||
|
||||
std::ifstream inFile(polyhedronFile.c_str());
|
||||
|
||||
if (!inFile)
|
||||
{
|
||||
throw std::runtime_error(std::string("Model file \"") + polyhedronFile + std::string("\" does not exist."));
|
||||
}
|
||||
|
||||
Polyhedron_3 polyhedron;
|
||||
|
||||
inFile >> polyhedron;
|
||||
inFile.close();
|
||||
|
||||
CGAL::set_halfedgeds_items_id(polyhedron);
|
||||
|
||||
boost::timer::cpu_timer timer;
|
||||
outData.reset();
|
||||
|
||||
outData.numVertices = num_vertices(polyhedron);
|
||||
outData.numEdges = num_edges(polyhedron);
|
||||
outData.numFaces = num_faces(polyhedron);
|
||||
|
||||
face_iterator startFace, endFace;
|
||||
boost::tie(startFace, endFace) = faces(polyhedron);
|
||||
|
||||
std::vector<face_descriptor> allFaces;
|
||||
|
||||
for (face_iterator currentFace = startFace; currentFace != endFace; ++currentFace)
|
||||
{
|
||||
allFaces.push_back(*currentFace);
|
||||
}
|
||||
|
||||
Traits traits;
|
||||
Surface_mesh_shortest_path shortestPaths(polyhedron, traits);
|
||||
|
||||
for (size_t i = 0; i < numTrials; ++i)
|
||||
{
|
||||
std::vector<Face_location> sourcePoints;
|
||||
|
||||
while (sourcePoints.size() < numSources)
|
||||
{
|
||||
face_descriptor sourceFace = allFaces[rand.get_int(0, allFaces.size())];
|
||||
Barycentric_coordinate sourceLocation = random_coordinate<Traits>(rand);
|
||||
sourcePoints.push_back(Face_location(sourceFace, sourceLocation));
|
||||
}
|
||||
|
||||
shortestPaths.clear();
|
||||
shortestPaths.add_source_points(sourcePoints.begin(), sourcePoints.end());
|
||||
|
||||
timer.start();
|
||||
shortestPaths.build_sequence_tree();
|
||||
timer.stop();
|
||||
|
||||
boost::timer::cpu_times elapsed = timer.elapsed();
|
||||
|
||||
outData.constructionTime.add_sample(elapsed.wall);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
outData.peakMemoryUsage.add_sample(std::max(shortestPaths.peak_memory_usage(), shortestPaths.current_memory_usage()));
|
||||
#endif
|
||||
|
||||
for (size_t j = 0; j < numQueries; ++j)
|
||||
{
|
||||
face_descriptor sourceFace = allFaces[rand.get_int(0, allFaces.size())];
|
||||
Barycentric_coordinate sourceLocation = random_coordinate<Traits>(rand);
|
||||
|
||||
timer.start();
|
||||
FT distance = shortestPaths.shortest_distance_to_source_points(sourceFace, sourceLocation).first;
|
||||
timer.stop();
|
||||
UNUSED(distance);
|
||||
|
||||
boost::timer::cpu_times elapsed = timer.elapsed();
|
||||
|
||||
outData.queryTime.add_sample(elapsed.wall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kernel_type parse_kernel_type(const std::string& s)
|
||||
{
|
||||
if (boost::iequals(s, "ipick"))
|
||||
{
|
||||
return KERNEL_IPICK;
|
||||
}
|
||||
else if (boost::iequals(s, "epick"))
|
||||
{
|
||||
return KERNEL_EPICK;
|
||||
}
|
||||
else if (boost::iequals(s, "epeck"))
|
||||
{
|
||||
return KERNEL_EPECK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return KERNEL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
po::options_description options;
|
||||
|
||||
options.add_options()
|
||||
("help,h", "Display help message")
|
||||
("polyhedron,p", po::value<std::string>(), "Polyhedron input file")
|
||||
("randomseed,r", po::value<size_t>()->default_value(0), "Randomization seed value")
|
||||
("trials,t", po::value<size_t>()->default_value(20), "Number of trials to run")
|
||||
("numpoints,n", po::value<size_t>()->default_value(1), "Number of source points per trial")
|
||||
("queries,q", po::value<size_t>()->default_value(100), "Number of queries to run per trial")
|
||||
("kernel,k", po::value<std::string>()->default_value("epick"), "Kernel to use. One of \'ipick\', \'epick\', \'epeck\'")
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(argc, argv, options), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("help"))
|
||||
{
|
||||
std::cout << options << std::endl;
|
||||
}
|
||||
else if (vm.count("polyhedron"))
|
||||
{
|
||||
Benchmark_data results;
|
||||
|
||||
CGAL::Random rand(vm["randomseed"].as<size_t>());
|
||||
size_t numTrials = vm["trials"].as<size_t>();
|
||||
size_t numPoints = vm["numpoints"].as<size_t>();
|
||||
size_t numQueries = vm["queries"].as<size_t>();
|
||||
std::string polyhedronFile = vm["polyhedron"].as<std::string>();
|
||||
|
||||
try
|
||||
{
|
||||
switch (parse_kernel_type(vm["kernel"].as<std::string>()))
|
||||
{
|
||||
case KERNEL_IPICK:
|
||||
run_benchmarks<CGAL::Simple_cartesian<double> >(rand, numTrials, numPoints, numQueries, polyhedronFile, results);
|
||||
break;
|
||||
case KERNEL_EPICK:
|
||||
run_benchmarks<CGAL::Exact_predicates_inexact_constructions_kernel>(rand, numTrials, numPoints, numQueries, polyhedronFile, results);
|
||||
break;
|
||||
case KERNEL_EPECK:
|
||||
run_benchmarks<CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt>(rand, numTrials, numPoints, numQueries, polyhedronFile, results);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Invalid kernel type: \"" << vm["kernel"].as<std::string>() << "\"" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "Runtime error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
print_results(std::cout, polyhedronFile, results);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Please specify a polyhedron to use. Use option --help for more details." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
The purpose of this file is to recompute the benchmarks section of the user manual.
|
||||
|
||||
Its intended usage is
|
||||
|
||||
python compileBenchmarks.py <modelsFile> <dataFileBase> <tableFileBase> <figureFileBase> <randomseed>
|
||||
|
||||
Where:
|
||||
- <modelsFile> - a file, containing all models to run tests on
|
||||
- <dataFileBase> - output data files will be of the form "<dataFileBase>_<modelname>.dat", where <modelname> is the basename of the model
|
||||
- <tableFileBase> - output tables will be of the form "<outputTableBase>_#.txt", where # is the number of source points
|
||||
- <figureFileBase> - output figures will be of the form "<outputBaseName>_<type>.png" where <type> is one of {query, construction, memory}
|
||||
- <randomseed> - a positive integer to seed the randomizer
|
||||
|
||||
Upon completion, a set of data, table, and figure files will be generated over the testing models set.
|
||||
|
||||
"""
|
||||
|
||||
import sys;
|
||||
import subprocess;
|
||||
import tempfile;
|
||||
import random;
|
||||
import re;
|
||||
import benchmark;
|
||||
import os;
|
||||
import argparse;
|
||||
|
||||
def make_table_file_name(tableFileBase, numSources):
|
||||
return tableFileBase + '_' + str(numSources) + ".txt";
|
||||
|
||||
def make_model_data_file_name(dataFileBase, modelFile):
|
||||
return dataFileBase + '_' + os.path.basename(modelFile).partition('.')[0] + ".dat";
|
||||
|
||||
def make_figure_file_name(figureFileBase, modelFile):
|
||||
return figureFileBase + '_' + os.path.basename(modelFile).partition('.')[0] + ".png";
|
||||
|
||||
def print_to_datafiles(config, dataFileName, modelInfo):
|
||||
file = open(dataFileName, "a");
|
||||
file.write("%d %d %s %s %s\n" % (config.numSources, int(modelInfo.get("num vertices", 0)), modelInfo.get('construction', '0'), modelInfo.get('query', '0'), modelInfo.get('memory (peak)', '0')));
|
||||
file.close();
|
||||
|
||||
def print_table(infoSet, config, outFile):
|
||||
outFile.write("\subsection Surface_mesh_shortest_pathBenchmark%s %s\n" % (re.sub(r"\s+", "", config.testName.strip()), config.testName));
|
||||
outFile.write("<center>\n");
|
||||
outFile.write("Model | Number of Vertices | Average Construction Time (s) | Average Queries Per Second | Peak Memory Usage (MB)\n");
|
||||
outFile.write("---|---|---|---|---\n");
|
||||
|
||||
for key, value in sorted(infoSet.items(), key=lambda v: int(v[1]["num vertices"])):
|
||||
outFile.write(key.split('/')[-1] + " | " +
|
||||
value.get("num vertices", "(crashed)") + " | " +
|
||||
value.get("construction", "(crashed)") + " | " +
|
||||
value.get("query", "(crashed)") + " | " +
|
||||
value.get("memory (peak)", "(crashed)") + "\n");
|
||||
outFile.write("</center>\n");
|
||||
outFile.write('\n');
|
||||
|
||||
parser = argparse.ArgumentParser(description="Run benchmarks on multiple model files");
|
||||
|
||||
parser.add_argument('-r', '--range', type=str, default=['1'], nargs='*', help="Can specify multiple single values, or ranges. Format is '#' or '#,#' or '#,#,#' for a single value, a range of values, or a range values of values with a specified skip");
|
||||
parser.add_argument('-f', '--modelsfile', '--modelsfiles', type=str, nargs='*', help="a file containing a list of models to test on, one per line");
|
||||
parser.add_argument('-m', '--model', '--models', type=str, nargs='*');
|
||||
parser.add_argument('-s', '--randseed', type=int, help="Random seed for tests.");
|
||||
parser.add_argument('-d', '--datafilebase', type=str, default='_modeldata', help="Base name for temporary data files (existing files will be overwritten).");
|
||||
parser.add_argument('-t', '--tablefilebase', type=str, help="Base name for generated user manual tables (will be of the form \"<tablefilebase>_#.txt\", leave blank to suppress generation)");
|
||||
parser.add_argument('-o', '--plotfilebase', type=str, help="Base name for generated plot figures (will be of the form \"<plotfilebase>_<modelname>.png\", leave blank to suppress generation)");
|
||||
parser.add_argument('-k', '--kernel', choices=['ipick', 'epick', 'epeck'], default='epick', help="Geometry kernel to use for the benchmark.");
|
||||
parser.add_argument('-n', '--numtrials', type=int, default=20, help="Specify the number of complete trial runs on each model.");
|
||||
parser.add_argument('-q', '--numqueries', type=int, default=100, help="Specify the number of shortest path queries to run per trial.");
|
||||
|
||||
programArgs = parser.parse_args();
|
||||
|
||||
setOfSamples = set();
|
||||
|
||||
if programArgs.range:
|
||||
for r in programArgs.range:
|
||||
toks = r.split(',');
|
||||
if len(toks) == 1:
|
||||
setOfSamples.add(int(toks[0]));
|
||||
elif len(toks) == 2:
|
||||
setOfSamples.update(range(int(toks[0]), int(toks[1])));
|
||||
elif len(toks) == 3:
|
||||
setOfSamples.update(range(int(toks[0]), int(toks[1]), int(toks[2])));
|
||||
else:
|
||||
raise "Invalid range: " + r;
|
||||
|
||||
sampleRange = reversed(sorted(list(setOfSamples)));
|
||||
|
||||
testModels = [];
|
||||
|
||||
if programArgs.modelsfile:
|
||||
for modelsFile in programArgs.modelsfile:
|
||||
testModels.extend(benchmark.read_all_lines(modelsFile));
|
||||
|
||||
if programArgs.model:
|
||||
for model in programArgs.model:
|
||||
testModels.append(model);
|
||||
|
||||
if len(testModels) == 0:
|
||||
print("Error, must specify at least one model to benchmark");
|
||||
sys.exit(1);
|
||||
|
||||
rand = random.Random(programArgs.randseed);
|
||||
|
||||
dataFileBase = programArgs.datafilebase;
|
||||
tableFileBase = programArgs.tablefilebase;
|
||||
plotFileBase = programArgs.plotfilebase;
|
||||
|
||||
kernel = programArgs.kernel;
|
||||
|
||||
if tableFileBase == None and plotFileBase == None:
|
||||
print("Error, must specify either a table output or figure output file");
|
||||
sys.exit(1);
|
||||
|
||||
if not benchmark.prepare_program():
|
||||
print("Error, could not compile program");
|
||||
sys.exit(1);
|
||||
|
||||
for model in testModels:
|
||||
modelDataFileName = make_model_data_file_name(dataFileBase, model);
|
||||
if os.path.exists(modelDataFileName):
|
||||
os.remove(modelDataFileName);
|
||||
|
||||
for numSources in sampleRange:
|
||||
testname = "1 Source Point" if numSources == 1 else ("%d Source Points" % numSources);
|
||||
config = benchmark.TestConfig(testname, testModels, programArgs.numtrials, numSources, programArgs.numqueries, rand.randint(0, 65536), kernel);
|
||||
infoSet = {};
|
||||
infoFile = tempfile.TemporaryFile();
|
||||
benchmark.run_benchmarks(config, infoFile);
|
||||
infoFile.seek(0);
|
||||
infoSet = {};
|
||||
benchmark.process_file(infoFile, infoSet);
|
||||
infoFile.close();
|
||||
for k in infoSet.keys():
|
||||
print_to_datafiles(config, make_model_data_file_name(dataFileBase, k), infoSet[k]);
|
||||
if tableFileBase != None:
|
||||
tableFile = open(make_table_file_name(tableFileBase, numSources), "w");
|
||||
print_table(infoSet, config, tableFile);
|
||||
tableFile.close();
|
||||
|
||||
if plotFileBase != None:
|
||||
for runParams in [('query', 4, "Average Queries Per Second"), ('construction', 3, "Average Construction Time"), ('memory', 5, "Peak Memory Usage")]:
|
||||
plotCommands = [];
|
||||
for k in testModels:
|
||||
plotCommands.append('"%s" using 1:%d with lines title "%s"' % (make_model_data_file_name(dataFileBase, k), runParams[1], os.path.basename(k)));
|
||||
plotCommand = "plot " + ', '.join(plotCommands);
|
||||
plotCommandFile = tempfile.TemporaryFile();
|
||||
plotCommandFile.write('set terminal png size 640,480;\n');
|
||||
plotCommandFile.write('set output "%s";\n' % make_figure_file_name(plotFileBase, runParams[0]));
|
||||
plotCommandFile.write('set xlabel "Number of Source Points";\n');
|
||||
plotCommandFile.write('set ylabel "%s";\n' % runParams[2]);
|
||||
plotCommandFile.write(plotCommand + ";\n");
|
||||
plotCommandFile.write('unset output;\n');
|
||||
plotCommandFile.write('quit\n');
|
||||
plotCommandFile.seek(0);
|
||||
subprocess.call(['gnuplot'], stdin=plotCommandFile);
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
OFF
|
||||
40 76 0
|
||||
|
||||
-0.5 0.1 -0.1
|
||||
-0.3 0.1 -0.1
|
||||
-0.1 0.1 -0.1
|
||||
-0.1 0.3 -0.1
|
||||
-0.1 0.5 -0.1
|
||||
0.1 0.5 -0.1
|
||||
0.1 0.3 -0.1
|
||||
0.1 0.1 -0.1
|
||||
0.3 0.1 -0.1
|
||||
0.5 0.1 -0.1
|
||||
0.5 -0.1 -0.1
|
||||
0.3 -0.1 -0.1
|
||||
0.1 -0.1 -0.1
|
||||
0.1 -0.3 -0.1
|
||||
0.1 -0.5 -0.1
|
||||
-0.1 -0.5 -0.1
|
||||
-0.1 -0.3 -0.1
|
||||
-0.1 -0.1 -0.1
|
||||
-0.3 -0.1 -0.1
|
||||
-0.5 -0.1 -0.1
|
||||
-0.5 0.1 0.1
|
||||
-0.3 0.1 0.1
|
||||
-0.1 0.1 0.1
|
||||
-0.1 0.3 0.1
|
||||
-0.1 0.5 0.1
|
||||
0.1 0.5 0.1
|
||||
0.1 0.3 0.1
|
||||
0.1 0.1 0.1
|
||||
0.3 0.1 0.1
|
||||
0.5 0.1 0.1
|
||||
0.5 -0.1 0.1
|
||||
0.3 -0.1 0.1
|
||||
0.1 -0.1 0.1
|
||||
0.1 -0.3 0.1
|
||||
0.1 -0.5 0.1
|
||||
-0.1 -0.5 0.1
|
||||
-0.1 -0.3 0.1
|
||||
-0.1 -0.1 0.1
|
||||
-0.3 -0.1 0.1
|
||||
-0.5 -0.1 0.1
|
||||
3 19 0 1
|
||||
3 18 1 2
|
||||
3 17 2 7
|
||||
3 7 2 3
|
||||
3 6 3 4
|
||||
3 12 7 8
|
||||
3 11 8 9
|
||||
3 17 12 13
|
||||
3 16 13 14
|
||||
3 21 1 0
|
||||
3 22 2 1
|
||||
3 23 3 2
|
||||
3 24 4 3
|
||||
3 25 5 4
|
||||
3 26 6 5
|
||||
3 27 7 6
|
||||
3 28 8 7
|
||||
3 29 9 8
|
||||
3 30 10 9
|
||||
3 31 11 10
|
||||
3 32 12 11
|
||||
3 33 13 12
|
||||
3 34 14 13
|
||||
3 35 15 14
|
||||
3 36 16 15
|
||||
3 37 17 16
|
||||
3 38 18 17
|
||||
3 39 19 18
|
||||
3 20 0 19
|
||||
3 20 39 38
|
||||
3 21 38 37
|
||||
3 22 37 32
|
||||
3 22 27 26
|
||||
3 23 26 25
|
||||
3 27 32 31
|
||||
3 28 31 30
|
||||
3 32 37 36
|
||||
3 33 36 35
|
||||
3 1 18 19
|
||||
3 2 17 18
|
||||
3 7 12 17
|
||||
3 3 6 7
|
||||
3 4 5 6
|
||||
3 8 11 12
|
||||
3 9 10 11
|
||||
3 13 16 17
|
||||
3 14 15 16
|
||||
3 0 20 21
|
||||
3 1 21 22
|
||||
3 2 22 23
|
||||
3 3 23 24
|
||||
3 4 24 25
|
||||
3 5 25 26
|
||||
3 6 26 27
|
||||
3 7 27 28
|
||||
3 8 28 29
|
||||
3 9 29 30
|
||||
3 10 30 31
|
||||
3 11 31 32
|
||||
3 12 32 33
|
||||
3 13 33 34
|
||||
3 14 34 35
|
||||
3 15 35 36
|
||||
3 16 36 37
|
||||
3 17 37 38
|
||||
3 18 38 39
|
||||
3 19 39 20
|
||||
3 38 21 20
|
||||
3 37 22 21
|
||||
3 32 27 22
|
||||
3 26 23 22
|
||||
3 25 24 23
|
||||
3 31 28 27
|
||||
3 30 29 28
|
||||
3 36 33 32
|
||||
3 35 34 33
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
OFF
|
||||
9 10 0
|
||||
-1 -1 -1
|
||||
-1 1 -1
|
||||
1 1 -1
|
||||
1 -1 -1
|
||||
-1 -1 1
|
||||
-1 1 1
|
||||
1 1 1
|
||||
1 -1 1
|
||||
1 2 1
|
||||
3 0 1 3
|
||||
3 3 1 2
|
||||
3 0 4 1
|
||||
3 1 4 5
|
||||
3 3 2 7
|
||||
3 7 2 6
|
||||
3 4 0 3
|
||||
3 7 4 3
|
||||
3 6 4 7
|
||||
3 6 5 4
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
OFF
|
||||
8 12 0
|
||||
-1 -1 -1
|
||||
-1 1 -1
|
||||
1 1 -1
|
||||
1 -1 -1
|
||||
-1 -1 1
|
||||
-1 1 1
|
||||
1 1 1
|
||||
1 -1 1
|
||||
3 0 1 3
|
||||
3 3 1 2
|
||||
3 0 4 1
|
||||
3 1 4 5
|
||||
3 3 2 7
|
||||
3 7 2 6
|
||||
3 4 0 3
|
||||
3 7 4 3
|
||||
3 6 4 7
|
||||
3 6 5 4
|
||||
3 1 5 6
|
||||
3 2 1 6
|
||||
|
|
@ -0,0 +1,483 @@
|
|||
OFF
|
||||
161 318 0
|
||||
|
||||
-0.222222 -0.332893 0.0171407
|
||||
-0.222222 -0.330685 -0.0419259
|
||||
-0.222222 -0.324022 0.0782296
|
||||
-0.222222 -0.319063 -0.0964926
|
||||
-0.222222 -0.303341 0.138185
|
||||
-0.222222 -0.288674 -0.166667
|
||||
-0.222222 -0.271341 0.193611
|
||||
-0.222222 -0.243096 -0.22807
|
||||
-0.222222 -0.229763 0.241496
|
||||
-0.222222 -0.201652 -0.265419
|
||||
-0.222222 -0.181289 0.279722
|
||||
-0.222222 -0.151604 -0.296863
|
||||
-0.222222 -0.129033 0.307344
|
||||
-0.222222 -0.094263 -0.31973
|
||||
-0.222222 -0.0759667 0.324563
|
||||
-0.222222 -0.032 -0.331793
|
||||
-0.222222 0 0.333333
|
||||
-0.222222 0.032 -0.331793
|
||||
-0.222222 0.0759667 0.324563
|
||||
-0.222222 0.094263 -0.31973
|
||||
-0.222222 0.129033 0.307344
|
||||
-0.222222 0.1516 -0.296863
|
||||
-0.222222 0.181289 0.279722
|
||||
-0.222222 0.201652 -0.265419
|
||||
-0.222222 0.229763 0.241496
|
||||
-0.222222 0.243096 -0.22807
|
||||
-0.222222 0.271341 0.193611
|
||||
-0.222222 0.288674 -0.166667
|
||||
-0.222222 0.303341 0.138181
|
||||
-0.222222 0.319063 -0.0964926
|
||||
-0.222222 0.324022 0.0782296
|
||||
-0.222222 0.330685 -0.0419259
|
||||
-0.222222 0.332893 0.0171407
|
||||
-0.185185 -0.333085 0.0128222
|
||||
-0.185185 -0.329674 -0.0492556
|
||||
-0.185185 -0.325474 0.0719667
|
||||
-0.185185 -0.313478 -0.113326
|
||||
-0.185185 -0.306107 0.131941
|
||||
-0.185185 -0.283441 -0.175419
|
||||
-0.185185 -0.274393 0.189263
|
||||
-0.185185 -0.240193 -0.231126
|
||||
-0.185185 -0.231126 0.240193
|
||||
-0.185185 -0.186193 -0.276485
|
||||
-0.185185 -0.17857 0.281467
|
||||
-0.185185 -0.125296 -0.308889
|
||||
-0.185185 -0.12007 0.310956
|
||||
-0.185185 -0.0619 -0.327537
|
||||
-0.185185 -0.0593926 0.328
|
||||
-0.185185 0 -0.333333
|
||||
-0.185185 0 0.333333
|
||||
-0.185185 0.0593926 0.328
|
||||
-0.185185 0.0619 -0.327537
|
||||
-0.185185 0.12007 0.310956
|
||||
-0.185185 0.125296 -0.308889
|
||||
-0.185185 0.17857 0.281467
|
||||
-0.185185 0.186193 -0.276485
|
||||
-0.185185 0.231126 0.240193
|
||||
-0.185185 0.240193 -0.231126
|
||||
-0.185185 0.274393 0.189263
|
||||
-0.185185 0.283441 -0.175419
|
||||
-0.185185 0.306107 0.131941
|
||||
-0.185185 0.313478 -0.113326
|
||||
-0.185185 0.325474 0.0719667
|
||||
-0.185185 0.329674 -0.0492556
|
||||
-0.185185 0.333085 0.0128222
|
||||
-0.0740741 -0.49963 0.0192296
|
||||
-0.0740741 -0.494511 -0.0738815
|
||||
-0.0740741 -0.488207 0.107948
|
||||
-0.0740741 -0.470219 -0.169985
|
||||
-0.0740741 -0.459163 0.197915
|
||||
-0.0740741 -0.425163 -0.26313
|
||||
-0.0740741 -0.411589 0.283893
|
||||
-0.0740741 -0.360289 -0.346689
|
||||
-0.0740741 -0.346689 0.360289
|
||||
-0.0740741 -0.279289 -0.414726
|
||||
-0.0740741 -0.267852 0.422204
|
||||
-0.0740741 -0.187944 -0.463333
|
||||
-0.0740741 -0.180107 0.466433
|
||||
-0.0740741 -0.0928481 -0.491304
|
||||
-0.0740741 -0.0890889 0.492
|
||||
-0.0740741 0 -0.5
|
||||
-0.0740741 0 0.5
|
||||
-0.0740741 0.0890889 0.492
|
||||
-0.0740741 0.0928481 -0.491304
|
||||
-0.0740741 0.180107 0.466433
|
||||
-0.0740741 0.187944 -0.463333
|
||||
-0.0740741 0.267852 0.422204
|
||||
-0.0740741 0.279289 -0.414726
|
||||
-0.0740741 0.346689 0.360289
|
||||
-0.0740741 0.360289 -0.346689
|
||||
-0.0740741 0.411589 0.283893
|
||||
-0.0740741 0.425163 -0.26313
|
||||
-0.0740741 0.459163 0.197915
|
||||
-0.0740741 0.470219 -0.169985
|
||||
-0.0740741 0.488207 0.107948
|
||||
-0.0740741 0.494511 -0.0738815
|
||||
-0.0740741 0.49963 0.0192296
|
||||
0.166667 -0.222059 0.00854815
|
||||
0.166667 -0.219781 -0.032837
|
||||
0.166667 -0.213585 0.0613519
|
||||
0.166667 -0.208985 -0.0755481
|
||||
0.166667 -0.197933 0.101019
|
||||
0.166667 -0.188959 -0.116948
|
||||
0.166667 -0.182926 0.126174
|
||||
0.166667 -0.16013 -0.154085
|
||||
0.166667 -0.154085 0.16013
|
||||
0.166667 -0.12413 -0.184322
|
||||
0.166667 -0.119044 0.187644
|
||||
0.166667 -0.0835296 -0.205926
|
||||
0.166667 -0.0800481 0.207304
|
||||
0.166667 -0.0412667 -0.218356
|
||||
0.166667 -0.0262 0.220674
|
||||
0.166667 0 -0.222222
|
||||
0.166667 0.017363 0.221544
|
||||
0.166667 0.0412667 -0.218356
|
||||
0.166667 0.0530889 0.215789
|
||||
0.166667 0.0835296 -0.205926
|
||||
0.166667 0.0933333 0.201674
|
||||
0.166667 0.119044 0.187644
|
||||
0.166667 0.12413 -0.184322
|
||||
0.166667 0.154085 0.16013
|
||||
0.166667 0.16013 -0.154085
|
||||
0.166667 0.182926 0.126174
|
||||
0.166667 0.188959 -0.116948
|
||||
0.166667 0.204074 0.087963
|
||||
0.166667 0.208985 -0.0755481
|
||||
0.166667 0.2195 0.0346704
|
||||
0.166667 0.219781 -0.032837
|
||||
0.166667 0.222167 -0.00496296
|
||||
0.222222 -0.444115 0.0170926
|
||||
0.222222 -0.439567 -0.0656741
|
||||
0.222222 -0.433963 0.0959519
|
||||
0.222222 -0.41797 -0.1511
|
||||
0.222222 -0.408144 0.175922
|
||||
0.222222 -0.377922 -0.233893
|
||||
0.222222 -0.365856 0.252352
|
||||
0.222222 -0.320256 -0.308167
|
||||
0.222222 -0.308167 0.320256
|
||||
0.222222 -0.248256 -0.368644
|
||||
0.222222 -0.238093 0.375289
|
||||
0.222222 -0.167063 -0.411852
|
||||
0.222222 -0.160096 0.414607
|
||||
0.222222 -0.0825296 -0.436715
|
||||
0.222222 -0.0791926 0.437333
|
||||
0.222222 0 -0.444444
|
||||
0.222222 0 0.444444
|
||||
0.222222 0.0791926 0.437333
|
||||
0.222222 0.0825296 -0.436715
|
||||
0.222222 0.160096 0.414607
|
||||
0.222222 0.167063 -0.411852
|
||||
0.222222 0.238093 0.375289
|
||||
0.222222 0.248256 -0.368644
|
||||
0.222222 0.308167 0.320256
|
||||
0.222222 0.320256 -0.308167
|
||||
0.222222 0.365856 0.252352
|
||||
0.222222 0.377922 -0.233893
|
||||
0.222222 0.408144 0.175922
|
||||
0.222222 0.41797 -0.1511
|
||||
0.222222 0.433963 0.0959519
|
||||
0.222222 0.439567 -0.0656741
|
||||
0.222222 0.444115 0.0170926
|
||||
3 127 128 125
|
||||
3 128 126 125
|
||||
3 125 126 123
|
||||
3 126 124 123
|
||||
3 123 124 121
|
||||
3 124 122 121
|
||||
3 121 122 119
|
||||
3 122 120 119
|
||||
3 119 120 116
|
||||
3 120 118 116
|
||||
3 116 118 114
|
||||
3 118 117 114
|
||||
3 114 117 112
|
||||
3 117 115 112
|
||||
3 112 115 110
|
||||
3 115 113 110
|
||||
3 110 113 108
|
||||
3 113 111 108
|
||||
3 108 111 106
|
||||
3 111 109 106
|
||||
3 106 109 104
|
||||
3 109 107 104
|
||||
3 104 107 102
|
||||
3 107 105 102
|
||||
3 102 105 100
|
||||
3 105 103 100
|
||||
3 100 103 98
|
||||
3 103 101 98
|
||||
3 98 101 97
|
||||
3 101 99 97
|
||||
3 154 122 156
|
||||
3 122 124 156
|
||||
3 156 124 158
|
||||
3 124 126 158
|
||||
3 158 126 160
|
||||
3 126 128 160
|
||||
3 160 128 159
|
||||
3 128 127 159
|
||||
3 159 127 157
|
||||
3 127 125 157
|
||||
3 157 125 155
|
||||
3 125 123 155
|
||||
3 155 123 153
|
||||
3 123 121 153
|
||||
3 153 121 151
|
||||
3 121 119 151
|
||||
3 151 119 149
|
||||
3 119 116 149
|
||||
3 149 116 147
|
||||
3 116 114 147
|
||||
3 147 114 144
|
||||
3 114 112 144
|
||||
3 144 112 142
|
||||
3 112 110 142
|
||||
3 142 110 140
|
||||
3 110 108 140
|
||||
3 140 108 138
|
||||
3 108 106 138
|
||||
3 138 106 136
|
||||
3 106 104 136
|
||||
3 136 104 134
|
||||
3 104 102 134
|
||||
3 134 102 132
|
||||
3 102 100 132
|
||||
3 132 100 130
|
||||
3 100 98 130
|
||||
3 130 98 129
|
||||
3 98 97 129
|
||||
3 129 97 131
|
||||
3 97 99 131
|
||||
3 131 99 133
|
||||
3 99 101 133
|
||||
3 133 101 135
|
||||
3 101 103 135
|
||||
3 135 103 137
|
||||
3 103 105 137
|
||||
3 137 105 139
|
||||
3 105 107 139
|
||||
3 139 107 141
|
||||
3 107 109 141
|
||||
3 141 109 143
|
||||
3 109 111 143
|
||||
3 143 111 145
|
||||
3 111 113 145
|
||||
3 145 113 146
|
||||
3 113 115 146
|
||||
3 146 115 148
|
||||
3 115 117 148
|
||||
3 148 117 150
|
||||
3 117 118 150
|
||||
3 150 118 152
|
||||
3 118 120 152
|
||||
3 152 120 154
|
||||
3 120 122 154
|
||||
3 80 144 78
|
||||
3 144 142 78
|
||||
3 142 140 78
|
||||
3 78 140 76
|
||||
3 140 138 76
|
||||
3 76 138 74
|
||||
3 138 136 74
|
||||
3 74 136 72
|
||||
3 136 134 72
|
||||
3 72 134 70
|
||||
3 134 132 70
|
||||
3 70 132 68
|
||||
3 132 130 68
|
||||
3 68 130 66
|
||||
3 130 129 66
|
||||
3 66 129 65
|
||||
3 129 131 65
|
||||
3 65 131 67
|
||||
3 131 133 67
|
||||
3 67 133 69
|
||||
3 133 135 69
|
||||
3 69 135 71
|
||||
3 135 137 71
|
||||
3 71 137 73
|
||||
3 137 139 73
|
||||
3 73 139 75
|
||||
3 139 141 75
|
||||
3 75 141 77
|
||||
3 141 143 77
|
||||
3 77 143 79
|
||||
3 143 145 79
|
||||
3 79 145 81
|
||||
3 145 146 81
|
||||
3 81 146 82
|
||||
3 146 148 82
|
||||
3 82 148 84
|
||||
3 148 150 84
|
||||
3 84 150 86
|
||||
3 150 152 86
|
||||
3 86 152 88
|
||||
3 152 154 88
|
||||
3 88 154 90
|
||||
3 154 156 90
|
||||
3 90 156 92
|
||||
3 156 158 92
|
||||
3 92 158 94
|
||||
3 158 160 94
|
||||
3 94 160 96
|
||||
3 160 159 96
|
||||
3 96 159 95
|
||||
3 159 157 95
|
||||
3 95 157 93
|
||||
3 157 155 93
|
||||
3 93 155 91
|
||||
3 155 153 91
|
||||
3 91 153 89
|
||||
3 153 151 89
|
||||
3 89 151 87
|
||||
3 151 149 87
|
||||
3 87 149 85
|
||||
3 149 147 85
|
||||
3 85 147 83
|
||||
3 147 144 83
|
||||
3 83 144 80
|
||||
3 36 68 34
|
||||
3 68 66 34
|
||||
3 34 66 33
|
||||
3 66 65 33
|
||||
3 33 65 35
|
||||
3 65 67 35
|
||||
3 35 67 37
|
||||
3 67 69 37
|
||||
3 37 69 39
|
||||
3 69 71 39
|
||||
3 39 71 41
|
||||
3 71 73 41
|
||||
3 41 73 43
|
||||
3 73 75 43
|
||||
3 43 75 45
|
||||
3 75 77 45
|
||||
3 45 77 47
|
||||
3 77 79 47
|
||||
3 47 79 49
|
||||
3 79 81 49
|
||||
3 49 81 50
|
||||
3 81 82 50
|
||||
3 50 82 52
|
||||
3 82 84 52
|
||||
3 52 84 54
|
||||
3 84 86 54
|
||||
3 54 86 56
|
||||
3 86 88 56
|
||||
3 56 88 58
|
||||
3 88 90 58
|
||||
3 58 90 60
|
||||
3 90 92 60
|
||||
3 60 92 62
|
||||
3 92 94 62
|
||||
3 62 94 64
|
||||
3 94 96 64
|
||||
3 64 96 63
|
||||
3 96 95 63
|
||||
3 63 95 61
|
||||
3 95 93 61
|
||||
3 61 93 59
|
||||
3 93 91 59
|
||||
3 59 91 57
|
||||
3 91 89 57
|
||||
3 57 89 55
|
||||
3 89 87 55
|
||||
3 55 87 53
|
||||
3 87 85 53
|
||||
3 53 85 51
|
||||
3 85 83 51
|
||||
3 51 83 48
|
||||
3 83 80 48
|
||||
3 48 80 46
|
||||
3 80 78 46
|
||||
3 46 78 44
|
||||
3 78 76 44
|
||||
3 44 76 42
|
||||
3 76 74 42
|
||||
3 42 74 40
|
||||
3 74 72 40
|
||||
3 40 72 38
|
||||
3 72 70 38
|
||||
3 38 70 36
|
||||
3 70 68 36
|
||||
3 32 31 30
|
||||
3 31 29 30
|
||||
3 30 29 28
|
||||
3 29 27 28
|
||||
3 28 27 26
|
||||
3 27 25 26
|
||||
3 26 25 24
|
||||
3 25 23 24
|
||||
3 24 23 22
|
||||
3 23 21 22
|
||||
3 22 21 20
|
||||
3 21 19 20
|
||||
3 20 19 18
|
||||
3 19 17 18
|
||||
3 18 17 16
|
||||
3 17 15 16
|
||||
3 16 15 14
|
||||
3 15 13 14
|
||||
3 14 13 12
|
||||
3 13 11 12
|
||||
3 12 11 10
|
||||
3 11 9 10
|
||||
3 10 9 8
|
||||
3 9 7 8
|
||||
3 8 7 6
|
||||
3 7 5 6
|
||||
3 6 5 4
|
||||
3 5 3 4
|
||||
3 4 3 2
|
||||
3 3 1 2
|
||||
3 2 1 0
|
||||
3 12 45 14
|
||||
3 45 47 14
|
||||
3 14 47 16
|
||||
3 47 49 16
|
||||
3 49 50 16
|
||||
3 16 50 18
|
||||
3 50 52 18
|
||||
3 18 52 20
|
||||
3 52 54 20
|
||||
3 20 54 22
|
||||
3 54 56 22
|
||||
3 22 56 24
|
||||
3 24 56 26
|
||||
3 56 58 26
|
||||
3 26 58 28
|
||||
3 58 60 28
|
||||
3 28 60 30
|
||||
3 60 62 30
|
||||
3 30 62 32
|
||||
3 62 64 32
|
||||
3 32 64 31
|
||||
3 64 63 31
|
||||
3 31 63 29
|
||||
3 63 61 29
|
||||
3 29 61 27
|
||||
3 61 59 27
|
||||
3 27 59 25
|
||||
3 59 57 25
|
||||
3 25 57 23
|
||||
3 57 55 23
|
||||
3 23 55 21
|
||||
3 55 53 21
|
||||
3 21 53 19
|
||||
3 53 51 19
|
||||
3 19 51 17
|
||||
3 51 48 17
|
||||
3 17 48 15
|
||||
3 48 46 15
|
||||
3 15 46 13
|
||||
3 46 44 13
|
||||
3 13 44 11
|
||||
3 44 42 11
|
||||
3 11 42 9
|
||||
3 42 40 9
|
||||
3 9 40 7
|
||||
3 40 38 7
|
||||
3 7 38 5
|
||||
3 38 36 5
|
||||
3 5 36 3
|
||||
3 36 34 3
|
||||
3 3 34 1
|
||||
3 34 33 1
|
||||
3 1 33 0
|
||||
3 33 35 0
|
||||
3 0 35 2
|
||||
3 35 37 2
|
||||
3 2 37 4
|
||||
3 37 39 4
|
||||
3 4 39 6
|
||||
3 39 41 6
|
||||
3 6 41 8
|
||||
3 8 41 10
|
||||
3 41 43 10
|
||||
3 10 43 12
|
||||
3 43 45 12
|
||||
|
||||
|
|
@ -0,0 +1,486 @@
|
|||
OFF
|
||||
162 320 0
|
||||
|
||||
0 0.3 0
|
||||
0.17888 0.13416 0
|
||||
0.05528 0.13416 -0.42535
|
||||
-0.14472 0.13416 -0.26285
|
||||
-0.14472 0.13416 0.26285
|
||||
0.05528 0.13416 0.42535
|
||||
0.14472 -0.13416 -0.26285
|
||||
-0.05528 -0.13416 -0.42535
|
||||
-0.17888 -0.13416 0
|
||||
-0.05528 -0.13416 0.42535
|
||||
0.14472 -0.13416 0.26285
|
||||
0 -0.3 0
|
||||
0.05466 0.28857 0
|
||||
0.10514 0.25521 0
|
||||
0.14764 0.20238 0
|
||||
0.016888 0.28857 -0.12995
|
||||
0.0325 0.25521 -0.25
|
||||
0.04562 0.20238 -0.351
|
||||
-0.04422 0.28857 -0.0803
|
||||
-0.08506 0.25521 -0.1545
|
||||
-0.11944 0.20238 -0.21695
|
||||
-0.04422 0.28857 0.0803
|
||||
-0.08506 0.25521 0.1545
|
||||
-0.11944 0.20238 0.21695
|
||||
0.016888 0.28857 0.12995
|
||||
0.0325 0.25521 0.25
|
||||
0.04562 0.20238 0.351
|
||||
0.16452 0.15171 -0.12995
|
||||
0.13764 0.15771 -0.25
|
||||
0.10028 0.15171 -0.351
|
||||
0.0014062 0.15171 -0.43135
|
||||
-0.05258 0.15771 -0.4045
|
||||
-0.10256 0.15171 -0.3469
|
||||
-0.16366 0.15171 -0.13665
|
||||
-0.17014 0.15771 0
|
||||
-0.16366 0.15171 0.13665
|
||||
-0.10256 0.15171 0.3469
|
||||
-0.05258 0.15771 0.4045
|
||||
0.0014064 0.15171 0.43135
|
||||
0.10028 0.15171 0.351
|
||||
0.13764 0.15771 0.25
|
||||
0.16452 0.15171 0.12995
|
||||
0.19186 0.06975 -0.0803
|
||||
0.19022 0 -0.1545
|
||||
0.1741 -0.06975 -0.21695
|
||||
0.02874 0.06975 -0.48095
|
||||
0 0 -0.5
|
||||
-0.02874 -0.06975 -0.48095
|
||||
-0.1741 0.06975 -0.21695
|
||||
-0.19022 0 -0.1545
|
||||
-0.19186 -0.06975 -0.0803
|
||||
-0.13632 0.06975 0.3469
|
||||
-0.11756 0 0.4045
|
||||
-0.08984 -0.06975 0.43135
|
||||
0.08984 0.06975 0.43135
|
||||
0.11756 0 0.4045
|
||||
0.13632 -0.06975 0.3469
|
||||
0.19186 0.06975 0.0803
|
||||
0.19022 0 0.1545
|
||||
0.1741 -0.06975 0.21695
|
||||
0.08984 0.06975 -0.43135
|
||||
0.11756 0 -0.4045
|
||||
0.13632 -0.06975 -0.3469
|
||||
-0.13632 0.06975 -0.3469
|
||||
-0.11756 0 -0.4045
|
||||
-0.08984 -0.06975 -0.43135
|
||||
-0.1741 0.06975 0.21695
|
||||
-0.19022 0 0.1545
|
||||
-0.19186 -0.06975 0.0803
|
||||
0.02874 0.06975 0.48095
|
||||
0 0 0.5
|
||||
-0.02874 -0.06975 0.48095
|
||||
0.10256 -0.15171 -0.3469
|
||||
0.05258 -0.15771 -0.4045
|
||||
-0.0014062 -0.15171 -0.43135
|
||||
-0.10028 -0.15171 -0.351
|
||||
-0.13764 -0.15771 -0.25
|
||||
-0.16452 -0.15171 -0.12995
|
||||
-0.16452 -0.15171 0.12995
|
||||
-0.13764 -0.15771 0.25
|
||||
-0.10028 -0.15171 0.351
|
||||
-0.0014062 -0.15171 0.43135
|
||||
0.05258 -0.15771 0.4045
|
||||
0.10256 -0.15171 0.3469
|
||||
0.16366 -0.15171 0.13665
|
||||
0.17014 -0.15771 0
|
||||
0.16366 -0.15171 -0.13665
|
||||
0.04422 -0.28857 -0.0803
|
||||
0.08506 -0.25521 -0.1545
|
||||
0.11944 -0.20238 -0.21695
|
||||
-0.016888 -0.28857 -0.12995
|
||||
-0.0325 -0.25521 -0.25
|
||||
-0.04562 -0.20238 -0.351
|
||||
-0.05466 -0.28857 0
|
||||
-0.10514 -0.25521 0
|
||||
-0.14764 -0.20238 0
|
||||
-0.016888 -0.28857 0.12995
|
||||
-0.0325 -0.25521 0.25
|
||||
-0.04562 -0.20238 0.351
|
||||
0.04422 -0.28857 0.0803
|
||||
0.08506 -0.25521 0.1545
|
||||
0.11944 -0.20238 0.21695
|
||||
0.07236 0.26832 -0.13145
|
||||
0.12358 0.22212 -0.13235
|
||||
0.08854 0.22212 -0.2529
|
||||
-0.02764 0.26832 -0.21265
|
||||
-0.012158 0.22212 -0.3347
|
||||
-0.06886 0.22212 -0.28865
|
||||
-0.08944 0.26832 0
|
||||
-0.13108 0.22212 -0.0745
|
||||
-0.13108 0.22212 0.0745
|
||||
-0.02764 0.26832 0.21265
|
||||
-0.06886 0.22212 0.28865
|
||||
-0.012158 0.22212 0.3347
|
||||
0.07236 0.26832 0.13145
|
||||
0.08854 0.22212 0.2529
|
||||
0.12358 0.22212 0.13235
|
||||
0.2 0 0
|
||||
0.19108 -0.07653 0.0745
|
||||
0.19108 -0.07653 -0.0745
|
||||
0.0618 0 -0.47555
|
||||
0.0874 -0.07653 -0.43125
|
||||
0.0307 -0.07653 -0.47735
|
||||
-0.1618 0 -0.2939
|
||||
-0.13706 -0.07653 -0.34105
|
||||
-0.1721 -0.07653 -0.2205
|
||||
-0.1618 0 0.2939
|
||||
-0.1721 -0.07653 0.2205
|
||||
-0.13706 -0.07653 0.34105
|
||||
0.0618 0 0.47555
|
||||
0.0307 -0.07653 0.47735
|
||||
0.0874 -0.07653 0.43125
|
||||
0.1618 0 -0.2939
|
||||
0.13706 0.07653 -0.34105
|
||||
0.1721 0.07653 -0.2205
|
||||
-0.0618 0 -0.47555
|
||||
-0.0874 0.07653 -0.43125
|
||||
-0.0307 0.07653 -0.47735
|
||||
-0.2 0 0
|
||||
-0.19108 0.07653 0.0745
|
||||
-0.19108 0.07653 -0.0745
|
||||
-0.0618 0 0.47555
|
||||
-0.0307 0.07653 0.47735
|
||||
-0.0874 0.07653 0.43125
|
||||
0.1618 0 0.2939
|
||||
0.1721 0.07653 0.2205
|
||||
0.13706 0.07653 0.34105
|
||||
0.02764 -0.26832 -0.21265
|
||||
0.012158 -0.22212 -0.3347
|
||||
0.06886 -0.22212 -0.28865
|
||||
-0.07236 -0.26832 -0.13145
|
||||
-0.12358 -0.22212 -0.13235
|
||||
-0.08854 -0.22212 -0.2529
|
||||
-0.07236 -0.26832 0.13145
|
||||
-0.08854 -0.22212 0.2529
|
||||
-0.12358 -0.22212 0.13235
|
||||
0.02764 -0.26832 0.21265
|
||||
0.06886 -0.22212 0.28865
|
||||
0.012158 -0.22212 0.3347
|
||||
0.08944 -0.26832 0
|
||||
0.13108 -0.22212 -0.0745
|
||||
0.13108 -0.22212 0.0745
|
||||
3 0 12 15
|
||||
3 12 13 102
|
||||
3 12 102 15
|
||||
3 15 102 16
|
||||
3 13 14 103
|
||||
3 13 103 102
|
||||
3 102 103 104
|
||||
3 102 104 16
|
||||
3 16 104 17
|
||||
3 14 1 27
|
||||
3 14 27 103
|
||||
3 103 27 28
|
||||
3 103 28 104
|
||||
3 104 28 29
|
||||
3 104 29 17
|
||||
3 17 29 2
|
||||
3 0 15 18
|
||||
3 15 16 105
|
||||
3 15 105 18
|
||||
3 18 105 19
|
||||
3 16 17 106
|
||||
3 16 106 105
|
||||
3 105 106 107
|
||||
3 105 107 19
|
||||
3 19 107 20
|
||||
3 17 2 30
|
||||
3 17 30 106
|
||||
3 106 30 31
|
||||
3 106 31 107
|
||||
3 107 31 32
|
||||
3 107 32 20
|
||||
3 20 32 3
|
||||
3 0 18 21
|
||||
3 18 19 108
|
||||
3 18 108 21
|
||||
3 21 108 22
|
||||
3 19 20 109
|
||||
3 19 109 108
|
||||
3 108 109 110
|
||||
3 108 110 22
|
||||
3 22 110 23
|
||||
3 20 3 33
|
||||
3 20 33 109
|
||||
3 109 33 34
|
||||
3 109 34 110
|
||||
3 110 34 35
|
||||
3 110 35 23
|
||||
3 23 35 4
|
||||
3 0 21 24
|
||||
3 21 22 111
|
||||
3 21 111 24
|
||||
3 24 111 25
|
||||
3 22 23 112
|
||||
3 22 112 111
|
||||
3 111 112 113
|
||||
3 111 113 25
|
||||
3 25 113 26
|
||||
3 23 4 36
|
||||
3 23 36 112
|
||||
3 112 36 37
|
||||
3 112 37 113
|
||||
3 113 37 38
|
||||
3 113 38 26
|
||||
3 26 38 5
|
||||
3 0 24 12
|
||||
3 24 25 114
|
||||
3 24 114 12
|
||||
3 12 114 13
|
||||
3 25 26 115
|
||||
3 25 115 114
|
||||
3 114 115 116
|
||||
3 114 116 13
|
||||
3 13 116 14
|
||||
3 26 5 39
|
||||
3 26 39 115
|
||||
3 115 39 40
|
||||
3 115 40 116
|
||||
3 116 40 41
|
||||
3 116 41 14
|
||||
3 14 41 1
|
||||
3 1 57 42
|
||||
3 57 58 117
|
||||
3 57 117 42
|
||||
3 42 117 43
|
||||
3 58 59 118
|
||||
3 58 118 117
|
||||
3 117 118 119
|
||||
3 117 119 43
|
||||
3 43 119 44
|
||||
3 59 10 84
|
||||
3 59 84 118
|
||||
3 118 84 85
|
||||
3 118 85 119
|
||||
3 119 85 86
|
||||
3 119 86 44
|
||||
3 44 86 6
|
||||
3 2 60 45
|
||||
3 60 61 120
|
||||
3 60 120 45
|
||||
3 45 120 46
|
||||
3 61 62 121
|
||||
3 61 121 120
|
||||
3 120 121 122
|
||||
3 120 122 46
|
||||
3 46 122 47
|
||||
3 62 6 72
|
||||
3 62 72 121
|
||||
3 121 72 73
|
||||
3 121 73 122
|
||||
3 122 73 74
|
||||
3 122 74 47
|
||||
3 47 74 7
|
||||
3 3 63 48
|
||||
3 63 64 123
|
||||
3 63 123 48
|
||||
3 48 123 49
|
||||
3 64 65 124
|
||||
3 64 124 123
|
||||
3 123 124 125
|
||||
3 123 125 49
|
||||
3 49 125 50
|
||||
3 65 7 75
|
||||
3 65 75 124
|
||||
3 124 75 76
|
||||
3 124 76 125
|
||||
3 125 76 77
|
||||
3 125 77 50
|
||||
3 50 77 8
|
||||
3 4 66 51
|
||||
3 66 67 126
|
||||
3 66 126 51
|
||||
3 51 126 52
|
||||
3 67 68 127
|
||||
3 67 127 126
|
||||
3 126 127 128
|
||||
3 126 128 52
|
||||
3 52 128 53
|
||||
3 68 8 78
|
||||
3 68 78 127
|
||||
3 127 78 79
|
||||
3 127 79 128
|
||||
3 128 79 80
|
||||
3 128 80 53
|
||||
3 53 80 9
|
||||
3 5 69 54
|
||||
3 69 70 129
|
||||
3 69 129 54
|
||||
3 54 129 55
|
||||
3 70 71 130
|
||||
3 70 130 129
|
||||
3 129 130 131
|
||||
3 129 131 55
|
||||
3 55 131 56
|
||||
3 71 9 81
|
||||
3 71 81 130
|
||||
3 130 81 82
|
||||
3 130 82 131
|
||||
3 131 82 83
|
||||
3 131 83 56
|
||||
3 56 83 10
|
||||
3 6 62 44
|
||||
3 62 61 132
|
||||
3 62 132 44
|
||||
3 44 132 43
|
||||
3 61 60 133
|
||||
3 61 133 132
|
||||
3 132 133 134
|
||||
3 132 134 43
|
||||
3 43 134 42
|
||||
3 60 2 29
|
||||
3 60 29 133
|
||||
3 133 29 28
|
||||
3 133 28 134
|
||||
3 134 28 27
|
||||
3 134 27 42
|
||||
3 42 27 1
|
||||
3 7 65 47
|
||||
3 65 64 135
|
||||
3 65 135 47
|
||||
3 47 135 46
|
||||
3 64 63 136
|
||||
3 64 136 135
|
||||
3 135 136 137
|
||||
3 135 137 46
|
||||
3 46 137 45
|
||||
3 63 3 32
|
||||
3 63 32 136
|
||||
3 136 32 31
|
||||
3 136 31 137
|
||||
3 137 31 30
|
||||
3 137 30 45
|
||||
3 45 30 2
|
||||
3 8 68 50
|
||||
3 68 67 138
|
||||
3 68 138 50
|
||||
3 50 138 49
|
||||
3 67 66 139
|
||||
3 67 139 138
|
||||
3 138 139 140
|
||||
3 138 140 49
|
||||
3 49 140 48
|
||||
3 66 4 35
|
||||
3 66 35 139
|
||||
3 139 35 34
|
||||
3 139 34 140
|
||||
3 140 34 33
|
||||
3 140 33 48
|
||||
3 48 33 3
|
||||
3 9 71 53
|
||||
3 71 70 141
|
||||
3 71 141 53
|
||||
3 53 141 52
|
||||
3 70 69 142
|
||||
3 70 142 141
|
||||
3 141 142 143
|
||||
3 141 143 52
|
||||
3 52 143 51
|
||||
3 69 5 38
|
||||
3 69 38 142
|
||||
3 142 38 37
|
||||
3 142 37 143
|
||||
3 143 37 36
|
||||
3 143 36 51
|
||||
3 51 36 4
|
||||
3 10 59 56
|
||||
3 59 58 144
|
||||
3 59 144 56
|
||||
3 56 144 55
|
||||
3 58 57 145
|
||||
3 58 145 144
|
||||
3 144 145 146
|
||||
3 144 146 55
|
||||
3 55 146 54
|
||||
3 57 1 41
|
||||
3 57 41 145
|
||||
3 145 41 40
|
||||
3 145 40 146
|
||||
3 146 40 39
|
||||
3 146 39 54
|
||||
3 54 39 5
|
||||
3 11 90 87
|
||||
3 90 91 147
|
||||
3 90 147 87
|
||||
3 87 147 88
|
||||
3 91 92 148
|
||||
3 91 148 147
|
||||
3 147 148 149
|
||||
3 147 149 88
|
||||
3 88 149 89
|
||||
3 92 7 74
|
||||
3 92 74 148
|
||||
3 148 74 73
|
||||
3 148 73 149
|
||||
3 149 73 72
|
||||
3 149 72 89
|
||||
3 89 72 6
|
||||
3 11 93 90
|
||||
3 93 94 150
|
||||
3 93 150 90
|
||||
3 90 150 91
|
||||
3 94 95 151
|
||||
3 94 151 150
|
||||
3 150 151 152
|
||||
3 150 152 91
|
||||
3 91 152 92
|
||||
3 95 8 77
|
||||
3 95 77 151
|
||||
3 151 77 76
|
||||
3 151 76 152
|
||||
3 152 76 75
|
||||
3 152 75 92
|
||||
3 92 75 7
|
||||
3 11 96 93
|
||||
3 96 97 153
|
||||
3 96 153 93
|
||||
3 93 153 94
|
||||
3 97 98 154
|
||||
3 97 154 153
|
||||
3 153 154 155
|
||||
3 153 155 94
|
||||
3 94 155 95
|
||||
3 98 9 80
|
||||
3 98 80 154
|
||||
3 154 80 79
|
||||
3 154 79 155
|
||||
3 155 79 78
|
||||
3 155 78 95
|
||||
3 95 78 8
|
||||
3 11 99 96
|
||||
3 99 100 156
|
||||
3 99 156 96
|
||||
3 96 156 97
|
||||
3 100 101 157
|
||||
3 100 157 156
|
||||
3 156 157 158
|
||||
3 156 158 97
|
||||
3 97 158 98
|
||||
3 101 10 83
|
||||
3 101 83 157
|
||||
3 157 83 82
|
||||
3 157 82 158
|
||||
3 158 82 81
|
||||
3 158 81 98
|
||||
3 98 81 9
|
||||
3 11 87 99
|
||||
3 87 88 159
|
||||
3 87 159 99
|
||||
3 99 159 100
|
||||
3 88 89 160
|
||||
3 88 160 159
|
||||
3 159 160 161
|
||||
3 159 161 100
|
||||
3 100 161 101
|
||||
3 89 6 86
|
||||
3 89 86 160
|
||||
3 160 86 85
|
||||
3 160 85 161
|
||||
3 161 85 84
|
||||
3 161 84 101
|
||||
3 101 84 10
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
OFF
|
||||
12 20 0
|
||||
-0.5257310271 0.0000000000 -0.8506510258
|
||||
0.5257310271 0.0000000000 -0.8506510258
|
||||
0.5257310271 0.0000000000 0.8506510258
|
||||
-0.5257310271 0.0000000000 0.8506510258
|
||||
-0.8506510258 -0.5257310271 0.0000000000
|
||||
-0.8506510258 0.5257310271 0.0000000000
|
||||
0.8506510258 0.5257310271 0.0000000000
|
||||
0.8506510258 -0.5257310271 0.0000000000
|
||||
0.0000000000 -0.8506510258 0.5257310271
|
||||
0.0000000000 -0.8506510258 -0.5257310271
|
||||
0.0000000000 0.8506510258 -0.5257310271
|
||||
0.0000000000 0.8506510258 0.5257310271
|
||||
3 1 9 0
|
||||
3 10 1 0
|
||||
3 5 10 0
|
||||
3 4 5 0
|
||||
3 9 4 0
|
||||
3 8 2 3
|
||||
3 4 8 3
|
||||
3 5 4 3
|
||||
3 11 5 3
|
||||
3 2 11 3
|
||||
3 11 2 6
|
||||
3 10 11 6
|
||||
3 1 10 6
|
||||
3 7 1 6
|
||||
3 2 7 6
|
||||
3 11 10 5
|
||||
3 9 8 4
|
||||
3 7 2 8
|
||||
3 9 7 8
|
||||
3 1 7 9
|
||||
|
|
@ -0,0 +1,671 @@
|
|||
OFF
|
||||
221 446 0
|
||||
|
||||
0.18987 0.5 0.0145757
|
||||
0.18987 -0.5 0.0145757
|
||||
0.160511 -0.5 0.0325677
|
||||
0.160511 0.5 0.0325677
|
||||
0.128697 -0.5 0.0457447
|
||||
0.128697 0.5 0.0457447
|
||||
0.0952137 -0.5 0.0537838
|
||||
0.0952137 0.5 0.0537838
|
||||
0.0608858 -0.5 0.0564848
|
||||
0.0608858 0.5 0.0564848
|
||||
0.0265575 -0.5 0.0537838
|
||||
0.0265575 0.5 0.0537838
|
||||
-0.0069256 -0.5 0.0457447
|
||||
-0.0069256 0.5 0.0457447
|
||||
-0.038739 -0.5 0.0325677
|
||||
-0.038739 0.5 0.0325677
|
||||
-0.0680987 -0.5 0.0145757
|
||||
-0.0680987 0.5 0.0145757
|
||||
-0.0942827 -0.5 -0.00778743
|
||||
-0.0942827 0.5 -0.00778743
|
||||
-0.116646 -0.5 -0.0339725
|
||||
-0.116646 0.5 -0.0339725
|
||||
-0.134639 -0.5 -0.0633324
|
||||
-0.134639 0.5 -0.0633324
|
||||
-0.147815 -0.5 -0.0951457
|
||||
-0.147815 0.5 -0.0951457
|
||||
-0.155855 -0.5 -0.128628
|
||||
-0.155855 0.5 -0.128628
|
||||
-0.158556 -0.5 -0.162956
|
||||
-0.158556 0.5 -0.162956
|
||||
-0.155855 -0.5 -0.197285
|
||||
-0.155855 0.5 -0.197285
|
||||
-0.147815 -0.5 -0.230768
|
||||
-0.147815 0.5 -0.230768
|
||||
-0.134639 -0.5 -0.262581
|
||||
-0.134639 0.5 -0.262581
|
||||
-0.116646 -0.5 -0.291941
|
||||
-0.116646 0.5 -0.291941
|
||||
-0.0942827 -0.5 -0.318125
|
||||
-0.0942827 0.5 -0.318125
|
||||
-0.0680987 -0.5 -0.340488
|
||||
-0.0680987 0.5 -0.340488
|
||||
-0.038739 -0.5 -0.358481
|
||||
-0.038739 0.5 -0.358481
|
||||
-0.0069256 -0.5 -0.371658
|
||||
-0.0069256 0.5 -0.371658
|
||||
0.0265574 -0.5 -0.379697
|
||||
0.0265574 0.5 -0.379697
|
||||
0.0608857 -0.5 -0.382398
|
||||
0.0608857 0.5 -0.382398
|
||||
0.0952137 -0.5 -0.379697
|
||||
0.0952137 0.5 -0.379697
|
||||
0.128696 -0.5 -0.371658
|
||||
0.128696 0.5 -0.371658
|
||||
0.16051 -0.5 -0.358481
|
||||
0.16051 0.5 -0.358481
|
||||
0.18987 -0.5 -0.340488
|
||||
0.18987 0.5 -0.340488
|
||||
0.216054 -0.5 -0.318125
|
||||
0.216054 0.5 -0.318125
|
||||
0.238418 -0.5 -0.291941
|
||||
0.238418 0.5 -0.291941
|
||||
0.25641 -0.5 -0.262581
|
||||
0.25641 0.5 -0.262581
|
||||
0.269587 -0.5 -0.230768
|
||||
0.269587 0.5 -0.230768
|
||||
0.277626 -0.5 -0.197285
|
||||
0.277626 0.5 -0.197285
|
||||
0.280327 -0.5 -0.162956
|
||||
0.280327 0.5 -0.162956
|
||||
0.277626 -0.5 -0.128628
|
||||
0.277626 0.5 -0.128628
|
||||
0.269587 -0.5 -0.0951457
|
||||
0.269587 0.5 -0.0951457
|
||||
0.25641 -0.5 -0.0633324
|
||||
0.25641 0.5 -0.0633324
|
||||
0.238418 -0.5 -0.0339725
|
||||
0.238418 0.5 -0.0339725
|
||||
0.216054 -0.5 -0.00778851
|
||||
0.216054 0.5 -0.00778851
|
||||
0.157965 -0.5 -0.461734
|
||||
0.203507 -0.5 -0.442869
|
||||
0.24554 -0.5 -0.417111
|
||||
0.283026 -0.5 -0.385097
|
||||
0.315041 -0.5 -0.347611
|
||||
0.340798 -0.5 -0.305579
|
||||
0.359662 -0.5 -0.260035
|
||||
0.371171 -0.5 -0.212101
|
||||
0.375039 -0.5 -0.162956
|
||||
0.371171 -0.5 -0.113812
|
||||
0.359662 -0.5 -0.0658783
|
||||
0.340799 -0.5 -0.0203345
|
||||
0.315041 -0.5 0.0216976
|
||||
0.283026 -0.5 0.0591838
|
||||
0.245541 -0.5 0.0911989
|
||||
0.203508 -0.5 0.116956
|
||||
0.157965 -0.5 0.13582
|
||||
0.11003 -0.5 0.147329
|
||||
0.0608858 -0.5 0.151196
|
||||
-0.375039 -0.5 -0.162956
|
||||
0.0608858 -0.5 -0.47711
|
||||
0.11003 -0.5 -0.473241
|
||||
0.203508 0.5 0.116956
|
||||
0.245541 0.5 0.0911989
|
||||
0.283026 0.5 0.0591838
|
||||
0.315041 0.5 0.0216986
|
||||
0.340799 0.5 -0.0203345
|
||||
0.359662 0.5 -0.0658783
|
||||
0.371171 0.5 -0.113812
|
||||
0.375039 0.5 -0.162956
|
||||
0.371171 0.5 -0.212101
|
||||
0.359662 0.5 -0.260035
|
||||
0.340798 0.5 -0.305579
|
||||
0.315041 0.5 -0.347611
|
||||
0.283026 0.5 -0.385097
|
||||
0.24554 0.5 -0.417111
|
||||
0.203507 0.5 -0.442869
|
||||
0.157965 0.5 -0.461734
|
||||
0.11003 0.5 -0.473241
|
||||
0.0608858 0.5 -0.47711
|
||||
-0.375039 0.5 -0.162956
|
||||
0.0608858 0.5 0.151196
|
||||
0.11003 0.5 0.147329
|
||||
0.157965 0.5 0.13582
|
||||
-0.375039 -0.5 -0.47711
|
||||
-0.157078 -0.5 0.151196
|
||||
-0.375039 -0.5 0.151196
|
||||
-0.375039 0.5 -0.47711
|
||||
-0.375039 -0.185847 0.47711
|
||||
-0.157078 -0.185847 0.47711
|
||||
-0.157078 0.5 0.47711
|
||||
-0.375039 0.5 0.47711
|
||||
-0.375039 0.5 0.151196
|
||||
-0.157078 0.5 0.151196
|
||||
-0.375039 -0.185847 0.151196
|
||||
-0.375039 -0.5 0.47711
|
||||
-0.157078 -0.5 0.47711
|
||||
0.0608859 -0.5 0.47711
|
||||
0.0608859 -0.185847 0.47711
|
||||
-0.157078 -0.185847 0.151196
|
||||
0.0608858 -0.185847 0.151196
|
||||
-0.375039 -0.315312 0.400904
|
||||
-0.375039 -0.329311 0.404264
|
||||
-0.375039 -0.343663 0.405393
|
||||
-0.375039 -0.358016 0.404264
|
||||
-0.375039 -0.372015 0.400904
|
||||
-0.375039 -0.385316 0.395395
|
||||
-0.375039 -0.397591 0.387872
|
||||
-0.375039 -0.408538 0.378521
|
||||
-0.375039 -0.417888 0.367575
|
||||
-0.375039 -0.42541 0.355299
|
||||
-0.375039 -0.43092 0.341999
|
||||
-0.375039 -0.434281 0.328
|
||||
-0.375039 -0.43541 0.313648
|
||||
-0.375039 -0.434281 0.299295
|
||||
-0.375039 -0.43092 0.285296
|
||||
-0.375039 -0.42541 0.271996
|
||||
-0.375039 -0.417888 0.25972
|
||||
-0.375039 -0.408538 0.248773
|
||||
-0.375039 -0.397591 0.239422
|
||||
-0.375039 -0.385316 0.2319
|
||||
-0.375039 -0.372015 0.22639
|
||||
-0.375039 -0.358016 0.223031
|
||||
-0.375039 -0.343663 0.221901
|
||||
-0.375039 -0.329311 0.223031
|
||||
-0.375039 -0.315312 0.22639
|
||||
-0.375039 -0.302011 0.2319
|
||||
-0.375039 -0.289736 0.239422
|
||||
-0.375039 -0.278789 0.248773
|
||||
-0.375039 -0.269439 0.25972
|
||||
-0.375039 -0.261916 0.271996
|
||||
-0.375039 -0.256407 0.285296
|
||||
-0.375039 -0.253046 0.299295
|
||||
-0.375039 -0.251917 0.313648
|
||||
-0.375039 -0.253046 0.328
|
||||
-0.375039 -0.256407 0.341999
|
||||
-0.375039 -0.261916 0.355299
|
||||
-0.375039 -0.269439 0.367575
|
||||
-0.375039 -0.278789 0.378521
|
||||
-0.375039 -0.289736 0.387872
|
||||
-0.375039 -0.302011 0.395395
|
||||
0.0608859 -0.302011 0.395395
|
||||
0.0608859 -0.289736 0.387872
|
||||
0.0608859 -0.278789 0.378521
|
||||
0.0608859 -0.269439 0.367575
|
||||
0.0608859 -0.261916 0.355299
|
||||
0.0608859 -0.256407 0.341999
|
||||
0.0608859 -0.253046 0.328
|
||||
0.0608859 -0.251917 0.313648
|
||||
0.0608859 -0.253046 0.299295
|
||||
0.0608859 -0.256407 0.285296
|
||||
0.0608859 -0.261916 0.271996
|
||||
0.0608859 -0.269439 0.25972
|
||||
0.0608859 -0.278789 0.248773
|
||||
0.0608859 -0.289736 0.239422
|
||||
0.0608859 -0.302011 0.2319
|
||||
0.0608859 -0.315312 0.22639
|
||||
0.0608859 -0.329311 0.223031
|
||||
0.0608859 -0.343663 0.221901
|
||||
0.0608859 -0.358016 0.223031
|
||||
0.0608859 -0.372015 0.22639
|
||||
0.0608859 -0.385316 0.2319
|
||||
0.0608859 -0.397591 0.239422
|
||||
0.0608859 -0.408538 0.248773
|
||||
0.0608859 -0.417888 0.25972
|
||||
0.0608859 -0.42541 0.271996
|
||||
0.0608859 -0.43092 0.285296
|
||||
0.0608859 -0.434281 0.299295
|
||||
0.0608859 -0.43541 0.313648
|
||||
0.0608859 -0.434281 0.328
|
||||
0.0608859 -0.43092 0.341999
|
||||
0.0608859 -0.42541 0.355299
|
||||
0.0608859 -0.417888 0.367575
|
||||
0.0608859 -0.408538 0.378521
|
||||
0.0608859 -0.397591 0.387872
|
||||
0.0608859 -0.385316 0.395395
|
||||
0.0608859 -0.372015 0.400904
|
||||
0.0608859 -0.358016 0.404264
|
||||
0.0608859 -0.343663 0.405393
|
||||
0.0608859 -0.329311 0.404264
|
||||
0.0608859 -0.315312 0.400904
|
||||
3 3 0 1
|
||||
3 3 1 2
|
||||
3 5 3 2
|
||||
3 5 2 4
|
||||
3 7 5 4
|
||||
3 7 4 6
|
||||
3 9 7 6
|
||||
3 9 6 8
|
||||
3 11 9 8
|
||||
3 11 8 10
|
||||
3 13 11 10
|
||||
3 13 10 12
|
||||
3 15 13 12
|
||||
3 17 14 16
|
||||
3 19 17 16
|
||||
3 23 21 20
|
||||
3 23 20 22
|
||||
3 25 23 22
|
||||
3 25 22 24
|
||||
3 27 25 24
|
||||
3 27 24 26
|
||||
3 29 27 26
|
||||
3 29 26 28
|
||||
3 31 29 28
|
||||
3 31 28 30
|
||||
3 33 31 30
|
||||
3 33 30 32
|
||||
3 35 33 32
|
||||
3 35 32 34
|
||||
3 37 35 34
|
||||
3 37 34 36
|
||||
3 39 37 36
|
||||
3 39 36 38
|
||||
3 41 39 38
|
||||
3 41 38 40
|
||||
3 43 41 40
|
||||
3 43 40 42
|
||||
3 45 43 42
|
||||
3 45 42 44
|
||||
3 47 45 44
|
||||
3 47 44 46
|
||||
3 49 47 46
|
||||
3 49 46 48
|
||||
3 51 49 48
|
||||
3 51 48 50
|
||||
3 53 51 50
|
||||
3 53 50 52
|
||||
3 55 53 52
|
||||
3 55 52 54
|
||||
3 57 55 54
|
||||
3 57 54 56
|
||||
3 59 57 56
|
||||
3 59 56 58
|
||||
3 61 59 58
|
||||
3 61 58 60
|
||||
3 63 61 60
|
||||
3 63 60 62
|
||||
3 65 63 62
|
||||
3 65 62 64
|
||||
3 67 65 64
|
||||
3 67 64 66
|
||||
3 69 67 66
|
||||
3 69 66 68
|
||||
3 71 69 68
|
||||
3 71 68 70
|
||||
3 73 71 70
|
||||
3 77 75 74
|
||||
3 77 74 76
|
||||
3 79 77 76
|
||||
3 79 76 78
|
||||
3 0 79 78
|
||||
3 0 78 1
|
||||
3 99 28 26
|
||||
3 30 28 99
|
||||
3 99 26 24
|
||||
3 32 30 99
|
||||
3 99 24 22
|
||||
3 34 32 99
|
||||
3 80 52 101
|
||||
3 83 60 58
|
||||
3 90 70 89
|
||||
3 99 22 20
|
||||
3 36 34 99
|
||||
3 20 126 99
|
||||
3 124 38 36
|
||||
3 10 97 98
|
||||
3 97 8 6
|
||||
3 97 6 4
|
||||
3 96 2 95
|
||||
3 89 70 68
|
||||
3 87 66 64
|
||||
3 101 52 50
|
||||
3 101 50 48
|
||||
3 100 48 46
|
||||
3 120 29 31
|
||||
3 27 29 120
|
||||
3 120 31 33
|
||||
3 25 27 120
|
||||
3 120 33 35
|
||||
3 23 25 120
|
||||
3 123 95 102
|
||||
3 55 115 116
|
||||
3 120 35 37
|
||||
3 103 79 0
|
||||
3 113 59 61
|
||||
3 37 39 127
|
||||
3 19 21 120
|
||||
3 118 49 51
|
||||
3 118 51 53
|
||||
3 118 53 55
|
||||
3 111 61 63
|
||||
3 111 63 65
|
||||
3 123 0 3
|
||||
3 123 3 5
|
||||
3 122 123 5
|
||||
3 122 5 7
|
||||
3 122 7 9
|
||||
3 122 9 11
|
||||
3 122 11 13
|
||||
3 13 133 121
|
||||
3 15 17 133
|
||||
3 133 17 19
|
||||
3 88 109 108
|
||||
3 88 108 89
|
||||
3 87 110 109
|
||||
3 87 109 88
|
||||
3 86 111 110
|
||||
3 86 110 87
|
||||
3 85 112 111
|
||||
3 85 111 86
|
||||
3 84 113 112
|
||||
3 84 112 85
|
||||
3 83 113 84
|
||||
3 82 114 83
|
||||
3 81 116 115
|
||||
3 81 115 82
|
||||
3 80 116 81
|
||||
3 101 118 117
|
||||
3 101 117 80
|
||||
3 100 119 118
|
||||
3 100 118 101
|
||||
3 97 122 121
|
||||
3 96 123 122
|
||||
3 96 122 97
|
||||
3 95 123 96
|
||||
3 92 105 104
|
||||
3 92 104 93
|
||||
3 91 106 105
|
||||
3 91 105 92
|
||||
3 90 107 106
|
||||
3 90 106 91
|
||||
3 89 108 107
|
||||
3 89 107 90
|
||||
3 131 128 129
|
||||
3 131 129 130
|
||||
3 124 127 119
|
||||
3 124 119 100
|
||||
3 120 127 124
|
||||
3 120 124 99
|
||||
3 120 99 126
|
||||
3 120 126 134
|
||||
3 120 134 132
|
||||
3 128 135 136
|
||||
3 128 136 129
|
||||
3 129 136 137
|
||||
3 129 137 138
|
||||
3 121 133 139
|
||||
3 129 139 133
|
||||
3 129 133 130
|
||||
3 130 133 132
|
||||
3 130 132 131
|
||||
3 131 132 134
|
||||
3 172 128 131
|
||||
3 135 126 125
|
||||
3 135 125 136
|
||||
3 167 168 134
|
||||
3 134 168 169
|
||||
3 166 167 134
|
||||
3 134 169 170
|
||||
3 165 166 134
|
||||
3 165 134 126
|
||||
3 164 165 126
|
||||
3 163 164 126
|
||||
3 162 163 126
|
||||
3 161 162 126
|
||||
3 160 161 126
|
||||
3 159 160 126
|
||||
3 158 159 126
|
||||
3 157 158 126
|
||||
3 156 157 126
|
||||
3 134 170 171
|
||||
3 134 171 172
|
||||
3 128 172 173
|
||||
3 128 173 174
|
||||
3 128 174 175
|
||||
3 128 175 176
|
||||
3 128 176 177
|
||||
3 128 177 178
|
||||
3 128 178 179
|
||||
3 128 179 180
|
||||
3 128 180 141
|
||||
3 135 128 141
|
||||
3 135 141 142
|
||||
3 135 142 143
|
||||
3 135 143 144
|
||||
3 135 144 145
|
||||
3 135 145 146
|
||||
3 135 146 147
|
||||
3 135 147 148
|
||||
3 135 148 149
|
||||
3 135 149 150
|
||||
3 135 150 151
|
||||
3 155 156 126
|
||||
3 155 126 135
|
||||
3 154 155 135
|
||||
3 153 154 135
|
||||
3 152 153 135
|
||||
3 135 151 152
|
||||
3 136 125 98
|
||||
3 136 98 137
|
||||
3 202 203 98
|
||||
3 98 203 204
|
||||
3 201 202 98
|
||||
3 98 204 205
|
||||
3 200 201 98
|
||||
3 200 98 140
|
||||
3 199 200 140
|
||||
3 198 199 140
|
||||
3 197 198 140
|
||||
3 196 197 140
|
||||
3 195 196 140
|
||||
3 194 195 140
|
||||
3 193 194 140
|
||||
3 192 193 140
|
||||
3 191 192 140
|
||||
3 98 205 206
|
||||
3 137 98 206
|
||||
3 137 206 207
|
||||
3 137 207 208
|
||||
3 137 208 209
|
||||
3 137 209 210
|
||||
3 137 210 211
|
||||
3 137 211 212
|
||||
3 137 212 213
|
||||
3 137 213 214
|
||||
3 137 214 215
|
||||
3 137 215 216
|
||||
3 138 137 216
|
||||
3 138 216 217
|
||||
3 138 217 218
|
||||
3 138 218 219
|
||||
3 138 219 220
|
||||
3 138 220 181
|
||||
3 138 181 182
|
||||
3 138 182 183
|
||||
3 138 183 184
|
||||
3 138 184 185
|
||||
3 138 185 186
|
||||
3 190 191 140
|
||||
3 190 140 138
|
||||
3 189 190 138
|
||||
3 188 189 138
|
||||
3 187 188 138
|
||||
3 138 186 187
|
||||
3 138 140 139
|
||||
3 138 139 129
|
||||
3 184 183 178
|
||||
3 184 178 177
|
||||
3 183 182 179
|
||||
3 183 179 178
|
||||
3 182 181 180
|
||||
3 182 180 179
|
||||
3 181 220 141
|
||||
3 181 141 180
|
||||
3 220 219 142
|
||||
3 220 142 141
|
||||
3 219 218 143
|
||||
3 219 143 142
|
||||
3 218 217 144
|
||||
3 218 144 143
|
||||
3 217 216 145
|
||||
3 217 145 144
|
||||
3 216 215 146
|
||||
3 216 146 145
|
||||
3 215 214 147
|
||||
3 215 147 146
|
||||
3 214 213 148
|
||||
3 214 148 147
|
||||
3 213 212 149
|
||||
3 213 149 148
|
||||
3 212 211 150
|
||||
3 212 150 149
|
||||
3 211 210 151
|
||||
3 211 151 150
|
||||
3 210 209 152
|
||||
3 210 152 151
|
||||
3 209 208 153
|
||||
3 209 153 152
|
||||
3 208 207 154
|
||||
3 208 154 153
|
||||
3 207 206 155
|
||||
3 207 155 154
|
||||
3 206 205 156
|
||||
3 206 156 155
|
||||
3 205 204 157
|
||||
3 205 157 156
|
||||
3 204 203 158
|
||||
3 204 158 157
|
||||
3 203 202 159
|
||||
3 203 159 158
|
||||
3 202 201 160
|
||||
3 202 160 159
|
||||
3 201 200 161
|
||||
3 201 161 160
|
||||
3 200 199 162
|
||||
3 200 162 161
|
||||
3 199 198 163
|
||||
3 199 163 162
|
||||
3 198 197 164
|
||||
3 198 164 163
|
||||
3 197 196 165
|
||||
3 197 165 164
|
||||
3 196 195 166
|
||||
3 196 166 165
|
||||
3 195 194 167
|
||||
3 195 167 166
|
||||
3 194 193 168
|
||||
3 194 168 167
|
||||
3 193 192 169
|
||||
3 193 169 168
|
||||
3 192 191 170
|
||||
3 192 170 169
|
||||
3 191 190 171
|
||||
3 191 171 170
|
||||
3 190 189 172
|
||||
3 190 172 171
|
||||
3 189 188 173
|
||||
3 189 173 172
|
||||
3 188 187 174
|
||||
3 188 174 173
|
||||
3 187 186 175
|
||||
3 187 175 174
|
||||
3 186 185 176
|
||||
3 186 176 175
|
||||
3 185 184 177
|
||||
3 185 177 176
|
||||
3 139 140 121
|
||||
3 97 121 140
|
||||
3 115 55 57
|
||||
3 115 57 59
|
||||
3 113 83 114
|
||||
3 59 113 114
|
||||
3 114 82 115
|
||||
3 114 115 59
|
||||
3 117 118 55
|
||||
3 116 80 117
|
||||
3 116 117 55
|
||||
3 132 133 19
|
||||
3 127 41 43
|
||||
3 39 41 127
|
||||
3 105 75 77
|
||||
3 105 77 79
|
||||
3 103 93 104
|
||||
3 79 103 104
|
||||
3 104 105 79
|
||||
3 106 73 75
|
||||
3 65 67 110
|
||||
3 61 111 112
|
||||
3 112 113 61
|
||||
3 110 67 69
|
||||
3 69 71 109
|
||||
3 109 110 69
|
||||
3 108 109 71
|
||||
3 71 73 107
|
||||
3 106 107 73
|
||||
3 75 105 106
|
||||
3 13 15 133
|
||||
3 121 122 13
|
||||
3 102 103 0
|
||||
3 0 123 102
|
||||
3 45 47 119
|
||||
3 49 118 119
|
||||
3 47 49 119
|
||||
3 127 43 45
|
||||
3 45 119 127
|
||||
3 140 98 97
|
||||
3 125 16 14
|
||||
3 14 12 98
|
||||
3 15 12 14
|
||||
3 127 120 37
|
||||
3 110 111 65
|
||||
3 107 108 71
|
||||
3 98 125 14
|
||||
3 131 134 172
|
||||
3 94 93 103
|
||||
3 94 102 95
|
||||
3 95 1 94
|
||||
3 93 1 78
|
||||
3 1 93 94
|
||||
3 1 95 2
|
||||
3 4 96 97
|
||||
3 2 96 4
|
||||
3 78 92 93
|
||||
3 92 78 76
|
||||
3 91 76 74
|
||||
3 74 90 91
|
||||
3 88 68 66
|
||||
3 86 64 62
|
||||
3 85 62 60
|
||||
3 85 60 84
|
||||
3 82 58 56
|
||||
3 81 56 54
|
||||
3 80 54 52
|
||||
3 124 36 99
|
||||
3 10 98 12
|
||||
3 60 83 84
|
||||
3 46 124 100
|
||||
3 44 124 46
|
||||
3 42 124 44
|
||||
3 40 124 42
|
||||
3 38 124 40
|
||||
3 97 10 8
|
||||
3 66 87 88
|
||||
3 48 100 101
|
||||
3 102 94 103
|
||||
3 76 91 92
|
||||
3 72 74 75
|
||||
3 68 88 89
|
||||
3 64 86 87
|
||||
3 62 85 86
|
||||
3 58 82 83
|
||||
3 56 81 82
|
||||
3 54 80 81
|
||||
3 126 16 125
|
||||
3 17 15 14
|
||||
3 120 132 19
|
||||
3 21 19 20
|
||||
3 23 120 21
|
||||
3 16 18 19
|
||||
3 19 18 20
|
||||
3 20 18 126
|
||||
3 16 126 18
|
||||
3 90 74 72
|
||||
3 73 70 72
|
||||
3 72 70 90
|
||||
3 72 75 73
|
||||
|
||||
|
|
@ -0,0 +1,484 @@
|
|||
OFF
|
||||
160 320 0
|
||||
|
||||
0.170625 -0.5 -1.40397e-007
|
||||
0.168523 -0.5 -0.0266916
|
||||
0.162273 -0.5 -0.052726
|
||||
0.152027 -0.5 -0.077462
|
||||
0.138038 -0.5 -0.100291
|
||||
0.12065 -0.5 -0.12065
|
||||
0.10029 -0.5 -0.138038
|
||||
0.0774619 -0.5 -0.152028
|
||||
0.0527258 -0.5 -0.162274
|
||||
0.0266915 -0.5 -0.168525
|
||||
-5.55112e-017 -0.5 -0.170625
|
||||
-0.0266915 -0.5 -0.168525
|
||||
-0.0527258 -0.5 -0.162274
|
||||
-0.0774619 -0.5 -0.152028
|
||||
-0.10029 -0.5 -0.138038
|
||||
-0.12065 -0.5 -0.12065
|
||||
-0.138039 -0.5 -0.100291
|
||||
-0.152028 -0.5 -0.077462
|
||||
-0.162274 -0.5 -0.052726
|
||||
-0.168523 -0.5 -0.0266916
|
||||
-0.170625 -0.5 -1.40397e-007
|
||||
-0.168523 -0.5 0.0266914
|
||||
-0.162274 -0.5 0.0527257
|
||||
-0.152028 -0.5 0.0774617
|
||||
-0.138039 -0.5 0.10029
|
||||
-0.12065 -0.5 0.12065
|
||||
-0.10029 -0.5 0.138037
|
||||
-0.0774619 -0.5 0.152028
|
||||
-0.0527258 -0.5 0.162273
|
||||
-0.0266915 -0.5 0.168523
|
||||
-5.55112e-017 -0.5 0.170624
|
||||
0.0266916 -0.5 0.168523
|
||||
0.052726 -0.5 0.162273
|
||||
0.0774619 -0.5 0.152028
|
||||
0.100291 -0.5 0.138037
|
||||
0.12065 -0.5 0.12065
|
||||
0.138038 -0.5 0.10029
|
||||
0.152027 -0.5 0.0774617
|
||||
0.162274 -0.5 0.0527257
|
||||
0.168523 -0.5 0.0266914
|
||||
0.170625 0.5 -1.40397e-007
|
||||
0.168523 0.5 -0.0266916
|
||||
0.162273 0.5 -0.052726
|
||||
0.152027 0.5 -0.077462
|
||||
0.138038 0.5 -0.100291
|
||||
0.12065 0.5 -0.12065
|
||||
0.10029 0.5 -0.138038
|
||||
0.0774619 0.5 -0.152028
|
||||
0.0527258 0.5 -0.162274
|
||||
0.0266915 0.5 -0.168525
|
||||
-5.55112e-017 0.5 -0.170625
|
||||
-0.0266915 0.5 -0.168525
|
||||
-0.0527258 0.5 -0.162274
|
||||
-0.0774619 0.5 -0.152028
|
||||
-0.10029 0.5 -0.138038
|
||||
-0.12065 0.5 -0.12065
|
||||
-0.138039 0.5 -0.100291
|
||||
-0.152028 0.5 -0.077462
|
||||
-0.162274 0.5 -0.052726
|
||||
-0.168523 0.5 -0.0266916
|
||||
-0.170625 0.5 -1.40397e-007
|
||||
-0.168523 0.5 0.0266914
|
||||
-0.162274 0.5 0.0527257
|
||||
-0.152028 0.5 0.0774617
|
||||
-0.138039 0.5 0.10029
|
||||
-0.12065 0.5 0.12065
|
||||
-0.10029 0.5 0.138037
|
||||
-0.0774619 0.5 0.152028
|
||||
-0.0527258 0.5 0.162273
|
||||
-0.0266915 0.5 0.168523
|
||||
-5.55112e-017 0.5 0.170624
|
||||
0.0266916 0.5 0.168523
|
||||
0.052726 0.5 0.162273
|
||||
0.0774619 0.5 0.152028
|
||||
0.100291 0.5 0.138037
|
||||
0.12065 0.5 0.12065
|
||||
0.138038 0.5 0.10029
|
||||
0.152027 0.5 0.0774617
|
||||
0.162274 0.5 0.0527257
|
||||
0.168523 0.5 0.0266914
|
||||
0.311022 0.5 -1.40397e-007
|
||||
0.307192 0.5 -0.0486547
|
||||
0.295799 0.5 -0.0961111
|
||||
0.277122 0.5 -0.141201
|
||||
0.251622 0.5 -0.182814
|
||||
0.219925 0.5 -0.219925
|
||||
0.182814 0.5 -0.251622
|
||||
0.141201 0.5 -0.277122
|
||||
0.096111 0.5 -0.295799
|
||||
0.0486546 0.5 -0.307192
|
||||
-5.55112e-017 0.5 -0.311022
|
||||
-0.0486546 0.5 -0.307192
|
||||
-0.096111 0.5 -0.295799
|
||||
-0.1412 0.5 -0.277122
|
||||
-0.182814 0.5 -0.251622
|
||||
-0.219925 0.5 -0.219925
|
||||
-0.251622 0.5 -0.182814
|
||||
-0.277122 0.5 -0.141201
|
||||
-0.295799 0.5 -0.0961111
|
||||
-0.307192 0.5 -0.0486547
|
||||
-0.311022 0.5 -1.40397e-007
|
||||
-0.307192 0.5 0.0486544
|
||||
-0.295799 0.5 0.0961109
|
||||
-0.277122 0.5 0.1412
|
||||
-0.251622 0.5 0.182814
|
||||
-0.219925 0.5 0.219925
|
||||
-0.182814 0.5 0.251622
|
||||
-0.1412 0.5 0.277122
|
||||
-0.096111 0.5 0.295799
|
||||
-0.0486546 0.5 0.307192
|
||||
-5.55112e-017 0.5 0.311022
|
||||
0.0486546 0.5 0.307192
|
||||
0.0961111 0.5 0.295799
|
||||
0.141201 0.5 0.277122
|
||||
0.182814 0.5 0.251622
|
||||
0.219925 0.5 0.219925
|
||||
0.251622 0.5 0.182814
|
||||
0.277122 0.5 0.1412
|
||||
0.295799 0.5 0.0961109
|
||||
0.307192 0.5 0.0486543
|
||||
0.311022 -0.5 -1.40397e-007
|
||||
0.307192 -0.5 -0.0486547
|
||||
0.295799 -0.5 -0.0961111
|
||||
0.277122 -0.5 -0.141201
|
||||
0.251622 -0.5 -0.182814
|
||||
0.219925 -0.5 -0.219925
|
||||
0.182814 -0.5 -0.251622
|
||||
0.141201 -0.5 -0.277122
|
||||
0.096111 -0.5 -0.295799
|
||||
0.0486546 -0.5 -0.307192
|
||||
-5.55112e-017 -0.5 -0.311022
|
||||
-0.0486546 -0.5 -0.307192
|
||||
-0.096111 -0.5 -0.295799
|
||||
-0.1412 -0.5 -0.277122
|
||||
-0.182814 -0.5 -0.251622
|
||||
-0.219925 -0.5 -0.219925
|
||||
-0.251622 -0.5 -0.182814
|
||||
-0.277122 -0.5 -0.141201
|
||||
-0.295799 -0.5 -0.0961111
|
||||
-0.307192 -0.5 -0.0486547
|
||||
-0.311022 -0.5 -1.40397e-007
|
||||
-0.307192 -0.5 0.0486544
|
||||
-0.295799 -0.5 0.0961109
|
||||
-0.277122 -0.5 0.1412
|
||||
-0.251622 -0.5 0.182814
|
||||
-0.219925 -0.5 0.219925
|
||||
-0.182814 -0.5 0.251622
|
||||
-0.1412 -0.5 0.277122
|
||||
-0.096111 -0.5 0.295799
|
||||
-0.0486546 -0.5 0.307192
|
||||
-5.55112e-017 -0.5 0.311022
|
||||
0.0486546 -0.5 0.307192
|
||||
0.0961111 -0.5 0.295799
|
||||
0.141201 -0.5 0.277122
|
||||
0.182814 -0.5 0.251622
|
||||
0.219925 -0.5 0.219925
|
||||
0.251622 -0.5 0.182814
|
||||
0.277122 -0.5 0.1412
|
||||
0.295799 -0.5 0.0961109
|
||||
0.307192 -0.5 0.0486543
|
||||
3 0 41 1
|
||||
3 0 40 41
|
||||
3 1 42 2
|
||||
3 1 41 42
|
||||
3 2 43 3
|
||||
3 2 42 43
|
||||
3 3 44 4
|
||||
3 3 43 44
|
||||
3 4 45 5
|
||||
3 4 44 45
|
||||
3 5 46 6
|
||||
3 5 45 46
|
||||
3 6 47 7
|
||||
3 6 46 47
|
||||
3 7 48 8
|
||||
3 7 47 48
|
||||
3 8 49 9
|
||||
3 8 48 49
|
||||
3 9 50 10
|
||||
3 9 49 50
|
||||
3 10 51 11
|
||||
3 10 50 51
|
||||
3 11 52 12
|
||||
3 11 51 52
|
||||
3 12 53 13
|
||||
3 12 52 53
|
||||
3 13 54 14
|
||||
3 13 53 54
|
||||
3 14 55 15
|
||||
3 14 54 55
|
||||
3 15 56 16
|
||||
3 15 55 56
|
||||
3 16 57 17
|
||||
3 16 56 57
|
||||
3 17 58 18
|
||||
3 17 57 58
|
||||
3 18 59 19
|
||||
3 18 58 59
|
||||
3 19 60 20
|
||||
3 19 59 60
|
||||
3 20 61 21
|
||||
3 20 60 61
|
||||
3 21 62 22
|
||||
3 21 61 62
|
||||
3 22 63 23
|
||||
3 22 62 63
|
||||
3 23 64 24
|
||||
3 23 63 64
|
||||
3 24 65 25
|
||||
3 24 64 65
|
||||
3 25 66 26
|
||||
3 25 65 66
|
||||
3 26 67 27
|
||||
3 26 66 67
|
||||
3 27 68 28
|
||||
3 27 67 68
|
||||
3 28 69 29
|
||||
3 28 68 69
|
||||
3 29 70 30
|
||||
3 29 69 70
|
||||
3 30 71 31
|
||||
3 30 70 71
|
||||
3 31 72 32
|
||||
3 31 71 72
|
||||
3 32 73 33
|
||||
3 32 72 73
|
||||
3 33 74 34
|
||||
3 33 73 74
|
||||
3 34 75 35
|
||||
3 34 74 75
|
||||
3 35 76 36
|
||||
3 35 75 76
|
||||
3 36 77 37
|
||||
3 36 76 77
|
||||
3 37 78 38
|
||||
3 37 77 78
|
||||
3 38 79 39
|
||||
3 38 78 79
|
||||
3 39 40 0
|
||||
3 39 79 40
|
||||
3 40 81 41
|
||||
3 40 80 81
|
||||
3 41 82 42
|
||||
3 41 81 82
|
||||
3 42 83 43
|
||||
3 42 82 83
|
||||
3 43 84 44
|
||||
3 43 83 84
|
||||
3 44 85 45
|
||||
3 44 84 85
|
||||
3 45 86 46
|
||||
3 45 85 86
|
||||
3 46 87 47
|
||||
3 46 86 87
|
||||
3 47 88 48
|
||||
3 47 87 88
|
||||
3 48 89 49
|
||||
3 48 88 89
|
||||
3 49 90 50
|
||||
3 49 89 90
|
||||
3 50 91 51
|
||||
3 50 90 91
|
||||
3 51 92 52
|
||||
3 51 91 92
|
||||
3 52 93 53
|
||||
3 52 92 93
|
||||
3 53 94 54
|
||||
3 53 93 94
|
||||
3 54 95 55
|
||||
3 54 94 95
|
||||
3 55 96 56
|
||||
3 55 95 96
|
||||
3 56 97 57
|
||||
3 56 96 97
|
||||
3 57 98 58
|
||||
3 57 97 98
|
||||
3 58 99 59
|
||||
3 58 98 99
|
||||
3 59 100 60
|
||||
3 59 99 100
|
||||
3 60 101 61
|
||||
3 60 100 101
|
||||
3 61 102 62
|
||||
3 61 101 102
|
||||
3 62 103 63
|
||||
3 62 102 103
|
||||
3 63 104 64
|
||||
3 63 103 104
|
||||
3 64 105 65
|
||||
3 64 104 105
|
||||
3 65 106 66
|
||||
3 65 105 106
|
||||
3 66 107 67
|
||||
3 66 106 107
|
||||
3 67 108 68
|
||||
3 67 107 108
|
||||
3 68 109 69
|
||||
3 68 108 109
|
||||
3 69 110 70
|
||||
3 69 109 110
|
||||
3 70 111 71
|
||||
3 70 110 111
|
||||
3 71 112 72
|
||||
3 71 111 112
|
||||
3 72 113 73
|
||||
3 72 112 113
|
||||
3 73 114 74
|
||||
3 73 113 114
|
||||
3 74 115 75
|
||||
3 74 114 115
|
||||
3 75 116 76
|
||||
3 75 115 116
|
||||
3 76 117 77
|
||||
3 76 116 117
|
||||
3 77 118 78
|
||||
3 77 117 118
|
||||
3 78 119 79
|
||||
3 78 118 119
|
||||
3 79 80 40
|
||||
3 79 119 80
|
||||
3 80 121 81
|
||||
3 80 120 121
|
||||
3 81 122 82
|
||||
3 81 121 122
|
||||
3 82 123 83
|
||||
3 82 122 123
|
||||
3 83 124 84
|
||||
3 83 123 124
|
||||
3 84 125 85
|
||||
3 84 124 125
|
||||
3 85 126 86
|
||||
3 85 125 126
|
||||
3 86 127 87
|
||||
3 86 126 127
|
||||
3 87 128 88
|
||||
3 87 127 128
|
||||
3 88 129 89
|
||||
3 88 128 129
|
||||
3 89 130 90
|
||||
3 89 129 130
|
||||
3 90 131 91
|
||||
3 90 130 131
|
||||
3 91 132 92
|
||||
3 91 131 132
|
||||
3 92 133 93
|
||||
3 92 132 133
|
||||
3 93 134 94
|
||||
3 93 133 134
|
||||
3 94 135 95
|
||||
3 94 134 135
|
||||
3 95 136 96
|
||||
3 95 135 136
|
||||
3 96 137 97
|
||||
3 96 136 137
|
||||
3 97 138 98
|
||||
3 97 137 138
|
||||
3 98 139 99
|
||||
3 98 138 139
|
||||
3 99 140 100
|
||||
3 99 139 140
|
||||
3 100 141 101
|
||||
3 100 140 141
|
||||
3 101 142 102
|
||||
3 101 141 142
|
||||
3 102 143 103
|
||||
3 102 142 143
|
||||
3 103 144 104
|
||||
3 103 143 144
|
||||
3 104 145 105
|
||||
3 104 144 145
|
||||
3 105 146 106
|
||||
3 105 145 146
|
||||
3 106 147 107
|
||||
3 106 146 147
|
||||
3 107 148 108
|
||||
3 107 147 148
|
||||
3 108 149 109
|
||||
3 108 148 149
|
||||
3 109 150 110
|
||||
3 109 149 150
|
||||
3 110 151 111
|
||||
3 110 150 151
|
||||
3 111 152 112
|
||||
3 111 151 152
|
||||
3 112 153 113
|
||||
3 112 152 153
|
||||
3 113 154 114
|
||||
3 113 153 154
|
||||
3 114 155 115
|
||||
3 114 154 155
|
||||
3 115 156 116
|
||||
3 115 155 156
|
||||
3 116 157 117
|
||||
3 116 156 157
|
||||
3 117 158 118
|
||||
3 117 157 158
|
||||
3 118 159 119
|
||||
3 118 158 159
|
||||
3 119 120 80
|
||||
3 119 159 120
|
||||
3 120 1 121
|
||||
3 120 0 1
|
||||
3 121 2 122
|
||||
3 121 1 2
|
||||
3 122 3 123
|
||||
3 122 2 3
|
||||
3 123 4 124
|
||||
3 123 3 4
|
||||
3 124 5 125
|
||||
3 124 4 5
|
||||
3 125 6 126
|
||||
3 125 5 6
|
||||
3 126 7 127
|
||||
3 126 6 7
|
||||
3 127 8 128
|
||||
3 127 7 8
|
||||
3 128 9 129
|
||||
3 128 8 9
|
||||
3 129 10 130
|
||||
3 129 9 10
|
||||
3 130 11 131
|
||||
3 130 10 11
|
||||
3 131 12 132
|
||||
3 131 11 12
|
||||
3 132 13 133
|
||||
3 132 12 13
|
||||
3 133 14 134
|
||||
3 133 13 14
|
||||
3 134 15 135
|
||||
3 134 14 15
|
||||
3 135 16 136
|
||||
3 135 15 16
|
||||
3 136 17 137
|
||||
3 136 16 17
|
||||
3 137 18 138
|
||||
3 137 17 18
|
||||
3 138 19 139
|
||||
3 138 18 19
|
||||
3 139 20 140
|
||||
3 139 19 20
|
||||
3 140 21 141
|
||||
3 140 20 21
|
||||
3 141 22 142
|
||||
3 141 21 22
|
||||
3 142 23 143
|
||||
3 142 22 23
|
||||
3 143 24 144
|
||||
3 143 23 24
|
||||
3 144 25 145
|
||||
3 144 24 25
|
||||
3 145 26 146
|
||||
3 145 25 26
|
||||
3 146 27 147
|
||||
3 146 26 27
|
||||
3 147 28 148
|
||||
3 147 27 28
|
||||
3 148 29 149
|
||||
3 148 28 29
|
||||
3 149 30 150
|
||||
3 149 29 30
|
||||
3 150 31 151
|
||||
3 150 30 31
|
||||
3 151 32 152
|
||||
3 151 31 32
|
||||
3 152 33 153
|
||||
3 152 32 33
|
||||
3 153 34 154
|
||||
3 153 33 34
|
||||
3 154 35 155
|
||||
3 154 34 35
|
||||
3 155 36 156
|
||||
3 155 35 36
|
||||
3 156 37 157
|
||||
3 156 36 37
|
||||
3 157 38 158
|
||||
3 157 37 38
|
||||
3 158 39 159
|
||||
3 158 38 39
|
||||
3 159 0 120
|
||||
3 159 39 0
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
OFF
|
||||
5 5 0
|
||||
|
||||
-1 -0.5 -0.5
|
||||
-1 -0.5 0.5
|
||||
-1 0.5 0.5
|
||||
-1 0.5 -0.5
|
||||
1 0 0
|
||||
|
||||
3 1 0 4
|
||||
3 2 1 4
|
||||
3 3 2 4
|
||||
3 0 3 4
|
||||
4 0 1 2 3
|
||||
|
|
@ -0,0 +1,486 @@
|
|||
OFF
|
||||
162 320 0
|
||||
|
||||
0 0.5 0
|
||||
0.4472 0.2236 0
|
||||
0.1382 0.2236 -0.42535
|
||||
-0.3618 0.2236 -0.26285
|
||||
-0.3618 0.2236 0.26285
|
||||
0.1382 0.2236 0.42535
|
||||
0.3618 -0.2236 -0.26285
|
||||
-0.1382 -0.2236 -0.42535
|
||||
-0.4472 -0.2236 0
|
||||
-0.1382 -0.2236 0.42535
|
||||
0.3618 -0.2236 0.26285
|
||||
0 -0.5 0
|
||||
0.13665 0.48095 0
|
||||
0.26285 0.42535 0
|
||||
0.3691 0.3373 0
|
||||
0.04222 0.48095 -0.12995
|
||||
0.08125 0.42535 -0.25
|
||||
0.11405 0.3373 -0.351
|
||||
-0.11055 0.48095 -0.0803
|
||||
-0.21265 0.42535 -0.1545
|
||||
-0.2986 0.3373 -0.21695
|
||||
-0.11055 0.48095 0.0803
|
||||
-0.21265 0.42535 0.1545
|
||||
-0.2986 0.3373 0.21695
|
||||
0.04222 0.48095 0.12995
|
||||
0.08125 0.42535 0.25
|
||||
0.11405 0.3373 0.351
|
||||
0.4113 0.25285 -0.12995
|
||||
0.3441 0.26285 -0.25
|
||||
0.2507 0.25285 -0.351
|
||||
0.0035155 0.25285 -0.43135
|
||||
-0.13145 0.26285 -0.4045
|
||||
-0.2564 0.25285 -0.3469
|
||||
-0.40915 0.25285 -0.13665
|
||||
-0.42535 0.26285 0
|
||||
-0.40915 0.25285 0.13665
|
||||
-0.2564 0.25285 0.3469
|
||||
-0.13145 0.26285 0.4045
|
||||
0.003516 0.25285 0.43135
|
||||
0.2507 0.25285 0.351
|
||||
0.3441 0.26285 0.25
|
||||
0.4113 0.25285 0.12995
|
||||
0.47965 0.11625 -0.0803
|
||||
0.47555 0 -0.1545
|
||||
0.43525 -0.11625 -0.21695
|
||||
0.07185 0.11625 -0.48095
|
||||
0 0 -0.5
|
||||
-0.07185 -0.11625 -0.48095
|
||||
-0.43525 0.11625 -0.21695
|
||||
-0.47555 0 -0.1545
|
||||
-0.47965 -0.11625 -0.0803
|
||||
-0.3408 0.11625 0.3469
|
||||
-0.2939 0 0.4045
|
||||
-0.2246 -0.11625 0.43135
|
||||
0.2246 0.11625 0.43135
|
||||
0.2939 0 0.4045
|
||||
0.3408 -0.11625 0.3469
|
||||
0.47965 0.11625 0.0803
|
||||
0.47555 0 0.1545
|
||||
0.43525 -0.11625 0.21695
|
||||
0.2246 0.11625 -0.43135
|
||||
0.2939 0 -0.4045
|
||||
0.3408 -0.11625 -0.3469
|
||||
-0.3408 0.11625 -0.3469
|
||||
-0.2939 0 -0.4045
|
||||
-0.2246 -0.11625 -0.43135
|
||||
-0.43525 0.11625 0.21695
|
||||
-0.47555 0 0.1545
|
||||
-0.47965 -0.11625 0.0803
|
||||
0.07185 0.11625 0.48095
|
||||
0 0 0.5
|
||||
-0.07185 -0.11625 0.48095
|
||||
0.2564 -0.25285 -0.3469
|
||||
0.13145 -0.26285 -0.4045
|
||||
-0.0035155 -0.25285 -0.43135
|
||||
-0.2507 -0.25285 -0.351
|
||||
-0.3441 -0.26285 -0.25
|
||||
-0.4113 -0.25285 -0.12995
|
||||
-0.4113 -0.25285 0.12995
|
||||
-0.3441 -0.26285 0.25
|
||||
-0.2507 -0.25285 0.351
|
||||
-0.0035155 -0.25285 0.43135
|
||||
0.13145 -0.26285 0.4045
|
||||
0.2564 -0.25285 0.3469
|
||||
0.40915 -0.25285 0.13665
|
||||
0.42535 -0.26285 0
|
||||
0.40915 -0.25285 -0.13665
|
||||
0.11055 -0.48095 -0.0803
|
||||
0.21265 -0.42535 -0.1545
|
||||
0.2986 -0.3373 -0.21695
|
||||
-0.04222 -0.48095 -0.12995
|
||||
-0.08125 -0.42535 -0.25
|
||||
-0.11405 -0.3373 -0.351
|
||||
-0.13665 -0.48095 0
|
||||
-0.26285 -0.42535 0
|
||||
-0.3691 -0.3373 0
|
||||
-0.04222 -0.48095 0.12995
|
||||
-0.08125 -0.42535 0.25
|
||||
-0.11405 -0.3373 0.351
|
||||
0.11055 -0.48095 0.0803
|
||||
0.21265 -0.42535 0.1545
|
||||
0.2986 -0.3373 0.21695
|
||||
0.1809 0.4472 -0.13145
|
||||
0.30895 0.3702 -0.13235
|
||||
0.22135 0.3702 -0.2529
|
||||
-0.0691 0.4472 -0.21265
|
||||
-0.030395 0.3702 -0.3347
|
||||
-0.17215 0.3702 -0.28865
|
||||
-0.2236 0.4472 0
|
||||
-0.3277 0.3702 -0.0745
|
||||
-0.3277 0.3702 0.0745
|
||||
-0.0691 0.4472 0.21265
|
||||
-0.17215 0.3702 0.28865
|
||||
-0.030395 0.3702 0.3347
|
||||
0.1809 0.4472 0.13145
|
||||
0.22135 0.3702 0.2529
|
||||
0.30895 0.3702 0.13235
|
||||
0.5 0 0
|
||||
0.4777 -0.12755 0.0745
|
||||
0.4777 -0.12755 -0.0745
|
||||
0.1545 0 -0.47555
|
||||
0.2185 -0.12755 -0.43125
|
||||
0.07675 -0.12755 -0.47735
|
||||
-0.4045 0 -0.2939
|
||||
-0.34265 -0.12755 -0.34105
|
||||
-0.43025 -0.12755 -0.2205
|
||||
-0.4045 0 0.2939
|
||||
-0.43025 -0.12755 0.2205
|
||||
-0.34265 -0.12755 0.34105
|
||||
0.1545 0 0.47555
|
||||
0.07675 -0.12755 0.47735
|
||||
0.2185 -0.12755 0.43125
|
||||
0.4045 0 -0.2939
|
||||
0.34265 0.12755 -0.34105
|
||||
0.43025 0.12755 -0.2205
|
||||
-0.1545 0 -0.47555
|
||||
-0.2185 0.12755 -0.43125
|
||||
-0.07675 0.12755 -0.47735
|
||||
-0.5 0 0
|
||||
-0.4777 0.12755 0.0745
|
||||
-0.4777 0.12755 -0.0745
|
||||
-0.1545 0 0.47555
|
||||
-0.07675 0.12755 0.47735
|
||||
-0.2185 0.12755 0.43125
|
||||
0.4045 0 0.2939
|
||||
0.43025 0.12755 0.2205
|
||||
0.34265 0.12755 0.34105
|
||||
0.0691 -0.4472 -0.21265
|
||||
0.030395 -0.3702 -0.3347
|
||||
0.17215 -0.3702 -0.28865
|
||||
-0.1809 -0.4472 -0.13145
|
||||
-0.30895 -0.3702 -0.13235
|
||||
-0.22135 -0.3702 -0.2529
|
||||
-0.1809 -0.4472 0.13145
|
||||
-0.22135 -0.3702 0.2529
|
||||
-0.30895 -0.3702 0.13235
|
||||
0.0691 -0.4472 0.21265
|
||||
0.17215 -0.3702 0.28865
|
||||
0.030395 -0.3702 0.3347
|
||||
0.2236 -0.4472 0
|
||||
0.3277 -0.3702 -0.0745
|
||||
0.3277 -0.3702 0.0745
|
||||
3 0 12 15
|
||||
3 12 13 102
|
||||
3 12 102 15
|
||||
3 15 102 16
|
||||
3 13 14 103
|
||||
3 13 103 102
|
||||
3 102 103 104
|
||||
3 102 104 16
|
||||
3 16 104 17
|
||||
3 14 1 27
|
||||
3 14 27 103
|
||||
3 103 27 28
|
||||
3 103 28 104
|
||||
3 104 28 29
|
||||
3 104 29 17
|
||||
3 17 29 2
|
||||
3 0 15 18
|
||||
3 15 16 105
|
||||
3 15 105 18
|
||||
3 18 105 19
|
||||
3 16 17 106
|
||||
3 16 106 105
|
||||
3 105 106 107
|
||||
3 105 107 19
|
||||
3 19 107 20
|
||||
3 17 2 30
|
||||
3 17 30 106
|
||||
3 106 30 31
|
||||
3 106 31 107
|
||||
3 107 31 32
|
||||
3 107 32 20
|
||||
3 20 32 3
|
||||
3 0 18 21
|
||||
3 18 19 108
|
||||
3 18 108 21
|
||||
3 21 108 22
|
||||
3 19 20 109
|
||||
3 19 109 108
|
||||
3 108 109 110
|
||||
3 108 110 22
|
||||
3 22 110 23
|
||||
3 20 3 33
|
||||
3 20 33 109
|
||||
3 109 33 34
|
||||
3 109 34 110
|
||||
3 110 34 35
|
||||
3 110 35 23
|
||||
3 23 35 4
|
||||
3 0 21 24
|
||||
3 21 22 111
|
||||
3 21 111 24
|
||||
3 24 111 25
|
||||
3 22 23 112
|
||||
3 22 112 111
|
||||
3 111 112 113
|
||||
3 111 113 25
|
||||
3 25 113 26
|
||||
3 23 4 36
|
||||
3 23 36 112
|
||||
3 112 36 37
|
||||
3 112 37 113
|
||||
3 113 37 38
|
||||
3 113 38 26
|
||||
3 26 38 5
|
||||
3 0 24 12
|
||||
3 24 25 114
|
||||
3 24 114 12
|
||||
3 12 114 13
|
||||
3 25 26 115
|
||||
3 25 115 114
|
||||
3 114 115 116
|
||||
3 114 116 13
|
||||
3 13 116 14
|
||||
3 26 5 39
|
||||
3 26 39 115
|
||||
3 115 39 40
|
||||
3 115 40 116
|
||||
3 116 40 41
|
||||
3 116 41 14
|
||||
3 14 41 1
|
||||
3 1 57 42
|
||||
3 57 58 117
|
||||
3 57 117 42
|
||||
3 42 117 43
|
||||
3 58 59 118
|
||||
3 58 118 117
|
||||
3 117 118 119
|
||||
3 117 119 43
|
||||
3 43 119 44
|
||||
3 59 10 84
|
||||
3 59 84 118
|
||||
3 118 84 85
|
||||
3 118 85 119
|
||||
3 119 85 86
|
||||
3 119 86 44
|
||||
3 44 86 6
|
||||
3 2 60 45
|
||||
3 60 61 120
|
||||
3 60 120 45
|
||||
3 45 120 46
|
||||
3 61 62 121
|
||||
3 61 121 120
|
||||
3 120 121 122
|
||||
3 120 122 46
|
||||
3 46 122 47
|
||||
3 62 6 72
|
||||
3 62 72 121
|
||||
3 121 72 73
|
||||
3 121 73 122
|
||||
3 122 73 74
|
||||
3 122 74 47
|
||||
3 47 74 7
|
||||
3 3 63 48
|
||||
3 63 64 123
|
||||
3 63 123 48
|
||||
3 48 123 49
|
||||
3 64 65 124
|
||||
3 64 124 123
|
||||
3 123 124 125
|
||||
3 123 125 49
|
||||
3 49 125 50
|
||||
3 65 7 75
|
||||
3 65 75 124
|
||||
3 124 75 76
|
||||
3 124 76 125
|
||||
3 125 76 77
|
||||
3 125 77 50
|
||||
3 50 77 8
|
||||
3 4 66 51
|
||||
3 66 67 126
|
||||
3 66 126 51
|
||||
3 51 126 52
|
||||
3 67 68 127
|
||||
3 67 127 126
|
||||
3 126 127 128
|
||||
3 126 128 52
|
||||
3 52 128 53
|
||||
3 68 8 78
|
||||
3 68 78 127
|
||||
3 127 78 79
|
||||
3 127 79 128
|
||||
3 128 79 80
|
||||
3 128 80 53
|
||||
3 53 80 9
|
||||
3 5 69 54
|
||||
3 69 70 129
|
||||
3 69 129 54
|
||||
3 54 129 55
|
||||
3 70 71 130
|
||||
3 70 130 129
|
||||
3 129 130 131
|
||||
3 129 131 55
|
||||
3 55 131 56
|
||||
3 71 9 81
|
||||
3 71 81 130
|
||||
3 130 81 82
|
||||
3 130 82 131
|
||||
3 131 82 83
|
||||
3 131 83 56
|
||||
3 56 83 10
|
||||
3 6 62 44
|
||||
3 62 61 132
|
||||
3 62 132 44
|
||||
3 44 132 43
|
||||
3 61 60 133
|
||||
3 61 133 132
|
||||
3 132 133 134
|
||||
3 132 134 43
|
||||
3 43 134 42
|
||||
3 60 2 29
|
||||
3 60 29 133
|
||||
3 133 29 28
|
||||
3 133 28 134
|
||||
3 134 28 27
|
||||
3 134 27 42
|
||||
3 42 27 1
|
||||
3 7 65 47
|
||||
3 65 64 135
|
||||
3 65 135 47
|
||||
3 47 135 46
|
||||
3 64 63 136
|
||||
3 64 136 135
|
||||
3 135 136 137
|
||||
3 135 137 46
|
||||
3 46 137 45
|
||||
3 63 3 32
|
||||
3 63 32 136
|
||||
3 136 32 31
|
||||
3 136 31 137
|
||||
3 137 31 30
|
||||
3 137 30 45
|
||||
3 45 30 2
|
||||
3 8 68 50
|
||||
3 68 67 138
|
||||
3 68 138 50
|
||||
3 50 138 49
|
||||
3 67 66 139
|
||||
3 67 139 138
|
||||
3 138 139 140
|
||||
3 138 140 49
|
||||
3 49 140 48
|
||||
3 66 4 35
|
||||
3 66 35 139
|
||||
3 139 35 34
|
||||
3 139 34 140
|
||||
3 140 34 33
|
||||
3 140 33 48
|
||||
3 48 33 3
|
||||
3 9 71 53
|
||||
3 71 70 141
|
||||
3 71 141 53
|
||||
3 53 141 52
|
||||
3 70 69 142
|
||||
3 70 142 141
|
||||
3 141 142 143
|
||||
3 141 143 52
|
||||
3 52 143 51
|
||||
3 69 5 38
|
||||
3 69 38 142
|
||||
3 142 38 37
|
||||
3 142 37 143
|
||||
3 143 37 36
|
||||
3 143 36 51
|
||||
3 51 36 4
|
||||
3 10 59 56
|
||||
3 59 58 144
|
||||
3 59 144 56
|
||||
3 56 144 55
|
||||
3 58 57 145
|
||||
3 58 145 144
|
||||
3 144 145 146
|
||||
3 144 146 55
|
||||
3 55 146 54
|
||||
3 57 1 41
|
||||
3 57 41 145
|
||||
3 145 41 40
|
||||
3 145 40 146
|
||||
3 146 40 39
|
||||
3 146 39 54
|
||||
3 54 39 5
|
||||
3 11 90 87
|
||||
3 90 91 147
|
||||
3 90 147 87
|
||||
3 87 147 88
|
||||
3 91 92 148
|
||||
3 91 148 147
|
||||
3 147 148 149
|
||||
3 147 149 88
|
||||
3 88 149 89
|
||||
3 92 7 74
|
||||
3 92 74 148
|
||||
3 148 74 73
|
||||
3 148 73 149
|
||||
3 149 73 72
|
||||
3 149 72 89
|
||||
3 89 72 6
|
||||
3 11 93 90
|
||||
3 93 94 150
|
||||
3 93 150 90
|
||||
3 90 150 91
|
||||
3 94 95 151
|
||||
3 94 151 150
|
||||
3 150 151 152
|
||||
3 150 152 91
|
||||
3 91 152 92
|
||||
3 95 8 77
|
||||
3 95 77 151
|
||||
3 151 77 76
|
||||
3 151 76 152
|
||||
3 152 76 75
|
||||
3 152 75 92
|
||||
3 92 75 7
|
||||
3 11 96 93
|
||||
3 96 97 153
|
||||
3 96 153 93
|
||||
3 93 153 94
|
||||
3 97 98 154
|
||||
3 97 154 153
|
||||
3 153 154 155
|
||||
3 153 155 94
|
||||
3 94 155 95
|
||||
3 98 9 80
|
||||
3 98 80 154
|
||||
3 154 80 79
|
||||
3 154 79 155
|
||||
3 155 79 78
|
||||
3 155 78 95
|
||||
3 95 78 8
|
||||
3 11 99 96
|
||||
3 99 100 156
|
||||
3 99 156 96
|
||||
3 96 156 97
|
||||
3 100 101 157
|
||||
3 100 157 156
|
||||
3 156 157 158
|
||||
3 156 158 97
|
||||
3 97 158 98
|
||||
3 101 10 83
|
||||
3 101 83 157
|
||||
3 157 83 82
|
||||
3 157 82 158
|
||||
3 158 82 81
|
||||
3 158 81 98
|
||||
3 98 81 9
|
||||
3 11 87 99
|
||||
3 87 88 159
|
||||
3 87 159 99
|
||||
3 99 159 100
|
||||
3 88 89 160
|
||||
3 88 160 159
|
||||
3 159 160 161
|
||||
3 159 161 100
|
||||
3 100 161 101
|
||||
3 89 6 86
|
||||
3 89 86 160
|
||||
3 160 86 85
|
||||
3 160 85 161
|
||||
3 161 85 84
|
||||
3 161 84 101
|
||||
3 101 84 10
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
OFF
|
||||
14 24 0
|
||||
|
||||
-0.125 -0.125 -0.125
|
||||
-0.125 0.125 -0.125
|
||||
0.125 0.125 -0.125
|
||||
0.125 -0.125 -0.125
|
||||
-0.125 -0.125 0.125
|
||||
-0.125 0.125 0.125
|
||||
0.125 0.125 0.125
|
||||
0.125 -0.125 0.125
|
||||
0.5 0 0
|
||||
0 0.5 0
|
||||
-0.5 0 0
|
||||
0 -0.5 0
|
||||
0 0 0.5
|
||||
0 0 -0.5
|
||||
3 0 1 13
|
||||
3 1 2 13
|
||||
3 2 3 13
|
||||
3 3 0 13
|
||||
3 3 2 8
|
||||
3 7 3 8
|
||||
3 6 7 8
|
||||
3 2 6 8
|
||||
3 7 6 12
|
||||
3 4 7 12
|
||||
3 5 4 12
|
||||
3 6 5 12
|
||||
3 4 5 10
|
||||
3 5 1 10
|
||||
3 1 0 10
|
||||
3 0 4 10
|
||||
3 5 6 9
|
||||
3 6 2 9
|
||||
3 2 1 9
|
||||
3 1 5 9
|
||||
3 7 4 11
|
||||
3 3 7 11
|
||||
3 0 3 11
|
||||
3 4 0 11
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
OFF
|
||||
8 12 0
|
||||
1.0 1.0 -1.0
|
||||
1.0 3.0 -1.0
|
||||
3.0 3.0 -1.0
|
||||
3.0 1.0 -1.0
|
||||
1.0 1.0 1.0
|
||||
1.0 3.0 1.0
|
||||
3.0 3.0 1.0
|
||||
3.0 1.0 1.0
|
||||
3 0 1 3
|
||||
3 3 1 2
|
||||
3 0 4 1
|
||||
3 1 4 5
|
||||
3 3 2 7
|
||||
3 7 2 6
|
||||
3 4 0 3
|
||||
3 7 4 3
|
||||
3 6 4 7
|
||||
3 6 5 4
|
||||
3 1 5 6
|
||||
3 2 1 6
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
OFF
|
||||
24 44 0
|
||||
|
||||
-0.462837 0.0205318 -0.140203
|
||||
-0.174333 0.0412215 -0.151981
|
||||
-0.144255 0.368209 -0.146404
|
||||
0.0936504 0.361854 -0.147855
|
||||
0.141347 0.0412215 -0.151981
|
||||
0.450915 -0.165801 -0.163699
|
||||
0.357073 -0.405901 -0.137953
|
||||
0.141347 -0.274458 -0.151981
|
||||
-0.174333 -0.274458 -0.151981
|
||||
-0.461176 -0.217462 -0.108519
|
||||
-0.450778 -0.0217283 0.159384
|
||||
-0.174333 0.0412215 0.163699
|
||||
-0.174333 0.356901 0.163699
|
||||
0.106877 0.34047 0.155338
|
||||
0.141347 0.0412215 0.163699
|
||||
0.452244 -0.184928 0.145632
|
||||
0.379439 -0.433293 0.144635
|
||||
0.141347 -0.274458 0.163699
|
||||
-0.174333 -0.274458 0.163699
|
||||
-0.413695 -0.363559 0.134658
|
||||
-0.5 -0.0816885 0.0513155
|
||||
-0.0364476 -0.274458 0.01209
|
||||
0.5 -0.344 -0.0556357
|
||||
0.00831896 0.433293 0.0305898
|
||||
3 0 1 9
|
||||
3 1 4 8
|
||||
3 1 2 4
|
||||
3 4 5 7
|
||||
3 1 0 11
|
||||
3 2 1 12
|
||||
3 4 3 14
|
||||
3 5 4 15
|
||||
3 7 6 17
|
||||
3 9 8 19
|
||||
3 19 18 10
|
||||
3 18 17 11
|
||||
3 14 13 11
|
||||
3 17 16 14
|
||||
3 8 9 1
|
||||
3 7 8 4
|
||||
3 3 4 2
|
||||
3 6 7 5
|
||||
3 10 11 0
|
||||
3 11 12 1
|
||||
3 13 14 3
|
||||
3 14 15 4
|
||||
3 16 17 6
|
||||
3 18 19 8
|
||||
3 11 10 18
|
||||
3 14 11 17
|
||||
3 12 11 13
|
||||
3 15 14 16
|
||||
3 0 20 10
|
||||
3 9 20 0
|
||||
3 19 20 9
|
||||
3 10 20 19
|
||||
3 7 21 8
|
||||
3 17 21 7
|
||||
3 18 21 17
|
||||
3 8 21 18
|
||||
3 15 22 5
|
||||
3 16 22 15
|
||||
3 6 22 16
|
||||
3 5 22 6
|
||||
3 3 23 13
|
||||
3 2 23 3
|
||||
3 12 23 2
|
||||
3 13 23 12
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
data/iphigenia.off
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
To compile all of the benchmarks in the user manual, simply run:
|
||||
|
||||
> ./run_benchmarks.sh
|
||||
|
||||
This will generate 3 sets of files.
|
||||
|
||||
Data Files:
|
||||
|
||||
- Files are of the form: "_modeldata_<modelname>.dat" , where
|
||||
- <modelname> is the base name of the model used
|
||||
- These simply contain the raw data points from the benchmarks, you do not need to interact with them directly
|
||||
|
||||
Table Files:
|
||||
|
||||
- Files are of the form: "benchmark_table_##.txt" , where
|
||||
- ## is the number of source points used for that trial
|
||||
- These files contain text for tables that can be pasted directly into the benchmarks section of the user manual
|
||||
|
||||
Comparison Figures
|
||||
|
||||
- Files are of the form: "benchmark_plot_<modelname>_<runtype>".png , where
|
||||
- <modelname> is the base name of the model used
|
||||
- <runtype> is one of 'query', 'construction', or 'memory'
|
||||
- These are images with scatter-plots tracking a specific variable for each model over multiple different number of source points
|
||||
- These figures should be pasted into the doc/Surface_mesh_shortest_path/fig/ subdirectory
|
||||
|
||||
If you want to change the set of models used, simply edit the file "testModels.txt" to add or remove the models you wish to test on (make sure that the model files exist in the data/ directory).
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ ! -a CMakeLists.txt ]
|
||||
then
|
||||
echo "CMakeLists.txt does not exist, generating..."
|
||||
cgal_create_CMakeLists -b program_options:timer -c Core
|
||||
fi
|
||||
|
||||
python compileBenchmarks.py -f testModels.txt -d _modeldata -t benchmark_table -o benchmark_plot -s 6062699 -r 1 5,55,5
|
||||
#python compileBenchmarks.py -k epeck -f simpleModels.txt -d _modeldata -t epeck_table -s 9894710 -r 1 -n 1 -q 1
|
||||
#python compileBenchmarks.py -f hugeModels.txt -d _modeldata -t huge_table -s 5937524 -r 1 -n 1 -q 1
|
||||
|
|
@ -0,0 +1 @@
|
|||
data/ellipsoid.off
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
data/anchor.off
|
||||
data/bones.off
|
||||
data/bull.off
|
||||
data/couplingdown.off
|
||||
data/cow.off
|
||||
data/elephant.off
|
||||
data/ellipsoid.off
|
||||
data/fandisk.off
|
||||
data/femur.off
|
||||
data/handle.off
|
||||
data/knot1.off
|
||||
data/knot2.off
|
||||
data/lion-head.off
|
||||
data/man.off
|
||||
data/mushroom.off
|
||||
data/retinal.off
|
||||
data/rotor.off
|
||||
data/spool.off
|
||||
data/turbine.off
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
/*!
|
||||
\ingroup PkgSurfaceMeshShortestPathConcepts
|
||||
|
||||
\cgalConcept
|
||||
|
||||
The concept `SurfaceMeshShortestPathTraits` describes the types,
|
||||
predicates, and constructions required by the traits class parameter of
|
||||
`CGAL::Surface_mesh_shortest_path`.
|
||||
|
||||
\cgalHasModel `CGAL::Surface_mesh_shortest_path_traits<K,P>`
|
||||
|
||||
*/
|
||||
|
||||
class SurfaceMeshShortestPathTraits
|
||||
{
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// A model of the concept `FaceListGraph`
|
||||
typedef unspecified_type Triangle_mesh;
|
||||
|
||||
/// A model of the concept `FieldWithSqrt` or a model of both `Field` and `RealEmbeddable`.
|
||||
typedef unspecified_type FT;
|
||||
|
||||
/// The 2-dimensional point type
|
||||
typedef unspecified_type Point_2;
|
||||
|
||||
/// The 2-dimensional vector type
|
||||
typedef unspecified_type Vector_2;
|
||||
|
||||
/// The 2-dimensional ray type
|
||||
typedef unspecified_type Ray_2;
|
||||
|
||||
/// The 2-dimensional line type
|
||||
typedef unspecified_type Line_2;
|
||||
|
||||
/// The 2-dimensional segment type
|
||||
typedef unspecified_type Segment_2;
|
||||
|
||||
/// The 2-dimensional triangle type
|
||||
typedef unspecified_type Triangle_2;
|
||||
|
||||
/// An ordered triple to specify barycentric coordinates in triangles.
|
||||
typedef unspecified_type Barycentric_coordinate;
|
||||
|
||||
/// The 3-dimensional point type
|
||||
typedef unspecified_type Point_3;
|
||||
|
||||
/// The 3-dimensional vector type
|
||||
typedef unspecified_type Vector_3;
|
||||
|
||||
/// The 3-dimensional ray type
|
||||
typedef unspecified_type Ray_3;
|
||||
|
||||
/// The 3-dimensional triangle type
|
||||
typedef unspecified_type Triangle_3;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Constructions
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(FT x, FT y)` and
|
||||
`Point_2 operator()(CGAL::ORIGIN)` to construct points with
|
||||
cartesian coordinates `(x,y)` and `(0,0)` respectively.
|
||||
*/
|
||||
typedef unspecified_type Construct_point_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Vector_2 operator()(Point_2 a, Point_2 b)`
|
||||
to construct the vector `b - a`
|
||||
*/
|
||||
typedef unspecified_type Construct_vector_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Ray_2 operator()(Point_2 a, Point_2 b)`
|
||||
to construct the ray originating from `a` and passing through `b`
|
||||
*/
|
||||
typedef unspecified_type Construct_ray_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Line_2 operator()(Segment_2 s)` and
|
||||
`Line_2 operator()(Ray_2 r)`
|
||||
to construct the supporting line to `s` and `r` respectively.
|
||||
*/
|
||||
typedef unspecified_type Construct_line_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Segment_2 operator()(Point_2 a, Point_2 b)`
|
||||
to construct the segment `(a,b)`
|
||||
*/
|
||||
typedef unspecified_type Construct_segment_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Triangle_2 operator()(Point_2 a, Point_2 b, Point_2 c)`
|
||||
to construct the triangle `(a,b,c)`
|
||||
*/
|
||||
typedef unspecified_type Construct_triangle_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(Segment_2 s, int i)`
|
||||
to return the source or target of `s`, depending on whether `i` is 0 or 1 respectively, and
|
||||
`Point_2 operator()(Triangle_2 t, int i)`
|
||||
to return the `i`th vertex of `t`.
|
||||
*/
|
||||
typedef unspecified_type Construct_vertex_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(Segment_2 s)`
|
||||
to return the source of `s`.
|
||||
*/
|
||||
typedef unspecified_type Construct_source_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(Segment_2 s)`
|
||||
to return the target of `s`.
|
||||
*/
|
||||
typedef unspecified_type Construct_target_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(Point_2 p1, FT w1, Point_2 p2, FT w2)`
|
||||
to compute the barycenter of the points `p1` and `p2` with corresponding weights `w1` and `w2`, and
|
||||
`Point_2 operator()(Point_2 p1, FT w1, Point_2 p2, FT w2, Point_2 p3, FT w3)`
|
||||
to compute the barycenter of the points `p1`, `p2`, and `p3` with corresponding weights `w1`, `w2`, and `w3`.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycenter_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`FT operator()(A obj1, B obj2)`
|
||||
to compute the squared distance between `obj1` and `obj2`, `A` and `B` can be any one of
|
||||
`Point_2`,
|
||||
`Segment_2`,
|
||||
type objects.
|
||||
*/
|
||||
typedef unspecified_type Compute_squared_distance_2;
|
||||
|
||||
/*!
|
||||
Function object type.
|
||||
Must provide
|
||||
`CGAL::cpp11::result_of<Intersect_2(A,B)>::%type operator()(A obj1, B obj2)`
|
||||
to compute the intersection between `obj1` and `obj2`, where `A` and `B` can be any type amongst
|
||||
`Line_2`, `Ray_2`, `Segment_2`.
|
||||
*/
|
||||
typedef unspecified_type Intersect_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_2 operator()(Ray_2 r, int i)`
|
||||
to construct a point on `r`, such that `i = 0` is the source, and any `i > 0` is not the source.
|
||||
*/
|
||||
typedef unspecified_type Construct_point_on_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Vector_3 operator()(Point_3 a, Point_3 b)`
|
||||
to construct the vector `b - a`
|
||||
*/
|
||||
typedef unspecified_type Construct_vector_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Triangle_3 operator()(Point_3 a, Point_3 b, Point_3 c)`
|
||||
to construct the triangle `(a,b,c)`
|
||||
*/
|
||||
typedef unspecified_type Construct_triangle_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_3 operator()(Segment_3 s, int i)`
|
||||
to return the source or target of `s`, depending on whether `i` is 0 or 1 respectively, and
|
||||
`Point_3 operator()(Triangle_3 t, int i)`
|
||||
to return the `i`th vertex of `t`.
|
||||
*/
|
||||
typedef unspecified_type Construct_vertex_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_3 operator()(Segment_3 s)`
|
||||
to return the source of `s`.
|
||||
*/
|
||||
typedef unspecified_type Construct_source_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_3 operator()(Segment_3 s)`
|
||||
to return the target of `s`.
|
||||
*/
|
||||
typedef unspecified_type Construct_target_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Point_3 operator()(Point_3 p1, FT w1, Point_3 p2)`
|
||||
to compute the barycenter of the points `p1` and `p2` with corresponding weights `w1` and `1-w1`, and
|
||||
`Point_3 operator()(Point_3 p1, FT w1, Point_3 p2, FT w2, Point_3 p3, FT w3)`
|
||||
to compute the barycenter of the points `p1`, `p2`, and `p3` with corresponding weights `w1`, `w2`, and `w3`.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycenter_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`FT operator()(Point_3 p1, Point_3 p2)`
|
||||
to compute the squared distance between `p1` and `p2`.
|
||||
*/
|
||||
typedef unspecified_type Compute_squared_distance_3;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Triangle_2 operator()(Triangle_3 t)`
|
||||
which computes a 2-dimensional projection of `t` that preserves edge lengths.
|
||||
*/
|
||||
typedef unspecified_type Construct_triangle_3_to_triangle_2_projection;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Triangle_2 operator()(Triangle_3 t, std::size_t i, Segment_2 base)`
|
||||
which computes a 2-dimensional projection of t that preserves edge lengths,
|
||||
such that the `i`th edge of the projection of `t` is incident to `base`.
|
||||
|
||||
\pre The length of the `i`th edge of `t` is equal to the length of `base`
|
||||
*/
|
||||
typedef unspecified_type Construct_triangle_3_along_segment_2_flattening;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`FT operator()(Point_2 x0, Point_2 x1, Point_2 p)`
|
||||
which computes the parametric distance of `p` along the
|
||||
segment `[x0,x1]`. That is, it computes `t`, such that
|
||||
`p = (1.0 - t)*x0 + t*x1`
|
||||
|
||||
\pre `p` is a point in the segment `[x0,x1]`
|
||||
*/
|
||||
typedef unspecified_type Compute_parametric_distance_along_segment_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Barycentric_coordinate operator()(FT a, FT b, FT c)`
|
||||
to introduce a new triangular barycentric coordinate.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycentric_coordinate;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`FT operator(Barycentric_coordinate b, std::size_t i)`
|
||||
to get the `i`th weight of barycentric coordinate `b`.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycentric_coordinate_weight;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Barycentric_coordinate operator()(Triangle_2 t, Point_2 p)`
|
||||
which computes the Barycentric location of `p` in `t`.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycentric_coordinate_in_triangle_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`Barycentric_coordinate operator()(Triangle_3 t, Point_3 p)`
|
||||
which computes the Barycentric location of `p` in `t`.
|
||||
*/
|
||||
typedef unspecified_type Construct_barycentric_coordinate_in_triangle_3;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Predicates
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`std::pair<CGAL::Surface_mesh_shortest_paths_3::Barycentric_coordinate_type,std::size_t> operator()(Barycentric_coordinate b)`,
|
||||
which computes the classification and the associated edge (if applicable) of the coordinate `b`
|
||||
\details Returns the pair (`type`, `i`), such that `type` is one of the values of `CGAL::Surface_mesh_shortest_paths_3::Barycentric_coordinate_type`
|
||||
- If `type` is `CGAL::Surface_mesh_shortest_paths_3::BARYCENTRIC_COORDINATE_ON_VERTEX`, `i` is the index of that vertex
|
||||
- If `type` is `CGAL::Surface_mesh_shortest_paths_3::BARYCENTRIC_COORDINATE_ON_BOUNDARY`, `i` is the index of the non-zero edge
|
||||
- 0 if (0,1) are the non-zero coordinates
|
||||
- 1 if (1,2) are the non-zero coordinates
|
||||
- 2 if (2,0) are the non-zero coordinates
|
||||
- Otherwise, the value of `i` is undefined.
|
||||
*/
|
||||
typedef unspecified_type Classify_barycentric_coordinate;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`CGAL::Orientation operator()(Point_2 s1, Point_2 s2, Point_2 s3)`,
|
||||
which performs an orientation test for the given points
|
||||
*/
|
||||
typedef unspecified_type Orientation_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`CGAL::Comparison_result operator()(Point_2 p1, Point_2 p2, Point_2 p3, Point_2 p4)`, which compares the
|
||||
squared distance between `p1` and `p2` with the squared distance between `p3` and `p4`.
|
||||
*/
|
||||
typedef unspecified_type Compare_distance_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`CGAL::Comparison_result operator()(Segment_2 s1, Line_2 l1, Segment_2 s2, Line_2 l2)`.
|
||||
This compares the relative parametric intersections of `s1` with `l1` against `s2` with `l2`.
|
||||
That is, compare the distance of the intersection of `s1` with `l1` from the
|
||||
source of `s1`, scaled by the length of `s1`, to the distance of the intersection
|
||||
of `s2` with `l2` from the source of `s2`, scaled by the length of `s2`.
|
||||
|
||||
\pre the intersection of `s1` and `l1` is a point
|
||||
\pre the intersection of `s2` and `l2` is a point
|
||||
*/
|
||||
typedef unspecified_type Compare_relative_intersection_along_segment_2;
|
||||
|
||||
/*!
|
||||
Function object type that provides
|
||||
`template <class VertexPointMap> bool operator()(boost::graph_traits<Triangle_mesh>::%vertex_descriptor v, Triangle_mesh& g, VertexPointMap vpm)`
|
||||
that returns true if the vertex is a saddle vertex (more than \f$ 2 \pi \f$ surface area
|
||||
over all adjacent faces), and false otherwise. `vpm` must be a model of concept `ReadablePropertyMap` that maps from `vertex_descriptor` to
|
||||
`Point_3` objects.
|
||||
*/
|
||||
typedef unspecified_type Is_saddle_vertex;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Creation
|
||||
/// @{
|
||||
/*!
|
||||
*/
|
||||
SurfaceMeshShortestPathTraits(SurfaceMeshShortestPathTraits& copy);
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Operations
|
||||
/// For all of the above predicate and construction types, e.g. `Func_obj_type`, a function must exist with the name `func_obj_type_object()` that creates an instance of the construction or predicate object type.
|
||||
/// For example:
|
||||
/// @{
|
||||
|
||||
Construct_point_2 construct_point_2_object();
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*!
|
||||
\ingroup PkgSurfaceMeshShortestPathConcepts
|
||||
|
||||
\cgalConcept
|
||||
|
||||
The concept `SurfaceMeshShortestPathVisitor` describes the requirements of the visitor type
|
||||
used to collect the edges and vertices traversed by a shortest path on the
|
||||
surface of a triangulated surface mesh.
|
||||
|
||||
The methods are called in the order of the shortest path sequence along the
|
||||
surface, starting with the target point and ending with the source point.
|
||||
|
||||
*/
|
||||
|
||||
class SurfaceMeshShortestPathVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
/// \name Methods
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
\brief Called when an edge was traversed in the shortest path sequence.
|
||||
\param edge halfedge of the surface mesh crossed by the shortest path. The halfedge is directed toward the face <em>nearest</em> to the target point.
|
||||
\param alpha value in the range [0.0,1.0] specifying where along `edge` the shortest path crossed.
|
||||
- 0.0 means it crossed at `source(edge)`
|
||||
- 1.0 means it crossed at `target(edge)`
|
||||
- Any other value is linearly interpolated between the endpoints.
|
||||
|
||||
Note that values of 0.0 and 1.0 are possible in some situations, and may not be reported as vertices.
|
||||
In particular, this will occur if the vertex crossed by the path is not a saddle vertex (less than \f$2\pi\f$ surface area).
|
||||
This is because from the perspective of the algorithm, this is indistinguishable from crossing anywhere else along the edge.
|
||||
*/
|
||||
void operator()(halfedge_descriptor edge, FT alpha);
|
||||
|
||||
/*!
|
||||
\brief Called when a vertex is encountered in the shortest path sequence.
|
||||
\param vertex the vertex of the surface mesh encountered by the shortest path.
|
||||
*/
|
||||
void operator()(vertex_descriptor vertex);
|
||||
|
||||
/*!
|
||||
\brief Called when a face location is encountered in the shortest path sequence.
|
||||
\remarks This will only be called as the first and/or last element in the path
|
||||
sequence, and only if the target/source point is an internal face location
|
||||
(i.e. not on an edge or at a vertex).
|
||||
\param face a face of the surface mesh encountered at the start or the end of the shortest path.
|
||||
\param location the barycentric coordinate inside `face` of this point on the path.
|
||||
*/
|
||||
void operator()(face_descriptor face, Barycentric_coordinate location);
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
PROJECT_NAME = "CGAL ${CGAL_CREATED_VERSION_NUM} - Triangulated Surface Mesh Shortest Paths"
|
||||
INPUT = ${CMAKE_SOURCE_DIR}/Surface_mesh_shortest_path/doc/Surface_mesh_shortest_path/ \
|
||||
${CMAKE_SOURCE_DIR}/Surface_mesh_shortest_path/include
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
EXTRACT_ALL = NO
|
||||
HIDE_UNDOC_CLASSES = YES
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Triangulated Surface Mesh Shortest Paths
|
||||
|
||||
/// \defgroup PkgSurfaceMeshShortestPath Triangulated Surface Mesh Shortest Paths Reference
|
||||
|
||||
/// \defgroup PkgSurfaceMeshShortestPathConcepts Concepts
|
||||
/// \ingroup PkgSurfaceMeshShortestPath
|
||||
|
||||
/// \defgroup PkgSurfaceMeshShortestPathTraitsClasses Traits Classes
|
||||
/// \ingroup PkgSurfaceMeshShortestPath
|
||||
|
||||
/*!
|
||||
\addtogroup PkgSurfaceMeshShortestPath
|
||||
\todo Modify the algorithm to support more efficient incremental construction
|
||||
\todo Add parallelization to the algorithm
|
||||
\todo Add methods for computing the ridge tree using the output of the algorithm
|
||||
\todo Add methods for computing shortest paths from geodesic sources as well
|
||||
|
||||
\cgalPkgDescriptionBegin{Triangulated Surface Mesh Shortest Paths,PkgSurfaceMeshShortestPathSummary}
|
||||
\cgalPkgPicture{shortestpathspackage-ico.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Stephen Kiazyk, Sébastien Loriot, Éric Colin de Verdière}
|
||||
\cgalPkgDesc{The package provides methods for computing shortest path on triangulated surface meshes. The algorithm used is based on a paper by Xin and Wang \cgalCite{XinWang2009improvingchenandhan} . The input of this package can be any model of the `FaceListGraph` concept. }
|
||||
\cgalPkgManuals{Chapter_Surface_mesh_shortest_path,PkgSurfaceMeshShortestPath}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{4.7}
|
||||
\cgalPkgDependsOn{\ref PkgBGLSummary and \ref PkgAABB_treeSummary for some convenience functions}
|
||||
\cgalPkgBib{cgal:klcdv-tsmsp}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Operations on Polyhedra,polyhedron_3.zip}
|
||||
\cgalPkgShortInfoEnd
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
## Concepts ##
|
||||
|
||||
- `SurfaceMeshShortestPathTraits`
|
||||
- `SurfaceMeshShortestPathVisitor`
|
||||
|
||||
## Classes ##
|
||||
- `CGAL::Surface_mesh_shortest_path<SurfaceMeshShortestPathTraits,VertexIndexMap, HalfedgeIndexMap, FaceIndexMap, VertexPointMap>`
|
||||
- `CGAL::Surface_mesh_shortest_path_traits<Kernel, FaceListGraph>`
|
||||
|
||||
## Enums ##
|
||||
|
||||
- `CGAL::Surface_mesh_shortest_paths_3::Barycentric_coordinate_type`
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\namespace CGAL::Surface_mesh_shortest_paths_3
|
||||
|
||||
\brief Namespace containing support members specific to this package.
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,413 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_Surface_mesh_shortest_path
|
||||
\anchor chaptersurfacemeshshortestpath
|
||||
\cgalAutoToc
|
||||
\author Stephen Kiazyk, Sébastien Loriot, and Éric Colin de Verdière
|
||||
|
||||
This package provides an algorithm to compute shortest paths on a triangulated surface mesh.
|
||||
|
||||
\cgalFigureBegin{Shortest_path_main,shortest_paths_overview.png}
|
||||
Shortest paths on a terrain using one source point represented by a green square.
|
||||
\cgalFigureEnd
|
||||
|
||||
\section Surface_mesh_shortest_pathIntroduction Introduction
|
||||
|
||||
The motion planning of a robot across the surface of a 3-dimensional terrain is a typical application of the shortest path computation.
|
||||
Using a 2-dimensional approximation would fail to capture anything interesting about the terrain we are trying to cross, and would give a poor solution. The problem is often called the <em>Discrete Geodesic Problem</em>. Although the more general version of this problem, shortest paths in 3D in the presence of obstacles, is NP-Hard, when the motion is constrained to the 2D surface of an object it can be solved efficiently.
|
||||
|
||||
The algorithm implemented in this package builds a data structure to efficiently answer queries of the following form:
|
||||
Given a triangulated surface mesh \f$\cal{M}\f$, a set of source points \f$S\f$ on \f$\cal{M}\f$, and a target point \f$t\f$ also on \f$\cal{M}\f$, find a shortest path \f$\lambda\f$ between \f$t\f$ and any element in \f$ S \f$, where \f$\lambda\f$ is constrained to the surface of \f$\cal{M}\f$.
|
||||
|
||||
The algorithm used is based on a paper by Xin and Wang \cgalCite{XinWang2009improvingchenandhan}, a fast and practical algorithm for exact computation of shortest paths. It is an extension of earlier results by Chen and Han \cgalCite{ch-spp-96} and Mitchell, Mount, and Papadimitriou \cgalCite{mmp-dgp-87} .
|
||||
|
||||
\section Surface_mesh_shortest_pathHowToUse User Interface Description
|
||||
|
||||
\subsection Surface_mesh_shortest_pathClass Surface Mesh Shortest Path Class
|
||||
|
||||
The main class of this package is `Surface_mesh_shortest_path`.
|
||||
In the following we describe the typical workflow when using this class
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathClassInput Specifying the Input
|
||||
|
||||
The shortest paths are computed on a triangulated surface mesh, represented by a model of
|
||||
the `FaceListGraph` concept. There is no restriction on the genus, connectivity, or convexity
|
||||
of the input surface mesh.
|
||||
|
||||
For efficiency reason, index property maps for vertices, halfedges and faces are internally used. For each simplex
|
||||
type the property map must provide an index between 0 and the number of simplices. We recommend to use
|
||||
the class `CGAL::Polyhedron_3` as model of `FaceListGraph` with the item class `CGAL::Polyhedron_items_with_id_3`,
|
||||
for which default property maps are provided.
|
||||
This item class associates to each simplex an index that provides a \f$O(1)\f$ time access to the indices.
|
||||
Note that the initialization of the property maps requires a call to `set_halfedgeds_items_id()`.
|
||||
|
||||
The access to the embedding of each vertex is done using a point vertex property map associating to each vertex a 3D point.
|
||||
%Defaults are provided for \cgal classes.
|
||||
|
||||
If the traits class used holds some local state, it must also be passed to the class when constructing it
|
||||
(the default one provided does not).
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathClassSource Specifying the Source Points
|
||||
|
||||
The set of source points for shortest path queries can be populated one by one or using a range.
|
||||
A source point can be specified using either a vertex of the input surface mesh or a face of the input surface mesh
|
||||
with some barycentric coordinate.
|
||||
Given a point \f$p\f$ that lies inside a triangle face \f$(A,B,C)\f$, its barycentric coordinate is a weight triple \f$(b_0,b_1,b_2)\f$ such that \f$p = b_0\cdot~A + b_1\cdot~B + b_2\cdot~C\f$, and \f$b_0 + b_1 + b_2 = 1\f$.
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathClassBuild Building the Internal Sequence Tree
|
||||
|
||||
A time consuming operation for shortest path queries consists in building an internal data structure used
|
||||
to make the queries. This data structure is called the <em>sequence tree</em>.
|
||||
It will be built automatically when the first shortest path query is done and will be reused
|
||||
for any subsequent query as long as the set of source points does not change. Each time the
|
||||
set of source points is changed the sequence tree needs to be rebuilt (if already built).
|
||||
Note that it can also be built manually by a call to `Surface_mesh_shortest_path::build_sequence_tree()`.
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathClassQueries Shortest Path Queries
|
||||
|
||||
As for specifying the source points, the target point for a shortest path query
|
||||
can be specified using either a vertex of the input surface mesh or a face of the input surface mesh
|
||||
and a barycentric coordinate.
|
||||
|
||||
There are three different kinds of query functions that can be called using the class `Surface_mesh_shortest_path`.
|
||||
Given a target point, all these functions compute the shortest path between that target point and the set of
|
||||
source points:
|
||||
|
||||
- `Surface_mesh_shortest_path::shortest_distance_to_source_points()` provides the closest source point to the target point together with the length of the shortest path.
|
||||
- `Surface_mesh_shortest_path::shortest_path_points_to_source_points()` provides all the intersection points of the shortest path with the edges and vertices of the input surface mesh (including the source and the target point). This function is useful for visualization purposes.
|
||||
- `Surface_mesh_shortest_path::shortest_path_sequence_to_source_points` gives access to the complete sequence of simplices crossed by the shortest path using a visitor object model of the concept `SurfaceMeshShortestPathVisitor`.
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathClassMore Additional Convenience Functionalities
|
||||
|
||||
Some convenience functions are provided to compute:
|
||||
- the point on the input surface mesh specified as a face of the input surface mesh and a barycentric coordinate.
|
||||
- the closest point on the input surface mesh (specified as a face of the input surface mesh and a barycentric coordinate) to a given 3D point. Those function are using the class `CGAL::AABB_tree`.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathKernelRecommendataions Kernel Recommendations
|
||||
In short, we recommend to use a \cgal kernel with exact predicates such as `CGAL::Exact_predicates_inexact_constructions_kernel`.
|
||||
|
||||
If you need the constructions to be exact (for the shortest path point computation for example), you should use a kernel with exact constructions.
|
||||
Although the algorithm uses square root operations, it will also work on geometry kernels which do not support them by first converting
|
||||
the kernel's number type to `double`, using the `std::sqrt`, and converting it back. Note that it would be preferable to use a kernel
|
||||
with directly supports square roots to get the most precision of the shortest path computations.
|
||||
|
||||
Using a kernel such as `CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt` with this package will indeed provide the exact shortest paths,
|
||||
but it will be extremely slow. Indeed, in order to compute the distance along the surface, it is necessary to unfold sequences of faces, edge-to-edge, out into a common plane. The functor `SurfaceMeshShortestPathTraits::Construct_triangle_3_to_triangle_2_projection` provides an initial layout of the first face in a sequence, by rotating a given face into the `xy`-plane. `SurfaceMeshShortestPathTraits::Construct_triangle_3_along_segment_2_flattening` unfolds a triangle into the plane, using a specified segment as a base. Since this results in a chain of constructed triangles in the plane, the exact representation types used with this kernel (either `CORE::Expr` or `leda_real`) will process extremely slow, even on very simple inputs. This is because the exact representations will effectively add an \f$O(n)\f$ factor to every computation.
|
||||
|
||||
\section Surface_mesh_shortest_pathExamples Examples
|
||||
|
||||
\subsection Surface_mesh_shortest_pathSimpleExample Simple Example
|
||||
|
||||
The following example shows how to get the shortest path to every vertex from an arbitrary source point on the surface. Note that this example uses the `Polyhedron_items_with_id_3` item class. The shortest path class needs to have an index associated to each vertex, halfedge and face. Using this item class provide an efficient direct access to the required indices.
|
||||
|
||||
\cgalExample{Surface_mesh_shortest_path/shortest_paths_with_id.cpp}
|
||||
|
||||
\subsection Surface_mesh_shortest_pathExampeWithoutId Example Using Polyhedron Items without IDs
|
||||
|
||||
Although it is better to have an index built into each simplex, you can also use a surface mesh without internal indices by using external indices.
|
||||
The following example shows how to proceed in this case.
|
||||
|
||||
\cgalExample{Surface_mesh_shortest_path/shortest_paths_no_id.cpp}
|
||||
|
||||
\subsection Surface_mesh_shortest_pathMultipleSources Using Multiple Source Points
|
||||
|
||||
This example shows how to compute the sequence tree from multiple source points, using an iterator range of `Surface_mesh_shortest_path::Face_location` objects generated at random.
|
||||
|
||||
\cgalExample{Surface_mesh_shortest_path/shortest_paths_multiple_sources.cpp}
|
||||
|
||||
\subsection Surface_mesh_shortest_pathSequenceVisitor Shortest Path Sequence Visitor
|
||||
|
||||
This example shows how to implement a model of the `SurfaceMeshShortestPathVisitor` concept to get detailed information about the sequence of simplicies crossed by a shortest path.
|
||||
|
||||
\cgalExample{Surface_mesh_shortest_path/shortest_path_sequence.cpp}
|
||||
|
||||
\todo add an example using the AABB-tree
|
||||
|
||||
\section Surface_mesh_shortest_pathBenchmarks Benchmarks
|
||||
|
||||
These benchmarks were run using randomly generated source and destination points over multiple trials.
|
||||
The measurements were executed using \cgal 4.5, under Cygwin 1.7.32, using the Gnu
|
||||
C++ compiler version 4.8.3 with options `-O3 -DNDEBUG`. The system used
|
||||
was a 64bit Intel Core i3 2.20GHz processor with 6GB of RAM
|
||||
|
||||
<!--
|
||||
They can be re-generated using
|
||||
\code{.sh}
|
||||
> ./run_benchmarks.sh
|
||||
\endcode
|
||||
|
||||
And then pasting the contents of benchmark_table_1.txt and benchmark_table_10.txt into the doc. For more details on how they were generated, see benchmarks/Surface_mesh_shortest_path/readme.txt
|
||||
-->
|
||||
|
||||
\subsection Surface_mesh_shortest_pathBenchmark1SourcePoint Single Source Point
|
||||
<center>
|
||||
Model | Number of Vertices | Average Construction Time (s) | Average Queries Per Second | Peak Memory Usage (MB)
|
||||
---|---|---|---|---
|
||||
ellipsoid.off | 162 | 0.00258805 | 1.21972e+06 | 0.39548
|
||||
anchor.off | 519 | 0.0580262 | 230461 | 3.88799
|
||||
rotor.off | 600 | 0.0386633 | 326175 | 3.10571
|
||||
spool.off | 649 | 0.0418305 | 299766 | 3.75773
|
||||
handle.off | 1165 | 0.0976167 | 227343 | 7.66706
|
||||
couplingdown.off | 1841 | 0.138467 | 246833 | 10.1731
|
||||
bones.off | 2154 | 0.0101125 | 1.31834e+06 | 0.865896
|
||||
mushroom.off | 2337 | 0.206034 | 202582 | 22.5804
|
||||
elephant.off | 2775 | 0.136177 | 313785 | 14.0987
|
||||
cow.off | 2904 | 0.259104 | 206515 | 17.4796
|
||||
knot1.off | 3200 | 0.279455 | 207084 | 25.314
|
||||
retinal.off | 3643 | 0.255788 | 247617 | 29.8031
|
||||
femur.off | 3897 | 0.25332 | 264825 | 21.4806
|
||||
knot2.off | 5760 | 0.295655 | 309593 | 22.5549
|
||||
bull.off | 6200 | 0.513506 | 209994 | 34.983
|
||||
fandisk.off | 6475 | 0.609507 | 198768 | 71.3617
|
||||
lion-head.off | 8356 | 1.23863 | 145810 | 86.6908
|
||||
turbine.off | 9210 | 2.23755 | 93079.5 | 172.072
|
||||
man.off | 17495 | 1.59015 | 187519 | 148.358
|
||||
</center>
|
||||
|
||||
\subsection Surface_mesh_shortest_pathBenchmark10SourcePoints Ten Source Points
|
||||
<center>
|
||||
Model | Number of Vertices | Average Construction Time (s) | Average Queries Per Second | Peak Memory Usage (MB)
|
||||
---|---|---|---|---
|
||||
ellipsoid.off | 162 | 0.00321017 | 911025 | 0.245674
|
||||
anchor.off | 519 | 0.03601 | 353062 | 3.19274
|
||||
rotor.off | 600 | 0.015864 | 805416 | 1.97554
|
||||
spool.off | 649 | 0.0165743 | 802701 | 2.09675
|
||||
handle.off | 1165 | 0.0294564 | 646057 | 4.62122
|
||||
couplingdown.off | 1841 | 0.126045 | 272465 | 7.80517
|
||||
bones.off | 2154 | 0.055434 | 536646 | 4.0203
|
||||
mushroom.off | 2337 | 0.139285 | 290425 | 11.462
|
||||
elephant.off | 2775 | 0.167269 | 285076 | 11.2743
|
||||
cow.off | 2904 | 0.15432 | 328549 | 13.0676
|
||||
knot1.off | 3200 | 0.114051 | 454640 | 16.1735
|
||||
retinal.off | 3643 | 0.233208 | 287869 | 18.6274
|
||||
femur.off | 3897 | 0.128097 | 457112 | 16.8295
|
||||
knot2.off | 5760 | 0.413548 | 260195 | 33.484
|
||||
bull.off | 6200 | 0.371713 | 297560 | 30.522
|
||||
fandisk.off | 6475 | 0.545929 | 223865 | 39.5607
|
||||
lion-head.off | 8356 | 0.70097 | 229449 | 59.6597
|
||||
turbine.off | 9210 | 1.35703 | 157301 | 90.7139
|
||||
man.off | 17495 | 1.75936 | 185194 | 122.541
|
||||
</center>
|
||||
|
||||
\subsection Surface_mesh_shortest_pathQueryComparison Comparison of Construction and Query Times with Multiple Source Points
|
||||
|
||||
The following figures track the construction time, query time, and peak memory usage for the various test models as the number of source points increases. Notice that none of the values increases significantly as the number of source points increases. In fact, in most cases, the running time and memory go down. This is because a larger number of source points tends to result in a more flat sequence tree, which translates to reduced runtime and memory costs.
|
||||
|
||||
\cgalFigureBegin{Benchmark_construction,benchmark_plot_construction.png}
|
||||
Plot of construction times against different numbers of source points.
|
||||
\cgalFigureEnd
|
||||
|
||||
\cgalFigureBegin{Benchmark_query,benchmark_plot_query.png}
|
||||
Plot of query times against different numbers of source points.
|
||||
\cgalFigureEnd
|
||||
|
||||
\cgalFigureBegin{Benchmark_memory,benchmark_plot_memory.png}
|
||||
Plot of peak memory usage against different numbers of source points.
|
||||
\cgalFigureEnd
|
||||
|
||||
\section Surface_mesh_shortest_pathTheory Implementation Details
|
||||
|
||||
\subsection Surface_mesh_shortest_pathDefinitions Definitions
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathGeodesics Geodesic Paths
|
||||
A <em>geodesic</em> curve is a <em>locally shortest</em> path on the surface of some manifold, that is, it cannot be made shorter by some local perturbations. On a surface mesh, this translates to a curve where, when the faces crossed by the curve are unfolded into the plane, the curve forms a straight line. Another way of describing it is that there is exactly \f$\pi\f$ surface angle to both sides at every point along the curve (except possibly at the curve's endpoints).
|
||||
|
||||
A geodesic curve between two points is not necessarily a shortest path, but all shortest paths on surface meshes are formed by sequences of one or more geodesic paths, whose junction points are either vertices on the boundary of the mesh, or \link Surface_mesh_shortest_pathSaddleVertex <em>saddle vertices</em>\endlink. We call such a curve on the surface of the mesh a <em>potential shortest path</em> between its two endpoints.
|
||||
|
||||
\cgalFigureBegin{Geodesic_perspective,perspectiveGeodesic.png}
|
||||
A geodesic on the surface of a simple surface mesh.
|
||||
\cgalFigureEnd
|
||||
|
||||
\cgalFigureBegin{Geodesic_unrolled,unrolledGeodesic.png}
|
||||
The same geodesic, with its faces unfolded into the plane. Note in the unfolding, the geodesic forms a straight line.
|
||||
\cgalFigureEnd
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathVisibilityWindow Visibility Window
|
||||
A <em>visibility window</em> (or <em>visibility cone</em>) is a pair of geodesic curves which share a common <em>source point</em> and enclose a <em>locally flat</em> region of the surface mesh. Locally flat means that between every pair of points inside the window, there is exactly one geodesic path between them which also stays inside the bounds of the window. Thus, operations, such as distance calculations, can be done with normal 2D %Euclidean operations while inside the window. When a visibility window encounters a vertex (a non-flat part of the surface), a <em>branch</em> occurs, forming a sub-window to either side.
|
||||
|
||||
\cgalFigureBegin{Visibility_window_1,visibilityCone-1.png}
|
||||
A single visibility window, before it encounters a vertex.
|
||||
\cgalFigureEnd
|
||||
|
||||
\cgalFigureBegin{Visibility_window_2,visibilityCone-2.png}
|
||||
After encountering a convex vertex, the visibility window branches to either side (blue on the left, red on the right). Note that the two new windows immediately overlap on the other side of the vertex, since the surrounding surface area is less than \f$2 \pi\f$. Points inside this region of overlap might have two possible shortest paths from the origin point.
|
||||
\cgalFigureEnd
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathSaddleVertex Saddle Vertices
|
||||
A <em>saddle vertex</em> on a surface mesh is a vertex \f$v\f$ where the sum of surface angles of all faces incident at \f$v\f$ is greater than \f$2 \pi\f$, or, in simpler terms, one cannot flatten all the faces incident to \f$v\f$ into the plane without overlap. Identifying and dealing with saddle vertices are important in shortest path algorithms because they form <em>blind spots</em> which cannot be reached by a single geodesic curve.
|
||||
|
||||
\cgalFigureBegin{Saddle_vertex,saddleVertex.png}
|
||||
A visibility window (shaded blue) encounters a saddle vertex; the shaded red region behind the vertex is not reachable by a geodesic curve from the source point (assuming the geodesic must stay inside the initial window).
|
||||
\cgalFigureEnd
|
||||
|
||||
In order to deal with this, we must create a new set of child visibility windows which branch out around the saddle vertex. The paths through these child windows would first arrive at the saddle vertex, and then follow a new visibility window (forming a kind of poly-line on the surface). Note that similar behavior is required when we reach a boundary vertex of a non-closed surface mesh.
|
||||
|
||||
\cgalFigureBegin{Saddle_vertex_expand,saddleVertexExpand.png}
|
||||
In order to see past the <em>blind spot</em> created by the saddle vertex, we create a branching set of visibility windows emanating from the saddle vertex. Note that only the branches which cover the <em>blind spot</em> for the parent visibility window are needed for our algorithm.
|
||||
\cgalFigureEnd
|
||||
|
||||
\subsubsection Surface_mesh_shortest_pathSequenceTree The Sequence Tree
|
||||
|
||||
In order to compute shortest paths, we build a <em>sequence tree</em> (or <em>cone tree</em>) from each source point. The sequence tree describes the combinatoric structure of all <em>potential shortest paths</em> which originate from a single source point, by organizing them into a hierarchy of visibility windows.
|
||||
|
||||
Whenever a vertex of the surface mesh is encountered, a branch occurs in the sequence tree. If the vertex is a non-saddle vertex, then only two children are created, one for each edge incident to that vertex on the current face. If the vertex is a saddle vertex, in addition to the two children mentioned above, a special type of node, called a <em>pseudo-source</em>, is created which branches out from that vertex.
|
||||
|
||||
Once a sequence tree is built, the <em>potential shortest paths</em> from the source to every point inside a given visibility window can be computed. The sequence of faces along each branch of the tree are laid out edge to edge, into a common plane, such that the geodesic distance from any point on the surface to its nearest source point can be obtained using a single 2D %Euclidean distance computation. Note that if the window belongs to a pseudo-source, the distance is measured from the target to the pseudo-source, and then the distance from the pseudo-source back to its parent is measured, and so on back to the original source.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathAlgorithmOverview Algorithm Overview
|
||||
The size of the sequence tree from any source point is theoretically infinite, however we only ever care about trees which are of depth at most N, where N is the number of faces in the surface mesh (since no shortest path can cross the same face twice). Even then, the size of this truncated sequence tree is potentially exponential in the size of the surface mesh, thus a simple breadth-first search is not feasible. Rather, we apply techniques to eliminate entire branches which are provably unable to contain shortest paths from the source point(s). The techniques used are given in greater detail in a paper by Xin and Wang \cgalCite{XinWang2009improvingchenandhan}, which itself expands an earlier work by Chen and Han \cgalCite{ch-spp-96} and Mitchell, Mount, and Papadimitriou \cgalCite{mmp-dgp-87} .
|
||||
|
||||
Handling multiple source points is simply a matter of constructing multiple sequence trees concurrently, using a method similar to the multi-source Dijsktra's algorithm.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathContinuousDijkstra Continuous Dijkstra
|
||||
Continuous Dijkstra is simply the application of the graph-search algorithm to a non-discrete setting. As we build the search tree, newly created nodes are tagged with a distance metric, and inserted into a priority queue, such that the shortest distance nodes are always first.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathOneAngleOneSplit One Angle, One Split
|
||||
This observation by Chen and Han states that out of all the branches that occur at any given vertex of the surface mesh, only a limited number have more than one child which can define shortest paths. This is accomplished by maintaining, for each vertex, all nodes of the sequence tree which can contain that vertex inside their visibility window.
|
||||
|
||||
- For each vertex, only <em>one</em> two-way branch may occur per face incident to that vertex, specifically, that of the nearest node to that vertex which crosses that face. We call that closest node the <em>occupier</em> of that vertex.
|
||||
- If the vertex is a saddle vertex, only one pseudo-source may be established at that vertex, this time by the absolute nearest node to that vertex.
|
||||
|
||||
|
||||
This method alone can decrease the running time for construction of the sequence tree construction to polynomial time.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathDistanceFiltering Distance Filtering
|
||||
|
||||
An additional distance filter proposed by Xin and Wang helps prune the search tree even further by comparing the current node's distance to the closest distance so far of the three vertices on the current face. Details on this method can be found in their paper \cgalCite{XinWang2009improvingchenandhan}.
|
||||
|
||||
\subsection Surface_mesh_shortest_pathLocatingShortestPaths Locating Shortest Paths
|
||||
|
||||
In order to locate the shortest path from a target point to a source point, we must select the correct visibility window. A simple method is to keep track for each face \f$f\f$ of all windows which cross \f$f\f$. In practice, at most a constant number of windows will cross any given face, so for simplicity this is the method we employ. An alternative is to construct a Voronoi-like structure on each face, where each cell represents a visibility window. We did not attempt this method, however it would seem likely that it would be of no computational benefit.
|
||||
|
||||
\subsection Pseudo-Code
|
||||
|
||||
In this section we give a brief outline of the pseudo-code for this algorithm. More details can be found in \cgalCite{ch-spp-96} and \cgalCite{XinWang2009improvingchenandhan}.
|
||||
|
||||
\verbatim
|
||||
--
|
||||
-- Global Values
|
||||
--
|
||||
G : FaceGraph(V,E,F)
|
||||
-- V - the set of vertices
|
||||
-- E - the set of edges
|
||||
-- F - the set of planar faces
|
||||
|
||||
Q : PriorityQueue
|
||||
-- A priority queue ordered using the metric given by Xin and Wang
|
||||
|
||||
--
|
||||
-- Types
|
||||
--
|
||||
type VisbilityWindow:
|
||||
f : a face of F, the current face of this window, we say this window 'crosses' face f
|
||||
s : a point on the surface of F, the source point of this window
|
||||
d : the 'base distance' to s, only non-zero if s is a pseudo-source
|
||||
l : the left-side bounding ray of this window, with its origin at s
|
||||
r : the right-side bounding ray of this window, with its origin at s
|
||||
p : its parent VisibilityWindow
|
||||
|
||||
--
|
||||
-- Methods
|
||||
--
|
||||
method XinWangDistanceFilter:
|
||||
Input:
|
||||
w : a VisibilityWindow
|
||||
Output:
|
||||
filter : true if w passes the distance filtering metric given by Xin and Wang, false otherwise
|
||||
|
||||
method PropagateWindow:
|
||||
Input:
|
||||
w : a visibility window
|
||||
e : an edge on face w.f
|
||||
Output:
|
||||
w' : A new visibility window on the face opposite w.f across edge e
|
||||
Begin:
|
||||
Let f' be the face on the opposite side of e as w.f
|
||||
Lay out face f' along e, such that it shares a common plane with w.f
|
||||
Create a new VisibilityWindow w', with
|
||||
- w its parent
|
||||
- the same source point and base distance as w
|
||||
- its boundary rays clipped to the sub-segment of e covered by w
|
||||
return w'
|
||||
|
||||
method CreateFaceWindow:
|
||||
Input:
|
||||
f : a face of F
|
||||
v : a vertex of f
|
||||
w : a VisibilityWindow which intersects f and contains v
|
||||
Output:
|
||||
w' : a new VisibilityWindow, with
|
||||
-- w its parent
|
||||
-- its source point s = v
|
||||
-- its two bounding rays along the edges incident to v
|
||||
-- face f as its crossed face
|
||||
-- its base distance being the distance of window w to v
|
||||
|
||||
method CreatePseudoSource:
|
||||
Input:
|
||||
w : the parent window
|
||||
v : a saddle vertex of V
|
||||
Begin:
|
||||
For each face f incident to v:
|
||||
w' = CreateFaceWindow(f, v, w)
|
||||
Q.insert(w')
|
||||
|
||||
method TreeDepth:
|
||||
Input:
|
||||
w : a VisibilityWindow in some sequence tree T
|
||||
Output:
|
||||
The depth of node w in its current sequence tree (this would typically be cached in w itself)
|
||||
|
||||
method ShortestPathTree:
|
||||
Input:
|
||||
s[1..n] : a set of source points on the surface of G.
|
||||
For simplicity (and without loss of generality),
|
||||
we will assume they are all vertices of G.
|
||||
Output:
|
||||
T[1..n] : a set of sequence trees for the source points
|
||||
Declare:
|
||||
O : a map of (f,v) => VisibilityWindow, which gives the 'vertex occupier' for (f,v),
|
||||
that is the window which crosses face f and whose source is nearest to vertex v
|
||||
S : a map of v => VisibilityWindow, which gives the window whose source is nearest
|
||||
to v. Note that this is a strict subset of O
|
||||
Begin:
|
||||
for i in 1..n:
|
||||
Let r[i] be the root of T[i], with distance 0 to s[i]
|
||||
CreatePseudoSource( r[i], s[i] )
|
||||
While Q is not empty:
|
||||
w = Q.take()
|
||||
if XinWangDistanceFilter(w) and TreeDepth(w) <= |F|:
|
||||
if w contains a vertex v of w.f:
|
||||
if w is closer to v than O[w.f,v]:
|
||||
O[w.f,v] = w
|
||||
if v is a boundary vertex or a saddle vertex, and w is closer to v than S[v]:
|
||||
S[v] = w
|
||||
CreatePseudoSource(w, v, w.dist(v))
|
||||
let {e_0, e_1} be the edges of f incident to v
|
||||
for i in [0,1]:
|
||||
w' = PropagateWindow(w, e_i)
|
||||
Q.insert(w')
|
||||
else:
|
||||
let e_n be the edge 'closer' to window w
|
||||
w' = PropagateWindow(w, e_n)
|
||||
Q.insert(w')
|
||||
else:
|
||||
let e_o be the only edge crossed by window w
|
||||
w' = PropagateWindow(w, e_o)
|
||||
Q.insert(w')
|
||||
return T[1..n]
|
||||
\endverbatim
|
||||
|
||||
To perform shortest path distance queries to each vertex, we can simply use the results stored in `S` after the completion of ShortestPathTree, as it contains a map from each vertex to the `VisibilityWindow` which has the shortest path to that vertex. Performing shortest path computations to any arbitrary face location is slightly more complex. As eluded to above, after completion of the algorithm, we traverse each of the sequence trees, and for each face `f` we store all the VisibilityWindows which cross `f` in a look-up structure. Then, to find the shortest path to a point on the surface of face `f`, we look up that pre-stored set of VisibilityWindows associated with it, and among those windows we select the one which contains the query point and has the shortest path back to the origin. Though it may seem slow since it involves a linear search but it is efficient in practice since the number of faces crossing any single face is typically limited (this is due to the additional filtering method given by Xin and Wang \cgalCite{XinWang2009improvingchenandhan}.
|
||||
|
||||
The actual surface paths can be reconstructed by backtracking from the VisibilityWindow, through its parents in the tree up to the root, and keeping track of each face that was crossed.
|
||||
|
||||
\section Surface_mesh_shortest_pathImplementationhistory Design and Implementation History
|
||||
This package is the result of the work of Stephen Kiazyk during the 2014 season
|
||||
of the Google Summer of Code. He has been mentored by Sébastien Loriot and Éric Colin de Verdière
|
||||
who also contributed to the documentation and the API definition.
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
STL_Extension
|
||||
Algebraic_foundations
|
||||
Circulator
|
||||
Stream_support
|
||||
BGL
|
||||
AABB_tree
|
||||
Polyhedron
|
||||
Number_types
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/*!
|
||||
\example Surface_mesh_shortest_path/shortest_paths_with_id.cpp
|
||||
\example Surface_mesh_shortest_path/shortest_paths_no_id.cpp
|
||||
\example Surface_mesh_shortest_path/shortest_paths_OpenMesh.cpp
|
||||
\example Surface_mesh_shortest_path/shortest_paths_multiple_sources.cpp
|
||||
\example Surface_mesh_shortest_path/shortest_path_sequence.cpp
|
||||
*/
|
||||
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -0,0 +1,3 @@
|
|||
demo
|
||||
benchmark
|
||||
examples
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# Created by the script cgal_create_cmake_script
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
|
||||
project( Surface_mesh_shortest_path_ )
|
||||
|
||||
cmake_minimum_required(VERSION 2.6.2)
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
|
||||
cmake_policy(VERSION 2.8.4)
|
||||
else()
|
||||
cmake_policy(VERSION 2.6)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(CGAL QUIET COMPONENTS Core )
|
||||
|
||||
if ( CGAL_FOUND )
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
include_directories (BEFORE "../../include")
|
||||
|
||||
create_single_source_cgal_program( "shortest_path_sequence.cpp" )
|
||||
create_single_source_cgal_program( "shortest_paths_multiple_sources.cpp" )
|
||||
create_single_source_cgal_program( "shortest_paths_no_id.cpp" )
|
||||
create_single_source_cgal_program( "shortest_paths_with_id.cpp" )
|
||||
|
||||
find_package( OpenMesh QUIET )
|
||||
if ( OpenMesh_FOUND )
|
||||
include( UseOpenMesh )
|
||||
create_single_source_cgal_program( "shortest_paths_OpenMesh.cpp" )
|
||||
target_link_libraries( shortest_paths_OpenMesh ${OPENMESH_LIBRARIES} )
|
||||
else()
|
||||
message(STATUS "Examples that use OpenMesh will not be compiled.")
|
||||
endif()
|
||||
else()
|
||||
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
|
||||
endif()
|
||||
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef Traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
typedef Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
typedef Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
// A model of SurfaceMeshShortestPathVisitor storing simplicies
|
||||
// using boost::variant
|
||||
struct Sequence_collector
|
||||
{
|
||||
typedef boost::variant< vertex_descriptor,
|
||||
std::pair<halfedge_descriptor,double>,
|
||||
std::pair<face_descriptor, Barycentric_coordinate> > Simplex;
|
||||
std::vector< Simplex > sequence;
|
||||
|
||||
void operator()(halfedge_descriptor he, double alpha)
|
||||
{
|
||||
|
||||
sequence.push_back( std::make_pair(he, alpha) );
|
||||
}
|
||||
|
||||
void operator()(vertex_descriptor v)
|
||||
{
|
||||
sequence.push_back( v );
|
||||
}
|
||||
|
||||
void operator()(face_descriptor f, Barycentric_coordinate alpha)
|
||||
{
|
||||
sequence.push_back( std::make_pair(f, alpha) );
|
||||
}
|
||||
};
|
||||
|
||||
// A visitor to print what a variant contains using boost::apply_visitor
|
||||
struct Print_visitor : public boost::static_visitor<> {
|
||||
int i;
|
||||
Polyhedron_3& g;
|
||||
|
||||
Print_visitor(Polyhedron_3& g) :i(-1), g(g) {}
|
||||
|
||||
void operator()(vertex_descriptor v)
|
||||
{
|
||||
std::cout << "#" << ++i << " : Vertex : " << get(boost::vertex_index, g)[v] << "\n";
|
||||
}
|
||||
|
||||
void operator()(const std::pair<halfedge_descriptor,double>& h_a)
|
||||
{
|
||||
std::cout << "#" << ++i << " : Edge : " << get(CGAL::halfedge_index, g)[h_a.first] << " , ("
|
||||
<< 1.0 - h_a.second << " , "
|
||||
<< h_a.second << ")\n";
|
||||
}
|
||||
|
||||
void operator()(const std::pair<face_descriptor, Barycentric_coordinate>& f_bc)
|
||||
{
|
||||
std::cout << "#" << ++i << " : Face : " << get(CGAL::face_index, g)[f_bc.first] << " , ("
|
||||
<< f_bc.second[0] << " , "
|
||||
<< f_bc.second[1] << " , "
|
||||
<< f_bc.second[2] << ")\n";
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// read input polyhedron
|
||||
Polyhedron_3 polyhedron;
|
||||
std::ifstream input((argc>1)?argv[1]:"data/elephant.off");
|
||||
input >> polyhedron;
|
||||
input.close();
|
||||
|
||||
// initialize indices of vertices, halfedges and facets
|
||||
CGAL::set_halfedgeds_items_id(polyhedron);
|
||||
|
||||
// pick up a random face
|
||||
const size_t randSeed = argc > 2 ? std::atoi(argv[2]) : 7915421;
|
||||
CGAL::Random rand(randSeed);
|
||||
const int target_face_index = rand.get_int(0, num_faces(polyhedron));
|
||||
face_iterator face_it = faces(polyhedron).first;
|
||||
std::advance(face_it,target_face_index);
|
||||
// ... and define a barycentric coordinate inside the face
|
||||
Barycentric_coordinate face_location = {{0.25, 0.5, 0.25}};
|
||||
|
||||
// construct a shortest path query object and add a source point
|
||||
Surface_mesh_shortest_path shortest_paths(polyhedron);
|
||||
shortest_paths.add_source_point(*face_it, face_location);
|
||||
|
||||
// pick a random target point inside a face
|
||||
face_it = faces(polyhedron).first;
|
||||
std::advance(face_it, rand.get_int(0, num_faces(polyhedron)));
|
||||
|
||||
// collect the sequence of simplicies crossed by the shortest path
|
||||
Sequence_collector sequence_collector;
|
||||
shortest_paths.shortest_path_sequence_to_source_points(*face_it, face_location, sequence_collector);
|
||||
|
||||
// print the sequence using the visitor pattern
|
||||
Print_visitor print_visitor(polyhedron);
|
||||
for (size_t i = 0; i < sequence_collector.sequence.size(); ++i)
|
||||
boost::apply_visitor(print_visitor, sequence_collector.sequence[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <OpenMesh/Core/IO/MeshIO.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
|
||||
|
||||
#include <CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h>
|
||||
#include <CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h>
|
||||
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path_traits.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
|
||||
typedef OpenMesh::PolyMesh_ArrayKernelT<> Mesh;
|
||||
|
||||
typedef boost::graph_traits<Mesh> Graph_traits;
|
||||
typedef Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Mesh> Traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// read the input surface mesh
|
||||
Mesh polyhedron;
|
||||
OpenMesh::IO::read_mesh(polyhedron, (argc>1)?argv[1]:"data/elephant.off");
|
||||
|
||||
// pick up a random face
|
||||
const size_t randSeed = argc > 2 ? std::atoi(argv[2]) : 7915421;
|
||||
CGAL::Random rand(randSeed);
|
||||
const int target_face_index = rand.get_int(0, num_faces(polyhedron));
|
||||
face_iterator face_it = faces(polyhedron).first;
|
||||
std::advance(face_it,target_face_index);
|
||||
// ... and define a barycentric coordinate inside the face
|
||||
Traits::Barycentric_coordinate face_location = {{0.25, 0.5, 0.25}};
|
||||
|
||||
// construct a shortest path query object and add a source point
|
||||
Surface_mesh_shortest_path shortest_paths(polyhedron);
|
||||
shortest_paths.add_source_point(*face_it, face_location);
|
||||
|
||||
// For all vertices in the polyhedron, compute the points of
|
||||
// the shortest path to the source point and write them
|
||||
// into a file readable using the CGAL Polyhedron demo
|
||||
std::ofstream output("shortest_paths_OpenMesh.cgal");
|
||||
vertex_iterator vit, vit_end;
|
||||
for ( boost::tie(vit, vit_end) = vertices(polyhedron);
|
||||
vit != vit_end; ++vit)
|
||||
{
|
||||
std::vector<Traits::Point_3> points;
|
||||
shortest_paths.shortest_path_points_to_source_points(*vit, std::back_inserter(points));
|
||||
|
||||
// print the points
|
||||
output << points.size() << " ";
|
||||
for (std::size_t i = 0; i < points.size(); ++i)
|
||||
output << " " << points[i];
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef Surface_mesh_shortest_path::Face_location Face_location;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// read input polyhedron
|
||||
Polyhedron_3 polyhedron;
|
||||
std::ifstream input((argc>1)?argv[1]:"data/elephant.off");
|
||||
input >> polyhedron;
|
||||
input.close();
|
||||
|
||||
// initialize indices of vertices, halfedges and facets
|
||||
CGAL::set_halfedgeds_items_id(polyhedron);
|
||||
|
||||
// pick up some source points inside faces,
|
||||
const size_t randSeed = argc > 2 ? std::atoi(argv[2]) : 7915421;
|
||||
CGAL::Random rand(randSeed);
|
||||
// by copying the faces in a vector to get a direct access to faces
|
||||
std::size_t nb_faces=num_faces(polyhedron);
|
||||
face_iterator fit, fit_end;
|
||||
boost::tie(fit, fit_end) = faces(polyhedron);
|
||||
std::vector<face_descriptor> face_vector(fit, fit_end);
|
||||
// and creating a vector of Face_location objects
|
||||
const std::size_t nb_source_points = 30;
|
||||
Traits::Barycentric_coordinate face_location = {{0.25, 0.5, 0.25}};
|
||||
std::vector<Face_location> faceLocations(nb_source_points, Face_location(face_descriptor(), face_location));
|
||||
for (std::size_t i = 0; i < nb_source_points; ++i)
|
||||
{
|
||||
faceLocations[i].first=face_vector[rand.get_int(0, nb_faces)];
|
||||
}
|
||||
|
||||
// construct a shortest path query object and add a range of source points
|
||||
Surface_mesh_shortest_path shortest_paths(polyhedron);
|
||||
shortest_paths.add_source_points(faceLocations.begin(), faceLocations.end());
|
||||
|
||||
// For all vertices in the polyhedron, compute the points of
|
||||
// the shortest path to the source point and write them
|
||||
// into a file readable using the CGAL Polyhedron demo
|
||||
std::ofstream output("shortest_paths_multiple_sources.cgal");
|
||||
vertex_iterator vit, vit_end;
|
||||
for ( boost::tie(vit, vit_end) = vertices(polyhedron);
|
||||
vit != vit_end; ++vit)
|
||||
{
|
||||
std::vector<Traits::Point_3> points;
|
||||
shortest_paths.shortest_path_points_to_source_points(*vit, std::back_inserter(points));
|
||||
|
||||
// print the points
|
||||
output << points.size() << " ";
|
||||
for (std::size_t i = 0; i < points.size(); ++i)
|
||||
output << " " << points[i];
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Default.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path.h>
|
||||
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
// default property maps
|
||||
typedef boost::property_map<Polyhedron_3,
|
||||
boost::vertex_external_index_t>::type Vertex_index_map;
|
||||
typedef boost::property_map<Polyhedron_3,
|
||||
CGAL::halfedge_external_index_t>::type Halfedge_index_map;
|
||||
typedef boost::property_map<Polyhedron_3,
|
||||
CGAL::face_external_index_t>::type Face_index_map;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits,
|
||||
Vertex_index_map,
|
||||
Halfedge_index_map,
|
||||
Face_index_map> Surface_mesh_shortest_path;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::halfedge_iterator halfedge_iterator;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// read input polyhedron
|
||||
Polyhedron_3 polyhedron;
|
||||
std::ifstream input((argc>1)?argv[1]:"data/elephant.off");
|
||||
input >> polyhedron;
|
||||
input.close();
|
||||
|
||||
// pick up a random face
|
||||
const size_t randSeed = argc > 2 ? std::atoi(argv[2]) : 7915421;
|
||||
CGAL::Random rand(randSeed);
|
||||
const int target_face_index = rand.get_int(0, num_faces(polyhedron));
|
||||
face_iterator face_it = faces(polyhedron).first;
|
||||
std::advance(face_it,target_face_index);
|
||||
// ... and define a barycentric coordinate inside the face
|
||||
Traits::Barycentric_coordinate face_location = {{0.25, 0.5, 0.25}};
|
||||
|
||||
// construct a shortest path query object and add a source point
|
||||
// Note that the external index property map are automatically initialized
|
||||
Surface_mesh_shortest_path shortest_paths(polyhedron,
|
||||
get(boost::vertex_external_index, polyhedron),
|
||||
get(CGAL::halfedge_external_index, polyhedron),
|
||||
get(CGAL::face_external_index, polyhedron),
|
||||
get(CGAL::vertex_point, polyhedron));
|
||||
shortest_paths.add_source_point(*face_it, face_location);
|
||||
|
||||
// For all vertices in the polyhedron, compute the points of
|
||||
// the shortest path to the source point and write them
|
||||
// into a file readable using the CGAL Polyhedron demo
|
||||
std::ofstream output("shortest_paths_no_id.cgal");
|
||||
vertex_iterator vit, vit_end;
|
||||
for ( boost::tie(vit, vit_end) = vertices(polyhedron);
|
||||
vit != vit_end; ++vit)
|
||||
{
|
||||
std::vector<Traits::Point_3> points;
|
||||
shortest_paths.shortest_path_points_to_source_points(*vit, std::back_inserter(points));
|
||||
|
||||
// print the points
|
||||
output << points.size() << " ";
|
||||
for (std::size_t i = 0; i < points.size(); ++i)
|
||||
output << " " << points[i];
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// read input polyhedron
|
||||
Polyhedron_3 polyhedron;
|
||||
std::ifstream input((argc>1)?argv[1]:"data/elephant.off");
|
||||
input >> polyhedron;
|
||||
input.close();
|
||||
|
||||
// initialize indices of vertices, halfedges and facets
|
||||
CGAL::set_halfedgeds_items_id(polyhedron);
|
||||
|
||||
// pick up a random face
|
||||
const size_t randSeed = argc > 2 ? std::atoi(argv[2]) : 7915421;
|
||||
CGAL::Random rand(randSeed);
|
||||
const int target_face_index = rand.get_int(0, num_faces(polyhedron));
|
||||
face_iterator face_it = faces(polyhedron).first;
|
||||
std::advance(face_it,target_face_index);
|
||||
// ... and define a barycentric coordinate inside the face
|
||||
Traits::Barycentric_coordinate face_location = {{0.25, 0.5, 0.25}};
|
||||
|
||||
// construct a shortest path query object and add a source point
|
||||
Surface_mesh_shortest_path shortest_paths(polyhedron);
|
||||
shortest_paths.add_source_point(*face_it, face_location);
|
||||
|
||||
// For all vertices in the polyhedron, compute the points of
|
||||
// the shortest path to the source point and write them
|
||||
// into a file readable using the CGAL Polyhedron demo
|
||||
std::ofstream output("shortest_paths_with_id.cgal");
|
||||
vertex_iterator vit, vit_end;
|
||||
for ( boost::tie(vit, vit_end) = vertices(polyhedron);
|
||||
vit != vit_end; ++vit)
|
||||
{
|
||||
std::vector<Traits::Point_3> points;
|
||||
shortest_paths.shortest_path_points_to_source_points(*vit, std::back_inserter(points));
|
||||
|
||||
// print the points
|
||||
output << points.size() << " ";
|
||||
for (std::size_t i = 0; i < points.size(); ++i)
|
||||
output << " " << points[i];
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_H
|
||||
|
||||
/**
|
||||
* \ingroup PkgSurfaceMeshShortestPath
|
||||
* \file CGAL/Surface_mesh_shortest_path.h
|
||||
* Convenience header file only including `CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h`
|
||||
* and `CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path_traits.h`.
|
||||
*/
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path_traits.h>
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATH_H
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_TRAITS_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_TRAITS_H
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/barycentric.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/function_objects.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgSurfaceMeshShortestPathTraitsClasses
|
||||
|
||||
\brief A model of the concept `SurfaceMeshShortestPathTraits`
|
||||
as required by the `Surface_mesh_shortest_path` class.
|
||||
|
||||
\tparam K A \cgal Kernel
|
||||
|
||||
\tparam G A model of `FaceListGraph`
|
||||
|
||||
\cgalModels `SurfaceMeshShortestPathTraits`
|
||||
*/
|
||||
template <
|
||||
class K,
|
||||
class G>
|
||||
class Surface_mesh_shortest_path_traits : public K
|
||||
{
|
||||
public:
|
||||
|
||||
/// Kernel type
|
||||
typedef K Kernel;
|
||||
|
||||
/// Triangle mesh type
|
||||
typedef G Triangle_mesh;
|
||||
|
||||
typedef typename Kernel::FT FT;
|
||||
|
||||
/// Barycentric coordinate type
|
||||
typedef typename CGAL::cpp11::array<FT,3> Barycentric_coordinate;
|
||||
|
||||
// Predicates
|
||||
public:
|
||||
typedef typename Surface_mesh_shortest_paths_3::Compare_relative_intersection_along_segment_2<Kernel> Compare_relative_intersection_along_segment_2;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Is_saddle_vertex<Kernel, Triangle_mesh> Is_saddle_vertex;
|
||||
|
||||
// Constructions
|
||||
public:
|
||||
class Construct_barycentric_coordinate
|
||||
{
|
||||
public:
|
||||
typedef Barycentric_coordinate result_type;
|
||||
|
||||
result_type operator() (const FT& a, const FT& b, const FT& c) const
|
||||
{
|
||||
Barycentric_coordinate output;
|
||||
output[0] = a;
|
||||
output[1] = b;
|
||||
output[2] = c;
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
class Construct_barycentric_coordinate_weight
|
||||
{
|
||||
public:
|
||||
typedef FT result_type;
|
||||
|
||||
result_type operator() (const Barycentric_coordinate b, std::size_t i) const
|
||||
{
|
||||
return b[i % 3];
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename Surface_mesh_shortest_paths_3::Construct_triangle_3_to_triangle_2_projection<K> Construct_triangle_3_to_triangle_2_projection;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Construct_triangle_3_along_segment_2_flattening<K> Construct_triangle_3_along_segment_2_flattening;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Compute_parametric_distance_along_segment_2<K> Compute_parametric_distance_along_segment_2;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Construct_barycentric_coordinate_in_triangle_2<K, Barycentric_coordinate, Construct_barycentric_coordinate> Construct_barycentric_coordinate_in_triangle_2;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Construct_barycentric_coordinate_in_triangle_3<K, Barycentric_coordinate, Construct_barycentric_coordinate> Construct_barycentric_coordinate_in_triangle_3;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Classify_barycentric_coordinate<Barycentric_coordinate, Construct_barycentric_coordinate_weight> Classify_barycentric_coordinate;
|
||||
|
||||
private:
|
||||
Kernel m_kernel;
|
||||
Construct_barycentric_coordinate m_construct_barycentric_coordinate_object;
|
||||
Construct_barycentric_coordinate_weight m_construct_barycentric_coordinate_weight_object;
|
||||
Classify_barycentric_coordinate m_classify_barycentric_coordinate_object;
|
||||
Construct_triangle_3_to_triangle_2_projection m_construct_triangle_3_to_triangle_2_projection_object;
|
||||
Construct_triangle_3_along_segment_2_flattening m_construct_triangle_3_along_segment_2_flattening_object;
|
||||
Construct_barycentric_coordinate_in_triangle_2 m_construct_barycentric_coordinate_in_triangle_2_object;
|
||||
Construct_barycentric_coordinate_in_triangle_3 m_construct_barycentric_coordinate_in_triangle_3_object;
|
||||
Compare_relative_intersection_along_segment_2 m_compare_relative_intersection_along_segment_2_object;
|
||||
Is_saddle_vertex m_is_saddle_vertex_object;
|
||||
Compute_parametric_distance_along_segment_2 m_compute_parametric_distance_along_segment_2_object;
|
||||
|
||||
public:
|
||||
|
||||
Surface_mesh_shortest_path_traits()
|
||||
{
|
||||
}
|
||||
|
||||
Surface_mesh_shortest_path_traits(const Kernel& kernel)
|
||||
: m_kernel(kernel)
|
||||
, m_classify_barycentric_coordinate_object(m_construct_barycentric_coordinate_weight_object)
|
||||
, m_construct_triangle_3_to_triangle_2_projection_object(m_kernel)
|
||||
, m_construct_triangle_3_along_segment_2_flattening_object(m_kernel)
|
||||
, m_is_saddle_vertex_object(m_kernel, m_construct_triangle_3_to_triangle_2_projection_object, m_construct_triangle_3_along_segment_2_flattening_object)
|
||||
, m_compare_relative_intersection_along_segment_2_object(m_kernel)
|
||||
, m_construct_barycentric_coordinate_in_triangle_2_object(m_construct_barycentric_coordinate_object, m_kernel.construct_vector_2_object(), m_kernel.compute_scalar_product_2_object())
|
||||
, m_construct_barycentric_coordinate_in_triangle_3_object(m_construct_barycentric_coordinate_object, m_kernel.construct_vector_3_object(), m_kernel.compute_scalar_product_3_object())
|
||||
{
|
||||
}
|
||||
|
||||
Construct_barycentric_coordinate construct_barycentric_coordinate_object() const { return m_construct_barycentric_coordinate_object; }
|
||||
Construct_barycentric_coordinate_weight construct_barycentric_coordinate_weight_object() const { return m_construct_barycentric_coordinate_weight_object; }
|
||||
Classify_barycentric_coordinate classify_barycentric_coordinate_object() const { return m_classify_barycentric_coordinate_object; }
|
||||
|
||||
Is_saddle_vertex is_saddle_vertex_object() const { return m_is_saddle_vertex_object; }
|
||||
|
||||
Compare_relative_intersection_along_segment_2 compare_relative_intersection_along_segment_2_object() const { return m_compare_relative_intersection_along_segment_2_object; }
|
||||
Construct_triangle_3_to_triangle_2_projection construct_triangle_3_to_triangle_2_projection_object() const { return m_construct_triangle_3_to_triangle_2_projection_object; }
|
||||
Construct_triangle_3_along_segment_2_flattening construct_triangle_3_along_segment_2_flattening_object() const { return m_construct_triangle_3_along_segment_2_flattening_object; }
|
||||
Construct_barycentric_coordinate_in_triangle_2 construct_barycentric_coordinate_in_triangle_2_object() const { return m_construct_barycentric_coordinate_in_triangle_2_object; }
|
||||
Construct_barycentric_coordinate_in_triangle_3 construct_barycentric_coordinate_in_triangle_3_object() const { return m_construct_barycentric_coordinate_in_triangle_3_object; }
|
||||
Compute_parametric_distance_along_segment_2 compute_parametric_distance_along_segment_2_object() const { return m_compute_parametric_distance_along_segment_2_object; }
|
||||
};
|
||||
|
||||
template <class Kernel, class Triangle_mesh>
|
||||
std::ostream& operator<<(std::ostream& os, typename Surface_mesh_shortest_path_traits<Kernel, Triangle_mesh>::Barycentric_coordinate b)
|
||||
{
|
||||
return os << b[0] << " " << b[1] << " " << b[2];
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN_RUNNING // needed due to a bug in doxygen
|
||||
/*!
|
||||
\ingroup PkgSurfaceMeshShortestPathTraitsClasses
|
||||
|
||||
\internal
|
||||
|
||||
\brief Provides an implementation of the SurfaceMeshShortestPathTraits
|
||||
model which uses an exact Kernel during the unfolding operations to achieve better overall precision
|
||||
|
||||
\tparam K Kernel Type
|
||||
|
||||
\tparam G triangle mesh type
|
||||
|
||||
\cgalModels `SurfaceMeshShortestPathTraits`
|
||||
*/
|
||||
template <
|
||||
class K,
|
||||
class G>
|
||||
class Surface_mesh_shortest_path_traits_with_robust_unfolding : public Surface_mesh_shortest_path_traits<K,G>
|
||||
{
|
||||
public:
|
||||
typedef K Kernel;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Robust_project_triangle_3_to_triangle_2<K> Construct_triangle_3_to_triangle_2_projection;
|
||||
typedef typename Surface_mesh_shortest_paths_3::Robust_flatten_triangle_3_along_segment_2<K> Construct_triangle_3_along_segment_2_flattening;
|
||||
|
||||
private:
|
||||
|
||||
Construct_triangle_3_to_triangle_2_projection m_robust_construct_triangle_3_to_triangle_2_projection_object;
|
||||
Construct_triangle_3_along_segment_2_flattening m_robust_flatten_triangle_3_along_segment_2;
|
||||
|
||||
public:
|
||||
|
||||
Surface_mesh_shortest_path_traits_with_robust_unfolding()
|
||||
{
|
||||
}
|
||||
|
||||
Surface_mesh_shortest_path_traits_with_robust_unfolding(const Kernel& kernel)
|
||||
: Surface_mesh_shortest_path_traits<K,G>(kernel)
|
||||
, m_robust_construct_triangle_3_to_triangle_2_projection_object(kernel)
|
||||
, m_robust_flatten_triangle_3_along_segment_2(kernel)
|
||||
{
|
||||
}
|
||||
|
||||
Construct_triangle_3_to_triangle_2_projection construct_triangle_3_to_triangle_2_projection_object() const { return m_robust_construct_triangle_3_to_triangle_2_projection_object; }
|
||||
Construct_triangle_3_along_segment_2_flattening construct_triangle_3_along_segment_2_flattening_object() const { return m_robust_flatten_triangle_3_along_segment_2; }
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATH_TRAITS_H
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_BARYCENTRIC_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_BARYCENTRIC_H
|
||||
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Surface_mesh_shortest_paths_3 {
|
||||
|
||||
template <class K, class B, class Construct_barycentric_coordinate>
|
||||
class Construct_barycentric_coordinate_in_triangle_2
|
||||
{
|
||||
public:
|
||||
typedef typename K::FT FT;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
typedef typename K::Point_2 Point_2;
|
||||
typedef typename K::Vector_2 Vector_2;
|
||||
|
||||
typedef typename K::Construct_vector_2 Construct_vector_2;
|
||||
typedef typename K::Compute_scalar_product_2 Compute_scalar_product_2;
|
||||
|
||||
typedef B result_type;
|
||||
|
||||
private:
|
||||
Construct_barycentric_coordinate m_construct_barycentric_coordinate;
|
||||
Construct_vector_2 m_construct_vector_2;
|
||||
Compute_scalar_product_2 m_compute_scalar_product_2;
|
||||
|
||||
public:
|
||||
Construct_barycentric_coordinate_in_triangle_2()
|
||||
{
|
||||
}
|
||||
|
||||
Construct_barycentric_coordinate_in_triangle_2(const Construct_barycentric_coordinate& cbc, const Construct_vector_2& cv2, const Compute_scalar_product_2& csp2)
|
||||
: m_construct_barycentric_coordinate(cbc)
|
||||
, m_construct_vector_2(cv2)
|
||||
, m_compute_scalar_product_2(csp2)
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator()(const Triangle_2& t, const Point_2& p) const
|
||||
{
|
||||
Vector_2 v0 = m_construct_vector_2(t[0], t[1]);
|
||||
Vector_2 v1 = m_construct_vector_2(t[0], t[2]);
|
||||
Vector_2 v2 = m_construct_vector_2(t[0], p);
|
||||
|
||||
FT d00 = m_compute_scalar_product_2(v0, v0);
|
||||
FT d01 = m_compute_scalar_product_2(v0, v1);
|
||||
FT d11 = m_compute_scalar_product_2(v1, v1);
|
||||
FT d20 = m_compute_scalar_product_2(v2, v0);
|
||||
FT d21 = m_compute_scalar_product_2(v2, v1);
|
||||
|
||||
FT denom = d00 * d11 - d01 * d01;
|
||||
|
||||
FT v = (d11 * d20 - d01 * d21) / denom;
|
||||
FT w = (d00 * d21 - d01 * d20) / denom;
|
||||
return m_construct_barycentric_coordinate(FT(1.0) - v - w, v, w);
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class B, class Construct_barycentric_coordinate>
|
||||
class Construct_barycentric_coordinate_in_triangle_3
|
||||
{
|
||||
public:
|
||||
typedef typename K::FT FT;
|
||||
typedef typename K::Triangle_3 Triangle_3;
|
||||
typedef typename K::Point_3 Point_3;
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
|
||||
typedef typename K::Construct_vector_3 Construct_vector_3;
|
||||
typedef typename K::Compute_scalar_product_3 Compute_scalar_product_3;
|
||||
|
||||
typedef B result_type;
|
||||
|
||||
private:
|
||||
Construct_barycentric_coordinate m_construct_barycentric_coordinate;
|
||||
Construct_vector_3 m_construct_vector_3;
|
||||
Compute_scalar_product_3 m_compute_scalar_product_3;
|
||||
|
||||
public:
|
||||
Construct_barycentric_coordinate_in_triangle_3()
|
||||
{
|
||||
}
|
||||
|
||||
Construct_barycentric_coordinate_in_triangle_3(const Construct_barycentric_coordinate& cbc, const Construct_vector_3& cv3, const Compute_scalar_product_3& csp3)
|
||||
: m_construct_barycentric_coordinate(cbc)
|
||||
, m_construct_vector_3(cv3)
|
||||
, m_compute_scalar_product_3(csp3)
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator()(const Triangle_3& t, const Point_3& p) const
|
||||
{
|
||||
Vector_3 v0 = m_construct_vector_3(t[0], t[1]);
|
||||
Vector_3 v1 = m_construct_vector_3(t[0], t[2]);
|
||||
Vector_3 v2 = m_construct_vector_3(t[0], p);
|
||||
|
||||
FT d00 = m_compute_scalar_product_3(v0, v0);
|
||||
FT d01 = m_compute_scalar_product_3(v0, v1);
|
||||
FT d11 = m_compute_scalar_product_3(v1, v1);
|
||||
FT d20 = m_compute_scalar_product_3(v2, v0);
|
||||
FT d21 = m_compute_scalar_product_3(v2, v1);
|
||||
|
||||
FT denom = d00 * d11 - d01 * d01;
|
||||
|
||||
FT v = (d11 * d20 - d01 * d21) / denom;
|
||||
FT w = (d00 * d21 - d01 * d20) / denom;
|
||||
return m_construct_barycentric_coordinate(FT(1.0) - v - w, v, w);
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Classification of the location of a 3-tuple barycentric coordinate in a triangle
|
||||
*/
|
||||
enum Barycentric_coordinate_type
|
||||
{
|
||||
/// If the coordinate is invalid
|
||||
BARYCENTRIC_COORDINATE_INVALID = 0,
|
||||
/// if the coordinate has exactly one non-zero weight equal to 1, and the rest are zero
|
||||
BARYCENTRIC_COORDINATE_ON_VERTEX,
|
||||
///if the coordinate has exactly one zero weight, and the rest sum to 1
|
||||
BARYCENTRIC_COORDINATE_ON_BOUNDARY,
|
||||
/// if the coordinate has no non-zero weight, and they all sum to 1
|
||||
BARYCENTRIC_COORDINATE_ON_BOUNDED_SIDE,
|
||||
/// if the weights of the coordinate do not sum to 1
|
||||
BARYCENTRIC_COORDINATE_ON_UNBOUNDED_SIDE
|
||||
};
|
||||
|
||||
template <class B, class Construct_barycentric_coordinate_weight>
|
||||
class Classify_barycentric_coordinate
|
||||
{
|
||||
public:
|
||||
typedef B Barycentric_coordinate;
|
||||
typedef std::pair<Barycentric_coordinate_type, std::size_t> result_type;
|
||||
|
||||
private:
|
||||
Construct_barycentric_coordinate_weight m_construct_barycentric_coordinate_weight;
|
||||
|
||||
public:
|
||||
|
||||
Classify_barycentric_coordinate()
|
||||
{
|
||||
}
|
||||
|
||||
Classify_barycentric_coordinate(const Construct_barycentric_coordinate_weight& construct_barycentric_coordinate_weight)
|
||||
: m_construct_barycentric_coordinate_weight(construct_barycentric_coordinate_weight)
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator()(const Barycentric_coordinate& baryCoords)
|
||||
{
|
||||
Construct_barycentric_coordinate_weight cbcw;
|
||||
|
||||
bool nonZero[3];
|
||||
std::size_t numNonZero = 0;
|
||||
|
||||
if (cbcw(baryCoords, 0) + cbcw(baryCoords, 1) + cbcw(baryCoords, 2) > 1.00001 || cbcw(baryCoords, 0) + cbcw(baryCoords, 1) + cbcw(baryCoords, 2) < 0.99999)
|
||||
{
|
||||
return std::make_pair(BARYCENTRIC_COORDINATE_ON_UNBOUNDED_SIDE, 0);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
nonZero[i] = !CGAL::is_zero(cbcw(baryCoords, i));
|
||||
|
||||
if (nonZero[i])
|
||||
{
|
||||
++numNonZero;
|
||||
}
|
||||
}
|
||||
|
||||
if (numNonZero == 3)
|
||||
{
|
||||
return std::make_pair(BARYCENTRIC_COORDINATE_ON_BOUNDED_SIDE, 0);
|
||||
}
|
||||
else if (numNonZero == 2)
|
||||
{
|
||||
std::size_t associatedEdge = 3;
|
||||
|
||||
if (!nonZero[0])
|
||||
{
|
||||
associatedEdge = 1;
|
||||
}
|
||||
else if (!nonZero[1])
|
||||
{
|
||||
associatedEdge = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
associatedEdge = 0;
|
||||
}
|
||||
|
||||
return std::make_pair(BARYCENTRIC_COORDINATE_ON_BOUNDARY, associatedEdge);
|
||||
}
|
||||
else if (numNonZero == 1)
|
||||
{
|
||||
std::size_t associatedEdge = 3;
|
||||
|
||||
if (nonZero[0])
|
||||
{
|
||||
associatedEdge = 0;
|
||||
}
|
||||
else if (nonZero[1])
|
||||
{
|
||||
associatedEdge = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
associatedEdge = 2;
|
||||
}
|
||||
|
||||
return std::make_pair(BARYCENTRIC_COORDINATE_ON_VERTEX, associatedEdge);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair(BARYCENTRIC_COORDINATE_INVALID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace Surface_mesh_shortest_paths_3
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATHS_3_BARYCENTRIC_H
|
||||
|
|
@ -0,0 +1,621 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/result_of.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/internal/misc_functions.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_FUNCTION_OBJECTS_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_FUNCTION_OBJECTS_H
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Surface_mesh_shortest_paths_3 {
|
||||
|
||||
template <class Kernel>
|
||||
class Compute_parametric_distance_along_segment_2
|
||||
{
|
||||
public:
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_2 Point_2;
|
||||
typedef typename Kernel::Vector_2 Vector_2;
|
||||
typedef typename Kernel::Segment_2 Segment_2;
|
||||
|
||||
typedef typename Kernel::Intersect_2 Intersect_2;
|
||||
typedef typename Kernel::Construct_cartesian_const_iterator_2 Construct_cartesian_const_iterator_2;
|
||||
typedef typename Kernel::Construct_vector_2 Construct_vector_2;
|
||||
typedef typename Kernel::Construct_source_2 Construct_source_2;
|
||||
typedef typename Kernel::Construct_target_2 Construct_target_2;
|
||||
|
||||
typedef typename Kernel::Cartesian_const_iterator_2 Cartesian_const_iterator_2;
|
||||
|
||||
typedef FT result_type;
|
||||
|
||||
private:
|
||||
Intersect_2 m_intersect_2;
|
||||
Construct_cartesian_const_iterator_2 m_construct_cartesian_const_iterator_2;
|
||||
Construct_vector_2 m_construct_vector_2;
|
||||
Construct_source_2 m_construct_source_2;
|
||||
Construct_target_2 m_construct_target_2;
|
||||
|
||||
|
||||
public:
|
||||
Compute_parametric_distance_along_segment_2()
|
||||
{
|
||||
}
|
||||
|
||||
Compute_parametric_distance_along_segment_2(const Kernel& kernel)
|
||||
: m_intersect_2(kernel.intersect_2_object())
|
||||
, m_construct_cartesian_const_iterator_2(kernel.construct_cartesian_const_iterator_2_object())
|
||||
, m_construct_vector_2(kernel.construct_vector_2_object())
|
||||
, m_construct_source_2(kernel.construct_source_2_object())
|
||||
, m_construct_target_2(kernel.construct_target_2_object())
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator () (const Segment_2& s, const Point_2& p) const
|
||||
{
|
||||
return (*this)(m_construct_source_2(s), m_construct_target_2(s), p);
|
||||
}
|
||||
|
||||
result_type operator () (const Point_2& x0, const Point_2& x1, const Point_2& point) const
|
||||
{
|
||||
Vector_2 lineDiff(m_construct_vector_2(x0, x1));
|
||||
Vector_2 pointDiff(m_construct_vector_2(x0, point));
|
||||
|
||||
Cartesian_const_iterator_2 lineDiffIt(m_construct_cartesian_const_iterator_2(lineDiff));
|
||||
Cartesian_const_iterator_2 pointDiffIt(m_construct_cartesian_const_iterator_2(pointDiff));
|
||||
|
||||
FT lineDiff_x = *lineDiffIt;
|
||||
++lineDiffIt;
|
||||
FT lineDiff_y = *lineDiffIt;
|
||||
|
||||
FT pointDiff_x = *pointDiffIt;
|
||||
++pointDiffIt;
|
||||
FT pointDiff_y = *pointDiffIt;
|
||||
|
||||
if (CGAL::abs(lineDiff_x) > CGAL::abs(lineDiff_y))
|
||||
{
|
||||
return pointDiff_x / lineDiff_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pointDiff_y / lineDiff_y;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Kernel>
|
||||
class Parametric_distance_along_segment_3
|
||||
{
|
||||
public:
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point_3;
|
||||
typedef typename Kernel::Vector_3 Vector_3;
|
||||
typedef typename Kernel::Segment_3 Segment_3;
|
||||
|
||||
typedef typename Kernel::Construct_cartesian_const_iterator_3 Construct_cartesian_const_iterator_3;
|
||||
typedef typename Kernel::Construct_vector_3 Construct_vector_3;
|
||||
typedef typename Kernel::Construct_source_3 Construct_source_3;
|
||||
typedef typename Kernel::Construct_target_3 Construct_target_3;
|
||||
|
||||
typedef typename Kernel::Cartesian_const_iterator_3 Cartesian_const_iterator_3;
|
||||
|
||||
typedef FT result_type;
|
||||
|
||||
private:
|
||||
Construct_cartesian_const_iterator_3 m_construct_cartesian_const_iterator_3;
|
||||
Construct_vector_3 m_construct_vector_3;
|
||||
Construct_source_3 m_construct_source_3;
|
||||
Construct_target_3 m_construct_target_3;
|
||||
|
||||
|
||||
public:
|
||||
Parametric_distance_along_segment_3()
|
||||
{
|
||||
}
|
||||
|
||||
Parametric_distance_along_segment_3(const Kernel& kernel)
|
||||
: m_construct_cartesian_const_iterator_3(kernel.construct_cartesian_const_iterator_3_object())
|
||||
, m_construct_vector_3(kernel.construct_vector_3_object())
|
||||
, m_construct_source_3(kernel.construct_source_3_object())
|
||||
, m_construct_target_3(kernel.construct_target_3_object())
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator () (const Segment_3& s, const Point_3& p) const
|
||||
{
|
||||
return (*this)(m_construct_source_3(s), m_construct_target_3(s), p);
|
||||
}
|
||||
|
||||
result_type operator () (const Point_3& x0, const Point_3& x1, const Point_3& point) const
|
||||
{
|
||||
Vector_3 lineDiff(m_construct_vector_3(x0, x1));
|
||||
Vector_3 pointDiff(m_construct_vector_3(x0, point));
|
||||
|
||||
Cartesian_const_iterator_3 lineDiffIt(m_construct_cartesian_const_iterator_3(lineDiff));
|
||||
Cartesian_const_iterator_3 pointDiffIt(m_construct_cartesian_const_iterator_3(pointDiff));
|
||||
|
||||
FT lineDiff_x = *lineDiffIt;
|
||||
++lineDiffIt;
|
||||
FT lineDiff_y = *lineDiffIt;
|
||||
++lineDiffIt;
|
||||
FT lineDiff_z = *lineDiffIt;
|
||||
|
||||
FT pointDiff_x = *pointDiffIt;
|
||||
++pointDiffIt;
|
||||
FT pointDiff_y = *pointDiffIt;
|
||||
++pointDiffIt;
|
||||
FT pointDiff_z = *pointDiffIt;
|
||||
|
||||
if (CGAL::abs(lineDiff_x) > CGAL::abs(lineDiff_y) && CGAL::abs(lineDiff_x) > CGAL::abs(lineDiff_z))
|
||||
{
|
||||
return pointDiff_x / lineDiff_x;
|
||||
}
|
||||
else if (CGAL::abs(lineDiff_y) > CGAL::abs(lineDiff_z))
|
||||
{
|
||||
return pointDiff_y / lineDiff_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pointDiff_z / lineDiff_z;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class K>
|
||||
class Construct_triangle_3_to_triangle_2_projection
|
||||
{
|
||||
public:
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
typedef typename K::FT FT;
|
||||
typedef typename K::Triangle_3 Triangle_3;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
typedef typename K::Point_2 Point_2;
|
||||
typedef typename K::Point_3 Point_3;
|
||||
typedef typename K::Line_3 Line_3;
|
||||
|
||||
typedef typename K::Construct_line_3 Construct_line_3;
|
||||
typedef typename K::Compute_squared_distance_3 Compute_squared_distance_3;
|
||||
typedef typename K::Construct_vertex_3 Construct_vertex_3;
|
||||
typedef typename K::Construct_vector_3 Construct_vector_3;
|
||||
typedef typename K::Construct_point_2 Construct_point_2;
|
||||
typedef typename K::Construct_triangle_2 Construct_triangle_2;
|
||||
typedef typename K::Construct_projected_point_3 Construct_projected_point_3;
|
||||
|
||||
private:
|
||||
Parametric_distance_along_segment_3<K> m_parametric_distance_along_segment_3;
|
||||
Compute_squared_distance_3 m_compute_squared_distance_3;
|
||||
Construct_line_3 m_construct_line_3;
|
||||
Construct_projected_point_3 m_construct_projected_point_3;
|
||||
mutable Construct_vertex_3 m_construct_vertex_3;
|
||||
//~ Construct_vector_3 m_construct_vector_3;
|
||||
Construct_point_2 m_construct_point_2;
|
||||
Construct_triangle_2 m_construct_triangle_2;
|
||||
|
||||
public:
|
||||
Construct_triangle_3_to_triangle_2_projection()
|
||||
{
|
||||
}
|
||||
|
||||
Construct_triangle_3_to_triangle_2_projection(const K& kernel)
|
||||
: m_compute_squared_distance_3(kernel.compute_squared_distance_3_object())
|
||||
, m_construct_line_3(kernel.construct_line_3_object())
|
||||
, m_construct_vertex_3(kernel.construct_vertex_3_object())
|
||||
, m_construct_projected_point_3(kernel.construct_projected_point_3_object())
|
||||
, m_construct_point_2(kernel.construct_point_2_object())
|
||||
, m_construct_triangle_2(kernel.construct_triangle_2_object())
|
||||
{
|
||||
}
|
||||
|
||||
Triangle_2 operator() (const Triangle_3& t3) const
|
||||
{
|
||||
Line_3 baseSegment(m_construct_line_3(m_construct_vertex_3(t3, 0), m_construct_vertex_3(t3, 1)));
|
||||
|
||||
Point_3 projectedLocation3d(m_construct_projected_point_3(baseSegment, m_construct_vertex_3(t3, 2)));
|
||||
FT scalePoint = m_parametric_distance_along_segment_3(m_construct_vertex_3(t3, 0), m_construct_vertex_3(t3, 1), projectedLocation3d);
|
||||
FT triangleHeight = CGAL::internal::select_sqrt(m_compute_squared_distance_3(projectedLocation3d, t3[2]));
|
||||
FT v01Len = CGAL::internal::select_sqrt(m_compute_squared_distance_3(t3[1], t3[0]));
|
||||
|
||||
Point_2 A(m_construct_point_2(0.0, 0.0));
|
||||
Point_2 B(m_construct_point_2(v01Len, 0.0));
|
||||
Point_2 C(m_construct_point_2(v01Len * scalePoint, triangleHeight));
|
||||
|
||||
return m_construct_triangle_2(A, B, C);
|
||||
}
|
||||
};
|
||||
|
||||
template<class K>
|
||||
class Robust_project_triangle_3_to_triangle_2
|
||||
{
|
||||
public:
|
||||
typedef typename K::Triangle_3 Triangle_3;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
typedef Exact_predicates_exact_constructions_kernel_with_sqrt EKSQRT;
|
||||
typedef Construct_triangle_3_to_triangle_2_projection<EKSQRT> Exact_project_triangle_3_to_triangle_2;
|
||||
typedef Cartesian_converter<K, EKSQRT> To_exact;
|
||||
typedef Cartesian_converter<EKSQRT, K> Back_from_exact;
|
||||
|
||||
public:
|
||||
Robust_project_triangle_3_to_triangle_2()
|
||||
{
|
||||
}
|
||||
|
||||
Robust_project_triangle_3_to_triangle_2(const K& /* kernel */)
|
||||
{
|
||||
}
|
||||
|
||||
Triangle_2 operator() (const Triangle_3& t3) const
|
||||
{
|
||||
Exact_project_triangle_3_to_triangle_2 ept3t2;
|
||||
To_exact to_exact;
|
||||
Back_from_exact back_from_exact;
|
||||
|
||||
return back_from_exact(ept3t2(to_exact(t3)));
|
||||
}
|
||||
};
|
||||
|
||||
template<class K>
|
||||
class Construct_triangle_3_along_segment_2_flattening
|
||||
{
|
||||
public:
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
typedef typename K::Vector_2 Vector_2;
|
||||
typedef typename K::Line_3 Line_3;
|
||||
typedef typename K::FT FT;
|
||||
typedef typename K::Triangle_3 Triangle_3;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
typedef typename K::Point_2 Point_2;
|
||||
typedef typename K::Point_3 Point_3;
|
||||
typedef typename K::Segment_2 Segment_2;
|
||||
|
||||
typedef typename K::Compute_squared_distance_3 Compute_squared_distance_3;
|
||||
typedef typename K::Construct_projected_point_3 Construct_projected_point_3;
|
||||
typedef typename K::Construct_perpendicular_vector_2 Construct_perpendicular_vector_2;
|
||||
typedef typename K::Construct_sum_of_vectors_2 Construct_sum_of_vectors_2;
|
||||
typedef typename K::Construct_scaled_vector_2 Construct_scaled_vector_2;
|
||||
typedef typename K::Construct_translated_point_2 Construct_translated_point_2;
|
||||
typedef typename K::Construct_vector_2 Construct_vector_2;
|
||||
typedef typename K::Compute_squared_length_2 Compute_squared_length_2;
|
||||
typedef typename K::Construct_vertex_3 Construct_vertex_3;
|
||||
typedef typename K::Construct_triangle_2 Construct_triangle_2;
|
||||
typedef typename K::Construct_line_3 Construct_line_3;
|
||||
typedef typename K::Construct_segment_3 Construct_segment_3;
|
||||
typedef typename K::Construct_source_2 Construct_source_2;
|
||||
typedef typename K::Construct_target_2 Construct_target_2;
|
||||
|
||||
typedef Triangle_2 result_type;
|
||||
|
||||
private:
|
||||
|
||||
Parametric_distance_along_segment_3<K> m_parametric_distance_along_segment_3;
|
||||
Compute_squared_distance_3 m_compute_squared_distance_3;
|
||||
Construct_projected_point_3 m_construct_projected_point_3;
|
||||
Construct_perpendicular_vector_2 m_construct_perpendicular_vector_2;
|
||||
Construct_sum_of_vectors_2 m_construct_sum_of_vectors_2;
|
||||
Construct_scaled_vector_2 m_construct_scaled_vector_2;
|
||||
Construct_translated_point_2 m_construct_translated_point_2;
|
||||
Construct_vector_2 m_construct_vector_2;
|
||||
Compute_squared_length_2 m_compute_squared_length_2;
|
||||
Construct_line_3 m_construct_line_3;
|
||||
Construct_segment_3 m_construct_segment_3;
|
||||
Construct_source_2 m_construct_source_2;
|
||||
Construct_target_2 m_construct_target_2;
|
||||
mutable Construct_vertex_3 m_construct_vertex_3;
|
||||
Construct_triangle_2 m_construct_triangle_2;
|
||||
|
||||
public:
|
||||
Construct_triangle_3_along_segment_2_flattening()
|
||||
{
|
||||
}
|
||||
|
||||
Construct_triangle_3_along_segment_2_flattening(const K& kernel)
|
||||
: m_compute_squared_distance_3(kernel.compute_squared_distance_3_object())
|
||||
, m_construct_projected_point_3(kernel.construct_projected_point_3_object())
|
||||
, m_construct_perpendicular_vector_2(kernel.construct_perpendicular_vector_2_object())
|
||||
, m_construct_sum_of_vectors_2(kernel.construct_sum_of_vectors_2_object())
|
||||
, m_construct_scaled_vector_2(kernel.construct_scaled_vector_2_object())
|
||||
, m_construct_translated_point_2(kernel.construct_translated_point_2_object())
|
||||
, m_construct_vector_2(kernel.construct_vector_2_object())
|
||||
, m_compute_squared_length_2(kernel.compute_squared_length_2_object())
|
||||
, m_construct_line_3(kernel.construct_line_3_object())
|
||||
, m_construct_segment_3(kernel.construct_segment_3_object())
|
||||
, m_construct_source_2(kernel.construct_source_2_object())
|
||||
, m_construct_target_2(kernel.construct_target_2_object())
|
||||
, m_construct_vertex_3(kernel.construct_vertex_3_object())
|
||||
, m_construct_triangle_2(kernel.construct_triangle_2_object())
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator() (const Triangle_3& t3, std::size_t edgeIndex, const Segment_2& segment) const
|
||||
{
|
||||
Point_3 projectedLocation3d(m_construct_projected_point_3(m_construct_line_3(m_construct_vertex_3(t3, edgeIndex), m_construct_vertex_3(t3, edgeIndex + 1)), m_construct_vertex_3(t3, edgeIndex + 2)));
|
||||
FT scalePoint = m_parametric_distance_along_segment_3(m_construct_segment_3(m_construct_vertex_3(t3, edgeIndex), m_construct_vertex_3(t3, edgeIndex + 1)), projectedLocation3d);
|
||||
FT triangleHeight = CGAL::internal::select_sqrt(m_compute_squared_distance_3(projectedLocation3d, m_construct_vertex_3(t3, edgeIndex + 2)));
|
||||
|
||||
Vector_2 edgeVector(m_construct_vector_2(segment));
|
||||
|
||||
Vector_2 perpendicularEdgeVector(m_construct_perpendicular_vector_2(edgeVector, CGAL::COUNTERCLOCKWISE));
|
||||
perpendicularEdgeVector = m_construct_scaled_vector_2(perpendicularEdgeVector, FT(1.0) / CGAL::internal::select_sqrt(m_compute_squared_length_2(perpendicularEdgeVector)));
|
||||
|
||||
Point_2 points[3];
|
||||
points[edgeIndex] = m_construct_source_2(segment);
|
||||
points[(edgeIndex + 1) % 3] = m_construct_target_2(segment);
|
||||
points[(edgeIndex + 2) % 3] = m_construct_translated_point_2(m_construct_source_2(segment), m_construct_sum_of_vectors_2(m_construct_scaled_vector_2(edgeVector, scalePoint), m_construct_scaled_vector_2(perpendicularEdgeVector, triangleHeight)));
|
||||
|
||||
return m_construct_triangle_2(points[0], points[1], points[2]);
|
||||
}
|
||||
};
|
||||
|
||||
template<class K>
|
||||
class Robust_flatten_triangle_3_along_segment_2
|
||||
{
|
||||
public:
|
||||
typedef typename K::Triangle_3 Triangle_3;
|
||||
typedef typename K::Segment_2 Segment_2;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
|
||||
typedef Exact_predicates_exact_constructions_kernel_with_sqrt EKSQRT;
|
||||
typedef Construct_triangle_3_along_segment_2_flattening<EKSQRT> Exact_flatten_triangle_3_along_segment_2;
|
||||
typedef Cartesian_converter<K, EKSQRT> To_exact;
|
||||
typedef Cartesian_converter<EKSQRT, K> Back_from_exact;
|
||||
|
||||
public:
|
||||
Robust_flatten_triangle_3_along_segment_2()
|
||||
{
|
||||
}
|
||||
|
||||
Robust_flatten_triangle_3_along_segment_2(const K& /* kernel */)
|
||||
{
|
||||
}
|
||||
|
||||
Triangle_2 operator() (const Triangle_3& t3, std::size_t edgeIndex, const Segment_2& segment) const
|
||||
{
|
||||
Exact_flatten_triangle_3_along_segment_2 eft3as2;
|
||||
To_exact to_exact;
|
||||
Back_from_exact back_from_exact;
|
||||
|
||||
return back_from_exact(eft3as2(to_exact(t3), edgeIndex, to_exact(segment)));
|
||||
}
|
||||
};
|
||||
|
||||
template <class K>
|
||||
class Compare_relative_intersection_along_segment_2
|
||||
{
|
||||
public:
|
||||
typedef typename K::FT FT;
|
||||
typedef typename K::Ray_2 Ray_2;
|
||||
typedef typename K::Vector_2 Vector_2;
|
||||
typedef typename K::Triangle_2 Triangle_2;
|
||||
typedef typename K::Point_2 Point_2;
|
||||
typedef typename K::Segment_2 Segment_2;
|
||||
typedef typename K::Line_2 Line_2;
|
||||
|
||||
typedef typename K::Intersect_2 Intersect_2;
|
||||
typedef typename K::Compare_distance_2 Compare_distance_2;
|
||||
typedef typename K::Construct_line_2 Construct_line_2;
|
||||
typedef typename K::Construct_source_2 Construct_source_2;
|
||||
typedef typename K::Construct_target_2 Construct_target_2;
|
||||
|
||||
typedef CGAL::Comparison_result result_type;
|
||||
|
||||
private:
|
||||
Compute_parametric_distance_along_segment_2<K> m_parametric_distance_along_segment_2;
|
||||
Intersect_2 m_intersect_2;
|
||||
Compare_distance_2 m_compare_distance_2;
|
||||
Construct_line_2 m_construct_line_2;
|
||||
Construct_source_2 m_construct_source_2;
|
||||
Construct_target_2 m_construct_target_2;
|
||||
|
||||
public:
|
||||
Compare_relative_intersection_along_segment_2()
|
||||
{
|
||||
}
|
||||
|
||||
Compare_relative_intersection_along_segment_2(const K& kernel)
|
||||
: m_intersect_2(kernel.intersect_2_object())
|
||||
, m_compare_distance_2(kernel.compare_distance_2_object())
|
||||
, m_construct_line_2(kernel.construct_line_2_object())
|
||||
, m_construct_source_2(kernel.construct_source_2_object())
|
||||
, m_construct_target_2(kernel.construct_target_2_object())
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator () (const Segment_2& s1, const Line_2& l1, const Segment_2& s2, const Line_2& l2) const
|
||||
{
|
||||
typedef typename CGAL::cpp11::result_of<Intersect_2(Line_2, Line_2)>::type LineLineIntersectResult;
|
||||
|
||||
Line_2 s1Line(m_construct_line_2(s1));
|
||||
|
||||
Line_2 s2Line(m_construct_line_2(s2));
|
||||
|
||||
LineLineIntersectResult intersectResult1(m_intersect_2(s1Line, l1));
|
||||
|
||||
assert(intersectResult1);
|
||||
|
||||
Point_2 p1;
|
||||
|
||||
FT t1;
|
||||
|
||||
if (intersectResult1)
|
||||
{
|
||||
Point_2* result = boost::get<Point_2, Point_2, Line_2>(&*intersectResult1);
|
||||
|
||||
assert(result && "Intersection should have been a point");
|
||||
|
||||
if (result)
|
||||
{
|
||||
t1 = m_parametric_distance_along_segment_2(s1, *result);
|
||||
p1 = *result;
|
||||
assert(t1 >= FT(-0.00001) && t1 <= FT(1.00001));
|
||||
}
|
||||
}
|
||||
|
||||
LineLineIntersectResult intersectResult2 = m_intersect_2(s2Line, l2);
|
||||
|
||||
assert(intersectResult2);
|
||||
|
||||
FT t2;
|
||||
Point_2 p2;
|
||||
|
||||
if (intersectResult2)
|
||||
{
|
||||
Point_2* result = boost::get<Point_2, Point_2, Line_2>(&*intersectResult2);
|
||||
|
||||
assert(result && "Intersection should have been a point");
|
||||
|
||||
if (result)
|
||||
{
|
||||
t2 = m_parametric_distance_along_segment_2(s2, *result);
|
||||
p2 = *result;
|
||||
assert(t2 >= FT(-0.00001) && t2 <= FT(1.00001));
|
||||
}
|
||||
}
|
||||
|
||||
result_type predicateResult = m_compare_distance_2(s1.source(), p1, s2.source(), p2);
|
||||
|
||||
return predicateResult;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Kernel, class FaceListGraph>
|
||||
class Is_saddle_vertex
|
||||
{
|
||||
public:
|
||||
typedef typename Kernel::Point_3 Point_3;
|
||||
typedef typename Kernel::Vector_3 Vector_3;
|
||||
typedef typename Kernel::Triangle_3 Triangle_3;
|
||||
typedef typename Kernel::Triangle_2 Triangle_2;
|
||||
typedef typename Kernel::Segment_2 Segment_2;
|
||||
typedef typename Kernel::Vector_2 Vector_2;
|
||||
typedef typename Kernel::Point_2 Point_2;
|
||||
|
||||
typedef typename boost::graph_traits<FaceListGraph> Graph_traits;
|
||||
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
typedef typename CGAL::Surface_mesh_shortest_paths_3::Construct_triangle_3_to_triangle_2_projection<Kernel> Construct_triangle_3_to_triangle_2_projection;
|
||||
typedef typename CGAL::Surface_mesh_shortest_paths_3::Construct_triangle_3_along_segment_2_flattening<Kernel> Construct_triangle_3_along_segment_2_flattening;
|
||||
typedef typename Kernel::Orientation_2 Orientation_2;
|
||||
typedef typename Kernel::Construct_triangle_3 Construct_triangle_3;
|
||||
typedef typename Kernel::Construct_vertex_2 Construct_vertex_2;
|
||||
typedef typename Kernel::Construct_segment_2 Construct_segment_2;
|
||||
typedef typename Kernel::Construct_source_2 Construct_source_2;
|
||||
typedef typename Kernel::Construct_target_2 Construct_target_2;
|
||||
|
||||
typedef typename Kernel::Boolean result_type;
|
||||
|
||||
private:
|
||||
Construct_triangle_3_to_triangle_2_projection m_project_triangle_3_to_triangle_2;
|
||||
Construct_triangle_3_along_segment_2_flattening m_flatten_triangle_3_along_segment_2;
|
||||
Construct_triangle_3 m_construct_triangle_3;
|
||||
mutable Construct_vertex_2 m_construct_vertex_2;
|
||||
Construct_segment_2 m_construct_segment_2;
|
||||
Construct_source_2 m_construct_source_2;
|
||||
Construct_target_2 m_construct_target_2;
|
||||
Orientation_2 m_orientation_2;
|
||||
|
||||
public:
|
||||
|
||||
Is_saddle_vertex()
|
||||
{
|
||||
}
|
||||
|
||||
Is_saddle_vertex(const Kernel& kernel, const Construct_triangle_3_to_triangle_2_projection& pt3tt2, const Construct_triangle_3_along_segment_2_flattening& ft3as2)
|
||||
: m_orientation_2(kernel.orientation_2_object())
|
||||
, m_construct_triangle_3(kernel.construct_triangle_3_object())
|
||||
, m_construct_vertex_2(kernel.construct_vertex_2_object())
|
||||
, m_construct_segment_2(kernel.construct_segment_2_object())
|
||||
, m_construct_source_2(kernel.construct_source_2_object())
|
||||
, m_construct_target_2(kernel.construct_target_2_object())
|
||||
, m_project_triangle_3_to_triangle_2(pt3tt2)
|
||||
, m_flatten_triangle_3_along_segment_2(ft3as2)
|
||||
{
|
||||
}
|
||||
|
||||
result_type operator() (vertex_descriptor v, FaceListGraph& g) const
|
||||
{
|
||||
return (*this)(v, g, get(boost::vertex_point, g));
|
||||
}
|
||||
|
||||
template<class VertexPointMap>
|
||||
result_type operator() (vertex_descriptor v, const FaceListGraph& g, VertexPointMap const& pointMap) const
|
||||
{
|
||||
halfedge_descriptor startEdge = halfedge(v, g);
|
||||
|
||||
Point_3 rootPoint(get(pointMap, v));
|
||||
Point_3 prevPoint(get(pointMap, source(startEdge, g)));
|
||||
|
||||
halfedge_descriptor currentEdge = next(startEdge, g);
|
||||
|
||||
Point_3 nextPoint(get(pointMap, target(currentEdge, g)));
|
||||
|
||||
Triangle_3 baseFace3(rootPoint, nextPoint, prevPoint);
|
||||
|
||||
currentEdge = opposite(currentEdge, g);
|
||||
|
||||
Triangle_2 baseFace2(m_project_triangle_3_to_triangle_2(baseFace3));
|
||||
|
||||
Point_2 A(m_construct_vertex_2(baseFace2, 0));
|
||||
Point_2 B(m_construct_vertex_2(baseFace2, 1));
|
||||
Point_2 C(m_construct_vertex_2(baseFace2, 2));
|
||||
|
||||
Segment_2 baseSegment(m_construct_segment_2(A, C));
|
||||
|
||||
Segment_2 nextSegment(m_construct_segment_2(B, A));
|
||||
|
||||
CGAL::Orientation baseOrientation = m_orientation_2(m_construct_vertex_2(baseFace2, 0), m_construct_vertex_2(baseFace2, 2), m_construct_vertex_2(baseFace2, 1));
|
||||
|
||||
assert(baseOrientation != CGAL::COLLINEAR);
|
||||
|
||||
do
|
||||
{
|
||||
prevPoint = nextPoint;
|
||||
currentEdge = next(currentEdge, g);
|
||||
nextPoint = get(pointMap, target(currentEdge, g));
|
||||
currentEdge = opposite(currentEdge, g);
|
||||
|
||||
Triangle_3 currentFace3(m_construct_triangle_3(rootPoint, nextPoint, prevPoint));
|
||||
Triangle_2 currentFace2(m_flatten_triangle_3_along_segment_2(currentFace3, 2, nextSegment));
|
||||
|
||||
if (m_orientation_2(m_construct_source_2(baseSegment), m_construct_target_2(baseSegment), m_construct_vertex_2(currentFace2, 2)) != baseOrientation && m_orientation_2(m_construct_source_2(baseSegment), m_construct_target_2(baseSegment), m_construct_vertex_2(currentFace2, 1)) == baseOrientation)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
nextSegment = m_construct_segment_2(currentFace2[1], currentFace2[0]);
|
||||
}
|
||||
while (currentEdge != startEdge);
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Surface_mesh_shortest_paths_3
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif /* CGAL_SURFACE_MESH_SHORTEST_PATHS_3_FUNCTION_OBJECTS_H */
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_EXPANSION_EVENT_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_EXPANSION_EVENT_H
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<class Traits>
|
||||
class Cone_tree_node;
|
||||
|
||||
template <class Traits>
|
||||
struct Cone_expansion_event
|
||||
{
|
||||
public:
|
||||
typedef typename Traits::Segment_2 Segment_2;
|
||||
typedef typename Traits::FT FT;
|
||||
|
||||
public:
|
||||
enum Expansion_type
|
||||
{
|
||||
LEFT_CHILD,
|
||||
RIGHT_CHILD,
|
||||
PSEUDO_SOURCE
|
||||
};
|
||||
|
||||
public:
|
||||
Cone_tree_node<Traits>* m_parent;
|
||||
FT m_distanceEstimate;
|
||||
Expansion_type m_type;
|
||||
Segment_2 m_windowSegment;
|
||||
bool m_cancelled;
|
||||
|
||||
public:
|
||||
Cone_expansion_event(Cone_tree_node<Traits>* parent, const FT& distanceEstimate, Expansion_type type)
|
||||
: m_parent(parent)
|
||||
, m_distanceEstimate(distanceEstimate)
|
||||
, m_type(type)
|
||||
, m_cancelled(false)
|
||||
{
|
||||
}
|
||||
|
||||
Cone_expansion_event(Cone_tree_node<Traits>* parent, const FT& distanceEstimate, Expansion_type type, const Segment_2& windowSegment)
|
||||
: m_parent(parent)
|
||||
, m_distanceEstimate(distanceEstimate)
|
||||
, m_type(type)
|
||||
, m_windowSegment(windowSegment)
|
||||
, m_cancelled(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Does the opposite of what you would expect in order to implement a min-priority queue
|
||||
template <class Traits>
|
||||
struct Cone_expansion_event_min_priority_queue_comparator
|
||||
{
|
||||
public:
|
||||
bool operator () (const Cone_expansion_event<Traits>* lhs, const Cone_expansion_event<Traits>* rhs) const
|
||||
{
|
||||
return rhs->m_distanceEstimate < lhs->m_distanceEstimate;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_EXPANSION_EVENT_H
|
||||
|
|
@ -0,0 +1,439 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_TREE_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_TREE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/internal/Cone_expansion_event.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/internal/misc_functions.h>
|
||||
|
||||
namespace CGAL
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<class Traits>
|
||||
class Cone_tree_node
|
||||
{
|
||||
public:
|
||||
enum Node_type
|
||||
{
|
||||
ROOT = 0,
|
||||
FACE_SOURCE = 1,
|
||||
EDGE_SOURCE = 2,
|
||||
VERTEX_SOURCE = 3,
|
||||
INTERVAL = 4
|
||||
};
|
||||
|
||||
private:
|
||||
typedef typename Traits::Triangle_mesh Triangle_mesh;
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_2 Point_2;
|
||||
typedef typename Traits::Triangle_2 Triangle_2;
|
||||
typedef typename Traits::Segment_2 Segment_2;
|
||||
typedef typename Traits::Ray_2 Ray_2;
|
||||
typedef typename boost::graph_traits<Triangle_mesh> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename CGAL::internal::Cone_expansion_event<Traits> Cone_expansion_event;
|
||||
|
||||
private:
|
||||
// These could be pulled back into a 'context' class to save space
|
||||
Traits& m_traits;
|
||||
Triangle_mesh& m_graph;
|
||||
|
||||
halfedge_descriptor m_entryEdge;
|
||||
|
||||
Point_2 m_sourceImage;
|
||||
Triangle_2 m_layoutFace;
|
||||
FT m_pseudoSourceDistance;
|
||||
|
||||
Point_2 m_windowLeft;
|
||||
Point_2 m_windowRight;
|
||||
|
||||
size_t m_level;
|
||||
size_t m_treeId;
|
||||
|
||||
Node_type m_nodeType;
|
||||
|
||||
Cone_tree_node* m_leftChild;
|
||||
Cone_tree_node* m_rightChild;
|
||||
|
||||
std::vector<Cone_tree_node*> m_middleChildren;
|
||||
Cone_tree_node* m_parent;
|
||||
|
||||
private:
|
||||
void on_child_link(Cone_tree_node* child)
|
||||
{
|
||||
child->m_parent = this;
|
||||
child->m_level = m_level + 1;
|
||||
child->m_treeId = m_treeId;
|
||||
}
|
||||
|
||||
public:
|
||||
Cone_tree_node(Traits& traits, Triangle_mesh& g, size_t treeId)
|
||||
: m_traits(traits)
|
||||
, m_graph(g)
|
||||
, m_sourceImage(Point_2(CGAL::ORIGIN))
|
||||
, m_layoutFace(Point_2(CGAL::ORIGIN),Point_2(CGAL::ORIGIN),Point_2(CGAL::ORIGIN))
|
||||
, m_pseudoSourceDistance(0.0)
|
||||
, m_level(0)
|
||||
, m_treeId(treeId)
|
||||
, m_nodeType(ROOT)
|
||||
, m_leftChild(NULL)
|
||||
, m_rightChild(NULL)
|
||||
, m_pendingLeftSubtree(NULL)
|
||||
, m_pendingRightSubtree(NULL)
|
||||
, m_pendingMiddleSubtree(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Cone_tree_node(Traits& traits, Triangle_mesh& g, size_t treeId, halfedge_descriptor entryEdge)
|
||||
: m_traits(traits)
|
||||
, m_graph(g)
|
||||
, m_entryEdge(entryEdge)
|
||||
, m_sourceImage(Point_2(CGAL::ORIGIN))
|
||||
, m_layoutFace(Point_2(CGAL::ORIGIN),Point_2(CGAL::ORIGIN),Point_2(CGAL::ORIGIN))
|
||||
, m_pseudoSourceDistance(0.0)
|
||||
, m_level(0)
|
||||
, m_treeId(treeId)
|
||||
, m_nodeType(ROOT)
|
||||
, m_leftChild(NULL)
|
||||
, m_rightChild(NULL)
|
||||
, m_pendingLeftSubtree(NULL)
|
||||
, m_pendingRightSubtree(NULL)
|
||||
, m_pendingMiddleSubtree(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Cone_tree_node(Traits& traits, Triangle_mesh& g, halfedge_descriptor entryEdge, const Triangle_2& layoutFace, const Point_2& sourceImage, const FT& pseudoSourceDistance, const Point_2& windowLeft, const Point_2& windowRight, Node_type nodeType = INTERVAL)
|
||||
: m_traits(traits)
|
||||
, m_graph(g)
|
||||
, m_entryEdge(entryEdge)
|
||||
, m_sourceImage(sourceImage)
|
||||
, m_layoutFace(layoutFace)
|
||||
, m_pseudoSourceDistance(pseudoSourceDistance)
|
||||
, m_windowLeft(windowLeft)
|
||||
, m_windowRight(windowRight)
|
||||
, m_nodeType(nodeType)
|
||||
, m_leftChild(NULL)
|
||||
, m_rightChild(NULL)
|
||||
, m_pendingLeftSubtree(NULL)
|
||||
, m_pendingRightSubtree(NULL)
|
||||
, m_pendingMiddleSubtree(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
size_t tree_id() const
|
||||
{
|
||||
return m_treeId;
|
||||
}
|
||||
|
||||
size_t level() const
|
||||
{
|
||||
return m_level;
|
||||
}
|
||||
|
||||
bool is_source_node() const
|
||||
{
|
||||
return m_nodeType == FACE_SOURCE || m_nodeType == EDGE_SOURCE || m_nodeType == VERTEX_SOURCE;
|
||||
}
|
||||
|
||||
bool is_vertex_node() const
|
||||
{
|
||||
return m_nodeType == VERTEX_SOURCE;
|
||||
}
|
||||
|
||||
bool is_root_node() const
|
||||
{
|
||||
return m_nodeType == ROOT;
|
||||
}
|
||||
|
||||
Triangle_2 layout_face() const
|
||||
{
|
||||
return m_layoutFace;
|
||||
}
|
||||
|
||||
face_descriptor current_face() const
|
||||
{
|
||||
return face(m_entryEdge, m_graph);
|
||||
}
|
||||
|
||||
bool is_null_face() const
|
||||
{
|
||||
return current_face() == Graph_traits::null_face();
|
||||
}
|
||||
|
||||
size_t edge_face_index() const
|
||||
{
|
||||
return CGAL::internal::edge_index(entry_edge(), m_graph);
|
||||
}
|
||||
|
||||
halfedge_descriptor entry_edge() const
|
||||
{
|
||||
return m_entryEdge;
|
||||
}
|
||||
|
||||
halfedge_descriptor left_child_edge() const
|
||||
{
|
||||
return opposite(prev(m_entryEdge, m_graph), m_graph);
|
||||
}
|
||||
|
||||
halfedge_descriptor right_child_edge() const
|
||||
{
|
||||
return opposite(next(m_entryEdge, m_graph), m_graph);
|
||||
}
|
||||
|
||||
vertex_descriptor target_vertex() const
|
||||
{
|
||||
return target(next(m_entryEdge, m_graph), m_graph);
|
||||
}
|
||||
|
||||
Point_2 source_image() const
|
||||
{
|
||||
return m_sourceImage;
|
||||
}
|
||||
|
||||
Node_type node_type() const
|
||||
{
|
||||
return m_nodeType;
|
||||
}
|
||||
|
||||
FT distance_to_root(const Point_2& point) const
|
||||
{
|
||||
typename Traits::Compute_squared_distance_2 csd2(m_traits.compute_squared_distance_2_object());
|
||||
return CGAL::internal::select_sqrt(csd2(point, m_sourceImage)) + m_pseudoSourceDistance;
|
||||
}
|
||||
|
||||
FT distance_from_source_to_root() const
|
||||
{
|
||||
return m_pseudoSourceDistance;
|
||||
}
|
||||
|
||||
FT distance_from_target_to_root() const
|
||||
{
|
||||
return distance_to_root(target_point());
|
||||
}
|
||||
|
||||
Ray_2 left_boundary() const
|
||||
{
|
||||
return Ray_2(source_image(), m_windowLeft);
|
||||
}
|
||||
|
||||
Ray_2 right_boundary() const
|
||||
{
|
||||
return Ray_2(source_image(), m_windowRight);
|
||||
}
|
||||
|
||||
Point_2 window_left() const
|
||||
{
|
||||
return m_windowLeft;
|
||||
}
|
||||
|
||||
Point_2 window_right() const
|
||||
{
|
||||
return m_windowRight;
|
||||
}
|
||||
|
||||
Ray_2 ray_to_target_vertex() const
|
||||
{
|
||||
return Ray_2(source_image(), target_point());
|
||||
}
|
||||
|
||||
bool inside_window(const Point_2& point) const
|
||||
{
|
||||
typename Traits::Orientation_2 orientation_2(m_traits.orientation_2_object());
|
||||
Point_2 sourceImagePoint(source_image());
|
||||
CGAL::Orientation leftOrientation = orientation_2(sourceImagePoint, m_windowLeft, point);
|
||||
CGAL::Orientation rightOrientation = orientation_2(sourceImagePoint, m_windowRight, point);
|
||||
return (leftOrientation == CGAL::RIGHT_TURN || leftOrientation == CGAL::COLLINEAR) && (rightOrientation == CGAL::LEFT_TURN || rightOrientation == CGAL::COLLINEAR);
|
||||
}
|
||||
|
||||
Point_2 target_point() const
|
||||
{
|
||||
typename Traits::Construct_vertex_2 cv2(m_traits.construct_vertex_2_object());
|
||||
return cv2(m_layoutFace, 2);
|
||||
}
|
||||
|
||||
bool is_target_vertex_inside_window() const
|
||||
{
|
||||
return inside_window(target_point());
|
||||
}
|
||||
|
||||
bool has_left_side() const
|
||||
{
|
||||
typename Traits::Orientation_2 orientation_2(m_traits.orientation_2_object());
|
||||
|
||||
if (is_source_node())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CGAL::Orientation orientation = orientation_2(source_image(), m_windowLeft, target_point());
|
||||
|
||||
return (orientation == CGAL::RIGHT_TURN || orientation == CGAL::COLLINEAR);
|
||||
}
|
||||
|
||||
bool has_right_side() const
|
||||
{
|
||||
typename Traits::Orientation_2 orientation_2(m_traits.orientation_2_object());
|
||||
|
||||
CGAL::Orientation orientation = orientation_2(source_image(), m_windowRight, target_point());
|
||||
|
||||
return (orientation == CGAL::LEFT_TURN || orientation == CGAL::COLLINEAR);
|
||||
}
|
||||
|
||||
Segment_2 left_child_base_segment() const
|
||||
{
|
||||
typename Traits::Construct_vertex_2 cv2(m_traits.construct_vertex_2_object());
|
||||
// reversed to maintain consistent triangle winding on the child
|
||||
return Segment_2(cv2(m_layoutFace, 0), cv2(m_layoutFace, 2));
|
||||
}
|
||||
|
||||
Segment_2 right_child_base_segment() const
|
||||
{
|
||||
typename Traits::Construct_vertex_2 cv2(m_traits.construct_vertex_2_object());
|
||||
// reversed to maintain consistent triangle winding on the child
|
||||
return Segment_2(cv2(m_layoutFace, 2), cv2(m_layoutFace, 1));
|
||||
}
|
||||
|
||||
Segment_2 entry_segment() const
|
||||
{
|
||||
typename Traits::Construct_vertex_2 cv2(m_traits.construct_vertex_2_object());
|
||||
return Segment_2(cv2(m_layoutFace, 0), cv2(m_layoutFace, 1));
|
||||
}
|
||||
|
||||
bool has_middle_children() const
|
||||
{
|
||||
return m_middleChildren.size() > 0;
|
||||
}
|
||||
|
||||
size_t num_middle_children() const
|
||||
{
|
||||
return m_middleChildren.size();
|
||||
}
|
||||
|
||||
Cone_tree_node* get_middle_child(size_t i) const
|
||||
{
|
||||
return m_middleChildren.at(i);
|
||||
}
|
||||
|
||||
void push_middle_child(Cone_tree_node* child)
|
||||
{
|
||||
if (m_pendingMiddleSubtree != NULL)
|
||||
{
|
||||
m_pendingMiddleSubtree->m_cancelled = true;
|
||||
m_pendingMiddleSubtree = NULL;
|
||||
}
|
||||
|
||||
m_middleChildren.push_back(child);
|
||||
on_child_link(child);
|
||||
}
|
||||
|
||||
Cone_tree_node* pop_middle_child()
|
||||
{
|
||||
Cone_tree_node* temp = m_middleChildren.back();
|
||||
m_middleChildren.pop_back();
|
||||
return temp;
|
||||
}
|
||||
|
||||
void set_left_child(Cone_tree_node* child)
|
||||
{
|
||||
if (m_pendingLeftSubtree != NULL)
|
||||
{
|
||||
m_pendingLeftSubtree->m_cancelled = true;
|
||||
m_pendingLeftSubtree = NULL;
|
||||
}
|
||||
|
||||
m_leftChild = child;
|
||||
on_child_link(child);
|
||||
}
|
||||
|
||||
Cone_tree_node* get_left_child() const
|
||||
{
|
||||
return m_leftChild;
|
||||
}
|
||||
|
||||
Cone_tree_node* remove_left_child()
|
||||
{
|
||||
Cone_tree_node* temp = m_leftChild;
|
||||
m_leftChild = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
void set_right_child(Cone_tree_node* child)
|
||||
{
|
||||
if (m_pendingRightSubtree != NULL)
|
||||
{
|
||||
m_pendingRightSubtree->m_cancelled = true;
|
||||
m_pendingRightSubtree = NULL;
|
||||
}
|
||||
|
||||
m_rightChild = child;
|
||||
on_child_link(child);
|
||||
}
|
||||
|
||||
Cone_tree_node* get_right_child() const
|
||||
{
|
||||
return m_rightChild;
|
||||
}
|
||||
|
||||
Cone_tree_node* remove_right_child()
|
||||
{
|
||||
Cone_tree_node* temp = m_rightChild;
|
||||
m_rightChild = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
Cone_tree_node* parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
bool is_left_child() const
|
||||
{
|
||||
return m_parent != NULL && m_parent->m_leftChild == this;
|
||||
}
|
||||
|
||||
bool is_right_child() const
|
||||
{
|
||||
return m_parent != NULL && m_parent->m_rightChild == this;
|
||||
}
|
||||
|
||||
public:
|
||||
Cone_expansion_event* m_pendingLeftSubtree;
|
||||
Cone_expansion_event* m_pendingRightSubtree;
|
||||
Cone_expansion_event* m_pendingMiddleSubtree;
|
||||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_CONE_TREE_H
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2014 GeometryFactory
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
//
|
||||
// Author(s) : Stephen Kiazyk
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_MISC_H
|
||||
#define CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_MISC_H
|
||||
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class Triangle_3, class Triangle_mesh, class VertexPointMap>
|
||||
Triangle_3 triangle_from_halfedge(typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor edge, const Triangle_mesh& g, VertexPointMap vertexPointMap)
|
||||
{
|
||||
typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
halfedge_descriptor e0 = edge;
|
||||
halfedge_descriptor e1 = next(edge, g);
|
||||
|
||||
return Triangle_3(get(vertexPointMap, boost::source(e0, g)), get(vertexPointMap, boost::target(e0, g)), get(vertexPointMap, boost::target(e1, g)));
|
||||
}
|
||||
|
||||
template <class Triangle_3, class Triangle_mesh>
|
||||
Triangle_3 triangle_from_halfedge(typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor edge, const Triangle_mesh& g)
|
||||
{
|
||||
return triangle_from_halfedge<Triangle_3, Triangle_mesh, typename boost::property_map<Triangle_mesh, boost::vertex_point_t>::type>(edge, g, get(boost::vertex_point, g));
|
||||
}
|
||||
|
||||
|
||||
template <class Triangle_mesh>
|
||||
size_t edge_index(typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor he, Triangle_mesh& p)
|
||||
{
|
||||
typedef typename boost::graph_traits<Triangle_mesh> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
face_descriptor f = face(he, p);
|
||||
|
||||
halfedge_descriptor start = halfedge(f, p);
|
||||
halfedge_descriptor current = start;
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while (current != he)
|
||||
{
|
||||
current = next(current, p);
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <class FT>
|
||||
FT internal_sqrt(const FT& x, CGAL::Tag_true)
|
||||
{
|
||||
return CGAL::sqrt(x);
|
||||
}
|
||||
|
||||
template <class FT>
|
||||
FT internal_sqrt(const FT& x, CGAL::Tag_false)
|
||||
{
|
||||
return FT(std::sqrt(CGAL::to_double(x)));
|
||||
}
|
||||
|
||||
template <class FT>
|
||||
FT select_sqrt(const FT& x)
|
||||
{
|
||||
typedef ::CGAL::Algebraic_structure_traits<FT> AST;
|
||||
static const bool has_sqrt = ! ::boost::is_same< ::CGAL::Null_functor, typename AST::Sqrt >::value;
|
||||
return internal_sqrt(x, ::CGAL::Boolean_tag<has_sqrt>());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_SHORTEST_PATH_INTERNAL_MISC_H
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# Created by the script cgal_create_cmake_script
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
|
||||
project( Surface_mesh_shortest_path_ )
|
||||
|
||||
cmake_minimum_required(VERSION 2.6.2)
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
|
||||
cmake_policy(VERSION 2.8.4)
|
||||
else()
|
||||
cmake_policy(VERSION 2.6)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(CGAL QUIET COMPONENTS Core )
|
||||
|
||||
if ( CGAL_FOUND )
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
|
||||
include_directories (BEFORE "../../include")
|
||||
|
||||
include_directories (BEFORE "include")
|
||||
|
||||
create_single_source_cgal_program( "Surface_mesh_shortest_path_test_1.cpp" )
|
||||
create_single_source_cgal_program( "Surface_mesh_shortest_path_test_2.cpp" )
|
||||
create_single_source_cgal_program( "Surface_mesh_shortest_path_test_3.cpp" )
|
||||
create_single_source_cgal_program( "Surface_mesh_shortest_path_test_4.cpp" )
|
||||
create_single_source_cgal_program( "Surface_mesh_shortest_path_traits_test.cpp" )
|
||||
|
||||
|
||||
# Link with Boost.ProgramOptions (optional)
|
||||
find_package(Boost QUIET COMPONENTS program_options)
|
||||
if(Boost_PROGRAM_OPTIONS_FOUND)
|
||||
if( CGAL_AUTO_LINK_ENABLED )
|
||||
message( STATUS "Boost.ProgramOptions library: found" )
|
||||
else()
|
||||
message( STATUS "Boost.ProgramOptions library: ${Boost_PROGRAM_OPTIONS_LIBRARY}" )
|
||||
endif()
|
||||
add_definitions( "-DCGAL_USE_BOOST_PROGRAM_OPTIONS" )
|
||||
list(APPEND CGAL_3RD_PARTY_LIBRARIES ${Boost_PROGRAM_OPTIONS_LIBRARY})
|
||||
create_single_source_cgal_program( "TestMesh.cpp" )
|
||||
else()
|
||||
message(STATUS "NOTICE: Example TestMesh.cpp requires boost program_option and will not be compiled.")
|
||||
endif()
|
||||
|
||||
|
||||
else()
|
||||
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
|
||||
endif()
|
||||
|
||||
|
|
@ -0,0 +1,468 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Polyhedron_items_with_id_3.h>
|
||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||
|
||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||
#include <CGAL/boost/graph/iterator.h>
|
||||
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path_traits.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/Surface_mesh_shortest_path.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/function_objects.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/barycentric.h>
|
||||
#include <CGAL/Surface_mesh_shortest_path/internal/misc_functions.h>
|
||||
|
||||
#include <CGAL/use.h>
|
||||
|
||||
#include <CGAL/test_util.h>
|
||||
#include "check.h"
|
||||
|
||||
void shortest_path_regular_tetrahedron()
|
||||
{
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef Traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef Traits::FT FT;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
|
||||
Traits traits;
|
||||
|
||||
Traits::Construct_barycentric_coordinate construct_barycentric_coordinate(traits.construct_barycentric_coordinate_object());
|
||||
|
||||
Polyhedron_3 P;
|
||||
|
||||
CGAL::test::make_regular_tetrahedron(P);
|
||||
|
||||
CGAL::set_halfedgeds_items_id(P);
|
||||
|
||||
Barycentric_coordinate b = construct_barycentric_coordinate(FT(1.0) / FT(3.0), FT(1.0) / FT(3.0), FT(1.0) / FT(3.0));
|
||||
|
||||
face_iterator startFace;
|
||||
face_iterator endFace;
|
||||
|
||||
boost::tie(startFace,endFace) = CGAL::faces(P);
|
||||
|
||||
face_descriptor firstFace = *startFace;
|
||||
|
||||
Surface_mesh_shortest_path shortestPaths(P, traits);
|
||||
//shortestPaths.m_debugOutput = true;
|
||||
shortestPaths.add_source_point(firstFace, b);
|
||||
shortestPaths.build_sequence_tree();
|
||||
|
||||
vertex_iterator currentVertex;
|
||||
vertex_iterator endVertex;
|
||||
|
||||
Kernel::FT sideLength = Kernel::FT(2.0);
|
||||
Kernel::FT halfSideLength = sideLength / Kernel::FT(2.0);
|
||||
Kernel::FT triangleHeight = CGAL::sqrt((sideLength*sideLength) - (halfSideLength*halfSideLength));
|
||||
|
||||
for (boost::tie(currentVertex, endVertex) = CGAL::vertices(P); currentVertex != endVertex; ++currentVertex)
|
||||
{
|
||||
if ((*currentVertex)->point().y()==-1)
|
||||
{
|
||||
CHECK_CLOSE(shortestPaths.shortest_distance_to_source_points(*currentVertex).first, Kernel::FT((triangleHeight * Kernel::FT(4.0)) / Kernel::FT(3.0)), Kernel::FT(0.000001));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_CLOSE(shortestPaths.shortest_distance_to_source_points(*currentVertex).first, Kernel::FT((triangleHeight * Kernel::FT(2.0)) / Kernel::FT(3.0)), Kernel::FT(0.000001));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_simple_saddle_vertex_mesh()
|
||||
{
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef Traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef Traits::FT FT;
|
||||
typedef Traits::Point_3 Point_3;
|
||||
typedef Traits::Point_2 Point_2;
|
||||
typedef Traits::Triangle_3 Triangle_3;
|
||||
typedef Traits::Triangle_2 Triangle_2;
|
||||
typedef Traits::Segment_2 Segment_2;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef boost::property_map<Polyhedron_3, CGAL::vertex_point_t>::type VPM;
|
||||
|
||||
Traits traits;
|
||||
|
||||
Traits::Compute_squared_distance_3 compute_squared_distance_3(traits.compute_squared_distance_3_object());
|
||||
Traits::Compute_squared_distance_2 compute_squared_distance_2(traits.compute_squared_distance_2_object());
|
||||
Traits::Construct_triangle_3_along_segment_2_flattening flatten_triangle_3_along_segment_2(traits.construct_triangle_3_along_segment_2_flattening_object());
|
||||
Traits::Construct_barycentric_coordinate construct_barycentric_coordinate(traits.construct_barycentric_coordinate_object());
|
||||
|
||||
std::ifstream inFile("data/saddle_vertex_mesh.off");
|
||||
|
||||
Polyhedron_3 P;
|
||||
|
||||
inFile >> P;
|
||||
|
||||
inFile.close();
|
||||
|
||||
CGAL::set_halfedgeds_items_id(P);
|
||||
|
||||
vertex_iterator startVertex;
|
||||
vertex_iterator endVertex;
|
||||
boost::tie(startVertex, endVertex) = CGAL::vertices(P);
|
||||
|
||||
vertex_iterator currentVertex = startVertex;
|
||||
|
||||
++currentVertex;
|
||||
vertex_descriptor rootSearchVertex = *currentVertex;
|
||||
|
||||
face_descriptor currentFace = CGAL::face(CGAL::halfedge(rootSearchVertex, P), P);
|
||||
size_t vertexIndex = CGAL::test::face_vertex_index(currentFace, rootSearchVertex, P);
|
||||
Barycentric_coordinate baryCoord = construct_barycentric_coordinate(vertexIndex == 0 ? FT(1.0) : FT(0.0), vertexIndex == 1 ? FT(1.0) : FT(0.0), vertexIndex == 2 ? FT(1.0) : FT(0.0));
|
||||
|
||||
Surface_mesh_shortest_path shortestPaths(P, traits);
|
||||
//shortestPaths.m_debugOutput = true;
|
||||
Surface_mesh_shortest_path::Source_point_iterator firstSourcePoint = shortestPaths.add_source_point(currentFace, baryCoord);
|
||||
shortestPaths.build_sequence_tree();
|
||||
|
||||
VPM vpm = CGAL::get(CGAL::vertex_point, P);
|
||||
|
||||
Point_3 vertexLocations[8];
|
||||
vertex_descriptor vertexHandles[8];
|
||||
|
||||
currentVertex = startVertex;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
vertexHandles[i] = *currentVertex;
|
||||
vertexLocations[i] = vpm[*currentVertex];
|
||||
++currentVertex;
|
||||
}
|
||||
|
||||
FT distanceToBottom = CGAL::sqrt(compute_squared_distance_3(vertexLocations[1], vertexLocations[0]));
|
||||
FT largerSideLength = CGAL::sqrt(compute_squared_distance_3(vertexLocations[1], vertexLocations[2]));
|
||||
FT distanceToSaddle = CGAL::sqrt(compute_squared_distance_3(vertexLocations[1], vertexLocations[4]));
|
||||
FT shorterSideLength = CGAL::sqrt(compute_squared_distance_3(vertexLocations[4], vertexLocations[6]));
|
||||
|
||||
Triangle_3 lower(vertexLocations[6], vertexLocations[4], vertexLocations[1]);
|
||||
Triangle_3 upper(vertexLocations[4], vertexLocations[6], vertexLocations[7]);
|
||||
|
||||
Segment_2 base(Point_2(CGAL::ORIGIN), Point_2(shorterSideLength, FT(0.0)));
|
||||
|
||||
Triangle_2 flatLower(flatten_triangle_3_along_segment_2(lower, 0, base));
|
||||
Triangle_2 flatUpper(flatten_triangle_3_along_segment_2(upper, 0, Segment_2(base[1], base[0])));
|
||||
|
||||
FT distanceToApex = CGAL::sqrt(compute_squared_distance_2(flatLower[2], flatUpper[2]));
|
||||
|
||||
FT expectedDistances[8] =
|
||||
{
|
||||
distanceToBottom, // a vertex of the larger tetrahedron
|
||||
FT(0.0), // the initial vertex
|
||||
largerSideLength, // a vertex of the larger tetrahedron
|
||||
largerSideLength, // a vertex of the larger tetrahedron
|
||||
distanceToSaddle, // direct line of sight from root
|
||||
distanceToSaddle + shorterSideLength, // around the corner from a pseudo-source (not in direct line of geodesic sight)
|
||||
distanceToSaddle, // direct line of sight from root
|
||||
distanceToApex,
|
||||
};
|
||||
|
||||
currentVertex = startVertex;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
CHECK_CLOSE(shortestPaths.shortest_distance_to_source_points(*currentVertex).first, expectedDistances[i], Kernel::FT(0.0001));
|
||||
++currentVertex;
|
||||
}
|
||||
|
||||
// test the edge sequence reporting
|
||||
CGAL::test::Edge_sequence_collector<Traits> collector(P);
|
||||
|
||||
shortestPaths.shortest_path_sequence_to_source_points(vertexHandles[5], collector);
|
||||
|
||||
CHECK_EQUAL(collector.m_sequence.size(), 3u);
|
||||
CHECK_EQUAL(collector.m_sequence[1].type, CGAL::test::SEQUENCE_ITEM_VERTEX);
|
||||
assert(collector.m_sequence[1].index == 4 || collector.m_sequence[1].index == 6);
|
||||
CHECK_EQUAL(collector.m_sequence[2].type, CGAL::test::SEQUENCE_ITEM_VERTEX);
|
||||
CHECK_EQUAL(collector.m_sequence[2].index, 1u);
|
||||
|
||||
collector.m_sequence.clear();
|
||||
|
||||
typedef boost::property_map<Polyhedron_3, CGAL::halfedge_external_index_t>::type HalfedgeIndexMap;
|
||||
|
||||
HalfedgeIndexMap halfedgeIndexMap(CGAL::get(CGAL::halfedge_external_index, P));
|
||||
|
||||
shortestPaths.shortest_path_sequence_to_source_points(vertexHandles[7], collector);
|
||||
|
||||
CHECK_EQUAL(collector.m_sequence.size(), 3u);
|
||||
CHECK_EQUAL(collector.m_sequence[1].type, CGAL::test::SEQUENCE_ITEM_EDGE);
|
||||
CHECK_EQUAL(collector.m_sequence[1].index, halfedgeIndexMap[CGAL::halfedge(vertexHandles[4], vertexHandles[6], P).first]);
|
||||
CHECK_CLOSE(collector.m_sequence[1].edgeAlpha, FT(0.5), FT(0.0001));
|
||||
CHECK_EQUAL(collector.m_sequence[2].type, CGAL::test::SEQUENCE_ITEM_VERTEX);
|
||||
CHECK_EQUAL(collector.m_sequence[2].index, 1u);
|
||||
|
||||
// Now test an internal face location sequence
|
||||
halfedge_descriptor firstCrossing = CGAL::halfedge(vertexHandles[4], vertexHandles[7], P).first;
|
||||
|
||||
size_t edgeIndex = CGAL::internal::edge_index(firstCrossing, P);
|
||||
|
||||
Barycentric_coordinate location = construct_barycentric_coordinate(0.25, 0.5, 0.25);
|
||||
|
||||
collector.m_sequence.clear();
|
||||
shortestPaths.shortest_path_sequence_to_source_points(CGAL::face(firstCrossing, P), construct_barycentric_coordinate(location[edgeIndex], location[(edgeIndex + 1) % 3], location[(edgeIndex + 2) % 3]), collector);
|
||||
|
||||
CHECK_EQUAL(collector.m_sequence.size(), 4u);
|
||||
CHECK_EQUAL(collector.m_sequence[1].type, CGAL::test::SEQUENCE_ITEM_EDGE);
|
||||
CHECK_EQUAL(collector.m_sequence[1].index, halfedgeIndexMap[firstCrossing]);
|
||||
CHECK_EQUAL(collector.m_sequence[2].type, CGAL::test::SEQUENCE_ITEM_EDGE);
|
||||
CHECK_EQUAL(collector.m_sequence[2].index, halfedgeIndexMap[CGAL::halfedge(vertexHandles[4], vertexHandles[6], P).first]);
|
||||
CHECK_EQUAL(collector.m_sequence[3].type, CGAL::test::SEQUENCE_ITEM_VERTEX);
|
||||
CHECK_EQUAL(collector.m_sequence[3].index, 1u);
|
||||
|
||||
// Now test with 2 source vertices
|
||||
currentVertex = startVertex;
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
++currentVertex;
|
||||
}
|
||||
|
||||
vertex_descriptor rootSearchVertex2 = *currentVertex;
|
||||
|
||||
face_descriptor currentFace2 = CGAL::face(CGAL::halfedge(rootSearchVertex2, P), P);
|
||||
size_t vertexIndex2 = CGAL::test::face_vertex_index(currentFace2, rootSearchVertex2, P);
|
||||
Barycentric_coordinate baryCoord2 = construct_barycentric_coordinate(vertexIndex2 == 0 ? FT(1.0) : FT(0.0), vertexIndex2 == 1 ? FT(1.0) : FT(0.0), vertexIndex2 == 2 ? FT(1.0) : FT(0.0));
|
||||
|
||||
Surface_mesh_shortest_path::Source_point_iterator secondSourcePoint = shortestPaths.add_source_point(currentFace2, baryCoord2);
|
||||
shortestPaths.build_sequence_tree();
|
||||
|
||||
FT distanceToApexFrom2 = CGAL::sqrt(compute_squared_distance_3(vertexLocations[5], vertexLocations[7]));
|
||||
|
||||
Triangle_3 lower2(vertexLocations[2], vertexLocations[3], vertexLocations[5]);
|
||||
Triangle_3 upper2(vertexLocations[3], vertexLocations[2], vertexLocations[0]);
|
||||
|
||||
Segment_2 base2(Point_2(CGAL::ORIGIN), Point_2(largerSideLength, FT(0.0)));
|
||||
|
||||
Triangle_2 flatLower2(flatten_triangle_3_along_segment_2(lower2, 0, base2));
|
||||
Triangle_2 flatUpper2(flatten_triangle_3_along_segment_2(upper2, 0, Segment_2(base2[1], base2[0])));
|
||||
|
||||
FT distanceToBottom2 = CGAL::sqrt(compute_squared_distance_2(flatLower2[2], flatUpper2[2]));
|
||||
|
||||
FT expectedDistances2[8] =
|
||||
{
|
||||
distanceToBottom2, // a vertex of the larger tetrahedron
|
||||
FT(0.0), // an initial vertex
|
||||
distanceToSaddle, // a vertex of the larger tetrahedron
|
||||
distanceToSaddle, // a vertex of the larger tetrahedron
|
||||
shorterSideLength, // direct line of sight from root
|
||||
FT(0.0), // around the corner from a pseudo-source (not in direct line of geodesic sight)
|
||||
shorterSideLength, // direct line of sight from root
|
||||
distanceToApexFrom2,
|
||||
};
|
||||
|
||||
Surface_mesh_shortest_path::Source_point_iterator expectedSources2[8] =
|
||||
{
|
||||
secondSourcePoint,
|
||||
firstSourcePoint,
|
||||
secondSourcePoint,
|
||||
secondSourcePoint,
|
||||
secondSourcePoint,
|
||||
secondSourcePoint,
|
||||
secondSourcePoint,
|
||||
secondSourcePoint,
|
||||
};
|
||||
|
||||
currentVertex = startVertex;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
Surface_mesh_shortest_path::Shortest_path_result result = shortestPaths.shortest_distance_to_source_points(*currentVertex);
|
||||
|
||||
CHECK_CLOSE(result.first, expectedDistances2[i], Kernel::FT(0.0001));
|
||||
assert(result.second == expectedSources2[i]);
|
||||
++currentVertex;
|
||||
}
|
||||
|
||||
// Test removing a source vertex
|
||||
|
||||
shortestPaths.remove_source_point(firstSourcePoint);
|
||||
shortestPaths.build_sequence_tree();
|
||||
|
||||
// replace the only shortest path which was not reporting to the 2nd source point
|
||||
expectedDistances2[1] = distanceToSaddle + shorterSideLength;
|
||||
|
||||
currentVertex = startVertex;
|
||||
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
{
|
||||
Surface_mesh_shortest_path::Shortest_path_result result = shortestPaths.shortest_distance_to_source_points(*currentVertex);
|
||||
|
||||
CHECK_CLOSE(result.first, expectedDistances2[i], Kernel::FT(0.0001));
|
||||
assert(result.second == secondSourcePoint);
|
||||
++currentVertex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void test_boundary_mesh()
|
||||
{
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel, CGAL::Polyhedron_items_with_id_3> Polyhedron_3;
|
||||
typedef CGAL::Surface_mesh_shortest_path_traits<Kernel, Polyhedron_3> Traits;
|
||||
typedef Traits::Barycentric_coordinate Barycentric_coordinate;
|
||||
typedef Traits::FT FT;
|
||||
typedef Traits::Point_3 Point_3;
|
||||
typedef Traits::Triangle_3 Triangle_3;
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef Graph_traits::vertex_iterator vertex_iterator;
|
||||
typedef Graph_traits::face_descriptor face_descriptor;
|
||||
typedef Graph_traits::face_iterator face_iterator;
|
||||
typedef CGAL::Surface_mesh_shortest_path<Traits> Surface_mesh_shortest_path;
|
||||
typedef boost::property_map<Polyhedron_3, CGAL::vertex_point_t>::type VPM;
|
||||
|
||||
Traits traits;
|
||||
|
||||
Traits::Construct_triangle_3_to_triangle_2_projection project_triangle_3_to_triangle_2(traits.construct_triangle_3_to_triangle_2_projection_object());
|
||||
CGAL_USE(project_triangle_3_to_triangle_2);
|
||||
Traits::Compute_squared_distance_3 compute_squared_distance_3(traits.compute_squared_distance_3_object());
|
||||
Traits::Construct_barycenter_3 construct_barycenter_3(traits.construct_barycenter_3_object());
|
||||
Traits::Construct_triangle_3_along_segment_2_flattening flatten_triangle_3_along_segment_2(traits.construct_triangle_3_along_segment_2_flattening_object());
|
||||
CGAL_USE(flatten_triangle_3_along_segment_2);
|
||||
Traits::Construct_barycentric_coordinate construct_barycentric_coordinate(traits.construct_barycentric_coordinate_object());
|
||||
|
||||
struct Construct_barycenter_in_triangle_3
|
||||
{
|
||||
Traits::Construct_barycenter_3 m_cb3;
|
||||
|
||||
Construct_barycenter_in_triangle_3(Traits::Construct_barycenter_3 cb3)
|
||||
: m_cb3(cb3)
|
||||
{
|
||||
}
|
||||
|
||||
Point_3 operator() (const Triangle_3& t, const Barycentric_coordinate& b)
|
||||
{
|
||||
return m_cb3(t[0], b[0], t[1], b[1], t[2], b[2]);
|
||||
}
|
||||
} construct_barycenter_in_triangle_3(construct_barycenter_3);
|
||||
|
||||
std::ifstream inFile("data/boundary_mesh.off");
|
||||
|
||||
Polyhedron_3 P;
|
||||
|
||||
inFile >> P;
|
||||
|
||||
inFile.close();
|
||||
|
||||
CGAL::set_halfedgeds_items_id(P);
|
||||
|
||||
face_iterator startFace;
|
||||
face_iterator endFace;
|
||||
|
||||
boost::tie(startFace, endFace) = CGAL::faces(P);
|
||||
|
||||
vertex_iterator currentVertex;
|
||||
vertex_iterator endVertex;
|
||||
|
||||
VPM vpm = CGAL::get(CGAL::vertex_point, P);
|
||||
|
||||
vertex_descriptor vertexHandles[10];
|
||||
face_descriptor faceHandles[8];
|
||||
Point_3 vertexLocations[10];
|
||||
size_t currentVertexIndex = 0;
|
||||
|
||||
for (boost::tie(currentVertex, endVertex) = CGAL::vertices(P); currentVertex != endVertex; ++currentVertex)
|
||||
{
|
||||
vertexHandles[currentVertexIndex] = *currentVertex;
|
||||
vertexLocations[currentVertexIndex] = vpm[*currentVertex];
|
||||
++currentVertexIndex;
|
||||
}
|
||||
|
||||
size_t currentFaceIndex = 0;
|
||||
|
||||
for (face_iterator currentFace = startFace; currentFace != endFace; ++currentFace)
|
||||
{
|
||||
faceHandles[currentFaceIndex] = *currentFace;
|
||||
++currentFaceIndex;
|
||||
}
|
||||
|
||||
Barycentric_coordinate startLocation = construct_barycentric_coordinate(FT(0.1), FT(0.8), FT(0.1));
|
||||
|
||||
typedef boost::property_map<Polyhedron_3, CGAL::face_external_index_t>::type FaceIndexMap;
|
||||
|
||||
FaceIndexMap faceIndexMap(CGAL::get(CGAL::face_external_index, P));
|
||||
|
||||
Surface_mesh_shortest_path shortestPaths(P, traits);
|
||||
//shortestPaths.m_debugOutput = true;
|
||||
shortestPaths.add_source_point(*startFace, startLocation);
|
||||
shortestPaths.build_sequence_tree();
|
||||
|
||||
Triangle_3 firstTriangle(vertexLocations[1], vertexLocations[0], vertexLocations[2]);
|
||||
|
||||
Point_3 locationInTriangle(construct_barycenter_in_triangle_3(firstTriangle, startLocation));
|
||||
|
||||
FT dist0 = shortestPaths.shortest_distance_to_source_points(vertexHandles[0]).first;
|
||||
CHECK_CLOSE(dist0, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[0])), FT(0.000001));
|
||||
|
||||
FT dist1 = shortestPaths.shortest_distance_to_source_points(vertexHandles[1]).first;
|
||||
CHECK_CLOSE(dist1, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[1])), FT(0.000001));
|
||||
|
||||
FT dist2 = shortestPaths.shortest_distance_to_source_points(vertexHandles[2]).first;
|
||||
CHECK_CLOSE(dist2, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[2])), FT(0.000001));
|
||||
|
||||
FT dist3 = shortestPaths.shortest_distance_to_source_points(vertexHandles[3]).first;
|
||||
CHECK_CLOSE(dist3, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[3])), FT(0.000001));
|
||||
|
||||
FT dist4 = shortestPaths.shortest_distance_to_source_points(vertexHandles[4]).first;
|
||||
CHECK_CLOSE(dist4, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[1])) + CGAL::sqrt(compute_squared_distance_3(vertexLocations[1], vertexLocations[4])), FT(0.000001));
|
||||
|
||||
FT dist5 = shortestPaths.shortest_distance_to_source_points(vertexHandles[5]).first;
|
||||
CHECK_CLOSE(dist5, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, vertexLocations[3])) + CGAL::sqrt(compute_squared_distance_3(vertexLocations[3], vertexLocations[5])), FT(0.000001));
|
||||
|
||||
Barycentric_coordinate somewhereElseInFirstTriangle = construct_barycentric_coordinate(0.8, 0.05, 0.15);
|
||||
|
||||
FT distT0 = shortestPaths.shortest_distance_to_source_points(faceHandles[0], somewhereElseInFirstTriangle).first;
|
||||
CHECK_CLOSE(distT0, CGAL::sqrt(compute_squared_distance_3(locationInTriangle, construct_barycenter_in_triangle_3(firstTriangle, somewhereElseInFirstTriangle))), FT(0.000001));
|
||||
|
||||
Triangle_3 oneStepTriangle(vertexLocations[4], vertexLocations[1], vertexLocations[3]);
|
||||
Barycentric_coordinate locationInOneStepTriangle = construct_barycentric_coordinate(0.1, 0.8, 0.1);
|
||||
|
||||
CGAL::test::Edge_sequence_collector<Traits> collector(P);
|
||||
shortestPaths.shortest_path_sequence_to_source_points(faceHandles[2], locationInOneStepTriangle, collector);
|
||||
|
||||
FT distT2 = shortestPaths.shortest_distance_to_source_points(faceHandles[2], locationInOneStepTriangle).first;
|
||||
CHECK_CLOSE(distT2, dist1 + CGAL::sqrt(compute_squared_distance_3(vertexLocations[1], construct_barycenter_in_triangle_3(oneStepTriangle, locationInOneStepTriangle))), FT(0.00001));
|
||||
|
||||
Triangle_3 twoStepTriangle(vertexLocations[6], vertexLocations[5], vertexLocations[7]);
|
||||
Barycentric_coordinate locationInTwoStepTriangle = construct_barycentric_coordinate(0.8, 0.1, 0.1);
|
||||
|
||||
FT distT5 = shortestPaths.shortest_distance_to_source_points(faceHandles[5], locationInTwoStepTriangle).first;
|
||||
CHECK_CLOSE(distT5, dist3 + CGAL::sqrt(compute_squared_distance_3(vertexLocations[3], construct_barycenter_in_triangle_3(twoStepTriangle, locationInTwoStepTriangle))), FT(0.00001));
|
||||
|
||||
Triangle_3 threeStepTriangle(vertexLocations[7], vertexLocations[5], vertexLocations[8]);
|
||||
Barycentric_coordinate locationInThreeStepTriangle = construct_barycentric_coordinate(0.2, 0.6, 0.2);
|
||||
|
||||
FT distT6 = shortestPaths.shortest_distance_to_source_points(faceHandles[6], locationInThreeStepTriangle).first;
|
||||
CHECK_CLOSE(distT6, dist5 + CGAL::sqrt(compute_squared_distance_3(vertexLocations[5], construct_barycenter_in_triangle_3(threeStepTriangle, locationInThreeStepTriangle))), FT(0.00001));
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
shortest_path_regular_tetrahedron();
|
||||
test_simple_saddle_vertex_mesh();
|
||||
test_boundary_mesh();
|
||||
|
||||
return 0;
|
||||
}
|
||||