2017-02-12 13:21:08 +01:00
/*
KLayout Layout Viewer
2020-01-05 00:59:43 +01:00
Copyright (C) 2006-2020 Matthias Koefferlein
2017-02-12 13:21:08 +01:00
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
*/
2018-06-17 09:43:25 +02:00
#include "layDiffToolDialog.h"
2017-02-12 13:21:08 +01:00
#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>
2018-06-17 09:43:25 +02:00
namespace lay
2017-02-12 13:21:08 +01:00
{
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 );
2020-06-04 12:17:34 +02:00
} else if ( ci . size () > 1 ) {
r += " (+" ;
r += tl :: to_string ( ci . size () - 1 );
r += " irregular placements)" ;
2017-02-12 13:21:08 +01:00
}
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 );
}
2020-02-07 01:27:24 +01:00
lay :: Dispatcher * config_root = lay :: Dispatcher :: instance ();
2017-02-12 13:21:08 +01:00
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" )));
}
2020-02-07 01:27:24 +01:00
lay :: Dispatcher * config_root = lay :: Dispatcher :: instance ();
2017-02-12 13:21:08 +01:00
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 ();
}
}