WIP: turned ext module into plugins.

This commit is contained in:
Matthias Koefferlein
2018-06-17 09:43:25 +02:00
parent 7e56ce23e5
commit 4097a5b361
71 changed files with 297 additions and 405 deletions
+3 -2
View File
@@ -3,7 +3,8 @@ include($$PWD/../klayout.pri)
TEMPLATE = lib
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC $$PWD/common
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC $$PWD/common
LIBS += -L$$DESTDIR/.. -lklayout_db -lklayout_tl -lklayout_gsi
DEFINES += MAKE_DB_PLUGIN_LIBRARY
+4 -2
View File
@@ -3,6 +3,8 @@ include($$PWD/../klayout.pri)
TEMPLATE = lib
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC
INCLUDEPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC $$PWD/common
DEPENDPATH += $$DB_INC $$TL_INC $$GSI_INC $$LAYBASIC_INC $$LAY_INC $$PWD/common
LIBS += -L$$DESTDIR/.. -lklayout_db -lklayout_tl -lklayout_gsi -lklayout_laybasic -lklayout_lay
DEFINES += MAKE_LAY_PLUGIN_LIBRARY
+1
View File
@@ -5,5 +5,6 @@ SUBDIR_LIST = $$files($$PWD/*)
SUBDIR_LIST -= $$PWD/plugins.pro
SUBDIR_LIST -= $$PWD/db_plugin.pri
SUBDIR_LIST -= $$PWD/lay_plugin.pri
SUBDIR_LIST -= $$PWD/common
SUBDIRS = $$SUBDIR_LIST
@@ -34,9 +34,6 @@
#include <string>
#include <vector>
// place this macro to force linking of CIF plugin
#define FORCE_LINK_CIF void force_link_CIF_f () { extern int force_link_CIF; force_link_CIF = 0; }
namespace db
{
@@ -25,17 +25,18 @@
#ifndef HDR_dbCIFReader
#define HDR_dbCIFReader
#include "dbPluginCommon.h"
#include "dbNamedLayerReader.h"
#include "dbLayout.h"
#include "dbCIF.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "dbNamedLayerReader.h"
#include "dbLayout.h"
#include "dbCIF.h"
#include "tlStream.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include <map>
#include <set>
@@ -46,7 +47,7 @@ namespace db
/**
* @brief Structure that holds the CIF specific options for the reader
*/
class DB_PUBLIC CIFReaderOptions
class DB_PLUGIN_PUBLIC CIFReaderOptions
: public FormatSpecificReaderOptions
{
public:
@@ -128,7 +129,7 @@ public:
/**
* @brief Generic base class of CIF reader exceptions
*/
class DB_PUBLIC CIFReaderException
class DB_PLUGIN_PUBLIC CIFReaderException
: public ReaderException
{
public:
@@ -140,7 +141,7 @@ public:
/**
* @brief The CIF format stream reader
*/
class DB_PUBLIC CIFReader
class DB_PLUGIN_PUBLIC CIFReader
: public NamedLayerReader,
public CIFDiagnostics
{
@@ -25,6 +25,7 @@
#ifndef HDR_dbCIFWriter
#define HDR_dbCIFWriter
#include "dbPluginCommon.h"
#include "dbWriter.h"
#include "dbCIF.h"
#include "dbSaveLayoutOptions.h"
@@ -44,7 +45,7 @@ class SaveLayoutOptions;
/**
* @brief Structure that holds the CIF specific options for the Writer
*/
class DB_PUBLIC CIFWriterOptions
class DB_PLUGIN_PUBLIC CIFWriterOptions
: public FormatSpecificWriterOptions
{
public:
@@ -92,7 +93,7 @@ public:
/**
* @brief A CIF writer abstraction
*/
class DB_PUBLIC CIFWriter
class DB_PLUGIN_PUBLIC CIFWriter
: public db::WriterBase
{
public:
@@ -8,8 +8,8 @@ include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbCIFReader.cc \
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -34,9 +34,6 @@
#include <string>
#include <vector>
// place this macro to force linking of DXF plugin
#define FORCE_LINK_DXF void force_link_DXF_f () { extern int force_link_DXF; force_link_DXF = 0; }
namespace db
{
@@ -25,17 +25,18 @@
#ifndef HDR_dbDXFReader
#define HDR_dbDXFReader
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbNamedLayerReader.h"
#include "dbDXF.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "dbLayout.h"
#include "dbNamedLayerReader.h"
#include "dbDXF.h"
#include "tlStream.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include <map>
#include <set>
@@ -48,7 +49,7 @@ class Matrix3d;
/**
* @brief Structure that holds the DXF specific options for the reader
*/
class DB_PUBLIC DXFReaderOptions
class DB_PLUGIN_PUBLIC DXFReaderOptions
: public FormatSpecificReaderOptions
{
public:
@@ -204,7 +205,7 @@ public:
/**
* @brief Generic base class of DXF reader exceptions
*/
class DB_PUBLIC DXFReaderException
class DB_PLUGIN_PUBLIC DXFReaderException
: public ReaderException
{
public:
@@ -220,7 +221,7 @@ public:
/**
* @brief The DXF format stream reader
*/
class DB_PUBLIC DXFReader
class DB_PLUGIN_PUBLIC DXFReader
: public NamedLayerReader,
public DXFDiagnostics
{
@@ -26,6 +26,7 @@
#ifndef HDR_dbDXFWriter
#define HDR_dbDXFWriter
#include "dbPluginCommon.h"
#include "dbWriter.h"
#include "dbDXF.h"
#include "dbSaveLayoutOptions.h"
@@ -45,7 +46,7 @@ class SaveLayoutOptions;
/**
* @brief Structure that holds the DXF specific options for the Writer
*/
class DB_PUBLIC DXFWriterOptions
class DB_PLUGIN_PUBLIC DXFWriterOptions
: public FormatSpecificWriterOptions
{
public:
@@ -89,7 +90,7 @@ public:
/**
* @brief A DXF writer abstraction
*/
class DB_PUBLIC DXFWriter
class DB_PLUGIN_PUBLIC DXFWriter
: public db::WriterBase
{
public:
@@ -8,8 +8,8 @@ include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbDXFReader.cc \
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -24,6 +24,7 @@
#ifndef HDR_dbGDS2ReaderText
#define HDR_dbGDS2ReaderText
#include "dbPluginCommon.h"
#include "dbGDS2Reader.h"
#include <sstream>
@@ -34,7 +35,7 @@ namespace db
/**
* @brief Generic base class of GDS2 Text reader exceptions
*/
class DB_PUBLIC GDS2ReaderTextException
class DB_PLUGIN_PUBLIC GDS2ReaderTextException
: public ReaderException
{
public:
@@ -46,7 +47,7 @@ public:
/**
* @brief The GDS2 text format stream reader
*/
class DB_PUBLIC GDS2ReaderText
class DB_PLUGIN_PUBLIC GDS2ReaderText
: public GDS2ReaderBase
{
@@ -24,6 +24,7 @@
#ifndef HDR_dbGDS2WriterText
#define HDR_dbGDS2WriterText
#include "dbPluginCommon.h"
#include "dbGDS2WriterBase.h"
#include <sstream>
#include <climits>
@@ -32,7 +33,7 @@ namespace db
{
class DB_PUBLIC GDS2WriterText
class DB_PLUGIN_PUBLIC GDS2WriterText
: public db::GDS2WriterBase
{
@@ -25,17 +25,17 @@
#ifndef HDR_dbGDS2Reader
#define HDR_dbGDS2Reader
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbGDS2ReaderBase.h"
#include "dbCommonReader.h"
#include "dbStreamLayers.h"
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "dbLayout.h"
#include "dbGDS2ReaderBase.h"
#include "dbCommonReader.h"
#include "tlStream.h"
#include "dbStreamLayers.h"
namespace db
{
@@ -43,7 +43,7 @@ namespace db
/**
* @brief Structure that holds the GDS2 specific options for the reader
*/
class DB_PUBLIC GDS2ReaderOptions
class DB_PLUGIN_PUBLIC GDS2ReaderOptions
: public FormatSpecificReaderOptions
{
public:
@@ -104,7 +104,7 @@ public:
/**
* @brief Generic base class of GDS2 reader exceptions
*/
class DB_PUBLIC GDS2ReaderException
class DB_PLUGIN_PUBLIC GDS2ReaderException
: public ReaderException
{
public:
@@ -116,7 +116,7 @@ public:
/**
* @brief The GDS2 format stream reader
*/
class DB_PUBLIC GDS2Reader
class DB_PLUGIN_PUBLIC GDS2Reader
: public GDS2ReaderBase
{
public:
@@ -25,16 +25,16 @@
#ifndef HDR_dbGDS2ReaderBase
#define HDR_dbGDS2ReaderBase
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbStreamLayers.h"
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "tlStream.h"
#include "dbStreamLayers.h"
namespace db
{
@@ -48,7 +48,7 @@ struct GDS2XY
/**
* @brief The GDS2 format basic stream reader
*/
class DB_PUBLIC GDS2ReaderBase
class DB_PLUGIN_PUBLIC GDS2ReaderBase
: public ReaderBase
{
public:
@@ -24,6 +24,7 @@
#ifndef HDR_dbGDS2Writer
#define HDR_dbGDS2Writer
#include "dbPluginCommon.h"
#include "dbGDS2WriterBase.h"
#include "dbWriterTools.h"
#include "tlProgress.h"
@@ -35,7 +36,7 @@ namespace db
* @brief A GDS2 writer abstraction
*/
class DB_PUBLIC GDS2Writer
class DB_PLUGIN_PUBLIC GDS2Writer
: public db::GDS2WriterBase
{
public:
@@ -24,6 +24,7 @@
#ifndef HDR_dbGDS2WriterBase
#define HDR_dbGDS2WriterBase
#include "dbPluginCommon.h"
#include "dbWriter.h"
#include "dbWriterTools.h"
#include "tlProgress.h"
@@ -42,7 +43,7 @@ class SaveLayoutOptions;
/**
* @brief Structure that holds the GDS2 specific options for the Writer
*/
class DB_PUBLIC GDS2WriterOptions
class DB_PLUGIN_PUBLIC GDS2WriterOptions
: public FormatSpecificWriterOptions
{
public:
@@ -149,7 +150,7 @@ public:
* @brief A GDS2 writer abstraction
*/
class DB_PUBLIC GDS2WriterBase
class DB_PLUGIN_PUBLIC GDS2WriterBase
: public db::WriterBase
{
public:
@@ -9,8 +9,8 @@ SOURCES = \
dbGDS2Reader.cc \
dbGDS2Writer.cc \
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -25,7 +25,7 @@
#ifndef HDR_dbDEFImporter
#define HDR_dbDEFImporter
#include "dbCommon.h"
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "tlStream.h"
#include "dbLEFImporter.h"
@@ -39,7 +39,7 @@ namespace db
/**
* @brief The DEF importer object
*/
class DB_PUBLIC DEFImporter
class DB_PLUGIN_PUBLIC DEFImporter
: public LEFDEFImporter
{
public:
@@ -24,7 +24,7 @@
#ifndef HDR_dbLEFDEFImporter
#define HDR_dbLEFDEFImporter
#include "dbCommon.h"
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbStreamLayers.h"
@@ -46,7 +46,7 @@ namespace db
/**
* @brief Generic base class of DXF reader exceptions
*/
class DB_PUBLIC LEFDEFReaderException
class DB_PLUGIN_PUBLIC LEFDEFReaderException
: public db::ReaderException
{
public:
@@ -60,7 +60,7 @@ public:
*
* This component provides technology specific information for the LEF/DEF importer.
*/
class DB_PUBLIC LEFDEFReaderOptions
class DB_PLUGIN_PUBLIC LEFDEFReaderOptions
: public db::FormatSpecificReaderOptions
{
public:
@@ -471,7 +471,7 @@ enum LayerPurpose
*
* This class will handle the creation and management of layers in the LEF/DEF reader context
*/
class DB_PUBLIC LEFDEFLayerDelegate
class DB_PLUGIN_PUBLIC LEFDEFLayerDelegate
{
public:
/**
@@ -536,7 +536,7 @@ private:
/**
* @brief The LEF importer object
*/
class DB_PUBLIC LEFDEFImporter
class DB_PLUGIN_PUBLIC LEFDEFImporter
{
public:
/**
@@ -25,9 +25,9 @@
#ifndef HDR_dbLEFImporter
#define HDR_dbLEFImporter
#include "dbPluginCommon.h"
#include "dbLEFDEFImporter.h"
#include "dbCommon.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbStreamLayers.h"
@@ -43,7 +43,7 @@ namespace db
/**
* @brief The LEF importer object
*/
class DB_PUBLIC LEFImporter
class DB_PLUGIN_PUBLIC LEFImporter
: public LEFDEFImporter
{
public:
@@ -24,7 +24,7 @@
#ifndef HDR_dbLEFImportDialog
#define HDR_dbLEFImportDialog
#include "layCommon.h"
#include "layPluginCommon.h"
#include "layTechnology.h"
#include "layStream.h"
@@ -39,7 +39,7 @@ namespace lay
/**
* @brief A structure containing the LEF importer data
*/
struct LAY_PUBLIC LEFDEFImportData
struct LAY_PLUGIN_PUBLIC LEFDEFImportData
{
LEFDEFImportData ();
@@ -54,7 +54,7 @@ struct LAY_PUBLIC LEFDEFImportData
/**
* @brief The LEF importer dialog
*/
class LAY_PUBLIC LEFDEFImportOptionsDialog
class LAY_PLUGIN_PUBLIC LEFDEFImportOptionsDialog
: public QDialog,
private Ui::LEFDEFImportOptionsDialog
{
@@ -8,8 +8,8 @@ include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbLEFDEFImport.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -24,6 +24,7 @@
#ifndef HDR_dbOASIS
#define HDR_dbOASIS
#include "dbPluginCommon.h"
#include "dbPoint.h"
#include "dbVector.h"
@@ -35,9 +36,6 @@
#include <string>
#include <vector>
// place this macro to force linking of OASIS plugin
#define FORCE_LINK_OASIS void force_link_OASIS_f () { extern int force_link_OASIS; force_link_OASIS = 0; }
namespace db
{
@@ -67,7 +65,7 @@ class OASISReader;
/**
* @brief A repetition iterator
*/
class DB_PUBLIC RepetitionIterator
class DB_PLUGIN_PUBLIC RepetitionIterator
{
public:
/**
@@ -125,7 +123,7 @@ private:
/**
* @brief A class representing a repetition
*/
class DB_PUBLIC Repetition
class DB_PLUGIN_PUBLIC Repetition
{
public:
/**
@@ -237,7 +235,7 @@ private:
// Base classes
class DB_PUBLIC RepetitionBase
class DB_PLUGIN_PUBLIC RepetitionBase
{
public:
RepetitionBase ()
@@ -25,19 +25,20 @@
#ifndef HDR_dbOASISReader
#define HDR_dbOASISReader
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbTypes.h"
#include "dbOASIS.h"
#include "tlStream.h"
#include "dbStreamLayers.h"
#include "dbPropertiesRepository.h"
#include "tlException.h"
#include "tlInternational.h"
#include "tlProgress.h"
#include "tlString.h"
#include "tlStream.h"
#include <map>
#include <set>
@@ -47,7 +48,7 @@ namespace db
/**
* @brief Generic base class of OASIS reader exceptions
*/
class DB_PUBLIC OASISReaderException
class DB_PLUGIN_PUBLIC OASISReaderException
: public ReaderException
{
public:
@@ -59,7 +60,7 @@ public:
/**
* @brief Structure that holds the OASIS specific options for the reader
*/
class DB_PUBLIC OASISReaderOptions
class DB_PLUGIN_PUBLIC OASISReaderOptions
: public FormatSpecificReaderOptions
{
public:
@@ -115,7 +116,7 @@ public:
/**
* @brief The OASIS format stream reader
*/
class DB_PUBLIC OASISReader
class DB_PLUGIN_PUBLIC OASISReader
: public ReaderBase,
public OASISDiagnostics
{
@@ -24,6 +24,7 @@
#ifndef HDR_dbOASISWriter
#define HDR_dbOASISWriter
#include "dbPluginCommon.h"
#include "dbWriter.h"
#include "dbOASIS.h"
#include "dbSaveLayoutOptions.h"
@@ -49,7 +50,7 @@ class OASISWriter;
/**
* @brief Structure that holds the OASIS specific options for the Writer
*/
class DB_PUBLIC OASISWriterOptions
class DB_PLUGIN_PUBLIC OASISWriterOptions
: public FormatSpecificWriterOptions
{
public:
@@ -190,7 +191,7 @@ private:
/**
* @brief A OASIS writer abstraction
*/
class DB_PUBLIC OASISWriter
class DB_PLUGIN_PUBLIC OASISWriter
: public db::WriterBase
{
public:
@@ -10,8 +10,8 @@ SOURCES = \
dbOASISWriter2.cc \
dbOASISWriter.cc \
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -24,8 +24,7 @@
#ifndef HDR_dbGerberImporter
#define HDR_dbGerberImporter
#include "dbCommon.h"
#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbTrans.h"
#include "dbEdgeProcessor.h"
@@ -606,7 +605,7 @@ private:
/**
* @brief Represents one file in a Gerber stack.
*/
class DB_PUBLIC GerberFile
class DB_PLUGIN_PUBLIC GerberFile
{
public:
GerberFile ();
@@ -770,7 +769,7 @@ private:
* This class provides a importer for Gerber layer stacks. It can be
* loaded from project files and saved to such.
*/
class DB_PUBLIC GerberImporter
class DB_PLUGIN_PUBLIC GerberImporter
{
public:
/**
@@ -8,8 +8,8 @@ include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbGerberImport.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
+5
View File
@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = lay_plugin
@@ -0,0 +1,279 @@
<ui version="4.0" >
<class>BooleanOptionsDialog</class>
<widget class="QDialog" name="BooleanOptionsDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>535</width>
<height>349</height>
</rect>
</property>
<property name="windowTitle" >
<string>Boolean Operation</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Boolean Operation Setup</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="4" >
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QComboBox" name="mode_cbx" >
<item>
<property name="text" >
<string>Union (OR)</string>
</property>
</item>
<item>
<property name="text" >
<string>Intersection (AND)</string>
</property>
</item>
<item>
<property name="text" >
<string>Difference (A NOT B)</string>
</property>
</item>
<item>
<property name="text" >
<string>Difference (B NOT A)</string>
</property>
</item>
<item>
<property name="text" >
<string>Symmetric Difference (XOR)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Source B</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Source A</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Mode</string>
</property>
</widget>
</item>
<item row="6" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Result</string>
</property>
</widget>
</item>
<item row="8" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Hierarchy</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="4" >
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="5" column="2" >
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cva_cbx" />
</item>
<item row="2" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cvb_cbx" />
</item>
<item row="6" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cvr_cbx" />
</item>
<item row="1" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layera_cbx" />
</item>
<item row="2" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layerb_cbx" />
</item>
<item row="6" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layerr_cbx" />
</item>
<item row="6" column="3" >
<widget class="QLabel" name="label_10" >
<property name="text" >
<string>(Layer is overwritten)</string>
</property>
</widget>
</item>
<item row="9" column="1" colspan="3" >
<widget class="QCheckBox" name="min_coherence_cb" >
<property name="text" >
<string>Minimum coherence (for touching corners)</string>
</property>
</widget>
</item>
<item row="8" column="1" colspan="3" >
<widget class="QComboBox" name="hier_mode_cbx" >
<item>
<property name="text" >
<string>Flat</string>
</property>
</item>
<item>
<property name="text" >
<string>Top cell only</string>
</property>
</item>
<item>
<property name="text" >
<string>Individually for current and subcells (semi hierarchical)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>506</width>
<height>51</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::CellViewSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
<customwidget>
<class>lay::LayerSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BooleanOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BooleanOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,247 @@
<ui version="4.0" >
<class>MergeOptionsDialog</class>
<widget class="QDialog" name="MergeOptionsDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>641</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle" >
<string>Merge Operation</string>
</property>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="margin" >
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Merge Operation Setup</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="7" column="1" colspan="3" >
<widget class="QComboBox" name="hier_mode_cbx" >
<item>
<property name="text" >
<string>Flat</string>
</property>
</item>
<item>
<property name="text" >
<string>Top cell only</string>
</property>
</item>
<item>
<property name="text" >
<string>Individually for current and subcells (semi hierarchical)</string>
</property>
</item>
</widget>
</item>
<item row="5" column="3" >
<widget class="QLabel" name="label_10" >
<property name="text" >
<string>(Layer is overwritten)</string>
</property>
</widget>
</item>
<item row="4" column="2" >
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cvr_cbx" />
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="threshold_le" />
</item>
<item row="6" column="0" colspan="4" >
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="7" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Hierarchy</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cv_cbx" />
</item>
<item row="5" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Result</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Source</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="1" colspan="3" >
<widget class="QCheckBox" name="min_coherence_cb" >
<property name="text" >
<string>Minimum coherence (for touching corners)</string>
</property>
</widget>
</item>
<item row="1" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layer_cbx" />
</item>
<item row="5" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layerr_cbx" />
</item>
<item row="3" column="2" colspan="2" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>(0: all polygons, 1: at least two overlapping ...)</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Overlap threshold</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>506</width>
<height>51</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::CellViewSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
<customwidget>
<class>lay::LayerSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MergeOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MergeOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,288 @@
<ui version="4.0" >
<class>SizingOptionsDialog</class>
<widget class="QDialog" name="SizingOptionsDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>567</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle" >
<string>Sizing Operation</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Sizing Operation Setup</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="8" column="1" colspan="3" >
<widget class="QComboBox" name="hier_mode_cbx" >
<item>
<property name="text" >
<string>Flat</string>
</property>
</item>
<item>
<property name="text" >
<string>Top cell only</string>
</property>
</item>
<item>
<property name="text" >
<string>Individually for current and subcells (semi hierarchical)</string>
</property>
</item>
</widget>
</item>
<item row="6" column="3" >
<widget class="QLabel" name="label_10" >
<property name="text" >
<string>(Layer is overwritten)</string>
</property>
</widget>
</item>
<item row="5" column="2" >
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="6" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cvr_cbx" />
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="value_le" />
</item>
<item row="7" column="0" colspan="4" >
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Hierarchy</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="cv_cbx" />
</item>
<item row="6" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Result</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Source</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>Layer</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="9" column="1" colspan="3" >
<widget class="QCheckBox" name="min_coherence_cb" >
<property name="text" >
<string>Minimum coherence (for touching corners)</string>
</property>
</widget>
</item>
<item row="1" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layer_cbx" />
</item>
<item row="6" column="2" >
<widget class="lay::LayerSelectionComboBox" name="layerr_cbx" />
</item>
<item row="3" column="2" colspan="2" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Single value or pair (one per direction: sx,sy)</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Layout and cell</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Sizing value</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_11" >
<property name="text" >
<string>Cutoff mode</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QComboBox" name="cutoff_cbx" >
<item>
<property name="text" >
<string>Strict (diagonal)</string>
</property>
</item>
<item>
<property name="text" >
<string>Strong (octagon)</string>
</property>
</item>
<item>
<property name="text" >
<string>Moderate (sharp bends only)</string>
</property>
</item>
<item>
<property name="text" >
<string>Weak (sharps bends >135 deg.)</string>
</property>
</item>
<item>
<property name="text" >
<string>Long limit (x10)</string>
</property>
</item>
<item>
<property name="text" >
<string>Extreme limit (x100)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>506</width>
<height>51</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::CellViewSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
<customwidget>
<class>lay::LayerSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SizingOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SizingOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,394 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layBooleanOperationsDialogs.h"
#include "layLayoutView.h"
#include "tlExceptions.h"
namespace lay
{
// --------------------------------------------------------------------------------
// BooleanOptionsDialog implementation
BooleanOptionsDialog::BooleanOptionsDialog (QWidget *parent)
: QDialog (parent),
mp_view (0)
{
setObjectName (QString::fromUtf8 ("boolean_options_dialog"));
Ui::BooleanOptionsDialog::setupUi (this);
connect (cva_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
connect (cvb_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
connect (cvr_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
}
BooleanOptionsDialog::~BooleanOptionsDialog ()
{
// .. nothing yet ..
}
void
BooleanOptionsDialog::cv_changed (int)
{
if (! mp_view) {
return;
}
layera_cbx->set_view (mp_view, cva_cbx->currentIndex ());
layerb_cbx->set_view (mp_view, cvb_cbx->currentIndex ());
layerr_cbx->set_view (mp_view, cvr_cbx->currentIndex ());
}
bool
BooleanOptionsDialog::exec_dialog (lay::LayoutView *view, int &cv_a, int &layer_a, int &cv_b, int &layer_b, int &cv_r, int &layer_r, int &mode, int &hier_mode, bool &min_coherence)
{
mp_view = view;
bool res = false;
cva_cbx->set_layout_view (view);
cva_cbx->set_current_cv_index (cv_a);
cvb_cbx->set_layout_view (view);
cvb_cbx->set_current_cv_index (cv_b);
cvb_cbx->setEnabled (true);
cvr_cbx->set_layout_view (view);
cvr_cbx->set_current_cv_index (cv_r);
cv_changed (0 /*dummy*/);
layera_cbx->set_current_layer (layer_a);
layerb_cbx->set_current_layer (layer_b);
layerb_cbx->setEnabled (true);
layerr_cbx->set_current_layer (layer_r);
hier_mode_cbx->setCurrentIndex (hier_mode);
mode_cbx->setCurrentIndex (mode);
min_coherence_cb->setChecked (min_coherence);
if (QDialog::exec ()) {
cv_a = cva_cbx->current_cv_index ();
cv_b = cvb_cbx->current_cv_index ();
cv_r = cvr_cbx->current_cv_index ();
layer_a = layera_cbx->current_layer ();
layer_b = layerb_cbx->current_layer ();
layer_r = layerr_cbx->current_layer ();
hier_mode = hier_mode_cbx->currentIndex ();
mode = mode_cbx->currentIndex ();
min_coherence = min_coherence_cb->isChecked ();
res = true;
}
mp_view = 0;
return res;
}
void
BooleanOptionsDialog::accept ()
{
BEGIN_PROTECTED;
int cv_a = cva_cbx->current_cv_index ();
if (cv_a < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for source 'A'")));
}
int cv_b = cvb_cbx->current_cv_index ();
if (cv_b < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for source 'B'")));
}
int cv_r = cvr_cbx->current_cv_index ();
if (cv_r < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for result")));
}
if (fabs (mp_view->cellview (cv_a)->layout ().dbu () - mp_view->cellview (cv_r)->layout ().dbu ()) > db::epsilon ||
fabs (mp_view->cellview (cv_b)->layout ().dbu () - mp_view->cellview (cv_r)->layout ().dbu ()) > db::epsilon) {
throw tl::Exception (tl::to_string (QObject::tr ("All source and result layouts must have the same database unit")));
}
if (layera_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for source 'A'")));
}
if (layerb_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for source 'B'")));
}
if (layerr_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for result layer")));
}
if (hier_mode_cbx->currentIndex () == 2 &&
cva_cbx->current_cv_index () != cvb_cbx->current_cv_index () &&
cva_cbx->current_cv_index () != cvr_cbx->current_cv_index ()) {
throw tl::Exception (tl::to_string (QObject::tr ("All source layouts and result layout must be same in 'cell by cell' mode")));
}
QDialog::accept ();
END_PROTECTED;
}
// --------------------------------------------------------------------------------
// SizingOptionsDialog implementation
SizingOptionsDialog::SizingOptionsDialog (QWidget *parent)
: QDialog (parent),
mp_view (0)
{
setObjectName (QString::fromUtf8 ("sizing_options_dialog"));
Ui::SizingOptionsDialog::setupUi (this);
connect (cv_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
connect (cvr_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
}
SizingOptionsDialog::~SizingOptionsDialog ()
{
// .. nothing yet ..
}
void
SizingOptionsDialog::cv_changed (int)
{
if (! mp_view) {
return;
}
layer_cbx->set_view (mp_view, cv_cbx->currentIndex ());
layerr_cbx->set_view (mp_view, cvr_cbx->currentIndex ());
}
bool
SizingOptionsDialog::exec_dialog (lay::LayoutView *view, int &cv, int &layer, int &cv_r, int &layer_r, double &dx, double &dy, unsigned int &size_mode, int &hier_mode, bool &min_coherence)
{
mp_view = view;
bool res = false;
cv_cbx->set_layout_view (view);
cv_cbx->set_current_cv_index (cv);
cvr_cbx->set_layout_view (view);
cvr_cbx->set_current_cv_index (cv_r);
cv_changed (0 /*dummy*/);
layer_cbx->set_current_layer (layer);
layerr_cbx->set_current_layer (layer_r);
hier_mode_cbx->setCurrentIndex (hier_mode);
cutoff_cbx->setCurrentIndex (size_mode);
if (dx == dy) {
value_le->setText (tl::to_qstring (tl::sprintf ("%.12g", dx)));
} else {
value_le->setText (tl::to_qstring (tl::sprintf ("%.12g,%.12g", dx, dy)));
}
min_coherence_cb->setChecked (min_coherence);
if (QDialog::exec ()) {
cv = cv_cbx->current_cv_index ();
cv_r = cvr_cbx->current_cv_index ();
layer = layer_cbx->current_layer ();
layer_r = layerr_cbx->current_layer ();
hier_mode = hier_mode_cbx->currentIndex ();
min_coherence = min_coherence_cb->isChecked ();
size_mode = cutoff_cbx->currentIndex ();
tl::string t (tl::to_string (value_le->text ()));
tl::Extractor ex (t.c_str ());
ex.read (dx);
if (ex.test (",")) {
ex.read (dy);
} else {
dy = dx;
}
res = true;
}
mp_view = 0;
return res;
}
void
SizingOptionsDialog::accept ()
{
BEGIN_PROTECTED;
int cv = cv_cbx->current_cv_index ();
if (cv < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for source")));
}
int cv_r = cvr_cbx->current_cv_index ();
if (cv_r < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for result")));
}
if (fabs (mp_view->cellview (cv)->layout ().dbu () - mp_view->cellview (cv_r)->layout ().dbu ()) > db::epsilon) {
throw tl::Exception (tl::to_string (QObject::tr ("Source and result layouts must have the same database unit")));
}
if (layer_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for source")));
}
if (layerr_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for result layer")));
}
if (hier_mode_cbx->currentIndex () == 2 &&
cv_cbx->current_cv_index () != cvr_cbx->current_cv_index ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout and result layout must be same in 'cell by cell' mode")));
}
double x, y;
tl::string t (tl::to_string (value_le->text ()));
tl::Extractor ex (t.c_str ());
ex.read (x);
if (ex.test (",")) {
ex.read (y);
}
QDialog::accept ();
END_PROTECTED;
}
// --------------------------------------------------------------------------------
// MergeOptionsDialog implementation
MergeOptionsDialog::MergeOptionsDialog (QWidget *parent)
: QDialog (parent),
mp_view (0)
{
setObjectName (QString::fromUtf8 ("merge_options_dialog"));
Ui::MergeOptionsDialog::setupUi (this);
connect (cv_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
connect (cvr_cbx, SIGNAL (activated (int)), this, SLOT (cv_changed (int)));
}
MergeOptionsDialog::~MergeOptionsDialog ()
{
// .. nothing yet ..
}
void
MergeOptionsDialog::cv_changed (int)
{
if (! mp_view) {
return;
}
layer_cbx->set_view (mp_view, cv_cbx->currentIndex ());
layerr_cbx->set_view (mp_view, cvr_cbx->currentIndex ());
}
bool
MergeOptionsDialog::exec_dialog (lay::LayoutView *view, int &cv, int &layer, int &cv_r, int &layer_r, unsigned int &min_wc, int &hier_mode, bool &min_coherence)
{
mp_view = view;
bool res = false;
cv_cbx->set_layout_view (view);
cv_cbx->set_current_cv_index (cv);
cvr_cbx->set_layout_view (view);
cvr_cbx->set_current_cv_index (cv_r);
cv_changed (0 /*dummy*/);
layer_cbx->set_current_layer (layer);
layerr_cbx->set_current_layer (layer_r);
hier_mode_cbx->setCurrentIndex (hier_mode);
threshold_le->setText (tl::to_qstring (tl::sprintf ("%u", min_wc)));
min_coherence_cb->setChecked (min_coherence);
if (QDialog::exec ()) {
cv = cv_cbx->current_cv_index ();
cv_r = cvr_cbx->current_cv_index ();
layer = layer_cbx->current_layer ();
layer_r = layerr_cbx->current_layer ();
hier_mode = hier_mode_cbx->currentIndex ();
min_coherence = min_coherence_cb->isChecked ();
std::string t (tl::to_string (threshold_le->text ()));
tl::Extractor ex (t.c_str ());
ex.read (min_wc);
res = true;
}
mp_view = 0;
return res;
}
void
MergeOptionsDialog::accept ()
{
BEGIN_PROTECTED;
int cv = cv_cbx->current_cv_index ();
if (cv < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for source")));
}
int cv_r = cvr_cbx->current_cv_index ();
if (cv_r < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layout specified for result")));
}
if (fabs (mp_view->cellview (cv)->layout ().dbu () - mp_view->cellview (cv_r)->layout ().dbu ()) > db::epsilon) {
throw tl::Exception (tl::to_string (QObject::tr ("Source and result layouts must have the same database unit")));
}
if (layer_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for source")));
}
if (layerr_cbx->current_layer () < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("No layer specified for result")));
}
if (hier_mode_cbx->currentIndex () == 2 &&
cv_cbx->current_cv_index () != cvr_cbx->current_cv_index ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout and result layout must be same in 'cell by cell' mode")));
}
unsigned int min_wc = 0;
std::string t (tl::to_string (threshold_le->text ()));
tl::Extractor ex (t.c_str ());
ex.read (min_wc);
QDialog::accept ();
END_PROTECTED;
}
}
@@ -0,0 +1,119 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layDialogs
#define HDR_layDialogs
#include "ui_BooleanOptionsDialog.h"
#include "ui_SizingOptionsDialog.h"
#include "ui_MergeOptionsDialog.h"
namespace db
{
class Layout;
}
namespace lay
{
class CellView;
class LayoutView;
/**
* @brief The boolean operation options
*/
class BooleanOptionsDialog
: public QDialog,
public Ui::BooleanOptionsDialog
{
Q_OBJECT
public:
BooleanOptionsDialog (QWidget *parent);
virtual ~BooleanOptionsDialog ();
bool exec_dialog (lay::LayoutView *view, int &cv_a, int &layer_a, int &cv_b, int &layer_b, int &cv_res, int &layer_res, int &mode, int &hier_mode, bool &min_coherence);
public slots:
void cv_changed (int);
private:
virtual void accept ();
lay::LayoutView *mp_view;
};
/**
* @brief The sizing operation options
*/
class SizingOptionsDialog
: public QDialog,
public Ui::SizingOptionsDialog
{
Q_OBJECT
public:
SizingOptionsDialog (QWidget *parent);
virtual ~SizingOptionsDialog ();
bool exec_dialog (lay::LayoutView *view, int &cv, int &layer, int &cv_res, int &layer_res, double &dx, double &dy, unsigned int &size_mode, int &hier_mode, bool &min_coherence);
public slots:
void cv_changed (int);
private:
virtual void accept ();
lay::LayoutView *mp_view;
};
/**
* @brief The merge operation options
*/
class MergeOptionsDialog
: public QDialog,
public Ui::MergeOptionsDialog
{
Q_OBJECT
public:
MergeOptionsDialog (QWidget *parent);
virtual ~MergeOptionsDialog ();
bool exec_dialog (lay::LayoutView *view, int &cv, int &layer, int &cv_res, int &layer_res, unsigned int &min_wc, int &hier_mode, bool &min_coherence);
public slots:
void cv_changed (int);
private:
virtual void accept ();
lay::LayoutView *mp_view;
};
}
#endif
@@ -0,0 +1,506 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layBooleanOperationsDialogs.h"
#include "layPlugin.h"
#include "layTipDialog.h"
#include "layLayoutView.h"
#include "dbShapeProcessor.h"
#include <QApplication>
namespace lay
{
class BooleanOperationsPlugin
: public lay::Plugin
{
public:
BooleanOperationsPlugin (Plugin *parent, lay::LayoutView *view)
: lay::Plugin (parent), mp_view (view)
{
m_boolean_cva = -1;
m_boolean_cvb = -1;
m_boolean_cvr = -1;
m_boolean_layera = -1;
m_boolean_layerb = -1;
m_boolean_layerr = -1;
m_boolean_hier_mode = 0;
m_boolean_mode = 0;
m_boolean_mincoh = true;
m_boolean_minwc = 0;
m_boolean_sizex = m_boolean_sizey = 0.0;
m_boolean_size_mode = 2;
}
~BooleanOperationsPlugin ()
{
// ...
}
void menu_activated (const std::string &symbol)
{
if (symbol == "lay::boolean") {
boolean ();
} else if (symbol == "lay::merge") {
merge ();
} else if (symbol == "lay::size") {
size ();
}
}
void boolean ()
{
struct { int *cv; int *layer; } specs [] = {
{ &m_boolean_cva, &m_boolean_layera },
{ &m_boolean_cvb, &m_boolean_layerb },
{ &m_boolean_cvr, &m_boolean_layerr }
};
for (unsigned int i = 0; i < sizeof (specs) / sizeof (specs[0]); ++i) {
int &cv = *(specs[i].cv);
int &layer = *(specs[i].layer);
if (cv >= int (mp_view->cellviews ())) {
cv = -1;
}
int index = mp_view->active_cellview_index ();
if (cv < 0) {
cv = index;
}
if (cv < 0 || ! mp_view->cellview (cv)->layout ().is_valid_layer ((unsigned int) layer)) {
layer = -1;
}
}
lay::BooleanOptionsDialog dialog (mp_view);
if (dialog.exec_dialog (mp_view, m_boolean_cva, m_boolean_layera, m_boolean_cvb, m_boolean_layerb, m_boolean_cvr, m_boolean_layerr, m_boolean_mode, m_boolean_hier_mode, m_boolean_mincoh)) {
mp_view->cancel ();
bool supports_undo = true;
if (db::transactions_enabled ()) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")),
"boolean-undo-buffering",
lay::TipDialog::yesnocancel_buttons);
lay::TipDialog::button_type button = lay::TipDialog::null_button;
td.exec_dialog (button);
if (button == lay::TipDialog::cancel_button) {
return;
}
supports_undo = (button == lay::TipDialog::yes_button);
} else {
supports_undo = false;
}
if (mp_view->manager ()) {
if (! supports_undo) {
mp_view->manager ()->clear ();
} else {
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Boolean operation")));
}
}
try {
db::BooleanOp::BoolOp op_mode;
switch (m_boolean_mode) {
default:
op_mode = db::BooleanOp::Or;
break;
case 1:
op_mode = db::BooleanOp::And;
break;
case 2:
op_mode = db::BooleanOp::ANotB;
break;
case 3:
op_mode = db::BooleanOp::BNotA;
break;
case 4:
op_mode = db::BooleanOp::Xor;
break;
}
if (m_boolean_hier_mode == 0) {
// flat mode
db::ShapeProcessor p (true);
p.boolean (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvb)->layout (), *mp_view->cellview (m_boolean_cvb).cell (), m_boolean_layerb,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), op_mode, true, true, m_boolean_mincoh);
// clear the result layer for all called cells in flat mode
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cvr).cell ()->collect_called_cells (called_cells);
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
mp_view->cellview (m_boolean_cvr)->layout ().cell (*c).shapes (m_boolean_layerr).clear ();
}
} else if (m_boolean_hier_mode == 1) {
// top cell only mode
db::ShapeProcessor p (true);
p.boolean (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvb)->layout (), *mp_view->cellview (m_boolean_cvb).cell (), m_boolean_layerb,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), op_mode, false, true, m_boolean_mincoh);
} else if (m_boolean_hier_mode == 2) {
// subcells cell by cell
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cva).cell ()->collect_called_cells (called_cells);
called_cells.insert (mp_view->cellview (m_boolean_cva).cell_index ());
db::ShapeProcessor p (true);
db::Layout &layout = mp_view->cellview (m_boolean_cva)->layout ();
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
db::Cell &cell = layout.cell (*c);
p.boolean (layout, cell, m_boolean_layera,
layout, cell, m_boolean_layerb,
cell.shapes (m_boolean_layerr), op_mode, false, true, m_boolean_mincoh);
}
}
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
} catch (...) {
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
throw;
}
}
}
void merge ()
{
struct { int *cv; int *layer; } specs [] = {
{ &m_boolean_cva, &m_boolean_layera },
{ &m_boolean_cvr, &m_boolean_layerr }
};
for (unsigned int i = 0; i < sizeof (specs) / sizeof (specs[0]); ++i) {
int &cv = *(specs[i].cv);
int &layer = *(specs[i].layer);
if (cv >= int (mp_view->cellviews ())) {
cv = -1;
}
int index = mp_view->active_cellview_index ();
if (cv < 0) {
cv = index;
}
if (cv < 0 || ! mp_view->cellview (cv)->layout ().is_valid_layer ((unsigned int) layer)) {
layer = -1;
}
}
lay::MergeOptionsDialog dialog (mp_view);
if (dialog.exec_dialog (mp_view, m_boolean_cva, m_boolean_layera, m_boolean_cvr, m_boolean_layerr, m_boolean_minwc, m_boolean_hier_mode, m_boolean_mincoh)) {
mp_view->cancel ();
bool supports_undo = true;
if (db::transactions_enabled ()) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")),
"merge-undo-buffering",
lay::TipDialog::yesnocancel_buttons);
lay::TipDialog::button_type button = lay::TipDialog::null_button;
td.exec_dialog (button);
if (button == lay::TipDialog::cancel_button) {
return;
}
supports_undo = (button == lay::TipDialog::yes_button);
} else {
supports_undo = false;
}
if (mp_view->manager ()) {
if (! supports_undo) {
mp_view->manager ()->clear ();
} else {
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Merge operation")));
}
}
try {
if (m_boolean_hier_mode == 0) {
// flat mode
db::ShapeProcessor p (true);
p.merge (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), true, m_boolean_minwc, true, m_boolean_mincoh);
// clear the result layer for all called cells in flat mode
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cvr).cell ()->collect_called_cells (called_cells);
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
mp_view->cellview (m_boolean_cvr)->layout ().cell (*c).shapes (m_boolean_layerr).clear ();
}
} else if (m_boolean_hier_mode == 1) {
// top cell only mode
db::ShapeProcessor p (true);
p.merge (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), false, m_boolean_minwc, true, m_boolean_mincoh);
} else if (m_boolean_hier_mode == 2) {
// subcells cell by cell
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cva).cell ()->collect_called_cells (called_cells);
called_cells.insert (mp_view->cellview (m_boolean_cva).cell_index ());
db::ShapeProcessor p (true);
db::Layout &layout = mp_view->cellview (m_boolean_cva)->layout ();
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
db::Cell &cell = layout.cell (*c);
p.merge (layout, cell, m_boolean_layera,
cell.shapes (m_boolean_layerr), false, m_boolean_minwc, true, m_boolean_mincoh);
}
}
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
} catch (...) {
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
throw;
}
}
}
void size ()
{
struct { int *cv; int *layer; } specs [] = {
{ &m_boolean_cva, &m_boolean_layera },
{ &m_boolean_cvr, &m_boolean_layerr }
};
for (unsigned int i = 0; i < sizeof (specs) / sizeof (specs[0]); ++i) {
int &cv = *(specs[i].cv);
int &layer = *(specs[i].layer);
if (cv >= int (mp_view->cellviews ())) {
cv = -1;
}
int index = mp_view->active_cellview_index ();
if (cv < 0) {
cv = index;
}
if (cv < 0 || ! mp_view->cellview (cv)->layout ().is_valid_layer ((unsigned int) layer)) {
layer = -1;
}
}
lay::SizingOptionsDialog dialog (mp_view);
if (dialog.exec_dialog (mp_view, m_boolean_cva, m_boolean_layera, m_boolean_cvr, m_boolean_layerr, m_boolean_sizex, m_boolean_sizey, m_boolean_size_mode, m_boolean_hier_mode, m_boolean_mincoh)) {
mp_view->cancel ();
bool supports_undo = true;
if (db::transactions_enabled ()) {
lay::TipDialog td (QApplication::activeWindow (),
tl::to_string (QObject::tr ("Undo buffering for the following operation can be memory and time consuming.\nChoose \"Yes\" to use undo buffering or \"No\" for no undo buffering. Warning: in the latter case, the undo history will be lost.\n\nChoose undo buffering?")),
"size-undo-buffering",
lay::TipDialog::yesnocancel_buttons);
lay::TipDialog::button_type button = lay::TipDialog::null_button;
td.exec_dialog (button);
if (button == lay::TipDialog::cancel_button) {
return;
}
supports_undo = (button == lay::TipDialog::yes_button);
} else {
supports_undo = false;
}
db::Coord dx_int, dy_int;
dx_int = db::coord_traits<db::Coord>::rounded (m_boolean_sizex / mp_view->cellview (m_boolean_cva)->layout ().dbu ());
dy_int = db::coord_traits<db::Coord>::rounded (m_boolean_sizey / mp_view->cellview (m_boolean_cva)->layout ().dbu ());
if (mp_view->manager ()) {
if (! supports_undo) {
mp_view->manager ()->clear ();
} else {
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Sizing operation")));
}
}
try {
if (m_boolean_hier_mode == 0) {
// flat mode
db::ShapeProcessor p (true);
p.size (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), dx_int, dy_int, m_boolean_size_mode, true, true, m_boolean_mincoh);
// clear the result layer for all called cells in flat mode
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cvr).cell ()->collect_called_cells (called_cells);
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
mp_view->cellview (m_boolean_cvr)->layout ().cell (*c).shapes (m_boolean_layerr).clear ();
}
} else if (m_boolean_hier_mode == 1) {
// top cell only mode
db::ShapeProcessor p (true);
p.size (mp_view->cellview (m_boolean_cva)->layout (), *mp_view->cellview (m_boolean_cva).cell (), m_boolean_layera,
mp_view->cellview (m_boolean_cvr).cell ()->shapes (m_boolean_layerr), dx_int, dy_int, m_boolean_size_mode, false, true, m_boolean_mincoh);
} else if (m_boolean_hier_mode == 2) {
// subcells cell by cell
std::set<db::cell_index_type> called_cells;
mp_view->cellview (m_boolean_cva).cell ()->collect_called_cells (called_cells);
called_cells.insert (mp_view->cellview (m_boolean_cva).cell_index ());
db::ShapeProcessor p (true);
db::Layout &layout = mp_view->cellview (m_boolean_cva)->layout ();
for (std::set<db::cell_index_type>::const_iterator c = called_cells.begin (); c != called_cells.end (); ++c) {
db::Cell &cell = layout.cell (*c);
p.size (layout, cell, m_boolean_layera,
cell.shapes (m_boolean_layerr), dx_int, dy_int, m_boolean_size_mode, false, true, m_boolean_mincoh);
}
}
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
} catch (...) {
if (supports_undo && mp_view->manager ()) {
mp_view->manager ()->commit ();
}
throw;
}
}
}
private:
lay::LayoutView *mp_view;
int m_boolean_cva, m_boolean_cvb, m_boolean_cvr;
int m_boolean_layera, m_boolean_layerb, m_boolean_layerr;
int m_boolean_hier_mode, m_boolean_mode;
bool m_boolean_mincoh;
unsigned int m_boolean_minwc;
double m_boolean_sizex, m_boolean_sizey;
unsigned int m_boolean_size_mode;
};
class BooleanOperationsPluginDeclaration
: public lay::PluginDeclaration
{
public:
BooleanOperationsPluginDeclaration ()
{
// .. nothing yet ..
}
virtual void get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
{
// .. nothing yet ..
}
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
{
// .. nothing yet ..
return 0;
}
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{
lay::PluginDeclaration::get_menu_entries (menu_entries);
menu_entries.push_back (lay::MenuEntry ("ops_group", "edit_menu.layer_menu.end"));
menu_entries.push_back (lay::MenuEntry ("lay::boolean", "boolean:edit:edit_mode", "edit_menu.layer_menu.end", tl::to_string (QObject::tr ("Boolean Operations"))));
menu_entries.push_back (lay::MenuEntry ("lay::merge", "merge:edit:edit_mode", "edit_menu.layer_menu.end", tl::to_string (QObject::tr ("Merge"))));
menu_entries.push_back (lay::MenuEntry ("lay::size", "size:edit:edit_mode", "edit_menu.layer_menu.end", tl::to_string (QObject::tr ("Size"))));
}
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
virtual void config_finalize ()
{
// .. nothing yet ..
}
lay::Plugin *create_plugin (db::Manager *, lay::PluginRoot *root, lay::LayoutView *view) const
{
return new BooleanOperationsPlugin (root, view);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::BooleanOperationsPluginDeclaration (), 3010, "lay::BooleanOperationsPlugin");
}
@@ -0,0 +1,17 @@
TARGET = bool
DESTDIR = $$OUT_PWD/../../../../lay_plugins
include($$PWD/../../../lay_plugin.pri)
HEADERS = \
layBooleanOperationsDialogs.h
SOURCES = \
layBooleanOperationsDialogs.cc \
layBooleanOperationsPlugin.cc
FORMS = \
BooleanOptionsDialog.ui \
SizingOptionsDialog.ui \
MergeOptionsDialog.ui \
+5
View File
@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = lay_plugin
@@ -0,0 +1,217 @@
<ui version="4.0" >
<class>DiffToolDialog</class>
<widget class="QDialog" name="DiffToolDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>498</width>
<height>404</height>
</rect>
</property>
<property name="windowTitle" >
<string>Diff Tool</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Input</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Layout A </string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Layout B</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="layouta" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy" >
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="lay::CellViewSelectionComboBox" name="layoutb" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy" >
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Options</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="smart_cbx" >
<property name="text" >
<string>Don't use names to match cells (use geometrical properties)</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="xor_cbx" >
<property name="text" >
<string>Run XOR on differences</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="summarize_cbx" >
<property name="text" >
<string>Summarize missing layers</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="detailed_cbx" >
<property name="text" >
<string>Detailed information</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="expand_cell_arrays_cbx" >
<property name="text" >
<string>Expand cell arrays (compare single instance by instance)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="exact_cbx" >
<property name="text" >
<string>Exact compare (includes properties, text orientation and similar)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>472</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::CellViewSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DiffToolDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DiffToolDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,116 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layPlugin.h"
namespace lay
{
class DiffPlugin
: public lay::Plugin
{
public:
DiffPlugin (Plugin *parent, lay::LayoutView *view)
: lay::Plugin (parent), mp_view (view)
{
mp_dialog = new lay::DiffToolDialog (0);
}
~DiffPlugin ()
{
delete mp_dialog;
mp_dialog = 0;
}
void menu_activated (const std::string &symbol)
{
if (symbol == "lay::diff_tool") {
if (mp_dialog->exec_dialog (mp_view)) {
// ... implementation is in layDiffToolDialog.cc ...
}
}
}
private:
lay::LayoutView *mp_view;
lay::DiffToolDialog *mp_dialog;
};
class DiffPluginDeclaration
: public lay::PluginDeclaration
{
public:
DiffPluginDeclaration ()
{
// .. nothing yet ..
}
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
{
options.push_back (std::pair<std::string, std::string> (cfg_diff_run_xor, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_diff_detailed, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_diff_summarize, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_diff_expand_cell_arrays, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_diff_exact, "false"));
}
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
{
// .. nothing yet ..
return 0;
}
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{
lay::PluginDeclaration::get_menu_entries (menu_entries);
menu_entries.push_back (lay::MenuEntry ("lay::diff_tool", "diff_tool:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("Diff Tool"))));
}
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
virtual void config_finalize ()
{
// .. nothing yet ..
}
lay::Plugin *create_plugin (db::Manager *, lay::PluginRoot *root, lay::LayoutView *view) const
{
return new DiffPlugin (root, view);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::DiffPluginDeclaration (), 3001, "lay::DiffPlugin");
}
@@ -0,0 +1,766 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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::PluginRoot *config_root = lay::PluginRoot::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::PluginRoot *config_root = lay::PluginRoot::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 ();
}
}
@@ -0,0 +1,78 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layDiffToolDialog
#define HDR_layDiffToolDialog
#include <QDialog>
#include <string>
namespace Ui
{
class DiffToolDialog;
}
namespace lay
{
class LayoutView;
}
namespace lay
{
extern std::string cfg_diff_run_xor;
extern std::string cfg_diff_detailed;
extern std::string cfg_diff_summarize;
extern std::string cfg_diff_expand_cell_arrays;
extern std::string cfg_diff_exact;
class DiffToolDialog
: public QDialog
{
Q_OBJECT
public:
DiffToolDialog (QWidget *parent);
~DiffToolDialog ();
int exec_dialog (lay::LayoutView *view);
protected slots:
void xor_changed () { update (); }
protected:
void accept ();
void run_diff ();
void update ();
private:
Ui::DiffToolDialog *mp_ui;
lay::LayoutView *mp_view;
};
}
#endif
@@ -0,0 +1,19 @@
TARGET = diff
DESTDIR = $$OUT_PWD/../../../../lay_plugins
include($$PWD/../../../lay_plugin.pri)
INCLUDEPATH += $$RDB_INC $$ANT_INC
DEPENDPATH += $$RDB_INC $$ANT_INC
LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant
HEADERS = \
layDiffToolDialog.h
SOURCES = \
layDiffPlugin.cc \
layDiffToolDialog.cc
FORMS = \
DiffToolDialog.ui \
+5
View File
@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = lay_plugin
@@ -0,0 +1,843 @@
<ui version="4.0" >
<class>StreamImportDialog</class>
<widget class="QDialog" name="StreamImportDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>754</width>
<height>604</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="6" column="1" >
<widget class="QPushButton" name="last_pb" >
<property name="text" >
<string>Back</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/back.png</iconset>
</property>
</widget>
</item>
<item row="6" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>331</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="3" >
<widget class="QPushButton" name="import_pb" >
<property name="text" >
<string>Import</string>
</property>
</widget>
</item>
<item row="6" column="2" >
<widget class="QPushButton" name="next_pb" >
<property name="text" >
<string>Next</string>
</property>
<property name="icon" >
<iconset resource="layResources.qrc" >:/forward.png</iconset>
</property>
</widget>
</item>
<item row="6" column="4" >
<widget class="QPushButton" name="cancel_pb" >
<property name="text" >
<string>Cancel</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="5" >
<widget class="Line" name="line_4" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0" colspan="5" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>736</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="5" >
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0" colspan="5" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>736</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="5" >
<widget class="QFrame" name="frame_3" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="section_header_lbl" >
<property name="font" >
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>SectionHeader</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="reset_pb" >
<property name="text" >
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="5" >
<widget class="QStackedWidget" name="central_stack" >
<property name="currentIndex" >
<number>2</number>
</property>
<widget class="QWidget" name="page" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="title" >
<string>Input</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="1" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Top cell </string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="file_le" />
</item>
<item row="0" column="3" >
<widget class="QToolButton" name="file_pb" >
<property name="text" >
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>File </string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2" >
<widget class="QLabel" name="label_2" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>(leave empty for selecting the top cell automatically)</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="topcell_le" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="4" >
<widget class="QFrame" name="frame_2" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Stream reader options </string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="edit_options_pb" >
<property name="text" >
<string>Edit ...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="reset_options_pb" >
<property name="text" >
<string>Reset</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Import Mode</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="import_simple_rb" >
<property name="text" >
<string>Merge - Merge new cell into current cell and create a new cell hierarchy below</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="import_extra_rb" >
<property name="text" >
<string>Extra cells - Import as extra cells</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="import_instantiate_rb" >
<property name="text" >
<string>Instantiate - Instantiate a new cell tree below the current cell</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="import_merge_rb" >
<property name="text" >
<string>Merge hierarchy - Merge into current cell's hierarchy (attempt to identify corresponding cells)</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Note: All modes except "Extra cells" require a unique top cell for the input file. Either one must be specified or the input file must have a single top cell.</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item rowspan="5" row="0" column="0" >
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Layer mapping</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="1" colspan="2" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Use "layer/datatype" notation to specify an offset to be added to layer and/or datatype.</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="offset_le" />
</item>
<item row="1" column="0" >
<widget class="QRadioButton" name="offset_rb" >
<property name="text" >
<string>On original layers plus offset</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QRadioButton" name="no_mapping_rb" >
<property name="text" >
<string>No mapping - use original layers</string>
</property>
</widget>
</item>
<item row="1" column="2" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>211</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_6" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QFrame" name="frame_5" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="3" column="5" >
<widget class="QLineEdit" name="layout_x1_le" />
</item>
<item row="5" column="2" >
<widget class="QLineEdit" name="pcb_y3_le" />
</item>
<item row="3" column="4" >
<widget class="QLabel" name="label_22" >
<property name="text" >
<string>Point 1</string>
</property>
</widget>
</item>
<item row="2" column="6" >
<widget class="QLabel" name="label_24" >
<property name="text" >
<string>y (micron)</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3" >
<widget class="QLabel" name="label_17" >
<property name="text" >
<string>Reference points coordinates on layout to import</string>
</property>
</widget>
</item>
<item row="4" column="2" >
<widget class="QLineEdit" name="pcb_y2_le" />
</item>
<item row="5" column="4" >
<widget class="QLabel" name="Point 3" >
<property name="text" >
<string>Point 3</string>
</property>
</widget>
</item>
<item row="4" column="5" >
<widget class="QLineEdit" name="layout_x2_le" />
</item>
<item row="0" column="4" colspan="3" >
<widget class="QLabel" name="label_18" >
<property name="text" >
<string>Reference point coordinates in existing layout</string>
</property>
</widget>
</item>
<item row="5" column="5" >
<widget class="QLineEdit" name="layout_x3_le" />
</item>
<item row="5" column="6" >
<widget class="QLineEdit" name="layout_y3_le" />
</item>
<item row="2" column="5" >
<widget class="QLabel" name="label_23" >
<property name="text" >
<string>x (micron)</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3" >
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_25" >
<property name="text" >
<string>Point 2</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLineEdit" name="pcb_x2_le" />
</item>
<item row="5" column="0" >
<widget class="QLabel" name="label_26" >
<property name="text" >
<string>Point 3</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_21" >
<property name="text" >
<string>Point 1</string>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="QLineEdit" name="pcb_x3_le" />
</item>
<item row="3" column="2" >
<widget class="QLineEdit" name="pcb_y1_le" />
</item>
<item row="1" column="4" colspan="3" >
<widget class="Line" name="line_3" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="pcb_x1_le" />
</item>
<item row="2" column="2" >
<widget class="QLabel" name="label_20" >
<property name="text" >
<string>y (micron)</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="label_19" >
<property name="text" >
<string>x (micron)</string>
</property>
</widget>
</item>
<item row="4" column="4" >
<widget class="QLabel" name="label_27" >
<property name="text" >
<string>Point 2</string>
</property>
</widget>
</item>
<item row="4" column="6" >
<widget class="QLineEdit" name="layout_y2_le" />
</item>
<item row="3" column="6" >
<widget class="QLineEdit" name="layout_y1_le" />
</item>
<item rowspan="6" row="0" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>16</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0" colspan="7" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>691</width>
<height>8</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0" colspan="7" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>15</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0" colspan="7" >
<widget class="QFrame" name="frame_6" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_30" >
<property name="text" >
<string>Explicit transformation</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="explicit_trans_le" >
<property name="toolTip" >
<string>Examples: "r90", "m45", "r90 (2000,-5000)"</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_31" >
<property name="text" >
<string>(Reference points have higher priority)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="7" column="0" colspan="7" >
<widget class="QLabel" name="label_29" >
<property name="text" >
<string>Leave fields empty to specify less reference points. One point is used to derive the displacement, further points are used to derive the orientation. Currently, no magnification is implied and only simple rotations are derived from the mapping points.
Alternatively the transformation (imported to existing layout) can be specified using the explicit transformation below. This allows to specify an arbitary transformation. Use the common notation (i.e. "*2 r90 10,-100").</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>file_le</tabstop>
<tabstop>file_pb</tabstop>
<tabstop>topcell_le</tabstop>
<tabstop>edit_options_pb</tabstop>
<tabstop>reset_options_pb</tabstop>
<tabstop>import_simple_rb</tabstop>
<tabstop>import_extra_rb</tabstop>
<tabstop>import_instantiate_rb</tabstop>
<tabstop>import_merge_rb</tabstop>
<tabstop>no_mapping_rb</tabstop>
<tabstop>offset_rb</tabstop>
<tabstop>offset_le</tabstop>
<tabstop>pcb_x1_le</tabstop>
<tabstop>pcb_y1_le</tabstop>
<tabstop>layout_x1_le</tabstop>
<tabstop>layout_y1_le</tabstop>
<tabstop>pcb_x2_le</tabstop>
<tabstop>pcb_y2_le</tabstop>
<tabstop>layout_x2_le</tabstop>
<tabstop>layout_y2_le</tabstop>
<tabstop>pcb_x3_le</tabstop>
<tabstop>pcb_y3_le</tabstop>
<tabstop>layout_x3_le</tabstop>
<tabstop>layout_y3_le</tabstop>
<tabstop>explicit_trans_le</tabstop>
<tabstop>last_pb</tabstop>
<tabstop>next_pb</tabstop>
<tabstop>import_pb</tabstop>
<tabstop>cancel_pb</tabstop>
</tabstops>
<resources>
<include location="layResources.qrc" />
</resources>
<connections>
<connection>
<sender>import_pb</sender>
<signal>clicked()</signal>
<receiver>StreamImportDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>572</x>
<y>598</y>
</hint>
<hint type="destinationlabel" >
<x>574</x>
<y>614</y>
</hint>
</hints>
</connection>
<connection>
<sender>cancel_pb</sender>
<signal>clicked()</signal>
<receiver>StreamImportDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>679</x>
<y>597</y>
</hint>
<hint type="destinationlabel" >
<x>683</x>
<y>613</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,173 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layStreamImportDialog.h"
#include "layStreamImporter.h"
#include "dbStream.h"
#include "tlExceptions.h"
#include "layPlugin.h"
#include "layMainWindow.h"
#include "layFileDialog.h"
#include <QApplication>
namespace lay
{
static const std::string cfg_stream_import_spec ("stream-import-spec2");
class StreamImportPluginDeclaration
: public lay::PluginDeclaration
{
public:
StreamImportPluginDeclaration ()
{
// .. nothing yet ..
}
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
{
options.push_back (std::pair<std::string, std::string> (cfg_stream_import_spec, ""));
}
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
{
// .. nothing yet ..
return 0;
}
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{
lay::PluginDeclaration::get_menu_entries (menu_entries);
menu_entries.push_back (lay::MenuEntry ("lay::import_stream", "import_stream:edit", "file_menu.import_menu.end", tl::to_string (QObject::tr ("Other File Into Current"))));
}
virtual bool configure (const std::string &name, const std::string &value)
{
if (name == cfg_stream_import_spec) {
m_import_spec = value;
return true;
} else {
return false;
}
}
virtual void config_finalize ()
{
// .. nothing yet ..
}
virtual bool menu_activated (const std::string &symbol) const
{
if (symbol == "lay::import_stream") {
lay::LayoutView *view = lay::LayoutView::current ();
if (! view) {
throw tl::Exception (tl::to_string (QObject::tr ("No view open to import files into")));
}
StreamImportData data;
try {
data.from_string (m_import_spec);
} catch (...) {
data = StreamImportData ();
}
lay::PluginRoot *config_root = lay::PluginRoot::instance ();
StreamImportDialog dialog (QApplication::activeWindow (), &data);
lay::StreamImporter importer;
bool ok = false;
while (! ok && dialog.exec ()) {
BEGIN_PROTECTED
data.setup_importer (&importer);
ok = true;
END_PROTECTED
}
if (ok) {
// clear selection
lay::MainWindow::instance ()->cancel ();
config_root->config_set (cfg_stream_import_spec, data.to_string ());
config_root->config_end ();
int cv_index = view->active_cellview_index ();
const lay::CellView &cv = view->cellview (cv_index);
std::vector <unsigned int> new_layer_ids;
importer.read (cv->layout (), cv.cell_index (), new_layer_ids);
// create the initial layer properties
std::vector <lay::ParsedLayerSource> new_layers;
new_layers.reserve (cv->layout ().layers ());
for (unsigned int i = 0; i < new_layer_ids.size (); ++i) {
if (cv->layout ().is_valid_layer (new_layer_ids [i])) {
db::LayerProperties lp (cv->layout ().get_properties (new_layer_ids [i]));
new_layers.push_back (lay::ParsedLayerSource (lp, cv_index));
}
}
std::sort (new_layers.begin (), new_layers.end ());
lay::LayerPropertiesList new_props (view->get_properties ());
// create the layers and do a basic recoloring ..
for (std::vector <lay::ParsedLayerSource>::const_iterator l = new_layers.begin (); l != new_layers.end (); ++l) {
lay::LayerProperties p;
p.set_source (*l);
view->init_layer_properties (p);
new_props.push_back (p);
}
view->set_properties (new_props);
view->update_content ();
config_root->config_set (cfg_stream_import_spec, data.to_string ());
config_root->config_end ();
}
return true;
} else {
return false;
}
}
private:
std::string m_import_spec;
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::StreamImportPluginDeclaration (), 1300, "lay::StreamImportPlugin");
}
@@ -0,0 +1,491 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "ui_StreamImportDialog.h"
#include "layStreamImporter.h"
#include "layStreamImportDialog.h"
#include "tlExceptions.h"
#include "layFileDialog.h"
#include "layDialogs.h"
#include "layConverters.h"
#include "layLoadLayoutOptionsDialog.h"
#include <QFileDialog>
#include <fstream>
namespace {
static struct {
const char *string;
lay::StreamImportData::mode_type value;
} mode_strings [] = {
{ "simple", lay::StreamImportData::Simple },
{ "instantiate", lay::StreamImportData::Instantiate },
{ "extra", lay::StreamImportData::Extra },
{ "merge", lay::StreamImportData::Merge }
};
struct ModeConverter
{
std::string to_string (lay::StreamImportData::mode_type t) const
{
for (unsigned int i = 0; i < sizeof (mode_strings) / sizeof (mode_strings [0]); ++i) {
if (mode_strings [i].value == t) {
return mode_strings [i].string;
}
}
return std::string ();
}
void from_string (const std::string &s, lay::StreamImportData::mode_type &t) const
{
for (unsigned int i = 0; i < sizeof (mode_strings) / sizeof (mode_strings [0]); ++i) {
if (s == mode_strings [i].string) {
t = mode_strings [i].value;
return;
}
}
t = mode_strings [0].value;
}
};
static struct {
const char *string;
lay::StreamImportData::layer_mode_type value;
} layer_mode_strings [] = {
{ "original", lay::StreamImportData::Original },
{ "offset", lay::StreamImportData::Offset }
};
struct LayerModeConverter
{
std::string to_string (lay::StreamImportData::layer_mode_type t) const
{
for (unsigned int i = 0; i < sizeof (layer_mode_strings) / sizeof (layer_mode_strings [0]); ++i) {
if (layer_mode_strings [i].value == t) {
return layer_mode_strings [i].string;
}
}
return std::string ();
}
void from_string (const std::string &s, lay::StreamImportData::layer_mode_type &t) const
{
for (unsigned int i = 0; i < sizeof (layer_mode_strings) / sizeof (layer_mode_strings [0]); ++i) {
if (s == layer_mode_strings [i].string) {
t = layer_mode_strings [i].value;
return;
}
}
t = layer_mode_strings [0].value;
}
};
}
namespace lay
{
// -----------------------------------------------------------------------------------------
// StreamImportData implementation
StreamImportData::StreamImportData ()
: mode (Simple), layer_mode (Original)
{
// .. nothing yet ..
}
void
StreamImportData::setup_importer (StreamImporter *importer)
{
importer->set_global_trans (explicit_trans);
importer->set_reference_points (reference_points);
importer->set_cell_mapping (mode);
importer->set_layer_mapping (layer_mode);
importer->set_file (file);
importer->set_topcell (topcell);
importer->set_layer_offset (layer_offset);
importer->set_reader_options (options);
}
static tl::XMLElementList xml_elements ()
{
typedef std::pair <db::DPoint, db::DPoint> ref_point;
typedef std::vector<ref_point> ref_point_v;
return
tl::make_member (&StreamImportData::file, "file") +
tl::make_member (&StreamImportData::topcell, "cell-name") +
tl::make_member (&StreamImportData::layer_offset, "layer-offset") +
tl::make_member (&StreamImportData::layer_mode, "layer-mode", LayerModeConverter ()) +
tl::make_member (&StreamImportData::mode, "import-mode", ModeConverter ()) +
tl::make_element (&StreamImportData::reference_points, "reference-points",
tl::make_element<ref_point, ref_point_v::const_iterator, ref_point_v> (&ref_point_v::begin, &ref_point_v::end, &ref_point_v::push_back, "reference-point",
tl::make_member (&ref_point::first, "p1") +
tl::make_member (&ref_point::second, "p2")
)
) +
tl::make_member (&StreamImportData::explicit_trans, "explicit-trans") +
tl::make_element (&StreamImportData::options, "options",
db::load_options_xml_element_list ()
);
}
void
StreamImportData::from_string (const std::string &s)
{
*this = StreamImportData ();
tl::XMLStringSource source (s);
tl::XMLStruct<StreamImportData> xml_struct ("stream-import-data", xml_elements ());
xml_struct.parse (source, *this);
}
std::string
StreamImportData::to_string () const
{
tl::OutputStringStream os;
tl::XMLStruct<StreamImportData> xml_struct ("stream-import-data", xml_elements ());
tl::OutputStream oss (os);
xml_struct.write (oss, *this);
return os.string ();
}
// -----------------------------------------------------------------------------------------
// StreamImportDialog implementation
StreamImportDialog::StreamImportDialog (QWidget *parent, StreamImportData *data)
: QDialog (parent), mp_data (data)
{
mp_ui = new Ui::StreamImportDialog ();
mp_ui->setupUi (this);
connect (mp_ui->last_pb, SIGNAL (clicked ()), this, SLOT (last_page ()));
connect (mp_ui->next_pb, SIGNAL (clicked ()), this, SLOT (next_page ()));
connect (mp_ui->file_pb, SIGNAL (clicked ()), this, SLOT (browse_filename ()));
connect (mp_ui->edit_options_pb, SIGNAL (clicked ()), this, SLOT (edit_options ()));
connect (mp_ui->reset_options_pb, SIGNAL (clicked ()), this, SLOT (reset_options ()));
connect (mp_ui->reset_pb, SIGNAL (clicked ()), this, SLOT (reset ()));
connect (mp_ui->offset_rb, SIGNAL (clicked ()), this, SLOT (mapping_changed ()));
connect (mp_ui->no_mapping_rb, SIGNAL (clicked ()), this, SLOT (mapping_changed ()));
}
StreamImportDialog::~StreamImportDialog ()
{
delete mp_ui;
mp_ui = 0;
}
void
StreamImportDialog::edit_options ()
{
lay::LoadLayoutOptionsDialog dialog (this, tl::to_string (QObject::tr ("Import Layout Options")));
dialog.get_options (mp_data->options);
}
void
StreamImportDialog::reset_options ()
{
mp_data->options = db::LoadLayoutOptions ();
}
void
StreamImportDialog::browse_filename ()
{
QString file = mp_ui->file_le->text ();
file = QFileDialog::getOpenFileName (this, QObject::tr ("File To Import"), file, QObject::tr ("All files (*)"));
if (! file.isNull ()) {
mp_ui->file_le->setText (file);
}
}
void
StreamImportDialog::reject ()
{
try {
commit_page ();
} catch (...) {
// .. nothing yet ..
}
QDialog::reject ();
}
void
StreamImportDialog::accept ()
{
BEGIN_PROTECTED
commit_page ();
QDialog::accept ();
END_PROTECTED
}
int
StreamImportDialog::exec ()
{
mp_ui->central_stack->setCurrentIndex (0);
update ();
return QDialog::exec ();
}
/*
* 0 - General
* 1 - Layers
* 2 - Reference points
*/
static int next_pages[] = { 1, 2, -1 };
static int prev_pages[] = { -1, 0, 1 };
void
StreamImportDialog::next_page ()
{
BEGIN_PROTECTED
commit_page ();
int index = mp_ui->central_stack->currentIndex ();
if (index >= 0 && index < int (sizeof (next_pages) / sizeof (next_pages [0]))) {
index = next_pages [index];
if (index >= 0) {
mp_ui->central_stack->setCurrentIndex (index);
enter_page ();
}
}
update ();
END_PROTECTED
}
void
StreamImportDialog::last_page ()
{
// "safe" commit
try {
commit_page ();
} catch (...) { }
BEGIN_PROTECTED
int index = mp_ui->central_stack->currentIndex ();
if (index >= 0 && index < int (sizeof (next_pages) / sizeof (next_pages [0]))) {
index = prev_pages [index];
if (index >= 0) {
mp_ui->central_stack->setCurrentIndex (index);
}
}
update ();
END_PROTECTED
}
void
StreamImportDialog::enter_page ()
{
// .. nothing yet ..
}
void
StreamImportDialog::commit_page ()
{
int page = mp_ui->central_stack->currentIndex ();
if (page == 0) {
// --- General page
mp_data->file = tl::to_string (mp_ui->file_le->text ());
mp_data->topcell = tl::to_string (mp_ui->topcell_le->text ());
if (mp_ui->import_simple_rb->isChecked ()) {
mp_data->mode = StreamImportData::Simple;
} else if (mp_ui->import_instantiate_rb->isChecked ()) {
mp_data->mode = StreamImportData::Instantiate;
} else if (mp_ui->import_extra_rb->isChecked ()) {
mp_data->mode = StreamImportData::Extra;
} else if (mp_ui->import_merge_rb->isChecked ()) {
mp_data->mode = StreamImportData::Merge;
}
} else if (page == 1) {
// --- Layer mapping
if (mp_ui->no_mapping_rb->isChecked ()) {
mp_data->layer_mode = StreamImportData::Original;
} else if (mp_ui->offset_rb->isChecked ()) {
mp_data->layer_mode = StreamImportData::Offset;
}
mp_data->layer_offset = db::LayerOffset ();
std::string offset = tl::to_string (mp_ui->offset_le->text ());
tl::Extractor ex (offset.c_str ());
mp_data->layer_offset.read (ex);
} else if (page == 2) {
// --- Coordinate Mapping page
QLineEdit *(coord_editors[][4]) = {
{ mp_ui->pcb_x1_le, mp_ui->pcb_y1_le, mp_ui->layout_x1_le, mp_ui->layout_y1_le },
{ mp_ui->pcb_x2_le, mp_ui->pcb_y2_le, mp_ui->layout_x2_le, mp_ui->layout_y2_le },
{ mp_ui->pcb_x3_le, mp_ui->pcb_y3_le, mp_ui->layout_x3_le, mp_ui->layout_y3_le }
};
mp_data->reference_points.clear ();
for (unsigned int i = 0; i < sizeof (coord_editors) / sizeof (coord_editors [0]); ++i) {
std::string t_pcb_x (tl::to_string (coord_editors [i][0]->text ()));
tl::Extractor pcb_x (t_pcb_x.c_str ());
std::string t_pcb_y (tl::to_string (coord_editors [i][1]->text ()));
tl::Extractor pcb_y (t_pcb_y.c_str ());
std::string t_layout_x (tl::to_string (coord_editors [i][2]->text ()));
tl::Extractor layout_x (t_layout_x.c_str ());
std::string t_layout_y (tl::to_string (coord_editors [i][3]->text ()));
tl::Extractor layout_y (t_layout_y.c_str ());
if (pcb_x.at_end () || pcb_y.at_end () || layout_x.at_end () || layout_y.at_end ()) {
if (! pcb_x.at_end () || ! pcb_y.at_end () || ! layout_x.at_end () || ! layout_y.at_end ()) {
throw tl::Exception (tl::to_string (QObject::tr ("All coordinates (imported and existing layout) must be specified for a reference point")));
}
} else {
double x, y;
pcb_x.read (x);
pcb_x.expect_end ();
pcb_y.read (y);
pcb_y.expect_end ();
db::DPoint pcb (x, y);
layout_x.read (x);
layout_x.expect_end ();
layout_y.read (y);
layout_y.expect_end ();
db::DPoint layout (x, y);
mp_data->reference_points.push_back (std::make_pair (pcb, layout));
}
}
std::string t (tl::to_string (mp_ui->explicit_trans_le->text ()));
tl::Extractor ex (t.c_str ());
mp_data->explicit_trans = db::DCplxTrans ();
if (! ex.at_end ()) {
ex.read (mp_data->explicit_trans);
ex.expect_end ();
}
}
}
void
StreamImportDialog::update ()
{
std::string section_headers[] = {
tl::to_string (QObject::tr ("General")),
tl::to_string (QObject::tr ("Layers")),
tl::to_string (QObject::tr ("Coordinate Mapping")),
};
int page = mp_ui->central_stack->currentIndex ();
if (page < 0 || page >= int (sizeof (section_headers) / sizeof (section_headers [0]))) {
return;
}
mp_ui->last_pb->setEnabled (page > 0);
mp_ui->next_pb->setEnabled (page < int (sizeof (section_headers) / sizeof (section_headers [0]) - 1));
mp_ui->section_header_lbl->setText (tl::to_qstring (section_headers [page]));
// --- General page
mp_ui->file_le->setText (tl::to_qstring (mp_data->file));
mp_ui->topcell_le->setText (tl::to_qstring (mp_data->topcell));
mp_ui->import_simple_rb->setChecked (mp_data->mode == StreamImportData::Simple);
mp_ui->import_extra_rb->setChecked (mp_data->mode == StreamImportData::Extra);
mp_ui->import_instantiate_rb->setChecked (mp_data->mode == StreamImportData::Instantiate);
mp_ui->import_merge_rb->setChecked (mp_data->mode == StreamImportData::Merge);
// --- Layers page
mp_ui->no_mapping_rb->setChecked (mp_data->layer_mode == StreamImportData::Original);
mp_ui->offset_rb->setChecked (mp_data->layer_mode == StreamImportData::Offset);
mp_ui->offset_le->setText (tl::to_qstring (mp_data->layer_offset.to_string ()));
mapping_changed ();
// --- Coordinate Mapping page
QLineEdit *(coord_editors[][4]) = {
{ mp_ui->pcb_x1_le, mp_ui->pcb_y1_le, mp_ui->layout_x1_le, mp_ui->layout_y1_le },
{ mp_ui->pcb_x2_le, mp_ui->pcb_y2_le, mp_ui->layout_x2_le, mp_ui->layout_y2_le },
{ mp_ui->pcb_x3_le, mp_ui->pcb_y3_le, mp_ui->layout_x3_le, mp_ui->layout_y3_le }
};
for (unsigned int i = 0; i < sizeof (coord_editors) / sizeof (coord_editors [0]); ++i) {
if (mp_data->reference_points.size () > i) {
coord_editors[i][0]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].first.x ())));
coord_editors[i][1]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].first.y ())));
coord_editors[i][2]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].second.x ())));
coord_editors[i][3]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].second.y ())));
} else {
for (unsigned int j = 0; j < 4; ++j) {
coord_editors[i][j]->setText (QString ());
}
}
}
if (mp_data->explicit_trans == db::DCplxTrans ()) {
mp_ui->explicit_trans_le->setText (QString ());
} else {
mp_ui->explicit_trans_le->setText (tl::to_qstring (mp_data->explicit_trans.to_string ()));
}
}
void
StreamImportDialog::mapping_changed ()
{
mp_ui->offset_le->setEnabled (mp_ui->offset_rb->isChecked ());
}
void
StreamImportDialog::reset ()
{
// Commit everything that is not loaded
try {
commit_page ();
} catch (...) {
// ..
}
*mp_data = StreamImportData ();
mp_ui->central_stack->setCurrentIndex (0);
update ();
}
}
@@ -0,0 +1,123 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layStreamImportDialog
#define HDR_layStreamImportDialog
#include <QDialog>
#include <QAction>
#include <QFrame>
#include <QComboBox>
#include "dbLayout.h"
#include "dbPoint.h"
#include "dbTrans.h"
#include "dbLayerProperties.h"
#include "dbLoadLayoutOptions.h"
#include <string>
#include <vector>
#include <algorithm>
class QTreeWidgetItem;
class QTreeWidget;
class QToolButton;
class QLineEdit;
namespace Ui
{
class StreamImportDialog;
}
namespace tl
{
class InputStream;
}
namespace lay
{
class PluginRoot;
}
namespace lay
{
class StreamImporter;
struct StreamImportData
{
public:
StreamImportData ();
enum mode_type { Simple = 0, Instantiate = 1, Extra = 2, Merge = 3 };
enum layer_mode_type { Original = 0, Offset = 1 };
mode_type mode;
std::string file;
std::string topcell;
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
db::DCplxTrans explicit_trans;
layer_mode_type layer_mode;
db::LayerOffset layer_offset;
db::LoadLayoutOptions options;
void setup_importer (StreamImporter *importer);
void from_string (const std::string &s);
std::string to_string () const;
};
class StreamImportDialog
: public QDialog
{
Q_OBJECT
public:
StreamImportDialog (QWidget *parent, StreamImportData *data);
~StreamImportDialog ();
int exec ();
void accept ();
void reject ();
public slots:
void next_page ();
void last_page ();
void browse_filename ();
void edit_options ();
void reset_options ();
void reset ();
void mapping_changed ();
private:
StreamImportData *mp_data;
Ui::StreamImportDialog *mp_ui;
void update ();
void commit_page ();
void enter_page ();
};
}
#endif
@@ -0,0 +1,281 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layStreamImporter.h"
#include "layLayoutView.h"
#include "tlStream.h"
#include "tlString.h"
#include "tlString.h"
#include "tlLog.h"
#include "dbEdgeProcessor.h"
#include "dbCellMapping.h"
#include "dbLayoutUtils.h"
#include <QDir>
#include <QMessageBox>
#include <QApplication>
#include <math.h>
namespace lay
{
// ---------------------------------------------------------------------------------------
// Implementation of StreamImporter
StreamImporter::StreamImporter ()
: m_cell_mapping (StreamImportData::Simple), m_layer_mapping (StreamImportData::Original)
{
// .. nothing yet ..
}
void
StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index, std::vector <unsigned int> &new_layers)
{
// Clear the undo buffer
if (target.manager () && !target.manager ()->transacting ()) {
target.manager ()->clear ();
}
tl::log << tl::to_string (QObject::tr ("Importing stream data"));
// tl::Progress m_progress (tl::to_string (QObject::tr ("Importing stream data")), m_files.size (), 1);
// TODO: this code should be available otherwise ...
// derive the actual global transformation from the reference points
db::DCplxTrans global_trans (m_global_trans);
if (! m_reference_points.empty ()) {
db::DPoint p1_pcb = m_reference_points[0].first;
db::DPoint p1_ly = m_reference_points[0].second;
if (m_reference_points.size () > 1) {
db::DPoint p2_pcb = m_reference_points[1].first;
db::DPoint p2_ly = m_reference_points[1].second;
db::DVector d12_pcb = (p2_pcb - p1_pcb) * (1.0 / p2_pcb.distance (p1_pcb));
db::DVector d12_ly = (p2_ly - p1_ly) * (1.0 / p2_ly.distance (p1_ly));
int ru = -1;
int rm = -1;
for (int f = 0; f < 8; ++f) {
db::DVector d12 = db::DTrans (f) * d12_pcb;
if ((d12 - d12_ly).length () < 0.1) {
if (f < 4) {
ru = f;
} else {
rm = f;
}
}
}
if (ru < 0 || rm < 0) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to deduce rotation from reference points p1 and p2 (imported and existing layout)")));
}
if (m_reference_points.size () > 2) {
db::DPoint p3_pcb = m_reference_points[2].first;
db::DPoint p3_ly = m_reference_points[2].second;
db::DVector d13_pcb = (p3_pcb - p1_pcb) * (1.0 / p3_pcb.distance (p1_pcb));
db::DVector d13_ly = (p3_ly - p1_ly) * (1.0 / p3_ly.distance (p1_ly));
double vp_pcb = d13_pcb.x () * d12_pcb.y () - d13_pcb.y () * d12_pcb.x ();
double vp_gds = d13_ly.x () * d12_ly.y () - d13_ly.y () * d12_ly.x ();
if (vp_pcb * vp_gds < 0.0) {
global_trans = db::DCplxTrans (db::DFTrans (rm));
} else {
global_trans = db::DCplxTrans (db::DFTrans (ru));
}
} else {
if (global_trans.is_mirror ()) {
global_trans = db::DCplxTrans (db::DFTrans (rm));
} else {
global_trans = db::DCplxTrans (db::DFTrans (ru));
}
}
}
global_trans = db::DCplxTrans (p1_ly - (db::DPoint () + global_trans.disp ())) * global_trans * db::DCplxTrans (db::DPoint () - p1_pcb);
}
// Prepare the layout to read
db::Layout source;
// Load the layout
{
tl::InputStream stream (m_file);
db::Reader reader (stream);
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << m_file;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading")));
reader.read (source, m_options);
}
// Locate the top cell in the source file
db::cell_index_type source_topcell;
std::vector <db::cell_index_type> source_cells;
if (m_cell_mapping != StreamImportData::Extra || !m_topcell.empty ()) {
if (m_topcell.empty ()) {
db::Layout::top_down_const_iterator t = source.begin_top_down ();
if (t == source.end_top_down ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a top cell")));
}
source_topcell = *t;
++t;
if (t != source.end_top_cells ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a unique top cell - specify one explicitly")));
}
} else {
std::pair<bool, db::cell_index_type> t = source.cell_by_name (m_topcell.c_str ());
if (! t.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a cell named '%s'")), m_topcell);
}
source_topcell = t.second;
}
source_cells.push_back (source_topcell);
} else {
// collect source cells
for (db::Layout::top_down_const_iterator t = source.begin_top_down (); t != source.end_top_cells (); ++t) {
source_cells.push_back (*t);
}
}
// Issue a warning, if the transformation is not ortho etc.
if (fabs (global_trans.mag () - floor (global_trans.mag () + 0.5)) > 1e-6 || ! global_trans.is_ortho ()) {
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Complex Transformation"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("The specified transformation (%s) is complex.\nGrid snapping to the database unit grid can occur and\neffectively alter the geometry of the layout.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
}
// Create a layer map
std::map <unsigned int, unsigned int> layer_map;
for (db::Layout::layer_iterator l = source.begin_layers (); l != source.end_layers (); ++l) {
db::LayerProperties lp (*(*l).second);
if (m_layer_mapping == StreamImportData::Offset) {
lp = m_layer_offset.apply (lp);
}
bool layer_found = false;
for (db::Layout::layer_iterator ll = target.begin_layers (); ll != target.end_layers () && ! layer_found; ++ll) {
if ((*ll).second->log_equal (lp)) {
layer_map.insert (std::make_pair ((*l).first, (*ll).first));
layer_found = true;
}
}
if (! layer_found) {
unsigned int new_layer = target.insert_layer (lp);
layer_map.insert (std::make_pair ((*l).first, new_layer));
new_layers.push_back (new_layer);
}
}
// Create a cell map
std::map <db::cell_index_type, db::cell_index_type> cell_map;
if (m_cell_mapping == StreamImportData::Simple) {
cell_map.insert (std::make_pair (source_topcell, target_cell_index));
} else if (m_cell_mapping == StreamImportData::Extra) {
// create new top cells for each source top cell
for (std::vector<db::cell_index_type>::const_iterator t = source_cells.begin (); t != source_cells.end (); ++t) {
db::cell_index_type new_top = target.add_cell (source.cell_name (*t));
cell_map.insert (std::make_pair (*t, new_top));
}
} else if (m_cell_mapping == StreamImportData::Instantiate) {
// Create a new top cell for importing into and use the cell reference to produce the first part of the transformation
db::cell_index_type new_top = target.add_cell (source.cell_name (source_topcell));
cell_map.insert (std::make_pair (source_topcell, new_top));
db::ICplxTrans gt_dbu = db::VCplxTrans (1.0 / target.dbu ()) * global_trans * db::CplxTrans (source.dbu ());
target.cell (target_cell_index).insert (db::CellInstArray (new_top, gt_dbu * db::ICplxTrans (1.0 / global_trans.mag ())));
global_trans = db::DCplxTrans (global_trans.mag ());
} else if (m_cell_mapping == StreamImportData::Merge) {
// Create the cell mapping
// TODO: Currently no merging is provided for non-unity transformations
if (! global_trans.equal (db::DCplxTrans ())) {
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Merge Mode Is Not Available"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Merge mode is not supported for the specified transformation (%s).\nSimple mode will be used instead.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
cell_map.insert (std::make_pair (source_topcell, target_cell_index));
} else {
db::CellMapping cm;
cm.create_from_geometry (target, target_cell_index, source, source_topcell);
cell_map.insert (cm.begin (), cm.end ());
}
}
// And actually merge
db::merge_layouts (target, source, db::VCplxTrans (1.0 / target.dbu ()) * global_trans * db::CplxTrans (source.dbu ()), source_cells, cell_map, layer_map);
}
}
@@ -0,0 +1,208 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layStreamImporter
#define HDR_layStreamImporter
#include "layPluginCommon.h"
#include "dbLayout.h"
#include "dbTrans.h"
#include "dbLoadLayoutOptions.h"
#include "tlStream.h"
#include "tlProgress.h"
#include "layStreamImportDialog.h"
#include <iostream>
namespace db
{
class Manager;
}
namespace lay
{
class LayoutView;
}
namespace lay
{
/**
* @brief The Stream importer object
*/
class LAY_PLUGIN_PUBLIC StreamImporter
{
public:
/**
* @brief Default constructor
*/
StreamImporter ();
/**
* @brief Read into an existing layout
*
* This method reads the layout specified into the given layout and cell.
*/
void read (db::Layout &layout, db::cell_index_type cell_index, std::vector <unsigned int> &new_layers);
/**
* @brief Specifies the global transformation
*
* This specifies the global transformation to apply (in micron units).
*/
void set_global_trans (const db::DCplxTrans &trans)
{
m_global_trans = trans;
}
/**
* @brief Gets the global transformation
*/
const db::DCplxTrans &global_trans () const
{
return m_global_trans;
}
/**
* @brief Set the reference points
*/
void set_reference_points (const std::vector<std::pair <db::DPoint, db::DPoint> > &pts)
{
m_reference_points = pts;
}
/**
* @brief Set file which is read.
*/
void set_file (const std::string &file)
{
m_file = file;
}
/**
* @brief Get the file which is read
*/
const std::string &file () const
{
return m_file;
}
/**
* @brief Set top cell name which is read.
*
* If an empty top cell name is specified, the top cell is determined automatically (it must be a unique top cell in some
* cases).
*/
void set_topcell (const std::string &topcell)
{
m_topcell = topcell;
}
/**
* @brief Get the top cell name.
*/
const std::string &topcell () const
{
return m_topcell;
}
/**
* @brief Set cell mapping mode
*/
void set_cell_mapping (StreamImportData::mode_type cell_mapping)
{
m_cell_mapping = cell_mapping;
}
/**
* @brief Get the cell mapping mode
*/
StreamImportData::mode_type cell_mapping () const
{
return m_cell_mapping;
}
/**
* @brief Set layer mapping mode
*/
void set_layer_mapping (StreamImportData::layer_mode_type layer_mapping)
{
m_layer_mapping = layer_mapping;
}
/**
* @brief Get the layer mapping mode
*/
StreamImportData::layer_mode_type layer_mapping () const
{
return m_layer_mapping;
}
/**
* @brief Set layer offset
*/
void set_layer_offset (const db::LayerOffset &layer_offset)
{
m_layer_offset = layer_offset;
}
/**
* @brief Get the layer offset
*/
db::LayerOffset layer_offset () const
{
return m_layer_offset;
}
/**
* @brief Set reader options
*/
void set_reader_options (const db::LoadLayoutOptions &options)
{
m_options = options;
}
/**
* @brief Get the reader options
*/
const db::LoadLayoutOptions &reader_options () const
{
return m_options;
}
private:
std::string m_file;
std::string m_topcell;
db::DCplxTrans m_global_trans;
std::vector <std::pair <db::DPoint, db::DPoint> > m_reference_points;
StreamImportData::mode_type m_cell_mapping;
StreamImportData::layer_mode_type m_layer_mapping;
db::LayerOffset m_layer_offset;
db::LoadLayoutOptions m_options;
};
}
#endif
@@ -0,0 +1,17 @@
TARGET = import
DESTDIR = $$OUT_PWD/../../../../lay_plugins
include($$PWD/../../../lay_plugin.pri)
HEADERS = \
layStreamImporter.h \
layStreamImportDialog.h
SOURCES = \
layStreamImporter.cc \
layStreamImportDialog.cc \
layStreamImport.cc
FORMS = \
StreamImportDialog.ui \
@@ -25,7 +25,7 @@
#ifndef HDR_dbNetTracer
#define HDR_dbNetTracer
#include "dbCommon.h"
#include "dbPluginCommon.h"
#include "dbShapes.h"
#include "dbShape.h"
@@ -52,7 +52,7 @@ class NetTracerData;
* the data and second, this guarantees that the Shape references delivered point to the same object
* for identical shapes.
*/
class DB_PUBLIC NetTracerShapeHeap
class DB_PLUGIN_PUBLIC NetTracerShapeHeap
{
public:
/**
@@ -81,7 +81,7 @@ private:
* This class describes a shape in the hierarchy by the transformation into the top cell, the shape reference, the cell
* index and the layer the shape resides on.
*/
class DB_PUBLIC NetTracerShape
class DB_PLUGIN_PUBLIC NetTracerShape
{
public:
/**
@@ -252,7 +252,7 @@ typedef db::box_tree<db::Box, const NetTracerShape *, HitTestDataBoxConverter, 1
/**
* @brief Describes a boolean expression for computed layers
*/
class DB_PUBLIC NetTracerLayerExpression
class DB_PLUGIN_PUBLIC NetTracerLayerExpression
{
public:
/**
@@ -397,7 +397,7 @@ private:
* This class has three members: the index of the first conductive layer, the
* index of the via layer and the index of the second conductive layer.
*/
class DB_PUBLIC NetTracerConnection
class DB_PLUGIN_PUBLIC NetTracerConnection
{
public:
/**
@@ -474,7 +474,7 @@ private:
/**
* @brief Wraps the data for a net tracing
*/
class DB_PUBLIC NetTracerData
class DB_PLUGIN_PUBLIC NetTracerData
{
public:
/**
@@ -582,7 +582,7 @@ private:
* Net tracing can be performed with a given seed point and given tracing data.
* The tracing is initiated with the "trace" method.
*/
class DB_PUBLIC NetTracer
class DB_PLUGIN_PUBLIC NetTracer
{
public:
typedef std::set <NetTracerShape>::const_iterator iterator;
@@ -23,6 +23,7 @@
#ifndef HDR_dbNetTracerIO
#define HDR_dbNetTracerIO
#include "dbPluginCommon.h"
#include "dbNetTracer.h"
#include "dbLayerProperties.h"
#include "dbTechnology.h"
@@ -34,7 +35,7 @@ namespace db
class NetTracerTechnologyComponent;
class DB_PUBLIC NetTracerLayerExpressionInfo
class DB_PLUGIN_PUBLIC NetTracerLayerExpressionInfo
{
public:
NetTracerLayerExpressionInfo ();
@@ -72,7 +73,7 @@ private:
NetTracerLayerExpression *get_expr (const db::LayerProperties &lp, const db::Layout &layout, const NetTracerTechnologyComponent &tech, const std::set<std::string> &used_symbols) const;
};
class DB_PUBLIC NetTracerConnectionInfo
class DB_PLUGIN_PUBLIC NetTracerConnectionInfo
{
public:
NetTracerConnectionInfo ();
@@ -118,7 +119,7 @@ private:
NetTracerLayerExpressionInfo m_la, m_via, m_lb;
};
class DB_PUBLIC NetTracerSymbolInfo
class DB_PLUGIN_PUBLIC NetTracerSymbolInfo
{
public:
NetTracerSymbolInfo ();
@@ -152,7 +153,7 @@ private:
std::string m_expression;
};
class DB_PUBLIC Net
class DB_PLUGIN_PUBLIC Net
{
public:
typedef std::vector <db::NetTracerShape>::const_iterator iterator;
@@ -355,7 +356,7 @@ private:
void define_layer (unsigned int l, const db::LayerProperties &lp, const db::LayerProperties &lp_representative);
};
class DB_PUBLIC NetTracerTechnologyComponent
class DB_PLUGIN_PUBLIC NetTracerTechnologyComponent
: public db::TechnologyComponent
{
public:
@@ -8,8 +8,8 @@ include($$PWD/../../../../lib_ut.pri)
SOURCES = \
dbNetTracer.cc \
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../db_plugin $$PWD/../../../common
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
@@ -0,0 +1,605 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>XORToolDialog</class>
<widget class="QDialog" name="XORToolDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>576</width>
<height>649</height>
</rect>
</property>
<property name="windowTitle">
<string>XOR Tool</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Input</string>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="5" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>From region</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Layout A</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Use for input </string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Layout B</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="input_layers_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>All Layers (different layouts)</string>
</property>
</item>
<item>
<property name="text">
<string>Visible layers (different layouts)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="region_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>All</string>
</property>
</item>
<item>
<property name="text">
<string>Visible region</string>
</property>
</item>
<item>
<property name="text">
<string>Clipped to ruler</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="lay::CellViewSelectionComboBox" name="layoutb">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="lay::CellViewSelectionComboBox" name="layouta">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Options</string>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="anotb_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>A NOT B (In A but not in B)</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QCheckBox" name="axorb_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>A XOR B (differences)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="summarize_cb">
<property name="text">
<string>Summarize missing layers</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Tolerances</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Compare modes </string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Tolerances (t1,t2,..) in micron</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Threads</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Tiling</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="tiling">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Tile size in micron</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="heal_cb">
<property name="text">
<string>Heal result shapes</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="7" column="1" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="threads">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Used for tiles and layers</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QCheckBox" name="bnota_cb">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>B NOT A (in B but not in A)</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="tolerances">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Output</string>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Send output to </string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="output_cbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Marker database</string>
</property>
</item>
<item>
<property name="text">
<string>Other layout</string>
</property>
</item>
<item>
<property name="text">
<string>New layers in layout A ...</string>
</property>
</item>
<item>
<property name="text">
<string>New layers in layout B ...</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="layer_offset_lbl">
<property name="text">
<string>with offset</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="layer_offset_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>1000/0</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>lay::CellViewSelectionComboBox</class>
<extends>QComboBox</extends>
<header>layWidgets.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>layouta</tabstop>
<tabstop>layoutb</tabstop>
<tabstop>input_layers_cbx</tabstop>
<tabstop>region_cbx</tabstop>
<tabstop>axorb_cb</tabstop>
<tabstop>anotb_cb</tabstop>
<tabstop>bnota_cb</tabstop>
<tabstop>summarize_cb</tabstop>
<tabstop>tolerances</tabstop>
<tabstop>tiling</tabstop>
<tabstop>threads</tabstop>
<tabstop>output_cbx</tabstop>
<tabstop>layer_offset_le</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>XORToolDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>XORToolDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,121 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layXORToolDialog.h"
#include "layPlugin.h"
namespace lay
{
class XORPlugin
: public lay::Plugin
{
public:
XORPlugin (Plugin *parent, lay::LayoutView *view)
: lay::Plugin (parent), mp_view (view)
{
mp_dialog = new lay::XORToolDialog (0);
}
~XORPlugin ()
{
delete mp_dialog;
mp_dialog = 0;
}
void menu_activated (const std::string &symbol)
{
if (symbol == "lay::xor_tool") {
if (mp_dialog->exec_dialog (mp_view)) {
// ... implementation is in layXORToolDialog.cc ...
}
}
}
private:
lay::LayoutView *mp_view;
lay::XORToolDialog *mp_dialog;
};
class XORPluginDeclaration
: public lay::PluginDeclaration
{
public:
XORPluginDeclaration ()
{
// .. nothing yet ..
}
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
{
options.push_back (std::pair<std::string, std::string> (cfg_xor_input_mode, "all"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_output_mode, "rdb"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_nworkers, "1"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_layer_offset, ""));
options.push_back (std::pair<std::string, std::string> (cfg_xor_axorb, "true"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_anotb, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_bnota, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_summarize, "false"));
options.push_back (std::pair<std::string, std::string> (cfg_xor_tolerances, ""));
options.push_back (std::pair<std::string, std::string> (cfg_xor_tiling, ""));
options.push_back (std::pair<std::string, std::string> (cfg_xor_region_mode, "all"));
}
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
{
// .. nothing yet ..
return 0;
}
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{
lay::PluginDeclaration::get_menu_entries (menu_entries);
menu_entries.push_back (lay::MenuEntry ("lay::xor_tool", "xor_tool:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("XOR Tool"))));
}
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
virtual void config_finalize ()
{
// .. nothing yet ..
}
lay::Plugin *create_plugin (db::Manager *, lay::PluginRoot *root, lay::LayoutView *view) const
{
return new XORPlugin (root, view);
}
};
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::XORPluginDeclaration (), 3000, "lay::XORPlugin");
}
@@ -0,0 +1,414 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "layXORProgress.h"
#include "tlString.h"
#include <QWidget>
#include <QImage>
#include <QPainter>
#include <QBitmap>
namespace lay
{
static inline void merge (size_t &a, size_t b)
{
if (a == missing_in_a || a == missing_in_b) {
// leave a
} else if (b == missing_in_a || b == missing_in_b) {
a = b;
} else {
a += b;
}
}
static void merge (std::vector<std::vector<size_t> > &a, const std::vector<std::vector<size_t> > &b)
{
if (a.size () < b.size ()) {
a.resize (b.size (), std::vector<size_t> ());
}
std::vector<std::vector<size_t> >::iterator ia = a.begin ();
for (std::vector<std::vector<size_t> >::const_iterator ib = b.begin (); ib != b.end (); ++ib, ++ia) {
if (ia->size () < ib->size ()) {
ia->resize (ib->size (), 0);
}
std::vector<size_t>::iterator ja = ia->begin ();
for (std::vector<size_t>::const_iterator jb = ib->begin (); jb != ib->end (); ++jb, ++ja) {
merge (*ja, *jb);
}
}
}
static size_t sum (const std::vector<std::vector<size_t> > &b)
{
size_t n = 0;
for (std::vector<std::vector<size_t> >::const_iterator i = b.begin (); i != b.end (); ++i) {
for (std::vector<size_t>::const_iterator j = i->begin (); j != i->end (); ++j) {
merge (n, *j);
}
if (n == missing_in_a || n == missing_in_b) {
break;
}
}
return n;
}
// --------------------------------------------------------------------------------------------------
// The progress widget class
struct CounterCompare
{
typedef std::pair<db::LayerProperties, size_t> value_type;
bool operator() (const value_type &a, const value_type &b) const
{
bool a_special = (a.second == missing_in_a || a.second == missing_in_b);
bool b_special = (b.second == missing_in_a || b.second == missing_in_b);
if (a_special != b_special) {
return a_special < b_special;
}
if (a.second != b.second) {
return a.second > b.second;
}
return a.first < b.first;
}
};
class XORProgressWidget
: public QWidget
{
public:
XORProgressWidget ()
: QWidget (0)
{
m_pixmap_size = 24;
m_spacing = 4;
QFontMetrics fm (font ());
m_line_height = std::max (fm.height (), m_pixmap_size + 4);
m_font_height = fm.height () * 3 / 2;
m_first_column_width = fm.width (QString::fromUtf8 ("LAYERNAME"));
m_column_width = m_pixmap_size + 4 + m_spacing + fm.width (QString::fromUtf8 ("1.00G "));
}
QSize sizeHint () const
{
int w = int (m_tolerance_labels.size ()) * (m_column_width + m_spacing) + m_first_column_width;
int col = std::max (1, width () / w);
return QSize (w * std::min (int (m_layer_labels.size ()), col), (m_line_height + m_spacing) * ((int (m_layer_labels.size ()) + col - 1) / col) + m_font_height * 2 + m_spacing);
}
void set_results (double dbu, int nx, int ny, const std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > > &results, const std::map<db::LayerProperties, size_t> &count_per_layer, const std::vector<db::Coord> &tolerances)
{
m_labels.clear ();
m_layer_labels.clear ();
m_red_images.clear ();
m_green_images.clear ();
m_blue_images.clear ();
m_yellow_images.clear ();
m_labels.clear ();
QSize szh = sizeHint ();
m_tolerance_labels.clear ();
for (std::vector<db::Coord>::const_iterator t = tolerances.begin (); t != tolerances.end (); ++t) {
m_tolerance_labels << tl::to_qstring (tl::sprintf ("%.12g µm", *t * dbu));
}
std::vector<std::pair<db::LayerProperties, size_t> > counters;
counters.insert (counters.end (), count_per_layer.begin (), count_per_layer.end ());
std::sort (counters.begin (), counters.end (), CounterCompare ());
for (std::vector<std::pair<db::LayerProperties, size_t> >::const_iterator c = counters.begin (); c != counters.end (); ++c) {
m_layer_labels << tl::to_qstring (c->first.to_string ());
m_labels.push_back (QStringList ());
m_red_images.push_back (std::vector<QImage> ());
m_green_images.push_back (std::vector<QImage> ());
m_blue_images.push_back (std::vector<QImage> ());
m_yellow_images.push_back (std::vector<QImage> ());
for (std::vector<db::Coord>::const_iterator t = tolerances.begin (); t != tolerances.end (); ++t) {
m_labels.back ().push_back (QString ());
m_red_images.back ().push_back (QImage (m_pixmap_size, m_pixmap_size, QImage::Format_MonoLSB));
m_green_images.back ().push_back (QImage (m_pixmap_size, m_pixmap_size, QImage::Format_MonoLSB));
m_blue_images.back ().push_back (QImage (m_pixmap_size, m_pixmap_size, QImage::Format_MonoLSB));
m_yellow_images.back ().push_back (QImage (m_pixmap_size, m_pixmap_size, QImage::Format_MonoLSB));
m_red_images.back ().back ().fill (Qt::black);
m_green_images.back ().back ().fill (Qt::black);
m_blue_images.back ().back ().fill (Qt::black);
m_yellow_images.back ().back ().fill (Qt::black);
size_t tot_count = 0;
std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > >::const_iterator rm = results.find (std::make_pair (c->first, *t));
if (rm != results.end ()) {
const std::vector<std::vector<size_t> > &counts = rm->second;
tot_count = sum (counts);
int ix = 0;
for (std::vector<std::vector<size_t> >::const_iterator c = counts.begin (); c != counts.end (); ++c, ++ix) {
int iy = 0;
for (std::vector<size_t>::const_iterator cc = c->begin (); cc != c->end (); ++cc, ++iy) {
QImage *img = 0;
if (*cc == 0) {
img = &m_green_images.back ().back ();
} else if (*cc == missing_in_a) {
m_blue_images.back ().back ().fill (Qt::white);
} else if (*cc == missing_in_b) {
m_yellow_images.back ().back ().fill (Qt::white);
} else {
img = &m_red_images.back ().back ();
}
if (img) {
if (nx == 0 || ny == 0) {
img->fill (Qt::white);
} else {
int y2 = m_pixmap_size - 1 - (iy * m_pixmap_size + m_pixmap_size / 2) / ny;
int y1 = m_pixmap_size - 1 - ((iy + 1) * m_pixmap_size + m_pixmap_size / 2) / ny;
int x1 = (ix * m_pixmap_size + m_pixmap_size / 2) / nx;
int x2 = ((ix + 1) * m_pixmap_size + m_pixmap_size / 2) / nx;
// "draw" the field
for (int y = y1; y <= y2 && y >= 0 && y < m_pixmap_size; ++y) {
*((uint32_t *) img->scanLine (y)) &= (((1 << x1) - 1) | ~((1 << (x2 + 1)) - 1));
}
}
}
}
}
}
QString text;
if (tot_count == missing_in_a) {
text = QString::fromUtf8 ("B");
} else if (tot_count == missing_in_b) {
text = QString::fromUtf8 ("A");
} else if (tot_count > 1000000000) {
text = QString::fromUtf8 ("%1G").arg (tot_count * 1e-9, 0, 'f', 2);
} else if (tot_count > 100000000) {
text = QString::fromUtf8 ("%1M").arg (tot_count * 1e-6, 0, 'f', 0);
} else if (tot_count > 10000000) {
text = QString::fromUtf8 ("%1M").arg (tot_count * 1e-6, 0, 'f', 1);
} else if (tot_count > 1000000) {
text = QString::fromUtf8 ("%1M").arg (tot_count * 1e-6, 0, 'f', 2);
} else if (tot_count > 100000) {
text = QString::fromUtf8 ("%1k").arg (tot_count * 1e-3, 0, 'f', 0);
} else if (tot_count > 10000) {
text = QString::fromUtf8 ("%1k").arg (tot_count * 1e-3, 0, 'f', 1);
} else if (tot_count > 1000) {
text = QString::fromUtf8 ("%1k").arg (tot_count * 1e-3, 0, 'f', 2);
} else {
text = QString::fromUtf8 ("%1").arg (tot_count);
}
m_labels.back ().back () = text;
}
}
if (szh != sizeHint ()) {
updateGeometry ();
}
update ();
}
void paintEvent (QPaintEvent * /*ev*/)
{
QPainter painter (this);
QSize szh = QSize (int (m_tolerance_labels.size ()) * (m_column_width + m_spacing) + m_first_column_width, (m_line_height + m_spacing) * int (m_layer_labels.size ()) + m_font_height * 2 + m_spacing + 10);
bool ellipsis = false;
int visible_lines = std::max (1, (height () - m_font_height * 2 - m_spacing) / (m_line_height + m_spacing));
int columns = std::min (std::max (1, width () / std::max (1, szh.width ())), int (m_layer_labels.size ()));
int x0 = std::max (0, (width () - szh.width () * columns) / 2);
int visible_columns = std::max (0, (width () - m_first_column_width + 20) / (m_column_width + m_spacing));
for (int c = 0; c < columns; ++c) {
painter.drawText (QRect (QPoint (x0 + c * szh.width (), 0), QSize (m_first_column_width, m_font_height)),
tr ("Lay/Tol."),
QTextOption (Qt::AlignRight | Qt::AlignTop));
for (int t = 0; t < m_tolerance_labels.size () && t < visible_columns; ++t) {
painter.drawText (QRect (QPoint (x0 + c * szh.width () + m_first_column_width + m_spacing + t * (m_column_width + m_spacing), 0), QSize (m_column_width, m_font_height)),
m_tolerance_labels [t],
QTextOption (Qt::AlignLeft | Qt::AlignTop));
}
}
int c = 0;
int r = 0;
for (int l = 0; l < m_layer_labels.size (); ++l, ++c) {
if (c == columns) {
c = 0;
++r;
if (r == visible_lines) {
ellipsis = true;
break;
}
}
painter.drawText (QRect (QPoint (x0 + c * szh.width (), m_font_height + m_spacing + r * (m_line_height + m_spacing)), QSize (m_first_column_width, m_line_height)),
m_layer_labels [l],
QTextOption (Qt::AlignRight | Qt::AlignVCenter));
for (int t = 0; t < m_tolerance_labels.size () && t < visible_columns; ++t) {
int x = x0 + c * szh.width () + m_first_column_width + m_spacing + t * (m_column_width + m_spacing);
int y = m_font_height + m_spacing + r * (m_line_height + m_spacing);
painter.drawText (QRect (QPoint (x + m_pixmap_size + 4 + m_spacing, y), QSize (m_column_width, m_line_height)),
m_labels [l][t],
QTextOption (Qt::AlignLeft | Qt::AlignVCenter));
painter.save ();
QLinearGradient grad (QPointF (0, 0), QPointF (1.0, 1.0));
grad.setCoordinateMode (QGradient::ObjectBoundingMode);
grad.setColorAt (0.0, QColor (248, 248, 248));
grad.setColorAt (1.0, QColor (224, 224, 224));
painter.setBrush (QBrush (grad));
painter.setPen (QPen (Qt::black));
painter.drawRect (QRect (QPoint (x, y - 2), QSize (m_pixmap_size + 3, m_pixmap_size + 3)));
painter.setBackgroundMode (Qt::TransparentMode);
painter.setPen (QColor (128, 255, 128));
painter.drawPixmap (x + 2, y, QBitmap::fromImage (m_green_images [l][t]));
painter.setPen (QColor (255, 128, 128));
painter.drawPixmap (x + 2, y, QBitmap::fromImage (m_red_images [l][t]));
painter.setPen (QColor (128, 128, 255));
painter.drawPixmap (x + 2, y, QBitmap::fromImage (m_blue_images [l][t]));
painter.setPen (QColor (255, 255, 128));
painter.drawPixmap (x + 2, y, QBitmap::fromImage (m_yellow_images [l][t]));
painter.restore ();
}
if (l == 0 && int (m_tolerance_labels.size ()) > visible_columns) {
int x = x0 + m_first_column_width + m_spacing + visible_columns * (m_column_width + m_spacing);
int y = m_font_height + m_spacing;
painter.drawText (QRect (QPoint (x - m_column_width, y), QSize (m_column_width, m_line_height)),
QString::fromUtf8 ("..."),
QTextOption (Qt::AlignRight | Qt::AlignVCenter));
}
}
if (ellipsis) {
painter.drawText (QRect (QPoint (x0 + c * szh.width (), m_font_height + m_spacing + r * (m_line_height + m_spacing)), QSize (m_first_column_width, m_font_height)),
QString::fromUtf8 ("..."),
QTextOption (Qt::AlignRight | Qt::AlignTop));
}
}
private:
int m_pixmap_size;
int m_line_height;
int m_font_height;
int m_spacing;
int m_column_width;
int m_first_column_width;
QStringList m_tolerance_labels;
QStringList m_layer_labels;
std::vector<QStringList> m_labels;
std::vector<std::vector<QImage> > m_green_images;
std::vector<std::vector<QImage> > m_red_images;
std::vector<std::vector<QImage> > m_yellow_images;
std::vector<std::vector<QImage> > m_blue_images;
};
// --------------------------------------------------------------------------------------------------
// XORProgress implementation
XORProgress::XORProgress (const std::string &title, size_t max_count, size_t yield_interval)
: tl::RelativeProgress (title, max_count, yield_interval), m_needs_update (true), m_dbu (1.0), m_nx (0), m_ny (0)
{
// .. nothing yet ..
}
QWidget *XORProgress::progress_widget () const
{
return new XORProgressWidget ();
}
void XORProgress::render_progress (QWidget *widget) const
{
XORProgressWidget *pw = dynamic_cast<XORProgressWidget *> (widget);
if (pw) {
pw->set_results (m_dbu, m_nx, m_ny, m_results, m_count_per_layer, m_tolerances);
}
}
void XORProgress::configure (double dbu, int nx, int ny, const std::vector<db::Coord> &tol)
{
if (m_tolerances != tol || fabs (m_dbu - dbu) > 1e-6 || m_nx != nx || m_ny != ny) {
m_dbu = dbu;
m_nx = nx;
m_ny = ny;
m_tolerances = tol;
m_needs_update = true;
}
}
void XORProgress::merge_results (std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > > &results)
{
for (std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > >::const_iterator r = results.begin (); r != results.end (); ++r) {
m_needs_update = true;
merge (m_results [r->first], r->second);
merge (m_count_per_layer [r->first.first], sum (r->second));
}
results.clear ();
}
}
@@ -0,0 +1,72 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layXORToolProgress
#define HDR_layXORToolProgress
#include "tlProgress.h"
#include "dbTypes.h"
#include "dbLayerProperties.h"
#include <map>
#include <vector>
#include <limits>
class QWidget;
namespace lay
{
const size_t missing_in_a = std::numeric_limits<size_t>::max ();
const size_t missing_in_b = std::numeric_limits<size_t>::max () - 1;
/**
* @brief A specialized progress reporter for the XOR feature
*
* The purpose of this class is to provide the special XOR progress widget that
* shows the XOR progress with numbers and a map (in tiled mode).
*/
class XORProgress
: public tl::RelativeProgress
{
public:
XORProgress (const std::string &title, size_t max_count, size_t yield_interval);
virtual QWidget *progress_widget () const;
virtual void render_progress (QWidget *widget) const;
void configure (double dbu, int nx, int ny, const std::vector<db::Coord> &tol);
void merge_results (std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > > &results);
private:
std::map<std::pair<db::LayerProperties, db::Coord>, std::vector<std::vector<size_t> > > m_results;
std::map<db::LayerProperties, size_t> m_count_per_layer;
std::vector<db::Coord> m_tolerances;
bool m_needs_update;
double m_dbu;
int m_nx, m_ny;
};
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,82 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_layXORToolDialog
#define HDR_layXORToolDialog
#include <QDialog>
#include "tlObject.h"
namespace Ui
{
class XORToolDialog;
}
namespace lay
{
class LayoutView;
}
namespace lay
{
extern std::string cfg_xor_input_mode;
extern std::string cfg_xor_output_mode;
extern std::string cfg_xor_nworkers;
extern std::string cfg_xor_layer_offset;
extern std::string cfg_xor_axorb;
extern std::string cfg_xor_anotb;
extern std::string cfg_xor_bnota;
extern std::string cfg_xor_summarize;
extern std::string cfg_xor_tolerances;
extern std::string cfg_xor_tiling;
extern std::string cfg_xor_region_mode;
class XORToolDialog
: public QDialog
{
Q_OBJECT
public:
XORToolDialog (QWidget *parent);
~XORToolDialog ();
int exec_dialog (lay::LayoutView *view);
protected:
void accept ();
void run_xor ();
protected slots:
void input_changed (int index);
void output_changed (int index);
private:
Ui::XORToolDialog *mp_ui;
tl::weak_ptr<lay::LayoutView> mp_view;
};
}
#endif
@@ -0,0 +1,21 @@
TARGET = xor
DESTDIR = $$OUT_PWD/../../../../lay_plugins
include($$PWD/../../../lay_plugin.pri)
INCLUDEPATH += $$RDB_INC $$ANT_INC
DEPENDPATH += $$RDB_INC $$ANT_INC
LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant
HEADERS = \
layXORToolDialog.h \
layXORProgress.h
SOURCES = \
layXORToolDialog.cc \
layXORProgress.cc \
layXORPlugin.cc
FORMS = \
XORToolDialog.ui \
+5
View File
@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = lay_plugin