mirror of https://github.com/KLayout/klayout.git
Fixed a XOR issue
Bug: sometimes, if the files had different database units, the XOR tool was showing differences while there are none. This was due to a sloppy computation of the tile boxes. The solution is to properly round the tile size to a common database unit and to use a common effective size for both inputs.
This commit is contained in:
parent
7d31825b11
commit
45b774a3af
|
|
@ -1792,7 +1792,7 @@ OASISWriter::write (const Repetition &rep)
|
|||
x = -x;
|
||||
}
|
||||
if (x != 0) {
|
||||
g = (g == 0) ? x : tl::lcd (g, x);
|
||||
g = (g == 0) ? x : tl::gcd (g, x);
|
||||
}
|
||||
|
||||
db::Coord y = safe_scale (m_sf, p->y ());
|
||||
|
|
@ -1800,7 +1800,7 @@ OASISWriter::write (const Repetition &rep)
|
|||
y = -y;
|
||||
}
|
||||
if (y != 0) {
|
||||
g = (g == 0) ? y : tl::lcd (g, y);
|
||||
g = (g == 0) ? y : tl::gcd (g, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "tlProgress.h"
|
||||
#include "tlThreadedWorkers.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "tlMath.h"
|
||||
#include "layCellView.h"
|
||||
#include "layLayoutView.h"
|
||||
#include "layApplication.h"
|
||||
|
|
@ -1181,7 +1182,12 @@ XORToolDialog::run_xor ()
|
|||
}
|
||||
XORJob job (nworkers, output_mode, op, el_handling, dbu, cva, cvb, tolerances, sub_categories, layer_categories, sub_cells, sub_output_layers, rdb, rdb_cell);
|
||||
|
||||
for (std::vector<db::DBox>::const_iterator box = boxes.begin (); box != boxes.end (); ++box) {
|
||||
double common_dbu = tl::lcm (cva->layout ().dbu (), cvb->layout ().dbu ());
|
||||
|
||||
for (std::vector<db::DBox>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
|
||||
|
||||
db::DBox box (tl::round_down (b->left (), common_dbu), tl::round_down (b->bottom (), common_dbu),
|
||||
tl::round_up (b->right (), common_dbu), tl::round_up (b->top (), common_dbu));
|
||||
|
||||
// compute the tiles if required
|
||||
db::Box box_a, box_b, box_out;
|
||||
|
|
@ -1189,33 +1195,34 @@ XORToolDialog::run_xor ()
|
|||
db::Coord box_width_b = 0, box_height_b = 0, box_height_out = 0;
|
||||
|
||||
size_t ntiles_w = 1, ntiles_h = 1;
|
||||
if (box->empty ()) {
|
||||
if (box.empty ()) {
|
||||
|
||||
ntiles_w = ntiles_h = 0;
|
||||
|
||||
} else if (tile_size > 0.0) {
|
||||
|
||||
box_a = db::Box (*box * (1.0 / cva->layout ().dbu ()));
|
||||
box_b = db::Box (*box * (1.0 / cvb->layout ().dbu ()));
|
||||
box_out = db::Box (*box * (1.0 / dbu));
|
||||
|
||||
ntiles_w = std::max (size_t (1), size_t (floor (box->width () / tile_size + 0.5)));
|
||||
ntiles_h = std::max (size_t (1), size_t (floor (box->height () / tile_size + 0.5)));
|
||||
|
||||
box_width_a = box_a.width () / ntiles_w;
|
||||
box_height_a = box_a.height () / ntiles_h;
|
||||
|
||||
box_width_b = box_b.width () / ntiles_w;
|
||||
box_height_b = box_b.height () / ntiles_h;
|
||||
|
||||
box_width_out = box_out.width () / ntiles_w;
|
||||
box_height_out = box_out.height () / ntiles_h;
|
||||
|
||||
} else {
|
||||
|
||||
box_a = db::Box (*box * (1.0 / cva->layout ().dbu ()));
|
||||
box_b = db::Box (*box * (1.0 / cvb->layout ().dbu ()));
|
||||
box_out = db::Box (*box * (1.0 / dbu));
|
||||
box_a = db::Box (box * (1.0 / cva->layout ().dbu ()));
|
||||
box_b = db::Box (box * (1.0 / cvb->layout ().dbu ()));
|
||||
box_out = db::Box (box * (1.0 / dbu));
|
||||
|
||||
if (tile_size > 0.0) {
|
||||
|
||||
ntiles_w = std::max (size_t (1), size_t (floor (box.width () / tile_size + 0.5)));
|
||||
ntiles_h = std::max (size_t (1), size_t (floor (box.height () / tile_size + 0.5)));
|
||||
|
||||
double box_width = tl::round_up (box.width () / ntiles_w, common_dbu);
|
||||
double box_height = tl::round_up (box.height () / ntiles_h, common_dbu);
|
||||
|
||||
box_width_a = db::coord_traits<db::Coord>::rounded (box_width / cva->layout ().dbu ());
|
||||
box_height_a = db::coord_traits<db::Coord>::rounded (box_height / cva->layout ().dbu ());
|
||||
|
||||
box_width_b = db::coord_traits<db::Coord>::rounded (box_width / cvb->layout ().dbu ());
|
||||
box_height_b = db::coord_traits<db::Coord>::rounded (box_height / cvb->layout ().dbu ());
|
||||
|
||||
box_width_out = db::coord_traits<db::Coord>::rounded (box_width / dbu);
|
||||
box_height_out = db::coord_traits<db::Coord>::rounded (box_height / dbu);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
118
src/tl/tlMath.h
118
src/tl/tlMath.h
|
|
@ -26,30 +26,116 @@
|
|||
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Compute the largest common divider of two numbers using the euclidian method
|
||||
* @brief A generic less operator
|
||||
*/
|
||||
template <class T>
|
||||
T lcd (T a, T b)
|
||||
bool less (T a, T b)
|
||||
{
|
||||
while (true) {
|
||||
if (a < b) {
|
||||
b %= a;
|
||||
if (b == 0) {
|
||||
return a;
|
||||
}
|
||||
} else if (b < a) {
|
||||
a %= b;
|
||||
if (a == 0) {
|
||||
return b;
|
||||
}
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
return a < b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A generic equal operator
|
||||
*/
|
||||
template <class T>
|
||||
bool equal (T a, T b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A generalization of the modulo operator
|
||||
*/
|
||||
template <class T>
|
||||
T modulo (T a, T b)
|
||||
{
|
||||
return a % b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A common uncertainty value for double compares
|
||||
* This implementation uses an uncertainty value of 1e-10
|
||||
* which is suitable for values in the order of 1.
|
||||
*/
|
||||
const double epsilon = 1e-10;
|
||||
|
||||
/**
|
||||
* @brief A specialization for double values
|
||||
*/
|
||||
bool less (double a, double b)
|
||||
{
|
||||
return a < b - tl::epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A specialization for double values
|
||||
*/
|
||||
bool equal (double a, double b)
|
||||
{
|
||||
return fabs (a - b) < tl::epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A specialization of the modulo operator for doubles
|
||||
* a % b == a - b * floor (a / b)
|
||||
*/
|
||||
double modulo (double a, double b)
|
||||
{
|
||||
return a - b * floor (a / b + tl::epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute the greatest common divider of two numbers using the euclidian method
|
||||
*/
|
||||
template <class T>
|
||||
T gcd (T a, T b)
|
||||
{
|
||||
while (! equal (b, T (0))) {
|
||||
T h = modulo (a, b);
|
||||
a = b;
|
||||
b = h;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute the lowest common multiple of two numbers using the euclidian method
|
||||
*/
|
||||
template <class T>
|
||||
T lcm (T a, T b)
|
||||
{
|
||||
return a * (b / gcd (a, b));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rounding down to the closest multiple of g
|
||||
*/
|
||||
double round_down (double x, double g)
|
||||
{
|
||||
return g * floor (x / g + tl::epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rounding up to the closest multiple of g
|
||||
*/
|
||||
double round_up (double x, double g)
|
||||
{
|
||||
return g * ceil (x / g - tl::epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rounding to the closest multiple of g
|
||||
* A value of (n+1/2)*g is rounded down.
|
||||
*/
|
||||
double round (double x, double g)
|
||||
{
|
||||
return g * floor (0.5 + x / g - tl::epsilon);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,62 @@
|
|||
TEST(1)
|
||||
{
|
||||
int x;
|
||||
x = tl::lcd (17, 6);
|
||||
x = tl::gcd (17, 6);
|
||||
EXPECT_EQ (x, 1);
|
||||
x = tl::lcd (27, 6);
|
||||
x = tl::gcd (27, 6);
|
||||
EXPECT_EQ (x, 3);
|
||||
x = tl::lcd (30, 6);
|
||||
x = tl::gcd (30, 6);
|
||||
EXPECT_EQ (x, 6);
|
||||
x = tl::lcd (31*17, 371*17);
|
||||
x = tl::gcd (31*17, 371*17);
|
||||
EXPECT_EQ (x, 17);
|
||||
x = tl::lcd (702*17, 372*17);
|
||||
x = tl::gcd (702*17, 372*17);
|
||||
EXPECT_EQ (x, 102);
|
||||
|
||||
EXPECT_EQ (tl::less (100, 200), true);
|
||||
EXPECT_EQ (tl::less (200, 100), false);
|
||||
EXPECT_EQ (tl::less (100, 100), false);
|
||||
EXPECT_EQ (tl::equal (200, 100), false);
|
||||
EXPECT_EQ (tl::equal (100, 100), true);
|
||||
|
||||
EXPECT_EQ (tl::less (0.1, 0.2), true);
|
||||
EXPECT_EQ (tl::less (0.2, 0.1), false);
|
||||
EXPECT_EQ (tl::less (0.1, 0.1), false);
|
||||
EXPECT_EQ (tl::less (0.1, 0.1 + 1e-7), true);
|
||||
EXPECT_EQ (tl::less (0.1, 0.1 + 1e-10), false);
|
||||
EXPECT_EQ (tl::equal (0.2, 0.1), false);
|
||||
EXPECT_EQ (tl::equal (0.1, 0.1), true);
|
||||
EXPECT_EQ (tl::equal (0.1, 0.1 + 1e-7), false);
|
||||
EXPECT_EQ (tl::equal (0.1, 0.1 + 1e-12), true);
|
||||
|
||||
double d;
|
||||
d = tl::gcd (702*1.7, 372*1.7);
|
||||
EXPECT_EQ (tl::equal (d, 10.2), true);
|
||||
d = tl::gcd (0.0025, 0.001);
|
||||
EXPECT_EQ (tl::equal (d, 0.0005), true);
|
||||
d = tl::gcd (0.0025, 0.001 + 1e-12);
|
||||
EXPECT_EQ (tl::equal (d, 0.0005), true);
|
||||
|
||||
d = tl::lcm (0.0025, 0.001);
|
||||
EXPECT_EQ (tl::equal (d, 0.005), true);
|
||||
d = tl::lcm (0.0025, 0.001 + 1e-12);
|
||||
EXPECT_EQ (tl::equal (d, 0.005), true);
|
||||
|
||||
EXPECT_EQ (tl::equal (tl::round_down (1.3, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_down (-1.3, 1.0), -2.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_down (1.0 + 1e-7, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_down (1.0 - 1e-7, 1.0), 0.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_down (1.0 - 1e-12, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_up (1.3, 1.0), 2.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_up (-1.3, 1.0), -1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_up (1.0 - 1e-7, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_up (1.0 + 1e-7, 1.0), 2.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round_up (1.0 + 1e-12, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (1.3, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (1.5, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (1.5 + 1e-12, 1.0), 1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (1.5 + 1e-7, 1.0), 2.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (1.7, 1.0), 2.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (-1.3, 1.0), -1.0), true);
|
||||
EXPECT_EQ (tl::equal (tl::round (-1.7, 1.0), -2.0), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue