mirror of https://github.com/KLayout/klayout.git
Added feature for computing area and perimeter from selection
This commit is contained in:
parent
2dc5c98416
commit
54833db00b
|
|
@ -0,0 +1,130 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AreaAndPerimeterDialog</class>
|
||||||
|
<widget class="QDialog" name="AreaAndPerimeterDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>367</width>
|
||||||
|
<height>205</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Area And Perimeter</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="4" column="0" colspan="3">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>10</width>
|
||||||
|
<height>11</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="perimeter_le">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Area</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>µm</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>µm²</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Perimeter</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="area_le">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0" colspan="3">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="3">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>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.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="3">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>AreaAndPerimeterDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>303</x>
|
||||||
|
<y>185</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>311</x>
|
||||||
|
<y>201</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -27,7 +27,8 @@ DEFINES += MAKE_EDT_LIBRARY
|
||||||
RoundCornerOptionsDialog.ui \
|
RoundCornerOptionsDialog.ui \
|
||||||
TextPropertiesPage.ui \
|
TextPropertiesPage.ui \
|
||||||
DistributeOptionsDialog.ui \
|
DistributeOptionsDialog.ui \
|
||||||
EditorOptionsInstPCellParam.ui
|
EditorOptionsInstPCellParam.ui \
|
||||||
|
AreaAndPerimeterDialog.ui
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -683,6 +683,29 @@ BEGIN_PROTECTED;
|
||||||
END_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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#include "ui_MakeCellOptionsDialog.h"
|
#include "ui_MakeCellOptionsDialog.h"
|
||||||
#include "ui_MakeArrayOptionsDialog.h"
|
#include "ui_MakeArrayOptionsDialog.h"
|
||||||
#include "ui_RoundCornerOptionsDialog.h"
|
#include "ui_RoundCornerOptionsDialog.h"
|
||||||
|
#include "ui_AreaAndPerimeterDialog.h"
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
@ -205,6 +206,22 @@ private:
|
||||||
bool m_has_extracted;
|
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
|
} // namespace edt
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "dbPolygonTools.h"
|
#include "dbPolygonTools.h"
|
||||||
#include "dbLibrary.h"
|
#include "dbLibrary.h"
|
||||||
#include "dbLibraryManager.h"
|
#include "dbLibraryManager.h"
|
||||||
|
#include "dbRegion.h"
|
||||||
#include "tlExceptions.h"
|
#include "tlExceptions.h"
|
||||||
#include "layLayoutView.h"
|
#include "layLayoutView.h"
|
||||||
#include "laySelector.h"
|
#include "laySelector.h"
|
||||||
|
|
@ -82,6 +83,7 @@ MainService::MainService (db::Manager *manager, lay::LayoutViewBase *view, lay::
|
||||||
{
|
{
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
mp_round_corners_dialog = 0;
|
mp_round_corners_dialog = 0;
|
||||||
|
mp_area_and_perimeter_dialog = 0;
|
||||||
mp_align_options_dialog = 0;
|
mp_align_options_dialog = 0;
|
||||||
mp_distribute_options_dialog = 0;
|
mp_distribute_options_dialog = 0;
|
||||||
mp_flatten_inst_options_dialog = 0;
|
mp_flatten_inst_options_dialog = 0;
|
||||||
|
|
@ -106,6 +108,15 @@ MainService::round_corners_dialog ()
|
||||||
return mp_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 *
|
edt::AlignOptionsDialog *
|
||||||
MainService::align_options_dialog ()
|
MainService::align_options_dialog ()
|
||||||
{
|
{
|
||||||
|
|
@ -168,6 +179,8 @@ MainService::menu_activated (const std::string &symbol)
|
||||||
cm_tap ();
|
cm_tap ();
|
||||||
} else if (symbol == "edt::sel_round_corners") {
|
} else if (symbol == "edt::sel_round_corners") {
|
||||||
cm_round_corners ();
|
cm_round_corners ();
|
||||||
|
} else if (symbol == "edt::sel_area_perimeter") {
|
||||||
|
cm_area_perimeter ();
|
||||||
} else if (symbol == "edt::sel_convert_to_pcell") {
|
} else if (symbol == "edt::sel_convert_to_pcell") {
|
||||||
cm_convert_to_pcell ();
|
cm_convert_to_pcell ();
|
||||||
} else if (symbol == "edt::sel_convert_to_cell") {
|
} 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::Service *> edt_services = view ()->get_plugins <edt::Service> ();
|
||||||
|
|
||||||
|
db::Region region;
|
||||||
|
|
||||||
|
// get (common) cellview index of the primary selection
|
||||||
|
for (std::vector<edt::Service *>::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 <db::Polygon> &poly, double &rinner, double &router, unsigned int &n)
|
static bool extract_rad (std::vector <db::Polygon> &poly, double &rinner, double &router, unsigned int &n)
|
||||||
{
|
{
|
||||||
std::vector <db::Point> new_pts;
|
std::vector <db::Point> new_pts;
|
||||||
|
|
@ -1356,7 +1430,7 @@ static bool extract_rad (std::vector <db::Polygon> &poly, double &rinner, double
|
||||||
db::Polygon new_poly;
|
db::Polygon new_poly;
|
||||||
|
|
||||||
new_pts.clear ();
|
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)) {
|
! extract_rad_from_contour (p->begin_hull (), p->end_hull (), rinner, router, n, &new_pts, true)) {
|
||||||
// ultimate fallback: assign original contour
|
// ultimate fallback: assign original contour
|
||||||
new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/);
|
new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/);
|
||||||
|
|
@ -1368,7 +1442,7 @@ static bool extract_rad (std::vector <db::Polygon> &poly, double &rinner, double
|
||||||
for (unsigned int h = 0; h < p->holes (); ++h) {
|
for (unsigned int h = 0; h < p->holes (); ++h) {
|
||||||
|
|
||||||
new_pts.clear ();
|
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)) {
|
! extract_rad_from_contour (p->begin_hole (h), p->end_hole (h), rinner, router, n, &new_pts, true)) {
|
||||||
// ultimate fallback: assign original contour
|
// ultimate fallback: assign original contour
|
||||||
new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/);
|
new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/);
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ class Service;
|
||||||
class EditorOptionsPages;
|
class EditorOptionsPages;
|
||||||
class EditorOptionsPage;
|
class EditorOptionsPage;
|
||||||
class RoundCornerOptionsDialog;
|
class RoundCornerOptionsDialog;
|
||||||
|
class AreaAndPerimeterDialog;
|
||||||
class MakeCellOptionsDialog;
|
class MakeCellOptionsDialog;
|
||||||
class MakeArrayOptionsDialog;
|
class MakeArrayOptionsDialog;
|
||||||
class AlignOptionsDialog;
|
class AlignOptionsDialog;
|
||||||
|
|
@ -104,6 +105,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void cm_round_corners ();
|
void cm_round_corners ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show area and perimeter of selection
|
||||||
|
*/
|
||||||
|
void cm_area_perimeter ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert selection to PCell
|
* @brief Convert selection to PCell
|
||||||
*/
|
*/
|
||||||
|
|
@ -223,6 +229,7 @@ private:
|
||||||
bool m_undo_before_apply;
|
bool m_undo_before_apply;
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
|
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
|
||||||
|
edt::AreaAndPerimeterDialog *mp_area_and_perimeter_dialog;
|
||||||
edt::AlignOptionsDialog *mp_align_options_dialog;
|
edt::AlignOptionsDialog *mp_align_options_dialog;
|
||||||
edt::DistributeOptionsDialog *mp_distribute_options_dialog;
|
edt::DistributeOptionsDialog *mp_distribute_options_dialog;
|
||||||
lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog;
|
lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog;
|
||||||
|
|
@ -234,6 +241,7 @@ private:
|
||||||
void check_no_guiding_shapes ();
|
void check_no_guiding_shapes ();
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
edt::RoundCornerOptionsDialog *round_corners_dialog ();
|
edt::RoundCornerOptionsDialog *round_corners_dialog ();
|
||||||
|
edt::AreaAndPerimeterDialog *area_and_perimeter_dialog ();
|
||||||
edt::AlignOptionsDialog *align_options_dialog ();
|
edt::AlignOptionsDialog *align_options_dialog ();
|
||||||
edt::DistributeOptionsDialog *distribute_options_dialog ();
|
edt::DistributeOptionsDialog *distribute_options_dialog ();
|
||||||
lay::FlattenInstOptionsDialog *flatten_inst_options_dialog ();
|
lay::FlattenInstOptionsDialog *flatten_inst_options_dialog ();
|
||||||
|
|
|
||||||
|
|
@ -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_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_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::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}"))));
|
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}"))));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue