mirror of
https://github.com/KLayout/klayout.git
synced 2026-09-03 08:26:27 +02:00
Merge branch 'master' into complex_drc_ops
This commit is contained in:
@@ -61,7 +61,7 @@ GDS2ReaderText::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
db::GDS2ReaderOptions gds2_options = options.get_options<db::GDS2ReaderOptions> ();
|
||||
db::CommonReaderOptions common_options = options.get_options<db::CommonReaderOptions> ();
|
||||
|
||||
return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode);
|
||||
return basic_read (layout, common_options.layer_map, common_options.create_other_layers, common_options.enable_text_objects, common_options.enable_properties, false, gds2_options.box_mode, common_options.cell_conflict_resolution);
|
||||
}
|
||||
|
||||
const LayerMap &
|
||||
@@ -259,7 +259,7 @@ GDS2ReaderText::get_double ()
|
||||
}
|
||||
|
||||
void
|
||||
GDS2ReaderText::get_string (tl::string &s) const
|
||||
GDS2ReaderText::get_string (std::string &s) const
|
||||
{
|
||||
// TODO: get rid of this const_cast hack
|
||||
s = (const_cast<GDS2ReaderText *> (this))->reader.skip ();
|
||||
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
|
||||
virtual std::string path () const;
|
||||
const char *get_string ();
|
||||
void get_string (tl::string &s) const;
|
||||
void get_string (std::string &s) const;
|
||||
int get_int ();
|
||||
short get_short ();
|
||||
unsigned short get_ushort ();
|
||||
|
||||
@@ -64,7 +64,7 @@ GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
--m_recnum;
|
||||
m_reclen = 0;
|
||||
|
||||
return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode);
|
||||
return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode, m_common_options.cell_conflict_resolution);
|
||||
}
|
||||
|
||||
const LayerMap &
|
||||
@@ -210,7 +210,7 @@ GDS2Reader::get_string ()
|
||||
}
|
||||
|
||||
void
|
||||
GDS2Reader::get_string (tl::string &s) const
|
||||
GDS2Reader::get_string (std::string &s) const
|
||||
{
|
||||
s.assign ((const char *) mp_rec_buf, 0, m_reclen);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
|
||||
virtual std::string path () const;
|
||||
virtual const char *get_string ();
|
||||
virtual void get_string (tl::string &s) const;
|
||||
virtual void get_string (std::string &s) const;
|
||||
virtual int get_int ();
|
||||
virtual short get_short ();
|
||||
virtual unsigned short get_ushort ();
|
||||
|
||||
@@ -84,7 +84,7 @@ GDS2ReaderBase::~GDS2ReaderBase ()
|
||||
}
|
||||
|
||||
const LayerMap &
|
||||
GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode)
|
||||
GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution)
|
||||
{
|
||||
m_layer_map = layer_map;
|
||||
m_layer_map.prepare (layout);
|
||||
@@ -95,9 +95,17 @@ GDS2ReaderBase::basic_read (db::Layout &layout, const LayerMap &layer_map, bool
|
||||
m_box_mode = box_mode;
|
||||
m_create_layers = create_other_layers;
|
||||
|
||||
set_cell_conflict_resolution (cc_resolution);
|
||||
|
||||
layout.start_changes ();
|
||||
do_read (layout);
|
||||
layout.end_changes ();
|
||||
try {
|
||||
do_read (layout);
|
||||
finish (layout);
|
||||
layout.end_changes ();
|
||||
} catch (...) {
|
||||
layout.end_changes ();
|
||||
throw;
|
||||
}
|
||||
|
||||
return m_layer_map;
|
||||
}
|
||||
@@ -235,7 +243,6 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
||||
{
|
||||
m_cellname = "";
|
||||
m_libname = "";
|
||||
m_mapped_cellnames.clear ();
|
||||
|
||||
// read header
|
||||
if (get_record () != sHEADER) {
|
||||
@@ -349,7 +356,7 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
||||
|
||||
} else {
|
||||
|
||||
db::cell_index_type cell_index = make_cell (layout, m_cellname.c_str (), false);
|
||||
db::cell_index_type cell_index = make_cell (layout, m_cellname);
|
||||
|
||||
db::Cell *cell = &layout.cell (cell_index);
|
||||
|
||||
@@ -359,8 +366,6 @@ GDS2ReaderBase::do_read (db::Layout &layout)
|
||||
if (layout.recover_proxy_as (cell_index, ctx->second.begin (), ctx->second.end (), &layer_mapping)) {
|
||||
// ignore everything in that cell since it is created by the import:
|
||||
cell = 0;
|
||||
// marks the cell for begin addressed by REF's despite being a proxy:
|
||||
m_mapped_cellnames.insert (std::make_pair (m_cellname, m_cellname));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -973,54 +978,6 @@ GDS2ReaderBase::read_box (db::Layout &layout, db::Cell &cell)
|
||||
}
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
GDS2ReaderBase::make_cell (db::Layout &layout, const char *cn, bool for_instance)
|
||||
{
|
||||
db::cell_index_type ci = 0;
|
||||
|
||||
// map to the real name which maybe a different one due to localization
|
||||
// of proxy cells (they are not to be reopened)
|
||||
bool is_mapped = false;
|
||||
if (! m_mapped_cellnames.empty ()) {
|
||||
std::map<tl::string, tl::string>::const_iterator n = m_mapped_cellnames.find (cn);
|
||||
if (n != m_mapped_cellnames.end ()) {
|
||||
cn = n->second.c_str ();
|
||||
is_mapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn);
|
||||
if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) {
|
||||
|
||||
// cell already there: just add instance (cell might have been created through forward reference)
|
||||
// NOTE: we don't address "reopened" proxies as proxies are always local to a layout
|
||||
|
||||
ci = c.second;
|
||||
|
||||
// mark the cell as read
|
||||
if (! for_instance) {
|
||||
layout.cell (ci).set_ghost_cell (false);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ci = layout.add_cell (cn);
|
||||
|
||||
if (for_instance) {
|
||||
// mark this cell a "ghost cell" until it's actually read
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
}
|
||||
|
||||
if (c.first) {
|
||||
// this cell has been given a new name: remember this name for localization
|
||||
m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
void
|
||||
GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, tl::vector<db::CellInstArray> &instances, tl::vector<db::CellInstArrayWithProperties> &instances_with_props)
|
||||
{
|
||||
@@ -1033,7 +990,7 @@ GDS2ReaderBase::read_ref (db::Layout &layout, db::Cell & /*cell*/, bool array, t
|
||||
error (tl::to_string (tr ("SNAME record expected")));
|
||||
}
|
||||
|
||||
db::cell_index_type ci = make_cell (layout, get_string (), true);
|
||||
db::cell_index_type ci = cell_for_instance (layout, get_string ());
|
||||
|
||||
bool mirror = false;
|
||||
int angle = 0;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "dbLayout.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbStreamLayers.h"
|
||||
#include "dbCommonReader.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlInternational.h"
|
||||
@@ -49,7 +50,7 @@ struct GDS2XY
|
||||
* @brief The GDS2 format basic stream reader
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC GDS2ReaderBase
|
||||
: public ReaderBase
|
||||
: public CommonReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -86,20 +87,21 @@ protected:
|
||||
* @param enable_properties A flag indicating whether to read user properties
|
||||
* @param allow_multi_xy_records If true, tries to check for multiple XY records for BOUNDARY elements
|
||||
* @param box_mode How to treat BOX records (0: ignore, 1: as rectangles, 2: as boundaries, 3: error)
|
||||
* @param cc_resolution The cell name conflict resolution mode
|
||||
* @return The LayerMap object that tells where which layer was loaded
|
||||
*/
|
||||
const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode);
|
||||
const LayerMap &basic_read (db::Layout &layout, const LayerMap &layer_map, bool create_other_layers, bool enable_text_objects, bool enable_properties, bool allow_multi_xy_records, unsigned int box_mode, db::CommonReader::CellConflictResolution cc_resolution);
|
||||
|
||||
/**
|
||||
* @brief Accessor method to the current cellname
|
||||
*/
|
||||
const tl::string &cellname () const { return m_cellname; }
|
||||
const std::string &cellname () const { return m_cellname; }
|
||||
|
||||
private:
|
||||
friend class GDS2ReaderLayerMapping;
|
||||
|
||||
LayerMap m_layer_map;
|
||||
tl::string m_cellname;
|
||||
std::string m_cellname;
|
||||
std::string m_libname;
|
||||
double m_dbu, m_dbuu;
|
||||
bool m_create_layers;
|
||||
@@ -109,7 +111,6 @@ private:
|
||||
unsigned int m_box_mode;
|
||||
std::map <tl::string, std::vector<std::string> > m_context_info;
|
||||
std::vector <db::Point> m_all_points;
|
||||
std::map <tl::string, tl::string> m_mapped_cellnames;
|
||||
|
||||
void read_context_info_cell ();
|
||||
void read_boundary (db::Layout &layout, db::Cell &cell, bool from_box_record);
|
||||
@@ -117,7 +118,6 @@ private:
|
||||
void read_text (db::Layout &layout, db::Cell &cell);
|
||||
void read_box (db::Layout &layout, db::Cell &cell);
|
||||
void read_ref (db::Layout &layout, db::Cell &cell, bool array, tl::vector<db::CellInstArray> &instances, tl::vector<db::CellInstArrayWithProperties> &insts_wp);
|
||||
db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance);
|
||||
|
||||
void do_read (db::Layout &layout);
|
||||
|
||||
@@ -125,12 +125,15 @@ private:
|
||||
std::pair <bool, db::properties_id_type> finish_element (db::PropertiesRepository &rep);
|
||||
void finish_element ();
|
||||
|
||||
virtual void common_reader_error (const std::string &msg) { error (msg); }
|
||||
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
|
||||
|
||||
virtual void error (const std::string &txt) = 0;
|
||||
virtual void warn (const std::string &txt) = 0;
|
||||
|
||||
virtual std::string path () const = 0;
|
||||
virtual const char *get_string () = 0;
|
||||
virtual void get_string (tl::string &s) const = 0;
|
||||
virtual void get_string (std::string &s) const = 0;
|
||||
virtual int get_int () = 0;
|
||||
virtual short get_short () = 0;
|
||||
virtual unsigned short get_ushort () = 0;
|
||||
|
||||
@@ -366,6 +366,8 @@ TEST(Bug_121_1)
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/bug_121_au1.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
@@ -434,3 +436,100 @@ TEST(3_AdvancedMapping)
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/alm_au.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(4_CollectModeRename)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::RenameCell;
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/collect_rename_au.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(4_CollectModeOverwrite)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::OverwriteCell;
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/collect_overwrite_au.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(4_CollectModeSkip)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::SkipNewCell;
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/collect_skip_au.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
TEST(4_CollectModeAdd)
|
||||
{
|
||||
db::Manager m (false);
|
||||
db::Layout layout (&m);
|
||||
|
||||
db::LoadLayoutOptions options;
|
||||
options.get_options<db::CommonReaderOptions> ().cell_conflict_resolution = db::CommonReader::AddToCell;
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_basic.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
{
|
||||
tl::InputStream file (tl::testsrc () + "/testdata/gds/collect_added.gds");
|
||||
db::Reader reader (file);
|
||||
reader.read (layout, options);
|
||||
}
|
||||
|
||||
std::string fn_au (tl::testsrc () + "/testdata/gds/collect_add_au.gds");
|
||||
db::compare_layouts (_this, layout, fn_au, db::WriteGDS2, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -340,26 +340,6 @@ END_PROTECTED
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// LEFDEF technology components editor
|
||||
|
||||
static void
|
||||
indicate_error (QWidget *le, const tl::Exception *ex)
|
||||
{
|
||||
// by the way, update the foreground color of the cell edit box as well (red, if not valid)
|
||||
QPalette pl = le->palette ();
|
||||
if (ex) {
|
||||
pl.setColor (QPalette::Active, QPalette::Text, Qt::red);
|
||||
pl.setColor (QPalette::Active, QPalette::Base, QColor (Qt::red).lighter (180));
|
||||
le->setToolTip (tl::to_qstring (ex->msg ()));
|
||||
} else {
|
||||
QWidget *pw = dynamic_cast<QWidget *> (le->parent ());
|
||||
tl_assert (pw != 0);
|
||||
pl.setColor (QPalette::Active, QPalette::Text, pw->palette ().color (QPalette::Text));
|
||||
pl.setColor (QPalette::Active, QPalette::Base, pw->palette ().color (QPalette::Base));
|
||||
le->setToolTip (QString ());
|
||||
}
|
||||
le->setPalette (pl);
|
||||
}
|
||||
|
||||
|
||||
LEFDEFReaderOptionsEditor::LEFDEFReaderOptionsEditor (QWidget *parent)
|
||||
: lay::StreamReaderOptionsPage (parent), mp_tech (0)
|
||||
{
|
||||
|
||||
@@ -144,9 +144,12 @@ OASISReader::read (db::Layout &layout, const db::LoadLayoutOptions &options)
|
||||
m_read_all_properties = oasis_options.read_all_properties;
|
||||
m_expect_strict_mode = oasis_options.expect_strict_mode;
|
||||
|
||||
set_cell_conflict_resolution (common_options.cell_conflict_resolution);
|
||||
|
||||
layout.start_changes ();
|
||||
try {
|
||||
do_read (layout);
|
||||
finish (layout);
|
||||
layout.end_changes ();
|
||||
} catch (...) {
|
||||
layout.end_changes ();
|
||||
@@ -758,17 +761,11 @@ OASISReader::do_read (db::Layout &layout)
|
||||
id_mode propstring_id_mode = any;
|
||||
id_mode propname_id_mode = any;
|
||||
|
||||
m_cellnames.clear ();
|
||||
m_cellname_properties.clear ();
|
||||
m_textstrings.clear ();
|
||||
m_propstrings.clear ();
|
||||
m_propnames.clear ();
|
||||
m_layernames.clear ();
|
||||
m_cells_by_id.clear ();
|
||||
m_cells_by_name.clear ();
|
||||
m_defined_cells_by_id.clear ();
|
||||
m_defined_cells_by_name.clear ();
|
||||
m_mapped_cellnames.clear ();
|
||||
|
||||
m_instances.clear ();
|
||||
m_instances_with_props.clear ();
|
||||
@@ -826,9 +823,7 @@ OASISReader::do_read (db::Layout &layout)
|
||||
get (id);
|
||||
}
|
||||
|
||||
if (! m_cellnames.insert (std::make_pair (id, name)).second) {
|
||||
error (tl::sprintf (tl::to_string (tr ("A CELLNAME with id %ld is present already")), id));
|
||||
}
|
||||
rename_cell (layout, id, name);
|
||||
|
||||
reset_modal_variables ();
|
||||
|
||||
@@ -1150,36 +1145,17 @@ OASISReader::do_read (db::Layout &layout)
|
||||
|
||||
unsigned long id = 0;
|
||||
get (id);
|
||||
if (! m_defined_cells_by_id.insert (id).second) {
|
||||
|
||||
std::pair<bool, db::cell_index_type> cc = cell_by_id (id);
|
||||
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id));
|
||||
}
|
||||
|
||||
std::map <unsigned long, db::cell_index_type>::const_iterator c = m_cells_by_id.find (id);
|
||||
if (c != m_cells_by_id.end ()) {
|
||||
|
||||
cell_index = c->second;
|
||||
layout.cell (cell_index).set_ghost_cell (false);
|
||||
|
||||
} else {
|
||||
|
||||
std::map <unsigned long, std::string>::const_iterator name = m_cellnames.find (id);
|
||||
if (name == m_cellnames.end ()) {
|
||||
|
||||
cell_index = layout.add_cell ();
|
||||
// force a cell rename to empty to avoid name clashes of the generated
|
||||
// $x names with the same inside the OASIS file.
|
||||
layout.rename_cell (cell_index, "");
|
||||
m_forward_references.insert (std::make_pair (id, cell_index));
|
||||
|
||||
} else {
|
||||
|
||||
cell_index = make_cell (layout, name->second.c_str (), false);
|
||||
m_cells_by_name.insert (std::make_pair (name->second, cell_index));
|
||||
|
||||
}
|
||||
|
||||
m_cells_by_id.insert (std::make_pair (id, cell_index));
|
||||
cell_index = make_cell (layout, id);
|
||||
|
||||
m_cellname = name_for_id (id);
|
||||
if (m_cellname.empty ()) {
|
||||
m_cellname = std::string ("#") + tl::to_string (id);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1189,22 +1165,15 @@ OASISReader::do_read (db::Layout &layout)
|
||||
}
|
||||
|
||||
std::string name = get_str ();
|
||||
if (! m_defined_cells_by_name.insert (name).second) {
|
||||
|
||||
std::pair<bool, db::cell_index_type> cc = cell_by_name (name);
|
||||
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
||||
error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ()));
|
||||
}
|
||||
|
||||
std::map <std::string, db::cell_index_type>::const_iterator c = m_cells_by_name.find (name);
|
||||
if (c != m_cells_by_name.end ()) {
|
||||
cell_index = make_cell (layout, name);
|
||||
|
||||
cell_index = c->second;
|
||||
layout.cell (cell_index).set_ghost_cell (false);
|
||||
|
||||
} else {
|
||||
|
||||
cell_index = make_cell (layout, name.c_str (), false);
|
||||
m_cells_by_name.insert (std::make_pair (name, cell_index));
|
||||
|
||||
}
|
||||
m_cellname = name;
|
||||
|
||||
}
|
||||
|
||||
@@ -1326,72 +1295,16 @@ OASISReader::do_read (db::Layout &layout)
|
||||
|
||||
}
|
||||
|
||||
for (std::map <unsigned long, db::cell_index_type>::const_iterator fw = m_forward_references.begin (); fw != m_forward_references.end (); ++fw) {
|
||||
|
||||
std::map <unsigned long, std::string>::const_iterator cn = m_cellnames.find (fw->first);
|
||||
if (cn == m_cellnames.end ()) {
|
||||
|
||||
error (tl::sprintf (tl::to_string (tr ("No cellname defined for cell name id %ld")), fw->first));
|
||||
|
||||
} else {
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn->second.c_str ());
|
||||
if (c.first) {
|
||||
|
||||
// needed, since we have disabled updates
|
||||
layout.force_update ();
|
||||
|
||||
// add-on reading of forward-referenced cell: need to copy the new cell to the original one plus
|
||||
// change instances of the new cell and delete the new cell then.
|
||||
|
||||
const db::Cell &new_cell = layout.cell (fw->second);
|
||||
db::Cell &org_cell = layout.cell (c.second);
|
||||
|
||||
// copy over the instances
|
||||
for (db::Cell::const_iterator i = new_cell.begin (); ! i.at_end (); ++i) {
|
||||
org_cell.insert (*i);
|
||||
}
|
||||
|
||||
// copy over the shapes
|
||||
for (unsigned int l = 0; l < layout.layers (); ++l) {
|
||||
if (layout.is_valid_layer (l) && ! new_cell.shapes (l).empty ()) {
|
||||
org_cell.shapes (l).insert (new_cell.shapes (l));
|
||||
}
|
||||
}
|
||||
|
||||
// replace all instances of the new cell with the original one
|
||||
std::vector<std::pair<db::cell_index_type, db::Instance> > parents;
|
||||
for (db::Cell::parent_inst_iterator pi = new_cell.begin_parent_insts (); ! pi.at_end (); ++pi) {
|
||||
parents.push_back (std::make_pair (pi->parent_cell_index (), pi->child_inst ()));
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<db::cell_index_type, db::Instance> >::const_iterator p = parents.begin (); p != parents.end (); ++p) {
|
||||
db::CellInstArray ia = p->second.cell_inst ();
|
||||
ia.object ().cell_index (org_cell.cell_index ());
|
||||
layout.cell (p->first).replace (p->second, ia);
|
||||
}
|
||||
|
||||
// finally delete the new cell
|
||||
layout.delete_cell (new_cell.cell_index ());
|
||||
|
||||
} else {
|
||||
layout.rename_cell (fw->second, cn->second.c_str ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// attach the properties found in CELLNAME to the cells (which may have other properties)
|
||||
for (std::map<unsigned long, db::properties_id_type>::const_iterator p = m_cellname_properties.begin (); p != m_cellname_properties.end (); ++p) {
|
||||
|
||||
std::map <unsigned long, db::cell_index_type>::const_iterator c = m_cells_by_id.find (p->first);
|
||||
if (c != m_cells_by_id.end ()) {
|
||||
std::pair<bool, db::cell_index_type> c = cell_by_id (p->first);
|
||||
if (c.first) {
|
||||
|
||||
db::PropertiesRepository::properties_set cnp = layout.properties_repository ().properties (p->second);
|
||||
|
||||
// Merge existing properties with the ones from CELLNAME
|
||||
db::Cell &cell = layout.cell (c->second);
|
||||
db::Cell &cell = layout.cell (c.second);
|
||||
if (cell.prop_id () != 0) {
|
||||
db::PropertiesRepository::properties_set cp = layout.properties_repository ().properties (cell.prop_id ());
|
||||
cnp.insert (cp.begin (), cp.end ());
|
||||
@@ -1844,54 +1757,6 @@ OASISReader::read_repetition ()
|
||||
return mm_repetition.get ().size () > 1;
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
OASISReader::make_cell (db::Layout &layout, const char *cn, bool for_instance)
|
||||
{
|
||||
db::cell_index_type ci = 0;
|
||||
|
||||
// map to the real name which maybe a different one due to localization
|
||||
// of proxy cells (they are not to be reopened)
|
||||
bool is_mapped = false;
|
||||
if (! m_mapped_cellnames.empty ()) {
|
||||
std::map<tl::string, tl::string>::const_iterator n = m_mapped_cellnames.find (cn);
|
||||
if (n != m_mapped_cellnames.end ()) {
|
||||
cn = n->second.c_str ();
|
||||
is_mapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, db::cell_index_type> c = layout.cell_by_name (cn);
|
||||
if (c.first && (is_mapped || ! layout.cell (c.second).is_proxy ())) {
|
||||
|
||||
// cell already there: just add instance (cell might have been created through forward reference)
|
||||
// NOTE: we don't address "reopened" proxies as proxies are always local to a layout
|
||||
|
||||
ci = c.second;
|
||||
|
||||
// mark the cell as read
|
||||
if (! for_instance) {
|
||||
layout.cell (ci).set_ghost_cell (false);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ci = layout.add_cell (cn);
|
||||
|
||||
if (for_instance) {
|
||||
// mark this cell a "ghost cell" until it's actually read
|
||||
layout.cell (ci).set_ghost_cell (true);
|
||||
}
|
||||
|
||||
if (c.first) {
|
||||
// this cell has been given a new name: remember this name for localization
|
||||
m_mapped_cellnames.insert (std::make_pair (cn, layout.cell_name (ci)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
void
|
||||
OASISReader::do_read_placement (unsigned char r,
|
||||
bool xy_absolute,
|
||||
@@ -1909,31 +1774,8 @@ OASISReader::do_read_placement (unsigned char r,
|
||||
// cell by id
|
||||
unsigned long id;
|
||||
get (id);
|
||||
std::map <unsigned long, db::cell_index_type>::const_iterator cid = m_cells_by_id.find (id);
|
||||
if (cid == m_cells_by_id.end ()) {
|
||||
|
||||
// create the cell
|
||||
std::map <unsigned long, std::string>::const_iterator name = m_cellnames.find (id);
|
||||
if (name == m_cellnames.end ()) {
|
||||
|
||||
mm_placement_cell = layout.add_cell ();
|
||||
m_forward_references.insert (std::make_pair (id, mm_placement_cell.get ()));
|
||||
|
||||
// temporarily mark as "ghost cell"
|
||||
layout.cell (mm_placement_cell.get ()).set_ghost_cell (true);
|
||||
|
||||
} else {
|
||||
|
||||
mm_placement_cell = make_cell (layout, name->second.c_str (), true);
|
||||
m_cells_by_name.insert (std::make_pair (name->second, mm_placement_cell.get ()));
|
||||
|
||||
}
|
||||
|
||||
m_cells_by_id.insert (std::make_pair (id, mm_placement_cell.get ()));
|
||||
|
||||
} else {
|
||||
mm_placement_cell = cid->second;
|
||||
}
|
||||
mm_placement_cell = cell_for_instance (layout, id);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1941,15 +1783,7 @@ OASISReader::do_read_placement (unsigned char r,
|
||||
std::string name;
|
||||
get_str (name);
|
||||
|
||||
std::map <std::string, db::cell_index_type>::const_iterator cid = m_cells_by_name.find (name);
|
||||
if (cid == m_cells_by_name.end ()) {
|
||||
|
||||
mm_placement_cell = make_cell (layout, name.c_str (), true);
|
||||
m_cells_by_name.insert (std::make_pair (name, mm_placement_cell.get ()));
|
||||
|
||||
} else {
|
||||
mm_placement_cell = cid->second;
|
||||
}
|
||||
mm_placement_cell = cell_for_instance (layout, name);
|
||||
|
||||
}
|
||||
|
||||
@@ -3433,7 +3267,6 @@ OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout)
|
||||
m_instances_with_props.clear ();
|
||||
|
||||
m_progress.set (m_stream.pos ());
|
||||
m_cellname = layout.cell_name (cell_index);
|
||||
|
||||
bool xy_absolute = true;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "dbOASISFormat.h"
|
||||
#include "dbStreamLayers.h"
|
||||
#include "dbPropertiesRepository.h"
|
||||
#include "dbCommonReader.h"
|
||||
|
||||
#include "tlException.h"
|
||||
#include "tlInternational.h"
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
* @brief The OASIS format stream reader
|
||||
*/
|
||||
class DB_PLUGIN_PUBLIC OASISReader
|
||||
: public ReaderBase,
|
||||
: public CommonReader,
|
||||
public OASISDiagnostics
|
||||
{
|
||||
public:
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
*/
|
||||
virtual const char *format () const { return "OASIS"; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Issue an error with positional information
|
||||
*
|
||||
@@ -132,6 +134,9 @@ public:
|
||||
*/
|
||||
virtual void warn (const std::string &txt);
|
||||
|
||||
virtual void common_reader_error (const std::string &msg) { error (msg); }
|
||||
virtual void common_reader_warn (const std::string &msg) { warn (msg); }
|
||||
|
||||
private:
|
||||
friend class OASISReaderLayerMapping;
|
||||
|
||||
@@ -194,7 +199,6 @@ private:
|
||||
modal_variable<bool> mm_last_property_is_sprop;
|
||||
modal_variable<property_value_list> mm_last_value_list;
|
||||
|
||||
std::map <unsigned long, std::string> m_cellnames;
|
||||
std::map <unsigned long, db::properties_id_type> m_cellname_properties;
|
||||
std::map <unsigned long, std::string> m_textstrings;
|
||||
std::map <unsigned long, const db::StringRef *> m_text_forward_references;
|
||||
@@ -205,18 +209,11 @@ private:
|
||||
tl::vector<db::CellInstArray> m_instances;
|
||||
tl::vector<db::CellInstArrayWithProperties> m_instances_with_props;
|
||||
|
||||
std::map <unsigned long, db::cell_index_type> m_cells_by_id;
|
||||
std::map <unsigned long, db::cell_index_type> m_forward_references;
|
||||
std::map <std::string, db::cell_index_type> m_cells_by_name;
|
||||
bool m_create_layers;
|
||||
bool m_read_texts;
|
||||
bool m_read_properties;
|
||||
bool m_read_all_properties;
|
||||
|
||||
std::set <unsigned long> m_defined_cells_by_id;
|
||||
std::set <std::string> m_defined_cells_by_name;
|
||||
std::map <tl::string, tl::string> m_mapped_cellnames;
|
||||
|
||||
std::map <unsigned long, db::property_names_id_type> m_propname_forward_references;
|
||||
std::map <unsigned long, std::string> m_propvalue_forward_references;
|
||||
db::property_names_id_type m_s_gds_property_name_id;
|
||||
@@ -238,7 +235,6 @@ private:
|
||||
void do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
|
||||
void do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
|
||||
void do_read_circle (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout);
|
||||
db::cell_index_type make_cell (db::Layout &layout, const char *cn, bool for_instance);
|
||||
|
||||
void reset_modal_variables ();
|
||||
|
||||
|
||||
@@ -1150,6 +1150,18 @@ OASISWriter::reset_modal_variables ()
|
||||
mm_last_value_list.reset ();
|
||||
}
|
||||
|
||||
static bool must_write_cell (const db::Cell &cref)
|
||||
{
|
||||
// Don't write proxy cells which are not employed
|
||||
return ! cref.is_proxy () || ! cref.is_top ();
|
||||
}
|
||||
|
||||
static bool skip_cell_body (const db::Cell &cref)
|
||||
{
|
||||
// Skip cell bodies for ghost cells unless empty (they are not longer ghost cells in this case)
|
||||
return cref.is_ghost_cell () && cref.empty ();
|
||||
}
|
||||
|
||||
void
|
||||
OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
@@ -1184,13 +1196,13 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
||||
cells_by_index.reserve (cell_set.size ());
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator cell = layout.begin_bottom_up (); cell != layout.end_bottom_up (); ++cell) {
|
||||
if (cell_set.find (*cell) != cell_set.end ()) {
|
||||
if (cell_set.find (*cell) != cell_set.end () && must_write_cell (layout.cell (*cell))) {
|
||||
cells.push_back (*cell);
|
||||
}
|
||||
}
|
||||
|
||||
for (db::Layout::const_iterator cell = layout.begin (); cell != layout.end (); ++cell) {
|
||||
if (cell_set.find (cell->cell_index ()) != cell_set.end ()) {
|
||||
if (cell_set.find (cell->cell_index ()) != cell_set.end () && must_write_cell (layout.cell (cell->cell_index ()))) {
|
||||
cells_by_index.push_back (cell->cell_index ());
|
||||
}
|
||||
}
|
||||
@@ -1594,80 +1606,79 @@ OASISWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::Save
|
||||
const db::Cell &cref (layout.cell (*cell));
|
||||
mp_cell = &cref;
|
||||
|
||||
// don't write ghost cells unless they are not empty (any more)
|
||||
// also don't write proxy cells which are not employed
|
||||
if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) {
|
||||
// skip cell body if the cell is not to be written
|
||||
if (skip_cell_body (cref)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// cell header
|
||||
// cell header
|
||||
|
||||
cell_positions.insert (std::make_pair (*cell, mp_stream->pos ()));
|
||||
cell_positions.insert (std::make_pair (*cell, mp_stream->pos ()));
|
||||
|
||||
write_record_id (13); // CELL
|
||||
write ((unsigned long) *cell);
|
||||
write_record_id (13); // CELL
|
||||
write ((unsigned long) *cell);
|
||||
|
||||
reset_modal_variables ();
|
||||
reset_modal_variables ();
|
||||
|
||||
if (m_options.write_cblocks) {
|
||||
begin_cblock ();
|
||||
}
|
||||
if (m_options.write_cblocks) {
|
||||
begin_cblock ();
|
||||
}
|
||||
|
||||
// context information as property named KLAYOUT_CONTEXT
|
||||
if (cref.is_proxy () && options.write_context_info ()) {
|
||||
// context information as property named KLAYOUT_CONTEXT
|
||||
if (cref.is_proxy () && options.write_context_info ()) {
|
||||
|
||||
context_prop_strings.clear ();
|
||||
context_prop_strings.clear ();
|
||||
|
||||
if (layout.get_context_info (*cell, context_prop_strings)) {
|
||||
if (layout.get_context_info (*cell, context_prop_strings)) {
|
||||
|
||||
write_record_id (28);
|
||||
write_byte (char (0xf6));
|
||||
std::map <std::string, unsigned long>::const_iterator pni = m_propnames.find (klayout_context_name);
|
||||
tl_assert (pni != m_propnames.end ());
|
||||
write (pni->second);
|
||||
write_record_id (28);
|
||||
write_byte (char (0xf6));
|
||||
std::map <std::string, unsigned long>::const_iterator pni = m_propnames.find (klayout_context_name);
|
||||
tl_assert (pni != m_propnames.end ());
|
||||
write (pni->second);
|
||||
|
||||
write ((unsigned long) context_prop_strings.size ());
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
write_byte (14); // b-string by reference number
|
||||
std::map <std::string, unsigned long>::const_iterator psi = m_propstrings.find (*c);
|
||||
tl_assert (psi != m_propstrings.end ());
|
||||
write (psi->second);
|
||||
}
|
||||
|
||||
mm_last_property_name = klayout_context_name;
|
||||
mm_last_property_is_sprop = false;
|
||||
mm_last_value_list.reset ();
|
||||
write ((unsigned long) context_prop_strings.size ());
|
||||
|
||||
for (std::vector <std::string>::const_iterator c = context_prop_strings.begin (); c != context_prop_strings.end (); ++c) {
|
||||
write_byte (14); // b-string by reference number
|
||||
std::map <std::string, unsigned long>::const_iterator psi = m_propstrings.find (*c);
|
||||
tl_assert (psi != m_propstrings.end ());
|
||||
write (psi->second);
|
||||
}
|
||||
|
||||
mm_last_property_name = klayout_context_name;
|
||||
mm_last_property_is_sprop = false;
|
||||
mm_last_value_list.reset ();
|
||||
|
||||
}
|
||||
|
||||
if (cref.prop_id () != 0) {
|
||||
write_props (cref.prop_id ());
|
||||
}
|
||||
|
||||
// instances
|
||||
if (cref.cell_instances () > 0) {
|
||||
write_insts (cell_set);
|
||||
}
|
||||
|
||||
// shapes
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
const db::Shapes &shapes = cref.shapes (l->first);
|
||||
if (! shapes.empty ()) {
|
||||
write_shapes (l->second, shapes);
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
// end CBLOCK if required
|
||||
if (m_options.write_cblocks) {
|
||||
end_cblock ();
|
||||
}
|
||||
|
||||
// end of cell
|
||||
|
||||
}
|
||||
|
||||
if (cref.prop_id () != 0) {
|
||||
write_props (cref.prop_id ());
|
||||
}
|
||||
|
||||
// instances
|
||||
if (cref.cell_instances () > 0) {
|
||||
write_insts (cell_set);
|
||||
}
|
||||
|
||||
// shapes
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
const db::Shapes &shapes = cref.shapes (l->first);
|
||||
if (! shapes.empty ()) {
|
||||
write_shapes (l->second, shapes);
|
||||
m_progress.set (mp_stream->pos ());
|
||||
}
|
||||
}
|
||||
|
||||
// end CBLOCK if required
|
||||
if (m_options.write_cblocks) {
|
||||
end_cblock ();
|
||||
}
|
||||
|
||||
// end of cell
|
||||
|
||||
}
|
||||
|
||||
// write cell table at the end in strict mode (in that mode we need the cell positions
|
||||
|
||||
@@ -570,11 +570,11 @@ TEST(100)
|
||||
|
||||
const char *expected =
|
||||
"begin_lib 0.001\n"
|
||||
"begin_cell {$4}\n"
|
||||
"end_cell\n"
|
||||
"begin_cell {$1}\n"
|
||||
"box 1 0 {0 100} {1000 1200}\n"
|
||||
"end_cell\n"
|
||||
"begin_cell {$4}\n"
|
||||
"end_cell\n"
|
||||
"begin_cell {$3}\n"
|
||||
"sref {$1} 90 1 1 {-10 20}\n"
|
||||
"sref {$4} 90 1 1 {-10 20}\n"
|
||||
@@ -1327,14 +1327,14 @@ TEST(116)
|
||||
" {{name} {117}}\n"
|
||||
"}\n"
|
||||
"begin_libp $props 0.001\n"
|
||||
"begin_cell {$2}\n"
|
||||
"end_cell\n"
|
||||
"set props {\n"
|
||||
" {42 {42}}\n"
|
||||
"}\n"
|
||||
"begin_cellp $props {$1}\n"
|
||||
"path 1 0 0 0 0 {0 100} {1000 1200}\n"
|
||||
"end_cell\n"
|
||||
"begin_cell {$2}\n"
|
||||
"end_cell\n"
|
||||
"end_lib\n"
|
||||
;
|
||||
|
||||
@@ -1376,14 +1376,14 @@ TEST(116)
|
||||
" {{name} {117}}\n"
|
||||
"}\n"
|
||||
"begin_libp $props 0.001\n"
|
||||
"begin_cell {$2}\n"
|
||||
"end_cell\n"
|
||||
"set props {\n"
|
||||
" {42 {42}}\n"
|
||||
"}\n"
|
||||
"begin_cellp $props {$1}\n"
|
||||
"path 1 0 0 0 0 {0 100} {1000 1200}\n"
|
||||
"end_cell\n"
|
||||
"begin_cell {$2}\n"
|
||||
"end_cell\n"
|
||||
"end_lib\n"
|
||||
;
|
||||
|
||||
@@ -1431,17 +1431,17 @@ TEST(116)
|
||||
"}\n"
|
||||
"begin_libp $props 0.001\n"
|
||||
"set props {\n"
|
||||
" {{S_BOUNDING_BOX} {2,0,0,0,0}}\n"
|
||||
"}\n"
|
||||
"begin_cellp $props {$2}\n"
|
||||
"end_cell\n"
|
||||
"set props {\n"
|
||||
" {{S_BOUNDING_BOX} {0,0,100,1000,1100}}\n"
|
||||
" {42 {42}}\n"
|
||||
"}\n"
|
||||
"begin_cellp $props {$1}\n"
|
||||
"path 1 0 0 0 0 {0 100} {1000 1200}\n"
|
||||
"end_cell\n"
|
||||
"set props {\n"
|
||||
" {{S_BOUNDING_BOX} {2,0,0,0,0}}\n"
|
||||
"}\n"
|
||||
"begin_cellp $props {$2}\n"
|
||||
"end_cell\n"
|
||||
"end_lib\n"
|
||||
;
|
||||
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>D25View</class>
|
||||
<widget class="QDialog" name="D25View">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>854</width>
|
||||
<height>665</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>2.5d View</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="QFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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="QSlider" name="zoom_slider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-300</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>300</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="zoom_factor">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_left">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_left.png</normaloff>:/fit_left.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_front">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_front.png</normaloff>:/fit_front.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_right">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_right.png</normaloff>:/fit_right.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_back">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_back.png</normaloff>:/fit_back.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_top">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_top.png</normaloff>:/fit_top.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="fit_bottom">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/fit_bottom.png</normaloff>:/fit_bottom.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="lay::D25ViewWidget" name="d25_view"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<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="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Press and hold SHIFT for top view</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>lay::D25ViewWidget</class>
|
||||
<extends>QOpenGLWidget</extends>
|
||||
<header>layD25ViewWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../../../lay/lay/layResources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>D25View</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>530</x>
|
||||
<y>626</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>443</x>
|
||||
<y>643</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layD25Camera.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "math.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
D25Camera::D25Camera ()
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
D25Camera::~D25Camera ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
D25Camera::init ()
|
||||
{
|
||||
m_fov = 90.0;
|
||||
m_cam_azimuth = m_cam_elevation = 0.0;
|
||||
m_top_view = false;
|
||||
}
|
||||
|
||||
void
|
||||
D25Camera::camera_reset ()
|
||||
{
|
||||
init ();
|
||||
camera_changed ();
|
||||
}
|
||||
|
||||
double
|
||||
D25Camera::cam_fov () const
|
||||
{
|
||||
return m_fov;
|
||||
}
|
||||
|
||||
double
|
||||
D25Camera::cam_dist () const
|
||||
{
|
||||
return 4.0;
|
||||
}
|
||||
|
||||
QVector3D
|
||||
D25Camera::cam_direction () const
|
||||
{
|
||||
return cam_trans ().inverted ().map (QVector3D (0, 0, -1));
|
||||
}
|
||||
|
||||
QVector3D
|
||||
D25Camera::cam_position () const
|
||||
{
|
||||
return cam_direction () * -cam_dist ();
|
||||
}
|
||||
|
||||
double
|
||||
D25Camera::cam_azimuth () const
|
||||
{
|
||||
return m_cam_azimuth;
|
||||
}
|
||||
|
||||
double
|
||||
D25Camera::cam_elevation () const
|
||||
{
|
||||
return m_top_view ? -90.0 : m_cam_elevation;
|
||||
}
|
||||
|
||||
QMatrix4x4
|
||||
D25Camera::cam_perspective () const
|
||||
{
|
||||
QMatrix4x4 t;
|
||||
t.perspective (cam_fov (), aspect_ratio (), 0.1f, 10000.0f);
|
||||
t.translate (QVector3D (0.0, 0.0, -cam_dist ()));
|
||||
return t;
|
||||
}
|
||||
|
||||
QMatrix4x4
|
||||
D25Camera::cam_trans () const
|
||||
{
|
||||
QMatrix4x4 t;
|
||||
t.rotate (-cam_elevation (), 1.0, 0.0, 0.0);
|
||||
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layD25Camera
|
||||
#define HDR_layD25Camera
|
||||
|
||||
#include "layPluginCommon.h"
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector3D>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class LAY_PLUGIN_PUBLIC D25Camera
|
||||
{
|
||||
public:
|
||||
D25Camera ();
|
||||
virtual ~D25Camera ();
|
||||
|
||||
/**
|
||||
* @brief Gets the position of the camera objective in the scene coordinate system
|
||||
*/
|
||||
QVector3D cam_position () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the direction the camera looks into in the scene coordinate system
|
||||
*/
|
||||
QVector3D cam_direction () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the perspective part of the transformation applied transform scene coordinates into the image plane
|
||||
* The full transformation for scene to image plane is cam_perspective * cam_trans.
|
||||
*/
|
||||
QMatrix4x4 cam_perspective () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the azimuth/elevation part of the transformation applied transform scene coordinates into the image plane
|
||||
* The full transformation for scene to image plane is cam_perspective * cam_trans.
|
||||
*/
|
||||
QMatrix4x4 cam_trans () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the distance of the objective in scene coordinates
|
||||
*/
|
||||
double cam_dist () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the field of view of the camera
|
||||
* The field of view is the objective opening angle.
|
||||
*/
|
||||
double cam_fov () const;
|
||||
|
||||
/**
|
||||
* @brief Gets a flag indicating whether top view is enabled
|
||||
* In "top view" mode, the elevation is fixed to -90 degree.
|
||||
*/
|
||||
bool top_view () const
|
||||
{
|
||||
return m_top_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether top view is enabled
|
||||
*/
|
||||
void set_top_view (bool f)
|
||||
{
|
||||
m_top_view = f;
|
||||
camera_changed ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the elevation angle
|
||||
* A negative angle means the camera looks down, a positive angle means it looks up.
|
||||
*/
|
||||
double cam_elevation () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the elevation angle
|
||||
*/
|
||||
void set_cam_elevation (double e)
|
||||
{
|
||||
m_cam_elevation = e;
|
||||
camera_changed ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the azimuth angle
|
||||
* A positive angle means we look from the left. A negative means we look from the right.
|
||||
*/
|
||||
double cam_azimuth () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the azimuth angle
|
||||
*/
|
||||
void set_cam_azimuth (double a)
|
||||
{
|
||||
m_cam_azimuth = a;
|
||||
camera_changed ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the camera's orientation
|
||||
*/
|
||||
void camera_reset ();
|
||||
|
||||
protected:
|
||||
virtual void camera_changed () { }
|
||||
virtual double aspect_ratio () const { return 1.0; }
|
||||
|
||||
private:
|
||||
double m_cam_azimuth, m_cam_elevation;
|
||||
bool m_top_view;
|
||||
QVector3D m_displacement;
|
||||
double m_fov;
|
||||
|
||||
void init ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layD25MemChunks.h"
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layD25MemChunks
|
||||
#define HDR_layD25MemChunks
|
||||
|
||||
#include <QDialog>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#include "tlObject.h"
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
template <class Obj>
|
||||
struct gl_type2enum
|
||||
{
|
||||
GLenum operator() () const;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct gl_type2enum<float>
|
||||
{
|
||||
GLenum operator() () const { return GL_FLOAT; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides a semi-contiguous array of objects
|
||||
*
|
||||
* The objects are kept in chunks of ChunkLen items.
|
||||
* The blocks can be accessed individually. The array can be
|
||||
* cleared and new items can be added. No insert or delete.
|
||||
*
|
||||
* This object is intended to be used for keeping vertex,
|
||||
* color or point data for OpenGL.
|
||||
*/
|
||||
template <class Obj, size_t ChunkLen = 1024>
|
||||
class mem_chunks
|
||||
: public QDialog
|
||||
{
|
||||
public:
|
||||
|
||||
struct chunk {
|
||||
public:
|
||||
chunk ()
|
||||
: m_len (0), m_next (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
chunk (const chunk &other)
|
||||
: m_len (0), m_next (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
chunk &operator= (const chunk &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
memcpy (&m_objects, &other.m_objects, sizeof (m_objects));
|
||||
m_len = other.m_len;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Obj *front () const { return m_objects; }
|
||||
size_t size () const { return m_len; }
|
||||
const chunk *next () const { return m_next; }
|
||||
|
||||
private:
|
||||
friend class mem_chunks;
|
||||
|
||||
Obj m_objects [ChunkLen];
|
||||
size_t m_len;
|
||||
chunk *m_next;
|
||||
};
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator (chunk *ch = 0)
|
||||
: mp_chunk (ch)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool operator== (iterator other) const
|
||||
{
|
||||
return mp_chunk == other.mp_chunk;
|
||||
}
|
||||
|
||||
bool operator!= (iterator other) const
|
||||
{
|
||||
return mp_chunk != other.mp_chunk;
|
||||
}
|
||||
|
||||
const chunk &operator* () const
|
||||
{
|
||||
return *mp_chunk;
|
||||
}
|
||||
|
||||
const chunk *operator-> () const
|
||||
{
|
||||
return mp_chunk;
|
||||
}
|
||||
|
||||
void operator++ ()
|
||||
{
|
||||
mp_chunk = mp_chunk->next ();
|
||||
}
|
||||
|
||||
private:
|
||||
const chunk *mp_chunk;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
* Creates an empty array
|
||||
*/
|
||||
mem_chunks ()
|
||||
: mp_chunks (0), mp_last_chunk (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~mem_chunks ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
mem_chunks (const mem_chunks &other)
|
||||
: mp_chunks (0), mp_last_chunk (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment
|
||||
*/
|
||||
mem_chunks &operator= (const mem_chunks &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
clear ();
|
||||
const chunk *ch = other.mp_chunks;
|
||||
while (ch) {
|
||||
if (! mp_chunks) {
|
||||
mp_last_chunk = mp_chunks = new chunk (*ch);
|
||||
} else {
|
||||
mp_last_chunk->m_next = new chunk (*ch);
|
||||
mp_last_chunk = mp_last_chunk->m_next;
|
||||
}
|
||||
ch = ch->next ();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the array
|
||||
*/
|
||||
void clear ()
|
||||
{
|
||||
chunk *ch = mp_chunks;
|
||||
mp_chunks = 0;
|
||||
mp_last_chunk = 0;
|
||||
while (ch) {
|
||||
chunk *del = ch;
|
||||
ch = ch->m_next;
|
||||
delete del;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an element to the array
|
||||
*/
|
||||
void add (const Obj &element)
|
||||
{
|
||||
if (! mp_last_chunk) {
|
||||
mp_chunks = mp_last_chunk = new chunk ();
|
||||
}
|
||||
|
||||
if (mp_last_chunk->m_len >= ChunkLen) {
|
||||
mp_last_chunk->m_next = new chunk ();
|
||||
mp_last_chunk = mp_last_chunk->m_next;
|
||||
}
|
||||
|
||||
mp_last_chunk->m_objects [mp_last_chunk->m_len++] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds two elements
|
||||
*/
|
||||
void add (const Obj &e1, const Obj &e2)
|
||||
{
|
||||
add (e1);
|
||||
add (e2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds three elements
|
||||
*/
|
||||
void add (const Obj &e1, const Obj &e2, const Obj &e3)
|
||||
{
|
||||
add (e1);
|
||||
add (e2);
|
||||
add (e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief begin iterator
|
||||
*/
|
||||
iterator begin () const { return iterator (mp_chunks); }
|
||||
|
||||
/**
|
||||
* @brief end iterator
|
||||
*/
|
||||
iterator end () const { return iterator (); }
|
||||
|
||||
/**
|
||||
* @brief Draw to the given context
|
||||
*/
|
||||
void draw_to (QOpenGLFunctions *ctx, GLuint location, GLenum mode) const
|
||||
{
|
||||
for (iterator c = begin (); c != end (); ++c) {
|
||||
ctx->glVertexAttribPointer (location, 3, gl_type2enum<Obj> () (), GL_FALSE, 0, c->front ());
|
||||
ctx->glDrawArrays (mode, 0, c->size () / 3);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
chunk *mp_chunks;
|
||||
chunk *mp_last_chunk;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "layD25View.h"
|
||||
#include "layDispatcher.h"
|
||||
|
||||
#include "layPlugin.h"
|
||||
|
||||
#include <QSurfaceFormat>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class D25Plugin
|
||||
: public lay::Plugin
|
||||
{
|
||||
public:
|
||||
D25Plugin (Plugin *parent, lay::LayoutView *view)
|
||||
: lay::Plugin (parent), mp_view (view)
|
||||
{
|
||||
mp_dialog = new lay::D25View (0);
|
||||
}
|
||||
|
||||
~D25Plugin ()
|
||||
{
|
||||
delete mp_dialog;
|
||||
mp_dialog = 0;
|
||||
}
|
||||
|
||||
void menu_activated (const std::string &symbol)
|
||||
{
|
||||
if (symbol == "lay::d25_view") {
|
||||
|
||||
if (mp_dialog->exec_dialog (mp_view)) {
|
||||
|
||||
// ... implementation is in layD25ToolDialog.cc ...
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
lay::LayoutView *mp_view;
|
||||
lay::D25View *mp_dialog;
|
||||
};
|
||||
|
||||
class D25PluginDeclaration
|
||||
: public lay::PluginDeclaration
|
||||
{
|
||||
public:
|
||||
D25PluginDeclaration ()
|
||||
{
|
||||
// .. 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::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View"))));
|
||||
}
|
||||
|
||||
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::Dispatcher *root, lay::LayoutView *view) const
|
||||
{
|
||||
return new D25Plugin (root, view);
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::D25PluginDeclaration (), 3100, "lay::D25Plugin");
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layD25View.h"
|
||||
#include "layLayoutView.h"
|
||||
|
||||
#include "ui_D25View.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
const double initial_elevation = 3.0;
|
||||
|
||||
D25View::D25View (QWidget *parent)
|
||||
: QDialog (parent)
|
||||
{
|
||||
mp_ui = new Ui::D25View ();
|
||||
mp_ui->setupUi (this);
|
||||
|
||||
mp_ui->d25_view->setFocusPolicy (Qt::StrongFocus);
|
||||
mp_ui->d25_view->setFocus ();
|
||||
|
||||
connect (mp_ui->fit_back, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->fit_front, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->fit_left, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->fit_right, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->fit_top, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->fit_bottom, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
|
||||
connect (mp_ui->zoom_slider, SIGNAL (valueChanged (int)), this, SLOT (scale_slider_changed (int)));
|
||||
connect (mp_ui->d25_view, SIGNAL (scale_factor_changed (double)), this, SLOT (scale_factor_changed (double)));
|
||||
}
|
||||
|
||||
D25View::~D25View ()
|
||||
{
|
||||
delete mp_ui;
|
||||
mp_ui = 0;
|
||||
}
|
||||
|
||||
static QString scale_factor_to_string (double f)
|
||||
{
|
||||
QString s;
|
||||
s.sprintf ("x %.3g", f);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
D25View::scale_slider_changed (int value)
|
||||
{
|
||||
double f = exp (log (10.0) * -0.01 * value);
|
||||
mp_ui->zoom_factor->setText (scale_factor_to_string (f));
|
||||
mp_ui->d25_view->set_scale_factor (f);
|
||||
}
|
||||
|
||||
void
|
||||
D25View::scale_factor_changed (double f)
|
||||
{
|
||||
mp_ui->zoom_factor->setText (scale_factor_to_string (f));
|
||||
int v = floor (0.5 - log10 (f) * 100.0);
|
||||
mp_ui->zoom_slider->blockSignals (true);
|
||||
mp_ui->zoom_slider->setValue (v);
|
||||
mp_ui->zoom_slider->blockSignals (false);
|
||||
}
|
||||
|
||||
int
|
||||
D25View::exec_dialog (lay::LayoutView *view)
|
||||
{
|
||||
mp_view.reset (view);
|
||||
bool any = mp_ui->d25_view->attach_view (view);
|
||||
|
||||
if (! any) {
|
||||
|
||||
mp_view.reset (0);
|
||||
mp_ui->d25_view->attach_view (0);
|
||||
|
||||
throw tl::Exception (tl::to_string (tr ("No z data configured for the layers in the view.\nUse \"Tools/Manage Technologies\" to set up a z stack.")));
|
||||
|
||||
}
|
||||
|
||||
mp_ui->d25_view->reset ();
|
||||
mp_ui->d25_view->set_cam_azimuth (0.0);
|
||||
mp_ui->d25_view->set_cam_elevation (initial_elevation);
|
||||
mp_ui->d25_view->fit ();
|
||||
|
||||
int ret = QDialog::exec ();
|
||||
|
||||
mp_ui->d25_view->attach_view (0);
|
||||
mp_view.reset (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
D25View::fit_button_clicked ()
|
||||
{
|
||||
double azimuth = mp_ui->d25_view->cam_azimuth ();
|
||||
double elevation = mp_ui->d25_view->cam_elevation ();
|
||||
|
||||
if (sender () == mp_ui->fit_back) {
|
||||
azimuth = -180.0;
|
||||
elevation = -initial_elevation;
|
||||
} else if (sender () == mp_ui->fit_front) {
|
||||
azimuth = 0.0;
|
||||
elevation = -initial_elevation;
|
||||
} else if (sender () == mp_ui->fit_left) {
|
||||
azimuth = 90.0;
|
||||
elevation = -initial_elevation;
|
||||
} else if (sender () == mp_ui->fit_right) {
|
||||
azimuth = -90.0;
|
||||
elevation = -initial_elevation;
|
||||
} else if (sender () == mp_ui->fit_top) {
|
||||
elevation = -90;
|
||||
} else if (sender () == mp_ui->fit_bottom) {
|
||||
elevation = 90;
|
||||
}
|
||||
|
||||
mp_ui->d25_view->set_cam_azimuth (azimuth);
|
||||
mp_ui->d25_view->set_cam_elevation (elevation);
|
||||
|
||||
mp_ui->d25_view->fit ();
|
||||
}
|
||||
|
||||
void
|
||||
D25View::accept ()
|
||||
{
|
||||
QDialog::accept ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layD25View
|
||||
#define HDR_layD25View
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "tlObject.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class D25View;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
class LayoutView;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class D25View
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
D25View (QWidget *parent);
|
||||
~D25View ();
|
||||
|
||||
int exec_dialog (lay::LayoutView *view);
|
||||
|
||||
protected:
|
||||
void accept ();
|
||||
|
||||
private slots:
|
||||
void fit_button_clicked ();
|
||||
void scale_factor_changed (double f);
|
||||
void scale_slider_changed (int value);
|
||||
|
||||
private:
|
||||
Ui::D25View *mp_ui;
|
||||
tl::weak_ptr<lay::LayoutView> mp_view;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layD25ViewUtils.h"
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QMatrix3x3>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
const double epsilon = 1e-10;
|
||||
|
||||
std::pair<bool, QVector3D>
|
||||
cutpoint_line_with_plane (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &plane_normal)
|
||||
{
|
||||
double dn = QVector3D::dotProduct (dir, plane_normal);
|
||||
if (fabs (dn) < epsilon) {
|
||||
return std::make_pair (false, QVector3D ());
|
||||
} else {
|
||||
return std::make_pair (true, line + dir * QVector3D::dotProduct (plane - line, plane_normal) / dn);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, QVector3D>
|
||||
cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &u, const QVector3D &v)
|
||||
{
|
||||
QVector3D n = QVector3D::crossProduct (u, v);
|
||||
std::pair<bool, QVector3D> r = cutpoint_line_with_plane (line, dir, plane, n);
|
||||
if (! r.first) {
|
||||
return r;
|
||||
}
|
||||
|
||||
double pu = QVector3D::dotProduct (r.second - plane, u);
|
||||
double pv = QVector3D::dotProduct (r.second - plane, v);
|
||||
|
||||
// test whether the cut point is inside the face
|
||||
if (pu < -epsilon || pu > u.lengthSquared () + epsilon || pv < -epsilon || pv > v.lengthSquared () + epsilon) {
|
||||
return std::make_pair (false, QVector3D ());
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
static bool somewhat_perpendicular (const QVector3D &a, const QVector3D &b)
|
||||
{
|
||||
// returns true if a and b are perpendicular within +/-30 degree
|
||||
return fabs (QVector3D::dotProduct (a, b)) < 0.5 * a.length () * b.length ();
|
||||
}
|
||||
|
||||
static std::pair<bool, QVector3D> plane_or_face (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &u, const QVector3D &v, bool face)
|
||||
{
|
||||
if (face) {
|
||||
return cutpoint_line_with_face (line, line_dir, corner, u, v);
|
||||
} else if (somewhat_perpendicular (u, line_dir) && somewhat_perpendicular (v, line_dir)) {
|
||||
return cutpoint_line_with_plane (line, line_dir, corner, QVector3D::crossProduct (u, v));
|
||||
} else {
|
||||
return std::make_pair (false, QVector3D ());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, QVector3D>
|
||||
hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &dim)
|
||||
{
|
||||
std::vector<std::pair<bool, QVector3D> > cutpoints;
|
||||
cutpoints.reserve (6); // 6 faces
|
||||
|
||||
for (int pass = 0; pass < 2; ++pass) {
|
||||
|
||||
bool face = (pass == 0);
|
||||
|
||||
if (face) {
|
||||
bool in_x = (line.x () > corner.x () - epsilon) && (line.x () < corner.x () + dim.x () + epsilon);
|
||||
bool in_y = (line.y () > corner.y () - epsilon) && (line.y () < corner.y () + dim.y () + epsilon);
|
||||
bool in_z = (line.z () > corner.z () - epsilon) && (line.z () < corner.z () + dim.z () + epsilon);
|
||||
if (in_x && in_y && in_z) {
|
||||
// inside cuboid
|
||||
return std::make_pair (true, line);
|
||||
}
|
||||
}
|
||||
|
||||
cutpoints.clear ();
|
||||
|
||||
// front
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face));
|
||||
// back
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, 0, dim.z ()), QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face));
|
||||
// bottom
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face));
|
||||
// top
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, dim.y (), 0), QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face));
|
||||
// left
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face));
|
||||
// right
|
||||
cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face));
|
||||
|
||||
double min_dist = 0.0;
|
||||
int min_dist_index = -1;
|
||||
QVector3D ld_norm = line_dir.normalized ();
|
||||
|
||||
for (std::vector<std::pair<bool, QVector3D> >::const_iterator i = cutpoints.begin (); i != cutpoints.end (); ++i) {
|
||||
if (i->first) {
|
||||
double dist = QVector3D::dotProduct (i->second - line, ld_norm);
|
||||
if (min_dist_index < 0) {
|
||||
min_dist = dist;
|
||||
min_dist_index = int (i - cutpoints.begin ());
|
||||
} else if (dist < min_dist) {
|
||||
min_dist = dist;
|
||||
min_dist_index = int (i - cutpoints.begin ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min_dist_index >= 0) {
|
||||
return cutpoints [min_dist_index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return std::make_pair (false, QVector3D ());
|
||||
}
|
||||
|
||||
std::pair<QVector3D, QVector3D>
|
||||
camera_normal (const QMatrix4x4 &camera_trans, double x, double y)
|
||||
{
|
||||
QVector3D p = camera_trans.inverted ().map (QVector3D (x, y, 1.0));
|
||||
|
||||
QVector4D pv = camera_trans.row (3);
|
||||
|
||||
QMatrix4x4 m (camera_trans);
|
||||
|
||||
float values[] = {
|
||||
float (x * pv.x ()), float (x * pv.y ()), float (x * pv.z ()), 0.0f,
|
||||
float (y * pv.x ()), float (y * pv.y ()), float (y * pv.z ()), 0.0f,
|
||||
float (pv.x ()), float (pv.y ()), float (pv.z ()), 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 0.0f
|
||||
};
|
||||
m -= QMatrix4x4 (values);
|
||||
|
||||
QMatrix3x3 nm = m.normalMatrix ();
|
||||
|
||||
QVector3D u (nm (2, 0), nm (2, 1), nm (2, 2));
|
||||
return (std::make_pair (p, u.normalized ()));
|
||||
}
|
||||
|
||||
void
|
||||
normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget)
|
||||
{
|
||||
// Here is the theory:
|
||||
// Let:
|
||||
// cam = ( M t ) M = 3x3 matrix, t = 3x1 translation vector, z = scalar, p = 1x3 perspective
|
||||
// ( p z )
|
||||
// and:
|
||||
// scene = ( S d*s ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector
|
||||
// ( 0 1 )
|
||||
// then:
|
||||
// cam * scene = ( M*s M*d*s+t )
|
||||
// ( p*s p*d*s+z ) (p*d = dot product)
|
||||
//
|
||||
// this is image invariant (only x,y results are considered) against changes of s (s->s') if
|
||||
//
|
||||
// 1.) (p*d*s+z)/s = (p*d'*s'+z)/s' (because x and y will be devided by this value)
|
||||
// 2.) (M*d*s+t)/s = (M*d'*s'+t)/s' for [x] and [y]
|
||||
//
|
||||
// or
|
||||
//
|
||||
// 1.) p*d+z/s = p*d'+z/s'
|
||||
// 2.) M*d+t/s = M*d'+t/s'
|
||||
//
|
||||
// If we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=1/s')
|
||||
//
|
||||
// 2.) M[xx] * d'[x] + M[xy] * d'[y] + t[x] * f = (M*d)[x] + t[x]/s - M[xz]*b
|
||||
// M[yx] * d'[x] + M[yy] * d'[y] + t[y] * f = (M*d)[y] + t[y]/s - M[yz]*b
|
||||
// 1.) p[x] * d'[x] + p[y] * d'[y] + z * f = p*d + z/s - p[z]*b
|
||||
//
|
||||
// we can solve these equations for d'[x], d'[y] and f.
|
||||
// With p[x]=M[wx], p[y]=M[wy] and z=t[w], the above equation system can be written as
|
||||
//
|
||||
// M[ix] * d'[x] + M[iy] * d'[y] + t[i] * f = (M*d)[i] - M[iz]*b + t[i]/s i = x,y,w
|
||||
//
|
||||
|
||||
QMatrix4x4 m;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (i != 2) {
|
||||
m (i, 0) = cam_trans (i, 0);
|
||||
m (i, 1) = cam_trans (i, 1);
|
||||
m (i, 3) = cam_trans (i, 3);
|
||||
}
|
||||
}
|
||||
|
||||
bool invertable = false;
|
||||
QMatrix4x4 minv = m.inverted (&invertable);
|
||||
if (! invertable) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector4D rhs = cam_trans.map (QVector4D (displacement.x (), displacement.y (), displacement.z () - ztarget, 1.0 / scale));
|
||||
QVector4D sol = minv.map (rhs);
|
||||
double f = sol.w ();
|
||||
if (f > 1e-6 /*skip weird solutions*/) {
|
||||
scale = 1.0 / f;
|
||||
displacement = QVector3D (sol.x (), sol.y (), ztarget);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layD25ViewUtils
|
||||
#define HDR_layD25ViewUtils
|
||||
|
||||
#include "layPluginCommon.h"
|
||||
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
#include <algorithm>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Computes the cutpoint between a line and a plane
|
||||
*
|
||||
* The line is given by a point and a direction (line, line_dir).
|
||||
* The plane is given by a point and a normal vector (plane, plane_normal)
|
||||
* The "first" component of the returned pair is false if not hit is present.
|
||||
*/
|
||||
|
||||
LAY_PLUGIN_PUBLIC std::pair<bool, QVector3D>
|
||||
cutpoint_line_with_plane (const QVector3D &line, const QVector3D &line_dir, const QVector3D &plane, const QVector3D &plane_normal);
|
||||
|
||||
/**
|
||||
* @brief Computes the cutpoint between a line and a face
|
||||
*
|
||||
* The line is given by a point and a direction (line, line_dir).
|
||||
* The face is given by a plane point and two vectors spanning the face.
|
||||
* The "first" component of the returned pair is false if not hit is present.
|
||||
*/
|
||||
|
||||
LAY_PLUGIN_PUBLIC std::pair<bool, QVector3D>
|
||||
cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &u, const QVector3D &v);
|
||||
|
||||
/**
|
||||
* @brief Determines a good hit point of a view line and a cuboid
|
||||
*
|
||||
* "corner, dim" are the coordinates for the cuboid (corner is the bottom, left, foremost corner, dim
|
||||
* is (width, height, depth)
|
||||
* "line, line_dir" is the view line where "line_dir" is pointing from the camera to the object.
|
||||
* The returned point is a suitable hit point.
|
||||
* The "first" component of the returned pair is false if no hit is present.
|
||||
*/
|
||||
LAY_PLUGIN_PUBLIC std::pair<bool, QVector3D>
|
||||
hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &dim);
|
||||
|
||||
/**
|
||||
* @brief For a given pixel coordinate and camera transformation matrix compute a line containing all points corresponding to this pixel
|
||||
*
|
||||
* The returned pair contains a point and a direction vector describing the line.
|
||||
*/
|
||||
LAY_PLUGIN_PUBLIC std::pair<QVector3D, QVector3D>
|
||||
camera_normal (const QMatrix4x4 &camera_trans, double x, double y);
|
||||
|
||||
/**
|
||||
* @brief Normalizes a scene transformation
|
||||
*
|
||||
* Scene transformations consist of a scaling and displacement. Both are
|
||||
* interchangeable to some extent under the presence of a perspective
|
||||
* transformation (further away makes the scene smaller). This normalization
|
||||
* tries to find a displacement which has "ztarget" target value for z. Without normalization
|
||||
* the scene tends to "move away" with respect to z.
|
||||
*/
|
||||
LAY_PLUGIN_PUBLIC void
|
||||
normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget = 0.0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,150 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_layD25ViewWidget
|
||||
#define HDR_layD25ViewWidget
|
||||
|
||||
#include "dbPolygon.h"
|
||||
|
||||
#include "layD25MemChunks.h"
|
||||
#include "layD25Camera.h"
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QMatrix4x4>
|
||||
#include <QPoint>
|
||||
#include <QVector3D>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace db
|
||||
{
|
||||
class Layout;
|
||||
class Cell;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class LayoutView;
|
||||
class D25ViewWidget;
|
||||
|
||||
class D25InteractionMode
|
||||
{
|
||||
public:
|
||||
D25InteractionMode (D25ViewWidget *widget);
|
||||
virtual ~D25InteractionMode ();
|
||||
|
||||
D25ViewWidget *view () { return mp_view; }
|
||||
virtual void mouse_move (QMouseEvent *event) = 0;
|
||||
|
||||
private:
|
||||
D25ViewWidget *mp_view;
|
||||
};
|
||||
|
||||
class D25ViewWidget
|
||||
: public QOpenGLWidget,
|
||||
private QOpenGLFunctions,
|
||||
public D25Camera
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
D25ViewWidget (QWidget *parent);
|
||||
~D25ViewWidget ();
|
||||
|
||||
void keyPressEvent (QKeyEvent *event);
|
||||
void keyReleaseEvent (QKeyEvent *event);
|
||||
void wheelEvent (QWheelEvent *event);
|
||||
void mousePressEvent (QMouseEvent *event);
|
||||
void mouseReleaseEvent (QMouseEvent *event);
|
||||
void mouseMoveEvent (QMouseEvent *event);
|
||||
|
||||
bool attach_view(lay::LayoutView *view);
|
||||
|
||||
QVector3D hit_point_with_scene(const QVector3D &line_dir);
|
||||
void refresh ();
|
||||
void reset ();
|
||||
|
||||
QVector3D displacement () const { return m_displacement; }
|
||||
|
||||
void set_displacement (const QVector3D &d)
|
||||
{
|
||||
m_displacement = d;
|
||||
refresh ();
|
||||
}
|
||||
|
||||
double scale_factor () const { return m_scale_factor; }
|
||||
|
||||
void set_scale_factor (double f)
|
||||
{
|
||||
m_scale_factor = f;
|
||||
refresh ();
|
||||
}
|
||||
|
||||
signals:
|
||||
void scale_factor_changed (double f);
|
||||
|
||||
protected:
|
||||
virtual void camera_changed ();
|
||||
virtual double aspect_ratio () const;
|
||||
|
||||
public slots:
|
||||
void fit ();
|
||||
|
||||
private:
|
||||
typedef lay::mem_chunks<GLfloat, 1024 * 18> chunks_type;
|
||||
|
||||
std::auto_ptr<D25InteractionMode> mp_mode;
|
||||
QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program;
|
||||
double m_scale_factor;
|
||||
QVector3D m_displacement;
|
||||
lay::LayoutView *mp_view;
|
||||
db::DBox m_bbox;
|
||||
double m_zmin, m_zmax;
|
||||
|
||||
std::list<chunks_type> m_vertex_chunks;
|
||||
|
||||
struct LayerInfo {
|
||||
const chunks_type *vertex_chunk;
|
||||
GLfloat color [4];
|
||||
};
|
||||
|
||||
std::list<LayerInfo> m_layers;
|
||||
|
||||
void initializeGL ();
|
||||
void paintGL ();
|
||||
void resizeGL (int w, int h);
|
||||
|
||||
bool prepare_view();
|
||||
void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop);
|
||||
void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop);
|
||||
void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "layXORToolDialog.h"
|
||||
#include "layDispatcher.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::menu_item ("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::Dispatcher *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,27 @@
|
||||
|
||||
TARGET = d25_ui
|
||||
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 = \
|
||||
layD25View.h \
|
||||
layD25ViewWidget.h \
|
||||
layD25MemChunks.h \
|
||||
layD25ViewUtils.h \
|
||||
layD25Camera.h
|
||||
|
||||
SOURCES = \
|
||||
layD25View.cc \
|
||||
layD25ViewWidget.cc \
|
||||
layD25Plugin.cc \
|
||||
layD25MemChunks.cc \
|
||||
layD25ViewUtils.cc \
|
||||
layD25Camera.cc
|
||||
|
||||
FORMS = \
|
||||
D25View.ui \
|
||||
@@ -0,0 +1,102 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layD25Camera.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
static std::string v2s (const QVector4D &v)
|
||||
{
|
||||
return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ());
|
||||
}
|
||||
|
||||
static std::string v2s (const QVector3D &v)
|
||||
{
|
||||
return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ());
|
||||
}
|
||||
|
||||
static std::string v2s_2d (const QVector3D &v)
|
||||
{
|
||||
return tl::to_string (v.x ()) + "," + tl::to_string (v.y ());
|
||||
}
|
||||
|
||||
TEST(1_Transformations)
|
||||
{
|
||||
lay::D25Camera cam;
|
||||
|
||||
cam.set_cam_azimuth (45.0);
|
||||
EXPECT_EQ (cam.cam_azimuth (), 45.0);
|
||||
cam.set_cam_elevation (22.0);
|
||||
EXPECT_EQ (cam.cam_elevation (), 22.0);
|
||||
|
||||
cam.camera_reset ();
|
||||
EXPECT_EQ (cam.cam_azimuth (), 0.0);
|
||||
EXPECT_EQ (cam.cam_elevation (), 0.0);
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,0,1");
|
||||
EXPECT_EQ (v2s (cam.cam_direction ()), "0,0,-1");
|
||||
EXPECT_EQ (v2s (cam.cam_position ()), "0,0,4");
|
||||
|
||||
// looking up from the bottom, x axis stays the same (azimuth = 0)
|
||||
cam.set_cam_elevation (90.0);
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,0,-1");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,1,0");
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_direction ()), "0,1,0");
|
||||
EXPECT_EQ (v2s (cam.cam_position ()), "0,-4,0");
|
||||
|
||||
// looking down from the top, x axis stays the same (azimuth = 0)
|
||||
cam.set_cam_elevation (-90.0);
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,0,1");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,-1,0");
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_direction ()), "0,-1,0");
|
||||
EXPECT_EQ (v2s (cam.cam_position ()), "0,4,0");
|
||||
|
||||
// looking from the left, y axis stays the same (elevation = 0)
|
||||
cam.set_cam_elevation (0.0);
|
||||
cam.set_cam_azimuth (90.0);
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "0,0,-1");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "1,0,0");
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_direction ()), "1,0,0");
|
||||
EXPECT_EQ (v2s (cam.cam_position ()), "-4,0,0");
|
||||
|
||||
// looking from the right, y axis stays the same (elevation = 0)
|
||||
cam.set_cam_elevation (0.0);
|
||||
cam.set_cam_azimuth (-90.0);
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "0,0,1");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0");
|
||||
EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "-1,0,0");
|
||||
|
||||
EXPECT_EQ (v2s (cam.cam_direction ()), "-1,0,0");
|
||||
EXPECT_EQ (v2s (cam.cam_position ()), "4,0,0");
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layD25MemChunks.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
TEST(1_Basic)
|
||||
{
|
||||
lay::mem_chunks<int, 2> ch;
|
||||
EXPECT_EQ (ch.begin () == ch.end (), true);
|
||||
|
||||
ch.add (1);
|
||||
EXPECT_EQ (ch.begin () == ch.end (), false);
|
||||
EXPECT_EQ (ch.begin ()->size (), size_t (1));
|
||||
EXPECT_EQ (ch.begin ()->front () [0], 1);
|
||||
|
||||
ch.add (17);
|
||||
EXPECT_EQ (ch.begin () == ch.end (), false);
|
||||
EXPECT_EQ (ch.begin ()->size (), size_t (2));
|
||||
EXPECT_EQ (ch.begin ()->front () [0], 1);
|
||||
EXPECT_EQ (ch.begin ()->front () [1], 17);
|
||||
|
||||
lay::mem_chunks<int, 2>::iterator c = ch.begin ();
|
||||
EXPECT_EQ (c == ch.end (), false);
|
||||
++c;
|
||||
EXPECT_EQ (c == ch.end (), true);
|
||||
|
||||
ch.add (42);
|
||||
c = ch.begin ();
|
||||
EXPECT_EQ (c == ch.end (), false);
|
||||
EXPECT_EQ (c->size (), size_t (2));
|
||||
EXPECT_EQ (c->front () [0], 1);
|
||||
EXPECT_EQ (c->front () [1], 17);
|
||||
++c;
|
||||
EXPECT_EQ (c == ch.end (), false);
|
||||
EXPECT_EQ (c->size (), size_t (1));
|
||||
EXPECT_EQ (c->front () [0], 42);
|
||||
++c;
|
||||
EXPECT_EQ (c == ch.end (), true);
|
||||
|
||||
ch.clear ();
|
||||
EXPECT_EQ (ch.begin () == ch.end (), true);
|
||||
}
|
||||
|
||||
TEST(2_Copy)
|
||||
{
|
||||
lay::mem_chunks<int, 2> ch1;
|
||||
ch1.add (1);
|
||||
ch1.add (17);
|
||||
ch1.add (42);
|
||||
|
||||
lay::mem_chunks<int, 2> ch (ch1);
|
||||
|
||||
lay::mem_chunks<int, 2>::iterator c = ch.begin ();
|
||||
|
||||
EXPECT_EQ (c == ch.end (), false);
|
||||
EXPECT_EQ (c->size (), size_t (2));
|
||||
EXPECT_EQ (c->front () [0], 1);
|
||||
EXPECT_EQ (c->front () [1], 17);
|
||||
++c;
|
||||
EXPECT_EQ (c == ch.end (), false);
|
||||
EXPECT_EQ (c->size (), size_t (1));
|
||||
EXPECT_EQ (c->front () [0], 42);
|
||||
++c;
|
||||
EXPECT_EQ (c == ch.end (), true);
|
||||
|
||||
ch1.clear ();
|
||||
ch = ch1;
|
||||
EXPECT_EQ (ch.begin () == ch.end (), true);
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layD25ViewUtils.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
static std::string v2s (const QVector3D &v)
|
||||
{
|
||||
return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ());
|
||||
}
|
||||
|
||||
static std::string v2s_2d (const QVector3D &v)
|
||||
{
|
||||
return tl::to_string (v.x ()) + "," + tl::to_string (v.y ());
|
||||
}
|
||||
|
||||
TEST(1_CutPoint)
|
||||
{
|
||||
std::pair<bool, QVector3D> r;
|
||||
|
||||
r = lay::cutpoint_line_with_plane (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (0, 0, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, false);
|
||||
|
||||
r = lay::cutpoint_line_with_plane (QVector3D (1, 2, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 0, 1));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "1,2,6");
|
||||
|
||||
r = lay::cutpoint_line_with_plane (QVector3D (1, 2, 3), QVector3D (0, 0, -1), QVector3D (4, 5, 6), QVector3D (1, 1, 1));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "1,2,12");
|
||||
}
|
||||
|
||||
TEST(2_Face)
|
||||
{
|
||||
std::pair<bool, QVector3D> r;
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (0, 0, 0), QVector3D (0, 1, 0), QVector3D (0, 0, 1));
|
||||
EXPECT_EQ (r.first, false);
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (1, 2, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, false);
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (4, 5, 3), QVector3D (0, 0, 3), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "4,5,6");
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (4, 7, 3), QVector3D (0, 0, 1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, false);
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (4, 6, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "4,6,6");
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (5, 6, 3), QVector3D (0, 0, -1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "5,6,6");
|
||||
|
||||
r = lay::cutpoint_line_with_face (QVector3D (6, 6, 3), QVector3D (0, 0, 1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0));
|
||||
EXPECT_EQ (r.first, false);
|
||||
}
|
||||
|
||||
TEST(3_HitWithCuboid)
|
||||
{
|
||||
std::pair<bool, QVector3D> r;
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "0,0,3");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (1, 1, 4), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "1,1,4");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (1, 1, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "1,1,3");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (5, -6, 0), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "5,-6,3");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (5, -6, 4), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "5,-6,3");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (5, -6, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "5,-6,3");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (5, 0, 0), QVector3D (-1, 0, 0), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "1,0,0");
|
||||
|
||||
r = lay::hit_point_with_cuboid (QVector3D (-5, 0, 0), QVector3D (1, 0, 0), QVector3D (-1, -1, 3), QVector3D (2, 2, 2));
|
||||
EXPECT_EQ (r.first, true);
|
||||
EXPECT_EQ (v2s (r.second), "-1,0,0");
|
||||
}
|
||||
|
||||
TEST(4_CameraNormal)
|
||||
{
|
||||
QMatrix4x4 matrix;
|
||||
matrix.perspective (60.0f, 1.5, 0.1f, 100.0f);
|
||||
|
||||
std::pair<QVector3D, QVector3D> ray;
|
||||
QVector3D p;
|
||||
|
||||
ray = lay::camera_normal (matrix, 0.0, 0.0);
|
||||
EXPECT_EQ (v2s (ray.second.normalized ()), "0,0,-1");
|
||||
|
||||
ray = lay::camera_normal (matrix, 1.0, 0.0);
|
||||
EXPECT_EQ (v2s (ray.second), "0.654654,0,-0.755929");
|
||||
|
||||
p = matrix.map (ray.first);
|
||||
EXPECT_EQ (v2s_2d (p), "1,0");
|
||||
|
||||
p = matrix.map (ray.first + ray.second);
|
||||
EXPECT_EQ (v2s_2d (p), "1,0");
|
||||
|
||||
p = matrix.map (ray.first + ray.second * 1000.0);
|
||||
EXPECT_EQ (v2s_2d (p), "1,0");
|
||||
|
||||
ray = lay::camera_normal (matrix, 0.0, -1.0);
|
||||
EXPECT_EQ (v2s (ray.second), "0,-0.5,-0.866025");
|
||||
|
||||
p = matrix.map (ray.first);
|
||||
EXPECT_EQ (v2s_2d (p), "0,-1");
|
||||
|
||||
p = matrix.map (ray.first + ray.second);
|
||||
EXPECT_EQ (v2s_2d (p), "0,-1");
|
||||
|
||||
p = matrix.map (ray.first + ray.second * 1000.0);
|
||||
EXPECT_EQ (v2s_2d (p), "0,-1");
|
||||
}
|
||||
|
||||
TEST(5_CameraNormal)
|
||||
{
|
||||
QMatrix4x4 matrix;
|
||||
QVector3D p;
|
||||
|
||||
matrix.perspective (60.0f, 1.5, 0.1f, 100.0f);
|
||||
matrix.rotate (22.0, 1.0, 0.0, 0.0);
|
||||
matrix.rotate (-15.0, 0.0, 1.0, 0.0);
|
||||
matrix.translate (QVector3D (0.0, 0.0, 4.0));
|
||||
|
||||
std::pair<QVector3D, QVector3D> ray;
|
||||
|
||||
ray = lay::camera_normal (matrix, 0.0, 1.0);
|
||||
EXPECT_EQ (v2s (ray.second), "-0.2563,0.139173,-0.956526");
|
||||
|
||||
p = matrix.map (ray.first);
|
||||
EXPECT_EQ (v2s_2d (p), "0,1");
|
||||
|
||||
p = matrix.map (ray.first + ray.second);
|
||||
EXPECT_EQ (v2s_2d (p), "0,1");
|
||||
|
||||
p = matrix.map (ray.first + ray.second * 1000.0);
|
||||
EXPECT_EQ (v2s_2d (p), "0,1");
|
||||
}
|
||||
|
||||
TEST(6_NormalizeSceneTrans)
|
||||
{
|
||||
QMatrix4x4 cam;
|
||||
cam.perspective (60.0f, 1.5, 0.1f, 100.0f);
|
||||
cam.rotate (22.0, 1.0, 0.0, 0.0);
|
||||
cam.rotate (-15.0, 0.0, 1.0, 0.0);
|
||||
cam.translate (QVector3D (0.0, 0.0, 4.0));
|
||||
|
||||
double scale = 0.1;
|
||||
QVector3D displacement (-5.0, 2.0, 20.0);
|
||||
|
||||
QMatrix4x4 scene1;
|
||||
scene1.scale (scale);
|
||||
scene1.translate (displacement);
|
||||
|
||||
QVector3D v1 = (cam * scene1).map (QVector3D (1.0, -1.0, 2.0));
|
||||
v1.setZ (0);
|
||||
QVector3D v2 = (cam * scene1).map (QVector3D (0.0, 0.0, 5.0));
|
||||
v2.setZ (0);
|
||||
QVector3D v3 = (cam * scene1).map (QVector3D (-1.0, 0.0, 1.0));
|
||||
v3.setZ (0);
|
||||
|
||||
lay::normalize_scene_trans (cam, displacement, scale);
|
||||
|
||||
QMatrix4x4 scene2;
|
||||
scene2.scale (scale);
|
||||
scene2.translate (displacement);
|
||||
|
||||
EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0667");
|
||||
|
||||
QVector3D u1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0));
|
||||
u1.setZ (0);
|
||||
QVector3D u2 = (cam * scene2).map (QVector3D (0.0, 0.0, 5.0));
|
||||
u2.setZ (0);
|
||||
QVector3D u3 = (cam * scene2).map (QVector3D (-1.0, 0.0, 1.0));
|
||||
u3.setZ (0);
|
||||
|
||||
EXPECT_EQ ((u1 - v1).length () < 1e-4, true);
|
||||
EXPECT_EQ ((u2 - v2).length () < 1e-4, true);
|
||||
EXPECT_EQ ((u3 - v3).length () < 1e-4, true);
|
||||
|
||||
lay::normalize_scene_trans (cam, displacement, scale, 10.0);
|
||||
|
||||
QMatrix4x4 scene3;
|
||||
scene3.scale (scale);
|
||||
scene3.translate (displacement);
|
||||
|
||||
EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0800");
|
||||
EXPECT_EQ (tl::to_string (displacement.z ()), "10");
|
||||
|
||||
QVector3D uu1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0));
|
||||
uu1.setZ (0);
|
||||
QVector3D uu2 = (cam * scene2).map (QVector3D (0.0, 0.0, 5.0));
|
||||
uu2.setZ (0);
|
||||
QVector3D uu3 = (cam * scene2).map (QVector3D (-1.0, 0.0, 1.0));
|
||||
uu3.setZ (0);
|
||||
|
||||
EXPECT_EQ ((uu1 - v1).length () < 1e-4, true);
|
||||
EXPECT_EQ ((uu2 - v2).length () < 1e-4, true);
|
||||
EXPECT_EQ ((uu3 - v3).length () < 1e-4, true);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
DESTDIR_UT = $$OUT_PWD/../../../..
|
||||
|
||||
TARGET = view_25d_tests
|
||||
|
||||
include($$PWD/../../../../lib_ut.pri)
|
||||
|
||||
SOURCES = \
|
||||
layD25MemChunksTests.cc \
|
||||
layD25ViewUtilsTests.cc \
|
||||
layD25CameraTests.cc
|
||||
|
||||
INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common
|
||||
DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common
|
||||
|
||||
LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi
|
||||
|
||||
PLUGINPATH = $$OUT_PWD/../../../../lay_plugins
|
||||
QMAKE_RPATHDIR += $$PLUGINPATH
|
||||
|
||||
LIBS += -L$$PLUGINPATH -ld25_ui
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
equals(HAVE_QT5, "1") {
|
||||
SUBDIRS = lay_plugin unit_tests
|
||||
}
|
||||
Reference in New Issue
Block a user