klayout/src/edt/edtPropertiesPageUtils.cc

789 lines
23 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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 "edtPropertiesPageUtils.h"
#include "dbShapes.h"
#include "dbLayout.h"
namespace edt
{
// -------------------------------------------------------------------------
// CombinedChangeApplicator implementation
CombinedChangeApplicator::CombinedChangeApplicator ()
{
}
CombinedChangeApplicator::CombinedChangeApplicator (ChangeApplicator *a1)
{
m_appl.push_back (a1);
}
CombinedChangeApplicator::CombinedChangeApplicator (ChangeApplicator *a1, ChangeApplicator *a2)
{
m_appl.push_back (a1);
m_appl.push_back (a2);
}
void CombinedChangeApplicator::add (ChangeApplicator *a)
{
m_appl.push_back (a);
}
CombinedChangeApplicator::~CombinedChangeApplicator ()
{
for (std::vector<ChangeApplicator *>::const_iterator a = m_appl.begin (); a != m_appl.end (); ++a) {
delete *a;
}
m_appl.clear ();
}
bool CombinedChangeApplicator::supports_relative_mode () const
{
for (std::vector<ChangeApplicator *>::const_iterator a = m_appl.begin (); a != m_appl.end (); ++a) {
if ((*a)->supports_relative_mode ()) {
return true;
}
}
return false;
}
db::Shape CombinedChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double dbu, bool relative) const
{
db::Shape s = shape;
for (std::vector<ChangeApplicator *>::const_iterator a = m_appl.begin (); a != m_appl.end (); ++a) {
if (*a) {
s = (*a)->do_apply (shapes, s, dbu, relative);
}
}
return s;
}
db::Instance CombinedChangeApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double dbu, bool relative) const
{
db::Instance i = instance;
for (std::vector<ChangeApplicator *>::const_iterator a = m_appl.begin (); a != m_appl.end (); ++a) {
if (*a) {
i = (*a)->do_apply_inst (cell, i, dbu, relative);
}
}
return i;
}
// -------------------------------------------------------------------------
// ChangePropertiesApplicator implementation
ChangePropertiesApplicator::ChangePropertiesApplicator (db::properties_id_type prop_id)
: m_prop_id (prop_id)
{
// .. nothing yet ...
}
db::Shape ChangePropertiesApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
return shapes.replace_prop_id (shape, m_prop_id);
}
db::Instance ChangePropertiesApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double /*dbu*/, bool /*relative*/) const
{
return cell.replace_prop_id (instance, m_prop_id);
}
// -------------------------------------------------------------------------
// BoxDimensionsChangeApplicator implementation
BoxDimensionsChangeApplicator::BoxDimensionsChangeApplicator (db::Coord dl, db::Coord db, db::Coord dr, db::Coord dt, db::Coord l, db::Coord b, db::Coord r, db::Coord t)
: m_dl (dl), m_db (db), m_dr (dr), m_dt (dt), m_l (l), m_b (b), m_r (r), m_t (t)
{
// .. nothing yet ..
}
db::Shape BoxDimensionsChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool relative) const
{
db::Box org_box;
shape.box (org_box);
db::Box new_box;
if (relative) {
new_box = db::Box (org_box.left () + m_dl,
org_box.bottom () + m_db,
org_box.right () + m_dr,
org_box.top () + m_dt);
} else {
db::Coord l = org_box.left ();
db::Coord r = org_box.right ();
if (m_dl != 0 && m_dr == 0) {
// left side is fixed
l = m_l;
} else if (m_dl == 0 && m_dr != 0) {
// right side is fixed
r = m_r;
} else if (m_dl != 0 && m_dl == m_dr) {
// center is fixed
l = (m_l + m_r) / 2 - org_box.width () / 2;
r = (m_l + m_r) / 2 + org_box.width () / 2;
} else if (m_dl != 0 && m_dl == -m_dr) {
// width is fixed
l = org_box.center ().x () - (m_r - m_l) / 2;
r = org_box.center ().x () + (m_r - m_l) / 2;
} else if (m_dl != 0 && m_dr != 0) {
// both sides have changed
l = m_l;
r = m_r;
}
db::Coord b = org_box.bottom ();
db::Coord t = org_box.top ();
if (m_db != 0 && m_dt == 0) {
// left side is fixed
b = m_b;
} else if (m_db == 0 && m_dt != 0) {
// right side is fixed
t = m_t;
} else if (m_db != 0 && m_db == m_dt) {
// center is fixed
b = (m_b + m_t) / 2 - org_box.height () / 2;
t = (m_b + m_t) / 2 + org_box.height () / 2;
} else if (m_db != 0 && m_db == -m_dt) {
// height is fixed
b = org_box.center ().y () - (m_t - m_b) / 2;
t = org_box.center ().y () + (m_t - m_b) / 2;
} else if (m_db != 0 && m_dt != 0) {
// both sides have changed
b = m_b;
t = m_t;
}
new_box = db::Box (l, b, r, t);
}
if (new_box != org_box) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_box);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PolygonChangeApplicator implementation
PolygonChangeApplicator::PolygonChangeApplicator (const db::Polygon &poly, const db::Polygon &org_poly)
: m_poly (poly), m_org_poly (org_poly)
{
// .. nothing yet ..
}
db::Shape PolygonChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool relative) const
{
db::Polygon org_poly;
shape.polygon (org_poly);
if (relative) {
db::Polygon new_poly = m_poly.moved (org_poly.box ().p1 () - m_poly.box ().p1 ());
if (new_poly != org_poly) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_poly);
} else {
// shape did not change
return shape;
}
} else if (m_poly != org_poly) {
// shape changed - replace the old by the new one
return shapes.replace (shape, m_poly);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextOrientationChangeApplicator implementation
TextOrientationChangeApplicator::TextOrientationChangeApplicator (const db::FTrans &trans)
: ChangeApplicator (), m_trans (trans)
{
// .. nothing yet ..
}
db::Shape TextOrientationChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
new_text.trans (db::Trans (org_text.trans ().disp ()) * db::Trans (m_trans));
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextPositionChangeApplicator implementation
TextPositionChangeApplicator::TextPositionChangeApplicator (const db::Vector &disp, const db::Vector &org_disp)
: ChangeApplicator (), m_disp (disp), m_org_disp (org_disp)
{
// .. nothing yet ..
}
db::Shape TextPositionChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool relative) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
if (relative) {
new_text.trans (db::Trans (m_disp - m_org_disp) * org_text.trans ());
} else {
db::Vector np = org_text.trans ().disp ();
if (m_disp.x () != m_org_disp.x ()) {
np.set_x (m_disp.x ());
}
if (m_disp.y () != m_org_disp.y ()) {
np.set_y (m_disp.y ());
}
new_text.trans (db::Trans (np - org_text.trans ().disp ()) * org_text.trans ());
}
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextHAlignChangeApplicator implementation
TextHAlignChangeApplicator::TextHAlignChangeApplicator (db::HAlign halign)
: ChangeApplicator (), m_halign (halign)
{
// .. nothing yet ..
}
db::Shape TextHAlignChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
new_text.halign (m_halign);
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextVAlignChangeApplicator implementation
TextVAlignChangeApplicator::TextVAlignChangeApplicator (db::VAlign valign)
: ChangeApplicator (), m_valign (valign)
{
// .. nothing yet ..
}
db::Shape TextVAlignChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
new_text.valign (m_valign);
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextSizeChangeApplicator implementation
TextSizeChangeApplicator::TextSizeChangeApplicator (db::Coord size)
: ChangeApplicator (), m_size (size)
{
// .. nothing yet ..
}
db::Shape TextSizeChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
new_text.size (m_size);
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// TextStringChangeApplicatorimplementation
TextStringChangeApplicator::TextStringChangeApplicator (const std::string &string)
: ChangeApplicator (), m_string (string)
{
// .. nothing yet ..
}
db::Shape TextStringChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Text org_text;
shape.text (org_text);
db::Text new_text = org_text;
new_text.string (m_string);
if (new_text != org_text) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_text);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PathPointsChangeApplicator implementation
PathPointsChangeApplicator::PathPointsChangeApplicator (const std::vector<db::Point> &points, const std::vector<db::Point> &org_points)
: ChangeApplicator (), m_points (points), m_org_points (org_points)
{
// .. nothing yet ..
}
db::Shape PathPointsChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool relative) const
{
db::Path org_path;
shape.path (org_path);
db::Path new_path = org_path;
if (relative && ! m_org_points.empty () && new_path.begin () != new_path.end ()) {
std::vector<db::Point> new_points = m_points;
for (std::vector<db::Point>::iterator p = new_points.begin (); p != new_points.end (); ++p) {
*p += *new_path.begin () - m_org_points.front ();
}
new_path.assign (new_points.begin (), new_points.end ());
} else {
new_path.assign (m_points.begin (), m_points.end ());
}
if (new_path != org_path) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_path);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PathWidthChangeApplicator implementation
PathWidthChangeApplicator::PathWidthChangeApplicator (db::Coord w, db::Coord org_w)
: ChangeApplicator (), m_width (w), m_org_width (org_w)
{
// .. nothing yet ..
}
db::Shape PathWidthChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool relative) const
{
db::Path org_path;
shape.path (org_path);
db::Path new_path = org_path;
if (relative) {
new_path.width (new_path.width () + m_width - m_org_width);
} else {
new_path.width (m_width);
}
// Adjust extensions if equal to half width if that was the case before
if (org_path.bgn_ext () == org_path.width () / 2) {
new_path.bgn_ext (new_path.width () / 2);
}
if (org_path.end_ext () == org_path.width () / 2) {
new_path.end_ext (new_path.width () / 2);
}
if (new_path != org_path) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_path);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PathStartExtensionChangeApplicator implementation
PathStartExtensionChangeApplicator::PathStartExtensionChangeApplicator (db::Coord e)
: ChangeApplicator (), m_ext (e)
{
// .. nothing yet ..
}
db::Shape PathStartExtensionChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Path org_path;
shape.path (org_path);
db::Path new_path = org_path;
if (m_ext == std::numeric_limits <db::Coord>::min ()) {
new_path.bgn_ext (new_path.width () / 2);
} else {
new_path.bgn_ext (m_ext);
}
if (new_path != org_path) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_path);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PathEndExtensionChangeApplicator implementation
PathEndExtensionChangeApplicator::PathEndExtensionChangeApplicator (db::Coord e)
: ChangeApplicator (), m_ext (e)
{
// .. nothing yet ..
}
db::Shape PathEndExtensionChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Path org_path;
shape.path (org_path);
db::Path new_path = org_path;
if (m_ext == std::numeric_limits <db::Coord>::min ()) {
new_path.end_ext (new_path.width () / 2);
} else {
new_path.end_ext (m_ext);
}
if (new_path != org_path) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_path);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// PathRoundEndChangeApplicator implementation
PathRoundEndChangeApplicator::PathRoundEndChangeApplicator (bool r)
: ChangeApplicator (), m_round (r)
{
// .. nothing yet ..
}
db::Shape PathRoundEndChangeApplicator::do_apply (db::Shapes &shapes, const db::Shape &shape, double /*dbu*/, bool /*relative*/) const
{
db::Path org_path;
shape.path (org_path);
db::Path new_path = org_path;
new_path.round (m_round);
if (new_path != org_path) {
// shape changed - replace the old by the new one
return shapes.replace (shape, new_path);
} else {
// shape did not change
return shape;
}
}
// -------------------------------------------------------------------------
// ChangeTargetCellApplicator implementation
ChangeTargetCellApplicator::ChangeTargetCellApplicator (db::cell_index_type cell_index)
: m_cell_index (cell_index)
{
// .. nothing yet ..
}
db::Instance ChangeTargetCellApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double /*dbu*/, bool /*relative*/) const
{
tl_assert (cell.layout ());
// detect recursions in the hierarchy
std::set<db::cell_index_type> called;
cell.layout ()->cell (m_cell_index).collect_called_cells (called);
if (m_cell_index == cell.cell_index () || called.find (cell.cell_index ()) != called.end ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Trying to build a recursive hierarchy")).c_str ());
}
db::CellInstArray arr = instance.cell_inst ();
arr.object ().cell_index (m_cell_index);
return cell.replace (instance, arr);
}
// -------------------------------------------------------------------------
// ChangeInstanceTransApplicator implementation
ChangeInstanceTransApplicator::ChangeInstanceTransApplicator (double a, double org_a, bool mirror, bool org_mirror, double m, double org_m, const db::DVector &disp, const db::DVector &org_disp)
: m_angle (a), m_org_angle (org_a), m_mirror (mirror), m_org_mirror (org_mirror),
m_mag (m), m_org_mag (org_m), m_disp (disp), m_org_disp (org_disp)
{
// .. nothing yet ..
}
db::Instance ChangeInstanceTransApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double dbu, bool relative) const
{
db::CellInstArray::complex_trans_type tr = instance.complex_trans ();
if (relative) {
tr = db::CellInstArray::complex_trans_type (m_mag, m_angle, m_mirror, db::Vector (m_disp * (1.0 / dbu))) * db::CellInstArray::complex_trans_type (m_org_mag, m_org_angle, m_org_mirror, db::Vector (m_org_disp * (1.0 / dbu))).inverted () * tr;
} else {
db::Vector disp = tr.disp ();
if (fabs (m_disp.x () - m_org_disp.x ()) > 1e-6) {
disp.set_x (m_disp.x () / dbu);
}
if (fabs (m_disp.y () - m_org_disp.y ()) > 1e-6) {
disp.set_y (m_disp.y () / dbu);
}
double mag = fabs (m_mag - m_org_mag) > 1e-6 ? m_mag : tr.mag ();
double angle = fabs (m_angle - m_org_angle) > 1e-6 ? m_angle : tr.angle ();
bool mirror = (m_mirror != m_org_mirror) ? m_mirror : tr.is_mirror ();
tr = db::CellInstArray::complex_trans_type (mag, angle, mirror, disp);
}
bool is_complex = (tr.is_mag () || ! tr.is_ortho ());
db::CellInstArray new_inst;
db::CellInstArray::vector_type a, b;
unsigned long na = 0, nb = 0;
if (instance.is_regular_array (a, b, na, nb)) {
if (is_complex) {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), tr, a, b, na, nb);
} else {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), db::Trans (tr.rot (), tr.disp ()), a, b, na, nb);
}
} else {
if (is_complex) {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), tr);
} else {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), db::Trans (tr.rot (), tr.disp ()));
}
}
if (new_inst != instance.cell_inst ()) {
return cell.replace (instance, new_inst);
} else {
return instance;
}
}
// -------------------------------------------------------------------------
// ChangeInstanceArrayApplicator implementation
ChangeInstanceArrayApplicator::ChangeInstanceArrayApplicator (const db::DVector &a, bool set_a, const db::DVector &b, bool set_b, unsigned long na, bool set_na, unsigned long nb, bool set_nb)
: m_a (a), m_set_a (set_a), m_b (b), m_set_b (set_b),
m_na (na), m_set_na (set_na), m_nb (nb), m_set_nb (set_nb)
{
// .. nothing yet ..
}
db::Instance ChangeInstanceArrayApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double dbu, bool /*relative*/) const
{
db::CellInstArray new_inst;
db::CellInstArray::vector_type a, b;
unsigned long na = 0, nb = 0;
if (! instance.is_regular_array (a, b, na, nb)) {
na = nb = 1;
a = db::Vector (m_a * (1.0 / dbu));
b = db::Vector (m_b * (1.0 / dbu));
}
if (m_set_a) {
a = db::Vector (m_a * (1.0 / dbu));
}
if (m_set_na) {
na = m_na;
}
if (m_set_b) {
b = db::Vector (m_b * (1.0 / dbu));
}
if (m_set_nb) {
nb = m_nb;
}
if (instance.is_complex ()) {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), instance.complex_trans (), a, b, na, nb);
} else {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), instance.front (), a, b, na, nb);
}
if (new_inst != instance.cell_inst ()) {
return cell.replace (instance, new_inst);
} else {
return instance;
}
}
// -------------------------------------------------------------------------
// InstanceRemoveArrayApplicator implementation
InstanceRemoveArrayApplicator::InstanceRemoveArrayApplicator ()
{
// .. nothing yet ..
}
db::Instance InstanceRemoveArrayApplicator::do_apply_inst (db::Cell &cell, const db::Instance &instance, double /*dbu*/, bool /*relative*/) const
{
db::CellInstArray new_inst;
if (instance.is_complex ()) {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), instance.complex_trans ());
} else {
new_inst = db::CellInstArray (db::CellInst (instance.cell_index ()), instance.front ());
}
if (new_inst != instance.cell_inst ()) {
return cell.replace (instance, new_inst);
} else {
return instance;
}
}
// -------------------------------------------------------------------------
// helper functions to convert coordinates
std::string
coord_to_string (double dc, double dbu, bool du)
{
if (du) {
return tl::db_to_string (dc);
} else {
return tl::micron_to_string (dc * dbu);
}
}
db::DCoord
dcoord_from_dcoord (double d, double dbu, bool du, const db::DCplxTrans &t)
{
db::DCoord dc = t.ctrans (d * (du ? 1.0 : 1.0 / dbu));
return db::Coord (floor (dc + 0.5)) * dbu;
}
db::Coord
coord_from_dcoord (double d, double dbu, bool du, const db::VCplxTrans &t)
{
return t.ctrans (d * (du ? 1.0 : 1.0 / dbu));
}
db::DPoint
dpoint_from_dpoint (const db::DPoint &dp, double dbu, bool du, const db::DCplxTrans &t)
{
return (t * (dp * (du ? 1.0 : 1.0 / dbu))) * dbu;
}
db::DVector
dvector_from_dvector (const db::DVector &dp, double dbu, bool du, const db::DCplxTrans &t)
{
return (t * (dp * (du ? 1.0 : 1.0 / dbu))) * dbu;
}
db::Point
point_from_dpoint (const db::DPoint &dp, double dbu, bool du, const db::VCplxTrans &t)
{
return t * (dp * (du ? 1.0 : 1.0 / dbu));
}
db::DCoord
dcoord_from_string (const char *txt, double dbu, bool du, const db::DCplxTrans &t)
{
double d = 0.0;
tl::from_string (txt, d);
return dcoord_from_dcoord (d, dbu, du, t);
}
db::Coord
coord_from_string (const char *txt, double dbu, bool du, const db::VCplxTrans &t)
{
double d = 0.0;
tl::from_string (txt, d);
return coord_from_dcoord (d, dbu, du, t);
}
std::string
coords_to_string (const db::DPoint &dp, double dbu, bool du, const char *sep)
{
return coord_to_string (dp.x (), dbu, du) + sep + coord_to_string (dp.y (), dbu, du);
}
}