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 \
|
||||
TextPropertiesPage.ui \
|
||||
DistributeOptionsDialog.ui \
|
||||
EditorOptionsInstPCellParam.ui
|
||||
EditorOptionsInstPCellParam.ui \
|
||||
AreaAndPerimeterDialog.ui
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::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)
|
||||
{
|
||||
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;
|
||||
|
||||
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 <db::Polygon> &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*/);
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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}"))));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue