klayout/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc

767 lines
28 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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
*/
#include "layDiffToolDialog.h"
#include "rdb.h"
#include "dbLayoutDiff.h"
#include "dbRecursiveShapeIterator.h"
#include "dbShapeProcessor.h"
#include "tlTimer.h"
#include "tlProgress.h"
#include "layCellView.h"
#include "layLayoutView.h"
#include "tlExceptions.h"
#include "ui_DiffToolDialog.h"
#include <stdio.h>
namespace lay
{
std::string cfg_diff_run_xor ("diff-run-xor");
std::string cfg_diff_detailed ("diff-detailed");
std::string cfg_diff_smart ("diff-smart");
std::string cfg_diff_summarize ("diff-summarize");
std::string cfg_diff_expand_cell_arrays ("diff-expand-cell-arrays");
std::string cfg_diff_exact ("diff-exact");
// ------------------------------------------------------------------------------
// RdbDifferenceReceiver definition
class RdbDifferenceReceiver
: public db::DifferenceReceiver
{
public:
RdbDifferenceReceiver (const db::Layout &la, const db::Layout &lb, rdb::Database *rdb, bool detailed, bool with_properties, bool run_xor);
void dbu_differs (double dbu_a, double dbu_b);
void layer_in_a_only (const db::LayerProperties &la);
void layer_in_b_only (const db::LayerProperties &lb);
void layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb);
void cell_in_a_only (const std::string &cellname, db::cell_index_type ci);
void cell_in_b_only (const std::string &cellname, db::cell_index_type ci);
void cell_name_differs (const std::string &cellname_a, db::cell_index_type cia, const std::string &cellname_b, db::cell_index_type cib);
void bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_cell (const std::string &cellname, db::cell_index_type cia, db::cell_index_type cib);
void begin_inst_differences ();
void instances_in_a (const std::vector <db::CellInstArrayWithProperties> &insts_a, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props);
void instances_in_b (const std::vector <db::CellInstArrayWithProperties> &insts_b, const std::vector <std::string> &cell_names, const db::PropertiesRepository &props);
void instances_in_a_only (const std::vector <db::CellInstArrayWithProperties> &anotb, const db::Layout &a);
void instances_in_b_only (const std::vector <db::CellInstArrayWithProperties> &bnota, const db::Layout &b);
void begin_layer (const db::LayerProperties &layer, unsigned int layer_index_a, bool is_valid_a, unsigned int layer_index_b, bool is_valid_b);
void end_layer ();
void per_layer_bbox_differs (const db::Box &ba, const db::Box &bb);
void begin_polygon_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Polygon, db::properties_id_type> > &a, const std::vector <std::pair <db::Polygon, db::properties_id_type> > &b);
void begin_path_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Path, db::properties_id_type> > &a, const std::vector <std::pair <db::Path, db::properties_id_type> > &b);
void begin_box_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Box, db::properties_id_type> > &a, const std::vector <std::pair <db::Box, db::properties_id_type> > &b);
void begin_edge_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
void begin_text_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b);
private:
const db::Layout *mp_layout_a;
const db::Layout *mp_layout_b;
rdb::Database *mp_rdb;
rdb::Cell *mp_cell;
rdb::Cell *mp_topcell;
rdb::Category *mp_general_cat;
rdb::Category *mp_a_only_cat;
rdb::Category *mp_b_only_cat;
std::vector<rdb::Category *> mp_a_only_per_layer_cat;
std::vector<rdb::Category *> mp_b_only_per_layer_cat;
std::map<std::pair<int, int>, rdb::Category *> mp_xor_cat;
std::vector<db::CellInstArrayWithProperties> m_insts_a, m_insts_b;
std::string m_cellname;
db::LayerProperties m_layer;
unsigned int m_layer_index_a, m_layer_index_b;
bool m_is_valid_layer_index_a, m_is_valid_layer_index_b;
bool m_diffs_reported;
bool m_with_properties;
bool m_detailed;
bool m_run_xor;
db::ShapeProcessor m_ep;
size_t m_obj_index;
void produce_cell_inst (const db::CellInstArrayWithProperties &ci, const db::Layout *layout, const rdb::Category *cat);
template <class SH> void produce_diffs_for_xor (const db::PropertiesRepository &pr, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b, double dbu_a, db::Shapes &shapes);
template <class SH> void produce_diffs (const db::PropertiesRepository &pr, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b, double dbu_a, const rdb::Category *cat);
template <class SH> void shape_diffs (const db::PropertiesRepository &pr, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b);
void shape_diffs_found ();
};
RdbDifferenceReceiver::RdbDifferenceReceiver (const db::Layout &layout_a, const db::Layout &layout_b, rdb::Database *rdb, bool detailed, bool with_properties, bool run_xor)
: mp_layout_a (&layout_a),
mp_layout_b (&layout_b),
mp_rdb (rdb),
mp_cell (0),
m_cellname (),
m_layer (),
m_layer_index_a (0),
m_layer_index_b (0),
m_is_valid_layer_index_a (false),
m_is_valid_layer_index_b (false),
m_diffs_reported (false),
m_with_properties (with_properties),
m_detailed (detailed),
m_run_xor (run_xor)
{
mp_topcell = rdb->create_cell ("" /*dummy*/);
mp_general_cat = rdb->create_category ("Summary");
mp_general_cat->set_description (tl::to_string (QObject::tr ("Summary of Differences")));
m_obj_index = 0;
std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc> layers;
for (db::Layout::layer_iterator l = layout_a.begin_layers (); l != layout_a.end_layers (); ++l) {
layers.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.first = (*l).first;
}
for (db::Layout::layer_iterator l = layout_b.begin_layers (); l != layout_b.end_layers (); ++l) {
layers.insert (std::make_pair (*(*l).second, std::make_pair (-1, -1))).first->second.second = (*l).first;
}
if (detailed) {
rdb::Category *instances_cat = rdb->create_category ("Instances");
instances_cat->set_description (tl::to_string (QObject::tr ("Differences in instances")));
mp_a_only_cat = rdb->create_category (instances_cat, "A");
mp_a_only_cat->set_description (tl::to_string (QObject::tr ("Instances in A but not in B")));
mp_b_only_cat = rdb->create_category (instances_cat, "B");
mp_b_only_cat->set_description (tl::to_string (QObject::tr ("Instances in B but not in A")));
for (std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
while ((int) mp_a_only_per_layer_cat.size () <= l->second.first) {
mp_a_only_per_layer_cat.push_back (0);
}
while ((int) mp_b_only_per_layer_cat.size () <= l->second.second) {
mp_b_only_per_layer_cat.push_back (0);
}
rdb::Category *layer_cat = rdb->create_category (l->first.to_string ());
layer_cat->set_description (tl::to_string (QObject::tr ("Differences in layer")) + " " + l->first.to_string ());
if (l->second.first >= 0) {
mp_a_only_per_layer_cat [(unsigned int) l->second.first] = rdb->create_category (layer_cat, "A");
mp_a_only_per_layer_cat [(unsigned int) l->second.first]->set_description (tl::to_string (QObject::tr ("Shapes in A but not in B, on Layer ")) + l->first.to_string ());
}
if (l->second.second >= 0) {
mp_b_only_per_layer_cat [(unsigned int) l->second.second] = rdb->create_category (layer_cat, "B");
mp_b_only_per_layer_cat [(unsigned int) l->second.second]->set_description (tl::to_string (QObject::tr ("Shapes in B but not in A, on Layer ")) + l->first.to_string ());
}
}
} else {
mp_a_only_cat = 0;
mp_b_only_cat = 0;
}
if (run_xor) {
for (std::map<db::LayerProperties, std::pair<int, int>, db::LPLogicalLessFunc>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
rdb::Category *cat = rdb->create_category (std::string ("XOR ") + l->first.to_string ());
cat->set_description (tl::to_string (QObject::tr ("Geometrical differences on layer")) + " " + l->first.to_string ());
mp_xor_cat [l->second] = cat;
}
}
}
static void
add_property_text (rdb::Item *item, const db::PropertiesRepository &pr, db::properties_id_type prop_id)
{
if (prop_id != 0) {
const db::PropertiesRepository::properties_set &p = pr.properties (prop_id);
for (db::PropertiesRepository::properties_set::const_iterator pp = p.begin (); pp != p.end (); ++pp) {
const tl::Variant &name = pr.prop_name (pp->first);
std::string r = std::string ("property: ") + name.to_string () + " = " + pp->second.to_string ();
item->add_value (r);
}
}
}
void
RdbDifferenceReceiver::produce_cell_inst (const db::CellInstArrayWithProperties &ci, const db::Layout *layout, const rdb::Category *cat)
{
db::box_convert <db::CellInstArrayWithProperties> bc (*layout);
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), cat->id ());
std::string r = "item: " + tl::sprintf (tl::to_string (QObject::tr ("instance: (%s) %s")), layout->cell_name (ci.object ().cell_index ()), ci.complex_trans ().to_string ());
db::Vector a, b;
unsigned long amax, bmax;
if (ci.is_regular_array (a, b, amax, bmax)) {
r += tl::sprintf (" [a=%s, b=%s, na=%ld, nb=%ld]", a.to_string (), b.to_string (), amax, bmax);
}
item->add_value (r);
db::Box box = bc (ci);
item->add_value (box * layout->dbu ());
if (m_with_properties) {
add_property_text (item, layout->properties_repository (), ci.properties_id ());
}
}
void
RdbDifferenceReceiver::dbu_differs (double dbu_a, double dbu_b)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Database units differ %g vs. %g")), dbu_a, dbu_b));
}
void
RdbDifferenceReceiver::layer_in_a_only (const db::LayerProperties &la)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Layer %s is not present in layout B, but in A")), la.to_string ()));
}
void
RdbDifferenceReceiver::layer_in_b_only (const db::LayerProperties &lb)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Layer %s is not present in layout A, but in B")), lb.to_string ()));
}
void
RdbDifferenceReceiver::layer_name_differs (const db::LayerProperties &la, const db::LayerProperties &lb)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Layer names differ between layout A and B for layer %d/%d: %s vs. %s")), la.layer, la.datatype, la.name, lb.name));
}
void
RdbDifferenceReceiver::cell_in_a_only (const std::string &cellname, db::cell_index_type /*ci*/)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Cell %s is not present in layout B, but in A")), cellname));
}
void
RdbDifferenceReceiver::cell_in_b_only (const std::string &cellname, db::cell_index_type /*ci*/)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Cell %s is not present in layout A, but in B")), cellname));
}
void
RdbDifferenceReceiver::cell_name_differs (const std::string &cellname_a, db::cell_index_type /*cia*/, const std::string &cellname_b, db::cell_index_type /*cib*/)
{
rdb::Item *item = mp_rdb->create_item (mp_topcell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Cell %s in A is renamed to %s in B")), cellname_a, cellname_b));
}
void
RdbDifferenceReceiver::begin_cell (const std::string &cellname, db::cell_index_type /*cia*/, db::cell_index_type /*cib*/)
{
mp_cell = mp_rdb->create_cell (cellname);
m_diffs_reported = false;
m_insts_a.clear ();
m_insts_b.clear ();
}
void
RdbDifferenceReceiver::bbox_differs (const db::Box &ba, const db::Box &bb)
{
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Bounding boxes differ: %s (A) vs. %s (B)")), ba.to_string (), bb.to_string ()));
}
void
RdbDifferenceReceiver::begin_inst_differences ()
{
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), mp_general_cat->id ());
item->add_value (tl::to_string (QObject::tr ("Instances differ")));
}
void
RdbDifferenceReceiver::instances_in_a (const std::vector <db::CellInstArrayWithProperties> & /*insts_a*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/)
{
// .. nothing ..
}
void
RdbDifferenceReceiver::instances_in_b (const std::vector <db::CellInstArrayWithProperties> & /*insts_b*/, const std::vector <std::string> & /*cell_names*/, const db::PropertiesRepository & /*props*/)
{
// .. nothing ..
}
void
RdbDifferenceReceiver::instances_in_a_only (const std::vector <db::CellInstArrayWithProperties> &anotb, const db::Layout & /*a*/)
{
if (m_detailed) {
for (std::vector <db::CellInstArrayWithProperties>::const_iterator s = anotb.begin (); s != anotb.end (); ++s) {
produce_cell_inst (*s, mp_layout_a, mp_a_only_cat);
}
}
if (m_run_xor) {
m_insts_a.insert (m_insts_a.end (), anotb.begin (), anotb.end ());
}
}
void
RdbDifferenceReceiver::instances_in_b_only (const std::vector <db::CellInstArrayWithProperties> &bnota, const db::Layout & /*b*/)
{
if (m_detailed) {
for (std::vector <db::CellInstArrayWithProperties>::const_iterator s = bnota.begin (); s != bnota.end (); ++s) {
produce_cell_inst (*s, mp_layout_b, mp_b_only_cat);
}
}
if (m_run_xor) {
m_insts_b.insert (m_insts_b.end (), bnota.begin (), bnota.end ());
}
}
void
RdbDifferenceReceiver::begin_layer (const db::LayerProperties &layer, unsigned int layer_index_a, bool is_valid_a, unsigned int layer_index_b, bool is_valid_b)
{
m_layer = layer;
m_diffs_reported = false;
m_layer_index_a = layer_index_a;
m_is_valid_layer_index_a = is_valid_a;
m_layer_index_b = layer_index_b;
m_is_valid_layer_index_b = is_valid_b;
if (m_run_xor) {
m_obj_index = 0;
if (is_valid_a) {
for (std::vector <db::CellInstArrayWithProperties>::const_iterator i = m_insts_a.begin (); i != m_insts_a.end (); ++i) {
for (db::RecursiveShapeIterator shapes (*mp_layout_a, mp_layout_a->cell (i->object ().cell_index ()), m_layer_index_a); ! shapes.at_end (); ++shapes) {
for (db::CellInstArray::iterator a = i->begin (); ! a.at_end (); ++a) {
m_ep.insert (shapes.shape (), i->complex_trans (*a) * shapes.trans (), m_obj_index * 2);
++m_obj_index;
}
}
}
}
if (is_valid_b) {
for (std::vector <db::CellInstArrayWithProperties>::const_iterator i = m_insts_b.begin (); i != m_insts_b.end (); ++i) {
for (db::RecursiveShapeIterator shapes (*mp_layout_b, mp_layout_b->cell (i->object ().cell_index ()), m_layer_index_b); ! shapes.at_end (); ++shapes) {
for (db::CellInstArray::iterator a = i->begin (); ! a.at_end (); ++a) {
m_ep.insert (shapes.shape (), i->complex_trans (*a) * shapes.trans (), m_obj_index * 2 + 1);
++m_obj_index;
}
}
}
}
}
}
void
RdbDifferenceReceiver::end_layer ()
{
if (m_run_xor) {
std::vector <db::Polygon> out_polygons;
db::BooleanOp op (db::BooleanOp::Xor);
db::PolygonContainer pc (out_polygons);
db::PolygonGenerator out (pc, false /*don't resolve holes*/, true /*min coherence*/);
m_ep.process (out, op);
db::CplxTrans t (mp_layout_a->dbu ());
rdb::Category *cat = mp_xor_cat [std::make_pair (m_is_valid_layer_index_a ? m_layer_index_a : -1, m_is_valid_layer_index_b ? m_layer_index_b : -1)];
if (cat) {
for (std::vector <db::Polygon>::const_iterator x = out_polygons.begin (); x != out_polygons.end (); ++x) {
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), cat->id ());
item->add_value (t * *x);
}
}
m_ep.clear ();
}
}
void
RdbDifferenceReceiver::per_layer_bbox_differs (const db::Box &ba, const db::Box &bb)
{
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Per-layer bounding boxes differ (layer %s): %s (A) vs. %s (B)")), m_layer.to_string (), ba.to_string (), bb.to_string ()));
}
void
RdbDifferenceReceiver::shape_diffs_found ()
{
if (! m_diffs_reported) {
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), mp_general_cat->id ());
item->add_value (tl::sprintf (tl::to_string (QObject::tr ("Shapes differ on layer %s")), m_layer.to_string ()));
m_diffs_reported = true;
}
}
void
RdbDifferenceReceiver::begin_polygon_differences ()
{
shape_diffs_found ();
}
inline std::string shape_type (const db::Polygon &)
{
return "polygon";
}
inline std::string shape_type (const db::Path &)
{
return "path";
}
inline std::string shape_type (const db::Edge &)
{
return "edge";
}
inline std::string shape_type (const db::Text &)
{
return "text";
}
inline std::string shape_type (const db::Box &)
{
return "box";
}
template <class SH>
void
RdbDifferenceReceiver::produce_diffs_for_xor (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b, double dbu_a, db::Shapes &shapes)
{
db::CplxTrans t (dbu_a);
std::vector <std::pair <SH, db::properties_id_type> > anotb;
std::set_difference (a.begin (), a.end (), b.begin (), b.end (), std::back_inserter (anotb));
for (typename std::vector <std::pair <SH, db::properties_id_type> >::const_iterator s = anotb.begin (); s != anotb.end (); ++s) {
shapes.insert (s->first);
}
}
template <class SH>
void
RdbDifferenceReceiver::produce_diffs (const db::PropertiesRepository &pr, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b, double dbu_a, const rdb::Category *cat)
{
db::CplxTrans t (dbu_a);
std::vector <std::pair <SH, db::properties_id_type> > anotb;
std::set_difference (a.begin (), a.end (), b.begin (), b.end (), std::back_inserter (anotb));
for (typename std::vector <std::pair <SH, db::properties_id_type> >::const_iterator s = anotb.begin (); s != anotb.end (); ++s) {
rdb::Item *item = mp_rdb->create_item (mp_cell->id (), cat->id ());
if (s->second && m_with_properties) {
item->add_value ("item: " + shape_type (s->first) + " " + tl::to_string (QObject::tr ("with properties")));
} else {
item->add_value ("item: " + shape_type (s->first));
}
item->add_value (t * s->first);
if (s->second && m_with_properties) {
add_property_text (item, pr, s->second);
}
}
}
template <class SH>
void
RdbDifferenceReceiver::shape_diffs (const db::PropertiesRepository &pr, const std::vector <std::pair <SH, db::properties_id_type> > &a, const std::vector <std::pair <SH, db::properties_id_type> > &b)
{
if (m_detailed && m_is_valid_layer_index_a && mp_a_only_per_layer_cat [m_layer_index_a] != 0) {
produce_diffs (pr, a, b, mp_layout_a->dbu (), mp_a_only_per_layer_cat [m_layer_index_a]);
}
if (m_run_xor && m_is_valid_layer_index_a) {
db::Shapes shapes;
produce_diffs_for_xor (pr, a, b, mp_layout_a->dbu (), shapes);
for (db::Shapes::shape_iterator s = shapes.begin (db::Shapes::shape_iterator::All); ! s.at_end (); ++s) {
m_ep.insert (*s, m_obj_index * 2);
++m_obj_index;
}
}
if (m_detailed && m_is_valid_layer_index_b && mp_b_only_per_layer_cat [m_layer_index_b] != 0) {
produce_diffs (pr, b, a, mp_layout_b->dbu (), mp_b_only_per_layer_cat [m_layer_index_b]);
}
if (m_run_xor && m_is_valid_layer_index_b) {
db::Shapes shapes;
produce_diffs_for_xor (pr, b, a, mp_layout_b->dbu (), shapes);
for (db::Shapes::shape_iterator s = shapes.begin (db::Shapes::shape_iterator::All); ! s.at_end (); ++s) {
m_ep.insert (*s, m_obj_index * 2 + 1);
++m_obj_index;
}
}
}
void
RdbDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Polygon, db::properties_id_type> > &a, const std::vector <std::pair <db::Polygon, db::properties_id_type> > &b)
{
shape_diffs (pr, a, b);
}
void
RdbDifferenceReceiver::begin_path_differences ()
{
shape_diffs_found ();
}
void
RdbDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Path, db::properties_id_type> > &a, const std::vector <std::pair <db::Path, db::properties_id_type> > &b)
{
shape_diffs (pr, a, b);
}
void
RdbDifferenceReceiver::begin_box_differences ()
{
shape_diffs_found ();
}
void
RdbDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Box, db::properties_id_type> > &a, const std::vector <std::pair <db::Box, db::properties_id_type> > &b)
{
shape_diffs (pr, a, b);
}
void
RdbDifferenceReceiver::begin_edge_differences ()
{
shape_diffs_found ();
}
void
RdbDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b)
{
shape_diffs (pr, a, b);
}
void
RdbDifferenceReceiver::begin_text_differences ()
{
shape_diffs_found ();
}
void
RdbDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b)
{
shape_diffs (pr, a, b);
}
// ------------------------------------------------------------------------------
// DiffToolDialog definition
DiffToolDialog::DiffToolDialog (QWidget *parent)
: QDialog (parent), mp_view (0)
{
mp_ui = new Ui::DiffToolDialog ();
mp_ui->setupUi (this);
connect (mp_ui->xor_cbx, SIGNAL (clicked ()), this, SLOT (xor_changed ()));
}
DiffToolDialog::~DiffToolDialog ()
{
delete mp_ui;
mp_ui = 0;
}
int
DiffToolDialog::exec_dialog (lay::LayoutView *view)
{
mp_view = view;
if (view != mp_ui->layouta->layout_view () || view != mp_ui->layoutb->layout_view ()) {
mp_ui->layouta->set_layout_view (view);
mp_ui->layoutb->set_layout_view (view);
if (view->cellviews () >= 2) {
mp_ui->layouta->set_current_cv_index (0);
mp_ui->layoutb->set_current_cv_index (1);
}
} else {
// force update of the layer list
// TODO: the controls should register a listener for the view so this activity is not necessary:
mp_ui->layouta->set_layout_view (view);
mp_ui->layoutb->set_layout_view (view);
}
lay::Dispatcher *config_root = lay::Dispatcher::instance ();
bool f = false;
if (config_root->config_get (cfg_diff_run_xor, f)) {
mp_ui->xor_cbx->setChecked (f);
}
if (config_root->config_get (cfg_diff_detailed, f)) {
mp_ui->detailed_cbx->setChecked (f);
}
if (config_root->config_get (cfg_diff_smart, f)) {
mp_ui->smart_cbx->setChecked (f);
}
if (config_root->config_get (cfg_diff_summarize, f)) {
mp_ui->summarize_cbx->setChecked (f);
}
if (config_root->config_get (cfg_diff_expand_cell_arrays, f)) {
mp_ui->expand_cell_arrays_cbx->setChecked (f);
}
if (config_root->config_get (cfg_diff_exact, f)) {
mp_ui->exact_cbx->setChecked (f);
}
update ();
int ret = QDialog::exec ();
if (ret) {
run_diff ();
}
mp_view = 0;
return ret;
}
void
DiffToolDialog::accept ()
{
BEGIN_PROTECTED
int cv_index_a = mp_ui->layouta->current_cv_index ();
int cv_index_b = mp_ui->layoutb->current_cv_index ();
const lay::CellView &cva = mp_view->cellview (cv_index_a);
const lay::CellView &cvb = mp_view->cellview (cv_index_b);
if (&cva->layout () == &cvb->layout () && cva.cell_index () == cvb.cell_index ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Trying to perform an Diff between identical layouts")));
}
lay::Dispatcher *config_root = lay::Dispatcher::instance ();
config_root->config_set (cfg_diff_run_xor, mp_ui->xor_cbx->isChecked ());
config_root->config_set (cfg_diff_detailed, mp_ui->detailed_cbx->isChecked ());
config_root->config_set (cfg_diff_smart, mp_ui->smart_cbx->isChecked ());
config_root->config_set (cfg_diff_summarize, mp_ui->summarize_cbx->isChecked ());
config_root->config_set (cfg_diff_expand_cell_arrays, mp_ui->expand_cell_arrays_cbx->isChecked ());
config_root->config_set (cfg_diff_exact, mp_ui->exact_cbx->isChecked ());
config_root->config_end ();
QDialog::accept ();
END_PROTECTED
}
void
DiffToolDialog::update ()
{
bool xor_mode = mp_ui->xor_cbx->isChecked ();
mp_ui->summarize_cbx->setEnabled (! xor_mode);
mp_ui->detailed_cbx->setEnabled (! xor_mode);
mp_ui->expand_cell_arrays_cbx->setEnabled (! xor_mode);
mp_ui->exact_cbx->setEnabled (! xor_mode);
}
void
DiffToolDialog::run_diff ()
{
bool smart = mp_ui->smart_cbx->isChecked ();
bool run_xor = mp_ui->xor_cbx->isChecked ();
bool detailed = !run_xor && mp_ui->detailed_cbx->isChecked ();
bool summarize = !run_xor && mp_ui->summarize_cbx->isChecked ();
bool expand_cell_arrays = !run_xor && mp_ui->expand_cell_arrays_cbx->isChecked ();
bool exact = !run_xor && mp_ui->exact_cbx->isChecked ();
int cv_index_a = mp_ui->layouta->current_cv_index ();
int cv_index_b = mp_ui->layoutb->current_cv_index ();
lay::CellView cva = mp_view->cellview (cv_index_a);
lay::CellView cvb = mp_view->cellview (cv_index_b);
unsigned int flags = 0;
if (detailed || run_xor) {
flags |= db::layout_diff::f_verbose;
}
if (!exact) {
flags |= db::layout_diff::f_no_text_details;
flags |= db::layout_diff::f_no_layer_names;
flags |= db::layout_diff::f_no_text_orientation;
flags |= db::layout_diff::f_no_properties;
flags |= db::layout_diff::f_boxes_as_polygons;
flags |= db::layout_diff::f_paths_as_polygons;
}
if (expand_cell_arrays) {
flags |= db::layout_diff::f_flatten_array_insts;
}
if (! summarize) {
flags |= db::layout_diff::f_dont_summarize_missing_layers;
}
if (smart) {
flags |= db::layout_diff::f_smart_cell_mapping;
}
// TODO: make an parameter
db::Coord tolerance = 0;
// Create the report database or identify the output layout
rdb::Database *rdb = 0;
int rdb_index = 0;
rdb = new rdb::Database ();
rdb->set_name ("Diff " + cva->name () + "/" + cvb->name ());
rdb->set_top_cell_name (cva->layout ().cell_name (cva.cell_index ()));
rdb_index = mp_view->add_rdb (rdb);
std::string srca = cva->name () + ", Cell " + cva->layout ().cell_name (cva.cell_index ());
std::string srcb = cvb->name () + ", Cell " + cvb->layout ().cell_name (cvb.cell_index ());
rdb->set_description ("Diff of '" + srca + "' vs. '" + srcb + "'");
RdbDifferenceReceiver r (cva->layout (), cvb->layout (), rdb, detailed, exact, run_xor);
db::compare_layouts (cva->layout (), cva.cell_index (), cvb->layout (), cvb.cell_index (), flags, tolerance, r);
mp_view->open_rdb_browser (rdb_index, cv_index_a);
mp_view->update_content ();
}
}