mirror of https://github.com/CGAL/cgal
610 lines
20 KiB
C++
610 lines
20 KiB
C++
// Copyright (c) 2012
|
|
// Utrecht University (The Netherlands),
|
|
// ETH Zurich (Switzerland),
|
|
// INRIA Sophia-Antipolis (France),
|
|
// Max-Planck-Institute Saarbruecken (Germany),
|
|
// and Tel-Aviv University (Israel). All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org)
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
|
//
|
|
//
|
|
// Author(s): Efi Fogel <efifogel@gmail.com>
|
|
|
|
#ifndef CGAL_DRAW_ARRANGEMENT_2_H
|
|
#define CGAL_DRAW_ARRANGEMENT_2_H
|
|
|
|
#include <CGAL/config.h>
|
|
|
|
#include <unordered_map>
|
|
#include <cstdlib>
|
|
#include <random>
|
|
|
|
#include <CGAL/Qt/Basic_viewer_qt.h>
|
|
|
|
#ifdef CGAL_USE_BASIC_VIEWER
|
|
|
|
#include <type_traits>
|
|
#include <CGAL/Qt/init_ogl_context.h>
|
|
#include <CGAL/Arrangement_2.h>
|
|
|
|
namespace CGAL {
|
|
|
|
struct Default_color_generator {
|
|
/*! Obtain color
|
|
*/
|
|
template <typename HalfedgeHandle>
|
|
CGAL::IO::Color operator()(HalfedgeHandle /* h */) {
|
|
static std::random_device rd;
|
|
static std::mt19937 rng(rd());
|
|
static std::uniform_int_distribution<int> uni(0, 255);
|
|
return CGAL::IO::Color(uni(rng), uni(rng), uni(rng));
|
|
}
|
|
};
|
|
|
|
// Viewer class for`< Polygon_2
|
|
template <typename Arrangement_2_,
|
|
typename ColorGenerator = Default_color_generator>
|
|
class Arr_2_basic_viewer_qt : public Basic_viewer_qt {
|
|
using Arr = Arrangement_2_;
|
|
using Color_generator = ColorGenerator;
|
|
using Base = Basic_viewer_qt;
|
|
using Gt = typename Arr::Geometry_traits_2;
|
|
using Point = typename Arr::Point_2;
|
|
using X_monotone_curve = typename Arr::X_monotone_curve_2;
|
|
using Vertex_const_handle = typename Arr::Vertex_const_handle;
|
|
using Halfedge_const_handle = typename Arr::Halfedge_const_handle;
|
|
using Face_const_handle = typename Arr::Face_const_handle;
|
|
using Ccb_halfedge_const_circulator =
|
|
typename Arr::Ccb_halfedge_const_circulator;
|
|
|
|
public:
|
|
/// Construct the viewer.
|
|
/// @param arr the arrangement to view
|
|
/// @param title the title of the window
|
|
Arr_2_basic_viewer_qt(QWidget* parent, const Arr& arr,
|
|
Color_generator color_generator,
|
|
const char* title = "2D Arrangement Basic Viewer",
|
|
bool draw_vertices = false) :
|
|
// First draw: vertices; edges, faces; multi-color; no inverse normal
|
|
Base(parent, title, draw_vertices, true, true, false, false),
|
|
m_arr(arr),
|
|
m_color_generator(color_generator)
|
|
{
|
|
// mimic the computation of Camera::pixelGLRatio()
|
|
auto bbox = bounding_box();
|
|
CGAL::qglviewer::Vec minv(bbox.xmin(), bbox.ymin(), 0);
|
|
CGAL::qglviewer::Vec maxv(bbox.xmax(), bbox.ymax(), 0);
|
|
auto diameter = (maxv - minv).norm();
|
|
m_pixel_ratio = diameter / m_height;
|
|
}
|
|
|
|
/*! Intercept the resizing of the window.
|
|
*/
|
|
virtual void resizeGL(int width, int height) {
|
|
CGAL::QGLViewer::resizeGL(width, height);
|
|
m_width = width;
|
|
m_height = height;
|
|
CGAL::qglviewer::Vec p;
|
|
auto ratio = camera()->pixelGLRatio(p);
|
|
if (ratio != m_pixel_ratio) {
|
|
m_pixel_ratio = ratio;
|
|
add_elements();
|
|
}
|
|
}
|
|
|
|
/*! Compute an approximation of the bounding box of a point.
|
|
* \param[in] p the (exact) point.
|
|
* Call this member function only if the geometry traits is equipped with
|
|
* the coordinate-approximation functionality of a point coordinate.
|
|
* This function must be inlined (e.g., a template) to enable the
|
|
* compiled-time dispatching in the function `bounding_box()`.
|
|
*/
|
|
template <typename Point, typename Approximate>
|
|
CGAL::Bbox_2 approximate_bbox(const Point& p, const Approximate& approx) {
|
|
auto x = approx(p, 0);
|
|
auto y = approx(p, 1);
|
|
return CGAL::Bbox_2(x, y, x, y);
|
|
}
|
|
|
|
/*! Obtain the bounding box of a point.
|
|
* \param[in] p the point.
|
|
* We assume that if the coordinate-approximation functionality is not
|
|
* supported, the point supports the member function `bbox()`.
|
|
* This function must be inlined (e.g., a template) to enable the
|
|
* compiled-time dispatching in the function `bounding_box()`.
|
|
*/
|
|
template <typename Point>
|
|
CGAL::Bbox_2 exact_bbox(const Point& p) { return p.bbox(); }
|
|
|
|
/*! Compile time dispatching
|
|
*/
|
|
#if 0
|
|
template <typename T>
|
|
void bounding_box_impl2(CGAL::Bbox_2& bbox, const Point& p, T const&, long)
|
|
{ bbox += exact_bbox(p); }
|
|
|
|
template <typename T>
|
|
auto bounding_box_impl2(CGAL::Bbox_2& bbox, const Point& p, T const& approx,
|
|
int) -> decltype(approx.operator()(p), void())
|
|
{ bbox += approximate_bbox(p, approx); }
|
|
|
|
template <typename T>
|
|
void bounding_box_impl1(CGAL::Bbox_2& bbox, const Point& p, T const&, long)
|
|
{ bbox += exact_bbox(p); }
|
|
|
|
template <typename T>
|
|
auto bounding_box_impl1(CGAL::Bbox_2& bbox, const Point& p, T const& traits,
|
|
int) ->
|
|
decltype(traits.approximate_2_object(), void()) {
|
|
using Approximate = typename Gt::Approximate_2;
|
|
bounding_box_impl2<Approximate>(bbox, p, traits.approximate_2_object(), 0);
|
|
}
|
|
#else
|
|
template <typename T>
|
|
void bounding_box_impl1(CGAL::Bbox_2& bbox, const Point& p, T const& traits,
|
|
int)
|
|
{ bbox += approximate_bbox(p, traits.approximate_2_object()); }
|
|
#endif
|
|
|
|
/*! Compute the bounding box.
|
|
*/
|
|
CGAL::Bbox_2 bounding_box() {
|
|
CGAL::Bbox_2 bbox;
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
// At this point we assume that the arrangement is not open, and thus the
|
|
// bounding box is defined by the vertices.
|
|
for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it)
|
|
bounding_box_impl1(bbox, it->point(), *traits, 0);
|
|
return bbox;
|
|
}
|
|
|
|
/*! Add all elements to be drawn.
|
|
*/
|
|
void add_elements() {
|
|
// std::cout << "ratio: " << this->pixel_ratio() << std::endl;
|
|
clear();
|
|
m_visited.clear();
|
|
|
|
if (m_arr.is_empty()) return;
|
|
for (auto it = m_arr.unbounded_faces_begin();
|
|
it != m_arr.unbounded_faces_end(); ++it)
|
|
add_face(it);
|
|
|
|
// Add edges that do not separe faces.
|
|
for (auto it = m_arr.edges_begin(); it != m_arr.edges_end(); ++it)
|
|
if (it->face() == it->twin()->face()) draw_curve(it->curve());
|
|
|
|
// Add all points
|
|
for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it)
|
|
draw_point(it->point());
|
|
|
|
m_visited.clear();
|
|
}
|
|
|
|
/*/ Obtain the pixel ratio
|
|
*/
|
|
double pixel_ratio() const { return m_pixel_ratio; }
|
|
|
|
protected:
|
|
/*! Find the halfedge incident to the lexicographically smallest vertex
|
|
* along the CCB, such that there is no other halfedge underneath.
|
|
*/
|
|
Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ) {
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
auto cmp_xy = traits->compare_xy_2_object();
|
|
auto cmp_y = traits->compare_y_at_x_right_2_object();
|
|
|
|
// Find the first halfedge directed from left to right
|
|
auto curr = circ;
|
|
do if (curr->direction() == CGAL::ARR_LEFT_TO_RIGHT) break;
|
|
while (++curr != circ);
|
|
Halfedge_const_handle ext = curr;
|
|
|
|
// Find the halfedge incident to the lexicographically smallest vertex,
|
|
// such that there is no other halfedge underneath.
|
|
do {
|
|
// Discard edges not directed from left to right:
|
|
if (curr->direction() != CGAL::ARR_LEFT_TO_RIGHT) continue;
|
|
|
|
|
|
auto res = cmp_xy(curr->source()->point(), ext->source()->point());
|
|
|
|
// Discard the edges inciden to a point strictly larger than the point
|
|
// incident to the stored extreme halfedge:
|
|
if (res == LARGER) continue;
|
|
|
|
// Store the edge inciden to a point strictly smaller:
|
|
if (res == SMALLER) {
|
|
ext = curr;
|
|
continue;
|
|
}
|
|
|
|
// The incident points are equal; compare the halfedges themselves:
|
|
if (cmp_y(curr->curve(), ext->curve(), curr->source()->point()) ==
|
|
SMALLER)
|
|
ext = curr;
|
|
} while (++curr != circ);
|
|
|
|
return ext;
|
|
}
|
|
|
|
/*! Draw a region using aproximate coordinates.
|
|
* Call this member function only if the geometry traits is equipped with
|
|
* the coordinate-approximation functionality of a curve.
|
|
* This function must be inlined (e.g., a template) to enable the
|
|
* compiled-time dispatching in the function `draw_region()`.
|
|
*/
|
|
template <typename Approximate>
|
|
void draw_approximate_region(Halfedge_const_handle curr,
|
|
const Approximate& approx) {
|
|
std::vector<typename Gt::Approximate_point_2> polyline;
|
|
double error(this->pixel_ratio());
|
|
bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT;
|
|
approx(curr->curve(), error, std::back_inserter(polyline), l2r);
|
|
if (polyline.empty()) return;
|
|
auto it = polyline.begin();
|
|
auto prev = it++;
|
|
for (; it != polyline.end(); prev = it++) {
|
|
this->add_segment(*prev, *it);
|
|
this->add_point_in_face(*prev);
|
|
}
|
|
}
|
|
|
|
/*! Draw an exact curve.
|
|
*/
|
|
template <typename XMonotoneCurve>
|
|
void draw_exact_curve(const XMonotoneCurve& curve) {
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
auto ctr_min = traits->construct_min_vertex_2_object();
|
|
auto ctr_max = traits->construct_max_vertex_2_object();
|
|
this->add_segment(ctr_min(curve), ctr_max(curve));
|
|
}
|
|
|
|
/*! Draw an exact region.
|
|
*/
|
|
void draw_exact_region(Halfedge_const_handle curr) {
|
|
this->add_point_in_face(curr->source()->point());
|
|
draw_exact_curve(curr->curve());
|
|
}
|
|
|
|
/*! Compile time dispatching
|
|
*/
|
|
#if 0
|
|
template <typename T, typename I = void>
|
|
void draw_region_impl2(Halfedge_const_handle curr, T const&, long)
|
|
{ draw_exact_region(curr); }
|
|
|
|
template <typename T, typename I>
|
|
auto draw_region_impl2(Halfedge_const_handle curr, T const& approx, int) ->
|
|
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
|
|
bool{}), void())
|
|
{ draw_approximate_region(curr, approx); }
|
|
|
|
template <typename T>
|
|
void draw_region_impl1(Halfedge_const_handle curr, T const&, long)
|
|
{ draw_exact_region(curr); }
|
|
|
|
template <typename T>
|
|
auto draw_region_impl1(Halfedge_const_handle curr, T const& traits, int) ->
|
|
decltype(traits.approximate_2_object(), void()) {
|
|
using Approximate = typename Gt::Approximate_2;
|
|
draw_region_impl2<Approximate, int>(curr, traits.approximate_2_object(), 0);
|
|
}
|
|
#else
|
|
template <typename T>
|
|
void draw_region_impl1(Halfedge_const_handle curr, T const& traits, int)
|
|
{ draw_approximate_region(curr, traits.approximate_2_object()); }
|
|
#endif
|
|
|
|
/*! Draw a region.
|
|
*/
|
|
void draw_region(Ccb_halfedge_const_circulator circ) {
|
|
/* Check whether the traits has a member function called
|
|
* approximate_2_object() and if so check whether the return type, namely
|
|
* `Approximate_2` has an appropriate operator.
|
|
*
|
|
* C++20 supports concepts and `requires` expression; see, e.g.,
|
|
* https://en.cppreference.com/w/cpp/language/constraints; thus, the first
|
|
* condition above can be elegantly verified as follows:
|
|
* constexpr bool has_approximate_2_object =
|
|
* requires(const Gt& traits) { traits.approximate_2_object(); };
|
|
*
|
|
* C++17 has experimental constructs called is_detected and
|
|
* is_detected_v that can be used to achieve the same goal.
|
|
*
|
|
* For now we use C++14 features.
|
|
*/
|
|
auto color = m_color_generator(circ->face());
|
|
this->face_begin(color);
|
|
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
auto ext = find_smallest(circ);
|
|
auto curr = ext;
|
|
|
|
do {
|
|
// Skip halfedges that are "antenas":
|
|
while (curr->face() == curr->twin()->face()) curr = curr->twin()->next();
|
|
draw_region_impl1(curr, *traits, 0);
|
|
curr = curr->next();
|
|
} while (curr != ext);
|
|
|
|
this->face_end();
|
|
}
|
|
|
|
/*! Draw a curve using aproximate coordinates.
|
|
* Call this member function only of the geometry traits is equipped with
|
|
* the coordinate-aproximation functionality of a curve.
|
|
* This function must be inlined (e.g., a template) to enable the
|
|
* compiled-time dispatching in the function `draw_curve()`.
|
|
*/
|
|
template <typename XMonotoneCurve, typename Approximate>
|
|
void draw_approximate_curve(const XMonotoneCurve& curve,
|
|
const Approximate& approx) {
|
|
std::vector<typename Gt::Approximate_point_2> polyline;
|
|
double error(this->pixel_ratio());
|
|
approx(curve, error, std::back_inserter(polyline));
|
|
if (polyline.empty()) return;
|
|
auto it = polyline.begin();
|
|
auto prev = it++;
|
|
for (; it != polyline.end(); prev = it++) this->add_segment(*prev, *it);
|
|
}
|
|
|
|
/*! Compile time dispatching
|
|
*/
|
|
#if 0
|
|
template <typename T, typename I = void>
|
|
void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long)
|
|
{ draw_exact_curve(xcv); }
|
|
|
|
template <typename T, typename I>
|
|
auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) ->
|
|
decltype(approx.template operator()<I>(X_monotone_curve{}, double{}, I{},
|
|
bool{}), void())
|
|
{ draw_approximate_curve(xcv, approx); }
|
|
|
|
template <typename T>
|
|
void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long)
|
|
{ draw_exact_curve(xcv); }
|
|
|
|
template <typename T>
|
|
auto draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int) ->
|
|
decltype(traits.approximate_2_object(), void()) {
|
|
using Approximate = typename Gt::Approximate_2;
|
|
draw_curve_impl2<Approximate, int>(xcv, traits.approximate_2_object(), 0);
|
|
}
|
|
#else
|
|
template <typename T>
|
|
void draw_curve_impl1(const X_monotone_curve& xcv, T const& traits, int)
|
|
{ draw_approximate_curve(xcv, traits.approximate_2_object()); }
|
|
#endif
|
|
|
|
/*! Draw a curve.
|
|
*/
|
|
template <typename XMonotoneCurve>
|
|
void draw_curve(const XMonotoneCurve& curve) {
|
|
/* Check whether the traits has a member function called
|
|
* approximate_2_object() and if so check whether the return type, namely
|
|
* `Approximate_2` has an appropriate operator.
|
|
*
|
|
* C++20 supports concepts and `requires` expression; see, e.g.,
|
|
* https://en.cppreference.com/w/cpp/language/constraints; thus, the first
|
|
* condition above can be elegantly verified as follows:
|
|
* constexpr bool has_approximate_2_object =
|
|
* requires(const Gt& traits) { traits.approximate_2_object(); };
|
|
*
|
|
* C++17 has experimental constructs called is_detected and
|
|
* is_detected_v that can be used to achieve the same goal.
|
|
*
|
|
* For now we use C++14 features.
|
|
*/
|
|
#if 0
|
|
if constexpr (std::experimental::is_detected_v<approximate_2_object_t, Gt>)
|
|
{
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
auto approx = traits->approximate_2_object();
|
|
draw_approximate_curve(curve, approx);
|
|
return;
|
|
}
|
|
draw_exact_curve(curve);
|
|
#else
|
|
const auto* traits = this->m_arr.geometry_traits();
|
|
draw_curve_impl1(curve, *traits, 0);
|
|
#endif
|
|
}
|
|
|
|
/*! Compile time dispatching
|
|
*/
|
|
#if 0
|
|
template <typename T>
|
|
void draw_point_impl2(const Point& p, T const&, long) { add_point(p); }
|
|
|
|
template <typename T>
|
|
auto draw_point_impl2(const Point& p, T const& approx, int) ->
|
|
decltype(approx.operator()(p), void())
|
|
{ add_point(approx(p)); }
|
|
|
|
template <typename T>
|
|
void draw_point_impl1(const Point& p, T const&, long) { add_point(p); }
|
|
|
|
template <typename T>
|
|
auto draw_point_impl1(const Point& p, T const& traits, int) ->
|
|
decltype(traits.approximate_2_object(), void()) {
|
|
using Approximate = typename Gt::Approximate_2;
|
|
draw_point_impl2<Approximate>(p, traits.approximate_2_object(), true);
|
|
}
|
|
#else
|
|
template <typename T>
|
|
void draw_point_impl1(const Point& p, T const& traits, int)
|
|
{ add_point(traits.approximate_2_object()(p)); }
|
|
#endif
|
|
|
|
/*! Draw a point.
|
|
*/
|
|
void draw_point(const Point& p) {
|
|
const auto* traits = m_arr.geometry_traits();
|
|
draw_point_impl1(p, *traits, 0);
|
|
}
|
|
|
|
/*! Add a Connected Component of the Boundary.
|
|
*/
|
|
void add_ccb(Ccb_halfedge_const_circulator circ) {
|
|
auto curr = circ;
|
|
do {
|
|
auto new_face = curr->twin()->face();
|
|
if (m_visited.find(new_face) != m_visited.end()) continue;
|
|
m_visited[new_face] = true;
|
|
add_face(new_face);
|
|
} while (++curr != circ);
|
|
}
|
|
|
|
/*! Add a face.
|
|
*/
|
|
void add_face(Face_const_handle face) {
|
|
using Inner_ccb_const_iterator = typename Arr::Inner_ccb_const_iterator;
|
|
using Outer_ccb_const_iterator = typename Arr::Outer_ccb_const_iterator;
|
|
|
|
for (Inner_ccb_const_iterator it = face->inner_ccbs_begin();
|
|
it != face->inner_ccbs_end(); ++it)
|
|
add_ccb(*it);
|
|
|
|
for (Outer_ccb_const_iterator it = face->outer_ccbs_begin();
|
|
it != face->outer_ccbs_end(); ++it) {
|
|
add_ccb(*it);
|
|
draw_region(*it);
|
|
}
|
|
}
|
|
|
|
//!
|
|
virtual void keyPressEvent(QKeyEvent* e) {
|
|
// Test key pressed:
|
|
// const ::Qt::KeyboardModifiers modifiers = e->modifiers();
|
|
// if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... }
|
|
|
|
// Call: * add_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
|
|
|
|
// Call the base method to process others/classicals key
|
|
Base::keyPressEvent(e);
|
|
}
|
|
|
|
protected:
|
|
//! The window width in pixels.
|
|
int m_width = CGAL_BASIC_VIEWER_INIT_SIZE_X;
|
|
|
|
//! The window height in pixels.
|
|
int m_height = CGAL_BASIC_VIEWER_INIT_SIZE_Y;
|
|
|
|
//! The ratio between pixel and opengl units (in world coordinate system).
|
|
double m_pixel_ratio = 1;
|
|
|
|
//! The arrangement to draw.
|
|
const Arr& m_arr;
|
|
|
|
//! The color generator.
|
|
Color_generator m_color_generator;
|
|
|
|
std::unordered_map<Face_const_handle, bool> m_visited;
|
|
};
|
|
|
|
//! Basic viewer of a 2D arrangement.
|
|
template <typename Arrangement_2_,
|
|
typename ColorGenerator = Default_color_generator>
|
|
class Arr_2_viewer_qt : public Arr_2_basic_viewer_qt<Arrangement_2_,
|
|
ColorGenerator> {
|
|
public:
|
|
using Arr = Arrangement_2_;
|
|
using Color_generator = ColorGenerator;
|
|
using Base = Arr_2_basic_viewer_qt<Arr, Color_generator>;
|
|
using Point = typename Arr::Point_2;
|
|
using X_monotone_curve = typename Arr::X_monotone_curve_2;
|
|
using Halfedge_const_handle = typename Arr::Halfedge_const_handle;
|
|
using Face_const_handle = typename Arr::Face_const_handle;
|
|
using Ccb_halfedge_const_circulator =
|
|
typename Arr::Ccb_halfedge_const_circulator;
|
|
|
|
/// Construct the viewer.
|
|
/// @param arr the arrangement to view
|
|
/// @param title the title of the window
|
|
Arr_2_viewer_qt(QWidget* parent, const Arr& arr,
|
|
Color_generator color_generator,
|
|
const char* title = "2D Arrangement Basic Viewer",
|
|
bool draw_vertices = false) :
|
|
Base(parent, arr, color_generator, title, draw_vertices)
|
|
{}
|
|
};
|
|
|
|
/*! Draw an arrangement.
|
|
*/
|
|
template <typename GeometryTraits_2, typename Dcel>
|
|
void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
|
|
const char* title = "2D Arrangement Basic Viewer",
|
|
bool draw_vertices = false) {
|
|
#if defined(CGAL_TEST_SUITE)
|
|
bool cgal_test_suite=true;
|
|
#else
|
|
bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
|
|
#endif
|
|
|
|
if (cgal_test_suite) return;
|
|
using Gt = GeometryTraits_2;
|
|
using Arr = CGAL::Arrangement_2<Gt, Dcel>;
|
|
using Viewer = Arr_2_viewer_qt<Arr, Default_color_generator>;
|
|
|
|
CGAL::Qt::init_ogl_context(4,3);
|
|
|
|
int argc = 1;
|
|
const char* argv[2] = {"t2_viewer", nullptr};
|
|
QApplication app(argc, const_cast<char**>(argv));
|
|
Default_color_generator color_generator;
|
|
Viewer mainwindow(app.activeWindow(), arr, color_generator, title,
|
|
draw_vertices);
|
|
mainwindow.add_elements();
|
|
mainwindow.show();
|
|
app.exec();
|
|
}
|
|
|
|
/*! Draw an arrangement using a given color generator.
|
|
*/
|
|
template <typename GeometryTraits_2, typename Dcel,
|
|
typename ColorGenerator>
|
|
void draw(const Arrangement_2<GeometryTraits_2, Dcel>& arr,
|
|
ColorGenerator color_generator,
|
|
const char* title = "2D Arrangement Basic Viewer",
|
|
bool draw_vertices = false) {
|
|
#if defined(CGAL_TEST_SUITE)
|
|
bool cgal_test_suite=true;
|
|
#else
|
|
bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE");
|
|
#endif
|
|
|
|
if (cgal_test_suite) return;
|
|
|
|
using Color_generator = ColorGenerator;
|
|
using Gt = GeometryTraits_2;
|
|
using Arr = CGAL::Arrangement_2<Gt, Dcel>;
|
|
using Viewer = Arr_2_viewer_qt<Arr, Color_generator>;
|
|
|
|
CGAL::Qt::init_ogl_context(4,3);
|
|
|
|
int argc = 1;
|
|
const char* argv[2] = {"t2_viewer", nullptr};
|
|
QApplication app(argc, const_cast<char**>(argv));
|
|
Viewer mainwindow(app.activeWindow(), arr, color_generator, title,
|
|
draw_vertices);
|
|
mainwindow.add_elements();
|
|
mainwindow.show();
|
|
app.exec();
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
#endif
|