mirror of https://github.com/KLayout/klayout.git
1437 lines
37 KiB
C++
1437 lines
37 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
This program is free software; 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef HDR_dbEdge
|
|
#define HDR_dbEdge
|
|
|
|
#include "dbCommon.h"
|
|
|
|
#include "dbTypes.h"
|
|
#include "dbPoint.h"
|
|
#include "dbVector.h"
|
|
#include "dbTrans.h"
|
|
#include "dbObjectTag.h"
|
|
#include "dbBox.h"
|
|
|
|
#include <string>
|
|
|
|
namespace db {
|
|
|
|
template <class C> class generic_repository;
|
|
class ArrayRepository;
|
|
|
|
template <class C>
|
|
class edge
|
|
{
|
|
public:
|
|
typedef C coord_type;
|
|
typedef db::box<C> box_type;
|
|
typedef db::point<C> point_type;
|
|
typedef db::vector<C> vector_type;
|
|
typedef db::coord_traits<C> coord_traits;
|
|
typedef typename coord_traits::distance_type distance_type;
|
|
typedef typename coord_traits::area_type area_type;
|
|
typedef db::object_tag< edge<C> > tag;
|
|
|
|
/**
|
|
* @brief The default constructor.
|
|
*
|
|
* The default constructor creates a degenerated edge
|
|
* with two points (0, 0).
|
|
*/
|
|
edge ()
|
|
: m_p1 (0, 0), m_p2 (0, 0)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The standard constructor taking four coordinates.
|
|
*
|
|
* Creates an edge from (x1,y1) to (x2,y2).
|
|
*
|
|
* @param x1 The first point's x coordinate.
|
|
* @param y1 The first point's y coordinate.
|
|
* @param x2 The second point's x coordinate.
|
|
* @param y2 The second point's y coordinate.
|
|
*/
|
|
template <class D>
|
|
edge (D x1, D y1, D x2, D y2)
|
|
: m_p1 (x1, y1), m_p2 (x2, y2)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The standard constructor taking two point objects.
|
|
*
|
|
* Creates an edge from p1 to p2.
|
|
*
|
|
* @param p1 The first point.
|
|
* @param p2 The first point.
|
|
*/
|
|
template <class D>
|
|
edge (const point<D> &p1, const point<D> &p2)
|
|
: m_p1 (p1), m_p2 (p2)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The standard constructor taking two point objects.
|
|
*
|
|
* Creates an edge from p1 to p2.
|
|
*
|
|
* @param p The first point.
|
|
* @param v The distance to the end point.
|
|
*/
|
|
template <class D>
|
|
edge (const point<D> &p, const vector<D> &v)
|
|
: m_p1 (p), m_p2 (p + v)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The copy constructor
|
|
*/
|
|
template <class D>
|
|
explicit edge (const edge<D> &e)
|
|
: m_p1 (e.p1 ()), m_p2 (e.p2 ())
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The (dummy) translation operator
|
|
*/
|
|
void translate (const edge<C> &d, db::generic_repository<C> &, db::ArrayRepository &)
|
|
{
|
|
*this = d;
|
|
}
|
|
|
|
/**
|
|
* @brief The (dummy) translation operator
|
|
*/
|
|
template <class T>
|
|
void translate (const edge<C> &d, const T &t, db::generic_repository<C> &, db::ArrayRepository &)
|
|
{
|
|
*this = d;
|
|
transform (t);
|
|
}
|
|
|
|
/**
|
|
* @brief A less operator to establish a sorting order.
|
|
*/
|
|
bool operator< (const edge<C> &b) const
|
|
{
|
|
return m_p1 < b.m_p1 || (m_p1 == b.m_p1 && m_p2 < b.m_p2);
|
|
}
|
|
|
|
/**
|
|
* @brief Equality test
|
|
*/
|
|
bool operator== (const edge<C> &b) const
|
|
{
|
|
return m_p1 == b.m_p1 && m_p2 == b.m_p2;
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality test
|
|
*/
|
|
bool operator!= (const edge<C> &b) const
|
|
{
|
|
return !operator== (b);
|
|
}
|
|
|
|
/**
|
|
* @brief A method binding of operator* (mainly for automation purposes)
|
|
*/
|
|
edge<C> scaled (double s) const
|
|
{
|
|
return edge<C> (point_type (p1 () * s), point_type (p2 () * s));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the moved edge
|
|
*
|
|
* Moves the edge by the given offset and returns the
|
|
* moved edge. The edge is not modified.
|
|
*
|
|
* @param p The distance to move the edge.
|
|
*
|
|
* @return The moved edge.
|
|
*/
|
|
edge<C> moved (const vector<C> &p) const
|
|
{
|
|
edge<C> b (*this);
|
|
b.move (p);
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the enlarged edge
|
|
*
|
|
* Enlarges the edge by the given offset and returns the
|
|
* moved edge. The edge is not modified. Enlargement means
|
|
* that the first point is shifted by -p, the second by p.
|
|
*
|
|
* @param p The distance to move the edge.
|
|
*
|
|
* @return The moved edge.
|
|
*/
|
|
edge<C> enlarged (const vector<C> &p) const
|
|
{
|
|
edge<C> b (*this);
|
|
b.enlarge (p);
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* @brief Extends the edge
|
|
*
|
|
* The extension is applied parallel to the edge at the
|
|
* start and end point.
|
|
* Degenerated edges become horizontal edges.
|
|
*/
|
|
edge<C> &extend (C e)
|
|
{
|
|
vector<double> dp;
|
|
if (is_degenerate ()) {
|
|
dp = vector<double> (e, 0.0);
|
|
} else {
|
|
dp = d () * (double (e) / double_length ());
|
|
}
|
|
*this = edge<C> (point<C> (point<double> (p1 ()) - dp), point<C> (point<double> (p2 ()) + dp));
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the extended edge
|
|
*
|
|
* The extension is applied parallel to the edge at the
|
|
* start and end point.
|
|
* Degenerated edges become horizontal edges.
|
|
*/
|
|
edge<C> extended (C e) const
|
|
{
|
|
vector<double> dp;
|
|
if (is_degenerate ()) {
|
|
dp = vector<double> (e, 0.0);
|
|
} else {
|
|
dp = d () * (double (e) / double_length ());
|
|
}
|
|
return edge<C> (point<C> (point<double> (p1 ()) - dp), point<C> (point<double> (p2 ()) + dp));
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the shifted edge
|
|
*
|
|
* The shift is applied perpendicular to the edge to the left of the edge
|
|
* if the shift is positive and to the right if negative.
|
|
* Degenerated edges are not shifted.
|
|
*/
|
|
edge<C> shifted (C e) const
|
|
{
|
|
if (is_degenerate ()) {
|
|
return *this;
|
|
} else {
|
|
vector<double> dp = d () * (double (e) / double_length ());
|
|
dp = vector<double> (-dp.y (), dp.x ());
|
|
return edge<C> (point<C> (point<double> (p1 ()) + dp), point<C> (point<double> (p2 ()) + dp));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Shifts the edge
|
|
*
|
|
* The shift is applied perpendicular to the edge to the left of the edge
|
|
* if the shift is positive and to the right if negative.
|
|
* Degenerated edges are not shifted.
|
|
*/
|
|
edge<C> &shift (C e)
|
|
{
|
|
if (! is_degenerate ()) {
|
|
vector<double> dp = d () * (double (e) / double_length ());
|
|
dp = vector<double> (-dp.y (), dp.x ());
|
|
*this = edge<C> (point<C> (point<double> (p1 ()) + dp), point<C> (point<double> (p2 ()) + dp));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Transform the edge.
|
|
*
|
|
* Transforms the edge with the given transformation.
|
|
* Modifies the edge with the transformed edge.
|
|
*
|
|
* @param t The transformation to apply.
|
|
*
|
|
* @return The transformed edge.
|
|
*/
|
|
template <class Tr>
|
|
edge<C> &transform (const Tr &t)
|
|
{
|
|
*this = edge<C> (t * m_p1, t * m_p2);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Transform the edge.
|
|
*
|
|
* Transforms the edge with the given transformation.
|
|
* Does not modify the edge but returns the transformed edge.
|
|
*
|
|
* @param t The transformation to apply.
|
|
*
|
|
* @return The transformed edge.
|
|
*/
|
|
template <class Tr>
|
|
edge<typename Tr::target_coord_type> transformed (const Tr &t) const
|
|
{
|
|
return edge<typename Tr::target_coord_type> (t * m_p1, t * m_p2);
|
|
}
|
|
|
|
/**
|
|
* @brief Moves the edge.
|
|
*
|
|
* Moves the edge by the given offset and returns the
|
|
* moved edge. The edge is overwritten.
|
|
*
|
|
* @param p The distance to move the edge.
|
|
*
|
|
* @return The moved edge.
|
|
*/
|
|
edge<C> &move (const vector<C> &p)
|
|
{
|
|
m_p1 += p;
|
|
m_p2 += p;
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Enlarges the edge.
|
|
*
|
|
* Enlarges the edge by the given distance and returns the
|
|
* enlarged edge. The edge is overwritten.
|
|
*
|
|
* @param p The distance to move the edge points.
|
|
*
|
|
* @return The enlarged edge.
|
|
*/
|
|
edge<C> &enlarge (const vector<C> &p)
|
|
{
|
|
m_p1 -= p;
|
|
m_p2 += p;
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the first point.
|
|
*/
|
|
void set_p1 (const point<C> &p)
|
|
{
|
|
m_p1 = p;
|
|
}
|
|
|
|
/**
|
|
* @brief Set the second point.
|
|
*/
|
|
void set_p2 (const point<C> &p)
|
|
{
|
|
m_p2 = p;
|
|
}
|
|
|
|
/**
|
|
* @brief The first point.
|
|
*/
|
|
const point<C> &p1 () const
|
|
{
|
|
return m_p1;
|
|
}
|
|
|
|
/**
|
|
* @brief The second point.
|
|
*/
|
|
const point<C> &p2 () const
|
|
{
|
|
return m_p2;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the bounding box
|
|
*/
|
|
box_type bbox () const
|
|
{
|
|
return box_type (m_p1, m_p2);
|
|
}
|
|
|
|
/**
|
|
* @brief The horizontal extend of the edge.
|
|
*/
|
|
vector_type d () const
|
|
{
|
|
return vector_type (dx (), dy ());
|
|
}
|
|
|
|
/**
|
|
* @brief The horizontal extend of the edge.
|
|
*/
|
|
C dx () const
|
|
{
|
|
return m_p2.x () - m_p1.x ();
|
|
}
|
|
|
|
/**
|
|
* @brief The vertical extend of the edge.
|
|
*/
|
|
C dy () const
|
|
{
|
|
return m_p2.y () - m_p1.y ();
|
|
}
|
|
|
|
/**
|
|
* @brief Shortcut for p1().x()
|
|
*/
|
|
C x1 () const
|
|
{
|
|
return m_p1.x ();
|
|
}
|
|
|
|
/**
|
|
* @brief Shortcut for p1().y()
|
|
*/
|
|
C y1 () const
|
|
{
|
|
return m_p1.y ();
|
|
}
|
|
|
|
/**
|
|
* @brief Shortcut for p2().x()
|
|
*/
|
|
C x2 () const
|
|
{
|
|
return m_p2.x ();
|
|
}
|
|
|
|
/**
|
|
* @brief Shortcut for p2().y()
|
|
*/
|
|
C y2 () const
|
|
{
|
|
return m_p2.y ();
|
|
}
|
|
|
|
/**
|
|
* @brief The absolute value of the horizontal extend of the edge.
|
|
*
|
|
* This function is safe against coordinate overflow for int32
|
|
* types.
|
|
*/
|
|
distance_type dx_abs () const
|
|
{
|
|
return m_p2.x () > m_p1.x () ? m_p2.x () - m_p1.x () : m_p1.x () - m_p2.x ();
|
|
}
|
|
|
|
/**
|
|
* @brief The vertical extend of the edge.
|
|
*
|
|
* This function is safe against coordinate overflow for int32
|
|
* types.
|
|
*/
|
|
distance_type dy_abs () const
|
|
{
|
|
return m_p2.y () > m_p1.y () ? m_p2.y () - m_p1.y () : m_p1.y () - m_p2.y ();
|
|
}
|
|
|
|
/**
|
|
* @brief Test if the edge is orthogonal (vertical or horizontal)
|
|
*/
|
|
bool is_ortho () const
|
|
{
|
|
return m_p1.x () == m_p2.x () || m_p1.y () == m_p2.y ();
|
|
}
|
|
|
|
/**
|
|
* @brief Test for degenerated edge
|
|
*/
|
|
bool is_degenerate () const
|
|
{
|
|
return m_p1 == m_p2;
|
|
}
|
|
|
|
/**
|
|
* @brief The length of the edge
|
|
*/
|
|
distance_type length () const
|
|
{
|
|
double ddx (m_p2.x () - m_p1.x ());
|
|
double ddy (m_p2.y () - m_p1.y ());
|
|
return coord_traits::rounded_distance (sqrt (ddx * ddx + ddy * ddy));
|
|
}
|
|
|
|
/**
|
|
* @brief The length of the edge
|
|
*/
|
|
double double_length () const
|
|
{
|
|
double ddx (m_p2.x () - m_p1.x ());
|
|
double ddy (m_p2.y () - m_p1.y ());
|
|
return sqrt (ddx * ddx + ddy * ddy);
|
|
}
|
|
|
|
/**
|
|
* @brief The square of the length of the edge
|
|
*/
|
|
area_type sq_length () const
|
|
{
|
|
return coord_traits::sq_length (m_p2.x (), m_p2.y (), m_p1.x (), m_p1.y ());
|
|
}
|
|
|
|
/**
|
|
* @brief The square of the length of the edge
|
|
*/
|
|
double double_sq_length () const
|
|
{
|
|
double ddx (m_p2.x () - m_p1.x ());
|
|
double ddy (m_p2.y () - m_p1.y ());
|
|
return (ddx * ddx + ddy * ddy);
|
|
}
|
|
|
|
/**
|
|
* @brief The orthogonal length of the edge
|
|
*
|
|
* @return The orthogonal length (abs(dx)+abs(dy))
|
|
*/
|
|
distance_type ortho_length () const
|
|
{
|
|
return dx_abs () + dy_abs ();
|
|
}
|
|
|
|
/**
|
|
* @brief Default conversion to string
|
|
*/
|
|
std::string to_string () const
|
|
{
|
|
return to_string (0.0);
|
|
}
|
|
|
|
/**
|
|
* @brief Conversion to a string.
|
|
*
|
|
* If dbu is set, it determines the factor by which the coordinates are multiplied to render
|
|
* micron units. In addition, a micron format is choosen for output of these coordinates.
|
|
*/
|
|
std::string to_string (double dbu) const
|
|
{
|
|
return "(" + m_p1.to_string (dbu) + ";" + m_p2.to_string (dbu) + ")";
|
|
}
|
|
|
|
/**
|
|
* @brief Reduce the edge
|
|
*
|
|
* Reduction of a edge normalizes the edge by extracting
|
|
* a suitable transformation and placing the edge in a unique
|
|
* way. In this implementation, p1 is set to zero.
|
|
*
|
|
* @return The transformation that must be applied to render the original edge
|
|
*/
|
|
void reduce (simple_trans<coord_type> &tr)
|
|
{
|
|
point_type d (m_p1);
|
|
move (-d);
|
|
tr = simple_trans<coord_type> (simple_trans<coord_type>::r0, d);
|
|
}
|
|
|
|
/**
|
|
* @brief Reduce the edge
|
|
*
|
|
* Reduction of a edge normalizes the edge by extracting
|
|
* a suitable transformation and placing the edge in a unique
|
|
* way. In this implementation, p1 is set to zero.
|
|
*
|
|
* @return The transformation that must be applied to render the original edge
|
|
*/
|
|
void reduce (disp_trans<coord_type> &tr)
|
|
{
|
|
vector_type d (m_p1);
|
|
move (-d);
|
|
tr = disp_trans<coord_type> (d);
|
|
}
|
|
|
|
/**
|
|
* @brief Reduce the edge
|
|
*
|
|
* Reduction of a edge normalizes the edge by extracting
|
|
* a suitable transformation and placing the edge in a unique
|
|
* way. In this implementation, p1 is set to zero.
|
|
*
|
|
* @return The transformation that must be applied to render the original edge
|
|
*/
|
|
void reduce (unit_trans<coord_type> & /*tr*/)
|
|
{
|
|
// .. no reduction possible ..
|
|
}
|
|
|
|
/**
|
|
* @brief Test for being parallel
|
|
*
|
|
* @param e The edge to test against
|
|
*
|
|
* @return True if both edges are parallel
|
|
*/
|
|
bool parallel (const db::edge<C> &e) const
|
|
{
|
|
return coord_traits::vprod_sign (m_p2.x () - m_p1.x (), m_p2.y () - m_p1.y (),
|
|
e.m_p2.x () - e.m_p1.x (), e.m_p2.y () - e.m_p1.y (),
|
|
0, 0) == 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Test whether a point is on an edge.
|
|
*
|
|
* A point is on a edge if it is on (at least closer
|
|
* than a grid point) the edge.
|
|
*
|
|
* @param The point to test with the edge.
|
|
*
|
|
* @return True if the point is on the edge.
|
|
*/
|
|
bool contains (const db::point<C> &p) const
|
|
{
|
|
if (is_degenerate ()) {
|
|
return m_p1 == p;
|
|
} else {
|
|
return distance_abs (p) < coord_traits::prec_distance () &&
|
|
coord_traits::sprod_sign (p.x (), p.y (), m_p2.x (), m_p2.y (), m_p1.x (), m_p1.y ()) >= 0 &&
|
|
coord_traits::sprod_sign (p.x (), p.y (), m_p1.x (), m_p1.y (), m_p2.x (), m_p2.y ()) >= 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Test whether a point is on an edge excluding the endpoints.
|
|
*
|
|
* A point is on a edge if it is on (at least closer
|
|
* than a grid point) the edge.
|
|
*
|
|
* @param The point to test with the edge.
|
|
*
|
|
* @return True if the point is on the edge but not equal p1 or p2.
|
|
*/
|
|
bool contains_excl (const db::point<C> &p) const
|
|
{
|
|
if (is_degenerate ()) {
|
|
return false;
|
|
} else {
|
|
return distance_abs (p) < coord_traits::prec_distance () &&
|
|
coord_traits::sprod_sign (p.x (), p.y (), m_p2.x (), m_p2.y (), m_p1.x (), m_p1.y ()) > 0 &&
|
|
coord_traits::sprod_sign (p.x (), p.y (), m_p1.x (), m_p1.y (), m_p2.x (), m_p2.y ()) > 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Coincidence check.
|
|
*
|
|
* Checks whether a edge is coincident with another edge.
|
|
* Coincidence is defined by being parallel, oriented the same way and that
|
|
* both edges share more than one point.
|
|
*
|
|
* @param e the edge to test with
|
|
*
|
|
* @return True if the edges are coincident.
|
|
*/
|
|
bool coincident (const db::edge<C> &e) const
|
|
{
|
|
return ! is_degenerate () && ! e.is_degenerate () &&
|
|
distance_abs (e.p1 ()) < coord_traits::prec_distance () &&
|
|
distance_abs (e.p2 ()) < coord_traits::prec_distance () &&
|
|
(sprod_sign (*this, e) < 0 ?
|
|
(coord_traits::sprod_sign (e.p2 ().x (), e.p2 ().y (), p1 ().x (), p1 ().y (), p2 ().x (), p2 ().y ()) > 0 &&
|
|
coord_traits::sprod_sign (e.p1 ().x (), e.p1 ().y (), p2 ().x (), p2 ().y (), p1 ().x (), p1 ().y ()) > 0) :
|
|
(coord_traits::sprod_sign (e.p1 ().x (), e.p1 ().y (), p1 ().x (), p1 ().y (), p2 ().x (), p2 ().y ()) > 0 &&
|
|
coord_traits::sprod_sign (e.p2 ().x (), e.p2 ().y (), p2 ().x (), p2 ().y (), p1 ().x (), p1 ().y ()) > 0));
|
|
}
|
|
|
|
/**
|
|
* @brief Intersection test.
|
|
*
|
|
* Returns true if the edges intersect.
|
|
* If the edges coincide, they also intersect.
|
|
* For degenerated edges, the intersection is mapped to
|
|
* point containment tests.
|
|
*
|
|
* @param e The edge to test.
|
|
*/
|
|
bool intersect (const db::edge<C> &e) const
|
|
{
|
|
if (is_degenerate ()) {
|
|
return e.contains (p1 ());
|
|
} else if (e.is_degenerate ()) {
|
|
return contains (e.p1 ());
|
|
} else if (! box_type (p1 (), p2 ()).touches (box_type (e.p1 (), e.p2 ()))) {
|
|
return false;
|
|
} else if (is_ortho () && e.is_ortho ()) {
|
|
return true;
|
|
} else {
|
|
return crossed_by (e) && e.crossed_by (*this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Intersection test with intersect point.
|
|
*
|
|
* Returns true if the edges intersect and returns the
|
|
* intersection point if true. For coinciding edges one
|
|
* of the points that coincide is returned.
|
|
*
|
|
* @param e The edge to test.
|
|
*
|
|
* @return A pair <bool,point> with true as the first element
|
|
* if the edges intersect and the intersection point as the second.
|
|
* If the edges do not intersect, returns <false,undef.>.
|
|
*/
|
|
std::pair <bool, db::point<C> > intersect_point (const db::edge<C> &e) const
|
|
{
|
|
if (is_degenerate ()) {
|
|
if (e.contains (p1 ())) {
|
|
return std::make_pair (true, p1 ());
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
} else if (e.is_degenerate ()) {
|
|
if (contains (e.p1 ())) {
|
|
return std::make_pair (true, e.p1 ());
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
} else if (! box_type (p1 (), p2 ()).touches (box_type (e.p1 (), e.p2 ()))) {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
} else if (is_ortho () && e.is_ortho ()) {
|
|
coord_type x = std::max (std::min (p1 ().x (), p2 ().x ()), std::min (e.p1 ().x (), e.p2 ().x ()));
|
|
coord_type y = std::max (std::min (p1 ().y (), p2 ().y ()), std::min (e.p1 ().y (), e.p2 ().y ()));
|
|
return std::make_pair (true, db::point<C> (x, y));
|
|
} else if (! crossed_by (e)) {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
} else {
|
|
|
|
bool res = true;
|
|
bool ends_on_edge = false;
|
|
|
|
area_type vxa = coord_traits::vprod (e.p2 ().x (), e.p2 ().y (), m_p1.x (), m_p1.y (), e.p1 ().x (), e.p1 ().y ());
|
|
if (vxa <= -coord_traits::prec_area ()) {
|
|
res = false;
|
|
} else if (vxa < coord_traits::prec_area ()) {
|
|
ends_on_edge = true;
|
|
}
|
|
|
|
area_type vxb = -coord_traits::vprod (e.p2 ().x (), e.p2 ().y (), m_p2.x (), m_p2.y (), e.p1 ().x (), e.p1 ().y ());
|
|
if (vxb <= -coord_traits::prec_area ()) {
|
|
res = !res;
|
|
} else if (vxb < coord_traits::prec_area ()) {
|
|
ends_on_edge = true;
|
|
}
|
|
|
|
if (ends_on_edge) {
|
|
|
|
if (contains (e.p1 ())) {
|
|
return std::make_pair (true, e.p1 ());
|
|
} else if (contains (e.p2 ())) {
|
|
return std::make_pair (true, e.p2 ());
|
|
} else if (e.contains (p1 ())) {
|
|
return std::make_pair (true, p1 ());
|
|
} else if (e.contains (p2 ())) {
|
|
return std::make_pair (true, p2 ());
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
|
|
} else if (res) {
|
|
|
|
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
|
|
|
coord_type x = m_p1.x () + coord_traits::rounded (dx () * f);
|
|
coord_type y = m_p1.y () + coord_traits::rounded (dy () * f);
|
|
|
|
return std::make_pair (true, db::point<C> (x, y));
|
|
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Distance between the edge and a point.
|
|
*
|
|
* Returns the distance between the edge and the point. The
|
|
* distance is signed which is negative if the point is to the
|
|
* "left" of the edge and positive if the point is to the "right".
|
|
* The distance is measured by projecting the point onto the
|
|
* line through the edge. If the edge is degenerated, the distance
|
|
* is not defined.
|
|
*
|
|
* @param p The point to test.
|
|
*
|
|
* @return The distance
|
|
*/
|
|
coord_type distance (const db::point<C> &p) const
|
|
{
|
|
// the distance is computed from
|
|
// d = (a x b) / sqrt (a * a)
|
|
// where b = p - p1, a = p2 - p1
|
|
if (is_degenerate ()) {
|
|
// for safty handle this case - without a reasonable result
|
|
return 0;
|
|
} else {
|
|
// compute the distance as described above
|
|
area_type axb = coord_traits::vprod (m_p2.x (), m_p2.y (), p.x (), p.y (), m_p1.x (), m_p1.y ());
|
|
double d = double (axb) / double (length ());
|
|
// and round
|
|
return coord_traits::rounded (d);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Side of the point
|
|
*
|
|
* Returns 1 if the point is "left" of the edge, 0 if on
|
|
* and -1 if the point is "right" of the edge.
|
|
*
|
|
* @param p The point to test.
|
|
*
|
|
* @return The side value
|
|
*/
|
|
int side_of (const db::point<C> &p) const
|
|
{
|
|
// the distance is computed from
|
|
// d = (a x b) / sqrt (a * a)
|
|
// where b = p - p1, a = p2 - p1
|
|
if (is_degenerate ()) {
|
|
// for safty handle this case - without a reasonable result
|
|
return 0;
|
|
} else {
|
|
// compute the side as the sign of the distance as in "distance"
|
|
area_type axb = coord_traits::vprod (m_p2.x (), m_p2.y (), p.x (), p.y (), m_p1.x (), m_p1.y ());
|
|
if (axb >= coord_traits::prec_area ()) {
|
|
return 1;
|
|
} else if (axb <= -coord_traits::prec_area ()) {
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Absolute distance between the edge and a point.
|
|
*
|
|
* Returns the distance between the edge and the point.
|
|
*
|
|
* @param p The point to test.
|
|
*
|
|
* @return The distance
|
|
*/
|
|
distance_type distance_abs (const db::point<C> &p) const
|
|
{
|
|
// the distance is computed from
|
|
// d = (a x b) / sqrt (a * a)
|
|
// where b = p - p1, a = p2 - p1
|
|
if (is_degenerate ()) {
|
|
// for safty handle this case - without a reasonable result
|
|
return 0;
|
|
} else {
|
|
// compute the distance as described above
|
|
area_type axb = coord_traits::vprod (m_p2.x (), m_p2.y (), p.x (), p.y (), m_p1.x (), m_p1.y ());
|
|
double d = fabs (double (axb)) / double (length ());
|
|
// and round
|
|
return coord_traits::rounded_distance (d);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Swap the points of the edge
|
|
*/
|
|
edge<C> &swap_points ()
|
|
{
|
|
std::swap (m_p1, m_p2);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the edge with swapped points
|
|
*/
|
|
edge<C> swapped_points () const
|
|
{
|
|
edge<C> e = *this;
|
|
e.swap_points ();
|
|
return e;
|
|
}
|
|
|
|
/**
|
|
* @brief Clip the line given by the edge at the given box
|
|
*
|
|
* Determines the part of the line (given by the edge) that runs through the given box.
|
|
* If the line does not hit the box, false is returned in the first member of the
|
|
* return value.
|
|
*
|
|
* @return first: false if the line does not hit the box, second: the part of the line inside the box
|
|
*/
|
|
std::pair<bool, edge> clipped_line (const db::box<C> &box) const
|
|
{
|
|
if (box.empty ()) {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
}
|
|
|
|
std::pair <bool, db::point<C> > pc1 (false, db::point<C> ()), pc2 (false, db::point<C> ());
|
|
|
|
pc1 = cut_point (db::edge<C> (box.p1 (), db::point<C> (box.p1 ().x (), box.p2 ().y ())));
|
|
if (pc1.first) {
|
|
pc2 = cut_point (db::edge<C> (db::point<C> (box.p2 ().x (), box.p1 ().y ()), box.p2 ()));
|
|
}
|
|
|
|
if (! pc1.first || ! pc2.first) {
|
|
pc1 = cut_point (db::edge<C> (box.p1 (), db::point<C> (box.p2 ().x (), box.p1 ().y ())));
|
|
if (pc1.first) {
|
|
pc2 = cut_point (db::edge<C> (db::point<C> (box.p1 ().x (), box.p2 ().y ()), box.p2 ()));
|
|
}
|
|
}
|
|
|
|
if (pc1.first && pc2.first) {
|
|
return db::edge<C> (pc1.second, pc2.second).clipped (box);
|
|
} else {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Clip at rectangle
|
|
*
|
|
* Clips the edge at the box provided. Maintains the orientation of the
|
|
* edge.
|
|
*
|
|
* @return first: false if edge disappears. second: the clipped edge
|
|
*/
|
|
std::pair<bool, edge> clipped (const db::box<C> &box) const
|
|
{
|
|
if (box.empty ()) {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
}
|
|
|
|
bool swapped = false;
|
|
|
|
db::point<C> p1 (m_p1), p2 (m_p2);
|
|
|
|
if (p1.x () > p2.x ()) {
|
|
std::swap (p1, p2);
|
|
swapped = !swapped;
|
|
}
|
|
|
|
if (p2.x () < box.left ()) {
|
|
return std::make_pair (false, db::edge<C>());
|
|
} else if (p1.x () < box.left ()) {
|
|
p1 = db::point<C> (box.left (), m_p1.y () + db::coord_traits<C>::rounded((double)(box.left () - m_p1.x ()) * double (dy ()) / double (dx ())));
|
|
}
|
|
if (p1.x () > box.right ()) {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
} else if (p2.x () > box.right ()) {
|
|
p2 = db::point<C> (box.right (), m_p1.y () + db::coord_traits<C>::rounded((double)(box.right () - m_p1.x ()) * double (dy ()) / double (dx ())));
|
|
}
|
|
|
|
if (p1.y () > p2.y ()) {
|
|
std::swap (p1, p2);
|
|
swapped = !swapped;
|
|
}
|
|
|
|
if (p2.y () < box.bottom ()) {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
} else if (p1.y () < box.bottom ()) {
|
|
p1 = db::point<C> (std::max (box.left (), std::min (box.right (), m_p1.x () + db::coord_traits<C>::rounded((double)(box.bottom () - m_p1.y ()) * double (dx ()) / double (dy ())))), box.bottom ());
|
|
}
|
|
if (p1.y () > box.top ()) {
|
|
return std::make_pair (false, db::edge<C> ());
|
|
} else if (p2.y () > box.top ()) {
|
|
p2 = db::point<C> (std::max (box.left (), std::min (box.right (), m_p1.x () + db::coord_traits<C>::rounded((double)(box.top () - m_p1.y ()) * double (dx ()) / double (dy ())))), box.top ());
|
|
}
|
|
|
|
if (swapped) {
|
|
return std::make_pair (true, db::edge<C> (p2, p1));
|
|
} else {
|
|
return std::make_pair (true, db::edge<C> (p1, p2));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Check, if an edge is cut by a line (given by an edge)
|
|
*
|
|
* This method returns true if p1 is in one semispace
|
|
* while p2 is in the other or one of them is on the line
|
|
* through the edge
|
|
*/
|
|
bool crossed_by (const db::edge <C> &e) const
|
|
{
|
|
// this is basically this algorithm:
|
|
// res = true;
|
|
// if (side_of (e.p1 ()) < 0) {
|
|
// res = false
|
|
// } else if (side_of (e.p1 ()) == 0) {
|
|
// return true;
|
|
// }
|
|
// if (side_of (e.p2 ()) > 0) {
|
|
// res = !res
|
|
// } else if (side_of (e.p2 ()) == 0) {
|
|
// return true;
|
|
// }
|
|
// return res;
|
|
|
|
bool res = true;
|
|
|
|
area_type vxa = coord_traits::vprod (m_p2.x (), m_p2.y (), e.p1 ().x (), e.p1 ().y (), m_p1.x (), m_p1.y ());
|
|
if (vxa <= -coord_traits::prec_area ()) {
|
|
res = false;
|
|
} else if (vxa < coord_traits::prec_area ()) {
|
|
return true;
|
|
}
|
|
|
|
area_type vxb = -coord_traits::vprod (m_p2.x (), m_p2.y (), e.p2 ().x (), e.p2 ().y (), m_p1.x (), m_p1.y ());
|
|
if (vxb <= -coord_traits::prec_area ()) {
|
|
res = !res;
|
|
} else if (vxb < coord_traits::prec_area ()) {
|
|
return true;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* @brief Check, if an edge is cut by a line (given by an edge)
|
|
*
|
|
* This method returns true if p1 is in one semispace
|
|
* while p2 is in the other or one of them is on the line
|
|
* through the edge. In addition to "crossed_by", also returns
|
|
* the point at which the edge is crossed.
|
|
*/
|
|
std::pair <bool, db::point<C> > crossed_by_point (const db::edge <C> &e) const
|
|
{
|
|
bool res = true;
|
|
|
|
area_type vxa = coord_traits::vprod (m_p2.x (), m_p2.y (), e.p1 ().x (), e.p1 ().y (), m_p1.x (), m_p1.y ());
|
|
if (vxa <= -coord_traits::prec_area ()) {
|
|
res = false;
|
|
} else if (vxa < coord_traits::prec_area ()) {
|
|
return std::make_pair (true, e.p1 ());
|
|
}
|
|
|
|
area_type vxb = -coord_traits::vprod (m_p2.x (), m_p2.y (), e.p2 ().x (), e.p2 ().y (), m_p1.x (), m_p1.y ());
|
|
if (vxb <= -coord_traits::prec_area ()) {
|
|
res = !res;
|
|
} else if (vxb < coord_traits::prec_area ()) {
|
|
return std::make_pair (true, e.p2 ());
|
|
}
|
|
|
|
if (res) {
|
|
|
|
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
|
|
|
coord_type x = e.p1 ().x () + coord_traits::rounded (e.dx () * f);
|
|
coord_type y = e.p1 ().y () + coord_traits::rounded (e.dy () * f);
|
|
|
|
return std::make_pair (true, db::point<C> (x, y));
|
|
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Compute the projection of a point on the edge
|
|
*
|
|
* This method returns true in the first member of the return
|
|
* value if the point can be projected on the edge. In this case,
|
|
* the second member will return the point projected on the edge.
|
|
*
|
|
* @param point The point to be projected
|
|
*/
|
|
std::pair <bool, db::point<C> > projected (const db::point<C> &pt) const
|
|
{
|
|
return db::edge <C> (pt, pt + db::vector<C> (dy (), -dx ())).crossed_by_point (*this);
|
|
}
|
|
|
|
/**
|
|
* @brief Compute cut point of two lines (given by edges)
|
|
*
|
|
* This method returns true in the first member if both edges cut.
|
|
* If this is the case, the second member of the returned pair is
|
|
* the point at which the edges would intersect, given they are
|
|
* extended beyond their ends.
|
|
*/
|
|
std::pair <bool, db::point<C> > cut_point (const db::edge<C> &e2) const
|
|
{
|
|
double pr1 = double (coord_traits::vprod (e2.p1 ().x (), e2.p1 ().y (), this->p2 ().x (), this->p2 ().y (), this->p1 ().x (), this->p1 ().y ()));
|
|
double pr2 = double (coord_traits::vprod (e2.dx (), e2.dy (), this->dx (), this->dy (), 0, 0));
|
|
if (fabs (pr2) > double (coord_traits::prec_area ())) {
|
|
db::point<C> p = e2.p1 () - db::vector<C> ((e2.p2 () - e2.p1 ()) * (pr1 / pr2));
|
|
return std::make_pair (true, p);
|
|
} else {
|
|
return std::make_pair (false, db::point<C> (0, 0));
|
|
}
|
|
}
|
|
|
|
private:
|
|
point<C> m_p1, m_p2;
|
|
};
|
|
|
|
/**
|
|
* @brief "intersect" binary predicate
|
|
*/
|
|
template <class Edge>
|
|
struct edges_intersect
|
|
{
|
|
bool operator() (const Edge &e1, const Edge &e2) const
|
|
{
|
|
return e1.intersect (e2);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Scaling of an edge
|
|
*
|
|
* @param e The edge to scale.
|
|
* @param s The scaling factor
|
|
*
|
|
* @return The scaled edge
|
|
*/
|
|
template <class C>
|
|
inline edge<double>
|
|
operator* (const edge<C> &e, double s)
|
|
{
|
|
return edge<double> (e.p1 () * s, e.p2 () * s);
|
|
}
|
|
|
|
/**
|
|
* @brief Binary * operator (transformation)
|
|
*
|
|
* Transforms the edge with the given transformation and
|
|
* returns the result.
|
|
*
|
|
* @param t The transformation to apply
|
|
* @param e The edge to transform
|
|
* @return t * e
|
|
*/
|
|
template <class Tr>
|
|
inline edge<typename Tr::target_coord_type>
|
|
operator* (const Tr &t, const edge<typename Tr::coord_type> &e)
|
|
{
|
|
return e.transformed (t);
|
|
}
|
|
|
|
/**
|
|
* @brief Output stream insertion operator
|
|
*/
|
|
template <class C>
|
|
inline std::ostream &
|
|
operator<< (std::ostream &os, const edge<C> &e)
|
|
{
|
|
return (os << e.to_string ());
|
|
}
|
|
|
|
/**
|
|
* @brief The standard edge typedef
|
|
*/
|
|
typedef edge<db::Coord> Edge;
|
|
|
|
/**
|
|
* @brief The double coordinate edge typedef
|
|
*/
|
|
typedef edge<db::DCoord> DEdge;
|
|
|
|
/**
|
|
* @brief Convenience wrappers for coord_traits functions: vector product: p x q
|
|
*/
|
|
template <class C>
|
|
typename db::coord_traits<C>::area_type vprod (const db::edge<C> &p, const db::edge<C> &q)
|
|
{
|
|
return db::coord_traits<C>::vprod (p.dx (), p.dy (), q.dx (), q.dy (), 0, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience wrappers for coord_traits functions: vector product sign: sign(p x q)
|
|
*/
|
|
template <class C>
|
|
int vprod_sign (const db::edge<C> &p, const db::edge<C> &q)
|
|
{
|
|
return db::coord_traits<C>::vprod_sign (p.dx (), p.dy (), q.dx (), q.dy (), 0, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience wrappers for coord_traits functions: scalar product: 0->p x 0->q
|
|
*/
|
|
template <class C>
|
|
typename db::coord_traits<C>::area_type sprod (const db::edge<C> &p, const db::edge<C> &q)
|
|
{
|
|
return db::coord_traits<C>::sprod (p.dx (), p.dy (), q.dx (), q.dy (), 0, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Convenience wrappers for coord_traits functions: scalar product sign: sign(0->p x 0->q)
|
|
*/
|
|
template <class C>
|
|
int sprod_sign (const db::edge<C> &p, const db::edge<C> &q)
|
|
{
|
|
return db::coord_traits<C>::sprod_sign (p.dx (), p.dy (), q.dx (), q.dy (), 0, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Determines the lower bound of the edge
|
|
*/
|
|
template <class C>
|
|
inline C edge_ymin (const db::edge<C> &e)
|
|
{
|
|
return std::min (e.p1 ().y (), e.p2 ().y ());
|
|
}
|
|
|
|
/**
|
|
* @brief Determines the upper bound of the edge
|
|
*/
|
|
template <class C>
|
|
inline C edge_ymax (const db::edge<C> &e)
|
|
{
|
|
return std::max (e.p1 ().y (), e.p2 ().y ());
|
|
}
|
|
|
|
/**
|
|
* @brief Determines the left bound of the edge
|
|
*/
|
|
template <class C>
|
|
inline C edge_xmin (const db::edge<C> &e)
|
|
{
|
|
return std::min (e.p1 ().x (), e.p2 ().x ());
|
|
}
|
|
|
|
/**
|
|
* @brief Determines the right bound of the edge
|
|
*/
|
|
template <class C>
|
|
inline C edge_xmax (const db::edge<C> &e)
|
|
{
|
|
return std::max (e.p1 ().x (), e.p2 ().x ());
|
|
}
|
|
|
|
/**
|
|
* @brief Computes the x value of an edge at the given y value
|
|
*
|
|
* HINT: for application in the scanline algorithm
|
|
* it is important that this method delivers exactly (!) the same x for the same edge
|
|
* (after normalization to dy()>0) and same y!
|
|
*/
|
|
template <class C>
|
|
inline double edge_xaty (db::edge<C> e, C y)
|
|
{
|
|
if (e.p1 ().y () > e.p2 ().y ()) {
|
|
e.swap_points ();
|
|
}
|
|
|
|
if (y <= e.p1 ().y ()) {
|
|
return e.p1 ().x ();
|
|
} else if (y >= e.p2 ().y ()) {
|
|
return e.p2 ().x ();
|
|
} else {
|
|
return double (e.p1 ().x ()) + double (e.dx ()) * double (y - e.p1 ().y ()) / double (e.dy ());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Functor that compares two edges by their lower bound.
|
|
*/
|
|
template <class C>
|
|
class edge_ymin_compare
|
|
{
|
|
public:
|
|
bool operator() (const db::edge<C> &a, const db::edge<C> &b) const
|
|
{
|
|
C ya = edge_ymin (a);
|
|
C yb = edge_ymin (b);
|
|
if (ya != yb) {
|
|
return ya < yb;
|
|
} else {
|
|
return a < b;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Functor that compares two edges by their upper bound.
|
|
*/
|
|
template <class C>
|
|
class edge_ymax_compare
|
|
{
|
|
public:
|
|
bool operator() (const db::edge<C> &a, const db::edge<C> &b) const
|
|
{
|
|
C ya = edge_ymax (a);
|
|
C yb = edge_ymax (b);
|
|
if (ya != yb) {
|
|
return ya < yb;
|
|
} else {
|
|
return a < b;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Functor that compares two edges by their left bound.
|
|
*/
|
|
template <class C>
|
|
class edge_xmin_compare
|
|
{
|
|
public:
|
|
bool operator() (const db::edge<C> &a, const db::edge<C> &b) const
|
|
{
|
|
C ya = edge_xmin (a);
|
|
C yb = edge_xmin (b);
|
|
if (ya != yb) {
|
|
return ya < yb;
|
|
} else {
|
|
return a < b;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Functor that compares two edges by their right bound.
|
|
*/
|
|
template <class C>
|
|
class edge_xmax_compare
|
|
{
|
|
public:
|
|
bool operator() (const db::edge<C> &a, const db::edge<C> &b) const
|
|
{
|
|
C ya = edge_xmax (a);
|
|
C yb = edge_xmax (b);
|
|
if (ya != yb) {
|
|
return ya < yb;
|
|
} else {
|
|
return a < b;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Computes the left bound of the edge geometry for a given band [y1..y2].
|
|
*/
|
|
template <class C>
|
|
inline C edge_xmin_at_yinterval (const db::edge<C> &e, C y1, C y2)
|
|
{
|
|
if (e.dx () == 0) {
|
|
return e.p1 ().x ();
|
|
} else if (e.dy () == 0) {
|
|
return std::min (e.p1 ().x (), e.p2 ().x ());
|
|
} else {
|
|
return C (floor (edge_xaty (e, ((e.dy () < 0) ^ (e.dx () < 0)) == 0 ? y1 : y2)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Computes the right bound of the edge geometry for a given band [y1..y2].
|
|
*/
|
|
template <class C>
|
|
inline C edge_xmax_at_yinterval (const db::edge<C> &e, C y1, C y2)
|
|
{
|
|
if (e.dx () == 0) {
|
|
return e.p1 ().x ();
|
|
} else if (e.dy () == 0) {
|
|
return std::max (e.p1 ().x (), e.p2 ().x ());
|
|
} else {
|
|
return C (ceil (edge_xaty (e, ((e.dy () < 0) ^ (e.dx () < 0)) != 0 ? y1 : y2)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Functor that compares two edges by their left bound for a given interval [y1..y2].
|
|
*
|
|
* This function is intended for use in scanline scenarious to determine what edges are
|
|
* interacting in a certain y interval.
|
|
*/
|
|
template <class C>
|
|
struct edge_xmin_at_yinterval_compare
|
|
{
|
|
edge_xmin_at_yinterval_compare (C y1, C y2)
|
|
: m_y1 (y1), m_y2 (y2)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
bool operator() (const db::edge<C> &a, const db::edge<C> &b) const
|
|
{
|
|
if (edge_xmax (a) < edge_xmin (b)) {
|
|
return true;
|
|
} else if (edge_xmin (a) >= edge_xmax (b)) {
|
|
return false;
|
|
} else {
|
|
C xa = edge_xmin_at_yinterval (a, m_y1, m_y2);
|
|
C xb = edge_xmin_at_yinterval (b, m_y1, m_y2);
|
|
if (xa != xb) {
|
|
return xa < xb;
|
|
} else {
|
|
return a < b;
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
C m_y1, m_y2;
|
|
};
|
|
|
|
} // namespace db
|
|
|
|
/**
|
|
* @brief Special extractors for the edges
|
|
*/
|
|
|
|
namespace tl
|
|
{
|
|
/**
|
|
* @brief The type traits for the edge type
|
|
*/
|
|
template <class C>
|
|
struct type_traits <db::edge<C> > : public type_traits<void>
|
|
{
|
|
typedef trivial_relocate_required relocate_requirements;
|
|
typedef true_tag supports_extractor;
|
|
typedef true_tag supports_to_string;
|
|
typedef true_tag has_less_operator;
|
|
typedef true_tag has_equal_operator;
|
|
};
|
|
|
|
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Edge &b);
|
|
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DEdge &b);
|
|
|
|
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Edge &b);
|
|
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DEdge &b);
|
|
|
|
} // namespace tl
|
|
|
|
#endif
|
|
|