diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp index c875dcbeacd..86ad76fe086 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp @@ -27,6 +27,7 @@ namespace Qt { static constexpr int margin = 2; +// ArrangementGraphicsItemBase::ArrangementGraphicsItemBase() : verticesPen(QPen(::Qt::blue, 3.)), edgesPen(QPen(::Qt::blue, 1.)) { @@ -38,13 +39,10 @@ ArrangementGraphicsItemBase::ArrangementGraphicsItemBase() : } // msvc2015 doesn't play well with polymorphic lambdas -namespace -{ -struct ExplicitLambda -{ +namespace { +struct ExplicitLambda { template - void operator()(demo_types::TypeHolder) - { + void operator()(demo_types::TypeHolder) { Arrangement* arr = nullptr; CGAL::assign(arr, arr_obj); agi = new ArrangementGraphicsItem(arr); @@ -53,10 +51,13 @@ struct ExplicitLambda ArrangementGraphicsItemBase*& agi; CGAL::Object& arr_obj; }; + } // anonymous namespace -ArrangementGraphicsItemBase* ArrangementGraphicsItemBase::create( - demo_types::TraitsType tt, CGAL::Object arr_obj) +// +ArrangementGraphicsItemBase* +ArrangementGraphicsItemBase::create(demo_types::TraitsType tt, + CGAL::Object arr_obj) { ArrangementGraphicsItemBase* agi; ExplicitLambda explicit_lambda{agi, arr_obj}; @@ -64,39 +65,35 @@ ArrangementGraphicsItemBase* ArrangementGraphicsItemBase::create( return agi; } +// const QPen& ArrangementGraphicsItemBase::getVerticesPen() const -{ - return this->verticesPen; -} +{ return this->verticesPen; } +// const QPen& ArrangementGraphicsItemBase::getEdgesPen() const -{ - return this->edgesPen; -} +{ return this->edgesPen; } +// void ArrangementGraphicsItemBase::setVerticesPen(const QPen& pen) -{ - this->verticesPen = pen; -} +{ this->verticesPen = pen; } +// void ArrangementGraphicsItemBase::setEdgesPen(const QPen& pen) -{ - this->edgesPen = pen; -} +{ this->edgesPen = pen; } +// template ArrangementGraphicsItem::ArrangementGraphicsItem(Arrangement* arr_) : - arr(arr_), pointsGraphicsItem(new PointsGraphicsItem(this)) + arr(arr_), + pointsGraphicsItem(new PointsGraphicsItem(this)) { this->updatePointsItem(); this->updateBoundingBox(); } +// template < typename Arr_ > -QRectF -ArrangementGraphicsItem< Arr_ >:: -boundingRect( ) const -{ +QRectF ArrangementGraphicsItem< Arr_ >::boundingRect() const { qreal xmin = -(std::numeric_limits::max)() / 4; qreal ymin = -(std::numeric_limits::max)() / 4; qreal xmax = (std::numeric_limits::max)() / 4; @@ -115,48 +112,47 @@ boundingRect( ) const return {QPointF{xmin, ymin}, QPointF{xmax, ymax}}; } +// template < typename Arr_ > void ArrangementGraphicsItem< Arr_ >:: paint(QPainter* painter, const QStyleOptionGraphicsItem* /* option */, QWidget* /*widget*/) -{ - this->paint(painter, *(arr->traits())); -} +{ this->paint(painter, *(arr->traits())); } +// template template -void ArrangementGraphicsItem::paint( - QPainter* painter, const TTraits& traits) -{ +void ArrangementGraphicsItem::paint(QPainter* painter, + const TTraits& traits) { this->paintFaces(painter); this->paintEdges(painter, traits); } +// template template -void ArrangementGraphicsItem::paint( - QPainter* painter, - const CGAL::Arr_algebraic_segment_traits_2& traits) -{ +void ArrangementGraphicsItem:: +paint(QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2& traits) { this->paintWithFloodFill(painter, traits); } +// template template -void ArrangementGraphicsItem::paint( - QPainter* painter, - const CGAL::Arr_rational_function_traits_2& traits) -{ +void ArrangementGraphicsItem:: +paint(QPainter* painter, + const CGAL::Arr_rational_function_traits_2& traits) { this->paintWithFloodFill(painter, traits); } +// template template -void ArrangementGraphicsItem::paintWithFloodFill( - QPainter* painter, const TTraits& traits) -{ +void ArrangementGraphicsItem:: +paintWithFloodFill(QPainter* painter, const TTraits& traits) { auto windowRect = painter->window(); auto width = windowRect.width(); auto height = windowRect.height(); @@ -171,15 +167,12 @@ void ArrangementGraphicsItem::paintWithFloodFill( // also useful with algebraic curves as sometimes pixels on the borders // aren't painted, and the flood algorithm 'leaks' static constexpr QRgb white = 0xFFFFFFFF; - for (uint16_t i = 0; i < margin; i++) - { - for (uint16_t j = 0; j < width; j++) - { + for (uint16_t i = 0; i < margin; i++) { + for (uint16_t j = 0; j < width; j++) { st[i * width + j] = white; st[(height - 1 - i) * width + j] = white; } - for (uint16_t j = 0; j < height; j++) - { + for (uint16_t j = 0; j < height; j++) { st[j * width + i] = white; st[j * width + (width - 1 - i)] = white; } @@ -204,11 +197,11 @@ void ArrangementGraphicsItem::paintWithFloodFill( painter->setTransform(painterTransform); } +// template template -void ArrangementGraphicsItem::paintEdges( - QPainter* painter, const TTraits&) -{ +void ArrangementGraphicsItem::paintEdges(QPainter* painter, + const TTraits&) { auto painterOstream = ArrangementPainterOstream(painter, this->boundingRect()); @@ -223,11 +216,12 @@ void ArrangementGraphicsItem::paintEdges( } } +// template template -void ArrangementGraphicsItem::paintEdges( - QPainter* painter, const CGAL::Arr_algebraic_segment_traits_2&) -{ +void ArrangementGraphicsItem:: +paintEdges(QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2&) { using TTraits = CGAL::Arr_algebraic_segment_traits_2; auto painterOstream = @@ -240,10 +234,10 @@ void ArrangementGraphicsItem::paintEdges( painterOstream.paintEdges(arr->edges_begin(), arr->edges_end()); } +// template -void ArrangementGraphicsItem::paintFacesFloodFill( - QPainter* painter, QImage& image) -{ +void ArrangementGraphicsItem::paintFacesFloodFill(QPainter* painter, + QImage& image) { static constexpr QRgb invalid_rgb = 0; QRgb* raw_img = reinterpret_cast(image.bits()); @@ -267,10 +261,8 @@ void ArrangementGraphicsItem::paintFacesFloodFill( static constexpr int tot_margin = margin + 2; auto cur_img_line = raw_img + tot_margin * width; - for (uint16_t y = tot_margin; y + 1 + tot_margin < height; y++) - { - for (uint16_t x = tot_margin; x + 1 + tot_margin < width; x++) - { + for (uint16_t y = tot_margin; y + 1 + tot_margin < height; y++) { + for (uint16_t x = tot_margin; x + 1 + tot_margin < width; x++) { // just to account for rendering errors // make sure the pixel falls in the right face if ( @@ -305,24 +297,24 @@ void ArrangementGraphicsItem::paintFacesFloodFill( } } -template < typename Arr_ > -void ArrangementGraphicsItem< Arr_ >::updateBoundingBox( ) -{ +// +template +void ArrangementGraphicsItem::updateBoundingBox() { this->prepareGeometryChange(); this->bb = {}; - ConstructBoundingBox construct_bounding_box; + ConstructBoundingBox ctr_bbox(*(this->arr->geometry_traits())); for (auto it = this->arr->edges_begin(); it != this->arr->edges_end(); ++it) - this->bb += construct_bounding_box(it->curve()); + this->bb += ctr_bbox(it->curve()); for (auto it = this->arr->vertices_begin(); it != this->arr->vertices_end(); ++it) - this->bb += construct_bounding_box(it->point()); + this->bb += ctr_bbox(it->point()); } +// template -void ArrangementGraphicsItem::updatePointsItem() -{ +void ArrangementGraphicsItem::updatePointsItem() { this->pointsGraphicsItem->clear(); for (auto it = this->arr->vertices_begin(); it != this->arr->vertices_end(); ++it) @@ -332,31 +324,27 @@ void ArrangementGraphicsItem::updatePointsItem() } } -template < typename Arr_ > -void ArrangementGraphicsItem< Arr_ >::modelChanged( ) -{ +// +template +void ArrangementGraphicsItem::modelChanged() { this->updatePointsItem(); - this->updateBoundingBox( ); - this->update( ); + this->updateBoundingBox(); + this->update(); } template < typename Arr_ > void -ArrangementGraphicsItem< Arr_ >:: -paintFace( Face_handle f, QPainter* painter ) -{ +ArrangementGraphicsItem::paintFace( Face_handle f, QPainter* painter) { if (f->visited()) return; Hole_iterator hit; // holes iterator this->paintFace(f, painter, *(arr->traits())); f->set_visited(true); - for (hit = f->holes_begin(); hit != f->holes_end(); ++hit) - { + for (hit = f->holes_begin(); hit != f->holes_end(); ++hit) { // Traverse in clockwise order Ccb_halfedge_circulator cc = *hit; - do - { + do { Halfedge_handle he = cc; Halfedge_handle he2 = he->twin(); Face_handle inner_face = he2->face(); @@ -367,13 +355,14 @@ paintFace( Face_handle f, QPainter* painter ) } } +// template template -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, const CGAL::Arr_segment_traits_2&) -{ - if (!f->is_unbounded()) // f is not the unbounded face - { +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_segment_traits_2&) { + if (!f->is_unbounded()) { + // f is not the unbounded face QVector< QPointF > pts; // holds the points of the polygon /* running with around the outer of the face and generate from it @@ -403,13 +392,13 @@ void ArrangementGraphicsItem::paintFace( } } +// template template -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, const CGAL::Arr_polyline_traits_2&) -{ - if (!f->is_unbounded()) - { +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_polyline_traits_2&) { + if (!f->is_unbounded()) { QVector< QPointF > pts; // holds the points of the polygon CGAL::Qt::Converter convert; @@ -433,8 +422,7 @@ void ArrangementGraphicsItem::paintFace( auto first_subcurve = curve.subcurves_begin(); QPointF src_first = convert(first_subcurve->source()); - if (src_first == src) - { + if (src_first == src) { for (auto it = curve.subcurves_begin(); it != curve.subcurves_end(); ++it) { @@ -442,8 +430,7 @@ void ArrangementGraphicsItem::paintFace( pts.push_back(convert(it->target())); } } - else - { + else { QVector pts_tmp; for (auto it = curve.subcurves_begin(); it != curve.subcurves_end(); ++it) @@ -461,19 +448,19 @@ void ArrangementGraphicsItem::paintFace( painter->setBrush(f->color()); painter->drawPolygon( pgn ); } - else - { + else { QRectF rect = this->viewportRect( ); QColor color = f->color(); painter->fillRect(rect, color); } } +// template template -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, - const CGAL::Arr_algebraic_segment_traits_2& /* traits */) +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2& /* traits */) { if (f->is_unbounded()) return; @@ -489,8 +476,7 @@ void ArrangementGraphicsItem::paintFace( * polygon */ Ccb_halfedge_circulator cc = f->outer_ccb(); - do - { + do { if (this->antenna(cc)) continue; auto points = painterOstream.getPointsList(cc->curve()); @@ -499,14 +485,12 @@ void ArrangementGraphicsItem::paintFace( double src_x = CGAL::to_double(cc->source()->point().x()); double tgt_x = CGAL::to_double(cc->target()->point().x()); - if (src_x < tgt_x) - { + if (src_x < tgt_x) { for (auto& vec : points) for(auto& vit : vec) pts.push_back({vit.first, vit.second}); } - else - { + else { for (auto vecit = points.rbegin(); vecit != points.rend(); ++vecit) for (auto vit = vecit->rbegin(); vit != vecit->rend(); ++vit) pts.push_back({vit->first, vit->second}); @@ -521,9 +505,9 @@ void ArrangementGraphicsItem::paintFace( painter->restore(); } +// template -void ArrangementGraphicsItem::paintFaces(QPainter* painter) -{ +void ArrangementGraphicsItem::paintFaces(QPainter* painter) { QPen pen = painter->pen(); painter->setPen(this->facesPen); @@ -537,18 +521,16 @@ void ArrangementGraphicsItem::paintFaces(QPainter* painter) painter->setPen(pen); } +// template -void ArrangementGraphicsItem::visit_ccb_faces( - Face_handle& fh, QPainter* painter) -{ +void ArrangementGraphicsItem::visit_ccb_faces(Face_handle& fh, + QPainter* painter) { this->paintFace(fh, painter); Ccb_halfedge_circulator cc = fh->outer_ccb(); - do - { + do { Halfedge he = *cc; - if (!he.twin()->face()->visited()) - { + if (!he.twin()->face()->visited()) { Face_handle nei = he.twin()->face(); this->visit_ccb_faces(nei, painter); } @@ -556,34 +538,34 @@ void ArrangementGraphicsItem::visit_ccb_faces( } while (++cc != fh->outer_ccb()); } +// template -bool ArrangementGraphicsItem::antenna(Halfedge_handle h) -{ +bool ArrangementGraphicsItem::antenna(Halfedge_handle h) { Halfedge_handle twin = h->twin(); return (twin->face() == h->face()); } +// template template void ArrangementGraphicsItem::paintFace(Face_handle, QPainter*, ArrTraits) -{ -} +{} +// template template -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, - const CGAL::Arr_conic_traits_2&) +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_conic_traits_2& traits) { - if (!f->is_unbounded()) // f is not the unbounded face - { + if (!f->is_unbounded()) { + // f is not the unbounded face QVector pts; // holds the points of the polygon /* running with around the outer of the face and generate from it * polygon */ Ccb_halfedge_circulator cc = f->outer_ccb(); - do - { + do { if (this->antenna(cc)) { continue; } Halfedge_handle he = cc; @@ -603,8 +585,7 @@ void ArrangementGraphicsItem::paintFace( QPoint coord_target_viewport = this->fromScene(coord_target); if (c.orientation() == CGAL::COLLINEAR) { pts.push_back(coord_source); } - else - { + else { // If the curve is monotone, than its source and its target has the // extreme x coordinates on this curve. bool is_source_left = (sx < tx); @@ -620,20 +601,17 @@ void ArrangementGraphicsItem::paintFace( int start; int end; int step; - if (is_source_left) - { + if (is_source_left) { start = x_min + DRAW_FACTOR; end = x_max; step = DRAW_FACTOR; } - else - { + else { start = x_max; end = x_min; step = -DRAW_FACTOR; } - for (int x = start; x < end; x += step) - { + for (int x = start; x < end; x += step) { double curr_x = this->toScene(QPoint{x, 0}).x(); AlgKernel ker; Point_2 curr_p(curr_x, 0); @@ -643,7 +621,7 @@ void ArrangementGraphicsItem::paintFace( ker.compare_x_2_object()(curr_p, c.right()) != CGAL::LARGER)) { continue; } - auto px = c.point_at_x(curr_p); + auto px = traits.point_at_x(c, curr_p); double curr_y = CGAL::to_double(px.y()); QPointF curr(curr_x, curr_y); pts.push_back(curr); @@ -656,33 +634,30 @@ void ArrangementGraphicsItem::paintFace( painter->setBrush(f->color()); painter->drawPolygon(pgn); } - else - { + else { QRectF rect = this->viewportRect(); QColor color = f->color(); painter->fillRect(rect, color); } } +// template -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, - const CGAL::Arr_Bezier_curve_traits_2< - RatKernel, AlgKernel, NtTraits, BoundingTraits>&) +template +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_Bezier_curve_traits_2 + &) { - if (!f->is_unbounded()) - { + if (!f->is_unbounded()) { ArrangementPainterOstream painterOstream{ painter, this->boundingRect()}; painterOstream.setScene(this->getScene()); QVector pts; Ccb_halfedge_circulator cc = f->outer_ccb(); - do - { + do { if (this->antenna(cc)) continue; const X_monotone_curve_2& curve = cc->curve(); @@ -702,31 +677,29 @@ void ArrangementGraphicsItem::paintFace( painter->setBrush(color); painter->drawPolygon(pgn); } - else - { + else { QRectF rect = this->viewportRect(); QColor color = f->color(); painter->fillRect(rect, color); } } +// template template -void ArrangementGraphicsItem::paintFace( - Face_handle f, QPainter* painter, - const CGAL::Arr_linear_traits_2& /* traits */) +void ArrangementGraphicsItem:: +paintFace(Face_handle f, QPainter* painter, + const CGAL::Arr_linear_traits_2& /* traits */) { QVector pts; // holds the points of the polygon QColor color = f->color(); painter->setBrush(color); - if (!f->is_unbounded()) - { + if (!f->is_unbounded()) { /* running with around the outer of the face and generate from it * polygon */ Ccb_halfedge_circulator cc = f->outer_ccb(); - do - { + do { Halfedge_handle hh = cc; if (this->antenna(hh)) continue; @@ -738,12 +711,10 @@ void ArrangementGraphicsItem::paintFace( painter->drawPolygon(QPolygonF{pts}); } - else - { + else { std::vector halfedges; Ccb_halfedge_circulator cc = f->outer_ccb(); - do - { + do { Halfedge_handle hh = cc; if (cc->is_fictitious() || this->antenna(hh)) continue; @@ -753,8 +724,7 @@ void ArrangementGraphicsItem::paintFace( QRectF rect = this->viewportRect(); - switch (halfedges.size()) - { + switch (halfedges.size()) { // one unbounded face case 0: { painter->fillRect(rect, color); @@ -766,39 +736,33 @@ void ArrangementGraphicsItem::paintFace( auto&& line = curve.line(); // horizontal or mostly horizontal - if (CGAL::abs(line.b()) > CGAL::abs(line.a())) - { + if (CGAL::abs(line.b()) > CGAL::abs(line.a())) { qreal left_y = CGAL::to_double(line.y_at_x(rect.left())); qreal right_y = CGAL::to_double(line.y_at_x(rect.right())); pts.push_back({rect.left(), left_y}); pts.push_back({rect.right(), right_y}); - if (cc->direction() == ARR_LEFT_TO_RIGHT) - { + if (cc->direction() == ARR_LEFT_TO_RIGHT) { pts.push_back(rect.bottomRight()); pts.push_back(rect.bottomLeft()); } - else - { + else { pts.push_back(rect.topRight()); pts.push_back(rect.topLeft()); } } // vertical or mostly vertical - else - { + else { qreal top_x = CGAL::to_double(line.x_at_y(rect.top())); qreal bottom_x = CGAL::to_double(line.x_at_y(rect.bottom())); pts.push_back({top_x, rect.top()}); pts.push_back({bottom_x, rect.bottom()}); - if (cc->direction() == ARR_LEFT_TO_RIGHT) - { + if (cc->direction() == ARR_LEFT_TO_RIGHT) { pts.push_back(rect.bottomLeft()); pts.push_back(rect.topLeft()); } - else - { + else { pts.push_back(rect.bottomRight()); pts.push_back(rect.topRight()); } @@ -806,121 +770,111 @@ void ArrangementGraphicsItem::paintFace( painter->drawPolygon(QPolygonF{pts}); break; - } - // general case - default: { - using Vertex_handle = typename Arrangement::Vertex_handle; + } + // general case + default: { + using Vertex_handle = typename Arrangement::Vertex_handle; - auto handle_vertex = [&](Halfedge_handle halfedge, Vertex_handle vertex) - { - // dx * y = dy * x + c - typename Kernel_::RT dx, dy, c; + auto handle_vertex = [&](Halfedge_handle halfedge, Vertex_handle vertex) + { + // dx * y = dy * x + c + typename Kernel_::RT dx, dy, c; - auto&& curve = halfedge->curve(); - if (curve.is_segment()) - { - auto&& src = halfedge->source()->point(); - auto&& tgt = halfedge->target()->point(); - dy = tgt.y() - src.y(); - dx = tgt.x() - src.x(); - c = dx * src.y() - dy * src.x(); - } - else if(curve.is_ray()) - { - auto&& ray = curve.ray(); - auto&& dir = ray.direction(); - auto&& src = ray.source(); - dy = dir.dy(); - dx = dir.dx(); - c = dx * src.y() - dy * src.x(); - } - // halfedge can be a line in case of a face between two parallel lines - else - { - auto&& line = curve.line(); - auto param_in_x = vertex->parameter_space_in_x(); - auto param_in_y = vertex->parameter_space_in_y(); - dy = line.a(); - dx = -line.b(); - c = line.c(); + auto&& curve = halfedge->curve(); + if (curve.is_segment()) { + auto&& src = halfedge->source()->point(); + auto&& tgt = halfedge->target()->point(); + dy = tgt.y() - src.y(); + dx = tgt.x() - src.x(); + c = dx * src.y() - dy * src.x(); + } + else if(curve.is_ray()) { + auto&& ray = curve.ray(); + auto&& dir = ray.direction(); + auto&& src = ray.source(); + dy = dir.dy(); + dx = dir.dx(); + c = dx * src.y() - dy * src.x(); + } + // halfedge can be a line in case of a face between two parallel lines + else { + auto&& line = curve.line(); + auto param_in_x = vertex->parameter_space_in_x(); + auto param_in_y = vertex->parameter_space_in_y(); + dy = line.a(); + dx = -line.b(); + c = line.c(); - if ( - (param_in_x == LEFT_BOUNDARY && CGAL::is_positive(dx)) || - (param_in_x == RIGHT_BOUNDARY && CGAL::is_negative(dx)) || - (param_in_y == BOTTOM_BOUNDARY && CGAL::is_positive(dy)) || - (param_in_y == TOP_BOUNDARY && CGAL::is_negative(dy))) - { - dx = -dx; - dy = -dy; - c = -c; - } - } - // horizontal or mostly horizontal - if (CGAL::abs(dx) > CGAL::abs(dy)) - { - qreal x = CGAL::is_positive(dx) ? rect.right() + rect.width() - : rect.left() - rect.width(); - // in case vertex is a finite point - if (!vertex->is_at_open_boundary()) - { - auto p = vertex->point(); - // check not far away - if ( - (CGAL::is_positive(dx) && p.x() < x) || - (CGAL::is_negative(dx) && p.x() > x)) - { - pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); - return; - } - } - // in case vertex is far away (finite or at infinity), get a nearer - // point on the line - // i.e. in case farther than twice the width of the viewport - qreal y = CGAL::to_double((dy / dx) * x + (c / dx)); - pts.push_back({x, y}); - } - // vertical or mostly vertical - else - { - qreal y = CGAL::is_positive(dy) ? rect.bottom() + rect.height() - : rect.top() - rect.height(); - // in case vertex is a finite point - if (!vertex->is_at_open_boundary()) - { - auto p = vertex->point(); - // check not far away - if ( - (CGAL::is_positive(dy) && p.y() < y) || - (CGAL::is_negative(dy) && p.y() > y)) - { - pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); - return; - } - } - // in case vertex is far away (finite or at infinity), get a nearer - // point on the line - // i.e. in case farther than twice the height of the viewport - qreal x = CGAL::to_double((dx / dy) * y - (c / dy)); - pts.push_back({x, y}); - } - }; + if ((param_in_x == LEFT_BOUNDARY && CGAL::is_positive(dx)) || + (param_in_x == RIGHT_BOUNDARY && CGAL::is_negative(dx)) || + (param_in_y == BOTTOM_BOUNDARY && CGAL::is_positive(dy)) || + (param_in_y == TOP_BOUNDARY && CGAL::is_negative(dy))) + { + dx = -dx; + dy = -dy; + c = -c; + } + } + // horizontal or mostly horizontal + if (CGAL::abs(dx) > CGAL::abs(dy)) { + qreal x = CGAL::is_positive(dx) ? + rect.right() + rect.width() : rect.left() - rect.width(); + // in case vertex is a finite point + if (!vertex->is_at_open_boundary()) { + auto p = vertex->point(); + // check not far away + if ((CGAL::is_positive(dx) && p.x() < x) || + (CGAL::is_negative(dx) && p.x() > x)) + { + pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); + return; + } + } + // in case vertex is far away (finite or at infinity), get a nearer + // point on the line + // i.e. in case farther than twice the width of the viewport + qreal y = CGAL::to_double((dy / dx) * x + (c / dx)); + pts.push_back({x, y}); + } + // vertical or mostly vertical + else { + qreal y = CGAL::is_positive(dy) ? + rect.bottom() + rect.height() : rect.top() - rect.height(); + // in case vertex is a finite point + if (!vertex->is_at_open_boundary()) { + auto p = vertex->point(); + // check not far away + if ((CGAL::is_positive(dy) && p.y() < y) || + (CGAL::is_negative(dy) && p.y() > y)) + { + pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); + return; + } + } + // in case vertex is far away (finite or at infinity), get a nearer + // point on the line + // i.e. in case farther than twice the height of the viewport + qreal x = CGAL::to_double((dx / dy) * y - (c / dy)); + pts.push_back({x, y}); + } + }; - for (auto hh : halfedges) - { - handle_vertex(hh, hh->source()); - handle_vertex(hh, hh->target()); - } + for (auto hh : halfedges) { + handle_vertex(hh, hh->source()); + handle_vertex(hh, hh->target()); + } - painter->drawPolygon(QPolygonF{pts}); - break; - } + painter->drawPolygon(QPolygonF{pts}); + break; + } } } } // TODO: clean all this portion up (move it somewhere?), it's ugly! -static CGAL::Bbox_2 reject_not_in_allowable_range( - const CGAL::Bbox_2& box, const CGAL::Bbox_2& allowable_range) +static CGAL::Bbox_2 +reject_not_in_allowable_range(const CGAL::Bbox_2& box, + const CGAL::Bbox_2& allowable_range) { double xmin = std::numeric_limits::infinity(); double ymin = std::numeric_limits::infinity(); @@ -934,25 +888,23 @@ static CGAL::Bbox_2 reject_not_in_allowable_range( return {xmin, ymin, xmax, ymax}; } -static bool isFinite(const CGAL::Bbox_2& box) -{ - return !std::isinf(box.xmin()) && !std::isinf(box.xmax()) && - !std::isinf(box.ymin()) && !std::isinf(box.ymax()); +// +static bool isFinite(const CGAL::Bbox_2& box) { + return ! std::isinf(box.xmin()) && !std::isinf(box.xmax()) && + ! std::isinf(box.ymin()) && !std::isinf(box.ymax()); } -static CGAL::Bbox_2 addMargins(const CGAL::Bbox_2& box) -{ +// +static CGAL::Bbox_2 addMargins(const CGAL::Bbox_2& box) { // add margin to bounding box double x_margin; double y_margin; - if (box.xmin() == box.xmax() || box.ymin() == box.ymax()) - { + if (box.xmin() == box.xmax() || box.ymin() == box.ymax()) { static constexpr float const_margin = 50; x_margin = const_margin; y_margin = const_margin; } - else - { + else { static constexpr double prop_margin = 0.10; x_margin = (box.xmax() - box.xmin()) * prop_margin; y_margin = (box.ymax() - box.ymin()) * prop_margin; @@ -962,25 +914,23 @@ static CGAL::Bbox_2 addMargins(const CGAL::Bbox_2& box) box.ymax() + y_margin}; } +// template CGAL::Bbox_2 -findOtherInterestingPoints(const Arr_*, const CGAL::Bbox_2&) -{ - return {}; -} +findOtherInterestingPoints(const Arr_*, const CGAL::Bbox_2&) { return {}; } #ifdef CGAL_USE_CORE + +// template static const auto& -getXyCurves(const CGAL::Arr_algebraic_segment_traits_2* traits) -{ +getXyCurves(const CGAL::Arr_algebraic_segment_traits_2* traits) { // the traits object is only needed the first time // this assumes that X_monotone_curves created from the first traits object // will work with arrangements with a different object using Traits = CGAL::Arr_algebraic_segment_traits_2; static std::vector xy_curves; - if (xy_curves.empty()) - { + if (xy_curves.empty()) { typedef typename Traits::Polynomial_2 Polynomial_2; auto construct_curve = traits->construct_curve_2_object(); auto make_x_monotone = traits->make_x_monotone_2_object(); @@ -1003,27 +953,25 @@ getXyCurves(const CGAL::Arr_algebraic_segment_traits_2* traits) return xy_curves; } +// template <> -CGAL::Bbox_2 findOtherInterestingPoints( - const demo_types::DemoTypes::Alg_seg_arr* arr, - const CGAL::Bbox_2& allowable_range) -{ +CGAL::Bbox_2 +findOtherInterestingPoints +(const demo_types::DemoTypes::Alg_seg_arr* arr, + const CGAL::Bbox_2& allowable_range) { using Traits = demo_types::DemoTypes::Alg_seg_traits; CGAL::Bbox_2 bb = {}; std::vector intersections; - for (auto it = arr->edges_begin(); it != arr->edges_end(); ++it) - { + for (auto it = arr->edges_begin(); it != arr->edges_end(); ++it) { for (auto& arc : getXyCurves(arr->traits())) if (arc.is_vertical() != it->curve().is_vertical()) it->curve().intersections(arc, std::back_inserter(intersections)); } - for (auto it = intersections.begin(); it != intersections.end(); it++) - { + for (auto it = intersections.begin(); it != intersections.end(); it++) { std::pair point_multiplicity; CGAL::assign(point_multiplicity, *it); auto& point = point_multiplicity.first; - if (point.location() == CGAL::ARR_INTERIOR) - { + if (point.location() == CGAL::ARR_INTERIOR) { auto xy = point.to_double(); bb += reject_not_in_allowable_range( {xy.first, xy.second, xy.first, xy.second}, allowable_range); @@ -1031,30 +979,28 @@ CGAL::Bbox_2 findOtherInterestingPoints( } return bb; } + #endif // CGAL_USE_CORE - +// template -QRectF ArrangementGraphicsItem::getInterestingViewport() const -{ +QRectF ArrangementGraphicsItem::getInterestingViewport() const { QRectF scene_rect = this->getScene()->sceneRect(); CGAL::Bbox_2 scene_bbox = { scene_rect.left(), scene_rect.top(), scene_rect.right(), scene_rect.bottom()}; - ConstructBoundingBox construct_bounding_box; + ConstructBoundingBox ctr_bbox(*(this->arr->geometry_traits())); CGAL::Bbox_2 bounding_box = {}; - for (auto it = this->arr->edges_begin(); - it != this->arr->edges_end(); ++it) - { + for (auto it = this->arr->edges_begin(); it != this->arr->edges_end(); ++it) { bounding_box += reject_not_in_allowable_range( - construct_bounding_box(it->curve()), scene_bbox); + ctr_bbox(it->curve()), scene_bbox); } for (auto it = this->arr->vertices_begin(); it != this->arr->vertices_end(); ++it) { bounding_box += reject_not_in_allowable_range( - construct_bounding_box(it->point()), scene_bbox); + ctr_bbox(it->point()), scene_bbox); } if (!isFinite(bounding_box)) @@ -1066,10 +1012,9 @@ QRectF ArrangementGraphicsItem::getInterestingViewport() const bounding_box = addMargins(bounding_box); - return QRectF( - bounding_box.xmin(), bounding_box.ymin(), - bounding_box.xmax() - bounding_box.xmin(), - bounding_box.ymax() - bounding_box.ymin()); + return QRectF(bounding_box.xmin(), bounding_box.ymin(), + bounding_box.xmax() - bounding_box.xmin(), + bounding_box.ymax() - bounding_box.ymin()); } } // namespace QT diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp index 5a9be364d6f..dc95842d6e1 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp @@ -19,13 +19,10 @@ #include #include -template < - typename Arrangement, - typename Traits = typename Arrangement::Geometry_traits_2> -struct ArrReader -{ - Arrangement* operator()(std::ifstream& ifs) - { +template +struct ArrReader { + Arrangement* operator()(std::ifstream& ifs) { using Text_formatter = CGAL::Arr_text_formatter; using ArrFormatter = CGAL::Arr_with_history_text_formatter; @@ -37,33 +34,34 @@ struct ArrReader }; #ifdef CGAL_USE_CORE -template < - typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, - typename Nt_traits_> -struct ArrReader< - Arrangement, CGAL::Arr_conic_traits_2> + +// Specialization of `ArrReader` for the conic traits. +template +struct ArrReader> { using Traits = typename Arrangement::Geometry_traits_2; using Curve_2 = typename Arrangement::Curve_2; - Arrangement* operator()(std::ifstream& ifs) - { - Conic_reader conicReader; + Arrangement* operator()(std::ifstream& ifs) { + auto arr = new Arrangement(); + const auto* traits = arr->geometry_traits(); + Conic_reader conicReader(*traits);; std::vector curve_list; CGAL::Bbox_2 bbox; conicReader.read_data(ifs, std::back_inserter(curve_list), bbox); - auto arr = new Arrangement(); CGAL::insert(*arr, curve_list.begin(), curve_list.end()); return arr; } }; -template < - typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, - typename Nt_traits_, typename Bounding_traits_> -struct ArrReader< - Arrangement, CGAL::Arr_Bezier_curve_traits_2< - Rat_kernel_, Alg_kernel_, Nt_traits_, Bounding_traits_>> +// Specialization of `ArrReader` for the Bezier traits. +template +struct ArrReader> { Arrangement* operator()(std::ifstream&) { return nullptr; } }; @@ -77,8 +75,7 @@ struct ArrReader< #endif std::pair -ArrangementIO::read(std::ifstream& ifs) -{ +ArrangementIO::read(std::ifstream& ifs) { // read type info while (ifs.peek() == '#' || std::isspace(ifs.peek())) ifs.get(); @@ -95,13 +92,10 @@ ArrangementIO::read(std::ifstream& ifs) return res; } -template < - typename Arrangement, - typename Traits = typename Arrangement::Geometry_traits_2> -struct ArrWriter -{ - void operator()(Arrangement* arr, std::ofstream& ofs) - { +template +struct ArrWriter { + void operator()(Arrangement* arr, std::ofstream& ofs) { using TextFormatter = CGAL::Arr_text_formatter; using ArrFormatter = CGAL::Arr_with_history_text_formatter; @@ -111,19 +105,18 @@ struct ArrWriter }; #ifdef CGAL_USE_CORE -template < - typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, - typename Nt_traits_> -struct ArrWriter< - Arrangement, CGAL::Arr_conic_traits_2> + +template +struct ArrWriter> { using Traits = typename Arrangement::Geometry_traits_2; using Curve_2 = typename Arrangement::Curve_2; - void operator()(Arrangement* arr, std::ofstream& ofs) - { - Conic_reader conicReader; - conicReader.write_data(ofs, arr->curves_begin(), arr->curves_end()); + void operator()(Arrangement* arr, std::ofstream& ofs) { + Conic_reader conic_reader(*(arr->geometry_traits())); + conic_reader.write_data(ofs, arr->curves_begin(), arr->curves_end()); } }; @@ -145,9 +138,9 @@ struct ArrWriter< }; #endif -bool ArrangementIO::write( - const std::pair& arr_pair, - std::ofstream& ofs) +bool ArrangementIO::write(const std::pair& arr_pair, + std::ofstream& ofs) { auto tt = arr_pair.second; auto arr_obj = arr_pair.first; @@ -159,8 +152,7 @@ bool ArrangementIO::write( demo_types::visitArrangementType(tt, [&](auto type_holder) { using Arrangement = typename decltype(type_holder)::type; Arrangement* arr; - if (CGAL::assign(arr, arr_obj)) - { + if (CGAL::assign(arr, arr_obj)) { ArrWriter{}(arr, ofs); result = true; } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp index 3616dc9fd64..2ea11fd5d49 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp @@ -15,55 +15,44 @@ #include -namespace CGAL -{ -namespace Qt -{ +namespace CGAL { +namespace Qt { -// Instantiation of Arr_segment_traits_2 +// Specialization of `ArrangementPainterOstream` for the segment traits. template ArrangementPainterOstream>& -ArrangementPainterOstream>::operator<<( - const X_monotone_curve_2& curve) -{ +ArrangementPainterOstream>:: +operator<<(const X_monotone_curve_2& curve) { const Point_2& p1 = curve.source(); const Point_2& p2 = curve.target(); Segment_2 seg(p1, p2); // skip segments outside our view QRectF seg_bb = this->convert(seg.bbox()); - if ( - this->clippingRect.isValid() && !this->clippingRect.intersects(seg_bb) && - (!seg.is_horizontal() && !seg.is_vertical())) - { return *this; } + if (this->clippingRect.isValid() && + ! this->clippingRect.intersects(seg_bb) && + ! seg.is_horizontal() && ! seg.is_vertical()) + return *this; this->painterOstream << seg; return *this; } -// Instantiation of Arr_polyline_traits_2 - +// Specialization of `ArrangementPainterOstream` for the polyline traits. template ArrangementPainterOstream>& ArrangementPainterOstream>:: -operator<<(const X_monotone_curve_2& curve) -{ - for (typename X_monotone_curve_2::Subcurve_const_iterator it = - curve.subcurves_begin(); - it != curve.subcurves_end(); ++it) - { +operator<<(const X_monotone_curve_2& curve) { + for (auto it = curve.subcurves_begin(); it != curve.subcurves_end(); ++it) this->painterOstream << *it; - } - return *this; } -// Instantiation of Arr_conic_traits_2 -template -auto ArrangementPainterOstream>::visibleParts(X_monotone_curve_2 curve) - -> std::vector -{ +// Specialization of `ArrangementPainterOstream` for the conic traits. +template +auto ArrangementPainterOstream +>:: +visibleParts(X_monotone_curve_2 curve) -> std::vector { // see if we intersect the bottom edge of the viewport Point_2 bottomLeft = this->convert(this->clippingRect.bottomLeft()); Point_2 bottomRight = this->convert(this->clippingRect.bottomRight()); @@ -99,18 +88,16 @@ auto ArrangementPainterOstream rightEndpt.x()) { std::swap(leftEndpt, rightEndpt); } + if (leftEndpt.x() > rightEndpt.x()) std::swap(leftEndpt, rightEndpt); QPointF qendpt1 = this->convert(leftEndpt); QPointF qendpt2 = this->convert(rightEndpt); std::list pointList; - for (unsigned int i = 0; i < intersections.size(); ++i) - { + for (unsigned int i = 0; i < intersections.size(); ++i) { CGAL::Object o = intersections[i]; std::pair pair; - if (CGAL::assign(pair, o)) - { + if (CGAL::assign(pair, o)) { Point_2 pt = pair.first; pointList.push_back(pt); } @@ -118,41 +105,36 @@ auto ArrangementPainterOstreamclippingRect.contains(qendpt1); bool includeRightEndpoint = this->clippingRect.contains(qendpt2); - if (includeLeftEndpoint) { pointList.push_front(leftEndpt); } + if (includeLeftEndpoint) pointList.push_front(leftEndpt); - if (includeRightEndpoint) { pointList.push_back(rightEndpt); } + if (includeRightEndpoint) pointList.push_back(rightEndpt); // TODO: make ArrangementPainterOstream take traits object - Traits traits; - Construct_x_monotone_subcurve_2 construct_x_monotone_subcurve_2{ - &traits}; + auto trim = traits.trim_2_object(); std::vector clippings; - typename std::list::iterator pointListItr = pointList.begin(); - for (unsigned int i = 0; i < pointList.size(); i += 2) - { - typename Traits::Point_2 p1 = *pointListItr++; - typename Traits::Point_2 p2 = *pointListItr++; - X_monotone_curve_2 subcurve = - construct_x_monotone_subcurve_2(curve, p1, p2); - clippings.push_back(subcurve); + auto it = pointList.begin(); + for (unsigned int i = 0; i < pointList.size(); i += 2) { + typename Traits::Point_2 p1 = *it++; + typename Traits::Point_2 p2 = *it++; + auto xcv = trim(curve, p1, p2); + clippings.push_back(xcv); } return clippings; } -template -void ArrangementPainterOstream< - CGAL::Arr_conic_traits_2>:: - filterIntersectionPoints(std::vector& res) -{ +// +template +void ArrangementPainterOstream +>:: +filterIntersectionPoints(std::vector& res) { std::vector> tmp; // filter out the non-intersection point results - for (unsigned int i = 0; i < res.size(); ++i) - { + for (unsigned int i = 0; i < res.size(); ++i) { CGAL::Object obj = res[i]; std::pair pair; - if (CGAL::assign(pair, obj)) { tmp.push_back(pair); } + if (CGAL::assign(pair, obj)) tmp.push_back(pair); } res.clear(); @@ -161,80 +143,76 @@ void ArrangementPainterOstream< std::sort(tmp.begin(), tmp.end(), compare_intersection_point_result); // box up the sorted elements - for (unsigned int i = 0; i < tmp.size(); ++i) - { + for (unsigned int i = 0; i < tmp.size(); ++i) { std::pair pair = tmp[i]; CGAL::Object o = CGAL::make_object(pair); res.push_back(o); } } -template -ArrangementPainterOstream< - CGAL::Arr_conic_traits_2>& -ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) -{ - CGAL::Bbox_2 bb = curve.bbox(); +// +template +ArrangementPainterOstream +>& +ArrangementPainterOstream +>:: +operator<<(const X_monotone_curve_2& curve) { + CGAL::Bbox_2 bb = traits.construct_bbox_2_object()(curve); QRectF qbb = this->convert(bb); // quick cull - if (this->clippingRect.isValid() && !this->clippingRect.intersects(qbb)) - { return *this; } + if (this->clippingRect.isValid() && ! this->clippingRect.intersects(qbb)) + return *this; // get number of segments QGraphicsView* view = this->scene->views().first(); - int xmin = view->mapFromScene(bb.xmin(), bb.ymin()).x(); - int xmax = view->mapFromScene(bb.xmax(), bb.ymin()).x(); - // can be negative due to rotation transformation - size_t n = static_cast(std::abs(xmax - xmin)); - if (n == 0) { return *this; } + auto pmin = view->mapFromScene(bb.xmin(), bb.ymin()); + auto pmax = view->mapFromScene(bb.xmax(), bb.ymax()); + double world_xdiff = std::abs(bb.xmax() - bb.xmin()); + double screen_xdiff = std::abs(pmax.x() - pmin.x()); + double error = world_xdiff / screen_xdiff; - auto paintCurve = [&](auto&& curve_) { - std::vector> app_pts; - app_pts.reserve(n + 1); - curve_.polyline_approximation(n, std::back_inserter(app_pts)); - - auto p_curr = app_pts.begin(); - auto end_pts = app_pts.end(); + auto paint_curve = [&](auto&& curve_) { + using Approximate_point_2 = typename Traits::Approximate_point_2; + std::vector points; + auto aprox = traits.approximate_2_object(); + aprox(curve_, error, std::back_inserter(points)); + auto p_curr = points.begin(); + auto end_pts = points.end(); auto p_next = p_curr + 1; - do - { - QPointF p1(p_curr->first, p_curr->second); - QPointF p2(p_next->first, p_next->second); + do { + QPointF p1(p_curr->x(), p_curr->y()); + QPointF p2(p_next->x(), p_next->y()); this->qp->drawLine(p1, p2); - p_curr++; - p_next++; + ++p_curr; + ++p_next; } while (p_next != end_pts); }; - if (this->clippingRect.isValid()) - { - std::vector visibleParts; - if (this->clippingRect.contains(qbb)) - visibleParts.push_back(curve); - else - visibleParts = this->visibleParts(curve); - - for (auto& visiblePart : visibleParts) paintCurve(visiblePart); - } - else - { // draw the whole curve - paintCurve(curve); + if (this->clippingRect.isValid()) { + if (this->clippingRect.contains(qbb)) { + paint_curve(curve); + return *this; + } + std::vector parts; + parts = this->visibleParts(curve); + for (auto& part : parts) paint_curve(part); + return *this; } + // draw the whole curve + paint_curve(curve); return *this; } -// Instantiation of Arr_Bezier_traits_2 -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> +// Specialization of `ArrangementPainterOstream` for the Bezier traits. +template std::vector> -ArrangementPainterOstream>::getPoints(const X_monotone_curve_2& curve) -{ +ArrangementPainterOstream +>:: +getPoints(const X_monotone_curve_2& curve) { std::pair param_range = curve.parameter_range(); auto&& supporting_curve = curve.supporting_curve(); @@ -250,12 +228,13 @@ ArrangementPainterOstream -auto ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) +// +template +auto ArrangementPainterOstream +>:: +operator<<(const X_monotone_curve_2& curve) -> ArrangementPainterOstream& { auto sampled_points = this->getPoints(curve); @@ -270,57 +249,45 @@ auto ArrangementPainterOstream ArrangementPainterOstream>& -ArrangementPainterOstream>::operator<<( - const X_monotone_curve_2& curve) -{ - if (curve.is_segment()) - { +ArrangementPainterOstream>:: +operator<<(const X_monotone_curve_2& curve) { + if (curve.is_segment()) { Segment_2 seg = curve.segment(); // skip segments outside our view QRectF seg_bb = this->convert(seg.bbox()); - if ( - this->clippingRect.isValid() && - !this->clippingRect.intersects(seg_bb) && + if (this->clippingRect.isValid() && + ! this->clippingRect.intersects(seg_bb) && (!seg.is_horizontal() && !seg.is_vertical())) - { return *this; } + return *this; this->painterOstream << seg; } - else if (curve.is_ray()) - { + else if (curve.is_ray()) { Ray_2 ray = curve.ray(); QLineF qseg = this->convert(ray); - if (qseg.isNull()) - { // it's out of view - return *this; - } + if (qseg.isNull()) return *this; // it's out of view Segment_2 seg = this->convert(qseg); this->painterOstream << seg; } - else // curve.is_line( ) - { + else { + // curve.is_line( ) Line_2 line = curve.line(); QLineF qseg = this->convert(line); - if (qseg.isNull()) - { // it's out of view - return *this; - } + if (qseg.isNull()) return *this; // it's out of view Segment_2 seg = this->convert(qseg); this->painterOstream << seg; } return *this; } -// Instantiation of Arr_algebraic_segment_traits_2 +// Specialization of `ArrangementPainterOstream` for the algebraic traits. template -static bool lies_on_border( - const ArrangementPainterOstream* apo, const QPointF& point) -{ +static bool lies_on_border(const ArrangementPainterOstream* apo, + const QPointF& point) { QGraphicsView* view = apo->getScene()->views().first(); qreal width = view->width(); qreal height = view->height(); @@ -329,26 +296,27 @@ static bool lies_on_border( std::abs(point.y() - height) < tol || point.y() < tol; } +// template -void ArrangementPainterOstream< - CGAL::Arr_algebraic_segment_traits_2>::remapFacadePainter() -{ - this->qp->setTransform(this->getPointsListMapping()); -} +void +ArrangementPainterOstream>:: +remapFacadePainter() +{ this->qp->setTransform(this->getPointsListMapping()); } +// template -QTransform ArrangementPainterOstream< - CGAL::Arr_algebraic_segment_traits_2>::getPointsListMapping() -{ +QTransform +ArrangementPainterOstream>:: +getPointsListMapping() { auto worldTransform = this->qp->transform(); return this->getPointsListMapping(worldTransform); } +// template QTransform ArrangementPainterOstream>:: - getPointsListMapping(const QTransform& worldTransform) -{ +getPointsListMapping(const QTransform& worldTransform) { auto view = this->getView(); QRectF viewport = this->viewportRect(); @@ -371,11 +339,11 @@ ArrangementPainterOstream>:: return QTransform{m11, m12, m21, m22, dx, dy}; } +// template -auto ArrangementPainterOstream>::getPointsList(const X_monotone_curve_2& curve) - -> std::vector -{ +auto ArrangementPainterOstream +>:: +getPointsList(const X_monotone_curve_2& curve) -> std::vector { typedef Curve_renderer_facade Facade; typedef std::pair Coord_2; typedef std::vector Coord_vec_2; @@ -385,11 +353,11 @@ auto ArrangementPainterOstream ArrangementPainterOstream>& ArrangementPainterOstream>:: -operator<<(const X_monotone_curve_2& curve) -{ +operator<<(const X_monotone_curve_2& curve) { this->qp->save(); this->remapFacadePainter(); this->paintCurve(curve); @@ -397,20 +365,19 @@ operator<<(const X_monotone_curve_2& curve) return *this; } +// template -void ArrangementPainterOstream>::paintCurve(const X_monotone_curve_2& curve) -{ +void ArrangementPainterOstream +>:: +paintCurve(const X_monotone_curve_2& curve) { std::vector points = this->getPointsList(curve); - for (auto& vec : points) - { + for (auto& vec : points) { auto vit = vec.begin(); QPainterPath path; QPointF qpt(vit->first, vit->second); path.moveTo(qpt); - for (auto& vit : vec) - { + for (auto& vit : vec) { QPointF qpt_new = QPointF(vit.first, vit.second); if (lies_on_border(this, qpt) && lies_on_border(this, qpt_new)) path.moveTo(qpt_new); @@ -422,10 +389,10 @@ void ArrangementPainterOstream -void ArrangementPainterOstream< - CGAL::Arr_algebraic_segment_traits_2>::setupFacade() -{ +void ArrangementPainterOstream +>::setupFacade() { typedef Curve_renderer_facade Facade; QGraphicsView* view = this->getView(); QRectF viewport = this->viewportRect(); @@ -433,18 +400,16 @@ void ArrangementPainterOstream< Facade::setup(bbox, view->width(), view->height()); } -// Instantiation of Arr_rational_function_traits_2 - -template +// Specialization of `ArrangementPainterOstream` for Arr_rational_function_traits_2 +template constexpr const T& clamp(const T& v, const T& lo, const T& hi) -{ - return (v < lo) ? lo : (hi < v) ? hi : v; -} +{ return (v < lo) ? lo : (hi < v) ? hi : v; } +// template -auto ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) -> Self& -{ +auto ArrangementPainterOstream +>:: +operator<<(const X_monotone_curve_2& curve) -> Self& { QPainterPath painterPath; const QRectF viewport = this->viewportRect(); // overshoot so that the slope would be more accurate @@ -458,8 +423,7 @@ auto ArrangementPainterOstream max_y || y < min_y) - { + if (y > max_y || y < min_y) { double x_ = x; double y_ = clamp(y, min_y, max_y); @@ -467,8 +431,8 @@ auto ArrangementPainterOstream -auto ArrangementPainterOstream>::getPointsList(const X_monotone_curve_2& curve) - -> std::vector -{ +auto ArrangementPainterOstream +>:: +getPointsList(const X_monotone_curve_2& curve) -> std::vector { std::vector points_list; Coord_vec_2* cur_list = nullptr; @@ -521,15 +482,13 @@ auto ArrangementPainterOstream max_y || y < min_y) - { + if (y > max_y || y < min_y) { double x_ = x; double y_ = clamp(y, min_y, max_y); - if (!disconnected) - cur_list->push_back({x_, y_}); - else if ( - (last_y == min_y && y_ == max_y) || (last_y == max_y && y_ == min_y)) + if (!disconnected) cur_list->push_back({x_, y_}); + else if ((last_y == min_y && y_ == max_y) || + (last_y == max_y && y_ == min_y)) { cur_list->push_back({last_x, last_y}); cur_list->push_back({x_, y_}); @@ -539,10 +498,8 @@ auto ArrangementPainterOstreampush_back({last_x, last_y}); @@ -557,12 +514,12 @@ auto ArrangementPainterOstream template -void ArrangementPainterOstream< - CGAL::Arr_rational_function_traits_2>:: - sample_points(const X_monotone_curve_2& curve, Lambda&& lambda) -{ +void ArrangementPainterOstream +>:: +sample_points(const X_monotone_curve_2& curve, Lambda&& lambda) { // TODO: cache maximum and minimal points for each curve, and include them // in the sampled points const QRectF viewport = this->viewportRect(); @@ -572,80 +529,63 @@ void ArrangementPainterOstream< auto&& numer = curve._f.numer(); auto&& denom = curve._f.denom(); - auto eval_at = [&](auto&& x) { - return numer.evaluate(x) / denom.evaluate(x); - }; + auto eval_at = [&](auto&& x) { return numer.evaluate(x) / denom.evaluate(x); }; - if ( // be conservative and prefer this branch to avoid zero division - curve.left_parameter_space_in_x() == ARR_INTERIOR && - curve.left_x().to_interval().second >= min_x) + // be conservative and prefer this branch to avoid zero division + if (curve.left_parameter_space_in_x() == ARR_INTERIOR && + curve.left_x().to_interval().second >= min_x) { min_x = curve.left_x().to_interval().second; - switch (curve.left_parameter_space_in_y()) - { - case ARR_INTERIOR: { - auto left_pt = curve.left().to_double(); - lambda(min_x, left_pt.second); - break; - } - case ARR_TOP_BOUNDARY: { - lambda(min_x, std::numeric_limits::infinity()); - break; - } - case ARR_BOTTOM_BOUNDARY: { - lambda(min_x, -std::numeric_limits::infinity()); - break; - } - default: { - CGAL_error(); - } + switch (curve.left_parameter_space_in_y()) { + case ARR_INTERIOR: { + auto left_pt = curve.left().to_double(); + lambda(min_x, left_pt.second); + break; + } + case ARR_TOP_BOUNDARY: { + lambda(min_x, std::numeric_limits::infinity()); + break; + } + case ARR_BOTTOM_BOUNDARY: { + lambda(min_x, -std::numeric_limits::infinity()); + break; + } + default: { + CGAL_error(); + } } } - else if ( - curve.right_parameter_space_in_x() != ARR_INTERIOR || - min_x < curve.right_x().to_interval().first) - { + else if (curve.right_parameter_space_in_x() != ARR_INTERIOR || + min_x < curve.right_x().to_interval().first) lambda(min_x, CGAL::to_double(eval_at(Rational{min_x}))); - } - else // outside of viewport - { - return; - } + else return; // outside of viewport std::pair last_pt; - if ( // be conservative and prefer this branch to avoid zero division - curve.right_parameter_space_in_x() == ARR_INTERIOR && - curve.right_x().to_interval().first <= max_x) + // be conservative and prefer this branch to avoid zero division + if (curve.right_parameter_space_in_x() == ARR_INTERIOR && + curve.right_x().to_interval().first <= max_x) { max_x = curve.right_x().to_interval().first; - switch (curve.right_parameter_space_in_y()) - { - case ARR_INTERIOR: { - last_pt = {max_x, curve.right().to_double().second}; - break; - } - case ARR_TOP_BOUNDARY: { - last_pt = {max_x, std::numeric_limits::infinity()}; - break; - } - case ARR_BOTTOM_BOUNDARY: { - last_pt = {max_x, -std::numeric_limits::infinity()}; - break; - } - default: { - CGAL_error(); - } + switch (curve.right_parameter_space_in_y()) { + case ARR_INTERIOR: { + last_pt = {max_x, curve.right().to_double().second}; + break; + } + case ARR_TOP_BOUNDARY: { + last_pt = {max_x, std::numeric_limits::infinity()}; + break; + } + case ARR_BOTTOM_BOUNDARY: { + last_pt = {max_x, -std::numeric_limits::infinity()}; + break; + } + default: { CGAL_error(); } } } else if (max_x > min_x) - { last_pt = {max_x, CGAL::to_double(eval_at(Rational{max_x}))}; - } - else // outside of viewport - { - return; - } + else return; // outside of viewport static constexpr int dx_pixel = 1; static constexpr int min_num_points = 20; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h index af97be31ca0..dfe56a74c6f 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h @@ -100,11 +100,9 @@ static constexpr TraitsType enumFromArrType() return details::EnumFromTraits::value; } -template -static void visitArrangementType(TraitsType tt, Lambda&& lambda) -{ - switch (tt) - { +template +static void visitArrangementType(TraitsType tt, Lambda&& lambda) { + switch (tt) { case TraitsType::SEGMENT_TRAITS: lambda(TypeHolder{}); break; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h index ada4f896c4d..6d16a471b40 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h @@ -18,8 +18,10 @@ #include template -class Conic_reader -{ +class Conic_reader { +private: + const Traits& m_traits; + public: typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -31,9 +33,13 @@ public: typedef typename Traits::Rat_segment_2 Rat_segment_2; typedef typename Traits::Rat_circle_2 Rat_circle_2; - template - int read_data(std::ifstream & inp, OutputIterator curves_out, - CGAL::Bbox_2 & bbox) + // Cnstruct from traits. + Conic_reader(const Traits& traits) : m_traits(traits) {} + + // + template + int read_data(std::ifstream& inp, OutputIterator curves_out, + CGAL::Bbox_2& bbox) { Curve_2 cv; @@ -49,7 +55,7 @@ public: for (int i = 0; i < count; i++) { if (read_curve(inp, cv)) { ++curves_out = cv; - CGAL::Bbox_2 curve_bbox = cv.bbox(); + CGAL::Bbox_2 curve_bbox = m_traits.construct_bbox_2_object()(cv); if (i == 0) bbox = curve_bbox; else bbox = bbox + curve_bbox; } @@ -58,8 +64,9 @@ public: } /*! */ - bool read_curve(std::ifstream & is, Curve_2 & cv) - { + bool read_curve(std::ifstream& is, Curve_2& cv) { + auto ctr_cv = m_traits.construct_curve_2_object(); + // Read a line from the input file. char one_line[128]; @@ -67,12 +74,11 @@ public: std::istringstream str_line (one_line); // Read the arc type and act accordingly. - char type; + char type; str_line >> type; - if (type == 's' || type == 'S') - { + if (type == 's' || type == 'S') { // Construct a line segment. The line should have the format: // s // where (x1, y1), (x2, y2) are the endpoints of a segment. @@ -81,49 +87,46 @@ public: //str_line >> x1 >> y1 >> x2 >> y2; str_line >> buf; - x1 = Algebraic( buf ).BigRatValue( ); + x1 = Algebraic( buf ).BigRatValue(); str_line >> buf; - y1 = Algebraic( buf ).BigRatValue( ); + y1 = Algebraic( buf ).BigRatValue(); str_line >> buf; - x2 = Algebraic( buf ).BigRatValue( ); + x2 = Algebraic( buf ).BigRatValue(); str_line >> buf; - y2 = Algebraic( buf ).BigRatValue( ); + y2 = Algebraic( buf ).BigRatValue(); - Rat_point_2 p1(x1, y1), p2(x2, y2); - Rat_segment_2 seg (p1, p2); + Rat_point_2 p1(x1, y1), p2(x2, y2); + Rat_segment_2 seg(p1, p2); - cv = Curve_2 (seg); + cv = ctr_cv(seg); } - else if (type == 'c' || type == 'C') - { + else if (type == 'c' || type == 'C') { // Construct a full circle. The line should have the format: // c // where (x0, y0) is the center of the circle and R_sq is its squared // radius. - Rational x0, y0, R_sq; + Rational x0, y0, R_sq; str_line >> x0 >> y0 >> R_sq; - Rat_point_2 p0(x0, y0); - Rat_circle_2 circ(p0, R_sq); + Rat_point_2 p0(x0, y0); + Rat_circle_2 circ(p0, R_sq); - cv = Curve_2 (circ); + cv = ctr_cv(circ); } - else if (type == 't' || type == 'T') - { + else if (type == 't' || type == 'T') { // Construct a circular arc. The line should have the format: // t // where (x1, y1), (x2, y2) and (x3, y3) define the arc. - Rational x1, y1, x2, y2, x3, y3; + Rational x1, y1, x2, y2, x3, y3; str_line >> x1 >> y1 >> x2 >> y2 >> x3 >> y3; - Rat_point_2 p1(x1, y1), p2(x2, y2), p3(x3, y3); + Rat_point_2 p1(x1, y1), p2(x2, y2), p3(x3, y3); - cv = Curve_2 (p1, p2, p3); + cv = ctr_cv(p1, p2, p3); } - else if (type == 'f' || type == 'F') - { + else if (type == 'f' || type == 'F') { // Construct a full conic curve. The line should have the format: // c // where r, s, t, u, v, w define the conic equation. @@ -131,10 +134,9 @@ public: str_line >> r >> s >> t >> u >> v >> w; - cv = Curve_2 (r, s, t, u, v, w); + cv = ctr_cv(r, s, t, u, v, w); } - else if (type == 'a' || type == 'A') - { + else if (type == 'a' || type == 'A') { // Construct a conic arc. The line should have the format: // c // where r, s, t, u, v, w define the conic equation, while (x1, y1) @@ -144,16 +146,13 @@ public: str_line >> r >> s >> t >> u >> v >> w; // Read the orientation. - int i_orient; + int i_orient; CGAL::Orientation orient; str_line >> i_orient; - if (i_orient > 0) - orient = CGAL::COUNTERCLOCKWISE; - else if (i_orient < 0) - orient = CGAL::CLOCKWISE; - else - orient = CGAL::COLLINEAR; + if (i_orient > 0) orient = CGAL::COUNTERCLOCKWISE; + else if (i_orient < 0) orient = CGAL::CLOCKWISE; + else orient = CGAL::COLLINEAR; // Read the end points of the arc and create it. // Notice we read the coordinates as strings, then we convert them to @@ -175,10 +174,9 @@ public: Point_2 ps (x1, y1); Point_2 pt (x2, y2); - cv = Curve_2 (r, s, t, u, v, w, orient, ps ,pt); + cv = ctr_cv(r, s, t, u, v, w, orient, ps ,pt); } - else if (type == 'q' || type == 'Q') - { + else if (type == 'q' || type == 'Q') { // Construct a circular arc. The line should have the format: // t // where (x1, y1), (x2, y2), (x3, y3), (x4, y4) and (x5, y5) define the @@ -189,16 +187,15 @@ public: Rat_point_2 p1(x1, y1), p2(x2, y2), p3(x3, y3), p4(x4, y4), p5(x5, y5); - cv = Curve_2 (p1, p2, p3, p4, p5); + cv = ctr_cv(p1, p2, p3, p4, p5); } - else if(type == 'e' || type == 'E') - { + else if(type == 'e' || type == 'E') { // Construct a full ellipse. The line should have the format: // e // raddi and center of ellipse - int x0, y0, r1, r2; - Rational sqr_r1, sqr_r2; - Rational R, S, T, U, V, W; + int x0, y0, r1, r2; + Rational sqr_r1, sqr_r2; + Rational R, S, T, U, V, W; str_line >> r1 >> r2 >> x0 >> y0; @@ -211,10 +208,9 @@ public: V = -2 * sqr_r1 * y0; W = sqr_r2*x0*x0 + sqr_r1*y0*y0 - sqr_r1*sqr_r2; - cv = Curve_2 (R, S, T, U, V, W); + cv = ctr_cv(R, S, T, U, V, W); } - else - { + else { std::cerr << "Illegal conic type specification: " << type << "." << std::endl; return false; @@ -224,8 +220,7 @@ public: } /*! */ - void skip_comments( std::ifstream& is, char* one_line ) - { + void skip_comments(std::ifstream& is, char* one_line) { while (!is.eof()) { is.getline(one_line, 128); if (one_line[0] != '#') break; @@ -234,13 +229,10 @@ public: // should probably change class name since it reads and writes template - int write_data(std::ofstream & ofs, InputIterator begin_, InputIterator end_) - { + int write_data(std::ofstream& ofs, InputIterator begin_, InputIterator end_) { ofs << std::distance(begin_, end_) << std::endl; - for (auto it = begin_; it != end_; ++it) - { - if (it->is_full_conic()) - { + for (auto it = begin_; it != end_; ++it) { + if (it->is_full_conic()) { ofs << "F "; ofs << it->r() << " "; ofs << it->s() << " "; @@ -250,15 +242,13 @@ public: ofs << it->w() << " "; ofs << std::endl; } - else if (it->orientation() == CGAL::COLLINEAR) - { + else if (it->orientation() == CGAL::COLLINEAR) { ofs << "S "; ofs << it->source() << " "; ofs << it->target() << " "; ofs << std::endl; } - else - { + else { ofs << "A "; ofs << it->r() << " "; ofs << it->s() << " "; @@ -266,12 +256,9 @@ public: ofs << it->u() << " "; ofs << it->v() << " "; ofs << it->w() << " "; - if (it->orientation() == CGAL::COUNTERCLOCKWISE) - ofs << "1 "; - else if (it->orientation() == CGAL::CLOCKWISE) - ofs << "-1 "; - else - ofs << "0 "; + if (it->orientation() == CGAL::COUNTERCLOCKWISE) ofs << "1 "; + else if (it->orientation() == CGAL::CLOCKWISE) ofs << "-1 "; + else ofs << "0 "; ofs << it->source() << " "; ofs << it->target() << " "; ofs << std::endl; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp index 863f7945cbd..ad8f7f7b7e9 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp @@ -18,25 +18,29 @@ #include -namespace CGAL -{ -namespace Qt -{ +namespace CGAL { +namespace Qt { -template -CurveGraphicsItem::CurveGraphicsItem() : - bb(), m_edgeColor(::Qt::red), m_edgeWidth(2), - m_vertexColor(::Qt::red), m_vertexRadius(1) +// +template +CurveGraphicsItem::CurveGraphicsItem(const Traits& traits) : + m_traits(traits), + bb(), + m_edgeColor(::Qt::red), + m_edgeWidth(2), + m_vertexColor(::Qt::red), + m_vertexRadius(1) { this->setZValue(4); this->pointsGraphicsItem.setParentItem(this); } -template -void CurveGraphicsItem::paint( - QPainter* painter, const QStyleOptionGraphicsItem* /* option */, - QWidget* /* widget */) -{ +// +template +void CurveGraphicsItem:: +paint(QPainter* painter, + const QStyleOptionGraphicsItem* /* option */, + QWidget* /* widget */) { // draw the curves QPen edgesPen(this->m_edgeColor, this->m_edgeWidth); edgesPen.setCosmetic(true); @@ -48,9 +52,9 @@ void CurveGraphicsItem::paint( for (auto& curve : this->curves) { painterOstream << curve; } } -template -QRectF CurveGraphicsItem::boundingRect() const -{ +// +template +QRectF CurveGraphicsItem::boundingRect() const { auto viewport = this->viewportRect(); qreal xmin = viewport.left(); qreal ymin = viewport.top(); @@ -60,8 +64,7 @@ QRectF CurveGraphicsItem::boundingRect() const if (this->bb.ymin() > ymin) ymin = this->bb.ymin(); if (this->bb.xmax() < xmax) xmax = this->bb.xmax(); if (this->bb.ymax() < ymax) ymax = this->bb.ymax(); - if (xmin > xmax || ymin > ymax) - { + if (xmin > xmax || ymin > ymax) { xmin = 0; xmax = 0; ymin = 0; @@ -70,93 +73,92 @@ QRectF CurveGraphicsItem::boundingRect() const return {QPointF{xmin, ymin}, QPointF{xmax, ymax}}; } -template -void CurveGraphicsItem::insert(const X_monotone_curve_2& curve) -{ +// +template +void CurveGraphicsItem::insert(const X_monotone_curve_2& curve) { this->curves.push_back(curve); this->updateBoundingBox(); } -template -void CurveGraphicsItem::insert(const Point_2& point) -{ +// +template +void CurveGraphicsItem::insert(const Point_2& point) { this->pointsGraphicsItem.insert(point); this->updateBoundingBox(); } -template -void CurveGraphicsItem::clear() -{ +// +template +void CurveGraphicsItem::clear() { this->curves.clear(); this->pointsGraphicsItem.clear(); this->updateBoundingBox(); } -template -void CurveGraphicsItem::modelChanged() -{ +// +template +void CurveGraphicsItem::modelChanged() { this->updateBoundingBox(); this->update(); } -template -const QColor& CurveGraphicsItem::edgeColor() const -{ +// +template +const QColor& CurveGraphicsItem::edgeColor() const { return this->m_edgeColor; } -template -void CurveGraphicsItem::setEdgeColor(const QColor& color) -{ +// +template +void CurveGraphicsItem::setEdgeColor(const QColor& color) { this->m_edgeColor = color; } -template -int CurveGraphicsItem::edgeWidth() const -{ +// +template +int CurveGraphicsItem::edgeWidth() const { return this->m_edgeWidth; } -template -void CurveGraphicsItem::setEdgeWidth(int width) -{ +// +template +void CurveGraphicsItem::setEdgeWidth(int width) { this->m_edgeWidth = width; } -template -const QColor& CurveGraphicsItem::vertexColor() const -{ +// +template +const QColor& CurveGraphicsItem::vertexColor() const { return this->m_vertexColor; } -template -void CurveGraphicsItem::setVertexColor(const QColor& color) -{ +// +template +void CurveGraphicsItem::setVertexColor(const QColor& color) { this->m_vertexColor = color; } -template -int CurveGraphicsItem::vertexRadius() const -{ +// +template +int CurveGraphicsItem::vertexRadius() const { return this->m_vertexRadius; } -template -void CurveGraphicsItem::setVertexRadius(int radius) -{ +// +template +void CurveGraphicsItem::setVertexRadius(int radius) { this->m_vertexRadius = radius; } -template -void CurveGraphicsItem::updateBoundingBox() -{ +// +template +void CurveGraphicsItem::updateBoundingBox() { this->prepareGeometryChange(); this->bb = {}; - ConstructBoundingBox construct_bounding_box; - for (auto& curve : curves) - this->bb += construct_bounding_box(curve); + ConstructBoundingBox ctr_bbox(m_traits); + for (auto& curve : curves) this->bb += ctr_bbox(curve); } ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(CurveGraphicsItem) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h index ce0fd6414f7..2478a567dac 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h @@ -23,48 +23,47 @@ namespace CGAL { namespace Qt { -/** - Draws selected curves and vertices of an arrangement. -*/ +/* Draws selected curves and vertices of an arrangement. + */ // TODO: ArrangementGraphicsItem should probably use this class -template < class ArrTraits > -class CurveGraphicsItem : public GraphicsItem, public GraphicsSceneMixin -{ +template +class CurveGraphicsItem : public GraphicsItem, public GraphicsSceneMixin { public: // known curve types - typedef ArrTraits Traits; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Point_2 Point_2; + typedef GeometryTraits Traits; + typedef typename Traits::Curve_2 Curve_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Point_2 Point_2; -public: // ctors - CurveGraphicsItem( ); +public: + // Construct from traits. + CurveGraphicsItem(const Traits& traits); public: // methods - void paint( - QPainter* painter, const QStyleOptionGraphicsItem* /* option */, - QWidget* /* widget */) override; - QRectF boundingRect( ) const override; - void insert( const X_monotone_curve_2& curve ); - void insert( const Point_2& point ); - void clear( ); + void paint(QPainter* painter, const QStyleOptionGraphicsItem* /* option */, + QWidget* /* widget */) override; + QRectF boundingRect() const override; + void insert(const X_monotone_curve_2& curve); + void insert(const Point_2& point); + void clear(); public Q_SLOTS: - void modelChanged( ) override; - const QColor& edgeColor( ) const; - void setEdgeColor( const QColor& color ); - int edgeWidth( ) const; - void setEdgeWidth( int width ); - const QColor& vertexColor( ) const; - void setVertexColor( const QColor& color ); - int vertexRadius( ) const; - void setVertexRadius( int radius ); + void modelChanged() override; + const QColor& edgeColor() const; + void setEdgeColor(const QColor& color); + int edgeWidth() const; + void setEdgeWidth(int width); + const QColor& vertexColor() const; + void setVertexColor(const QColor& color); + int vertexRadius() const; + void setVertexRadius(int radius); protected: // methods void updateBoundingBox( ); protected: // fields - std::vector< X_monotone_curve_2 > curves; + const Traits& m_traits; + std::vector curves; PointsGraphicsItem pointsGraphicsItem; CGAL::Bbox_2 bb; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp index d30c5493d14..4e548644e3e 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp @@ -20,8 +20,7 @@ #include "Utils/Utils.h" template -class DeleteCurveCallback : public DeleteCurveCallbackBase -{ +class DeleteCurveCallback : public DeleteCurveCallbackBase { public: typedef Arr_ Arrangement; typedef typename Arrangement::Halfedge_handle Halfedge_handle; @@ -62,11 +61,12 @@ struct ExplicitLambda CGAL::Object& arr_obj; QObject* parent; }; + } // anonymous namespace +// DeleteCurveCallbackBase* DeleteCurveCallbackBase::create( - demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) -{ + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) { DeleteCurveCallbackBase* res; ExplicitLambda explicit_lambda{res, arr_obj, parent}; demo_types::visitArrangementType(tt, explicit_lambda); @@ -75,13 +75,14 @@ DeleteCurveCallbackBase* DeleteCurveCallbackBase::create( /*! Constructor */ template -DeleteCurveCallback::DeleteCurveCallback( - Arrangement* arr_, QObject* parent_) : - DeleteCurveCallbackBase(parent_), - highlightedCurve(new CGAL::Qt::CurveGraphicsItem()), arr(arr_) +DeleteCurveCallback::DeleteCurveCallback(Arrangement* arr_, + QObject* parent_) : + DeleteCurveCallbackBase(parent_), + highlightedCurve(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))), + arr(arr_) { - QObject::connect( - this, SIGNAL(modelChanged()), this->highlightedCurve, SLOT(modelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), + this->highlightedCurve, SLOT(modelChanged())); this->setDeleteMode(DeleteMode::DeleteOriginatingCuve); } @@ -91,13 +92,13 @@ DeleteCurveCallback::DeleteCurveCallback( sets the current scene of the viewport */ template -void DeleteCurveCallback::setScene(QGraphicsScene* scene_) -{ +void DeleteCurveCallback::setScene(QGraphicsScene* scene_) { CGAL::Qt::Callback::setScene(scene_); this->highlightedCurve->setScene(scene_); if (this->scene) { this->scene->addItem(this->highlightedCurve); } } +// template void DeleteCurveCallback::reset() { @@ -105,28 +106,25 @@ void DeleteCurveCallback::reset() this->removableHalfedge = Halfedge_handle(); } +// template -void DeleteCurveCallback::mousePressEvent( - QGraphicsSceneMouseEvent* /* event */) -{ +void DeleteCurveCallback:: +mousePressEvent(QGraphicsSceneMouseEvent* /* event */) { if (this->removableHalfedge == Halfedge_handle()) { return; } - if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) - { + if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) { Originating_curve_iterator it = this->arr->originating_curves_begin(this->removableHalfedge); Originating_curve_iterator it_end = this->arr->originating_curves_end(this->removableHalfedge); - while (it != it_end) - { + while (it != it_end) { Originating_curve_iterator temp = it; ++temp; CGAL::remove_curve(*(this->arr), it); it = temp; } } - else - { + else { // CGAL::remove_edge( *(this->arr), this->removableHalfedge->curve( ) ); this->arr->remove_edge(this->removableHalfedge); } @@ -134,16 +132,15 @@ void DeleteCurveCallback::mousePressEvent( Q_EMIT modelChanged(); } +// template void DeleteCurveCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - this->highlightNearestCurve(event); -} +{ this->highlightNearestCurve(event); } +// template -void DeleteCurveCallback::highlightNearestCurve( - QGraphicsSceneMouseEvent* event) -{ +void DeleteCurveCallback:: +highlightNearestCurve(QGraphicsSceneMouseEvent* event) { typedef typename ArrTraitsAdaptor::Kernel Kernel; typedef typename Kernel::Point_2 Point; @@ -164,12 +161,11 @@ void DeleteCurveCallback::highlightNearestCurve( // create a curve graphics item and add it to the scene this->highlightedCurve->clear(); - if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) - { // highlight the originating curve + if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) { + // highlight the originating curve Originating_curve_iterator ocit, temp; ocit = this->arr->originating_curves_begin(this->removableHalfedge); - while (ocit != this->arr->originating_curves_end(this->removableHalfedge)) - { + while (ocit != this->arr->originating_curves_end(this->removableHalfedge)) { temp = ocit; ++temp; @@ -184,8 +180,8 @@ void DeleteCurveCallback::highlightNearestCurve( ocit = temp; } } - else - { // highlight just the edge + else { + // highlight just the edge this->highlightedCurve->insert(this->removableHalfedge->curve()); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp index 71bb0f1d3c9..4e3cf4cd47a 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp @@ -84,10 +84,13 @@ struct ExplicitLambda CGAL::Object& arr_obj; QObject* parent; }; + } // anonymous namespace -EnvelopeCallbackBase* EnvelopeCallbackBase::create( - demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +// +EnvelopeCallbackBase* +EnvelopeCallbackBase::create(demo_types::TraitsType tt, CGAL::Object arr_obj, + QObject* parent) { EnvelopeCallbackBase* res; ExplicitLambda explicit_lambda{res, arr_obj, parent}; @@ -95,11 +98,12 @@ EnvelopeCallbackBase* EnvelopeCallbackBase::create( return res; } +// template EnvelopeCallback::EnvelopeCallback(Arrangement* arr_, QObject* parent) : EnvelopeCallbackBase(parent), arr(arr_), - lowerEnvelope(new CGAL::Qt::CurveGraphicsItem()), - upperEnvelope(new CGAL::Qt::CurveGraphicsItem()), showLower(false), + lowerEnvelope(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))), + upperEnvelope(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))), showLower(false), showUpper(false) { this->lowerEnvelope->hide(); @@ -107,7 +111,7 @@ EnvelopeCallback::EnvelopeCallback(Arrangement* arr_, QObject* parent) : } template < typename Arr_ > -void EnvelopeCallback::setEnvelopeEdgeColor( const QColor& color ) +void EnvelopeCallback::setEnvelopeEdgeColor(const QColor& color) { this->lowerEnvelope->setEdgeColor( color ); this->upperEnvelope->setEdgeColor( color ); diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp index 441cdf5271b..9505c6161e7 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp @@ -24,11 +24,10 @@ #include #include +// template -inline std::enable_if_t -for_each(std::tuple&, FuncT) -{ -} +inline typename std::enable_if::type +for_each(std::tuple&, FuncT) {} template inline std::enable_if_t < @@ -38,103 +37,95 @@ template for_each(t, f); } -namespace CGAL -{ -namespace Qt -{ +namespace CGAL { +namespace Qt { -GraphicsViewCurveInputBase::GraphicsViewCurveInputBase( - QObject* parent, QGraphicsScene* scene) : - Callback(parent, scene), - inputMethod(nullptr) -{ -} +// +GraphicsViewCurveInputBase:: +GraphicsViewCurveInputBase(QObject* parent, QGraphicsScene* scene) : + Callback(parent, scene), + inputMethod(nullptr) +{} +// void GraphicsViewCurveInputBase::setInputMethod(CurveInputMethod* inputMethod_) -{ - this->inputMethod = inputMethod_; -} +{ this->inputMethod = inputMethod_; } -void GraphicsViewCurveInputBase::reset() -{ - if (this->inputMethod) - { +// +void GraphicsViewCurveInputBase::reset() { + if (this->inputMethod) { this->inputMethod->reset(); this->inputMethod = nullptr; } } +// bool GraphicsViewCurveInputBase::eventFilter(QObject* obj, QEvent* event) -{ - return this->inputMethod->eventFilter(obj, event); -} +{ return this->inputMethod->eventFilter(obj, event); } +// void GraphicsViewCurveInputBase::setColor(QColor c) -{ - this->inputMethod->setColor(c); -} +{ this->inputMethod->setColor(c); } +// template -GraphicsViewCurveInput::GraphicsViewCurveInput( - Arrangement* arrangement_, QObject* parent, QGraphicsScene* scene) : - GraphicsViewCurveInputBase(parent, scene), - arrangement(arrangement_) +GraphicsViewCurveInput:: +GraphicsViewCurveInput(Arrangement* arrangement_, QObject* parent, + QGraphicsScene* scene) : + GraphicsViewCurveInputBase(parent, scene), + arrangement(arrangement_) { - this->setDefaultInputMethod( - std::integral_constant< - bool, std::tuple_size::value != 0>{}); + this->setDefaultInputMethod(std::integral_constant::value != 0>{}); for_each(inputMethods, [&](auto&& it) { - it.setScene(scene); - it.setCallback(this); - }); + it.setScene(scene); + it.setCallback(this); + }); curveGenerator.setTraits(this->arrangement->traits()); } +// template -void GraphicsViewCurveInput::setCurveType(CurveType type) -{ +void GraphicsViewCurveInput::setCurveType(CurveType type) { this->reset(); - for_each(inputMethods, [&](auto&& it) { - if (it.curveType() == type) - this->setInputMethod(static_cast(&it)); - }); + for_each(inputMethods, + [&](auto&& it) { + if (it.curveType() == type) + this->setInputMethod(static_cast(&it)); + }); } +// template void GraphicsViewCurveInput::setPointSnapper(PointSnapperBase* snapper_) -{ - for_each(inputMethods, [&](auto&& it) { it.setPointSnapper(snapper_); }); -} +{ for_each(inputMethods, [&](auto&& it) { it.setPointSnapper(snapper_); }); } +// template template void GraphicsViewCurveInput::setDefaultInputMethod(std::true_type) -{ - this->setInputMethod(&std::get<0>(inputMethods)); -} +{ this->setInputMethod(&std::get<0>(inputMethods)); } +// template void GraphicsViewCurveInput::setDefaultInputMethod(std::false_type) -{ -} +{} +// template -void GraphicsViewCurveInput::generate(CGAL::Object o) -{ - insertCurve( - demo_types::enumFromArrType(), - CGAL::make_object(this->arrangement), o); +void GraphicsViewCurveInput::generate(CGAL::Object o) { + insertCurve(demo_types::enumFromArrType(), + CGAL::make_object(this->arrangement), o); Q_EMIT CGAL::Qt::GraphicsViewCurveInputBase::modelChanged(); } +// template -void GraphicsViewCurveInput::curveInputDoneEvent( - const std::vector& clickedPoints, CurveType type) -{ +void GraphicsViewCurveInput:: +curveInputDoneEvent(const std::vector& clickedPoints, CurveType type) { boost::optional cv = this->curveGenerator.generate(clickedPoints, type); - if (cv) - { + if (cv) { Insert_curve{}(this->arrangement, *cv); Q_EMIT this->modelChanged(); } @@ -142,13 +133,12 @@ void GraphicsViewCurveInput::curveInputDoneEvent( // CurveGeneratorBase template -auto CurveGeneratorBase::generate( - const std::vector& clickedPoints, CurveType type) +auto CurveGeneratorBase:: +generate(const std::vector& clickedPoints, CurveType type) -> boost::optional { boost::optional res; - switch (type) - { + switch (type) { case CurveType::Segment: res = generateSegment(clickedPoints); break; @@ -171,7 +161,7 @@ auto CurveGeneratorBase::generate( res = generateThreePointCircularArc(clickedPoints); break; case CurveType::FivePointConicArc: - res = generateFivePointConicArc(clickedPoints); + res = generateFivePointConicArc(clickedPoints); break; case CurveType::Bezier: res = generateBezier(clickedPoints); @@ -181,16 +171,16 @@ auto CurveGeneratorBase::generate( return res; } +// template void CurveGeneratorBase::setTraits(const ArrTraits* traits_) -{ - this->traits = traits_; -} +{ this->traits = traits_; } // Curve Generator Segment Traits template -auto CurveGenerator>::generateSegment( - const std::vector& clickedPoints) -> boost::optional +auto CurveGenerator>:: +generateSegment(const std::vector& clickedPoints) + -> boost::optional { Curve_2 res{clickedPoints[0], clickedPoints[1]}; return res; @@ -211,25 +201,25 @@ auto CurveGenerator>:: // Curve Generator Linear Traits template -auto CurveGenerator>::generateSegment( - const std::vector& points) -> boost::optional +auto CurveGenerator>:: +generateSegment(const std::vector& points) -> boost::optional { Curve_2 res = Curve_2(Segment_2(points[0], points[1])); return res; } +// template -auto CurveGenerator>::generateRay( - const std::vector& points) -> boost::optional -{ +auto CurveGenerator>:: +generateRay(const std::vector& points) -> boost::optional { Curve_2 res = Curve_2(Ray_2(points[0], points[1])); return res; } +// template -auto CurveGenerator>::generateLine( - const std::vector& points) -> boost::optional -{ +auto CurveGenerator>:: +generateLine(const std::vector& points) -> boost::optional { Curve_2 res = Curve_2(Line_2(points[0], points[1])); return res; } @@ -237,28 +227,31 @@ auto CurveGenerator>::generateLine( // CurveGenerator Conic Traits template auto CurveGenerator>:: - generateSegment(const std::vector& points) - -> boost::optional +generateSegment(const std::vector& points) + -> boost::optional { - Curve_2 res = Curve_2(Rat_segment_2(points[0], points[1])); + auto ctr_cv = this->traits->construct_curve_2_object(); + Curve_2 res = ctr_cv(Rat_segment_2(points[0], points[1])); return res; } +// template auto CurveGenerator>:: - generateCircle(const std::vector& points) -> boost::optional -{ +generateCircle(const std::vector& points) -> boost::optional { auto sq_rad = (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) + (points[0].y() - points[1].y()) * (points[0].y() - points[1].y()); - Curve_2 res = Curve_2(Rat_circle_2(points[0], sq_rad)); + auto ctr_cv = this->traits->construct_curve_2_object(); + Curve_2 res = ctr_cv(Rat_circle_2(points[0], sq_rad)); return res; } +// template auto CurveGenerator>:: - generateEllipse(const std::vector& points) - -> boost::optional +generateEllipse(const std::vector& points) + -> boost::optional { auto x1 = (CGAL::min)(points[0].x(), points[1].x()); auto y1 = (CGAL::min)(points[0].y(), points[1].y()); @@ -279,14 +272,16 @@ auto CurveGenerator>:: Rat_FT v = -2 * y0 * a_sq; Rat_FT ww = x0 * x0 * b_sq + y0 * y0 * a_sq - a_sq * b_sq; - Curve_2 res = Curve_2(r, s, t, u, v, ww); + auto ctr_cv = this->traits->construct_curve_2_object(); + Curve_2 res = ctr_cv(r, s, t, u, v, ww); return res; } +// template auto CurveGenerator>:: - generateThreePointCircularArc(const std::vector& points) - -> boost::optional +generateThreePointCircularArc(const std::vector& points) + -> boost::optional { auto& qp1 = points[0]; auto& qp2 = points[1]; @@ -295,22 +290,22 @@ auto CurveGenerator>:: Rat_point_2 p2 = Rat_point_2(qp2.x(), qp2.y()); Rat_point_2 p3 = Rat_point_2(qp3.x(), qp3.y()); RatKernel ker; - if (!ker.collinear_2_object()(p1, p2, p3)) - { - Curve_2 res(p1, p2, p3); + if (! ker.collinear_2_object()(p1, p2, p3)) { + auto ctr_cv = this->traits->construct_curve_2_object(); + Curve_2 res = ctr_cv(p1, p2, p3); return res; } - else - { + else { std::cout << "Points don't specify a valid conic." << std::endl; return {}; } } +// template auto CurveGenerator>:: - generateFivePointConicArc(const std::vector& points) - -> boost::optional +generateFivePointConicArc(const std::vector& points) + -> boost::optional { auto& qp0 = points[0]; auto& qp1 = points[1]; @@ -322,17 +317,14 @@ auto CurveGenerator>:: Rat_point_2 p2 = Rat_point_2(qp2.x(), qp2.y()); Rat_point_2 p3 = Rat_point_2(qp3.x(), qp3.y()); Rat_point_2 p4 = Rat_point_2(qp4.x(), qp4.y()); - try - { - Curve_2 res(p0, p1, p2, p3, p4); - if (res.is_valid()) - return res; - else - std::cout << "Points don't specify a valid conic. Try again!" - << std::endl; + try { + auto ctr_cv = this->traits->construct_curve_2_object(); + Curve_2 res = ctr_cv(p0, p1, p2, p3, p4); + if (res.is_valid()) return res; + else std::cout << "Points don't specify a valid conic. Try again!" + << std::endl; } - catch (...) - { + catch (...) { std::cout << "Points don't specify a valid conic. Try again!" << std::endl; } return {}; @@ -341,8 +333,7 @@ auto CurveGenerator>:: // CurveGenerator Algebraic Traits template auto CurveGenerator>:: - generateLine(const std::vector& points) -> boost::optional -{ +generateLine(const std::vector& points) -> boost::optional { RationalTraits ratTraits; Rational dx = points[1].x() - points[0].x(); @@ -351,8 +342,7 @@ auto CurveGenerator>:: Polynomial_2 y = CGAL::shift(Polynomial_2(1), 1, 1); Polynomial_2 poly; - if (dx != 0) - { + if (dx != 0) { Rational mRat = dy / dx; Rational cRat = points[0].y() - mRat * points[0].x(); // y = (a/b) x + (e/f) @@ -364,8 +354,7 @@ auto CurveGenerator>:: poly = b * f * y - f * a * x - b * e; } // vertical line - else - { + else { Rational xP = points[0].x(); auto a = ratTraits.numerator(xP); auto b = ratTraits.denominator(xP); @@ -377,10 +366,10 @@ auto CurveGenerator>:: return res; } +// template auto CurveGenerator>:: - generateCircle(const std::vector& points) -> boost::optional -{ +generateCircle(const std::vector& points) -> boost::optional { auto sq_rad = (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) + (points[0].y() - points[1].y()) * (points[0].y() - points[1].y()); @@ -389,8 +378,8 @@ auto CurveGenerator>:: template auto CurveGenerator>:: - generateEllipse(const std::vector& points) - -> boost::optional +generateEllipse(const std::vector& points) + -> boost::optional { auto rx = (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) / 4.; @@ -401,10 +390,11 @@ auto CurveGenerator>:: return this->generateEllipse_(center, rx, ry); } +// template auto CurveGenerator>:: - generateEllipse_(const Point_2& center, Rational rxRat, Rational ryRat) - -> boost::optional +generateEllipse_(const Point_2& center, Rational rxRat, Rational ryRat) + -> boost::optional { RationalTraits ratTraits; @@ -432,26 +422,23 @@ auto CurveGenerator>:: return res; } -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -auto CurveGenerator< - Arr_Bezier_curve_traits_2>:: - generateBezier(const std::vector& clickedPoints) - -> boost::optional +// +template +auto CurveGenerator +>:: +generateBezier(const std::vector& clickedPoints) + -> boost::optional { if (clickedPoints.size() < 2) return {}; return Curve_2{clickedPoints.begin(), clickedPoints.end()}; } // msvc2015 doesn't play well with polymorphic lambdas -namespace -{ -struct ExplicitLambda -{ +namespace { +struct ExplicitLambda { template - void operator()(demo_types::TypeHolder) - { + void operator()(demo_types::TypeHolder) { Arrangement* arr = nullptr; CGAL::assign(arr, arr_obj); res = new GraphicsViewCurveInput(arr, parent, scene); @@ -464,6 +451,7 @@ struct ExplicitLambda }; } // anonymous namespace +// GraphicsViewCurveInputBase* GraphicsViewCurveInputBase::create( demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent, QGraphicsScene* scene) @@ -478,8 +466,11 @@ GraphicsViewCurveInputBase* GraphicsViewCurveInputBase::create( } // namespace CGAL #ifdef CGAL_USE_CORE -CGAL::Object algebraicCurveFromExpression( - const CGAL::Object& arr_obj, const std::string& exp, bool& is_first_curve) + +// +CGAL::Object algebraicCurveFromExpression(const CGAL::Object& arr_obj, + const std::string& exp, + bool& is_first_curve) { using Polynomial_2 = demo_types::DemoTypes::Alg_seg_traits::Polynomial_2; using Alg_seg_arr = demo_types::DemoTypes::Alg_seg_arr; @@ -498,15 +489,17 @@ CGAL::Object algebraicCurveFromExpression( return CGAL::make_object(cv); } -CGAL::Object rationalCurveFromExpression( - const CGAL::Object& arr_obj, const std::string& numerator, - const std::string& denominator, bool& is_first_curve) +// +CGAL::Object rationalCurveFromExpression(const CGAL::Object& arr_obj, + const std::string& numerator, + const std::string& denominator, + bool& is_first_curve) { using Polynomial_1 = demo_types::DemoTypes::Rational_traits::Polynomial_1; using Rational_arr = demo_types::DemoTypes::Rational_arr; Rational_arr* arr; - if (!CGAL::assign(arr, arr_obj)) CGAL_error(); + if (! CGAL::assign(arr, arr_obj)) CGAL_error(); is_first_curve = (arr->number_of_edges() == 0); @@ -521,4 +514,5 @@ CGAL::Object rationalCurveFromExpression( return CGAL::make_object(cv); } + #endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h index 1c8a1b94699..2b4a68457f8 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h @@ -30,14 +30,11 @@ namespace demo_types enum class TraitsType : int; } -namespace CGAL -{ -namespace Qt -{ +namespace CGAL { +namespace Qt { template -class CurveGeneratorBase -{ +class CurveGeneratorBase { public: using ArrTraits = ArrTraits_; using Curve_2 = typename ArrTraits::Curve_2; @@ -50,31 +47,40 @@ public: virtual boost::optional generateSegment(const std::vector&) { return {}; } + virtual boost::optional generateRay(const std::vector&) { return {}; } + virtual boost::optional generateLine(const std::vector&) { return {}; } + virtual boost::optional generatePolyline(const std::vector&) { return {}; } + virtual boost::optional generateCircle(const std::vector&) { return {}; } + virtual boost::optional generateEllipse(const std::vector&) { return {}; } + virtual boost::optional generateThreePointCircularArc(const std::vector&) { return {}; } + virtual boost::optional generateFivePointConicArc(const std::vector&) { return {}; } + virtual boost::optional generateBezier(const std::vector&) { return {}; } const ArrTraits* traits; }; +// Generic implementation. template struct CurveGenerator : public CurveGeneratorBase -{ -}; +{}; +// Specialization for the segment traits. template struct CurveGenerator> : public CurveGeneratorBase> @@ -89,6 +95,7 @@ struct CurveGenerator> : generateSegment(const std::vector&) override; }; +// Specialization for the polyline traits. template struct CurveGenerator> : public CurveGeneratorBase> @@ -102,10 +109,10 @@ struct CurveGenerator> : generatePolyline(const std::vector&) override; }; +// Specialization for the conic traits. template struct CurveGenerator> : - public CurveGeneratorBase< - Arr_conic_traits_2> + public CurveGeneratorBase> { using ArrTraits = Arr_conic_traits_2; using Curve_2 = typename ArrTraits::Curve_2; @@ -120,11 +127,15 @@ struct CurveGenerator> : boost::optional generateSegment(const std::vector&) override; + boost::optional generateCircle(const std::vector&) override; + boost::optional generateEllipse(const std::vector&) override; + boost::optional generateThreePointCircularArc(const std::vector&) override; + boost::optional generateFivePointConicArc(const std::vector&) override; }; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp index 45651705ba2..0729852bcbe 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp @@ -21,15 +21,14 @@ #include template -class MergeEdgeCallback : public MergeEdgeCallbackBase -{ +class MergeEdgeCallback : public MergeEdgeCallbackBase { public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef Arr_ Arrangement; + typedef typename Arrangement::Halfedge_handle Halfedge_handle; + typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; + typedef typename Arrangement::Vertex_iterator Vertex_iterator; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; MergeEdgeCallback(Arrangement* arr_, QObject* parent_); void setScene(QGraphicsScene* scene_) override; @@ -51,14 +50,12 @@ protected: }; // class MergeEdgeCallback // msvc2015 doesn't play well with polymorphic lambdas -namespace -{ -struct ExplicitLambda -{ +namespace { + +struct ExplicitLambda { template - void operator()(demo_types::TypeHolder) - { - Arrangement* arr = nullptr; + void operator()(demo_types::TypeHolder) { + Arrangement* arr(nullptr); CGAL::assign(arr, arr_obj); res = new MergeEdgeCallback(arr, parent); } @@ -67,11 +64,13 @@ struct ExplicitLambda CGAL::Object& arr_obj; QObject* parent; }; + } // anonymous namespace -MergeEdgeCallbackBase* MergeEdgeCallbackBase::create( - demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) -{ +// +MergeEdgeCallbackBase* +MergeEdgeCallbackBase::create(demo_types::TraitsType tt, CGAL::Object arr_obj, + QObject* parent) { MergeEdgeCallbackBase* res; ExplicitLambda explicit_lambda{res, arr_obj, parent}; demo_types::visitArrangementType(tt, explicit_lambda); @@ -80,55 +79,52 @@ MergeEdgeCallbackBase* MergeEdgeCallbackBase::create( /*! Constructor */ template -MergeEdgeCallback::MergeEdgeCallback( - Arrangement* arr_, QObject* parent_) : - MergeEdgeCallbackBase(parent_), - highlightedCurve(new CGAL::Qt::CurveGraphicsItem()), - highlightedCurve2(new CGAL::Qt::CurveGraphicsItem()), arr(arr_), - isFirst(true) +MergeEdgeCallback::MergeEdgeCallback(Arrangement* arr_, + QObject* parent_) : + MergeEdgeCallbackBase(parent_), + highlightedCurve(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))), + highlightedCurve2(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))), arr(arr_), + isFirst(true) { - QObject::connect( - this, SIGNAL(modelChanged()), this->highlightedCurve, SLOT(modelChanged())); - QObject::connect( - this, SIGNAL(modelChanged()), this->highlightedCurve2, - SLOT(modelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), this->highlightedCurve, + SLOT(modelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), this->highlightedCurve2, + SLOT(modelChanged())); } +// template -void MergeEdgeCallback::setScene(QGraphicsScene* scene_) -{ +void MergeEdgeCallback::setScene(QGraphicsScene* scene_) { Callback::setScene(scene_); this->highlightedCurve->setScene(scene_); this->highlightedCurve2->setScene(scene_); - if (scene_) - { + if (scene_) { this->scene->addItem(this->highlightedCurve); this->scene->addItem(this->highlightedCurve2); } } +// template -void MergeEdgeCallback::reset() -{ +void MergeEdgeCallback::reset() { this->isFirst = true; this->highlightedCurve->clear(); this->highlightedCurve2->clear(); this->mergeableHalfedge = Halfedge_handle(); } +// template -void MergeEdgeCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - if (this->isFirst) - { // save the first edge if mergeable +void MergeEdgeCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) { + if (this->isFirst) { + // save the first edge if mergeable Halfedge_handle halfedge = this->getNearestMergeableCurve(event); - if (halfedge == Halfedge_handle()) { return; } + if (halfedge == Halfedge_handle()) return; this->isFirst = false; this->mergeableHalfedge = halfedge; } - else - { + else { Halfedge_handle nextHalfedge = this->getNearestMergeableCurve(this->mergeableHalfedge, event); this->mergeEdge.mergeEdge(this->arr, this->mergeableHalfedge, nextHalfedge); @@ -138,24 +134,21 @@ void MergeEdgeCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) Q_EMIT modelChanged(); } +// template -void MergeEdgeCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - if (this->isFirst) - { +void MergeEdgeCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { + if (this->isFirst) { Halfedge_handle halfedge = this->getNearestMergeableCurve(event); if (halfedge == Halfedge_handle()) { return; } this->highlightedCurve->clear(); this->highlightedCurve->insert(halfedge->curve()); Q_EMIT modelChanged(); } - else - { + else { Halfedge_handle nextHalfedge = this->getNearestMergeableCurve(this->mergeableHalfedge, event); - if (nextHalfedge != Halfedge_handle()) - { + if (nextHalfedge != Halfedge_handle()) { this->highlightedCurve2->clear(); this->highlightedCurve2->insert(nextHalfedge->curve()); Q_EMIT modelChanged(); @@ -163,65 +156,60 @@ void MergeEdgeCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) } } +// template typename MergeEdgeCallback::Halfedge_handle -MergeEdgeCallback::getNearestMergeableCurve( - QGraphicsSceneMouseEvent* event) -{ +MergeEdgeCallback:: +getNearestMergeableCurve(QGraphicsSceneMouseEvent* event) { // find the nearest curve to the cursor that is adjacent to a curve that // can be merged with it - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; + using Kernel = typename ArrTraitsAdaptor::Kernel; + using Kernel_point_2 = typename Kernel::Point_2; Kernel_point_2 p = CGAL::Qt::Converter{}(event->scenePos()); - double minDist = (std::numeric_limits::max)(); + double min_dist = (std::numeric_limits::max)(); Halfedge_iterator nearestHei; bool found = false; - for (Halfedge_iterator hei = this->arr->halfedges_begin(); + for (auto hei = this->arr->halfedges_begin(); hei != this->arr->halfedges_end(); ++hei) { Vertex_iterator source = hei->source(); Vertex_iterator target = hei->target(); - if (source->degree() != 2 && target->degree() != 2) - { // then this halfedge has no mergeable neighbors - continue; - } + // then this halfedge has no mergeable neighbors + if (source->degree() != 2 && target->degree() != 2) continue; Halfedge_handle h1 = hei->prev(); Halfedge_handle h2 = hei->next(); - if ( - (!this->mergeEdge.areMergeable(this->arr, hei, h1)) && - (!this->mergeEdge.areMergeable(this->arr, hei, h2))) + if ((!this->mergeEdge.areMergeable(this->arr, hei, h1)) && + (!this->mergeEdge.areMergeable(this->arr, hei, h2))) { continue; } X_monotone_curve_2 curve = hei->curve(); - Compute_squared_distance_2 squaredDistance; - squaredDistance.setScene(this->getScene()); - double dist = CGAL::to_double(squaredDistance(p, curve)); - if (!found || dist < minDist) - { + Compute_squared_distance_2 + squared_distance(*(arr->geometry_traits())); + squared_distance.setScene(this->getScene()); + double dist = CGAL::to_double(squared_distance(p, curve)); + if (! found || dist < min_dist) { found = true; - minDist = dist; + min_dist = dist; nearestHei = hei; } } - if (!found) - { // then we did not find a mergeable halfedge - return Halfedge_handle(); - } + // then we did not find a mergeable halfedge + if (! found) return Halfedge_handle(); return nearestHei; } +// template typename MergeEdgeCallback::Halfedge_handle -MergeEdgeCallback::getNearestMergeableCurve( - Halfedge_handle h, QGraphicsSceneMouseEvent* event) -{ +MergeEdgeCallback:: +getNearestMergeableCurve(Halfedge_handle h, QGraphicsSceneMouseEvent* event) { // find the nearest curve to the cursor that is adjacent to a curve that // can be merged with it - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; + using Kernel = typename ArrTraitsAdaptor::Kernel; + using Kernel_point_2 = typename Kernel::Point_2 ; Kernel_point_2 p = CGAL::Qt::Converter{}(event->scenePos()); Halfedge_handle h1 = h->prev(); @@ -229,29 +217,23 @@ MergeEdgeCallback::getNearestMergeableCurve( Vertex_iterator source = h->source(); Vertex_iterator target = h->target(); - if (source->degree() != 2 && target->degree() != 2) - return Halfedge_handle(); - else if (source->degree() != 2) - return h2; - else if (target->degree() != 2) - return h1; - else if ( - this->mergeEdge.areMergeable(arr, h, h1) && - this->mergeEdge.areMergeable(arr, h, h2)) + if (source->degree() != 2 && target->degree() != 2) return Halfedge_handle(); + else if (source->degree() != 2) return h2; + else if (target->degree() != 2) return h1; + else if (this->mergeEdge.areMergeable(arr, h, h1) && + this->mergeEdge.areMergeable(arr, h, h2)) { X_monotone_curve_2 c1 = h1->curve(); X_monotone_curve_2 c2 = h2->curve(); - Compute_squared_distance_2 squaredDistance; - squaredDistance.setScene(this->getScene()); - double d1 = CGAL::to_double(squaredDistance(p, c1)); - double d2 = CGAL::to_double(squaredDistance(p, c2)); + Compute_squared_distance_2 + squared_distance(*(arr->geometry_traits())); + squared_distance.setScene(this->getScene()); + double d1 = CGAL::to_double(squared_distance(p, c1)); + double d2 = CGAL::to_double(squared_distance(p, c2)); return (d1 < d2) ? h1 : h2; } - else if (this->mergeEdge.areMergeable(arr, h, h2)) - return h2; - else if (this->mergeEdge.areMergeable(arr, h, h1)) - return h1; - else - return Halfedge_handle(); + else if (this->mergeEdge.areMergeable(arr, h, h2)) return h2; + else if (this->mergeEdge.areMergeable(arr, h, h1)) return h1; + else return Halfedge_handle(); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp index 6e2763f02fc..4baf3436435 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp @@ -96,54 +96,55 @@ PointLocationCallbackBase* PointLocationCallbackBase::create( /*! Constructor */ template -PointLocationCallback::PointLocationCallback( - Arrangement* arr_, QObject* parent_) : - PointLocationCallbackBase(parent_), - arr(arr_), highlightedCurves(new CGAL::Qt::CurveGraphicsItem()) +PointLocationCallback::PointLocationCallback(Arrangement* arr_, + QObject* parent_) : + PointLocationCallbackBase(parent_), + arr(arr_), + highlightedCurves(new CGAL::Qt::CurveGraphicsItem(*(arr_->geometry_traits()))) { - QObject::connect( - this, SIGNAL(modelChanged()), this->highlightedCurves, - SLOT(modelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), this->highlightedCurves, + SLOT(modelChanged())); } +// template -void PointLocationCallback::setScene(QGraphicsScene* scene_) -{ +void PointLocationCallback::setScene(QGraphicsScene* scene_) { this->scene = scene_; this->highlightedCurves->setScene(scene_); if (this->scene) { this->scene->addItem(this->highlightedCurves); } } +// template -void PointLocationCallback::reset() -{ +void PointLocationCallback::reset() { this->highlightedCurves->clear(); Q_EMIT modelChanged(); } +// template -void PointLocationCallback::mousePressEvent( - QGraphicsSceneMouseEvent* event) -{ +void PointLocationCallback:: +mousePressEvent(QGraphicsSceneMouseEvent* event) { this->highlightPointLocation(event); } +// template -void PointLocationCallback::mouseMoveEvent( - QGraphicsSceneMouseEvent* /* event */) -{ +void PointLocationCallback:: +mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) { } +// template -void PointLocationCallback::highlightPointLocation( - QGraphicsSceneMouseEvent* event) -{ +void PointLocationCallback:: +highlightPointLocation(QGraphicsSceneMouseEvent* event) { typename Traits::Left_side_category category; this->highlightPointLocation(event, category); Q_EMIT modelChanged(); } +// template void PointLocationCallback::highlightPointLocation( QGraphicsSceneMouseEvent* event, CGAL::Arr_oblivious_side_tag) @@ -152,22 +153,19 @@ void PointLocationCallback::highlightPointLocation( PointLocationFunctions{}.getFace(this->arr, event->scenePos()); this->highlightedCurves->clear(); - if (!face->is_unbounded()) - { // it is an interior face; highlight its border + if (!face->is_unbounded()) { // it is an interior face; highlight its border Ccb_halfedge_const_circulator cc = face->outer_ccb(); - do - { + do { X_monotone_curve_2 curve = cc->curve(); this->highlightedCurves->insert(curve); } while (++cc != face->outer_ccb()); } Hole_const_iterator hit; Hole_const_iterator eit = face->holes_end(); - for (hit = face->holes_begin(); hit != eit; ++hit) - { // highlight any holes inside this face + for (hit = face->holes_begin(); hit != eit; ++hit) { + // highlight any holes inside this face Ccb_halfedge_const_circulator cc = *hit; - do - { + do { X_monotone_curve_2 curve = cc->curve(); this->highlightedCurves->insert(curve); cc++; @@ -175,30 +173,28 @@ void PointLocationCallback::highlightPointLocation( } } +// template -void PointLocationCallback::highlightPointLocation( - QGraphicsSceneMouseEvent* event, CGAL::Arr_open_side_tag) +void PointLocationCallback:: +highlightPointLocation(QGraphicsSceneMouseEvent* event, CGAL::Arr_open_side_tag) { Face_const_handle face = PointLocationFunctions{}.getFace(this->arr, event->scenePos()); this->highlightedCurves->clear(); Ccb_halfedge_const_circulator cc = face->outer_ccb(); - do - { - if (!cc->is_fictitious()) - { + do { + if (!cc->is_fictitious()) { X_monotone_curve_2 curve = cc->curve(); this->highlightedCurves->insert(curve); } } while (++cc != face->outer_ccb()); Hole_const_iterator hit; Hole_const_iterator eit = face->holes_end(); - for (hit = face->holes_begin(); hit != eit; ++hit) - { // highlight any holes inside this face + for (hit = face->holes_begin(); hit != eit; ++hit) { + // highlight any holes inside this face Ccb_halfedge_const_circulator cc = *hit; - do - { + do { X_monotone_curve_2 curve = cc->curve(); this->highlightedCurves->insert(curve); cc++; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp index 9c1c8fbc83d..2d5422fa9ec 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp @@ -16,6 +16,7 @@ #include #include +// static const CGAL::Bbox_2 inf_bbox = { -std::numeric_limits::infinity(), -std::numeric_limits::infinity(), @@ -24,25 +25,27 @@ static const CGAL::Bbox_2 inf_bbox = { static constexpr double inf_double = std::numeric_limits::infinity(); -template -struct ConstructBoundingBox_impl -{ - using Traits = Traits_; +// +template +class ConstructBoundingBox_impl { + using Traits = GeometryTraits; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) { #ifdef CGAL_USE_CORE using Zero_resultant_exception = CGAL::internal::Zero_resultant_exception< typename demo_types::DemoTypes::Alg_seg_traits::Polynomial_2>; #endif CGAL::Bbox_2 bbox; - try - { + try { bbox = curve.bbox(); } // algebraic traits sometimes crash when calling bbox @@ -70,13 +73,15 @@ struct ConstructBoundingBox_impl return bbox; } - CGAL::Bbox_2 - operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { double x = CGAL::to_double(point.x()); double y = CGAL::to_double(point.y()); return {x, y, x, y}; } + +private: + const Traits& m_traits; }; // We currently avoid using bbox function in Arr_sgegment_2 because it creates @@ -84,21 +89,22 @@ struct ConstructBoundingBox_impl // TODO: remove this class and the polyline one once it's fixed // and use bbox directly template -struct ConstructBoundingBox_impl> -{ +class ConstructBoundingBox_impl> { using Traits = CGAL::Arr_segment_traits_2; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { - return this->operator()(curve.source(), curve.target()); - } +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} - CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) - { + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) + { return this->operator()(curve.source(), curve.target()); } + + // + CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) { CGAL::Bbox_2 bbox; double x1 = CGAL::to_double(p1.x()); double y1 = CGAL::to_double(p1.y()); @@ -106,40 +112,39 @@ struct ConstructBoundingBox_impl> double y2 = CGAL::to_double(p2.y()); double min_x, max_x, min_y, max_y; - if (x1 < x2) - { + if (x1 < x2) { min_x = x1; max_x = x2; } - else - { + else { min_x = x2; max_x = x1; } - if (y1 < y2) - { + if (y1 < y2) { min_y = y1; max_y = y2; } - else - { + else { min_y = y2; max_y = y1; } return {min_x, min_y, max_x, max_y}; } - CGAL::Bbox_2 - operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { double x = CGAL::to_double(point.x()); double y = CGAL::to_double(point.y()); return {x, y, x, y}; } + +private: + const Traits& m_traits; }; +// template -struct ConstructBoundingBox_impl> +class ConstructBoundingBox_impl> { using Traits = CGAL::Arr_polyline_traits_2; using SegmentTraits_2 = SegmentTraits_2_; @@ -147,21 +152,22 @@ struct ConstructBoundingBox_impl> using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { - ConstructBoundingBox_impl construct_bounding_box; +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) { + const auto* sub_traits = m_traits.subcurve_traits_2(); + ConstructBoundingBox_impl ctr_bbox(*sub_traits); auto n = curve.number_of_subcurves(); CGAL::Bbox_2 bbox; - for (std::size_t i = 0; i < n; ++i) - bbox += construct_bounding_box(curve[i]); - + for (std::size_t i = 0; i < n; ++i) bbox += ctr_bbox(curve[i]); return bbox; } - CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) - { + // + CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) { CGAL::Bbox_2 bbox; double x1 = CGAL::to_double(p1.x()); double y1 = CGAL::to_double(p1.y()); @@ -169,61 +175,57 @@ struct ConstructBoundingBox_impl> double y2 = CGAL::to_double(p2.y()); double min_x, max_x, min_y, max_y; - if (x1 < x2) - { + if (x1 < x2) { min_x = x1; max_x = x2; } - else - { + else { min_x = x2; max_x = x1; } - if (y1 < y2) - { + if (y1 < y2) { min_y = y1; max_y = y2; } - else - { + else { min_y = y2; max_y = y1; } return {min_x, min_y, max_x, max_y}; } - CGAL::Bbox_2 - operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { double x = CGAL::to_double(point.x()); double y = CGAL::to_double(point.y()); return {x, y, x, y}; } + +private: + const Traits& m_traits; }; +// template -struct ConstructBoundingBox_impl> -{ +class ConstructBoundingBox_impl> { using Traits = CGAL::Arr_linear_traits_2; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { - if (curve.is_segment()) - { - return ConstructBoundingBox_impl>{}( - curve.source(), curve.target()); - } - else if (curve.is_line()) - { - return inf_bbox; +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) { + if (curve.is_segment()) { + auto&& seg = curve.segment(); + return operator()(seg.source()) + operator()(seg.target()); } + else if (curve.is_line()) return inf_bbox; // ray - else - { + else { auto&& ray = curve.ray(); auto&& src = ray.source(); double src_x = CGAL::to_double(src.x()); @@ -232,65 +234,101 @@ struct ConstructBoundingBox_impl> bool dx = CGAL::is_positive(dir.dx()); bool dy = CGAL::is_positive(dir.dy()); - if (dx && dy) - return {src_x, src_y, inf_double, inf_double}; - else if (!dx && dy) - return {-inf_double, src_y, src_x, inf_double}; - else if (!dx && !dy) - return {-inf_double, -inf_double, src_x, src_y}; + if (dx && dy) return {src_x, src_y, inf_double, inf_double}; + else if (!dx && dy) return {-inf_double, src_y, src_x, inf_double}; + else if (!dx && !dy) return {-inf_double, -inf_double, src_x, src_y}; else // if (dx && !dy) return {src_x, -inf_double, inf_double, src_y}; } } - CGAL::Bbox_2 operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { double x = CGAL::to_double(point.x()); double y = CGAL::to_double(point.y()); return {x, y, x, y}; } + +private: + const Traits& m_traits; }; +// Specialization of `ConstructBoundingBox_impl` for the conic traits. +template +class ConstructBoundingBox_impl +> { + using Traits = CGAL::Arr_conic_traits_2; + using Point_2 = typename Traits::Point_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; -template < - typename RatKernel_, typename AlgKernel_, typename NtTraits_, - typename BoundingTraits_> -struct ConstructBoundingBox_impl> +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + + // Obtain the bounding box for an x-monotone conic curve. + CGAL::Bbox_2 operator()(const X_monotone_curve_2& xcv) + { return m_traits.construct_bbox_2_object()(xcv); } + + // Obtain the bounding box for an conic point. + CGAL::Bbox_2 operator()(const Point_2& point) { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } + +private: + const Traits& m_traits; +}; + +// Specialization of `ConstructBoundingBox_impl` for the Bezier traits. +template +class ConstructBoundingBox_impl> { - using Traits = typename CGAL::Arr_Bezier_curve_traits_2< - RatKernel_, AlgKernel_, NtTraits_, BoundingTraits_>; + using Traits = typename CGAL::Arr_Bezier_curve_traits_2 + ; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) { // TODO: find a way to find the bounding box of a bezier X_monotone_curve return curve.supporting_curve().bbox(); } - CGAL::Bbox_2 - operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { std::pair p = point.approximate(); return {p.first, p.second, p.first, p.second}; } + +private: + const Traits& m_traits; }; +// Specialization of `ConstructBoundingBox_impl` for the rational-function +// traits. template -struct ConstructBoundingBox_impl< - CGAL::Arr_rational_function_traits_2> -{ +class ConstructBoundingBox_impl> { using Traits = CGAL::Arr_rational_function_traits_2; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Curve_2 = typename Traits::Curve_2; using Point_2 = typename Traits::Point_2; - CGAL::Bbox_2 - operator()(const X_monotone_curve_2& curve) - { +public: + // Construct from traits; + ConstructBoundingBox_impl(const Traits& traits) : m_traits(traits) {} + + // + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve) { double min_x, max_x, min_y, max_y; if (curve.left_parameter_space_in_x() == CGAL::ARR_INTERIOR) min_x = CGAL::to_double(curve.left_x()); @@ -313,25 +351,26 @@ struct ConstructBoundingBox_impl< return {min_x, min_y, max_x, max_y}; } - CGAL::Bbox_2 - operator()(const Point_2& point) - { + // + CGAL::Bbox_2 operator()(const Point_2& point) { double x = CGAL::to_double(point.x()); double y = CGAL::to_double(point.y()); return {x, y, x, y}; } + +private: + const Traits& m_traits; }; +// template CGAL::Bbox_2 ConstructBoundingBox::operator()(const X_monotone_curve_2& curve) -{ - return ConstructBoundingBox_impl{}(curve); -} +{ return ConstructBoundingBox_impl(m_traits)(curve); } + +// template CGAL::Bbox_2 ConstructBoundingBox::operator()(const Point_2& point) -{ - return ConstructBoundingBox_impl{}(point); -} +{ return ConstructBoundingBox_impl(m_traits)(point); } ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(ConstructBoundingBox) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h index 83b6e712f1b..ccd4511cac3 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h @@ -17,15 +17,23 @@ // bounding box utility for arrangements // doesn't have to be exact, only good enough for rendering template -class ConstructBoundingBox -{ +class ConstructBoundingBox { public: using Traits = Traits_; using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; using Point_2 = typename Traits::Point_2; + // Construct from traits. + ConstructBoundingBox(const Traits& traits) : m_traits(traits) {} + + // CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve); + + // CGAL::Bbox_2 operator()(const Point_2& point); + +private: + const Traits& m_traits; }; #endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp index 5fcdeb8fc3c..5a397f53bde 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp @@ -23,11 +23,11 @@ #include #include +// template double -Compute_squared_distance_2>::operator()( - const Point_2& p, const X_monotone_curve_2& c) const -{ +Compute_squared_distance_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& c) const { Point_2 p1 = c.source(); Point_2 p2 = c.target(); Segment_2 seg(p1, p2); @@ -35,33 +35,31 @@ Compute_squared_distance_2>::operator()( return CGAL::to_double(CGAL::squared_distance(p, seg)); } +// template double -Compute_squared_distance_2>::operator()( - const Point_2& p, const X_monotone_curve_2& c) const -{ +Compute_squared_distance_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& c) const { Segment_2 seg; Ray_2 ray; Line_2 line; FT res; - if (c.is_segment()) - { + if (c.is_segment()) { seg = c.segment(); res = CGAL::squared_distance(p, seg); } - else if (c.is_ray()) - { + else if (c.is_ray()) { ray = c.ray(); res = CGAL::squared_distance(p, ray); } - else // ( c.is_line( ) ) - { + else {// ( c.is_line( ) ) line = c.line(); res = CGAL::squared_distance(p, line); } return CGAL::to_double(res); } +// template double Compute_squared_distance_2>::operator()( @@ -72,13 +70,11 @@ Compute_squared_distance_2>::operator()( bool first = true; FT min_dist = 0; - while (seg_it_s != c.subcurves_end()) - { + while (seg_it_s != c.subcurves_end()) { Segment_2 seg = *seg_it_s; FT dist = CGAL::squared_distance(p, seg); - if (first || dist < min_dist) - { + if (first || dist < min_dist) { first = false; min_dist = dist; } @@ -88,19 +84,18 @@ Compute_squared_distance_2>::operator()( return CGAL::to_double(min_dist); } +// template -double Compute_squared_distance_2< - CGAL::Arr_conic_traits_2>:: -operator()(const Point_2& p, const X_monotone_curve_2& c) const -{ - // Get the coordinates of the curve's source and target. +double Compute_squared_distance_2 +>:: +operator()(const Point_2& p, const X_monotone_curve_2& c) const { + // Get the coordinates of the curve source and target. // double sx = CGAL::to_double( c.source( ).x( ) ); // double sy = CGAL::to_double( c.source( ).y( ) ); // double tx = CGAL::to_double( c.target( ).x( ) ); // double ty = CGAL::to_double( c.target( ).y( ) ); - if (c.orientation() == CGAL::COLLINEAR) - { + if (c.orientation() == CGAL::COLLINEAR) { Point_2 ps = c.source(); Point_2 pt = c.target(); Segment_2 seg(ps, pt); @@ -108,8 +103,7 @@ operator()(const Point_2& p, const X_monotone_curve_2& c) const FT res = CGAL::squared_distance(p, seg); return CGAL::to_double(res); } - else - { + else { // If the curve is monotone, than its source and its target has the // extreme x coordinates on this curve. // bool is_source_left = (sx < tx); @@ -126,10 +120,11 @@ operator()(const Point_2& p, const X_monotone_curve_2& c) const // AlgKernel ker; int n = 100; - if (this->scene != nullptr && this->scene->views().size() != 0) - { // use the scene to approximate the resolution of the curve + if (this->scene != nullptr && this->scene->views().size() != 0) { + // use the scene to approximate the resolution of the curve QGraphicsView* view = this->scene->views().first(); - CGAL::Bbox_2 bb = c.bbox(); // assumes bounded curve + // assumes bounded curve + CGAL::Bbox_2 bb = this->m_traits.construct_bbox_2_object()(c); int xmin = view->mapFromScene(bb.xmin(), bb.ymin()).x(); int xmax = view->mapFromScene(bb.xmax(), bb.ymin()).x(); n = xmax - xmin; @@ -142,34 +137,32 @@ operator()(const Point_2& p, const X_monotone_curve_2& c) const auto end_pts = app_pts.end(); auto p_curr = app_pts.begin(); auto p_next = p_curr + 1; - do - { + do { Point_2 p1(p_curr->first, p_curr->second); Point_2 p2(p_next->first, p_next->second); Segment_2 seg(p1, p2); FT dist = CGAL::squared_distance(p, seg); - if (first || dist < min_dist) - { + if (first || dist < min_dist) { first = false; min_dist = dist; } - p_curr++; - p_next++; + ++p_curr; + ++p_next; } while (p_next != end_pts); return CGAL::to_double(min_dist); } } -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -double Compute_squared_distance_2>:: -operator()(const Point_2& p, const X_monotone_curve_2& curve) const -{ +// +template +double Compute_squared_distance_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& curve) const { // TODO: this should probably be cached! CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; painterOstream.setScene(this->getScene()); @@ -177,23 +170,22 @@ operator()(const Point_2& p, const X_monotone_curve_2& curve) const std::pair p_pair = { CGAL::to_double(p.x()), CGAL::to_double(p.y())}; - double minDist = (std::numeric_limits::max)(); + double min_dist = (std::numeric_limits::max)(); auto points = painterOstream.getPoints(curve); - for (auto& vit : points) - { + for (auto& vit : points) { QPointF coord(vit.first, vit.second); - float curDist = (vit.first - p_pair.first) * (vit.first - p_pair.first) + - (vit.second - p_pair.second) * (vit.second - p_pair.second); - minDist = curDist < minDist ? curDist : minDist; + float cur_dist = (vit.first - p_pair.first) * (vit.first - p_pair.first) + + (vit.second - p_pair.second) * (vit.second - p_pair.second); + min_dist = cur_dist < min_dist ? cur_dist : min_dist; } - return minDist; + return min_dist; } +// template double Compute_squared_distance_2>:: -operator()(const Point_2& p, const X_monotone_curve_2& curve) const -{ +operator()(const Point_2& p, const X_monotone_curve_2& curve) const { // TODO: this should probably be cached! CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; painterOstream.setScene(this->getScene()); @@ -212,78 +204,74 @@ operator()(const Point_2& p, const X_monotone_curve_2& curve) const QPoint p_viewport = view->mapFromScene(QPointF{p.x().doubleValue(), p.y().doubleValue()}); - double minDist = (std::numeric_limits::max)(); - for (auto& vec : points) - { - for (auto vit = vec.begin(); vit != vec.end(); ++vit) - { + double min_dist = (std::numeric_limits::max)(); + for (auto& vec : points) { + for (auto vit = vec.begin(); vit != vec.end(); ++vit) { QPoint coord(vit->first, vit->second); - float curDist = QLineF{facadeToViewport.map(coord), p_viewport}.length(); - minDist = curDist < minDist ? curDist : minDist; + float cur_dist = QLineF{facadeToViewport.map(coord), p_viewport}.length(); + min_dist = cur_dist < min_dist ? cur_dist : min_dist; } } - return minDist; + return min_dist; } +// template double Compute_squared_distance_2< CGAL::Arr_rational_function_traits_2>:: -operator()(const Point_2& p, const X_monotone_curve_2& curve) const -{ +operator()(const Point_2& p, const X_monotone_curve_2& curve) const { // TODO: this should probably be cached! - CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; - painterOstream.setScene(this->getScene()); + CGAL::Qt::ArrangementPainterOstream painter_ostream{nullptr}; + painter_ostream.setScene(this->getScene()); std::pair p_pair = { - CGAL::to_double(p.x()), CGAL::to_double(p.y())}; + CGAL::to_double(p.x()), CGAL::to_double(p.y()) + }; - double minDist = (std::numeric_limits::max)(); - auto points_list = painterOstream.getPointsList(curve); - for (auto& points : points_list) - { - for (auto& vit : points) - { + double min_dist = (std::numeric_limits::max)(); + auto points_list = painter_ostream.getPointsList(curve); + for (auto& points : points_list) { + for (auto& vit : points) { QPointF coord(vit.first, vit.second); - float curDist = + float cur_dist = (vit.first - p_pair.first) * (vit.first - p_pair.first) + (vit.second - p_pair.second) * (vit.second - p_pair.second); - minDist = curDist < minDist ? curDist : minDist; + min_dist = cur_dist < min_dist ? cur_dist : min_dist; } } - return minDist; + return min_dist; } +// template -auto Arr_construct_point_2::operator()(const Kernel_point_2& pt) - -> Point_2 -{ - return (*this)(FT{pt.x()}, FT{pt.y()}, traits); -} +auto Arr_construct_point_2:: +operator()(const Kernel_point_2& pt) -> Point_2 +{ return (*this)(FT{pt.x()}, FT{pt.y()}, traits); } +// template -auto Arr_construct_point_2::operator()(const FT& x, const FT& y) - -> Point_2 -{ - return (*this)(x, y, traits); -} +auto Arr_construct_point_2:: +operator()(const FT& x, const FT& y) -> Point_2 +{ return (*this)(x, y, traits); } +// template template -auto Arr_construct_point_2::operator()( - const FT& x, const FT& y, const TTraits*) -> Point_2 -{ +auto Arr_construct_point_2:: +operator()(const FT& x, const FT& y, const TTraits*) -> Point_2 { CoordinateType xx(x); CoordinateType yy(y); Point_2 res(xx, yy); return res; } +// template template -auto Arr_construct_point_2::operator()( - const FT& x, const FT& y, - const CGAL::Arr_rational_function_traits_2*) +auto Arr_construct_point_2:: +operator()(const FT& x, const FT& y, + const CGAL::Arr_rational_function_traits_2*) -> Point_2 { using Rational = typename ArrTraits::Rational; @@ -304,46 +292,44 @@ auto Arr_construct_point_2::operator()( return res; } +// template -auto Find_nearest_edge::operator()(const Point_2& queryPt) +auto Find_nearest_edge::operator()(const Point_2& query_pt) -> Halfedge_const_handle { Face_const_handle face = - PointLocationFunctions{}.getFace(arr, queryPt); + PointLocationFunctions{}.getFace(arr, query_pt); bool first = 1; X_monotone_curve_2 closestCurve; Halfedge_const_handle closestEdge; - double minDist(0); + double min_dist(0); - if (!face->is_unbounded()) - { // it is an interior face so it has a ccb + const auto& traits = arr->geometry_traits(); + Point_curve_distance point_curve_distance(*traits); + if (! face->is_unbounded()) { + // it is an interior face so it has a ccb Ccb_halfedge_const_circulator cc = face->outer_ccb(); - do - { + do { X_monotone_curve_2 curve = cc->curve(); - double dist = this->pointCurveDistance(queryPt, curve); - if (first || dist < minDist) - { + double dist = point_curve_distance(query_pt, curve); + if (first || dist < min_dist) { first = 0; - minDist = dist; + min_dist = dist; closestEdge = cc; } } while (++cc != face->outer_ccb()); } - else if (face->has_outer_ccb()) - { + else if (face->has_outer_ccb()) { Ccb_halfedge_const_circulator cc = face->outer_ccb(); - do - { - if (cc->is_fictitious()) { continue; } + do { + if (cc->is_fictitious()) continue; X_monotone_curve_2 curve = cc->curve(); - double dist = this->pointCurveDistance(queryPt, curve); - if (first || dist < minDist) - { + double dist = point_curve_distance(query_pt, curve); + if (first || dist < min_dist) { first = 0; - minDist = dist; + min_dist = dist; closestEdge = cc; } } while (++cc != face->outer_ccb()); @@ -351,17 +337,15 @@ auto Find_nearest_edge::operator()(const Point_2& queryPt) Hole_const_iterator hit; Hole_const_iterator eit = face->holes_end(); // int counter = 0; - for (hit = face->holes_begin(); hit != eit; ++hit) - { // check any holes inside this face + for (hit = face->holes_begin(); hit != eit; ++hit) { + // check any holes inside this face Ccb_halfedge_const_circulator cc = *hit; - do - { + do { X_monotone_curve_2 curve = cc->curve(); - double dist = this->pointCurveDistance(queryPt, curve); - if (first || dist < minDist) - { + double dist = point_curve_distance(query_pt, curve); + if (first || dist < min_dist) { first = 0; - minDist = dist; + min_dist = dist; closestEdge = cc; } cc++; @@ -371,6 +355,7 @@ auto Find_nearest_edge::operator()(const Point_2& queryPt) return closestEdge; } +// template auto Find_nearest_edge::getFace(const CGAL::Object& obj) -> Face_const_handle @@ -389,6 +374,7 @@ auto Find_nearest_edge::getFace(const CGAL::Object& obj) return (eit->face()); } +// template Construct_x_monotone_subcurve_2::Construct_x_monotone_subcurve_2( const ArrTraits* traits_) : @@ -402,6 +388,7 @@ Construct_x_monotone_subcurve_2::Construct_x_monotone_subcurve_2( { } +// template auto Construct_x_monotone_subcurve_2::operator()( const X_monotone_curve_2& curve, const boost::optional& pLeft, @@ -424,47 +411,45 @@ auto Construct_x_monotone_subcurve_2::operator()( X_monotone_curve_2 subcurve; X_monotone_curve_2 unusedTrimmings; X_monotone_curve_2 finalSubcurve; - if ( - pLeft && (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) + if (pLeft && + (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) { auto y1 = this->compute_y_at_x(curve, pLeft->x()); Point_2 splitPoint = {pLeft->x(), y1}; this->split_2(curve, splitPoint, unusedTrimmings, subcurve); } - else - { + else { subcurve = curve; } - if ( - pRight && - (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) + if (pRight && + (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) { auto y2 = this->compute_y_at_x(subcurve, pRight->x()); Point_2 splitPoint = {pRight->x(), y2}; this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); } - else - { + else { finalSubcurve = subcurve; } return finalSubcurve; } +// template -auto Construct_x_monotone_subcurve_2< - CGAL::Arr_conic_traits_2>:: -operator()( - const X_monotone_curve_2& curve, const boost::optional& pLeft, - const boost::optional& pRight) -> X_monotone_curve_2 +auto Construct_x_monotone_subcurve_2 +>:: +operator()(const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight) -> X_monotone_curve_2 { // TODO: handle when pLeft or pRight is null // find the points on the curve - Point_2 left = curve.point_at_x(*pLeft); - Point_2 right = curve.point_at_x(*pRight); + Point_2 left = m_traits.point_at_x(curve, *pLeft); + Point_2 right = m_traits.point_at_x(curve, *pRight); // make sure the points are oriented in the direction that the curve is // going @@ -475,16 +460,17 @@ operator()( ker.compare_xy_2_object()(left, right) == CGAL::LARGER))) { std::swap(left, right); } - X_monotone_curve_2 res = curve.trim(left, right); + X_monotone_curve_2 res = m_traits.trim_2_object()(curve, left, right); return res; } -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -Construct_x_monotone_subcurve_2>::Construct_x_monotone_subcurve_2(const ArrTraits* traits_) : +// +template +Construct_x_monotone_subcurve_2>:: +Construct_x_monotone_subcurve_2(const ArrTraits* traits_) : traits(traits_), split_2(this->traits->split_2_object()), compare_x_2(this->traits->compare_x_2_object()), @@ -494,9 +480,9 @@ Construct_x_monotone_subcurve_2 +// +template auto Construct_x_monotone_subcurve_2>:: operator()( @@ -516,40 +502,35 @@ operator()( // at algebraic "x", so we need to make it rational auto local_get_t = [&](auto&& point) { if (point.is_rational()) - return this->compute_y_at_x.get_t( - curve, ((typename Point_2::Rat_point_2)point).x()); + return this->compute_y_at_x.get_t(curve, ((typename Point_2::Rat_point_2)point).x()); else return this->compute_y_at_x.get_t(curve, point.approximate().first); }; - if (pLeft && this->compare_x_2(*pLeft, pMin) == CGAL::LARGER) - { + if (pLeft && this->compare_x_2(*pLeft, pMin) == CGAL::LARGER) { auto t = local_get_t(*pLeft); Point_2 splitPoint(curve.supporting_curve(), t); this->split_2(curve, splitPoint, unusedTrimmings, subcurve); } - else - { + else { subcurve = curve; } - if (pRight && this->compare_x_2(*pRight, pMax) == CGAL::SMALLER) - { + if (pRight && this->compare_x_2(*pRight, pMax) == CGAL::SMALLER) { auto t = local_get_t(*pRight); Point_2 splitPoint(curve.supporting_curve(), t); this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); } - else - { + else { finalSubcurve = subcurve; } return finalSubcurve; } +// template Construct_x_monotone_subcurve_2>::Construct_x_monotone_subcurve_2(const Traits* - traits_) : + AlgebraicKernel_d_1>>::Construct_x_monotone_subcurve_2(const Traits* traits_) : traits(traits_), split_2(this->traits->split_2_object()), compare_x_2(this->traits->compare_x_2_object()), @@ -559,6 +540,7 @@ Construct_x_monotone_subcurve_2 auto Construct_x_monotone_subcurve_2< CGAL::Arr_rational_function_traits_2>:: @@ -577,95 +559,93 @@ operator()( X_monotone_curve_2 subcurve; X_monotone_curve_2 unusedTrimmings; X_monotone_curve_2 finalSubcurve; - if ( - pLeft && (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) + if (pLeft && + (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) { Point_2 splitPoint{curve._f, pLeft->x()}; this->split_2(curve, splitPoint, unusedTrimmings, subcurve); } - else - { + else { subcurve = curve; } - if ( - pRight && - (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) + if (pRight && + (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) { auto y2 = this->compute_y_at_x(subcurve, pRight->x()); Point_2 splitPoint{curve._f, pRight->x()}; this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); } - else - { + else { finalSubcurve = subcurve; } return finalSubcurve; } +// template Arr_compute_y_at_x_2::Arr_compute_y_at_x_2(const Traits* traits_) : - traits(traits_), - intersectCurves(this->traits->intersect_2_object()) + traits(traits_), + intersectCurves(this->traits->intersect_2_object()) { } +// template -auto Arr_compute_y_at_x_2::operator()( - const X_monotone_curve_2& curve, const CoordinateType& x) -> CoordinateType +auto Arr_compute_y_at_x_2:: +operator()(const X_monotone_curve_2& curve, const CoordinateType& x) + -> CoordinateType { typename Traits::Left_side_category category; return this->operator()(curve, x, this->traits, category); } +// template -double Arr_compute_y_at_x_2::approx( - const X_monotone_curve_2& curve, const CoordinateType& x) +double Arr_compute_y_at_x_2:: +approx(const X_monotone_curve_2& curve, const CoordinateType& x) { return CGAL::to_double((*this)(curve, x)); } +// template template -auto Arr_compute_y_at_x_2::operator()( - const X_monotone_curve_2& curve, const CoordinateType& x, - const TTraits* traits_, CGAL::Arr_oblivious_side_tag) -> CoordinateType +auto Arr_compute_y_at_x_2:: +operator()(const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_oblivious_side_tag) + -> CoordinateType { - typedef - typename TTraits::Construct_x_monotone_curve_2 Construct_x_monotone_curve_2; - Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = - traits_->construct_x_monotone_curve_2_object(); + auto ctr_xcv = traits_->construct_x_monotone_curve_2_object(); CoordinateType res(0); CGAL::Bbox_2 clipRect = curve.bbox(); Point_2 p1c1(x, CoordinateType(clipRect.ymin() - 1)); // clicked point // upper bounding box Point_2 p2c1(x, CoordinateType(clipRect.ymax() + 1)); - const X_monotone_curve_2 verticalLine = - construct_x_monotone_curve_2(p1c1, p2c1); + const X_monotone_curve_2 verticalLine = ctr_xcv(p1c1, p2c1); CGAL::Object o; CGAL::Oneset_iterator oi(o); this->intersectCurves(curve, verticalLine, oi); IntersectionResult pair; - if (CGAL::assign(pair, o)) - { + if (CGAL::assign(pair, o)) { Point_2 pt = pair.first; res = pt.y(); } return res; } +// template template -auto Arr_compute_y_at_x_2::operator()( - const X_monotone_curve_2& curve, const CoordinateType& x, - const TTraits* traits_, CGAL::Arr_open_side_tag) -> CoordinateType +auto Arr_compute_y_at_x_2:: +operator()(const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_open_side_tag) -> CoordinateType { - typename TTraits::Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = - traits_->construct_x_monotone_curve_2_object(); + auto ctr_xcv = traits_->construct_x_monotone_curve_2_object(); CoordinateType res(0); // QRectF clipRect = this->viewportRect( ); Line_2 line = curve.supporting_line(); @@ -673,22 +653,56 @@ auto Arr_compute_y_at_x_2::operator()( Point_2 p1c1(x, CoordinateType(-10000000)); // clicked point Point_2 p2c1(x, CoordinateType(10000000)); // upper bounding box - const X_monotone_curve_2 verticalLine = - construct_x_monotone_curve_2(p1c1, p2c1); + const X_monotone_curve_2 verticalLine = ctr_xcv(p1c1, p2c1); CGAL::Object o; CGAL::Oneset_iterator oi(o); this->intersectCurves(curve, verticalLine, oi); IntersectionResult pair; - if (CGAL::assign(pair, o)) - { + if (CGAL::assign(pair, o)) { Point_2 pt = pair.first; res = pt.y(); } return res; } +// Specialization for the conic traits. +template +auto +Arr_compute_y_at_x_2>:: +operator()(const X_monotone_curve_2& curve, const Coordinate_type& x) + -> Coordinate_type +{ + auto ctr_xcv = m_traits.construct_x_monotone_curve_2_object(); + CGAL::Bbox_2 clip_rect = m_traits.construct_bbox_2_object()(curve); + Point_2 p1c1(x, Coordinate_type(clip_rect.ymin() - 1)); // clicked point + // upper bounding box + Point_2 p2c1(x, Coordinate_type(clip_rect.ymax() + 1)); + + const X_monotone_curve_2 vertical_line = ctr_xcv(p1c1, p2c1); + CGAL::Object o; + CGAL::Oneset_iterator oi(o); + + this->intersect_curves(curve, vertical_line, oi); + + Coordinate_type res(0); + IntersectionResult pair; + if (CGAL::assign(pair, o)) { + Point_2 pt = pair.first; + res = pt.y(); + } + return res; +} + +// Specialization for the conic traits. +template +double +Arr_compute_y_at_x_2>:: +approx(const X_monotone_curve_2& curve, const Coordinate_type& x) +{ return CGAL::to_double((*this)(curve, x)); } + +// Specialization for the algebraic traits. template auto Arr_compute_y_at_x_2>:: operator()(const X_monotone_curve_2& curve, const CoordinateType& x) @@ -700,19 +714,19 @@ operator()(const X_monotone_curve_2& curve, const CoordinateType& x) X_monotone_curve_2 c2 = this->makeVerticalLine(x); intersect(curve, c2, oi); std::pair res; - if (CGAL::assign(res, o)) // TODO: handle failure case - { + if (CGAL::assign(res, o)) { + // TODO: handle failure case const Point_2& p = res.first; CoordinateType coord = p.y(); return coord; } - else - { + else { std::cout << "Warning: vertical projection failed" << std::endl; return CoordinateType(0); } } +// Specialization for the algebraic traits. template double Arr_compute_y_at_x_2>:: @@ -721,6 +735,7 @@ Arr_compute_y_at_x_2>:: return CGAL::to_double(this->operator()(curve, x)); } +// Specialization for the algebraic traits. template auto Arr_compute_y_at_x_2>:: makeVerticalLine(const CoordinateType& x) -> X_monotone_curve_2 @@ -739,6 +754,7 @@ auto Arr_compute_y_at_x_2>:: return curves[0]; // by construction, there is one curve in curves } +// template static inline auto get_t_range(const Bezier_x_monotone_2& curve) { @@ -754,9 +770,9 @@ static inline auto get_t_range(const Bezier_x_monotone_2& curve) (pt_org->point_bound().t_min + pt_org->point_bound().t_max) / 2); } -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> +// +template auto Arr_compute_y_at_x_2>:: operator()(const X_monotone_curve_2& curve, const Rational& x) -> Algebraic @@ -768,9 +784,9 @@ operator()(const X_monotone_curve_2& curve, const Rational& x) -> Algebraic nt_traits.convert(supp_curve.y_norm()); } -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> +// +template auto Arr_compute_y_at_x_2>:: get_t(const X_monotone_curve_2& curve, const Rational& x) -> Algebraic @@ -782,8 +798,7 @@ auto Arr_compute_y_at_x_2 -double Arr_compute_y_at_x_2>::approx(const X_monotone_curve_2& curve, const Rational& x) -{ +// +template +double Arr_compute_y_at_x_2>:: +approx(const X_monotone_curve_2& curve, const Rational& x) { return CGAL::to_double((*this)(curve, x)); } +// template auto Arr_compute_y_at_x_2< CGAL::Arr_rational_function_traits_2>:: @@ -814,6 +830,7 @@ operator()(const X_monotone_curve_2& curve, const Algebraic_real_1& x) return Point_2{curve._f, x}.y(); } +// template auto Arr_compute_y_at_x_2< CGAL::Arr_rational_function_traits_2>:: @@ -822,6 +839,7 @@ operator()(const X_monotone_curve_2& curve, const Rational& x) -> Rational return curve._f.numer().evaluate(x) / curve._f.denom().evaluate(x); } +// template auto Arr_compute_y_at_x_2< CGAL::Arr_rational_function_traits_2>:: @@ -830,6 +848,7 @@ approx(const X_monotone_curve_2& curve, const Rational& x) -> double return CGAL::to_double((*this)(curve, x)); } +// CGAL::Object createArrangement(demo_types::TraitsType tt) { CGAL::Object res; @@ -858,18 +877,16 @@ void deleteArrangement(demo_types::TraitsType tt, const CGAL::Object& arr_obj) }); } -CGAL::Object makeOverlayArrangement(const std::vector& arrs) -{ +// +CGAL::Object makeOverlayArrangement(const std::vector& arrs) { CGAL::Object arr_obj; - if (arrs.size() == 2) - { + if (arrs.size() == 2) { demo_types::forEachArrangementType([&](auto type_holder) { using Arrangement = typename decltype(type_holder)::type; Arrangement* arr1; Arrangement* arr2; - if (CGAL::assign(arr1, arrs[0]) && CGAL::assign(arr2, arrs[1])) - { + if (CGAL::assign(arr1, arrs[0]) && CGAL::assign(arr2, arrs[1])) { auto overlay_arr = new Arrangement(); CGAL::Arr_default_overlay_traits overlay_traits; @@ -881,9 +898,9 @@ CGAL::Object makeOverlayArrangement(const std::vector& arrs) return arr_obj; } -void insertCurve( - demo_types::TraitsType tt, const CGAL::Object& arr_obj, - const CGAL::Object& curve_obj) +// +void insertCurve(demo_types::TraitsType tt, const CGAL::Object& arr_obj, + const CGAL::Object& curve_obj) { demo_types::visitArrangementType(tt, [&](auto type_holder) { using Arrangement = typename decltype(type_holder)::type; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h index 3775dfa43af..b0905210094 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h @@ -21,186 +21,282 @@ class QGraphicsScene; -template -class Arr_compute_y_at_x_2 : public GraphicsSceneMixin -{ +// Genereic `Arr_compute_y_at_x_2` +template +class Arr_compute_y_at_x_2 : public GraphicsSceneMixin { public: - typedef ArrTraits Traits; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename ArrTraitsAdaptor< Traits >::CoordinateType CoordinateType; + typedef Traits_ Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename ArrTraitsAdaptor::CoordinateType CoordinateType; // typedef typename Kernel::FT FT; typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Line_2 Line_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; typedef typename Traits::Multiplicity Multiplicity; typedef typename Traits::Intersect_2 Intersect_2; - typedef std::pair< typename Traits::Point_2, Multiplicity > + typedef std::pair IntersectionResult; /*! Constructor */ - Arr_compute_y_at_x_2( const Traits* ); + Arr_compute_y_at_x_2(const Traits* traits); + // CoordinateType operator()(const X_monotone_curve_2& curve, const CoordinateType& x); + // double approx(const X_monotone_curve_2& curve, const CoordinateType& x); protected: + // template - CoordinateType operator()( - const X_monotone_curve_2& curve, const CoordinateType& x, - const TTraits* traits_, CGAL::Arr_oblivious_side_tag); + CoordinateType operator()(const X_monotone_curve_2& curve, + const CoordinateType& x, const TTraits* traits_, + CGAL::Arr_oblivious_side_tag); + // template - CoordinateType operator()( - const X_monotone_curve_2& curve, const CoordinateType& x, - const TTraits* traits_, CGAL::Arr_open_side_tag); + CoordinateType operator()(const X_monotone_curve_2& curve, + const CoordinateType& x, const TTraits* traits_, + CGAL::Arr_open_side_tag); protected: const Traits* traits; Intersect_2 intersectCurves; }; -template -class Arr_compute_y_at_x_2< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > : public GraphicsSceneMixin +// Specialization of `Arr_compute_y_at_x_2` for the conic traits. +template +class Arr_compute_y_at_x_2 + > : + public GraphicsSceneMixin { public: - typedef Coefficient_ Coefficient; - typedef CGAL::Arr_algebraic_segment_traits_2< Coefficient > Traits; - typedef typename Traits::Algebraic_real_1 CoordinateType; - typedef typename Traits::Point_2 Point_2; - typedef typename Traits::Intersect_2 Intersect_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef CGAL::Arr_conic_traits_2 + Traits; + typedef typename Traits::Point_2 Point_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraitsAdaptor::CoordinateType Coordinate_type; + typedef typename Traits::Intersect_2 Intersect_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef std::pair IntersectionResult; + // Construct from traits. + Arr_compute_y_at_x_2(const Traits* traits) : + m_traits(*traits), + intersect_curves(m_traits.intersect_2_object()) + {} + + // Compute the y-coordinate at of the curve at a give x-coordinate. + Coordinate_type + operator()(const X_monotone_curve_2& curve, const Coordinate_type& x); + + // Compute an approximation of the y-coordinate at of the curve at a give + // x-coordinate. + double approx(const X_monotone_curve_2& curve, const Coordinate_type& x); + +private: + const Traits& m_traits; + Intersect_2 intersect_curves; +}; + +// Specialization of `Arr_compute_y_at_x_2` for the algebraic traits. +template +class Arr_compute_y_at_x_2> : + public GraphicsSceneMixin +{ +public: + typedef Coefficient_ Coefficient; + typedef CGAL::Arr_algebraic_segment_traits_2 Traits; + typedef typename Traits::Algebraic_real_1 CoordinateType; + typedef typename Traits::Point_2 Point_2; + typedef typename Traits::Intersect_2 Intersect_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + // Arr_compute_y_at_x_2(const Traits* traits_) : traits(traits_) { } + // CoordinateType operator()(const X_monotone_curve_2& curve, const CoordinateType& x); + // double approx(const X_monotone_curve_2& curve, const CoordinateType& x); protected: + // X_monotone_curve_2 makeVerticalLine(const CoordinateType& x); + const Traits* traits; }; -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> +// Specialization of `Arr_compute_y_at_x_2` for the Bezier traits. +template class Arr_compute_y_at_x_2> : public GraphicsSceneMixin { public: typedef CGAL::Arr_Bezier_curve_traits_2< - RatKernel, AlgKernel, NtTraits, BoundingTraits> Traits; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Rational Rational; - typedef typename Traits::Algebraic Algebraic; - typedef typename Traits::Point_2 Point_2; + RatKernel, AlgKernel, NtTraits, BoundingTraits> Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Rational Rational; + typedef typename Traits::Algebraic Algebraic; + typedef typename Traits::Point_2 Point_2; + // Arr_compute_y_at_x_2(const Traits*) { } + // Algebraic operator()(const X_monotone_curve_2& curve, const Rational& x); + + // double approx(const X_monotone_curve_2& curve, const Rational& x); + + // Algebraic get_t(const X_monotone_curve_2& curve, const Rational& x); }; +// Specialization of `Arr_compute_y_at_x_2` for the rational-function traits. template -class Arr_compute_y_at_x_2< - CGAL::Arr_rational_function_traits_2> : +class Arr_compute_y_at_x_2> : public GraphicsSceneMixin { public: typedef CGAL::Arr_rational_function_traits_2 Traits; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Algebraic_real_1 Algebraic_real_1; - typedef typename Traits::Point_2 Point_2; - typedef typename Traits::Rational Rational; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Algebraic_real_1 Algebraic_real_1; + typedef typename Traits::Point_2 Point_2; + typedef typename Traits::Rational Rational; - Arr_compute_y_at_x_2(const Traits*) { } + // + Arr_compute_y_at_x_2(const Traits*) {} + // Algebraic_real_1 operator()(const X_monotone_curve_2& curve, const Algebraic_real_1& x); + + // Rational operator()(const X_monotone_curve_2& curve, const Rational& x); + + // double approx(const X_monotone_curve_2& curve, const Rational& x); }; -template -class Compute_squared_distance_2_base : public GraphicsSceneMixin -{ +// Common base class for all `Compute_squared_distance_2` +template +class Compute_squared_distance_2_base : public GraphicsSceneMixin { + using Traits = Traits_; + +public: + // Construct from traits. + Compute_squared_distance_2_base(const Traits& traits) : m_traits(traits) {} + +protected: + const Traits& m_traits; }; -template +// Generic `Compute_squared_distance_2` +template class Compute_squared_distance_2 : - public Compute_squared_distance_2_base< ArrTraits > -{ }; - -template -class Compute_squared_distance_2< CGAL::Arr_segment_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > + public Compute_squared_distance_2_base { -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_segment_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + using Traits = Traits_; + using Base = Compute_squared_distance_2_base; - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; +public: + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} }; -template -class Compute_squared_distance_2< CGAL::Arr_linear_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > +// Specialization of `Compute_squared_distance_2` for the segment traits. +template +class Compute_squared_distance_2> : + public Compute_squared_distance_2_base> { public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_linear_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Kernel::Line_2 Line_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef Kernel_ Kernel; + typedef CGAL::Arr_segment_traits_2 Traits; + typedef Compute_squared_distance_2_base Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // + double operator() ( const Point_2& p, const X_monotone_curve_2& c) const; }; -template -class Compute_squared_distance_2< CGAL::Arr_polyline_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > +// Specialization of `Compute_squared_distance_2` for the linear traits. +template +class Compute_squared_distance_2< CGAL::Arr_linear_traits_2< Kernel_>> : + public Compute_squared_distance_2_base> { public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_polyline_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Curve_2::Subcurve_const_iterator Seg_const_it; + typedef Kernel_ Kernel; + typedef CGAL::Arr_linear_traits_2 Traits; + typedef Compute_squared_distance_2_base Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Kernel::Ray_2 Ray_2; + typedef typename Kernel::Line_2 Line_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; }; +// Specialization of `Compute_squared_distance_2` for the polyline traits. +template +class Compute_squared_distance_2< CGAL::Arr_polyline_traits_2< Kernel_>> : + public Compute_squared_distance_2_base> +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_polyline_traits_2 Traits; + typedef Compute_squared_distance_2_base Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Traits::Curve_2 Curve_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Curve_2::Subcurve_const_iterator Seg_const_it; + + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; +}; + +// Specialization of `Compute_squared_distance_2` for the conic traits. template -class Compute_squared_distance_2< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > : - public Compute_squared_distance_2_base< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > +class Compute_squared_distance_2> : + public Compute_squared_distance_2_base> { public: typedef AlgKernel Kernel; - typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > Traits; + typedef CGAL::Arr_conic_traits_2 Traits; typedef Compute_squared_distance_2_base< Traits > Superclass; // _Conic_point_2< AlgKernel > : public AlgKernel::Point_2 typedef typename Traits::Point_2 Conic_point_2; @@ -210,35 +306,48 @@ public: typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; -public: // methods - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; -}; + using Base = Compute_squared_distance_2_base; -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -class Compute_squared_distance_2> : - public Compute_squared_distance_2_base> -{ -public: - typedef CGAL::Arr_Bezier_curve_traits_2< - RatKernel, AlgKernel, NtTraits, BoundingTraits> - Traits; - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} -public: // methods + // double operator()(const Point_2& p, const X_monotone_curve_2& c) const; }; +// Specialization of `Compute_squared_distance_2` for the Bezier traits. +template +class Compute_squared_distance_2 +> : + public Compute_squared_distance_2_base + > +{ +public: + typedef CGAL::Arr_Bezier_curve_traits_2 Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; +}; + +// Specialization of `Compute_squared_distance_2` for the rational-function +// traits. template -class Compute_squared_distance_2< - CGAL::Arr_rational_function_traits_2> : - public Compute_squared_distance_2_base< - CGAL::Arr_rational_function_traits_2> +class Compute_squared_distance_2 + > : + public Compute_squared_distance_2_base + > { public: typedef CGAL::Arr_rational_function_traits_2 Traits; @@ -246,15 +355,21 @@ public: typedef typename Kernel::Point_2 Point_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; -public: + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // double operator()(const Point_2& p, const X_monotone_curve_2& c) const; }; -template -class Compute_squared_distance_2< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > : - public Compute_squared_distance_2_base< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > +// Specialization of `Compute_squared_distance_2` for the algebraic traits. +template +class Compute_squared_distance_2 + > : + public Compute_squared_distance_2_base + > { public: typedef Coefficient_ Coefficient; @@ -265,8 +380,8 @@ public: typedef typename Kernel::Point_2 Point_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; typedef typename Traits::CKvA_2 CKvA_2; - typedef std::pair< double, double > Coord_2; - typedef std::vector< Coord_2 > Coord_vec_2; + typedef std::pair Coord_2; + typedef std::vector Coord_vec_2; typedef typename X_monotone_curve_2::Curve_analysis_2 Curve; typedef typename Curve::Polynomial_traits_2 Polynomial_traits_2; typedef typename Curve::Polynomial_2 Polynomial_2; @@ -277,69 +392,75 @@ public: Construct_innermost_coefficient_const_iterator_range ConstructInnerCoeffIter; -public: + using Base = Compute_squared_distance_2_base; + + // Construct from traits. + Compute_squared_distance_2(const Traits& traits) : Base(traits) {} + + // double operator()(const Point_2& p, const X_monotone_curve_2& c) const; }; // check if arrangement is a model of the concept ArrangementOpenBoundaryTraits_2 template struct IsOpenBoundaryArrangement : - public CGAL::Boolean_tag< - std::is_convertible< - typename ArrTraits::Left_side_category, - CGAL::Arr_open_side_tag>::value && - std::is_convertible< - typename ArrTraits::Bottom_side_category, - CGAL::Arr_open_side_tag>::value && - std::is_convertible< - typename ArrTraits::Top_side_category, - CGAL::Arr_open_side_tag>::value && - std::is_convertible< - typename ArrTraits::Right_side_category, - CGAL::Arr_open_side_tag>::value> -{ -}; + public CGAL::Boolean_tag< + std::is_convertible< + typename ArrTraits::Left_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Bottom_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Top_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Right_side_category, + CGAL::Arr_open_side_tag>::value> +{}; +// template -class Param_space_in_x_2 -{ +class Param_space_in_x_2 { public: typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + // Param_space_in_x_2(const ArrTraits*) {} + + // CGAL::Arr_parameter_space operator()(const X_monotone_curve_2&, CGAL::Arr_curve_end) - { - return CGAL::INTERIOR; - } + { return CGAL::INTERIOR; } }; +// template -class Param_space_in_x_2< - ArrTraits, std::enable_if_t::value>> +class Param_space_in_x_2:: + value>> { public: typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; typedef typename ArrTraits::Parameter_space_in_x_2 Parameter_space_in_x_2; + // Param_space_in_x_2(const ArrTraits* traits) : parameter_space_in_x_2(traits->parameter_space_in_x_2_object()) - { - } + {} + // CGAL::Arr_parameter_space operator()(const X_monotone_curve_2& curve, CGAL::Arr_curve_end curve_end) - { - return this->parameter_space_in_x_2(curve, curve_end); - } + { return this->parameter_space_in_x_2(curve, curve_end); } private: Parameter_space_in_x_2 parameter_space_in_x_2; }; +// template -class Construct_x_monotone_subcurve_2 -{ +class Construct_x_monotone_subcurve_2 { public: typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; typedef typename ArrTraits::Split_2 Split_2; @@ -349,77 +470,77 @@ public: typedef Param_space_in_x_2 Parameter_space_in_x_2; typedef typename ArrTraits::Point_2 Point_2; - Construct_x_monotone_subcurve_2( const ArrTraits* traits_ ); + // + Construct_x_monotone_subcurve_2(const ArrTraits* traits_); - /* - Return the subcurve of curve bracketed by pLeft and pRight. - - We assume pLeft and pRight don't lie on the curve and always do a vertical - projection. - */ - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const boost::optional& pLeft, - const boost::optional& pRight ); + /* Return the subcurve of curve bracketed by pLeft and pRight. + * + * We assume pLeft and pRight don't lie on the curve and always do a vertical + * projection. + */ + X_monotone_curve_2 operator()(const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight); protected: const ArrTraits* traits; Split_2 split_2; Compare_x_2 compare_x_2; - Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; + Arr_compute_y_at_x_2 compute_y_at_x; Construct_min_vertex_2 construct_min_vertex_2; Construct_max_vertex_2 construct_max_vertex_2; Parameter_space_in_x_2 parameter_space_in_x_2; }; // class Construct_x_monotone_subcurve_2 -/* - * This specialization for conic traits makes use of X_monotone_curve_2::trim, +/* This specialization for conic traits makes use of X_monotone_curve_2::trim, * which is not necessarily available. */ template -class Construct_x_monotone_subcurve_2< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > +class Construct_x_monotone_subcurve_2> { public: typedef CGAL::Arr_conic_traits_2 - ArrTraits; - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraits::Split_2 Split_2; - typedef typename ArrTraits::Intersect_2 Intersect_2; - typedef typename ArrTraits::Multiplicity Multiplicity; - typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; - typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; - typedef typename ArrTraits::Compare_x_2 Compare_x_2; + Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Split_2 Split_2; + typedef typename Traits::Intersect_2 Intersect_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename Traits::Construct_max_vertex_2 Construct_max_vertex_2; + typedef typename Traits::Compare_x_2 Compare_x_2; typedef typename Kernel::FT FT; - typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType + typedef typename ArrTraitsAdaptor::CoordinateType CoordinateType; - typedef typename ArrTraits::Point_2 Point_2; + typedef typename Traits::Point_2 Point_2; typedef typename Kernel::Point_2 Kernel_point_2; - Construct_x_monotone_subcurve_2( const ArrTraits* ) - { - } + // Construct from traits. + Construct_x_monotone_subcurve_2(const Traits* traits) : m_traits(*traits) {} - /* - Return the subcurve of curve bracketed by pLeft and pRight. - */ - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const boost::optional& pLeft, - const boost::optional& pRight ); + /* Return the subcurve of curve bracketed by pLeft and pRight. + */ + X_monotone_curve_2 operator()(const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight ); -}; // class Construct_x_monotone_subcurve_2 for Arr_conic_traits_2 +private: + const Traits& m_traits; +}; -template < - typename RatKernel, typename AlgKernel, typename NtTraits, - typename BoundingTraits> -class Construct_x_monotone_subcurve_2> +// +template +class Construct_x_monotone_subcurve_2 +> { public: - typedef CGAL::Arr_Bezier_curve_traits_2< - RatKernel, AlgKernel, NtTraits, BoundingTraits> + typedef CGAL::Arr_Bezier_curve_traits_2 ArrTraits; typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; typedef typename ArrTraits::Split_2 Split_2; @@ -430,14 +551,15 @@ public: typedef typename ArrTraits::Compare_x_2 Compare_x_2; typedef typename ArrTraits::Point_2 Point_2; + // Construct_x_monotone_subcurve_2(const ArrTraits* traits_); /* Return the subcurve of curve bracketed by pLeft and pRight. */ - X_monotone_curve_2 operator()( - const X_monotone_curve_2& curve, const boost::optional& pLeft, - const boost::optional& pRight); + X_monotone_curve_2 operator()(const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight); protected: const ArrTraits* traits; @@ -446,8 +568,9 @@ protected: Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; Construct_min_vertex_2 construct_min_vertex_2; Construct_max_vertex_2 construct_max_vertex_2; -}; // class Construct_x_monotone_subcurve_2 for Arr_conic_traits_2 +}; +// template class Construct_x_monotone_subcurve_2< CGAL::Arr_rational_function_traits_2> @@ -471,33 +594,30 @@ public: Construct_x_monotone_subcurve_2( const Traits* traits_ ); - /* - Return the subcurve of curve bracketed by pLeft and pRight. - - We assume pLeft and pRight don't lie on the curve and always do a vertical - projection. - */ - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const boost::optional& pLeft, - const boost::optional& pRight ); + /* Return the subcurve of curve bracketed by pLeft and pRight. + * + * We assume pLeft and pRight don't lie on the curve and always do a vertical + * projection. + */ + X_monotone_curve_2 operator()(const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight); protected: const Traits* traits; Split_2 split_2; Compare_x_2 compare_x_2; - Arr_compute_y_at_x_2< Traits > compute_y_at_x; + Arr_compute_y_at_x_2 compute_y_at_x; Construct_min_vertex_2 construct_min_vertex_2; Construct_max_vertex_2 construct_max_vertex_2; }; // class Construct_x_monotone_subcurve_2 -/** - Converts between Kernel points and Arrangement points. - - The conversion is not necessarily exact. -*/ +/* Converts between Kernel points and Arrangement points. + * + * The conversion is not necessarily exact. + */ template -class Arr_construct_point_2 -{ +class Arr_construct_point_2 { typedef ArrTraits Traits; typedef typename ArrTraits::Point_2 Point_2; typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType CoordinateType; @@ -506,50 +626,53 @@ class Arr_construct_point_2 typedef typename Kernel::FT FT; public: + // Arr_construct_point_2(const Traits* traits_) : traits(traits_) { } + // template - Point_2 operator()(const P& p) - { - return this->operator()(p.x(), p.y()); - } + Point_2 operator()(const P& p) { return this->operator()(p.x(), p.y()); } + // template Point_2 operator()(const T& x, const U& y) - { - return this->operator()(FT{x}, FT{y}); - } + { return this->operator()(FT{x}, FT{y}); } + // Point_2 operator()(const Kernel_point_2& pt); + + // Point_2 operator()(const FT& x, const FT& y); protected: + // template Point_2 operator()(const FT& x, const FT& y, const TTraits*); + // template - Point_2 operator()( - const FT& x, const FT& y, - const CGAL::Arr_rational_function_traits_2*); + Point_2 + operator()(const FT& x, const FT& y, + const CGAL::Arr_rational_function_traits_2*); const Traits* traits; }; -class Find_nearest_edge_base : public GraphicsSceneMixin -{ +// +class Find_nearest_edge_base : public GraphicsSceneMixin { public: - /*! Destructor (virtual) */ + /*! Destructor */ virtual ~Find_nearest_edge_base() {} }; +// template -class Find_nearest_edge : public Find_nearest_edge_base -{ -public: // typedefs - typedef Arr_ Arrangement; - typedef typename Arrangement::Geometry_traits_2 ArrTraits; - typedef Compute_squared_distance_2< ArrTraits > Point_curve_distance; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; +class Find_nearest_edge : public Find_nearest_edge_base { +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 ArrTraits; + typedef Compute_squared_distance_2 Point_curve_distance; + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; typedef typename ArrTraitsAdaptor::Kernel Kernel; typedef typename Kernel::Point_2 Point_2; typedef typename Arrangement::Face_const_handle Face_const_handle; @@ -561,49 +684,53 @@ public: // typedefs public: /*! constructor */ - Find_nearest_edge( Arrangement* arr_ ) : - Find_nearest_edge_base( ), - arr( arr_ ) - { } + Find_nearest_edge(Arrangement* arr_) : + Find_nearest_edge_base(), + arr(arr_) + {} /*! Destructor (virtual) */ virtual ~Find_nearest_edge() {} public: // member methods - Halfedge_const_handle operator()( const Point_2& queryPt ); + // + Halfedge_const_handle operator()(const Point_2& queryPt); - virtual void setScene( QGraphicsScene* scene_ ) - { - this->pointCurveDistance.setScene( scene_ ); - Find_nearest_edge_base::setScene( scene_ ); + // + virtual void setScene(QGraphicsScene* scene_) { + // this->pointCurveDistance.setScene(scene_); + Find_nearest_edge_base::setScene(scene_); } -protected: // member methods - Face_const_handle getFace( const CGAL::Object& obj ); +protected: + // + Face_const_handle getFace(const CGAL::Object& obj); -protected: // member fields +protected: Arrangement* arr; - Point_curve_distance pointCurveDistance; - -}; // class Find_nearest_edge +}; +// template -class Insert_curve -{ +class Insert_curve { public: typedef Arr_ Arrangement; typedef typename Arrangement::Geometry_traits_2 ArrTraits; typedef typename ArrTraits::Curve_2 Curve_2; + // void operator()(Arrangement*, const Curve_2&); }; // free functions gathered here to speed up compilation of other files // specializing once in one file is better than in multiple files CGAL::Object createArrangement(demo_types::TraitsType); + void deleteArrangement(demo_types::TraitsType, const CGAL::Object&); + CGAL::Object makeOverlayArrangement(const std::vector&); -void insertCurve( - demo_types::TraitsType, const CGAL::Object& arr, const CGAL::Object& curve); + +void insertCurve(demo_types::TraitsType, const CGAL::Object& arr, + const CGAL::Object& curve); #endif // CGAL_ARRANGEMENTS_DEMO_UTILS_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp index 2738e18edce..69bfebf8495 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp @@ -22,8 +22,7 @@ #include template -class VerticalRayShootCallback : public VerticalRayShootCallbackBase -{ +class VerticalRayShootCallback : public VerticalRayShootCallbackBase { public: typedef VerticalRayShootCallbackBase Superclass; typedef Arr_ Arrangement; @@ -57,13 +56,12 @@ VerticalRayShootCallbackBase::VerticalRayShootCallbackBase(QObject* parent_) : } // msvc2015 doesn't play well with polymorphic lambdas -namespace -{ -struct ExplicitLambda -{ +namespace { + + // +struct ExplicitLambda { template - void operator()(demo_types::TypeHolder) - { + void operator()(demo_types::TypeHolder) { Arrangement* arr = nullptr; CGAL::assign(arr, arr_obj); res = new VerticalRayShootCallback(arr, parent); @@ -73,28 +71,30 @@ struct ExplicitLambda CGAL::Object& arr_obj; QObject* parent; }; + } // anonymous namespace -VerticalRayShootCallbackBase* VerticalRayShootCallbackBase::create( - demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) -{ +// +VerticalRayShootCallbackBase* +VerticalRayShootCallbackBase::create(demo_types::TraitsType tt, + CGAL::Object arr_obj, QObject* parent) { VerticalRayShootCallbackBase* res; ExplicitLambda explicit_lambda{res, arr_obj, parent}; demo_types::visitArrangementType(tt, explicit_lambda); return res; } +// void VerticalRayShootCallbackBase::setShootingUp(bool isShootingUp) -{ - this->shootingUp = isShootingUp; -} +{ this->shootingUp = isShootingUp; } +// template -VerticalRayShootCallback::VerticalRayShootCallback( - Arrangement* arr_, QObject* parent_) : - VerticalRayShootCallbackBase(parent_), - arr(arr_), - highlightedCurves(new CGAL::Qt::CurveGraphicsItem()) +VerticalRayShootCallback:: +VerticalRayShootCallback(Arrangement* arr_, QObject* parent_) : + VerticalRayShootCallbackBase(parent_), + arr(arr_), + highlightedCurves(new CGAL::Qt::CurveGraphicsItem(*(arr->geometry_traits()))) { this->rayGraphicsItem.setZValue(100); @@ -102,81 +102,75 @@ VerticalRayShootCallback::VerticalRayShootCallback( this->highlightedCurves->setVertexColor(this->rayGraphicsItem.color()); this->highlightedCurves->setZValue(100); - QObject::connect( - this, SIGNAL(modelChanged()), this->highlightedCurves, - SLOT(modelChanged())); - QObject::connect( - this, SIGNAL(modelChanged()), this, SLOT(slotModelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), this->highlightedCurves, + SLOT(modelChanged())); + QObject::connect(this, SIGNAL(modelChanged()), this, SLOT(slotModelChanged())); } +// template -void VerticalRayShootCallback::setEdgeWidth( int width ) -{ - this->highlightedCurves->setEdgeWidth( width ); - this->rayGraphicsItem.setWidth( width ); +void VerticalRayShootCallback::setEdgeWidth(int width) { + this->highlightedCurves->setEdgeWidth(width); + this->rayGraphicsItem.setWidth(width); } +// template -void VerticalRayShootCallback::setEdgeColor( const QColor& color ) -{ - this->highlightedCurves->setEdgeColor( color ); - this->rayGraphicsItem.setColor( color ); +void VerticalRayShootCallback::setEdgeColor(const QColor& color) { + this->highlightedCurves->setEdgeColor(color); + this->rayGraphicsItem.setColor(color); } +// template -const QColor& VerticalRayShootCallback::edgeColor( ) const -{ - return this->highlightedCurves->edgeColor( ); -} +const QColor& VerticalRayShootCallback::edgeColor() const +{ return this->highlightedCurves->edgeColor(); } +// template -int VerticalRayShootCallback::edgeWidth( ) const -{ - return this->highlightedCurves->edgeWidth( ); -} +int VerticalRayShootCallback::edgeWidth() const +{ return this->highlightedCurves->edgeWidth(); } +// template -void VerticalRayShootCallback::setScene(QGraphicsScene* scene_) -{ +void VerticalRayShootCallback::setScene(QGraphicsScene* scene_) { CGAL::Qt::Callback::setScene(scene_); this->highlightedCurves->setScene(scene_); - if (scene_) - { + if (scene_) { this->scene->addItem(this->highlightedCurves); this->scene->addItem(&this->rayGraphicsItem); } } +// template void VerticalRayShootCallback::slotModelChanged() { } +// template -void VerticalRayShootCallback::reset() -{ +void VerticalRayShootCallback::reset() { this->rayGraphicsItem.reset(); this->highlightedCurves->clear(); Q_EMIT modelChanged(); } +// template -void VerticalRayShootCallback::mousePressEvent( - QGraphicsSceneMouseEvent* event) -{ - this->highlightPointLocation(event); -} +void VerticalRayShootCallback:: +mousePressEvent(QGraphicsSceneMouseEvent* event) +{ this->highlightPointLocation(event); } +// template -void VerticalRayShootCallback::mouseMoveEvent( - QGraphicsSceneMouseEvent* /* event */) -{ -} +void VerticalRayShootCallback:: +mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) {} +// template -void VerticalRayShootCallback::highlightPointLocation( - QGraphicsSceneMouseEvent* event) -{ +void VerticalRayShootCallback:: +highlightPointLocation(QGraphicsSceneMouseEvent* event) { this->highlightedCurves->clear(); QPointF queryQPt = event->scenePos(); @@ -192,25 +186,21 @@ void VerticalRayShootCallback::highlightPointLocation( QRectF viewportRect = this->viewportRect(); qreal y2; - if (this->shootingUp) - { // +y in Qt is towards the bottom + if (this->shootingUp) { // +y in Qt is towards the bottom y2 = viewportRect.bottom(); } - else - { + else { y2 = viewportRect.top(); } Face_const_handle unboundedFace; Halfedge_const_handle halfedge; Vertex_const_handle vertex; - if (CGAL::assign(unboundedFace, pointLocationResult)) - { + if (CGAL::assign(unboundedFace, pointLocationResult)) { this->rayGraphicsItem.setSource(queryQPt); this->rayGraphicsItem.setTargetY(y2); this->rayGraphicsItem.setIsInfinite(true); } - else if (CGAL::assign(halfedge, pointLocationResult)) - { + else if (CGAL::assign(halfedge, pointLocationResult)) { this->highlightedCurves->insert(halfedge->curve()); // draw a ray from the clicked point to the hit curve @@ -221,10 +211,8 @@ void VerticalRayShootCallback::highlightPointLocation( this->rayGraphicsItem.setTargetY(yApprox); this->rayGraphicsItem.setIsInfinite(false); } - else if (CGAL::assign(vertex, pointLocationResult)) - { - if (!vertex->is_at_open_boundary()) - { + else if (CGAL::assign(vertex, pointLocationResult)) { + if (!vertex->is_at_open_boundary()) { auto pt = vertex->point(); this->highlightedCurves->insert(pt); } diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt index 2050328161b..431083db107 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt @@ -4819,21 +4819,19 @@ defined in the header file `arr_conics.h`. #include #include -typedef CGAL::CORE_algebraic_number_traits Nt_traits; -typedef Nt_traits::Rational Rational; -typedef CGAL::Cartesian Rat_kernel; -typedef Rat_kernel::Point_2 Rat_point; -typedef Rat_kernel::Segment_2 Rat_segment; -typedef Rat_kernel::Circle_2 Rat_circle; -typedef Nt_traits::Algebraic Algebraic; -typedef CGAL::Cartesian Alg_kernel; - -typedef CGAL::Arr_conic_traits_2 - Traits; -typedef Traits::Point_2 Point; -typedef Traits::Curve_2 Conic_arc; -typedef Traits::X_monotone_curve_2 X_monotone_conic_arc; -typedef CGAL::Arrangement_2 Arrangement; +using Nt_traits = CGAL::CORE_algebraic_number_traits; +using Rational = Nt_traits::Rational; +using Rat_kernel = CGAL::Cartesian; +using Rat_point = Rat_kernel::Point_2; +using Rat_segment = Rat_kernel::Segment_2; +using Rat_circle = Rat_kernel::Circle_2; +using Algebraic = Nt_traits::Algebraic; +using Alg_kernel = CGAL::Cartesian; +using Traits = CGAL::Arr_conic_traits_2; +using Point = Traits::Point_2; +using Conic_arc = Traits::Curve_2; +using X_monotone_conic_arc = Traits::X_monotone_curve_2; +using Arrangement = CGAL::Arrangement_2; \endcode @@ -6599,7 +6597,7 @@ member functions when operating on an arrangement-with-history object. \cgalExample{Arrangement_on_surface_2/edge_manipulation_curve_history.cpp} -\section aos_sec-io Input/Output Streams +\section aos_sec-io Input/Output Streams and Visualization In some cases, one would like to save an arrangement object @@ -6744,6 +6742,24 @@ arrangement formatter class (see Section \ref arr_ssecarr_io_aux_data) and defines a simple textual input/output format. \cgalAdvancedEnd + +\subsection arr_ssecarr_io_vis Drawing an Arrangement + + +An arrangement data structure can be visualized by calling the \link PkgArrangementOnSurface2Draw CGAL::draw() \endlink function as shown in the following example. This function opens a new window showing the given arrangement. A call to this function is blocking; that is, the program continues execution only after the user closes the window. + +\cgalExample{Arrangement_on_surface_2/draw_arr.cpp} + +This function requires `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is defined. +Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link with `CGAL_Qt5` and add the definition `CGAL_USE_BASIC_VIEWER`. + +\cgalFigureBegin{aos_fig-draw_arr,draw_arr.png} +A snapshot of the window created by the program +\ref Arrangement_on_surface_2/draw_arr.cpp. The constructed arrangement consists +of 14 vertices, 15 edges, and 3 faces. Notice that the colors are generated at random. +\cgalFigureEnd + + \section aos_sec-bgl Adapting to Boost Graphs diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h index 8d7a6e647e6..fe6e70de9c5 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arr_conic_traits_2.h @@ -4,22 +4,22 @@ namespace CGAL { * * The class `Arr_conic_traits_2` is a model of the `ArrangementTraits_2` * concept and can be used to construct and maintain arrangements of bounded - * segments of algebraic curves of degree \f$ 2\f$ at most, also known as + * segments of algebraic curves of degree \f$2\f$ at most, also known as * conic curves. * - * A general conic curve \f$ C\f$ is the locus of all points \f$ (x,y)\f$ - * satisfying the equation: \f$ r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, + * A general conic curve \f$C\f$ is the locus of all points \f$(x,y)\f$ + * satisfying the equation: \f$r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, * where: * *
    - *
  • If \f$ 4 r s - t^2 > 0\f$, \f$ C\f$ is an ellipse. A special case occurs - * when \f$ r = s\f$ and \f$ t = 0\f$, when \f$ C\f$ becomes a circle. + *
  • If \f$4 r s - t^2 > 0\f$, \f$ C\f$ is an ellipse. A special case occurs + * when \f$r = s\f$ and \f$ t = 0\f$, when \f$ C\f$ becomes a circle. * - *
  • If \f$ 4 r s - t^2 < 0\f$, \f$ C\f$ is a hyperbola. + *
  • If \f$4 r s - t^2 < 0\f$, \f$ C\f$ is a hyperbola. * - *
  • If \f$ 4 r s - t^2 = 0\f$, \f$ C\f$ is a parabola. A degenerate case - * occurs when \f$ r = s = t = 0\f$, when \f$ C\f$ is a line. + *
  • If \f$4 r s - t^2 = 0\f$, \f$ C\f$ is a parabola. A degenerate case + * occurs when \f$r = s = t = 0\f$, when \f$ C\f$ is a line. * *
* @@ -34,37 +34,37 @@ namespace CGAL { * p_t\f$ (the source and target points, respectively). The orientation \f$ o\f$ * indicates whether we proceed from \f$ p_s\f$ to \f$ p_t\f$ in a clockwise or * in a counterclockwise direction. Note that \f$ C\f$ may also correspond to a - * line or to pair of lines - in this case \f$ o\f$ may specify a `COLLINEAR` + * line or to pair of lines---in this case \f$ o\f$ may specify a `COLLINEAR` * orientation. * * * * A very useful subset of the set of conic arcs are line segments and circular * arcs, as arrangements of circular arcs and line segments have some - * interesting applications (e.g. offsetting polygons, motion planning for a - * disc robot, etc.). Circular arcs and line segment are simpler objects and can - * be dealt with more efficiently than arbitrary arcs. For these reasons, it is - * possible to construct conic arcs from segments and from circles. Using these - * constructors is highly recommended: It is more straightforward and also - * speeds up the arrangement construction. However, in case the set of input - * curves contain only circular arcs and line segments, it is recommended to use - * the `Arr_circle_segment_2` class to achieve faster running times. + * interesting applications (e.g., offsetting polygons and motion planning for a + * disc robot). Circular arcs and line segment are simpler objects and can be + * dealt with more efficiently than arbitrary arcs. Indeed, it is possible to + * construct conic arcs from segments and from circles. Using these constructors + * is highly recommended: It is more straightforward and also expedites the + * arrangement construction. However, in case the set of input curves contain + * only circular arcs and line segments, it is recommended using the + * `Arr_circle_segment_2` class to achieve better running times. * - * In our representation, all conic coefficients (namely \f$ r, s, t, u, v, - * w\f$) must be rational numbers. This guarantees that the coordinates of all + * In our representation, all conic coefficients (namely \f$r, s, t, u, v, w\f$) + * must be rational numbers. This guarantees that the coordinates of all * arrangement vertices (in particular, those representing intersection points) - * are algebraic numbers of degree \f$ 4\f$ (a real number \f$ \alpha\f$ is an - * algebraic number of degree \f$ d\f$ if there exist a polynomial \f$ p\f$ with - * integer coefficient of degree \f$ d\f$ such that \f$ p(\alpha) = - * 0\f$). We therefore require separate representations of the curve + * are algebraic numbers of degree \f$4\f$ (a real number \f$\alpha\f$ is an + * algebraic number of degree \f$d\f$ if there exist a polynomial \f$ p\f$ with + * integer coefficient of degree \f$d\f$ such that \f$p(\alpha) = 0\f$). + * We therefore require separate representations of the curve * coefficients and the point coordinates. The `NtTraits` should be instantiated - * with a class that defines nested `Integer`, `Rational` and `Algebraic` number + * with a class that defines nested `Integer`, `Rational`, and `Algebraic` number * types and supports various operations on them, yielding certified computation * results (for example, it can convert rational numbers to algebraic numbers * and can compute roots of polynomials with integer coefficients). The other * template parameters, `RatKernel` and `AlgKernel` should be geometric kernels - * templated with the `NtTraits::Rational` and `NtTraits::Algebraic` number - * types, respectively. It is recommended to instantiate the + * instantiated with the `NtTraits::Rational` and `NtTraits::Algebraic` number + * types, respectively. It is recommended instantiating the * `CORE_algebraic_number_traits` class as the `NtTraits` parameter, with * `Cartesian` and `Cartesian` * instantiating the two kernel types, respectively. The number types in this @@ -72,7 +72,7 @@ namespace CGAL { * simple algebraic numbers. * * The traits class inherits its point type from `AlgKernel::Point_2`, - * and defines a curve and \f$ x\f$-monotone curve types, as detailed below. + * and defines a curve and \f$x\f$-monotone curve types, as detailed below. * * While the `Arr_conic_traits_2` models the concept * `ArrangementDirectionalXMonotoneTraits_2`, the implementation of @@ -115,110 +115,9 @@ public: /// \name Creation /// @{ - /*! constructs an arc corresponding to the line segment `seg`. + /*! constructs an empty (invalid) arc. */ - Curve_2(const typename RatKernel::Segment_2& seg); - - /*! constructs an arc corresponding to the full circle `circ` - * (note that this circle has a center point with rational coordinates - * and rational squared radius). - */ - Curve_2(const typename RatKernel::Circle_2& circ); - - /*! constructs a circular arc supported by the circle `circ`, going - * in the given orientation `o` from the source point `ps` to its target - * point `pt`. - * - * \pre `ps` and `pt` both lie on the circle `circ`. - * - * \pre `o` is not `COLLINEAR`. - */ - Curve_2(const typename RatKernel::Circle_2& circ, Orientation o, - const Point_2& ps, const Point_2& pt); - - /*! constructs a circular arc going from `p1` (its source point) - * through `p2` to `p3` (its target point). Note that all three points have - * rational coordinates. The orientation of the arc is determined - * automatically. - * - * \pre The three points are not collinear. - */ - Curve_2(const typename RatKernel::Point_2& p1, - const typename RatKernel::Point_2& p2, - const typename RatKernel::Point_2& p3); - - /*! constructs a conic arc that corresponds to the full conic curve - * \f$ r x^2 + s y^2 + t x y + u x + v y + w = 0\f$. - * - * \pre As a conic arc must be bounded, the given curve must be an ellipse, - * that is \f$ 4 r s - t^2 > 0\f$. - */ - Curve_2(const Rational& r, const Rational& s, - const Rational& t, const Rational& u, - const Rational& v, const Rational& w); - - /*! constructs a conic arc supported by the conic curve - * \f$ r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, going in the given - * orientation `o` from the source point `ps` to its target point `pt`. * * - * - * \pre `ps` and `pt` both satisfy the equation of the supporting conic - * curve and define a bounded segment of this curve (e.g. in case of a - * hyperbolic arc, both point should be located on the same branch of the - * hyperbola). - * - * \pre `o` is not `COLLINEAR` if the supporting conic is curves, and must - * be `COLLINEAR` if it is not curved (a line or a line-pair). - */ - Curve_2(const Rational& r, const Rational& s, - const Rational& t, const Rational& u, - const Rational& v, const Rational& w, - Orientation o, - const Point_2& ps, const Point_2& pt); - - /*! constructs a conic arc going from `p1` (its source point) - * through `p2`, `p3` and `p4` (in this order) to `p5` (its target - * point). Note that all five points have rational coordinates. The - * orientation of the arc is determined automatically. - * - * \pre No three points of the five are not collinear. - * - * \pre The five points define a valid arc, in their given order. - */ - Curve_2(const typename RatKernel::Point_2& p1, - const typename RatKernel::Point_2& p2, - const typename RatKernel::Point_2& p3, - const typename RatKernel::Point_2& p4, - const typename RatKernel::Point_2& p5); - - /*! constructs a conic arc supported by the conic curve - * \f$ r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, going in the given - * orientation `o` from its source point to its target Point. In this case - * only some approximations of the endpoints (`app_ps` and `app_pt`, - * respectively) is available, and their exact locations are given - * implicitly, specified by the intersections of the supporting conic curve - * with \f$ r_1 x^2 + s_1 y^2 + t_1 x y + u_1 x + v_1 y + w_1 = 0\f$ and \f$ - * r_2 x^2 + s_2 y^2 + t_2 x y + u_2 x + v_2 y + w_2 = 0\f$, respectively. - * - * \pre The two auxiliary curves specifying the endpoints really intersect - * with the supporting conic curve, such that the arc endpoints define a - * bounded segment of the supporting curve (e.g. in case of a hyperbolic - * arc, both point should be located on the same branch of the hyperbola). - * - * \pre `o` is not `COLLINEAR` if the supporting conic is curves, and must - * be `COLLINEAR` if it is not curved (a line or a line-pair). - */ - Curve_2(const Rational& r, const Rational& s, - const Rational& t, const Rational& u, - const Rational& v, const Rational& w, - Orientation o, - const Point_2& app_ps, - const Rational& r1, const Rational& s1, - const Rational& t1, const Rational& u1, - const Rational& v1, const Rational& w1, - const Point_2& app_pt, - const Rational& r2, const Rational& s2, - const Rational& t2, const Rational& u2, - const Rational& v2, const Rational& w2); + Curve_2(); /// @} @@ -230,20 +129,19 @@ public: * violation does not cause the program to abort. Instead, the constructed * arc is invalid (a defaultly constructed arc is also invalid). It is * however recommended to check that a constructed arc is valid before - * inserting it to an arrangement, as this operation will cause the - * program to abort. + * inserting it to an arrangement. */ bool is_valid() const; - /*! determines whether the arc is \f$ x\f$-monotone, namely each vertical + /*! determines whether the arc is \f$x\f$-monotone, namely each vertical * line intersects it at most once. A vertical line segment is also - * considered (weakly) \f$ x\f$-monotone. + * considered (weakly) \f$x\f$-monotone. */ bool is_x_monotone() const; - /*! determines whether the arc is \f$ y\f$-monotone, namely each horizontal + /*! determines whether the arc is \f$y\f$-monotone, namely each horizontal * line intersects it at most once. A horizontal line segment is also - * considered (weakly) \f$ x\f$-monotone. + * considered (weakly) \f$x\f$-monotone. */ bool is_y_monotone() const; @@ -261,23 +159,23 @@ public: */ /// @{ - /*! returns the coefficient of \f$ x^2\f$. + /*! returns the coefficient of \f$x^2\f$. */ const typename NtTraits::Integer& r() const; - /*! returns the coefficient of \f$ t^2\f$. + /*! returns the coefficient of \f$t^2\f$. */ const typename NtTraits::Integer& s() const; - /*! returns the coefficient of \f$ x y\f$. + /*! returns the coefficient of \f$x y\f$. */ const typename NtTraits::Integer& t() const; - /*! returns the coefficient of \f$ x\f$. + /*! returns the coefficient of \f$x\f$. */ const typename NtTraits::Integer& u() const; - /*! returns the coefficient of \f$ y\f$. + /*! returns the coefficient of \f$y\f$. */ const typename NtTraits::Integer& v() const; @@ -299,10 +197,6 @@ public: */ Orientation orientation() const; - /*! return a bounding box of the arc `a`. - */ - Bbox_2 bbox() const; - /// @} /// \name Operations @@ -322,15 +216,16 @@ public: }; /* end Arr_conic_traits_2::Curve_2 */ - /*! The `X_monotone_curve_2` class nested within the conic-arc traits is + /*! \class X_monotone_curve_2 + * The `X_monotone_curve_2` class nested within the conic-arc traits is * used to represent \f$x\f$-monotone conic arcs. It inherits from the * `Curve_2` type, therefore supports the access methods and the operations * listed above. * - * For efficiency reasons, we recommend users not to construct \f$ - * x\f$-monotone conic arc directly, but rather use the `Make_x_monotone_2` + * For efficiency reasons, we recommend users not to construct + * \f$x\f$-monotone conic arc directly, but rather use the `Make_x_monotone_2` * functor supplied by the conic-arc traits class to convert conic curves to - * \f$ x\f$-monotone curves. + * \f$x\f$-monotone curves. */ class X_monotone_curve_2 { public: @@ -338,10 +233,9 @@ public: /// \name Creation /// @{ - /*! converts the given arc to an \f$ x\f$-monotone arc. - * \pre `arc` is \f$ x\f$-monotone. + /*! constructs an empty (invalid) arc. */ - X_monotone_curve_2(const Curve_2& arc); + X_monotone_curve_2(); /// @} @@ -387,21 +281,251 @@ public: /// @} }; + /*! \class Construct_curve_2 + * A functor that constructs a conic arc. + */ + class Construct_curve_2 { + public: + /*! constructs an arc corresponding to the line segment `seg`. + */ + Curve_2 operator()(const typename RatKernel::Segment_2& seg) const; + + /*! constructs an arc corresponding to the full circle `circ` + * (note that this circle has a center point with rational coordinates + * and rational squared radius). + */ + Curve_2 operator()(const typename RatKernel::Circle_2& circ) const; + + /*! constructs a circular arc supported by the circle `circ`, going + * in the given orientation `o` from the source point `ps` to its target + * point `pt`. + * + * \pre `ps` and `pt` both lie on the circle `circ`. + * + * \pre `o` is not `COLLINEAR`. + */ + Curve_2 operator()(const typename RatKernel::Circle_2& circ, Orientation o, + const Point_2& ps, const Point_2& pt) const; + + /*! constructs a circular arc going from `p1` (its source point) + * through `p2` to `p3` (its target point). Note that all three points have + * rational coordinates. The orientation of the arc is determined + * automatically. + * + * \pre The three points are not collinear. + */ + Curve_2 operator()(const typename RatKernel::Point_2& p1, + const typename RatKernel::Point_2& p2, + const typename RatKernel::Point_2& p3) const; + + /*! constructs a conic arc that corresponds to the full conic curve + * \f$r x^2 + s y^2 + t x y + u x + v y + w = 0\f$. + * + * \pre As a conic arc must be bounded, the given curve must be an ellipse, + * that is \f$4 r s - t^2 > 0\f$. + */ + Curve_2 operator()(const Rational& r, const Rational& s, + const Rational& t, const Rational& u, + const Rational& v, const Rational& w) const; + + /*! constructs a conic arc supported by the conic curve + * \f$r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, going in the given + * orientation `o` from the source point `ps` to its target point `pt`. + * + * \pre `ps` and `pt` both satisfy the equation of the supporting conic + * curve and define a bounded segment of this curve (e.g. in case of a + * hyperbolic arc, both point should be located on the same branch of the + * hyperbola). + * + * \pre `o` is not `COLLINEAR` if the supporting conic is curves, and must + * be `COLLINEAR` if it is not curved (a line or a line-pair). + */ + Curve_2 operator()(const Rational& r, const Rational& s, + const Rational& t, const Rational& u, + const Rational& v, const Rational& w, + Orientation o, + const Point_2& ps, const Point_2& pt) const; + + /*! constructs a conic arc going from `p1` (its source point) + * through `p2`, `p3` and `p4` (in this order) to `p5` (its target + * point). Note that all five points have rational coordinates. The + * orientation of the arc is determined automatically. + * + * \pre No three points of the five are not collinear. + * + * \pre The five points define a valid arc, in their given order. + */ + Curve_2 operator()(const typename RatKernel::Point_2& p1, + const typename RatKernel::Point_2& p2, + const typename RatKernel::Point_2& p3, + const typename RatKernel::Point_2& p4, + const typename RatKernel::Point_2& p5) const; + + /*! constructs a conic arc supported by the conic curve + * \f$r x^2 + s y^2 + t x y + u x + v y + w = 0\f$, going in the given + * orientation `o` from its source point to its target Point. In this case + * only some approximations of the endpoints (`app_ps` and `app_pt`, + * respectively) is available, and their exact locations are given + * implicitly, specified by the intersections of the supporting conic curve + * with \f$r_1 x^2 + s_1 y^2 + t_1 x y + u_1 x + v_1 y + w_1 = 0\f$ and + * \f$r_2 x^2 + s_2 y^2 + t_2 x y + u_2 x + v_2 y + w_2 = 0\f$, respectively. + * + * \pre The two auxiliary curves specifying the endpoints really intersect + * with the supporting conic curve, such that the arc endpoints define a + * bounded segment of the supporting curve (e.g. in case of a hyperbolic + * arc, both point should be located on the same branch of the hyperbola). + * + * \pre `o` is not `COLLINEAR` if the supporting conic is curves, and must + * be `COLLINEAR` if it is not curved (a line or a line-pair). + */ + Curve_2 operator()(const Rational& r, const Rational& s, + const Rational& t, const Rational& u, + const Rational& v, const Rational& w, + Orientation o, + const Point_2& app_ps, + const Rational& r1, const Rational& s1, + const Rational& t1, const Rational& u1, + const Rational& v1, const Rational& w1, + const Point_2& app_pt, + const Rational& r2, const Rational& s2, + const Rational& t2, const Rational& u2, + const Rational& v2, const Rational& w2) const; + }; + + /*! \class Construct_x_monotone_curve_2 + * A functor that constructs an \f$x\f$-monotone conic arc. + */ + class Construct_x_monotone_curve_2 { + public: + /*! converts a given arc to an \f$x\f$-monotone arc. + * \param cv The input arc. + * \pre `cv` is \f$x\f$-monotone. + */ + X_monotone_curve_2 operator()(const Curve_2& cv) const; + + /*! Constructs an \f$x\f$-monotone curve connecting the two given endpoints. + * \param source The first point. + * \param target The second point. + * \pre `source` and `target` must not be the same. + * \return A segment connecting `source` and `target`. + */ + X_monotone_curve_2 operator()(const Point_2& source, const Point_2& target) const; + + /*! Constructs a special segment of a given line connecting to given + * endpoints. + * \param a, b, c The coefficients of the supporting line (\f$ax + by + c = 0\f$). + * \param source The source point. + * \param target The target point. + * \pre `source` and `target` must not be the same. + * \return A segment connecting `source` and `target`. + */ + X_monotone_curve_2 operator()(const Algebraic& a, const Algebraic& b, + const Algebraic& c, + const Point_2& source, const Point_2& target) const; + }; + + /*! \class Construct_bbox_2 + * A functor that constructs a bounding box of a conic arc. + */ + class Construct_bbox_2 { + public: + /*! Obtain a bounding box for a conic arc. + * \param cv The conic arc. + * \return The bounding box. + */ + Bbox_2 operator()(const Curve_2& cv) const { return bbox(cv); } + + /*! Obtain a bounding box for an \f$x\f$-monotone conic arc. + * \param xcv The \f$x\f$-monotone conic arc. + * \return The bounding box. + */ + Bbox_2 operator()(const X_monotone_curve_2& xcv) const { return bbox(xcv); } + }; + + /*! \name Auxiliary Functor definitions, used gor, e.g., the landmarks + * point-location strategy and the drawing function. + */ + //@{ + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; + + /*! \class Approximate_2 + * A functor that approximates a point and an \f$x\f$-monotone curve. + */ + class Approximate_2 { + public: + /*! Obtain an approximation of a point coordinate. + * \param p The exact point. + * \param i The coordinate index (either 0 or 1). + * \pre `i` is either 0 or 1. + * \return An approximation of p's \f$x\f$-coordinate (if `i` == 0), or an + * approximation of p's \f$y\f$-coordinate (if `i` == 1). + */ + Approximate_number_type operator()(const Point_2& p, int i) const; + + /*! Obtain an approximation of a point. + * \param p The exact point. + */ + Approximate_point_2 operator()(const Point_2& p) const; + + /*! Obtain a polyline that approximates an \f$x\f$-monotone curve. The + * polyline is defined by a range of approximate points beginning at + * `oi`. The type `OutputIterator` must dereference the type + * `Approximate_point_2`. The first and last points in the range are always + * the endpoints of the given arc `xcv`. The operator returns a + * past-the-end iterator of the destination range. + * \param oi An output iterator for the resulting polyline. + * \param error The error bound of the polyline approximation. This is + * the Hausdorff distance between the arc and the polyline + * that approximates the arc. + * \param xcv The exact \f$x\f$-monotone arc. + * \param l2r A Boolean flag that indicates whether the arc direction is + * left to right. + * \return The past-the-end iterator of the output iterator. + */ + template + OutputIterator operator()(OutputIterator oi, double error, + const X_monotone_curve_2& xcv, + bool l2r = true) const; + }; + + /*! \class Trim_2 + * A functor that trims a conic arc. + */ class Trim_2 { public: - /// \name Creation - /// @{ - - /*! Trims the given x-monotone curve to an from src to tgt. - * \ pre `src` and `tgt` lies on the curve + /*! Trims the given \f$x\f$-monotone arc to new endpoints. + * \param xcv The \f$x\f$-monotone arc + * \param source The new source point. + * \param target The new target point. + * \pre `source` and `target` lies on the arc. */ - X_monotone_curve_2(const X_monotone_curve_2& xcv, - const Point_2& src, - const Point_2& tgt) const; + X_monotone_curve_2 operator()(const X_monotone_curve_2& xcv, + const Point_2& source, + const Point_2& target) const; - /// @} - }/* end Arr_conic_traits_2::Trim_2 */ + }; + /// \name Accessing Functor Objects + /// @{ + + /*! Obtain a `Construct_curve_2` functor. */ + Construct_curve_2 construct_curve_2_object() const; + + /*! Obtain a `Construct_x_monotone_curve_2` functor. */ + Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object() const; + + /*! Obtain a `Bbox_2` functor. */ + Construct_bbox_2 construct_bbox_2_object() const; + + /*! Obtain a `Trim_2` functor. */ + Trim_2 trim_2_object() const; + + /*! Obtain an `Approximate_2` functor. */ + Trim_2 approximate_2_object() const; + + /// @} }; /* end Arr_conic_traits_2 */ } /* end namespace CGAL */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arrangement_on_surface_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arrangement_on_surface_2.h index 4aee4e22035..4ae02d2b0e1 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arrangement_on_surface_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/Arrangement_on_surface_2.h @@ -52,6 +52,10 @@ namespace CGAL { * \sa `PkgArrangementOnSurface2Read` * \sa `PkgArrangementOnSurface2Write` + * + * Drawing function + * + * \sa `PkgArrangementOnSurface2Draw` */ template class Arrangement_on_surface_2 { diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h new file mode 100644 index 00000000000..f415f5c9e7e --- /dev/null +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/CGAL/draw_arrangement_2.h @@ -0,0 +1,55 @@ +// 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 + +#ifndef CGAL_DRAW_ARRANGEMENT_2_H +#define CGAL_DRAW_ARRANGEMENT_2_H + +#include + +#ifdef DOXYGEN_RUNNING + +namespace CGAL { + +/*! \ingroup PkgArrangementOnSurface2Draw + * + * opens a new window and draws `arr`, an instance of the `CGAL::Arrangement_2` + * class template. A call to this function is blocking; that is, the program + * continues only after the user closes the window. This function requires + * `CGAL_Qt5`, and is only available if the macro `CGAL_USE_BASIC_VIEWER` is + * defined. Linking with the cmake target `CGAL::CGAL_Basic_viewer` will link + * with `CGAL_Qt5` and add the definition `CGAL_USE_BASIC_VIEWER`. + * + * \tparam GeometryTraits_2 a geometry traits type, a model of a 2D arrangement + * traits concept. At this point it must be an instance of either + * `CGAL::Arr_segment_traits_2` or `CGAL::Arr_conic_traits_2`. + * + * \tparam Dcel the \dcel type, a model of the `ArrangementDcel` concept. + * + * \param arr the 2D arrangement to draw. + * \param title the window title. + * + * \sa `ArrangementDcel` + * \sa `ArrangementTraits_2` + */ +template +void draw(const Arrangement_2& arr, + const char* title = "2D Arrangement Basic Viewer"); + +} /* namespace CGAL */ + +#endif + +#endif diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrTraits--Intersect_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrTraits--Intersect_2.h index 0350b6ce654..5e11e857548 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrTraits--Intersect_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrTraits--Intersect_2.h @@ -37,8 +37,8 @@ public: */ template OutputIterator operator()(ArrTraits::X_monotone_curve_2 xc1, - ArrTraits::X_monotone_curve_2 xc2, - OutputIterator& oi); + ArrTraits::X_monotone_curve_2 xc2, + OutputIterator& oi); /// @} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt index 8d6daf70bd6..04ce3c47c28 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/PackageDescription.txt @@ -46,6 +46,14 @@ namespace ArrTraits {} /// \defgroup PkgArrangementOnSurface2Funcs Free Functions /// \ingroup PkgArrangementOnSurface2Ref +/*! + \code + #include + \endcode +*/ +/// \defgroup PkgArrangementOnSurface2Draw Drawing +/// \ingroup PkgArrangementOnSurface2Ref + /// \defgroup PkgArrangementOnSurface2Insert CGAL::insert() /// \ingroup PkgArrangementOnSurface2Funcs @@ -252,4 +260,7 @@ implemented as peripheral classes or as free (global) functions. - \link PkgArrangementOnSurface2op_left_shift `CGAL::operator<<` \endlink - \link PkgArrangementOnSurface2op_right_shift `CGAL::operator<<` \endlink +\cgalCRPSection{Draw an `Arrangemen_2` object} +- \link PkgArrangementOnSurface2Draw CGAL::draw<>() \endlink + */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt index 0cac1f68db1..1196580e382 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/examples.txt @@ -43,4 +43,9 @@ \example Arrangement_on_surface_2/unbounded_non_intersecting.cpp \example Arrangement_on_surface_2/unbounded_rational_functions.cpp \example Arrangement_on_surface_2/vertical_ray_shooting.cpp +\example Arrangement_on_surface_2/draw_arr.cpp +\example Arrangement_on_surface_2/linear_conics.cpp +\example Arrangement_on_surface_2/parabolas.cpp +\example Arrangement_on_surface_2/ellipses.cpp +\example Arrangement_on_surface_2/hyperbolas.cpp */ diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/fig/draw_arr.png b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/fig/draw_arr.png new file mode 100644 index 00000000000..6e7b0c874b3 Binary files /dev/null and b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/fig/draw_arr.png differ diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt index 7b6e319643d..bd3e707c4b4 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1...3.23) project(Arrangement_on_surface_2_Examples) -find_package(CGAL REQUIRED COMPONENTS Core) +find_package(CGAL REQUIRED COMPONENTS Core OPTIONAL_COMPONENTS Qt5) # create a target per cppfile file( @@ -14,3 +14,19 @@ file( foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() + +if(CGAL_Qt5_FOUND) + target_link_libraries(draw_arr PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(linear_conics PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(parabolas PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(ellipses PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(hyperbolas PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(polylines PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(circles PUBLIC CGAL::CGAL_Basic_viewer) + target_link_libraries(circular_arcs PUBLIC CGAL::CGAL_Basic_viewer) +else() + message( + STATUS + "NOTICE: Several examples require Qt and will not be compiled." + ) +endif() diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/arr_conics.h b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/arr_conics.h index d0a29ba9336..8e222124fd3 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/arr_conics.h +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/arr_conics.h @@ -6,20 +6,18 @@ #include #include -typedef CGAL::CORE_algebraic_number_traits Nt_traits; -typedef Nt_traits::Rational Rational; -typedef CGAL::Cartesian Rat_kernel; -typedef Rat_kernel::Point_2 Rat_point; -typedef Rat_kernel::Segment_2 Rat_segment; -typedef Rat_kernel::Circle_2 Rat_circle; -typedef Nt_traits::Algebraic Algebraic; -typedef CGAL::Cartesian Alg_kernel; - -typedef CGAL::Arr_conic_traits_2 - Traits; -typedef Traits::Point_2 Point; -typedef Traits::Curve_2 Conic_arc; -typedef Traits::X_monotone_curve_2 X_monotone_conic_arc; -typedef CGAL::Arrangement_2 Arrangement; +using Nt_traits = CGAL::CORE_algebraic_number_traits; +using Rational = Nt_traits::Rational; +using Rat_kernel = CGAL::Cartesian; +using Rat_point = Rat_kernel::Point_2; +using Rat_segment = Rat_kernel::Segment_2; +using Rat_circle = Rat_kernel::Circle_2; +using Algebraic = Nt_traits::Algebraic; +using Alg_kernel = CGAL::Cartesian; +using Traits = CGAL::Arr_conic_traits_2; +using Point = Traits::Point_2; +using Conic_arc = Traits::Curve_2; +using X_monotone_conic_arc = Traits::X_monotone_curve_2; +using Arrangement = CGAL::Arrangement_2; #endif diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp index 014cae1d161..f12cfb5af63 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circles.cpp @@ -1,6 +1,8 @@ //! \file examples/Arrangement_on_surface_2/circles.cpp // Constructing an arrangement of circles using the circle-segment traits. +#include + #include "arr_circular.h" int main() { @@ -27,5 +29,6 @@ int main() { std::cout << "The vertex with maximal degree in the arrangement is: " << "v_max = (" << v_max->point() << ") " << "with degree " << v_max->degree() << "." << std::endl; + CGAL::draw(arr); return 0; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp index 926162f1997..11043fb5555 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/circular_arcs.cpp @@ -1,6 +1,8 @@ //! \file examples/Arrangement_on_surface_2/circular_arc.cpp // Constructing an arrangement of various circular arcs and line segments. +#include + #include "arr_circular.h" #include "arr_print.h" @@ -56,5 +58,6 @@ int main() { Arrangement arr; insert(arr, curves.begin(), curves.end()); print_arrangement_size(arr); + CGAL::draw(arr); return 0; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conic_multiplicities.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conic_multiplicities.cpp index 158ce153703..752f6e21f9d 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conic_multiplicities.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conic_multiplicities.cpp @@ -14,7 +14,10 @@ typedef CGAL::Arr_naive_point_location Naive_pl; int main() { - Arrangement arr; + Traits traits; + auto ctr_cv = traits.construct_curve_2_object(); + + Arrangement arr(&traits); Naive_pl pl(arr); // Insert a hyperbolic arc, supported by the hyperbola y = x^2/(1-x) @@ -22,18 +25,20 @@ int main() { // Note that the arc is counterclockwise oriented. Point ps1(-1, Rational(1,2)); Point pt1(Rational(1,2), Rational(1,2)); - Conic_arc cv1(1, 0, 1, 0, -1, 0, CGAL::COUNTERCLOCKWISE, ps1, pt1); - insert(arr, cv1, pl); + Conic_arc cv1 = ctr_cv(1, 0, 1, 0, -1, 0, CGAL::COUNTERCLOCKWISE, ps1, pt1); + // insert(arr, cv1, pl); +#if 0 // Insert the bottom half of the circle centered at (0, 1/2) whose radius // is 1/2 (therefore its squared radius is 1/4). Rat_circle circ2(Rat_point(0, Rational(1,2)), Rational(1,4)); Point ps2(-Rational(1,2), Rational(1,2)); Point pt2(Rational(1,2), Rational(1,2)); - Conic_arc cv2(circ2, CGAL::COUNTERCLOCKWISE, ps2, pt2); + Conic_arc cv2 = ctr_cv(circ2, CGAL::COUNTERCLOCKWISE, ps2, pt2); insert(arr, cv2, pl); +#endif - print_arrangement (arr); + print_arrangement(arr); return 0; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conics.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conics.cpp index c831b617d9f..81faf630352 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conics.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/conics.cpp @@ -9,31 +9,31 @@ #include "arr_print.h" int main() { - Arrangement arr; + Traits traits; + Arrangement arr(&traits); + auto ctr_cv = traits.construct_curve_2_object(); // Insert a hyperbolic arc (C1), supported by the hyperbola y = 1/x // (or: xy - 1 = 0) with the endpoints (1/4, 4) and (2, 1/2). // The arc is counterclockwise oriented. - insert(arr, Conic_arc(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, - Point(Rational(1,4), 4), Point(2, Rational(1,2)))); + insert(arr, ctr_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, + Point(Rational(1,4), 4), Point(2, Rational(1,2)))); // Insert a full ellipse (C2), which is (x/4)^2 + (y/2)^2 = 0 rotated by // phi = 36.87 degrees (such that sin(phi) = 0.6, cos(phi) = 0.8), // yielding: 58x^2 + 72y^2 - 48xy - 360 = 0. - insert(arr, Conic_arc (58, 72, -48, 0, 0, -360)); + insert(arr, ctr_cv(58, 72, -48, 0, 0, -360)); // Insert the segment (C3) (1, 1) -- (0, -3). - insert(arr, Conic_arc(Rat_segment(Rat_point(1, 1), Rat_point(0, -3)))); + insert(arr, ctr_cv(Rat_segment(Rat_point(1, 1), Rat_point(0, -3)))); // Insert a circular arc (C4) supported by the circle x^2 + y^2 = 5^2, // with (-3, 4) and (4, 3) as its endpoints. We want the arc to be // clockwise-oriented, so it passes through (0, 5) as well. - Conic_arc c4(Rat_point(-3, 4), Rat_point(0, 5), Rat_point(4, 3)); - - insert(arr, c4); + insert(arr, ctr_cv(Rat_point(-3, 4), Rat_point(0, 5), Rat_point(4, 3))); // Insert a full unit circle (C5) that is centered at (0, 4). - insert(arr, Conic_arc(Rat_circle(Rat_point(0,4), 1))); + insert(arr, ctr_cv(Rat_circle(Rat_point(0,4), 1))); // Insert a parabolic arc (C6) supported by the parabola y = -x^2 with // endpoints (-sqrt(3),-3) (~(-1.73,-3)) and (sqrt(2),-2) (~(1.41,-2)). @@ -41,18 +41,18 @@ int main() { // we specify them as the intersections of the parabola with the lines // y = -3 and y = -2, respectively. The arc is clockwise-oriented. Conic_arc c6 = - Conic_arc(1, 0, 0, 0, 1, 0, CGAL::CLOCKWISE, // The parabola. - Point(-1.73, -3), // approximation of the source. - 0, 0, 0, 0, 1, 3, // the line: y = -3. - Point(1.41, -2), // approximation of the target. - 0, 0, 0, 0, 1, 2); // the line: y = -2. - + ctr_cv(1, 0, 0, 0, 1, 0, CGAL::CLOCKWISE, // The parabola. + Point(-1.73, -3), // approximation of the source. + 0, 0, 0, 0, 1, 3, // the line: y = -3. + Point(1.41, -2), // approximation of the target. + 0, 0, 0, 0, 1, 2); // the line: y = -2. insert(arr, c6); // Insert the right half of the circle centered at (4, 2.5) whose radius // is 1/2 (therefore its squared radius is 1/4) (C7). Rat_circle circ7(Rat_point(4, Rational(5,2)), Rational(1,4)); - insert(arr, Conic_arc(circ7, CGAL::CLOCKWISE, Point(4, 3), Point(4, 2))); + insert(arr, ctr_cv(circ7, CGAL::CLOCKWISE, Point(4, 3), Point(4, 2))); + print_arrangement_size(arr); return 0; @@ -62,8 +62,7 @@ int main() { #include -int main () -{ +int main() { std::cout << "Sorry, this example needs GMP and CORE\n"; return 0; } diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp new file mode 100644 index 00000000000..ea99cca39a8 --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/draw_arr.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Traits = CGAL::Arr_segment_traits_2; +using Point = Traits::Point_2; +using Arrangement_2 = CGAL::Arrangement_2; + +/*! Convert HSV to RGB color space + * Converts a given set of HSV values `h', `s', `v' into RGB coordinates. + * The output RGB values are in the range [0, 255], and the input HSV values + * are in the ranges h = [0, 360], and s, v = [0, 1], respectively. + * + * \param hue Hue component range: [0, 360] + * \param sat Saturation component range: [0, 1] + * \param value Value component range: [0, 1] + * \return tuple, where each component is in the range [0, 255] +*/ +std::tuple +hsv_to_rgb(float hue, float sat, float value) { + float red, green, blue; + float fc = value * sat; // Chroma + float hue_prime = fmod(hue / 60.0, 6); + float fx = fc * (1.0 - fabs(fmod(hue_prime, 2) - 1.0)); + float fm = value - fc; + + if(0 <= hue_prime && hue_prime < 1) { + red = fc; + green = fx; + blue = 0; + } + else if(1 <= hue_prime && hue_prime < 2) { + red = fx; + green = fc; + blue = 0; + } + else if(2 <= hue_prime && hue_prime < 3) { + red = 0; + green = fc; + blue = fx; + } + else if(3 <= hue_prime && hue_prime < 4) { + red = 0; + green = fx; + blue = fc; + } + else if(4 <= hue_prime && hue_prime < 5) { + red = fx; + green = 0; + blue = fc; + } + else if(5 <= hue_prime && hue_prime < 6) { + red = fc; + green = 0; + blue = fx; + } + else { + red = 0; + green = 0; + blue = 0; + } + + red += fm; + green += fm; + blue += fm; + + red *= 255; + green *= 255; + blue *= 255; + return std::make_tuple(red, green, blue); +} + +int main() { + Traits traits; + Arrangement_2 arr(&traits); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + + CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(2,-2))); + CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(2,2))); + CGAL::insert(arr, ctr_xcv(Point(2,2), Point(-2,2))); + CGAL::insert(arr, ctr_xcv(Point(-2,2), Point(-2,-2))); + + CGAL::insert(arr, ctr_xcv(Point(-1,-1), Point(1,-1))); + CGAL::insert(arr, ctr_xcv(Point(1,-1), Point(1,1))); + CGAL::insert(arr, ctr_xcv(Point(1,1), Point(-1,1))); + CGAL::insert(arr, ctr_xcv(Point(-1,1), Point(-1,-1))); + + CGAL::insert(arr, ctr_xcv(Point(-2,-2), Point(-2,-4))); + CGAL::insert(arr, ctr_xcv(Point(2,-2), Point(4,-2))); + + CGAL::insert(arr, ctr_xcv(Point(0,0), Point(0,-3))); + + std::cout << arr.number_of_vertices() << ", " + << arr.number_of_edges() << ", " + << arr.number_of_faces() << std::endl; + + std::size_t id(0); + CGAL::draw(arr, [&] (Arrangement_2::Face_const_handle) -> CGAL::IO::Color { + float h = 360.0 * id++ / arr.number_of_faces(); + float s = 0.5; + float v = 0.5; + float r, g, b; + std::tie(r, g, b) = hsv_to_rgb(h, s, v); + return CGAL::IO::Color(r, g, b); + }, "hsv colors", true); + + return EXIT_SUCCESS; +} diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp new file mode 100644 index 00000000000..bc2403f2aeb --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/ellipses.cpp @@ -0,0 +1,57 @@ +//! \file examples/Arrangement_on_surface_2/conics.cpp +// Constructing an arrangement of various conic arcs. + +#include + +#ifdef CGAL_USE_CORE + +#include +#include + +#include "arr_conics.h" +#include "arr_print.h" + +int main() { + Traits traits; + Arrangement arr(&traits); + + auto ctr_cv = traits.construct_curve_2_object(); + + // Insert a full x-major ellipse + CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, + Point(4,0), Point(0,2))); + CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, + Point(0,2), Point(-4,0))); + CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, + Point(-4,0), Point(0,-2))); + CGAL::insert(arr, ctr_cv(1, 4, 0, 0, 0, -16, CGAL::COUNTERCLOCKWISE, + Point(0,-2), Point(4,0))); + + // Insert a full y-major ellipse + CGAL::insert(arr, ctr_cv(4, 1, 0, 0, 0, -16)); + + // Insert the full ellipse (x/4)^2 + (y/2)^2 = 1 clockwise rotated by + // phi = 36.87 degrees (such that sin(phi) = 0.6, cos(phi) = 0.8), + CGAL::insert(arr, ctr_cv(52, 73, 72, 0, 0, -400)); + + // Insert the full ellipse (x/4)^2 + (y/2)^2 = 1 counter clockwise rotated by + // phi = 36.87 degrees (such that sin(phi) = 0.6, cos(phi) = 0.8), + CGAL::insert(arr, ctr_cv(52, 73, -72, 0, 0, -400)); + + print_arrangement_size(arr); + + CGAL::draw(arr); + + return 0; +} + +#else + +#include + +int main() { + std::cout << "Sorry, this example needs GMP and CORE\n"; + return 0; +} + +#endif diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp new file mode 100644 index 00000000000..aa68c6c247f --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/hyperbolas.cpp @@ -0,0 +1,93 @@ +//! \file examples/Arrangement_on_surface_2/conics.cpp +// Constructing an arrangement of various conic arcs. + +#include + +#ifdef CGAL_USE_CORE + +#include +#include + +#include "arr_conics.h" +#include "arr_print.h" + +int main() { + Traits traits; + Arrangement arr(&traits); + + auto ctr_cv = traits.construct_curve_2_object(); + + // Insert a hyperbolic arc (C1), supported by the hyperbola y = 1/x + // (or: xy - 1 = 0) with the endpoints (1/4, 4) and (2, 1/2). + // The arc is counterclockwise oriented. + CGAL::insert(arr, ctr_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, + Point(Rational(1,4), 4), Point(2, Rational(1,2)))); + CGAL::insert(arr, ctr_cv(0, 0, -1, 0, 0, -1, CGAL::CLOCKWISE, + Point(Rational(-1,4), 4), Point(-2, Rational(1,2)))); + + CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, + Point(3, 4), Point(1, 0))); + CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, + Point(1, 0), Point(3, -4))); + CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE, + Point(-3, 4), Point(-1, 0))); + CGAL::insert(arr, ctr_cv(2, -1, 0, 0, 0, -2, CGAL::CLOCKWISE, + Point(-1, 0), Point(-3, -4))); + + CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE, + Point(4, 3), Point(0, 1))); + CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::CLOCKWISE, + Point(0, 1), Point(-4, 3))); + CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, + Point(4, -3), Point(0, -1))); + CGAL::insert(arr, ctr_cv(-1, 2, 0, 0, 0, -2, CGAL::COUNTERCLOCKWISE, + Point(0, -1), Point(-4, -3))); + + CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, + Point(-5, 0), + Point(Rational(14, 10), Rational(48, 10)))); + CGAL::insert(arr, ctr_cv(4, 46, -144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, + Point(5, 0), + Point(Rational(-14, 10), Rational(-48, 10)))); + // 4*x*x + 46*y*y - 144*x*y - 100 + + CGAL::insert(arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE, + Point(0, -5), + Point(Rational(48, 10), Rational(14, 10)))); + CGAL::insert(arr, ctr_cv(46, 4, -144, 0, 0, -100, CGAL::CLOCKWISE, + Point(0, 5), + Point(Rational(-48, 10), Rational(-14, 10)))); + // 46*x*x + 4*y*y - 144*x*y - 100 + + CGAL::insert(arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE, + Point(-5, 0), + Point(Rational(14,10), Rational(-48,10)))); + CGAL::insert(arr, ctr_cv(4, 46, 144, 0, 0, -100, CGAL::CLOCKWISE, + Point(5, 0), + Point(Rational(-14,10), Rational(48,10)))); + // 4*x*x + 46*y*y + 144*x*y - 100 + + CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, + Point(0, -5), + Point(Rational(-48,10), Rational(14,10)))); + CGAL::insert(arr, ctr_cv(46, 4, 144, 0, 0, -100, CGAL::COUNTERCLOCKWISE, + Point(0, 5), + Point(Rational(48,10), Rational(-14,10)))); + + print_arrangement_size(arr); + + CGAL::draw(arr); + + return 0; +} + +#else + +#include + +int main() { + std::cout << "Sorry, this example needs GMP and CORE\n"; + return 0; +} + +#endif diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp new file mode 100644 index 00000000000..b0f990e0ee9 --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/linear_conics.cpp @@ -0,0 +1,74 @@ +//! \file examples/Arrangement_on_surface_2/conics.cpp +// Constructing an arrangement of various conic arcs. + +#include + +#ifdef CGAL_USE_CORE + +#include +#include + +#include "arr_conics.h" +#include "arr_print.h" + +int main() { + Traits traits; + Arrangement arr(&traits); + + auto ctr_cv = traits.construct_curve_2_object(); + Point p0(0, 0); + Point p1(-1, 0); + Point p2(0, -1); + Point p3(0, 1); + Point p4(1, 0); + Point p5(Rational(1,2),Rational(1,2)); + Point p6(Rational(-1,2),Rational(1,2)); + Rat_point rp0(0, 0); + Rat_point rp1(1, 0); + Rat_point rp2(0, 1); + Rat_point rp3(0, -1); + + // horizontal + // insert the segment (0, 0)--(1, 0). + CGAL::insert(arr, ctr_cv(Rat_segment(rp0, rp1))); + // insert the segment (0, 0)--(-1, 0). + CGAL::insert(arr, ctr_cv(0, 0, 0, 0, 1, 0, CGAL::COLLINEAR, p0, p1)); + + // vertical + // insert the segment (0, -1)--(0, 0). + CGAL::insert(arr, ctr_cv(Rat_segment(rp3, rp0))); + + // translated + // insert the segment (0, -1)--(1, 0). + CGAL::insert(arr, ctr_cv(Rat_segment(rp3, rp1))); + // insert the segment (0, -1)--(-1, 0). + CGAL::insert(arr, ctr_cv(0, 0, 0, -1, -1, -1, CGAL::COLLINEAR, p2, p1)); + + // Special segments + // horizontal special segment + CGAL::insert(arr, ctr_cv(p5, p6)); + + // vertical special segment + CGAL::insert(arr, ctr_cv(p0, p3)); + + // special translated + CGAL::insert(arr, ctr_cv(p1, p3)); + CGAL::insert(arr, ctr_cv(p3, p4)); + + print_arrangement_size(arr); + + CGAL::draw(arr); + + return 0; +} + +#else + +#include + +int main() { + std::cout << "Sorry, this example needs GMP and CORE\n"; + return 0; +} + +#endif diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp new file mode 100644 index 00000000000..2f3bf04bf61 --- /dev/null +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/parabolas.cpp @@ -0,0 +1,91 @@ +//! \file examples/Arrangement_on_surface_2/conics.cpp +// Constructing an arrangement of various conic arcs. + +#include + +#ifdef CGAL_USE_CORE + +#include +#include + +#include "arr_conics.h" +#include "arr_print.h" + +int main() { + Traits traits; + Arrangement arr(&traits); + + auto ctr_cv = traits.construct_curve_2_object(); + + // x-major + // insert the parabola y = x^2; (-1,1)--(1,1) + CGAL::insert(arr, ctr_cv(1, 0, 0, 0, -1, 0, CGAL::COUNTERCLOCKWISE, + Point(-1, 1), Point(1, 1))); + + // translated + // Insert the parabola y = x^2 - 2x + 2; (1,1)--(2,2) + CGAL::insert(arr, ctr_cv(1, 0, 0, -2, -1, 2, CGAL::COUNTERCLOCKWISE, + Point(1, 1), Point(2, 2))); + CGAL::insert(arr, ctr_cv(1, 0, 0, 2, -1, 2, CGAL::COUNTERCLOCKWISE, + Point(-2, 2), Point(-1, 1))); + + // rotated + // Insert the parabola y = x^2 rotated clockwise about theta, such that + // sin(theta) = 0.6, cos(theta) = 0.8 + CGAL::insert(arr, ctr_cv(16, 9, -24, -15, -20, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(-2,10), Rational(14,10)), + Point(Rational(14,10), Rational(2,10)))); + CGAL::insert(arr, ctr_cv(16, 9, 24, 15, -20, 0, CGAL::CLOCKWISE, + Point(Rational(2,10), Rational(14,10)), + Point(Rational(-14,10), Rational(2,10)))); + CGAL::insert(arr, ctr_cv(16, 9, 24, -15, 20, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(14,10), Rational(-2,10)), + Point(Rational(-2,10), Rational(-14,10)))); + CGAL::insert(arr, ctr_cv(16, 9, -24, 15, 20, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(2,10), Rational(-14,10)), + Point(Rational(-14,10), Rational(-2,10)))); + + // 16*x*x+9*y*y-24*x*y-15*x-20*y + + CGAL::insert(arr, ctr_cv(9, 16, -24, -20, -15, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(2,10), Rational(14,10)), + Point(Rational(14,10), Rational(-2,10)))); + CGAL::insert(arr, ctr_cv(9, 16, 24, -20, 15, 0, CGAL::CLOCKWISE, + Point(Rational(2,10), Rational(-14,10)), + Point(Rational(14,10), Rational(2,10)))); + CGAL::insert(arr, ctr_cv(9, 16, 24, 20, -15, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(-14,10), Rational(-2,10)), + Point(Rational(-2,10), Rational(14,10)))); + CGAL::insert(arr, ctr_cv(9, 16, -24, 20, 15, 0, CGAL::COUNTERCLOCKWISE, + Point(Rational(-2,10), Rational(-14,10)), + Point(Rational(-14,10), Rational(2,10)))); + + // 9*x*x+16*y*y-24*x*y+20*x+15*y + + // rotated & translated + CGAL::insert(arr, ctr_cv(16, 9, -24, -23, -14, 36, CGAL::COUNTERCLOCKWISE, + Point(Rational(8,10), Rational(24,10)), + Point(Rational(24,10), Rational(12,10)))); + CGAL::insert(arr, ctr_cv(16, 9, 24, 23, -14, 36, CGAL::CLOCKWISE, + Point(Rational(-8,10), Rational(24,10)), + Point(Rational(-24,10), Rational(12,10)))); + + // 16*x*x+9*y*y-24*x*y-23*x-14*y+36 + + print_arrangement_size(arr); + + CGAL::draw(arr); + + return 0; +} + +#else + +#include + +int main() { + std::cout << "Sorry, this example needs GMP and CORE\n"; + return 0; +} + +#endif diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polycurve_conic.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polycurve_conic.cpp index db6b1b19853..803a0696bd2 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polycurve_conic.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polycurve_conic.cpp @@ -27,7 +27,10 @@ typedef Polycurve_conic_traits_2::Curve_2 Polycurve; typedef CGAL::Arrangement_2 Polycurve_conic_arrangment; int main() { - Polycurve_conic_traits_2 traits; + Traits sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_sub_xcv = sub_traits.construct_x_monotone_curve_2_object(); // Polycurve construction functors auto ctr_xpolycurve = traits.construct_x_monotone_curve_2_object(); @@ -39,29 +42,29 @@ int main() { // Create polycurves // y=x^2 - Conic_arc c3(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(0), Algebraic(0)), - Point(Algebraic(3), Algebraic(9))); - Conic_arc c4(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(3), Algebraic(9)), - Point(Algebraic(5), Algebraic(25))); - Conic_arc c5(0,1,0,1,0,0, CGAL::COUNTERCLOCKWISE, - Point(Algebraic(-25), Algebraic(-5)), - Point(Algebraic(0), Algebraic(0))); + Conic_arc c3 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(0), Algebraic(0)), + Point(Algebraic(3), Algebraic(9))); + Conic_arc c4 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(3), Algebraic(9)), + Point(Algebraic(5), Algebraic(25))); + Conic_arc c5 = ctr_sub_cv(0,1,0,1,0,0, CGAL::COUNTERCLOCKWISE, + Point(Algebraic(-25), Algebraic(-5)), + Point(Algebraic(0), Algebraic(0))); - Conic_arc c6(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(-7), Algebraic(13)), - Point(Algebraic(-3), Algebraic(9))); - Conic_arc c7(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(-3), Algebraic(9)), - Point(Algebraic(0), Algebraic(0))); - Conic_arc c8(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, - Point(Algebraic(0), Algebraic(0)), - Point(Algebraic(4), Algebraic(-2))); + Conic_arc c6 = ctr_sub_cv(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(-7), Algebraic(13)), + Point(Algebraic(-3), Algebraic(9))); + Conic_arc c7 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(-3), Algebraic(9)), + Point(Algebraic(0), Algebraic(0))); + Conic_arc c8 = ctr_sub_cv(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, + Point(Algebraic(0), Algebraic(0)), + Point(Algebraic(4), Algebraic(-2))); - Conic_arc c9(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(-5), Algebraic(25)), - Point(Algebraic(5), Algebraic(25))); + Conic_arc c9 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(-5), Algebraic(25)), + Point(Algebraic(5), Algebraic(25))); // Construct poly-curve conic_curves.clear(); @@ -69,12 +72,12 @@ int main() { Polycurve conic_polycurve_1 = ctr_polycurve(conic_curves.begin(), conic_curves.end()); - Conic_arc c11(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(25), Algebraic(-5)), - Point(Algebraic(0), Algebraic(0))); - Conic_arc c12(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Point(Algebraic(0), Algebraic(0)), - Point(Algebraic(5), Algebraic(25))); + Conic_arc c11 = ctr_sub_cv(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(25), Algebraic(-5)), + Point(Algebraic(0), Algebraic(0))); + Conic_arc c12 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Point(Algebraic(0), Algebraic(0)), + Point(Algebraic(5), Algebraic(25))); // Construct poly-curve conic_curves.clear(); @@ -84,12 +87,12 @@ int main() { ctr_polycurve(conic_curves.begin(), conic_curves.end()); // Construct x-monotone conic curves from conic curves - X_monotone_conic_arc xc3(c3); - X_monotone_conic_arc xc4(c4); - X_monotone_conic_arc xc5(c5); - X_monotone_conic_arc xc6(c6); - X_monotone_conic_arc xc7(c7); - X_monotone_conic_arc xc8(c8); + X_monotone_conic_arc xc3 = ctr_sub_xcv(c3); + X_monotone_conic_arc xc4 = ctr_sub_xcv(c4); + X_monotone_conic_arc xc5 = ctr_sub_xcv(c5); + X_monotone_conic_arc xc6 = ctr_sub_xcv(c6); + X_monotone_conic_arc xc7 = ctr_sub_xcv(c7); + X_monotone_conic_arc xc8 = ctr_sub_xcv(c8); // Construct x-monotone poly-curve from x-monotone conic curves. xmono_conic_curves_2.clear(); @@ -98,7 +101,7 @@ int main() { xmono_conic_curves_2.push_back(xc4); X_monotone_polycurve conic_x_mono_polycurve_1 = ctr_xpolycurve(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + xmono_conic_curves_2.end()); // Construct x-monotone poly-curve. xmono_conic_curves_2.clear(); diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp index b81c2ad65fc..51fa18d82c8 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/polylines.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "arr_polylines.h" #include "arr_print.h" @@ -44,5 +46,6 @@ int main() { insert(arr, pi2); insert(arr, pi3); print_arrangement_size(arr); // print the arrangement size + CGAL::draw(arr); return 0; } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_circle_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_circle_segment_traits_2.h index 3dabf797184..64f7cd6dea9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_circle_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_circle_segment_traits_2.h @@ -23,13 +23,16 @@ * The header file for the Arr_circle_segment_traits_2 class. */ -#include -#include -#include - +// Keep the following 2 lines first. +#include #include #include +#include +#include +#include +#include + namespace CGAL { /*! \class @@ -378,6 +381,183 @@ public: } //@} + /// \name Functor definitions for approximations. Used by the landmarks + // point-location strategy and the drawing procedure. + //@{ + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; + + class Approximate_2 { + protected: + using Traits = Arr_circle_segment_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_circle_segment_traits_2; + + public: + /*! Obtain an approximation of a point coordinate. + * \param p the exact point. + * \param i the coordinate index (either 0 or 1). + * \pre i is either 0 or 1. + * \return An approximation of p's x-coordinate (if i == 0), or an + * approximation of p's y-coordinate (if i == 1). + */ + Approximate_number_type operator()(const Point_2& p, int i) const { + CGAL_precondition((i == 0) || (i == 1)); + return (i == 0) ? (CGAL::to_double(p.x())) : (CGAL::to_double(p.y())); + } + + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2& p) const + { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv, double error, + OutputIterator oi, bool l2r = true) const { + if (xcv.is_linear()) return approximate_segment(xcv, oi, l2r); + return approximate_arc(xcv, error, oi, l2r);; + } + + private: + /*! Handle segments. + */ + template + OutputIterator approximate_segment(const X_monotone_curve_2& xcv, + OutputIterator oi, + bool l2r = true) const { + // std::cout << "SEGMENT\n"; + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + *oi++ = Approximate_point_2(xs, ys); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + + template + OutputIterator add_points(double x1, double y1, double t1, + double x2, double y2, double t2, + double error, OutputIterator oi, + Op op, Transform transform) const { + auto tm = (t1 + t2)*0.5; + + // Compute the canocal point where the error is maximal. + double xm, ym; + op(tm, xm, ym); + + auto dx = x2 - x1; + auto dy = y2 - y1; + + // Compute the error; abort if it is below the threshold + auto l = std::sqrt(dx*dx + dy*dy); + auto e = std::abs((xm*dy - ym*dx + x2*y1 - x1*y2) / l); + if (e < error) return oi; + + double x, y; + transform(xm, ym, x, y); + add_points(x1, y1, t1, xm, ym, tm, error, oi, op, transform); + *oi++ = Approximate_point_2(x, y); + add_points(xm, ym, tm, x2, y2, t2, error, oi, op, transform); + return oi; + } + + /*! Compute the circular point given the parameter t and the transform + * data, that is, the center (translation) and the sin and cos of the + * rotation angle. + */ + void circular_point(double r, double t, double& x, double& y) const { + x = r * std::cos(t); + y = r * std::sin(t); + } + + /*! Transform a point. In particular, rotate the canonical point + * (`xc`,`yc`) by an angle, the sine and cosine of which are `sint` and + * `cost`, respectively, and translate by (`cx`,`cy`). + */ + void transform_point(double xc, double yc, double cx, double cy, + double& x, double& y) const { + x = xc + cx; + y = yc + cy; + } + + /*! Handle circular arcs. + */ + template + OutputIterator approximate_arc(const X_monotone_curve_2& xcv, + double error, OutputIterator oi, + bool l2r = true) const { + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + + const typename Kernel::Circle_2& circ = xcv.supporting_circle(); + auto r_sqr = circ.squared_radius(); + auto r = std::sqrt(CGAL::to_double(r_sqr)); + + // Obtain the center: + auto cx = CGAL::to_double(circ.center().x()); + auto cy = CGAL::to_double(circ.center().y()); + + // Inverse transform the source and target + auto xs_t = xs - cx; + auto ys_t = ys - cy; + auto xt_t = xt - cx; + auto yt_t = yt - cy; + + // Compute the parameters ts and tt such that + // source == (x(ts),y(ts)), and + // target == (x(tt),y(tt)) + auto ts = std::atan2(r*ys_t, r*xs_t); + if (ts < 0) ts += 2*CGAL_PI; + auto tt = std::atan2(r*yt_t, r*xt_t); + if (tt < 0) tt += 2*CGAL_PI; + auto orient(xcv.orientation()); + if (xcv.source() != src) orient = CGAL::opposite(orient); + if (orient == COUNTERCLOCKWISE) { + if (tt < ts) tt += 2*CGAL_PI; + } + else { + if (ts < tt) ts += 2*CGAL_PI; + } + + *oi++ = Approximate_point_2(xs, ys); + add_points(xs_t, ys_t, ts, xt_t, yt_t, tt, error, oi, + [&](double tm, double& xm, double& ym) { + circular_point(r, tm, xm, ym); + }, + [&](double xc, double& yc, double& x, double& y) { + transform_point(xc, yc, cx, cy, x, y); + }); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + }; + + /*! Obtain an Approximate_2 functor object. */ + Approximate_2 approximate_2_object() const { return Approximate_2(*this); } + //@} + /// \name Intersections, subdivisions, and mergings //@{ diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_conic_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_conic_traits_2.h index 8c3e7f6533e..638e5f630b2 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_conic_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_conic_traits_2.h @@ -10,6 +10,7 @@ // // Author(s): Ron Wein // Waqar Khan +// Efi Fogel #ifndef CGAL_ARR_CONIC_TRAITS_2_H #define CGAL_ARR_CONIC_TRAITS_2_H @@ -22,19 +23,29 @@ * The conic traits-class for the arrangement package. */ +// Keep the following 2 lines first. +#include #include #include +#include +#include +#include +#include + +#include #include #include +#include #include #include #include +#include +#include namespace CGAL { -/*! - * \class A traits class for maintaining an arrangement of conic arcs (bounded +/*! \class A traits class for maintaining an arrangement of conic arcs (bounded * segments of algebraic curves of degree 2 at most). * * The class is templated with two parameters: @@ -46,14 +57,12 @@ namespace CGAL { * Nt_traits A traits class for performing various operations on the integer, * rational and algebraic types. */ -template -class Arr_conic_traits_2 -{ +template +class Arr_conic_traits_2 { public: - - typedef Rat_kernel_ Rat_kernel; - typedef Alg_kernel_ Alg_kernel; - typedef Nt_traits_ Nt_traits; + typedef RatKernel Rat_kernel; + typedef AlgKernel Alg_kernel; + typedef NtTraits Nt_traits; typedef typename Rat_kernel::FT Rational; typedef typename Rat_kernel::Point_2 Rat_point_2; @@ -62,11 +71,10 @@ public: typedef typename Rat_kernel::Circle_2 Rat_circle_2; typedef typename Alg_kernel::FT Algebraic; + typedef typename Alg_kernel::Point_2 Alg_point_2; typedef typename Nt_traits::Integer Integer; - typedef Arr_conic_traits_2 Self; - // Category tags: typedef Tag_true Has_left_category; typedef Tag_true Has_merge_category; @@ -79,36 +87,77 @@ public: typedef Arr_oblivious_side_tag Right_side_category; // Traits objects: - typedef _Conic_arc_2 Curve_2; - typedef _Conic_x_monotone_arc_2 X_monotone_curve_2; - typedef _Conic_point_2 Point_2; - typedef unsigned int Multiplicity; + typedef Conic_arc_2 Curve_2; + typedef Conic_x_monotone_arc_2 X_monotone_curve_2; + typedef Conic_point_2 Point_2; + typedef size_t Multiplicity; private: - // Type definition for the intersection points mapping. - typedef typename X_monotone_curve_2::Conic_id Conic_id; - typedef typename X_monotone_curve_2::Intersection_point Intersection_point; - typedef typename X_monotone_curve_2::Intersection_map Intersection_map; + using Conic_id = typename Point_2::Conic_id; + using Conic_pair = std::pair; - mutable Intersection_map inter_map; // Mapping conic pairs to their + /*! \struct Less functor for Conic_pair. + */ + struct Less_conic_pair { + bool operator()(const Conic_pair& cp1, const Conic_pair& cp2) const { + // Compare the pairs of IDs lexicographically. + return ((cp1.first < cp2.first) || + ((cp1.first == cp2.first) && (cp1.second < cp2.second))); + } + }; + + typedef std::pair Intersection_point; + typedef std::list Intersection_list; + typedef std::map + Intersection_map; + typedef typename Intersection_map::iterator Intersection_map_iterator; + + + typedef std::shared_ptr Shared_rat_kernel; + typedef std::shared_ptr Shared_alg_kernel; + typedef std::shared_ptr Shared_nt_traits; + + const Shared_rat_kernel m_rat_kernel; + const Shared_alg_kernel m_alg_kernel; + const Shared_nt_traits m_nt_traits; + + mutable Intersection_map m_inter_map; // Mapping conic pairs to their // intersection points. public: - - /*! - * Default constructor. + /*! Default constructor. */ - Arr_conic_traits_2 () + Arr_conic_traits_2() {} + + /*! Construct from resources. + */ + Arr_conic_traits_2(Shared_rat_kernel rat_kernel, + Shared_alg_kernel alg_kernel, + Shared_nt_traits nt_traits) : + m_rat_kernel(rat_kernel), + m_alg_kernel(alg_kernel), + m_nt_traits(nt_traits) {} - /*! Get the next conic index. */ - static unsigned int get_index () - { + /*! Obtain the rational kernel. + */ + Shared_rat_kernel rat_kernel() { return m_rat_kernel; } + + /*! Obtain the algebraic kernel. + */ + Shared_alg_kernel alg_kernel() { return m_alg_kernel; } + + /*! Obtain the nt traits. + */ + Shared_nt_traits nt_traits() { return m_nt_traits; } + + /*! Obtain the next conic index. */ + static size_t get_index() { #ifdef CGAL_NO_ATOMIC - static unsigned int index; + static size_t index; #else - static std::atomic index; + static std::atomic index; #endif return (++index); } @@ -116,336 +165,671 @@ public: /// \name Basic functor definitions. //@{ - class Compare_x_2 - { + class Compare_x_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Compare_x_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + public: - /*! - * Compare the x-coordinates of two points. + /*! Compare the x-coordinates of two points. * \param p1 The first point. * \param p2 The second point. * \return LARGER if x(p1) > x(p2); * SMALLER if x(p1) < x(p2); * EQUAL if x(p1) = x(p2). */ - Comparison_result operator() (const Point_2 & p1, const Point_2 & p2) const - { - Alg_kernel ker; - return (ker.compare_x_2_object() (p1, p2)); - } + Comparison_result operator() (const Point_2& p1, const Point_2& p2) const + { return m_traits.m_alg_kernel->compare_x_2_object()(p1, p2); } }; - /*! Get a Compare_x_2 functor object. */ - Compare_x_2 compare_x_2_object () const - { - return Compare_x_2(); - } + /*! Obtain a Compare_x_2 functor object. */ + Compare_x_2 compare_x_2_object() const { return Compare_x_2(*this); } + + class Compare_xy_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Compare_xy_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; - class Compare_xy_2 - { public: - /*! - * Compares two points lexigoraphically: by x, then by y. + /*! Compares two points lexigoraphically: by x, then by y. * \param p1 The first point. * \param p2 The second point. - * \return LARGER if x(p1) > x(p2), or if x(p1) = x(p2) and y(p1) > y(p2); - * SMALLER if x(p1) < x(p2), or if x(p1) = x(p2) and y(p1) < y(p2); - * EQUAL if the two points are equal. + * \return `LARGER` if `x(p1) > x(p2)`, or if `x(p1) = x(p2)` and `y(p1) > y(p2)`; + * `SMALLER` if `x(p1) < x(p2)`, or if `x(p1) = x(p2)` and `y(p1) < y(p2)`; + * `EQUAL` if the two points are equal. */ - Comparison_result operator() (const Point_2& p1, const Point_2& p2) const - { - Alg_kernel ker; - return (ker.compare_xy_2_object() (p1, p2)); - } + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const + { return m_traits.m_alg_kernel->compare_xy_2_object()(p1, p2); } }; - /*! Get a Compare_xy_2 functor object. */ - Compare_xy_2 compare_xy_2_object () const - { - return Compare_xy_2(); - } + /*! Obtain a Compare_xy_2 functor object. */ + Compare_xy_2 compare_xy_2_object() const { return Compare_xy_2(*this); } - class Construct_min_vertex_2 - { + class Construct_min_vertex_2 { public: - /*! - * Get the left endpoint of the x-monotone curve (segment). - * \param cv The curve. + /*! Obtain the left endpoint of an x-monotone arc. + * \param cv The arc. * \return The left endpoint. */ - const Point_2& operator() (const X_monotone_curve_2 & cv) const - { - return (cv.left()); - } + const Point_2& operator()(const X_monotone_curve_2& xcv) const + { return xcv.left(); } }; - /*! Get a Construct_min_vertex_2 functor object. */ - Construct_min_vertex_2 construct_min_vertex_2_object () const - { - return Construct_min_vertex_2(); - } + /*! Obtain a Construct_min_vertex_2 functor object. */ + Construct_min_vertex_2 construct_min_vertex_2_object() const + { return Construct_min_vertex_2(); } - class Construct_max_vertex_2 - { + class Construct_max_vertex_2 { public: - /*! - * Get the right endpoint of the x-monotone curve (segment). - * \param cv The curve. + /*! Obtain the right endpoint of the x-monotone arc. + * \param cv The arc. * \return The right endpoint. */ - const Point_2& operator() (const X_monotone_curve_2 & cv) const - { - return (cv.right()); - } + const Point_2& operator()(const X_monotone_curve_2& xcv) const + { return xcv.right(); } }; - /*! Get a Construct_max_vertex_2 functor object. */ - Construct_max_vertex_2 construct_max_vertex_2_object () const - { - return Construct_max_vertex_2(); - } + /*! Obtain a Construct_max_vertex_2 functor object. */ + Construct_max_vertex_2 construct_max_vertex_2_object() const + { return Construct_max_vertex_2(); } - class Is_vertical_2 - { + class Is_vertical_2 { public: - /*! - * Check whether the given x-monotone curve is a vertical segment. - * \param cv The curve. - * \return (true) if the curve is a vertical segment; (false) otherwise. + /*! Check whether a given x-monotone arc is a vertical segment. + * \param cv The vertical segment. + * \return `true` if the arc is a vertical segment; `false` otherwise. */ - bool operator() (const X_monotone_curve_2& cv) const - { - return (cv.is_vertical()); - } + bool operator()(const X_monotone_curve_2& cv) const + { return cv.is_vertical(); } }; - /*! Get an Is_vertical_2 functor object. */ - Is_vertical_2 is_vertical_2_object () const - { - return Is_vertical_2(); - } + /*! Obtain an Is_vertical_2 functor object. */ + Is_vertical_2 is_vertical_2_object() const { return Is_vertical_2(); } + + class Compare_y_at_x_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Compare_y_at_x_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; - class Compare_y_at_x_2 - { public: - /*! - * Return the location of the given point with respect to the input curve. - * \param cv The curve. + /*! Return the location of a given point with respect to an input arc. + * \param xcv The arc. * \param p The point. - * \pre p is in the x-range of cv. - * \return SMALLER if y(p) < cv(x(p)), i.e. the point is below the curve; - * LARGER if y(p) > cv(x(p)), i.e. the point is above the curve; - * EQUAL if p lies on the curve. + * \pre `p` is in the \f$x\f$-range of `xcv`. + * \return `SMALLER` if `y(p) < xcv(x(p))`, i.e. the point is below the arc; + * `LARGER` if `y(p) > xcv(x(p))`, i.e. the point is above the arc; + * `EQUAL` if `p` lies on the curve. */ - Comparison_result operator() (const Point_2 & p, - const X_monotone_curve_2 & cv) const - { - Alg_kernel ker; + Comparison_result operator()(const Point_2& p, + const X_monotone_curve_2& xcv) const { + auto cmp_y = m_traits.m_alg_kernel->compare_y_2_object(); - if (cv.is_vertical()) - { + if (xcv.is_vertical()) { // A special treatment for vertical segments: // In case p has the same x c-ordinate of the vertical segment, compare // it to the segment endpoints to determine its position. - Comparison_result res1 = ker.compare_y_2_object() (p, cv.left()); - Comparison_result res2 = ker.compare_y_2_object() (p, cv.right()); - - if (res1 == res2) - return (res1); - else - return (EQUAL); + Comparison_result res1 = cmp_y(p, xcv.left()); + Comparison_result res2 = cmp_y(p, xcv.right()); + return (res1 == res2) ? res1 : EQUAL; } // Check whether the point is exactly on the curve. - if (cv.contains_point(p)) - return (EQUAL); + if (m_traits.contains_point(xcv, p)) return EQUAL; - // Get a point q on the x-monotone arc with the same x coordinate as p. - Comparison_result x_res; - Point_2 q; + // Obtain a point q on the x-monotone arc with the same x coordinate as p. + Point_2 q; - if ((x_res = ker.compare_x_2_object() (p, cv.left())) == EQUAL) - { - q = cv.left(); - } - else - { - CGAL_precondition (x_res != SMALLER); - - if ((x_res = ker.compare_x_2_object() (p, cv.right())) == EQUAL) - { - q = cv.right(); - } - else - { - CGAL_precondition (x_res != LARGER); - - q = cv.point_at_x (p); + auto cmp_x = m_traits.m_alg_kernel->compare_x_2_object(); + Comparison_result x_res_left = cmp_x(p, xcv.left()); + if (x_res_left == EQUAL) q = xcv.left(); + else { + CGAL_precondition(x_res_left != SMALLER); + auto x_res_right = cmp_x(p, xcv.right()); + if (x_res_right == EQUAL) q = xcv.right(); + else { + CGAL_precondition(x_res_right != LARGER); + q = m_traits.point_at_x(xcv, p); } } // Compare p with the a point of the curve with the same x coordinate. - return (ker.compare_y_2_object() (p, q)); + return cmp_y(p, q); } }; - /*! Get a Compare_y_at_x_2 functor object. */ - Compare_y_at_x_2 compare_y_at_x_2_object () const - { - return Compare_y_at_x_2(); - } + /*! Obtain a Compare_y_at_x_2 functor object. */ + Compare_y_at_x_2 compare_y_at_x_2_object() const + { return Compare_y_at_x_2(*this); } - class Compare_y_at_x_left_2 - { - public: - /*! - * Compares the y value of two x-monotone curves immediately to the left - * of their intersection point. - * \param cv1 The first curve. - * \param cv2 The second curve. - * \param p The intersection point. - * \pre The point p lies on both curves, and both of them must be also be - * defined (lexicographically) to its left. - * \return The relative position of cv1 with respect to cv2 immdiately to - * the left of p: SMALLER, LARGER or EQUAL. + class Compare_y_at_x_left_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. */ - Comparison_result operator() (const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2, - const Point_2& p) const + Compare_y_at_x_left_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Compares the \f$y\f$ value of two \f$x\f$-monotone arcs immediately + * to the left of their intersection point. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \param p The intersection point. + * \pre The point `p` lies on both curves, and both of them must be also be + * defined (lexicographically) to its left. + * \return The relative position of `xcv1` with respect to `xcv2` immdiately + * to the left of `p`: `SMALLER`, `LARGER`, or `EQUAL`. + */ + Comparison_result operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + const Point_2& p) const { // Make sure that p lies on both curves, and that both are defined to its // left (so their left endpoint is lexicographically smaller than p). - CGAL_precondition (cv1.contains_point (p) && - cv2.contains_point (p)); + CGAL_precondition(m_traits.contains_point(xcv1, p) && + m_traits.contains_point(xcv2, p)); - CGAL_precondition_code ( - Alg_kernel ker; - ); - CGAL_precondition (ker.compare_xy_2_object() (p, - cv1.left()) == LARGER && - ker.compare_xy_2_object() (p, - cv2.left()) == LARGER); + CGAL_precondition_code(const auto ker = m_traits.m_alg_kernel); + CGAL_precondition(ker->compare_xy_2_object()(p, xcv1.left()) == LARGER && + ker->compare_xy_2_object()(p, xcv2.left()) == LARGER); // If one of the curves is vertical, it is below the other one. - if (cv1.is_vertical()) - { - if (cv2.is_vertical()) - // Both are vertical: - return (EQUAL); - else - return (SMALLER); - } - else if (cv2.is_vertical()) - { - return (LARGER); - } + if (xcv1.is_vertical()) return (xcv2.is_vertical()) ? EQUAL : SMALLER; + else if (xcv2.is_vertical()) return LARGER; // Compare the two curves immediately to the left of p: - return (cv1.compare_to_left (cv2, p)); + return compare_to_left(xcv1, xcv2, p); } + + private: + /*! Compare two arcs immediately to the leftt of their intersection point. + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. + * \param p The reference intersection point. + * \return The relative position of the arcs to the left of `p`. + * \pre Both arcs we compare are not vertical segments. + */ + Comparison_result compare_to_left(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + const Point_2& p) const { + CGAL_precondition(! xcv1.is_vertical() && ! xcv2.is_vertical()); + + // In case one arc is facing upwards and another facing downwards, it is + // clear that the one facing upward is above the one facing downwards. + if (m_traits.has_same_supporting_conic(xcv1, xcv2)) { + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_DOWN)) + return LARGER; + else if (xcv1.test_flag(X_monotone_curve_2::FACING_DOWN) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) + return SMALLER; + + // In this case the two arcs overlap. + CGAL_assertion(xcv1.facing_mask() == xcv2.facing_mask()); + + return EQUAL; + } + + // Compare the slopes of the two arcs at p, using their first-order + // partial derivatives. + Algebraic slope1_numer, slope1_denom; + Algebraic slope2_numer, slope2_denom; + + xcv1.derive_by_x_at(p, 1, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 1, slope2_numer, slope2_denom); + + // Check if any of the slopes is vertical. + const bool is_vertical_slope1 = (CGAL::sign (slope1_denom) == ZERO); + const bool is_vertical_slope2 = (CGAL::sign (slope2_denom) == ZERO); + + if (! is_vertical_slope1 && ! is_vertical_slope2) { + // The two derivatives at p are well-defined: use them to determine + // which arc is above the other (the one with a larger slope is below). + Comparison_result slope_res = CGAL::compare(slope2_numer*slope1_denom, + slope1_numer*slope2_denom); + + if (slope_res != EQUAL) return slope_res; + + // Use the second-order derivative. + xcv1.derive_by_x_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 2, slope2_numer, slope2_denom); + + slope_res = CGAL::compare(slope1_numer*slope2_denom, + slope2_numer*slope1_denom); + + if (slope_res != EQUAL) return (slope_res); + + // Use the third-order derivative. + xcv1.derive_by_x_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 3, slope2_numer, slope2_denom); + + slope_res = CGAL::compare(slope2_numer*slope1_denom, + slope1_numer*slope2_denom); + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + return slope_res; + } + else if (! is_vertical_slope2) { + // The first arc has a vertical slope at p: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv1.facing_mask() != 0); + + return (xcv1.test_flag(X_monotone_curve_2::FACING_UP)) ? + LARGER : SMALLER; + } + else if (! is_vertical_slope1) { + // The second arc has a vertical slope at p_int: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv2.facing_mask() != 0); + + return (xcv2.test_flag(X_monotone_curve_2::FACING_UP)) ? + SMALLER : LARGER; + } + + // The two arcs have vertical slopes at p_int: + // First check whether one is facing up and one down. In this case the + // comparison result is trivial. + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_DOWN)) + return LARGER; + else if (xcv1.test_flag(X_monotone_curve_2::FACING_DOWN) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) + return SMALLER; + + // Compute the second-order derivative by y and act according to it. + xcv1.derive_by_y_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 2, slope2_numer, slope2_denom); + + Comparison_result slope_res = + CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); + + // If necessary, use the third-order derivative by y. + if (slope_res == EQUAL) { + // \todo Check this! + xcv1.derive_by_y_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 3, slope2_numer, slope2_denom); + + slope_res = + CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); + } + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + // Check whether both are facing up. + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) + return ((slope_res == LARGER) ? SMALLER : LARGER); + + // Both are facing down. + return slope_res; + } + }; - /*! Get a Compare_y_at_x_left_2 functor object. */ - Compare_y_at_x_left_2 compare_y_at_x_left_2_object () const - { - return Compare_y_at_x_left_2(); - } + /*! Obtain a Compare_y_at_x_left_2 functor object. */ + Compare_y_at_x_left_2 compare_y_at_x_left_2_object() const + { return Compare_y_at_x_left_2(*this); } - class Compare_y_at_x_right_2 - { - public: - /*! - * Compares the y value of two x-monotone curves immediately to the right - * of their intersection point. - * \param cv1 The first curve. - * \param cv2 The second curve. - * \param p The intersection point. - * \pre The point p lies on both curves, and both of them must be also be - * defined (lexicographically) to its right. - * \return The relative position of cv1 with respect to cv2 immdiately to - * the right of p: SMALLER, LARGER or EQUAL. + class Compare_y_at_x_right_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. */ - Comparison_result operator() (const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2, - const Point_2& p) const + Compare_y_at_x_right_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Compares the `y` value of two \f$x\f$-monotone arcs immediately + * to the right of their intersection point. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \param p The intersection point. + * \pre The point `p` lies on both curves, and both of them must be also be + * defined (lexicographically) to its right. + * \return The relative position of `xcv1` with respect to `xcv2` immdiately + * to the right of `p`: `SMALLER`, `LARGER`, or `EQUAL`. + */ + Comparison_result operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + const Point_2& p) const { // Make sure that p lies on both curves, and that both are defined to its // left (so their left endpoint is lexicographically smaller than p). - CGAL_precondition (cv1.contains_point (p) && - cv2.contains_point (p)); - - CGAL_precondition_code ( - Alg_kernel ker; - ); - - CGAL_precondition (ker.compare_xy_2_object() (p, - cv1.right()) == SMALLER && - ker.compare_xy_2_object() (p, - cv2.right()) == SMALLER); + CGAL_precondition(m_traits.contains_point(xcv1, p) && + m_traits.contains_point(xcv2, p)); + CGAL_precondition_code(const auto ker = m_traits.m_alg_kernel); + CGAL_precondition_code(auto cmp_xy = ker->compare_xy_2_object()); + CGAL_precondition(cmp_xy(p, xcv1.right()) == SMALLER && + cmp_xy(p, xcv2.right()) == SMALLER); // If one of the curves is vertical, it is above the other one. - if (cv1.is_vertical()) - { - if (cv2.is_vertical()) - // Both are vertical: - return (EQUAL); - else - return (LARGER); - } - else if (cv2.is_vertical()) - { - return (SMALLER); - } + if (xcv1.is_vertical()) return (xcv2.is_vertical()) ? EQUAL : LARGER; + else if (xcv2.is_vertical()) return SMALLER; // Compare the two curves immediately to the right of p: - return (cv1.compare_to_right (cv2, p)); + return compare_to_right(xcv1, xcv2, p); } - }; - /*! Get a Compare_y_at_x_right_2 functor object. */ - Compare_y_at_x_right_2 compare_y_at_x_right_2_object () const - { - return Compare_y_at_x_right_2(); + private: + /*! Compare two arcs immediately to the right of their intersection point. + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. + * \param p The reference intersection point. + * \return The relative position of the arcs to the right of `p`. + * \pre Both arcs we compare are not vertical segments. + */ + Comparison_result compare_to_right(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + const Point_2& p) const { + CGAL_precondition(! xcv1.is_vertical() && ! xcv2.is_vertical()); + + // In case one arc is facing upwards and another facing downwards, it is + // clear that the one facing upward is above the one facing downwards. + if (m_traits.has_same_supporting_conic(xcv1, xcv2)) { + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_DOWN)) + return LARGER; + else if (xcv1.test_flag(X_monotone_curve_2::FACING_DOWN) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) + return SMALLER; + + // In this case the two arcs overlap. + CGAL_assertion(xcv1.facing_mask() == xcv2.facing_mask()); + return EQUAL; + } + + // Compare the slopes of the two arcs at p, using their first-order + // partial derivatives. + Algebraic slope1_numer, slope1_denom; + Algebraic slope2_numer, slope2_denom; + + xcv1.derive_by_x_at(p, 1, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 1, slope2_numer, slope2_denom); + + // Check if any of the slopes is vertical. + const bool is_vertical_slope1 = (CGAL::sign(slope1_denom) == ZERO); + const bool is_vertical_slope2 = (CGAL::sign(slope2_denom) == ZERO); + + if (! is_vertical_slope1 && ! is_vertical_slope2) { + // The two derivatives at p are well-defined: use them to determine + // which arc is above the other (the one with a larger slope is below). + Comparison_result slope_res = + CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); + + if (slope_res != EQUAL) return (slope_res); + + // Use the second-order derivative. + xcv1.derive_by_x_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 2, slope2_numer, slope2_denom); + + slope_res = + CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); + + if (slope_res != EQUAL) return (slope_res); + + // Use the third-order derivative. + xcv1.derive_by_x_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 3, slope2_numer, slope2_denom); + + slope_res = + CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + return slope_res; + } + else if (! is_vertical_slope2) { + // The first arc has a vertical slope at p: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv1.facing_mask() != 0); + + return (xcv1.test_flag(X_monotone_curve_2::FACING_UP)) ? LARGER : SMALLER; + } + else if (! is_vertical_slope1) { + // The second arc has a vertical slope at p_int: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv2.facing_mask() != 0); + + return (xcv2.test_flag(X_monotone_curve_2::FACING_UP)) ? SMALLER : LARGER; + } + + // The two arcs have vertical slopes at p_int: + // First check whether one is facing up and one down. In this case the + // comparison result is trivial. + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_DOWN)) return LARGER; + else if (xcv1.test_flag(X_monotone_curve_2::FACING_DOWN) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) return SMALLER; + + // Compute the second-order derivative by y and act according to it. + xcv1.derive_by_y_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 2, slope2_numer, slope2_denom); + + Comparison_result slope_res = + CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); + + // If necessary, use the third-order derivative by y. + if (slope_res == EQUAL) { + // \todo Check this! + xcv1.derive_by_y_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 3, slope2_numer, slope2_denom); + + slope_res = + CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); + } + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + if (xcv1.test_flag(X_monotone_curve_2::FACING_UP) && + xcv2.test_flag(X_monotone_curve_2::FACING_UP)) + return (slope_res == LARGER) ? SMALLER : LARGER; // both are facing up + return slope_res; // both are facing down } - class Equal_2 - { - public: - /*! - * Check if the two x-monotone curves are the same (have the same graph). - * \param cv1 The first curve. - * \param cv2 The second curve. - * \return (true) if the two curves are the same; (false) otherwise. - */ - bool operator() (const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2) const - { - if (&cv1 == &cv2) - return (true); + }; - return (cv1.equals (cv2)); + /*! Obtain a Compare_y_at_x_right_2 functor object. */ + Compare_y_at_x_right_2 compare_y_at_x_right_2_object() const + { return Compare_y_at_x_right_2(*this); } + + class Equal_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Equal_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Check whether two \f$x\f$-monotone curves are the same (have the same + * graph). + * \param xcv1 The first curve. + * \param xcv2 The second curve. + * \return `true` if the two curves are the same; `false` otherwise. + */ + bool operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2) const + { + if (&xcv1 == &xcv2) return true; + return equals(xcv1, xcv2); } - /*! - * Check if the two points are the same. + /*! Check whether two points are the same. * \param p1 The first point. * \param p2 The second point. - * \return (true) if the two point are the same; (false) otherwise. + * \return `true` if the two point are the same; `false` otherwise. */ - bool operator() (const Point_2& p1, const Point_2& p2) const - { - if (&p1 == &p2) - return (true); + bool operator()(const Point_2& p1, const Point_2& p2) const { + if (&p1 == &p2) return (true); + return(m_traits.m_alg_kernel->compare_xy_2_object()(p1, p2) == EQUAL); + } - Alg_kernel ker; - return (ker.compare_xy_2_object() (p1, p2) == EQUAL); + private: + /*! Check whether two arcs are equal (have the same graph). + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. + * \return `true` if the two arcs have the same graph; `false` otherwise. + */ + bool equals(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2) const { + // The two arc must have the same supporting conic curves. + if (! m_traits.has_same_supporting_conic(xcv1, xcv2)) return false; + + auto eq = m_traits.m_alg_kernel->equal_2_object(); + + // Check that the arc endpoints are the same. + if (xcv1.orientation() == COLLINEAR) { + CGAL_assertion(xcv2.orientation() == COLLINEAR); + return((eq(xcv1.source(), xcv2.source()) && + eq(xcv1.target(), xcv2.target())) || + (eq(xcv1.source(), xcv2.target()) && + eq(xcv1.target(), xcv2.source()))); + } + + if (xcv1.orientation() == xcv2.m_orient) { + // Same orientation - the source and target points must be the same. + return (eq(xcv1.source(), xcv2.source()) && + eq(xcv1.target(), xcv2.target())); + } + + // Reverse orientation - the source and target points must be swapped. + return (eq(xcv1.source(), xcv2.target()) && + eq(xcv1.target(), xcv2.source())); } }; - /*! Get an Equal_2 functor object. */ - Equal_2 equal_2_object () const - { - return Equal_2(); - } + /*! Obtain an Equal_2 functor object. */ + Equal_2 equal_2_object() const { return Equal_2(*this); } + //@} + + /// \name Functor definitions to handle boundaries + //@{ + + /*! A function object that obtains the parameter space of a geometric + * entity along the \f$x-\f$xaxis. + */ + class Parameter_space_in_x_2 { + public: + /*! Obtains the parameter space at the end of an arc along the \f$x\f$-axis. + * \param xcv The arc. + * \param ce The arc end indicator: + * `ARR_MIN_END`—the minimal end of `xcv` or + * `ARR_MAX_END`—the maximal end of `xcv`. + * \return the parameter space at the `ce` end of the arc `xcv`. + * `ARR_LEFT_BOUNDARY` —the arc approaches the identification curve from + * the right at the arc left end. + * `ARR_INTERIOR` —the arc does not approache the identification curve. + * `ARR_RIGHT_BOUNDARY`—the arc approaches the identification curve from + * the left at the arc right end. + */ + Arr_parameter_space operator()(const X_monotone_curve_2 & /* xcv */, + Arr_curve_end /* ce */) const { + CGAL_error_msg("Not implemented yet!"); + return ARR_INTERIOR; + } + + /*! Obtains the parameter space at a point along the \f$x\f$-axis. + * \param p The point. + * \return the parameter space at `p`. + */ + Arr_parameter_space operator()(const Point_2 ) const + { return ARR_INTERIOR; } + }; + + /*! Obtain a Parameter_space_in_x_2 function object */ + Parameter_space_in_x_2 parameter_space_in_x_2_object() const + { return Parameter_space_in_x_2(); } + + /*! A function object that obtains the parameter space of a geometric + * entity along the y-axis + */ + class Parameter_space_in_y_2 { + public: + /*! Obtains the parameter space at the end of an arc along the \f$y\f$-axis . + * Note that if the arc end coincides with a pole, then unless the arc + * coincides with the identification curve, the arc end is considered to + * be approaching the boundary, but not on the boundary. + * If the arc coincides with the identification curve, it is assumed to + * be smaller than any other object. + * \param xcv The arc. + * \param ce The arc end indicator: + * `ARR_MIN_END`—the minimal end of `xcv` or + * `ARR_MAX_END`—the maximal end of `xcv`. + * \return the parameter space at the `ce` end of the arc `xcv`. + * `ARR_BOTTOM_BOUNDARY`—the arc approaches the south pole at the arc + * left end. + * `ARR_INTERIOR` —the arc does not approache a contraction point. + * `ARR_TOP_BOUNDARY` —the arc approaches the north pole at the arc + * right end. + */ + Arr_parameter_space operator()(const X_monotone_curve_2& /* xcv */, + Arr_curve_end /* ce */) const { + CGAL_error_msg("Not implemented yet!"); + return ARR_INTERIOR; + } + + /*! Obtains the parameter space at a point along the \f$y\f$-axis. + * \param p The point. + * \return The parameter space at `p`. + */ + Arr_parameter_space operator()(const Point_2 /* p */) const + { return ARR_INTERIOR; } + }; + + /*! Obtain a Parameter_space_in_y_2 function object */ + Parameter_space_in_y_2 parameter_space_in_y_2_object() const + { return Parameter_space_in_y_2(); } + //@} /// \name Intersections, subdivisions, and mergings @@ -455,37 +839,46 @@ public: * A functor for subdividing curves into x-monotone curves. */ class Make_x_monotone_2 { - typedef Arr_conic_traits_2 Self; + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Make_x_monotone_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; public: - /*! Subdivide a given conic curve (or conic arc) into x-monotone subcurves + /*! Subdivide a given conic arc into \f$x\f$-monotone sub arcs * and insert them to a given output iterator. - * \param cv the curve. + * \param cv The arc. * \param oi the output iterator for the result. Its dereference type is a * variant that wraps a \c Point_2 or an \c X_monotone_curve_2 * objects. * \return the past-the-end iterator. */ template - OutputIterator operator()(const Curve_2& cv, OutputIterator oi) const - { + OutputIterator operator()(const Curve_2& cv, OutputIterator oi) const { typedef boost::variant Make_x_monotone_result; + auto ctr_xcv = m_traits.construct_x_monotone_curve_2_object(); + // Increment the serial number of the curve cv, which will serve as its // unique identifier. - auto index = Self::get_index(); + auto index = Traits::get_index(); Conic_id conic_id(index); // Find the points of vertical tangency to cv and act accordingly. - typename Curve_2::Point_2 vtan_ps[2]; - int n_vtan_ps; - - n_vtan_ps = cv.vertical_tangency_points(vtan_ps); - + Alg_point_2 vtan_ps[2]; + auto n_vtan_ps = m_traits.vertical_tangency_points(cv, vtan_ps); if (n_vtan_ps == 0) { // In case the given curve is already x-monotone: - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, conic_id)); return oi; } @@ -497,23 +890,19 @@ public: // In case the curve is a full conic, split it into two x-monotone // arcs, one going from ps[0] to ps[1], and the other from ps[1] to // ps[0]. - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, vtan_ps[0], - vtan_ps[1], - conic_id)); - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, vtan_ps[1], - vtan_ps[0], - conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, vtan_ps[0], vtan_ps[1], + conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, vtan_ps[1], vtan_ps[0], + conic_id)); } else { if (n_vtan_ps == 1) { // Split the arc into two x-monotone sub-curves: one going from the // arc source to ps[0], and the other from ps[0] to the target. - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, cv.source(), - vtan_ps[0], - conic_id)); - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, vtan_ps[0], - cv.target(), - conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, cv.source(), vtan_ps[0], + conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, vtan_ps[0], cv.target(), + conic_id)); } else { CGAL_assertion(n_vtan_ps == 2); @@ -524,17 +913,14 @@ public: // tangnecy points (or both lies above it). int ind_first = 0; int ind_second = 1; - Alg_kernel_ ker; - typename Alg_kernel_::Line_2 line = - ker.construct_line_2_object()(vtan_ps[0], vtan_ps[1]); - const Comparison_result start_pos = - ker.compare_y_at_x_2_object() (cv.source(), line); - const Comparison_result order_vpts = - ker.compare_x_2_object()(vtan_ps[0], vtan_ps[1]); + auto ker = m_traits.m_alg_kernel; + auto cmp_y_at_x_2 = ker->compare_y_at_x_2_object(); + auto line = ker->construct_line_2_object()(vtan_ps[0], vtan_ps[1]); + auto start_pos = cmp_y_at_x_2(cv.source(), line); + auto order_vpts = ker->compare_x_2_object()(vtan_ps[0], vtan_ps[1]); - CGAL_assertion(start_pos != EQUAL && - ker.compare_y_at_x_2_object()(cv.target(), - line) == start_pos); + CGAL_assertion((start_pos != EQUAL) && + (cmp_y_at_x_2(cv.target(), line) == start_pos)); CGAL_assertion(order_vpts != EQUAL); if (((cv.orientation() == COUNTERCLOCKWISE) && @@ -546,19 +932,16 @@ public: } // Split the arc into three x-monotone sub-curves. - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, cv.source(), - vtan_ps[ind_first], - conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, cv.source(), + vtan_ps[ind_first], + conic_id)); - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, - vtan_ps[ind_first], - vtan_ps[ind_second], - conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, vtan_ps[ind_first], + vtan_ps[ind_second], + conic_id)); - *oi++ = Make_x_monotone_result(X_monotone_curve_2(cv, - vtan_ps[ind_second], - cv.target(), - conic_id)); + *oi++ = Make_x_monotone_result(ctr_xcv(cv, vtan_ps[ind_second], + cv.target(), conic_id)); } } @@ -566,252 +949,1889 @@ public: } }; - /*! Get a Make_x_monotone_2 functor object. */ + /*! Obtain a Make_x_monotone_2 functor object. */ Make_x_monotone_2 make_x_monotone_2_object() const - { return Make_x_monotone_2(); } + { return Make_x_monotone_2(*this); } - class Split_2 - { - public: - /*! - * Split a given x-monotone curve at a given point into two sub-curves. - * \param cv The curve to split - * \param p The split point. - * \param c1 Output: The left resulting subcurve (p is its right endpoint). - * \param c2 Output: The right resulting subcurve (p is its left endpoint). - * \pre p lies on cv but is not one of its end-points. - */ - void operator() (const X_monotone_curve_2& cv, const Point_2 & p, - X_monotone_curve_2& c1, X_monotone_curve_2& c2) const - { - cv.split (p, c1, c2); - return; - } - }; - - /*! Get a Split_2 functor object. */ - Split_2 split_2_object () const - { - return Split_2(); - } - - class Intersect_2 { - private: - Intersection_map& _inter_map; // The map of intersection points. - - public: - /*! Constructor. */ - Intersect_2(Intersection_map& map) : _inter_map(map) {} - - /*! Find the intersections of the two given curves and insert them to the - * given output iterator. As two segments may itersect only once, only a - * single will be contained in the iterator. - * \param cv1 The first curve. - * \param cv2 The second curve. - * \param oi The output iterator. - * \return The past-the-end iterator. - */ - template - OutputIterator operator()(const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2, - OutputIterator oi) const - { return (cv1.intersect(cv2, _inter_map, oi)); } - }; - - /*! Get an Intersect_2 functor object. */ - Intersect_2 intersect_2_object () const { return (Intersect_2(inter_map)); } - - class Are_mergeable_2 - { - public: - /*! - * Check whether it is possible to merge two given x-monotone curves. - * \param cv1 The first curve. - * \param cv2 The second curve. - * \return (true) if the two curves are mergeable - if they are supported - * by the same line and share a common endpoint; (false) otherwise. - */ - bool operator() (const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2) const - { - return (cv1.can_merge_with (cv2)); - } - }; - - /*! Get an Are_mergeable_2 functor object. */ - Are_mergeable_2 are_mergeable_2_object () const - { - return Are_mergeable_2(); - } - - /*! \class Merge_2 - * A functor that merges two x-monotone arcs into one. - */ - class Merge_2 - { + class Split_2 { protected: - typedef Arr_conic_traits_2 Traits; + using Traits = Arr_conic_traits_2; /*! The traits (in case it has state) */ - const Traits* m_traits; + const Traits& m_traits; /*! Constructor - * \param traits the traits (in case it has state) + * \param traits The traits. */ - Merge_2(const Traits* traits) : m_traits(traits) {} + Split_2(const Traits& traits) : m_traits(traits) {} friend class Arr_conic_traits_2; public: - /*! - * Merge two given x-monotone curves into a single curve (segment). - * \param cv1 The first curve. - * \param cv2 The second curve. - * \param c Output: The merged curve. - * \pre The two curves are mergeable. + /*! Split a given \f$x\f$-monotone arc at a given point into two sub-arcs. + * \param xcv The arc to split + * \param p The split point. + * \param xcv1 Output: The left resulting sub-arc (`p` is its right endpoint). + * \param xcv2 Output: The right resulting sub-arc (`p` is its left endpoint). + * \pre `p` lies on `xcv` but is not one of its end-points. */ - void operator() (const X_monotone_curve_2& cv1, - const X_monotone_curve_2& cv2, - X_monotone_curve_2& c) const - { - CGAL_precondition(m_traits->are_mergeable_2_object()(cv2, cv1)); + void operator()(const X_monotone_curve_2& xcv, const Point_2 & p, + X_monotone_curve_2& xcv1, X_monotone_curve_2& xcv2) const + { split(xcv, p, xcv1, xcv2); } - c = cv1; - c.merge (cv2); + private: + /*! Split the arc into two at a given split point. + * \param p The split point. + * \param xcv1 Output: The first resulting arc, lying to the left of `p`. + * \param xcv2 Output: The first resulting arc, lying to the right of `p`. + * \pre `p` lies in the interior of the arc (not one of its endpoints). + */ + void split(const X_monotone_curve_2& xcv, const Point_2& p, + X_monotone_curve_2& xcv1, X_monotone_curve_2& xcv2) const { + // Make sure that p lies on the interior of the arc. + CGAL_precondition_code(auto eq = m_traits.m_alg_kernel->equal_2_object()); + CGAL_precondition(m_traits.contains_point(xcv, p) && + ! eq(p, xcv.source()) && ! eq(p, xcv.target())); + + // Make copies of the current arc. + xcv1 = xcv; + xcv2 = xcv; + + // Assign the endpoints of the arc. + if (xcv.test_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT)) { + // The arc is directed from left to right, so p becomes xcv1's target + // and xcv2's source. + xcv1.set_target(p); + xcv2.set_source(p); + + if (! p.is_generating_conic(xcv.id())) { + xcv1.target().set_generating_conic(xcv.id()); + xcv2.source().set_generating_conic(xcv.id()); + } + } + else { + // The arc is directed from right to left, so p becomes xcv2's target + // and xcv1's source. + xcv1.set_source(p); + xcv2.set_target(p); + + if (! p.is_generating_conic(xcv.id())) { + xcv1.source().set_generating_conic(xcv.id()); + xcv2.target().set_generating_conic(xcv.id()); + } + } + } + + }; + + /*! Obtain a Split_2 functor object. */ + Split_2 split_2_object() const { return Split_2(*this); } + + class Intersect_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor. + * \param traits The traits. + */ + Intersect_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Find the intersections of the two given curves and insert them to the + * given output iterator. As two segments may itersect only once, only a + * single will be contained in the iterator. + * \param cv1 The first arc. + * \param cv2 The second arc. + * \param oi The output iterator. + * \return The past-the-end iterator. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + OutputIterator oi) const + { return intersect(xcv1, xcv2, m_traits.m_inter_map, oi); } + + private: + /*! Compute the overlap with a given arc, which is supposed to have the same + * supporting conic curve as this arc. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \param overlap Output: The overlapping arc (if any). + * \return Whether we found an overlap. + */ + bool compute_overlap(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + X_monotone_curve_2& overlap) const { + // Check if the two arcs are identical. + if (m_traits.equal_2_object()(xcv1,xcv2)) { + overlap = xcv2; + return true; + } + + if (m_traits.is_strictly_between_endpoints(xcv1, xcv2.left())) { + if (m_traits.is_strictly_between_endpoints(xcv1, xcv2.right())) { + // Case 1 - *this: +-----------> + // arc: +=====> + overlap = xcv2; + return true; + } + else { + // Case 2 - *this: +-----------> + // arc: +=====> + overlap = xcv1; + + if (overlap.is_directed_right()) overlap.m_source = xcv2.left(); + else overlap.m_target = xcv2.left(); + + return true; + } + } + else if (m_traits.is_strictly_between_endpoints(xcv1, xcv2.right())) { + // Case 3 - *this: +-----------> + // arc: +=====> + overlap = xcv1; + if (overlap.is_directed_right()) overlap.m_target = xcv2.right(); + else overlap.m_source = xcv2.right(); + return true; + } + else if (m_traits.is_between_endpoints(xcv2, xcv1.source()) && + m_traits.is_between_endpoints(xcv2, xcv1.target()) && + (m_traits.is_strictly_between_endpoints(xcv2, xcv1.source()) || + m_traits.is_strictly_between_endpoints(xcv2, xcv1.target()))) + { + // Case 4 - *this: +-----------> + // arc: +================> + overlap = xcv1; + return true; + } + + // If we reached here, there are no overlaps: + return false; + } + + /*! Intersect the supporing conic curves of this arc and the given arc. + * \param arc The arc to intersect with. + * \param inter_list The list of intersection points. + */ + void intersect_supporting_conics(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + Intersection_list& inter_list) const { + if (xcv1.is_special_segment() && ! xcv2.is_special_segment()) { + // If one of the arcs is a special segment, make sure it is (arc). + intersect_supporting_conics(xcv2, xcv1, inter_list); + return; + } + + const int deg1 = + (xcv1.degree_mask() == X_monotone_curve_2::degree_1_mask()) ? 1 : 2; + const int deg2 = + (xcv2.degree_mask() == X_monotone_curve_2::degree_1_mask()) ? 1 : 2; + const auto nt_traits = m_traits.m_nt_traits; + Algebraic xs[4]; + int n_xs = 0; + Algebraic ys[4]; + int n_ys = 0; + + if (xcv2.is_special_segment()) { + // The second arc is a special segment (a*x + b*y + c = 0). + if (xcv1.is_special_segment()) { + // Both arc are sepcial segment, so they have at most one intersection + // point. + const auto* extra_data1 = xcv1.extra_data(); + const auto* extra_data2 = xcv2.extra_data(); + Algebraic denom = + extra_data1->a * extra_data2->b - extra_data1->b * extra_data2->a; + if (CGAL::sign (denom) != CGAL::ZERO) { + xs[0] = (extra_data1->b * extra_data2->c - + extra_data1->c * extra_data2->b) / denom; + n_xs = 1; + + ys[0] = (extra_data1->c * extra_data2->a - + extra_data1->a * extra_data2->c) / denom; + n_ys = 1; + } + } + else { + const auto* extra_data2 = xcv2.extra_data(); + + // Compute the x-coordinates of the intersection points. + n_xs = compute_resultant_roots(*nt_traits, + xcv1.alg_r(), xcv1.alg_s(), + xcv1.alg_t(), xcv1.alg_u(), + xcv1.alg_v(), xcv1.alg_w(), + deg1, + extra_data2->a, + extra_data2->b, + extra_data2->c, + xs); + CGAL_assertion(n_xs <= 2); + + // Compute the y-coordinates of the intersection points. + n_ys = compute_resultant_roots(*nt_traits, + xcv1.alg_s(), xcv1.alg_r(), + xcv1.alg_t(), xcv1.alg_v(), + xcv1.alg_u(), xcv1.alg_w(), + deg1, + extra_data2->b, + extra_data2->a, + extra_data2->c, + ys); + CGAL_assertion(n_ys <= 2); + } + } + else { + // Compute the x-coordinates of the intersection points. + n_xs = compute_resultant_roots(*nt_traits, + xcv1.r(), xcv1.s(), xcv1.t(), + xcv1.u(), xcv1.v(), xcv1.w(), + deg1, + xcv2.r(), xcv2.s(), xcv2.t(), + xcv2.u(), xcv2.v(), xcv2.w(), + deg2, + xs); + CGAL_assertion(n_xs <= 4); + + // Compute the y-coordinates of the intersection points. + n_ys = compute_resultant_roots(*nt_traits, + xcv1.s(), xcv1.r(), xcv1.t(), + xcv1.v(), xcv1.u(), xcv1.w(), + deg1, + xcv2.s(), xcv2.r(), xcv2.t(), + xcv2.v(), xcv2.u(), xcv2.w(), + deg2, + ys); + CGAL_assertion(n_ys <= 4); + } + + // Pair the coordinates of the intersection points. As the vectors of + // x and y-coordinates are sorted in ascending order, we output the + // intersection points in lexicographically ascending order. + Multiplicity mult; + int i, j; + + if (xcv2.is_special_segment()) { + if ((n_xs == 0) || (n_ys == 0)) return; + + if ((n_xs == 1) && (n_ys == 1)) { + // Single intersection. + Point_2 ip(xs[0], ys[0]); + ip.set_generating_conic(xcv1.id()); + ip.set_generating_conic(xcv2.id()); + + // In case the other curve is of degree 2, this is a tangency point. + mult = ((deg1 == 1) || xcv1.is_special_segment()) ? 1 : 2; + inter_list.push_back(Intersection_point(ip, mult)); + } + else if ((n_xs == 1) && (n_ys == 2)) { + Point_2 ip1(xs[0], ys[0]); + ip1.set_generating_conic(xcv1.id()); + ip1.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip1, 1)); + + Point_2 ip2(xs[0], ys[1]); + ip2.set_generating_conic(xcv1.id()); + ip2.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip2, 1)); + } + else if ((n_xs == 2) && (n_ys == 1)) { + Point_2 ip1(xs[0], ys[0]); + ip1.set_generating_conic(xcv1.id()); + ip1.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip1, 1)); + + Point_2 ip2(xs[1], ys[0]); + ip2.set_generating_conic(xcv1.id()); + ip2.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip2, 1)); + } + else { + CGAL_assertion((n_xs == 2) && (n_ys == 2)); + + // The x-coordinates and the y-coordinates are given in ascending + // order. If the slope of the segment is positive, we pair the + // coordinates as is - otherwise, we swap the pairs. + int ind_first_y(0), ind_second_y(1); + + const auto* extra_data2 = xcv2.extra_data(); + if (CGAL::sign(extra_data2->b) == CGAL::sign(extra_data2->a)) { + ind_first_y = 1; + ind_second_y = 0; + } + + Point_2 ip1(xs[0], ys[ind_first_y]); + ip1.set_generating_conic(xcv1.id()); + ip1.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip1, 1)); + + Point_2 ip2(xs[1], ys[ind_second_y]); + ip2.set_generating_conic(xcv1.id()); + ip2.set_generating_conic(xcv2.id()); + + inter_list.push_back(Intersection_point(ip2, 1)); + } + + return; + } + + for (i = 0; i < n_xs; ++i) { + for (j = 0; j < n_ys; ++j) { + if (xcv1.is_on_supporting_conic(xs[i], ys[j]) && + xcv2.is_on_supporting_conic(xs[i], ys[j])) + { + // Create the intersection point and set its generating conics. + Point_2 ip(xs[i], ys[j]); + + ip.set_generating_conic(xcv1.id()); + ip.set_generating_conic(xcv2.id()); + + // Compute the multiplicity of the intersection point. + if (deg1 == 1 && deg2 == 1) mult = 1; + else mult = xcv1.multiplicity_of_intersection_point(xcv2, ip); + + // Insert the intersection point to the output list. + inter_list.push_back(Intersection_point(ip, mult)); + } + } + } + } + + /*! Compute the intersections with the given arc. + * \param arc The given intersecting arc. + * \param inter_map Maps conic pairs to lists of their intersection points. + * \param oi The output iterator. + * \return The past-the-end iterator. + */ + template + OutputIterator intersect(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + Intersection_map& inter_map, + OutputIterator oi) const { + typedef boost::variant + Intersection_result; + + if (m_traits.has_same_supporting_conic(xcv1, xcv2)) { + // Check for overlaps between the two arcs. + X_monotone_curve_2 overlap; + + if (compute_overlap(xcv1, xcv2, overlap)) { + // There can be just a single overlap between two x-monotone arcs: + *oi++ = Intersection_result(overlap); + return oi; + } + + // In case there is not overlap and the supporting conics are the same, + // there cannot be any intersection points, unless the two arcs share + // an end point. + // Note that in this case we do not define the multiplicity of the + // intersection points we report. + auto alg_kernel = m_traits.m_alg_kernel; + auto eq = alg_kernel->equal_2_object(); + if (eq(xcv1.left(), xcv2.left())) { + Intersection_point ip(xcv1.left(), 0); + *oi++ = Intersection_result(ip); + } + + if (eq(xcv1.right(), xcv2.right())) { + Intersection_point ip(xcv1.right(), 0); + *oi++ = Intersection_result(ip); + } + + if (eq(xcv1.left(), xcv2.right())) { + Intersection_point ip(xcv1.left(), 0); + *oi++ = Intersection_result(ip); + } + + if (eq(xcv1.right(), xcv2.left())) { + Intersection_point ip(xcv1.right(), 0); + *oi++ = Intersection_result(ip); + } + + return oi; + } + + // Search for the pair of supporting conics in the map (the first conic + // ID in the pair should be smaller than the second one, to guarantee + // uniqueness). + Conic_pair conic_pair; + Intersection_map_iterator map_iter; + Intersection_list inter_list; + bool invalid_ids = false; + + if (xcv1.id().is_valid() && xcv2.id().is_valid()) { + if (xcv1.id() < xcv2.id()) conic_pair = Conic_pair(xcv1.id(), xcv2.id()); + else conic_pair = Conic_pair(xcv2.id(), xcv1.id()); + map_iter = inter_map.find(conic_pair); + } + else { + // In case one of the IDs is invalid, we do not look in the map neither + // we cache the results. + map_iter = inter_map.end(); + invalid_ids = true; + } + + if (map_iter == inter_map.end()) { + // In case the intersection points between the supporting conics have + // not been computed before, compute them now and store them in the map. + intersect_supporting_conics(xcv1, xcv2, inter_list); + if (! invalid_ids) inter_map[conic_pair] = inter_list; + } + else { + // Obtain the precomputed intersection points from the map. + inter_list = (*map_iter).second; + } + + // Go over the list of intersection points and report those that lie on + // both x-monotone arcs. + for (auto iter = inter_list.begin(); iter != inter_list.end(); ++iter) { + if (m_traits.is_between_endpoints(xcv1, (*iter).first) && + m_traits.is_between_endpoints(xcv2, (*iter).first)) + { + *oi++ = Intersection_result(*iter); + } + } + + return oi; + } + }; + + /*! Obtain an Intersect_2 functor object. */ + Intersect_2 intersect_2_object() const { return Intersect_2(*this); } + + class Are_mergeable_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits (in case it has state) + */ + Are_mergeable_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Check whether it is possible to merge two given x-monotone curves. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \return `true` if the two curves are mergeable; that is, they are + * supported by the same curve and share a common endpoint); + * `false` otherwise. + */ + bool operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2) const + { return can_merge_with(xcv1, xcv2); } + + private: + /*! Check whether it is possible to merge the arc with the given arc. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \return `true` if it is possible to merge the two arcs; + * `false` otherwise. + */ + bool can_merge_with(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2) const { + // In order to merge the two arcs, they should have the same supporting + // conic. + if (! m_traits.has_same_supporting_conic(xcv1, xcv2)) return false; + + // Check if the left endpoint of one curve is the right endpoint of the + // other. + auto eq = m_traits.m_alg_kernel->equal_2_object(); + return (eq(xcv1.right(), xcv2.left()) || eq(xcv1.left(), xcv2.right())); + } + }; + + /*! Obtain an Are_mergeable_2 functor object. */ + Are_mergeable_2 are_mergeable_2_object() const + { return Are_mergeable_2(*this); } + + /*! \class Merge_2 + * A functor that merges two x-monotone arcs into one. + */ + class Merge_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits (in case it has state) + */ + Merge_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Merge two given x-monotone curves into a single curve (segment). + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \param xcv The merged arc. + * \pre The two arcs are mergeable. + */ + void operator()(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2, + X_monotone_curve_2& xcv) const + { + CGAL_precondition(m_traits.are_mergeable_2_object()(xcv2, xcv1)); + xcv = xcv1; + merge(xcv, xcv2); + } + + private: + /*! Merge the current arc with the given arc. + * \param xcv1 The first arc to merge with. + * \param xcv2 The second arc to merge with. + * \pre The two arcs are mergeable. + */ + void merge(X_monotone_curve_2& xcv1, const X_monotone_curve_2& xcv2) const { + // Check whether we should extend the arc to the left or to the right. + auto eq = m_traits.m_alg_kernel->equal_2_object(); + if (eq(xcv1.right(), xcv2.left())) { + // Extend the arc to the right. + if (xcv1.test_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT)) + xcv1.set_target(xcv2.right()); + else xcv1.set_source(xcv2.right()); + } + else { + CGAL_precondition(eq(xcv1.left(), xcv2.right())); + + // Extend the arc to the left. + if (xcv1.test_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT)) + xcv1.set_source(xcv2.left()); + else xcv1.set_target(xcv2.left()); + } } }; /*! Obtain a Merge_2 functor object. */ - Merge_2 merge_2_object() const - { - return Merge_2(this); - } + Merge_2 merge_2_object() const { return Merge_2(*this); } //@} - /// \name Functor definitions for the landmarks point-location strategy. + /*! \name Auxiliary Functor definitions, used gor, e.g., the landmarks + * point-location strategy and the drawing function. + */ //@{ - typedef double Approximate_number_type; + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; + + class Approximate_curve_length_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_curve_length_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; - class Approximate_2 - { public: + /*! Obtain an approximation of the length of a curve. + * \param xcv The curve. + * \return An approximation of the length of `xcv`. + */ + Approximate_number_type operator()(const X_monotone_curve_2& xcv) const { + if (xcv.orientation() == COLLINEAR) return segment_length(xcv); + CGAL::Sign sign_conic = CGAL::sign(4*xcv.r()*xcv.s() - xcv.t()*xcv.t()); + if (sign_conic == POSITIVE) return ellipse_length(xcv); + if (sign_conic == NEGATIVE) return hyperbola_length(xcv); + return parabola_length(xcv); + } - /*! - * Return an approximation of a point coordinate. + private: + /*! Obtain the segment length. + */ + double segment_length(const X_monotone_curve_2& xcv) { + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& minv = min_vertex(xcv); + const auto& maxv = max_vertex(xcv); + auto x1 = CGAL::to_double(minv.x()); + auto y1 = CGAL::to_double(minv.y()); + auto x2 = CGAL::to_double(maxv.x()); + auto y2 = CGAL::to_double(maxv.y()); + auto dx = x2 - x1; + auto dy = y2 - y1; + double l = std::sqrt(x2*x2 + y2*y2); + return l; + } + + /*! The formula for the arc length of a parabola is: + * L = 1/2 * √(b^2+16⋅a^2) + b^2/(8*a) * ln((4*a+√(b^2+16⋅a^2))/b) + * where: + * L is the length of the parabola arc. + * a is the length along the parabola axis. + * b is the length of the chord perpendicular to the axis. + * + * --- + * / | \ + * / |a \ + * / | \ + * /---------\ + * / b \ + * + */ + double parabolic_arc_length(double a, double b) const { + if (a == 0) return b; + if (b == 0) return a; + auto b_sqr = b*b; + auto tmp = std::sqrt(b_sqr+16.0*a*a); + return tmp/2.0 + b_sqr*std::log((4.0*a + tmp)/b)/(8.0*a); + } + + /*! Obtain the parabolic arc length. + */ + double parabola_length(const X_monotone_curve_2& xcv) { + double r_m, t_m, s_m, u_m, v_m, w_m; + double cost, sint; + double xs_t, ys_t, xt_t, yt_t; + double a; + double ts, tt; + double cx, cy; + m_traits.approximate_parabola(xcv, + r_m, t_m, s_m, u_m, v_m, w_m, cost, sint, + xs_t, ys_t, xt_t, yt_t, a, ts, tt, cx, cy); + + auto ds = parabolic_arc_length(xs_t, 2.0*std::abs(ys_t)); + auto dt = parabolic_arc_length(xt_t, 2.0*std::abs(yt_t)); + auto d = (CGAL::sign(ys_t) == CGAL::sign(yt_t)) ? + std::abs(ds - dt)/2.0 : (ds + dt)/2.0; + // std::cout << "d, ds, dt = " << d << ", " << ds << "," << dt + // << std::endl; + return d; + } + + double ellipse_length(const X_monotone_curve_2& xcv) { + double r_m, t_m, s_m, u_m, v_m, w_m; + double cost, sint; + double xs_t, ys_t, xt_t, yt_t; + double a, b; + double cx, cy; + double ts, tt; + m_traits.approximate_ellipse(xcv, r_m, t_m, s_m, u_m, v_m, w_m, cost, sint, + xs_t, ys_t, ts, xt_t, yt_t, tt, + a, b, cx, cy); + + namespace bm = boost::math; + auto ratio = b/a; + auto k = std::sqrt(1 - (ratio*ratio)); + auto ds = a*bm::ellint_2(k, ts); + auto dt = a*bm::ellint_2(k, tt); + auto d = std::abs(dt - ds); + // std::cout << "d,ds,dt: " << d << "," << ds << ", " << dt << std::endl; + return d; + } + + double hyperbola_length(const X_monotone_curve_2& /* xcv */) { + CGAL_error_msg("Not implemented yet!"); + double l(0.0); + return l; + } + }; + + class Approximate_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Obtain an approximation of a point coordinate. * \param p The exact point. * \param i The coordinate index (either 0 or 1). * \pre i is either 0 or 1. * \return An approximation of p's x-coordinate (if i == 0), or an * approximation of p's y-coordinate (if i == 1). */ - Approximate_number_type operator() (const Point_2& p, - int i) const - { - CGAL_precondition (i == 0 || i == 1); + Approximate_number_type operator()(const Point_2& p, int i) const { + CGAL_precondition((i == 0) || (i == 1)); - if (i == 0) - return (CGAL::to_double(p.x())); - else - return (CGAL::to_double(p.y())); + if (i == 0) return CGAL::to_double(p.x()); + else return CGAL::to_double(p.y()); + } + + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2& p) const + { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv, double error, + OutputIterator oi, bool l2r = true) const { + if (xcv.orientation() == COLLINEAR) + return approximate_segment(xcv, oi, l2r); + CGAL::Sign sign_conic = CGAL::sign(4*xcv.r()*xcv.s() - xcv.t()*xcv.t()); + if (sign_conic == POSITIVE) + return approximate_ellipse(xcv, error, oi, l2r); + if (sign_conic == NEGATIVE) + return approximate_hyperbola(xcv, error, oi, l2r); + return approximate_parabola(xcv, error, oi, l2r); + } + + private: + /*! Handle segments. + */ + template + OutputIterator approximate_segment(const X_monotone_curve_2& xcv, + OutputIterator oi, bool l2r) const { + // std::cout << "SEGMENT\n"; + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + *oi++ = Approximate_point_2(xs, ys); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + + /*! Transform a point. In particular, rotate the canonical point + * (`xc`,`yc`) by an angle, the sine and cosine of which are `sint` and + * `cost`, respectively, and translate by (`cx`,`cy`). + */ + void transform_point(double xc, double yc, + double cost, double sint, + double cx, double cy, + double& x, double& y) const { + x = xc*cost - yc*sint + cx; + y = xc*sint + yc*cost + cy; + } + + /*! Handle ellipses. + * The general equation of an ellipse is: + * r·𝑥^2 + s·𝑦^2 + t·𝑥·𝑦 + u·𝑥 + v·𝑦 + w = 0 + * where 4·r·s−t^2 > 0 + * We eliminate t so that the x·y term vanishes, applying an inverse + * rotation. Then, we compute the radi and the center. Finaly, we rotate + * back. The angle of rotation is given by: + * 𝑡𝑎𝑛(2𝜃) = 𝐵 / (𝐴−𝐶) + * Then + * 𝑐𝑜𝑠(2𝜃) = sqrt((1 + 𝑐𝑜𝑠(2𝜃))/2) + * 𝑠𝑖𝑛(2𝜃) = sqrt((1 - 𝑐𝑜𝑠(2𝜃))/2) + * The coefficients of the new ellipse are given by: + * r′ = r·𝑐𝑜𝑠(𝜃)^2 + s·𝑠𝑖𝑛(𝜃)^2 + t·𝑐𝑜𝑠(𝜃)·𝑠𝑖𝑛(𝜃) + * s′ = r·𝑠𝑖𝑛(𝜃)^2 + s·𝑐𝑜𝑠(𝜃)^2 − t·𝑐𝑜𝑠(𝜃)·𝑠𝑖𝑛(𝜃) + * t′ = 0 + * u′ = u·𝑐𝑜𝑠(𝜃) + v·𝑠𝑖𝑛(𝜃) + * v′ = −u·𝑠𝑖𝑛(𝜃) + v·𝑐𝑜𝑠(𝜃) + * w′ = w + * After writing this equation in the form: + * (𝑥′ − 𝐶𝑥′)^2 (𝑦′ − 𝐶𝑦′)^2 + * ----------- + ------------ = 1 + * 𝑎^2 𝑏^2 + * We get: + * -u′ + * 𝐶𝑥′ = ---- + * 2·r′ + * + * -v′ + * 𝐶𝑦′ = ---- + * 2·s′ + * + * −4·w′·r′·s′ + s′·u′2 + r′·v′2 + * a^2 = ---------------------------- + * 4·r′^2·s′ + * + * −4·w′·r′·s′ + s′·u′2 + r′·v′2 + * b^2 = ---------------------------- + * 4·r′·s′^2 + * + * Rotate back about angle 𝜃 to find the coordinates of the center: + * 𝐶𝑥 = 𝐶𝑥′·𝑐𝑜𝑠𝜃 − 𝐶𝑦′·𝑠𝑖𝑛𝜃 + * 𝐶𝑦 = 𝐶𝑥′·𝑠𝑖𝑛𝜃 + 𝐶𝑦′·𝑐𝑜𝑠𝜃 + * + * The parametric formula of an ellipse centered at the origin with major + * axis parallel to the x-axis and minor axis parallel to the y-axis is: + * 𝑥(𝛼) = a·𝑐𝑜𝑠(𝛼) + * 𝑦(𝛼) = b·𝑠𝑖𝑛(𝛼) + * where a is the major radius and b is the minor radius. + * + * The rotation transformation is fiven by + * 𝑥 = 𝑥(𝑡)·𝑐𝑜𝑠(𝜃) − 𝑦(𝑡)·𝑠𝑖𝑛(𝜃) + * 𝑦 = 𝑥(𝑡)·𝑠𝑖𝑛(𝜃) + 𝑦(𝑡)·𝑐𝑜𝑠(𝜃) + * Where 𝜃 is the rotation angle + * + * Combining the above we get + * 𝑥(𝛼) = a·𝑐𝑜𝑠(𝛼)·𝑐𝑜𝑠(𝜃) − b·𝑠𝑖𝑛(𝛼)·𝑠𝑖𝑛(𝜃) + * 𝑦(𝛼) = a·𝑐𝑜𝑠(𝛼)·𝑠𝑖𝑛(𝜃) + b·𝑠𝑖𝑛(𝛼)·𝑐𝑜𝑠(𝜃) + * + * To shift from the center we add 𝐶𝑥 to the 𝑥(𝛼) and 𝐶𝑦 to 𝑦(𝛼). + * Therefore, the equations of a Rotated Ellipse are: + * 𝑥(𝛼) = a·𝑐𝑜𝑠(𝛼)·𝑐𝑜𝑠(𝜃) − b·𝑠𝑖𝑛(𝛼)·𝑠𝑖𝑛(𝜃) + 𝐶𝑥 + * 𝑦(𝛼) = a·𝑐𝑜𝑠(𝛼)·𝑠𝑖𝑛(𝜃) + b·𝑠𝑖𝑛(𝛼)·𝑐𝑜𝑠(𝜃) + 𝐶𝑦 + * + * @param error the error bound of the generated approximation. This is + * the Hausdorff distance between the arc and the polyline, + * which approximates the arc. + */ + template + OutputIterator approximate_ellipse(const X_monotone_curve_2& xcv, + double error, OutputIterator oi, + bool l2r = true) const { + // std::cout << "ELLIPSE\n"; + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + // std::cout << "curve: (" << xs << "," << ys + // << ") => (" << xt << "," << yt << ")" + // << std::endl; + + double r_m, t_m, s_m, u_m, v_m, w_m; + double cost, sint; + double xs_t, ys_t, xt_t, yt_t; + double a, b; + double cx, cy; + double ts, tt; + m_traits.approximate_ellipse(xcv, r_m, t_m, s_m, u_m, v_m, w_m, cost, sint, + xs_t, ys_t, ts, xt_t, yt_t, tt, + a, b, cx, cy, l2r); + // std::cout << "a, b: " << a << "," << b << std::endl; + + *oi++ = Approximate_point_2(xs, ys); + add_points(xs_t, ys_t, ts, xt_t, yt_t, tt, error, oi, + [&](double tm, double& xm, double& ym) { + elliptic_point(a, b, tm, xm, ym); + }, + [&](double xc, double& yc, double& x, double& y) { + transform_point(xc, yc, cost, sint, cx, cy, x, y); + }); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + + /*! Add either an elliptic or a hyperbilc point. + * The arc endpoints are (`x1`, `y1`) and (`x2`, `y2`). + * In our parametric representations for ellipses and hyperbolas the + * following holds: + * p1 = (x1, y1); x1 = x(t1), y1 = y(t1), and + * p2 = (x2, y2); x2 = x(t2), y2 = y(t2) + * The Hausdorff distance between the arc and the segment (p1,p2) is + * at (xm,ym), where xm = x(tm), ym = y(tmp), and tm = (t1 + t2) / 2. + * \param[in] x1 the canonical-arc source-point \f$x\f$-coordinate. + * \param[in] y1 the canonical-arc source-point \f$y\f$-coordinate. + * \param[in] t1 the source-point parameter; \f$yx1 = x(t1) and y1 = y(t1)\f$y. + * \param[in] x2 the canonical-arc target-point \f$x\f$-coordinate. + * \param[in] y2 the canonical arc target-point \f$y\f$-coordinate. + * \param[in] t2 the target-point parameter; \f$yx2 = x(t2) and y2 = y(t2)\f$y. + * \param[in] error + * \param[out] oi + * \param[in] op a function that computes a point \f$(x(t),y(t))\f$ given \f$t\f$. + * \param[in] transform a function that transforms a canonical point to an + * actual point + * + * Observe that in our parametric representation for parabolas, the + * expression for tm is different. + */ + template + OutputIterator add_points(double x1, double y1, double t1, + double x2, double y2, double t2, + double error, OutputIterator oi, + Op op, Transform transform) const { + auto tm = (t1 + t2)*0.5; + + // Compute the canocal point where the error is maximal. + double xm, ym; + op(tm, xm, ym); + + auto dx = x2 - x1; + auto dy = y2 - y1; + + // Compute the error; abort if it is below the threshold + auto l = std::sqrt(dx*dx + dy*dy); + auto e = std::abs((xm*dy - ym*dx + x2*y1 - x1*y2) / l); + if (e < error) return oi; + + double x, y; + transform(xm, ym, x, y); + add_points(x1, y1, t1, xm, ym, tm, error, oi, op, transform); + *oi++ = Approximate_point_2(x, y); + add_points(xm, ym, tm, x2, y2, t2, error, oi, op, transform); + return oi; + } + + /*! Compute the elliptic point given the parameter t and the transform + * data, that is, the center (translation) and the sin and cos of the + * rotation angle. + */ + void elliptic_point(double a, double b, double t, + double& x, double& y) const { + x = a * std::cos(t); + y = b * std::sin(t); + } + + /*! Handle parabolas. + * The arc-length closed form can be found here: + * https://www.vcalc.com/wiki/vCalc/Parabola+-+arc+length + */ + template + OutputIterator approximate_parabola(const X_monotone_curve_2& xcv, + double error, OutputIterator oi, + bool l2r = true) + const { + // std::cout << "PARABOLA\n"; + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + // std::cout << "curve: (" << xs << "," << ys + // << ") => (" << xt << "," << yt << ")" + // << std::endl; + + double r_m, t_m, s_m, u_m, v_m, w_m; + double cost, sint; + double xs_t, ys_t, xt_t, yt_t; + double a; + double ts, tt; + double cx, cy; + m_traits.approximate_parabola(xcv, + r_m, t_m, s_m, u_m, v_m, w_m, cost, sint, + xs_t, ys_t, xt_t, yt_t, a, ts, tt, cx, cy, + l2r); + // std::cout << "sint, cost: " << sint << "," << cost << std::endl; + // std::cout << "a: " << a << std::endl; + // std::cout << "xs' = " << xs_t << "," << ys_t << std::endl; + // std::cout << "xt' = " << xt_t << "," << yt_t << std::endl; + // std::cout << "ts,tt = " << ts << "," << tt << std::endl; + + *oi++ = Approximate_point_2(xs, ys); + add_parabolic_points(xs_t, ys_t, ts, xt_t, yt_t, tt, error, oi, + [&](double tm, double& xm, double& ym) { + parabolic_point(a, tm, xm, ym); + }, + [&](double xc, double& yc, double& x, double& y) { + transform_point(xc, yc, cost, sint, cx, cy, x, y); + }); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + + /*! Add either an elliptic or a hyperbilc point. + * The arc endpoints are (`x1`, `y1`) and (`x2`, `y2`). + * In our parametric representations for ellipses and hyperbolas the + * following holds: + * \f$p1 = (x1, y1); x1 = x(t1), y1 = y(t1)\f$, and + * \f$p2 = (x2, y2); x2 = x(t2), y2 = y(t2)\f$ + * The Hausdorff distance between the arc and the segment (p1,p2) is + * at (xm,ym), where xm = x(tm), ym = y(tmp), and tm = (x2-x1) / (y2-y1). + * \param[in] x1 the canonical-arc source-point \f$x\f$-coordinate. + * \param[in] y1 the canonical-arc source-point \f$y\f$-coordinate. + * \param[in] t1 the source-point parameter; \f$yx1 = x(t1) and y1 = y(t1)\f$y. + * \param[in] x2 the canonical-arc target-point \f$x\f$-coordinate. + * \param[in] y2 the canonical arc target-point \f$y\f$-coordinate. + * \param[in] t2 the target-point parameter; \f$yx2 = x(t2) and y2 = y(t2)\f$y. + * \param[in] error + * \param[out] oi + * \param[in] op a function that computes a point \f$(x(t),y(t))\f$ given \f$t\f$. + * \param[in] transform a function that transforms a canonical point to an + * actual point + * + * Observe that in our parametric representation for ellipses and + * hyperbolas, the expression for tm is different. + */ + template + OutputIterator add_parabolic_points(double x1, double y1, double t1, + double x2, double y2, double t2, + double error, OutputIterator oi, + Op op, Transform transform) const { + auto dx = x2 - x1; + auto dy = y2 - y1; + auto tm = (dy == 0) ? 0 : dx / dy; + + // Compute the canocal point where the error is maximal. + double xm, ym; + op(tm, xm, ym); + + // Compute the error and abort if it is below the threshold + auto l = std::sqrt(dx*dx + dy*dy); + auto e = std::abs((xm*dy - ym*dx + x2*y1 - x1*y2) / l); + if (e < error) return oi; + + // Compute the actual (transformed) point + double x, y; + transform(xm, ym, x, y); + add_parabolic_points(x1, y1, t1, xm, ym, tm, error, oi, op, transform); + *oi++ = Approximate_point_2(x, y); + add_parabolic_points(xm, ym, tm, x2, y2, t2, error, oi, op, transform); + return oi; + } + + /*! Compute the parabolic point given the parameter t and the transform + * data, that is, the center (translation) and the sin and cos of the + * rotation angle. + */ + void parabolic_point(double a, double t, double& x, double& y) const { + x = a*t*t; + y = 2.0*a*t; + } + + /*! Handle hyperbolas. + */ + template + OutputIterator approximate_hyperbola(const X_monotone_curve_2& xcv, + double error, OutputIterator oi, + bool l2r = true) const { + // std::cout << "HYPERBOLA\n"; + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + + double r_m, t_m, s_m, u_m, v_m, w_m; + double cost, sint; + double xs_t, ys_t, xt_t, yt_t; + double a, b; + double cx, cy; + double ts, tt; + m_traits.approximate_hyperbola(xcv, r_m, t_m, s_m, u_m, v_m, w_m, + cost, sint, + xs_t, ys_t, ts, xt_t, yt_t, tt, + a, b, cx, cy, l2r); + // std::cout << "a, b: " << a << "," << b << std::endl; + // std::cout << "ts, tt: " << ts << "," << tt << std::endl; + + // std::cout << "a, b: " << a << "," << b << std::endl; + *oi++ = Approximate_point_2(xs, ys); + add_points(xs_t, ys_t, ts, xt_t, yt_t, tt, error, oi, + [&](double tm, double& xm, double& ym) { + hyperbolic_point(a, b, tm, xm, ym); + }, + [&](double xc, double& yc, double& x, double& y) { + transform_point(xc, yc, cost, sint, cx, cy, x, y); + }); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } + + /*! Compute the hyperbolic point given the parameter t and the transform + * data, that is, the center (translation) and the sin and cos of the + * rotation angle. + */ + void hyperbolic_point(double a, double b, double t, + double& x, double& y) const { + x = a * std::cosh(t); + y = b * std::sinh(t); } }; - /*! Get an Approximate_2 functor object. */ - Approximate_2 approximate_2_object () const - { - return Approximate_2(); - } + /*! Obtain an Approximate_2 functor object. */ + Approximate_2 approximate_2_object() const { return Approximate_2(*this); } //! Functor class Construct_x_monotone_curve_2 { - public: - /*! Return an x-monotone curve connecting the two given endpoints. - * \param p The first point. - * \param q The second point. - * \pre p and q must not be the same. - * \return A segment connecting p and q. + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. */ - X_monotone_curve_2 operator()(const Point_2& p, const Point_2& q) const - { return (X_monotone_curve_2(p, q)); } + Construct_x_monotone_curve_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Construct an \f$x\f$-monotone arc from a conic arc. + * \param cv The given curve. + * \pre cv is \f$x\f$-monotone. + */ + X_monotone_curve_2 operator()(const Curve_2& cv) const { + CGAL_precondition(cv.is_valid() && is_x_monotone(cv)); + X_monotone_curve_2 xcv(cv); + m_traits.set_x_monotone(xcv); + return xcv; + } + + /*! Construct an \f$x\f$-monotone arc from a conic arc. + * \param xcv The given curve. + * \param id The ID of the base curve. + */ + X_monotone_curve_2 operator()(const Curve_2& cv, const Conic_id& id) const { + X_monotone_curve_2 xcv(cv, id); + CGAL_precondition(xcv.is_valid() && id.is_valid()); + m_traits.set_x_monotone(xcv); + return xcv; + } + + /*! Construct an \f$x\f$-monotone sub-arc from a conic arc. + * \param cv The given (base) arc. + * \param source The source point. + * \param target The target point. + * \param id The id of the base arc. + */ + X_monotone_curve_2 operator()(const Curve_2& cv, + const Point_2& source, const Point_2& target, + const Conic_id& id) const + { + // Set the two endpoints. + X_monotone_curve_2 xcv(cv, id); + xcv.set_source(source); + xcv.set_target(target); + CGAL_precondition(xcv.is_valid() && id.is_valid()); + m_traits.set_x_monotone(xcv); + return xcv; + } + + /*! Return an \f$x\f$-monotone curve connecting the two given endpoints. + * \param source The first point. + * \param target The second point. + * \pre `source` and `target` must not be the same. + * \return A segment connecting `source` and `target`. + */ + X_monotone_curve_2 operator()(const Point_2& source, const Point_2& target) + const + { + X_monotone_curve_2 xcv; + + // Set the basic properties. + xcv.set_endpoints(source, target); + xcv.set_orientation(COLLINEAR); + xcv.set_flag(Curve_2::IS_VALID); + + // Set the other properties. + xcv.set_flag(X_monotone_curve_2::DEGREE_1); + xcv.set_flag(X_monotone_curve_2::IS_SPECIAL_SEGMENT); + xcv.update_extra_data(); + + auto cmp_xy = m_traits.m_alg_kernel->compare_xy_2_object(); + Comparison_result res = cmp_xy(source, target); + CGAL_precondition(res != EQUAL); + if (res == SMALLER) xcv.set_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT); + + // Check whether the segment is vertical. + if (CGAL::sign(xcv.extra_data()->b) == ZERO) + xcv.set_flag(X_monotone_curve_2::IS_VERTICAL_SEGMENT); + + return xcv; + } + + /*! Construct a special segment of a given line connecting to given + * endpoints. + * \param a, b, c The coefficients of the supporting line (`ax + by + c = 0`). + * \param source The source point. + * \param target The target point. + */ + X_monotone_curve_2 operator()(const Algebraic& a, const Algebraic& b, + const Algebraic& c, + const Point_2& source, const Point_2& target) + const + { + auto cmp_xy = m_traits.m_alg_kernel->compare_xy_2_object(); + Comparison_result res = cmp_xy(source, target); + CGAL_precondition(res != EQUAL); + + X_monotone_curve_2 xcv; + // Make sure the two endpoints lie on the supporting line. + CGAL_precondition(CGAL::sign(a*source.x()+b*source.y()+c) == CGAL::ZERO); + CGAL_precondition(CGAL::sign(a*target.x()+b*target.y()+c) == CGAL::ZERO); + + // Set the basic properties. + xcv.set_endpoints(source, target); + xcv.set_orientation(COLLINEAR); + xcv.set_flag(Curve_2::IS_VALID); + + // Set the other properties. + if (res == SMALLER) xcv.set_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT); + + xcv.set_flag(X_monotone_curve_2::DEGREE_1); + xcv.set_flag(X_monotone_curve_2::IS_SPECIAL_SEGMENT); + xcv.set_extra_data(a, b, c, ZERO); + + // Check whether the segment is vertical. + if (CGAL::sign(xcv.extra_data()->b) == ZERO) + xcv.set_flag(X_monotone_curve_2::IS_VERTICAL_SEGMENT); + + return xcv; + } + + private: + /*! Determine whether the arc is \f$x\f$-monotone. + */ + bool is_x_monotone(const Curve_2& cv) const { + // Collect vertical tangency points. + Alg_point_2 vtan_ps[2]; + auto res = m_traits.vertical_tangency_points(cv, vtan_ps); + return (res == 0); + } + + /*! Determine whether the arc is \f$y\f$-monotone. + */ + bool is_y_monotone(const Curve_2& cv) const { + // Collect horizontal tangency points. + Alg_point_2 htan_ps[2]; + auto res = m_traits.horizontal_tangency_points(cv, htan_ps); + return (res == 0); + } + }; - /*! Get a Construct_x_monotone_curve_2 functor object. */ + /*! Obtain a Construct_x_monotone_curve_2 functor object. */ Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object () const - { return Construct_x_monotone_curve_2(); } + { return Construct_x_monotone_curve_2(*this); } - //! Functor + //! Constructor of conic arcs class Construct_curve_2 { - public: - /*! Return a curve connecting the two given endpoints. - * \param p The first point. - * \param q The second point. - * \pre p and q must not be the same. - * \return A segment connecting p and q. + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. */ - Curve_2 operator()(const Point_2& p, const Point_2& q) const - { return (Curve_2(p, q)); } + Construct_curve_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Construct an empty curve. + */ + Curve_2 operator()() const { return Curve_2(); } + + /*! Construct a conic arc which is the full conic: + * `C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0` + * \pre The conic C must be an ellipse (so `4rs - t^2 > 0`). + */ + Curve_2 operator()(const Rational& r, const Rational& s, const Rational& t, + const Rational& u, const Rational& v, const Rational& w) + const + { + // Ensure that the given curve is an ellipse (4rs - t^2 is positive). + CGAL_precondition(CGAL::sign(4*r*s - t*t) == POSITIVE); + + // Set the arc to be the full conic (and compute the orientation). + Rational rat_coeffs[6]; + rat_coeffs[0] = r; + rat_coeffs[1] = s; + rat_coeffs[2] = t; + rat_coeffs[3] = u; + rat_coeffs[4] = v; + rat_coeffs[5] = w; + Curve_2 arc; + m_traits.set_full(arc, rat_coeffs, true); + return arc; + } + + /*! Construct a conic arc that lies on the conic: + * `C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0` + * \param orient The orientation of the arc (clockwise or counterclockwise). + * \param source The source point. + * \param target The target point. + * \pre The source and the target must be on the conic boundary and must + * not be the same. + */ + Curve_2 operator()(const Rational& r, const Rational& s, const Rational& t, + const Rational& u, const Rational& v, const Rational& w, + const Orientation& orient, + const Point_2& source, const Point_2& target) const { + // Make sure that the source and the taget are not the same. + const auto alg_kernel = m_traits.m_alg_kernel; + CGAL_precondition_code(auto eq = alg_kernel->compare_xy_2_object()); + CGAL_precondition(eq(source, target) != EQUAL); + // Set the arc properties (no need to compute the orientation). + Rational rat_coeffs[6] = {r, s, t, u, v, w}; + Curve_2 arc; + arc.set_orientation(orient); + arc.set_endpoints(source, target); + m_traits.set(arc, rat_coeffs); + return arc; + } + + /*! Construct a conic arc that is a circular arc from given three points. + * \param p1 The arc source. + * \param p2 A point in the interior of the arc. + * \param p3 The arc target. + * \pre The three points must not be collinear. + */ + Curve_2 operator()(const Rat_point_2& p1, const Rat_point_2& p2, + const Rat_point_2& p3) { + Curve_2 arc; + + // Set the source and target. + const Rational& x1 = p1.x(); + const Rational& y1 = p1.y(); + const Rational& x2 = p2.x(); + const Rational& y2 = p2.y(); + const Rational& x3 = p3.x(); + const Rational& y3 = p3.y(); + + const auto nt_traits = m_traits.m_nt_traits; + const auto alg_kernel = m_traits.m_alg_kernel; + Point_2 source(nt_traits->convert(x1), nt_traits->convert(y1)); + Point_2 target(nt_traits->convert(x3), nt_traits->convert(y3)); + arc.set_endpoints(source, target); + + // Make sure that the source and the taget are not the same. + CGAL_precondition_code(auto cmp_xy = alg_kernel->compare_xy_2_object()); + CGAL_precondition(cmp_xy(source, target) != EQUAL); + + // Compute the lines: A1*x + B1*y + C1 = 0, + // and: A2*x + B2*y + C2 = 0, + // where: + const Rational two(2); + + const Rational A1 = two*(x1 - x2); + const Rational B1 = two*(y1 - y2); + const Rational C1 = y2*y2 - y1*y1 + x2*x2 - x1*x1; + + const Rational A2 = two*(x2 - x3); + const Rational B2 = two*(y2 - y3); + const Rational C2 = y3*y3 - y2*y2 + x3*x3 - x2*x2; + + // Compute the coordinates of the intersection point between the + // two lines, given by (Nx / D, Ny / D), where: + const Rational Nx = B1*C2 - B2*C1; + const Rational Ny = A2*C1 - A1*C2; + const Rational D = A1*B2 - A2*B1; + + // Make sure the three points are not collinear. + const bool points_collinear = (CGAL::sign(D) == ZERO); + + if (points_collinear) { + arc.reset_flags(); // inavlid arc + return arc; + } + + // The equation of the underlying circle is given by: + Rational rat_coeffs[6]; + rat_coeffs[0] = D*D; + rat_coeffs[1] = D*D; + rat_coeffs[2] = 0; + rat_coeffs[3] = -two*D*Nx; + rat_coeffs[4] = -two*D*Ny; + rat_coeffs[5] = + Nx*Nx + Ny*Ny - ((D*x2 - Nx)*(D*x2 - Nx) + (D*y2 - Ny)*(D*y2 - Ny)); + + // Determine the orientation: If the mid-point forms a left-turn with + // the source and the target points, the orientation is positive (going + // counterclockwise). + // Otherwise, it is negative (going clockwise). + auto orient_f = alg_kernel->orientation_2_object(); + Point_2 p_mid(nt_traits->convert(x2), nt_traits->convert(y2)); + + auto orient = (orient_f(source, p_mid, target) == LEFT_TURN) ? + COUNTERCLOCKWISE : CLOCKWISE; + arc.set_orientation(orient); + + // Set the arc properties (no need to compute the orientation). + m_traits.set(arc, rat_coeffs); + return arc; + } + + /*! Construct a conic arc from given five points, specified by the + * points p1, p2, p3, p4 and p5. + * \param p1 The source point of the given arc. + * \param p2,p3,p4 Points lying on the conic arc, between p1 and p5. + * \param p5 The target point of the given arc. + * \pre No three points are collinear. + */ + Curve_2 operator()(const Rat_point_2& p1, const Rat_point_2& p2, + const Rat_point_2& p3, const Rat_point_2& p4, + const Rat_point_2& p5) { + Curve_2 arc; + + // Make sure that no three points are collinear. + auto orient_f = m_traits.m_rat_kernel->orientation_2_object(); + const bool point_collinear = + (orient_f(p1, p2, p3) == COLLINEAR || + orient_f(p1, p2, p4) == COLLINEAR || + orient_f(p1, p2, p5) == COLLINEAR || + orient_f(p1, p3, p4) == COLLINEAR || + orient_f(p1, p3, p5) == COLLINEAR || + orient_f(p1, p4, p5) == COLLINEAR || + orient_f(p2, p3, p4) == COLLINEAR || + orient_f(p2, p3, p5) == COLLINEAR || + orient_f(p2, p4, p5) == COLLINEAR || + orient_f(p3, p4, p5) == COLLINEAR); + + if (point_collinear) { + arc.reset_flags(); // inavlid arc + return arc; + } + + // Set the source and target. + const Rational& x1 = p1.x(); + const Rational& y1 = p1.y(); + const Rational& x5 = p5.x(); + const Rational& y5 = p5.y(); + + const auto nt_traits = m_traits.m_nt_traits; + Point_2 source(nt_traits->convert(x1), nt_traits->convert(y1)); + Point_2 target(nt_traits->convert(x5), nt_traits->convert(y5)); + arc.set_endpoints(source, target); + + // Set a conic curve that passes through the five given point. + typename Rat_kernel::Conic_2 temp_conic; + temp_conic.set(p1, p2, p3, p4, p5); + + // Get the conic coefficients. + Rational rat_coeffs[6]; + rat_coeffs[0] = temp_conic.r(); + rat_coeffs[1] = temp_conic.s(); + rat_coeffs[2] = temp_conic.t(); + rat_coeffs[3] = temp_conic.u(); + rat_coeffs[4] = temp_conic.v(); + rat_coeffs[5] = temp_conic.w(); + + // Determine the orientation: If one of the midpoints forms a left-turn + // with the source and the target points, the orientation is positive + // (going counterclockwise). + // Otherwise, it is negative (going clockwise). + const Orientation turn = orient_f(p1, p2, p5); + + if (turn == LEFT_TURN) { + arc.set_orientation(COUNTERCLOCKWISE); + CGAL_precondition(orient_f(p1, p3, p5) == LEFT_TURN && + orient_f(p1, p4, p5) == LEFT_TURN); + } + else { + arc.set_orientation(CLOCKWISE); + CGAL_precondition(orient_f(p1, p3, p5) != LEFT_TURN && + orient_f(p1, p4, p5) != LEFT_TURN); + } + + // Set the arc properties (no need to compute the orientation). + m_traits.set(arc, rat_coeffs); + + // Make sure that all midpoints are strictly between the + // source and the target. + Point_2 mp2(nt_traits->convert(p2.x()), nt_traits->convert(p2.y())); + Point_2 mp3(nt_traits->convert(p3.x()), nt_traits->convert(p3.y())); + Point_2 mp4(nt_traits->convert(p4.x()), nt_traits->convert(p4.y())); + + if (! m_traits.is_strictly_between_endpoints(arc, mp2) || + ! m_traits.is_strictly_between_endpoints(arc, mp3) || + ! m_traits.is_strictly_between_endpoints(arc, mp4)) + { + arc.reset_flags(); // inavlid arc + return arc; + } + return arc; + } + + /*! Construct a conic arc that lies on a conic given by its coefficients: + * `C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0` + * The source and the target are specified by the intersection of the + * conic with: + * `C_1: r_1*x^2 + s_1*y^2 + t_1*xy + u_1*x + v_1*y + w_1 = 0` + * `C_2: r_2*x^2 + s_2*y^2 + t_2*xy + u_2*x + v_2*y + w_2 = 0` + * The user must also specify the source and the target with approximated + * coordinates. The actual intersection points that best fits the source + * (or the target) will be selected. + */ + Curve_2 operator()(const Rational& r, const Rational& s, const Rational& t, + const Rational& u, const Rational& v, const Rational& w, + const Orientation& orient, + const Point_2& app_source, + const Rational& r_1, const Rational& s_1, + const Rational& t_1, const Rational& u_1, + const Rational& v_1, const Rational& w_1, + const Point_2& app_target, + const Rational& r_2, const Rational& s_2, + const Rational& t_2, const Rational& u_2, + const Rational& v_2, const Rational& w_2) const { + Curve_2 arc; + arc.set_orientation(orient); + + // Create the integer coefficients of the base conic. + Rational rat_coeffs [6]; + rat_coeffs[0] = r; + rat_coeffs[1] = s; + rat_coeffs[2] = t; + rat_coeffs[3] = u; + rat_coeffs[4] = v; + rat_coeffs[5] = w; + + const auto nt_traits = m_traits.m_nt_traits; + Integer base_coeffs[6]; + nt_traits->convert_coefficients(rat_coeffs, rat_coeffs + 6, base_coeffs); + + int deg_base = (CGAL::sign(base_coeffs[0]) == ZERO && + CGAL::sign(base_coeffs[1]) == ZERO && + CGAL::sign(base_coeffs[2]) == ZERO) ? 1 : 2; + + // Compute the endpoints. + Rational aux_rat_coeffs [6]; + Algebraic xs[4]; + Algebraic ys[4]; + Algebraic val; + bool found; + double curr_dist; + double min_dist = -1; + Integer aux_coeffs[6]; + for (int k = 1; k <= 2; ++k) { + // Get the integer coefficients of the k'th auxiliary conic curve. + aux_rat_coeffs[0] = (k == 1) ? r_1 : r_2; + aux_rat_coeffs[1] = (k == 1) ? s_1 : s_2; + aux_rat_coeffs[2] = (k == 1) ? t_1 : t_2; + aux_rat_coeffs[3] = (k == 1) ? u_1 : u_2; + aux_rat_coeffs[4] = (k == 1) ? v_1 : v_2; + aux_rat_coeffs[5] = (k == 1) ? w_1 : w_2; + + nt_traits->convert_coefficients(aux_rat_coeffs, aux_rat_coeffs + 6, + aux_coeffs); + + int deg_aux = ((CGAL::sign(aux_coeffs[0]) == ZERO) && + (CGAL::sign(aux_coeffs[1]) == ZERO) && + (CGAL::sign(aux_coeffs[2]) == ZERO)) ? 1 : 2; + + // Compute the x- and y-coordinates of intersection points of the base + // conic and the k'th auxiliary conic. + int n_xs = compute_resultant_roots(*nt_traits, + base_coeffs[0], base_coeffs[1], + base_coeffs[2], + base_coeffs[3], base_coeffs[4], + base_coeffs[5], + deg_base, + aux_coeffs[0], aux_coeffs[1], + aux_coeffs[2], + aux_coeffs[3], aux_coeffs[4], + aux_coeffs[5], + deg_aux, + xs); + + int n_ys = compute_resultant_roots(*nt_traits, + base_coeffs[1], base_coeffs[0], + base_coeffs[2], + base_coeffs[4], base_coeffs[3], + base_coeffs[5], + deg_base, + aux_coeffs[1], aux_coeffs[0], + aux_coeffs[2], + aux_coeffs[4], aux_coeffs[3], + aux_coeffs[5], + deg_aux, + ys); + + // Find the intersection point which is nearest the given approximation + // and set it as the endpoint. + found = false; + for (int i = 0; i < n_xs; ++i) { + for (int j = 0; j < n_ys; ++j) { + // Check if the point (xs[i], ys[j]) lies on both conics. + val = nt_traits->convert(base_coeffs[0]) * xs[i]*xs[i] + + nt_traits->convert(base_coeffs[1]) * ys[j]*ys[j] + + nt_traits->convert(base_coeffs[2]) * xs[i]*ys[j] + + nt_traits->convert(base_coeffs[3]) * xs[i] + + nt_traits->convert(base_coeffs[4]) * ys[j] + + nt_traits->convert(base_coeffs[5]); + + if (CGAL::sign(val) != ZERO) continue; + + val = nt_traits->convert(aux_coeffs[0]) * xs[i]*xs[i] + + nt_traits->convert(aux_coeffs[1]) * ys[j]*ys[j] + + nt_traits->convert(aux_coeffs[2]) * xs[i]*ys[j] + + nt_traits->convert(aux_coeffs[3]) * xs[i] + + nt_traits->convert(aux_coeffs[4]) * ys[j] + + nt_traits->convert(aux_coeffs[5]); + + if (CGAL::sign(val) == ZERO) { + // Compute the distance of (xs[i], ys[j]) from the approximated + // endpoint. + double dx, dy; + if (k == 1) { + dx = CGAL::to_double (xs[i] - app_source.x()); + dy = CGAL::to_double (ys[j] - app_source.y()); + } + else { + dx = CGAL::to_double (xs[i] - app_target.x()); + dy = CGAL::to_double (ys[j] - app_target.y()); + } + + curr_dist = dx*dx + dy*dy; + + // Update the endpoint if (xs[i], ys[j]) is the nearest pair so + // far. + if (! found || curr_dist < min_dist) { + if (k == 1) arc.set_source(Point_2(xs[i], ys[j])); + else arc.set_target(Point_2(xs[i], ys[j])); + min_dist = curr_dist; + found = true; + } + } + } + } + + if (! found) { + arc.reset_flags(); // inavlid arc + return arc; + } + } + + // Make sure that the source and the target are not the same. + auto cmp_xy = m_traits.m_alg_kernel->compare_xy_2_object(); + if (cmp_xy(arc.source(), arc.target()) == EQUAL) { + arc.reset_flags(); // inavlid arc + return arc; + } + + // Set the arc properties (no need to compute the orientation). + m_traits.set(arc, rat_coeffs); + return arc; + } + + /*! Return a segment connecting the two given endpoints. + * \param source The source point. + * \param target The target point. + * \pre `source` and `target` must not be the same. + * \return A segment connecting `source` and `target`. + */ + Curve_2 operator()(const Point_2& source, const Point_2& target) const { + const auto alg_kernel = m_traits.m_alg_kernel; + CGAL_precondition_code(auto cmp_xy = alg_kernel->compare_xy_2_object()); + CGAL_precondition(cmp_xy(source, target) != EQUAL); + + Curve_2 cv; + cv.set_coefficients(0, 0, 0, 0, 0, 0); + cv.set_orientation(COLLINEAR); + cv.set_flag(Curve_2::IS_VALID); + cv.set_endpoints(source, target); + cv.update_extra_data(); + return cv; + } + + /*! Construct a conic arc from a given line segment. + * \param seg The line segment with rational endpoints. + */ + Curve_2 operator()(const Rat_segment_2& seg) const { + Curve_2 cv; + cv.set_orientation(COLLINEAR); + + // Set the source and target. + const auto rat_kernel = m_traits.m_rat_kernel; + Rat_point_2 source = rat_kernel->construct_vertex_2_object()(seg, 0); + Rat_point_2 target = rat_kernel->construct_vertex_2_object()(seg, 1); + const Rational& x1 = source.x(); + const Rational& y1 = source.y(); + const Rational& x2 = target.x(); + const Rational& y2 = target.y(); + + const auto nt_traits = m_traits.m_nt_traits; + cv.set_source(Point_2(nt_traits->convert(x1), nt_traits->convert(y1))); + cv.set_target(Point_2(nt_traits->convert(x2), nt_traits->convert(y2))); + + // Make sure that the source and the taget are not the same. + CGAL_precondition_code(auto cmp_xy = rat_kernel->compare_xy_2_object()); + CGAL_precondition(cmp_xy(source, target) != EQUAL); + + // The supporting conic is r=s=t=0, and u*x + v*y + w = 0 should hold + // for both the source (x1,y1) and the target (x2, y2). + const Rational zero(0); + const Rational one(1); + Rational rat_coeffs[6]; + + rat_coeffs[0] = zero; + rat_coeffs[1] = zero; + rat_coeffs[2] = zero; + + if (rat_kernel->compare_x_2_object()(source, target) == EQUAL) { + // The supporting conic is a vertical line, of the form x = CONST. + rat_coeffs[3] = one; + rat_coeffs[4] = zero; + rat_coeffs[5] = -x1; + } + else { + // The supporting line is A*x + B*y + C = 0, where: + // + // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 + // + rat_coeffs[3] = y2 - y1; + rat_coeffs[4] = x1 - x2; + rat_coeffs[5] = x2*y1 - x1*y2; + } + + // Set the arc properties (no need to compute the orientation). + m_traits.set(cv, rat_coeffs); + return cv; + } + + /*! Construct a conic arc that is a full circle. + * \param circ The circle with rational center and rational squared radius. + */ + Curve_2 operator()(const Rat_circle_2& circ) const { + Curve_2 cv; + cv.set_orientation(CLOCKWISE); + + // Get the circle properties. + const auto rat_kernel = m_traits.m_rat_kernel; + Rat_point_2 center = rat_kernel->construct_center_2_object()(circ); + Rational x0 = center.x(); + Rational y0 = center.y(); + Rational r_sqr = rat_kernel->compute_squared_radius_2_object()(circ); + + // Produce the correponding conic: if the circle center is (x0,y0) + // and its squared radius is R^2, that its equation is: + // x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0 + // Note that this equation describes a curve with a negative (clockwise) + // orientation. + const Rational zero(0); + const Rational one(1); + const Rational minus_two(-2); + Rational rat_coeffs[6]; + rat_coeffs[0] = one; + rat_coeffs[1] = one; + rat_coeffs[2] = zero; + rat_coeffs[3] = minus_two*x0; + rat_coeffs[4] = minus_two*y0; + rat_coeffs[5] = x0*x0 + y0*y0 - r_sqr; + + // Set the arc to be the full conic (no need to compute the orientation). + m_traits.set_full(cv, rat_coeffs, false); + return cv; + } + + /*! Construct a conic arc that lies on a given circle: + * `C: (x - x0)^2 + (y - y0)^2 = R^2` + * \param orient The orientation of the circle. + * \param source The source point. + * \param target The target point. + * \pre The source and the target must be on the conic boundary and must + * not be the same. + */ + Curve_2 operator()(const Rat_circle_2& circ, const Orientation& orient, + const Point_2& source, const Point_2& target) const { + + // Make sure that the source and the taget are not the same. + CGAL_precondition_code(auto cmp_xy = + m_traits.m_alg_kernel->compare_xy_2_object()); + CGAL_precondition(cmp_xy(source, target) != EQUAL); + CGAL_precondition(orient != COLLINEAR); + + Curve_2 cv; + cv.set_endpoints(source, target); + cv.set_orientation(orient); + + // Get the circle properties. + const auto rat_kernel = m_traits.m_rat_kernel; + Rat_point_2 center = rat_kernel->construct_center_2_object()(circ); + Rational x0 = center.x(); + Rational y0 = center.y(); + Rational r_sqr = rat_kernel->compute_squared_radius_2_object()(circ); + + // Produce the correponding conic: if the circle center is (x0,y0) + // and it squared radius is R^2, that its equation is: + // x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0 + // Since this equation describes a curve with a negative (clockwise) + // orientation, we multiply it by -1 if nece_Conic_arc_2 ssary to obtain a + // positive (counterclockwise) orientation. + const Rational zero(0); + Rational rat_coeffs[6]; + + if (cv.orientation() == COUNTERCLOCKWISE) { + const Rational minus_one(-1); + const Rational two(2); + + rat_coeffs[0] = minus_one; + rat_coeffs[1] = minus_one; + rat_coeffs[2] = zero; + rat_coeffs[3] = two*x0; + rat_coeffs[4] = two*y0; + rat_coeffs[5] = r_sqr - x0*x0 - y0*y0; + } + else { + const Rational one(1); + const Rational minus_two(-2); + + rat_coeffs[0] = one; + rat_coeffs[1] = one; + rat_coeffs[2] = zero; + rat_coeffs[3] = minus_two*x0; + rat_coeffs[4] = minus_two*y0; + rat_coeffs[5] = x0*x0 + y0*y0 - r_sqr; + } + + // Set the arc properties (no need to compute the orientation). + m_traits.set(cv, rat_coeffs); + return cv; + } }; - /*! Get a Construct_curve_2 functor object. */ - Construct_curve_2 construct_curve_2_object () const - { return Construct_curve_2(); } + /*! Obtain a Construct_curve_2 functor object. */ + Construct_curve_2 construct_curve_2_object() const + { return Construct_curve_2(*this); } //@} /// \name Functor definitions for the Boolean set-operation traits. //@{ - class Compare_endpoints_xy_2 - { + class Compare_endpoints_xy_2 { public: - - /*! - * Compare the endpoints of an $x$-monotone curve lexicographically. + /*! Compare the endpoints of an $x$-monotone curve lexicographically. * (assuming the curve has a designated source and target points). * \param cv The curve. * \return SMALLER if the curve is directed right; * LARGER if the curve is directed left. */ - Comparison_result operator() (const X_monotone_curve_2& cv) const - { - if (cv.is_directed_right()) - return (SMALLER); - else - return (LARGER); - } + Comparison_result operator()(const X_monotone_curve_2& cv) const + { return (cv.is_directed_right()) ? SMALLER : LARGER; } }; - /*! Get a Compare_endpoints_xy_2 functor object. */ + /*! Obtain a Compare_endpoints_xy_2 functor object. */ Compare_endpoints_xy_2 compare_endpoints_xy_2_object() const - { - return Compare_endpoints_xy_2(); - } + { return Compare_endpoints_xy_2(); } - class Construct_opposite_2 - { + class Construct_opposite_2 { public: - - /*! - * Construct an opposite x-monotone (with swapped source and target). + /*! Construct an opposite x-monotone (with swapped source and target). * \param cv The curve. * \return The opposite curve. */ - X_monotone_curve_2 operator() (const X_monotone_curve_2& cv) const - { - return (cv.flip()); - } + X_monotone_curve_2 operator()(const X_monotone_curve_2& cv) const + { return cv.flip(); } }; - /*! Get a Construct_opposite_2 functor object. */ + /*! Obtain a Construct_opposite_2 functor object. */ Construct_opposite_2 construct_opposite_2_object() const - { - return Construct_opposite_2(); - } + { return Construct_opposite_2(); } - class Trim_2 - { + class Trim_2 { protected: - typedef Arr_conic_traits_2 Traits; + using Traits = Arr_conic_traits_2; /*! The traits (in case it has state) */ const Traits& m_traits; @@ -821,10 +2841,11 @@ public: */ Trim_2(const Traits& traits) : m_traits(traits) {} - public: friend class Arr_conic_traits_2; + + public: /*!\brief - * Returns a trimmed version of an arc + * Returns a trimmed version of an cv * * \param xcv The arc * \param src the new first endpoint @@ -835,34 +2856,1427 @@ public: * \pre both points must be interior and must lie on \c cv */ X_monotone_curve_2 operator()(const X_monotone_curve_2& xcv, - const Point_2& src, - const Point_2& tgt)const + const Point_2& src, const Point_2& tgt) const { // make functor objects CGAL_precondition_code(Compare_y_at_x_2 compare_y_at_x_2 = m_traits.compare_y_at_x_2_object()); CGAL_precondition_code(Equal_2 equal_2 = m_traits.equal_2_object()); Compare_x_2 compare_x_2 = m_traits.compare_x_2_object(); - // Check whether source and target are two distinct points and they lie + // Check whether source and taget are two distinct points and they lie // on the line. CGAL_precondition(compare_y_at_x_2(src, xcv) == EQUAL); CGAL_precondition(compare_y_at_x_2(tgt, xcv) == EQUAL); CGAL_precondition(! equal_2(src, tgt)); //check if the orientation conforms to the src and tgt. - if( (xcv.is_directed_right() && compare_x_2(src, tgt) == LARGER) || - (! xcv.is_directed_right() && compare_x_2(src, tgt) == SMALLER) ) - return (xcv.trim(tgt, src)); - else return (xcv.trim(src, tgt)); + return ((xcv.is_directed_right() && compare_x_2(src, tgt) == LARGER) || + (! xcv.is_directed_right() && compare_x_2(src, tgt) == SMALLER)) ? + trim(xcv, tgt, src) : trim(xcv, src, tgt); + } + + private: + /*! Trim the arc given its new endpoints. + * \param ps The new source point. + * \param pt The new target point. + * \return The new trimmed arc. + * \pre Both ps and pt lies on the arc and must conform with the current + * direction of the arc. + */ + X_monotone_curve_2 trim(const X_monotone_curve_2& xcv, + const Point_2& ps, const Point_2& pt) const { + // Make sure that both ps and pt lie on the arc. + CGAL_precondition(m_traits.contains_point(xcv, ps) && + m_traits.contains_point(xcv, pt)); + + X_monotone_curve_2 res_xcv = xcv; // make a copy of the current arc + + auto eq = m_traits.m_alg_kernel->equal_2_object(); + auto set_source = [&](const Point_2 ps)->void { + if (! eq(ps, xcv.source())) { + res_xcv.set_source(ps); + if (! ps.is_generating_conic(xcv.id())) + res_xcv.source().set_generating_conic(xcv.id()); + } + }; + auto set_target = [&](const Point_2 pt)->void { + if (! eq(pt, xcv.target())) { + res_xcv.set_target(pt); + if (! pt.is_generating_conic(xcv.id())) + res_xcv.target().set_generating_conic(xcv.id()); + } + }; + + // Make sure that the endpoints conform with the direction of the arc. + auto cmp_xy = m_traits.m_alg_kernel->compare_xy_2_object(); + auto res = cmp_xy(ps, pt); + CGAL_assertion(res != EQUAL); + if ((xcv.test_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT) && + (res == LARGER)) || + (! xcv.test_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT) && + (res == SMALLER))) { + set_source(pt); + set_target(ps); + } + else { + set_source(ps); + set_target(pt); + } + + return res_xcv; } }; /*! Obtain a Trim_2 functor object. */ Trim_2 trim_2_object() const { return Trim_2(*this); } //@} + + /// \name Extra functor definitions. + //@{ + + class Construct_bbox_2 { + protected: + using Traits = Arr_conic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits The traits. + */ + Construct_bbox_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_conic_traits_2; + + public: + /*! Obtain a bounding box for the conic arc. + * \return The bounding box. + */ + Bbox_2 operator()(const X_monotone_curve_2& xcv) const { return bbox(xcv); } + Bbox_2 operator()(const Curve_2& cv) const { return bbox(cv); } + + private: + Bbox_2 bbox(const X_monotone_curve_2& xcv) const { + CGAL_precondition(xcv.is_valid()); + double x_min(0), y_min(0), x_max(0), y_max(0); + + if (xcv.is_full_conic()) { + // In case of a full conic (an ellipse or a circle), compute the + // horizontal and vertical tangency points and use them to bound the arc. + Alg_point_2 tan_ps[2]; + CGAL_assertion_code(size_t n_tan_ps); + + CGAL_assertion_code + (n_tan_ps = m_traits.vertical_tangency_points(xcv, tan_ps)); + CGAL_assertion(n_tan_ps == 2); + + if (CGAL::to_double(tan_ps[0].x()) < CGAL::to_double(tan_ps[1].x())) { + x_min = CGAL::to_double(tan_ps[0].x()); + x_max = CGAL::to_double(tan_ps[1].x()); + } + else { + x_min = CGAL::to_double(tan_ps[1].x()); + x_max = CGAL::to_double(tan_ps[0].x()); + } + + CGAL_assertion_code + (n_tan_ps = m_traits.horizontal_tangency_points(xcv, tan_ps)); + CGAL_assertion(n_tan_ps == 2); + + if (CGAL::to_double(tan_ps[0].y()) < CGAL::to_double(tan_ps[1].y())) { + y_min = CGAL::to_double(tan_ps[0].y()); + y_max = CGAL::to_double(tan_ps[1].y()); + } + else { + y_min = CGAL::to_double(tan_ps[1].y()); + y_max = CGAL::to_double(tan_ps[0].y()); + } + } + else { + // Use the source and target to initialize the exterme points. + bool source_left = + CGAL::to_double(xcv.source().x()) < CGAL::to_double(xcv.target().x()); + x_min = (source_left) ? + CGAL::to_double(xcv.source().x()) : + CGAL::to_double(xcv.target().x()); + x_max = source_left ? + CGAL::to_double(xcv.target().x()) : + CGAL::to_double(xcv.source().x()); + + bool source_down = + CGAL::to_double(xcv.source().y()) < CGAL::to_double(xcv.target().y()); + y_min = source_down ? + CGAL::to_double(xcv.source().y()) : + CGAL::to_double(xcv.target().y()); + y_max = source_down ? + CGAL::to_double(xcv.target().y()) : + CGAL::to_double(xcv.source().y()); + + // Go over the vertical tangency points and try to update the x-points. + Alg_point_2 tan_ps[2]; + auto n_tan_ps = m_traits.vertical_tangency_points(xcv, tan_ps); + for (decltype(n_tan_ps) i = 0; i < n_tan_ps; ++i) { + if (CGAL::to_double(tan_ps[i].x()) < x_min) + x_min = CGAL::to_double(tan_ps[i].x()); + if (CGAL::to_double(tan_ps[i].x()) > x_max) + x_max = CGAL::to_double(tan_ps[i].x()); + } + + // Go over the horizontal tangency points and try to update the y-points. + n_tan_ps = m_traits.horizontal_tangency_points(xcv, tan_ps); + for (decltype(n_tan_ps) i = 0; i < n_tan_ps; ++i) { + if (CGAL::to_double(tan_ps[i].y()) < y_min) + y_min = CGAL::to_double(tan_ps[i].y()); + if (CGAL::to_double(tan_ps[i].y()) > y_max) + y_max = CGAL::to_double(tan_ps[i].y()); + } + } + + // Return the resulting bounding box. + return Bbox_2(x_min, y_min, x_max, y_max); + } + }; + + /*! Obtain a Bbox_2 functor object. */ + Construct_bbox_2 construct_bbox_2_object() const + { return Construct_bbox_2(*this); } + //@} + + /*! Set the properties of a conic arc (for the usage of the constructors). + * \param rat_coeffs A vector of size 6, storing the rational coefficients + * of \f$x^2\f$, \f$y^2\f$, \f$x \cdot y\f$, \f$x\f$, \f$y\f$ + * and the free coefficient resp. + */ + void set(Curve_2& cv, const Rational* rat_coeffs) const { + cv.set_flag(Curve_2::IS_VALID); + + // Convert the coefficients vector to an equivalent vector of integer + // coefficients. + Integer int_coeffs[6]; + m_nt_traits->convert_coefficients(rat_coeffs, rat_coeffs + 6, int_coeffs); + + // Check the orientation of conic curve, and negate the conic coefficients + // if its given orientation. + typename Rat_kernel::Conic_2 temp_conic(rat_coeffs[0], rat_coeffs[1], + rat_coeffs[2], rat_coeffs[3], + rat_coeffs[4], rat_coeffs[5]); + + + Integer r, s, t, u, v, w; + if (cv.orientation() == temp_conic.orientation()) { + r = int_coeffs[0]; + s = int_coeffs[1]; + t = int_coeffs[2]; + u = int_coeffs[3]; + v = int_coeffs[4]; + w = int_coeffs[5]; + } + else { + r = -int_coeffs[0]; + s = -int_coeffs[1]; + t = -int_coeffs[2]; + u = -int_coeffs[3]; + v = -int_coeffs[4]; + w = -int_coeffs[5]; + } + cv.set_coefficients(r, s, t, u, v, w); + + const auto& source = cv.source(); + const auto& target = cv.target(); + // Make sure both endpoint lie on the supporting conic. + if (! is_on_supporting_conic(cv, source) || + ! is_on_supporting_conic(cv, target)) + { + cv.reset_flags(); // inavlid arc + return; + } + + // Check whether we have a degree 2 curve. + if ((CGAL::sign(r) != ZERO) || (CGAL::sign(s) != ZERO) || + (CGAL::sign(t) != ZERO)) + { + if (cv.orientation() == COLLINEAR) { + // Make sure the midpoint is on the line pair (thus making sure that + // the two points are not taken from different lines). + auto ctr_mid_point = m_alg_kernel->construct_midpoint_2_object(); + Point_2 p_mid = ctr_mid_point(source, target); + // if (! is_on_supporting_conic(arc, p_mid)) + if (CGAL::sign((m_nt_traits->convert(r)*p_mid.x() + + m_nt_traits->convert(t)*p_mid.y() + + m_nt_traits->convert(u)) * p_mid.x() + + (m_nt_traits->convert(s)*p_mid.y() + + m_nt_traits->convert(v)) * p_mid.y() + + m_nt_traits->convert(w)) != ZERO) + { + cv.reset_flags(); // inavlid arc + return; + } + + // We have a segment of a line pair with rational coefficients. + // Compose the equation of the underlying line + // (with algebraic coefficients). + cv.update_extra_data(); + } + else { + // The sign of (4rs - t^2) detetmines the conic type: + // - if it is possitive, the conic is an ellipse, + // - if it is negative, the conic is a hyperbola, + // - if it is zero, the conic is a parabola. + CGAL::Sign sign_conic = CGAL::sign(4*r*s - t*t); + + // Build the extra hyperbolic data if necessary + if (sign_conic == NEGATIVE) build_hyperbolic_arc_data(cv); + + if (sign_conic != POSITIVE) { + // In case of a non-degenerate parabola or a hyperbola, make sure + // the arc is not infinite. + Point_2 p_mid = + m_alg_kernel->construct_midpoint_2_object()(source, target); + Alg_point_2 ps[2]; + bool finite_at_x = (points_at_x(cv, p_mid, ps) > 0); + bool finite_at_y = (points_at_y(cv, p_mid, ps) > 0); + if (! finite_at_x && ! finite_at_y) { + cv.reset_flags(); // inavlid arc + return; + } + } + } + } + + + cv.set_flag(Curve_2::IS_VALID); // arc is valid + cv.reset_flag(Curve_2::IS_FULL_CONIC); // not a full conic + } + + /*! Set the properties of a conic arc that is really a full curve + * (that is, an ellipse). + * \param rat_coeffs A vector of size 6, storing the rational coefficients + * of \f$x^2\f$, \f$y^2\f$, \f$x \cdot y\f$, \f$x\f$, \f$y\f$ + * and the free coefficient resp. + * \param comp_orient Should we compute the orientation of the given curve. + */ + void set_full(Curve_2& cv, const Rational* rat_coeffs, + const bool& comp_orient) const { + // Convert the coefficients vector to an equivalent vector of integer + // coefficients. + Integer int_coeffs[6]; + m_nt_traits->convert_coefficients(rat_coeffs, rat_coeffs + 6, int_coeffs); + + // Check the orientation of conic curve, and negate the conic coefficients + // if its given orientation. + typename Rat_kernel::Conic_2 temp_conic(rat_coeffs[0], rat_coeffs[1], + rat_coeffs[2], rat_coeffs[3], + rat_coeffs[4], rat_coeffs[5]); + const Orientation temp_orient = temp_conic.orientation(); + + if (comp_orient) cv.set_orientation(temp_orient); + + Integer r, s, t, u, v, w; + if (cv.orientation() == temp_orient) { + r = int_coeffs[0]; + s = int_coeffs[1]; + t = int_coeffs[2]; + u = int_coeffs[3]; + v = int_coeffs[4]; + w = int_coeffs[5]; + } + else { + r = -int_coeffs[0]; + s = -int_coeffs[1]; + t = -int_coeffs[2]; + u = -int_coeffs[3]; + v = -int_coeffs[4]; + w = -int_coeffs[5]; + } + cv.set_coefficients(r, s, t, u, v, w); + + // Make sure the conic is a non-degenerate ellipse: + // The coefficients should satisfy (4rs - t^2) > 0. + const bool is_ellipse = (CGAL::sign(4*r*s - t*t) == POSITIVE); + CGAL_assertion(is_ellipse); + + // We do not have to store any extra data with the arc. + + // Mark that this arc is a full conic curve. + if (is_ellipse) { + cv.set_flag(Curve_2::IS_VALID); + cv.set_flag(Curve_2::IS_FULL_CONIC); + } + else cv.reset_flags(); // inavlid arc + } + + /*! Check whether the given point lies on the supporting conic of the arc. + * \param p The query point. + * \return true if p lies on the supporting conic; (false) otherwise. + */ + bool is_on_supporting_conic(Curve_2& cv, const Point_2& p) const { + // Check whether p satisfies the conic equation. + const Algebraic r = m_nt_traits->convert(cv.r()); + const Algebraic t = m_nt_traits->convert(cv.t()); + const Algebraic u = m_nt_traits->convert(cv.u()); + const Algebraic s = m_nt_traits->convert(cv.s()); + const Algebraic v = m_nt_traits->convert(cv.v()); + const Algebraic w = m_nt_traits->convert(cv.w()); + + // The point must satisfy: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0. + const Algebraic val = + (r*p.x() + t*p.y() + u)*p.x() + (s*p.y() + v)* p.y() + w; + return (CGAL::sign(val) == ZERO); + } + + /*! Check whether the given point is between the source and the target. + * The point is assumed to be on the conic's boundary. + * \param p The query point. + * \return `true` if the point is between the two endpoints; + * `false` if it is not. + */ + bool is_between_endpoints(const Curve_2& cv, const Point_2& p) const { + CGAL_precondition(! cv.is_full_conic()); + + // Check if p is one of the endpoints. + auto eq = m_alg_kernel->equal_2_object(); + if (eq(p, cv.source()) || eq(p, cv.target())) return true; + else return is_strictly_between_endpoints(cv, p); + } + + /*! Check whether the given point is strictly between the source and the + * target (but not any of them). + * The point is assumed to be on the conic's boundary. + * \param p The query point. + * \return `true` if the point is strictly between the two endpoints; + * `false` if it is not. + */ + bool is_strictly_between_endpoints(const Curve_2& cv, const Point_2& p) const + { + // In case this is a full conic, any point on its boundary is between + // its end points. + if (cv.is_full_conic()) return true; + + // Check if we have extra data available. + const auto* extra_data = cv.extra_data(); + if (extra_data != nullptr) { + if (extra_data->side != ZERO) { + // In case of a hyperbolic arc, make sure the point is located on the + // same branch as the arc. + if (cv.sign_of_extra_data(p.x(), p.y()) != extra_data->side) + return false; + } + else { + // In case we have a segment of a line pair, make sure that p really + // satisfies the equation of the line. + if (cv.sign_of_extra_data(p.x(), p.y()) != ZERO) return false; + } + } + + // Act according to the conic degree. + auto orient_f = m_alg_kernel->orientation_2_object(); + const auto& source = cv.source(); + const auto& target = cv.target(); + if (cv.orientation() == COLLINEAR) { + Comparison_result res1; + Comparison_result res2; + + if (m_alg_kernel->compare_x_2_object()(source, target) == EQUAL) { + // In case of a vertical segment - just check whether the y coordinate + // of p is between those of the source's and of the target's. + auto cmp_y = m_alg_kernel->compare_y_2_object(); + res1 = cmp_y(p, source); + res2 = cmp_y(p, target); + } + else { + // Otherwise, since the segment is x-monotone, just check whether the + // x coordinate of p is between those of the source's and of the + // target's. + auto cmp_x = m_alg_kernel->compare_x_2_object(); + res1 = cmp_x(p, source); + res2 = cmp_x(p, target); + } + + // If p is not in the (open) x-range (or y-range) of the segment, it + // cannot be contained in the segment. + if ((res1 == EQUAL) || (res2 == EQUAL) || (res1 == res2)) return false; + + // Perform an orientation test: This is crucial for segment of line + // pairs, as we want to make sure that p lies on the same line as the + // source and the target. + return (orient_f(source, p, target) == COLLINEAR); + } + + // In case of a conic of degree 2, make a decision based on the conic's + // orientation and whether (source,p,target) is a right or a left turn. + if (cv.orientation() == COUNTERCLOCKWISE) + return (orient_f(source, p, target) == LEFT_TURN); + else + return (orient_f(source, p, target) == RIGHT_TURN); + } + + /*! Build the data for hyperbolic arc, contaning the characterization of the + * hyperbolic branch the arc is placed on. + */ + void build_hyperbolic_arc_data(Curve_2& cv) const { + // Let phi be the rotation angle of the conic from its canonic form. + // We can write: + // + // t + // sin(2*phi) = ----------------------- + // sqrt((r - s)^2 + t^2) + // + // r - s + // cos(2*phi) = ----------------------- + // sqrt((r - s)^2 + t^2) + // + const int or_fact = (cv.orientation() == CLOCKWISE) ? -1 : 1; + const Algebraic r = m_nt_traits->convert(or_fact * cv.r()); + const Algebraic s = m_nt_traits->convert(or_fact * cv.s()); + const Algebraic t = m_nt_traits->convert(or_fact * cv.t()); + const Algebraic cos_2phi = (r - s) / m_nt_traits->sqrt((r-s)*(r-s) + t*t); + const Algebraic zero = 0; + const Algebraic one = 1; + const Algebraic two = 2; + Algebraic sin_phi; + Algebraic cos_phi; + + // Calculate sin(phi) and cos(phi) according to the half-angle formulae: + // + // sin(phi)^2 = 0.5 * (1 - cos(2*phi)) + // cos(phi)^2 = 0.5 * (1 + cos(2*phi)) + Sign sign_t = CGAL::sign(t); + + if (sign_t == ZERO) { + // sin(2*phi) == 0, so phi = 0 or phi = PI/2 + if (CGAL::sign(cos_2phi) == POSITIVE) { + // phi = 0. + sin_phi = zero; + cos_phi = one; + } + else { + // phi = PI/2. + sin_phi = one; + cos_phi = zero; + } + } + else if (sign_t == POSITIVE) { + // sin(2*phi) > 0 so 0 < phi < PI/2. + sin_phi = m_nt_traits->sqrt((one + cos_2phi) / two); + cos_phi = m_nt_traits->sqrt((one - cos_2phi) / two); + } + else { + // sin(2*phi) < 0 so PI/2 < phi < PI. + sin_phi = m_nt_traits->sqrt((one + cos_2phi) / two); + cos_phi = - m_nt_traits->sqrt((one - cos_2phi) / two); + } + + // Calculate the center (x0, y0) of the conic, given by the formulae: + // + // t*v - 2*s*u t*u - 2*r*v + // x0 = ------------- , y0 = ------------- + // 4*r*s - t^2 4*r*s - t^2 + // + // The denominator (4*r*s - t^2) must be negative for hyperbolas. + const Algebraic u = m_nt_traits->convert(or_fact * cv.u()); + const Algebraic v = m_nt_traits->convert(or_fact * cv.v()); + const Algebraic det = 4*r*s - t*t; + Algebraic x0, y0; + + CGAL_assertion(CGAL::sign(det) == NEGATIVE); + + x0 = (t*v - two*s*u) / det; + y0 = (t*u - two*r*v) / det; + + // The axis separating the two branches of the hyperbola is now given by: + // + // cos(phi)*x + sin(phi)*y - (cos(phi)*x0 + sin(phi)*y0) = 0 + // + // We store the equation of this line in the extra data structure and also + // the sign (side of half-plane) our arc occupies with respect to the line. + // We use it to make sure that the two endpoints are located on the same + // branch of the hyperbola. + auto a = cos_phi; + auto b = sin_phi; + auto c = - (cos_phi*x0 + sin_phi*y0); + const auto& source = cv.source(); + auto val = a * source.x() + b * source.y() + c; + auto side = CGAL::sign(val); + CGAL_assertion(side != ZERO); + cv.set_extra_data(a, b, c, side); + CGAL_assertion_code(const auto& target = cv.target()); + CGAL_assertion(side == cv.sign_of_extra_data(target.x(), target.y())); + } + + /*! Find the x coordinates of the underlying conic at a given y coordinate. + * \param y The y coordinate. + * \param xs The output x coordinates. + * \pre The vector xs must be allocated at the size of 2. + * \return The number of x coordinates computed (either 0, 1 or 2). + */ + int conic_get_x_coordinates(const Curve_2& cv, + const Algebraic& y, Algebraic* xs) const { + // Solve the quadratic equation for a given y and find the x values: + // r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0 + Algebraic A = m_nt_traits->convert(cv.r()); + Algebraic B = m_nt_traits->convert(cv.t())*y + m_nt_traits->convert(cv.u()); + Algebraic C = + (m_nt_traits->convert(cv.s())*y + m_nt_traits->convert(cv.v()))*y + + m_nt_traits->convert(cv.w()); + + return solve_quadratic_equation(A, B, C, xs[0], xs[1]); + } + + /*! Find the y coordinates of the underlying conic at a given x coordinate. + * \param x The x coordinate. + * \param ys The output y coordinates. + * \pre The vector ys must be allocated at the size of 2. + * \return The number of y coordinates computed (either 0, 1 or 2). + */ + int conic_get_y_coordinates(const Curve_2& cv, + const Algebraic& x, Algebraic* ys) const { + // Solve the quadratic equation for a given x and find the y values: + // s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0 + Algebraic A = m_nt_traits->convert(cv.s()); + Algebraic B = m_nt_traits->convert(cv.t())*x + m_nt_traits->convert(cv.v()); + Algebraic C = + (m_nt_traits->convert(cv.r())*x + m_nt_traits->convert(cv.u()))*x + + m_nt_traits->convert(cv.w()); + + return solve_quadratic_equation(A, B, C, ys[0], ys[1]); + } + + /*! Solve the given quadratic equation: Ax^2 + B*x + C = 0. + * \param x_minus The root obtained from taking -sqrt(discriminant). + * \param x_plus The root obtained from taking -sqrt(discriminant). + * \return The number of disticnt solutions to the equation. + */ + int solve_quadratic_equation(const Algebraic& A, + const Algebraic& B, + const Algebraic& C, + Algebraic& x_minus, Algebraic& x_plus) const { + // Check if we actually have a linear equation. + if (CGAL::sign(A) == ZERO) { + if (CGAL::sign(B) == ZERO) return 0; + x_minus = x_plus = -C / B; + return 1; + } + + // Compute the discriminant and act according to its sign. + const Algebraic disc = B*B - 4*A*C; + Sign sign_disc = CGAL::sign(disc); + + // Check whether there are no real-valued solutions: + if (sign_disc == NEGATIVE) return 0; + else if (sign_disc == ZERO) { + // One distinct solution: + x_minus = x_plus = -B / (2*A); + return 1; + } + + // Compute the two distinct solutions: + Algebraic _2A = 2*A; + Algebraic sqrt_disc = m_nt_traits->sqrt(disc); + + x_minus = -(B + sqrt_disc) / _2A; + x_plus = (sqrt_disc - B) / _2A; + return 2; + } + + /*! Compute a point on an arc with the same \f$x\f$-coordiante as the given + * point. + * \param p The given point. + * \pre The arc is not vertical and `p` is in the \f$x\f$-range of the arc. + * \return A point on the arc with the same \f$x\f$-coordiante as `p`. + */ + Point_2 point_at_x(const X_monotone_curve_2& xcv, const Point_2& p) const { + // Make sure that p is in the x-range of the arc. + CGAL_precondition(! xcv.is_vertical()); + + CGAL_precondition_code(auto cmp_x = m_alg_kernel->compare_x_2_object()); + CGAL_precondition((cmp_x(p, xcv.left()) != SMALLER) && + (cmp_x(p, xcv.right()) != LARGER)); + + if (xcv.is_special_segment()) { + // In case of a special segment, the equation of the supported line + // (a*x + b*y + c) = 0 is stored with the extra data field, and we + // simply have: + const auto& extra_data = xcv.extra_data(); + Algebraic y = -(extra_data->a*p.x() + extra_data->c) / extra_data->b; + + // Return the computed point. + return Point_2(p.x(), y); + } + + // Compute the y-coordinate according to the degree of the supporting + // conic curve. + Algebraic y; + + if (xcv.degree_mask() == X_monotone_curve_2::degree_1_mask()) { + // In case of a linear curve, the y-coordinate is a simple linear + // expression of x(p) (note that v is not 0 as the arc is not vertical): + // y = -(u*x(p) + w) / v + y = -(xcv.alg_u()*p.x() + xcv.alg_w()) / xcv.alg_v(); + } + else if (xcv.orientation() == COLLINEAR) { + const auto& extra_data = xcv.extra_data(); + CGAL_assertion(extra_data != nullptr); + + // In this case the equation of the supporting line is given by the + // extra data structure. + y = -(extra_data->a * p.x() + extra_data->c) / extra_data->b; + } + else { + CGAL_assertion(xcv.degree_mask() == X_monotone_curve_2::degree_2_mask()); + + // In this case the y-coordinate is one of solutions to the quadratic + // equation: + // s*y^2 + (t*x(p) + v)*y + (r*x(p)^2 + u*x(p) + w) = 0 + Algebraic A = xcv.alg_s(); + Algebraic B = xcv.alg_t()*p.x() + xcv.alg_v(); + Algebraic C = (xcv.alg_r()*p.x() + xcv.alg_u())*p.x() + xcv.alg_w(); + + if (CGAL::sign(xcv.s()) == ZERO) { + // In this case A is 0 and we have a linear equation. + CGAL_assertion(CGAL::sign(B) != ZERO); + + y = -C / B; + } + else { + // Solve the quadratic equation. + Algebraic disc = B*B - 4*A*C; + + CGAL_assertion(CGAL::sign(disc) != NEGATIVE); + + // We take either the root involving -sqrt(disc) or +sqrt(disc) + // based on the information flags. + y = (xcv.test_flag(X_monotone_curve_2::PLUS_SQRT_DISC_ROOT)) ? + (m_nt_traits->sqrt(disc) - B) / (2*A) : + -(B + m_nt_traits->sqrt(disc)) / (2*A); + } + } + + // Return the computed point. + return Point_2(p.x(), y); + } + + /*! Find all points on the arc with a given \f$x\f$-coordinate. + * \param p A placeholder for the \f$x\f$-coordinate. + * \param ps The point on the arc at `x(p)`. + * \pre The vector `ps` should be allocated at the size of 2. + * \return The number of points found. + */ + int points_at_x(const Curve_2& cv, const Point_2& p, Alg_point_2* ps) const { + // Get the y coordinates of the points on the conic. + Algebraic ys[2]; + int n = conic_get_y_coordinates(cv, p.x(), ys); + + // Find all the points that are contained in the arc. + int m = 0; + + for (int i = 0; i < n; ++i) { + ps[m] = Point_2(p.x(), ys[i]); + if (cv.is_full_conic() || is_between_endpoints(cv, ps[m])) ++m; + } + + // Return the number of points on the arc. + CGAL_assertion(m <= 2); + return m; + } + + /*! Find all points on the arc with a given \f$y\f$-coordinate. + * \param p A placeholder for the \f$y\f$-coordinate. + * \param ps The point on the arc at `x(p)`. + * \pre The vector `ps` should be allocated at the size of 2. + * \return The number of points found. + */ + int points_at_y(const Curve_2& cv, const Point_2& p, Alg_point_2* ps) const { + // Get the y coordinates of the points on the conic. + Algebraic xs[2]; + int n = conic_get_x_coordinates(cv, p.y(), xs); + + // Find all the points that are contained in the arc. + int m = 0; + + for (int i = 0; i < n; ++i) { + ps[m] = Point_2(xs[i], p.y()); + if (cv.is_full_conic() || is_between_endpoints(cv, ps[m])) ++m; + } + + // Return the number of points on the arc. + CGAL_assertion(m <= 2); + return m; + } + + /*! Set the properties of the x-monotone conic arc (for the usage of the + * constructors). + */ + void set_x_monotone(X_monotone_curve_2& xcv) const { + // Convert the coefficients of the supporting conic to algebraic numbers. + auto alg_r = m_nt_traits->convert(xcv.r()); + auto alg_s = m_nt_traits->convert(xcv.s()); + auto alg_t = m_nt_traits->convert(xcv.t()); + auto alg_u = m_nt_traits->convert(xcv.u()); + auto alg_v = m_nt_traits->convert(xcv.v()); + auto alg_w = m_nt_traits->convert(xcv.w()); + xcv.set_alg_coefficients(alg_r, alg_s, alg_t, alg_u, alg_v, alg_w); + + // Set the generating conic ID for the source and target points. + xcv.set_generating_conic(xcv.id()); + + // Update the m_info bits. + xcv.set_flag(Curve_2::IS_VALID); + xcv.reset_flag(Curve_2::IS_FULL_CONIC); + + // Check (i) whether the arc is a vertical segment, and (ii) whether it is + // directed right. + auto cmp_x = m_alg_kernel->compare_x_2_object(); + Comparison_result resx = cmp_x(xcv.source(), xcv.target()); + if (resx == SMALLER) xcv.set_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT); + else if (resx == EQUAL) { + xcv.set_flag(X_monotone_curve_2::IS_VERTICAL_SEGMENT); + + auto cmp_y = m_alg_kernel->compare_y_2_object(); + Comparison_result resy = cmp_y(xcv.source(), xcv.target()); + CGAL_assertion(resy != EQUAL); + if (resy == SMALLER) xcv.set_flag(X_monotone_curve_2::IS_DIRECTED_RIGHT); + } + + if (xcv.orientation() == COLLINEAR) { + // Compute the degree of the underlying conic. + if ((CGAL::sign(xcv.r()) != ZERO) || + (CGAL::sign(xcv.s()) != ZERO) || + (CGAL::sign(xcv.t()) != ZERO)) + { + xcv.set_flag(X_monotone_curve_2::DEGREE_2); + xcv.set_flag(X_monotone_curve_2::IS_SPECIAL_SEGMENT); + } + else { + xcv.set_flag(X_monotone_curve_2::DEGREE_1); + + // Check whether this is a special segment + if ((CGAL::sign(xcv.u()) == ZERO) && (CGAL::sign(xcv.v()) == ZERO)) { + xcv.set_flag(X_monotone_curve_2::IS_SPECIAL_SEGMENT); + xcv.update_extra_data(); + } + } + return; + } + + xcv.set_flag(X_monotone_curve_2::DEGREE_2); + + // Compute a midpoint between the source and the target and get the y-value + // of the arc at its x-coordiante. + Point_2 p_mid = + m_alg_kernel->construct_midpoint_2_object()(xcv.source(), xcv.target()); + Algebraic ys[2]; + CGAL_assertion_code(int n_ys = ) + conic_get_y_coordinates(xcv, p_mid.x(), ys); + + CGAL_assertion(n_ys != 0); + + // Check which solution lies on the x-monotone arc. + Point_2 p_arc_mid(p_mid.x(), ys[0]); + + if (is_strictly_between_endpoints(xcv, p_arc_mid)) { + // Mark that we should use the -sqrt(disc) root for points on this + // x-monotone arc. + xcv.reset_flag(X_monotone_curve_2::PLUS_SQRT_DISC_ROOT); + } + else { + CGAL_assertion(n_ys == 2); + p_arc_mid = Point_2(p_mid.x(), ys[1]); + CGAL_assertion(is_strictly_between_endpoints(xcv, p_arc_mid)); + + // Mark that we should use the +sqrt(disc) root for points on this + // x-monotone arc. + xcv.set_flag(X_monotone_curve_2::PLUS_SQRT_DISC_ROOT); + } + + // Check whether the conic is facing up or facing down: + // Check whether the arc (which is x-monotone of degree 2) lies above or + // below the segement that connects its two end-points (x1,y1) and (x2,y2). + // To do that, we find the y coordinate of a point on the arc whose x + // coordinate is (x1+x2)/2 and compare it to (y1+y2)/2. + auto cmp_y = m_alg_kernel->compare_y_2_object(); + Comparison_result res = cmp_y(p_arc_mid, p_mid); + + // If the arc is above the connecting segment, so it is facing upwards. + if (res == LARGER) xcv.set_flag(X_monotone_curve_2::FACING_UP); + // If the arc is below the connecting segment, so it is facing downwards. + else if (res == SMALLER) xcv.set_flag(X_monotone_curve_2::FACING_DOWN); + } + + /*! Check whether the two arcs have the same supporting conic. + * \param xcv1 The first comparedb arc. + * \param xcv2 The secind compared arc. + * \return `true` if the two supporting conics are the same. + */ + bool has_same_supporting_conic(const X_monotone_curve_2& xcv1, + const X_monotone_curve_2& xcv2) const { + // Check if the two arcs originate from the same conic: + if ((xcv1.id() == xcv2.id()) && + xcv1.id().is_valid() && xcv2.id().is_valid()) + return true; + + // In case both arcs are collinear, check if they have the same + // supporting lines. + if ((xcv1.orientation() == COLLINEAR) && + (xcv2.orientation() == COLLINEAR)) { + // Construct the two supporting lines and compare them. + auto ctr_line = m_alg_kernel->construct_line_2_object(); + typename Alg_kernel::Line_2 l1 = ctr_line(xcv1.source(), xcv1.target()); + typename Alg_kernel::Line_2 l2 = ctr_line(xcv2.source(), xcv2.target()); + auto equal = m_alg_kernel->equal_2_object(); + if (equal(l1, l2)) return true; + + l2 = ctr_line(xcv2.target(), xcv2.source()); + return equal(l1, l2); + } + else if ((xcv1.orientation() == COLLINEAR) || + (xcv2.orientation() == COLLINEAR)) { + // Only one arc is collinear; therefore so the supporting curves cannot + // be the same: + return false; + } + + // Check whether the coefficients of the two supporting conics are equal + // up to a constant factor. + Integer factor1 = 1; + Integer factor2 = 1; + + if (CGAL::sign(xcv1.r()) != ZERO) factor1 = xcv1.r(); + else if (CGAL::sign(xcv1.s()) != ZERO) factor1 = xcv1.s(); + else if (CGAL::sign(xcv1.t()) != ZERO) factor1 = xcv1.t(); + else if (CGAL::sign(xcv1.u()) != ZERO) factor1 = xcv1.u(); + else if (CGAL::sign(xcv1.v()) != ZERO) factor1 = xcv1.v(); + else if (CGAL::sign(xcv1.w()) != ZERO) factor1 = xcv1.w(); + + if (CGAL::sign(xcv2.r()) != ZERO) factor2 = xcv2.r(); + else if (CGAL::sign(xcv2.s()) != ZERO) factor2 = xcv2.s(); + else if (CGAL::sign(xcv2.t()) != ZERO) factor2 = xcv2.t(); + else if (CGAL::sign(xcv2.u()) != ZERO) factor2 = xcv2.u(); + else if (CGAL::sign(xcv2.v()) != ZERO) factor2 = xcv2.v(); + else if (CGAL::sign(xcv2.w()) != ZERO) factor2 = xcv2.w(); + + return (CGAL::compare(xcv1.r() * factor2, xcv2.r() * factor1) == EQUAL && + CGAL::compare(xcv1.s() * factor2, xcv2.s() * factor1) == EQUAL && + CGAL::compare(xcv1.t() * factor2, xcv2.t() * factor1) == EQUAL && + CGAL::compare(xcv1.u() * factor2, xcv2.u() * factor1) == EQUAL && + CGAL::compare(xcv1.v() * factor2, xcv2.v() * factor1) == EQUAL && + CGAL::compare(xcv1.w() * factor2, xcv2.w() * factor1) == EQUAL); + } + + /*! Check whether the given point lies on the arc. + * \param p The qury point. + * \param (true) if p lies on the arc; (false) otherwise. + */ + bool contains_point(const X_monotone_curve_2& xcv, const Point_2& p) const { + // First check if p lies on the supporting conic. We first check whether + // it is one of p's generating conic curves. + bool p_on_conic(false); + if (p.is_generating_conic(xcv.id())) p_on_conic = true; + else { + // Check whether p satisfies the supporting conic equation. + p_on_conic = xcv.is_on_supporting_conic(p.x(), p.y()); + if (p_on_conic) { + // As p lies on the supporting conic of our arc, add its ID to + // the list of generating conics for p. + Point_2& p_non_const = const_cast(p); + p_non_const.set_generating_conic(xcv.id()); + } + } + + if (! p_on_conic) return false; + + // Check if p is between the endpoints of the arc. + return is_between_endpoints(xcv, p); + } + + /*! Find the vertical tangency points of the undelying conic. + * \param ps The output points of vertical tangency. + * This area must be allocated at the size of 2. + * \return The number of vertical tangency points. + */ + int conic_vertical_tangency_points(const Curve_2& cv, Alg_point_2* ps) const { + // In case the base conic is of degree 1 (and not 2), the arc has no + // vertical tangency points. + if (CGAL::sign(cv.s()) == ZERO) return 0; + + // We are interested in the x coordinates where the quadratic equation: + // s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0 + // has a single solution (obviously if s = 0, there are no such points). + // We therefore demand that the discriminant of this equation is zero: + // (t*x + v)^2 - 4*s*(r*x^2 + u*x + w) = 0 + const Integer two(2); + const Integer four(4); + Algebraic xs[2]; + + auto r = cv.r(); + auto s = cv.s(); + auto t = cv.t(); + auto u = cv.u(); + auto v = cv.v(); + auto w = cv.w(); + Algebraic* xs_end = m_nt_traits->solve_quadratic_equation(t*t - four*r*s, + two*t*v - four*s*u, + v*v - four*s*w, + xs); + auto n_xs = static_cast(xs_end - xs); + + // Find the y-coordinates of the vertical tangency points. + Algebraic ys[2]; + Algebraic* ys_end; + int n_ys; + + if (CGAL::sign(cv.t()) == ZERO) { + // The two vertical tangency points have the same y coordinate: + ys[0] = m_nt_traits->convert(-v) / m_nt_traits->convert(two*s); + n_ys = 1; + } + else { + ys_end = m_nt_traits->solve_quadratic_equation(four*r*s*s - s*t*t, + four*r*s*v - two*s*t*u, + r*v*v - t*u*v + + t*t*w, + ys); + n_ys = static_cast(ys_end - ys); + } + + // Pair the x and y coordinates and obtain the vertical tangency points. + int n(0); + + for (int i = 0; i < n_xs; ++i) { + if (n_ys == 1) { + ps[n++] = Point_2(xs[i], ys[0]); + } + else { + for (int j = 0; j < n_ys; ++j) { + if (CGAL::compare(m_nt_traits->convert(two*s) * ys[j], + -(m_nt_traits->convert(t) * xs[i] + + m_nt_traits->convert(v))) == EQUAL) + { + ps[n++] = Point_2(xs[i], ys[j]); + break; + } + } + } + } + + CGAL_assertion(n <= 2); + return n; + } + + /*! Calculate the vertical tangency points of the arc. + * \param vpts The vertical tangency points. + * \pre The vpts vector should be allocated at the size of 2. + * \return The number of vertical tangency points. + */ + size_t vertical_tangency_points(const Curve_2& cv, Alg_point_2* vpts) const { + // No vertical tangency points for line segments: + if (cv.orientation() == COLLINEAR) return 0; + + // Calculate the vertical tangency points of the supporting conic. + Alg_point_2 ps[2]; + auto n = conic_vertical_tangency_points(cv, ps); + // Return only the points that are contained in the arc interior. + size_t m(0); + for (int i = 0; i < n; ++i) { + if (cv.is_full_conic() || is_strictly_between_endpoints(cv, ps[i])) + vpts[m++] = ps[i]; + } + + // Return the number of vertical tangency points found. + CGAL_assertion(m <= 2); + return m; + } + + /*! Find the horizontal tangency points of the undelying conic. + * \param ps The output points of horizontal tangency. + * This area must be allocated at the size of 2. + * \return The number of horizontal tangency points. + */ + size_t conic_horizontal_tangency_points(const Curve_2& cv, Alg_point_2* ps) + const { + const Integer zero(0); + + // In case the base conic is of degree 1 (and not 2), the arc has no + // vertical tangency points. + if (CGAL::sign(cv.r()) == ZERO) return 0; + + // We are interested in the y coordinates were the quadratic equation: + // r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0 + // has a single solution (obviously if r = 0, there are no such points). + // We therefore demand that the discriminant of this equation is zero: + // (t*y + u)^2 - 4*r*(s*y^2 + v*y + w) = 0 + const Integer two(2); + const Integer four(4); + Algebraic ys[2]; + + auto r = cv.r(); + auto s = cv.s(); + auto t = cv.t(); + auto u = cv.u(); + auto v = cv.v(); + auto w = cv.w(); + Algebraic* ys_end = m_nt_traits->solve_quadratic_equation(t*t - four*r*s, + two*t*u - four*r*v, + u*u - four*r*w, + ys); + auto n = static_cast(ys_end - ys); + + // Compute the x coordinates and construct the horizontal tangency points. + for (int i = 0; i < n; ++i) { + // Having computed y, x is the single solution to the quadratic equation + // above, and since its discriminant is 0, x is simply given by: + Algebraic x = -(m_nt_traits->convert(t)*ys[i] + m_nt_traits->convert(u)) / + m_nt_traits->convert(two*r); + ps[i] = Point_2(x, ys[i]); + } + + CGAL_assertion(n <= 2); + return n; + } + + /*! Calculate the horizontal tangency points of the arc. + * \param hpts The horizontal tangency points. + * \pre The hpts vector should be allocated at the size of 2. + * \return The number of horizontal tangency points. + */ + int horizontal_tangency_points(const Curve_2& cv, Alg_point_2* hpts) const { + // No horizontal tangency points for line segments: + if (cv.orientation() == COLLINEAR) return 0; + + // Calculate the horizontal tangency points of the conic. + Alg_point_2 ps[2]; + std::size_t n = conic_horizontal_tangency_points(cv, ps); + + // Return only the points that are contained in the arc interior. + int m = 0; + + for (std::size_t i = 0; i < n; ++i) { + if (cv.is_full_conic() || is_strictly_between_endpoints(cv, ps[i])) + hpts[m++] = ps[i]; + } + + // Return the number of horizontal tangency points found. + CGAL_assertion(m <= 2); + return m; + } + + /*! Apply the inverse of the rotation given by the sin and cosine of the + * rotation angle to the given conic arc. + */ + void inverse_conic(const X_monotone_curve_2& xcv, + double cost, double sint, + double& r_m, double& s_m, double& t_m, + double& u_m, double& v_m, double& w_m) const { + auto r = CGAL::to_double(xcv.r()); + auto s = CGAL::to_double(xcv.s()); + auto t = CGAL::to_double(xcv.t()); + auto u = CGAL::to_double(xcv.u()); + auto v = CGAL::to_double(xcv.v()); + auto w = CGAL::to_double(xcv.w()); + + r_m = r * cost*cost + t*cost*sint + s*sint*sint; + t_m = 0; + s_m = r * sint*sint - t*cost*sint + s*cost*cost; + u_m = u*cost + v*sint; + v_m = - u*sint + v*cost; + w_m = w; + } + + /*! Obtain (i) the rotation that yields the given conic arc when applied + * to the canonical arc, and (ii) the canonical arc. + * \param[in] arc the given arc + * \param[out] r_m the coefficients of the canonical conic. + * \param[out] s_m + * \param[out] t_m + * \param[out] u_m + * \param[out] v_m + * \param[out] w_m + * \param[out] cost the cosine of the rotation angle. + * \param[out] sint the sine of the rotation angle. + */ + void canonical_conic(const X_monotone_curve_2& xcv, + double& r_m, double& s_m, double& t_m, + double& u_m, double& v_m, double& w_m, + double& cost, double& sint) const { + auto r = CGAL::to_double(xcv.r()); + auto s = CGAL::to_double(xcv.s()); + auto t = CGAL::to_double(xcv.t()); + // auto u = CGAL::to_double(xcv.u()); + // auto v = CGAL::to_double(xcv.v()); + // auto w = CGAL::to_double(xcv.w()); + // std::cout << r << "," << s << "," << t << "," + // << u << "," << v << "," << w << std::endl; + + // Compute the cos and sin of the rotation angle + // This eliminates the t coefficinet (which multiplies x·y). + + if (r != s) { + auto theta = atan2(t, r-s) * 0.5; + cost = std::cos(theta); + sint = std::sin(theta); + } + else if (r != 0) { + cost = 1.0; + sint = 0.0; + } + else { + cost = std::sqrt(0.5); + sint = cost; + } + + inverse_conic(xcv, cost, sint, r_m, s_m, t_m, u_m, v_m, w_m); + } + + /*! Inverse transform a point. In particular, inversly rotate the point + * (`x`,`y`) by an angle, the sine and cosine of which are `sint` and + * `cost`, respectively, and translate by (`-cx`,`-cy`). + */ + void inverse_transform_point(double x, double y, + double cost, double sint, + double cx, double cy, + double& xc, double& yc) const { + xc = x*cost + y*sint - cx; + yc = -x*sint + y*cost - cy; + } + + /*! Handle parabolas. + * The arc-length closed form can be found here: + * https://www.vcalc.com/wiki/vCalc/Parabola+-+arc+length + */ + void approximate_parabola(const X_monotone_curve_2& xcv, + double& r_m, double& t_m, double& s_m, + double& u_m, double& v_m, double& w_m, + double& cost, double& sint, + double& xs_t, double& ys_t, + double& xt_t, double& yt_t, + double& a, double& ts, double& tt, + double& cx, double& cy, + bool l2r = true) + const { + auto min_vertex = construct_min_vertex_2_object(); + auto max_vertex = construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + + canonical_conic(xcv, r_m, s_m, t_m, u_m, v_m, w_m, cost, sint); + // std::cout << r_m << "," << s_m << "," << t_m << "," + // << u_m << "," << v_m << "," << w_m << std::endl; + // std::cout << "sint, cost: " << sint << "," << cost << std::endl; + + /* If the axis of the parabola is the 𝑌-axis, shift + * the parabola by 90, essentially, converting the + * parabola to one the axis of which is the 𝑋-axis, as the + * remaining code assume that the 𝑋-axis is the parabola axis. + * + * We need to test whether s_m vanished; however, because of limited + * precision, s_m can become very small. Therefore, instead for comparing + * s_m with zero we compare its absolute value with the absolute value of + * r_m, which is expected to be larger. + */ + if (std::abs(s_m) < std::abs(r_m)) { + // Shift phase: + auto tmp(cost); + cost = sint; + sint = -tmp; + + // Recompute: + inverse_conic(xcv, cost, sint, r_m, s_m, t_m, u_m, v_m, w_m); + } + // std::cout << r_m << "," << s_m << "," << t_m << "," + // << u_m << "," << v_m << "," << w_m << std::endl; + + // Compute the center of the inversly rotated parabola: + // double cx_m = -u_m / (2*r_m); + // double cy_m = (u_m*u_m - 4*r_m*w_m) / (4*r_m*v_m); + auto cx_m = (v_m*v_m - 4*s_m*w_m) / (4*s_m*u_m); + auto cy_m = -v_m / (2*s_m); + // std::cout << "cx_m, cy_m: " << cx_m << "," << cy_m << std::endl; + + // Inverse transform the source and target + inverse_transform_point(xs, ys, cost, sint, cx_m, cy_m, xs_t, ys_t); + inverse_transform_point(xt, yt, cost, sint, cx_m, cy_m, xt_t, yt_t); + + a = -u_m / (4.0*s_m); + ts = ys_t / (2.0*a); + tt = yt_t / (2.0*a); + + // Compute the center (cx,cy) of the ellipse, rotating back: + cx = cx_m*cost - cy_m*sint; + cy = cx_m*sint + cy_m*cost; + // std::cout << "center: " << cx << "," << cy << std::endl; + } + + /*! Handle ellipses. + */ + void approximate_ellipse(const X_monotone_curve_2& xcv, + double& r_m, double& t_m, double& s_m, + double& u_m, double& v_m, double& w_m, + double& cost, double& sint, + double& xs_t, double& ys_t, double& ts, + double& xt_t, double& yt_t, double& tt, + double& a, double& b, double& cx, double& cy, + bool l2r = true) + const { + auto min_vertex = construct_min_vertex_2_object(); + auto max_vertex = construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + + canonical_conic(xcv, r_m, s_m, t_m, u_m, v_m, w_m, cost, sint); + // std::cout << r_m << "," << s_m << "," << t_m << "," + // << u_m << "," << v_m << "," << w_m << std::endl; + // std::cout << "sint, cost: " << sint << "," << cost << std::endl; + + // Compute the radi of the ellipse: + auto numerator = -4*w_m*r_m*s_m + s_m*u_m*u_m + r_m*v_m*v_m; + auto a_sqr = numerator / (4*r_m*r_m*s_m); + auto b_sqr = numerator / (4*r_m*s_m*s_m); + if (a_sqr < b_sqr) { + // Shift phase: + auto tmp(cost); + cost = sint; + sint = -tmp; + + // Recompute: + inverse_conic(xcv, cost, sint, r_m, s_m, t_m, u_m, v_m, w_m); + numerator = -4*w_m*r_m*s_m + s_m*u_m*u_m + r_m*v_m*v_m; + a_sqr = numerator / (4*r_m*r_m*s_m); + b_sqr = numerator / (4*r_m*s_m*s_m); + } + + a = std::sqrt(a_sqr); + b = std::sqrt(b_sqr); + + // Compute the center of the inversly rotated ellipse: + auto cx_m = -u_m / (2*r_m); + auto cy_m = -v_m / (2*s_m); + + // Compute the center (cx,cy) of the ellipse, rotating back: + cx = cx_m*cost - cy_m*sint; + cy = cx_m*sint + cy_m*cost; + // std::cout << "center: " << cx << "," << cy << std::endl; + + // Inverse transform the source and target + inverse_transform_point(xs, ys, cost, sint, cx_m, cy_m, xs_t, ys_t); + inverse_transform_point(xt, yt, cost, sint, cx_m, cy_m, xt_t, yt_t); + // std::cout << "xs_t,ys_t: " << xs_t << "," << ys_t << std::endl; + // std::cout << "xt_t,yt_t: " << xt_t << "," << yt_t << std::endl; + + // Compute the parameters ts and tt such that + // source == (x(ts),y(ts)), and + // target == (x(tt),y(tt)) + ts = std::atan2(a*ys_t, b*xs_t); + if (ts < 0) ts += 2*CGAL_PI; + tt = std::atan2(a*yt_t, b*xt_t); + if (tt < 0) tt += 2*CGAL_PI; + auto orient(xcv.orientation()); + if (xcv.source() != src) orient = CGAL::opposite(orient); + if (orient == COUNTERCLOCKWISE) { + if (tt < ts) tt += 2*CGAL_PI; + } + else { + if (ts < tt) ts += 2*CGAL_PI; + } + // std::cout << "ts,tt: " << ts << "," << tt << std::endl; + } + + /*! Handle hyperbolas. + */ + void approximate_hyperbola(const X_monotone_curve_2& xcv, + double& r_m, double& t_m, double& s_m, + double& u_m, double& v_m, double& w_m, + double& cost, double& sint, + double& xs_t, double& ys_t, double& ts, + double& xt_t, double& yt_t, double& tt, + double& a, double& b, double& cx, double& cy, + bool l2r = true) + const { + auto min_vertex = construct_min_vertex_2_object(); + auto max_vertex = construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + // std::cout << "curve: (" << xs << "," << ys + // << ") => (" << xt << "," << yt << ")" + // << std::endl; + + // If the hyperbola conjugate axis is the Y-axis, add + canonical_conic(xcv, r_m, s_m, t_m, u_m, v_m, w_m, cost, sint); + // std::cout << r_m << "," << s_m << "," << t_m << "," + // << u_m << "," << v_m << "," << w_m << std::endl; + // std::cout << "sint, cost: " << sint << "," << cost << std::endl; + + auto numerator = -4*w_m*r_m*s_m + s_m*u_m*u_m + r_m*v_m*v_m; + auto a_sqr = numerator / (4*r_m*r_m*s_m); + auto b_sqr = -numerator / (4*r_m*s_m*s_m); + + /* If the conjugate axis of the canonical hyperbula is the 𝑌-axis, shift + * the canonical hyperbula by 90, essentially, converting the canonical + * hyperbula to one the conjugate axis of which is the 𝑋-axis, as the + * remaining code assume that the conjugate axis is the 𝑋-axis. + * Here, + * 1. a_sqr = -a_sqr, b_sqr = -b_sqr, and + * 2. x(t),y(t) = a*sinh(t), b*cosh(t) + */ + if (a_sqr < 0) { + // Shift phase: + auto tmp(cost); + cost = sint; + sint = -tmp; + + // Recompute: + inverse_conic(xcv, cost, sint, r_m, s_m, t_m, u_m, v_m, w_m); + numerator = -4*w_m*r_m*s_m + s_m*u_m*u_m + r_m*v_m*v_m; + a_sqr = numerator / (4*r_m*r_m*s_m); + b_sqr = -numerator / (4*r_m*s_m*s_m); + } + // std::cout << "sint, cost: " << sint << "," << cost << std::endl; + + // Compute the center of the inversly rotated ellipse: + auto cx_m = -u_m / (2*r_m); + auto cy_m = -v_m / (2*s_m); + + // Inverse transform the source and target + inverse_transform_point(xs, ys, cost, sint, cx_m, cy_m, xs_t, ys_t); + inverse_transform_point(xt, yt, cost, sint, cx_m, cy_m, xt_t, yt_t); + // std::cout << "xs_t,ys_t: " << xs_t << "," << ys_t << std::endl; + // std::cout << "xt_t,yt_t: " << xt_t << "," << yt_t << std::endl; + + // Compute the center (cx,cy) of the hyperbola, rotating back: + cx = cx_m*cost - cy_m*sint; + cy = cx_m*sint + cy_m*cost; + // std::cout << "center: " << cx << "," << cy << std::endl; + + a = std::sqrt(a_sqr); + b = std::sqrt(b_sqr); + + // We use the parametric representation x(t),y(t) = a*cosh(t), b*sinh(t) + // cosh(t) = (e^t + e^(-t))/2 + // sinh(t) = (e^t - e^(-t))/2 + // Compute the parameters ts and tt such that + // source == (x(ts),y(ts)), and + // target == (x(tt),y(tt)) + // Compute the radi of the hyperbola: + ts = std::asinh(ys_t/b); + tt = std::asinh(yt_t/b); + assert(std::signbit(xs_t) == std::signbit(xt_t)); + + if (std::signbit(xs_t)) a = -a; + } }; #include } //namespace CGAL + #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h index 1468d38bc67..c87b4a357e7 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -2834,11 +2835,12 @@ public: /// \name Functor definitions for the landmarks point-location strategy. //@{ - typedef double Approximate_number_type; + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; class Approximate_2 { public: - /*! Return an approximation of a point coordinate. * \param p the exact point. * \param i the coordinate index (either 0 or 1). @@ -2846,11 +2848,23 @@ public: * \return an approximation of p's x-coordinate (if i == 0), or an * approximation of p's y-coordinate (if i == 1). */ - Approximate_number_type operator()(const Point_2& p, int i) const - { - CGAL_precondition(i == 0 || i == 1); + Approximate_number_type operator()(const Point_2& p, int i) const { + CGAL_precondition((i == 0) || (i == 1)); return (i == 0) ? CGAL::to_double(p.x()) : CGAL::to_double(p.y()); } + + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2& p) const + { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& /* xcv */, double /* error */, + OutputIterator /* oi */, bool /* l2r */ = true) const { + CGAL_error_msg("Not implemented yet!"); + } }; /*! Obtain an Approximate_2 function object */ diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_arc_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_arc_2.h index cbff44dbe24..db6c0fccfc8 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_arc_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_arc_2.h @@ -8,29 +8,29 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Ron Wein +// Author(s): Ron Wein +// Efi Fogel #ifndef CGAL_CONIC_ARC_2_H #define CGAL_CONIC_ARC_2_H #include - /*! \file - * Header file for the _Conic_arc_2 class. + * Header file for the Conic_arc_2 class. */ -#include -#include -#include - #include +#include + +// The following is included for the benefit of deprecated functions. +#include +#include + namespace CGAL { - -/*! - * Representation of a conic arc -- a bounded segment that lies on a conic +/*! Representation of a conic arc -- a bounded segment that lies on a conic * curve, the loci of all points satisfying the equation: * r*x^2 + s*y^2 + t*xy + u*x + v*y +w = 0 * @@ -44,16 +44,14 @@ namespace CGAL { * rational and algebraic types. */ -template -class _Conic_arc_2 -{ +template +class Conic_arc_2 { public: + typedef RatKernel Rat_kernel; + typedef AlgKernel Alg_kernel; + typedef NtTraits Nt_traits; - typedef Rat_kernel_ Rat_kernel; - typedef Alg_kernel_ Alg_kernel; - typedef Nt_traits_ Nt_traits; - - typedef _Conic_arc_2 Self; + typedef Conic_arc_2 Self; typedef typename Rat_kernel::FT Rational; typedef typename Rat_kernel::Point_2 Rat_point_2; @@ -63,30 +61,8 @@ public: typedef typename Nt_traits::Integer Integer; typedef typename Alg_kernel::FT Algebraic; - typedef typename Alg_kernel::Point_2 Point_2; - typedef _Conic_point_2 Conic_point_2; - -protected: - - Integer _r; // - Integer _s; // The coefficients of the supporting conic curve: - Integer _t; // - Integer _u; // - Integer _v; // r*x^2 + s*y^2 + t*xy + u*x + v*y +w = 0 . - Integer _w; // - - Orientation _orient; // The orientation of the conic. - - // Bit masks for the _info field. - enum - { - IS_VALID = 1, - IS_FULL_CONIC = 2 - }; - - int _info; // Does the arc represent a full conic curve. - Conic_point_2 _source; // The source of the arc (if not a full curve). - Conic_point_2 _target; // The target of the arc (if not a full curve). + typedef typename Alg_kernel::Point_2 Alg_point_2; + typedef Conic_point_2 Point_2; /*! \struct * For arcs whose base is a hyperbola we store the axis (a*x + b*y + c = 0) @@ -96,76 +72,64 @@ protected: * structure two store the coefficients of the line supporting this segment. * In this case we set the side field to be ZERO. */ - struct Extra_data - { - Algebraic a; - Algebraic b; - Algebraic c; - Sign side; + struct Extra_data { + Algebraic a; + Algebraic b; + Algebraic c; + Sign side; }; - Extra_data *_extra_data_P; // The extra data stored with the arc - // (may be nullptr). + // Bit masks for the m_info field. + enum { + IS_VALID = 0, + IS_FULL_CONIC, + LAST_INFO, + }; + +protected: + Integer m_r; // + Integer m_s; // The coefficients of the supporting conic curve: + Integer m_t; // + Integer m_u; // + Integer m_v; // r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0 + Integer m_w; // + + Orientation m_orient; // The orientation of the conic. + int m_info; // does the arc represent a full conic curve. + Point_2 m_source; // the source of the arc (if not a full curve). + Point_2 m_target; // the target of the arc (if not a full curve). + Extra_data* m_extra_data; // The extra data stored with the arc + // (may be nullptr). public: - - /// \name Construction and destruction functions. + /// \name Deprecated Constructions. //@{ - /*! - * Default constructor. - */ - _Conic_arc_2 () : - _r(0), _s(0), _t(0), _u(0), _v(0), _w(0), - _orient (COLLINEAR), - _info (0), - _extra_data_P (nullptr) - {} - - /*! - * Copy constructor. - * \param arc The copied arc. - */ - _Conic_arc_2 (const Self& arc) : - _r(arc._r), _s(arc._s), _t(arc._t), _u(arc._u), _v(arc._v), _w(arc._w), - _orient (arc._orient), - _info (arc._info), - _source(arc._source), - _target(arc._target) - { - if (arc._extra_data_P != nullptr) - _extra_data_P = new Extra_data (*(arc._extra_data_P)); - else - _extra_data_P = nullptr; - } - - /*! - * Construct a conic arc which is the full conic: + /*!Construct a conic arc which is the full conic: * C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0 * \pre The conic C must be an ellipse (so 4rs - t^2 > 0). */ - _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t, - const Rational& u, const Rational& v, const Rational& w) : - _extra_data_P (nullptr) + CGAL_DEPRECATED Conic_arc_2(const Rational& r, const Rational& s, + const Rational& t, const Rational& u, + const Rational& v, const Rational& w) : + m_info(0), + m_extra_data(nullptr) { - // Make sure the given curve is an ellipse (4rs - t^2 should be positive). - CGAL_precondition (CGAL::sign (4*r*s - t*t) == POSITIVE); + // Ensure that the given curve is an ellipse (4rs - t^2 is positive). + CGAL_precondition(CGAL::sign(4*r*s - t*t) == POSITIVE); // Set the arc to be the full conic (and compute the orientation). - Rational rat_coeffs [6]; - + Rational rat_coeffs[6]; rat_coeffs[0] = r; rat_coeffs[1] = s; rat_coeffs[2] = t; rat_coeffs[3] = u; rat_coeffs[4] = v; rat_coeffs[5] = w; - - _set_full (rat_coeffs, true); + _set_full(rat_coeffs, true); } - /*! - * Construct a conic arc which lies on the conic: + /*! Construct a conic arc which lies on the conic: * C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0 * \param orient The orientation of the arc (clockwise or counterclockwise). * \param source The source point. @@ -173,43 +137,37 @@ public: * \pre The source and the target must be on the conic boundary and must * not be the same. */ - _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t, - const Rational& u, const Rational& v, const Rational& w, - const Orientation& orient, - const Point_2& source, const Point_2& target) : - _orient (orient), - _source (source), - _target (target), - _extra_data_P (nullptr) + CGAL_DEPRECATED + Conic_arc_2(const Rational& r, const Rational& s, const Rational& t, + const Rational& u, const Rational& v, const Rational& w, + const Orientation& orient, + const Point_2& source, const Point_2& target) : + m_orient(orient), + m_source(source), + m_target(target), + m_extra_data(nullptr) { // Make sure that the source and the target are not the same. - CGAL_precondition (Alg_kernel().compare_xy_2_object() (source, - target) != EQUAL); + CGAL_precondition(Alg_kernel().compare_xy_2_object()(source, target) != + EQUAL); // Set the arc properties (no need to compute the orientation). - Rational rat_coeffs [6]; - - rat_coeffs[0] = r; - rat_coeffs[1] = s; - rat_coeffs[2] = t; - rat_coeffs[3] = u; - rat_coeffs[4] = v; - rat_coeffs[5] = w; - - _set (rat_coeffs); + Rational rat_coeffs[6] = {r, s, t, u, v, w}; + _set(rat_coeffs); } /*! Construct a segment conic arc from two endpoints. * \param source the source point with rational coordinates. */ - _Conic_arc_2(const Point_2& source, const Point_2& target) : - _orient (COLLINEAR), - _info(static_cast(IS_VALID)), - _source(source), - _target(target), - _extra_data_P(nullptr) + CGAL_DEPRECATED Conic_arc_2(const Point_2& source, const Point_2& target) : + m_orient(COLLINEAR), + m_info(0), + m_source(source), + m_target(target), + m_extra_data(nullptr) { - CGAL_precondition(Alg_kernel().compare_xy_2_object()(_source, _target) != + set_flag(IS_VALID); + CGAL_precondition(Alg_kernel().compare_xy_2_object()(source, target) != EQUAL); // Compose the equation of the underlying line. @@ -221,57 +179,55 @@ public: // The supporting line is A*x + B*y + C = 0, where: // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 // We use the extra data field to store the equation of this line. - _extra_data_P = new Extra_data; - _extra_data_P->a = y2 - y1; - _extra_data_P->b = x1 - x2; - _extra_data_P->c = x2*y1 - x1*y2; - _extra_data_P->side = ZERO; + m_extra_data = new Extra_data; + m_extra_data->a = y2 - y1; + m_extra_data->b = x1 - x2; + m_extra_data->c = x2*y1 - x1*y2; + m_extra_data->side = ZERO; } - /*! - * Construct a conic arc from the given line segment. + /*! Construct a conic arc from the given line segment. * \param seg The line segment with rational endpoints. */ - _Conic_arc_2 (const Rat_segment_2& seg) : - _orient (COLLINEAR), - _extra_data_P (nullptr) + CGAL_DEPRECATED Conic_arc_2 (const Rat_segment_2& seg) : + m_orient(COLLINEAR), + m_info(0), + m_extra_data(nullptr) { // Set the source and target. - Rat_kernel ker; - Rat_point_2 source = ker.construct_vertex_2_object() (seg, 0); - Rat_point_2 target = ker.construct_vertex_2_object() (seg, 1); - Rational x1 = source.x(); - Rational y1 = source.y(); - Rational x2 = target.x(); - Rational y2 = target.y(); - Nt_traits nt_traits; + Rat_kernel ker; + Rat_point_2 source = ker.construct_vertex_2_object()(seg, 0); + Rat_point_2 target = ker.construct_vertex_2_object()(seg, 1); + Rational x1 = source.x(); + Rational y1 = source.y(); + Rational x2 = target.x(); + Rational y2 = target.y(); + Nt_traits nt_traits; - _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1)); - _target = Point_2 (nt_traits.convert (x2), nt_traits.convert (y2)); + m_source = Point_2(nt_traits.convert (x1), nt_traits.convert(y1)); + m_target = Point_2(nt_traits.convert (x2), nt_traits.convert(y2)); // Make sure that the source and the target are not the same. - CGAL_precondition (Alg_kernel().compare_xy_2_object() (_source, - _target) != EQUAL); + CGAL_precondition (Alg_kernel().compare_xy_2_object()(m_source, m_target) + != EQUAL); // The supporting conic is r=s=t=0, and u*x + v*y + w = 0 should hold // for both the source (x1,y1) and the target (x2, y2). - const Rational _zero (0); - const Rational _one (1); - Rational rat_coeffs [6]; + const Rational zero (0); + const Rational one (1); + Rational rat_coeffs[6]; - rat_coeffs[0] = _zero; - rat_coeffs[1] = _zero; - rat_coeffs[2] = _zero; + rat_coeffs[0] = zero; + rat_coeffs[1] = zero; + rat_coeffs[2] = zero; - if (CGAL::compare (x1, x2) == EQUAL) - { + if (CGAL::compare(x1, x2) == EQUAL) { // The supporting conic is a vertical line, of the form x = CONST. - rat_coeffs[3] = _one; - rat_coeffs[4] = _zero; + rat_coeffs[3] = one; + rat_coeffs[4] = zero; rat_coeffs[5] = -x1; } - else - { + else { // The supporting line is A*x + B*y + C = 0, where: // // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 @@ -282,47 +238,46 @@ public: } // Set the arc properties (no need to compute the orientation). - _set (rat_coeffs); + _set(rat_coeffs); } - /*! - * Set a circular arc that corresponds to a full circle. + /*! Set a circular arc that corresponds to a full circle. * \param circ The circle (with rational center and rational squared radius). */ - _Conic_arc_2 (const Rat_circle_2& circ) : - _orient (CLOCKWISE), - _extra_data_P (nullptr) + CGAL_DEPRECATED Conic_arc_2(const Rat_circle_2& circ) : + m_orient(CLOCKWISE), + m_info(0), + m_extra_data(nullptr) { // Get the circle properties. - Rat_kernel ker; - Rat_point_2 center = ker.construct_center_2_object() (circ); - Rational x0 = center.x(); - Rational y0 = center.y(); - Rational R_sqr = ker.compute_squared_radius_2_object() (circ); + Rat_kernel ker; + Rat_point_2 center = ker.construct_center_2_object()(circ); + Rational x0 = center.x(); + Rational y0 = center.y(); + Rational R_sqr = ker.compute_squared_radius_2_object()(circ); // Produce the corresponding conic: if the circle center is (x0,y0) // and its squared radius is R^2, that its equation is: // x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0 // Note that this equation describes a curve with a negative (clockwise) // orientation. - const Rational _zero (0); - const Rational _one (1); - const Rational _minus_two (-2); - Rational rat_coeffs [6]; + const Rational zero(0); + const Rational one (1); + const Rational minus_two(-2); + Rational rat_coeffs[6]; - rat_coeffs[0] = _one; - rat_coeffs[1] = _one; - rat_coeffs[2] = _zero; - rat_coeffs[3] = _minus_two*x0; - rat_coeffs[4] = _minus_two*y0; + rat_coeffs[0] = one; + rat_coeffs[1] = one; + rat_coeffs[2] = zero; + rat_coeffs[3] = minus_two*x0; + rat_coeffs[4] = minus_two*y0; rat_coeffs[5] = x0*x0 + y0*y0 - R_sqr; // Set the arc to be the full conic (no need to compute the orientation). - _set_full (rat_coeffs, false); + _set_full(rat_coeffs, false); } - /*! - * Set a circular arc that lies on the given circle: + /*! Set a circular arc that lies on the given circle: * C: (x - x0)^2 + (y - y0)^2 = R^2 * \param orient The orientation of the circle. * \param source The source point. @@ -330,128 +285,124 @@ public: * \pre The source and the target must be on the conic boundary and must * not be the same. */ - _Conic_arc_2 (const Rat_circle_2& circ, - const Orientation& orient, - const Point_2& source, const Point_2& target) : - _orient(orient), - _source(source), - _target(target), - _extra_data_P (nullptr) + CGAL_DEPRECATED + Conic_arc_2(const Rat_circle_2& circ, const Orientation& orient, + const Point_2& source, const Point_2& target) : + m_orient(orient), + m_info(0), + m_source(source), + m_target(target), + m_extra_data(nullptr) { // Make sure that the source and the target are not the same. - CGAL_precondition (Alg_kernel().compare_xy_2_object() (source, - target) != EQUAL); - CGAL_precondition (orient != COLLINEAR); + CGAL_precondition(Alg_kernel().compare_xy_2_object()(source, target) != + EQUAL); + CGAL_precondition(orient != COLLINEAR); // Get the circle properties. - Rat_kernel ker; - Rat_point_2 center = ker.construct_center_2_object() (circ); - Rational x0 = center.x(); - Rational y0 = center.y(); - Rational R_sqr = ker.compute_squared_radius_2_object() (circ); + Rat_kernel ker; + Rat_point_2 center = ker.construct_center_2_object()(circ); + Rational x0 = center.x(); + Rational y0 = center.y(); + Rational R_sqr = ker.compute_squared_radius_2_object()(circ); // Produce the corresponding conic: if the circle center is (x0,y0) // and it squared radius is R^2, that its equation is: // x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0 // Since this equation describes a curve with a negative (clockwise) - // orientation, we multiply it by -1 if nece_Conic_arc_2 ssary to obtain a positive - // (counterclockwise) orientation. - const Rational _zero (0); - Rational rat_coeffs[6]; + // orientation, we multiply it by -1 if nece_Conic_arc_2 ssary to obtain a + // positive (counterclockwise) orientation. + const Rational zero (0); + Rational rat_coeffs[6]; - if (_orient == COUNTERCLOCKWISE) - { - const Rational _minus_one (-1); - const Rational _two (2); + if (m_orient == COUNTERCLOCKWISE) { + const Rational minus_one(-1); + const Rational two(2); - rat_coeffs[0] = _minus_one; - rat_coeffs[1] = _minus_one; - rat_coeffs[2] = _zero; - rat_coeffs[3] = _two*x0; - rat_coeffs[4] = _two*y0; + rat_coeffs[0] = minus_one; + rat_coeffs[1] = minus_one; + rat_coeffs[2] = zero; + rat_coeffs[3] = two*x0; + rat_coeffs[4] = two*y0; rat_coeffs[5] = R_sqr - x0*x0 - y0*y0; } - else - { - const Rational _one (1); - const Rational _minus_two (-2); + else { + const Rational one(1); + const Rational minus_two(-2); - rat_coeffs[0] = _one; - rat_coeffs[1] = _one; - rat_coeffs[2] = _zero; - rat_coeffs[3] = _minus_two*x0; - rat_coeffs[4] = _minus_two*y0; + rat_coeffs[0] = one; + rat_coeffs[1] = one; + rat_coeffs[2] = zero; + rat_coeffs[3] = minus_two*x0; + rat_coeffs[4] = minus_two*y0; rat_coeffs[5] = x0*x0 + y0*y0 - R_sqr; } // Set the arc properties (no need to compute the orientation). - _set (rat_coeffs); + _set(rat_coeffs); } - /*! - * Construct a circular arc from the given three points. + /*! Construct a circular arc from the given three points. * \param p1 The arc source. * \param p2 A point in the interior of the arc. * \param p3 The arc target. * \pre The three points must not be collinear. */ - _Conic_arc_2 (const Rat_point_2& p1, - const Rat_point_2& p2, - const Rat_point_2& p3): - _extra_data_P (nullptr) + CGAL_DEPRECATED Conic_arc_2(const Rat_point_2& p1, const Rat_point_2& p2, + const Rat_point_2& p3) : + m_info(0), + m_extra_data(nullptr) { // Set the source and target. - Rational x1 = p1.x(); - Rational y1 = p1.y(); - Rational x2 = p2.x(); - Rational y2 = p2.y(); - Rational x3 = p3.x(); - Rational y3 = p3.y(); - Nt_traits nt_traits; + Rational x1 = p1.x(); + Rational y1 = p1.y(); + Rational x2 = p2.x(); + Rational y2 = p2.y(); + Rational x3 = p3.x(); + Rational y3 = p3.y(); + Nt_traits nt_traits; - _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1)); - _target = Point_2 (nt_traits.convert (x3), nt_traits.convert (y3)); + m_source = Point_2(nt_traits.convert (x1), nt_traits.convert(y1)); + m_target = Point_2(nt_traits.convert (x3), nt_traits.convert(y3)); // Make sure that the source and the target are not the same. - CGAL_precondition (Alg_kernel().compare_xy_2_object() (_source, - _target) != EQUAL); + CGAL_precondition(Alg_kernel().compare_xy_2_object()(m_source, m_target) != + EQUAL); // Compute the lines: A1*x + B1*y + C1 = 0, // and: A2*x + B2*y + C2 = 0, // where: - const Rational _two = 2; + const Rational two = 2; - const Rational A1 = _two*(x1 - x2); - const Rational B1 = _two*(y1 - y2); - const Rational C1 = y2*y2 - y1*y1 + x2*x2 - x1*x1; + const Rational A1 = two*(x1 - x2); + const Rational B1 = two*(y1 - y2); + const Rational C1 = y2*y2 - y1*y1 + x2*x2 - x1*x1; - const Rational A2 = _two*(x2 - x3); - const Rational B2 = _two*(y2 - y3); - const Rational C2 = y3*y3 - y2*y2 + x3*x3 - x2*x2; + const Rational A2 = two*(x2 - x3); + const Rational B2 = two*(y2 - y3); + const Rational C2 = y3*y3 - y2*y2 + x3*x3 - x2*x2; // Compute the coordinates of the intersection point between the // two lines, given by (Nx / D, Ny / D), where: - const Rational Nx = B1*C2 - B2*C1; - const Rational Ny = A2*C1 - A1*C2; - const Rational D = A1*B2 - A2*B1; + const Rational Nx = B1*C2 - B2*C1; + const Rational Ny = A2*C1 - A1*C2; + const Rational D = A1*B2 - A2*B1; // Make sure the three points are not collinear. - const bool points_collinear = (CGAL::sign (D) == ZERO); + const bool points_collinear = (CGAL::sign(D) == ZERO); - if (points_collinear) - { - _info = 0; // Invalid arc. + if (points_collinear) { + reset_flags(); // inavlid arc return; } // The equation of the underlying circle is given by: - Rational rat_coeffs[6]; - + Rational rat_coeffs[6]; rat_coeffs[0] = D*D; rat_coeffs[1] = D*D; rat_coeffs[2] = 0; - rat_coeffs[3] = -_two*D*Nx; - rat_coeffs[4] = -_two*D*Ny; + rat_coeffs[3] = -two*D*Nx; + rat_coeffs[4] = -two*D*Ny; rat_coeffs[5] = Nx*Nx + Ny*Ny - ((D*x2 - Nx)*(D*x2 - Nx) + (D*y2 - Ny)*(D*y2 - Ny)); @@ -459,40 +410,37 @@ public: // the source and the target points, the orientation is positive (going // counterclockwise). // Otherwise, it is negative (going clockwise). - Alg_kernel ker; + Alg_kernel ker; typename Alg_kernel::Orientation_2 orient_f = ker.orientation_2_object(); + Point_2 p_mid = Point_2(nt_traits.convert(x2), nt_traits.convert(y2)); - Point_2 p_mid = Point_2 (nt_traits.convert (x2), nt_traits.convert (y2)); - - if (orient_f(_source, p_mid, _target) == LEFT_TURN) - _orient = COUNTERCLOCKWISE; + if (orient_f(m_source, p_mid, m_target) == LEFT_TURN) + m_orient = COUNTERCLOCKWISE; else - _orient = CLOCKWISE; + m_orient = CLOCKWISE; // Set the arc properties (no need to compute the orientation). - _set (rat_coeffs); + _set(rat_coeffs); } - /*! - * Construct a conic arc from the given five points, specified by the + /*! Construct a conic arc from the given five points, specified by the * points p1, p2, p3, p4 and p5. * \param p1 The source point of the given arc. * \param p2,p3,p4 Points lying on the conic arc, between p1 and p5. * \param p5 The target point of the given arc. * \pre No three points are collinear. */ - _Conic_arc_2 (const Rat_point_2& p1, - const Rat_point_2& p2, - const Rat_point_2& p3, - const Rat_point_2& p4, - const Rat_point_2& p5) : - _extra_data_P(nullptr) + CGAL_DEPRECATED Conic_arc_2(const Rat_point_2& p1, const Rat_point_2& p2, + const Rat_point_2& p3, const Rat_point_2& p4, + const Rat_point_2& p5) : + m_info(0), + m_extra_data(nullptr) { // Make sure that no three points are collinear. - Rat_kernel ker; + Rat_kernel ker; typename Rat_kernel::Orientation_2 orient_f = ker.orientation_2_object(); - const bool point_collinear = + const bool point_collinear = (orient_f (p1, p2, p3) == COLLINEAR || orient_f (p1, p2, p4) == COLLINEAR || orient_f (p1, p2, p5) == COLLINEAR || @@ -504,27 +452,26 @@ public: orient_f (p2, p4, p5) == COLLINEAR || orient_f (p3, p4, p5) == COLLINEAR); - if (point_collinear) - { - _info = 0; // Invalid arc. + if (point_collinear) { + reset_flags(); // inavlid arc return; } // Set the source and target. - Rational x1 = p1.x(); - Rational y1 = p1.y(); - Rational x5 = p5.x(); - Rational y5 = p5.y(); - Nt_traits nt_traits; + Rational x1 = p1.x(); + Rational y1 = p1.y(); + Rational x5 = p5.x(); + Rational y5 = p5.y(); + Nt_traits nt_traits; - _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1)); - _target = Point_2 (nt_traits.convert (x5), nt_traits.convert (y5)); + m_source = Point_2(nt_traits.convert (x1), nt_traits.convert(y1)); + m_target = Point_2(nt_traits.convert (x5), nt_traits.convert(y5)); // Set a conic curve that passes through the five given point. - typename Rat_kernel::Conic_2 temp_conic; - Rational rat_coeffs [6]; + typename Rat_kernel::Conic_2 temp_conic; + Rational rat_coeffs [6]; - temp_conic.set (p1, p2, p3, p4, p5); + temp_conic.set(p1, p2, p3, p4, p5); // Get the conic coefficients. rat_coeffs[0] = temp_conic.r(); @@ -538,43 +485,37 @@ public: // with the source and the target points, the orientation is positive // (going counterclockwise). // Otherwise, it is negative (going clockwise). - const Orientation turn = orient_f(p1, p2, p5); + const Orientation turn = orient_f(p1, p2, p5); - if (turn == LEFT_TURN) - { - _orient = COUNTERCLOCKWISE; - CGAL_precondition (orient_f(p1, p3, p5) == LEFT_TURN && - orient_f(p1, p4, p5) == LEFT_TURN); + if (turn == LEFT_TURN) { + m_orient = COUNTERCLOCKWISE; + CGAL_precondition(orient_f(p1, p3, p5) == LEFT_TURN && + orient_f(p1, p4, p5) == LEFT_TURN); } - else - { - _orient = CLOCKWISE; - CGAL_precondition (orient_f(p1, p3, p5) != LEFT_TURN && - orient_f(p1, p4, p5) != LEFT_TURN); + else { + m_orient = CLOCKWISE; + CGAL_precondition(orient_f(p1, p3, p5) != LEFT_TURN && + orient_f(p1, p4, p5) != LEFT_TURN); } // Set the arc properties (no need to compute the orientation). - _set (rat_coeffs); + _set(rat_coeffs); // Make sure that all midpoints are strictly between the // source and the target. - Point_2 mp2 = Point_2 (nt_traits.convert (p2.x()), - nt_traits.convert (p2.y())); - Point_2 mp3 = Point_2 (nt_traits.convert (p3.x()), - nt_traits.convert (p3.y())); - Point_2 mp4 = Point_2 (nt_traits.convert (p4.x()), - nt_traits.convert (p4.y())); + Point_2 mp2 = Point_2(nt_traits.convert(p2.x()), nt_traits.convert(p2.y())); + Point_2 mp3 = Point_2(nt_traits.convert(p3.x()), nt_traits.convert(p3.y())); + Point_2 mp4 = Point_2(nt_traits.convert(p4.x()), nt_traits.convert(p4.y())); - if (! _is_strictly_between_endpoints (mp2) || - ! _is_strictly_between_endpoints (mp3) || - ! _is_strictly_between_endpoints (mp4)) + if (! _is_strictly_between_endpoints(mp2) || + ! _is_strictly_between_endpoints(mp3) || + ! _is_strictly_between_endpoints(mp4)) { - _info = 0; // Inalvid arc. + reset_flags(); // inavlid arc } } - /*! - * Construct a conic arc which lies on the conic: + /*! Construct a conic arc which lies on the conic: * C: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0 * The source and the target are specified by the intersection of the * conic with: @@ -584,63 +525,53 @@ public: * coordinates. The actual intersection points that best fits the source * (or the target) will be selected. */ - _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t, - const Rational& u, const Rational& v, const Rational& w, - const Orientation& orient, - const Point_2& app_source, - const Rational& r_1, const Rational& s_1, const Rational& t_1, - const Rational& u_1, const Rational& v_1, const Rational& w_1, - const Point_2& app_target, - const Rational& r_2, const Rational& s_2, const Rational& t_2, - const Rational& u_2, const Rational& v_2, const Rational& w_2): - _orient(orient), - _extra_data_P(nullptr) + CGAL_DEPRECATED + Conic_arc_2(const Rational& r, const Rational& s, const Rational& t, + const Rational& u, const Rational& v, const Rational& w, + const Orientation& orient, + const Point_2& app_source, + const Rational& r_1, const Rational& s_1, const Rational& t_1, + const Rational& u_1, const Rational& v_1, const Rational& w_1, + const Point_2& app_target, + const Rational& r_2, const Rational& s_2, const Rational& t_2, + const Rational& u_2, const Rational& v_2, const Rational& w_2): + m_orient(orient), + m_info(0), + m_extra_data(nullptr) { // Create the integer coefficients of the base conic. - Rational rat_coeffs [6]; - Nt_traits nt_traits; - Integer base_coeffs[6]; - int deg_base; - - rat_coeffs[0] = r; - rat_coeffs[1] = s; - rat_coeffs[2] = t; - rat_coeffs[3] = u; - rat_coeffs[4] = v; - rat_coeffs[5] = w; - - nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6, - base_coeffs); + Nt_traits nt_traits; + Integer base_coeffs[6]; + int deg_base; + Rational rat_coeffs [6] = {r, s, t, u, v, w}; + nt_traits.convert_coefficients(rat_coeffs, rat_coeffs + 6, base_coeffs); if (CGAL::sign (base_coeffs[0]) == ZERO && CGAL::sign (base_coeffs[1]) == ZERO && - CGAL::sign (base_coeffs[2]) == ZERO) - { + CGAL::sign (base_coeffs[2]) == ZERO) { deg_base = 1; } - else - { + else { deg_base = 2; } // Compute the endpoints. - Rational aux_rat_coeffs [6]; - Integer aux_coeffs[6]; - int deg_aux; - Algebraic xs[4]; - int n_xs; - Algebraic ys[4]; - int n_ys; - int i, j; - Algebraic val; - bool found; - double dx, dy; - double curr_dist; - double min_dist = -1; - int k; + Rational aux_rat_coeffs [6]; + Integer aux_coeffs[6]; + int deg_aux; + Algebraic xs[4]; + int n_xs; + Algebraic ys[4]; + int n_ys; + int i, j; + Algebraic val; + bool found; + double dx, dy; + double curr_dist; + double min_dist = -1; + int k; - for (k = 1; k <= 2; k++) - { + for (k = 1; k <= 2; ++k) { // Get the integer coefficients of the k'th auxiliary conic curve. aux_rat_coeffs[0] = (k == 1) ? r_1 : r_2; aux_rat_coeffs[1] = (k == 1) ? s_1 : s_2; @@ -649,55 +580,51 @@ public: aux_rat_coeffs[4] = (k == 1) ? v_1 : v_2; aux_rat_coeffs[5] = (k == 1) ? w_1 : w_2; - nt_traits.convert_coefficients (aux_rat_coeffs, aux_rat_coeffs + 6, - aux_coeffs); + nt_traits.convert_coefficients(aux_rat_coeffs, aux_rat_coeffs + 6, + aux_coeffs); if (CGAL::sign (aux_coeffs[0]) == ZERO && CGAL::sign (aux_coeffs[1]) == ZERO && - CGAL::sign (aux_coeffs[2]) == ZERO) - { + CGAL::sign (aux_coeffs[2]) == ZERO) { deg_aux = 1; } - else - { + else { deg_aux = 2; } // Compute the x- and y-coordinates of intersection points of the base // conic and the k'th auxiliary conic. - n_xs = _compute_resultant_roots (nt_traits, - base_coeffs[0], base_coeffs[1], - base_coeffs[2], - base_coeffs[3], base_coeffs[4], - base_coeffs[5], - deg_base, - aux_coeffs[0], aux_coeffs[1], - aux_coeffs[2], - aux_coeffs[3], aux_coeffs[4], - aux_coeffs[5], - deg_aux, - xs); + n_xs = compute_resultant_roots(nt_traits, + base_coeffs[0], base_coeffs[1], + base_coeffs[2], + base_coeffs[3], base_coeffs[4], + base_coeffs[5], + deg_base, + aux_coeffs[0], aux_coeffs[1], + aux_coeffs[2], + aux_coeffs[3], aux_coeffs[4], + aux_coeffs[5], + deg_aux, + xs); - n_ys = _compute_resultant_roots (nt_traits, - base_coeffs[1], base_coeffs[0], - base_coeffs[2], - base_coeffs[4], base_coeffs[3], - base_coeffs[5], - deg_base, - aux_coeffs[1], aux_coeffs[0], - aux_coeffs[2], - aux_coeffs[4], aux_coeffs[3], - aux_coeffs[5], - deg_aux, - ys); + n_ys = compute_resultant_roots(nt_traits, + base_coeffs[1], base_coeffs[0], + base_coeffs[2], + base_coeffs[4], base_coeffs[3], + base_coeffs[5], + deg_base, + aux_coeffs[1], aux_coeffs[0], + aux_coeffs[2], + aux_coeffs[4], aux_coeffs[3], + aux_coeffs[5], + deg_aux, + ys); // Find the intersection point which is nearest the given approximation // and set it as the endpoint. found = false; - for (i = 0; i < n_xs; i++) - { - for (j = 0; j < n_ys; j++) - { + for (i = 0; i < n_xs; ++i) { + for (j = 0; j < n_ys; ++j) { // Check if the point (xs[i], ys[j]) lies on both conics. val = nt_traits.convert(base_coeffs[0]) * xs[i]*xs[i] + nt_traits.convert(base_coeffs[1]) * ys[j]*ys[j] + @@ -706,8 +633,7 @@ public: nt_traits.convert(base_coeffs[4]) * ys[j] + nt_traits.convert(base_coeffs[5]); - if (CGAL::sign (val) != ZERO) - continue; + if (CGAL::sign (val) != ZERO) continue; val = nt_traits.convert(aux_coeffs[0]) * xs[i]*xs[i] + nt_traits.convert(aux_coeffs[1]) * ys[j]*ys[j] + @@ -716,17 +642,14 @@ public: nt_traits.convert(aux_coeffs[4]) * ys[j] + nt_traits.convert(aux_coeffs[5]); - if (CGAL::sign (val) == ZERO) - { + if (CGAL::sign (val) == ZERO) { // Compute the distance of (xs[i], ys[j]) from the approximated // endpoint. - if (k == 1) - { + if (k == 1) { dx = CGAL::to_double (xs[i] - app_source.x()); dy = CGAL::to_double (ys[j] - app_source.y()); } - else - { + else { dx = CGAL::to_double (xs[i] - app_target.x()); dy = CGAL::to_double (ys[j] - app_target.y()); } @@ -735,13 +658,9 @@ public: // Update the endpoint if (xs[i], ys[j]) is the nearest pair so // far. - if (! found || curr_dist < min_dist) - { - if (k == 1) - _source = Point_2 (xs[i], ys[j]); - else - _target = Point_2 (xs[i], ys[j]); - + if (! found || curr_dist < min_dist) { + if (k == 1) m_source = Point_2 (xs[i], ys[j]); + else m_target = Point_2 (xs[i], ys[j]); min_dist = curr_dist; found = true; } @@ -749,180 +668,45 @@ public: } } - if (! found) - { - _info = 0; // Invalid arc. + if (! found) { + reset_flags(); // inavlid arc return; } } // Make sure that the source and the target are not the same. - if (Alg_kernel().compare_xy_2_object() (_source, - _target) == EQUAL) - { - _info = 0; // Invalid arc. + if (Alg_kernel().compare_xy_2_object()(m_source, m_target) == EQUAL) { + reset_flags(); // inavlid arc return; } // Set the arc properties (no need to compute the orientation). - _set (rat_coeffs); + _set(rat_coeffs); } - /*! - * Destructor. - */ - virtual ~_Conic_arc_2 () - { - if (_extra_data_P != nullptr) - delete _extra_data_P; - } - - /*! - * Assignment operator. - * \param arc The copied arc. - */ - const Self& operator= (const Self& arc) - { - if (this == &arc) - return (*this); - - // Free any existing data. - if (_extra_data_P != nullptr) - delete _extra_data_P; - - // Copy the arc's attributes. - _r = arc._r; - _s = arc._s; - _t = arc._t; - _u = arc._u; - _v = arc._v; - _w = arc._w; - - _orient = arc._orient; - _info = arc._info; - _source = arc._source; - _target = arc._target; - - // Duplicate the extra data, if necessary. - if (arc._extra_data_P != nullptr) - _extra_data_P = new Extra_data (*(arc._extra_data_P)); - else - _extra_data_P = nullptr; - - return (*this); - } - //@} - - /// \name Get the arc properties. - //@{ - - /*! - * Check if the arc is valid. - */ - bool is_valid () const - { - return ((_info & IS_VALID) != 0); - } - - /*! - * Get the coefficients of the underlying conic. - */ - const Integer& r () const {return (_r);} - const Integer& s () const {return (_s);} - const Integer& t () const {return (_t);} - const Integer& u () const {return (_u);} - const Integer& v () const {return (_v);} - const Integer& w () const {return (_w);} - - /*! - * Check whether the arc is x-monotone. - */ - bool is_x_monotone () const - { - // Check if the arc contains no vertical tangency points. - Point_2 vtan_ps[2]; - return (vertical_tangency_points (vtan_ps) == 0); - } - - /*! - * Check whether the arc is y-monotone. - */ - bool is_y_monotone () const - { - // Check if the arc contains no horizontal tangency points. - Point_2 htan_ps[2]; - return (horizontal_tangency_points (htan_ps) == 0); - } - - /*! - * Check whether the arc represents a full conic curve. - */ - bool is_full_conic () const - { - return ((_info & IS_FULL_CONIC) != 0); - } - - /*! - * Get the arc's source. - * \return The source point. - * \pre The arc does not represent a full conic curve. - */ - const Point_2& source () const - { - CGAL_precondition (! is_full_conic()); - - return (_source); - } - - /*! - * Get the arc's target. - * \return The target point. - * \pre The arc does not represent a full conic curve. - */ - const Point_2& target () const - { - CGAL_precondition (! is_full_conic()); - - return (_target); - } - - /*! - * Get the orientation of the arc. - * \return The orientation. - */ - Orientation orientation () const - { - return (_orient); - } - - /*! - * Get a bounding box for the conic arc. + /*! Get a bounding box for the conic arc. * \return The bounding box. */ - Bbox_2 bbox () const - { + CGAL_DEPRECATED Bbox_2 bbox() const { CGAL_precondition (is_valid()); - double x_min = 0, y_min = 0; - double x_max = 0, y_max = 0; + double x_min(0), y_min(0); + double x_max(0), y_max(0); - if (is_full_conic()) - { + if (is_full_conic()) { // In case of a full conic (an ellipse or a circle), compute the // horizontal and vertical tangency points and use them to bound the arc. - Point_2 tan_ps[2]; + Point_2 tan_ps[2]; CGAL_assertion_code(int n_tan_ps); CGAL_assertion_code(n_tan_ps = vertical_tangency_points(tan_ps)); CGAL_assertion(n_tan_ps == 2); - if (CGAL::to_double(tan_ps[0].x()) < CGAL::to_double(tan_ps[1].x())) - { + if (CGAL::to_double(tan_ps[0].x()) < CGAL::to_double(tan_ps[1].x())) { x_min = CGAL::to_double(tan_ps[0].x()); x_max = CGAL::to_double(tan_ps[1].x()); } - else - { + else { x_min = CGAL::to_double(tan_ps[1].x()); x_max = CGAL::to_double(tan_ps[0].x()); } @@ -930,42 +714,38 @@ public: CGAL_assertion_code(n_tan_ps = horizontal_tangency_points(tan_ps)); CGAL_assertion(n_tan_ps == 2); - if (CGAL::to_double(tan_ps[0].y()) < CGAL::to_double(tan_ps[1].y())) - { + if (CGAL::to_double(tan_ps[0].y()) < CGAL::to_double(tan_ps[1].y())) { y_min = CGAL::to_double(tan_ps[0].y()); y_max = CGAL::to_double(tan_ps[1].y()); } - else - { + else { y_min = CGAL::to_double(tan_ps[1].y()); y_max = CGAL::to_double(tan_ps[0].y()); } } - else - { - // Use the source and target to initialize the extreme points. + else { + // Use the source and target to initialize the exterme points. bool source_left = - CGAL::to_double(_source.x()) < CGAL::to_double(_target.x()); + CGAL::to_double(m_source.x()) < CGAL::to_double(m_target.x()); x_min = source_left ? - CGAL::to_double(_source.x()) : CGAL::to_double(_target.x()); + CGAL::to_double(m_source.x()) : CGAL::to_double(m_target.x()); x_max = source_left ? - CGAL::to_double(_target.x()) : CGAL::to_double(_source.x()); + CGAL::to_double(m_target.x()) : CGAL::to_double(m_source.x()); - bool source_down = - CGAL::to_double(_source.y()) < CGAL::to_double(_target.y()); + bool source_down = + CGAL::to_double(m_source.y()) < CGAL::to_double(m_target.y()); y_min = source_down ? - CGAL::to_double(_source.y()) : CGAL::to_double(_target.y()); + CGAL::to_double(m_source.y()) : CGAL::to_double(m_target.y()); y_max = source_down ? - CGAL::to_double(_target.y()) : CGAL::to_double(_source.y()); + CGAL::to_double(m_target.y()) : CGAL::to_double(m_source.y()); // Go over the vertical tangency points and try to update the x-points. - Point_2 tan_ps[2]; - int n_tan_ps; - int i; + Alg_point_2 tan_ps[2]; + int n_tan_ps; + int i; - n_tan_ps = vertical_tangency_points (tan_ps); - for (i = 0; i < n_tan_ps; i++) - { + n_tan_ps = vertical_tangency_points(tan_ps); + for (i = 0; i < n_tan_ps; ++i) { if (CGAL::to_double(tan_ps[i].x()) < x_min) x_min = CGAL::to_double(tan_ps[i].x()); if (CGAL::to_double(tan_ps[i].x()) > x_max) @@ -973,9 +753,8 @@ public: } // Go over the horizontal tangency points and try to update the y-points. - n_tan_ps = horizontal_tangency_points (tan_ps); - for (i = 0; i < n_tan_ps; i++) - { + n_tan_ps = horizontal_tangency_points(tan_ps); + for (i = 0; i < n_tan_ps; ++i) { if (CGAL::to_double(tan_ps[i].y()) < y_min) y_min = CGAL::to_double(tan_ps[i].y()); if (CGAL::to_double(tan_ps[i].y()) > y_max) @@ -984,398 +763,340 @@ public: } // Return the resulting bounding box. - return (Bbox_2 (x_min, y_min, x_max, y_max)); - } - //@} - - /// \name Modifying functions. - //@{ - - /*! - * Set the source point of the conic arc. - * \param ps The new source point. - * \pre The arc is not a full conic curve. - * ps must lie on the supporting conic curve. - */ - void set_source (const Point_2& ps) - { - CGAL_precondition (! is_full_conic()); - CGAL_precondition (_is_on_supporting_conic (ps)); - CGAL_precondition (Alg_kernel().orientation_2_object() - (_source, ps, _target) == _orient || - Alg_kernel().orientation_2_object() - (ps, _source, _target) == _orient); - - _source = ps; - return; - } - - /*! - * Set the target point of the conic arc. - * \param pt The new source point. - * \pre The arc is not a full conic curve. - * pt must lie on the supporting conic curve. - */ - void set_target (const Point_2& pt) - { - CGAL_precondition (! is_full_conic()); - CGAL_precondition (_is_on_supporting_conic (pt)); - CGAL_precondition (Alg_kernel().orientation_2_object() - (_source, pt, _target) == _orient || - Alg_kernel().orientation_2_object() - (_source, _target, pt) == _orient); - - _target = pt; - return; + return Bbox_2(x_min, y_min, x_max, y_max); } //@} - /// \name Compute points on the arc. - //@{ - - /*! - * Calculate the vertical tangency points of the arc. +protected: + /*! Calculate the vertical tangency points of the arc. * \param vpts The vertical tangency points. * \pre The vpts vector should be allocated at the size of 2. * \return The number of vertical tangency points. */ - int vertical_tangency_points (Point_2* vpts) const - { + CGAL_DEPRECATED int vertical_tangency_points(Alg_point_2* vpts) const { // No vertical tangency points for line segments: - if (_orient == COLLINEAR) - return (0); + if (m_orient == COLLINEAR) return 0; // Calculate the vertical tangency points of the supporting conic. - Point_2 ps[2]; - int n; - - n = _conic_vertical_tangency_points (ps); + Alg_point_2 ps[2]; + int n = _conic_vertical_tangency_points(ps); // Return only the points that are contained in the arc interior. - int m = 0; + int m(0); - for (int i = 0; i < n; i++) - { - if (is_full_conic() || _is_strictly_between_endpoints(ps[i])) - { + for (int i = 0; i < n; ++i) { + if (is_full_conic() || _is_strictly_between_endpoints(ps[i])) { vpts[m] = ps[i]; - m++; + ++m; } } // Return the number of vertical tangency points found. - CGAL_assertion (m <= 2); - return (m); + CGAL_assertion(m <= 2); + return m; } - /*! - * Calculate the horizontal tangency points of the arc. + /*! Calculate the horizontal tangency points of the arc. * \param hpts The horizontal tangency points. * \pre The hpts vector should be allocated at the size of 2. * \return The number of horizontal tangency points. */ - int horizontal_tangency_points (Point_2* hpts) const - { + CGAL_DEPRECATED int horizontal_tangency_points(Alg_point_2* hpts) const { // No horizontal tangency points for line segments: - if (_orient == COLLINEAR) - return (0); + if (m_orient == COLLINEAR) return 0; // Calculate the horizontal tangency points of the conic. - Point_2 ps[2]; - int n; - - n = _conic_horizontal_tangency_points (ps); + Alg_point_2 ps[2]; + int n = _conic_horizontal_tangency_points(ps); // Return only the points that are contained in the arc interior. - int m = 0; + int m = 0; - for (int i = 0; i < n; i++) - { - if (is_full_conic() || _is_strictly_between_endpoints(ps[i])) - { + for (int i = 0; i < n; ++i) { + if (is_full_conic() || _is_strictly_between_endpoints(ps[i])) { hpts[m] = ps[i]; - m++; + ++m; } } // Return the number of horizontal tangency points found. - CGAL_assertion (m <= 2); - return (m); + CGAL_assertion(m <= 2); + return m; } - /*! - * Find all points on the arc with a given x-coordinate. - * \param p A placeholder for the x-coordinate. - * \param ps The point on the arc at x(p). - * \pre The vector ps should be allocated at the size of 2. - * \return The number of points found. + /*! Check whether the given point is strictly between the source and the + * target (but not any of them). + * The point is assumed to be on the conic's boundary. + * \param p The query point. + * \return (true) if the point is strictly between the two endpoints, + * (false) if it is not. */ - int points_at_x (const Point_2& p, - Point_2 *ps) const - { - // Get the y coordinates of the points on the conic. - Algebraic ys[2]; - int n; + CGAL_DEPRECATED bool _is_strictly_between_endpoints(const Point_2& p) const { + // In case this is a full conic, any point on its boundary is between + // its end points. + if (is_full_conic()) return true; - n = _conic_get_y_coordinates (p.x(), ys); - - // Find all the points that are contained in the arc. - int m = 0; - - for (int i = 0; i < n; i++) - { - ps[m] = Point_2 (p.x(), ys[i]); - - if (is_full_conic() || _is_between_endpoints(ps[m])) - m++; - } - - // Return the number of points on the arc. - CGAL_assertion (m <= 2); - return (m); - } - - /*! - * Find all points on the arc with a given y-coordinate. - * \param p A placeholder for the y-coordinate. - * \param ps The point on the arc at x(p). - * \pre The vector ps should be allocated at the size of 2. - * \return The number of points found. - */ - int points_at_y (const Point_2& p, - Point_2 *ps) const - { - // Get the y coordinates of the points on the conic. - Algebraic xs[2]; - int n; - - n = _conic_get_x_coordinates (p.y(), xs); - - // Find all the points that are contained in the arc. - int m = 0; - - for (int i = 0; i < n; i++) - { - ps[m] = Point_2 (xs[i], p.y()); - - if (is_full_conic() || _is_between_endpoints(ps[m])) - m++; - } - - // Return the number of points on the arc. - CGAL_assertion (m <= 2); - return (m); - } - //@} - -private: - - /// \name Auxiliary construction functions. - //@{ - - /*! - * Set the properties of a conic arc (for the usage of the constructors). - * \param rat_coeffs A vector of size 6, storing the rational coefficients - * of x^2, y^2, xy, x, y and the free coefficient resp. - */ - void _set (const Rational* rat_coeffs) - { - _info = IS_VALID; - - // Convert the coefficients vector to an equivalent vector of integer - // coefficients. - Nt_traits nt_traits; - Integer int_coeffs[6]; - - nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6, - int_coeffs); - - // Check the orientation of conic curve, and negate the conic coefficients - // if its given orientation. - typename Rat_kernel::Conic_2 temp_conic (rat_coeffs[0], rat_coeffs[1], - rat_coeffs[2], rat_coeffs[3], - rat_coeffs[4], rat_coeffs[5]); - - if (_orient == temp_conic.orientation()) - { - _r = int_coeffs[0]; - _s = int_coeffs[1]; - _t = int_coeffs[2]; - _u = int_coeffs[3]; - _v = int_coeffs[4]; - _w = int_coeffs[5]; - } - else - { - _r = -int_coeffs[0]; - _s = -int_coeffs[1]; - _t = -int_coeffs[2]; - _u = -int_coeffs[3]; - _v = -int_coeffs[4]; - _w = -int_coeffs[5]; - } - - // Make sure both endpoint lie on the supporting conic. - if (! _is_on_supporting_conic (_source) || - ! _is_on_supporting_conic (_target)) - { - _info = 0; // Invalid arc. - return; - } - - _extra_data_P = nullptr; - - // Check whether we have a degree 2 curve. - if ((CGAL::sign (_r) != ZERO || - CGAL::sign (_s) != ZERO || - CGAL::sign (_t) != ZERO)) - { - if (_orient == COLLINEAR) - { - // We have a segment of a line pair with rational coefficients. - // Compose the equation of the underlying line - // (with algebraic coefficients). - const Algebraic x1 = _source.x(), y1 = _source.y(); - const Algebraic x2 = _target.x(), y2 = _target.y(); - - // The supporting line is A*x + B*y + C = 0, where: - // - // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 - // - // We use the extra dat field to store the equation of this line. - _extra_data_P = new Extra_data; - _extra_data_P->a = y2 - y1; - _extra_data_P->b = x1 - x2; - _extra_data_P->c = x2*y1 - x1*y2; - _extra_data_P->side = ZERO; - - // Make sure the midpoint is on the line pair (thus making sure that - // the two points are not taken from different lines). - Alg_kernel ker; - Point_2 p_mid = ker.construct_midpoint_2_object() (_source, - _target); - - if (CGAL::sign ((nt_traits.convert(_r)*p_mid.x() + - nt_traits.convert(_t)*p_mid.y() + - nt_traits.convert(_u)) * p_mid.x() + - (nt_traits.convert(_s)*p_mid.y() + - nt_traits.convert(_v)) * p_mid.y() + - nt_traits.convert(_w)) != ZERO) - { - _info = 0; // Invalid arc. - return; - } + // Check if we have extra data available. + if (m_extra_data != nullptr) { + if (m_extra_data->side != ZERO) { + // In case of a hyperbolic arc, make sure the point is located on the + // same branch as the arc. + if (sign_of_extra_data(p.x(), p.y()) != m_extra_data->side) + return false; } + else { + // In case we have a segment of a line pair, make sure that p really + // satisfies the equation of the line. + if (sign_of_extra_data(p.x(), p.y()) != ZERO) return false; + } + } + + // Act according to the conic degree. + Alg_kernel ker; + + if (m_orient == COLLINEAR) { + Comparison_result res1; + Comparison_result res2; + + if (ker.compare_x_2_object()(m_source, m_target) == EQUAL) { + // In case of a vertical segment - just check whether the y coordinate + // of p is between those of the source's and of the target's. + res1 = ker.compare_y_2_object()(p, m_source); + res2 = ker.compare_y_2_object()(p, m_target); + } + else { + // Otherwise, since the segment is x-monotone, just check whether the + // x coordinate of p is between those of the source's and of the + // target's. + res1 = ker.compare_x_2_object()(p, m_source); + res2 = ker.compare_x_2_object()(p, m_target); + } + + // If p is not in the (open) x-range (or y-range) of the segment, it + // cannot be contained in the segment. + if (res1 == EQUAL || res2 == EQUAL || res1 == res2) return false; + + // Perform an orientation test: This is crucial for segment of line + // pairs, as we want to make sure that p lies on the same line as the + // source and the target. + return (ker.orientation_2_object()(m_source, p, m_target) == COLLINEAR); + } + else { + // In case of a conic of degree 2, make a decision based on the conic's + // orientation and whether (source,p,target) is a right or a left turn. + if (m_orient == COUNTERCLOCKWISE) + return (ker.orientation_2_object()(m_source, p, m_target) == LEFT_TURN); else - { - // The sign of (4rs - t^2) detetmines the conic type: - // - if it is positive, the conic is an ellipse, - // - if it is negative, the conic is a hyperbola, - // - if it is zero, the conic is a parabola. - CGAL::Sign sign_conic = CGAL::sign (4*_r*_s - _t*_t); + return (ker.orientation_2_object()(m_source, p, m_target) == RIGHT_TURN); + } + } - if (sign_conic == NEGATIVE) - // Build the extra hyperbolic data - _build_hyperbolic_arc_data (); + /*! Find the vertical tangency points of the undelying conic. + * \param ps The output points of vertical tangency. + * This area must be allocated at the size of 2. + * \return The number of vertical tangency points. + */ + CGAL_DEPRECATED + int _conic_vertical_tangency_points(Alg_point_2* ps) const { + const auto& cv = *this; + Nt_traits nt_traits; - if (sign_conic != POSITIVE) - { - // In case of a non-degenerate parabola or a hyperbola, make sure - // the arc is not infinite. - Alg_kernel ker; - Point_2 p_mid = ker.construct_midpoint_2_object() (_source, - _target); - Point_2 ps[2]; + // In case the base conic is of degree 1 (and not 2), the arc has no + // vertical tangency points. + if (CGAL::sign(cv.s()) == ZERO) return 0; - bool finite_at_x = (points_at_x(p_mid, ps) > 0); - bool finite_at_y = (points_at_y(p_mid, ps) > 0); + // We are interested in the x coordinates where the quadratic equation: + // s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0 + // has a single solution (obviously if s = 0, there are no such points). + // We therefore demand that the discriminant of this equation is zero: + // (t*x + v)^2 - 4*s*(r*x^2 + u*x + w) = 0 + const Integer two(2); + const Integer four(4); + Algebraic xs[2]; - if (! finite_at_x && ! finite_at_y) + auto r = cv.r(); + auto s = cv.s(); + auto t = cv.t(); + auto u = cv.u(); + auto v = cv.v(); + auto w = cv.w(); + Algebraic* xs_end = nt_traits.solve_quadratic_equation(t*t - four*r*s, + two*t*v - four*s*u, + v*v - four*s*w, + xs); + auto n_xs = static_cast(xs_end - xs); + + // Find the y-coordinates of the vertical tangency points. + Algebraic ys[2]; + Algebraic* ys_end; + int n_ys; + + if (CGAL::sign(cv.t()) == ZERO) { + // The two vertical tangency points have the same y coordinate: + ys[0] = nt_traits.convert(-v) / nt_traits.convert(two*s); + n_ys = 1; + } + else { + ys_end = nt_traits.solve_quadratic_equation(four*r*s*s - s*t*t, + four*r*s*v - two*s*t*u, + r*v*v - t*u*v + + t*t*w, + ys); + n_ys = static_cast(ys_end - ys); + } + + // Pair the x and y coordinates and obtain the vertical tangency points. + int n(0); + + for (int i = 0; i < n_xs; ++i) { + if (n_ys == 1) { + ps[n++] = Point_2(xs[i], ys[0]); + } + else { + for (int j = 0; j < n_ys; ++j) { + if (CGAL::compare(nt_traits.convert(two*s) * ys[j], + -(nt_traits.convert(t) * xs[i] + + nt_traits.convert(v))) == EQUAL) { - _info = 0; // Invalid arc. - return; + ps[n++] = Point_2(xs[i], ys[j]); + break; } } } } - // Mark that this arc valid and is not a full conic curve. - _info = IS_VALID; - - return; + CGAL_assertion(n <= 2); + return n; } - /*! - * Set the properties of a conic arc that is really a full curve + /*! Find the horizontal tangency points of the undelying conic. + * \param ps The output points of horizontal tangency. + * This area must be allocated at the size of 2. + * \return The number of horizontal tangency points. + */ + CGAL_DEPRECATED + size_t _conic_horizontal_tangency_points(Alg_point_2* ps) const { + const auto& cv = *this; + Nt_traits nt_traits; + + const Integer zero(0); + + // In case the base conic is of degree 1 (and not 2), the arc has no + // vertical tangency points. + if (CGAL::sign(cv.r()) == ZERO) return 0; + + // We are interested in the y coordinates were the quadratic equation: + // r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0 + // has a single solution (obviously if r = 0, there are no such points). + // We therefore demand that the discriminant of this equation is zero: + // (t*y + u)^2 - 4*r*(s*y^2 + v*y + w) = 0 + const Integer two(2); + const Integer four(4); + Algebraic ys[2]; + + auto r = cv.r(); + auto s = cv.s(); + auto t = cv.t(); + auto u = cv.u(); + auto v = cv.v(); + auto w = cv.w(); + Algebraic* ys_end = nt_traits.solve_quadratic_equation(t*t - four*r*s, + two*t*u - four*r*v, + u*u - four*r*w, + ys); + auto n = static_cast(ys_end - ys); + + // Compute the x coordinates and construct the horizontal tangency points. + for (int i = 0; i < n; ++i) { + // Having computed y, x is the single solution to the quadratic equation + // above, and since its discriminant is 0, x is simply given by: + Algebraic x = -(nt_traits.convert(t)*ys[i] + nt_traits.convert(u)) / + nt_traits.convert(two*r); + ps[i] = Point_2(x, ys[i]); + } + + CGAL_assertion(n <= 2); + return n; + } + + /*! Set the properties of a conic arc that is really a full curve * (that is, an ellipse). * \param rat_coeffs A vector of size 6, storing the rational coefficients * of x^2, y^2, xy, x, y and the free coefficient resp. * \param comp_orient Should we compute the orientation of the given curve. */ - void _set_full (const Rational* rat_coeffs, - const bool& comp_orient) - { + CGAL_DEPRECATED + void _set_full(const Rational* rat_coeffs, const bool& comp_orient) { // Convert the coefficients vector to an equivalent vector of integer // coefficients. - Nt_traits nt_traits; - Integer int_coeffs[6]; + Nt_traits nt_traits; + Integer int_coeffs[6]; - nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6, - int_coeffs); + nt_traits.convert_coefficients(rat_coeffs, rat_coeffs + 6, int_coeffs); // Check the orientation of conic curve, and negate the conic coefficients // if its given orientation. - typename Rat_kernel::Conic_2 temp_conic (rat_coeffs[0], rat_coeffs[1], - rat_coeffs[2], rat_coeffs[3], - rat_coeffs[4], rat_coeffs[5]); - const Orientation temp_orient = temp_conic.orientation(); + typename Rat_kernel::Conic_2 temp_conic(rat_coeffs[0], rat_coeffs[1], + rat_coeffs[2], rat_coeffs[3], + rat_coeffs[4], rat_coeffs[5]); + const Orientation temp_orient = temp_conic.orientation(); - if (comp_orient) - _orient = temp_orient; + if (comp_orient) set_orientation(temp_orient); - if (_orient == temp_orient) - { - _r = int_coeffs[0]; - _s = int_coeffs[1]; - _t = int_coeffs[2]; - _u = int_coeffs[3]; - _v = int_coeffs[4]; - _w = int_coeffs[5]; + if (orientation() == temp_orient) { + m_r = int_coeffs[0]; + m_s = int_coeffs[1]; + m_t = int_coeffs[2]; + m_u = int_coeffs[3]; + m_v = int_coeffs[4]; + m_w = int_coeffs[5]; } - else - { - _r = -int_coeffs[0]; - _s = -int_coeffs[1]; - _t = -int_coeffs[2]; - _u = -int_coeffs[3]; - _v = -int_coeffs[4]; - _w = -int_coeffs[5]; + else { + m_r = -int_coeffs[0]; + m_s = -int_coeffs[1]; + m_t = -int_coeffs[2]; + m_u = -int_coeffs[3]; + m_v = -int_coeffs[4]; + m_w = -int_coeffs[5]; } // Make sure the conic is a non-degenerate ellipse: // The coefficients should satisfy (4rs - t^2) > 0. - const bool is_ellipse = (CGAL::sign (4*_r*_s - _t*_t) == POSITIVE); - CGAL_assertion (is_ellipse); - - // We do not have to store any extra data with the arc. - _extra_data_P = nullptr; + const bool is_ellipse = (CGAL::sign(4*m_r*m_s - m_t*m_t) == POSITIVE); + CGAL_assertion(is_ellipse); // Mark that this arc is a full conic curve. - if (is_ellipse) - _info = IS_VALID | IS_FULL_CONIC; - else - _info = 0; - - return; + if (is_ellipse) { + set_flag(IS_VALID); + set_flag(IS_FULL_CONIC); + } + else reset_flags(); // inavlid arc } - /*! - * Build the data for hyperbolic arc, containing the characterization of the + /*! Check whether the given point lies on the supporting conic of the arc. + * \param p The query point. + * \return (true) if p lies on the supporting conic; (false) otherwise. + */ + CGAL_DEPRECATED bool _is_on_supporting_conic(const Point_2& p) const { + // Check whether p satisfies the conic equation. + // The point must satisfy: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0. + Nt_traits nt_traits; + const Algebraic val = + (nt_traits.convert(m_r)*p.x() + + nt_traits.convert(m_t)*p.y() + + nt_traits.convert(m_u)) * p.x() + + (nt_traits.convert(m_s)*p.y() + + nt_traits.convert(m_v)) * p.y() + + nt_traits.convert(m_w); + + return (CGAL::sign(val) == ZERO); + } + + /*! Build the data for hyperbolic arc, contaning the characterization of the * hyperbolic branch the arc is placed on. */ - void _build_hyperbolic_arc_data () - { + CGAL_DEPRECATED void _build_hyperbolic_arc_data() { // Let phi be the rotation angle of the conic from its canonic form. // We can write: // @@ -1387,51 +1108,47 @@ private: // cos(2*phi) = ----------------------- // sqrt((r - s)^2 + t^2) // - Nt_traits nt_traits; - const int or_fact = (_orient == CLOCKWISE) ? -1 : 1; - const Algebraic r = nt_traits.convert (or_fact * _r); - const Algebraic s = nt_traits.convert (or_fact * _s); - const Algebraic t = nt_traits.convert (or_fact * _t); - const Algebraic cos_2phi = (r - s) / nt_traits.sqrt((r-s)*(r-s) + t*t); - const Algebraic _zero = 0; - const Algebraic _one = 1; - const Algebraic _two = 2; - Algebraic sin_phi; - Algebraic cos_phi; + Nt_traits nt_traits; + const int or_fact = (m_orient == CLOCKWISE) ? -1 : 1; + const Algebraic r = nt_traits.convert(or_fact * m_r); + const Algebraic s = nt_traits.convert(or_fact * m_s); + const Algebraic t = nt_traits.convert(or_fact * m_t); + const Algebraic cos_2phi = (r - s) / nt_traits.sqrt((r-s)*(r-s) + t*t); + const Algebraic zero = 0; + const Algebraic one = 1; + const Algebraic two = 2; + Algebraic sin_phi; + Algebraic cos_phi; // Calculate sin(phi) and cos(phi) according to the half-angle formulae: // // sin(phi)^2 = 0.5 * (1 - cos(2*phi)) // cos(phi)^2 = 0.5 * (1 + cos(2*phi)) - Sign sign_t = CGAL::sign (t); + Sign sign_t = CGAL::sign(t); - if (sign_t == ZERO) - { + if (sign_t == ZERO) { // sin(2*phi) == 0, so phi = 0 or phi = PI/2 - if (CGAL::sign (cos_2phi) == POSITIVE) - { + if (CGAL::sign(cos_2phi) == POSITIVE) { // phi = 0. - sin_phi = _zero; - cos_phi = _one; + sin_phi = zero; + cos_phi = one; } - else - { + else { // phi = PI/2. - sin_phi = _one; - cos_phi = _zero; + sin_phi = one; + cos_phi = zero; } } - else if (sign_t == POSITIVE) - { + else if (sign_t == POSITIVE) { // sin(2*phi) > 0 so 0 < phi < PI/2. - sin_phi = nt_traits.sqrt((_one + cos_2phi) / _two); - cos_phi = nt_traits.sqrt((_one - cos_2phi) / _two); + sin_phi = nt_traits.sqrt((one + cos_2phi) / two); + cos_phi = nt_traits.sqrt((one - cos_2phi) / two); } else { // sin(2*phi) < 0 so PI/2 < phi < PI. - sin_phi = nt_traits.sqrt((_one + cos_2phi) / _two); - cos_phi = -nt_traits.sqrt((_one - cos_2phi) / _two); + sin_phi = nt_traits.sqrt((one + cos_2phi) / two); + cos_phi = -nt_traits.sqrt((one - cos_2phi) / two); } // Calculate the center (x0, y0) of the conic, given by the formulae: @@ -1441,15 +1158,15 @@ private: // 4*r*s - t^2 4*r*s - t^2 // // The denominator (4*r*s - t^2) must be negative for hyperbolas. - const Algebraic u = nt_traits.convert (or_fact * _u); - const Algebraic v = nt_traits.convert (or_fact * _v); - const Algebraic det = 4*r*s - t*t; - Algebraic x0, y0; + const Algebraic u = nt_traits.convert(or_fact * m_u); + const Algebraic v = nt_traits.convert(or_fact * m_v); + const Algebraic det = 4*r*s - t*t; + Algebraic x0, y0; - CGAL_assertion (CGAL::sign (det) == NEGATIVE); + CGAL_assertion (CGAL::sign(det) == NEGATIVE); - x0 = (t*v - _two*s*u) / det; - y0 = (t*u - _two*r*v) / det; + x0 = (t*v - two*s*u) / det; + y0 = (t*u - two*r*v) / det; // The axis separating the two branches of the hyperbola is now given by: // @@ -1457,407 +1174,529 @@ private: // // We store the equation of this line in the extra data structure and also // the sign (side of half-plane) our arc occupies with respect to the line. - _extra_data_P = new Extra_data; + m_extra_data = new Extra_data; - _extra_data_P->a = cos_phi; - _extra_data_P->b = sin_phi; - _extra_data_P->c = - (cos_phi*x0 + sin_phi*y0); + m_extra_data->a = cos_phi; + m_extra_data->b = sin_phi; + m_extra_data->c = - (cos_phi*x0 + sin_phi*y0); // Make sure that the two endpoints are located on the same branch // of the hyperbola. - _extra_data_P->side = _sign_of_extra_data (_source.x(), _source.y()); + m_extra_data->side = sign_of_extra_data(m_source.x(), m_source.y()); - CGAL_assertion (_extra_data_P->side != ZERO); - CGAL_assertion (_extra_data_P->side == _sign_of_extra_data(_target.x(), - _target.y())); - - return; - } - //@} - -protected: - - /// \name Auxiliary functions. - //@{ - - /*! - * Evaluate the sign of (a*x + b*y + c) stored with the extra data field - * at a given point. - * \param px The x-coordinate of query point. - * \param py The y-coordinate of query point. - * \return The sign of (a*x + b*y + c). - */ - Sign _sign_of_extra_data (const Algebraic& px, - const Algebraic& py) const - { - CGAL_assertion (_extra_data_P != nullptr); - - if (_extra_data_P == nullptr) - return (ZERO); - - Algebraic val = (_extra_data_P->a*px + _extra_data_P->b*py + - _extra_data_P->c); - - return (CGAL::sign (val)); + CGAL_assertion(m_extra_data->side != ZERO); + CGAL_assertion(m_extra_data->side == + sign_of_extra_data(m_target.x(), m_target.y())); } - /*! - * Check whether the given point lies on the supporting conic of the arc. - * \param p The query point. - * \return (true) if p lies on the supporting conic; (false) otherwise. - */ - bool _is_on_supporting_conic (const Point_2& p) const - { - // Check whether p satisfies the conic equation. - // The point must satisfy: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0. - Nt_traits nt_traits; - const Algebraic val = (nt_traits.convert(_r)*p.x() + - nt_traits.convert(_t)*p.y() + - nt_traits.convert(_u)) * p.x() + - (nt_traits.convert(_s)*p.y() + - nt_traits.convert(_v)) * p.y() + - nt_traits.convert(_w); - - return (CGAL::sign (val) == ZERO); - } - - /*! - * Check whether the given point is between the source and the target. + /*! Check whether the given point is between the source and the target. * The point is assumed to be on the conic's boundary. * \param p The query point. * \return (true) if the point is between the two endpoints, * (false) if it is not. */ - bool _is_between_endpoints (const Point_2& p) const - { - CGAL_precondition (! is_full_conic()); + CGAL_DEPRECATED bool _is_between_endpoints(const Point_2& p) const { + CGAL_precondition(! is_full_conic()); // Check if p is one of the endpoints. - Alg_kernel ker; - - if (ker.equal_2_object() (p, _source) || - ker.equal_2_object() (p, _target)) - { - return (true); - } - else - { - return (_is_strictly_between_endpoints(p)); - } + Alg_kernel ker; + if (ker.equal_2_object()(p, m_source) || + ker.equal_2_object()(p, m_target)) + return true; + else return _is_strictly_between_endpoints(p); } - /*! - * Check whether the given point is strictly between the source and the - * target (but not any of them). - * The point is assumed to be on the conic's boundary. - * \param p The query point. - * \return (true) if the point is strictly between the two endpoints, - * (false) if it is not. - */ - bool _is_strictly_between_endpoints (const Point_2& p) const - { - // In case this is a full conic, any point on its boundary is between - // its end points. - if (is_full_conic()) - return (true); - - // Check if we have extra data available. - if (_extra_data_P != nullptr) - { - if (_extra_data_P->side != ZERO) - { - // In case of a hyperbolic arc, make sure the point is located on the - // same branch as the arc. - if (_sign_of_extra_data(p.x(), p.y()) != _extra_data_P->side) - return (false); - } - else - { - // In case we have a segment of a line pair, make sure that p really - // satisfies the equation of the line. - if (_sign_of_extra_data(p.x(), p.y()) != ZERO) - return (false); - } - } - - // Act according to the conic degree. - Alg_kernel ker; - - if (_orient == COLLINEAR) - { - Comparison_result res1; - Comparison_result res2; - - if (ker.compare_x_2_object() (_source, _target) == EQUAL) - { - // In case of a vertical segment - just check whether the y coordinate - // of p is between those of the source's and of the target's. - res1 = ker.compare_y_2_object() (p, _source); - res2 = ker.compare_y_2_object() (p, _target); - } - else - { - // Otherwise, since the segment is x-monotone, just check whether the - // x coordinate of p is between those of the source's and of the - // target's. - res1 = ker.compare_x_2_object() (p, _source); - res2 = ker.compare_x_2_object() (p, _target); - } - - // If p is not in the (open) x-range (or y-range) of the segment, it - // cannot be contained in the segment. - if (res1 == EQUAL || res2 == EQUAL || res1 == res2) - return (false); - - // Perform an orientation test: This is crucial for segment of line - // pairs, as we want to make sure that p lies on the same line as the - // source and the target. - return (ker.orientation_2_object()(_source, p, _target) == COLLINEAR); - } - else - { - // In case of a conic of degree 2, make a decision based on the conic's - // orientation and whether (source,p,target) is a right or a left turn. - if (_orient == COUNTERCLOCKWISE) - return (ker.orientation_2_object()(_source, p, _target) == LEFT_TURN); - else - return (ker.orientation_2_object()(_source, p, _target) == RIGHT_TURN); - } - } - - /*! - * Find the vertical tangency points of the underlying conic. - * \param ps The output points of vertical tangency. - * This area must be allocated at the size of 2. - * \return The number of vertical tangency points. - */ - int _conic_vertical_tangency_points (Point_2* ps) const - { - // In case the base conic is of degree 1 (and not 2), the arc has no - // vertical tangency points. - if (CGAL::sign (_s) == ZERO) - return (0); - - // We are interested in the x coordinates where the quadratic equation: - // s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0 - // has a single solution (obviously if s = 0, there are no such points). - // We therefore demand that the discriminant of this equation is zero: - // (t*x + v)^2 - 4*s*(r*x^2 + u*x + w) = 0 - const Integer _two = 2; - const Integer _four = 4; - Algebraic xs[2]; - Algebraic *xs_end; - int n_xs; - Nt_traits nt_traits; - - xs_end = nt_traits.solve_quadratic_equation (_t*_t - _four*_r*_s, - _two*_t*_v - _four*_s*_u, - _v*_v - _four*_s*_w, - xs); - n_xs = static_cast(xs_end - xs); - - // Find the y-coordinates of the vertical tangency points. - Algebraic ys[2]; - Algebraic *ys_end; - int n_ys; - - if (CGAL::sign (_t) == ZERO) - { - // The two vertical tangency points have the same y coordinate: - ys[0] = nt_traits.convert (-_v) /nt_traits.convert (_two*_s); - n_ys = 1; - } - else - { - ys_end = - nt_traits.solve_quadratic_equation (_four*_r*_s*_s - _s*_t*_t, - _four*_r*_s*_v - _two*_s*_t*_u, - _r*_v*_v - _t*_u*_v + _t*_t*_w, - ys); - n_ys = static_cast(ys_end - ys); - } - - // Pair the x and y coordinates and obtain the vertical tangency points. - int n = 0; - int i, j; - - for (i = 0; i < n_xs; i++) - { - if (n_ys == 1) - { - ps[n] = Point_2 (xs[i], ys[0]); - n++; - } - else - { - for (j = 0; j < n_ys; j++) - { - if (CGAL::compare (nt_traits.convert(_two*_s) * ys[j], - -(nt_traits.convert(_t) * xs[i] + - nt_traits.convert(_v))) == EQUAL) - { - ps[n] = Point_2 (xs[i], ys[j]); - n++; - break; - } - } - } - } - - CGAL_assertion (n <= 2); - return (n); - } - - /*! - * Find the horizontal tangency points of the underlying conic. - * \param ps The output points of horizontal tangency. - * This area must be allocated at the size of 2. - * \return The number of horizontal tangency points. - */ - int _conic_horizontal_tangency_points (Point_2* ps) const - { - const Integer _zero = 0; - - // In case the base conic is of degree 1 (and not 2), the arc has no - // vertical tangency points. - if (CGAL::sign (_r) == ZERO) - return (0); - - // We are interested in the y coordinates were the quadratic equation: - // r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0 - // has a single solution (obviously if r = 0, there are no such points). - // We therefore demand that the discriminant of this equation is zero: - // (t*y + u)^2 - 4*r*(s*y^2 + v*y + w) = 0 - const Integer _two = 2; - const Integer _four = 4; - int n; - Algebraic ys[2]; - Algebraic *ys_end; - Nt_traits nt_traits; - - ys_end = nt_traits.solve_quadratic_equation (_t*_t - _four*_r*_s, - _two*_t*_u - _four*_r*_v, - _u*_u - _four*_r*_w, - ys); - n = static_cast(ys_end - ys); - - // Compute the x coordinates and construct the horizontal tangency points. - Algebraic x; - int i; - - for (i = 0; i < n; i++) - { - // Having computed y, x is the single solution to the quadratic equation - // above, and since its discriminant is 0, x is simply given by: - x = -(nt_traits.convert(_t)*ys[i] + nt_traits.convert(_u)) / - nt_traits.convert(_two*_r); - - ps[i] = Point_2 (x, ys[i]); - } - - CGAL_assertion (n <= 2); - return (n); - } - - /*! - * Find the y coordinates of the underlying conic at a given x coordinate. + /*! Find the y coordinates of the underlying conic at a given x coordinate. * \param x The x coordinate. * \param ys The output y coordinates. * \pre The vector ys must be allocated at the size of 2. * \return The number of y coordinates computed (either 0, 1 or 2). */ - int _conic_get_y_coordinates (const Algebraic& x, - Algebraic *ys) const - { + CGAL_DEPRECATED + int _conic_get_y_coordinates(const Algebraic& x, Algebraic* ys) const { // Solve the quadratic equation for a given x and find the y values: // s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0 - Nt_traits nt_traits; - Algebraic A = nt_traits.convert(_s); - Algebraic B = nt_traits.convert(_t)*x + nt_traits.convert(_v); - Algebraic C = (nt_traits.convert(_r)*x + - nt_traits.convert(_u))*x + nt_traits.convert(_w); - - return (_solve_quadratic_equation (A, B, C, ys[0], ys[1])); + Nt_traits nt_traits; + Algebraic A = nt_traits.convert(m_s); + Algebraic B = nt_traits.convert(m_t)*x + nt_traits.convert(m_v); + Algebraic C = (nt_traits.convert(m_r)*x + + nt_traits.convert(m_u))*x + nt_traits.convert(m_w); + return (_solve_quadratic_equation(A, B, C, ys[0], ys[1])); } - /*! - * Find the x coordinates of the underlying conic at a given y coordinate. + /*! Find all points on the arc with a given x-coordinate. + * \param p A placeholder for the x-coordinate. + * \param ps The point on the arc at x(p). + * \pre The vector ps should be allocated at the size of 2. + * \return The number of points found. + */ + CGAL_DEPRECATED int _points_at_x(const Point_2& p, Point_2* ps) const { + // Get the y coordinates of the points on the conic. + Algebraic ys[2]; + int n = _conic_get_y_coordinates(p.x(), ys); + + // Find all the points that are contained in the arc. + int m(0); + + for (int i = 0; i < n; ++i) { + ps[m] = Point_2 (p.x(), ys[i]); + if (is_full_conic() || _is_between_endpoints(ps[m])) ++m; + } + + // Return the number of points on the arc. + CGAL_assertion(m <= 2); + return m; + } + + /*! Solve the given quadratic equation: Ax^2 + B*x + C = 0. + * \param x_minus The root obtained from taking -sqrt(discriminant). + * \param x_plus The root obtained from taking -sqrt(discriminant). + * \return The number of disticnt solutions to the equation. + */ + CGAL_DEPRECATED int _solve_quadratic_equation(const Algebraic& A, + const Algebraic& B, + const Algebraic& C, + Algebraic& x_minus, + Algebraic& x_plus) const { + // Check if we actually have a linear equation. + if (CGAL::sign(A) == ZERO) { + if (CGAL::sign(B) == ZERO) return (0); + x_minus = x_plus = -C / B; + return 1; + } + + // Compute the discriminant and act according to its sign. + const Algebraic disc = B*B - 4*A*C; + Sign sign_disc = CGAL::sign(disc); + + if (sign_disc == NEGATIVE) { + // No real-valued solutions: + return 0; + } + else if (sign_disc == ZERO) { + // One distinct solution: + x_minus = x_plus = -B / (2*A); + return 1; + } + + // Compute the two distinct solutions: + Algebraic _2A = 2*A; + Nt_traits nt_traits; + Algebraic sqrt_disc = nt_traits.sqrt (disc); + + x_minus = -(B + sqrt_disc) / _2A; + x_plus = (sqrt_disc - B) / _2A; + return 2; + } + + /*! Find the x coordinates of the underlying conic at a given y coordinate. * \param y The y coordinate. * \param xs The output x coordinates. * \pre The vector xs must be allocated at the size of 2. * \return The number of x coordinates computed (either 0, 1 or 2). */ - int _conic_get_x_coordinates (const Algebraic& y, - Algebraic *xs) const - { + CGAL_DEPRECATED + int _conic_get_x_coordinates(const Algebraic& y, Algebraic* xs) const { // Solve the quadratic equation for a given y and find the x values: // r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0 - Nt_traits nt_traits; - Algebraic A = nt_traits.convert(_r); - Algebraic B = nt_traits.convert(_t)*y + nt_traits.convert(_u); - Algebraic C = (nt_traits.convert(_s)*y + - nt_traits.convert(_v))*y + nt_traits.convert(_w); + Nt_traits nt_traits; + Algebraic A = nt_traits.convert(m_r); + Algebraic B = nt_traits.convert(m_t)*y + nt_traits.convert(m_u); + Algebraic C = (nt_traits.convert(m_s)*y + + nt_traits.convert(m_v))*y + nt_traits.convert(m_w); - return (_solve_quadratic_equation (A, B, C, xs[0], xs[1])); + return (_solve_quadratic_equation(A, B, C, xs[0], xs[1])); } - /*! - * Solve the given quadratic equation: Ax^2 + B*x + C = 0. - * \param x_minus The root obtained from taking -sqrt(discriminant). - * \param x_plus The root obtained from taking -sqrt(discriminant). - * \return The number of disticnt solutions to the equation. + /*! Find all points on the arc with a given y-coordinate. + * \param p A placeholder for the y-coordinate. + * \param ps The point on the arc at x(p). + * \pre The vector ps should be allocated at the size of 2. + * \return The number of points found. */ - int _solve_quadratic_equation (const Algebraic& A, - const Algebraic& B, - const Algebraic& C, - Algebraic& x_minus, Algebraic& x_plus) const + CGAL_DEPRECATED int _points_at_y(const Point_2& p, Point_2* ps) const { + // Get the y coordinates of the points on the conic. + Algebraic xs[2]; + int n = _conic_get_x_coordinates(p.y(), xs); + + // Find all the points that are contained in the arc. + int m(0); + + for (int i = 0; i < n; ++i) { + ps[m] = Point_2 (xs[i], p.y()); + if (is_full_conic() || _is_between_endpoints(ps[m])) ++m; + } + + // Return the number of points on the arc. + CGAL_assertion(m <= 2); + return m; + } + + /*! Set the properties of a conic arc (for the usage of the constructors). + * \param rat_coeffs A vector of size 6, storing the rational coefficients + * of x^2, y^2, xy, x, y and the free coefficient resp. + */ + CGAL_DEPRECATED void _set(const Rational* rat_coeffs) { + set_flag(IS_VALID); + Nt_traits nt_traits; + + // Convert the coefficients vector to an equivalent vector of integer + // coefficients. + Integer int_coeffs[6]; + nt_traits.convert_coefficients(rat_coeffs, rat_coeffs + 6, int_coeffs); + + // Check the orientation of conic curve, and negate the conic coefficients + // if its given orientation. + typename Rat_kernel::Conic_2 temp_conic(rat_coeffs[0], rat_coeffs[1], + rat_coeffs[2], rat_coeffs[3], + rat_coeffs[4], rat_coeffs[5]); + + if (orientation() == temp_conic.orientation()) { + m_r = int_coeffs[0]; + m_s = int_coeffs[1]; + m_t = int_coeffs[2]; + m_u = int_coeffs[3]; + m_v = int_coeffs[4]; + m_w = int_coeffs[5]; + } + else { + m_r = -int_coeffs[0]; + m_s = -int_coeffs[1]; + m_t = -int_coeffs[2]; + m_u = -int_coeffs[3]; + m_v = -int_coeffs[4]; + m_w = -int_coeffs[5]; + } + + // Make sure both endpoint lie on the supporting conic. + if (! _is_on_supporting_conic(m_source) || + ! _is_on_supporting_conic(m_target)) + { + reset_flags(); // inavlid arc + return; + } + + // Check whether we have a degree 2 curve. + if ((CGAL::sign(m_r) != ZERO) || (CGAL::sign(m_s) != ZERO) || + (CGAL::sign(m_t) != ZERO)) + { + if (orientation() == COLLINEAR) { + // Make sure the midpoint is on the line pair (thus making sure that + // the two points are not taken from different lines). + Alg_kernel ker; + auto ctr_mid_point = ker.construct_midpoint_2_object(); + Point_2 p_mid = ctr_mid_point(m_source, m_target); + // if (! is_on_supporting_conic(arc, p_mid)) + if (CGAL::sign((nt_traits.convert(m_r)*p_mid.x() + + nt_traits.convert(m_t)*p_mid.y() + + nt_traits.convert(m_u)) * p_mid.x() + + (nt_traits.convert(m_s)*p_mid.y() + + nt_traits.convert(m_v)) * p_mid.y() + + nt_traits.convert(m_w)) != ZERO) + { + reset_flags(); // inavlid arc + return; + } + + // We have a segment of a line pair with rational coefficients. + // Compose the equation of the underlying line + // (with algebraic coefficients). + const Algebraic& x1 = m_source.x(); + const Algebraic& y1 = m_source.y(); + const Algebraic& x2 = m_target.x(); + const Algebraic& y2 = m_target.y(); + + // The supporting line is A*x + B*y + C = 0, where: + // + // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 + // + // We use the extra dat field to store the equation of this line. + m_extra_data = new Extra_data; + m_extra_data->a = y2 - y1; + m_extra_data->b = x1 - x2; + m_extra_data->c = x2*y1 - x1*y2; + m_extra_data->side = ZERO; + } + else { + // The sign of (4rs - t^2) detetmines the conic type: + // - if it is possitive, the conic is an ellipse, + // - if it is negative, the conic is a hyperbola, + // - if it is zero, the conic is a parabola. + CGAL::Sign sign_conic = CGAL::sign(4*m_r*m_s - m_t*m_t); + + // Build the extra hyperbolic data if necessary + if (sign_conic == NEGATIVE) _build_hyperbolic_arc_data(); + + if (sign_conic != POSITIVE) { + // In case of a non-degenerate parabola or a hyperbola, make sure + // the arc is not infinite. + Alg_kernel ker; + Point_2 p_mid = ker.construct_midpoint_2_object()(m_source, m_target); + Point_2 ps[2]; + + bool finite_at_x = (_points_at_x(p_mid, ps) > 0); + bool finite_at_y = (_points_at_y(p_mid, ps) > 0); + + if (! finite_at_x && ! finite_at_y) { + reset_flags(); // inavlid arc + return; + } + } + } + } + + + set_flag(IS_VALID); // arc is valid + reset_flag(IS_FULL_CONIC); // not a full conic + } + +public: + /// \name Construction and destruction functions. + //@{ + + /*! Default constructor. + */ + Conic_arc_2() : + m_r(0), m_s(0), m_t(0), m_u(0), m_v(0), m_w(0), + m_orient(COLLINEAR), + m_info(0), + m_extra_data(nullptr) + {} + + /*! Copy constructor. + * \param arc The copied arc. + */ + Conic_arc_2(const Self& arc) : + m_r(arc.m_r), m_s(arc.m_s), m_t(arc.m_t), + m_u(arc.m_u), m_v(arc.m_v), m_w(arc.m_w), + m_orient(arc.m_orient), + m_info(arc.m_info), + m_source(arc.m_source), + m_target(arc.m_target) { - // Check if we actually have a linear equation. - if (CGAL::sign(A) == ZERO) - { - if (CGAL::sign(B) == ZERO) - return (0); + m_extra_data = (arc.m_extra_data != nullptr) ? + new Extra_data(*(arc.m_extra_data)) : nullptr; + } - x_minus = x_plus = -C / B; - return (1); - } + /*! Destructor. + */ + virtual ~Conic_arc_2() { if (m_extra_data != nullptr) delete m_extra_data; } - // Compute the discriminant and act according to its sign. - const Algebraic disc = B*B - 4*A*C; - Sign sign_disc = CGAL::sign (disc); + /*! Assignment operator. + * \param arc The copied arc. + */ + const Self& operator=(const Self& arc) { + if (this == &arc) return (*this); - if (sign_disc == NEGATIVE) - { - // No real-valued solutions: - return (0); - } - else if (sign_disc == ZERO) - { - // One distinct solution: - x_minus = x_plus = -B / (2*A); - return (1); - } + // Free any existing data. + if (m_extra_data != nullptr) delete m_extra_data; - // Compute the two distinct solutions: - Algebraic _2A = 2*A; - Nt_traits nt_traits; - Algebraic sqrt_disc = nt_traits.sqrt (disc); + // Copy the arc's attributes. + m_r = arc.m_r; + m_s = arc.m_s; + m_t = arc.m_t; + m_u = arc.m_u; + m_v = arc.m_v; + m_w = arc.m_w; - x_minus = -(B + sqrt_disc) / _2A; - x_plus = (sqrt_disc - B) / _2A; - return (2); + m_orient = arc.m_orient; + m_info = arc.m_info; + m_source = arc.m_source; + m_target = arc.m_target; + + // Duplicate the extra data, if necessary. + m_extra_data = (arc.m_extra_data != nullptr) ? + new Extra_data(*(arc.m_extra_data)) : nullptr; + + return (*this); } //@} + /// \name Get the arc properties. + //@{ + + /*! Determine wheather the arc is valid. + */ + bool is_valid() const { return test_flag(IS_VALID); } + + /*! Determine whether the arc represents a full conic curve. + */ + bool is_full_conic() const { return test_flag(IS_FULL_CONIC); } + + /*! Obtain the coefficients of the underlying conic. + */ + const Integer& r() const { return (m_r); } + const Integer& s() const { return (m_s); } + const Integer& t() const { return (m_t); } + const Integer& u() const { return (m_u); } + const Integer& v() const { return (m_v); } + const Integer& w() const { return (m_w); } + + /*! Obtain the arc's source. + * \return The source point. + * \pre The arc does not represent a full conic curve. + */ + const Point_2& source() const { + CGAL_precondition(! is_full_conic()); + return m_source; + } + + /*! Obtain the non const reference to the curve source point. + */ + Point_2& source() { + CGAL_precondition(! is_full_conic()); + return (this->m_source); + } + + /*! Obtain the arc's target. + * \return The target point. + * \pre The arc does not represent a full conic curve. + */ + const Point_2& target() const { + CGAL_precondition(! is_full_conic()); + return m_target; + } + + /*! Obtain the non const reference to the curve source point. + */ + Point_2& target() { + CGAL_precondition(! is_full_conic()); + return this->m_target; + } + + /*! Obtain the orientation of the arc. + * \return The orientation. + */ + Orientation orientation() const { return m_orient; } + + /*! Obtain the extra data. + */ + const Extra_data* extra_data() const { return m_extra_data; } + //@} + +protected: + template friend class Arr_conic_traits_2; + + /// \name Flag manipulation functions. + //@{ + template + static constexpr auto flag_mask(const T flag) { return 0x1 << flag; } + + void reset_flags() { m_info = 0; } + + template + void set_flag(const T flag) { m_info |= flag_mask(flag); } + + template + void reset_flag(const T flag) { m_info &= ~flag_mask(flag); } + + template + void flip_flag(const T flag) { m_info ^= flag_mask(flag);} + + template + bool test_flag(const T flag) const + { return (m_info & flag_mask(flag)); } + //@} + +public: + /// \name Modifying functions (setters); + // only friends have the priviledge to use. + //@{ + + /*! Set the source point of the conic arc. + * \param ps The new source point. + */ + void set_source(const Point_2& ps) { m_source = ps; } + + /*! Set the target point of the conic arc. + * \param pt The new source point. + */ + void set_target(const Point_2& pt) { m_target = pt; } + + /*! Set the coefficients. + */ + void set_coefficients(Integer r, Integer s, Integer t, + Integer u, Integer v, Integer w) { + m_r = r; + m_s = s; + m_t = t; + m_u = u; + m_v = v; + m_w = w; + } + + /*! Set the orientation. + */ + void set_orientation(Orientation orient) { m_orient = orient; } + + /*! Set the endpoints. + */ + void set_endpoints(const Point_2& source, const Point_2& target) { + m_source = source; + m_target = target; + } + + /*! Set the extra data field. + */ + void set_extra_data(Extra_data* extra_data) { m_extra_data = extra_data; } + + /*! Set the extra data field. + */ + void set_extra_data(const Algebraic& a, const Algebraic& b, + const Algebraic& c, Sign side) + { + m_extra_data = new Extra_data; + m_extra_data->a = a; + m_extra_data->b = b; + m_extra_data->c = c; + m_extra_data->side = side; + } + + /*! Update the extra data field. + */ + void update_extra_data() { + const Algebraic x1 = source().x(); + const Algebraic y1 = source().y(); + const Algebraic x2 = target().x(); + const Algebraic y2 = target().y(); + + // The supporting line is A*x + B*y + C = 0, where: + // A = y2 - y1, B = x1 - x2, C = x2*y1 - x1*y2 + // We use the extra data field to store the equation of this line. + m_extra_data = new Extra_data; + m_extra_data->a = y2 - y1; + m_extra_data->b = x1 - x2; + m_extra_data->c = x2*y1 - x1*y2; + m_extra_data->side = ZERO; + } + //@} + +public: + /// \name Auxiliary functions. + //@{ + + /*! Evaluate the sign of (a*x + b*y + c) stored with the extra data field + * at a given point. + * \param px The x-coordinate of query point. + * \param py The y-coordinate of query point. + * \return The sign of (a*x + b*y + c). + */ + Sign sign_of_extra_data(const Algebraic& px, const Algebraic& py) const { + CGAL_assertion(m_extra_data != nullptr); + if (m_extra_data == nullptr) return ZERO; + Algebraic val = m_extra_data->a*px + m_extra_data->b*py + m_extra_data->c; + return CGAL::sign(val); + } + + //@} }; -/*! - * Exporter for conic arcs. +/*! Exporter for conic arcs. */ -template +template std::ostream& operator<< (std::ostream& os, - const _Conic_arc_2 & arc) + const Conic_arc_2& arc) { os << "{" << CGAL::to_double(arc.r()) << "*x^2 + " << CGAL::to_double(arc.s()) << "*y^2 + " @@ -1866,27 +1705,20 @@ operator<< (std::ostream& os, << CGAL::to_double(arc.v()) << "*y + " << CGAL::to_double(arc.w()) << "}"; - if (arc.is_full_conic()) - { - os << " - Full curve"; - } - else - { + if (arc.is_full_conic()) os << " - Full curve"; + else { os << " : (" << CGAL::to_double(arc.source().x()) << "," << CGAL::to_double(arc.source().y()) << ") "; - if (arc.orientation() == CLOCKWISE) - os << "--cw-->"; - else if (arc.orientation() == COUNTERCLOCKWISE) - os << "--ccw-->"; - else - os << "--l-->"; + if (arc.orientation() == CLOCKWISE) os << "--cw-->"; + else if (arc.orientation() == COUNTERCLOCKWISE) os << "--ccw-->"; + else os << "--l-->"; os << " (" << CGAL::to_double(arc.target().x()) << "," << CGAL::to_double(arc.target().y()) << ")"; } - return (os); + return os; } } //namespace CGAL diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_intersections_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_intersections_2.h index 79049ca3977..223fcda24e9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_intersections_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_intersections_2.h @@ -8,7 +8,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Ron Wein +// Author(s): Ron Wein #ifndef CGAL_CONIC_INTERSECTIONS_2_H #define CGAL_CONIC_INTERSECTIONS_2_H @@ -24,8 +24,7 @@ namespace CGAL { -/*! - * Compute the roots of the resultants of the two bivariate polynomials: +/*! Compute the roots of the resultants of the two bivariate polynomials: * C1: r1*x^2 + s1*y^2 + t1*xy + u1*x + v1*y + w1 = 0 * C2: r2*x^2 + s2*y^2 + t2*xy + u2*x + v2*y + w2 = 0 * \param deg1 The degree of the first curve. @@ -35,84 +34,76 @@ namespace CGAL { * \pre xs must be a vector of size 4. * \return The number of distinct roots found. */ -template -int - _compute_resultant_roots (Nt_traits& nt_traits, - const typename Nt_traits::Integer& r1, - const typename Nt_traits::Integer& s1, - const typename Nt_traits::Integer& t1, - const typename Nt_traits::Integer& u1, - const typename Nt_traits::Integer& v1, - const typename Nt_traits::Integer& w1, - const int& deg1, - const typename Nt_traits::Integer& r2, - const typename Nt_traits::Integer& s2, - const typename Nt_traits::Integer& t2, - const typename Nt_traits::Integer& u2, - const typename Nt_traits::Integer& v2, - const typename Nt_traits::Integer& w2, - const int& deg2, - typename Nt_traits::Algebraic *xs) +template +int compute_resultant_roots(const Nt_traits& nt_traits, + const typename Nt_traits::Integer& r1, + const typename Nt_traits::Integer& s1, + const typename Nt_traits::Integer& t1, + const typename Nt_traits::Integer& u1, + const typename Nt_traits::Integer& v1, + const typename Nt_traits::Integer& w1, + const int& deg1, + const typename Nt_traits::Integer& r2, + const typename Nt_traits::Integer& s2, + const typename Nt_traits::Integer& t2, + const typename Nt_traits::Integer& u2, + const typename Nt_traits::Integer& v2, + const typename Nt_traits::Integer& w2, + const int& deg2, + typename Nt_traits::Algebraic* xs) { - if (deg1 == 2 && deg2 == 1) - { + if ((deg1 == 2) && (deg2 == 1)) { // If necessary, swap roles between the two curves, so that the first // curve always has the minimal degree. - return (_compute_resultant_roots (nt_traits, - r2, s2, t2, u2, v2, w2, - deg2, - r1, s1, t1, u1, v1, w1, - deg1, - xs)); + return (compute_resultant_roots(nt_traits, + r2, s2, t2, u2, v2, w2, + deg2, + r1, s1, t1, u1, v1, w1, + deg1, + xs)); } // Act according to the degree of the first conic curve. - const typename Nt_traits::Integer _two = 2; - typename Nt_traits::Integer c[5]; - unsigned int degree = 4; - typename Nt_traits::Algebraic *xs_end; + const typename Nt_traits::Integer two = 2; + typename Nt_traits::Integer c[5]; + unsigned int degree = 4; + typename Nt_traits::Algebraic* xs_end; - if (deg1 == 1) - { + if (deg1 == 1) { // The first curve has no quadratic coefficients, and represents a line. - if (CGAL::sign (v1) == ZERO) - { + if (CGAL::sign (v1) == ZERO) { // The first line is u1*x + w1 = 0, therefore: xs[0] = nt_traits.convert(-w1) / nt_traits.convert(u1); - return (1); + return 1; } // We can write the first curve as: y = -(u1*x + w1) / v1. - if (deg2 == 1) - { + if (deg2 == 1) { // The second curve is also a line. We therefore get the linear // equation c[1]*x + c[0] = 0: c[1] = v1*u2 - u1*v2; c[0] = v1*w2 - w1*v2; - if (CGAL::sign (c[1]) == ZERO) - // The two lines are parallel: - return (0); + // Return if the two lines are parallel + if (CGAL::sign (c[1]) == ZERO) return 0; - xs[0] = nt_traits.convert(-c[0]) / nt_traits.convert(c[1]); - return (1); + xs[0] = nt_traits.convert(-c[0]) / nt_traits.convert(c[1]); + return 1; } // We substitute this expression into the equation of the second // conic, and get the quadratic equation c[2]*x^2 + c[1]*x + c[0] = 0: c[2] = u1*u1*s2 - u1*v1*t2 + v1*v1*r2; - c[1] = _two*u1*w1*s2 - u1*v1*v2 - v1*w1*t2 + v1*v1*u2; + c[1] = two*u1*w1*s2 - u1*v1*v2 - v1*w1*t2 + v1*v1*u2; c[0] = w1*w1*s2 - v1*w1*v2 + v1*v1*w2; - xs_end = nt_traits.solve_quadratic_equation (c[2], c[1], c[0], - xs); + xs_end = nt_traits.solve_quadratic_equation(c[2], c[1], c[0], xs); return static_cast(xs_end - xs); } // At this stage, both curves have degree 2. We obtain a qaurtic polynomial // whose roots are the x-coordinates of the intersection points. - if (CGAL::sign (s1) == ZERO && CGAL::sign (s2) == ZERO) - { + if (CGAL::sign (s1) == ZERO && CGAL::sign (s2) == ZERO) { // If both s1 and s2 are zero, we can write the two curves as: // C1: (t1*x + v1)*y + (r1*x^2 + u1*x + w1) = 0 // C2: (t2*x + v2)*y + (r2*x^2 + u2*x + w2) = 0 @@ -125,50 +116,47 @@ int degree = 3; } - else - { + else { // We can write the two curves as: // C1: (s1)*y^2 + (t1*x + v1)*y + (r1*x^2 + u1*x + w1) = 0 // C2: (s2)*y^2 + (t2*x + v2)*y + (r2*x^2 + u2*x + w2) = 0 // By writing the resultant of these two polynomials we get a quartic // polynomial, whose coefficients are given by: - c[4] = -_two*s1*s2*r1*r2 + s1*t2*t2*r1 - s1*t2*t1*r2 + + c[4] = -two*s1*s2*r1*r2 + s1*t2*t2*r1 - s1*t2*t1*r2 + s1*s1*r2*r2 - s2*t1*r1*t2 + s2*t1*t1*r2 + s2*s2*r1*r1; c[3] = -t2*r1*v1*s2 - u2*t1*t2*s1 - v2*r1*t1*s2 - - r2*t1*v2*s1 - _two*s1*s2*r1*u2 - t2*u1*t1*s2 + u2*t1*t1*s2 - - r2*v1*t2*s1 + u1*t2*t2*s1 + _two*v2*r1*t2*s1 + _two*u2*r2*s1*s1 + - _two*r2*v1*t1*s2 + _two*u1*r1*s2*s2 - _two*s1*s2*u1*r2; + r2*t1*v2*s1 - two*s1*s2*r1*u2 - t2*u1*t1*s2 + u2*t1*t1*s2 - + r2*v1*t2*s1 + u1*t2*t2*s1 + two*v2*r1*t2*s1 + two*u2*r2*s1*s1 + + two*r2*v1*t1*s2 + two*u1*r1*s2*s2 - two*s1*s2*u1*r2; - c[2] = -r2*v1*v2*s1 + u2*u2*s1*s1 + _two*w2*r2*s1*s1 + - _two*u2*v1*t1*s2 - u2*v1*t2*s1 + w2*t1*t1*s2 - _two*s1*s2*u1*u2 - + c[2] = -r2*v1*v2*s1 + u2*u2*s1*s1 + two*w2*r2*s1*s1 + + two*u2*v1*t1*s2 - u2*v1*t2*s1 + w2*t1*t1*s2 - two*s1*s2*u1*u2 - w2*t1*t2*s1 + v2*v2*r1*s1 + u1*u1*s2*s2 - v2*r1*v1*s2 + - _two*w1*r1*s2*s2 - u2*t1*v2*s1 - t2*u1*v1*s2 - _two*s1*s2*r1*w2 - - _two*s1*s2*w1*r2 + r2*v1*v1*s2 + w1*t2*t2*s1 - v2*u1*t1*s2 - - t2*w1*t1*s2 + _two*v2*u1*t2*s1; + two*w1*r1*s2*s2 - u2*t1*v2*s1 - t2*u1*v1*s2 - two*s1*s2*r1*w2 - + two*s1*s2*w1*r2 + r2*v1*v1*s2 + w1*t2*t2*s1 - v2*u1*t1*s2 - + t2*w1*t1*s2 + two*v2*u1*t2*s1; - c[1] = _two*w2*u2*s1*s1 + _two*w2*v1*t1*s2 - w2*v1*t2*s1 + - _two*v2*w1*t2*s1 + _two*w1*u1*s2*s2 - v2*u1*v1*s2 - _two*s1*s2*u1*w2 - + c[1] = two*w2*u2*s1*s1 + two*w2*v1*t1*s2 - w2*v1*t2*s1 + + two*v2*w1*t2*s1 + two*w1*u1*s2*s2 - v2*u1*v1*s2 - two*s1*s2*u1*w2 - v2*w1*t1*s2 + u2*v1*v1*s2 - t2*w1*v1*s2 - w2*t1*v2*s1 + - v2*v2*u1*s1 - u2*v1*v2*s1 - _two*s1*s2*w1*u2; + v2*v2*u1*s1 - u2*v1*v2*s1 - two*s1*s2*w1*u2; c[0] = s2*v1*v1*w2 - s1*v2*v1*w2 - s2*v1*w1*v2 + s2*s2*w1*w1 - - _two*s1*s2*w1*w2 + s1*w1*v2*v2 + s1*s1*w2*w2; + two*s1*s2*w1*w2 + s1*w1*v2*v2 + s1*s1*w2*w2; degree = 4; } // Compute the roots of the resultant polynomial. - typename Nt_traits::Polynomial poly = - nt_traits.construct_polynomial (c, degree); + typename Nt_traits::Polynomial poly = + nt_traits.construct_polynomial(c, degree); - xs_end = nt_traits.compute_polynomial_roots (poly, - xs); + xs_end = nt_traits.compute_polynomial_roots(poly, xs); return static_cast(xs_end - xs); } -/*! - * Compute the roots of the resultants of the two bivariate polynomials: +/*! Compute the roots of the resultants of the two bivariate polynomials: * C1: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0 * C2: A*x + B*y + C = 0 * \param deg1 The degree of the first curve. @@ -177,55 +165,50 @@ int * \pre xs must be a vector of size 4. * \return The number of distinct roots found. */ -template -int -_compute_resultant_roots (Nt_traits& nt_traits, - const typename Nt_traits::Algebraic& r, - const typename Nt_traits::Algebraic& s, - const typename Nt_traits::Algebraic& t, - const typename Nt_traits::Algebraic& u, - const typename Nt_traits::Algebraic& v, - const typename Nt_traits::Algebraic& w, - const int& deg1, - const typename Nt_traits::Algebraic& A, - const typename Nt_traits::Algebraic& B, - const typename Nt_traits::Algebraic& C, - typename Nt_traits::Algebraic *xs) +template +int compute_resultant_roots(const Nt_traits& nt_traits, + const typename Nt_traits::Algebraic& r, + const typename Nt_traits::Algebraic& s, + const typename Nt_traits::Algebraic& t, + const typename Nt_traits::Algebraic& u, + const typename Nt_traits::Algebraic& v, + const typename Nt_traits::Algebraic& w, + const int& deg1, + const typename Nt_traits::Algebraic& A, + const typename Nt_traits::Algebraic& B, + const typename Nt_traits::Algebraic& C, + typename Nt_traits::Algebraic* xs) { - if (deg1 == 1) - { + if (deg1 == 1) { // We should actually compute the intersection of two line: // (u*x + v*y + w = 0) and (A*x + B*y + C = 0): - const typename Nt_traits::Algebraic denom = A*v - B*u; + const typename Nt_traits::Algebraic denom = A*v - B*u; - if (CGAL::sign (denom) == CGAL::ZERO) - // The two lines are parallel and do not intersect. - return (0); + // Return if the two lines are parallel and do not intersect. + if (CGAL::sign(denom) == CGAL::ZERO) return 0; xs[0] = (B*w - C*v) / denom; - return (1); + return 1; } - if (CGAL::sign (B) == CGAL::ZERO) - { + if (CGAL::sign(B) == CGAL::ZERO) { // The first line is A*x + C = 0, therefore: xs[0] = -C / A; - return (1); + return 1; } // We can write the first curve as: y = -(A*x + C) / B. // We substitute this expression into the equation of the conic, and get // the quadratic equation c[2]*x^2 + c[1]*x + c[0] = 0: - const typename Nt_traits::Algebraic _two = 2; - typename Nt_traits::Algebraic c[3]; - typename Nt_traits::Algebraic *xs_end; + const typename Nt_traits::Algebraic two = 2; + typename Nt_traits::Algebraic c[3]; + typename Nt_traits::Algebraic* xs_end; c[2] = A*A*s - A*B*t + B*B*r; - c[1] = _two*A*C*s - A*B*v - B*C*t + B*B*u; + c[1] = two*A*C*s - A*B*v - B*C*t + B*B*u; c[0] = C*C*s - B*C*v + B*B*w; - xs_end = nt_traits.solve_quadratic_equation (c[2], c[1], c[0], - xs); + xs_end = nt_traits.solve_quadratic_equation(c[2], c[1], c[0], xs); return static_cast(xs_end - xs); } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_point_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_point_2.h index d1c5ed3826c..6361c0bfe7c 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_point_2.h @@ -8,154 +8,105 @@ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // -// Author(s) : Ron Wein +// Author(s): Ron Wein +// Efi Fogel #ifndef CGAL_CONIC_POINT_2_H #define CGAL_CONIC_POINT_2_H #include - /*! \file - * Header file for the _Conic_point_2 class. + * Header file for the Conic_point_2 class. */ #include + #include namespace CGAL { -/*! - * \class A class that stores additional information with the point's +/*! \class + * A class that stores additional information with the point's * coordinates, namely the conic IDs of the generating curves. */ -template -class _Conic_point_2 : public Alg_kernel_::Point_2 -{ +template +class Conic_point_2 : public AlgKernel::Point_2 { public: + typedef AlgKernel Alg_kernel; + typedef typename Alg_kernel::Point_2 Base; + typedef Conic_point_2 Self; - typedef Alg_kernel_ Alg_kernel; - typedef typename Alg_kernel::Point_2 Base; - typedef _Conic_point_2 Self; - - typedef typename Alg_kernel::FT Algebraic; + typedef typename Alg_kernel::FT Algebraic; /*! \class * Representation of an ID of a conic arc. */ - class Conic_id - { + class Conic_id { private: - - unsigned int index; // The index of the conic arc. + size_t index; // the index of the conic arc public: - /*! Default constructor. */ - Conic_id () : - index (0) - {} + Conic_id() : index(0) {} /*! Constructor. */ - Conic_id (unsigned int ind) : - index (ind) - { - CGAL_precondition (ind != 0); - } + Conic_id(size_t ind) : index(ind) { CGAL_precondition(ind != 0); } /*! Check if the ID is valid. */ - bool is_valid () const - { - return (index != 0); - } + bool is_valid() const { return (index != 0); } /*! Equality operator. */ - bool operator== (const Conic_id& id) const - { - return (index == id.index); - } + bool operator==(const Conic_id& id) const { return (index == id.index); } /*! Inequality operator. */ - bool operator!= (const Conic_id& id) const - { - return (index != id.index); - } + bool operator!=(const Conic_id& id) const { return (index != id.index); } /*! Less-than operator. */ - bool operator< (const Conic_id& id) const - { - return (index < id.index); - } + bool operator<(const Conic_id& id) const { return (index < id.index); } /*! Greater-than operator. */ - bool operator> (const Conic_id& id) const - { - return (index > id.index); - } + bool operator>(const Conic_id& id) const { return (index > id.index); } }; private: - typedef std::list Ids_container; typedef typename std::list::const_iterator Ids_iterator; - Ids_container conic_ids; // The IDs of the generating conics. - - public: + Ids_container conic_ids; // the IDs of the generating conics. +public: /// \name Constructors. //@{ /*! Default constructors. */ - _Conic_point_2 () : - Base() - {} + Conic_point_2() : Base() {} - /*! Constructor from the base class. */ - _Conic_point_2 (const Base& p) : - Base (p) - {} + /*! Constrcutor from the base class. */ + Conic_point_2(const Base& p) : Base(p) {} - /*! Constructor with homogeneous coordinates. */ - _Conic_point_2 (const Algebraic& hx, - const Algebraic& hy, - const Algebraic& hz) : - Base (hx, hy, hz) + /*! Constructor with homegeneous coordinates. */ + Conic_point_2(const Algebraic& hx, const Algebraic& hy, const Algebraic& hz) : + Base(hx, hy, hz) {} /*! Constructor with Cartesian coordinates. */ - _Conic_point_2 (const Algebraic& x, const Algebraic& y) : - Base (x, y) - {} + Conic_point_2(const Algebraic& x, const Algebraic& y) : Base(x, y) {} //@} /// \name Maintaining the generating conic IDs. //@{ /*! Add a generating conic ID. */ - void set_generating_conic (const Conic_id& id) - { - if (id.is_valid()) - conic_ids.push_back (id); - - return; - } + void set_generating_conic(const Conic_id& id) + { if (id.is_valid()) conic_ids.push_back(id); } /*! Check if the given conic generates the point. */ - bool is_generating_conic (const Conic_id& id) const - { - if (! id.is_valid()) - return (false); - - Ids_iterator it; - - for (it = conic_ids.begin(); it != conic_ids.end(); ++it) - { - if (*it == id) - return (true); - } - - return (false); + bool is_generating_conic(const Conic_id& id) const { + if (! id.is_valid()) return false; + for (auto it = conic_ids.begin(); it != conic_ids.end(); ++it) + if (*it == id) return true; + return false; } //@} diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_x_monotone_arc_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_x_monotone_arc_2.h index 7579788a8a4..6d2bf119bb9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_x_monotone_arc_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_x_monotone_arc_2.h @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s): Ron Wein +// Author(s): Ron Wein +// Efi Fogel #ifndef CGAL_CONIC_X_MONOTONE_ARC_2_H #define CGAL_CONIC_X_MONOTONE_ARC_2_H @@ -15,146 +16,89 @@ #include /*! \file - * Header file for the _Conic_x_monotone_arc_2 class. + * Header file for the Conic_x_monotone_arc_2 class. */ -#include #include -#include - -#include - namespace CGAL { /*! Representation of an x-monotone conic arc. * The class is templated by a representation of a general bounded conic arc. */ - -template -class _Conic_x_monotone_arc_2 : private Conic_arc_ { +template +class Conic_x_monotone_arc_2 : public ConicArc { public: + typedef ConicArc Conic_arc_2; + typedef Conic_x_monotone_arc_2 Self; - typedef Conic_arc_ Conic_arc_2; - typedef _Conic_x_monotone_arc_2 Self; + typedef typename Conic_arc_2::Alg_kernel Alg_kernel; + typedef typename Conic_arc_2::Algebraic Algebraic; - typedef typename Conic_arc_2::Alg_kernel Alg_kernel; - typedef typename Conic_arc_2::Algebraic Algebraic; - - typedef typename Conic_arc_2::Point_2 Point_2; - typedef typename Conic_arc_2::Conic_point_2 Conic_point_2; + typedef typename Conic_arc_2::Alg_point_2 Alg_point_2; + typedef typename Conic_arc_2::Point_2 Point_2; // Type definition for the intersection points mapping. - typedef typename Conic_point_2::Conic_id Conic_id; - typedef std::pair Conic_pair; - typedef std::pair Intersection_point; - typedef std::list Intersection_list; + typedef typename Point_2::Conic_id Conic_id; - using Conic_arc_2::_sign_of_extra_data; + using Conic_arc_2::sign_of_extra_data; using Conic_arc_2::_is_between_endpoints; - using Conic_arc_2::_is_strictly_between_endpoints; - using Conic_arc_2::_conic_get_y_coordinates; - /*! - * \struct Less functor for Conic_pair. - */ - struct Less_conic_pair { - bool operator()(const Conic_pair& cp1, const Conic_pair& cp2) const - { - // Compare the pairs of IDs lexicographically. - return ((cp1.first < cp2.first) || - ((cp1.first == cp2.first) && (cp1.second < cp2.second))); - } - }; - typedef std::map Intersection_map; - typedef typename Intersection_map::value_type Intersection_map_entry; - typedef typename Intersection_map::iterator Intersection_map_iterator; + using Conic_arc_2::IS_VALID; + using Conic_arc_2::IS_FULL_CONIC; -protected: + using Conic_arc_2::flag_mask; + using Conic_arc_2::reset_flags; + using Conic_arc_2::set_flag; + using Conic_arc_2::reset_flag; + using Conic_arc_2::flip_flag; + using Conic_arc_2::test_flag; +private: typedef Conic_arc_2 Base; typedef typename Conic_arc_2::Integer Integer; - typedef typename Conic_arc_2::Nt_traits Nt_traits; - typedef typename Conic_arc_2::Rat_kernel Rat_kernel; - // Bit masks for the _info field (the two least significant bits are already - // used by the base class). - enum { - IS_VERTICAL_SEGMENT = 4, - IS_DIRECTED_RIGHT = 8, - DEGREE_1 = 16, - DEGREE_2 = 32, - DEGREE_MASK = 16 + 32, - PLUS_SQRT_DISC_ROOT = 64, - FACING_UP = 128, - FACING_DOWN = 256, - FACING_MASK = 128 + 256, - IS_SPECIAL_SEGMENT = 512 - }; + Algebraic m_alg_r; // The coefficients of the supporting conic curve: + Algebraic m_alg_s; // + Algebraic m_alg_t; // r*x^2 + s*y^2 + t*xy + u*x + v*y +w = 0 , + Algebraic m_alg_u; // + Algebraic m_alg_v; // converted to algebraic numbers. + Algebraic m_alg_w; // - Algebraic alg_r; // The coefficients of the supporting conic curve: - Algebraic alg_s; // - Algebraic alg_t; // r*x^2 + s*y^2 + t*xy + u*x + v*y +w = 0 , - Algebraic alg_u; // - Algebraic alg_v; // converted to algebraic numbers. - Algebraic alg_w; // - - Conic_id _id; // The ID number of the supporting conic curve. + Conic_id m_id; // The ID number of the supporting conic curve. public: + // Bit masks for the m_info field (the two least significant bits are already + // used by the base class). + enum { + IS_VERTICAL_SEGMENT = Conic_arc_2::LAST_INFO, + IS_DIRECTED_RIGHT, + DEGREE_1, + DEGREE_2, + PLUS_SQRT_DISC_ROOT, + FACING_UP, + FACING_DOWN, + IS_SPECIAL_SEGMENT, - /// \name Construction methods. + DEGREE_MASK = (0x1 << DEGREE_1) | (0x1 << DEGREE_2), + FACING_MASK = (0x1 << FACING_UP) | (0x1 << FACING_DOWN) + }; + + /// \name Deprecated Constructions. //@{ - /*! - * Default constructor. - */ - _Conic_x_monotone_arc_2 () : - Base(), - _id() - {} - - /*! - * Copy constructor. - * \param arc The copied arc. - */ - _Conic_x_monotone_arc_2(const Self& arc) : - Base(arc), - alg_r(arc.alg_r), - alg_s(arc.alg_s), - alg_t(arc.alg_t), - alg_u(arc.alg_u), - alg_v(arc.alg_v), - alg_w(arc.alg_w), - _id(arc._id) - {} - - /*! Construct an x-monotone arc from a conic arc. - * \param arc The given (base) arc. - * \pre The given arc is x-monotone. - */ - _Conic_x_monotone_arc_2(const Base& arc) : - Base(arc), - _id() - { - CGAL_precondition(arc.is_valid() && arc.is_x_monotone()); - _set (); - } - - /*! Construct an x-monotone arc from a conic arc. - * \param arc The given (base) arc. - * \param id The ID of the base arc. - */ - _Conic_x_monotone_arc_2(const Base& arc, const Conic_id& id) : - Base(arc), - _id(id) - { - CGAL_precondition(arc.is_valid() && id.is_valid()); - _set (); - } + // /*! Construct an x-monotone arc from a conic arc. + // * \param arc The given (base) arc. + // * \param id The ID of the base arc. + // */ + // CGAL_DEPRECATED Conic_x_monotone_arc_2(const Base& arc, const Conic_id& id) : + // Base(arc), + // m_id(id) + // { + // CGAL_precondition(arc.is_valid() && id.is_valid()); + // _set(); + // } /*! Construct an x-monotone sub-arc from a conic arc. * \param arc The given (base) arc. @@ -162,18 +106,15 @@ public: * \param target The target point. * \param id The ID of the base arc. */ - _Conic_x_monotone_arc_2(const Base& arc, - const Point_2& source, const Point_2& target, - const Conic_id& id) : + CGAL_DEPRECATED Conic_x_monotone_arc_2(const Base& arc, + const Point_2& source, + const Point_2& target, + const Conic_id& id) : Base(arc), - _id(id) + m_id(id) { CGAL_precondition(arc.is_valid() && id.is_valid()); - - // Set the two endpoints. - this->_source = source; - this->_target = target; - + set_endpoints(source, target); _set(); } @@ -182,94 +123,209 @@ public: * \param source The source point. * \param target The target point. */ - _Conic_x_monotone_arc_2(const Point_2& source, const Point_2& target) : + CGAL_DEPRECATED + Conic_x_monotone_arc_2(const Point_2& source, const Point_2& target) : Base(source, target) { - this->_info |= static_cast(DEGREE_1); + set_flag(DEGREE_1); Alg_kernel ker; auto cmp_xy = ker.compare_xy_2_object(); - Comparison_result dir_res = cmp_xy(this->_source, this->_target); - if (dir_res == SMALLER) this->_info |= IS_DIRECTED_RIGHT; + Comparison_result dir_res = cmp_xy(source, target); + if (dir_res == SMALLER) set_flag(IS_DIRECTED_RIGHT); // Check if the segment is vertical. - if (CGAL::sign(this->_extra_data_P->b) == ZERO) - this->_info |= IS_VERTICAL_SEGMENT; + if (CGAL::sign(this->extra_data->b) == ZERO) set_flag(IS_VERTICAL_SEGMENT); // Mark that this is a special segment. - this->_info |= IS_SPECIAL_SEGMENT; + set_flag(IS_SPECIAL_SEGMENT); } - /*! - * Construct a special segment of a given line connecting to given + /*! Construct a special segment of a given line connecting to given * endpoints. * \param a, b, c The coefficients of the supporting line (ax + by + c = 0). * \param source The source point. * \param target The target point. */ - _Conic_x_monotone_arc_2(const Algebraic& a, - const Algebraic& b, - const Algebraic& c, - const Point_2& source, const Point_2& target) : + CGAL_DEPRECATED + Conic_x_monotone_arc_2(const Algebraic& a, const Algebraic& b, + const Algebraic& c, + const Point_2& source, const Point_2& target) : Base() { // Make sure the two endpoints lie on the supporting line. - CGAL_precondition(CGAL::sign(a * source.x() + - b * source.y() + c) == CGAL::ZERO); + CGAL_precondition(CGAL::sign(a * source.x() + b * source.y() + c) == + CGAL::ZERO); - CGAL_precondition(CGAL::sign(a * target.x() + - b * target.y() + c) == CGAL::ZERO); + CGAL_precondition(CGAL::sign(a * target.x() + b * target.y() + c) == + CGAL::ZERO); // Set the basic properties and clear the _info bits. - this->_source = source; - this->_target = target; - this->_orient = COLLINEAR; - this->_info = 0; + this->set_endpoints(source, target); + this->set_orientation(COLLINEAR); + this->reset_flags(); // inavlid arc // Check if the arc is directed right (the target is lexicographically // greater than the source point), or to the left. Alg_kernel ker; - Comparison_result res = - ker.compare_x_2_object()(this->_source, this->_target); + Comparison_result res = ker.compare_x_2_object()(source, target); - this->_info = (static_cast(Conic_arc_2::IS_VALID) | static_cast(DEGREE_1)); + set_flag(Base::IS_VALID); + set_flag(DEGREE_1); if (res == EQUAL) { // Mark that the segment is vertical. - this->_info = (this->_info | IS_VERTICAL_SEGMENT); + set_flag(IS_VERTICAL_SEGMENT); // Compare the endpoints lexicographically. - res = ker.compare_y_2_object()(this->_source, this->_target); - - CGAL_precondition (res != EQUAL); + res = ker.compare_y_2_object()(source, target); + CGAL_precondition(res != EQUAL); if (res == EQUAL) { - // Invalid arc: - this->_info = 0; + reset_flags(); // inavlid arc return; } } - if (res == SMALLER) - this->_info = (this->_info | IS_DIRECTED_RIGHT); + if (res == SMALLER) set_flag(IS_DIRECTED_RIGHT); // Store the coefficients of the line. - this->_extra_data_P = new typename Base::Extra_data; - this->_extra_data_P->a = a; - this->_extra_data_P->b = b; - this->_extra_data_P->c = c; - this->_extra_data_P->side = ZERO; + this->m_extra_data = new typename Base::Extra_data; + this->m_extra_data->a = a; + this->m_extra_data->b = b; + this->m_extra_data->c = c; + this->m_extra_data->side = ZERO; // Mark that this is a special segment. - this->_info = (this->_info | IS_SPECIAL_SEGMENT); + set_flag(IS_SPECIAL_SEGMENT); + } + //@} - return; +private: + /*! Set the properties of the x-monotone conic arc (for the usage of the + * constructors). + */ + CGAL_DEPRECATED void _set() { + // Convert the coefficients of the supporting conic to algebraic numbers. + typename Base::Nt_traits nt_traits; + + m_alg_r = nt_traits.convert(this->r()); + m_alg_s = nt_traits.convert(this->s()); + m_alg_t = nt_traits.convert(this->t()); + m_alg_u = nt_traits.convert(this->u()); + m_alg_v = nt_traits.convert(this->v()); + m_alg_w = nt_traits.convert(this->w()); + + // Set the generating conic ID for the source and target points. + this->m_source.set_generating_conic(m_id); + this->m_target.set_generating_conic(m_id); + + // Clear the _info bits. + this->set_flag(Base::IS_VALID); + this->reset_flag(Base::IS_FULL_CONIC); + + // Check if the arc is directed right (the target is lexicographically + // greater than the source point), or to the left. + Alg_kernel ker; + Comparison_result dir_res = + ker.compare_xy_2_object()(this->source(), this->target()); + + CGAL_assertion(dir_res != EQUAL); + + if (dir_res == SMALLER) set_flag(IS_DIRECTED_RIGHT); + + // Compute the degree of the underlying conic. + if (CGAL::sign(this->r()) != ZERO || + CGAL::sign(this->s()) != ZERO || + CGAL::sign(this->t()) != ZERO) + { + set_flag(DEGREE_2); + + if (this->m_orient == COLLINEAR) { + set_flag(IS_SPECIAL_SEGMENT); + + // The arc is a vertical segment: + if (ker.compare_x_2_object()(this->source(), this->target()) == EQUAL) + set_flag(IS_VERTICAL_SEGMENT); + return; + } + } + else { + CGAL_assertion(CGAL::sign(this->m_u) != ZERO || + CGAL::sign(this->m_v) != ZERO); + // The supporting curve is of the form: _u*x + _w = 0 + if (CGAL::sign(this->m_v) == ZERO) this->set_flag(IS_VERTICAL_SEGMENT); + this->set_flag(DEGREE_1); + return; + } + + if (this->m_orient == COLLINEAR) return; + + // Compute a midpoint between the source and the target and get the y-value + // of the arc at its x-coordiante. + Point_2 p_mid = + ker.construct_midpoint_2_object()(this->source(), this->target()); + Algebraic ys[2]; + CGAL_assertion_code(int n_ys = ) + this->_conic_get_y_coordinates(p_mid.x(), ys); + + CGAL_assertion(n_ys != 0); + + // Check which solution lies on the x-monotone arc. + Point_2 p_arc_mid(p_mid.x(), ys[0]); + + if (this->_is_strictly_between_endpoints(p_arc_mid)) { + // Mark that we should use the -sqrt(disc) root for points on this + // x-monotone arc. + this->reset_flag(PLUS_SQRT_DISC_ROOT); + } + else { + CGAL_assertion(n_ys == 2); + p_arc_mid = Point_2(p_mid.x(), ys[1]); + + CGAL_assertion(this->_is_strictly_between_endpoints(p_arc_mid)); + + // Mark that we should use the +sqrt(disc) root for points on this + // x-monotone arc. + this->set_flag(PLUS_SQRT_DISC_ROOT); + } + + // Check whether the conic is facing up or facing down: + // Check whether the arc (which is x-monotone of degree 2) lies above or + // below the segement that contects its two end-points (x1,y1) and (x2,y2). + // To do that, we find the y coordinate of a point on the arc whose x + // coordinate is (x1+x2)/2 and compare it to (y1+y2)/2. + Comparison_result res = ker.compare_y_2_object()(p_arc_mid, p_mid); + // The arc is above the connecting segment, so it is facing upwards. + if (res == LARGER) this->set_flag(FACING_UP); + // The arc is below the connecting segment, so it is facing downwards. + else if (res == SMALLER) this->set_flag(FACING_DOWN); } - /*! - * Assignment operator. +public: + /// \name Public constrcutors, assignment operators, and destructors. + //@{ + + /*! Default constructor. + */ + Conic_x_monotone_arc_2() : Base(), m_id() {} + + /*! Copy constructor. * \param arc The copied arc. */ - const Self& operator=(const Self& arc) - { + Conic_x_monotone_arc_2(const Self& arc) : + Base(arc), + m_alg_r(arc.m_alg_r), + m_alg_s(arc.m_alg_s), + m_alg_t(arc.m_alg_t), + m_alg_u(arc.m_alg_u), + m_alg_v(arc.m_alg_v), + m_alg_w(arc.m_alg_w), + m_id(arc.m_id) + {} + + /*! Assignment operator. + * \param arc The copied arc. + */ + const Self& operator=(const Self& arc) { CGAL_precondition (arc.is_valid()); if (this == &arc) return (*this); @@ -278,214 +334,263 @@ public: Base::operator= (arc); // Set the rest of the properties. - alg_r = arc.alg_r; - alg_s = arc.alg_s; - alg_t = arc.alg_t; - alg_u = arc.alg_u; - alg_v = arc.alg_v; - alg_w = arc.alg_w; + m_alg_r = arc.m_alg_r; + m_alg_s = arc.m_alg_s; + m_alg_t = arc.m_alg_t; + m_alg_u = arc.m_alg_u; + m_alg_v = arc.m_alg_v; + m_alg_w = arc.m_alg_w; - _id = arc._id; + m_id = arc.m_id; return (*this); } //@} +private: + template friend class Arr_conic_traits_2; + + /// \name private constrcutors to be used only by the traits class template. + //@{ + + /*! Construct an x-monotone arc from a conic arc. + * \param arc The given (base) arc. + * \pre The given arc is x-monotone. + */ + Conic_x_monotone_arc_2(const Base& arc) : Base(arc), m_id() {} + + /*! Construct an x-monotone arc from a conic arc. + * \param arc The given (base) arc. + * \param id The ID of the base arc. + */ + Conic_x_monotone_arc_2(const Base& arc, const Conic_id& id) : + Base(arc), + m_id(id) + {} + //@} + +public: /// \name Accessing the arc properties. //@{ - /*! - * Get the coefficients of the underlying conic. + /*! Obtain the facing mask. */ - const Integer& r() const { return (this->_r); } - const Integer& s() const { return (this->_s); } - const Integer& t() const { return (this->_t); } - const Integer& u() const { return (this->_u); } - const Integer& v() const { return (this->_v); } - const Integer& w() const { return (this->_w); } + size_t facing_mask() const { return this->m_info & FACING_MASK; } - /*! - * Get the arc's source. - * \return The source point. + /*! Obtain the degree mask. */ - const Conic_point_2& source() const { return (this->_source); } + size_t degree_mask() const { return this->m_info & DEGREE_MASK; } - /*! Get the arc's target. - * \return The target point. + /*! Obtain the coefficients of the underlying conic. */ - const Conic_point_2& target() const { return (this->_target); } + const Integer& r() const { return ( this->m_r); } + const Integer& s() const { return ( this->m_s); } + const Integer& t() const { return ( this->m_t); } + const Integer& u() const { return ( this->m_u); } + const Integer& v() const { return ( this->m_v); } + const Integer& w() const { return ( this->m_w); } - /*! Get the orientation of the arc. - * \return The orientation. + /*! Obtain the left endpoint of the arc. */ - Orientation orientation() const { return (this->_orient); } - - /*! Get the left endpoint of the arc. - */ - const Conic_point_2& left () const - { - if ((this->_info & IS_DIRECTED_RIGHT) != 0) return (this->_source); - else return (this->_target); + const Point_2& left() const { + if (this->test_flag(IS_DIRECTED_RIGHT)) return this->source(); + else return this->target(); } - /*! - * Get the right endpoint of the arc. + /*! Obtain the right endpoint of the arc. */ - const Conic_point_2& right () const - { - if ((this->_info & IS_DIRECTED_RIGHT) != 0) return (this->_target); - else return (this->_source); + const Point_2& right() const { + if (this->test_flag(IS_DIRECTED_RIGHT)) return this->target(); + else return this->source(); } - /*! - * Return true iff the conic arc is directed right iexicographically. + /*! Determine whether the conic arc is directed iexicographically right. */ - bool is_directed_right() const - { return ((this->_info & IS_DIRECTED_RIGHT) != 0); } + bool is_directed_right() const { return this->test_flag(IS_DIRECTED_RIGHT); } - /*! - * Get a bounding box for the conic arc. - * \return The bounding box. + /*! Determine whether the conic arc is a vertical segment. */ - Bbox_2 bbox() const { return (Base::bbox()); } - //@} + bool is_vertical() const { return this->test_flag(IS_VERTICAL_SEGMENT); } - /// \name Predicates. - //@{ - - /*! - * Check if the conic arc is a vertical segment. + /*! Determine whether the conic arc is a facing up. */ - bool is_vertical () const - { - return ((this->_info & IS_VERTICAL_SEGMENT) != 0); - } + bool is_upper() const { return this->test_flag(FACING_UP); } - /*! - * Check whether the given point lies on the arc. + /*! Determine whether the conic arc is a facing down. + */ + bool is_lower() const { return this->test_flag(FACING_DOWN); } + + /*! Check whether the arc is a special segment connecting two algebraic + * endpoints (and has no undelying integer conic coefficients). + */ + bool is_special_segment() const { return this->test_flag(IS_SPECIAL_SEGMENT); } + + /*! Obtain the mask of the DEGREE_1 flag. + */ + static constexpr size_t degree_1_mask() { return flag_mask(DEGREE_1); } + + /*! Obtain the mask of the DEGREE_1 flag. + */ + static constexpr size_t degree_2_mask() { return flag_mask(DEGREE_2); } + + /*! Obtain the algebraic coefficients. + */ + Algebraic alg_r() const { return m_alg_r; } + Algebraic alg_s() const { return m_alg_s; } + Algebraic alg_t() const { return m_alg_t; } + Algebraic alg_u() const { return m_alg_u; } + Algebraic alg_v() const { return m_alg_v; } + Algebraic alg_w() const { return m_alg_w; } + + /*! Obtain the conic id. + */ + Conic_id id() const { return m_id; } + + /*! Check whether the given point lies on the arc. * \param p The qury point. * \param (true) if p lies on the arc; (false) otherwise. */ - bool contains_point(const Conic_point_2& p) const - { + CGAL_DEPRECATED + bool contains_point(const Point_2& p) const { + const auto& xcv = *this; // First check if p lies on the supporting conic. We first check whether // it is one of p's generating conic curves. - bool p_on_conic = false; - - if (p.is_generating_conic(_id)) { - p_on_conic = true; - } + bool p_on_conic(false); + if (p.is_generating_conic(xcv.id())) p_on_conic = true; else { // Check whether p satisfies the supporting conic equation. - p_on_conic = _is_on_supporting_conic(p.x(), p.y()); - + p_on_conic = xcv.is_on_supporting_conic(p.x(), p.y()); if (p_on_conic) { // As p lies on the supporting conic of our arc, add its ID to // the list of generating conics for p. - Conic_point_2& p_non_const = const_cast (p); - p_non_const.set_generating_conic (_id); + Point_2& p_non_const = const_cast(p); + p_non_const.set_generating_conic(xcv.id()); } } - if (! p_on_conic) - return (false); + if (! p_on_conic) return false; // Check if p is between the endpoints of the arc. - return (_is_between_endpoints (p)); + return _is_between_endpoints(p); + } + + /*! Obtain a bounding box for the conic arc. + * \return The bounding box. + */ + CGAL_DEPRECATED Bbox_2 bbox() const { return Base::bbox(); } + //@} + + // Setters + //@{ + + /*! Set the algebraic coefficients. + */ + void set_alg_coefficients(const Algebraic& alg_r, const Algebraic& alg_s, + const Algebraic& alg_t, const Algebraic& alg_u, + const Algebraic& alg_v, const Algebraic& alg_w) + { + m_alg_r = alg_r; + m_alg_s = alg_s; + m_alg_t = alg_t; + m_alg_u = alg_u; + m_alg_v = alg_v; + m_alg_w = alg_w; + } + + /*! Add a generating conic ID. + */ + void set_generating_conic(const Conic_id& id) { + this->m_source.set_generating_conic(id); + this->m_target.set_generating_conic(id); } //@} - /// \name Constructing points on the arc. - //@{ - - /*! - * Compute a point on the arc with the same x-coordiante as the given point. + /*! Compute a point on an arc with the same \f$x\f$-coordiante as the given + * point. * \param p The given point. - * \pre The arc is not vertical and p is in the x-range of the arc. - * \return A point on the arc with the same x-coordiante as p. + * \pre The arc is not vertical and `p` is in the \f$x\f$-range of the arc. + * \return A point on the arc with the same \f$x\f$-coordiante as `p`. */ - Point_2 point_at_x (const Point_2& p) const - { + CGAL_DEPRECATED + Point_2 point_at_x(const Point_2& p) const { + const auto& xcv = *this; + Alg_kernel alg_kernel; + // Make sure that p is in the x-range of the arc. - CGAL_precondition ((this->_info & IS_VERTICAL_SEGMENT) == 0); + CGAL_precondition(! xcv.is_vertical()); - CGAL_precondition_code ( - Alg_kernel ker; - ); + CGAL_precondition_code(auto cmp_x = alg_kernel.compare_x_2_object()); + CGAL_precondition((cmp_x(p, xcv.left()) != SMALLER) && + (cmp_x(p, xcv.right()) != LARGER)); - CGAL_precondition(ker.compare_x_2_object() (p, left()) != SMALLER && - ker.compare_x_2_object() (p, right()) != LARGER); - - if (_is_special_segment()) { + if (xcv.is_special_segment()) { // In case of a special segment, the equation of the supported line // (a*x + b*y + c) = 0 is stored with the extra data field, and we // simply have: - Algebraic _y = -(this->_extra_data_P->a*p.x() + - this->_extra_data_P->c) / - this->_extra_data_P->b; + const auto& extra_data = xcv.extra_data(); + Algebraic y = -(extra_data->a*p.x() + extra_data->c) / extra_data->b; // Return the computed point. - return (Point_2 (p.x(), _y)); + return Point_2(p.x(), y); } // Compute the y-coordinate according to the degree of the supporting // conic curve. - Nt_traits nt_traits; + typename Base::Nt_traits nt_traits; Algebraic y; - if ((this->_info & DEGREE_MASK) == DEGREE_1) { + if (xcv.degree_mask() == Self::degree_1_mask()) { // In case of a linear curve, the y-coordinate is a simple linear // expression of x(p) (note that v is not 0 as the arc is not vertical): // y = -(u*x(p) + w) / v - y = -(alg_u*p.x() + alg_w) / alg_v; + y = -(xcv.alg_u()*p.x() + xcv.alg_w()) / xcv.alg_v(); } - else if (this->_orient == COLLINEAR) { - CGAL_assertion (this->_extra_data_P != nullptr); + else if (xcv.orientation() == COLLINEAR) { + const auto& extra_data = xcv.extra_data(); + CGAL_assertion(extra_data != nullptr); // In this case the equation of the supporting line is given by the // extra data structure. - y = -(this->_extra_data_P->a * p.x() + - this->_extra_data_P->c) / this->_extra_data_P->b; + y = -(extra_data->a * p.x() + extra_data->c) / extra_data->b; } else { - CGAL_assertion((this->_info & DEGREE_MASK) == DEGREE_2); + CGAL_assertion(xcv.degree_mask() == Self::degree_2_mask()); // In this case the y-coordinate is one of solutions to the quadratic // equation: // s*y^2 + (t*x(p) + v)*y + (r*x(p)^2 + u*x(p) + w) = 0 - Algebraic A = alg_s; - Algebraic B = alg_t*p.x() + alg_v; - Algebraic C = (alg_r*p.x() + alg_u)*p.x() + alg_w; + Algebraic A = xcv.alg_s(); + Algebraic B = xcv.alg_t()*p.x() + xcv.alg_v(); + Algebraic C = (xcv.alg_r()*p.x() + xcv.alg_u())*p.x() + xcv.alg_w(); - if (CGAL::sign(this->_s) == ZERO) { + if (CGAL::sign(xcv.s()) == ZERO) { // In this case A is 0 and we have a linear equation. - CGAL_assertion (CGAL::sign (B) != ZERO); + CGAL_assertion(CGAL::sign(B) != ZERO); y = -C / B; } else { // Solve the quadratic equation. - Algebraic disc = B*B - 4*A*C; + Algebraic disc = B*B - 4*A*C; - CGAL_assertion (CGAL::sign (disc) != NEGATIVE); + CGAL_assertion(CGAL::sign(disc) != NEGATIVE); // We take either the root involving -sqrt(disc) or +sqrt(disc) // based on the information flags. - if ((this->_info & PLUS_SQRT_DISC_ROOT) != 0) { - y = (nt_traits.sqrt (disc) - B) / (2*A); - } - else { - y = -(B + nt_traits.sqrt (disc)) / (2*A); - } + y = (xcv.test_flag(Self::PLUS_SQRT_DISC_ROOT)) ? + (nt_traits.sqrt(disc) - B) / (2*A) : + -(B + nt_traits.sqrt(disc)) / (2*A); } } // Return the computed point. - return (Point_2 (p.x(), y)); + return Point_2(p.x(), y); } - /*! - * Get a polyline approximating the conic arc. + /// \name Constructing points on the arc. + //@{ + + /*! Obtain a polyline approximating the conic arc. * \param n The maximal number of sample points. * \param oi An output iterator, whose value-type is pair * (representing an approximated point). @@ -494,10 +599,8 @@ public: * (p_0, p_1, ..., p_n), where p_0 and p_n are the left and right * endpoints of the arc, respectively. */ - template - OutputIterator polyline_approximation (size_t n, - OutputIterator oi) const - { + template + OutputIterator polyline_approximation(size_t n, OutputIterator oi) const { CGAL_precondition (n != 0); const double x_left = CGAL::to_double (left().x()); @@ -505,83 +608,152 @@ public: const double x_right = CGAL::to_double (right().x()); const double y_right = CGAL::to_double (right().y()); - if (this->_orient == COLLINEAR) { + if (this->m_orient == COLLINEAR) { // In case of a line segment, return the two endpoints. - *oi++ = std::pair (x_left, y_left); - *oi++ = std::pair (x_right, y_right); + *oi++ = std::pair(x_left, y_left); + *oi++ = std::pair(x_right, y_right); return oi; } // Otherwise, sample (n - 1) equally-spaced points in between. - const double app_r = CGAL::to_double (this->_r); - const double app_s = CGAL::to_double (this->_s); - const double app_t = CGAL::to_double (this->_t); - const double app_u = CGAL::to_double (this->_u); - const double app_v = CGAL::to_double (this->_v); - const double app_w = CGAL::to_double (this->_w); + const double app_r = CGAL::to_double(this->m_r); + const double app_s = CGAL::to_double(this->m_s); + const double app_t = CGAL::to_double(this->m_t); + const double app_u = CGAL::to_double(this->m_u); + const double app_v = CGAL::to_double(this->m_v); + const double app_w = CGAL::to_double(this->m_w); const double x_jump = (x_right - x_left) / n; - double x, y; - const bool A_is_zero = (CGAL::sign(this->_s) == ZERO); - double A = app_s, B, C; - double disc; - size_t i; + double x, y; + const bool A_is_zero = (CGAL::sign(this->m_s) == ZERO); + double A = app_s, B, C; + double disc; + size_t i; - *oi = std::pair(x_left, y_left); // The left point. - ++oi; - for (i = 1; i < n; i++) { + *oi++ = std::pair(x_left, y_left); // the left point + for (i = 1; i < n; ++i) { x = x_left + x_jump*i; // Solve the quadratic equation: A*x^2 + B*x + C = 0: B = app_t*x + app_v; C = (app_r*x + app_u)*x + app_w; - if (A_is_zero) { - y = -C / B; - } + if (A_is_zero) y = -C / B; else { disc = B*B - 4*A*C; - if (disc < 0) disc = 0; // We take either the root involving -sqrt(disc) or +sqrt(disc) // based on the information flags. - if ((this->_info & PLUS_SQRT_DISC_ROOT) != 0) { - y = (std::sqrt(disc) - B) / (2*A); - } - else { - y = -(B + std::sqrt (disc)) / (2*A); - } + y = (test_flag(PLUS_SQRT_DISC_ROOT)) ? + (std::sqrt(disc) - B) / (2*A) : -(B + std::sqrt (disc)) / (2*A); } - - *oi++ = std::pair (x, y); + *oi++ = std::pair(x, y); } - *oi++ = std::pair (x_right, y_right); // The right point. + *oi++ = std::pair(x_right, y_right); // the right point return oi; } - /*! Compare to arcs immediately to the right of their intersection point. - * \param arc The compared arc. + //@} + + /// \name Constructing x-monotone arcs. + //@{ + + /*! Flip the arc. + * \return An arc with swapped source and target and a reverse orienation. + */ + Self flip() const { + // Make a copy of the current arc. + Self arc = *this; + + // Reverse the orientation. + if (this->m_orient == CLOCKWISE) arc.m_orient = COUNTERCLOCKWISE; + else if (this->m_orient == COUNTERCLOCKWISE) arc.m_orient = CLOCKWISE; + + // Swap the source and the target. + arc.m_source = this->m_target; + arc.m_target = this->m_source; + + // Change the direction bit among the information flags. + arc.flip_flag(IS_DIRECTED_RIGHT); + + return arc; + } + + /*! Trim the arc given its new endpoints. + * \param ps The new source point. + * \param pt The new target point. + * \return The new trimmed arc. + * \pre Both ps and pt lies on the arc and must conform with the current + * direction of the arc. + */ + CGAL_DEPRECATED + Self trim(const Point_2& ps, const Point_2& pt) const { + auto& xcv = *this; + // Make sure that both ps and pt lie on the arc. + CGAL_precondition(contains_point(ps) && contains_point(pt)); + + // Make sure that the endpoints conform with the direction of the arc. + Alg_kernel alg_kernel; + Self res_xcv = xcv; // make a copy of the current arc + auto eq = alg_kernel.equal_2_object(); + auto set_source = [&](const Point_2 ps)->void { + if (! eq(ps, xcv.source())) { + res_xcv.set_source(ps); + if (! ps.is_generating_conic(xcv.id())) + res_xcv.source().set_generating_conic(xcv.id()); + } + }; + auto set_target = [&](const Point_2 pt)->void { + if (! eq(pt, xcv.target())) { + res_xcv.set_target(pt); + if (! pt.is_generating_conic(xcv.id())) + res_xcv.target().set_generating_conic(xcv.id()); + } + }; + + auto cmp_xy = alg_kernel.compare_xy_2_object(); + auto res = cmp_xy(ps, pt); + CGAL_assertion(res != EQUAL); + if ((xcv.test_flag(Self::IS_DIRECTED_RIGHT) && (res == LARGER)) || + (! xcv.test_flag(Self::IS_DIRECTED_RIGHT) && (res == SMALLER))) { + set_source(pt); + set_target(ps); + } + else { + set_source(ps); + set_target(pt); + } + + return res_xcv; + } + + //@} + + /*! Compare two arcs immediately to the leftt of their intersection point. + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. * \param p The reference intersection point. - * \return The relative position of the arcs to the right of p. + * \return The relative position of the arcs to the left of `p`. * \pre Both arcs we compare are not vertical segments. */ - Comparison_result compare_to_right(const Self& arc, - const Conic_point_2& p) const - { - CGAL_precondition((this->_info & IS_VERTICAL_SEGMENT) == 0 && - (arc._info & IS_VERTICAL_SEGMENT) == 0); + CGAL_DEPRECATED + Comparison_result compare_to_left(const Self& xcv2, const Point_2& p) const { + const auto& xcv1 = *this; + CGAL_precondition(! xcv1.is_vertical() && ! xcv2.is_vertical()); // In case one arc is facing upwards and another facing downwards, it is // clear that the one facing upward is above the one facing downwards. - if (_has_same_supporting_conic (arc)) { - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_DOWN) != 0) + if (_has_same_supporting_conic(xcv2)) { + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_DOWN)) return LARGER; - else if ((this->_info & FACING_DOWN) != 0 && (arc._info & FACING_UP) != 0) + else if (xcv1.test_flag(Self::FACING_DOWN) && + xcv2.test_flag(Self::FACING_UP)) return SMALLER; // In this case the two arcs overlap. - CGAL_assertion((this->_info & FACING_MASK) == (arc._info & FACING_MASK)); + CGAL_assertion(xcv1.facing_mask() == xcv2.facing_mask()); return EQUAL; } @@ -591,14 +763,138 @@ public: Algebraic slope1_numer, slope1_denom; Algebraic slope2_numer, slope2_denom; - _derive_by_x_at (p, 1, slope1_numer, slope1_denom); - arc._derive_by_x_at (p, 1, slope2_numer, slope2_denom); + xcv1.derive_by_x_at(p, 1, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 1, slope2_numer, slope2_denom); + + // Check if any of the slopes is vertical. + const bool is_vertical_slope1 = (CGAL::sign (slope1_denom) == ZERO); + const bool is_vertical_slope2 = (CGAL::sign (slope2_denom) == ZERO); + + if (! is_vertical_slope1 && ! is_vertical_slope2) { + // The two derivatives at p are well-defined: use them to determine + // which arc is above the other (the one with a larger slope is below). + Comparison_result slope_res = CGAL::compare(slope2_numer*slope1_denom, + slope1_numer*slope2_denom); + + if (slope_res != EQUAL) return slope_res; + + // Use the second-order derivative. + xcv1.derive_by_x_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 2, slope2_numer, slope2_denom); + + slope_res = CGAL::compare(slope1_numer*slope2_denom, + slope2_numer*slope1_denom); + + if (slope_res != EQUAL) return (slope_res); + + // Use the third-order derivative. + xcv1.derive_by_x_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 3, slope2_numer, slope2_denom); + + slope_res = CGAL::compare(slope2_numer*slope1_denom, + slope1_numer*slope2_denom); + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + return slope_res; + } + else if (! is_vertical_slope2) { + // The first arc has a vertical slope at p: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv1.facing_mask() != 0); + + return (xcv1.test_flag(Self::FACING_UP)) ? + LARGER : SMALLER; + } + else if (! is_vertical_slope1) { + // The second arc has a vertical slope at p_int: check whether it is + // facing upwards or downwards and decide accordingly. + CGAL_assertion(xcv2.facing_mask() != 0); + + return (xcv2.test_flag(Self::FACING_UP)) ? + SMALLER : LARGER; + } + + // The two arcs have vertical slopes at p_int: + // First check whether one is facing up and one down. In this case the + // comparison result is trivial. + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_DOWN)) + return LARGER; + else if (xcv1.test_flag(Self::FACING_DOWN) && + xcv2.test_flag(Self::FACING_UP)) + return SMALLER; + + // Compute the second-order derivative by y and act according to it. + xcv1.derive_by_y_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 2, slope2_numer, slope2_denom); + + Comparison_result slope_res = + CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); + + // If necessary, use the third-order derivative by y. + if (slope_res == EQUAL) { + // \todo Check this! + xcv1.derive_by_y_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 3, slope2_numer, slope2_denom); + + slope_res = + CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); + } + + // \todo Handle higher-order derivatives: + CGAL_assertion(slope_res != EQUAL); + + // Check whether both are facing up. + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_UP)) + return ((slope_res == LARGER) ? SMALLER : LARGER); + + // Both are facing down. + return slope_res; + } + + /*! Compare two arcs immediately to the right of their intersection point. + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. + * \param p The reference intersection point. + * \return The relative position of the arcs to the right of `p`. + * \pre Both arcs we compare are not vertical segments. + */ + CGAL_DEPRECATED + Comparison_result compare_to_right(const Self& xcv2, const Point_2& p) const { + const auto& xcv1 = *this; + CGAL_precondition(! xcv1.is_vertical() && ! xcv2.is_vertical()); + + // In case one arc is facing upwards and another facing downwards, it is + // clear that the one facing upward is above the one facing downwards. + if (_has_same_supporting_conic(xcv2)) { + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_DOWN)) + return LARGER; + else if (xcv1.test_flag(Self::FACING_DOWN) && + xcv2.test_flag(Self::FACING_UP)) + return SMALLER; + + // In this case the two arcs overlap. + CGAL_assertion(xcv1.facing_mask() == xcv2.facing_mask()); + return EQUAL; + } + + // Compare the slopes of the two arcs at p, using their first-order + // partial derivatives. + Algebraic slope1_numer, slope1_denom; + Algebraic slope2_numer, slope2_denom; + + xcv1.derive_by_x_at(p, 1, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 1, slope2_numer, slope2_denom); // Check if any of the slopes is vertical. const bool is_vertical_slope1 = (CGAL::sign(slope1_denom) == ZERO); const bool is_vertical_slope2 = (CGAL::sign(slope2_denom) == ZERO); - if (!is_vertical_slope1 && !is_vertical_slope2) { + if (! is_vertical_slope1 && ! is_vertical_slope2) { // The two derivatives at p are well-defined: use them to determine // which arc is above the other (the one with a larger slope is below). Comparison_result slope_res = @@ -607,8 +903,8 @@ public: if (slope_res != EQUAL) return (slope_res); // Use the second-order derivative. - _derive_by_x_at(p, 2, slope1_numer, slope1_denom); - arc._derive_by_x_at(p, 2, slope2_numer, slope2_denom); + xcv1.derive_by_x_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 2, slope2_numer, slope2_denom); slope_res = CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); @@ -616,45 +912,43 @@ public: if (slope_res != EQUAL) return (slope_res); // Use the third-order derivative. - _derive_by_x_at(p, 3, slope1_numer, slope1_denom); - arc._derive_by_x_at(p, 3, slope2_numer, slope2_denom); + xcv1.derive_by_x_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_x_at(p, 3, slope2_numer, slope2_denom); slope_res = CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); // \todo Handle higher-order derivatives: - CGAL_assertion (slope_res != EQUAL); + CGAL_assertion(slope_res != EQUAL); - return (slope_res); + return slope_res; } - else if (!is_vertical_slope2) { + else if (! is_vertical_slope2) { // The first arc has a vertical slope at p: check whether it is // facing upwards or downwards and decide accordingly. - CGAL_assertion ((this->_info & FACING_MASK) != 0); + CGAL_assertion(xcv1.facing_mask() != 0); - if ((this->_info & FACING_UP) != 0) return (LARGER); - return SMALLER; + return (xcv1.test_flag(Self::FACING_UP)) ? LARGER : SMALLER; } - else if (!is_vertical_slope1) { + else if (! is_vertical_slope1) { // The second arc has a vertical slope at p_int: check whether it is // facing upwards or downwards and decide accordingly. - CGAL_assertion ((arc._info & FACING_MASK) != 0); + CGAL_assertion(xcv2.facing_mask() != 0); - if ((arc._info & FACING_UP) != 0) return (SMALLER); - return LARGER; + return (xcv2.test_flag(Self::FACING_UP)) ? SMALLER : LARGER; } // The two arcs have vertical slopes at p_int: // First check whether one is facing up and one down. In this case the // comparison result is trivial. - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_DOWN) != 0) - return (LARGER); - else if ((this->_info & FACING_DOWN) != 0 && (arc._info & FACING_UP) != 0) - return SMALLER; + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_DOWN)) return LARGER; + else if (xcv1.test_flag(Self::FACING_DOWN) && + xcv2.test_flag(Self::FACING_UP)) return SMALLER; // Compute the second-order derivative by y and act according to it. - _derive_by_y_at (p, 2, slope1_numer, slope1_denom); - arc._derive_by_y_at (p, 2, slope2_numer, slope2_denom); + xcv1.derive_by_y_at(p, 2, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 2, slope2_numer, slope2_denom); Comparison_result slope_res = CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom); @@ -662,8 +956,8 @@ public: // If necessary, use the third-order derivative by y. if (slope_res == EQUAL) { // \todo Check this! - _derive_by_y_at(p, 3, slope1_numer, slope1_denom); - arc._derive_by_y_at(p, 3, slope2_numer, slope2_denom); + xcv1.derive_by_y_at(p, 3, slope1_numer, slope1_denom); + xcv2.derive_by_y_at(p, 3, slope2_numer, slope2_denom); slope_res = CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); @@ -672,720 +966,142 @@ public: // \todo Handle higher-order derivatives: CGAL_assertion(slope_res != EQUAL); - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_UP) != 0) { - // Both are facing up. - return ((slope_res == LARGER) ? SMALLER : LARGER); - } - // Both are facing down. - return (slope_res); + if (xcv1.test_flag(Self::FACING_UP) && + xcv2.test_flag(Self::FACING_UP)) + return (slope_res == LARGER) ? SMALLER : LARGER; // both are facing up + return slope_res; // both are facing down } - /*! - * Compare to arcs immediately to the leftt of their intersection point. - * \param arc The compared arc. - * \param p The reference intersection point. - * \return The relative position of the arcs to the left of p. - * \pre Both arcs we compare are not vertical segments. + /*! Check whether two arcs are equal (have the same graph). + * \param xcv1 The first compared arc. + * \param xcv2 The second compared arc. + * \return `true` if the two arcs have the same graph; `false` otherwise. */ - Comparison_result compare_to_left(const Self& arc, - const Conic_point_2& p) const - { - CGAL_precondition((this->_info & IS_VERTICAL_SEGMENT) == 0 && - (arc._info & IS_VERTICAL_SEGMENT) == 0); + CGAL_DEPRECATED + bool equals(const Self& xcv2) const { + const auto& xcv1 = *this; + Alg_kernel alg_kernel; - // In case one arc is facing upwards and another facing downwards, it is - // clear that the one facing upward is above the one facing downwards. - if (_has_same_supporting_conic (arc)) { - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_DOWN) != 0) - return LARGER; - else if ((this->_info & FACING_DOWN) != 0 && (arc._info & FACING_UP) != 0) - return SMALLER; - - // In this case the two arcs overlap. - CGAL_assertion((this->_info & FACING_MASK) == (arc._info & FACING_MASK)); - - return EQUAL; - } - - // Compare the slopes of the two arcs at p, using their first-order - // partial derivatives. - Algebraic slope1_numer, slope1_denom; - Algebraic slope2_numer, slope2_denom; - - _derive_by_x_at(p, 1, slope1_numer, slope1_denom); - arc._derive_by_x_at(p, 1, slope2_numer, slope2_denom); - - // Check if any of the slopes is vertical. - const bool is_vertical_slope1 = (CGAL::sign (slope1_denom) == ZERO); - const bool is_vertical_slope2 = (CGAL::sign (slope2_denom) == ZERO); - - if (!is_vertical_slope1 && !is_vertical_slope2) { - // The two derivatives at p are well-defined: use them to determine - // which arc is above the other (the one with a larger slope is below). - Comparison_result slope_res = CGAL::compare(slope2_numer*slope1_denom, - slope1_numer*slope2_denom); - - if (slope_res != EQUAL) return (slope_res); - - // Use the second-order derivative. - _derive_by_x_at (p, 2, slope1_numer, slope1_denom); - arc._derive_by_x_at (p, 2, slope2_numer, slope2_denom); - - slope_res = CGAL::compare (slope1_numer*slope2_denom, - slope2_numer*slope1_denom); - - if (slope_res != EQUAL) return (slope_res); - - // Use the third-order derivative. - _derive_by_x_at(p, 3, slope1_numer, slope1_denom); - arc._derive_by_x_at(p, 3, slope2_numer, slope2_denom); - - slope_res = CGAL::compare(slope2_numer*slope1_denom, - slope1_numer*slope2_denom); - - // \todo Handle higher-order derivatives: - CGAL_assertion (slope_res != EQUAL); - - return (slope_res); - } - else if (!is_vertical_slope2) { - // The first arc has a vertical slope at p: check whether it is - // facing upwards or downwards and decide accordingly. - CGAL_assertion ((this->_info & FACING_MASK) != 0); - - if ((this->_info & FACING_UP) != 0) return (LARGER); - return SMALLER; - } - else if (!is_vertical_slope1) { - // The second arc has a vertical slope at p_int: check whether it is - // facing upwards or downwards and decide accordingly. - CGAL_assertion ((arc._info & FACING_MASK) != 0); - - if ((arc._info & FACING_UP) != 0) return (SMALLER); - return LARGER; - } - - // The two arcs have vertical slopes at p_int: - // First check whether one is facing up and one down. In this case the - // comparison result is trivial. - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_DOWN) != 0) - return LARGER; - else if ((this->_info & FACING_DOWN) != 0 && (arc._info & FACING_UP) != 0) - return SMALLER; - - // Compute the second-order derivative by y and act according to it. - _derive_by_y_at(p, 2, slope1_numer, slope1_denom); - arc._derive_by_y_at(p, 2, slope2_numer, slope2_denom); - - Comparison_result slope_res = - CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); - - // If necessary, use the third-order derivative by y. - if (slope_res == EQUAL) { - // \todo Check this! - _derive_by_y_at(p, 3, slope1_numer, slope1_denom); - arc._derive_by_y_at(p, 3, slope2_numer, slope2_denom); - - slope_res = - CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom); - } - - // \todo Handle higher-order derivatives: - CGAL_assertion(slope_res != EQUAL); - - if ((this->_info & FACING_UP) != 0 && (arc._info & FACING_UP) != 0) { - // Both are facing up. - return ((slope_res == LARGER) ? SMALLER : LARGER); - } - // Both are facing down. - return (slope_res); - } - - /*! - * Compute the intersections with the given arc. - * \param arc The given intersecting arc. - * \param inter_map Maps conic pairs to lists of their intersection points. - * \param oi The output iterator. - * \return The past-the-end iterator. - */ - template - OutputIterator intersect(const Self& arc, - Intersection_map& inter_map, - OutputIterator oi) const - { - typedef boost::variant Intersection_result; - - if (_has_same_supporting_conic(arc)) { - // Check for overlaps between the two arcs. - Self overlap; - - if (_compute_overlap(arc, overlap)) { - // There can be just a single overlap between two x-monotone arcs: - *oi++ = Intersection_result(overlap); - return oi; - } - - // In case there is not overlap and the supporting conics are the same, - // there cannot be any intersection points, unless the two arcs share - // an end point. - // Note that in this case we do not define the multiplicity of the - // intersection points we report. - Alg_kernel ker; - - if (ker.equal_2_object()(left(), arc.left())) { - Intersection_point ip(left(), 0); - *oi++ = Intersection_result(ip); - } - - if (ker.equal_2_object()(right(), arc.right())) { - Intersection_point ip(right(), 0); - *oi++ = Intersection_result(ip); - } - - return oi; - } - - // Search for the pair of supporting conics in the map (the first conic - // ID in the pair should be smaller than the second one, to guarantee - // uniqueness). - Conic_pair conic_pair; - Intersection_map_iterator map_iter; - Intersection_list inter_list; - bool invalid_ids = false; - - if (_id.is_valid() && arc._id.is_valid()) { - if (_id < arc._id) conic_pair = Conic_pair (_id, arc._id); - else conic_pair = Conic_pair (arc._id, _id); - map_iter = inter_map.find (conic_pair); - } - else { - // In case one of the IDs is invalid, we do not look in the map neither - // we cache the results. - map_iter = inter_map.end(); - invalid_ids = true; - } - - if (map_iter == inter_map.end()) { - // In case the intersection points between the supporting conics have - // not been computed before, compute them now and store them in the map. - _intersect_supporting_conics(arc, inter_list); - - if (! invalid_ids) inter_map[conic_pair] = inter_list; - } - else { - // Obtain the precomputed intersection points from the map. - inter_list = (*map_iter).second; - } - - // Go over the list of intersection points and report those that lie on - // both x-monotone arcs. - for (auto iter = inter_list.begin(); iter != inter_list.end(); ++iter) { - if (_is_between_endpoints((*iter).first) && - arc._is_between_endpoints((*iter).first)) - { - *oi++ = Intersection_result(*iter); - } - } - - return oi; - } - //@} - - /// \name Constructing x-monotone arcs. - //@{ - - /*! - * Split the arc into two at a given split point. - * \param p The split point. - * \param c1 Output: The first resulting arc, lying to the left of p. - * \param c2 Output: The first resulting arc, lying to the right of p. - * \pre p lies in the interior of the arc (not one of its endpoints). - */ - void split(const Conic_point_2& p, Self& c1, Self& c2) const - { - // Make sure that p lies on the interior of the arc. - CGAL_precondition_code(Alg_kernel ker); - - CGAL_precondition (this->contains_point (p) && - ! ker.equal_2_object() (p, this->_source) && - ! ker.equal_2_object() (p, this->_target)); - - // Make copies of the current arc. - c1 = *this; - c2 = *this; - - // Assign the endpoints of the arc. - if ((this->_info & IS_DIRECTED_RIGHT) != 0) - { - // The arc is directed from left to right, so p becomes c1's target - // and c2's source. - c1._target = p; - c2._source = p; - - if (! p.is_generating_conic (_id)) { - c1._target.set_generating_conic (_id); - c2._source.set_generating_conic (_id); - } - } - else - { - // The arc is directed from right to left, so p becomes c2's target - // and c1's source. - c1._source = p; - c2._target = p; - - if (! p.is_generating_conic (_id)) { - c1._source.set_generating_conic (_id); - c2._target.set_generating_conic (_id); - } - } - - return; - } - - /*! - * Flip the arc. - * \return An arc with swapped source and target and a reverse orientation. - */ - Self flip() const - { - // Make a copy of the current arc. - Self arc = *this; - - // Reverse the orientation. - if (this->_orient == CLOCKWISE) arc._orient = COUNTERCLOCKWISE; - else if (this->_orient == COUNTERCLOCKWISE) arc._orient = CLOCKWISE; - - // Swap the source and the target. - arc._source = this->_target; - arc._target = this->_source; - - // Change the direction bit among the information flags. - arc._info = (this->_info ^ IS_DIRECTED_RIGHT); - - return arc; - } - - /*! - * Trim the arc given its new endpoints. - * \param ps The new source point. - * \param pt The new target point. - * \return The new trimmed arc. - * \pre Both ps and pt lies on the arc and must conform with the current - * direction of the arc. - */ - Self trim(const Conic_point_2& ps, const Conic_point_2& pt) const - { - // Make sure that both ps and pt lie on the arc. - CGAL_precondition(this->contains_point (ps) && - this->contains_point (pt)); - - // Make sure that the endpoints conform with the direction of the arc. - Self arc = *this; - Alg_kernel ker; - - if (! ((((this->_info & IS_DIRECTED_RIGHT) != 0) && - ker.compare_xy_2_object() (ps, pt) == SMALLER) || - (((this->_info & IS_DIRECTED_RIGHT) == 0) && - ker.compare_xy_2_object() (ps, pt) == LARGER))) - { - // We are allowed to change the direction only in case of a segment. - CGAL_assertion (this->_orient == COLLINEAR); - arc._info = (this->_info ^ IS_DIRECTED_RIGHT); - } - - // Make a copy of the current arc and assign its endpoints. - if (! ker.equal_2_object() (ps, this->_source)) { - arc._source = ps; - - if (! ps.is_generating_conic (_id)) - arc._source.set_generating_conic (_id); - } - - if (! ker.equal_2_object() (pt, this->_target)) - { - arc._target = pt; - - if (! pt.is_generating_conic (_id)) - arc._target.set_generating_conic (_id); - } - - return (arc); - } - - /*! - * Check whether the two arcs are equal (have the same graph). - * \param arc The compared arc. - * \return (true) if the two arcs have the same graph; (false) otherwise. - */ - bool equals (const Self& arc) const - { // The two arc must have the same supporting conic curves. - if (! _has_same_supporting_conic (arc)) - return false; + if (! _has_same_supporting_conic(xcv2)) return false; + + auto eq = alg_kernel.equal_2_object(); // Check that the arc endpoints are the same. - Alg_kernel ker; - - if (this->_orient == COLLINEAR) { - CGAL_assertion(arc._orient == COLLINEAR); - return((ker.equal_2_object()(this->_source, arc._source) && - ker.equal_2_object()(this->_target, arc._target)) || - (ker.equal_2_object()(this->_source, arc._target) && - ker.equal_2_object()(this->_target, arc._source))); + if (xcv1.orientation() == COLLINEAR) { + CGAL_assertion(xcv2.orientation() == COLLINEAR); + return((eq(xcv1.source(), xcv2.source()) && + eq(xcv1.target(), xcv2.target())) || + (eq(xcv1.source(), xcv2.target()) && + eq(xcv1.target(), xcv2.source()))); } - if (this->_orient == arc._orient) { + if (xcv1.orientation() == xcv2.m_orient) { // Same orientation - the source and target points must be the same. - return (ker.equal_2_object()(this->_source, arc._source) && - ker.equal_2_object()(this->_target, arc._target)); - } - else { - // Reverse orientation - the source and target points must be swapped. - return (ker.equal_2_object()(this->_source, arc._target) && - ker.equal_2_object()(this->_target, arc._source)); + return (eq(xcv1.source(), xcv2.source()) && + eq(xcv1.target(), xcv2.target())); } + + // Reverse orientation - the source and target points must be swapped. + return (eq(xcv1.source(), xcv2.target()) && + eq(xcv1.target(), xcv2.source())); } /*! Check whether it is possible to merge the arc with the given arc. - * \param arc The query arc. - * \return (true) if it is possible to merge the two arcs; - * (false) otherwise. + * \param xcv1 The first arc. + * \param xcv2 The second arc. + * \return `true` if it is possible to merge the two arcs; + * `false` otherwise. */ - bool can_merge_with(const Self& arc) const - { + CGAL_DEPRECATED + bool can_merge_with(const Self& xcv2) const { + const auto& xcv1 = *this; + Alg_kernel alg_kernel; + // In order to merge the two arcs, they should have the same supporting // conic. - if (! _has_same_supporting_conic(arc)) return false; + if (! _has_same_supporting_conic(xcv2)) return false; // Check if the left endpoint of one curve is the right endpoint of the // other. - Alg_kernel ker; - - return (ker.equal_2_object() (right(), arc.left()) || - ker.equal_2_object() (left(), arc.right())); + auto eq = alg_kernel.equal_2_object(); + return (eq(xcv1.right(), xcv2.left()) || eq(xcv1.left(), xcv2.right())); } /*! Merge the current arc with the given arc. - * \param arc The arc to merge with. + * \param xcv1 The first arc to merge with. + * \param xcv2 The second arc to merge with. * \pre The two arcs are mergeable. */ - void merge(const Self& arc) - { - CGAL_precondition (this->can_merge_with (arc)); + CGAL_DEPRECATED + void merge(const Self& xcv2) const { + const auto& xcv1 = *this; + Alg_kernel alg_kernel; - // Check if we should extend the arc to the left or to the right. - Alg_kernel ker; - - if (ker.equal_2_object() (right(), arc.left())) { + // Check whether we should extend the arc to the left or to the right. + auto eq = alg_kernel.equal_2_object(); + if (eq(xcv1.right(), xcv2.left())) { // Extend the arc to the right. - if ((this->_info & IS_DIRECTED_RIGHT) != 0) this->_target = arc.right(); - else this->_source = arc.right(); + if (xcv1.test_flag(Self::IS_DIRECTED_RIGHT)) + xcv1.set_target(xcv2.right()); + else xcv1.set_source(xcv2.right()); } else { - CGAL_precondition (ker.equal_2_object() (left(), arc.right())); + CGAL_precondition(eq(xcv1.left(), xcv2.right())); // Extend the arc to the left. - if ((this->_info & IS_DIRECTED_RIGHT) != 0) - this->_source = arc.left(); - else - this->_target = arc.left(); + if (xcv1.test_flag(Self::IS_DIRECTED_RIGHT)) + xcv1.set_source(xcv2.left()); + else xcv1.set_target(xcv2.left()); } - - return; } - bool is_upper() const - { - return ((this->_info & FACING_UP) != 0); - } - - bool is_lower() const - { - return ((this->_info & FACING_DOWN) != 0); - } - //@} - private: - /// \name Auxiliary (private) functions. //@{ - /*! - * Set the properties of the x-monotone conic arc (for the usage of the - * constructors). - */ - void _set () - { - // Convert the coefficients of the supporting conic to algebraic numbers. - Nt_traits nt_traits; - - alg_r = nt_traits.convert (this->_r); - alg_s = nt_traits.convert (this->_s); - alg_t = nt_traits.convert (this->_t); - alg_u = nt_traits.convert (this->_u); - alg_v = nt_traits.convert (this->_v); - alg_w = nt_traits.convert (this->_w); - - // Set the generating conic ID for the source and target points. - this->_source.set_generating_conic (_id); - this->_target.set_generating_conic (_id); - - // Clear the _info bits. - this->_info = Conic_arc_2::IS_VALID; - - // Check if the arc is directed right (the target is lexicographically - // greater than the source point), or to the left. - Alg_kernel ker; - Comparison_result dir_res = ker.compare_xy_2_object() (this->_source, - this->_target); - - CGAL_assertion (dir_res != EQUAL); - - if (dir_res == SMALLER) - this->_info = (this->_info | IS_DIRECTED_RIGHT); - - // Compute the degree of the underlying conic. - if (CGAL::sign (this->_r) != ZERO || - CGAL::sign (this->_s) != ZERO || - CGAL::sign (this->_t) != ZERO) - { - this->_info = (this->_info | DEGREE_2); - - if (this->_orient == COLLINEAR) - { - this->_info = (this->_info | IS_SPECIAL_SEGMENT); - - if (ker.compare_x_2_object() (this->_source, this->_target) == EQUAL) - { - // The arc is a vertical segment: - this->_info = (this->_info | IS_VERTICAL_SEGMENT); - } - - return; - } - } - else - { - CGAL_assertion (CGAL::sign (this->_u) != ZERO || - CGAL::sign (this->_v) != ZERO); - - if (CGAL::sign (this->_v) == ZERO) - { - - // The supporting curve is of the form: _u*x + _w = 0 - this->_info = (this->_info | IS_VERTICAL_SEGMENT); - } - - this->_info = (this->_info | DEGREE_1); - - return; - } - - if (this->_orient == COLLINEAR) - return; - - // Compute a midpoint between the source and the target and get the y-value - // of the arc at its x-coordiante. - Point_2 p_mid = ker.construct_midpoint_2_object() (this->_source, - this->_target); - Algebraic ys[2]; - CGAL_assertion_code(int n_ys = ) - _conic_get_y_coordinates (p_mid.x(), ys); - - CGAL_assertion (n_ys != 0); - - // Check which solution lies on the x-monotone arc. - Point_2 p_arc_mid (p_mid.x(), ys[0]); - - if (_is_strictly_between_endpoints (p_arc_mid)) - { - // Mark that we should use the -sqrt(disc) root for points on this - // x-monotone arc. - this->_info = (this->_info & ~PLUS_SQRT_DISC_ROOT); - } - else - { - CGAL_assertion (n_ys == 2); - p_arc_mid = Point_2 (p_mid.x(), ys[1]); - - CGAL_assertion (_is_strictly_between_endpoints (p_arc_mid)); - - // Mark that we should use the +sqrt(disc) root for points on this - // x-monotone arc. - this->_info = (this->_info | PLUS_SQRT_DISC_ROOT); - } - - // Check whether the conic is facing up or facing down: - // Check whether the arc (which is x-monotone of degree 2) lies above or - // below the segment that connects its two end-points (x1,y1) and (x2,y2). - // To do that, we find the y coordinate of a point on the arc whose x - // coordinate is (x1+x2)/2 and compare it to (y1+y2)/2. - Comparison_result res = ker.compare_y_2_object() (p_arc_mid, p_mid); - - if (res == LARGER) - { - // The arc is above the connecting segment, so it is facing upwards. - this->_info = (this->_info | FACING_UP); - } - else if (res == SMALLER) - { - // The arc is below the connecting segment, so it is facing downwards. - this->_info = (this->_info | FACING_DOWN); - } - - return; - } - - /*! - * Check if the arc is a special segment connecting two algebraic endpoints - * (and has no underlying integer conic coefficients). - */ - bool _is_special_segment () const - { - return ((this->_info & IS_SPECIAL_SEGMENT) != 0); - } - - /*! - * Check whether the given point lies on the supporting conic of the arc. + /*! Check whether the given point lies on the supporting conic of the arc. * \param px The x-coordinate of query point. * \param py The y-coordinate of query point. * \return (true) if p lies on the supporting conic; (false) otherwise. */ - bool _is_on_supporting_conic (const Algebraic& px, - const Algebraic& py) const - { - CGAL::Sign _sign; - - if (! _is_special_segment()) - { + bool is_on_supporting_conic(const Algebraic& px, const Algebraic& py) const { + CGAL::Sign my_sign = (! is_special_segment()) ? // Check whether p satisfies the conic equation. // The point must satisfy: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0. - _sign = CGAL::sign ((alg_r*px + alg_t*py + alg_u) * px + - (alg_s*py + alg_v) * py + - alg_w); - } - else - { + CGAL::sign((m_alg_r*px + m_alg_t*py + m_alg_u) * px + + (m_alg_s*py + m_alg_v) * py + m_alg_w) : // Check whether p satisfies the equation of the line stored with the // extra data. - _sign = _sign_of_extra_data (px, py); - } - - return (_sign == ZERO); + sign_of_extra_data(px, py); + return (my_sign == ZERO); } - /*! - * Check whether the two arcs have the same supporting conic. - * \param arc The compared arc. - * \return (true) if the two supporting conics are the same. - */ - bool _has_same_supporting_conic (const Self& arc) const - { - // Check if the two arcs originate from the same conic: - if (_id == arc._id && _id.is_valid() && arc._id.is_valid()) - return (true); - - // In case both arcs are collinear, check if they have the same - // supporting lines. - if (this->_orient == COLLINEAR && arc._orient == COLLINEAR) - { - // Construct the two supporting lines and compare them. - Alg_kernel ker; - typename Alg_kernel::Construct_line_2 construct_line = - ker.construct_line_2_object(); - typename Alg_kernel::Line_2 l1 = construct_line (this->_source, - this->_target); - typename Alg_kernel::Line_2 l2 = construct_line (arc._source, - arc._target); - typename Alg_kernel::Equal_2 equal = ker.equal_2_object(); - - if (equal (l1, l2)) - return (true); - - // Try to compare l1 with the opposite of l2. - l2 = construct_line (arc._target, arc._source); - - return (equal (l1, l2)); - } - else if (this->_orient == COLLINEAR || arc._orient == COLLINEAR) - { - // Only one arc is collinear, so the supporting curves cannot be the - // same: - return (false); - } - - // Check whether the coefficients of the two supporting conics are equal - // up to a constant factor. - Integer factor1 = 1; - Integer factor2 = 1; - - if (CGAL::sign (this->_r) != ZERO) - factor1 = this->_r; - else if (CGAL::sign (this->_s) != ZERO) - factor1 = this->_s; - else if (CGAL::sign (this->_t) != ZERO) - factor1 = this->_t; - else if (CGAL::sign (this->_u) != ZERO) - factor1 = this->_u; - else if (CGAL::sign (this->_v) != ZERO) - factor1 = this->_v; - else if (CGAL::sign (this->_w) != ZERO) - factor1 = this->_w; - - if (CGAL::sign (arc._r) != ZERO) - factor2 = arc._r; - else if (CGAL::sign (arc._s) != ZERO) - factor2 = arc._s; - else if (CGAL::sign (arc._t) != ZERO) - factor2 = arc._t; - else if (CGAL::sign (arc._u) != ZERO) - - factor2 = arc._u; - else if (CGAL::sign (arc._v) != ZERO) - factor2 = arc._v; - else if (CGAL::sign (arc._w) != ZERO) - factor2 = arc._w; - - return (CGAL::compare (this->_r * factor2, arc._r * factor1) == EQUAL && - CGAL::compare (this->_s * factor2, arc._s * factor1) == EQUAL && - CGAL::compare (this->_t * factor2, arc._t * factor1) == EQUAL && - CGAL::compare (this->_u * factor2, arc._u * factor1) == EQUAL && - CGAL::compare (this->_v * factor2, arc._v * factor1) == EQUAL && - CGAL::compare (this->_w * factor2, arc._w * factor1) == EQUAL); - } - - /*! - * Get the i'th order derivative by x of the conic at the point p=(x,y). +public: + /*! Obtain the i'th order derivative by x of the conic at the point p=(x,y). * \param p The point where we derive. * \param i The order of the derivatives (either 1, 2 or 3). * \param slope_numer The numerator of the slope. * \param slope_denom The denominator of the slope. * \todo Allow higher order derivatives. */ - void _derive_by_x_at (const Point_2& p, const unsigned int& i, - Algebraic& slope_numer, Algebraic& slope_denom) const - { - if (_is_special_segment()) - { + void derive_by_x_at(const Alg_point_2& p, const unsigned int& i, + Algebraic& slope_numer, Algebraic& slope_denom) const { + if (is_special_segment()) { // Special treatment for special segments, given by (a*x + b*y + c = 0), // so their first-order derivative by x is simply -a/b. The higher-order // derivatives are all 0. - if (i == 1) - { - if (CGAL::sign (this->_extra_data_P->b) != NEGATIVE) - { - slope_numer = - this->_extra_data_P->a; - slope_denom = this->_extra_data_P->b; + if (i == 1) { + if (CGAL::sign(this->m_extra_data->b) != NEGATIVE) { + slope_numer = - this->m_extra_data->a; + slope_denom = this->m_extra_data->b; } - else - { - slope_numer = this->_extra_data_P->a; - slope_denom = - this->_extra_data_P->b; + else { + slope_numer = this->m_extra_data->a; + slope_denom = - this->m_extra_data->b; } } - else - { + else { slope_numer = 0; slope_denom = 1; } @@ -1401,20 +1117,17 @@ private: // y' = - ---------------- = - ------- // 2s*y + t*x + v beta // - const Algebraic _two = 2; - const Algebraic sl_numer = _two*alg_r*p.x() + alg_t*p.y() + alg_u; - const Algebraic sl_denom = _two*alg_s*p.y() + alg_t*p.x() + alg_v; + const Algebraic two = 2; + const Algebraic sl_numer = two*m_alg_r*p.x() + m_alg_t*p.y() + m_alg_u; + const Algebraic sl_denom = two*m_alg_s*p.y() + m_alg_t*p.x() + m_alg_v; - if (i == 1) - { + if (i == 1) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { + if (CGAL::sign (sl_denom) != NEGATIVE) { slope_numer = -sl_numer; slope_denom = sl_denom; } - else - { + else { slope_numer = sl_numer; slope_denom = -sl_denom; } @@ -1428,22 +1141,18 @@ private: // y'' = -2 ------------------------------------- = ------- // beta^3 delta // - const Algebraic sl2_numer = alg_s * sl_numer*sl_numer - - alg_t * sl_numer*sl_denom + - alg_r * sl_denom*sl_denom; - const Algebraic sl2_denom = sl_denom*sl_denom*sl_denom; + const Algebraic sl2_numer = m_alg_s * sl_numer*sl_numer - + m_alg_t * sl_numer*sl_denom + m_alg_r * sl_denom*sl_denom; + const Algebraic sl2_denom = sl_denom*sl_denom*sl_denom; - if (i == 2) - { + if (i == 2) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { - slope_numer = -_two *sl2_numer; + if (CGAL::sign (sl_denom) != NEGATIVE) { + slope_numer = -two *sl2_numer; slope_denom = sl2_denom; } - else - { - slope_numer = _two *sl2_numer; + else { + slope_numer = two *sl2_numer; slope_denom = -sl2_denom; } @@ -1456,20 +1165,17 @@ private: // y''' = -6 ------------------------------ // beta^2 * delta // - const Algebraic sl3_numer = (_two * alg_s * sl_numer - - alg_t * sl_denom) * sl2_numer; - const Algebraic sl3_denom = sl_denom*sl_denom * sl2_denom; + const Algebraic sl3_numer = + (two * m_alg_s * sl_numer - m_alg_t * sl_denom) * sl2_numer; + const Algebraic sl3_denom = sl_denom*sl_denom * sl2_denom; - if (i == 3) - { + if (i == 3) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { + if (CGAL::sign (sl_denom) != NEGATIVE) { slope_numer = -6 * sl3_numer; slope_denom = sl3_denom; } - else - { + else { slope_numer = 6 * sl3_numer; slope_denom = -sl2_denom; } @@ -1479,40 +1185,32 @@ private: // \todo Handle higher-order derivatives as well. CGAL_error(); - return; } - /*! - * Get the i'th order derivative by y of the conic at the point p=(x,y). + /*! Obtain the i'th order derivative by y of the conic at the point p=(x,y). * \param p The point where we derive. * \param i The order of the derivatives (either 1, 2 or 3). * \param slope_numer The numerator of the slope. * \param slope_denom The denominator of the slope. * \todo Allow higher order derivatives. */ - void _derive_by_y_at (const Point_2& p, const int& i, - Algebraic& slope_numer, Algebraic& slope_denom) const - { - if (_is_special_segment()) - { + void derive_by_y_at(const Alg_point_2& p, const int& i, + Algebraic& slope_numer, Algebraic& slope_denom) const { + if (is_special_segment()) { // Special treatment for special segments, given by (a*x + b*y + c = 0), // so their first-order derivative by x is simply -b/a. The higher-order // derivatives are all 0. - if (i == 1) - { - if (CGAL::sign (this->_extra_data_P->a) != NEGATIVE) - { - slope_numer = - this->_extra_data_P->b; - slope_denom = this->_extra_data_P->a; + if (i == 1) { + if (CGAL::sign(this->m_extra_data->a) != NEGATIVE) { + slope_numer = - this->m_extra_data->b; + slope_denom = this->m_extra_data->a; } - else - { - slope_numer = this->_extra_data_P->b; - slope_denom = - this->_extra_data_P->a; + else { + slope_numer = this->m_extra_data->b; + slope_denom = - this->m_extra_data->a; } } - else - { + else { slope_numer = 0; slope_denom = 1; } @@ -1528,25 +1226,21 @@ private: // x' = - ---------------- = ------- // 2r*x + t*y + u beta // - const Algebraic _two = 2; - const Algebraic sl_numer = _two*alg_s*p.y() + alg_t*p.x() + alg_v; - const Algebraic sl_denom = _two*alg_r*p.x() + alg_t*p.y() + alg_u; + const Algebraic two = 2; + const Algebraic sl_numer = two*m_alg_s*p.y() + m_alg_t*p.x() + m_alg_v; + const Algebraic sl_denom = two*m_alg_r*p.x() + m_alg_t*p.y() + m_alg_u; - if (i == 1) - { + if (i == 1) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { + if (CGAL::sign (sl_denom) != NEGATIVE) { slope_numer = -sl_numer; slope_denom = sl_denom; } - else - { + else { slope_numer = sl_numer; slope_denom = -sl_denom; } - return; } @@ -1556,23 +1250,18 @@ private: // x'' = -2 ------------------------------------- // beta^3 // - const Algebraic sl2_numer = alg_r * sl_numer*sl_numer - - alg_t * sl_numer*sl_denom + - alg_s * sl_denom*sl_denom; - const Algebraic sl2_denom = sl_denom*sl_denom*sl_denom; - - if (i == 2) - { + const Algebraic sl2_numer = m_alg_r * sl_numer*sl_numer - + m_alg_t * sl_numer*sl_denom + m_alg_s * sl_denom*sl_denom; + const Algebraic sl2_denom = sl_denom*sl_denom*sl_denom; + if (i == 2) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { - slope_numer = -_two *sl2_numer; + if (CGAL::sign (sl_denom) != NEGATIVE) { + slope_numer = -two *sl2_numer; slope_denom = sl2_denom; } - else - { - slope_numer = _two *sl2_numer; + else { + slope_numer = two *sl2_numer; slope_denom = -sl2_denom; } @@ -1585,20 +1274,17 @@ private: // y''' = -6 ------------------------------ // beta^2 * delta // - const Algebraic sl3_numer = (_two * alg_r * sl_numer - - alg_t * sl_denom) * sl2_numer; - const Algebraic sl3_denom = sl_denom*sl_denom * sl2_denom; + const Algebraic sl3_numer = + (two * m_alg_r * sl_numer - m_alg_t * sl_denom) * sl2_numer; + const Algebraic sl3_denom = sl_denom*sl_denom * sl2_denom; - if (i == 3) - { + if (i == 3) { // Make sure that the denominator is always positive. - if (CGAL::sign (sl_denom) != NEGATIVE) - { + if (CGAL::sign(sl_denom) != NEGATIVE) { slope_numer = -6 * sl3_numer; slope_denom = sl3_denom; } - else - { + else { slope_numer = 6 * sl3_numer; slope_denom = -sl2_denom; } @@ -1608,363 +1294,86 @@ private: // \todo Handle higher-order derivatives as well. CGAL_error(); - return; } - /*! - * Compute the overlap with a given arc, which is supposed to have the same - * supporting conic curve as this arc. - * \param arc The given arc. - * \param overlap Output: The overlapping arc (if any). - * \return Whether we found an overlap. - */ - bool _compute_overlap (const Self& arc, Self& overlap) const - { - // Check if the two arcs are identical. - if (equals (arc)) - { - overlap = arc; - return (true); - } - - if (_is_strictly_between_endpoints (arc.left())) - { - if (_is_strictly_between_endpoints(arc.right())) - { - // Case 1 - *this: +-----------> - // arc: +=====> - overlap = arc; - return (true); - } - else - { - // Case 2 - *this: +-----------> - // arc: +=====> - overlap = *this; - - if ((overlap._info & IS_DIRECTED_RIGHT) != 0) - overlap._source = arc.left(); - else - overlap._target = arc.left(); - - return (true); - } - } - else if (_is_strictly_between_endpoints (arc.right())) - { - // Case 3 - *this: +-----------> - // arc: +=====> - overlap = *this; - - if ((overlap._info & IS_DIRECTED_RIGHT) != 0) - overlap._target = arc.right(); - else - overlap._source = arc.right(); - - return (true); - } - else if (arc._is_between_endpoints (this->_source) && - arc._is_between_endpoints (this->_target) && - (arc._is_strictly_between_endpoints(this->_source) || - arc._is_strictly_between_endpoints(this->_target))) - { - // Case 4 - *this: +-----------> - // arc: +================> - overlap = *this; - return (true); - } - - // If we reached here, there are no overlaps: - return (false); - } - - /*! - * Intersect the supporting conic curves of this arc and the given arc. - * \param arc The arc to intersect with. - * \param inter_list The list of intersection points. - */ - void _intersect_supporting_conics(const Self& arc, - Intersection_list& inter_list) const - { - if (_is_special_segment() && ! arc._is_special_segment()) { - // If one of the arcs is a special segment, make sure it is (arc). - arc._intersect_supporting_conics(*this, inter_list); - return; - } - - const int deg1 = ((this->_info & DEGREE_MASK) == DEGREE_1) ? 1 : 2; - const int deg2 = ((arc._info & DEGREE_MASK) == DEGREE_1) ? 1 : 2; - Nt_traits nt_traits; - Algebraic xs[4]; - int n_xs = 0; - Algebraic ys[4]; - int n_ys = 0; - - if (arc._is_special_segment()) { - // The second arc is a special segment (a*x + b*y + c = 0). - if (_is_special_segment()) { - // Both arc are special segment, so they have at most one intersection - // point. - Algebraic denom = this->_extra_data_P->a * arc._extra_data_P->b - - this->_extra_data_P->b * arc._extra_data_P->a; - - if (CGAL::sign (denom) != CGAL::ZERO) { - xs[0] = (this->_extra_data_P->b * arc._extra_data_P->c - - this->_extra_data_P->c * arc._extra_data_P->b) / denom; - n_xs = 1; - - ys[0] = (this->_extra_data_P->c * arc._extra_data_P->a - - this->_extra_data_P->a * arc._extra_data_P->c) / denom; - n_ys = 1; - } - } - else { - // Compute the x-coordinates of the intersection points. - n_xs = _compute_resultant_roots (nt_traits, - alg_r, alg_s, alg_t, - alg_u, alg_v, alg_w, - deg1, - arc._extra_data_P->a, - arc._extra_data_P->b, - arc._extra_data_P->c, - xs); - CGAL_assertion (n_xs <= 2); - - // Compute the y-coordinates of the intersection points. - n_ys = _compute_resultant_roots (nt_traits, - alg_s, alg_r, alg_t, - alg_v, alg_u, alg_w, - deg1, - arc._extra_data_P->b, - arc._extra_data_P->a, - arc._extra_data_P->c, - ys); - CGAL_assertion (n_ys <= 2); - } - } - else { - // Compute the x-coordinates of the intersection points. - n_xs = _compute_resultant_roots (nt_traits, - this->_r, this->_s, this->_t, - this->_u, this->_v, this->_w, - deg1, - arc._r, arc._s, arc._t, - arc._u, arc._v, arc._w, - deg2, - xs); - CGAL_assertion (n_xs <= 4); - - // Compute the y-coordinates of the intersection points. - n_ys = _compute_resultant_roots (nt_traits, - this->_s, this->_r, this->_t, - this->_v, this->_u, this->_w, - deg1, - arc._s, arc._r, arc._t, - arc._v, arc._u, arc._w, - deg2, - ys); - CGAL_assertion(n_ys <= 4); - } - - // Pair the coordinates of the intersection points. As the vectors of - // x and y-coordinates are sorted in ascending order, we output the - // intersection points in lexicographically ascending order. - unsigned int mult; - int i, j; - - if (arc._is_special_segment()) - { - if (n_xs == 0 || n_ys == 0) - return; - - if (n_xs == 1 && n_ys == 1) - { - // Single intersection. - Conic_point_2 ip (xs[0], ys[0]); - - ip.set_generating_conic (_id); - ip.set_generating_conic (arc._id); - - // In case the other curve is of degree 2, this is a tangency point. - mult = (deg1 == 1 || _is_special_segment()) ? 1 : 2; - inter_list.push_back(Intersection_point (ip, mult)); - } - else if (n_xs == 1 && n_ys == 2) - { - Conic_point_2 ip1 (xs[0], ys[0]); - - ip1.set_generating_conic (_id); - ip1.set_generating_conic (arc._id); - - inter_list.push_back(Intersection_point (ip1, 1)); - - Conic_point_2 ip2 (xs[0], ys[1]); - - ip2.set_generating_conic (_id); - ip2.set_generating_conic (arc._id); - - inter_list.push_back(Intersection_point (ip2, 1)); - } - else if (n_xs == 2 && n_ys == 1) - { - Conic_point_2 ip1 (xs[0], ys[0]); - - ip1.set_generating_conic (_id); - ip1.set_generating_conic (arc._id); - - inter_list.push_back(Intersection_point (ip1, 1)); - - Conic_point_2 ip2 (xs[1], ys[0]); - - ip2.set_generating_conic (_id); - ip2.set_generating_conic (arc._id); - - inter_list.push_back(Intersection_point (ip2, 1)); - - } - else { - CGAL_assertion (n_xs == 2 && n_ys == 2); - - // The x-coordinates and the y-coordinates are given in ascending - // order. If the slope of the segment is positive, we pair the - // coordinates as is - otherwise, we swap the pairs. - int ind_first_y = 0, ind_second_y = 1; - - if (CGAL::sign (arc._extra_data_P->b) == - CGAL::sign(arc._extra_data_P->a)) - { - ind_first_y = 1; - ind_second_y = 0; - } - - Conic_point_2 ip1(xs[0], ys[ind_first_y]); - - ip1.set_generating_conic(_id); - ip1.set_generating_conic(arc._id); - - inter_list.push_back(Intersection_point (ip1, 1)); - - Conic_point_2 ip2(xs[1], ys[ind_second_y]); - - ip2.set_generating_conic (_id); - ip2.set_generating_conic (arc._id); - - inter_list.push_back(Intersection_point(ip2, 1)); - } - - return; - } - - for (i = 0; i < n_xs; i++) { - for (j = 0; j < n_ys; j++) { - if (_is_on_supporting_conic (xs[i], ys[j]) && - arc._is_on_supporting_conic (xs[i], ys[j])) - { - // Create the intersection point and set its generating conics. - Conic_point_2 ip(xs[i], ys[j]); - - ip.set_generating_conic (_id); - ip.set_generating_conic (arc._id); - - // Compute the multiplicity of the intersection point. - if (deg1 == 1 && deg2 == 1) mult = 1; - else mult = _multiplicity_of_intersection_point(arc, ip); - - // Insert the intersection point to the output list. - inter_list.push_back(Intersection_point(ip, mult)); - } - } - } - - return; - } - - /*! - * Compute the multiplicity of an intersection point. +private: + /*! Compute the multiplicity of an intersection point. * \param arc The arc to intersect with. * \param p The intersection point. * \return The multiplicity of the intersection point. */ - unsigned int _multiplicity_of_intersection_point (const Self& arc, - const Point_2& p) const - { - CGAL_assertion (! _is_special_segment() || ! arc._is_special_segment()); + size_t multiplicity_of_intersection_point(const Self& xcv, + const Alg_point_2& p) const { + CGAL_assertion(! is_special_segment() || ! xcv.is_special_segment()); // Compare the slopes of the two arcs at p, using their first-order // partial derivatives. - Algebraic slope1_numer, slope1_denom; - Algebraic slope2_numer, slope2_denom; + Algebraic slope1_numer, slope1_denom; + Algebraic slope2_numer, slope2_denom; - _derive_by_x_at (p, 1, slope1_numer, slope1_denom); - arc._derive_by_x_at (p, 1, slope2_numer, slope2_denom); + derive_by_x_at(p, 1, slope1_numer, slope1_denom); + xcv.derive_by_x_at(p, 1, slope2_numer, slope2_denom); - if (CGAL::compare (slope1_numer*slope2_denom, - slope2_numer*slope1_denom) != EQUAL) - { + if (CGAL::compare(slope1_numer*slope2_denom, slope2_numer*slope1_denom) != + EQUAL) { // Different slopes at p - the mutiplicity of p is 1: - return (1); + return 1; } - if (CGAL::sign (slope1_denom) != ZERO && - CGAL::sign (slope2_denom) != ZERO) - { + if (CGAL::sign(slope1_denom) != ZERO && + CGAL::sign(slope2_denom) != ZERO) { // The curves do not have a vertical slope at p. // Compare their second-order derivative by x: - _derive_by_x_at (p, 2, slope1_numer, slope1_denom); - arc._derive_by_x_at (p, 2, slope2_numer, slope2_denom); + derive_by_x_at(p, 2, slope1_numer, slope1_denom); + xcv.derive_by_x_at(p, 2, slope2_numer, slope2_denom); } - else - { + else { // Both curves have a vertical slope at p. // Compare their second-order derivative by y: - _derive_by_y_at (p, 2, slope1_numer, slope1_denom); - arc._derive_by_y_at (p, 2, slope2_numer, slope2_denom); + derive_by_y_at(p, 2, slope1_numer, slope1_denom); + xcv.derive_by_y_at(p, 2, slope2_numer, slope2_denom); } - if (CGAL::compare (slope1_numer*slope2_denom, - slope2_numer*slope1_denom) != EQUAL) + if (CGAL::compare(slope1_numer*slope2_denom, + slope2_numer*slope1_denom) != EQUAL) { // Different curvatures at p - the mutiplicity of p is 2: - return (2); + return 2; } // If we reached here, the multiplicity of the intersection point is 3: - return (3); + return 3; } //@} }; -/*! - * Exporter for x-monotone conic arcs. +/*! Exporter for x-monotone conic arcs. */ -template -std::ostream& operator<< (std::ostream& os, - const _Conic_x_monotone_arc_2& arc) +template +std::ostream& operator<<(std::ostream& os, + const Conic_x_monotone_arc_2& xcv) { // Output the supporting conic curve. - os << "{" << CGAL::to_double(arc.r()) << "*x^2 + " - << CGAL::to_double(arc.s()) << "*y^2 + " - << CGAL::to_double(arc.t()) << "*xy + " - << CGAL::to_double(arc.u()) << "*x + " - << CGAL::to_double(arc.v()) << "*y + " - << CGAL::to_double(arc.w()) << "}"; + os << "{" << CGAL::to_double(xcv.r()) << "*x^2 + " + << CGAL::to_double(xcv.s()) << "*y^2 + " + << CGAL::to_double(xcv.t()) << "*xy + " + << CGAL::to_double(xcv.u()) << "*x + " + << CGAL::to_double(xcv.v()) << "*y + " + << CGAL::to_double(xcv.w()) << "}"; // Output the endpoints. - os << " : (" << CGAL::to_double(arc.source().x()) << "," - << CGAL::to_double(arc.source().y()) << ") "; + os << " : (" << CGAL::to_double(xcv.source().x()) << "," + << CGAL::to_double(xcv.source().y()) << ") "; - if (arc.orientation() == CLOCKWISE) - os << "--cw-->"; - else if (arc.orientation() == COUNTERCLOCKWISE) - os << "--ccw-->"; - else - os << "--l-->"; + if (xcv.orientation() == CLOCKWISE) os << "--cw-->"; + else if (xcv.orientation() == COUNTERCLOCKWISE) os << "--ccw-->"; + else os << "--l-->"; - os << " (" << CGAL::to_double(arc.target().x()) << "," - << CGAL::to_double(arc.target().y()) << ")"; + os << " (" << CGAL::to_double(xcv.target().x()) << "," + << CGAL::to_double(xcv.target().y()) << ")"; - return (os); + return os; } } //namespace CGAL diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_non_caching_segment_basic_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_non_caching_segment_basic_traits_2.h index 1190c3e1085..f394e3adf86 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_non_caching_segment_basic_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_non_caching_segment_basic_traits_2.h @@ -30,6 +30,7 @@ * functors required by the concept it models. */ +#include #include #include #include @@ -230,37 +231,63 @@ public: /// \name Functor definitions for the landmarks point-location strategy. //@{ - typedef double Approximate_number_type; + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; + + class Approximate_2 { + protected: + using Traits = Arr_non_caching_segment_basic_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_non_caching_segment_basic_traits_2; - class Approximate_2 - { public: - - /*! - * Return an approximation of a point coordinate. + /*! Return an approximation of a point coordinate. * \param p The exact point. * \param i The coordinate index (either 0 or 1). * \pre i is either 0 or 1. * \return An approximation of p's x-coordinate (if i == 0), or an * approximation of p's y-coordinate (if i == 1). */ - Approximate_number_type operator() (const Point_2& p, - int i) const - { + Approximate_number_type operator() (const Point_2& p, int i) const { CGAL_precondition (i == 0 || i == 1); + return (i == 0) ? (CGAL::to_double(p.x())) : (CGAL::to_double(p.y())); + } - if (i == 0) - return (CGAL::to_double(p.x())); - else - return (CGAL::to_double(p.y())); + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2& p) const + { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv, double /* error */, + OutputIterator oi, bool l2r = true) const { + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + *oi++ = Approximate_point_2(xs, ys); + *oi++ = Approximate_point_2(xt, yt); + return oi; } }; /*! Get an Approximate_2 functor object. */ - Approximate_2 approximate_2_object () const - { - return Approximate_2(); - } + Approximate_2 approximate_2_object () const { return Approximate_2(*this); } typedef typename Kernel::Construct_segment_2 Construct_x_monotone_curve_2; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h index 0824ddf9e02..84c9cee01d9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_basic_traits_2.h @@ -1088,59 +1088,66 @@ public: // ArrangementLandmarkTraits concept. //@{ -#if 0 - // The following block assumes that the subcurve traits template parameter - // is a model of the ArrangementLandmarkTraits concept; in other words, it - // defines the nested types Approximate_number_type and Approximate_2 and - // the member function approximate_2_object(). It cannot be used as is if - // the subcurve traits does not model the ArrangementLandmarkTraits concept. - // The functor Construct_x_monotone_curve_2 is provided regardless of the - // subcurve traits. - - typedef typename Subcurve_traits_2::Approximate_number_type - Approximate_number_type; - typedef typename Subcurve_traits_2::Approximate_2 Approximate_2; - - /*! Obtain an Approximate_2 functor object. */ - Approximate_2 approximate_2_object() const - { return subcurve_traits_2()->approximate_2_object(); } -#else // The following block defines the nested types Approximate_number_type and // Approximate_2 and the member function approximate_2_object() based on the // corresponding types and function definitions of the subcurve traits. If // the subcurve traits does not provide these definitions, they are defined - // as dummies. Essentially, the polycurve traits becomes a practical model of - // the ArrangementLandmarkTraits concept only if the subcurve traits is a - // model of this concept. + // as dummies. Essentially, the polycurve traits becomes a model of the + // ArrangementLandmarkTraits concept only if the subcurve traits is a model + // of this concept. // // The following implementation is inspired by // https://stackoverflow.com/a/11816999/1915421 - template - struct Void { - typedef void type; - }; + template using void_t = void; - template + template struct has_approximate_2 { // Generic implementation - typedef void Approximate_number_type; - typedef void Approximate_2; + using Approximate_number_type = void; + using Approximate_point_2 = void; + + struct Approximate_2 { + /*! Obtain an approximation of a point coordinate. + * \param p the exact point. + * \param i the coordinate index (either 0 or 1). + * \pre i is either 0 or 1. + * \return An approximation of p's x-coordinate (if i == 0), or an + * approximation of p's y-coordinate (if i == 1). + */ + Approximate_number_type operator()(const Point_2&, int) const + { CGAL_error_msg("The subtraits does not define Approximate_2!"); } + + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2&) const + { CGAL_error_msg("The subtraits does not define Approximate_2!"); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2&, double, + OutputIterator oi, bool = true) const { + CGAL_error_msg("The subtraits does not define Approximate_2!"); + return oi; + } + }; }; template - struct has_approximate_2::type> - { + struct has_approximate_2> { // Specialization for types holding a nested type T::Approximate_2 - typedef typename T::Approximate_number_type - Approximate_number_type; - typedef typename T::Approximate_2 Approximate_2; + using Approximate_number_type = typename T::Approximate_number_type; + using Approximate_2 = typename T::Approximate_2; + using Approximate_point_2 = typename T::Approximate_point_2; }; - typedef typename has_approximate_2::Approximate_number_type - Approximate_number_type; - typedef typename has_approximate_2::Approximate_2 - Approximate_2; + using Approximate_number_type = + typename has_approximate_2::Approximate_number_type; + using Approximate_2 = + typename has_approximate_2::Approximate_2; + using Approximate_point_2 = + typename has_approximate_2::Approximate_point_2; /*! Obtain an Approximate_2 functor object. */ Approximate_2 approximate_2_object_impl(std::false_type) const @@ -1148,13 +1155,12 @@ public: Approximate_2 approximate_2_object_impl(std::true_type) const { } - Approximate_2 approximate_2_object() const - { - typedef typename std::is_same::type Is_void; + Approximate_2 approximate_2_object() const { + using Is_void = typename std::is_same::type; return approximate_2_object_impl(Is_void()); } -#endif + // class Construct_x_monotone_curve_2 { protected: typedef Arr_polycurve_basic_traits_2 diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h index f2f7fe7c8e2..be6fb987894 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_polyline_traits_2.h @@ -98,7 +98,6 @@ public: typedef typename Base::Equal_2 Equal_2; typedef typename Base::Compare_endpoints_xy_2 Compare_endpoints_xy_2; typedef typename Base::Construct_opposite_2 Construct_opposite_2; - typedef typename Base::Approximate_2 Approximate_2; typedef typename Base::Parameter_space_in_x_2 Parameter_space_in_x_2; typedef typename Base::Parameter_space_in_y_2 Parameter_space_in_y_2; typedef typename Base::Compare_x_on_boundary_2 Compare_x_on_boundary_2; @@ -595,6 +594,62 @@ public: Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object() const { return Construct_x_monotone_curve_2(*this); } + // + using Approximate_number_type = typename Base::Approximate_number_type; + using Approximate_point_2 = typename Base::Approximate_point_2; + + class Approximate_2 : public Base::Approximate_2 { + protected: + using Traits = Arr_polyline_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_2(const Traits& traits) : + Base::Approximate_2(*(traits.subcurve_traits_2())), + m_traits(traits) + {} + + friend class Arr_polyline_traits_2; + + public: + Approximate_number_type operator()(const Point_2& p, int i) const + { return Base::Approximate_2::operator()(p, i); } + + Approximate_point_2 operator()(const Point_2& p) const + { return Base::Approximate_2::operator()(p); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv, double /* error */, + OutputIterator oi, bool l2r = true) const { + if (l2r) { + for (auto it = xcv.points_begin(); it != xcv.points_end(); ++it) { + const auto& p = *it; + auto x = CGAL::to_double(p.x()); + auto y = CGAL::to_double(p.y()); + *oi++ = Approximate_point_2(x, y); + } + return oi; + } + + for (auto it = xcv.points_rbegin(); it != xcv.points_rend(); ++it) { + const auto& p = *it; + auto x = CGAL::to_double(p.x()); + auto y = CGAL::to_double(p.y()); + *oi++ = Approximate_point_2(x, y); + } + return oi; + } + }; + + /*! Obtain an Approximate_2 functor object. */ + Approximate_2 approximate_2_object() const { return Approximate_2(*this); } + /*! Deprecated! * Obtain the segment traits. * \return the segment traits. diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 1e3b908faa6..e4828c134c4 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -879,9 +880,24 @@ public: /// \name Functor definitions for the landmarks point-location strategy. //@{ - typedef double Approximate_number_type; + typedef double Approximate_number_type; + typedef CGAL::Cartesian Approximate_kernel; + typedef Approximate_kernel::Point_2 Approximate_point_2; class Approximate_2 { + protected: + using Traits = Arr_segment_traits_2; + + /*! The traits (in case it has state) */ + const Traits& m_traits; + + /*! Constructor + * \param traits the traits. + */ + Approximate_2(const Traits& traits) : m_traits(traits) {} + + friend class Arr_segment_traits_2; + public: /*! Obtain an approximation of a point coordinate. * \param p the exact point. @@ -890,15 +906,37 @@ public: * \return An approximation of p's x-coordinate (if i == 0), or an * approximation of p's y-coordinate (if i == 1). */ - Approximate_number_type operator()(const Point_2& p, int i) const - { + Approximate_number_type operator()(const Point_2& p, int i) const { CGAL_precondition((i == 0) || (i == 1)); return (i == 0) ? (CGAL::to_double(p.x())) : (CGAL::to_double(p.y())); } + + /*! Obtain an approximation of a point. + */ + Approximate_point_2 operator()(const Point_2& p) const + { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + + /*! Obtain an approximation of an \f$x\f$-monotone curve. + */ + template + OutputIterator operator()(const X_monotone_curve_2& xcv, double /* error */, + OutputIterator oi, bool l2r = true) const { + auto min_vertex = m_traits.construct_min_vertex_2_object(); + auto max_vertex = m_traits.construct_max_vertex_2_object(); + const auto& src = (l2r) ? min_vertex(xcv) : max_vertex(xcv); + const auto& trg = (l2r) ? max_vertex(xcv) : min_vertex(xcv); + auto xs = CGAL::to_double(src.x()); + auto ys = CGAL::to_double(src.y()); + auto xt = CGAL::to_double(trg.x()); + auto yt = CGAL::to_double(trg.y()); + *oi++ = Approximate_point_2(xs, ys); + *oi++ = Approximate_point_2(xt, yt); + return oi; + } }; /*! Obtain an Approximate_2 functor object. */ - Approximate_2 approximate_2_object() const { return Approximate_2(); } + Approximate_2 approximate_2_object() const { return Approximate_2(*this); } //! Functor class Construct_x_monotone_curve_2 { diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_spherical_gaussian_map_3/Arr_polyhedral_sgm_polyhedron_3.h b/Arrangement_on_surface_2/include/CGAL/Arr_spherical_gaussian_map_3/Arr_polyhedral_sgm_polyhedron_3.h index b76c7d5088b..16b7724b8de 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_spherical_gaussian_map_3/Arr_polyhedral_sgm_polyhedron_3.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_spherical_gaussian_map_3/Arr_polyhedral_sgm_polyhedron_3.h @@ -64,11 +64,12 @@ public: typedef typename Base::Point Point; /*! Constructor */ - Arr_polyhedral_sgm_polyhedron_3_vertex() : Base(), m_marked(false) {} + Arr_polyhedral_sgm_polyhedron_3_vertex() : + Base(), m_processed(false), m_marked(false) {} /*! Constructor */ Arr_polyhedral_sgm_polyhedron_3_vertex(const Point & p) : - Base(p), m_marked(false) {} + Base(p), m_processed(false), m_marked(false) {} /*! Obtain the mutable (geometrical) point. Delegate */ Point & point() { return Base::point(); } diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h index 2e16e30a823..36f83a0e6a1 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -154,7 +154,7 @@ protected: // the right endpoint it its interior. Point_2 m_intersect_p; // The next intersection point. - unsigned int m_ip_multiplicity; // Its multiplicity + Multiplicity m_ip_multiplicity; // Its multiplicity // (0 in case of an overlap). bool m_found_intersect; // An intersection has been found. // (or an overlap). diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h index 53b5d589b13..fbdb113ac65 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h @@ -76,8 +76,7 @@ public: typedef typename Curve_kernel_2::Curve_analysis_2 Curve_analysis_2; //! default constructor - Point_2_rep() { - } + Point_2_rep() : _m_location(CGAL::ARR_INTERIOR) {} //! constructs a "finite" point on curve, //! implies CGAL::NO_BOUNDARY in x/y diff --git a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h new file mode 100644 index 00000000000..c7637f04b91 --- /dev/null +++ b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h @@ -0,0 +1,609 @@ +// 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 + +#ifndef CGAL_DRAW_ARRANGEMENT_2_H +#define CGAL_DRAW_ARRANGEMENT_2_H + +#include + +#include +#include +#include + +#include + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include +#include + +namespace CGAL { + +struct Default_color_generator { + /*! Obtain color + */ + template + CGAL::IO::Color operator()(HalfedgeHandle /* h */) { + static std::random_device rd; + static std::mt19937 rng(rd()); + static std::uniform_int_distribution uni(0, 255); + return CGAL::IO::Color(uni(rng), uni(rng), uni(rng)); + } +}; + +// Viewer class for`< Polygon_2 +template +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 + 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 + CGAL::Bbox_2 exact_bbox(const Point& p) { return p.bbox(); } + + /*! Compile time dispatching + */ +#if 0 + template + void bounding_box_impl2(CGAL::Bbox_2& bbox, const Point& p, T const&, long) + { bbox += exact_bbox(p); } + + template + 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 + void bounding_box_impl1(CGAL::Bbox_2& bbox, const Point& p, T const&, long) + { bbox += exact_bbox(p); } + + template + 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(bbox, p, traits.approximate_2_object(), 0); + } +#else + template + 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 + void draw_approximate_region(Halfedge_const_handle curr, + const Approximate& approx) { + std::vector 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 + 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 + void draw_region_impl2(Halfedge_const_handle curr, T const&, long) + { draw_exact_region(curr); } + + template + auto draw_region_impl2(Halfedge_const_handle curr, T const& approx, int) -> + decltype(approx.template operator()(X_monotone_curve{}, double{}, I{}, + bool{}), void()) + { draw_approximate_region(curr, approx); } + + template + void draw_region_impl1(Halfedge_const_handle curr, T const&, long) + { draw_exact_region(curr); } + + template + 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(curr, traits.approximate_2_object(), 0); + } +#else + template + 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 + void draw_approximate_curve(const XMonotoneCurve& curve, + const Approximate& approx) { + std::vector 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 + void draw_curve_impl2(const X_monotone_curve& xcv, T const&, long) + { draw_exact_curve(xcv); } + + template + auto draw_curve_impl2(const X_monotone_curve& xcv, T const& approx, int) -> + decltype(approx.template operator()(X_monotone_curve{}, double{}, I{}, + bool{}), void()) + { draw_approximate_curve(xcv, approx); } + + template + void draw_curve_impl1(const X_monotone_curve& xcv, T const&, long) + { draw_exact_curve(xcv); } + + template + 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(xcv, traits.approximate_2_object(), 0); + } +#else + template + 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 + 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) + { + 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 + void draw_point_impl2(const Point& p, T const&, long) { add_point(p); } + + template + auto draw_point_impl2(const Point& p, T const& approx, int) -> + decltype(approx.operator()(p), void()) + { add_point(approx(p)); } + + template + void draw_point_impl1(const Point& p, T const&, long) { add_point(p); } + + template + 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(p, traits.approximate_2_object(), true); + } +#else + template + 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 m_visited; +}; + +//! Basic viewer of a 2D arrangement. +template +class Arr_2_viewer_qt : public Arr_2_basic_viewer_qt { +public: + using Arr = Arrangement_2_; + using Color_generator = ColorGenerator; + using Base = Arr_2_basic_viewer_qt; + 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 +void draw(const Arrangement_2& 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; + using Viewer = Arr_2_viewer_qt; + + CGAL::Qt::init_ogl_context(4,3); + + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(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 +void draw(const Arrangement_2& 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; + using Viewer = Arr_2_viewer_qt; + + CGAL::Qt::init_ogl_context(4,3); + + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(argv)); + Viewer mainwindow(app.activeWindow(), arr, color_generator, title, + draw_vertices); + mainwindow.add_elements(); + mainwindow.show(); + app.exec(); +} + +} + +#endif +#endif diff --git a/Arrangement_on_surface_2/package_info/Arrangement_on_surface_2/dependencies b/Arrangement_on_surface_2/package_info/Arrangement_on_surface_2/dependencies index bd73b84a902..a723fb58f63 100644 --- a/Arrangement_on_surface_2/package_info/Arrangement_on_surface_2/dependencies +++ b/Arrangement_on_surface_2/package_info/Arrangement_on_surface_2/dependencies @@ -10,6 +10,7 @@ Circulator Distance_2 Distance_3 Filtered_kernel +GraphicsView HalfedgeDS Hash_map Homogeneous_kernel diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/IO_base_test.h b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/IO_base_test.h index 9065587101e..d08285f483c 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/IO_base_test.h +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/IO_base_test.h @@ -239,14 +239,15 @@ bool read_orientation_and_end_points(InputStream_& is, } /*! */ -template -bool read_general_arc(InputStream_& is, Curve& cv) +template +bool read_general_arc(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a general conic, given by its coefficients . Rational r, s, t, u, v, w; // The conic coefficients. is >> r >> s >> t >> u >> v >> w; // Read the orientation. - int i_orient = 0; + int i_orient(0); is >> i_orient; CGAL::Orientation orient = (i_orient > 0) ? CGAL::COUNTERCLOCKWISE : (i_orient < 0) ? CGAL::CLOCKWISE : CGAL::COLLINEAR; @@ -255,7 +256,7 @@ bool read_general_arc(InputStream_& is, Curve& cv) // whose intersection with // defines the source. Point_2 app_source; - if (!read_app_point(is, app_source)) return false; + if (! read_app_point(is, app_source)) return false; Rational r1, s1, t1, u1, v1, w1; is >> r1 >> s1 >> t1 >> u1 >> v1 >> w1; @@ -263,44 +264,47 @@ bool read_general_arc(InputStream_& is, Curve& cv) // whose intersection with // defines the target. Point_2 app_target; - if (!read_app_point(is, app_target)) return false; + if (! read_app_point(is, app_target)) return false; Rational r2, s2, t2, u2, v2, w2; is >> r2 >> s2 >> t2 >> u2 >> v2 >> w2; // Create the conic arc. - cv = Curve(r, s, t, u, v, w, orient, + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, app_source, r1, s1, t1, u1, v1, w1, app_target, r2, s2, t2, u2, v2, w2); return true; } /*! */ -template -bool read_general_conic(InputStream_& is, Curve& cv) -{ +template +bool read_general_conic(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a general conic, given by its coefficients . Rational r, s, t, u, v, w; is >> r >> s >> t >> u >> v >> w; // Create a full conic (should work only for ellipses). - cv = Curve(r, s, t, u, v, w); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w); return true; } /*! */ -template -bool read_general_curve(InputStream_& is, Curve& cv) -{ +template +bool read_general_curve(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { Rational r, s, t, u, v, w; // The conic coefficients. // Read a general conic, given by its coefficients . is >> r >> s >> t >> u >> v >> w; CGAL::Orientation orient; Point_2 source, target; - if (!read_orientation_and_end_points(is, orient, source, target)) + if (! read_orientation_and_end_points(is, orient, source, target)) return false; // Create the conic (or circular) arc. - cv = Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } @@ -308,8 +312,7 @@ bool read_general_curve(InputStream_& is, Curve& cv) template <> template bool IO_base_test::read_xcurve(InputStream_& is, - X_monotone_curve_2& xcv) -{ + X_monotone_curve_2& xcv) { // since we are dealing with polycurve, we will make more than 1 conic curves // (polycurve compatible) and return the x-monotone-constructed polycurve. @@ -324,24 +327,24 @@ bool IO_base_test::read_xcurve(InputStream_& is, is >> type; //get number of x-monotone conic-arcs. - unsigned int number_of_curves; + size_t number_of_curves; is >> number_of_curves; + const auto& sub_traits = *(m_geom_traits.subcurve_traits_2()); + auto ctr_xcv = sub_traits.construct_x_monotone_curve_2_object(); + for (unsigned int i=0; i::read_xcurve(InputStream_& is, /*! Read a conic poly-curve */ template <> template -bool IO_base_test::read_curve(InputStream_& is, Curve_2& cv) -{ +bool IO_base_test::read_curve(InputStream_& is, Curve_2& cv) { // since we are dealing with polycurve, we will make more than 1 conic curves // (polycurve compatible) and return the constructed polycurve. @@ -376,20 +378,21 @@ bool IO_base_test::read_curve(InputStream_& is, Curve_2& cv) is >> type; //get number of xmonotone-conic arcs. - unsigned int number_of_curves; + size_t number_of_curves; is >> number_of_curves; + const auto& sub_traits = *(m_geom_traits.subcurve_traits_2()); for (unsigned int i = 0; i < number_of_curves; ++i) { if ((type == 'a') || (type == 'A')) { - if (!read_general_curve(is, tmp_cv)) return false; + if (! read_general_curve(is, tmp_cv, sub_traits)) return false; conic_segments.push_back(tmp_cv); } else if ((type == 'c') || (type == 'C')) { - if (!read_general_conic(is, tmp_cv)) return false; + if (! read_general_conic(is, tmp_cv, sub_traits)) return false; conic_segments.push_back(tmp_cv); } else if ((type == 'i') || (type == 'I')) { - if (!read_general_arc(is, tmp_cv)) return false; + if (! read_general_arc(is, tmp_cv, sub_traits)) return false; conic_segments.push_back(tmp_cv); } @@ -422,12 +425,11 @@ template bool IO_base_test::read_segment(InputStream_& is, Subcurve_2& seg) { - Subcurve_2 tmp_seg; char type; is >> type; - if (!read_general_curve(is, tmp_seg)) return false; - seg = tmp_seg; - return true; + const auto& sub_traits = *(m_geom_traits.subcurve_traits_2()); + if (! read_general_curve(is, seg, sub_traits)) return false; + return true; } template <> @@ -438,8 +440,10 @@ bool IO_base_test::read_xsegment(InputStream_& is, char type; is >> type; Subcurve_2 tmp_seg; - if (!read_general_curve(is, tmp_seg)) return false; - xseg = X_monotone_subcurve_2(tmp_seg); + const auto& sub_traits = *(m_geom_traits.subcurve_traits_2()); + if (! read_general_curve(is, tmp_seg, sub_traits)) return false; + auto ctr_xcv = sub_traits.construct_x_monotone_curve_2_object(); + xseg = ctr_xcv(tmp_seg); return true; } @@ -1037,9 +1041,9 @@ bool read_ellipse(InputStream_& is, bool& is_circle, Rat_circle& circle, } /*! */ -template -bool read_partial_ellipse(InputStream_& is, Curve& cv) -{ +template +bool read_partial_ellipse(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { bool is_circle; // Is this a circle. Rat_circle circle; Rational r, s, t, u, v, w; @@ -1050,15 +1054,16 @@ bool read_partial_ellipse(InputStream_& is, Curve& cv) return false; // Create the conic (or circular) arc. - cv = (is_circle) ? Curve(circle, orient, source, target) : - Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = (is_circle) ? ctr_cv(circle, orient, source, target) : + ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } /*! */ -template -bool read_full_ellipse(InputStream_& is, Curve& cv) -{ +template +bool read_full_ellipse(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { bool is_circle; // Is this a circle. Rat_circle circle; Rational r, s, t, u, v, w; @@ -1066,14 +1071,14 @@ bool read_full_ellipse(InputStream_& is, Curve& cv) return false; // Create a full ellipse (or circle). - cv = (is_circle) ? Curve(circle) : Curve(r, s, t, u, v, w); + auto ctr_cv = traits.construct_curve_2_object(); + cv = (is_circle) ? ctr_cv(circle) : ctr_cv(r, s, t, u, v, w); return true; } /*! Read a hyperbola */ -template -bool read_hyperbola(InputStream_& is, Curve& cv) -{ +template +bool read_hyperbola(InputStream_& is, Curve& cv, const Traits& traits) { // Read the hyperbola (using the format "a b x0 y0"): // 2 2 // ( x - x0 ) ( y - y0 ) @@ -1096,14 +1101,15 @@ bool read_hyperbola(InputStream_& is, Curve& cv) return false; // Create the conic (or circular) arc. - cv = Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } /*! Read a hyperbola */ -template -bool read_parabola(InputStream_& is, Curve& cv) -{ +template +bool read_parabola(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read the parabola (using the format "c x0 y0"): // // 2 @@ -1125,15 +1131,15 @@ bool read_parabola(InputStream_& is, Curve& cv) return false; // Create the conic (or circular) arc. - cv = Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } /*! */ -template -bool read_segment(InputStream_& is, Curve& cv) -{ - +template +bool read_segment(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a segment, given by its endpoints (x1,y1) and (x2,y2); Rational x1, y1, x2, y2; is >> x1 >> y1 >> x2 >> y2; @@ -1143,19 +1149,20 @@ bool read_segment(InputStream_& is, Curve& cv) Rat_segment segment(source, target); // Create the segment. - cv = Curve(segment); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(segment); return true; } /*! */ -template -bool read_general_arc(InputStream_& is, Curve& cv) -{ +template +bool read_general_arc(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a general conic, given by its coefficients . Rational r, s, t, u, v, w; // The conic coefficients. is >> r >> s >> t >> u >> v >> w; // Read the orientation. - int i_orient = 0; + int i_orient(0); is >> i_orient; CGAL::Orientation orient = (i_orient > 0) ? CGAL::COUNTERCLOCKWISE : (i_orient < 0) ? CGAL::CLOCKWISE : CGAL::COLLINEAR; @@ -1164,7 +1171,7 @@ bool read_general_arc(InputStream_& is, Curve& cv) // whose intersection with // defines the source. Point_2 app_source; - if (!read_app_point(is, app_source)) return false; + if (! read_app_point(is, app_source)) return false; Rational r1, s1, t1, u1, v1, w1; is >> r1 >> s1 >> t1 >> u1 >> v1 >> w1; @@ -1172,32 +1179,34 @@ bool read_general_arc(InputStream_& is, Curve& cv) // whose intersection with // defines the target. Point_2 app_target; - if (!read_app_point(is, app_target)) return false; + if (! read_app_point(is, app_target)) return false; Rational r2, s2, t2, u2, v2, w2; is >> r2 >> s2 >> t2 >> u2 >> v2 >> w2; // Create the conic arc. - cv = Curve(r, s, t, u, v, w, orient, + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, app_source, r1, s1, t1, u1, v1, w1, app_target, r2, s2, t2, u2, v2, w2); return true; } /*! */ -template -bool read_general_curve(InputStream_& is, Curve& cv) -{ +template +bool read_general_curve(InputStream_& is, typename Traits::Curve_2& cv, + const Traits& traits) { Rational r, s, t, u, v, w; // The conic coefficients. // Read a general conic, given by its coefficients . is >> r >> s >> t >> u >> v >> w; CGAL::Orientation orient; Point_2 source, target; - if (!read_orientation_and_end_points(is, orient, source, target)) + if (! read_orientation_and_end_points(is, orient, source, target)) return false; // Create the conic (or circular) arc. - cv = Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } @@ -1205,11 +1214,11 @@ bool read_general_curve(InputStream_& is, Curve& cv) template <> template bool IO_base_test::read_xcurve(InputStream_& is, - X_monotone_curve_2& xcv) -{ + X_monotone_curve_2& xcv) { Curve_2 tmp_cv; - if (!read_curve(is, tmp_cv)) return false; - xcv = X_monotone_curve_2(tmp_cv); + if (! read_curve(is, tmp_cv)) return false; + auto ctr_xcv = m_geom_traits.construct_x_monotone_curve_2_object(); + xcv = ctr_xcv(tmp_cv); return true; } @@ -1221,25 +1230,37 @@ bool IO_base_test::read_curve(InputStream_& is, Curve_2& cv) // Get the arc type: char type; is >> type; - if ((type == 'f') || (type == 'F')) return read_full_ellipse(is, cv); - else if ((type == 's') || (type == 'S')) return read_segment(is, cv); - else if ((type == 'i') || (type == 'I')) return read_general_arc(is, cv); - else if ((type == 'c') || (type == 'C')) { - // Read a general conic, given by its coefficients . - Rational r, s, t, u, v, w; - is >> r >> s >> t >> u >> v >> w; - // Create a full conic (should work only for ellipses). - cv = Curve_2(r, s, t, u, v, w); - return true; + switch (type) { + case 'f': + case 'F': return read_full_ellipse(is, cv, m_geom_traits); + case 's': + case 'S': return read_segment(is, cv, m_geom_traits); + case 'i': + case 'I': return read_general_arc(is, cv, m_geom_traits); + case 'c': + case 'C': + { + // Read a general conic, given by its coefficients . + Rational r, s, t, u, v, w; + is >> r >> s >> t >> u >> v >> w; + // Create a full conic (should work only for ellipses). + auto ctr_cv = m_geom_traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w); + return true; + } + case 'e': + case 'E': return read_partial_ellipse(is, cv, m_geom_traits); + case 'h': + case 'H': return read_hyperbola(is, cv, m_geom_traits); + case 'p': + case 'P': return read_parabola(is, cv, m_geom_traits); + case 'a': + case 'A': return read_general_curve(is, cv, m_geom_traits); + default: + // If we reached here, we have an unknown conic type: + std::cerr << "Illegal conic type specification: " << type << "." + << std::endl; } - else if ((type == 'e') || (type == 'E')) return read_partial_ellipse(is, cv); - else if ((type == 'h') || (type == 'H')) return read_hyperbola(is, cv); - else if ((type == 'p') || (type == 'P')) return read_parabola(is, cv); - else if ((type == 'a') || (type == 'A')) return read_general_curve(is, cv); - - // If we reached here, we have an unknown conic type: - std::cerr << "Illegal conic type specification: " << type << "." - << std::endl; return false; } @@ -1446,7 +1467,7 @@ bool IO_base_test::read_curve(InputStream_& is, Curve_2& cv) // If we reached here, we have an unknown rational arc type: std::cerr << "Illegal rational arc type specification: " << type << "." << std::endl; - return (false); + return false; } // Bezier diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_conic_polycurve.cpp b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_conic_polycurve.cpp index 02f85dc22e7..dda30274d8d 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_conic_polycurve.cpp +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_conic_polycurve.cpp @@ -50,43 +50,41 @@ typedef Polycurve_conic_traits_2::Point_2 Pc_point_2; // CGAL::CORE_algebraic_number_traits> // >::Point_2 test_point_2; -void check_equal() -{ +void check_equal() { bool are_equal; - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Equal_2 equal = traits.equal_2_object(); - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto equal = traits.equal_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); //create some curves Conic_point_2 ps1(Rational(1,4), 4); Conic_point_2 pt1(2, Rational(1,2)); - Conic_curve_2 c1(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, ps1, pt1); + Conic_curve_2 c1 = + ctr_sub_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, ps1, pt1); Conic_point_2 ps2(Rational(1,4), 4); Conic_point_2 pt2(2, Rational(1,2)); - Conic_curve_2 c2(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, ps2, pt2); + Conic_curve_2 c2 = + ctr_sub_cv(0, 0, 1, 0, 0, -1, CGAL::COUNTERCLOCKWISE, ps2, pt2); Rat_point_2 ps3(Rational(1,4), 4); Rat_point_2 pmid3(Rational(3,2), 2); Rat_point_2 pt3(2, Rational(1,3)); - Conic_curve_2 c3(ps3, pmid3, pt3); + Conic_curve_2 c3 = ctr_sub_cv(ps3, pmid3, pt3); Rat_point_2 ps4(1, 5); Rat_point_2 pmid4(Rational(3,2), 3); Rat_point_2 pt4(3, Rational(1,3)); - Conic_curve_2 c4(ps4, pmid4, pt4); + Conic_curve_2 c4 = ctr_sub_cv(ps4, pmid4, pt4); // //make x_monotone - Polycurve_conic_traits_2::X_monotone_curve_2 xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 xmc2 = - construct_x_monotone_curve_2(c2); - Polycurve_conic_traits_2::X_monotone_curve_2 xmc3 = - construct_x_monotone_curve_2(c3); - Polycurve_conic_traits_2::X_monotone_curve_2 xmc4 = - construct_x_monotone_curve_2(c4); + Polycurve_conic_traits_2::X_monotone_curve_2 xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 xmc2 = ctr_xcv(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 xmc3 = ctr_xcv(c3); + Polycurve_conic_traits_2::X_monotone_curve_2 xmc4 = ctr_xcv(c4); are_equal = equal(xmc1, xmc2); std::cout << "Two equal conic arcs are computed as: " @@ -104,8 +102,7 @@ void check_equal() template void check_intersect(typename Traits::X_monotone_curve_2& xcv1, typename Traits::X_monotone_curve_2& xcv2, - const Traits& traits) - { + const Traits& traits) { typedef typename Traits::Multiplicity Multiplicity; typedef typename Traits::Point_2 Point_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -114,8 +111,8 @@ void check_equal() Intersection_result; std::vector intersection_points; - traits.intersect_2_object()(xcv1, xcv2, - std::back_inserter(intersection_points)); + auto intersect = traits.intersect_2_object(); + intersect(xcv1, xcv2, std::back_inserter(intersection_points)); std::cout<< "Number of intersection Points: " << intersection_points.size() << std::endl; @@ -133,13 +130,12 @@ void check_equal() // } } -void check_compare_end_points_xy_2() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Compare_endpoints_xy_2 compare_endpoints_xy_2 = - traits.compare_endpoints_xy_2_object(); +void check_compare_end_points_xy_2() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto cmp_endpoints = traits.compare_endpoints_xy_2_object(); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); //create some curves Conic_point_2 ps1(Rational(1,4), 4); @@ -153,69 +149,69 @@ void check_compare_end_points_xy_2() // as the intersections of the parabola with the lines y = -3 and y = -2. // Note that the arc is clockwise oriented. Conic_curve_2 - c2 = Conic_curve_2(1, 0, 0, 0, 1, 0, // The parabola. - CGAL::CLOCKWISE, - Conic_point_2(-1.73, -3), // Approximation of the source. - 0, 0, 0, 0, 1, 3, // The line: y = -3. - Conic_point_2(1.41, -2), // Approximation of the target. - 0, 0, 0, 0, 1, 2); // The line: y = -2. + c2 = ctr_sub_cv(1, 0, 0, 0, 1, 0, // The parabola. + CGAL::CLOCKWISE, + Conic_point_2(-1.73, -3), // Approximation of the source. + 0, 0, 0, 0, 1, 3, // The line: y = -3. + Conic_point_2(1.41, -2), // Approximation of the target. + 0, 0, 0, 0, 1, 2); // The line: y = -2. assert(c2.is_valid()); //make polyline x-monotone curves - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = - construct_x_monotone_curve_2(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = ctr_xcv(c2); - CGAL::Comparison_result res = compare_endpoints_xy_2(polyline_xmc1); + CGAL::Comparison_result res = cmp_endpoints(polyline_xmc1); std::cout << "compare_end_points_xy_2 for counterclockwise curve: " << (res == CGAL::SMALLER ? "SMALLER": (res == CGAL::LARGER ? "LARGER" : "EQUAL")) << std::endl; - res = compare_endpoints_xy_2(polyline_xmc2); + res = cmp_endpoints(polyline_xmc2); std::cout<< "compare_end_points_xy_2 for clockwise curve: " << (res == CGAL::SMALLER ? "SMALLER": (res == CGAL::LARGER ? "LARGER" : "EQUAL")) << std::endl; } template -void check_split(Curve_type &xcv1, Curve_type &xcv2) -{ - Polycurve_conic_traits_2 traits; +void check_split(Curve_type& xcv1, Curve_type& xcv2) { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_sub_xcv = sub_traits.construct_x_monotone_curve_2_object(); //split x poly-curves - Conic_curve_2 c6(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-7), Algebraic(13)), - Conic_point_2(Algebraic(-3), Algebraic(9))); - Conic_curve_2 c7(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-3), Algebraic(9)), - Conic_point_2(Algebraic(0), Algebraic(0))); - Conic_curve_2 c8(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(4), Algebraic(-2))); + Conic_curve_2 c6 = ctr_sub_cv(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-7), Algebraic(13)), + Conic_point_2(Algebraic(-3), Algebraic(9))); + Conic_curve_2 c7 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-3), Algebraic(9)), + Conic_point_2(Algebraic(0), Algebraic(0))); + Conic_curve_2 c8 = ctr_sub_cv(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(4), Algebraic(-2))); - Conic_x_monotone_curve_2 xc6(c6); - Conic_x_monotone_curve_2 xc7(c7); - Conic_x_monotone_curve_2 xc8(c8); + Conic_x_monotone_curve_2 xc6 = ctr_sub_xcv(c6); + Conic_x_monotone_curve_2 xc7 = ctr_sub_xcv(c7); + Conic_x_monotone_curve_2 xc8 = ctr_sub_xcv(c8); std::vector xmono_conic_curves_2; + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + xmono_conic_curves_2.push_back(xc6); xmono_conic_curves_2.push_back(xc7); Pc_x_monotone_curve_2 split_expected_1 = - traits.construct_x_monotone_curve_2_object()(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); xmono_conic_curves_2.clear(); xmono_conic_curves_2.push_back(xc8); Pc_x_monotone_curve_2 split_expected_2 = - traits.construct_x_monotone_curve_2_object()(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); Polycurve_conic_traits_2::X_monotone_curve_2 split_curve_1, split_curve_2; - Polycurve_conic_traits_2::Point_2 - point_of_split = Polycurve_conic_traits_2::Point_2(0,0); + Polycurve_conic_traits_2::Point_2 point_of_split = + Polycurve_conic_traits_2::Point_2(0,0); //Split functor traits.split_2_object()(xcv2, point_of_split, split_curve_1, split_curve_2); @@ -229,23 +225,21 @@ void check_split(Curve_type &xcv1, Curve_type &xcv2) std::cout << "Something is wrong with split" << std::endl; } -void check_is_vertical() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Is_vertical_2 is_vertical = - traits.is_vertical_2_object(); +void check_is_vertical() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto is_vertical = traits.is_vertical_2_object(); //create a curve Rat_point_2 ps1(1, 10); Rat_point_2 pmid1(5, 4); Rat_point_2 pt1(10, 1); - Conic_curve_2 c1(ps1, pmid1, pt1); + Conic_curve_2 c1 = ctr_sub_cv(ps1, pmid1, pt1); //make x-monotone curve - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); bool result = is_vertical(polyline_xmc1); std::cout << "Is_verticle:: Expected first result is not vertivle: Computed: " @@ -254,8 +248,7 @@ void check_is_vertical() /*! */ template -bool read_orientation(stream& is, CGAL::Orientation& orient) -{ +bool read_orientation(stream& is, CGAL::Orientation& orient) { int i_orient; is >> i_orient; orient = (i_orient > 0) ? CGAL::COUNTERCLOCKWISE : @@ -265,8 +258,7 @@ bool read_orientation(stream& is, CGAL::Orientation& orient) /*! */ template -bool read_app_point(stream& is, Conic_point_2& p) -{ +bool read_app_point(stream& is, Conic_point_2& p) { //waqar: original double x, y; is >> x >> y; @@ -290,18 +282,18 @@ bool read_orientation_and_end_points(stream& is, CGAL::Orientation& orient, Conic_point_2& target) { // Read the orientation. - if (!read_orientation(is, orient)) return false; + if (! read_orientation(is, orient)) return false; // Read the end points of the arc and create it. - if (!read_app_point(is, source)) return false; - if (!read_app_point(is, target)) return false; + if (! read_app_point(is, source)) return false; + if (! read_app_point(is, target)) return false; return true; } /*! */ -template -bool read_general_arc(stream& is, Curve& cv) -{ +template +bool read_general_arc(stream& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a general conic, given by its coefficients . Rational r, s, t, u, v, w; // The conic coefficients. is >> r >> s >> t >> u >> v >> w; @@ -315,7 +307,7 @@ bool read_general_arc(stream& is, Curve& cv) // whose intersection with // defines the source. Conic_point_2 app_source; - if (!read_app_point(is, app_source)) return false; + if (! read_app_point(is, app_source)) return false; Rational r1, s1, t1, u1, v1, w1; is >> r1 >> s1 >> t1 >> u1 >> v1 >> w1; @@ -323,7 +315,7 @@ bool read_general_arc(stream& is, Curve& cv) // whose intersection with // defines the target. Conic_point_2 app_target; - if (!read_app_point(is, app_target)) return false; + if (! read_app_point(is, app_target)) return false; Rational r2, s2, t2, u2, v2, w2; is >> r2 >> s2 >> t2 >> u2 >> v2 >> w2; @@ -333,34 +325,36 @@ bool read_general_arc(stream& is, Curve& cv) << r2 << s2 << t2 << u2 << v2 << w2 << std::endl; // Create the conic arc. - cv = Curve(r, s, t, u, v, w, orient, - app_source, r1, s1, t1, u1, v1, w1, - app_target, r2, s2, t2, u2, v2, w2); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, + app_source, r1, s1, t1, u1, v1, w1, + app_target, r2, s2, t2, u2, v2, w2); return true; } /*! */ -template -bool read_general_conic(stream& is, Curve& cv) -{ +template +bool read_general_conic(stream& is, typename Traits::Curve_2& cv, + const Traits& traits) { // Read a general conic, given by its coefficients . Rational r, s, t, u, v, w; is >> r >> s >> t >> u >> v >> w; // Create a full conic (should work only for ellipses). - cv = Curve(r, s, t, u, v, w); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w); return true; } // /*! */ -template -bool read_general_curve(stream& is, Curve& cv) -{ +template +bool read_general_curve(stream& is, typename Traits::Curve_2& cv, + const Traits& traits) { Rational r, s, t, u, v, w; // The conic coefficients. // Read a general conic, given by its coefficients . is >> r >> s >> t >> u >> v >> w; CGAL::Orientation orient; Conic_point_2 source, target; - if (!read_orientation_and_end_points(is, orient, source, target)) + if (! read_orientation_and_end_points(is, orient, source, target)) return false; // Create the conic (or circular) arc. @@ -368,26 +362,25 @@ bool read_general_curve(stream& is, Curve& cv) // << u << " " << v << " " << w << std::endl; // std::cout << "Read Points : " << source.x() << " " << source.y() << " " // << target.x() << " " << target.y() << std::endl; - cv = Curve(r, s, t, u, v, w, orient, source, target); + auto ctr_cv = traits.construct_curve_2_object(); + cv = ctr_cv(r, s, t, u, v, w, orient, source, target); return true; } -std::istream& skip_comments(std::istream& is, std::string& line) -{ +std::istream& skip_comments(std::istream& is, std::string& line) { while (std::getline(is, line)) if (!line.empty() && (line[0] != '#')) break; return is; } -bool check_compare_y_at_x_2() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Compare_y_at_x_2 cmp_y_at_x_2 = - traits.compare_y_at_x_2_object(); +bool check_compare_y_at_x_2() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_sub_xcv = sub_traits.construct_x_monotone_curve_2_object(); + auto cmp_y_at_x_2 = traits.compare_y_at_x_2_object(); //polycurve constructors - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_mono_polycurve = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Construct_curve_2 construct_polycurve = - traits.construct_curve_2_object(); + auto construct_x_mono_polycurve = traits.construct_x_monotone_curve_2_object(); + auto ctr_cv = traits.construct_curve_2_object(); //create a curve Rat_point_2 ps1(1, 10); @@ -399,14 +392,14 @@ bool check_compare_y_at_x_2() Rat_point_2 ps2(10, 1); Rat_point_2 pmid2(15, 5); Rat_point_2 pt2(20, 10); - Conic_curve_2 c2(ps2, pmid2, pt2); + Conic_curve_2 c2 = ctr_sub_cv(ps2, pmid2, pt2); - Conic_curve_2 c3(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(3), Algebraic(9))); - Conic_curve_2 c4(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(3), Algebraic(9)), - Conic_point_2(Algebraic(5), Algebraic(25))); + Conic_curve_2 c3 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(3), Algebraic(9))); + Conic_curve_2 c4 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(3), Algebraic(9)), + Conic_point_2(Algebraic(5), Algebraic(25))); std::vector conic_curves, conic_curves_2, Conic_curves_3; conic_curves.push_back(c1); @@ -415,10 +408,10 @@ bool check_compare_y_at_x_2() //conic_curves_2.push_back(c3); //conic_curves_2.push_back(c4); - Conic_x_monotone_curve_2 xc1(c1); - Conic_x_monotone_curve_2 xc2(c2); - Conic_x_monotone_curve_2 xc3(c3); - Conic_x_monotone_curve_2 xc4(c4); + Conic_x_monotone_curve_2 xc1 = ctr_sub_xcv(c1); + Conic_x_monotone_curve_2 xc2 = ctr_sub_xcv(c2); + Conic_x_monotone_curve_2 xc3 = ctr_sub_xcv(c3); + Conic_x_monotone_curve_2 xc4 = ctr_sub_xcv(c4); std::vector xmono_conic_curves, xmono_conic_curves_2; /* VERY IMPORTANT @@ -441,13 +434,13 @@ bool check_compare_y_at_x_2() //construct poly-curve Polycurve_conic_traits_2::Curve_2 conic_polycurve = - construct_polycurve(conic_curves.begin(), conic_curves.end()); + ctr_cv(conic_curves.begin(), conic_curves.end()); //Polycurve_conic_traits_2::Curve_2 conic_polycurve_2 = - // construct_polycurve(conic_curves_2.begin(), conic_curves_2.end()); + // ctr_cv(conic_curves_2.begin(), conic_curves_2.end()); //make x-monotone curve //Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - // construct_x_monotone_curve_2(c1); + // ctr_xcv(c1); //create points Polycurve_conic_traits_2::Point_2 @@ -475,37 +468,33 @@ bool check_compare_y_at_x_2() return true; } -void check_are_mergable() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Are_mergeable_2 are_mergeable_2 = - traits.are_mergeable_2_object(); +void check_are_mergable() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto are_mergeable_2 = traits.are_mergeable_2_object(); //create a curve Rat_point_2 ps1(1, 10); Rat_point_2 pmid1(5, 4); Rat_point_2 pt1(10, 1); - Conic_curve_2 c1(ps1, pmid1, pt1); + Conic_curve_2 c1 = ctr_sub_cv(ps1, pmid1, pt1); Rat_point_2 ps2(10, 1); Rat_point_2 pmid2(15, 14); Rat_point_2 pt2(20, 20); - Conic_curve_2 c2(ps2, pmid2, pt2); + Conic_curve_2 c2 = ctr_sub_cv(ps2, pmid2, pt2); Rat_point_2 ps3(Rational(1,4), 4); Rat_point_2 pmid3(Rational(3,2), 2); Rat_point_2 pt3(2, Rational(1,3)); - Conic_curve_2 c3(ps3, pmid3, pt3); + Conic_curve_2 c3 = ctr_sub_cv(ps3, pmid3, pt3); //construct x-monotone curve(compatible with polyline class) - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = - construct_x_monotone_curve_2(c2); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc3 = - construct_x_monotone_curve_2(c3); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = ctr_xcv(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc3 = ctr_xcv(c3); bool result = are_mergeable_2(polyline_xmc1, polyline_xmc2); std::cout << "Are_mergeable:: Mergeable x-monotone polycurves are Computed as: " @@ -516,29 +505,27 @@ void check_are_mergable() << ((result)? "Mergeable" : "Not-Mergeable") << std::endl; } -void check_merge_2() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Merge_2 merge_2 = traits.merge_2_object(); +void check_merge_2() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto merge_2 = traits.merge_2_object(); //create a curve Rat_point_2 ps1(1, 10); Rat_point_2 pmid1(5, 4); Rat_point_2 pt1(10, 1); - Conic_curve_2 c1(ps1, pmid1, pt1); + Conic_curve_2 c1 = ctr_sub_cv(ps1, pmid1, pt1); Rat_point_2 ps2(10, 1); Rat_point_2 pmid2(15, 14); Rat_point_2 pt2(20, 20); - Conic_curve_2 c2(ps2, pmid2, pt2); + Conic_curve_2 c2 = ctr_sub_cv(ps2, pmid2, pt2); //construct x-monotone curve (compatible with polyline class) - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = - construct_x_monotone_curve_2(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = ctr_xcv(c2); Polycurve_conic_traits_2::X_monotone_curve_2 merged_xmc; @@ -547,101 +534,93 @@ void check_merge_2() << std:: endl; } -void check_construct_opposite() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Construct_opposite_2 construct_opposite_2 = - traits.construct_opposite_2_object(); +void check_construct_opposite() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto ctr_opposite = traits.construct_opposite_2_object(); //create a curve Rat_point_2 ps1(1, 10); Rat_point_2 pmid1(5, 4); Rat_point_2 pt1(10, 1); - Conic_curve_2 c1(ps1, pmid1, pt1); + Conic_curve_2 c1 = ctr_sub_cv(ps1, pmid1, pt1); //construct x-monotone curve (compatible with polyline class) Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); + ctr_xcv(c1); Polycurve_conic_traits_2::X_monotone_curve_2 polyline_opposite_curve = - construct_opposite_2(polyline_xmc1); + ctr_opposite(polyline_xmc1); std::cout<< "Construct_opposite_2:: Opposite curve created"; } -void check_compare_y_at_x_right() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Compare_y_at_x_right_2 cmp_y_at_x_right_2 = - traits.compare_y_at_x_right_2_object(); +void check_compare_y_at_x_right() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto cmp_y_at_x_right = traits.compare_y_at_x_right_2_object(); //create constructing curves Rat_point_2 ps2(1, 10); Rat_point_2 pmid2(5, 4); Rat_point_2 pt2(10, 1); - Conic_curve_2 c1(ps2, pmid2, pt2); + Conic_curve_2 c1 = ctr_sub_cv(ps2, pmid2, pt2); Rat_point_2 ps3(10, 1); Rat_point_2 pmid3(5, 4); Rat_point_2 pt3(1, 10); - Conic_curve_2 c2(ps3, pmid3, pt3); + Conic_curve_2 c2 = ctr_sub_cv(ps3, pmid3, pt3); //construct x-monotone curve (compatible with polyline class) - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = - construct_x_monotone_curve_2(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = ctr_xcv(c2); Polycurve_conic_traits_2::Point_2 intersection_point = Polycurve_conic_traits_2::Point_2(5,4); CGAL::Comparison_result result; - result = cmp_y_at_x_right_2(polyline_xmc1, polyline_xmc2, intersection_point); + result = cmp_y_at_x_right(polyline_xmc1, polyline_xmc2, intersection_point); std::cout << "Compare_y_at_x_right:: Expected Answer: equal, Computed answer: " << (result == CGAL::SMALLER ? "smaller": (result == CGAL::LARGER ? "Larger" : "equal")) << std::endl; } -void check_compare_y_at_x_left() -{ - Polycurve_conic_traits_2 traits; - Polycurve_conic_traits_2::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = traits.construct_x_monotone_curve_2_object(); - Polycurve_conic_traits_2::Compare_y_at_x_left_2 cmp_y_at_x_left_2 = - traits.compare_y_at_x_left_2_object(); +void check_compare_y_at_x_left() { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto cmp_y_at_x_left = traits.compare_y_at_x_left_2_object(); //create constructing curves Rat_point_2 ps2(1, 10); Rat_point_2 pmid2(5, 4); Rat_point_2 pt2(10, 1); - Conic_curve_2 c1(ps2, pmid2, pt2); + Conic_curve_2 c1 = ctr_sub_cv(ps2, pmid2, pt2); Rat_point_2 ps3(10, 1); Rat_point_2 pmid3(5, 4); Rat_point_2 pt3(1, 10); - Conic_curve_2 c2(ps3, pmid3, pt3); + Conic_curve_2 c2 = ctr_sub_cv(ps3, pmid3, pt3); //construct x-monotone curve(compatible with polyline class) - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = - construct_x_monotone_curve_2(c1); - Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = - construct_x_monotone_curve_2(c2); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc1 = ctr_xcv(c1); + Polycurve_conic_traits_2::X_monotone_curve_2 polyline_xmc2 = ctr_xcv(c2); Polycurve_conic_traits_2::Point_2 intersection_point = Polycurve_conic_traits_2::Point_2(5,4); CGAL::Comparison_result result; - result = cmp_y_at_x_left_2(polyline_xmc1, polyline_xmc2, intersection_point); + result = cmp_y_at_x_left(polyline_xmc1, polyline_xmc2, intersection_point); std::cout << "Compare_y_at_x_left:: Expected Answer: equal, Computed answer: " << (result == CGAL::SMALLER ? "smaller": (result == CGAL::LARGER ? "Larger" : "equal")) << std::endl; } template -void check_make_x_monotne_curve(const typename GeometryTraits::Curve_2& c1) -{ +void check_make_x_monotne_curve(const typename GeometryTraits::Curve_2& c1) { typename GeometryTraits::Point_2 Point_2; typename GeometryTraits::X_monotone_curve_2 X_monotone_curve_2; typedef boost::variant Make_x_monotone_result; @@ -662,8 +641,7 @@ void check_make_x_monotne_curve(const typename GeometryTraits::Curve_2& c1) } template -void check_push_front(Curve base_curve, Segment curve_tobe_pushed) -{ +void check_push_front(Curve base_curve, Segment curve_tobe_pushed) { Polycurve_conic_traits_2 traits; std::cout << "Base curve: " << base_curve << std::endl; @@ -674,8 +652,7 @@ void check_push_front(Curve base_curve, Segment curve_tobe_pushed) } template -void check_push_back(Curve& base_curve, Segment curve_tobe_pushed) -{ +void check_push_back(Curve& base_curve, Segment curve_tobe_pushed) { Polycurve_conic_traits_2 traits; std::cout << "Base curve: " << base_curve << std::endl; @@ -687,8 +664,7 @@ void check_push_back(Curve& base_curve, Segment curve_tobe_pushed) } template -void check_compare_x_2(const Segment& seg1, const Segment& seg2) -{ +void check_compare_x_2(const Segment& seg1, const Segment& seg2) { Polycurve_conic_traits_2 traits; CGAL::Comparison_result result; @@ -706,16 +682,14 @@ void check_compare_x_2(const Segment& seg1, const Segment& seg2) } template -void check_compare_points(Curve& cv) -{ +void check_compare_points(Curve& cv) { Polycurve_conic_traits_2 traits; CGAL::Arr_parameter_space result = traits.parameter_space_in_x_2_object()(cv, CGAL::ARR_MAX_END); } template -void check_trim(curve& xcv, int sx, int sy, int tx, int ty) -{ +void check_trim(curve& xcv, int sx, int sy, int tx, int ty) { Polycurve_conic_traits_2 traits; // Conic_point_2 source(Algebraic(-16), Algebraic(-4)); @@ -731,39 +705,41 @@ void check_trim(curve& xcv, int sx, int sy, int tx, int ty) } -int main(int argc, char* argv[]) -{ - Polycurve_conic_traits_2 traits; +int main(int argc, char* argv[]) { + Conic_traits_2 sub_traits; + Polycurve_conic_traits_2 traits(&sub_traits); + auto ctr_sub_cv = sub_traits.construct_curve_2_object(); + auto ctr_sub_xcv = sub_traits.construct_x_monotone_curve_2_object(); //polycurve constructors - auto construct_x_mono_polycurve = traits.construct_x_monotone_curve_2_object(); - auto construct_polycurve = traits.construct_curve_2_object(); + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + auto ctr_cv = traits.construct_curve_2_object(); //create a curve - Conic_curve_2 c3(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(3), Algebraic(9))); - Conic_curve_2 c4(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(3), Algebraic(9)), - Conic_point_2(Algebraic(5), Algebraic(25))); - Conic_curve_2 c5(0,1,0,1,0,0, CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-25), Algebraic(-5)), - Conic_point_2(Algebraic(0), Algebraic(0))); + Conic_curve_2 c3 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(3), Algebraic(9))); + Conic_curve_2 c4 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(3), Algebraic(9)), + Conic_point_2(Algebraic(5), Algebraic(25))); + Conic_curve_2 c5 = ctr_sub_cv(0,1,0,1,0,0, CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-25), Algebraic(-5)), + Conic_point_2(Algebraic(0), Algebraic(0))); - Conic_curve_2 c6(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-7), Algebraic(13)), - Conic_point_2(Algebraic(-3), Algebraic(9))); - Conic_curve_2 c7(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-3), Algebraic(9)), - Conic_point_2(Algebraic(0), Algebraic(0))); - Conic_curve_2 c8(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(4), Algebraic(-2))); + Conic_curve_2 c6 = ctr_sub_cv(1,1,0,6,-26,162,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-7), Algebraic(13)), + Conic_point_2(Algebraic(-3), Algebraic(9))); + Conic_curve_2 c7 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-3), Algebraic(9)), + Conic_point_2(Algebraic(0), Algebraic(0))); + Conic_curve_2 c8 = ctr_sub_cv(0,1,0,-1,0,0, CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(4), Algebraic(-2))); - Conic_curve_2 c9(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(-5), Algebraic(25)), - Conic_point_2(Algebraic(5), Algebraic(25))); - Conic_curve_2 c10(58, 72, -48, 0, 0, -360); + Conic_curve_2 c9 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(-5), Algebraic(25)), + Conic_point_2(Algebraic(5), Algebraic(25))); + Conic_curve_2 c10 = ctr_sub_cv(58, 72, -48, 0, 0, -360); //This vector is used to store curves that will be used to create polycurve std::vector conic_curves; @@ -771,21 +747,21 @@ int main(int argc, char* argv[]) //construct poly-curve Polycurve_conic_traits_2::Curve_2 conic_polycurve = - construct_polycurve(conic_curves.begin(), conic_curves.end()); + ctr_cv(conic_curves.begin(), conic_curves.end()); - Conic_curve_2 c11(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(25), Algebraic(-5)), - Conic_point_2(Algebraic(0), Algebraic(0))); - Conic_curve_2 c12(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(5), Algebraic(25))); + Conic_curve_2 c11 = ctr_sub_cv(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(25), Algebraic(-5)), + Conic_point_2(Algebraic(0), Algebraic(0))); + Conic_curve_2 c12 = ctr_sub_cv(1,0,0,0,-1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(5), Algebraic(25))); conic_curves.clear(); conic_curves.push_back(c11); conic_curves.push_back(c12); //construct poly-curve Polycurve_conic_traits_2::Curve_2 conic_polycurve_2 = - construct_polycurve(conic_curves.begin(), conic_curves.end()); + ctr_cv(conic_curves.begin(), conic_curves.end()); /* VERY IMPORTANT * For efficiency reasons, we recommend users not to construct @@ -793,13 +769,12 @@ int main(int argc, char* argv[]) * functor supplied by the conic-arc traits class to convert conic curves * to x-monotone curves. */ - Conic_x_monotone_curve_2 xc3(c3); - Conic_x_monotone_curve_2 xc4(c4); - Conic_x_monotone_curve_2 xc5(c5); - Conic_x_monotone_curve_2 xc6(c6); - Conic_x_monotone_curve_2 xc7(c7); - Conic_x_monotone_curve_2 xc8(c8); - + Conic_x_monotone_curve_2 xc3 = ctr_sub_xcv(c3); + Conic_x_monotone_curve_2 xc4 = ctr_sub_xcv(c4); + Conic_x_monotone_curve_2 xc5 = ctr_sub_xcv(c5); + Conic_x_monotone_curve_2 xc6 = ctr_sub_xcv(c6); + Conic_x_monotone_curve_2 xc7 = ctr_sub_xcv(c7); + Conic_x_monotone_curve_2 xc8 = ctr_sub_xcv(c8); //This vector is used to store curves that will be used to create //X-monotone-polycurve @@ -808,11 +783,9 @@ int main(int argc, char* argv[]) xmono_conic_curves_2.push_back(xc3); xmono_conic_curves_2.push_back(xc4); - //construct x-monotone poly-curve Pc_x_monotone_curve_2 conic_x_mono_polycurve_1 = - construct_x_mono_polycurve(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); xmono_conic_curves_2.clear(); xmono_conic_curves_2.push_back(xc6); @@ -820,15 +793,13 @@ int main(int argc, char* argv[]) xmono_conic_curves_2.push_back(xc8); //construct x-monotone poly-curve Pc_x_monotone_curve_2 conic_x_mono_polycurve_2 = - construct_x_mono_polycurve(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); xmono_conic_curves_2.clear(); xmono_conic_curves_2.push_back(xc5); Pc_x_monotone_curve_2 x_polycurve_push = - construct_x_mono_polycurve(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); Polycurve_conic_traits_2::X_monotone_subcurve_2 xcurve_push = Polycurve_conic_traits_2::X_monotone_subcurve_2(c5); //traits.construct_x_monotone_curve_2_object()(c5); @@ -837,28 +808,27 @@ int main(int argc, char* argv[]) xmono_conic_curves_2.push_back(xc3); xmono_conic_curves_2.push_back(xc4); Pc_x_monotone_curve_2 base_curve = - construct_x_mono_polycurve(xmono_conic_curves_2.begin(), - xmono_conic_curves_2.end()); + ctr_xcv(xmono_conic_curves_2.begin(), xmono_conic_curves_2.end()); //curves for push_back - Conic_curve_2 c13(1,1,0,-50,12,660,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(25), Algebraic(-7)), - Conic_point_2(Algebraic(25), Algebraic(-5))); - Conic_curve_2 c14(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(25), Algebraic(-5)), - Conic_point_2(Algebraic(0), Algebraic(0))); - Conic_curve_2 c15(-1,0,0,0,1,0,CGAL::COUNTERCLOCKWISE, - Conic_point_2(Algebraic(0), Algebraic(0)), - Conic_point_2(Algebraic(5), Algebraic(25))); + Conic_curve_2 c13 = ctr_sub_cv(1,1,0,-50,12,660,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(25), Algebraic(-7)), + Conic_point_2(Algebraic(25), Algebraic(-5))); + Conic_curve_2 c14 = ctr_sub_cv(0,1,0,-1,0,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(25), Algebraic(-5)), + Conic_point_2(Algebraic(0), Algebraic(0))); + Conic_curve_2 c15 = ctr_sub_cv(-1,0,0,0,1,0,CGAL::COUNTERCLOCKWISE, + Conic_point_2(Algebraic(0), Algebraic(0)), + Conic_point_2(Algebraic(5), Algebraic(25))); conic_curves.clear(); conic_curves.push_back(c13); conic_curves.push_back(c14); Polycurve_conic_traits_2::Curve_2 base_curve_push_back = - construct_polycurve(conic_curves.begin(), conic_curves.end()); + ctr_cv(conic_curves.begin(), conic_curves.end()); conic_curves.push_back(c15); Polycurve_conic_traits_2::Curve_2 Expected_push_back_result = - construct_polycurve(conic_curves.begin(), conic_curves.end()); + ctr_cv(conic_curves.begin(), conic_curves.end()); // //checking the orientattion consistency // Conic_curve_2 c21(0,1,0,1,0,0,CGAL::CLOCKWISE, @@ -873,7 +843,7 @@ int main(int argc, char* argv[]) // xmono_conic_curves_2.push_back(xc20); // xmono_conic_curves_2.push_back(xc21); // Pc_x_monotone_curve_2 eric_polycurve = - // construct_x_mono_polycurve(xmono_conic_curves_2.begin(), + // ctr_xcv(xmono_conic_curves_2.begin(), // xmono_conic_curves_2.end()); // std::cout << "the polycurve is: " << eric_polycurve << std::endl; diff --git a/Boolean_set_operations_2/examples/Boolean_set_operations_2/conic_traits_adapter.cpp b/Boolean_set_operations_2/examples/Boolean_set_operations_2/conic_traits_adapter.cpp index 3046b9f4f72..a35c90e29c6 100644 --- a/Boolean_set_operations_2/examples/Boolean_set_operations_2/conic_traits_adapter.cpp +++ b/Boolean_set_operations_2/examples/Boolean_set_operations_2/conic_traits_adapter.cpp @@ -40,51 +40,50 @@ typedef Traits_2::Point_2 Point_2; // Insert a conic arc as a polygon edge: Subdivide the arc into x-monotone // sub-arcs and append these sub-arcs as polygon edges. -void append_conic_arc (Polygon_2& polygon, const Curve_2& arc) -{ - Conic_traits_2 traits; - std::list objects; - std::list::iterator it; - X_monotone_curve_2 xarc; +void append_conic_arc(Polygon_2& polygon, const Curve_2& arc) { + Conic_traits_2 traits; + std::list objects; + X_monotone_curve_2 xarc; traits.make_x_monotone_2_object() (arc, std::back_inserter(objects)); - for (it = objects.begin(); it != objects.end(); ++it) - { + for (auto it = objects.begin(); it != objects.end(); ++it) { if (CGAL::assign (xarc, *it)) polygon.push_back (xarc); } } -int main () -{ +int main() { + Conic_traits_2 traits; + auto ctr_cv = traits.construct_curve_2_object(); + // Construct a parabolic arc supported by a parabola: x^2 + 2y - 4 = 0, // and whose endpoints lie on the line y = 0: - Curve_2 parabola1 = Curve_2 (1, 0, 0, 0, 2, -4, CGAL::COUNTERCLOCKWISE, - Point_2(2, 0), Point_2(-2, 0)); + Curve_2 parabola1 = ctr_cv(1, 0, 0, 0, 2, -4, CGAL::COUNTERCLOCKWISE, + Point_2(2, 0), Point_2(-2, 0)); // Construct a parabolic arc supported by a parabola: x^2 - 2y - 4 = 0, // and whose endpoints lie on the line y = 0: - Curve_2 parabola2 = Curve_2 (1, 0, 0, 0, -2, -4, CGAL::COUNTERCLOCKWISE, - Point_2(-2, 0), Point_2(2, 0)); + Curve_2 parabola2 = ctr_cv(1, 0, 0, 0, -2, -4, CGAL::COUNTERCLOCKWISE, + Point_2(-2, 0), Point_2(2, 0)); // Construct a polygon from these two parabolic arcs. Polygon_2 P; - append_conic_arc (P, parabola1); - append_conic_arc (P, parabola2); + append_conic_arc(P, parabola1); + append_conic_arc(P, parabola2); // Construct a polygon that corresponds to the ellipse: x^2 + 9y^2 - 9 = 0: Polygon_2 Q; - append_conic_arc (Q, Curve_2 (-1, -9, 0, 0, 0, 9)); + append_conic_arc(Q, ctr_cv(-1, -9, 0, 0, 0, 9)); // Compute the intersection of the two polygons. std::list res; - CGAL::intersection (P, Q, std::back_inserter(res)); + CGAL::intersection(P, Q, std::back_inserter(res)); - std::copy (res.begin(), res.end(), // export to standard output - std::ostream_iterator(std::cout, "\n")); + std::copy(res.begin(), res.end(), // export to standard output + std::ostream_iterator(std::cout, "\n")); std::cout << std::endl; - return (0); + return 0; } #endif diff --git a/Envelope_3/include/CGAL/Env_sphere_traits_3.h b/Envelope_3/include/CGAL/Env_sphere_traits_3.h index e36e284367f..9dcfa59fe5c 100644 --- a/Envelope_3/include/CGAL/Env_sphere_traits_3.h +++ b/Envelope_3/include/CGAL/Env_sphere_traits_3.h @@ -28,49 +28,47 @@ namespace CGAL { -template -class Env_sphere_traits_3 : public ConicTraits_2 -{ +template +class Env_sphere_traits_3 : public ConicTraits_2 { public: - typedef ConicTraits_2 Traits_2; - typedef Env_sphere_traits_3 Self; + typedef ConicTraits_2 Traits_2; + typedef Env_sphere_traits_3 Self; - typedef typename Traits_2::Point_2 Point_2; - typedef typename Traits_2::Curve_2 Curve_2; - typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits_2::Multiplicity Multiplicity; + typedef typename Traits_2::Point_2 Point_2; + typedef typename Traits_2::Curve_2 Curve_2; + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits_2::Multiplicity Multiplicity; - typedef typename Traits_2::Rat_kernel Rat_kernel; - typedef typename Traits_2::Alg_kernel Alg_kernel; - typedef typename Traits_2::Nt_traits Nt_traits; + typedef typename Traits_2::Rat_kernel Rat_kernel; + typedef typename Traits_2::Alg_kernel Alg_kernel; + typedef typename Traits_2::Nt_traits Nt_traits; - typedef typename Rat_kernel::FT Rational; - typedef typename Rat_kernel::Point_2 Rat_point_2; - typedef typename Rat_kernel::Segment_2 Rat_segment_2; - typedef typename Rat_kernel::Line_2 Rat_line_2; - typedef typename Rat_kernel::Circle_2 Rat_circle_2; - typedef typename Rat_kernel::Point_3 Rat_point_3; + typedef typename Rat_kernel::FT Rational; + typedef typename Rat_kernel::Point_2 Rat_point_2; + typedef typename Rat_kernel::Segment_2 Rat_segment_2; + typedef typename Rat_kernel::Line_2 Rat_line_2; + typedef typename Rat_kernel::Circle_2 Rat_circle_2; + typedef typename Rat_kernel::Point_3 Rat_point_3; - typedef typename Alg_kernel::FT Algebraic; - typedef typename Alg_kernel::Point_2 Alg_point_2; - typedef typename Alg_kernel::Circle_2 Alg_circle_2; + typedef typename Alg_kernel::FT Algebraic; + typedef typename Alg_kernel::Point_2 Alg_point_2; + typedef typename Alg_kernel::Circle_2 Alg_circle_2; - typedef typename Rat_kernel::Sphere_3 Surface_3; + typedef typename Rat_kernel::Sphere_3 Surface_3; // here we refer to the lower part of the sphere only - typedef Surface_3 Xy_monotone_surface_3; + typedef Surface_3 Xy_monotone_surface_3; + protected: - typedef std::pair Intersection_curve; + typedef std::pair Intersection_curve; public: class Make_xy_monotone_3 { protected: - const Self & parent; + const Self& parent; public: - Make_xy_monotone_3(const Self * p) : parent(*p) - {} + Make_xy_monotone_3(const Self * p) : parent(*p) {} // create xy-monotone surfaces from a general surface // return a past-the-end iterator @@ -89,32 +87,28 @@ public: /*! Get a Make_xy_monotone_3 functor object. */ Make_xy_monotone_3 - make_xy_monotone_3_object() const - { - return Make_xy_monotone_3(this); - } + make_xy_monotone_3_object() const { return Make_xy_monotone_3(this); } - class Construct_projected_boundary_2 - { + class Construct_projected_boundary_2 { protected: - const Self & parent; + const Self& parent; public: - Construct_projected_boundary_2(const Self * p) : parent(*p) - {} + Construct_projected_boundary_2(const Self* p) : parent(*p) {} // insert into the OutputIterator all the (2d) curves of the boundary of // the vertical projection of the surface on the xy-plane // the OutputIterator value type is X_monotone_curve_2 template OutputIterator - operator()(const Xy_monotone_surface_3& s, OutputIterator o) const - { + operator()(const Xy_monotone_surface_3& s, OutputIterator o) const { + const auto gt_2 = parent.geometry_traits_2(); + // the projected boundary in a circle, with a projected center, // and same radius Rat_point_2 proj_center = parent.project(s.center()); Rat_circle_2 circ(proj_center, s.squared_radius()); - Curve_2 curve(circ); + Curve_2 curve = gt_2->construct_curve_2_object()(circ); Object objs[2]; CGAL_assertion_code(Object *p = ) parent.make_x_monotone_2_object()(curve, objs); @@ -128,14 +122,12 @@ public: assign(cv1, objs[0]); assign(cv2, objs[1]); - if(cv1.is_lower()) - { + if (cv1.is_lower()) { CGAL_assertion(cv2.is_upper()); *o++ = make_object(std::make_pair(cv1, ON_POSITIVE_SIDE)); *o++ = make_object(std::make_pair(cv2, ON_NEGATIVE_SIDE)); } - else - { + else { CGAL_assertion(cv2.is_lower()); *o++ = make_object(std::make_pair(cv1, ON_NEGATIVE_SIDE)); *o++ = make_object(std::make_pair(cv2, ON_POSITIVE_SIDE)); @@ -148,59 +140,57 @@ public: /*! Get a Construct_projected_boundary_2 functor object. */ Construct_projected_boundary_2 construct_projected_boundary_2_object() const - { - return Construct_projected_boundary_2(this); - } + { return Construct_projected_boundary_2(this); } - class Construct_projected_intersections_2 - { + class Construct_projected_intersections_2 { protected: - const Self & parent; + const Self& parent; public: - Construct_projected_intersections_2(const Self * p) : parent(*p) - {} + Construct_projected_intersections_2(const Self * p) : parent(*p) {} // insert into OutputIterator all the (2d) projections on the xy plane of // the intersection objects between the 2 surfaces // the data type of OutputIterator is Object - template + template OutputIterator - operator()(const Xy_monotone_surface_3& s1, - const Xy_monotone_surface_3& s2, - OutputIterator o) const - { + operator()(const Xy_monotone_surface_3& s1, const Xy_monotone_surface_3& s2, + OutputIterator o) const { + const auto gt_2 = parent.geometry_traits_2(); + auto ctr_cv = gt_2->construct_curve_2_object(); + auto nt_traits = gt_2->nt_traits(); + Rat_point_3 p1 = s1.center(); Rat_point_3 p2 = s2.center(); - const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(), - a2 = p2.x(), b2 = p2.y(), c2 = p2.z(); - const Rational sqr_r1 = s1.squared_radius(), - sqr_r2 = s2.squared_radius(); + const Rational a1 = p1.x(); + const Rational b1 = p1.y(); + const Rational c1 = p1.z(); + const Rational a2 = p2.x(); + const Rational b2 = p2.y(); + const Rational c2 = p2.z(); + const Rational sqr_r1 = s1.squared_radius(); + const Rational sqr_r2 = s2.squared_radius(); -// // the spheres intersect iff d(p1, p2) <= (r1+r2) -// // squaring this twice, we get the condition -// // sqr_d^2 + (1-2*sqr_d)(sqr_r1 + sqr_r2) - 2*sqr_r1*sqr_r2 <= 0 -// // with only rational numbers involved. -// // todo: check if it helps -// Rat_kernel ratk; -// Rational sqr_d = ratk.compute_squared_distance_3_object()(p1, p2); -// Sign do_inter = CGAL_NTS sign(sqr_d*sqr_d + (1-2*sqr_d)*(sqr_r1+sqr_r2)-2*sqr_r1*sqr_r2); -// if (do_inter == POSITIVE) -// return o; - - Nt_traits nt_traits; + // // the spheres intersect iff d(p1, p2) <= (r1+r2) + // // squaring this twice, we get the condition + // // sqr_d^2 + (1-2*sqr_d)(sqr_r1 + sqr_r2) - 2*sqr_r1*sqr_r2 <= 0 + // // with only rational numbers involved. + // // todo: check if it helps + // Rat_kernel ratk; + // Rational sqr_d = ratk.compute_squared_distance_3_object()(p1, p2); + // Sign do_inter = + // CGAL_NTS sign(sqr_d*sqr_d + (1-2*sqr_d)*(sqr_r1+sqr_r2)-2*sqr_r1*sqr_r2); + // if (do_inter == POSITIVE) + // return o; // we check if the centers of the 2 spheres have same z coordinate - // in this case the potential projected intersection is a segment // (or point) - if (CGAL_NTS compare(c1, c2) == EQUAL) - { - if (CGAL_NTS compare(b1, b2) == EQUAL) - { - if (CGAL_NTS compare(a1, a2) == EQUAL) + if (CGAL_NTS compare(c1, c2) == EQUAL) { + if (CGAL_NTS compare(b1, b2) == EQUAL) { + if (CGAL_NTS compare(a1, a2) == EQUAL) { // the same center, we have no intersection // (we don't return overlappings as intersections) - { return o; } @@ -234,24 +224,17 @@ public: Rational B = -8*b1*sqr_a_diff; Rational C = 4*sqr_a_diff*(sqr_a1+sqr_b1-sqr_r1) + m*m - 4*m*a1*a_diff; - Algebraic ys[2]; - Algebraic *ys_end; - std::ptrdiff_t n_ys; - ys_end = nt_traits.solve_quadratic_equation(A, B, C, ys); - n_ys = ys_end - ys; + Algebraic* ys_end = nt_traits->solve_quadratic_equation(A, B, C, ys); + std::ptrdiff_t n_ys = ys_end - ys; - if (n_ys == 0) - { - return o; // no intersection - } + if (n_ys == 0) return o; // no intersection // the x coordinate of the solution points Algebraic xs = m / (2*a_diff); - if (n_ys == 1) - { + if (n_ys == 1) { // intersection is a point Point_2 inter_point(xs , ys[0]); *o++ = make_object(inter_point); @@ -268,14 +251,12 @@ public: // equation (1) is: // 2(a1-a2)x - m = 0 - - Curve_2 res(0,0,0, 2*a_diff, 0, -m, COLLINEAR, end1, end2); + Curve_2 res = ctr_cv(0, 0, 0, 2*a_diff, 0, -m, COLLINEAR, end1, end2); parent.add_curve_to_output(res, o); //*o++ = make_object(Intersection_curve(res, TRANSVERSAL)); } - else - { + else { // here we have c1 == c2, b1 != b2. // the intersection lies on the plane // -2(a1-a2)x + m @@ -316,19 +297,15 @@ public: Rational E = -8*a1*sqr_b_diff - 4*m*a_diff + 8*b1*a_diff*b_diff; Rational F = 4*sqr_b_diff*(sqr_a1+sqr_b1-sqr_r1) + m*m - 4*m*b1*b_diff; - Algebraic xs[2]; - Algebraic *xs_end; - std::ptrdiff_t n_xs; + Algebraic xs[2]; - xs_end = nt_traits.solve_quadratic_equation(D, E, F, xs); - n_xs = xs_end - xs; + Algebraic* xs_end = nt_traits->solve_quadratic_equation(D, E, F, xs); + std::ptrdiff_t n_xs = xs_end - xs; - if (n_xs == 0) - { + if (n_xs == 0) { return o; // no intersection } - if (n_xs == 1) - { + if (n_xs == 1) { // intersection is a point Point_2 inter_point(xs[0], (-2*a_diff*xs[0] + m)/(2*b_diff) ); *o++ = make_object(inter_point); @@ -348,16 +325,15 @@ public: // equation (1) is: // 2(a1-a2)x + 2(b1-b2)y - m = 0 - Curve_2 res(0,0,0, 2*a_diff, 2*b_diff, -m, COLLINEAR, end1, end2); + Curve_2 res = + ctr_cv(0,0,0, 2*a_diff, 2*b_diff, -m, COLLINEAR, end1, end2); parent.add_curve_to_output(res, o); //*o++ = make_object(Intersection_curve(res, TRANSVERSAL)); } - } // now the potential intersection is (a part of) a circle, // and the projection is (a part of) an ellipse - else - { + else { // here we have c1 != c2. // the intersection lies on the plane: // -2(a1-a2)x -2(b1-b2)y + m @@ -411,7 +387,7 @@ public: Rational sqr_c1 = c1*c1, sqr_c2 = c2*c2; Rational m = sqr_a1 + sqr_b1 + sqr_c1 - - sqr_a2 - sqr_b2 - sqr_c2 + sqr_r2 - sqr_r1; + sqr_a2 - sqr_b2 - sqr_c2 + sqr_r2 - sqr_r1; Rational R = 4*sqr_c_diff + 4*sqr_a_diff; Rational S = 4*sqr_c_diff + 4*sqr_b_diff; @@ -419,26 +395,20 @@ public: Rational U = -8*a1*sqr_c_diff + 8*c1*c_diff*a_diff - 4*m*a_diff; Rational V = -8*b1*sqr_c_diff + 8*c1*c_diff*b_diff - 4*m*b_diff; Rational W = 4*sqr_c_diff*(sqr_a1+sqr_b1+sqr_c1-sqr_r1) - - 4*m*c1*c_diff + m*m; + 4*m*c1*c_diff + m*m; // if the full spheres do not intersect, the equation we get has no // real solution, so we should check it: bool ellipse_is_point = false; - if (!parent.is_valid_conic_equation(R, S, T, U, V, W, - ellipse_is_point)) - { + if (! parent.is_valid_conic_equation(R, S, T, U, V, W, ellipse_is_point)) return o; - } // we need only a part of the ellipse (as stated in (**)) so we // construct the cutting line, which is: // equation (*) <= min(c1,c2) -- for lower envelope // equation (*) >= max(c1,c2) -- for upper envelope - Rational z_plane; - if (parent.m_is_lower) - z_plane = ((c1 < c2) ? c1 : c2); - else - z_plane = ((c1 > c2) ? c1 : c2); + Rational z_plane = (parent.m_is_lower) ? + ((c1 < c2) ? c1 : c2) : ((c1 > c2) ? c1 : c2); // we get (for lower envelope) @@ -452,33 +422,30 @@ public: // for upper envelope, we should multiply the line equation by -1 int envelope_coef = 1; - if (!parent.m_is_lower) - envelope_coef = -1; + if (! parent.m_is_lower) envelope_coef = -1; Sign sign_c_diff = CGAL_NTS sign(c_diff); Rational la = envelope_coef*2*a_diff*sign_c_diff; Rational lb = envelope_coef*2*b_diff*sign_c_diff; Rational lc = envelope_coef*sign_c_diff*(2*c_diff*z_plane - m); - if (ellipse_is_point) - { + if (ellipse_is_point) { // as specified in the is_valid_conic_equation method, the // intersection point is: // Rational px = S*(4*U - T*V)/(T*T - 4*S*R); px = px / 2; - Rational py = -(T*px + V)/(2*S); + Rational py = -(T*px + V)/(2*S); // should check if the point is in the non-negative side of the // line - if (CGAL_NTS sign(la*px + lb*py +lc) != NEGATIVE) - { - *o++ = make_object(Point_2(px, py)); - } + if (CGAL_NTS sign(la*px + lb*py +lc) != NEGATIVE) + *o++ = make_object(Point_2(px, py)); return o; - } + } // EBEB 2012/06/29: Added because of - // no matching function for call to 'compare(CGAL::Env_sphere_traits_3::Rational&, int) + // no matching function for call to + // compare(CGAL::Env_sphere_traits_3::Rational&, int) Rational zero(0); // if (a1==a2) and (b1==b2) (*) is a plane parallel to the xy-plane @@ -490,9 +457,8 @@ public: CGAL_NTS compare(b_diff, zero) == EQUAL) { Sign sign_lc = CGAL_NTS sign(lc); - if (sign_lc != NEGATIVE) - { - Curve_2 res(R, S, T, U, V, W); + if (sign_lc != NEGATIVE) { + Curve_2 res = ctr_cv(R, S, T, U, V, W); parent.add_curve_to_output(res, o); //*o++ = make_object(Intersection_curve(res, TRANSVERSAL)); } @@ -505,31 +471,29 @@ public: // R*x^2 + S*y^2 + T*xy + U*x + V*y + W = 0 Alg_point_2 source, target, pmid; std::ptrdiff_t n_inter_points; - if (CGAL_NTS compare(lb, zero) != EQUAL) - { + if (CGAL_NTS compare(lb, zero) != EQUAL) { // Find the x-coordinates of the intersection points of the conic // curve and the line y = -(la*x + lc) / lb: // we get a quadratic equation Ax^2 + Bx + C = 0 // where A = lb*lb*R + la*(la*S - lb*T) // B = 2*la*lc*S - lb*(lc*T + la*V - lb*U) // C = S*lc*lc + lb*(lb*W - lc*V) - Rational A = lb*lb*R + la*(la*S - lb*T), - B = 2*la*lc*S - lb*(lc*T + la*V - lb*U), - C = S*lc*lc + lb*(lb*W - lc*V); + Rational A = lb*lb*R + la*(la*S - lb*T); + Rational B = 2*la*lc*S - lb*(lc*T + la*V - lb*U); + Rational C = S*lc*lc + lb*(lb*W - lc*V); - Algebraic inter_xs[2]; - Algebraic *inter_xs_end; + Algebraic inter_xs[2]; + Algebraic* inter_xs_end; - inter_xs_end = nt_traits.solve_quadratic_equation(A, B, C, inter_xs); + inter_xs_end = nt_traits->solve_quadratic_equation(A, B, C, inter_xs); n_inter_points = inter_xs_end - inter_xs; if (n_inter_points > 0) - source = Alg_point_2(inter_xs[0], - -(la*inter_xs[0] + lc) / Algebraic(lb)); - if (n_inter_points == 2) - { - target = Alg_point_2(inter_xs[1], - -(la*inter_xs[1] + lc) / Algebraic(lb)); + source = + Alg_point_2(inter_xs[0], -(la*inter_xs[0] + lc) / Algebraic(lb)); + if (n_inter_points == 2) { + target = + Alg_point_2(inter_xs[1], -(la*inter_xs[1] + lc) / Algebraic(lb)); // Get the conic points whose x-coordinate are in the middle of the // two endpoints. @@ -542,30 +506,30 @@ public: CGAL_precondition_code(int x_mid_n_y_points;); Alg_point_2 x_mid_y_points[2]; - Curve_2 inter_cv(R, S, T, U, V, W); + Curve_2 inter_cv = ctr_cv(R, S, T, U, V, W); CGAL_precondition_code(x_mid_n_y_points = ) - inter_cv.points_at_x(x_mid_point, x_mid_y_points); + gt_2->points_at_x(inter_cv, x_mid_point, x_mid_y_points); CGAL_precondition(x_mid_n_y_points > 0); Algebraic y1 = x_mid_y_points[0].y(), y2 = x_mid_y_points[1].y(); - if (CGAL_NTS compare(Algebraic(la)*x_mid + Algebraic(lb)*y1 + Algebraic(lc), - Algebraic(0) - ) == LARGER) - { + if (CGAL_NTS compare(Algebraic(la)*x_mid + Algebraic(lb)*y1 + + Algebraic(lc), + Algebraic(0)) == LARGER) + { pmid = Alg_point_2(x_mid, y1); } - else - { - CGAL_assertion(CGAL_NTS compare(Algebraic(la)*x_mid + Algebraic(lb)*y2 + Algebraic(lc), + else { + CGAL_assertion(CGAL_NTS compare(Algebraic(la)*x_mid + + Algebraic(lb)*y2 + Algebraic(lc), Algebraic(0)) == LARGER); pmid = Alg_point_2(x_mid, y2); } } } - else - { // lb == 0 + else { + // lb == 0 CGAL_assertion(CGAL_NTS compare(la, zero) != EQUAL); // Find the intersection of the vertical line x = -lc / la: @@ -574,21 +538,20 @@ public: // where A = S // B = T*inter_x + V // C = R*inter_x^2 + U*inter_x + W - Rational A = S, - B = T*inter_x + V, - C = R*inter_x*inter_x + U*inter_x + W; + Rational A = S; + Rational B = T*inter_x + V; + Rational C = R*inter_x*inter_x + U*inter_x + W; - Algebraic inter_points[2]; - Algebraic *inter_points_end; + Algebraic inter_points[2]; + Algebraic* inter_points_end; inter_points_end = - nt_traits.solve_quadratic_equation(A, B, C, inter_points); + nt_traits->solve_quadratic_equation(A, B, C, inter_points); n_inter_points = inter_points_end - inter_points; if (n_inter_points > 0) source = Alg_point_2(Algebraic(inter_x), inter_points[0]); - if (n_inter_points == 2) - { + if (n_inter_points == 2) { target = Alg_point_2(Algebraic(inter_x), inter_points[1]); // Get the conic points whose y-coordinate are in the middle of the @@ -599,32 +562,30 @@ public: Alg_point_2 y_mid_point(0, y_mid); Alg_point_2 y_mid_x_points[2]; - Curve_2 inter_cv(R, S, T, U, V, W); - - CGAL_precondition_code(int y_mid_n_x_points =) - inter_cv.points_at_y(y_mid_point, y_mid_x_points); + Curve_2 inter_cv = ctr_cv(R, S, T, U, V, W); + CGAL_precondition_code(int y_mid_n_x_points =) + gt_2->points_at_y(inter_cv, y_mid_point, y_mid_x_points); CGAL_precondition(y_mid_n_x_points > 0); Algebraic x1 = y_mid_x_points[0].x(), x2 = y_mid_x_points[1].x(); - if (CGAL_NTS compare( - Algebraic(la)*x1 + Algebraic(lb)*y_mid + Algebraic(lc), - Algebraic(0)) == LARGER) + if (CGAL_NTS compare(Algebraic(la)*x1 + Algebraic(lb)*y_mid + + Algebraic(lc), + Algebraic(0)) == LARGER) { pmid = Alg_point_2(x1, y_mid); } - else - { - CGAL_assertion(CGAL_NTS compare ( - Algebraic(la)*x2 + Algebraic(lb)*y_mid + Algebraic(lc), - Algebraic(0)) == LARGER); + else { + CGAL_assertion(CGAL_NTS compare(Algebraic(la)*x2 + + Algebraic(lb)*y_mid + + Algebraic(lc), + Algebraic(0)) == LARGER); pmid = Alg_point_2(x2, Algebraic(y_mid)); } } } - if (n_inter_points < 2) - { + if (n_inter_points < 2) { // we should check whether the ellipse is in the positive side of the // line - in which case we return the full ellipse // or not - in which case there is no intersection if @@ -634,31 +595,27 @@ public: // for this, we find a point inside the ellipse and substitute // its coordinates in the line equation - Curve_2 inter_cv(R, S, T, U, V, W); + Curve_2 inter_cv = ctr_cv(R, S, T, U, V, W); Alg_point_2 vtan_ps[2]; - CGAL_assertion_code(int n_vtan_ps =) - inter_cv.vertical_tangency_points(vtan_ps); - + CGAL_assertion_code(std::size_t n_vtan_ps =) + gt_2->vertical_tangency_points(inter_cv, vtan_ps); CGAL_assertion(n_vtan_ps == 2); Algebraic lval = Algebraic(la)*vtan_ps[0].x() + Algebraic(lb)*vtan_ps[0].y() + Algebraic(lc); Sign lval_sign = CGAL_NTS sign(lval); - if (lval_sign == POSITIVE) - { + if (lval_sign == POSITIVE) { // the full ellipse is in the positive side parent.add_curve_to_output(inter_cv, o); //*o++ = make_object(Intersection_curve(inter_cv, TRANSVERSAL)); return o; } - else if (lval_sign == NEGATIVE) - { + else if (lval_sign == NEGATIVE) { // the full ellipse is in the negative side, except maybe the point // source in the case n_inter_points = 1 (which lies on the line) - if (n_inter_points == 1) - *o++ = make_object(Point_2(source)); + if (n_inter_points == 1) *o++ = make_object(Point_2(source)); return o; } @@ -667,16 +624,14 @@ public: // n_inter_points == 1 and source = vtan_ps[0] CGAL_assertion(n_inter_points == 1 && source == vtan_ps[0]); // so we try the other vertical tangency point - lval = Algebraic(la)*vtan_ps[1].x() + - Algebraic(lb)*vtan_ps[1].y() + Algebraic(lc); + lval = Algebraic(la)*vtan_ps[1].x() + Algebraic(lb)*vtan_ps[1].y() + + Algebraic(lc); lval_sign = CGAL_NTS sign(lval); CGAL_assertion(lval_sign != ZERO); - if (lval_sign == POSITIVE) - parent.add_curve_to_output(inter_cv, o); + if (lval_sign == POSITIVE) parent.add_curve_to_output(inter_cv, o); //*o++ = make_object(Intersection_curve(inter_cv, TRANSVERSAL)); - else - *o++ = make_object(Point_2(source)); + else *o++ = make_object(Point_2(source)); return o; } @@ -688,15 +643,12 @@ public: // If the mid-point forms a left-turn with the source and the target // points, the orientation is positive (going counterclockwise). // Otherwise, it is negative (going clockwise). - Alg_kernel k; - typename Alg_kernel::Orientation_2 orient_f = k.orientation_2_object(); - Orientation orient; - if (orient_f(source, pmid, target) == LEFT_TURN) - orient = CGAL::COUNTERCLOCKWISE; - else - orient = CGAL::CLOCKWISE; + auto alg_kernel = gt_2->alg_kernel(); + auto orient_f = alg_kernel->orientation_2_object(); + Orientation orient = (orient_f(source, pmid, target) == LEFT_TURN) ? + CGAL::COUNTERCLOCKWISE : CGAL::CLOCKWISE; - Curve_2 res(R, S, T, U, V, W, orient, source, target); + Curve_2 res = ctr_cv(R, S, T, U, V, W, orient, source, target); CGAL_assertion(res.is_valid()); parent.add_curve_to_output(res, o); //*o++ = make_object(Intersection_curve(res, TRANSVERSAL)); @@ -709,18 +661,14 @@ public: /*! Get a Construct_projected_intersections_2 functor object. */ Construct_projected_intersections_2 construct_projected_intersections_2_object() const - { - return Construct_projected_intersections_2(this); - } + { return Construct_projected_intersections_2(this); } - class Compare_z_at_xy_3 - { + class Compare_z_at_xy_3 { protected: - const Self & parent; + const Self& parent; public: - Compare_z_at_xy_3(const Self * p) : parent(*p) - {} + Compare_z_at_xy_3(const Self* p) : parent(*p) {} // check which of the surfaces is closer to the envelope at the xy // coordinates of point (i.e. lower if computing the lower envelope, or @@ -728,8 +676,7 @@ public: // precondition: the surfaces are defined in point Comparison_result operator()(const Point_2& p, const Xy_monotone_surface_3& s1, - const Xy_monotone_surface_3& s2) const - { + const Xy_monotone_surface_3& s2) const { Comparison_result c2 = compare_in_point_second_method(p, s1, s2); CGAL_expensive_assertion_code( @@ -747,12 +694,10 @@ public: // answer is the same for each of these points Comparison_result operator()(const X_monotone_curve_2& cv, const Xy_monotone_surface_3& s1, - const Xy_monotone_surface_3& s2) const - { + const Xy_monotone_surface_3& s2) const { // we compute a middle point on cv and use the previous function Point_2 mid = parent.construct_middle_point(cv); - Comparison_result res = - parent.compare_z_at_xy_3_object()(mid, s1, s2); + Comparison_result res = parent.compare_z_at_xy_3_object()(mid, s1, s2); return res; } @@ -762,18 +707,15 @@ public: Comparison_result compare_in_point_first_method(const Point_2& p, const Xy_monotone_surface_3& s1, - const Xy_monotone_surface_3& s2) const - { + const Xy_monotone_surface_3& s2) const { // find the z coordinates of surface 1 over p Algebraic z1 = parent.compute_envelope_z_in_point(p, s1); // find the z coordinates of surface 2 over p Algebraic z2 = parent.compute_envelope_z_in_point(p, s2); Sign res = CGAL_NTS sign(z1 - z2); - if (parent.m_is_lower) - return res; - else - return -res; + if (parent.m_is_lower) return res; + else return -res; } // second method of compare in point @@ -796,10 +738,14 @@ public: { Rat_point_3 p1 = s1.center(); Rat_point_3 p2 = s2.center(); - const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(), - a2 = p2.x(), b2 = p2.y(), c2 = p2.z(); - const Rational sqr_r1 = s1.squared_radius(), - sqr_r2 = s2.squared_radius(); + const Rational a1 = p1.x(); + const Rational b1 = p1.y(); + const Rational c1 = p1.z(); + const Rational a2 = p2.x(); + const Rational b2 = p2.y(); + const Rational c2 = p2.z(); + const Rational sqr_r1 = s1.squared_radius(); + const Rational sqr_r2 = s2.squared_radius(); const Algebraic x1 = p.x(), y1 = p.y(); Rational c_diff = c1 - c2; @@ -814,34 +760,28 @@ public: if (CGAL_NTS sign(A2) == NEGATIVE) std::cout << "A2 = " << A2 << std::endl; - Sign res; // sign_a_plus_b_x_sqrt_e_plus_c_x_sqrt_f is a CGAL method which // computes the sign of quantity: a + b * sqrt(e) + c * sqrt(f) - - res = CGAL::sign_a_plus_b_x_sqrt_e_plus_c_x_sqrt_f(Algebraic(c_diff), - Algebraic(-1), - Algebraic(1), - A1, - A2); + Sign res = + CGAL::sign_a_plus_b_x_sqrt_e_plus_c_x_sqrt_f(Algebraic(c_diff), + Algebraic(-1), + Algebraic(1), + A1, + A2); return res; } }; /*! Get a Compare_z_at_xy_3 functor object. */ Compare_z_at_xy_3 - compare_z_at_xy_3_object() const - { - return Compare_z_at_xy_3(this); - } + compare_z_at_xy_3_object() const { return Compare_z_at_xy_3(this); } - class Compare_z_at_xy_above_3 - { + class Compare_z_at_xy_above_3 { protected: - const Self & parent; + const Self& parent; public: - Compare_z_at_xy_above_3(const Self * p) : parent(*p) - {} + Compare_z_at_xy_above_3(const Self* p) : parent(*p) {} // check which of the surfaces is closer to the envelope on the points above // the curve cv (i.e. lower if computing the lower envelope, or upper if @@ -854,27 +794,20 @@ public: operator()(const X_monotone_curve_2& cv, const Xy_monotone_surface_3& s1, const Xy_monotone_surface_3& s2) const - { - Comparison_result res = parent.compare_on_side(cv, s1, s2, false); - return res; - } + { return parent.compare_on_side(cv, s1, s2, false); } }; /*! Get a Compare_z_at_xy_above_3 functor object. */ Compare_z_at_xy_above_3 compare_z_at_xy_above_3_object() const - { - return Compare_z_at_xy_above_3(this); - } + { return Compare_z_at_xy_above_3(this); } - class Compare_z_at_xy_below_3 - { + class Compare_z_at_xy_below_3 { protected: - const Self & parent; + const Self& parent; public: - Compare_z_at_xy_below_3(const Self * p) : parent(*p) - {} + Compare_z_at_xy_below_3(const Self* p) : parent(*p) {} Comparison_result operator()(const X_monotone_curve_2& cv, @@ -889,46 +822,40 @@ public: /*! Get a Compare_z_at_xy_below_3 functor object. */ Compare_z_at_xy_below_3 compare_z_at_xy_below_3_object() const - { - return Compare_z_at_xy_below_3(this); - } + { return Compare_z_at_xy_below_3(this); } /***************************************************************************/ // public method needed for testing // checks if point is in the xy-range of surf - class Is_defined_over - { + class Is_defined_over { protected: - const Self & parent; + const Self& parent; public: - Is_defined_over(const Self * p) : parent(*p) - {} + Is_defined_over(const Self* p) : parent(*p) {} // checks if point is in the xy-range of surf - bool operator()(const Point_2& p, const Xy_monotone_surface_3& s) const - { + bool operator()(const Point_2& p, const Xy_monotone_surface_3& s) const { // project the surface on the plane Rat_point_2 proj_center = parent.project(s.center()); Rat_circle_2 boundary(proj_center, s.squared_radius()); - Nt_traits nt_traits; - Alg_kernel k; + const auto gt_2 = parent.geometry_traits_2(); + auto nt_traits = gt_2->nt_traits(); Alg_point_2 aproj_center(proj_center.x(), proj_center.y()); - Alg_circle_2 aboundary(aproj_center, nt_traits.convert(s.squared_radius())); + Alg_circle_2 aboundary(aproj_center, nt_traits->convert(s.squared_radius())); // check if the projected point is inside the projected boundary - return (!k.has_on_unbounded_side_2_object()(aboundary, p)); + auto alg_kernel = gt_2->alg_kernel(); + return (! alg_kernel->has_on_unbounded_side_2_object()(aboundary, p)); } }; /*! Get a Is_defined_over functor object. */ Is_defined_over is_defined_over_object() const - { - return Is_defined_over(this); - } + { return Is_defined_over(this); } /***************************************************************************/ @@ -1005,64 +932,52 @@ public: // and we solve the problem as for triangles Rat_point_3 p1 = s1.center(); Rat_point_3 p2 = s2.center(); - const Rational a1 = p1.x(), b1 = p1.y(), c1 = p1.z(), - a2 = p2.x(), b2 = p2.y(), c2 = p2.z(); + const Rational a1 = p1.x(); + const Rational b1 = p1.y(); + const Rational c1 = p1.z(); + const Rational a2 = p2.x(); + const Rational b2 = p2.y(); + const Rational c2 = p2.z(); Algebraic A1 = x0 - a1, B1 = y0 - b1, C1 = z0 - c1; Algebraic A2 = x0 - a2, B2 = y0 - b2, C2 = z0 - c2; - if (C1 != 0 && C2 != 0) - { + if (C1 != 0 && C2 != 0) { Sign sign1 = CGAL_NTS sign((A2*A3+B2*B3)/C2-(A1*A3+B1*B3)/C1); // to make sure the direction is correct, we take a second point on the // line: for vertical line we take (x0, y0+1) // otherwise we take (x0+1, y0+ m/n) Algebraic x1, y1; - if (n == 0) - { + if (n == 0) { x1 = x0; y1 = y0+1; } - else - { + else { x1 = x0+1; y1 = y0 + (m/n); } Sign sign2 = CGAL_NTS sign(-B3*x1+A3*y1-(-B3*x0+A3*y0)); // the answer negates according to the side of the line we ask of - Sign sign3 = (compare_on_right ? (CGAL_NTS sign(1)) : - (CGAL_NTS sign(-1))); + Sign sign3 = (compare_on_right ? (CGAL_NTS sign(1)) : (CGAL_NTS sign(-1))); return sign1 * sign2 * sign3; } - else if (C1 != 0 && C2 == 0) - { - // sphere 2 is on the envelope (both lower & upper) - return LARGER; - } - else if (C1 == 0 && C2 != 0) - - { - // sphere 1 is on the envelope (both lower & upper) - return SMALLER; - } - else - CGAL_error(); - + // sphere 2 is on the envelope (both lower & upper) + else if (C1 != 0 && C2 == 0) return LARGER; + // sphere 1 is on the envelope (both lower & upper) + else if (C1 == 0 && C2 != 0) return SMALLER; + else CGAL_error(); return EQUAL; } Rat_point_2 project(const Rat_point_3& p) const - { - return Rat_point_2(p.x(), p.y()); - } + { return Rat_point_2(p.x(), p.y()); } // compute the z coordinate of the surface s in point p on the envelope // (i.e. take lower point if lower envelope, upper otherwise) // precondition: s is defined at p Algebraic compute_envelope_z_in_point(const Point_2& p, - const Xy_monotone_surface_3& s) const - { + const Xy_monotone_surface_3& s) const { Algebraic res; // the point coordinates @@ -1079,57 +994,49 @@ public: // z^2 - 2cz + [(x1-a)^2 + (y1-b)^2 + c^2 - r^2] = 0 Algebraic x_diff = x1 - a, y_diff = y1 - b; // the coefficients are: - Algebraic A = 1, - B = -2*c, - C = x_diff*x_diff + y_diff*y_diff + c*c - sqr_r; + Algebraic A = 1; + Algebraic B = -2*c; + Algebraic C = x_diff*x_diff + y_diff*y_diff + c*c - sqr_r; Algebraic zs[2]; - Algebraic *zs_end; + Algebraic* zs_end; std::ptrdiff_t n_zs; - Nt_traits nt_traits; - zs_end = nt_traits.solve_quadratic_equation(A, B, C, zs); + auto nt_traits = m_geometry_traits_2->nt_traits(); + zs_end = nt_traits->solve_quadratic_equation(A, B, C, zs); n_zs = zs_end - zs; CGAL_precondition(n_zs > 0); - if (n_zs == 1) - // only one point is defined at p, this is the result - return zs[0]; + // only one point is defined at p, this is the result + if (n_zs == 1) return zs[0]; CGAL_assertion(n_zs == 2); Comparison_result comp = CGAL_NTS compare(zs[0], zs[1]); - if (m_is_lower) - res = ((comp == SMALLER) ? zs[0] : zs[1]); - else - res = ((comp == LARGER) ? zs[0] : zs[1]); - + if (m_is_lower) res = ((comp == SMALLER) ? zs[0] : zs[1]); + else res = ((comp == LARGER) ? zs[0] : zs[1]); return res; } // construct the point in the middle of cv - Point_2 construct_middle_point(const X_monotone_curve_2& cv) const - { + Point_2 construct_middle_point(const X_monotone_curve_2& cv) const { // get the x-value of the middle point - Alg_kernel k; - Alg_point_2 mid_x = k.construct_midpoint_2_object()(cv.source(), - cv.target()); + auto alg_kernel = m_geometry_traits_2->alg_kernel(); + Alg_point_2 mid_x = + alg_kernel->construct_midpoint_2_object()(cv.source(), cv.target()); -// TODO_NEW_DESIGN - this is not implemented in X_monotone_curve_2, but maybe we want it there? -// if (cv.is_segment()) -// return mid_x; - if (cv.is_vertical()) - return Point_2(mid_x); - - return Point_2(cv.point_at_x(mid_x)); + // TODO_NEW_DESIGN - this is not implemented in X_monotone_curve_2, but + // maybe we want it there? + // if (cv.is_segment()) return mid_x; + if (cv.is_vertical()) return Point_2(mid_x); + return Point_2(m_geometry_traits_2->point_at_x(cv, mid_x)); } // for the test - Point_2 construct_middle_point(const Point_2& p1, const Point_2& p2) const - { - Alg_kernel k; - return Point_2(k.construct_midpoint_2_object()(p1, p2)); + Point_2 construct_middle_point(const Point_2& p1, const Point_2& p2) const { + auto alg_kernel = m_geometry_traits_2->alg_kernel(); + return Point_2(alg_kernel->construct_midpoint_2_object()(p1, p2)); } // check if the equation @@ -1139,8 +1046,7 @@ public: template bool is_valid_conic_equation(const NT& r, const NT& s, const NT& t, const NT& u, const NT& v, const NT& w, - bool &is_point) const - { + bool& is_point) const { // initialize is_point to false, and will change it when we detect // that the equation represents a point is_point = false; @@ -1160,16 +1066,14 @@ public: // (the conic equation in this case represents hyperbola or 2 // intersecting lines) Sign sign_A = CGAL_NTS sign(t*t - 4*s*r); - if (sign_A == POSITIVE) - return true; + if (sign_A == POSITIVE) return true; // if A < 0 we have a sad parabula, so we should check if it crosses the // x-axis, i.e. if the equation f(x) = 0 has a real solution x. // this means that discriminant(f(x)) >= 0 // discriminant(f(x)) = B^2 - 4AC // = (2tv-4su)^2 - 4(t^2-4sr)(v^2-4sw) // = s(-tvu + su^2 + wt^2 + rv^2 - 4srw) - if (sign_A == NEGATIVE) - { + if (sign_A == NEGATIVE) { // (in this case the conic equation represents ellipse, circle, point // or no curve) Sign sign_s = CGAL_NTS sign(s); @@ -1178,9 +1082,7 @@ public: // solution for f(x), say x0. since we get f(x0)=0 and f(x)<0 forall // x!=x0, we have only one solution for (**). So the equation represents // a point with coordinates x0=-B/2A, y0=-(tx0 + v)/2s - if (sign_eq == ZERO) - is_point = true; - + if (sign_eq == ZERO) is_point = true; Sign sign_disc = CGAL_NTS sign(int(sign_s * sign_eq)); return (sign_disc != NEGATIVE); } @@ -1192,47 +1094,36 @@ public: // (in this case the conic equation represents parabola, 2 parallel lines, // 1 line or no curve) Sign sign_B = CGAL_NTS sign(s*(t*v - 4*u)); - if (sign_B != ZERO) - return true; + if (sign_B != ZERO) return true; Sign sign_C = CGAL_NTS sign(v*v - 4*s*w); - return (sign_C != NEGATIVE); } // for the test: - Point_2 vertical_ray_shoot_2(const Point_2& pt, - const X_monotone_curve_2& cv) const + Point_2 vertical_ray_shoot_2(const Point_2& pt, const X_monotone_curve_2& cv) + const { - if (cv.is_vertical()) - { - Alg_kernel k; - if (!k.less_y_2_object()(cv.left(), pt)) + if (cv.is_vertical()) { + auto alg_kernel = m_geometry_traits_2->alg_kernel(); + if (! alg_kernel->less_y_2_object()(cv.left(), pt)) return cv.left(); - else - { - CGAL_assertion(k.less_y_2_object()(cv.right(), pt)); + else { + CGAL_assertion(alg_kernel->less_y_2_object()(cv.right(), pt)); return cv.right(); } } - else - return cv.point_at_x(pt); + else return m_geometry_traits_2->point_at_x(cv, pt); } - template - OutputIterator add_curve_to_output(const Curve_2& c, OutputIterator oi) const - { + template + OutputIterator add_curve_to_output(const Curve_2& c, OutputIterator oi) const { Object objs[2]; Object* p_obj = this->make_x_monotone_2_object()(c, objs); - for(Object* o = objs; o != p_obj; ++o) - { + for(Object* o = objs; o != p_obj; ++o) { X_monotone_curve_2 cv; - if(assign(cv, *o)) - { - *oi++ = make_object(Intersection_curve(cv, 1)); - } - else - { + if(assign(cv, *o)) *oi++ = make_object(Intersection_curve(cv, 1)); + else { Point_2 pt; CGAL_assertion(assign(pt, *o)); assign(pt, *o); @@ -1242,45 +1133,54 @@ public: return oi; } + typedef std::shared_ptr Shared_geometry_traits_2; + /*! Default constructor. */ - Env_sphere_traits_3() : m_is_lower(true) + Env_sphere_traits_3() : + m_is_lower(true), + m_geometry_traits_2(new Traits_2) {} + /*! Constructor from a conic 2D geometry traits. */ + Env_sphere_traits_3(Shared_geometry_traits_2 geometry_traits_2) : + m_is_lower(true), + m_geometry_traits_2(geometry_traits_2) + {} + + /*! Obtain the undelying conic 2D geometry traits. + */ + const Shared_geometry_traits_2 geometry_traits_2() const + { return m_geometry_traits_2; } + protected: mutable bool m_is_lower; + +private: + //! The conic geometry-traits. + const Shared_geometry_traits_2 m_geometry_traits_2; }; /*! * Compare two spheres: first compare their center points in an * xyz-lexicographic order, then by their radii. */ -template -bool operator< (const CGAL::Sphere_3 & a, - const CGAL::Sphere_3 & b) +template +bool operator<(const CGAL::Sphere_3& a, const CGAL::Sphere_3& b) { - Kernel k; + Kernel k; Comparison_result res = k.compare_xyz_3_object()(a.center(), b.center()); - - if (res == EQUAL) - { - res = CGAL::compare (a.squared_radius(), b.squared_radius()); - } - + if (res == EQUAL) res = CGAL::compare (a.squared_radius(), b.squared_radius()); return (res == SMALLER); } /*! * Compare two spheres for equality. */ -template +template bool operator== (const typename Kernel::Sphere_3& a, - const typename Kernel::Sphere_3& b) -{ - Kernel k; - - if (! k.equal_3_object() (a.center(), b.center())) - return (false); - + const typename Kernel::Sphere_3& b) { + Kernel k; + if (! k.equal_3_object() (a.center(), b.center())) return (false); return (CGAL::compare (a.squared_radius(), b.squared_radius()) == EQUAL); } diff --git a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h index 3c7b05082b9..37873145733 100644 --- a/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h +++ b/GraphicsView/include/CGAL/Qt/Basic_viewer_qt.h @@ -1816,8 +1816,8 @@ protected: namespace CGAL { - template - void draw(const T&, const char* ="", bool=false) + template + void draw(T...) { std::cerr<<"Impossible to draw, CGAL_USE_BASIC_VIEWER is not defined."< -class Exact_offset_base_2 -{ +template +class Exact_offset_base_2 { private: - typedef Traits_ Traits_2; // Rational kernel types: @@ -48,7 +46,6 @@ protected: typedef Rational Basic_NT; private: - // Algebraic kernel types: typedef typename Traits_2::Alg_kernel Alg_kernel; typedef typename Alg_kernel::FT Algebraic; @@ -63,7 +60,6 @@ private: typedef CGAL::Gps_traits_2 Gps_traits_2; protected: - typedef CGAL::Polygon_2 Polygon_2; typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; @@ -75,21 +71,15 @@ private: typedef typename Polygon_2::Vertex_circulator Vertex_circulator; protected: - typedef Arr_labeled_traits_2 Labeled_traits_2; - typedef typename Labeled_traits_2::X_monotone_curve_2 Labeled_curve_2; public: - /*! Default constructor. */ - Exact_offset_base_2 () - {} + Exact_offset_base_2() {} protected: - - /*! - * Compute the curves that constitute the offset of a simple polygon by a + /*! Compute the curves that constitute the offset of a simple polygon by a * given radius. * \param pgn The polygon. * \param orient The orientation to traverse the vertices. @@ -99,16 +89,16 @@ protected: * \pre The value type of the output iterator is Labeled_curve_2. * \return A past-the-end iterator for the holes container. */ - template - OutputIterator _offset_polygon (const Polygon_2& pgn, - CGAL::Orientation orient, - const Rational& r, - unsigned int cycle_id, - OutputIterator oi) const + template + OutputIterator _offset_polygon(const Polygon_2& pgn, + CGAL::Orientation orient, + const Rational& r, + unsigned int cycle_id, + OutputIterator oi) const { // Prepare circulators over the polygon vertices. - const bool forward = (pgn.orientation() == orient); - Vertex_circulator first, curr, next; + const bool forward = (pgn.orientation() == orient); + Vertex_circulator first, curr, next; first = pgn.vertices_circulator(); curr = first; @@ -116,38 +106,33 @@ protected: // Traverse the polygon vertices and edges and construct the arcs that // constitute the single convolution cycle. - Alg_kernel alg_ker; - typename Alg_kernel::Equal_2 f_equal = alg_ker.equal_2_object(); + const Rational sqr_r = CGAL::square (r); + Rational x1, y1; // The source of the current edge. + Rational x2, y2; // The target of the current edge. + Rational delta_x, delta_y; // (x2 - x1) and (y2 - y1), resp. + Algebraic len; // The length of the current edge. + Algebraic trans_x, trans_y; // The translation vector. + Alg_point_2 op1, op2; // The edge points of the offset edge. + Alg_point_2 first_op; // The first offset point. + Algebraic a, b, c; - Nt_traits nt_traits; - const Rational sqr_r = CGAL::square (r); - const Algebraic alg_r = nt_traits.convert (r); - Rational x1, y1; // The source of the current edge. - Rational x2, y2; // The target of the current edge. - Rational delta_x, delta_y; // (x2 - x1) and (y2 - y1), resp. - Algebraic len; // The length of the current edge. - Algebraic trans_x, trans_y; // The translation vector. - Alg_point_2 op1, op2; // The edge points of the offset edge. - Alg_point_2 first_op; // The first offset point. - Algebraic a, b, c; + unsigned int curve_index(0); + std::list xobjs; - unsigned int curve_index = 0; - Traits_2 traits; - std::list xobjs; - std::list::iterator xobj_it; - typename Traits_2::Make_x_monotone_2 - f_make_x_monotone = traits.make_x_monotone_2_object(); - Curve_2 arc; - X_monotone_curve_2 xarc; - bool assign_success; + Traits_2 traits; + auto nt_traits = traits.nt_traits(); + const Algebraic alg_r = nt_traits->convert(r); + auto f_make_x_monotone = traits.make_x_monotone_2_object(); - do - { + auto alg_ker = traits.alg_kernel(); + auto f_equal = alg_ker->equal_2_object(); + + bool assign_success; + + do { // Get a circulator for the next vertex (in the proper orientation). - if (forward) - ++next; - else - --next; + if (forward) ++next; + else --next; // Compute the vector v = (delta_x, delta_y) of the current edge, // and compute the edge length ||v||. @@ -158,8 +143,8 @@ protected: delta_x = x2 - x1; delta_y = y2 - y1; - len = nt_traits.sqrt (nt_traits.convert (CGAL::square (delta_x) + - CGAL::square (delta_y))); + len = nt_traits->sqrt(nt_traits->convert(CGAL::square(delta_x) + + CGAL::square(delta_y))); // The angle theta between the vector v and the x-axis is given by: // @@ -174,45 +159,39 @@ protected: // // trans_x = r*cos(alpha - PI/2) = r*sin(alpha) // trans_y = r*sin(alpha - PI/2) = -r*cos(alpha) - trans_x = nt_traits.convert (r * delta_y) / len; - trans_y = nt_traits.convert (-r * delta_x) / len; + trans_x = nt_traits->convert(r * delta_y) / len; + trans_y = nt_traits->convert(-r * delta_x) / len; // Construct the first offset vertex, which corresponds to the // source vertex of the current polygon edge. - op1 = Alg_point_2 (nt_traits.convert (x1) + trans_x, - nt_traits.convert (y1) + trans_y); + op1 = Alg_point_2(nt_traits->convert(x1) + trans_x, + nt_traits->convert(y1) + trans_y); - if (curr == first) - { + if (curr == first) { // This is the first edge we visit -- store op1 for future use. first_op = op1; } - else - { - if (! f_equal (op2, op1)) - { + else { + if (! f_equal (op2, op1)) { // Connect op2 (from the previous iteration) and op1 with a circular // arc, whose supporting circle is (x1, x2) with radius r. - arc = Curve_2 (Rat_circle_2 (*curr, sqr_r), - CGAL::COUNTERCLOCKWISE, - op2, op1); + auto ctr_cv = traits.construct_curve_2_object(); + Curve_2 arc = ctr_cv(Rat_circle_2 (*curr, sqr_r), + CGAL::COUNTERCLOCKWISE, op2, op1); // Subdivide the arc into x-monotone subarcs and append them to the // convolution cycle. xobjs.clear(); - f_make_x_monotone (arc, std::back_inserter(xobjs)); + f_make_x_monotone(arc, std::back_inserter(xobjs)); - for (xobj_it = xobjs.begin(); xobj_it != xobjs.end(); ++xobj_it) - { - assign_success = CGAL::assign (xarc, *xobj_it); + for (auto xobj_it = xobjs.begin(); xobj_it != xobjs.end(); ++xobj_it) { + X_monotone_curve_2 xarc; + assign_success = CGAL::assign(xarc, *xobj_it); CGAL_assertion (assign_success); CGAL_USE(assign_success); - *oi = Labeled_curve_2 (xarc, - X_curve_label (xarc.is_directed_right(), - cycle_id, - curve_index)); - ++oi; + *oi++ = Labeled_curve_2(xarc, X_curve_label(xarc.is_directed_right(), + cycle_id, curve_index)); curve_index++; } } @@ -220,25 +199,21 @@ protected: // Construct the second offset vertex, which corresponds to the // target vertex of the current polygon edge. - op2 = Alg_point_2 (nt_traits.convert (x2) + trans_x, - nt_traits.convert (y2) + trans_y); + op2 = Alg_point_2(nt_traits->convert(x2) + trans_x, + nt_traits->convert(y2) + trans_y); // The equation of the line connecting op1 and op2 is given by: // // (y1 - y2)*x + (x2 - x1)*y + (r*len - y1*x2 - x1*y2) = 0 // - a = nt_traits.convert (-delta_y); - b = nt_traits.convert (delta_x); - c = alg_r*len - nt_traits.convert (y1*x2 - x1*y2); + a = nt_traits->convert(-delta_y); + b = nt_traits->convert(delta_x); + c = alg_r*len - nt_traits->convert(y1*x2 - x1*y2); - xarc = X_monotone_curve_2 (a, b, c, - op1, op2); - - *oi = Labeled_curve_2 (xarc, - X_curve_label (xarc.is_directed_right(), - cycle_id, - curve_index)); - ++oi; + auto ctr_xcv = traits.construct_x_monotone_curve_2_object(); + X_monotone_curve_2 xarc = ctr_xcv(a, b, c, op1, op2); + *oi++ = Labeled_curve_2(xarc, X_curve_label(xarc.is_directed_right(), + cycle_id, curve_index)); curve_index++; // Proceed to the next polygon vertex. @@ -246,42 +221,38 @@ protected: } while (curr != first); - if (! f_equal (op2, first_op)) - { + if (! f_equal (op2, first_op)) { // Close the convolution cycle by creating the final circular arc, // centered at the first vertex. - arc = Curve_2 (Rat_circle_2 (*first, sqr_r), - CGAL::COUNTERCLOCKWISE, - op2, first_op); + auto ctr_cv = traits.construct_curve_2_object(); + Curve_2 arc = ctr_cv(Rat_circle_2 (*first, sqr_r), + CGAL::COUNTERCLOCKWISE, op2, first_op); // Subdivide the arc into x-monotone subarcs and append them to the // convolution cycle. - bool is_last; + bool is_last; xobjs.clear(); - f_make_x_monotone (arc, std::back_inserter(xobjs)); + f_make_x_monotone(arc, std::back_inserter(xobjs)); - xobj_it = xobjs.begin(); - while (xobj_it != xobjs.end()) - { - assign_success = CGAL::assign (xarc, *xobj_it); + auto xobj_it = xobjs.begin(); + while (xobj_it != xobjs.end()) { + X_monotone_curve_2 xarc; + assign_success = CGAL::assign(xarc, *xobj_it); CGAL_assertion (assign_success); CGAL_USE(assign_success); ++xobj_it; is_last = (xobj_it == xobjs.end()); - *oi = Labeled_curve_2 (xarc, - X_curve_label (xarc.is_directed_right(), - cycle_id, - curve_index, - is_last)); - ++oi; + *oi++ = Labeled_curve_2(xarc, X_curve_label(xarc.is_directed_right(), + cycle_id, curve_index, + is_last)); curve_index++; } } - return (oi); + return oi; } }; diff --git a/Surface_sweep_2/include/CGAL/Surface_sweep_2.h b/Surface_sweep_2/include/CGAL/Surface_sweep_2.h index 16c2fdedb38..82146be11f5 100644 --- a/Surface_sweep_2/include/CGAL/Surface_sweep_2.h +++ b/Surface_sweep_2/include/CGAL/Surface_sweep_2.h @@ -222,7 +222,7 @@ protected: * \param c2 The second curve. */ void _create_intersection_point(const Point_2& xp, - unsigned int mult, + Multiplicity mult, Subcurve*& c1, Subcurve*& c2); }; diff --git a/Surface_sweep_2/include/CGAL/Surface_sweep_2/Surface_sweep_2_impl.h b/Surface_sweep_2/include/CGAL/Surface_sweep_2/Surface_sweep_2_impl.h index 52f2dde71b1..63ad21b4bc1 100644 --- a/Surface_sweep_2/include/CGAL/Surface_sweep_2/Surface_sweep_2_impl.h +++ b/Surface_sweep_2/include/CGAL/Surface_sweep_2/Surface_sweep_2_impl.h @@ -773,7 +773,7 @@ void Surface_sweep_2::_intersect(Subcurve* c1, Subcurve* c2, // template void Surface_sweep_2::_create_intersection_point(const Point_2& xp, - unsigned int multiplicity, + Multiplicity multiplicity, Subcurve*& c1, Subcurve*& c2) { diff --git a/Surface_sweep_2/include/CGAL/Surface_sweep_2_algorithms.h b/Surface_sweep_2/include/CGAL/Surface_sweep_2_algorithms.h index f18f1018db3..62d6d31aaec 100644 --- a/Surface_sweep_2/include/CGAL/Surface_sweep_2_algorithms.h +++ b/Surface_sweep_2/include/CGAL/Surface_sweep_2_algorithms.h @@ -62,8 +62,8 @@ struct Default_arr_traits -struct Default_arr_traits > +struct Default_arr_traits > { typedef CGAL::Arr_conic_traits_2 Traits; diff --git a/Surface_sweep_2/test/Surface_sweep_2/test_sweep_conic.cpp b/Surface_sweep_2/test/Surface_sweep_2/test_sweep_conic.cpp index 45ae9544851..90866e1a98d 100644 --- a/Surface_sweep_2/test/Surface_sweep_2/test_sweep_conic.cpp +++ b/Surface_sweep_2/test/Surface_sweep_2/test_sweep_conic.cpp @@ -40,13 +40,15 @@ typedef std::list CurveList; typedef std::list PointList; typedef PointList::iterator PointListIter; - /*! Conic reader */ template class Conic_reader { +private: + Traits_2 m_traits; + public: - int ReadData(const char* filename, CurveList& curves, CGAL::Bbox_2& bbox) - { + int read_data(const char* filename, CurveList& curves, CGAL::Bbox_2& bbox, + const Traits& traits) { Curve_2 cv; char dummy[256]; @@ -58,10 +60,10 @@ public: int count; inp >> count; inp.getline(dummy, sizeof(dummy)); - for (int i = 0; i < count; i++) { - ReadCurve(inp, cv); + for (int i = 0; i < count; ++i) { + read_curve(inp, cv); curves.push_back(cv); - CGAL::Bbox_2 curve_bbox = cv.bbox(); + CGAL::Bbox_2 curve_bbox = traits.construct_bbox_2_object()(cv); if (i == 0) bbox = curve_bbox; else bbox = bbox + curve_bbox; } @@ -69,50 +71,47 @@ public: return 0; } - void ReadCurve(std::ifstream & is, Curve_2 & cv) - { + void read_curve(std::ifstream& is, Curve_2& cv) { + auto ctr_cv = m_traits.construct_curve_2_object(); + // Read a line from the input file. char one_line[128]; - skip_comments (is, one_line); + skip_comments(is, one_line); std::string stringvalues(one_line); - std::istringstream str_line (stringvalues, std::istringstream::in); + std::istringstream str_line(stringvalues, std::istringstream::in); // Get the arc type. // Supported types are: 'f' - Full ellipse (or circle). // 'e' - Elliptic arc (or circular arc). // 's' - Line segment. - char type; - bool is_circle = false; // Is this a circle. + bool is_circle(false); // Is this a circle. Rat_circle_2 circle; - Rational r, s, t, u, v, w; // The conic coefficients. + Rational r, s, t, u, v, w; // The conic coefficients. + char type; str_line >> type; // An ellipse (full ellipse or a partial ellipse): - if (type == 'f' || type == 'F' || type == 'e' || type == 'E') - { + if (type == 'f' || type == 'F' || type == 'e' || type == 'E') { // Read the ellipse (using the format "a b x0 y0"): // // x - x0 2 y - y0 2 // ( -------- ) + ( -------- ) = 1 // a b // - int a, b, x0, y0; - + int a, b, x0, y0; str_line >> a >> b >> x0 >> y0; - Rational a_sq = Rational(a*a); - Rational b_sq = Rational(b*b); + Rational a_sq = Rational(a*a); + Rational b_sq = Rational(b*b); - if (a == b) - { + if (a == b) { is_circle = true; - circle = Rat_circle_2 (Rat_point_2 (Rational(x0), Rational(y0)), - Rational(a*b)); + circle = + Rat_circle_2(Rat_point_2(Rational(x0), Rational(y0)), Rational(a*b)); } - else - { + else { r = b_sq; s = a_sq; t = 0; @@ -121,54 +120,43 @@ public: w = Rational(x0*x0*b_sq + y0*y0*a_sq - a_sq*b_sq); } - if (type == 'f' || type == 'F') - { + if (type == 'f' || type == 'F') { // Create a full ellipse (or circle). - if (is_circle) - cv = Curve_2 (circle); - else - cv = Curve_2 (r, s, t, u, v, w); + cv = (is_circle) ? ctr_cv(circle) : ctr_cv(r, s, t, u, v, w); + return; } - else - { - // Read the endpointd of the arc. - int x1, y1, x2, y2; - str_line >> x1 >> y1 >> x2 >> y2; + // Read the endpointd of the arc. + int x1, y1, x2, y2; + str_line >> x1 >> y1 >> x2 >> y2; - Point_2 source = Point_2 (Algebraic(x1), Algebraic(y1)); - Point_2 target = Point_2 (Algebraic(x2), Algebraic(y2)); + Point_2 source = Point_2 (Algebraic(x1), Algebraic(y1)); + Point_2 target = Point_2 (Algebraic(x2), Algebraic(y2)); - // Create the arc. Note that it is always clockwise oriented. - if (is_circle) - cv = Curve_2 (circle, - CGAL::CLOCKWISE, - source, target); - else - cv = Curve_2 (r, s, t, u, v, w, - CGAL::CLOCKWISE, - source, target); - } + // Create the arc. Note that it is always clockwise oriented. + cv = (is_circle) ? + ctr_cv(circle, CGAL::CLOCKWISE, source, target) : + ctr_cv(r, s, t, u, v, w, CGAL::CLOCKWISE, source, target); + return; } - else if (type == 's' || type == 'S') - { - // Read a segment, given by its endpoints (x1,y1) and (x2,y2); - int x1, y1, x2, y2; + if (type == 's' || type == 'S') { + // Read a segment, given by its endpoints (x1,y1) and (x2,y2); + int x1, y1, x2, y2; str_line >> x1 >> y1 >> x2 >> y2; // Create the segment. - Rat_point_2 source = Rat_point_2 (Rational(x1), Rational(y1)); - Rat_point_2 target = Rat_point_2 (Rational(x2), Rational(y2)); + Rat_point_2 source = Rat_point_2(Rational(x1), Rational(y1)); + Rat_point_2 target = Rat_point_2(Rational(x2), Rational(y2)); - cv = Curve_2(Rat_segment_2 (source, target)); + cv = ctr_cv(Rat_segment_2(source, target)); + return; } - return; + std::cerr << "Invalid type (" << type << ")" << std::endl; } - void skip_comments( std::ifstream& is, char* one_line ) - { + void skip_comments( std::ifstream& is, char* one_line) { while( !is.eof() ){ is.getline( one_line, 128 ); if( one_line[0] != '#' ){ @@ -181,42 +169,39 @@ public: //--------------------------------------------------------------------------- // The main: // -int main (int argc, char** argv) -{ +int main(int argc, char* argv[]) { bool verbose = false; // Define a test objects to read the conic arcs from it. - if (argc<2) - { + if (argc<2) { std::cerr << "Usage: Conic_traits_test " << std::endl; exit(1); } + Traits_2 traits; CGAL::Bbox_2 bbox; CurveList curves; Conic_reader reader; - reader.ReadData(argv[1], curves, bbox); + reader.read_data(argv[1], curves, bbox, traits); // run the sweep std::list mylist; CGAL::compute_subcurves(curves.begin(), curves.end(), - std::back_inserter(mylist), false); + std::back_inserter(mylist), false); PointList point_list_with_ends; CGAL::compute_intersection_points(curves.begin(), curves.end(), - std::back_inserter(point_list_with_ends), true); + std::back_inserter(point_list_with_ends), + true); std::size_t point_count_with_ends_calculated = point_list_with_ends.size(); // generate the string for the output std::stringstream out1; - for ( std::list::iterator iter = mylist.begin() ; - iter != mylist.end() ; ++iter ) - { + for (auto iter = mylist.begin(); iter != mylist.end(); ++iter) out1 << *iter << "\n"; - } // read the output from the file std::stringstream out2; @@ -226,12 +211,10 @@ int main (int argc, char** argv) std::ifstream in_file(argv[1]); in_file >> count; in_file.getline(buf, 1024); // to get rid of the new line - for ( int i = 0 ; i < count ; i++ ) { - in_file.getline(buf, 1024); - } + for (int i = 0 ; i < count ; ++i) in_file.getline(buf, 1024); in_file >> count; in_file.getline(buf, 1024); // to get rid of the new line - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; ++i) { in_file.getline(buf, 1024); out2 << buf << "\n"; } @@ -239,31 +222,28 @@ int main (int argc, char** argv) in_file >> point_count_with_ends_from_file; in_file.close(); - if ( verbose ) - { + if (verbose) { std::cout << "Result: \n" << mylist.size() << "\n"; - for ( std::list::iterator i = mylist.begin() ; - i != mylist.end() ; ++i ) - { + for (auto i = mylist.begin(); i != mylist.end() ; ++i) std::cout << *i << "\n"; - } } std::string calculated = out1.str(); std::string infile = out2.str(); - if ( infile == calculated ) { - if ( point_count_with_ends_from_file != - point_count_with_ends_calculated ) { + if (infile == calculated) { + if (point_count_with_ends_from_file != point_count_with_ends_calculated) { std::cout << "number of intersection points (with ends):" << point_count_with_ends_calculated << ". Should be " << point_count_with_ends_from_file << "\n"; std::cout << argv[1] << " Error\n"; return -1; - } else { + } + else { std::cout << argv[1] << " OK!\n"; } - } else { + } + else { std::cout << argv[1] << " Error\n"; std::cout << "\ncalculated:\n"; std::cout << calculated << std::endl;