diff --git a/src/edt/edt/AreaAndPerimeterDialog.ui b/src/edt/edt/AreaAndPerimeterDialog.ui
new file mode 100644
index 000000000..9fd1a263a
--- /dev/null
+++ b/src/edt/edt/AreaAndPerimeterDialog.ui
@@ -0,0 +1,130 @@
+
+
+ AreaAndPerimeterDialog
+
+
+
+ 0
+ 0
+ 367
+ 205
+
+
+
+ Area And Perimeter
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 10
+ 11
+
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Area
+
+
+
+ -
+
+
+ µm
+
+
+
+ -
+
+
+ µm²
+
+
+
+ -
+
+
+ Perimeter
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Ok
+
+
+
+ -
+
+
+ Note: area and perimeter are computed in "merged mode". This means, overlapping shapes are counted once for area calculation.
+The perimeter calculation only takes true outside edges into account. Internal edges are ignored.
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 5
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ AreaAndPerimeterDialog
+ accept()
+
+
+ 303
+ 185
+
+
+ 311
+ 201
+
+
+
+
+
diff --git a/src/edt/edt/edt.pro b/src/edt/edt/edt.pro
index 24075ca3b..7680a9946 100644
--- a/src/edt/edt/edt.pro
+++ b/src/edt/edt/edt.pro
@@ -27,7 +27,8 @@ DEFINES += MAKE_EDT_LIBRARY
RoundCornerOptionsDialog.ui \
TextPropertiesPage.ui \
DistributeOptionsDialog.ui \
- EditorOptionsInstPCellParam.ui
+ EditorOptionsInstPCellParam.ui \
+ AreaAndPerimeterDialog.ui
}
diff --git a/src/edt/edt/edtDialogs.cc b/src/edt/edt/edtDialogs.cc
index 1486b2abf..498eb8e47 100644
--- a/src/edt/edt/edtDialogs.cc
+++ b/src/edt/edt/edtDialogs.cc
@@ -683,6 +683,29 @@ BEGIN_PROTECTED;
END_PROTECTED;
}
+// --------------------------------------------------------------------------------
+// AreaAndPerimeterDialog implementation
+
+AreaAndPerimeterDialog::AreaAndPerimeterDialog (QWidget *parent)
+ : QDialog (parent)
+{
+ setupUi (this);
+}
+
+AreaAndPerimeterDialog::~AreaAndPerimeterDialog ()
+{
+ // .. nothing yet ..
+}
+
+bool
+AreaAndPerimeterDialog::exec_dialog (double area, double perimeter)
+{
+ area_le->setText (tl::to_qstring (tl::sprintf ("%.12g", area)));
+ perimeter_le->setText (tl::to_qstring (tl::sprintf ("%.12g", perimeter)));
+
+ return exec () != 0;
+}
+
}
#endif
diff --git a/src/edt/edt/edtDialogs.h b/src/edt/edt/edtDialogs.h
index 5864a8d54..a108585b5 100644
--- a/src/edt/edt/edtDialogs.h
+++ b/src/edt/edt/edtDialogs.h
@@ -43,6 +43,7 @@
#include "ui_MakeCellOptionsDialog.h"
#include "ui_MakeArrayOptionsDialog.h"
#include "ui_RoundCornerOptionsDialog.h"
+#include "ui_AreaAndPerimeterDialog.h"
namespace lay
{
@@ -205,6 +206,22 @@ private:
bool m_has_extracted;
};
+/**
+ * @brief Result dialog for "area and perimeter"
+ */
+class AreaAndPerimeterDialog
+ : public QDialog,
+ private Ui::AreaAndPerimeterDialog
+{
+Q_OBJECT
+
+public:
+ AreaAndPerimeterDialog (QWidget *parent);
+ ~AreaAndPerimeterDialog ();
+
+ bool exec_dialog (double area, double perimeter);
+};
+
} // namespace edt
#endif
diff --git a/src/edt/edt/edtMainService.cc b/src/edt/edt/edtMainService.cc
index 0f97e0166..c7b51e1b9 100644
--- a/src/edt/edt/edtMainService.cc
+++ b/src/edt/edt/edtMainService.cc
@@ -25,6 +25,7 @@
#include "dbPolygonTools.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
+#include "dbRegion.h"
#include "tlExceptions.h"
#include "layLayoutView.h"
#include "laySelector.h"
@@ -82,6 +83,7 @@ MainService::MainService (db::Manager *manager, lay::LayoutViewBase *view, lay::
{
#if defined(HAVE_QT)
mp_round_corners_dialog = 0;
+ mp_area_and_perimeter_dialog = 0;
mp_align_options_dialog = 0;
mp_distribute_options_dialog = 0;
mp_flatten_inst_options_dialog = 0;
@@ -106,6 +108,15 @@ MainService::round_corners_dialog ()
return mp_round_corners_dialog;
}
+edt::AreaAndPerimeterDialog *
+MainService::area_and_perimeter_dialog ()
+{
+ if (! mp_area_and_perimeter_dialog) {
+ mp_area_and_perimeter_dialog = new edt::AreaAndPerimeterDialog (lay::widget_from_view (view ()));
+ }
+ return mp_area_and_perimeter_dialog;
+}
+
edt::AlignOptionsDialog *
MainService::align_options_dialog ()
{
@@ -168,6 +179,8 @@ MainService::menu_activated (const std::string &symbol)
cm_tap ();
} else if (symbol == "edt::sel_round_corners") {
cm_round_corners ();
+ } else if (symbol == "edt::sel_area_perimeter") {
+ cm_area_perimeter ();
} else if (symbol == "edt::sel_convert_to_pcell") {
cm_convert_to_pcell ();
} else if (symbol == "edt::sel_convert_to_cell") {
@@ -1346,6 +1359,67 @@ MainService::cm_convert_to_pcell ()
}
}
+void MainService::cm_area_perimeter ()
+{
+#if ! defined(HAVE_QT)
+ tl_assert (false); // see TODO
+#endif
+
+ double dbu = 0.0;
+
+ std::vector edt_services = view ()->get_plugins ();
+
+ db::Region region;
+
+ // get (common) cellview index of the primary selection
+ for (std::vector::const_iterator es = edt_services.begin (); es != edt_services.end (); ++es) {
+
+ for (edt::Service::obj_iterator s = (*es)->selection ().begin (); s != (*es)->selection ().end (); ++s) {
+
+ if (s->is_cell_inst ()) {
+ continue;
+ }
+
+ db::Polygon poly;
+ if (!s->shape ().polygon (poly)) {
+ continue;
+ }
+
+ double shape_dbu = view ()->cellview (s->cv_index ())->layout ().dbu ();
+
+ if (dbu == 0.0) {
+ // first CV is used for reference DBU
+ dbu = shape_dbu;
+ }
+
+ if (fabs (shape_dbu - dbu) < db::epsilon) {
+ region.insert (s->trans () * poly);
+ } else {
+ region.insert ((db::ICplxTrans (shape_dbu / dbu) * s->trans ()) * poly);
+ }
+
+ }
+
+ }
+
+#if defined(HAVE_QT)
+ if (region.count () > 100000) {
+ if (QMessageBox::warning (lay::widget_from_view (view ()), tr ("Warning: Big Selection"),
+ tr ("The selection contains many shapes. Area and perimeter computation may take a long time.\nContinue anyway?"),
+ QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
+ return;
+ }
+ }
+#endif
+
+ double area = region.area () * dbu * dbu;
+ double perimeter = region.perimeter () * dbu;
+
+#if defined(HAVE_QT)
+ area_and_perimeter_dialog ()->exec_dialog (area, perimeter);
+#endif
+}
+
static bool extract_rad (std::vector &poly, double &rinner, double &router, unsigned int &n)
{
std::vector new_pts;
@@ -1356,7 +1430,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double
db::Polygon new_poly;
new_pts.clear ();
- if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) &&
+ if (! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts) &&
! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts, true)) {
// ultimate fallback: assign original contour
new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/);
@@ -1368,7 +1442,7 @@ static bool extract_rad (std::vector &poly, double &rinner, double
for (unsigned int h = 0; h < p->holes (); ++h) {
new_pts.clear ();
- if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) &&
+ if (! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts) &&
! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts, true)) {
// ultimate fallback: assign original contour
new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/);
diff --git a/src/edt/edt/edtMainService.h b/src/edt/edt/edtMainService.h
index e6b26f98b..cc9fc2426 100644
--- a/src/edt/edt/edtMainService.h
+++ b/src/edt/edt/edtMainService.h
@@ -48,6 +48,7 @@ class Service;
class EditorOptionsPages;
class EditorOptionsPage;
class RoundCornerOptionsDialog;
+class AreaAndPerimeterDialog;
class MakeCellOptionsDialog;
class MakeArrayOptionsDialog;
class AlignOptionsDialog;
@@ -104,6 +105,11 @@ public:
*/
void cm_round_corners ();
+ /**
+ * @brief Show area and perimeter of selection
+ */
+ void cm_area_perimeter ();
+
/**
* @brief Convert selection to PCell
*/
@@ -223,6 +229,7 @@ private:
bool m_undo_before_apply;
#if defined(HAVE_QT)
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
+ edt::AreaAndPerimeterDialog *mp_area_and_perimeter_dialog;
edt::AlignOptionsDialog *mp_align_options_dialog;
edt::DistributeOptionsDialog *mp_distribute_options_dialog;
lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog;
@@ -234,6 +241,7 @@ private:
void check_no_guiding_shapes ();
#if defined(HAVE_QT)
edt::RoundCornerOptionsDialog *round_corners_dialog ();
+ edt::AreaAndPerimeterDialog *area_and_perimeter_dialog ();
edt::AlignOptionsDialog *align_options_dialog ();
edt::DistributeOptionsDialog *distribute_options_dialog ();
lay::FlattenInstOptionsDialog *flatten_inst_options_dialog ();
diff --git a/src/edt/edt/edtPlugin.cc b/src/edt/edt/edtPlugin.cc
index 8df9edfa7..f4aed23d9 100644
--- a/src/edt/edt/edtPlugin.cc
+++ b/src/edt/edt/edtPlugin.cc
@@ -342,6 +342,8 @@ public:
menu_entries.push_back (lay::menu_item ("edt::sel_make_cell_variants", "make_cell_variants:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Make Cell Variants"))));
menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_pcell", "convert_to_pcell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To PCell"))));
menu_entries.push_back (lay::menu_item ("edt::sel_convert_to_cell", "convert_to_cell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (tr ("Convert To Static Cell"))));
+ menu_entries.push_back (lay::separator ("hier_group:edit_info", "edit_menu.selection_menu.end"));
+ menu_entries.push_back (lay::menu_item ("edt::sel_area_perimeter", "area_perimeter", "edit_menu.selection_menu.end", tl::to_string (tr ("Area and Perimeter"))));
menu_entries.push_back (lay::menu_item ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end_modes", tl::to_string (tr ("Combine{Select background combination mode}"))));
}