dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/draw_linear_cell_complex.h

425 lines
14 KiB
C++

// Copyright (c) 2018 CNRS and LIRIS' Establishments (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.1/Linear_cell_complex/include/CGAL/draw_linear_cell_complex.h $
// $Id: draw_linear_cell_complex.h 3fb644e 2020-04-10T17:40:30+02:00 Guillaume Damiand
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr>
#ifndef CGAL_DRAW_LCC_H
#define CGAL_DRAW_LCC_H
#include <CGAL/Qt/Basic_viewer_qt.h>
#ifdef CGAL_USE_BASIC_VIEWER
#include <CGAL/Linear_cell_complex_operations.h>
#include <CGAL/Random.h>
namespace CGAL
{
// Default color functor; user can change it to have its own face color
struct DefaultDrawingFunctorLCC
{
/// @return true iff the volume containing dh is drawn.
template<typename LCC>
bool draw_volume(const LCC&,
typename LCC::Dart_const_handle) const
{ return true; }
/// @return true iff the face containing dh is drawn.
template<typename LCC>
bool draw_face(const LCC&,
typename LCC::Dart_const_handle) const
{ return true; }
/// @return true iff the edge containing dh is drawn.
template<typename LCC>
bool draw_edge(const LCC&,
typename LCC::Dart_const_handle) const
{ return true; }
/// @return true iff the vertex containing dh is drawn.
template<typename LCC>
bool draw_vertex(const LCC&,
typename LCC::Dart_const_handle) const
{ return true; }
/// @return true iff the volume containing dh is drawn in wireframe.
template<typename LCC>
bool volume_wireframe(const LCC&,
typename LCC::Dart_const_handle) const
{ return false; }
/// @return true iff the face containing dh is drawn in wireframe.
template<typename LCC>
bool face_wireframe(const LCC&,
typename LCC::Dart_const_handle) const
{ return false; }
/// @return true iff the volume containing dh is colored.
template<typename LCC>
bool colored_volume(const LCC&,
typename LCC::Dart_const_handle) const
{ return true; }
/// @return true iff the face containing dh is colored.
/// if we have also colored_volume(alcc, dh), the volume color is
/// ignored and only the face color is considered.
template<typename LCC>
bool colored_face(const LCC&,
typename LCC::Dart_const_handle) const
{ return false; }
/// @return true iff the edge containing dh is colored.
template<typename LCC>
bool colored_edge(const LCC&,
typename LCC::Dart_const_handle) const
{ return false; }
/// @return true iff the vertex containing dh is colored.
template<typename LCC>
bool colored_vertex(const LCC&,
typename LCC::Dart_const_handle) const
{ return false; }
/// @return the color of the volume containing dh
/// used only if colored_volume(alcc, dh) and !colored_face(alcc, dh)
template<typename LCC>
CGAL::Color volume_color(const LCC& alcc,
typename LCC::Dart_const_handle dh) const
{
CGAL::Random random((unsigned int)(alcc.darts().index(dh)));
return get_random_color(random);
}
/// @return the color of the face containing dh
/// used only if colored_face(alcc, dh)
template<typename LCC>
CGAL::Color face_color(const LCC& alcc,
typename LCC::Dart_const_handle dh) const
{
CGAL::Random random((unsigned int)(alcc.darts().index(dh)));
return get_random_color(random);
}
/// @return the color of the edge containing dh
/// used only if colored_edge(alcc, dh)
template<typename LCC>
CGAL::Color edge_color(const LCC& alcc,
typename LCC::Dart_const_handle dh) const
{
CGAL::Random random((unsigned int)(alcc.darts().index(dh)));
return get_random_color(random);
}
/// @return the color of the vertex containing dh
/// used only if colored_vertex(alcc, dh)
template<typename LCC>
CGAL::Color vertex_color(const LCC& alcc,
typename LCC::Dart_const_handle dh) const
{
CGAL::Random random((unsigned int)(alcc.darts().index(dh)));
return get_random_color(random);
}
};
template<class LCC, class Local_kernel, int dim=LCC::ambient_dimension>
struct LCC_geom_utils;
template<class LCC, class Local_kernel>
struct LCC_geom_utils<LCC, Local_kernel, 3>
{
static typename Local_kernel::Vector_3
get_vertex_normal(const LCC& lcc, typename LCC::Dart_const_handle dh)
{
typename Local_kernel::Vector_3 n = internal::Geom_utils
<typename LCC::Traits, Local_kernel>::
get_local_vector(CGAL::compute_normal_of_cell_0<LCC>(lcc,dh));
n = n/(CGAL::sqrt(n*n));
return n;
}
};
template<class LCC, class Local_kernel>
struct LCC_geom_utils<LCC, Local_kernel, 2>
{
static typename Local_kernel::Vector_3
get_vertex_normal(const LCC&, typename LCC::Dart_const_handle)
{
typename Local_kernel::Vector_3 n=CGAL::NULL_VECTOR;
return n;
}
};
// Viewer class for LCC
template<class LCC, class DrawingFunctorLCC>
class SimpleLCCViewerQt : public Basic_viewer_qt
{
typedef Basic_viewer_qt Base;
typedef typename LCC::Dart_const_handle Dart_const_handle;
typedef typename LCC::Traits Kernel;
typedef typename Kernel::Point Point;
typedef typename Kernel::Vector Vector;
public:
/// Construct the viewer.
/// @param alcc the lcc to view
/// @param title the title of the window
/// @param anofaces if true, do not draw faces (faces are not computed; this can be
/// usefull for very big object where this time could be long)
SimpleLCCViewerQt(QWidget* parent,
const LCC* alcc=nullptr,
const char* title="Basic LCC Viewer",
bool anofaces=false,
const DrawingFunctorLCC& drawing_functor=DrawingFunctorLCC()) :
// First draw: vertices; edges, faces; multi-color; inverse normal
Base(parent, title, true, true, true, false, false),
lcc(alcc),
m_oriented_mark(lcc->get_new_mark()),
m_nofaces(anofaces),
m_random_face_color(false),
m_drawing_functor(drawing_functor)
{
lcc->orient(m_oriented_mark);
compute_elements();
}
~SimpleLCCViewerQt()
{ lcc->free_mark(m_oriented_mark); }
protected:
void set_lcc(const LCC* alcc, bool doredraw=true)
{
if (lcc!=nullptr)
{ lcc->free_mark(m_oriented_mark); }
lcc=alcc;
m_oriented_mark=lcc->get_new_mark();
lcc->orient(m_oriented_mark);
compute_elements();
if (doredraw) { redraw(); }
}
void compute_face(Dart_const_handle dh, Dart_const_handle voldh)
{
if (m_nofaces || !m_drawing_functor.draw_face(*lcc, dh)) return;
// We fill only closed faces.
Dart_const_handle cur=dh;
Dart_const_handle min=dh;
do
{
if (!lcc->is_next_exist(cur)) return; // open face=>not filled
if (cur<min) min=cur;
cur=lcc->next(cur);
}
while(cur!=dh);
if (m_random_face_color)
{
CGAL::Random random((unsigned int)(lcc->darts().index(dh)));
CGAL::Color c=get_random_color(random);
face_begin(c);
}
else if (m_drawing_functor.colored_face(*lcc, dh))
{
CGAL::Color c=m_drawing_functor.face_color(*lcc, dh);
face_begin(c);
}
else if (m_drawing_functor.colored_volume(*lcc, voldh))
{
CGAL::Color c=m_drawing_functor.volume_color(*lcc, voldh);
face_begin(c);
}
else
{ face_begin(); }
cur=dh;
do
{
add_point_in_face(lcc->point(cur), LCC_geom_utils<LCC, Local_kernel>::
get_vertex_normal(*lcc, cur));
cur=lcc->next(cur);
}
while(cur!=dh);
face_end();
}
void compute_edge(Dart_const_handle dh)
{
if (!m_drawing_functor.draw_edge(*lcc, dh)) return;
Point p1 = lcc->point(dh);
Dart_const_handle d2 = lcc->other_extremity(dh);
if (d2!=nullptr)
{
if (m_drawing_functor.colored_edge(*lcc, dh))
{ add_segment(p1, lcc->point(d2), m_drawing_functor.edge_color(*lcc, dh)); }
else
{ add_segment(p1, lcc->point(d2)); }
}
}
void compute_vertex(Dart_const_handle dh)
{
if (!m_drawing_functor.draw_vertex(*lcc, dh)) return;
if (m_drawing_functor.colored_vertex(*lcc, dh))
{ add_point(lcc->point(dh), m_drawing_functor.vertex_color(*lcc, dh)); }
else
{ add_point(lcc->point(dh)); }
}
void compute_elements()
{
clear();
if (lcc==nullptr) return;
typename LCC::size_type markvolumes = lcc->get_new_mark();
typename LCC::size_type markfaces = lcc->get_new_mark();
typename LCC::size_type markedges = lcc->get_new_mark();
typename LCC::size_type markvertices = lcc->get_new_mark();
for (typename LCC::Dart_range::const_iterator it=lcc->darts().begin(),
itend=lcc->darts().end(); it!=itend; ++it )
{
if (!lcc->is_marked(it, markvolumes) &&
m_drawing_functor.draw_volume(*lcc, it))
{
for (typename LCC::template Dart_of_cell_basic_range<3>::
const_iterator itv=lcc->template darts_of_cell_basic<3>(it, markvolumes).begin(),
itvend=lcc->template darts_of_cell_basic<3>(it, markvolumes).end();
itv!=itvend; ++itv)
{
lcc->mark(itv, markvolumes); // To be sure that all darts of the basic iterator will be marked
if (!lcc->is_marked(itv, markfaces) &&
lcc->is_marked(itv, m_oriented_mark) &&
m_drawing_functor.draw_face(*lcc, itv))
{
if (!m_drawing_functor.volume_wireframe(*lcc, itv) &&
!m_drawing_functor.face_wireframe(*lcc, itv))
{ compute_face(itv, it); }
for (typename LCC::template Dart_of_cell_basic_range<2>::
const_iterator itf=lcc->template darts_of_cell_basic<2>(itv, markfaces).begin(),
itfend=lcc->template darts_of_cell_basic<2>(itv, markfaces).end();
itf!=itfend; ++itf)
{
if (!m_drawing_functor.volume_wireframe(*lcc, itv) &&
!m_drawing_functor.face_wireframe(*lcc, itv))
{ lcc->mark(itf, markfaces); } // To be sure that all darts of the basic iterator will be marked
if ( !lcc->is_marked(itf, markedges) &&
m_drawing_functor.draw_edge(*lcc, itf))
{
compute_edge(itf);
for (typename LCC::template Dart_of_cell_basic_range<1>::
const_iterator ite=lcc->template darts_of_cell_basic<1>(itf, markedges).begin(),
iteend=lcc->template darts_of_cell_basic<1>(itf, markedges).end();
ite!=iteend; ++ite)
{
lcc->mark(ite, markedges); // To be sure that all darts of the basic iterator will be marked
if ( !lcc->is_marked(ite, markvertices) &&
m_drawing_functor.draw_vertex(*lcc, ite))
{
compute_vertex(ite);
CGAL::mark_cell<LCC, 0>(*lcc, ite, markvertices);
}
}
}
}
}
}
}
}
for (typename LCC::Dart_range::const_iterator it=lcc->darts().begin(),
itend=lcc->darts().end(); it!=itend; ++it )
{
lcc->unmark(it, markvertices);
lcc->unmark(it, markedges);
lcc->unmark(it, markfaces);
lcc->unmark(it, markvolumes);
}
lcc->free_mark(markvolumes);
lcc->free_mark(markfaces);
lcc->free_mark(markedges);
lcc->free_mark(markvertices);
}
virtual void init()
{
Base::init();
setKeyDescription(::Qt::Key_R, "Toggles random face colors");
}
virtual void keyPressEvent(QKeyEvent *e)
{
const ::Qt::KeyboardModifiers modifiers = e->modifiers();
if ((e->key()==::Qt::Key_R) && (modifiers==::Qt::NoButton))
{
m_random_face_color=!m_random_face_color;
displayMessage(QString("Random face color=%1.").arg(m_random_face_color?"true":"false"));
compute_elements();
redraw();
}
else
{ Base::keyPressEvent(e); } // Call the base method to process others/classicals key
// Call: * compute_elements() if the model changed, followed by
// * redraw() if some viewing parameters changed that implies some
// modifications of the buffers
// (eg. type of normal, color/mono)
// * update() just to update the drawing
}
protected:
const LCC* lcc;
typename LCC::size_type m_oriented_mark;
bool m_nofaces;
bool m_random_face_color;
const DrawingFunctorLCC& m_drawing_functor;
};
// Specialization of draw function.
#define CGAL_LCC_TYPE CGAL::Linear_cell_complex_base \
<d_, ambient_dim, Traits_, Items_, Alloc_, Map, Refs, Storage_>
template < unsigned int d_, unsigned int ambient_dim,
class Traits_,
class Items_,
class Alloc_,
template<unsigned int,class,class,class,class>
class Map,
class Refs,
class Storage_,
class DrawingFunctorLCC=DefaultDrawingFunctorLCC>
void draw(const CGAL_LCC_TYPE& alcc,
const char* title="LCC for CMap Basic Viewer",
bool nofill=false,
const DrawingFunctorLCC& drawing_functor=DrawingFunctorLCC())
{
#if defined(CGAL_TEST_SUITE)
bool cgal_test_suite=true;
#else
bool cgal_test_suite=qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
#endif
if (!cgal_test_suite)
{
int argc=1;
const char* argv[2]={"lccviewer","\0"};
QApplication app(argc,const_cast<char**>(argv));
SimpleLCCViewerQt<CGAL_LCC_TYPE, DrawingFunctorLCC>
mainwindow(app.activeWindow(), &alcc, title, nofill, drawing_functor);
mainwindow.show();
app.exec();
}
}
// Todo a function taking a const DrawingFunctorLCC& drawing_functor as parameter
#undef CGAL_LCC_TYPE
} // End namespace CGAL
#endif // CGAL_USE_BASIC_VIEWER
#endif // CGAL_DRAW_LCC_H