// Copyright (c) 1997
// 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: https://github.com/CGAL/cgal/blob/v6.1.1/HalfedgeDS/include/CGAL/halfedgeDS_cut_component.h $
// $Id: include/CGAL/halfedgeDS_cut_component.h 08b27d3db14 $
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Lutz Kettner  <kettner@mpi-sb.mpg.de>

// Cuts out a piece of a halfedge data structure defined by a predicate.


#ifndef CGAL_HALFEDGEDS_CUT_COMPONENT_H
#define CGAL_HALFEDGEDS_CUT_COMPONENT_H 1

#include <CGAL/disable_warnings.h>

#include <CGAL/basic.h>
#include <CGAL/HalfedgeDS_decorator.h>

namespace CGAL {


template < class HDS, class Predicate >
typename HDS::Halfedge_handle
halfedgeDS_cut_component( HDS&                           hds,
                          typename HDS::Halfedge_handle  h,
                          Predicate                      pred,
                          typename HDS::Halfedge_handle& cut_piece)
// Cuts out a piece of a halfedge data structure for which the predicate
// `pred' is true for the vertices.
// The edge-vertex graph of the piece has to be a connected component.
// The remaining piece gets a new boundary. Returns a border halfedge of
// the new boundary on the remaining piece. Assigns a halfedge of the
// cut outpiece to `cut_piece'.
// The geometry for the vertices
// on the boundary and the hole have to be taken care of after this
// function call. The cut-out piece can be deleted with the member
// function erase_connected_component of the decorator class. It can
// technically happen that only an isolated vertex would remain in the
// cut out piece, in which case a dummy halfedge pair and vertex will be
// created to keep this vertex representable in the halfedge data structure.
// Precondition: pred( h->vertex()) && ! pred( h->opposite()->vertex()).
{
    typedef typename HDS::Vertex_handle    Vertex_handle;
    typedef typename HDS::Halfedge_handle  Halfedge_handle;
    typedef typename HDS::Face_handle      Face_handle;
    typedef typename HDS::Vertex           Vertex;
    typedef typename HDS::Halfedge         Halfedge;
    typedef typename HDS::Face             Face;
    CGAL::HalfedgeDS_decorator<HDS> D(hds);

    CGAL_precondition( D.is_valid(false,3));
    CGAL_precondition( pred( h->vertex()));
    CGAL_precondition( ! pred( h->opposite()->vertex()));

    Halfedge_handle start = h;
    Halfedge_handle hnew;
    Halfedge_handle hlast;
    while (true) {
        // search re-entry point
        Halfedge_handle g = h;
        while ( pred( g->next()->vertex())) {
            g = g->next();
            // create border edges around cap
            D.set_face( g, Face_handle());
        }
        if ( hnew == Halfedge_handle()) {
            // first edge, special case
            CGAL_assertion( g->next() != h && g->next()->opposite() != h);
            Halfedge_handle gnext = g->next()->opposite();
            D.remove_tip( g);
            Vertex_handle v = D.vertices_push_back( Vertex());
            D.close_tip( gnext, v);
            hnew = hds.edges_push_back( Halfedge(), Halfedge());
            hlast = hnew->opposite();
            D.insert_tip( hlast, gnext);
            D.set_face( hnew, D.get_face( gnext));
            D.set_face_halfedge( hnew);
            h = g;
            D.set_vertex_halfedge( h);
        } else { // general case and last case
            Halfedge_handle gnext = g->next()->opposite();
            if ( gnext == start && gnext == g) {
                // last edge, special case of isolated vertex.
                // Create dummy edge and dummy vertex and attach it to g
                g = hds.edges_push_back( Halfedge(), Halfedge());
                D.insert_tip( g, gnext);
                D.close_tip(g->opposite(), D.vertices_push_back(Vertex()));
                D.set_vertex_halfedge( g);
                D.set_vertex_halfedge( g->opposite());
            }
            D.remove_tip( g);
            Vertex_handle v = D.vertices_push_back( Vertex());
            D.close_tip( hnew, v);
            D.insert_tip( gnext, hnew);
            hnew = hds.edges_push_back( Halfedge(), Halfedge());
            D.insert_tip( hnew->opposite(), gnext);
            D.set_face( hnew, D.get_face( gnext));
            D.set_face_halfedge( hnew);
            h = g;
            D.set_vertex_halfedge( h);
            if ( gnext == start) {
                // last edge, special
                D.insert_tip( hnew, hlast);
                break;
            }
        }
    } // while(true)
    Face_handle fnew = D.faces_push_back( Face());
    D.set_face_in_face_loop( hlast, fnew);
    D.set_face_halfedge( hlast);
    cut_piece = h;
    CGAL_postcondition( D.is_valid(false,3));
    return hlast;
}

template < class HDS, class Predicate >
typename HDS::Halfedge_handle
halfedgeDS_cut_component( HDS&                           hds,
                          typename HDS::Halfedge_handle  h,
                          Predicate                      pred)
// Same function as above, but deletes the cut out piece immediately.
{
    typedef typename HDS::Halfedge_handle  Halfedge_handle;
    CGAL::HalfedgeDS_decorator<HDS> D(hds);

    CGAL_precondition( D.is_valid(false,3));
    CGAL_precondition( pred( h->vertex()));
    CGAL_precondition( ! pred( h->opposite()->vertex()));
    Halfedge_handle cut_piece;
    Halfedge_handle hnew = halfedgeDS_cut_component( hds, h, pred, cut_piece);
    D.erase_connected_component( cut_piece);
    CGAL_postcondition( D.is_valid(false,3));
    return hnew;
}

} //namespace CGAL

#include <CGAL/enable_warnings.h>

#endif // CGAL_HALFEDGEDS_CUT_COMPONENT_H //
// EOF //
