// Copyright (c) 2000 Max-Planck-Institute Saarbruecken (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Susan Hert #ifndef CGAL_GREENE_APPROX_H #define CGAL_GREENE_APPROX_H #include #include #include #include #include #include #include #include #include #include #include #include // These things should be constant: // front is where you add things to a chain // top chain shares its back with front (top) of stack // bottom chain shares its back with the back (bottom) of the stack // bottom of the stack has lower y value than top. // ==> chain direction is cw, make ccw polygon from front to back // and chain direction is ccw, make ccw polygon from back to front namespace CGAL { template bool is_adjacent_to(BidirectionalCirculator new_point_ref, BidirectionalCirculator old_point_ref) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "is_adjacent_to: new_point " << *new_point_ref << " old_point " << *old_point_ref << std::endl; #endif // find the old point in original list of points if (*new_point_ref == *(++old_point_ref)) return true; // check ccw #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "is_adjacent_to: next point is " << *old_point_ref << std::endl; #endif old_point_ref--; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "is_adjacent_to: old_point is " << *old_point_ref << std::endl; #endif if (*new_point_ref == *(--old_point_ref)) return true; // check cw #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "is_adjacent_to: previous points is " << *old_point_ref << std::endl; #endif return false; } // erases vertices in the range [first, last) (counterclockwise) template void erase_vertices(BidirectionalCirculator first, BidirectionalCirculator last, Polygon& polygon, bool& update_required) { typedef typename Polygon::iterator Vertex_iterator; Vertex_iterator it = polygon.begin(); Vertex_iterator temp_it; update_required = false; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "before erasing polygon is "; for (Vertex_iterator v = polygon.begin(); v != polygon.end(); v++) { std::cout << " " << *v; } std::cout << std::endl; std::cout << "erasing from " << *first << " to " << *last << std::endl; #endif it = first.current_iterator(); CGAL_partition_assertion (it != polygon.end()); while ( (it != polygon.end()) && (*it != *last) ) { while ( (it != polygon.end()) && (*it != *last) ) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "erase_vertices: erasing " << *it << std::endl; #endif temp_it = it; // when the beginning vertex of the polygon is deleted, all the // circulators for that polygon become invalid and must be updated. if (it == polygon.begin()) update_required = true; it++; #ifdef CGAL_GREENE_APPROX_DEBUG if (it != polygon.end()) std::cout << "erase_vertices: next vertex is " << *it << std::endl; #endif polygon.erase(temp_it); } if (it == polygon.end()) it = polygon.begin(); } // Yes, both loops here are necessary in case the range of vertices // includes the last and first points. } template void visible(Polygon& polygon, const BidirectionalCirculator& new_point_ref, Circ_pair< BidirectionalCirculator >& stack, Circ_pair< BidirectionalCirculator >& bottom_chain, Circ_pair< BidirectionalCirculator >& top_chain, OutputIterator& result, const Traits& traits) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: stack.back " << *stack.back() << " stack.before_back " << *stack.before_back() << " new_point_ref " << *new_point_ref << std::endl; #endif typedef typename Traits::Point_2 Point_2; typedef typename Traits::Left_turn_2 Left_turn_2; Left_turn_2 left_turn = traits.left_turn_2_object(); Turn_reverser right_turn(left_turn); if (((bottom_chain.direction() == CLOCKWISE) && right_turn(*stack.back(), *stack.before_back(), *new_point_ref)) || ((bottom_chain.direction() == COUNTERCLOCKWISE) && left_turn(*stack.back(), *stack.before_back(), *new_point_ref))) { typedef typename Traits::Polygon_2 new_Polygon_2; new_Polygon_2 new_polygon; bool done = false; bool big_angle_at_stack = false; bool is_visible = false; bool update_required; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: bottom_chain.front " << *bottom_chain.front() << std::endl; #endif do { new_Polygon_2 new_polygon; stack.pop_back(); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: stack.back " << *stack.back() << std::endl; #endif if (bottom_chain.direction() == CLOCKWISE) { std::copy(bottom_chain.front(), stack.before_back(), std::back_inserter(new_polygon)); erase_vertices(bottom_chain.before_front(), stack.back(), polygon, update_required); } else { std::copy(stack.back(), bottom_chain.after_front(), std::back_inserter(new_polygon)); erase_vertices(bottom_chain.back(), bottom_chain.front(), polygon, update_required); } if (!is_degenerate_polygon_2(new_polygon.vertices_begin(), new_polygon.vertices_end(), traits)) { *result = new_polygon; result++; } bottom_chain.push_back(stack.back()); if (stack.back() == stack.front()) // form new stack with previous { // point and old stack top // (still on stack) done = true; typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object(); if (less_yx(*(stack.front()),*bottom_chain.front())) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: reversing stack and swapping chains " << std::endl; #endif stack.push_front(bottom_chain.front()); // reverse stack direction stack.change_dir(); bottom_chain = top_chain; // swap chains top_chain.initialize(stack.front()); top_chain.change_dir(); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: stack is now " << *stack.back() << " " << *stack.front() << " dir " << int(stack.direction()) << std::endl; std::cout << "visible: bottom_chain is now " << *bottom_chain.back() << " " << *bottom_chain.front() << " dir " << int(bottom_chain.direction()) << std::endl; std::cout << "visible: top_chain is now " << *top_chain.back() << " " << *top_chain.front() << " dir " << int(top_chain.direction()) << std::endl; #endif } else { stack.push_back(bottom_chain.front()); bottom_chain.push_back(bottom_chain.front()); } } else // stack size must be >= 2 here { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "visible: stack.before_back " << *stack.before_back() << std::endl; #endif // angle at stack > 180 if (bottom_chain.direction() == CLOCKWISE) big_angle_at_stack = right_turn(*bottom_chain.front(), *stack.back(), *stack.before_back()); else big_angle_at_stack = left_turn(*bottom_chain.front(), *stack.back(), *stack.before_back()); if (bottom_chain.direction() == CLOCKWISE) is_visible = !right_turn(*stack.back(), *stack.before_back(), *new_point_ref); else is_visible = !left_turn(*stack.back(), *stack.before_back(), *new_point_ref); // point can see stack bottom } } while (!done && !big_angle_at_stack && !is_visible); if (big_angle_at_stack) // previous point is placed on bottom of stack { stack.push_back(bottom_chain.front()); bottom_chain.push_back(bottom_chain.front()); } } } template void stack_extend(Polygon& polygon, BidirectionalCirculator& point_ref, Circ_pair< BidirectionalCirculator >& stack, Circ_pair< BidirectionalCirculator >& top_chain, OutputIterator& result, const Traits& traits) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "stack_extend" << std::endl; std::cout << "stack_extend: stack.before_front() " << *stack.before_front() << " stack.front " << *stack.front() << " point_ref " << *point_ref << std::endl; #endif typedef typename Traits::Point_2 Point_2; typedef typename Traits::Left_turn_2 Left_turn_2; Left_turn_2 left_turn = traits.left_turn_2_object(); Turn_reverser right_turn(left_turn); if (((stack.direction() == COUNTERCLOCKWISE) && right_turn(*stack.before_front(), *stack.front(), *point_ref)) || ((stack.direction() == CLOCKWISE) && left_turn(*stack.before_front(), *stack.front(), *point_ref))) { // new stack top becomes new first (and only) element of top chain stack.push_front(point_ref); top_chain.initialize(point_ref); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "stack_extend: top_chain.front " << *top_chain.front() << std::endl; #endif } else change_top_chain(polygon, point_ref, stack, top_chain, result, traits); } template void change_top_chain(Polygon& polygon, BidirectionalCirculator new_point_ref, Circ_pair< BidirectionalCirculator >& stack, Circ_pair< BidirectionalCirculator >& top_chain, OutputIterator& result, const Traits& traits) { BidirectionalCirculator next_point_ref = new_point_ref; if (top_chain.direction() == COUNTERCLOCKWISE) next_point_ref++; else next_point_ref--; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_top_chain: top_chain.front " << *top_chain.front() << " new_point_ref " << *new_point_ref << " next_point_ref " << *next_point_ref << std::endl; #endif typedef typename Traits::Point_2 Point_2; typedef typename Traits::Left_turn_2 Left_turn_2; Left_turn_2 left_turn = traits.left_turn_2_object(); Turn_reverser right_turn(left_turn); if (((top_chain.direction() == COUNTERCLOCKWISE) && !right_turn(*top_chain.front(), *new_point_ref, *next_point_ref)) || ((top_chain.direction() == CLOCKWISE) && !left_turn(*top_chain.front(), *new_point_ref, *next_point_ref))) { top_chain.push_front(new_point_ref); } else { typedef typename Traits::Polygon_2 new_Polygon_2; BidirectionalCirculator old_top_ref; bool done = false; bool big_angle_at_stack = false; bool small_angle_at_point = false; bool update_required; // pop off element already on top chain old_top_ref = stack.front(); stack.pop_front(); do { new_Polygon_2 new_polygon; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_top_chain: stack.front " << *stack.front() << std::endl; #endif if (top_chain.direction() == COUNTERCLOCKWISE) { std::copy(stack.front(), next_point_ref, std::back_inserter(new_polygon)); erase_vertices(old_top_ref, new_point_ref, polygon, update_required); } else { std::copy(new_point_ref, stack.before_front(), std::back_inserter(new_polygon)); typedef typename Polygon::iterator iterator; erase_vertices(top_chain.front(), stack.front(), polygon, update_required); top_chain.push_front(stack.front()); } if (!is_degenerate_polygon_2(new_polygon.vertices_begin(), new_polygon.vertices_end(), traits)) { *result = new_polygon; result++; } if (stack.front() == stack.back()) // the "stack empty" case { done = true; stack.push_front(new_point_ref); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_top_chain: stack is empty. New stack top is " << *stack.front() << std::endl; std::cout << "stack.back is " << *stack.back() << std::endl; std::cout << "stack.before_back is " << *stack.before_back() << std::endl; #endif top_chain.initialize(new_point_ref); // top chain should share top of stack } else // stack size must be >= 2 here { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_top_chain: stack.front " << *stack.front() << std::endl; #endif if (top_chain.direction() == COUNTERCLOCKWISE) big_angle_at_stack = !left_turn(*stack.before_front(), *stack.front(), *new_point_ref); else big_angle_at_stack = !right_turn(*stack.before_front(), *stack.front(), *new_point_ref); if (top_chain.direction() == COUNTERCLOCKWISE) small_angle_at_point = left_turn(*stack.front(), *new_point_ref, *next_point_ref); else small_angle_at_point = right_turn(*stack.front(), *new_point_ref, *next_point_ref); if (!big_angle_at_stack && !small_angle_at_point) { old_top_ref = stack.front(); stack.pop_front(); } } } while (!done && !big_angle_at_stack && !small_angle_at_point); if (big_angle_at_stack) // promote point to stack { stack.push_front(new_point_ref); top_chain.initialize(new_point_ref); // top chain shares top of stack } else if (small_angle_at_point) { top_chain.push_back(stack.front()); top_chain.push_front(new_point_ref); } } } template void change_bottom_chain(Polygon& polygon, BidirectionalCirculator new_point_ref, Circ_pair< BidirectionalCirculator >& stack, Circ_pair< BidirectionalCirculator >& bottom_chain, Circ_pair< BidirectionalCirculator >& top_chain, OutputIterator& result, const Traits& traits) { BidirectionalCirculator next_point_ref = new_point_ref; if (bottom_chain.direction() == COUNTERCLOCKWISE) next_point_ref++; else next_point_ref--; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_bottom_chain: bottom_chain.front " << *bottom_chain.front() << " new_point_ref " << *new_point_ref << " next_point_ref " << *next_point_ref << std::endl; #endif typedef typename Traits::Point_2 Point_2; typedef typename Traits::Left_turn_2 Left_turn_2; Left_turn_2 left_turn = traits.left_turn_2_object(); Turn_reverser right_turn(left_turn); if (((bottom_chain.direction() == CLOCKWISE) && !left_turn(*bottom_chain.front(), *new_point_ref, *next_point_ref)) || ((bottom_chain.direction() == COUNTERCLOCKWISE) && !right_turn(*bottom_chain.front(), *new_point_ref, *next_point_ref))) { bottom_chain.push_front(new_point_ref); } else { typedef typename Traits::Polygon_2 new_Polygon_2; bool done = false; bool small_angle_at_point = false; bool update_required; do { new_Polygon_2 new_polygon; stack.pop_back(); // remove old bottom of stack #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_bottom_chain: stack.front " << *stack.front() << " stack.back " << *stack.back() << std::endl; #endif if (bottom_chain.direction() == CLOCKWISE) { std::copy(new_point_ref, stack.before_back(), std::back_inserter(new_polygon)); erase_vertices(bottom_chain.front(), stack.back(), polygon, update_required); } else { std::copy(stack.back(), next_point_ref, std::back_inserter(new_polygon)); erase_vertices(bottom_chain.back(), new_point_ref, polygon, update_required); } if (!is_degenerate_polygon_2(new_polygon.vertices_begin(), new_polygon.vertices_end(), traits)) { *result = new_polygon; result++; } bottom_chain.initialize(stack.back()); if (stack.back() == stack.front()) // form new stack with new point { // and old stack top (still on stack) done = true; typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object(); if (less_yx(*(stack.front()),*new_point_ref)) { #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_bottom_chain: reversing stack and " << "swapping chains" << std::endl; #endif stack.push_front(new_point_ref); // reverse stack direction stack.change_dir(); bottom_chain = top_chain; // swap the chains top_chain.initialize(stack.front()); top_chain.change_dir(); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "change_bottom_chain: stack is now " << *stack.back() << " " << *stack.front() << " dir " << int(stack.direction()) << std::endl; std::cout << "change_bottom_chain: bottom_chain is now " << *bottom_chain.back() << " " << *bottom_chain.front() << " dir " << int(bottom_chain.direction()) << std::endl; std::cout << "change_bottom_chain: top_chain is now " << *top_chain.back() << " " << *top_chain.front() << " dir " << int(top_chain.direction()) << std::endl; #endif } else stack.push_back(new_point_ref); } else // stack size must be >= 2 here { // angle at new point is < 180 if (bottom_chain.direction() == CLOCKWISE) small_angle_at_point = right_turn(*stack.back(), *new_point_ref, *next_point_ref); else small_angle_at_point = left_turn(*stack.back(), *new_point_ref, *next_point_ref); } } while (!done && !small_angle_at_point); if (small_angle_at_point) { bottom_chain.push_back(stack.back()); bottom_chain.push_front(new_point_ref); } } } template void make_polygons_from_stack(Polygon& polygon, const BidirectionalCirculator& high_point_ref, Circ_pair< BidirectionalCirculator >& stack, Circ_pair< BidirectionalCirculator >& bottom_chain, OutputIterator& result, const Traits& traits) { bool update_required; // make polygons by connecting the high point to every point on the stack // except the first and the last. #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "make_polygons_from_stack: high_point_ref " << *high_point_ref << " stack.back " << *stack.back() << " stack.before_back " << *stack.before_back() << std::endl; #endif typedef typename Traits::Polygon_2 new_Polygon_2; new_Polygon_2 new_polygon; BidirectionalCirculator next_point_ref = high_point_ref; if (bottom_chain.direction() == COUNTERCLOCKWISE) next_point_ref++; stack.pop_back(); while (stack.front() != stack.back()) { new_Polygon_2 new_polygon; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "make_polygons_from_stack: stack.back " << *stack.back() << std::endl; #endif if (bottom_chain.direction() == CLOCKWISE) { std::copy(high_point_ref, stack.before_back(), std::back_inserter(new_polygon)); erase_vertices(bottom_chain.front(), stack.back(), polygon, update_required); bottom_chain.initialize(stack.back()); } else { std::copy(stack.back(), next_point_ref, std::back_inserter(new_polygon)); erase_vertices(bottom_chain.back(), high_point_ref, polygon, update_required); bottom_chain.push_back(stack.back()); } if (!is_degenerate_polygon_2(new_polygon.vertices_begin(), new_polygon.vertices_end(), traits)) { *result = new_polygon; result++; } stack.pop_back(); } // add remaining points from the top chain if there is more than one std::copy(polygon.begin(), polygon.end(), std::back_inserter(new_polygon)); if (!is_degenerate_polygon_2(new_polygon.vertices_begin(), new_polygon.vertices_end(), traits)) { *result = new_polygon; result++; } } template void find_smallest_yx(BidirectionalCirculator& first, const Traits& traits) { BidirectionalCirculator current = first; current++; // find out which direction to go typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object(); if (less_yx(*current, *first)) // go foward { do { first++; current++; } while (less_yx(*current, *first)); } else { current = first; current--; if (less_yx(*current, *first)) // go backward { do { first--; current--; } while (less_yx(*current, *first)); } } // otherwise both previous and next are larger, so no need to move } template bool second_point_is_next(BidirectionalCirculator first, const Traits& traits) { BidirectionalCirculator next = first; next++; BidirectionalCirculator previous = first; previous--; typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object(); return less_yx(*next, *previous); } template BidirectionalCirculator next_vertex(BidirectionalCirculator& ccw_current, BidirectionalCirculator& cw_current, const Traits& traits) { BidirectionalCirculator ccw_next = ccw_current; ccw_next++; BidirectionalCirculator cw_next = cw_current; cw_next--; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "next_vertex: ccw_next " << *ccw_next << " cw_next " << *cw_next << std::endl; #endif if (ccw_next == cw_next) { cw_current = cw_next; ccw_current = ccw_next; return cw_next; } else { typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object(); if (less_yx(*ccw_next,*cw_next)) { ccw_current = ccw_next; return ccw_next; } else { cw_current = cw_next; return cw_next; } } } template void ga_convex_decomposition(ForwardIterator first, ForwardIterator beyond, OutputIterator& result, const Traits& traits) { if (first == beyond) return; typedef typename Traits::Point_2 Point_2; typedef std::list Vertex_list; typedef Circulator_from_container Vertex_circulator; Vertex_list polygon(first, beyond); CGAL_partition_precondition( orientation_2(polygon.begin(), polygon.end(), traits) == COUNTERCLOCKWISE); CGAL_partition_precondition( is_y_monotone_2(polygon.begin(), polygon.end(), traits)); Vertex_circulator point_ref(&polygon); Vertex_circulator circ = point_ref; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "before find_smallest_yx " << std::endl; do { std::cout << *circ << std::endl; } while (++circ != point_ref); #endif find_smallest_yx(point_ref, traits); circ = point_ref; #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "after find_smallest_yx " << std::endl; do { std::cout << *circ << std::endl; } while (++circ != point_ref); #endif Vertex_circulator ccw_chain_ref = point_ref; Vertex_circulator cw_chain_ref = point_ref; Circ_pair< Vertex_circulator > stack(point_ref, COUNTERCLOCKWISE); Circ_pair< Vertex_circulator > bottom_chain(point_ref, CLOCKWISE); Circ_pair< Vertex_circulator > top_chain(point_ref, COUNTERCLOCKWISE); // discover which is the direction to the next point if (second_point_is_next(point_ref, traits)) { ccw_chain_ref++; stack.push_front(ccw_chain_ref); stack.set_direction(COUNTERCLOCKWISE); top_chain.initialize(ccw_chain_ref); top_chain.set_direction(COUNTERCLOCKWISE); bottom_chain.set_direction(CLOCKWISE); } else { cw_chain_ref--; stack.push_front(cw_chain_ref); stack.set_direction(CLOCKWISE); top_chain.initialize(cw_chain_ref); top_chain.set_direction(CLOCKWISE); bottom_chain.set_direction(COUNTERCLOCKWISE); } #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "after inserting first two points: ccw_chain_ref " << *ccw_chain_ref << " cw_chain_ref " << *cw_chain_ref << std::endl; #endif while (ccw_chain_ref != cw_chain_ref) { point_ref = next_vertex(ccw_chain_ref, cw_chain_ref, traits); #ifdef CGAL_GREENE_APPROX_DEBUG std::cout << "after next_vertex: ccw_chain_ref " << *ccw_chain_ref << " cw_chain_ref " << *cw_chain_ref << std::endl; std::cout << "current point: " << *point_ref << std::endl; #endif if (is_adjacent_to(point_ref, bottom_chain.front())) visible(polygon, point_ref, stack, bottom_chain, top_chain, result, traits); if (ccw_chain_ref == cw_chain_ref) { make_polygons_from_stack(polygon, point_ref, stack, bottom_chain, result, traits); return; } if (is_adjacent_to(point_ref, stack.front())) stack_extend(polygon, point_ref, stack, top_chain, result, traits); else if (is_adjacent_to(point_ref, top_chain.front())) change_top_chain(polygon, point_ref, stack, top_chain, result, traits); else change_bottom_chain(polygon, point_ref, stack, bottom_chain, top_chain, result, traits); } } // should change this so it is like the others in that it adds diagonals // to a partition polygon and then calls partition // have to be able to go over the vertices again in order to check the // result, so they have to be stored somewhere else. template OutputIterator partition_greene_approx_convex_2(InputIterator first, InputIterator beyond, OutputIterator result, const Traits& traits) { if (first == beyond) return result; typedef typename Traits::Point_2 Point_2; typedef typename Traits::Polygon_2 Polygon_2; #if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \ defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG) OutputIterator res(result); #else Tee_for_output_iterator res(result); #endif // no postconditions Polygon_2 polygon(first, beyond); CGAL_partition_precondition( orientation_2(polygon.vertices_begin(), polygon.vertices_end(), traits) == COUNTERCLOCKWISE); std::list MP_list; typename std::list::iterator MP_it; y_monotone_partition_2(polygon.vertices_begin(), polygon.vertices_end(), std::back_inserter(MP_list), traits); for(MP_it = MP_list.begin(); MP_it != MP_list.end(); MP_it++) { ga_convex_decomposition((*MP_it).vertices_begin(), (*MP_it).vertices_end(), res, traits); } CGAL_partition_postcondition( convex_partition_is_valid_2(polygon.vertices_begin(), polygon.vertices_end(), res.output_so_far_begin(), res.output_so_far_end(), traits)); #if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \ defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG) return res; #else return res.to_output_iterator(); #endif // no postconditions } template inline OutputIterator partition_greene_approx_convex_2(InputIterator first, InputIterator beyond, OutputIterator result) { typedef typename std::iterator_traits::value_type Point_2; typedef typename Kernel_traits::Kernel K; return partition_greene_approx_convex_2(first, beyond, result, Partition_traits_2()); } } #endif // CGAL_GREENE_APPROX_H