From 0e256389927b02a2d2daa801d212a42a0ab7bf35 Mon Sep 17 00:00:00 2001 From: Pierre Alliez Date: Mon, 13 Jul 2009 18:58:28 +0000 Subject: [PATCH] AABB tree: final polishing. --- AABB_tree/demo/AABB_tree/AABB_demo.pdf | Bin 719525 -> 719944 bytes AABB_tree/demo/AABB_tree/AABB_demo.ppt | Bin 2126336 -> 2136064 bytes AABB_tree/demo/AABB_tree/MainWindow.cpp | 12 +- AABB_tree/demo/AABB_tree/MainWindow.h | 1 + AABB_tree/demo/AABB_tree/MainWindow.ui | 6 + AABB_tree/demo/AABB_tree/Scene.cpp | 951 ++++++++++--------- AABB_tree/demo/AABB_tree/Scene.h | 195 ++-- AABB_tree/doc_tex/AABB_tree/performances.tex | 6 +- 8 files changed, 601 insertions(+), 570 deletions(-) diff --git a/AABB_tree/demo/AABB_tree/AABB_demo.pdf b/AABB_tree/demo/AABB_tree/AABB_demo.pdf index 1c85d073f7da09e90d5496ba528d1a676dedbcba..4336f97f0cbbdff13bc82a70cda3048898273dda 100644 GIT binary patch delta 23506 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 O58x73 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 delta 199 zcmZqJ(8SpAq>-_qg|UUHg}H^Lg|&sPg}sHNg|mgLg}a5Pg|~%o3qNZwqrr5xUVb%} z4~hF3rW^F~EATor2t0nxbc&Igfq~)j_Sjy2f!C}bg@8iaiz)=zn3%GhwpUdNv`K*& zOj8BUF*3P1wO^Vh0K|eoECj^DKr8~pqChML#Nt3K0mPC(ECs~UKr92qvOp}i{n9jf dt^~$^8!sv|Zu=phRk8idGzAmJ=?T>WNdO#EPS*ec diff --git a/AABB_tree/demo/AABB_tree/MainWindow.cpp b/AABB_tree/demo/AABB_tree/MainWindow.cpp index 028ad3a403c..4b80e3bee41 100644 --- a/AABB_tree/demo/AABB_tree/MainWindow.cpp +++ b/AABB_tree/demo/AABB_tree/MainWindow.cpp @@ -373,6 +373,14 @@ void MainWindow::on_actionBench_distances_vs_nbt_triggered() QApplication::restoreOverrideCursor(); } +void MainWindow::on_actionRefine_loop_triggered() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + m_pScene->refine_loop(); + QApplication::restoreOverrideCursor(); + m_pViewer->update(); +} + void MainWindow::on_actionSave_snapshot_triggered() { QApplication::setOverrideCursor(Qt::WaitCursor); @@ -384,8 +392,8 @@ void MainWindow::on_actionCopy_snapshot_triggered() // copy snapshot to clipboard QApplication::setOverrideCursor(Qt::WaitCursor); QClipboard *qb = QApplication::clipboard(); - m_pViewer->makeCurrent(); - m_pViewer->raise(); + m_pViewer->makeCurrent(); + m_pViewer->raise(); QImage snapshot = m_pViewer->grabFrameBuffer(true); qb->setImage(snapshot); QApplication::restoreOverrideCursor(); diff --git a/AABB_tree/demo/AABB_tree/MainWindow.h b/AABB_tree/demo/AABB_tree/MainWindow.h index 81289578ea3..5b262fc1a70 100644 --- a/AABB_tree/demo/AABB_tree/MainWindow.h +++ b/AABB_tree/demo/AABB_tree/MainWindow.h @@ -49,6 +49,7 @@ public: void on_actionClear_distance_function_triggered(); // algorithm menu + void on_actionRefine_loop_triggered(); void on_actionEdge_points_triggered(); void on_actionInside_points_triggered(); void on_actionBoundary_points_triggered(); diff --git a/AABB_tree/demo/AABB_tree/MainWindow.ui b/AABB_tree/demo/AABB_tree/MainWindow.ui index 24dd97313ff..834bb49b7ce 100644 --- a/AABB_tree/demo/AABB_tree/MainWindow.ui +++ b/AABB_tree/demo/AABB_tree/MainWindow.ui @@ -65,6 +65,7 @@ Refine + @@ -253,6 +254,11 @@ Copy snapshot + + + Loop subdivision + + diff --git a/AABB_tree/demo/AABB_tree/Scene.cpp b/AABB_tree/demo/AABB_tree/Scene.cpp index aebb4aa70c8..a0ca77535be 100644 --- a/AABB_tree/demo/AABB_tree/Scene.cpp +++ b/AABB_tree/demo/AABB_tree/Scene.cpp @@ -10,264 +10,270 @@ #include "Refiner.h" #include "render_edges.h" -#include + #include +#include +#include Scene::Scene() { - m_pPolyhedron = NULL; + m_pPolyhedron = NULL; - // view options - m_view_points = true; - m_view_segments = true; - m_view_polyhedron = true; - m_view_distance_function = true; + // view options + m_view_points = true; + m_view_segments = true; + m_view_polyhedron = true; + m_view_distance_function = true; - // distance function - m_red_ramp.build_red(); - m_blue_ramp.build_blue(); - m_max_distance_function = (FT)0.0; - m_signed_distance_function = false; + // distance function + m_red_ramp.build_red(); + m_blue_ramp.build_blue(); + m_max_distance_function = (FT)0.0; + m_signed_distance_function = false; } Scene::~Scene() { - delete m_pPolyhedron; + delete m_pPolyhedron; } int Scene::open(QString filename) { - QTextStream cerr(stderr); - cerr << QString("Opening file \"%1\"\n").arg(filename); - QApplication::setOverrideCursor(QCursor(::Qt::WaitCursor)); + QTextStream cerr(stderr); + cerr << QString("Opening file \"%1\"\n").arg(filename); + QApplication::setOverrideCursor(QCursor(::Qt::WaitCursor)); - QFileInfo fileinfo(filename); - std::ifstream in(filename.toUtf8()); + QFileInfo fileinfo(filename); + std::ifstream in(filename.toUtf8()); - if(!in || !fileinfo.isFile() || ! fileinfo.isReadable()) - { - std::cerr << "unable to open file" << std::endl; - QApplication::restoreOverrideCursor(); - return -1; - } + if(!in || !fileinfo.isFile() || ! fileinfo.isReadable()) + { + std::cerr << "unable to open file" << std::endl; + QApplication::restoreOverrideCursor(); + return -1; + } - if(m_pPolyhedron != NULL) - delete m_pPolyhedron; + if(m_pPolyhedron != NULL) + delete m_pPolyhedron; - // allocate new polyhedron - m_pPolyhedron = new Polyhedron; - in >> *m_pPolyhedron; - if(!in) - { - std::cerr << "invalid OFF file" << std::endl; - QApplication::restoreOverrideCursor(); + // allocate new polyhedron + m_pPolyhedron = new Polyhedron; + in >> *m_pPolyhedron; + if(!in) + { + std::cerr << "invalid OFF file" << std::endl; + QApplication::restoreOverrideCursor(); - delete m_pPolyhedron; - m_pPolyhedron = NULL; + delete m_pPolyhedron; + m_pPolyhedron = NULL; - return -1; - } + return -1; + } - QApplication::restoreOverrideCursor(); - return 0; + QApplication::restoreOverrideCursor(); + return 0; } void Scene::update_bbox() { - std::cout << "Compute bbox..."; - m_bbox = Bbox(); + std::cout << "Compute bbox..."; + m_bbox = Bbox(); - if(m_pPolyhedron == NULL) - { - std::cout << "failed (no polyhedron)." << std::endl; - return; - } + if(m_pPolyhedron == NULL) + { + std::cout << "failed (no polyhedron)." << std::endl; + return; + } - if(m_pPolyhedron->empty()) - { - std::cout << "failed (empty polyhedron)." << std::endl; - return; - } + if(m_pPolyhedron->empty()) + { + std::cout << "failed (empty polyhedron)." << std::endl; + return; + } - Polyhedron::Point_iterator it = m_pPolyhedron->points_begin(); - m_bbox = (*it).bbox(); - for(; it != m_pPolyhedron->points_end();it++) - m_bbox = m_bbox + (*it).bbox(); - std::cout << "done (" << m_pPolyhedron->size_of_facets() - << " facets)" << std::endl; + Polyhedron::Point_iterator it = m_pPolyhedron->points_begin(); + m_bbox = (*it).bbox(); + for(; it != m_pPolyhedron->points_end();it++) + m_bbox = m_bbox + (*it).bbox(); + std::cout << "done (" << m_pPolyhedron->size_of_facets() + << " facets)" << std::endl; } void Scene::draw() { - if(m_view_polyhedron) - draw_polyhedron(); + if(m_view_polyhedron) + draw_polyhedron(); - if(m_view_points) - draw_points(); + if(m_view_points) + draw_points(); - if(m_view_segments) - draw_segments(); + if(m_view_segments) + draw_segments(); - if(m_view_distance_function) - { - if(m_signed_distance_function) - draw_signed_distance_function(); - else - draw_unsigned_distance_function(); - } + if(m_view_distance_function) + { + if(m_signed_distance_function) + draw_signed_distance_function(); + else + draw_unsigned_distance_function(); + } } void Scene::draw_polyhedron() { - // draw black edges - if(m_pPolyhedron != NULL) - { - ::glDisable(GL_LIGHTING); - ::glColor3ub(0,0,0); - ::glLineWidth(1.0f); - gl_render_edges(*m_pPolyhedron); - } + // draw black edges + if(m_pPolyhedron != NULL) + { + ::glDisable(GL_LIGHTING); + ::glColor3ub(0,0,0); + ::glLineWidth(1.0f); + gl_render_edges(*m_pPolyhedron); + } } void Scene::draw_segments() { - if(m_segments.size() != 0) - { - ::glDisable(GL_LIGHTING); - ::glColor3ub(0,100,0); - ::glLineWidth(2.0f); - ::glBegin(GL_LINES); - std::list::iterator it; - for(it = m_segments.begin(); it != m_segments.end(); it++) - { - const Segment& s = *it; - const Point& p = s.source(); - const Point& q = s.target(); - ::glVertex3d(p.x(),p.y(),p.z()); - ::glVertex3d(q.x(),q.y(),q.z()); - } - ::glEnd(); - } + if(m_segments.size() != 0) + { + ::glDisable(GL_LIGHTING); + ::glColor3ub(0,100,0); + ::glLineWidth(2.0f); + ::glBegin(GL_LINES); + std::list::iterator it; + for(it = m_segments.begin(); it != m_segments.end(); it++) + { + const Segment& s = *it; + const Point& p = s.source(); + const Point& q = s.target(); + ::glVertex3d(p.x(),p.y(),p.z()); + ::glVertex3d(q.x(),q.y(),q.z()); + } + ::glEnd(); + } } void Scene::draw_points() { - // draw red points - if(m_points.size() != 0) - { - ::glDisable(GL_LIGHTING); - ::glColor3ub(180,0,0); - ::glPointSize(2.0f); - ::glBegin(GL_POINTS); - std::list::iterator it; - for(it = m_points.begin(); it != m_points.end(); it++) - { - const Point& p = *it; - ::glVertex3d(p.x(),p.y(),p.z()); - } - ::glEnd(); - } + // draw red points + if(m_points.size() != 0) + { + ::glDisable(GL_LIGHTING); + ::glColor3ub(180,0,0); + ::glPointSize(2.0f); + ::glBegin(GL_POINTS); + std::list::iterator it; + for(it = m_points.begin(); it != m_points.end(); it++) + { + const Point& p = *it; + ::glVertex3d(p.x(),p.y(),p.z()); + } + ::glEnd(); + } } void Scene::draw_unsigned_distance_function() { - if(m_max_distance_function == (FT)0.0) - return; + if(m_max_distance_function == (FT)0.0) + return; - ::glDisable(GL_LIGHTING); - ::glShadeModel(GL_SMOOTH); - ::glBegin(GL_QUADS); - int i,j; - const int nb_quads = 99; - for(i=0;i 0.0) - ::glColor3ub(m_red_ramp.r(i00),m_red_ramp.g(i00),m_red_ramp.b(i00)); - else - ::glColor3ub(m_blue_ramp.r(i00),m_blue_ramp.g(i00),m_blue_ramp.b(i00)); - ::glVertex3d(p00.x(),p00.y(),p00.z()); + // assembles one quad + if(d00 > 0.0) + ::glColor3ub(m_red_ramp.r(i00),m_red_ramp.g(i00),m_red_ramp.b(i00)); + else + ::glColor3ub(m_blue_ramp.r(i00),m_blue_ramp.g(i00),m_blue_ramp.b(i00)); + ::glVertex3d(p00.x(),p00.y(),p00.z()); - if(d01 > 0.0) - ::glColor3ub(m_red_ramp.r(i01),m_red_ramp.g(i01),m_red_ramp.b(i01)); - else - ::glColor3ub(m_blue_ramp.r(i01),m_blue_ramp.g(i01),m_blue_ramp.b(i01)); - ::glVertex3d(p01.x(),p01.y(),p01.z()); + if(d01 > 0.0) + ::glColor3ub(m_red_ramp.r(i01),m_red_ramp.g(i01),m_red_ramp.b(i01)); + else + ::glColor3ub(m_blue_ramp.r(i01),m_blue_ramp.g(i01),m_blue_ramp.b(i01)); + ::glVertex3d(p01.x(),p01.y(),p01.z()); - if(d11 > 0) - ::glColor3ub(m_red_ramp.r(i11),m_red_ramp.g(i11),m_red_ramp.b(i11)); - else - ::glColor3ub(m_blue_ramp.r(i11),m_blue_ramp.g(i11),m_blue_ramp.b(i11)); - ::glVertex3d(p11.x(),p11.y(),p11.z()); + if(d11 > 0) + ::glColor3ub(m_red_ramp.r(i11),m_red_ramp.g(i11),m_red_ramp.b(i11)); + else + ::glColor3ub(m_blue_ramp.r(i11),m_blue_ramp.g(i11),m_blue_ramp.b(i11)); + ::glVertex3d(p11.x(),p11.y(),p11.z()); - if(d10 > 0) - ::glColor3ub(m_red_ramp.r(i10),m_red_ramp.g(i10),m_red_ramp.b(i10)); - else - ::glColor3ub(m_blue_ramp.r(i10),m_blue_ramp.g(i10),m_blue_ramp.b(i10)); - ::glVertex3d(p10.x(),p10.y(),p10.z()); - } - ::glEnd(); + if(d10 > 0) + ::glColor3ub(m_red_ramp.r(i10),m_red_ramp.g(i10),m_red_ramp.b(i10)); + else + ::glColor3ub(m_blue_ramp.r(i10),m_blue_ramp.g(i10),m_blue_ramp.b(i10)); + ::glVertex3d(p10.x(),p10.y(),p10.z()); + } + } + ::glEnd(); } FT Scene::random_in(const double a, @@ -287,382 +293,389 @@ Point Scene::random_point(const CGAL::Bbox_3& bbox) Vector Scene::random_vector() { - FT x = random_in(0.0,1.0); - FT y = random_in(0.0,1.0); - FT z = random_in(0.0,1.0); - return Vector(x,y,z); + FT x = random_in(0.0,1.0); + FT y = random_in(0.0,1.0); + FT z = random_in(0.0,1.0); + return Vector(x,y,z); } Ray Scene::random_ray(const CGAL::Bbox_3& bbox) { - Point p = random_point(bbox); - Point q = random_point(bbox); - return Ray(p,q); + Point p = random_point(bbox); + Point q = random_point(bbox); + return Ray(p,q); } Segment Scene::random_segment(const CGAL::Bbox_3& bbox) { - Point p = random_point(bbox); - Point q = random_point(bbox); - return Segment(p,q); + Point p = random_point(bbox); + Point q = random_point(bbox); + return Segment(p,q); } Line Scene::random_line(const CGAL::Bbox_3& bbox) { - Point p = random_point(bbox); - Point q = random_point(bbox); - return Line(p,q); + Point p = random_point(bbox); + Point q = random_point(bbox); + return Line(p,q); } Plane Scene::random_plane(const CGAL::Bbox_3& bbox) { - Point p = random_point(bbox); - Vector vec = random_vector(); - return Plane(p,vec); + Point p = random_point(bbox); + Vector vec = random_vector(); + return Plane(p,vec); } void Scene::generate_points_in(const unsigned int nb_points, const double min, const double max) { - typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; + typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; - std::cout << "Construct AABB tree..."; - Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - std::cout << "done." << std::endl; + std::cout << "Construct AABB tree..."; + Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + std::cout << "done." << std::endl; - CGAL::Timer timer; - timer.start(); - std::cout << "Generate " << nb_points << " points in interval [" - << min << ";" << max << "]"; + CGAL::Timer timer; + timer.start(); + std::cout << "Generate " << nb_points << " points in interval [" + << min << ";" << max << "]"; - unsigned int nb_trials = 0; - Vector vec = random_vector(); - while(m_points.size() < nb_points) - { - Point p = random_point(tree.bbox()); + unsigned int nb_trials = 0; + Vector vec = random_vector(); + while(m_points.size() < nb_points) + { + Point p = random_point(tree.bbox()); - // measure distance - FT signed_distance = std::sqrt(tree.squared_distance(p)); + // measure distance + FT signed_distance = std::sqrt(tree.squared_distance(p)); - // measure sign - Ray ray(p,vec); - int nb_intersections = (int)tree.number_of_intersected_primitives(ray); - if(nb_intersections % 2 != 0) - signed_distance *= -1.0; + // measure sign + Ray ray(p,vec); + int nb_intersections = (int)tree.number_of_intersected_primitives(ray); + if(nb_intersections % 2 != 0) + signed_distance *= -1.0; - if(signed_distance >= min && - signed_distance <= max) - { - m_points.push_back(p); - if(m_points.size()%(nb_points/10) == 0) - std::cout << "."; // ASCII progress bar - } - nb_trials++; - } - double speed = (double)nb_trials / timer.time(); - std::cout << "done (" << nb_trials << " trials, " - << timer.time() << " s, " - << speed << " queries/s)" << std::endl; + if(signed_distance >= min && + signed_distance <= max) + { + m_points.push_back(p); + if(m_points.size()%(nb_points/10) == 0) + std::cout << "."; // ASCII progress bar + } + nb_trials++; + } + double speed = (double)nb_trials / timer.time(); + std::cout << "done (" << nb_trials << " trials, " + << timer.time() << " s, " + << speed << " queries/s)" << std::endl; } void Scene::generate_inside_points(const unsigned int nb_points) { - typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; + typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; - std::cout << "Construct AABB tree..."; - Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - std::cout << "done." << std::endl; + std::cout << "Construct AABB tree..."; + Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + std::cout << "done." << std::endl; - CGAL::Timer timer; - timer.start(); - std::cout << "Generate " << nb_points << " inside points"; + CGAL::Timer timer; + timer.start(); + std::cout << "Generate " << nb_points << " inside points"; - unsigned int nb_trials = 0; - Vector vec = random_vector(); - while(m_points.size() < nb_points) - { - Point p = random_point(tree.bbox()); - Ray ray(p,vec); - int nb_intersections = (int)tree.number_of_intersected_primitives(ray); - if(nb_intersections % 2 != 0) - { - m_points.push_back(p); - if(m_points.size()%(nb_points/10) == 0) - std::cout << "."; // ASCII progress bar - } - nb_trials++; - } - double speed = (double)nb_trials / timer.time(); - std::cout << "done (" << nb_trials << " trials, " - << timer.time() << " s, " - << speed << " queries/s)" << std::endl; + unsigned int nb_trials = 0; + Vector vec = random_vector(); + while(m_points.size() < nb_points) + { + Point p = random_point(tree.bbox()); + Ray ray(p,vec); + int nb_intersections = (int)tree.number_of_intersected_primitives(ray); + if(nb_intersections % 2 != 0) + { + m_points.push_back(p); + if(m_points.size()%(nb_points/10) == 0) + std::cout << "."; // ASCII progress bar + } + nb_trials++; + } + double speed = (double)nb_trials / timer.time(); + std::cout << "done (" << nb_trials << " trials, " + << timer.time() << " s, " + << speed << " queries/s)" << std::endl; } void Scene::generate_boundary_segments(const unsigned int nb_slices) { - typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; - typedef Tree::Object_and_primitive_id Object_and_primitive_id; + typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef Tree::Object_and_primitive_id Object_and_primitive_id; - std::cout << "Construct AABB tree..."; - Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - std::cout << "done." << std::endl; + std::cout << "Construct AABB tree..."; + Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + std::cout << "done." << std::endl; - CGAL::Timer timer; - timer.start(); - std::cout << "Generate boundary segments from " << nb_slices << " slices: "; + CGAL::Timer timer; + timer.start(); + std::cout << "Generate boundary segments from " << nb_slices << " slices: "; - Vector normal((FT)0.0,(FT)0.0,(FT)1.0); - unsigned int i; + Vector normal((FT)0.0,(FT)0.0,(FT)1.0); + unsigned int i; - const double dz = m_bbox.zmax() - m_bbox.zmin(); - for(i=0;i intersections; - tree.all_intersections(plane,std::back_inserter(intersections)); + std::list intersections; + tree.all_intersections(plane,std::back_inserter(intersections)); - std::list::iterator it; - for(it = intersections.begin(); - it != intersections.end(); - it++) - { - Object_and_primitive_id op = *it; - CGAL::Object object = op.first; - Segment segment; - if(CGAL::assign(segment,object)) - m_segments.push_back(segment); - } - } - std::cout << m_segments.size() << " segments, " << timer.time() << " s." << std::endl; + std::list::iterator it; + for(it = intersections.begin(); + it != intersections.end(); + it++) + { + Object_and_primitive_id op = *it; + CGAL::Object object = op.first; + Segment segment; + if(CGAL::assign(segment,object)) + m_segments.push_back(segment); + } + } + std::cout << m_segments.size() << " segments, " << timer.time() << " s." << std::endl; } void Scene::generate_boundary_points(const unsigned int nb_points) { - typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; - typedef Tree::Object_and_primitive_id Object_and_primitive_id; + typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef Tree::Object_and_primitive_id Object_and_primitive_id; - std::cout << "Construct AABB tree..."; - Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - std::cout << "done." << std::endl; + std::cout << "Construct AABB tree..."; + Tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + std::cout << "done." << std::endl; - CGAL::Timer timer; - timer.start(); - std::cout << "Generate boundary points: "; + CGAL::Timer timer; + timer.start(); + std::cout << "Generate boundary points: "; - unsigned int nb = 0; - unsigned int nb_lines = 0; - while(nb < nb_points) - { - Line line = random_line(tree.bbox()); + unsigned int nb = 0; + unsigned int nb_lines = 0; + while(nb < nb_points) + { + Line line = random_line(tree.bbox()); - std::list intersections; - tree.all_intersections(line,std::back_inserter(intersections)); - nb_lines++; + std::list intersections; + tree.all_intersections(line,std::back_inserter(intersections)); + nb_lines++; - std::list::iterator it; - for(it = intersections.begin(); - it != intersections.end(); - it++) - { - Object_and_primitive_id op = *it; - CGAL::Object object = op.first; - Point point; - if(CGAL::assign(point,object)) - { - m_points.push_back(point); - nb++; - } - } - } - std::cout << nb_lines << " line queries, " << timer.time() << " s." << std::endl; + std::list::iterator it; + for(it = intersections.begin(); + it != intersections.end(); + it++) + { + Object_and_primitive_id op = *it; + CGAL::Object object = op.first; + Point point; + if(CGAL::assign(point,object)) + { + m_points.push_back(point); + nb++; + } + } + } + std::cout << nb_lines << " line queries, " << timer.time() << " s." << std::endl; } void Scene::generate_edge_points(const unsigned int nb_points) { - typedef CGAL::AABB_polyhedron_segment_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; - typedef Tree::Object_and_primitive_id Object_and_primitive_id; + typedef CGAL::AABB_polyhedron_segment_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + typedef Tree::Object_and_primitive_id Object_and_primitive_id; - std::cout << "Construct AABB tree..."; - Tree tree(m_pPolyhedron->edges_begin(),m_pPolyhedron->edges_end()); - std::cout << "done." << std::endl; + std::cout << "Construct AABB tree..."; + Tree tree(m_pPolyhedron->edges_begin(),m_pPolyhedron->edges_end()); + std::cout << "done." << std::endl; - CGAL::Timer timer; - timer.start(); - std::cout << "Generate edge points: "; + CGAL::Timer timer; + timer.start(); + std::cout << "Generate edge points: "; - unsigned int nb = 0; - unsigned int nb_planes = 0; - while(nb < nb_points) - { - Plane plane = random_plane(tree.bbox()); + unsigned int nb = 0; + unsigned int nb_planes = 0; + while(nb < nb_points) + { + Plane plane = random_plane(tree.bbox()); - std::list intersections; - tree.all_intersections(plane,std::back_inserter(intersections)); - nb_planes++; + std::list intersections; + tree.all_intersections(plane,std::back_inserter(intersections)); + nb_planes++; - std::list::iterator it; - for(it = intersections.begin(); - it != intersections.end(); - it++) - { - Object_and_primitive_id op = *it; - CGAL::Object object = op.first; - Point point; - if(CGAL::assign(point,object)) - { - m_points.push_back(point); - nb++; - } - } - } - std::cout << nb_planes << " plane queries, " << timer.time() << " s." << std::endl; + std::list::iterator it; + for(it = intersections.begin(); + it != intersections.end(); + it++) + { + Object_and_primitive_id op = *it; + CGAL::Object object = op.first; + Point point; + if(CGAL::assign(point,object)) + { + m_points.push_back(point); + nb++; + } + } + } + std::cout << nb_planes << " plane queries, " << timer.time() << " s." << std::endl; } void Scene::unsigned_distance_function() { - CGAL::Timer timer; - timer.start(); - std::cout << "Construct AABB tree..."; - Facet_tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - tree.accelerate_distance_queries(); - std::cout << "done (" << timer.time() << " s)" << std::endl; + CGAL::Timer timer; + timer.start(); + std::cout << "Construct AABB tree..."; + Facet_tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + tree.accelerate_distance_queries(); + std::cout << "done (" << timer.time() << " s)" << std::endl; - m_max_distance_function = (FT)0.0; - int i,j; - const double dx = m_bbox.xmax() - m_bbox.xmin(); - const double dy = m_bbox.ymax() - m_bbox.ymin(); - const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); - for(i=0;i<100;i++) - { - FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); - for(j=0;j<100;j++) - { - FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); - Point query(x,y,z); - FT sq_distance = tree.squared_distance(query); - FT distance = std::sqrt(sq_distance); - m_distance_function[i][j] = Point_distance(query,distance); - m_max_distance_function = distance > m_max_distance_function ? - distance : m_max_distance_function; - } - } - m_signed_distance_function = false; + m_max_distance_function = (FT)0.0; + int i,j; + const double dx = m_bbox.xmax() - m_bbox.xmin(); + const double dy = m_bbox.ymax() - m_bbox.ymin(); + const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); + for(i=0;i<100;i++) + { + FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); + for(j=0;j<100;j++) + { + FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); + Point query(x,y,z); + FT sq_distance = tree.squared_distance(query); + FT distance = std::sqrt(sq_distance); + m_distance_function[i][j] = Point_distance(query,distance); + m_max_distance_function = distance > m_max_distance_function ? +distance : m_max_distance_function; + } + } + m_signed_distance_function = false; } void Scene::unsigned_distance_function_to_edges() { - typedef CGAL::AABB_polyhedron_segment_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Edge_tree; + typedef CGAL::AABB_polyhedron_segment_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Edge_tree; - CGAL::Timer timer; - timer.start(); - std::cout << "Construct AABB tree from edges..."; - Edge_tree tree(m_pPolyhedron->edges_begin(),m_pPolyhedron->edges_end()); - tree.accelerate_distance_queries(); - std::cout << "done (" << timer.time() << " s)" << std::endl; + CGAL::Timer timer; + timer.start(); + std::cout << "Construct AABB tree from edges..."; + Edge_tree tree(m_pPolyhedron->edges_begin(),m_pPolyhedron->edges_end()); + tree.accelerate_distance_queries(); + std::cout << "done (" << timer.time() << " s)" << std::endl; - m_max_distance_function = (FT)0.0; - const double dx = m_bbox.xmax() - m_bbox.xmin(); - const double dy = m_bbox.ymax() - m_bbox.ymin(); - const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); - int i,j; - for(i=0;i<100;i++) - { - FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); - for(j=0;j<100;j++) - { - FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); - Point query(x,y,z); - FT sq_distance = tree.squared_distance(query); - FT distance = std::sqrt(sq_distance); - m_distance_function[i][j] = Point_distance(query,distance); - m_max_distance_function = distance > m_max_distance_function ? + m_max_distance_function = (FT)0.0; + const double dx = m_bbox.xmax() - m_bbox.xmin(); + const double dy = m_bbox.ymax() - m_bbox.ymin(); + const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); + int i,j; + for(i=0;i<100;i++) + { + FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); + for(j=0;j<100;j++) + { + FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); + Point query(x,y,z); + FT sq_distance = tree.squared_distance(query); + FT distance = std::sqrt(sq_distance); + m_distance_function[i][j] = Point_distance(query,distance); + m_max_distance_function = distance > m_max_distance_function ? distance : m_max_distance_function; - } - } - m_signed_distance_function = false; + } + } + m_signed_distance_function = false; } void Scene::signed_distance_function() { - CGAL::Timer timer; - timer.start(); - std::cout << "Construct AABB tree..."; - Facet_tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); - tree.accelerate_distance_queries(); - std::cout << "done (" << timer.time() << " s)" << std::endl; + CGAL::Timer timer; + timer.start(); + std::cout << "Construct AABB tree..."; + Facet_tree tree(m_pPolyhedron->facets_begin(),m_pPolyhedron->facets_end()); + tree.accelerate_distance_queries(); + std::cout << "done (" << timer.time() << " s)" << std::endl; - m_max_distance_function = (FT)0.0; - Vector vec = random_vector(); + m_max_distance_function = (FT)0.0; + Vector vec = random_vector(); - const double dx = m_bbox.xmax() - m_bbox.xmin(); - const double dy = m_bbox.ymax() - m_bbox.ymin(); - const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); - int i,j; - for(i=0;i<100;i++) - { - FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); - for(j=0;j<100;j++) - { - FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); - Point query(x,y,z); - FT sq_distance = tree.squared_distance(query); - FT unsigned_distance = std::sqrt(sq_distance); + const double dx = m_bbox.xmax() - m_bbox.xmin(); + const double dy = m_bbox.ymax() - m_bbox.ymin(); + const double z = 0.5 * (m_bbox.zmax() + m_bbox.zmin()); + int i,j; + for(i=0;i<100;i++) + { + FT x = m_bbox.xmin() + (FT)((double)i/100.0 * dx); + for(j=0;j<100;j++) + { + FT y = m_bbox.ymin() + (FT)((double)j/100.0 * dy); + Point query(x,y,z); + FT sq_distance = tree.squared_distance(query); + FT unsigned_distance = std::sqrt(sq_distance); - // get sign through ray casting (random vector) - Ray ray(query,vec); - unsigned int nbi = tree.number_of_intersected_primitives(ray); - FT sign = nbi%2 == 0 ? (FT)1.0 : (FT)-1.0; - FT signed_distance = sign * unsigned_distance; + // get sign through ray casting (random vector) + Ray ray(query,vec); + unsigned int nbi = tree.number_of_intersected_primitives(ray); + FT sign = nbi%2 == 0 ? (FT)1.0 : (FT)-1.0; + FT signed_distance = sign * unsigned_distance; - m_distance_function[i][j] = Point_distance(query,signed_distance); - m_max_distance_function = unsigned_distance > m_max_distance_function ? + m_distance_function[i][j] = Point_distance(query,signed_distance); + m_max_distance_function = unsigned_distance > m_max_distance_function ? unsigned_distance : m_max_distance_function; - } - } - m_signed_distance_function = true; + } + } + m_signed_distance_function = true; } void Scene::toggle_view_poyhedron() { - m_view_polyhedron = !m_view_polyhedron; + m_view_polyhedron = !m_view_polyhedron; } void Scene::toggle_view_segments() { - m_view_segments = !m_view_segments; + m_view_segments = !m_view_segments; } void Scene::toggle_view_points() { - m_view_points = !m_view_points; + m_view_points = !m_view_points; } void Scene::toggle_view_distance_function() { - m_view_distance_function = !m_view_distance_function; + m_view_distance_function = !m_view_distance_function; } void Scene::refine_bisection(const FT max_sqlen) { - std::cout << "Refine through recursive longest edge bisection..."; - Refiner refiner(m_pPolyhedron); - refiner(max_sqlen); - std::cout << "done (" << m_pPolyhedron->size_of_facets() << " facets)" << std::endl; + std::cout << "Refine through recursive longest edge bisection..."; + Refiner refiner(m_pPolyhedron); + refiner(max_sqlen); + std::cout << "done (" << m_pPolyhedron->size_of_facets() << " facets)" << std::endl; +} + +void Scene::refine_loop() +{ + std::cout << "Loop subdivision..."; + CGAL::Subdivision_method_3::Loop_subdivision(*m_pPolyhedron, 1); + std::cout << "done (" << m_pPolyhedron->size_of_facets() << " facets)" << std::endl; } diff --git a/AABB_tree/demo/AABB_tree/Scene.h b/AABB_tree/demo/AABB_tree/Scene.h index 6d5c6ca8abf..02270e5e0de 100644 --- a/AABB_tree/demo/AABB_tree/Scene.h +++ b/AABB_tree/demo/AABB_tree/Scene.h @@ -17,121 +17,124 @@ class Scene { public: - Scene(); - ~Scene(); + Scene(); + ~Scene(); public: - // types - typedef CGAL::Bbox_3 Bbox; - typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Facet_tree; - typedef Facet_tree::Object_and_primitive_id Object_and_primitive_id; - typedef Facet_tree::Primitive_id Primitive_id; + // types + typedef CGAL::Bbox_3 Bbox; + typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Facet_tree; + typedef Facet_tree::Object_and_primitive_id Object_and_primitive_id; + typedef Facet_tree::Primitive_id Primitive_id; public: - void draw(); - void update_bbox(); - Bbox bbox() { return m_bbox; } + void draw(); + void update_bbox(); + Bbox bbox() { return m_bbox; } private: - // member data - Bbox m_bbox; - Polyhedron *m_pPolyhedron; - std::list m_points; - std::list m_segments; + // member data + Bbox m_bbox; + Polyhedron *m_pPolyhedron; + std::list m_points; + std::list m_segments; - // distance functions (simple 2D arrays) - Color_ramp m_red_ramp; - Color_ramp m_blue_ramp; - Color_ramp m_thermal_ramp; - FT m_max_distance_function; - bool m_view_distance_function; - bool m_signed_distance_function; - typedef std::pair Point_distance; - Point_distance m_distance_function[100][100]; + // distance functions (simple 2D arrays) + Color_ramp m_red_ramp; + Color_ramp m_blue_ramp; + Color_ramp m_thermal_ramp; + FT m_max_distance_function; + bool m_view_distance_function; + bool m_signed_distance_function; + typedef std::pair Point_distance; + Point_distance m_distance_function[100][100]; private: - // utility functions - Vector random_vector(); - Ray random_ray(const Bbox& bbox); - FT random_in(const double a,const double b); - Line random_line(const Bbox& bbox); - Point random_point(const Bbox& bbox); - Plane random_plane(const Bbox& bbox); - Segment random_segment(const Bbox& bbox); + // utility functions + Vector random_vector(); + Ray random_ray(const Bbox& bbox); + Line random_line(const Bbox& bbox); + Point random_point(const Bbox& bbox); + Plane random_plane(const Bbox& bbox); + Segment random_segment(const Bbox& bbox); + FT random_in(const double a,const double b); public: - // file menu - int open(QString filename); + // file menu + int open(QString filename); - // edit menu - void clear_points() { m_points.clear(); } - void clear_segments() { m_segments.clear(); } - void clear_distance_function() { m_max_distance_function = 0.0; } + // edit menu + void clear_points() { m_points.clear(); } + void clear_segments() { m_segments.clear(); } + void clear_distance_function() { m_max_distance_function = 0.0; } - // algorithms - void refine_bisection(const FT max_sqlen); - void generate_edge_points(const unsigned int nb_points); - void generate_inside_points(const unsigned int nb_points); - void generate_boundary_points(const unsigned int nb_points); - void generate_boundary_segments(const unsigned int nb_slices); - void generate_points_in(const unsigned int nb_points, - const double min, const double max); + // algorithms + void generate_edge_points(const unsigned int nb_points); + void generate_inside_points(const unsigned int nb_points); + void generate_boundary_points(const unsigned int nb_points); + void generate_boundary_segments(const unsigned int nb_slices); + void generate_points_in(const unsigned int nb_points, + const double min, const double max); - // distance functions - void signed_distance_function(); - void unsigned_distance_function(); - void unsigned_distance_function_to_edges(); + // algorithms/refine + void refine_loop(); + void refine_bisection(const FT max_sqlen); - // toggle view options - void toggle_view_points(); - void toggle_view_segments(); - void toggle_view_poyhedron(); - void toggle_view_distance_function(); + // distance functions + void signed_distance_function(); + void unsigned_distance_function(); + void unsigned_distance_function_to_edges(); - // view options - bool m_view_points; - bool m_view_segments; - bool m_view_polyhedron; + // toggle view options + void toggle_view_points(); + void toggle_view_segments(); + void toggle_view_poyhedron(); + void toggle_view_distance_function(); - // benchmarks - enum {DO_INTERSECT, - ANY_INTERSECTION, - NB_INTERSECTIONS, - ALL_INTERSECTIONS, - ANY_INTERSECTED_PRIMITIVE, - ALL_INTERSECTED_PRIMITIVES}; - void bench_memory(); - void bench_construction(); - void bench_distances_vs_nbt(); - void bench_intersections_vs_nbt(); - void benchmark_intersections(const double duration); - unsigned int nb_digits(const unsigned int value); + // view options + bool m_view_points; + bool m_view_segments; + bool m_view_polyhedron; - template - void bench_intersection(Facet_tree& tree,const int function,const double duration, - char *query_name, const std::vector& queries, const int nb_queries); - void bench_intersections(Facet_tree& tree, const double duration, const int function, - char *function_name, const std::vector& rays, - const std::vector& lines, const std::vector& planes, - const std::vector& segments, const int nb_queries); + // benchmarks + enum {DO_INTERSECT, + ANY_INTERSECTION, + NB_INTERSECTIONS, + ALL_INTERSECTIONS, + ANY_INTERSECTED_PRIMITIVE, + ALL_INTERSECTED_PRIMITIVES}; + void bench_memory(); + void bench_construction(); + void bench_distances_vs_nbt(); + void bench_intersections_vs_nbt(); + void benchmark_intersections(const double duration); + unsigned int nb_digits(const unsigned int value); - // distance benchmarks - enum {SQ_DISTANCE, - CLOSEST_POINT, - CLOSEST_POINT_AND_PRIMITIVE_ID}; - void benchmark_distances(const double duration); - void bench_closest_point(Facet_tree& tree,const double duration); - void bench_squared_distance(Facet_tree& tree,const double duration); - void bench_closest_point_and_primitive(Facet_tree& tree,const double duration); - void bench_distance(Facet_tree& tree,const int function,const double duration); + template + void bench_intersection(Facet_tree& tree,const int function,const double duration, + char *query_name, const std::vector& queries, const int nb_queries); + void bench_intersections(Facet_tree& tree, const double duration, const int function, + char *function_name, const std::vector& rays, + const std::vector& lines, const std::vector& planes, + const std::vector& segments, const int nb_queries); - // drawing - void draw_points(); - void draw_segments(); - void draw_polyhedron(); - void draw_signed_distance_function(); - void draw_unsigned_distance_function(); + // distance benchmarks + enum {SQ_DISTANCE, + CLOSEST_POINT, + CLOSEST_POINT_AND_PRIMITIVE_ID}; + void benchmark_distances(const double duration); + void bench_closest_point(Facet_tree& tree,const double duration); + void bench_squared_distance(Facet_tree& tree,const double duration); + void bench_closest_point_and_primitive(Facet_tree& tree,const double duration); + void bench_distance(Facet_tree& tree,const int function,const double duration); + + // drawing + void draw_points(); + void draw_segments(); + void draw_polyhedron(); + void draw_signed_distance_function(); + void draw_unsigned_distance_function(); }; // end class Scene diff --git a/AABB_tree/doc_tex/AABB_tree/performances.tex b/AABB_tree/doc_tex/AABB_tree/performances.tex index a20515dffb3..e614129e549 100644 --- a/AABB_tree/doc_tex/AABB_tree/performances.tex +++ b/AABB_tree/doc_tex/AABB_tree/performances.tex @@ -1,11 +1,11 @@ \section{Performances} \label{AABB_tree_section_performances} -We provide some performance numbers for the case where the AABB tree contains a set of polyhedron triangle facets. We measure the tree construction time, the memory occupancy, and the number of queries per second for a variety of intersection and distance queries. The machine used is a PC running Windows XP64 with an Intel CPU Core2 Extreme clocked at 3.06 GHz with 4GB of RAM. By default the kernel used is \ccc{Simple_cartesian} (the fastest in our experiments). The program has been compiled with Visual C++ 2005 compiler with the O2 option (maximize speed). +We provide some performance numbers for the case where the AABB tree contains a set of polyhedron triangle facets. We measure the tree construction time, the memory occupancy and the number of queries per second for a variety of intersection and distance queries. The machine used is a PC running Windows XP64 with an Intel CPU Core2 Extreme clocked at 3.06 GHz with 4GB of RAM. By default the kernel used is \ccc{Simple_cartesian} (the fastest in our experiments). The program has been compiled with Visual C++ 2005 compiler with the O2 option which maximizes speed. \subsection{Construction} -The surface triangle mesh chosen for benchmarking the tree construction is the knot model (14,400 triangles) available in the demo data folder. We measure the tree construction time (both AABB tree alone and AABB tree with internal KD-tree) for this model as well as for three denser versions subdivided through the Loop subdivision scheme which increases the number of triangles by a factor of four. +The surface triangle mesh chosen for benchmarking the tree construction is the knot model (14,400 triangles) depicted by Figure \ref{fig:AABB-tree-bench}. We measure the tree construction time (both AABB tree alone and AABB tree with internal KD-tree) for this model as well as for three denser versions subdivided through the Loop subdivision scheme which multiplies the number of triangles by four. \begin{tabular}{|l|c|c|} \hline @@ -111,7 +111,7 @@ The surface triangle mesh chosen for benchmarking distances is again the knot mo \subsection{Summary} -The experiments described above are neither exhaustive nor conclusive as we have chosen one specific case where the input primitives are the facets of a triangle surface polyhedron. Nevertheless we provide the reader with some general observations and advices about how to put the AABB tree to use with satisfactory performances. While the tree construction times and memory occupancy do not fluctuate much in our experiments depending on the input surface triangle mesh, the performance expressed in number of queries varies greatly depending on a complex combination of criteria: type of kernel, number of input primitives, distribution of primitives in space, type of function queried, type of query, and location of query in space. +The experiments described above are neither exhaustive nor conclusive as we have chosen one specific case where the input primitives are the facets of a triangle surface polyhedron. Nevertheless we now provide some general observations and advices about how to put the AABB tree to use with satisfactory performances. While the tree construction times and memory occupancy do not fluctuate much in our experiments depending on the input surface triangle mesh, the performance expressed in number of queries varies greatly depending on a complex combination of criteria: type of kernel, number of input primitives, distribution of primitives in space, type of function queried, type of query and location of query in space. \begin{itemize}