mirror of https://github.com/CGAL/cgal
fix drawing degenerate paths
This commit is contained in:
parent
3f90d36604
commit
cd1951be26
|
|
@ -12,39 +12,44 @@
|
|||
|
||||
#include "ArrangementDemoGraphicsView.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFontMetrics>
|
||||
#include <QKeyEvent>
|
||||
#include <QPen>
|
||||
#include <QVarLengthArray>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <QVarLengthArray>
|
||||
#include <QPen>
|
||||
#include <QCoreApplication>
|
||||
#include <QKeyEvent>
|
||||
#include <QFontMetrics>
|
||||
|
||||
//! Member function to setup the viewport of the screen
|
||||
/*!
|
||||
\param parent a Qwidget pointer to the class
|
||||
*/
|
||||
ArrangementDemoGraphicsView::ArrangementDemoGraphicsView(QWidget* parent)
|
||||
: QGraphicsView(parent)
|
||||
, maxScale(500000)
|
||||
, minScale(0.0002) {
|
||||
ArrangementDemoGraphicsView::ArrangementDemoGraphicsView( QWidget* parent ) :
|
||||
QGraphicsView( parent ),
|
||||
maxScale( 500000 ),
|
||||
minScale( 0.0002 )
|
||||
{
|
||||
this->resetTransform();
|
||||
this->setResizeAnchor(QGraphicsView::AnchorUnderMouse);
|
||||
this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||
this->setMouseTracking(true);
|
||||
this->setMouseTracking( true );
|
||||
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
// TODO: Make options menu work
|
||||
this->setRenderHint(QPainter::Antialiasing);
|
||||
}
|
||||
|
||||
void ArrangementDemoGraphicsView::paintEvent(QPaintEvent* event) {
|
||||
void ArrangementDemoGraphicsView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
qreal scale = std::sqrt(std::abs(this->transform().determinant()));
|
||||
if(scale > this->maxScale)
|
||||
if (scale > this->maxScale)
|
||||
this->scale(this->maxScale / scale, this->maxScale / scale);
|
||||
else if(scale < this->minScale)
|
||||
else if (scale < this->minScale)
|
||||
this->scale(this->minScale / scale, this->minScale / scale);
|
||||
QGraphicsView::paintEvent(event);
|
||||
}
|
||||
|
||||
void ArrangementDemoGraphicsView::resetTransform() { this->setTransform({1.0, 0.0, 0.0, -1.0, 0.0, 0.0}); }
|
||||
void ArrangementDemoGraphicsView::resetTransform()
|
||||
{
|
||||
this->setTransform({1.0, 0.0, 0.0, -1.0, 0.0, 0.0});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,16 +84,19 @@ public:
|
|||
Vertex_cache_range vertex_cache() const {
|
||||
return boost::make_iterator_range(vertex_cache_begin(), vertex_cache_end());
|
||||
}
|
||||
std::size_t vertex_cache_size() const { return m_vertex_cache.size(); }
|
||||
|
||||
Halfedge_cache_const_iterator halfedge_cache_begin() const { return m_halfedge_cache.begin(); }
|
||||
Halfedge_cache_const_iterator halfedge_cache_end() const { return m_halfedge_cache.end(); }
|
||||
Halfedge_cache_range halfedge_cache() const {
|
||||
return boost::make_iterator_range(halfedge_cache_begin(), halfedge_cache_end());
|
||||
}
|
||||
std::size_t halfedge_cache_size() const { return m_halfedge_cache.size(); }
|
||||
|
||||
Face_cache_const_iterator face_cache_begin() const { return m_face_cache.begin(); }
|
||||
Face_cache_const_iterator face_cache_end() const { return m_face_cache.end(); }
|
||||
Face_cache_range face_cache() const { return boost::make_iterator_range(face_cache_begin(), face_cache_end()); }
|
||||
std::size_t face_cache_size() const { return m_face_cache.size(); }
|
||||
|
||||
private:
|
||||
Vertex_cache m_vertex_cache;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "CGAL/Arr_enums.h"
|
||||
#include "CGAL/Draw_aos/Arr_bounded_approximate_point_2.h"
|
||||
#include "CGAL/Draw_aos/Arr_bounded_compute_y_at_x.h"
|
||||
#include "CGAL/Draw_aos/Arr_compute_y_at_x.h"
|
||||
#include "CGAL/Draw_aos/Arr_construct_curve_end.h"
|
||||
#include "CGAL/Draw_aos/Arr_construct_segments.h"
|
||||
#include "CGAL/Draw_aos/Arr_render_context.h"
|
||||
|
|
@ -48,13 +48,13 @@ class Arr_bounded_approximate_curve_2
|
|||
Execution_context(const Arr_bounded_render_context& ctx,
|
||||
const X_monotone_curve_2& curve,
|
||||
const Arr_bounded_approximate_point_2& approx_pt,
|
||||
const Arr_bounded_compute_y_at_x& compute_y_at_x,
|
||||
const Arr_compute_y_at_x& compute_y_at_x,
|
||||
const Intersections_vector& top_inters,
|
||||
const Intersections_vector& bottom_inters,
|
||||
Polyline_geom& polyline)
|
||||
: Arr_context_delegator(ctx)
|
||||
, curve(curve)
|
||||
, bounded_compute_y_at_x(compute_y_at_x)
|
||||
, compute_y_at_x(compute_y_at_x)
|
||||
, bounded_approx_pt(approx_pt)
|
||||
, top_inters(top_inters)
|
||||
, bottom_inters(bottom_inters)
|
||||
|
|
@ -72,7 +72,7 @@ class Arr_bounded_approximate_curve_2
|
|||
bool is_bounded_curve() const { return is_min_end_bounded() && is_max_end_bounded(); }
|
||||
|
||||
const X_monotone_curve_2& curve;
|
||||
const Arr_bounded_compute_y_at_x& bounded_compute_y_at_x;
|
||||
const Arr_compute_y_at_x& compute_y_at_x;
|
||||
const Arr_bounded_approximate_point_2& bounded_approx_pt;
|
||||
const Intersections_vector &top_inters, bottom_inters;
|
||||
const std::optional<Point_2> min_end, max_end;
|
||||
|
|
@ -132,7 +132,7 @@ private:
|
|||
*/
|
||||
static void approximate_simple_curve_segment(Execution_context& ctx, const FT& start, const FT& end, double step) {
|
||||
for(FT x = start + step; x < end; x += step) {
|
||||
auto y = ctx.bounded_compute_y_at_x(ctx.curve, x);
|
||||
auto y = ctx.compute_y_at_x(ctx.curve, x);
|
||||
if(!y.has_value()) {
|
||||
// break as soon as there's no more intersections
|
||||
break;
|
||||
|
|
@ -143,14 +143,14 @@ private:
|
|||
}
|
||||
*ctx.out_it++ = ctx->approx_pt(Point_2(x, y.value()));
|
||||
if(y > ctx->ymax() || y < ctx->ymin()) {
|
||||
// We are outside the bbox. The dummy point is inserted to indicate the curve is outside the bbox.
|
||||
// We are outside the bbox. The dummy point was already inserted to indicate that.
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void approximate_vertical_curve(Execution_context& ctx) {
|
||||
if(ctx.is_bounded_curve() && ctx.min_end->x() < ctx->xmin() && ctx.min_end->x() > ctx->xmax()) {
|
||||
if(ctx.is_bounded_curve() && (ctx.min_end->x() < ctx->xmin() || ctx.min_end->x() > ctx->xmax())) {
|
||||
// The curve is outside the bbox in x direction, no need to approximate
|
||||
return;
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ private:
|
|||
public:
|
||||
Arr_bounded_approximate_curve_2(const Arr_bounded_render_context& ctx,
|
||||
const Arr_bounded_approximate_point_2& point_approx)
|
||||
: m_bounded_compute_y_at_x(ctx)
|
||||
: m_compute_y_at_x(ctx)
|
||||
, m_approx_pt(point_approx)
|
||||
, m_ctx(ctx)
|
||||
, m_top(ctx.cst_horizontal_segment(ctx.ymax(), ctx.xmin(), ctx.xmax()))
|
||||
|
|
@ -210,7 +210,7 @@ public:
|
|||
|
||||
auto top_inters = compute_intersections(curve, m_top, m_ctx.intersect_2, m_ctx.cst_curve_end);
|
||||
auto bottom_inters = compute_intersections(curve, m_bottom, m_ctx.intersect_2, m_ctx.cst_curve_end);
|
||||
Execution_context ctx(m_ctx, curve, m_approx_pt, m_bounded_compute_y_at_x, top_inters, bottom_inters, polyline);
|
||||
Execution_context ctx(m_ctx, curve, m_approx_pt, m_compute_y_at_x, top_inters, bottom_inters, polyline);
|
||||
|
||||
if(ctx->is_vertical_2(curve)) {
|
||||
approximate_vertical_curve(ctx);
|
||||
|
|
@ -224,7 +224,7 @@ public:
|
|||
FT last_x;
|
||||
std::optional<Point_2> first_inter = first_intersection(ctx);
|
||||
|
||||
if(auto y_at_txmin = ctx.bounded_compute_y_at_x(curve, txmin);
|
||||
if(auto y_at_txmin = ctx.compute_y_at_x(curve, txmin);
|
||||
y_at_txmin.has_value() && y_at_txmin != ctx->ymin() && y_at_txmin != ctx->ymax())
|
||||
{
|
||||
// The tight starting point of the curve is within the bbox and
|
||||
|
|
@ -237,16 +237,7 @@ public:
|
|||
} else if(first_inter.has_value()) {
|
||||
last_x = first_inter->x();
|
||||
} else {
|
||||
// We assert that the curve is outbound.
|
||||
// If the min end is bounded, it's obvious.
|
||||
//
|
||||
// If the min end is unbounded, we know that the curve has no intersections with top, bottom or left edge(txmin ==
|
||||
// xmin when the min end is unbounded) and the min end of the curve is outbound (it approaches infinity in one or
|
||||
// both dimension).
|
||||
// Assume that the curve does has one point within the bbox. Note that it's a contiguous
|
||||
// x-monotone curve. So it must cross the top, bottom or left edge to reach the min end from right to left,
|
||||
// which is a contradiction.
|
||||
return polyline;
|
||||
return polyline; // The curve is entirely outside the bbox in x direction.
|
||||
}
|
||||
|
||||
// iterate through the intersections and insert segments in-between.
|
||||
|
|
@ -258,7 +249,7 @@ public:
|
|||
}),
|
||||
[&ctx](const Point_2& pt1, const Point_2& pt2) { return ctx->compare_xy_2(pt1, pt2) == CGAL::SMALLER; });
|
||||
|
||||
if(auto y_at_txmax = ctx.bounded_compute_y_at_x(curve, txmax);
|
||||
if(auto y_at_txmax = ctx.compute_y_at_x(curve, txmax);
|
||||
y_at_txmax.has_value() && y_at_txmax != ctx->ymin() && y_at_txmax != ctx->ymax())
|
||||
{
|
||||
approximate_simple_curve_segment(ctx, last_x, txmax, ctx->approx_error);
|
||||
|
|
@ -272,7 +263,7 @@ public:
|
|||
private:
|
||||
const Arr_bounded_render_context& m_ctx;
|
||||
const Arr_bounded_approximate_point_2& m_approx_pt;
|
||||
const Arr_bounded_compute_y_at_x m_bounded_compute_y_at_x;
|
||||
const Arr_compute_y_at_x m_compute_y_at_x;
|
||||
const X_monotone_curve_2 m_top;
|
||||
const X_monotone_curve_2 m_bottom;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
namespace CGAL {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
* @brief Patches corners between two boundary points of the bbox
|
||||
* counter-clockwisely.
|
||||
|
|
@ -118,6 +117,7 @@ public:
|
|||
continue;
|
||||
}
|
||||
*out_it++ = corner;
|
||||
std::cout << "Patching corner: " << corner << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -126,6 +126,64 @@ private:
|
|||
const Bbox_2 m_bbox;
|
||||
};
|
||||
|
||||
template <typename OutputIterator>
|
||||
class Geom_simplifier
|
||||
{
|
||||
using Approx_point = Arr_approximation_geometry_traits::Approx_point;
|
||||
|
||||
private:
|
||||
void dump() {
|
||||
if(m_start.has_value()) {
|
||||
*m_out_it++ = m_start.value();
|
||||
m_start.reset();
|
||||
}
|
||||
if(m_mid.has_value()) {
|
||||
*m_out_it++ = m_mid.value();
|
||||
m_mid.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Geom_simplifier(OutputIterator& out_it, const Bbox_2& bbox)
|
||||
: m_out_it(out_it)
|
||||
, m_bbox(bbox) {}
|
||||
|
||||
decltype(auto) insert_iterator() {
|
||||
return boost::make_function_output_iterator([this](const Approx_point& p) {
|
||||
if(m_mid.has_value()) {
|
||||
if(m_mid.value() == p) {
|
||||
return;
|
||||
}
|
||||
if(p.y() == m_mid->y() && p.y() == m_start->y() || p.x() == m_mid->x() && p.x() == m_start->x()) {
|
||||
// Three points are collinear horizontally or vertically.
|
||||
m_mid = p;
|
||||
} else {
|
||||
*m_out_it++ = m_start.value();
|
||||
m_start = m_mid;
|
||||
m_mid = p;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_start.has_value()) {
|
||||
if(m_start.value() == p) {
|
||||
return;
|
||||
}
|
||||
m_mid = p;
|
||||
} else {
|
||||
m_start = p;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
~Geom_simplifier() { dump(); }
|
||||
|
||||
private:
|
||||
OutputIterator& m_out_it;
|
||||
std::optional<Approx_point> m_start, m_mid;
|
||||
Bbox_2 m_bbox;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
|
|
@ -141,8 +199,11 @@ class Arr_bounded_approximate_face_2
|
|||
using Polyline_geom = Approx_geom_traits::Polyline_geom;
|
||||
using Ccb_halfedge_const_circulator = Arrangement::Ccb_halfedge_const_circulator;
|
||||
using Approx_point = Approx_geom_traits::Approx_point;
|
||||
using Patch_boundary = internal::Patch_boundary;
|
||||
using Triangulated_face = Approx_geom_traits::Triangulated_face;
|
||||
using Patch_boundary = internal::Patch_boundary;
|
||||
|
||||
template <typename OutputIterator>
|
||||
using Geom_simplifier = internal::Geom_simplifier<OutputIterator>;
|
||||
|
||||
struct Left_to_right_tag
|
||||
{};
|
||||
|
|
@ -155,9 +216,9 @@ private:
|
|||
public:
|
||||
Execution_context(const Arr_bounded_render_context& ctx,
|
||||
Arr_bounded_face_triangulator& triangulator,
|
||||
const Patch_boundary& patch_boundary,
|
||||
const Arr_bounded_approximate_point_2& bounded_approx_pt,
|
||||
const Arr_bounded_approximate_curve_2& bounded_approx_curve,
|
||||
const Patch_boundary& patch_boundary)
|
||||
const Arr_bounded_approximate_curve_2& bounded_approx_curve)
|
||||
: Arr_context_delegator(ctx)
|
||||
, triangulator(triangulator)
|
||||
, patch_boundary(patch_boundary)
|
||||
|
|
@ -167,8 +228,8 @@ private:
|
|||
public:
|
||||
const Arr_bounded_approximate_point_2& bounded_approx_pt;
|
||||
const Arr_bounded_approximate_curve_2& bounded_approx_curve;
|
||||
const Patch_boundary& patch_boundary;
|
||||
Arr_bounded_face_triangulator& triangulator;
|
||||
const Patch_boundary& patch_boundary;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -194,46 +255,75 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Ccb_tag>
|
||||
static void approximate_ccb(Execution_context& ctx, const Ccb_halfedge_const_circulator& start_circ) {
|
||||
constexpr bool Is_outer_ccb = std::is_same_v<Ccb_tag, Outer_ccb_tag>;
|
||||
auto ccb_constraint = ctx.triangulator.make_ccb_constraint<Ccb_tag>();
|
||||
auto out_it = ccb_constraint.insert_iterator();
|
||||
template <typename CcbTag, bool Bounded = true>
|
||||
static void approximate_ccb(Execution_context& ctx, Ccb_halfedge_const_circulator start_circ) {
|
||||
constexpr bool Is_outer_ccb = std::is_same_v<CcbTag, Outer_ccb_tag>;
|
||||
static_assert(Is_outer_ccb || Bounded, "Inner CCBs are impossible to be unbounded.");
|
||||
|
||||
std::optional<Approx_point> ccb_last_pt, ccb_first_pt;
|
||||
auto counter_clockwise_start_circ = Is_outer_ccb ? start_circ : Ccb_halfedge_const_circulator(start_circ->twin());
|
||||
auto circ = counter_clockwise_start_circ;
|
||||
do {
|
||||
bool is_he_first_pt = true;
|
||||
auto patch_out_it = boost::make_function_output_iterator([&](const Approx_point& pt) {
|
||||
if(ccb_last_pt == pt || !ctx->contains(pt)) {
|
||||
return;
|
||||
}
|
||||
if(is_he_first_pt && ccb_last_pt.has_value()) {
|
||||
ctx.patch_boundary(ccb_last_pt.value(), pt, out_it);
|
||||
}
|
||||
|
||||
*out_it++ = pt;
|
||||
ccb_last_pt = pt;
|
||||
if(!ccb_first_pt.has_value()) {
|
||||
ccb_first_pt = pt;
|
||||
}
|
||||
is_he_first_pt = false;
|
||||
});
|
||||
|
||||
approximate_halfedge_of_ccb(ctx, circ, patch_out_it);
|
||||
approximate_vertex(ctx, circ->target());
|
||||
} while(++circ != counter_clockwise_start_circ);
|
||||
|
||||
if(Is_outer_ccb && !ccb_first_pt.has_value()) {
|
||||
*out_it++ = Approx_point(ctx->xmin(), ctx->ymin());
|
||||
*out_it++ = Approx_point(ctx->xmax(), ctx->ymin());
|
||||
*out_it++ = Approx_point(ctx->xmax(), ctx->ymax());
|
||||
*out_it++ = Approx_point(ctx->xmin(), ctx->ymax());
|
||||
// For unbound ccb, we start on a fictitious edge
|
||||
if constexpr(!Bounded) {
|
||||
while(!start_circ->is_fictitious()) {
|
||||
++start_circ;
|
||||
}
|
||||
}
|
||||
if(ccb_first_pt.has_value() && ccb_first_pt != ccb_last_pt) {
|
||||
// Close the ccb
|
||||
ctx.patch_boundary(ccb_last_pt.value(), ccb_first_pt.value(), out_it);
|
||||
|
||||
auto ccb_constraint = ctx.triangulator.make_ccb_constraint<CcbTag>();
|
||||
auto constraint_out_it = ccb_constraint.insert_iterator();
|
||||
|
||||
auto simplifier = Geom_simplifier(constraint_out_it, ctx->bbox());
|
||||
auto simplifier_out_it = simplifier.insert_iterator();
|
||||
|
||||
auto circ = start_circ;
|
||||
std::optional<Approx_point> last_pt;
|
||||
|
||||
// These vars are used only in unbounded ccb.
|
||||
std::optional<Approx_point> first_pt;
|
||||
bool passed_fictitious_edge = false;
|
||||
|
||||
auto he_process_out_it = boost::make_function_output_iterator([&](const Approx_point& pt) {
|
||||
Approx_point regulated_pt(pt.x(), std::clamp(pt.y(), ctx->ymin(), ctx->ymax()));
|
||||
if(last_pt == regulated_pt) {
|
||||
return;
|
||||
}
|
||||
|
||||
*simplifier_out_it++ = regulated_pt;
|
||||
|
||||
if constexpr(!Bounded) {
|
||||
// TODO: nesting too deep and looks ugly
|
||||
if(passed_fictitious_edge) {
|
||||
passed_fictitious_edge = false;
|
||||
if(last_pt.has_value()) {
|
||||
ctx.patch_boundary(last_pt.value(), regulated_pt, simplifier_out_it);
|
||||
}
|
||||
}
|
||||
if(!first_pt.has_value()) {
|
||||
first_pt = regulated_pt;
|
||||
}
|
||||
}
|
||||
|
||||
last_pt = regulated_pt;
|
||||
});
|
||||
|
||||
do {
|
||||
if constexpr(!Bounded) {
|
||||
if(circ->is_fictitious()) {
|
||||
passed_fictitious_edge = true;
|
||||
}
|
||||
}
|
||||
approximate_halfedge_of_ccb(ctx, circ, he_process_out_it);
|
||||
approximate_vertex(ctx, circ->target());
|
||||
} while(++circ != start_circ);
|
||||
|
||||
if constexpr(!Bounded) {
|
||||
if(!first_pt.has_value()) {
|
||||
*simplifier_out_it++ = Approx_point(ctx->xmin(), ctx->ymin());
|
||||
*simplifier_out_it++ = Approx_point(ctx->xmin(), ctx->ymax());
|
||||
*simplifier_out_it++ = Approx_point(ctx->xmax(), ctx->ymax());
|
||||
*simplifier_out_it++ = Approx_point(ctx->xmax(), ctx->ymin());
|
||||
|
||||
} else {
|
||||
ctx.patch_boundary(last_pt.value(), first_pt.value(), simplifier_out_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,18 +347,34 @@ public:
|
|||
}
|
||||
|
||||
CGAL_assertion_msg(!fh->is_fictitious(), "Cannot approximate a fictitious face.");
|
||||
|
||||
if(!fh->has_outer_ccb()) {
|
||||
// The face is the unbounded face of bounded arrangements
|
||||
// The face is the unbounded face of bounded arrangements, we skip approximating any non degenerate features.
|
||||
for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) {
|
||||
if((*inner_ccb)->twin()->face() != (*inner_ccb)->face()) {
|
||||
continue;
|
||||
}
|
||||
m_curve_approx(*inner_ccb);
|
||||
}
|
||||
for(auto isolated_vh = fh->isolated_vertices_begin(); isolated_vh != fh->isolated_vertices_end(); ++isolated_vh) {
|
||||
m_point_approx(isolated_vh);
|
||||
}
|
||||
return triangulated_face;
|
||||
}
|
||||
|
||||
Arr_bounded_face_triangulator triangulator(m_ctx);
|
||||
Execution_context ctx(m_ctx, triangulator, m_point_approx, m_curve_approx, m_patch_boundary);
|
||||
Execution_context ctx(m_ctx, triangulator, m_patch_boundary, m_point_approx, m_curve_approx);
|
||||
|
||||
if(fh->is_unbounded()) {
|
||||
approximate_ccb<Outer_ccb_tag, false>(ctx, fh->outer_ccb());
|
||||
} else {
|
||||
approximate_ccb<Outer_ccb_tag, true>(ctx, fh->outer_ccb());
|
||||
}
|
||||
|
||||
approximate_ccb<Outer_ccb_tag>(ctx, fh->outer_ccb());
|
||||
for(auto inner_ccb = fh->inner_ccbs_begin(); inner_ccb != fh->inner_ccbs_end(); ++inner_ccb) {
|
||||
approximate_ccb<Inner_ccb_tag>(ctx, *inner_ccb);
|
||||
}
|
||||
|
||||
for(auto isolated_vh = fh->isolated_vertices_begin(); isolated_vh != fh->isolated_vertices_begin(); ++isolated_vh) {
|
||||
approximate_vertex(ctx, isolated_vh);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,73 +7,9 @@
|
|||
#include <CGAL/Draw_aos/helpers.h>
|
||||
#include <CGAL/Draw_aos/Arr_construct_segments.h>
|
||||
#include <CGAL/Draw_aos/Arr_construct_curve_end.h>
|
||||
#include <CGAL/Draw_aos/Arr_compute_y_at_x.h>
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
#include <optional>
|
||||
|
||||
namespace CGAL {
|
||||
/**
|
||||
* @brief Functor to compute the y-coordinate at a given x-coordinate for an x-monotone curve within a bounding box.
|
||||
*/
|
||||
class Arr_bounded_compute_y_at_x
|
||||
{
|
||||
public:
|
||||
using Point_2 = Geom_traits::Point_2;
|
||||
using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2;
|
||||
using Intersect_2 = Geom_traits::Intersect_2;
|
||||
using Construct_min_vertex_2 = Geom_traits::Construct_min_vertex_2;
|
||||
using FT = Geom_traits::FT;
|
||||
using Approximate_2 = Geom_traits::Approximate_2;
|
||||
using Is_vertical_2 = Geom_traits::Is_vertical_2;
|
||||
|
||||
Arr_bounded_compute_y_at_x(const Arr_bounded_render_context& ctx)
|
||||
: m_ctx(ctx)
|
||||
// TODO: some traits does not have approximate_2_object. we'll need a specialization for them.
|
||||
, m_approx(ctx.traits.approximate_2_object()) {}
|
||||
|
||||
/**
|
||||
* @brief Computes the y-coordinate at a given x-coordinate for an x-monotone curve trimmed
|
||||
* to the bounding box.
|
||||
*
|
||||
* The bounding box here is considered as closed.
|
||||
*
|
||||
* @precondition The curve is not verical
|
||||
* @param curve
|
||||
* @param x
|
||||
* @return true if there is an intersection at given x within the bounding box,
|
||||
* @return false otherwise.
|
||||
*/
|
||||
std::optional<FT> operator()(const X_monotone_curve_2& curve, const FT& x) const {
|
||||
CGAL_assertion(!m_ctx.is_vertical_2(curve));
|
||||
if(!m_ctx.contains_x(x)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto min_pt = m_ctx.cst_curve_end(curve, ARR_MIN_END);
|
||||
auto max_pt = m_ctx.cst_curve_end(curve, ARR_MAX_END);
|
||||
if(min_pt.has_value() && min_pt->x() == x) {
|
||||
return min_pt->y();
|
||||
}
|
||||
if(max_pt.has_value() && max_pt->x() == x) {
|
||||
return max_pt->y();
|
||||
}
|
||||
|
||||
using Multiplicity = Geom_traits::Multiplicity;
|
||||
using Intersect_point = std::pair<Point_2, Multiplicity>;
|
||||
using Intersect_curve = X_monotone_curve_2;
|
||||
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
|
||||
|
||||
auto vertical_line = m_ctx.cst_vertical_segment(x, m_ctx.ymin(), m_ctx.ymax());
|
||||
std::optional<FT> y;
|
||||
auto func_out_iter = boost::make_function_output_iterator(
|
||||
[&y, this](const Intersect_type& res) { y = std::get<Intersect_point>(res).first.y(); });
|
||||
m_ctx.intersect_2(curve, vertical_line, func_out_iter);
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
const Arr_bounded_render_context& m_ctx;
|
||||
Approximate_2 m_approx;
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
namespace CGAL {} // namespace CGAL
|
||||
#endif // CGAL_DRAW_AOS_ARR_BOUNDED_COMPUTE_Y_AT_X_H
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
#ifndef CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H
|
||||
#define CGAL_DRAW_AOS_ARR_FACE_TRIANGULATOR_H
|
||||
|
||||
#include "CGAL/Constrained_Delaunay_triangulation_2.h"
|
||||
#include "CGAL/Constrained_triangulation_2.h"
|
||||
#include "CGAL/Constrained_triangulation_face_base_2.h"
|
||||
#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h"
|
||||
#include "CGAL/Draw_aos/Arr_render_context.h"
|
||||
#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
|
||||
#include "CGAL/Triangulation_vertex_base_with_info_2.h"
|
||||
#include "CGAL/basic.h"
|
||||
#include "CGAL/mark_domain_in_triangulation.h"
|
||||
#include "CGAL/number_utils.h"
|
||||
#include "CGAL/unordered_flat_map.h"
|
||||
#include <cstddef>
|
||||
#include <CGAL/Draw_aos/helpers.h>
|
||||
|
|
@ -49,8 +51,8 @@ class Arr_bounded_face_triangulator
|
|||
using Fb = CGAL::Constrained_triangulation_face_base_2<Epick>;
|
||||
using Tds = CGAL::Triangulation_data_structure_2<Vb, Fb>;
|
||||
using Ct = Constrained_triangulation_2<Epick, Tds, Exact_predicates_tag>;
|
||||
using Point = Epick::Point_2;
|
||||
using Point_with_info = std::pair<Point, Point_index>;
|
||||
using KPoint = Epick::Point_2;
|
||||
using KPoint_with_info = std::pair<KPoint, Point_index>;
|
||||
|
||||
std::size_t counter{0};
|
||||
|
||||
|
|
@ -63,12 +65,14 @@ class Arr_bounded_face_triangulator
|
|||
class Ccb_constraint
|
||||
{
|
||||
constexpr static bool Is_outer_ccb = std::is_same_v<Ccb_tag, Outer_ccb_tag>;
|
||||
|
||||
friend class Arr_bounded_face_triangulator;
|
||||
using Side_of_boundary = Arr_bounded_render_context::Side_of_boundary;
|
||||
|
||||
std::ofstream m_ofs;
|
||||
Ccb_constraint(Arr_bounded_face_triangulator& triangulator)
|
||||
: m_triangulator(&triangulator) {
|
||||
m_ccb_start = m_triangulator->m_points.size();
|
||||
: m_triangulator(&triangulator)
|
||||
, m_ccb_start(m_triangulator->m_points.size()) {
|
||||
triangulator.m_has_active_constraint = true;
|
||||
|
||||
if(Is_outer_ccb) {
|
||||
|
|
@ -80,24 +84,28 @@ class Arr_bounded_face_triangulator
|
|||
}
|
||||
|
||||
private:
|
||||
Point offset_boundary_point(const Point& pt) const {
|
||||
constexpr double offset = 1; // It doesn't matter how much we offset the point
|
||||
double x = pt.x(), y = pt.y();
|
||||
const auto& ctx = m_triangulator->m_ctx;
|
||||
std::vector<KPoint_with_info>& points() { return m_triangulator->m_points; }
|
||||
const std::vector<KPoint_with_info>& points() const { return m_triangulator->m_points; }
|
||||
auto first_point() const { return points()[m_ccb_start].first; }
|
||||
auto last_point() const { return points().back().first; }
|
||||
const Arr_bounded_render_context& ctx() const { return m_triangulator->m_ctx; }
|
||||
void add_point(const KPoint& pt) { points().emplace_back(pt, points().size()); }
|
||||
std::size_t ccb_size() const { return m_triangulator->m_points.size() - m_ccb_start - m_helper_indices.size(); }
|
||||
|
||||
if(x == ctx.xmin()) {
|
||||
x -= offset;
|
||||
KPoint offset_boundary_point(const KPoint& pt, Side_of_boundary side, double offset) const {
|
||||
CGAL_precondition(side != Side_of_boundary::None);
|
||||
switch(side) {
|
||||
case Side_of_boundary::Left:
|
||||
return KPoint(pt.x() - offset, pt.y());
|
||||
case Side_of_boundary::Right:
|
||||
return KPoint(pt.x() + offset, pt.y());
|
||||
case Side_of_boundary::Top:
|
||||
return KPoint(pt.x(), pt.y() + offset);
|
||||
case Side_of_boundary::Bottom:
|
||||
return KPoint(pt.x(), pt.y() - offset);
|
||||
default:
|
||||
return pt; // Should not reach here
|
||||
}
|
||||
if(x == ctx.xmax()) {
|
||||
x += offset;
|
||||
}
|
||||
if(y == ctx.ymin()) {
|
||||
y -= offset;
|
||||
}
|
||||
if(y == ctx.ymax()) {
|
||||
y += offset;
|
||||
}
|
||||
return Point(x, y);
|
||||
}
|
||||
|
||||
void insert_ccb() {
|
||||
|
|
@ -123,30 +131,39 @@ class Arr_bounded_face_triangulator
|
|||
};
|
||||
|
||||
auto index_to_point_with_info = [&points](std::size_t idx) { return points[idx]; };
|
||||
|
||||
auto indexes_begin = boost::make_counting_iterator<std::size_t>(m_ccb_start);
|
||||
auto indexes_end = boost::make_counting_iterator<std::size_t>(points.size());
|
||||
auto filtered_begin = boost::make_filter_iterator(concrete_pt_filter, indexes_begin, indexes_end);
|
||||
auto filtered_end = boost::make_filter_iterator(concrete_pt_filter, indexes_end, indexes_end);
|
||||
auto transformed_begin = boost::make_transform_iterator(filtered_begin, index_to_point_with_info);
|
||||
auto transformed_end = boost::make_transform_iterator(filtered_end, index_to_point_with_info);
|
||||
// {
|
||||
// std::ofstream ofs_index("/Users/shep/codes/aos_2_js_helper/shapes.txt", std::ios::app);
|
||||
// auto& ctx = const_cast<Arr_bounded_render_context&>(m_triangulator->m_ctx);
|
||||
// ofs_index << "ccb_" << ctx.counter << ".txt" << std::endl;
|
||||
// std::ofstream ofs("/Users/shep/codes/aos_2_js_helper/ccb_" + std::to_string(ctx.counter++) + ".txt",
|
||||
// std::ios::out | std::ios::trunc);
|
||||
// for(auto it = filtered_begin; it != filtered_end; ++it) {
|
||||
// const auto& pt = it->first;
|
||||
// ofs << pt.x() << " " << pt.y() << std::endl;
|
||||
// }
|
||||
// }
|
||||
ct.insert_with_info<Point_with_info>(transformed_begin, transformed_end);
|
||||
|
||||
ct.insert_with_info<KPoint_with_info>(transformed_begin, transformed_end);
|
||||
} else {
|
||||
ct.insert_with_info<Point_with_info>(begin, end);
|
||||
ct.insert_with_info<KPoint_with_info>(begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
void try_add_offset(const KPoint& from, const KPoint& to) {
|
||||
if(from == to) {
|
||||
return;
|
||||
}
|
||||
auto shared_side = ctx().shared_boundary_side(from, to);
|
||||
if(shared_side == Arr_bounded_render_context::Side_of_boundary::None) {
|
||||
return;
|
||||
}
|
||||
// m_helper_indices.push_back(points().size());
|
||||
// add_point(offset_boundary_point(from, shared_side, m_offset));
|
||||
m_helper_indices.push_back(points().size());
|
||||
add_point(offset_boundary_point(KPoint((from.x() + to.x()) / 2, (from.y() + to.y()) / 2), shared_side, m_offset));
|
||||
|
||||
// TODO: we'll come back to find out if we do need to offset the second point.
|
||||
// m_helper_indices.push_back(points().size());
|
||||
// add_point(offset_boundary_point(to, shared_side, m_offset));
|
||||
// Doesn't matter how much we increase the offset.
|
||||
m_offset += 0.5;
|
||||
}
|
||||
|
||||
public:
|
||||
Ccb_constraint(const Ccb_constraint&) = delete;
|
||||
Ccb_constraint& operator=(const Ccb_constraint&) = delete;
|
||||
|
|
@ -162,22 +179,18 @@ class Arr_bounded_face_triangulator
|
|||
return *this;
|
||||
}
|
||||
|
||||
decltype(auto) insert_iterator() {
|
||||
return boost::make_function_output_iterator([&, this](const Approx_point& pt) {
|
||||
auto& points = m_triangulator->m_points;
|
||||
auto insert_iterator() {
|
||||
return boost::make_function_output_iterator([this](const Approx_point& pt) {
|
||||
CGAL_assertion_msg(m_triangulator != nullptr, "Use of destructed or moved Ccb_constraint object.");
|
||||
CGAL_assertion_msg(m_triangulator->m_ctx.contains(pt), "Outbound point in Ccb_constraint.");
|
||||
CGAL_assertion_msg(ctx().contains(pt), "Outbound point in Ccb_constraint.");
|
||||
KPoint kp(pt.x(), pt.y());
|
||||
|
||||
if constexpr(Is_outer_ccb) {
|
||||
bool is_on_boundary = m_triangulator->m_ctx.is_on_boundary(pt);
|
||||
if(is_on_boundary && m_is_last_on_boundary) {
|
||||
m_helper_indices.push_back(points.size());
|
||||
points.emplace_back(offset_boundary_point(points.back().first), Point_index());
|
||||
}
|
||||
m_is_last_on_boundary = is_on_boundary;
|
||||
if(Is_outer_ccb && ccb_size() != 0) {
|
||||
try_add_offset(last_point(), kp);
|
||||
m_ofs << pt.x() << " " << pt.y() << std::endl;
|
||||
}
|
||||
points.emplace_back(Point(pt.x(), pt.y()), points.size());
|
||||
|
||||
add_point(kp);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -185,15 +198,9 @@ class Arr_bounded_face_triangulator
|
|||
if(m_triangulator == nullptr) {
|
||||
return;
|
||||
}
|
||||
if(Is_outer_ccb && m_is_last_on_boundary && m_triangulator->m_points.size() != m_ccb_start) {
|
||||
auto& points = m_triangulator->m_points;
|
||||
const auto& first_pt = points[m_ccb_start].first;
|
||||
const auto& last_pt = points.back().first;
|
||||
bool is_first_on_boundary = m_triangulator->m_ctx.is_on_boundary(first_pt);
|
||||
if(m_is_last_on_boundary && is_first_on_boundary) {
|
||||
m_helper_indices.push_back(points.size());
|
||||
points.emplace_back(offset_boundary_point(last_pt), Point_index());
|
||||
}
|
||||
|
||||
if(Is_outer_ccb && ccb_size() != 0) {
|
||||
try_add_offset(last_point(), first_point());
|
||||
}
|
||||
|
||||
insert_ccb();
|
||||
|
|
@ -203,8 +210,10 @@ class Arr_bounded_face_triangulator
|
|||
|
||||
private:
|
||||
Arr_bounded_face_triangulator* m_triangulator;
|
||||
std::size_t m_ccb_start;
|
||||
bool m_is_last_on_boundary = false;
|
||||
const std::size_t m_ccb_start;
|
||||
|
||||
// These are used only for outer CCBs.
|
||||
double m_offset = 0.5; // Doesn't matter how much we offset.
|
||||
std::vector<std::size_t> m_helper_indices; // The offseted point indices when inserting outer ccb constraint
|
||||
};
|
||||
|
||||
|
|
@ -217,12 +226,15 @@ public:
|
|||
operator Triangulated_face() && {
|
||||
CGAL_assertion(!m_has_active_constraint && "There is an active constraint in the triangulator.");
|
||||
CGAL_assertion(m_outer_ccb_processed && "Outer CCB has not been processed yet.");
|
||||
if(m_points.empty() || m_ct.number_of_faces() == 0) {
|
||||
return Triangulated_face();
|
||||
}
|
||||
|
||||
// insert_constraint() should be called after insert_with_info(), or info will not be set correctly.
|
||||
auto first_of_pair = [](const Point_with_info& pt_with_info) { return pt_with_info.first; };
|
||||
auto first_of_pair = [](const KPoint_with_info& pt_with_info) { return pt_with_info.first; };
|
||||
for(std::size_t i = 0; i < m_ccb_start_indices.size(); ++i) {
|
||||
auto begin = m_points.begin() + m_ccb_start_indices[i];
|
||||
auto end = m_points.begin() + (i + 1 < m_ccb_start_indices.size() ? m_ccb_start_indices[i + 1] : m_points.size());
|
||||
auto end = i + 1 < m_ccb_start_indices.size() ? m_points.begin() + m_ccb_start_indices[i + 1] : m_points.end();
|
||||
{
|
||||
std::ofstream ofs_index("/Users/shep/codes/aos_2_js_helper/shapes.txt", std::ios::app);
|
||||
auto& ctx = const_cast<Arr_bounded_render_context&>(m_ctx);
|
||||
|
|
@ -258,12 +270,11 @@ public:
|
|||
tf.triangles.emplace_back(tri);
|
||||
}
|
||||
|
||||
auto transform_first_of_pair = [](const Point_with_info& pt_with_info) {
|
||||
return Approx_point(pt_with_info.first.x(), pt_with_info.first.y());
|
||||
auto transform_first_of_pair = [](const KPoint_with_info& pt_with_info) {
|
||||
return Approx_point(CGAL::to_double(pt_with_info.first.x()), CGAL::to_double(pt_with_info.first.y()));
|
||||
};
|
||||
tf.points = Point_vec(boost::make_transform_iterator(m_points.begin(), transform_first_of_pair),
|
||||
boost::make_transform_iterator(m_points.end(), transform_first_of_pair));
|
||||
m_ct.clear();
|
||||
return tf;
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +297,7 @@ public:
|
|||
private:
|
||||
const Arr_bounded_render_context& m_ctx;
|
||||
Ct m_ct;
|
||||
std::vector<Point_with_info> m_points;
|
||||
std::vector<KPoint_with_info> m_points;
|
||||
std::vector<std::size_t> m_ccb_start_indices;
|
||||
bool m_has_active_constraint = false;
|
||||
bool m_outer_ccb_processed = false;
|
||||
|
|
|
|||
|
|
@ -129,11 +129,10 @@ private:
|
|||
auto he = *inner_ccb;
|
||||
auto inner_face = he->twin()->face();
|
||||
|
||||
bool is_degenerate = inner_face == fh;
|
||||
bool within_bounds = ctx->strictly_contains(inner_face->outer_ccb()->source()->point());
|
||||
if(is_degenerate || !within_bounds) {
|
||||
if(inner_face == fh || !ctx->strictly_contains(inner_face->outer_ccb()->source()->point())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
discover_faces(ctx, inner_face);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H
|
||||
#define CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H
|
||||
#include "CGAL/Bbox_2.h"
|
||||
#include "CGAL/Draw_aos/Arr_render_context.h"
|
||||
#include "CGAL/Draw_aos/helpers.h"
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/**
|
||||
* @brief Functor to compute the y-coordinate at a given x-coordinate for an x-monotone curve within a bounding box.
|
||||
*/
|
||||
class Arr_compute_y_at_x
|
||||
{
|
||||
public:
|
||||
using Point_2 = Geom_traits::Point_2;
|
||||
using X_monotone_curve_2 = Geom_traits::X_monotone_curve_2;
|
||||
using Intersect_2 = Geom_traits::Intersect_2;
|
||||
using Construct_min_vertex_2 = Geom_traits::Construct_min_vertex_2;
|
||||
using FT = Geom_traits::FT;
|
||||
using Approximate_2 = Geom_traits::Approximate_2;
|
||||
using Is_vertical_2 = Geom_traits::Is_vertical_2;
|
||||
|
||||
Arr_compute_y_at_x(const Arr_render_context& ctx)
|
||||
: m_ctx(ctx)
|
||||
// TODO: some traits does not have approximate_2_object. we'll need a specialization for them.
|
||||
, m_approx(ctx.traits.approximate_2_object()) {}
|
||||
|
||||
/**
|
||||
* @brief Computes the y-coordinate at a given x-coordinate for an x-monotone curve trimmed
|
||||
* to the bounding box.
|
||||
*
|
||||
* The bounding box here is considered as closed.
|
||||
*
|
||||
* @precondition The curve is not verical
|
||||
* @param curve
|
||||
* @param x
|
||||
* @return true if there is an intersection at given x within the bounding box,
|
||||
* @return false otherwise.
|
||||
*/
|
||||
std::optional<FT> operator()(const X_monotone_curve_2& curve, const FT& x) const {
|
||||
CGAL_assertion(!m_ctx.is_vertical_2(curve));
|
||||
|
||||
auto min_pt = m_ctx.cst_curve_end(curve, ARR_MIN_END);
|
||||
auto max_pt = m_ctx.cst_curve_end(curve, ARR_MAX_END);
|
||||
if(min_pt.has_value() && min_pt->x() == x) {
|
||||
return min_pt->y();
|
||||
}
|
||||
if(max_pt.has_value() && max_pt->x() == x) {
|
||||
return max_pt->y();
|
||||
}
|
||||
|
||||
using Multiplicity = Geom_traits::Multiplicity;
|
||||
using Intersect_point = std::pair<Point_2, Multiplicity>;
|
||||
using Intersect_curve = X_monotone_curve_2;
|
||||
using Intersect_type = std::variant<Intersect_point, Intersect_curve>;
|
||||
|
||||
auto vertical_line = m_ctx.cst_vertical_segment(x, m_ymin, m_ymax);
|
||||
std::optional<FT> y;
|
||||
auto func_out_iter = boost::make_function_output_iterator(
|
||||
[&y, this](const Intersect_type& res) { y = std::get<Intersect_point>(res).first.y(); });
|
||||
m_ctx.intersect_2(curve, vertical_line, func_out_iter);
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
Approximate_2 m_approx;
|
||||
const Arr_render_context& m_ctx;
|
||||
|
||||
// Should be enough for visualization purposes.
|
||||
constexpr static double m_ymin = std::numeric_limits<double>::lowest();
|
||||
constexpr static double m_ymax = std::numeric_limits<double>::max();
|
||||
};
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_DRAW_AOS_ARR_COMPUTE_Y_AT_X_H
|
||||
|
|
@ -59,6 +59,14 @@ protected:
|
|||
: m_bbox(bbox) {}
|
||||
|
||||
public:
|
||||
enum class Side_of_boundary {
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
Top,
|
||||
None,
|
||||
};
|
||||
|
||||
double xmin() const { return m_bbox.xmin(); }
|
||||
double xmax() const { return m_bbox.xmax(); }
|
||||
double ymin() const { return m_bbox.ymin(); }
|
||||
|
|
@ -102,6 +110,20 @@ public:
|
|||
(pt.y() == ymin() || pt.y() == ymax()) && contains_x(pt.x());
|
||||
}
|
||||
|
||||
template <typename Point>
|
||||
Side_of_boundary shared_boundary_side(const Point& pt1, const Point& pt2) const {
|
||||
if(pt1.x() == xmin() && pt2.x() == xmin() && contains_y(pt1.y()) && contains_y(pt2.y())) {
|
||||
return Side_of_boundary::Left;
|
||||
} else if(pt1.x() == xmax() && pt2.x() == xmax() && contains_y(pt1.y()) && contains_y(pt2.y())) {
|
||||
return Side_of_boundary::Right;
|
||||
} else if(pt1.y() == ymin() && pt2.y() == ymin() && contains_x(pt1.x()) && contains_x(pt2.x())) {
|
||||
return Side_of_boundary::Bottom;
|
||||
} else if(pt1.y() == ymax() && pt2.y() == ymax() && contains_x(pt1.x()) && contains_x(pt2.x())) {
|
||||
return Side_of_boundary::Top;
|
||||
}
|
||||
return Side_of_boundary::None;
|
||||
}
|
||||
|
||||
private:
|
||||
const Bbox_2 m_bbox;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@
|
|||
#include <array>
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
#include "CGAL/Arr_trapezoid_ric_point_location.h"
|
||||
#include "CGAL/Arrangement_on_surface_2.h"
|
||||
#include "CGAL/Bbox_2.h"
|
||||
#include "CGAL/Draw_aos/Arr_bounded_renderer.h"
|
||||
#include "CGAL/Draw_aos/Arr_render_context.h"
|
||||
#include "CGAL/Graphics_scene.h"
|
||||
#include "CGAL/Graphics_scene_options.h"
|
||||
#include "CGAL/Qt/camera.h"
|
||||
#include "CGAL/unordered_flat_map.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtOpenGLWidgets/QtOpenGLWidgets>
|
||||
|
|
@ -20,6 +22,10 @@
|
|||
#include <CGAL/Basic_viewer.h>
|
||||
#include <cstddef>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
|
@ -31,6 +37,7 @@ class Arr_viewer : public Qt::Basic_viewer
|
|||
using Face_const_handle = Arrangement::Face_const_handle;
|
||||
using Graphics_scene_options =
|
||||
Graphics_scene_options<Arrangement, Vertex_const_handle, Halfedge_const_handle, Face_const_handle>;
|
||||
using Point_location = Arr_trapezoid_ric_point_location<Arrangement>;
|
||||
|
||||
private:
|
||||
// Function to check if the camera's state has changed
|
||||
|
|
@ -48,17 +55,17 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
Bbox_2 initial_bbox() const {
|
||||
Bbox_2 bbox;
|
||||
for(const auto& vh : m_arr.vertex_handles()) {
|
||||
bbox += vh->point().bbox();
|
||||
}
|
||||
if(bbox.x_span() == 0 || bbox.y_span() == 0) {
|
||||
// make a default bbox around the degenrate rect
|
||||
bbox = Bbox_2(bbox.xmin() - 1, bbox.ymin() - 1, bbox.xmax() + 1, bbox.ymax() + 1);
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
// Bbox_2 initial_bbox() const {
|
||||
// Bbox_2 bbox;
|
||||
// for(const auto& vh : m_arr.vertex_handles()) {
|
||||
// bbox += vh->point().bbox();
|
||||
// }
|
||||
// if(bbox.x_span() == 0 || bbox.y_span() == 0) {
|
||||
// // make a default bbox around the degenrate rect
|
||||
// bbox = Bbox_2(bbox.xmin() - 1, bbox.ymin() - 1, bbox.xmax() + 1, bbox.ymax() + 1);
|
||||
// }
|
||||
// return bbox;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Computes the bounding box of the view from orthogonal camera.
|
||||
|
|
@ -101,7 +108,9 @@ private:
|
|||
std::array<GLint, 4> viewport;
|
||||
camera_->getViewport(viewport.data());
|
||||
double width = static_cast<double>(viewport[2]);
|
||||
return 0.5;
|
||||
// return bbox.x_span() / std::min(600.0, width);
|
||||
// We are testing linear traits, lets set it to inf
|
||||
return 10000;
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -111,26 +120,22 @@ public:
|
|||
const char* title = "Arrangement Viewer")
|
||||
: Basic_viewer(parent, m_scene, title)
|
||||
, m_scene_options(options)
|
||||
, m_pl(arr)
|
||||
, m_arr(arr) {}
|
||||
, m_arr(arr)
|
||||
, m_pl(arr) {}
|
||||
|
||||
void rerender(Bbox_2 bbox) {
|
||||
Arr_render_context ctx(m_arr, m_pl, get_approx_error(bbox));
|
||||
void render_arr(const Arrangement& arr, const Point_location& pl, const Bbox_2& bbox) {
|
||||
Arr_render_context ctx(arr, pl, get_approx_error(bbox));
|
||||
Arr_bounded_renderer renderer(ctx, bbox);
|
||||
const auto& cache = renderer.render();
|
||||
|
||||
m_scene.clear();
|
||||
|
||||
int counter = 0;
|
||||
|
||||
// add faces
|
||||
for(const auto& [fh, face_tris] : cache.face_cache()) {
|
||||
const auto& points = face_tris.points;
|
||||
const auto& tris = face_tris.triangles;
|
||||
bool draw_face = m_scene_options.colored_face(m_arr, fh);
|
||||
bool draw_face = m_scene_options.colored_face(arr, fh);
|
||||
for(const auto& t : tris) {
|
||||
if(draw_face) {
|
||||
m_scene.face_begin(m_scene_options.face_color(m_arr, fh));
|
||||
m_scene.face_begin(m_scene_options.face_color(arr, fh));
|
||||
} else {
|
||||
m_scene.face_begin();
|
||||
}
|
||||
|
|
@ -142,15 +147,13 @@ public:
|
|||
}
|
||||
|
||||
// add edges
|
||||
counter = 0;
|
||||
for(const auto& [he, polyline] : cache.halfedge_cache()) {
|
||||
if(polyline.size() < 2) {
|
||||
continue; // skip degenerate edges
|
||||
}
|
||||
// ofs_index << "polyline_" << counter << ".txt" << std::endl;
|
||||
// std::ofstream ofs("/Users/shep/codes/aos_2_js_helper/polyline_" + std::to_string(counter++) + ".txt");
|
||||
bool draw_colored_edge = m_scene_options.colored_edge(m_arr, he);
|
||||
auto color = draw_colored_edge ? m_scene_options.edge_color(m_arr, he) : CGAL::IO::Color();
|
||||
|
||||
bool draw_colored_edge = m_scene_options.colored_edge(arr, he);
|
||||
auto color = draw_colored_edge ? m_scene_options.edge_color(arr, he) : CGAL::IO::Color();
|
||||
for(size_t i = 0; i < polyline.size() - 1; ++i) {
|
||||
const auto& cur_pt = polyline[i];
|
||||
const auto& next_pt = polyline[i + 1];
|
||||
|
|
@ -160,25 +163,26 @@ public:
|
|||
{
|
||||
continue;
|
||||
}
|
||||
// ofs << cur_pt << "\n";
|
||||
if(draw_colored_edge) {
|
||||
m_scene.add_segment(cur_pt, next_pt, color);
|
||||
} else {
|
||||
m_scene.add_segment(cur_pt, next_pt);
|
||||
}
|
||||
}
|
||||
// ofs << polyline.back() << "\n";
|
||||
// ofs << std::endl;
|
||||
}
|
||||
// add vertices
|
||||
for(const auto& [vh, pt] : cache.vertex_cache()) {
|
||||
// std::cout << pt << std::endl;
|
||||
if(m_scene_options.colored_vertex(m_arr, vh)) {
|
||||
m_scene.add_point(pt, m_scene_options.vertex_color(m_arr, vh));
|
||||
if(m_scene_options.colored_vertex(arr, vh)) {
|
||||
m_scene.add_point(pt, m_scene_options.vertex_color(arr, vh));
|
||||
} else {
|
||||
m_scene.add_point(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rerender(Bbox_2 bbox) {
|
||||
m_scene.clear();
|
||||
render_arr(m_arr, m_pl, bbox);
|
||||
Basic_viewer::redraw();
|
||||
}
|
||||
|
||||
|
|
@ -200,8 +204,8 @@ public:
|
|||
private:
|
||||
Graphics_scene m_scene;
|
||||
Graphics_scene_options m_scene_options;
|
||||
const Arrangement& m_arr;
|
||||
Arr_trapezoid_ric_point_location<Arrangement> m_pl;
|
||||
Arrangement m_arr;
|
||||
Point_location m_pl;
|
||||
QMatrix4x4 m_last_proj_matrix;
|
||||
QMatrix4x4 m_last_modelview_matrix;
|
||||
};
|
||||
|
|
@ -225,7 +229,9 @@ void draw_viewer(const Arrangement& arr) {
|
|||
CGAL::Random random((size_t(&*vh)));
|
||||
return get_random_color(random);
|
||||
};
|
||||
// Arr_viewer viewer(app.activeWindow(), move_degenerate_features(arr), gso, "Arrangement Viewer");
|
||||
Arr_viewer viewer(app.activeWindow(), arr, gso, "Arrangement Viewer");
|
||||
std::cout << "Preprocess complete" << std::endl;
|
||||
viewer.show();
|
||||
app.exec();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
namespace CGAL {
|
||||
|
||||
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Geom_traits = Arr_linear_traits_2<Exact_kernel>;
|
||||
// using Geom_traits = Arr_segment_traits_2<Exact_kernel>;
|
||||
using Geom_traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
|
||||
using Arrangement = Arrangement_2<Geom_traits>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef APPROX_Y_AT_X_H
|
||||
#define APPROX_Y_AT_X_H
|
||||
#include <CGAL/Arr_segment_traits_2.h>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
using Segment_traits_2 = CGAL::Arr_segment_traits_2<Exact_kernel>;
|
||||
using Arr = CGAL::Arrangement_2<Segment_traits_2>;
|
||||
double approx_y_at_x(const Arr::Traits_2& traits, const Arr::X_monotone_curve_2& curve, double x) {}
|
||||
#endif // APPROX_Y_AT_X_H
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +0,0 @@
|
|||
0.200004 -1.24026
|
||||
3.73824 -1.24026
|
||||
3.73824 1.94415
|
||||
0.200004 1.94415
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
#ifndef _PRINT_ARR_H_
|
||||
#define _PRINT_ARR_H_
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <iostream>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print all neighboring vertices to a given arrangement vertex.
|
||||
//
|
||||
template <class Arrangement>
|
||||
void print_neighboring_vertices(typename Arrangement::Vertex_const_handle v) {
|
||||
if(v->is_isolated()) {
|
||||
std::cout << "The vertex (" << v->point() << ") is isolated\n";
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "The neighbors of the vertex (" << v->point() << ") are:";
|
||||
typename Arrangement::Halfedge_around_vertex_const_circulator first, curr;
|
||||
first = curr = v->incident_halfedges();
|
||||
do
|
||||
std::cout << " (" << curr->source()->point() << ")";
|
||||
while(++curr != first);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print all vertices (points) and edges (curves) along a connected component
|
||||
// boundary.
|
||||
//
|
||||
template <typename Arrangement>
|
||||
void print_ccb(typename Arrangement::Ccb_halfedge_const_circulator circ) {
|
||||
std::cout << "(" << circ->source()->point() << ")";
|
||||
typename Arrangement::Ccb_halfedge_const_circulator curr = circ;
|
||||
do {
|
||||
typename Arrangement::Halfedge_const_handle e = curr;
|
||||
std::cout << " [" << e->curve() << "] "
|
||||
<< "(" << e->target()->point() << ")";
|
||||
} while(++curr != circ);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print the boundary description of an arrangement face.
|
||||
//
|
||||
template <typename Arrangement>
|
||||
void print_face(typename Arrangement::Face_const_handle f) {
|
||||
// Print the outer boundary.
|
||||
if(f->is_unbounded()) {
|
||||
std::cout << "Unbounded face.\n";
|
||||
} else {
|
||||
std::cout << "Outer boundary: ";
|
||||
print_ccb<Arrangement>(f->outer_ccb());
|
||||
}
|
||||
|
||||
// Print the boundary of each of the holes.
|
||||
size_t index = 1;
|
||||
for(auto hole = f->holes_begin(); hole != f->holes_end(); ++hole, ++index) {
|
||||
std::cout << " Hole #" << index << ": ";
|
||||
// The following statement pacifies msvc.
|
||||
typename Arrangement::Ccb_halfedge_const_circulator circ = *hole;
|
||||
print_ccb<Arrangement>(circ);
|
||||
}
|
||||
|
||||
// Print the isolated vertices.
|
||||
index = 1;
|
||||
for(auto iv = f->isolated_vertices_begin(); iv != f->isolated_vertices_end(); ++iv, ++index) {
|
||||
std::cout << " Isolated vertex #" << index << ": "
|
||||
<< "(" << iv->point() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print the given arrangement.
|
||||
//
|
||||
template <typename Arrangement>
|
||||
void print_arrangement(const Arrangement& arr) {
|
||||
CGAL_precondition(arr.is_valid());
|
||||
|
||||
// Print the arrangement vertices.
|
||||
std::cout << arr.number_of_vertices() << " vertices:\n";
|
||||
for(auto vit = arr.vertices_begin(); vit != arr.vertices_end(); ++vit) {
|
||||
std::cout << "(" << vit->point() << ")";
|
||||
if(vit->is_isolated())
|
||||
std::cout << " - Isolated.\n";
|
||||
else
|
||||
std::cout << " - degree " << vit->degree() << std::endl;
|
||||
}
|
||||
|
||||
// Print the arrangement edges.
|
||||
std::cout << arr.number_of_edges() << " edges:\n";
|
||||
for(auto eit = arr.edges_begin(); eit != arr.edges_end(); ++eit)
|
||||
std::cout << "[" << eit->curve() << "]\n";
|
||||
|
||||
// Print the arrangement faces.
|
||||
std::cout << arr.number_of_faces() << " faces:\n";
|
||||
for(auto fit = arr.faces_begin(); fit != arr.faces_end(); ++fit)
|
||||
print_face<Arrangement>(fit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print the size of the given arrangement.
|
||||
//
|
||||
template <typename Arrangement>
|
||||
void print_arrangement_size(const Arrangement& arr) {
|
||||
std::cout << "The arrangement size:\n"
|
||||
<< " |V| = " << arr.number_of_vertices() << ", |E| = " << arr.number_of_edges()
|
||||
<< ", |F| = " << arr.number_of_faces() << std::endl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print the size of the given unbounded arrangement.
|
||||
//
|
||||
template <typename Arrangement>
|
||||
void print_unbounded_arrangement_size(const Arrangement& arr) {
|
||||
std::cout << "The arrangement size:\n"
|
||||
<< " |V| = " << arr.number_of_vertices() << " (plus " << arr.number_of_vertices_at_infinity()
|
||||
<< " at infinity)"
|
||||
<< ", |E| = " << arr.number_of_edges() << ", |F| = " << arr.number_of_faces() << " ("
|
||||
<< arr.number_of_unbounded_faces() << " unbounded)\n\n";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
#include "CGAL/Bbox_2.h"
|
||||
#include "CGAL/Draw_aos/Arr_approximation_geometry_traits.h"
|
||||
#include <CGAL/Draw_aos/Arr_bounded_approximate_face_2.h>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
using Approx_point = CGAL::Arr_approximation_geometry_traits::Approx_point;
|
||||
|
||||
struct Test_case
|
||||
{
|
||||
std::vector<Approx_point> points_to_insert;
|
||||
std::vector<Approx_point> expected_points;
|
||||
CGAL::Bbox_2 bbox;
|
||||
|
||||
Test_case(std::vector<Approx_point> points, std::vector<Approx_point> expected, CGAL::Bbox_2 b)
|
||||
: points_to_insert(std::move(points))
|
||||
, expected_points(std::move(expected))
|
||||
, bbox(b) {}
|
||||
};
|
||||
|
||||
void test_geom_fill_corners_output_iterator(const Test_case& test_case) {
|
||||
std::vector<Approx_point> points{};
|
||||
auto inserter = std::back_inserter(points);
|
||||
CGAL::Geom_fill_corners_output_iterator<std::back_insert_iterator<decltype(points)>> geom_inserter(
|
||||
inserter, CGAL::Bbox_2(test_case.bbox));
|
||||
|
||||
for(const auto& pt : test_case.points_to_insert) {
|
||||
geom_inserter++ = pt;
|
||||
}
|
||||
|
||||
if(points != test_case.expected_points) {
|
||||
std::cerr << "Test failed for bbox: " << test_case.bbox << std::endl;
|
||||
std::cerr << "Points inserted: \n";
|
||||
for(const auto& pt : test_case.points_to_insert) {
|
||||
std::cerr << pt << "\n";
|
||||
}
|
||||
std::cerr << "\nExpected: \n";
|
||||
for(const auto& pt : test_case.expected_points) {
|
||||
std::cerr << pt << "\n";
|
||||
}
|
||||
std::cerr << "\nGot:\n";
|
||||
for(const auto& pt : points) {
|
||||
std::cerr << pt << "\n";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
CGAL::Bbox_2 bbox(0, 0, 10, 10);
|
||||
std::vector<Test_case> cases{
|
||||
/**
|
||||
* --------------------
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1-------------------
|
||||
*/
|
||||
Test_case({Approx_point(0, 0)}, {Approx_point(0, 0)}, bbox),
|
||||
|
||||
/**
|
||||
* 2-------------------
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1-------------------
|
||||
*
|
||||
* Expected:
|
||||
*
|
||||
* 4------------------3
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1------------------2
|
||||
*/
|
||||
Test_case({Approx_point(0, 0), Approx_point(0, 10)},
|
||||
{Approx_point(0, 0), Approx_point(10, 0), Approx_point(10, 10), Approx_point(0, 10)}, bbox),
|
||||
/**
|
||||
* --------------------
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1------------------2
|
||||
*
|
||||
* Expected:
|
||||
*
|
||||
* 2-------------------
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1------------------2
|
||||
*/
|
||||
Test_case({Approx_point(0, 0), Approx_point(10, 0)}, {Approx_point(0, 0), Approx_point(10, 0)}, bbox),
|
||||
/**
|
||||
* --------------------
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1---------2---------
|
||||
*
|
||||
* Expected:
|
||||
*
|
||||
* --------------------
|
||||
* | |
|
||||
* | |
|
||||
* 2 |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 1-------------------
|
||||
*/
|
||||
Test_case({Approx_point(0, 0), Approx_point(5, 0)}, {Approx_point(0, 0), Approx_point(5, 0)}, bbox),
|
||||
/**
|
||||
* --------------------
|
||||
* | |
|
||||
* | |
|
||||
* | 1
|
||||
* | |
|
||||
* | 2
|
||||
* | |
|
||||
* --------------------
|
||||
*
|
||||
* Expected:
|
||||
*
|
||||
* 3------------------2
|
||||
* | |
|
||||
* | |
|
||||
* | 1
|
||||
* | |
|
||||
* | 6
|
||||
* | |
|
||||
* 4------------------5
|
||||
*/
|
||||
Test_case({Approx_point(10, 5), Approx_point(10, 3)},
|
||||
{Approx_point(10, 5), Approx_point(10, 10), Approx_point(0, 10), Approx_point(0, 0),
|
||||
Approx_point(10, 0), Approx_point(10, 3)},
|
||||
bbox),
|
||||
/**
|
||||
* -------------------1
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | 2
|
||||
* | |
|
||||
* -------------------|
|
||||
*
|
||||
* Expected:
|
||||
*
|
||||
* 2------------------1
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | 5
|
||||
* | |
|
||||
* 3------------------4
|
||||
*/
|
||||
Test_case({Approx_point(10, 10), Approx_point(10, 3)},
|
||||
{
|
||||
Approx_point(10, 10),
|
||||
Approx_point(0, 10),
|
||||
Approx_point(0, 0),
|
||||
Approx_point(10, 0),
|
||||
Approx_point(10, 3),
|
||||
},
|
||||
bbox),
|
||||
};
|
||||
|
||||
for(size_t i = 0; i < cases.size(); ++i) {
|
||||
const auto& test_case = cases[i];
|
||||
test_geom_fill_corners_output_iterator(test_case);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#include "CGAL/Exact_predicates_exact_constructions_kernel.h"
|
||||
#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
|
||||
#include <CGAL/draw_arrangement_2.h>
|
||||
#include <vector>
|
||||
|
||||
// void draw_segments_arr_1() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
|
@ -111,26 +112,120 @@
|
|||
// // CGAL::draw_viewer(arr);
|
||||
// }
|
||||
|
||||
void draw_linear_arr_1() {
|
||||
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
using Traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
|
||||
using Point_2 = Traits::Point_2;
|
||||
using Line_2 = Traits::Line_2;
|
||||
using Ray_2 = Traits::Ray_2;
|
||||
using Curve_2 = Traits::Curve_2;
|
||||
using Arrangement = CGAL::Arrangement_2<Traits>;
|
||||
using Face_const_handle = Arrangement::Face_const_handle;
|
||||
using Halfedge_const_handle = Arrangement::Halfedge_const_iterator;
|
||||
using X_monotone_curve_2 = Traits::X_monotone_curve_2;
|
||||
// void draw_segments_arr_4() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Segment_traits = CGAL::Arr_segment_traits_2<Exact_kernel>;
|
||||
// using Point_2 = Segment_traits::Point_2;
|
||||
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
|
||||
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
|
||||
// Arrangement arr;
|
||||
// auto traits = arr.traits();
|
||||
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
|
||||
|
||||
Arrangement arr;
|
||||
auto x_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(1, 0)));
|
||||
auto y_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(0, 1)));
|
||||
CGAL::insert(arr, x_axis);
|
||||
CGAL::insert(arr, y_axis);
|
||||
// std::vector<X_monotone_curve_2> segments;
|
||||
|
||||
CGAL::draw_viewer(arr);
|
||||
}
|
||||
// std::vector<Point_2> polyline1{
|
||||
// {6, -21}, {6, -3}, {13, -3}, {13, -12}, {18, -12}, {18, -4}, {18, -3}, {25, -3}, {25, -21}, {6, -21},
|
||||
// };
|
||||
// for(size_t i = 0; i < polyline1.size() - 1; ++i) {
|
||||
// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1]));
|
||||
// }
|
||||
|
||||
// std::vector<Point_2> polyline2{
|
||||
// {-27, -14}, {-24, -14}, {-21, -16}, {-19, -18}, {-18, -21}, {-17, -24}, {-18, -28}, {-19, -30}, {-22, -32},
|
||||
// {-24, -33}, {-29, -33}, {-34, -33}, {-38, -32}, {-43, -30}, {-46, -29}, {-50, -25}, {-53, -21}, {-53, -17},
|
||||
// {-54, -12}, {-53, -7}, {-52, -2}, {-50, 2}, {-45, 5}, {-40, 6}, {-34, 7}, {-29, 7}, {-23, 7},
|
||||
// {-20, 6}, {-18, 5}, {-16, 2}, {-15, 0}, {-16, -3}, {-17, -3}, {-18, -1}, {-19, 1}, {-20, 4},
|
||||
// {-22, 4}, {-26, 4}, {-28, 4}, {-31, 4}, {-33, 4}, {-37, 4}, {-41, 3}, {-44, 2}, {-47, 1},
|
||||
// {-48, 0}, {-49, -2}, {-50, -5}, {-51, -8}, {-51, -13}, {-51, -16}, {-50, -18}, {-49, -22}, {-46, -24},
|
||||
// {-42, -27}, {-40, -29}, {-36, -29}, {-32, -30}, {-28, -31}, {-24, -31}, {-21, -30}, {-19, -28}, {-19, -25},
|
||||
// {-20, -23}, {-21, -21}, {-24, -18}, {-26, -16}, {-27, -15}, {-27, -14},
|
||||
// };
|
||||
// for(size_t i = 0; i < polyline2.size() - 1; ++i) {
|
||||
// segments.push_back(cst_x_curve(polyline2[i], polyline2[i + 1]));
|
||||
// }
|
||||
|
||||
// CGAL::insert(arr, segments.begin(), segments.end());
|
||||
|
||||
// CGAL::draw_viewer(arr);
|
||||
// }
|
||||
|
||||
// void draw_segments_arr_5() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Segment_traits = CGAL::Arr_segment_traits_2<Exact_kernel>;
|
||||
// using Point_2 = Segment_traits::Point_2;
|
||||
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
|
||||
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
|
||||
// Arrangement arr;
|
||||
// auto traits = arr.traits();
|
||||
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
|
||||
|
||||
// std::vector<X_monotone_curve_2> segments;
|
||||
|
||||
// std::vector<Point_2> polyline1{
|
||||
// {11, 23}, {12, -13}, {17, -13}, {18, 1}, {18, 16}, {18, 23}, {15, 35}, {15, 44}, {18, 47}, {19, 42},
|
||||
// {19, 37}, {20, 28}, {23, 21}, {23, 9}, {24, -7}, {22, -15}, {20, -19}, {15, -19}, {10, -16}, {7, -14},
|
||||
// {7, -3}, {5, 11}, {1, 20}, {0, 35}, {1, 45}, {3, 51}, {5, 53}, {11, 53}, {19, 53}, {23, 49},
|
||||
// {25, 40}, {28, 31}, {34, 16}, {35, 7}, {38, -11}, {44, -11}, {43, -7}, {43, -5}, {42, 7}, {40, 23},
|
||||
// {38, 30}, {35, 49}, {19, 57}, {8, 58}, {-2, 55}, {-2, 30}, {-3, 15}, {-3, -16}, {1, -20}, {12, -22},
|
||||
// {20, -22}, {25, -21}, {26, -14}, {28, -3}, {27, 15}, {23, 31}, {22, 44}, {20, 49}, {15, 49}, {10, 46},
|
||||
// {8, 39}, {8, 32}, {8, 28}, {11, 23},
|
||||
// };
|
||||
// for(size_t i = 0; i < polyline1.size() - 1; ++i) {
|
||||
// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1]));
|
||||
// }
|
||||
|
||||
// CGAL::insert(arr, segments.begin(), segments.end());
|
||||
|
||||
// CGAL::draw_viewer(arr);
|
||||
// }
|
||||
|
||||
// void draw_segments_arr_6() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Segment_traits = CGAL::Arr_segment_traits_2<Exact_kernel>;
|
||||
// using Point_2 = Segment_traits::Point_2;
|
||||
// using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
|
||||
// using Arrangement = CGAL::Arrangement_2<Segment_traits>;
|
||||
// Arrangement arr;
|
||||
// auto traits = arr.traits();
|
||||
// auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
|
||||
|
||||
// std::vector<X_monotone_curve_2> segments;
|
||||
|
||||
// std::vector<Point_2> polyline1{
|
||||
// {9, -3}, {11, -34}, {26, -34}, {26, -8}, {26, -34}, {36, -34}, {36, -31}, {36, -27}, {37, -23}, {41, -23},
|
||||
// {47, -23}, {49, -16}, {49, -2}, {42, 10}, {41, 0}, {41, -19}, {41, 0}, {42, 10}, {30, 10}, {28, 6},
|
||||
// {28, 2}, {29, -30}, {28, 2}, {28, 6}, {30, 10}, {42, 10}, {29, 16}, {18, 12}, {9, -3},
|
||||
// };
|
||||
// for(size_t i = 0; i < polyline1.size() - 1; ++i) {
|
||||
// segments.push_back(cst_x_curve(polyline1[i], polyline1[i + 1]));
|
||||
// }
|
||||
|
||||
// CGAL::insert(arr, segments.begin(), segments.end());
|
||||
|
||||
// CGAL::draw_viewer(arr);
|
||||
// }
|
||||
|
||||
// void draw_linear_arr_1() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
|
||||
// using Point_2 = Traits::Point_2;
|
||||
// using Line_2 = Traits::Line_2;
|
||||
// using Ray_2 = Traits::Ray_2;
|
||||
// using Curve_2 = Traits::Curve_2;
|
||||
// using Arrangement = CGAL::Arrangement_2<Traits>;
|
||||
// using Face_const_handle = Arrangement::Face_const_handle;
|
||||
// using Halfedge_const_handle = Arrangement::Halfedge_const_iterator;
|
||||
// using X_monotone_curve_2 = Traits::X_monotone_curve_2;
|
||||
|
||||
// Arrangement arr;
|
||||
// auto x_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(1, 0)));
|
||||
// auto y_axis = X_monotone_curve_2(Ray_2(Point_2(0, 0), Point_2(0, 1)));
|
||||
// CGAL::insert(arr, x_axis);
|
||||
// CGAL::insert(arr, y_axis);
|
||||
|
||||
// CGAL::draw_viewer(arr);
|
||||
// }
|
||||
|
||||
void draw_linear_arr_2() {
|
||||
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
|
@ -148,17 +243,17 @@ void draw_linear_arr_2() {
|
|||
Arrangement arr;
|
||||
auto& traits = *arr.traits();
|
||||
// Insert a n*n grid, each cell is a square of size 5
|
||||
int n = 1;
|
||||
// for(int i = 0; i < n; ++i) {
|
||||
// Point_2 p1(i * 5, 0);
|
||||
// Point_2 p2(i * 5, 1);
|
||||
// CGAL::insert(arr, Curve_2(Line_2(p1, p2)));
|
||||
// }
|
||||
// for(int i = 0; i < n; ++i) {
|
||||
// Point_2 p1(0, i * 5);
|
||||
// Point_2 p2(1, i * 5);
|
||||
// CGAL::insert(arr, Curve_2(Line_2(p1, p2)));
|
||||
// }
|
||||
int n = 5;
|
||||
for(int i = 0; i < n; ++i) {
|
||||
Point_2 p1(i * 5, 0);
|
||||
Point_2 p2(i * 5, 1);
|
||||
CGAL::insert(arr, Curve_2(Line_2(p1, p2)));
|
||||
}
|
||||
for(int i = 0; i < n; ++i) {
|
||||
Point_2 p1(0, i * 5);
|
||||
Point_2 p2(1, i * 5);
|
||||
CGAL::insert(arr, Curve_2(Line_2(p1, p2)));
|
||||
}
|
||||
// Generate a inner square(2*2) for all cells
|
||||
// And an inner triangle for each square
|
||||
for(int i = 0; i < n; ++i) {
|
||||
|
|
@ -183,12 +278,49 @@ void draw_linear_arr_2() {
|
|||
CGAL::insert(arr, Curve_2(Segment_2(tri_p1, top)));
|
||||
}
|
||||
}
|
||||
|
||||
auto arr2 = arr;
|
||||
|
||||
std::cout << "Arrangement has " << arr.number_of_faces() << " faces." << std::endl;
|
||||
CGAL::draw_viewer(arr);
|
||||
}
|
||||
|
||||
// void draw_linear_arr_3() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
// using Traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
|
||||
// using Point_2 = Traits::Point_2;
|
||||
// using Line_2 = Traits::Line_2;
|
||||
// using Segment_2 = Traits::Segment_2;
|
||||
// using Ray_2 = Traits::Ray_2;
|
||||
// using Curve_2 = Traits::Curve_2;
|
||||
// using Arrangement = CGAL::Arrangement_2<Traits>;
|
||||
// using Face_const_handle = Arrangement::Face_const_handle;
|
||||
// using Halfedge_const_handle = Arrangement::Halfedge_const_iterator;
|
||||
// using X_monotone_curve_2 = Traits::X_monotone_curve_2;
|
||||
|
||||
// std::vector<Point_2> points{
|
||||
// {11, 23}, {12, -13}, {17, -13}, {18, 1}, {18, 16}, {18, 23}, {15, 35}, {15, 44}, {18, 47}, {19, 42},
|
||||
// {19, 37}, {20, 28}, {23, 21}, {23, 9}, {24, -7}, {22, -15}, {20, -19}, {15, -19}, {10, -16}, {7, -14},
|
||||
// {7, -3}, {5, 11}, {1, 20}, {0, 35}, {1, 45}, {3, 51}, {5, 53}, {11, 53}, {19, 53}, {23, 49},
|
||||
// {25, 40}, {28, 31}, {34, 16}, {35, 7}, {38, -11}, {44, -11}, {43, -7}, {43, -5}, {42, 7}, {40, 23},
|
||||
// {38, 30}, {35, 49}, {19, 57}, {8, 58}, {-2, 55}, {-2, 30}, {-3, 15}, {-3, -16}, {1, -20}, {12, -22},
|
||||
// {20, -22}, {25, -21}, {26, -14}, {28, -3}, {27, 15}, {23, 31}, {22, 44}, {20, 49}, {15, 49}, {10, 46},
|
||||
// {8, 39}, {8, 32}, {8, 28}, {11, 23},
|
||||
// };
|
||||
|
||||
// Arrangement arr;
|
||||
// auto& traits = *arr.traits();
|
||||
// std::vector<X_monotone_curve_2> segments;
|
||||
// for(size_t i = 0; i < points.size() - 1; ++i) {
|
||||
// Point_2 p1 = points[i];
|
||||
// Point_2 p2 = points[i + 1];
|
||||
// // create a segment
|
||||
// X_monotone_curve_2 seg = traits.construct_x_monotone_curve_2_object()(p1, p2);
|
||||
// segments.push_back(seg);
|
||||
// }
|
||||
|
||||
// // insert segments into the arrangement
|
||||
// CGAL::insert(arr, segments.begin(), segments.end());
|
||||
|
||||
// CGAL::draw_viewer(arr);
|
||||
// }
|
||||
// // supports segments
|
||||
// void draw_circle_segs_arr() {
|
||||
// using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
|
|
@ -311,7 +443,7 @@ using Point = Kernel::Point_2;
|
|||
// }
|
||||
|
||||
int main() {
|
||||
// draw_segments_arr_2();
|
||||
// draw_segments_arr_6();
|
||||
draw_linear_arr_2();
|
||||
// test_zone();
|
||||
// draw_conic_arcs_arr();
|
||||
|
|
|
|||
|
|
@ -52,11 +52,30 @@ int main() {
|
|||
using Point = K::Point_2;
|
||||
|
||||
Cdt cdt;
|
||||
std::vector<Point> outer = {Point(0, 0), Point(5, 0), Point(5, 5), Point(0, 5), Point(0, 0)};
|
||||
std::vector<Point> outer = {{4, 1}, {4, 4}, {2.5, 4}, {2.32026, 3.28104}, {2.32026, 2.64052},
|
||||
{2.5, 3}, {3, 2}, {2.32026, 2}, {2.32026, 3.28104}, {2.5, 4},
|
||||
{2.32026, 4}, {2.32026, 1}, {4, 1}};
|
||||
std::vector<Point> inner = {Point(0, 0), Point(0.5, 0), Point(0.5, 0.5), Point(0.5, 0),
|
||||
Point(1, 0), Point(1, 1), Point(0, 1)};
|
||||
std::vector<Point> outer_constraint = {Point(0, 0), Point(-1, -1), Point(5, 0), Point(6, -1),
|
||||
Point(5, 5), Point(6, 6), Point(0, 5), Point(-1, 6)};
|
||||
std::vector<Point> outer_constraint = {{4, 1},
|
||||
{4, 4},
|
||||
{2.5, 4},
|
||||
{2.32026, 3.28104},
|
||||
{1.32026, 3.28104},
|
||||
{1.32026, 2.64052},
|
||||
{2.32026, 2.64052},
|
||||
{2.5, 3},
|
||||
{3, 2},
|
||||
{2.32026, 2},
|
||||
{1.32026, 2},
|
||||
{1.32026, 3.28104},
|
||||
{2.32026, 3.28104},
|
||||
{2.5, 4},
|
||||
{2.32026, 4},
|
||||
{1.32026, 4},
|
||||
{1.32026, 1},
|
||||
{2.32026, 1},
|
||||
{4, 1}};
|
||||
|
||||
auto add_info = [](const Point& p) { return std::make_pair(p, 1); };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
#ifndef ZONE_EXP_H
|
||||
#define ZONE_EXP_H
|
||||
#include "CGAL/Arr_trapezoid_ric_point_location.h"
|
||||
#include <CGAL/Arr_algebraic_segment_traits_2.h>
|
||||
#include <CGAL/Arr_linear_traits_2.h>
|
||||
#include <CGAL/Arr_segment_traits_2.h>
|
||||
#include <CGAL/Arrangement_2.h>
|
||||
#include <CGAL/Arrangement_2/Arr_compute_zone_visitor.h>
|
||||
#include <CGAL/Arrangement_zone_2.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/draw_arrangement_2.h>
|
||||
|
||||
void test_zone() {
|
||||
using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel;
|
||||
using Segment_traits = CGAL::Arr_segment_traits_2<Exact_kernel>;
|
||||
using Point_2 = Segment_traits::Point_2;
|
||||
using Arrangement = CGAL::Arrangement_2<Segment_traits>;
|
||||
using X_monotone_curve_2 = Segment_traits::X_monotone_curve_2;
|
||||
using Traits = CGAL::Arr_linear_traits_2<Exact_kernel>;
|
||||
using Face_const_handle = Arrangement::Face_const_handle;
|
||||
using Halfedge_const_handle = Arrangement::Halfedge_const_handle;
|
||||
using Vertex_const_handle = Arrangement::Vertex_const_handle;
|
||||
using Face_handle = Arrangement::Face_handle;
|
||||
using Halfedge_handle = Arrangement::Halfedge_handle;
|
||||
using Vertex_handle = Arrangement::Vertex_handle;
|
||||
using Halfedge_const_handle = Arrangement::Halfedge_const_handle;
|
||||
|
||||
Arrangement arr;
|
||||
auto traits = arr.traits();
|
||||
|
||||
auto cst_x_curve = traits->construct_x_monotone_curve_2_object();
|
||||
auto tri = {
|
||||
cst_x_curve({-1, 0}, {1, 0}),
|
||||
cst_x_curve({1, 0}, {0, 3}),
|
||||
cst_x_curve({0, 3}, {-1, 0}),
|
||||
};
|
||||
CGAL::insert(arr, tri.begin(), tri.end());
|
||||
|
||||
// point location
|
||||
auto pl = CGAL::Arr_trapezoid_ric_point_location<Arrangement>(arr);
|
||||
|
||||
// test zone construction
|
||||
using Feature = std::variant<Vertex_handle, Halfedge_handle, Face_handle>;
|
||||
using Feature_vector = std::vector<Feature>;
|
||||
using Feature_vector_out_iter = std::back_insert_iterator<Feature_vector>;
|
||||
using Zone_visitor = CGAL::Arr_compute_zone_visitor<Arrangement, Feature_vector_out_iter>;
|
||||
|
||||
Feature_vector zone_features;
|
||||
Feature_vector_out_iter out_iter(zone_features);
|
||||
Zone_visitor zone_visitor(out_iter);
|
||||
auto cv = cst_x_curve({-1, 0}, {1, 0});
|
||||
CGAL::Arrangement_zone_2<Arrangement, Zone_visitor> zone(arr, &zone_visitor);
|
||||
|
||||
zone.init(cv, pl);
|
||||
zone.compute_zone();
|
||||
|
||||
for(const auto& feature : zone_features) {
|
||||
if(auto* hf = std::get_if<Halfedge_handle>(&feature)) {
|
||||
std::cout << "Halfedge: " << (*hf)->curve() << std::endl;
|
||||
Halfedge_const_handle che(*hf);
|
||||
std::cout << " const curve" << che->curve() << std::endl;
|
||||
} else if(auto* vh = std::get_if<Vertex_handle>(&feature)) {
|
||||
std::cout << "Vertex: " << (*vh)->point() << std::endl;
|
||||
} else if(auto* fh = std::get_if<Face_handle>(&feature)) {
|
||||
std::cout << "Face: " << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
CGAL::draw(arr);
|
||||
}
|
||||
#endif // ZONE_EXP_H
|
||||
|
|
@ -13,8 +13,8 @@
|
|||
#ifndef CGAL_BASIC_VIEWER_H
|
||||
#define CGAL_BASIC_VIEWER_H
|
||||
|
||||
#include <CGAL/Graphics_scene.h>
|
||||
#include <CGAL/license/GraphicsView.h>
|
||||
#include <CGAL/Graphics_scene.h>
|
||||
|
||||
// compatibility
|
||||
#if defined(CGAL_USE_BASIC_VIEWER) && !defined(CGAL_USE_BASIC_VIEWER_QT)
|
||||
|
|
@ -30,10 +30,14 @@
|
|||
// #elif defined(CGAL_USE_BASIC_VIEWER_GLFW)
|
||||
// #include <CGAL/GLFW/Basic_viewer.h>
|
||||
#else
|
||||
namespace CGAL {
|
||||
inline void draw_graphics_scene(const Graphics_scene&, const char* = "CGAL Basic Viewer") {
|
||||
std::cerr << "Impossible to draw, CGAL_USE_BASIC_VIEWER is not defined." << std::endl;
|
||||
}
|
||||
namespace CGAL
|
||||
{
|
||||
inline
|
||||
void draw_graphics_scene(const Graphics_scene&,
|
||||
const char* ="CGAL Basic Viewer")
|
||||
{
|
||||
std::cerr<<"Impossible to draw, CGAL_USE_BASIC_VIEWER is not defined."<<std::endl;
|
||||
}
|
||||
} // End namespace CGAL
|
||||
#endif
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue