Second fix for issue #306 (round function problem)

This fix adds a "amend" option to the rounded corners
dialog - disabling this option allows to skip the "undo rounding"
step in case the algorithm does not determine the rounding
properties of the input properly.

Without "amend" enabled, the rounding will always be
applied atop of any existing rounding.
This commit is contained in:
Matthias Koefferlein 2019-08-18 17:25:28 +02:00
parent 8981ed434a
commit 2cc6909d2c
5 changed files with 216 additions and 93 deletions

View File

@ -1,70 +1,78 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RoundCornerOptionsDialog</class>
<widget class="QDialog" name="RoundCornerOptionsDialog" >
<property name="geometry" >
<widget class="QDialog" name="RoundCornerOptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>241</height>
<height>271</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="2" column="1" >
<widget class="QLineEdit" name="router_le" />
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Outer corner radius</string>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="3">
<widget class="QCheckBox" name="amend_cb">
<property name="text">
<string>Amend mode (undo existing rounding before applying new one)</string>
</property>
</widget>
</item>
<item row="5" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<item row="7" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Number of points (for full circle)</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Inner corner radius</string>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="rinner_le" />
<item row="5" column="1">
<widget class="QLineEdit" name="rinner_le"/>
</item>
<item row="5" column="1" >
<widget class="QLineEdit" name="points_le" />
<item row="4" column="1">
<widget class="QLineEdit" name="router_le"/>
</item>
<item row="4" column="0" colspan="3" >
<widget class="Line" name="line" >
<property name="orientation" >
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Outer corner radius</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="points_le"/>
</item>
<item row="6" column="0" colspan="3">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Radius to apply on polygon corners
(Radius for inner corners can be specified separately.
Leave empty to get the same radius than for outer corners)</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3" >
<spacer name="verticalSpacer" >
<property name="orientation" >
<item row="8" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>448</width>
<height>11</height>
@ -72,29 +80,29 @@ Leave empty to get the same radius than for outer corners)</string>
</property>
</spacer>
</item>
<item row="2" column="2" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<item row="4" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<item row="5" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>micron</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3" >
<spacer name="verticalSpacer_2" >
<property name="orientation" >
<item row="3" column="0" colspan="3">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0" >
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
@ -102,28 +110,33 @@ Leave empty to get the same radius than for outer corners)</string>
</property>
</spacer>
</item>
<item row="7" column="0" colspan="3" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<item row="9" column="0" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<spacer name="verticalSpacer_3">
<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>
<zorder>router_le</zorder>
<zorder>label</zorder>
<zorder>label_2</zorder>
<zorder>label_3</zorder>
<zorder>rinner_le</zorder>
<zorder>points_le</zorder>
<zorder>line</zorder>
<zorder>label_4</zorder>
<zorder>label_5</zorder>
<zorder>label_6</zorder>
<zorder>buttonBox</zorder>
</widget>
<resources/>
<connections>
@ -133,11 +146,11 @@ Leave empty to get the same radius than for outer corners)</string>
<receiver>RoundCornerOptionsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
@ -149,11 +162,11 @@ Leave empty to get the same radius than for outer corners)</string>
<receiver>RoundCornerOptionsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>

View File

@ -414,11 +414,13 @@ MakeCellOptionsDialog::button_clicked ()
// RoundCornerOptionsDialog implementation
RoundCornerOptionsDialog::RoundCornerOptionsDialog (QWidget *parent)
: QDialog (parent), mp_layout (0)
: QDialog (parent), mp_layout (0), m_router_extracted (0.0), m_rinner_extracted (0.0), m_npoints_extracted (64), m_has_extracted (false)
{
setObjectName (QString::fromUtf8 ("round_corners_options_dialog"));
Ui::RoundCornerOptionsDialog::setupUi (this);
connect (amend_cb, SIGNAL (stateChanged (int)), this, SLOT (amend_changed ()));
}
RoundCornerOptionsDialog::~RoundCornerOptionsDialog ()
@ -426,21 +428,51 @@ RoundCornerOptionsDialog::~RoundCornerOptionsDialog ()
// .. nothing yet ..
}
bool
RoundCornerOptionsDialog::exec_dialog (const db::Layout &layout, double &router, double &rinner, unsigned int &npoints)
void
RoundCornerOptionsDialog::amend_changed ()
{
if (amend_cb->isChecked () && m_has_extracted) {
router_le->setText (tl::to_qstring (tl::to_string (m_router_extracted)));
if (db::coord_traits<double>::equal (m_router_extracted, m_rinner_extracted)) {
rinner_le->setText (QString ());
} else {
rinner_le->setText (tl::to_qstring (tl::to_string (m_rinner_extracted)));
}
points_le->setText (tl::to_qstring (tl::to_string (m_npoints_extracted)));
}
}
bool
RoundCornerOptionsDialog::exec_dialog (const db::Layout &layout, double &router, double &rinner, unsigned int &npoints, bool &undo_before_apply, double router_extracted, double rinner_extracted, unsigned int npoints_extracted, bool has_extracted)
{
m_router_extracted = router_extracted;
m_rinner_extracted = rinner_extracted;
m_npoints_extracted = npoints_extracted;
m_has_extracted = has_extracted;
amend_cb->blockSignals (true);
amend_cb->setEnabled (has_extracted);
amend_cb->setChecked (undo_before_apply && has_extracted);
amend_cb->blockSignals (false);
mp_layout = &layout;
router_le->setText (tl::to_qstring (tl::to_string (router)));
if (fabs (router - rinner) < 1e-6) {
double ro = undo_before_apply && has_extracted ? router_extracted : router;
double ri = undo_before_apply && has_extracted ? rinner_extracted : rinner;
unsigned int n = undo_before_apply && has_extracted ? npoints_extracted : npoints;
router_le->setText (tl::to_qstring (tl::to_string (ro)));
if (db::coord_traits<double>::equal (ro, ri)) {
rinner_le->setText (QString ());
} else {
rinner_le->setText (tl::to_qstring (tl::to_string (rinner)));
rinner_le->setText (tl::to_qstring (tl::to_string (ri)));
}
points_le->setText (tl::to_qstring (tl::to_string (npoints)));
points_le->setText (tl::to_qstring (tl::to_string (n)));
if (QDialog::exec ()) {
undo_before_apply = m_has_extracted && amend_cb->isChecked ();
tl::from_string (tl::to_string (router_le->text ()), router);
if (rinner_le->text ().isEmpty ()) {
rinner = router;

View File

@ -173,12 +173,18 @@ public:
RoundCornerOptionsDialog (QWidget *parent);
~RoundCornerOptionsDialog ();
bool exec_dialog (const db::Layout &layout, double &rhull, double &rholes, unsigned int &npoints);
bool exec_dialog (const db::Layout &layout, double &router, double &rinner, unsigned int &npoints, bool &undo_before_apply, double router_extracted, double rinner_extracted, unsigned int npoints_extracted, bool has_extracted);
virtual void accept ();
private slots:
void amend_changed ();
private:
const db::Layout *mp_layout;
double m_router_extracted, m_rinner_extracted;
unsigned int m_npoints_extracted;
bool m_has_extracted;
};
} // namespace edt

View File

@ -60,7 +60,13 @@ MainService::MainService (db::Manager *manager, lay::LayoutView *view, lay::Plug
m_align_hmode (0), m_align_vmode (0), m_align_visible_layers (false),
m_origin_mode_x (-1), m_origin_mode_y (-1), m_origin_visible_layers_for_bbox (false),
m_array_a (0.0, 1.0), m_array_b (1.0, 0.0),
m_array_na (1), m_array_nb (1)
m_array_na (1), m_array_nb (1),
m_router (0.0), m_rinner (0.0), m_npoints (64), m_undo_before_apply (true),
mp_round_corners_dialog (0),
mp_align_options_dialog (0),
mp_flatten_inst_options_dialog (0),
mp_make_cell_options_dialog (0),
mp_make_array_options_dialog (0)
{
// .. nothing yet ..
}
@ -70,7 +76,52 @@ MainService::~MainService ()
// .. nothing yet ..
}
void
edt::RoundCornerOptionsDialog *
MainService::round_corners_dialog ()
{
if (! mp_round_corners_dialog) {
mp_round_corners_dialog = new edt::RoundCornerOptionsDialog (view ());
}
return mp_round_corners_dialog;
}
edt::AlignOptionsDialog *
MainService::align_options_dialog ()
{
if (! mp_align_options_dialog) {
mp_align_options_dialog = new edt::AlignOptionsDialog (view ());
}
return mp_align_options_dialog;
}
lay::FlattenInstOptionsDialog *
MainService::flatten_inst_options_dialog ()
{
if (! mp_flatten_inst_options_dialog) {
mp_flatten_inst_options_dialog = new lay::FlattenInstOptionsDialog (view (), false /*don't allow prunining*/);
}
return mp_flatten_inst_options_dialog;
}
edt::MakeCellOptionsDialog *
MainService::make_cell_options_dialog ()
{
if (! mp_make_cell_options_dialog) {
mp_make_cell_options_dialog = new edt::MakeCellOptionsDialog (view ());
}
return mp_make_cell_options_dialog;
}
edt::MakeArrayOptionsDialog *
MainService::make_array_options_dialog ()
{
if (! mp_make_array_options_dialog) {
mp_make_array_options_dialog = new edt::MakeArrayOptionsDialog (view ());
}
return mp_make_array_options_dialog;
}
void
MainService::menu_activated (const std::string &symbol)
{
if (symbol == "edt::descend") {
@ -318,9 +369,7 @@ MainService::cm_flatten_insts ()
tl_assert (view ()->is_editable ());
check_no_guiding_shapes ();
lay::FlattenInstOptionsDialog options_dialog (view (), false /*don't allow prunining*/);
if (options_dialog.exec_dialog (m_flatten_insts_levels, m_flatten_prune) && m_flatten_insts_levels != 0) {
if (flatten_inst_options_dialog ()->exec_dialog (m_flatten_insts_levels, m_flatten_prune) && m_flatten_insts_levels != 0) {
view ()->cancel_edits ();
@ -908,11 +957,9 @@ MainService::cm_make_cell ()
if (cv_index >= 0) {
MakeCellOptionsDialog dialog (view ());
const lay::CellView &cv = view ()->cellview (cv_index);
if (dialog.exec_dialog (cv->layout (), m_make_cell_name, m_origin_mode_x, m_origin_mode_y)) {
if (make_cell_options_dialog ()->exec_dialog (cv->layout (), m_make_cell_name, m_origin_mode_x, m_origin_mode_y)) {
// Compute the selection's bbox to establish a good origin for the new cell
db::Box selection_bbox;
@ -1231,9 +1278,10 @@ MainService::cm_convert_to_pcell ()
}
}
static void 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;
bool any_extracted = false;
for (std::vector<db::Polygon>::iterator p = poly.begin (); p != poly.end (); ++p) {
@ -1246,6 +1294,7 @@ static void extract_rad (std::vector <db::Polygon> &poly, double &rinner, double
new_poly.assign_hull (p->begin_hull (), p->end_hull (), false /*don't compress*/);
} else {
new_poly.assign_hull (new_pts.begin (), new_pts.end (), true /*compress*/);
any_extracted = true;
}
for (unsigned int h = 0; h < p->holes (); ++h) {
@ -1257,13 +1306,16 @@ static void extract_rad (std::vector <db::Polygon> &poly, double &rinner, double
new_poly.insert_hole (p->begin_hole (h), p->end_hole (h), false /*don't compress*/);
} else {
new_poly.insert_hole (new_pts.begin (), new_pts.end (), true /*compress*/);
any_extracted = true;
}
}
p->swap (new_poly);
}
}
return any_extracted;
}
void
@ -1310,15 +1362,17 @@ MainService::cm_round_corners ()
// prepare: merge to remove cutlines and smooth to remove effects of cutlines
db::EdgeProcessor ep;
std::vector <db::Polygon> out;
ep.merge (primary, out, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/);
for (std::vector <db::Polygon>::iterator p = out.begin (); p != out.end (); ++p) {
std::vector <db::Polygon> in;
ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/);
for (std::vector <db::Polygon>::iterator p = in.begin (); p != in.end (); ++p) {
*p = smooth (*p, 1);
}
std::vector <db::Polygon> out = in;
unsigned int n = 100;
double rinner = 0.0, router = 0.0;
extract_rad (out, rinner, router, n);
bool has_extracted = extract_rad (out, rinner, router, n);
const lay::CellView &cv = view ()->cellview (cv_index);
double dbu = cv->layout ().dbu ();
@ -1326,13 +1380,16 @@ MainService::cm_round_corners ()
rinner *= dbu;
router *= dbu;
RoundCornerOptionsDialog dialog (view ());
if (! dialog.exec_dialog (cv->layout (), router, rinner, n)) {
if (! round_corners_dialog ()->exec_dialog (cv->layout (), m_router, m_rinner, m_npoints, m_undo_before_apply, router, rinner, n, has_extracted)) {
return;
}
if (! m_undo_before_apply || ! has_extracted) {
out.swap (in);
}
for (std::vector <db::Polygon>::iterator p = out.begin (); p != out.end (); ++p) {
*p = compute_rounded (*p, rinner / dbu, router / dbu, n);
*p = compute_rounded (*p, m_rinner / dbu, m_router / dbu, m_npoints);
}
// remove holes (result in primary)
@ -1700,8 +1757,7 @@ MainService::cm_align ()
std::vector<edt::Service *> edt_services = view ()->get_plugins <edt::Service> ();
AlignOptionsDialog dialog (view ());
if (! dialog.exec_dialog (view (), m_align_hmode, m_align_vmode, m_align_visible_layers)) {
if (! align_options_dialog ()->exec_dialog (view (), m_align_hmode, m_align_vmode, m_align_visible_layers)) {
return;
}
@ -1797,9 +1853,7 @@ MainService::cm_make_array ()
throw tl::Exception (tl::to_string (QObject::tr ("Nothing selected to make arrays of")));
}
MakeArrayOptionsDialog dialog (view ());
if (dialog.exec_dialog (m_array_a, m_array_na, m_array_b, m_array_nb)) {
if (make_array_options_dialog ()->exec_dialog (m_array_a, m_array_na, m_array_b, m_array_nb)) {
view ()->cancel_edits ();

View File

@ -39,6 +39,7 @@
namespace lay {
class PluginRoot;
class FlattenInstOptionsDialog;
}
namespace edt {
@ -46,6 +47,10 @@ namespace edt {
class Service;
class EditorOptionsPages;
class EditorOptionsPage;
class RoundCornerOptionsDialog;
class MakeCellOptionsDialog;
class MakeArrayOptionsDialog;
class AlignOptionsDialog;
// -------------------------------------------------------------
@ -205,9 +210,22 @@ private:
bool m_origin_visible_layers_for_bbox;
db::DVector m_array_a, m_array_b;
unsigned int m_array_na, m_array_nb;
double m_router, m_rinner;
unsigned int m_npoints;
bool m_undo_before_apply;
edt::RoundCornerOptionsDialog *mp_round_corners_dialog;
edt::AlignOptionsDialog *mp_align_options_dialog;
lay::FlattenInstOptionsDialog *mp_flatten_inst_options_dialog;
edt::MakeCellOptionsDialog *mp_make_cell_options_dialog;
edt::MakeArrayOptionsDialog *mp_make_array_options_dialog;
void boolean_op (int mode);
void check_no_guiding_shapes ();
edt::RoundCornerOptionsDialog *round_corners_dialog ();
edt::AlignOptionsDialog *align_options_dialog ();
lay::FlattenInstOptionsDialog *flatten_inst_options_dialog ();
edt::MakeCellOptionsDialog *make_cell_options_dialog ();
edt::MakeArrayOptionsDialog *make_array_options_dialog ();
};
}