799 lines
26 KiB
C
799 lines
26 KiB
C
|
// Copyright (c) 2001 Tel-Aviv University (Israel).
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// This file is part of CGAL (www.cgal.org).
|
||
|
// You can redistribute it and/or modify it under the terms of the GNU
|
||
|
// General Public License as published by the Free Software Foundation,
|
||
|
// either version 3 of the License, or (at your option) any later version.
|
||
|
//
|
||
|
// 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$
|
||
|
// SPDX-License-Identifier: GPL-3.0+
|
||
|
//
|
||
|
//
|
||
|
// author(s) : Eli Packer <elip@post.tau.ac.il>
|
||
|
|
||
|
#ifndef CGAL_SNAP_ROUNDING_2_H
|
||
|
#define CGAL_SNAP_ROUNDING_2_H
|
||
|
|
||
|
#include <CGAL/license/Snap_rounding_2.h>
|
||
|
|
||
|
|
||
|
#include <iostream>
|
||
|
#include <CGAL/basic.h>
|
||
|
#include <CGAL/enum.h>
|
||
|
#include <CGAL/predicates_on_points_2.h>
|
||
|
#include <CGAL/intersection_2.h>
|
||
|
#include <CGAL/Surface_sweep_2_algorithms.h>
|
||
|
#include <list>
|
||
|
#include <set>
|
||
|
#include <CGAL/Snap_rounding_kd_2.h>
|
||
|
#include <CGAL/utility.h>
|
||
|
#include <CGAL/Iterator_project.h>
|
||
|
#include <CGAL/function_objects.h>
|
||
|
#include <CGAL/tss.h>
|
||
|
|
||
|
namespace CGAL {
|
||
|
|
||
|
enum SEG_Direction {SEG_UP_RIGHT,SEG_UP_LEFT,SEG_DOWN_RIGHT,SEG_DOWN_LEFT,
|
||
|
SEG_UP,SEG_DOWN,SEG_LEFT,SEG_RIGHT,SEG_POINT_SEG};
|
||
|
|
||
|
template<class Traits_>
|
||
|
class Segment_data {
|
||
|
private:
|
||
|
typedef Traits_ Traits;
|
||
|
typedef typename Traits::FT NT;
|
||
|
typedef typename Traits::Segment_2 Segment_2;
|
||
|
typedef typename Traits::Point_2 Point_2;
|
||
|
|
||
|
private:
|
||
|
Point_2 p;
|
||
|
Point_2 q;
|
||
|
|
||
|
Traits m_gt;
|
||
|
|
||
|
public:
|
||
|
Segment_data();
|
||
|
Segment_data(const Point_2 & p_inp,const Point_2 & q_inp);
|
||
|
Segment_2 segment() const { return(Segment_2(p, q)); }
|
||
|
const Point_2& source() const { return(p); }
|
||
|
const Point_2& target() const { return(q); }
|
||
|
inline void set_data(const Point_2 & inp_p,const Point_2 & inp_q);
|
||
|
void determine_direction(SEG_Direction & seg_dir);
|
||
|
bool equal(const Segment_2 & s);
|
||
|
Segment_data(const Segment_data & other);
|
||
|
};
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
class Hot_pixel {
|
||
|
private:
|
||
|
typedef Traits_ Traits;
|
||
|
typedef typename Traits::FT NT;
|
||
|
typedef typename Traits::Segment_2 Segment_2;
|
||
|
typedef typename Traits::Point_2 Point_2;
|
||
|
typedef CGAL::Segment_data<Traits> Segment_data;
|
||
|
|
||
|
private:
|
||
|
// p is the center of the hot pixel
|
||
|
Point_2 p;
|
||
|
Point_2 p_left;
|
||
|
Point_2 p_right;
|
||
|
Point_2 p_down;
|
||
|
Point_2 p_up;
|
||
|
Traits_ m_gt;
|
||
|
NT pixel_size;
|
||
|
Segment_2 *right_seg;
|
||
|
Segment_2 *left_seg;
|
||
|
Segment_2 *top_seg;
|
||
|
Segment_2 *bot_seg;
|
||
|
|
||
|
static SEG_Direction& direction()
|
||
|
{
|
||
|
CGAL_STATIC_THREAD_LOCAL_VARIABLE(SEG_Direction, seg_dir,SEG_UP);
|
||
|
return seg_dir;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
public:
|
||
|
Hot_pixel(const Point_2 & inp_point, NT inp_pixel_size);
|
||
|
~Hot_pixel();
|
||
|
inline Point_2 get_center() const;
|
||
|
inline Point_2 get_center(bool int_output) const;
|
||
|
bool intersect_left(const Segment_2 & seg, SEG_Direction seg_dir) const;
|
||
|
bool intersect_right(const Segment_2 & seg, SEG_Direction seg_dir) const;
|
||
|
bool intersect_bot(const Segment_2 & seg, SEG_Direction seg_dir) const;
|
||
|
bool intersect_top(const Segment_2 & seg, SEG_Direction seg_dir) const;
|
||
|
bool intersect(Segment_data & seg, SEG_Direction seg_dir) const;
|
||
|
void set_direction(SEG_Direction inp_seg_dir) { direction() = inp_seg_dir; }
|
||
|
SEG_Direction get_direction() const { return direction(); }
|
||
|
};
|
||
|
|
||
|
/*! */
|
||
|
|
||
|
|
||
|
// a function for compare two hot pixels for the set of hot pixels
|
||
|
template<class Traits_>
|
||
|
struct Hot_pixel_auclidian_cmp {
|
||
|
typedef CGAL::Hot_pixel<Traits_> Hot_pixel;
|
||
|
|
||
|
Traits_ m_gt;
|
||
|
|
||
|
bool operator()(const Hot_pixel * h1, const Hot_pixel * h2) const;
|
||
|
};
|
||
|
|
||
|
// a function for compare two hot pixels for the set of hot pixels a
|
||
|
// certain segment intersect
|
||
|
template<class Traits_>
|
||
|
struct Hot_pixel_dir_cmp {
|
||
|
typedef CGAL::Hot_pixel<Traits_> Hot_pixel;
|
||
|
|
||
|
Traits_ m_gt;
|
||
|
|
||
|
bool operator()(const Hot_pixel * h1, const Hot_pixel * h2) const;
|
||
|
};
|
||
|
|
||
|
#ifdef CGAL_SR_DEBUG
|
||
|
int number_of_false_hp;
|
||
|
#endif
|
||
|
|
||
|
template<class Traits_,class OutputContainer>
|
||
|
class Snap_rounding_2 {
|
||
|
private:
|
||
|
typedef Traits_ Traits;
|
||
|
typedef typename Traits::FT NT;
|
||
|
typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2;
|
||
|
typedef typename OutputContainer::value_type Polyline_type;
|
||
|
typedef CGAL::Hot_pixel<Traits_> Hot_pixel;
|
||
|
typedef CGAL::Segment_data<Traits> Segment_data;
|
||
|
typedef CGAL::Multiple_kd_tree<Traits,Hot_pixel *> Multiple_kd_tree;
|
||
|
typedef std::list<Segment_data> Segment_data_list;
|
||
|
typedef CGAL::Hot_pixel_dir_cmp<Traits> Hot_pixel_dir_cmp;
|
||
|
typedef std::set<Hot_pixel *, Hot_pixel_dir_cmp> Hot_pixel_set;
|
||
|
|
||
|
public:
|
||
|
// friend class Segment_data<Traits>;
|
||
|
// friend class Hot_pixel<Traits>;
|
||
|
// friend struct Hot_pixel_dir_cmp<Traits>;
|
||
|
|
||
|
typedef typename Traits::Segment_2 Segment_2;
|
||
|
typedef typename Traits::Point_2 Point_2;
|
||
|
typedef std::list<Point_2> Point_list;
|
||
|
|
||
|
void find_hot_pixels_and_create_kd_trees(NT pixel_size,
|
||
|
unsigned int number_of_kd_trees,
|
||
|
Segment_data_list & seg_list,
|
||
|
Multiple_kd_tree ** mul_kd_tree);
|
||
|
|
||
|
void iterate(OutputContainer & output_container,
|
||
|
NT pixel_size, bool int_output, bool do_isr,
|
||
|
Segment_data_list & seg_list,
|
||
|
Multiple_kd_tree * mul_kd_tree);
|
||
|
|
||
|
private:
|
||
|
Traits m_gt;
|
||
|
|
||
|
static const int default_number_of_kd_trees = 1;
|
||
|
|
||
|
void find_intersected_hot_pixels(Segment_data & seg,
|
||
|
Hot_pixel_set &hot_pixels_intersected_set,
|
||
|
int &number_of_intersections,
|
||
|
NT pixel_size,
|
||
|
Multiple_kd_tree * mul_kd_tree);
|
||
|
|
||
|
void reroute_sr(Hot_pixel_set & inp_hot_pixels_intersected_set,
|
||
|
Polyline_type & seg_output,
|
||
|
bool int_output);
|
||
|
|
||
|
void reroute_isr(Hot_pixel_set & inp_hot_pixels_intersected_set,
|
||
|
Polyline_type & seg_output,
|
||
|
int number_of_intersections,
|
||
|
bool first_time,
|
||
|
NT pixel_size,
|
||
|
bool int_output,
|
||
|
Multiple_kd_tree * mul_kd_tree);
|
||
|
};
|
||
|
|
||
|
/*! Constructor */
|
||
|
template<class Traits_>
|
||
|
Segment_data<Traits_>::Segment_data() {}
|
||
|
|
||
|
/*! Constructor */
|
||
|
template<class Traits_>
|
||
|
Segment_data<Traits_>::Segment_data(const Point_2 & p_inp,
|
||
|
const Point_2 & q_inp) :
|
||
|
p(p_inp), q(q_inp) {}
|
||
|
|
||
|
/*! Constructor */
|
||
|
template<class Traits_>
|
||
|
Segment_data<Traits_>::Segment_data(const Segment_data & other)
|
||
|
{
|
||
|
p = other.p;
|
||
|
q = other.q;
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
inline void Segment_data<Traits_>::set_data(const Point_2 & inp_p,
|
||
|
const Point_2 & inp_q)
|
||
|
{
|
||
|
p = inp_p;
|
||
|
q = inp_q;
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool Segment_data<Traits_>::equal(const Segment_2 & s)
|
||
|
{
|
||
|
typedef typename Traits_::Construct_vertex_2 Construct_vertex_2;
|
||
|
Construct_vertex_2 construct_vertex = m_gt.construct_vertex_2_object();
|
||
|
return(construct_vertex(s, 0) == p && construct_vertex(s, 1) == q);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
void Segment_data<Traits_>::determine_direction(SEG_Direction & seg_dir)
|
||
|
{
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
|
||
|
Comparison_result cx = compare_x(p, q);
|
||
|
Comparison_result cy = compare_y(p, q);
|
||
|
|
||
|
if (cx == SMALLER) {
|
||
|
if (cy == SMALLER) seg_dir = SEG_UP_RIGHT;
|
||
|
else if (cy == EQUAL) seg_dir = SEG_RIGHT;
|
||
|
else seg_dir = SEG_DOWN_RIGHT;
|
||
|
} else if (cx == EQUAL) {
|
||
|
if (cy == SMALLER) seg_dir = SEG_UP;
|
||
|
else if (cy == EQUAL) seg_dir = SEG_POINT_SEG;
|
||
|
else seg_dir = SEG_DOWN;
|
||
|
} else {
|
||
|
if (cy == SMALLER) seg_dir = SEG_UP_LEFT;
|
||
|
else if (cy == EQUAL) seg_dir = SEG_LEFT;
|
||
|
else seg_dir = SEG_DOWN_LEFT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// intersection pixel
|
||
|
template<class Traits_>
|
||
|
Hot_pixel<Traits_>::Hot_pixel(const Point_2 & inp_point, NT inp_pixel_size) :
|
||
|
pixel_size(inp_pixel_size)
|
||
|
{
|
||
|
NT x,y;
|
||
|
m_gt.snap_2_object()(inp_point, pixel_size, x, y);
|
||
|
|
||
|
NT left_coord = x - pixel_size / NT(2.0);
|
||
|
NT right_coord = x + pixel_size / NT(2.0);
|
||
|
NT bottom_coord = y - pixel_size / NT(2.0);
|
||
|
NT top_coord = y + pixel_size / NT(2.0);
|
||
|
p = Point_2(x, y);
|
||
|
p_left = Point_2(left_coord, y);
|
||
|
p_right = Point_2(right_coord, y);
|
||
|
p_down = Point_2(x, bottom_coord);
|
||
|
p_up = Point_2(x, top_coord);
|
||
|
|
||
|
typedef typename Traits::Construct_segment_2 Construct_segment_2;
|
||
|
Construct_segment_2 construct_seg = m_gt.construct_segment_2_object();
|
||
|
|
||
|
Point_2 lb(left_coord, bottom_coord);
|
||
|
Point_2 rb(right_coord, bottom_coord);
|
||
|
Point_2 lt(left_coord, top_coord);
|
||
|
Point_2 rt(right_coord, top_coord);
|
||
|
right_seg = new Segment_2(construct_seg(rb, rt));
|
||
|
left_seg = new Segment_2(construct_seg(lb, lt));
|
||
|
top_seg = new Segment_2(construct_seg(lt, rt));
|
||
|
bot_seg = new Segment_2(construct_seg(lb, rb));
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
Hot_pixel<Traits_>::~Hot_pixel()
|
||
|
{
|
||
|
delete right_seg;
|
||
|
delete left_seg;
|
||
|
delete top_seg;
|
||
|
delete bot_seg;
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
inline typename Hot_pixel<Traits_>::Point_2
|
||
|
Hot_pixel<Traits_>::get_center() const
|
||
|
{
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
inline typename Hot_pixel<Traits_>::Point_2
|
||
|
Hot_pixel<Traits_>::get_center(bool int_output) const
|
||
|
{
|
||
|
if (int_output) {
|
||
|
Point_2 out_p = m_gt.integer_grid_point_2_object()(p,pixel_size);
|
||
|
return(out_p);
|
||
|
} else
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel<Traits_>::intersect_left(const Segment_2 & seg,
|
||
|
SEG_Direction seg_dir) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
typedef typename Traits_::Construct_vertex_2 Construct_vertex_2;
|
||
|
|
||
|
Object result;
|
||
|
Point_2 p;
|
||
|
Segment_2 s;
|
||
|
|
||
|
result = intersection(seg, *left_seg);
|
||
|
|
||
|
if (assign(p, result)) {
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
Construct_vertex_2 construct_vertex = m_gt.construct_vertex_2_object();
|
||
|
|
||
|
Comparison_result c_p = compare_y(p, p_up);
|
||
|
Comparison_result c_target = compare_y(construct_vertex(seg, 1), p_up);
|
||
|
Comparison_result c_source = compare_y(construct_vertex(seg, 0), p_up);
|
||
|
|
||
|
return(c_p != EQUAL || (seg_dir == SEG_UP_LEFT && c_source != EQUAL) ||
|
||
|
(seg_dir == SEG_DOWN_RIGHT && c_target != EQUAL));
|
||
|
} else if (assign(s,result))
|
||
|
return(true);
|
||
|
else
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel<Traits_>::intersect_right(const Segment_2 & seg,
|
||
|
SEG_Direction seg_dir) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
typedef typename Traits_::Construct_vertex_2 Construct_vertex_2;
|
||
|
|
||
|
Object result;
|
||
|
Point_2 p;
|
||
|
Segment_2 s;
|
||
|
|
||
|
result = intersection(seg, *right_seg);
|
||
|
|
||
|
if (assign(p,result)) {
|
||
|
// bottom right point was checked in intersect_bot
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
Construct_vertex_2 construct_vertex = m_gt.construct_vertex_2_object();
|
||
|
|
||
|
Comparison_result c1 = compare_y(p, p_up);
|
||
|
Comparison_result c2 = compare_y(p, p_down);
|
||
|
|
||
|
Point_2 src = construct_vertex(seg, 0);
|
||
|
Point_2 trg = construct_vertex(seg, 1);
|
||
|
Comparison_result c3 = compare_y(src, p_up);
|
||
|
Comparison_result c4 = compare_y(trg, p_up);
|
||
|
|
||
|
if (c1 == EQUAL)
|
||
|
return ((seg_dir == SEG_UP_RIGHT && c3 != EQUAL) ||
|
||
|
(seg_dir == SEG_DOWN_LEFT && c4 != EQUAL));
|
||
|
else if (c2 == EQUAL)
|
||
|
return false;// was checked
|
||
|
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Comparison_result c_target = compare_x(p_right, trg);
|
||
|
Comparison_result c_source = compare_x(p_right, src);
|
||
|
|
||
|
return (((seg_dir == SEG_LEFT || seg_dir == SEG_DOWN_LEFT ||
|
||
|
seg_dir == SEG_UP_LEFT) && c_target != EQUAL) ||
|
||
|
((seg_dir == SEG_RIGHT || seg_dir == SEG_DOWN_RIGHT ||
|
||
|
seg_dir == SEG_UP_RIGHT) && c_source != EQUAL));
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel<Traits_>::intersect_bot(const Segment_2 & seg,
|
||
|
SEG_Direction seg_dir) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
typedef typename Traits_::Construct_vertex_2 Construct_vertex_2;
|
||
|
|
||
|
Object result;
|
||
|
Point_2 p;
|
||
|
Segment_2 s;
|
||
|
|
||
|
result = intersection(seg,*bot_seg);
|
||
|
|
||
|
if (assign(p,result)) {
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Construct_vertex_2 construct_vertex = m_gt.construct_vertex_2_object();
|
||
|
|
||
|
Comparison_result c_p = compare_x(p, p_right);
|
||
|
Comparison_result c_target = compare_x(construct_vertex(seg, 1), p_right);
|
||
|
Comparison_result c_source = compare_x(construct_vertex(seg, 0), p_right);
|
||
|
|
||
|
return(c_p != EQUAL || (seg_dir == SEG_UP_LEFT && c_target != EQUAL) ||
|
||
|
(seg_dir == SEG_DOWN_RIGHT && c_source != EQUAL));
|
||
|
} else if (assign(s,result))
|
||
|
return(true);
|
||
|
else
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel<Traits_>::intersect_top(const Segment_2 & seg,
|
||
|
SEG_Direction seg_dir) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
typedef typename Traits_::Construct_vertex_2 Construct_vertex_2;
|
||
|
|
||
|
Object result;
|
||
|
Point_2 p;
|
||
|
Segment_2 s;
|
||
|
|
||
|
result = intersection(seg, *top_seg);
|
||
|
|
||
|
if (assign(p,result))
|
||
|
{
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
Construct_vertex_2 construct_vertex = m_gt.construct_vertex_2_object();
|
||
|
|
||
|
// corner points was checked in intersect_bot
|
||
|
Comparison_result c1 = compare_x(p, p_left);
|
||
|
Comparison_result c2 = compare_x(p, p_right);
|
||
|
Comparison_result c3 = compare_y(construct_vertex(seg, 1), p_up);
|
||
|
Comparison_result c4 = compare_y(construct_vertex(seg, 0), p_up);
|
||
|
|
||
|
if (c1 == EQUAL || c2 == EQUAL)
|
||
|
return(false);// were checked
|
||
|
else
|
||
|
return(((seg_dir == SEG_DOWN || seg_dir == SEG_DOWN_LEFT ||
|
||
|
seg_dir == SEG_DOWN_RIGHT) && c3 != EQUAL) ||
|
||
|
((seg_dir == SEG_UP || seg_dir == SEG_UP_LEFT ||
|
||
|
seg_dir == SEG_UP_RIGHT) && c4 != EQUAL));
|
||
|
}
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_>
|
||
|
bool
|
||
|
Hot_pixel<Traits_>::intersect(Segment_data & seg, SEG_Direction my_seg_dir) const
|
||
|
{
|
||
|
Segment_2 s = seg.segment();
|
||
|
|
||
|
return(intersect_bot(s,my_seg_dir) || intersect_left(s, my_seg_dir) ||
|
||
|
intersect_right(s, my_seg_dir) || intersect_top(s, my_seg_dir));
|
||
|
}
|
||
|
|
||
|
// a function for compare two hot pixels for the set of hot pixels
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel_auclidian_cmp<Traits_>::
|
||
|
operator()(const Hot_pixel * h1, const Hot_pixel * h2) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
|
||
|
Comparison_result cx = compare_x(h1->get_center(), h2->get_center());
|
||
|
Comparison_result cy = compare_y(h1->get_center(), h2->get_center());
|
||
|
|
||
|
return(cx == SMALLER || ( cx == EQUAL && cy == SMALLER));
|
||
|
}
|
||
|
|
||
|
// a function for compare two hot pixels for the set of hot pixels a certain
|
||
|
// segment intersect
|
||
|
template<class Traits_>
|
||
|
bool Hot_pixel_dir_cmp<Traits_>::operator ()(const Hot_pixel * h1,
|
||
|
const Hot_pixel * h2) const
|
||
|
{
|
||
|
typedef typename Traits_::Compare_x_2 Compare_x_2;
|
||
|
typedef typename Traits_::Compare_y_2 Compare_y_2;
|
||
|
|
||
|
Compare_x_2 compare_x = m_gt.compare_x_2_object();
|
||
|
Compare_y_2 compare_y = m_gt.compare_y_2_object();
|
||
|
|
||
|
Comparison_result cx = compare_x(h1->get_center(), h2->get_center());
|
||
|
Comparison_result cy = compare_y(h1->get_center(), h2->get_center());
|
||
|
SEG_Direction seg_dir = h1->get_direction();
|
||
|
|
||
|
// Point segment intersects only one pixel, thus ignored
|
||
|
return((seg_dir == SEG_UP_RIGHT && (cx == SMALLER || (cx == EQUAL &&
|
||
|
cy == SMALLER))) ||
|
||
|
(seg_dir == SEG_UP_LEFT && (cx == LARGER || (cx == EQUAL &&
|
||
|
cy == SMALLER))) ||
|
||
|
(seg_dir == SEG_DOWN_RIGHT && (cx == SMALLER || (cx == EQUAL &&
|
||
|
cy == LARGER))) ||
|
||
|
(seg_dir == SEG_DOWN_LEFT && (cx == LARGER || (cx == EQUAL &&
|
||
|
cy == LARGER))) ||
|
||
|
(seg_dir == SEG_UP && cy == SMALLER) ||
|
||
|
(seg_dir == SEG_DOWN && cy == LARGER) ||
|
||
|
(seg_dir == SEG_LEFT && cx == LARGER) ||
|
||
|
(seg_dir == SEG_RIGHT && cx == SMALLER));
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits,class OutputContainer>
|
||
|
void Snap_rounding_2<Traits,OutputContainer>::
|
||
|
find_hot_pixels_and_create_kd_trees(NT pixel_size,
|
||
|
unsigned int number_of_kd_trees,
|
||
|
std::list<Segment_data> & seg_list,
|
||
|
Multiple_kd_tree ** mul_kd_tree)
|
||
|
{
|
||
|
typedef std::pair<Point_2, Hot_pixel *> Point_hot_pixel_pair;
|
||
|
typedef typename std::list<Segment_data>::iterator Segment_data_iter;
|
||
|
typedef std::list<Segment_2> Segment_list;
|
||
|
typedef typename std::list<Point_2>::const_iterator Point_const_iter;
|
||
|
|
||
|
typedef typename Traits::Construct_segment_2 Construct_segment_2;
|
||
|
Construct_segment_2 construct_seg = m_gt.construct_segment_2_object();
|
||
|
|
||
|
Hot_pixel * hp;
|
||
|
Segment_data_iter iter1;
|
||
|
Object result;
|
||
|
Point_2 p;
|
||
|
std::list<Point_hot_pixel_pair> hot_pixels_list;
|
||
|
Segment_list segments;
|
||
|
|
||
|
if (seg_list.empty()) return;
|
||
|
|
||
|
for (iter1 = seg_list.begin(); iter1 != seg_list.end(); ++iter1) {
|
||
|
segments.push_back(construct_seg(iter1->source(), iter1->target()));
|
||
|
}
|
||
|
|
||
|
// get intersection points (with endpoints)
|
||
|
Point_list mypointlist;
|
||
|
|
||
|
CGAL::compute_intersection_points(segments.begin(), segments.end(),
|
||
|
std::back_inserter(mypointlist), true, m_gt);
|
||
|
|
||
|
for (Point_const_iter v_iter = mypointlist.begin();
|
||
|
v_iter != mypointlist.end(); ++v_iter)
|
||
|
{
|
||
|
hp = new Hot_pixel(*v_iter, pixel_size);
|
||
|
hot_pixels_list.push_back(Point_hot_pixel_pair(hp->get_center(), hp));
|
||
|
}
|
||
|
|
||
|
// create kd multiple tree
|
||
|
// create simple_list from seg_list
|
||
|
Segment_list simple_seg_list;
|
||
|
for (Segment_data_iter iter = seg_list.begin(); iter != seg_list.end();
|
||
|
++iter)
|
||
|
{
|
||
|
simple_seg_list.push_back(construct_seg(iter->source(), iter->target()));
|
||
|
}
|
||
|
*mul_kd_tree = new Multiple_kd_tree(hot_pixels_list, number_of_kd_trees,
|
||
|
simple_seg_list);
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_,class OutputContainer>
|
||
|
void Snap_rounding_2<Traits_,OutputContainer>::
|
||
|
find_intersected_hot_pixels(Segment_data & seg,
|
||
|
std::set<Hot_pixel *,
|
||
|
Hot_pixel_dir_cmp> & hot_pixels_intersected_set,
|
||
|
int &number_of_intersections,
|
||
|
NT pixel_size,
|
||
|
Multiple_kd_tree * mul_kd_tree)
|
||
|
{
|
||
|
typedef typename std::list<Hot_pixel *>::iterator Hot_pixel_iter;
|
||
|
|
||
|
Hot_pixel_iter iter;
|
||
|
SEG_Direction seg_dir;
|
||
|
|
||
|
hot_pixels_intersected_set.clear();
|
||
|
seg.determine_direction(seg_dir);
|
||
|
number_of_intersections = 0;
|
||
|
std::list<Hot_pixel *> hot_pixels_list;
|
||
|
|
||
|
mul_kd_tree->get_intersecting_points(hot_pixels_list,
|
||
|
Segment_2(seg.segment()), pixel_size);
|
||
|
|
||
|
for (iter = hot_pixels_list.begin();iter != hot_pixels_list.end();++iter) {
|
||
|
if ((*iter)->intersect(seg,seg_dir)) {
|
||
|
(*iter)->set_direction(seg_dir);
|
||
|
hot_pixels_intersected_set.insert(*iter);
|
||
|
}
|
||
|
|
||
|
#ifdef CGAL_SR_DEBUG
|
||
|
else
|
||
|
++number_of_false_hp;
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
number_of_intersections = static_cast<int>(hot_pixels_intersected_set.size());
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_,class OutputContainer>
|
||
|
void Snap_rounding_2<Traits_,OutputContainer>::
|
||
|
reroute_sr(std::set<Hot_pixel *, Hot_pixel_dir_cmp>
|
||
|
& inp_hot_pixels_intersected_set,
|
||
|
Polyline_type & seg_output,
|
||
|
bool int_output)
|
||
|
{
|
||
|
typedef typename std::set<Hot_pixel *, Hot_pixel_dir_cmp>::iterator
|
||
|
Hot_pixel_iter;
|
||
|
|
||
|
Hot_pixel_iter hot_pixel_iter = inp_hot_pixels_intersected_set.begin();
|
||
|
++hot_pixel_iter;
|
||
|
|
||
|
while (hot_pixel_iter != inp_hot_pixels_intersected_set.end()) {
|
||
|
seg_output.push_back((*hot_pixel_iter)->get_center(int_output));
|
||
|
++hot_pixel_iter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_,class OutputContainer>
|
||
|
void Snap_rounding_2<Traits_,OutputContainer>::
|
||
|
reroute_isr(std::set<Hot_pixel *, Hot_pixel_dir_cmp>
|
||
|
& inp_hot_pixels_intersected_set,
|
||
|
Polyline_type & seg_output,
|
||
|
int number_of_intersections,
|
||
|
bool first_time,
|
||
|
NT pixel_size,
|
||
|
bool int_output,
|
||
|
Multiple_kd_tree * mul_kd_tree)
|
||
|
{
|
||
|
typedef std::set<Hot_pixel *, Hot_pixel_dir_cmp> Hot_pixel_set;
|
||
|
typedef typename std::set<Hot_pixel *, Hot_pixel_dir_cmp>::iterator
|
||
|
Hot_pixel_iter;
|
||
|
|
||
|
Hot_pixel_iter hot_pixel_iter, next_hot_pixel_iter,
|
||
|
before_last_hot_pixel_iter;
|
||
|
Segment_data seg;
|
||
|
Hot_pixel_set hot_pixels_intersected_set;
|
||
|
SEG_Direction seg_dir;
|
||
|
|
||
|
if (number_of_intersections > 2 || first_time) {
|
||
|
before_last_hot_pixel_iter = inp_hot_pixels_intersected_set.end();
|
||
|
--before_last_hot_pixel_iter;
|
||
|
|
||
|
for (hot_pixel_iter = inp_hot_pixels_intersected_set.begin();
|
||
|
hot_pixel_iter != before_last_hot_pixel_iter; ++hot_pixel_iter)
|
||
|
{
|
||
|
next_hot_pixel_iter = hot_pixel_iter;
|
||
|
++next_hot_pixel_iter;
|
||
|
seg.set_data((*hot_pixel_iter)->get_center(),
|
||
|
(*next_hot_pixel_iter)->get_center());
|
||
|
seg.determine_direction(seg_dir);
|
||
|
find_intersected_hot_pixels(seg, hot_pixels_intersected_set,
|
||
|
number_of_intersections, pixel_size,
|
||
|
mul_kd_tree);
|
||
|
reroute_isr(hot_pixels_intersected_set, seg_output,
|
||
|
number_of_intersections,false, pixel_size,
|
||
|
int_output, mul_kd_tree);
|
||
|
}
|
||
|
} else {
|
||
|
// insert second hot pixel
|
||
|
hot_pixel_iter = inp_hot_pixels_intersected_set.begin();
|
||
|
++hot_pixel_iter;
|
||
|
seg_output.push_back((*hot_pixel_iter)->get_center(int_output));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits_, class OutputContainer>
|
||
|
void Snap_rounding_2<Traits_,OutputContainer>::
|
||
|
iterate(OutputContainer & output_container,
|
||
|
NT pixel_size,
|
||
|
bool int_output, bool do_isr,
|
||
|
std::list<Segment_data> & seg_list,
|
||
|
Multiple_kd_tree * mul_kd_tree)
|
||
|
{
|
||
|
typedef std::set<Hot_pixel *, Hot_pixel_dir_cmp> Hot_pixel_set;
|
||
|
typedef typename std::set<Hot_pixel *, Hot_pixel_dir_cmp>::iterator
|
||
|
Hot_pixel_iter;
|
||
|
typedef typename std::list<Segment_data>::iterator Segment_data_iter;
|
||
|
|
||
|
Polyline_type seg_output;
|
||
|
Hot_pixel_set hot_pixels_intersected_set;
|
||
|
Hot_pixel_iter hot_pixel_iter;
|
||
|
int number_of_intersections;
|
||
|
Hot_pixel * hp;
|
||
|
SEG_Direction seg_dir;
|
||
|
|
||
|
for (Segment_data_iter iter = seg_list.begin(); iter != seg_list.end();
|
||
|
++iter)
|
||
|
{
|
||
|
seg_output.clear();
|
||
|
iter->determine_direction(seg_dir);
|
||
|
find_intersected_hot_pixels(*iter, hot_pixels_intersected_set,
|
||
|
number_of_intersections, pixel_size,
|
||
|
mul_kd_tree);
|
||
|
// hot_pixels_intersected_set must have at least two hot pixels when the
|
||
|
// segment is not in entirely inside a hot pixel enter first hot pixel
|
||
|
hot_pixel_iter = hot_pixels_intersected_set.begin();
|
||
|
if (hot_pixel_iter == hot_pixels_intersected_set.end()) {
|
||
|
// segment entirely inside a pixel
|
||
|
hp = new Hot_pixel(iter->source(), pixel_size);
|
||
|
seg_output.push_back(hp->get_center(int_output));
|
||
|
delete hp;
|
||
|
} else {
|
||
|
seg_output.push_back((*hot_pixel_iter)->get_center(int_output));
|
||
|
if (number_of_intersections > 1) {
|
||
|
// segments that have at most one intersecting hot pixel are
|
||
|
// done(it was inserted)
|
||
|
if (do_isr)
|
||
|
reroute_isr(hot_pixels_intersected_set, seg_output,
|
||
|
number_of_intersections, true,pixel_size,
|
||
|
int_output, mul_kd_tree);
|
||
|
else
|
||
|
reroute_sr(hot_pixels_intersected_set, seg_output, int_output);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
output_container.push_back(seg_output);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*! */
|
||
|
template<class Traits, class InputIterator, class OutputContainer>
|
||
|
void snap_rounding_2(InputIterator begin,
|
||
|
InputIterator end,
|
||
|
OutputContainer & output_container,
|
||
|
typename Traits::NT pixel_size,
|
||
|
bool do_isr = true,
|
||
|
bool int_output = true,
|
||
|
unsigned int number_of_kd_trees = 1)
|
||
|
{
|
||
|
#ifdef CGAL_SR_DEBUG
|
||
|
number_of_false_hp = 0;
|
||
|
#endif
|
||
|
|
||
|
typedef CGAL::Hot_pixel<Traits> Hot_pixel;
|
||
|
typedef CGAL::Segment_data<Traits> Segment_data;
|
||
|
typedef CGAL::Multiple_kd_tree<Traits,Hot_pixel *> Multiple_kd_tree;
|
||
|
typedef std::list<Segment_data> Segment_data_list;
|
||
|
|
||
|
Segment_data_list seg_list;
|
||
|
Multiple_kd_tree * mul_kd_tree = NULL;
|
||
|
|
||
|
output_container.clear();
|
||
|
// copy segments list
|
||
|
while (begin != end) {
|
||
|
seg_list.push_back(Segment_data(begin->source(), begin->target()));
|
||
|
++begin;
|
||
|
}
|
||
|
|
||
|
Snap_rounding_2<Traits,OutputContainer> s;
|
||
|
|
||
|
s.find_hot_pixels_and_create_kd_trees(pixel_size, number_of_kd_trees,
|
||
|
seg_list, &mul_kd_tree);
|
||
|
s.iterate(output_container, pixel_size, int_output, do_isr,seg_list,
|
||
|
mul_kd_tree);
|
||
|
|
||
|
// hope that find_hot_pixels_and_create_kd_trees does not suddenly
|
||
|
// new up an array of multiple kd_tree
|
||
|
delete mul_kd_tree;
|
||
|
|
||
|
#ifdef CGAL_SR_DEBUG
|
||
|
std::cout << "Overall number of false hot pixels in all the queries : "
|
||
|
<< number_of_false_hp << std::endl;
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
} //namespace CGAL
|
||
|
|
||
|
#endif
|