mirror of https://github.com/KLayout/klayout.git
Attempt to fix a scanline issue.
This commit is contained in:
parent
b10c64907a
commit
efd9e47c1f
|
|
@ -23,6 +23,33 @@
|
|||
|
||||
#include "dbEdge.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Computes the gcd of two numbers
|
||||
*/
|
||||
template <class C>
|
||||
inline C gcd (C a, C b)
|
||||
{
|
||||
while (b != 0) {
|
||||
a %= b;
|
||||
std::swap (a, b);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
db::Coord div_exact (db::Coord a, db::coord_traits<db::Coord>::area_type b, db::coord_traits<db::Coord>::area_type d)
|
||||
{
|
||||
if (a < 0) {
|
||||
return -db::Coord ((__int128 (-a) * __int128 (b) + __int128 (d / 2)) / __int128 (d));
|
||||
} else {
|
||||
return db::Coord ((__int128 (a) * __int128 (b) + __int128 ((d - 1) / 2)) / __int128 (d));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,25 @@
|
|||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief A helper function for dividing integers with exact rounding
|
||||
* This function computes (a*b/d) where rounding is exact in the sense of:
|
||||
* a*b/d == N+0.5 => div_exact(a*b/d) = N
|
||||
* b and d needs to be positive.
|
||||
* a can be positive or negative.
|
||||
* The implementation uses the gcd to reduce the ratios. This way we can
|
||||
* represent the numbers with the area type.
|
||||
*/
|
||||
db::Coord DB_PUBLIC div_exact (db::Coord a, db::coord_traits<db::Coord>::area_type b, db::coord_traits<db::Coord>::area_type d);
|
||||
|
||||
/**
|
||||
* @brief An overload of div_exact for double types
|
||||
*/
|
||||
inline db::DCoord div_exact (db::DCoord a, db::coord_traits<db::DCoord>::area_type b, db::coord_traits<db::DCoord>::area_type d)
|
||||
{
|
||||
return db::coord_traits<db::DCoord>::rounded (double (a) * double (b) / double (d));
|
||||
}
|
||||
|
||||
template <class C> class generic_repository;
|
||||
class ArrayRepository;
|
||||
|
||||
|
|
@ -794,10 +813,15 @@ public:
|
|||
|
||||
} else if (res) {
|
||||
|
||||
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
||||
if (vxa < 0) {
|
||||
vxa = -vxa;
|
||||
}
|
||||
if (vxb < 0) {
|
||||
vxb = -vxb;
|
||||
}
|
||||
|
||||
coord_type x = m_p1.x () + coord_traits::rounded (dx () * f);
|
||||
coord_type y = m_p1.y () + coord_traits::rounded (dy () * f);
|
||||
coord_type x = m_p1.x () + div_exact (dx (), vxa, vxa + vxb);
|
||||
coord_type y = m_p1.y () + div_exact (dy (), vxa, vxa + vxb);
|
||||
|
||||
return std::make_pair (true, db::point<C> (x, y));
|
||||
|
||||
|
|
@ -1073,10 +1097,15 @@ public:
|
|||
|
||||
if (res) {
|
||||
|
||||
double f = fabs (double (vxa)) / (fabs (double (vxa)) + fabs (double (vxb)));
|
||||
if (vxa < 0) {
|
||||
vxa = -vxa;
|
||||
}
|
||||
if (vxb < 0) {
|
||||
vxb = -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);
|
||||
coord_type x = e.p1 ().x () + div_exact (e.dx (), vxa, vxa + vxb);
|
||||
coord_type y = e.p1 ().y () + div_exact (e.dy (), vxa, vxa + vxb);
|
||||
|
||||
return std::make_pair (true, db::point<C> (x, y));
|
||||
|
||||
|
|
|
|||
|
|
@ -514,3 +514,74 @@ TEST(14)
|
|||
EXPECT_EQ (e.coincident (db::Edge (db::Point (49, 0), db::Point (200, 0))), false);
|
||||
}
|
||||
|
||||
// exact rounding behaviour
|
||||
TEST(15)
|
||||
{
|
||||
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||
// div_exact(a, b, d) computes a*b/d with exact rounding behaviour
|
||||
EXPECT_EQ (db::div_exact (area_type (0), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (0), area_type (176)), 0);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (3), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (4), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (7), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (12), area_type (22), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (13), area_type (22), area_type (176)), 2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (3 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (4 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (7 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (12 * 11), area_type (2), area_type (176)), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (13 * 11), area_type (2), area_type (176)), 2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3), area_type (22), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-7), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8), area_type (22), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-12), area_type (22), area_type (176)), -2);
|
||||
EXPECT_EQ (db::div_exact (area_type (-13), area_type (22), area_type (176)), -2);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3 * 11), area_type (2), area_type (176)), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-7 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8 * 11), area_type (2), area_type (176)), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-12 * 11), area_type (2), area_type (176)), -2);
|
||||
EXPECT_EQ (db::div_exact (area_type (-13 * 11), area_type (2), area_type (176)), -2);
|
||||
|
||||
area_type f = 790014345;
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (4), area_type (22) * f, area_type (176) * f), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (5), area_type (22) * f, area_type (176) * f), 1);
|
||||
EXPECT_EQ (db::div_exact (area_type (8), area_type (22) * f, area_type (176) * f), 1);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (-3), area_type (22) * f, area_type (176) * f), 0);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4), area_type (22) * f, area_type (176) * f), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5), area_type (22) * f, area_type (176) * f), -1);
|
||||
EXPECT_EQ (db::div_exact (area_type (-8), area_type (22) * f, area_type (176) * f), -1);
|
||||
|
||||
EXPECT_EQ (db::div_exact (area_type (4) * 1000000000, area_type (22) * f, area_type (176) * f), 500000000);
|
||||
EXPECT_EQ (db::div_exact (area_type (5) * 1000000000, area_type (22) * f, area_type (176) * f), 625000000);
|
||||
EXPECT_EQ (db::div_exact (area_type (-4) * 1000000000, area_type (22) * f, area_type (176) * f), -500000000);
|
||||
EXPECT_EQ (db::div_exact (area_type (-5) * 1000000000, area_type (22) * f, area_type (176) * f), -625000000);
|
||||
|
||||
EXPECT_EQ (db::div_exact (1000000004, area_type (22) * f, area_type (176) * f), 125000000);
|
||||
EXPECT_EQ (db::div_exact (1000000005, area_type (22) * f, area_type (176) * f), 125000001);
|
||||
EXPECT_EQ (db::div_exact (-1000000003, area_type (22) * f, area_type (176) * f), -125000000);
|
||||
EXPECT_EQ (db::div_exact (-1000000004, area_type (22) * f, area_type (176) * f), -125000001);
|
||||
EXPECT_EQ (db::div_exact (-1000000005, area_type (22) * f, area_type (176) * f), -125000001);
|
||||
|
||||
db::Edge e1 (db::Point (3, -3), db::Point (-8, -1));
|
||||
db::Edge e2 (db::Point (-4, -2), db::Point (13, -4));
|
||||
|
||||
std::pair<bool, db::Point> ip;
|
||||
ip = e1.intersect_point (e2);
|
||||
EXPECT_EQ (ip.second.to_string ().c_str (), "0,-3");
|
||||
ip = e2.intersect_point (e1);
|
||||
EXPECT_EQ (ip.second.to_string ().c_str (), "0,-3");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2386,3 +2386,31 @@ TEST(134)
|
|||
|
||||
EXPECT_EQ (out.size (), size_t (0));
|
||||
}
|
||||
|
||||
TEST(135)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
db::Point pts[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (19, 19),
|
||||
db::Point (19, 18),
|
||||
db::Point (43, 32),
|
||||
db::Point (37, 27)
|
||||
};
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
|
||||
p.size (-2, -2, 2);
|
||||
|
||||
ep.insert (p);
|
||||
|
||||
// merge the resulting polygons to get the true outer contour
|
||||
std::vector<db::Polygon> out;
|
||||
db::PolygonContainer pc (out);
|
||||
db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/);
|
||||
db::SimpleMerge op (1 /*wc>0*/);
|
||||
ep.process (pg2, op);
|
||||
|
||||
EXPECT_EQ (out.size (), size_t (0));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue