WIP: new implementation of distribute algorithm - the previous one wasn't really smart.

This commit is contained in:
Matthias Koefferlein 2020-08-08 14:11:59 +02:00
parent 28520697a3
commit 9842ff8f1b
5 changed files with 633 additions and 306 deletions

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>716</width>
<width>689</width>
<height>574</height>
</rect>
</property>
@ -23,147 +23,17 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Alignment</string>
<string>The pitch specifies the offset at which the objects are placed relative to each other. The space is the minimum distance between the objects.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="5">
<widget class="QLabel" name="label_8">
<property name="text">
<string>right</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="6">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>243</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0" colspan="2">
<widget class="QRadioButton" name="h_left_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_left.png</normaloff>:/align_left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QRadioButton" name="h_right_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_right.png</normaloff>:/align_right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="2" column="0" colspan="7">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QRadioButton" name="h_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_hcenter.png</normaloff>:/align_hcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>left</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0" colspan="7">
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
@ -264,16 +134,6 @@
</layout>
</widget>
</item>
<item row="1" column="0" colspan="7">
<widget class="QLabel" name="label_9">
<property name="text">
<string>The pitch specifies the offset at which the objects are placed relative to each other. The space is the minimum distance between the objects.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -282,7 +142,7 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
<height>0</height>
</size>
</property>
<property name="title">
@ -291,87 +151,8 @@
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="4">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>top</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QRadioButton" name="v_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_vcenter.png</normaloff>:/align_vcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="3" column="6">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>243</width>
<height>34</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="7">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="7">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
@ -472,44 +253,7 @@
</layout>
</widget>
</item>
<item row="4" column="3">
<widget class="QLabel" name="label_3">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QLabel" name="label_4">
<property name="text">
<string>bottom</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QRadioButton" name="v_bottom_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_bottom.png</normaloff>:/align_bottom.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0" colspan="7">
<item row="1" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>The pitch specifies the offset at which the objects are placed relative to each other. The space is the minimum distance between the objects.</string>
@ -519,7 +263,227 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Horizonal alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QRadioButton" name="h_none_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="h_left_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_left.png</normaloff>:/align_left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QRadioButton" name="h_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_hcenter.png</normaloff>:/align_hcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QRadioButton" name="h_right_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_right.png</normaloff>:/align_right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>245</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>none</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>left</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_8">
<property name="text">
<string>right</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Vertical alignment</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="v_none_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_none.png</normaloff>:/align_none.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="v_top_rb">
<property name="text">
<string/>
@ -536,13 +500,132 @@
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="4">
<widget class="QRadioButton" name="v_center_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_vcenter.png</normaloff>:/align_vcenter.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="5">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QRadioButton" name="v_bottom_rb">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../lay/lay/layResources.qrc">
<normaloff>:/align_bottom.png</normaloff>:/align_bottom.png</iconset>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>245</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>none</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_14">
<property name="text">
<string>top</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_15">
<property name="text">
<string>center</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="label_17">
<property name="text">
<string>bottom</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Layers for distribution of instances</string>
<string>For the computation of cell instance bounding boxes ...</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
@ -590,12 +673,6 @@
<tabstops>
<tabstop>all_layers_rb</tabstop>
<tabstop>visible_layers_rb</tabstop>
<tabstop>h_left_rb</tabstop>
<tabstop>h_center_rb</tabstop>
<tabstop>h_right_rb</tabstop>
<tabstop>v_top_rb</tabstop>
<tabstop>v_center_rb</tabstop>
<tabstop>v_bottom_rb</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>

View File

@ -343,10 +343,10 @@ DistributeOptionsDialog::~DistributeOptionsDialog ()
}
bool
DistributeOptionsDialog::exec_dialog (lay::LayoutView *view, bool &hdistribute, int &hmode, double &hpitch, double &hspace, bool &vdistribute, int &vmode, double &vpitch, double &vspace, bool &visible_layers)
DistributeOptionsDialog::exec_dialog (lay::LayoutView * /*view*/, bool &hdistribute, int &hmode, double &hpitch, double &hspace, bool &vdistribute, int &vmode, double &vpitch, double &vspace, bool &visible_layers)
{
QRadioButton *hmode_buttons [] = { (QRadioButton *) 0, this->h_left_rb, this->h_center_rb, this->h_right_rb };
QRadioButton *vmode_buttons [] = { (QRadioButton *) 0, this->v_top_rb, this->v_center_rb, this->v_bottom_rb };
QRadioButton *hmode_buttons [] = { this->h_none_rb, this->h_left_rb, this->h_center_rb, this->h_right_rb };
QRadioButton *vmode_buttons [] = { this->v_none_rb, this->v_top_rb, this->v_center_rb, this->v_bottom_rb };
QRadioButton *layers_buttons [] = { this->all_layers_rb, this->visible_layers_rb };
this->h_distribute->setChecked (hdistribute);

View File

@ -150,6 +150,7 @@ void compute_positions (int ref, typename Box::coord_type pitch, typename Box::c
if (first) {
min = b1;
max = b2;
first = false;
} else {
min = std::min (min, b1);
max = std::max (max, b1);
@ -163,9 +164,19 @@ void compute_positions (int ref, typename Box::coord_type pitch, typename Box::c
// Determines the next column/row's position as the minimum position which is compatible with
// the space constraint.
coord_type prev_bin_end = 0;
bool prev_bin_end_set = false;
for (std::vector<std::vector<size_t> >::const_iterator b = bins.begin (); b != bins.end (); ++b) {
coord_type min_pos = 1;
coord_type bin_end = prev_bin_end;
bool bin_end_set = prev_bin_end_set;
coord_type max_limit = 0;
for (typename tl::interval_map<coord_type, coord_type>::const_iterator j = limits.begin (); j != limits.end (); ++j) {
max_limit = std::max (max_limit, j->second);
}
for (std::vector<size_t>::const_iterator i = b->begin (); i != b->end (); ++i) {
@ -176,13 +187,32 @@ void compute_positions (int ref, typename Box::coord_type pitch, typename Box::c
coord_type start = box_position<Box, horizontally> (box, -1);
coord_type ref_pos = box_position<Box, horizontally> (box, ref);
coord_type end_pos = box_position<Box, horizontally> (box, 1);
bin_end = bin_end_set ? std::max (end_pos, bin_end) : end_pos;
bin_end_set = true;
if (prev_bin_end_set && db::coord_traits<coord_type>::less (start, prev_bin_end)) {
// for boxes overlapping into the previous bin try to shift them into the previous bin
for (typename tl::interval_map<coord_type, coord_type>::const_iterator j = limits.find (b1); j != limits.end () && db::coord_traits<coord_type>::less (j->first.first, b2); ++j) {
if (db::coord_traits<coord_type>::less (b1, j->first.second)) {
min_pos = std::max (min_pos, j->second + space + (ref_pos - start));
}
}
} else {
// otherwise separate the bins
min_pos = std::max (min_pos, max_limit + space + (ref_pos - start));
for (typename tl::interval_map<coord_type, coord_type>::const_iterator j = limits.find (b1); j != limits.end () && db::coord_traits<coord_type>::less (j->first.first, b2); ++j) {
min_pos = std::max (min_pos, j->second + space + (ref_pos - start));
}
}
prev_bin_end = bin_end;
prev_bin_end_set = bin_end_set;
if (pitch > 0) {
min_pos = db::coord_traits<coord_type>::rounded (ceil (double (min_pos) / double (pitch) - 1e-10) * double (pitch));
}
@ -194,16 +224,29 @@ void compute_positions (int ref, typename Box::coord_type pitch, typename Box::c
coord_type b1 = box_position<Box, ! horizontally> (box, -1);
coord_type b2 = box_position<Box, ! horizontally> (box, 1);
coord_type start = box_position<Box, horizontally> (box, -1);
coord_type ref_pos = box_position<Box, horizontally> (box, ref);
coord_type end_pos = box_position<Box, horizontally> (box, 1);
if (horizontally) {
box.move (db::vector<coord_type> (min_pos - ref_pos, 0));
} else {
box.move (db::vector<coord_type> (0, min_pos - ref_pos));
// because multiple objects may fall into one bin we need to look up again:
coord_type pos = min_pos;
for (typename tl::interval_map<coord_type, coord_type>::const_iterator j = limits.find (b1); j != limits.end () && db::coord_traits<coord_type>::less (j->first.first, b2); ++j) {
if (db::coord_traits<coord_type>::less (b1, j->first.second)) {
pos = std::max (pos, j->second + space + (ref_pos - start));
}
}
limits.add (b1, b2, min_pos + (end_pos - ref_pos), join_op);
if (pitch > 0 && ! db::coord_traits<coord_type>::equal (pos, min_pos)) {
pos = db::coord_traits<coord_type>::rounded (ceil (double (pos) / double (pitch) - 1e-10) * double (pitch));
}
if (horizontally) {
box.move (db::vector<coord_type> (pos - ref_pos, 0));
} else {
box.move (db::vector<coord_type> (0, pos - ref_pos));
}
limits.add (b1, b2, pos + (end_pos - ref_pos), join_op);
}
@ -266,24 +309,26 @@ public:
* @brief Distributes the stored objects in vertical direction only
*
* @param ref The reference location (-1: bottom, 0: center, 1: top)
* @param refp The alignment in the other (horizontal) direction (-1: left, 0: center, 1: right, other: leave as is)
* @param pitch The distribution pitch (grid) or 0 for no pitch
* @param space The minimum space between the objects
*/
void distribute_v (int ref, coord_type pitch, coord_type space)
void distribute_v (int ref, int refp, coord_type pitch, coord_type space)
{
do_distribute_1d<false> (ref, pitch, space);
do_distribute_1d<false> (ref, refp, pitch, space);
}
/**
* @brief Distributes the stored objects in horizontal direction only
*
* @param ref The reference location (-1: left, 0: center, 1: right)
* @param refp The alignment in the other (vertical) direction (-1: bottom, 0: center, 1: top, other: leave as is)
* @param pitch The distribution pitch (grid) or 0 for no pitch
* @param space The minimum space between the objects
*/
void distribute_h (int ref, coord_type pitch, coord_type space)
void distribute_h (int ref, int refp, coord_type pitch, coord_type space)
{
do_distribute_1d<true> (ref, pitch, space);
do_distribute_1d<true> (ref, refp, pitch, space);
}
/**
@ -305,8 +350,8 @@ public:
// The algorithm is this:
// 1.) Bin the boxes according to their positions in horizontal and vertical direction.
// This forms the potential columns and rows
// 2.) Compute the actual column and row positions by applying space and pitch constraints:
// horizontally first, then vertically (TODO: we could try both ways and test which one is better)
// 2.) Compute the row and column widths and heights as the maximum of their content
// 3.) position the objects inside these cells
std::vector<std::pair<Box, size_t> > indexed_boxes;
indexed_boxes.reserve (m_objects.size ());
@ -329,10 +374,134 @@ public:
std::sort (indexed_boxes.begin (), indexed_boxes.end (), box_compare<Box, size_t, false> (vref));
do_bin<Box, false> (indexed_boxes.begin (), indexed_boxes.end (), vref, vbins);
compute_positions<Box, objects, true> (href, hpitch, hspace, hbins, m_objects);
compute_positions<Box, objects, false> (vref, vpitch, vspace, vbins, m_objects);
std::vector<std::vector<std::vector<size_t> > > cells;
// Final adjustments
cells.resize (hbins.size ());
for (size_t i = 0; i < hbins.size (); ++i) {
cells [i].resize (vbins.size ());
}
{
std::vector<size_t> hbin_for_index;
hbin_for_index.resize (indexed_boxes.size (), size_t (0));
for (std::vector<std::vector<size_t> >::const_iterator i = hbins.begin (); i != hbins.end (); ++i) {
for (std::vector<size_t>::const_iterator j = i->begin (); j != i->end (); ++j) {
hbin_for_index [*j] = i - hbins.begin ();
}
}
for (std::vector<std::vector<size_t> >::const_iterator i = vbins.begin (); i != vbins.end (); ++i) {
for (std::vector<size_t>::const_iterator j = i->begin (); j != i->end (); ++j) {
cells [hbin_for_index [*j]][i - vbins.begin ()].push_back (*j);
}
}
}
std::vector<coord_type> cell_widths, cell_heights;
cell_widths.resize (hbins.size (), 0);
cell_heights.resize (vbins.size (), 0);
for (std::vector<std::vector<std::vector<size_t> > >::const_iterator i = cells.begin (); i != cells.end (); ++i) {
for (std::vector<std::vector<size_t> >::const_iterator j = i->begin (); j != i->end (); ++j) {
coord_type wcell = 0, hcell = 0;
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
coord_type w = m_objects [*k].first.width () + hspace;
if (hpitch > 0) {
w = db::coord_traits<coord_type>::rounded (ceil (double (w) / double (hpitch) - 1e-10) * double (hpitch));
}
// NOTE: intra-cell objects are distributed horizontally
wcell += w;
coord_type h = m_objects [*k].first.height () + vspace;
if (vpitch > 0) {
h = db::coord_traits<coord_type>::rounded (ceil (double (h) / double (vpitch) - 1e-10) * double (vpitch));
}
hcell = std::max (hcell, h);
}
cell_widths [i - cells.begin ()] = std::max (cell_widths [i - cells.begin ()], wcell);
cell_heights [j - i->begin ()] = std::max (cell_heights [j - i->begin ()], hcell);
}
}
std::vector<coord_type> cell_xpos, cell_ypos;
cell_xpos.reserve (cell_widths.size ());
cell_ypos.reserve (cell_heights.size ());
coord_type x = 0, y = 0;
for (typename std::vector<coord_type>::const_iterator i = cell_widths.begin (); i != cell_widths.end (); ++i) {
cell_xpos.push_back (x);
x += *i;
}
for (typename std::vector<coord_type>::const_iterator i = cell_heights.begin (); i != cell_heights.end (); ++i) {
cell_ypos.push_back (y);
y += *i;
}
for (std::vector<std::vector<std::vector<size_t> > >::const_iterator i = cells.begin (); i != cells.end (); ++i) {
for (std::vector<std::vector<size_t> >::const_iterator j = i->begin (); j != i->end (); ++j) {
coord_type wcell = 0;
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
coord_type w = m_objects [*k].first.width () + hspace;
if (hpitch > 0) {
w = db::coord_traits<coord_type>::rounded (ceil (double (w) / double (hpitch) - 1e-10) * double (hpitch));
}
// NOTE: intra-cell objects are distributed horizontally
wcell += w;
}
coord_type x = cell_xpos [i - cells.begin ()];
if (href == 0) {
x += (cell_widths [i - cells.begin ()] - wcell) / 2;
} else if (href > 0) {
x += (cell_widths [i - cells.begin ()] - wcell);
}
for (std::vector<size_t>::const_iterator k = j->begin (); k != j->end (); ++k) {
coord_type w = m_objects [*k].first.width () + hspace;
if (hpitch > 0) {
w = db::coord_traits<coord_type>::rounded (ceil (double (w) / double (hpitch) - 1e-10) * double (hpitch));
}
coord_type h = m_objects [*k].first.height () + vspace;
if (vpitch > 0) {
h = db::coord_traits<coord_type>::rounded (ceil (double (h) / double (vpitch) - 1e-10) * double (vpitch));
}
coord_type y = cell_ypos [j - i->begin ()];
if (vref == 0) {
y += (cell_heights [j - i->begin ()] - h) / 2;
} else if (href > 0) {
y += (cell_heights [j - i->begin ()] - h);
}
m_objects [*k].first.move (db::point<coord_type> (x, y) - m_objects [*k].first.p1 ());
// NOTE: intra-cell objects are distributed horizontally
x += w;
}
}
}
// Final adjustments - align the whole matrix with the original bounding box
Box new_all;
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i, ++n) {
@ -352,7 +521,7 @@ private:
objects m_objects;
template <bool horizontally>
void do_distribute_1d (int ref, coord_type pitch, coord_type space)
void do_distribute_1d (int ref, int refp, coord_type pitch, coord_type space)
{
if (m_objects.size () < 2) {
return;
@ -402,7 +571,24 @@ private:
}
for (typename objects::iterator i = m_objects.begin (); i != m_objects.end (); ++i) {
i->first.move (mv);
if (refp >= -1 && refp <= 1) {
coord_type dp = box_position<Box, ! horizontally> (all, refp) - box_position<Box, ! horizontally> (i->first, refp);
db::vector<coord_type> mvp;
if (horizontally) {
mvp = db::vector<coord_type> (0, dp);
} else {
mvp = db::vector<coord_type> (dp, 0);
}
i->first.move (mvp);
}
}
}
};

View File

@ -1869,7 +1869,7 @@ MainService::cm_distribute ()
if (! distribute_options_dialog ()->exec_dialog (view (), m_hdistribute, m_distribute_hmode, m_distribute_hpitch, m_distribute_hspace,
m_vdistribute, m_distribute_vmode, m_distribute_vpitch, m_distribute_vspace,
m_align_visible_layers)) {
m_distribute_visible_layers)) {
return;
}
@ -1925,13 +1925,16 @@ MainService::cm_distribute ()
}
int href = int (m_distribute_hmode - 2);
int vref = 2 - int (m_distribute_vmode);
if (m_hdistribute && m_vdistribute) {
placer.distribute_matrix (int (m_distribute_hmode - 2), m_distribute_hpitch, m_distribute_hspace,
2 - int (m_distribute_vmode), m_distribute_vpitch, m_distribute_vspace);
placer.distribute_matrix (href, m_distribute_hpitch, m_distribute_hspace,
vref, m_distribute_vpitch, m_distribute_vspace);
} else if (m_hdistribute) {
placer.distribute_h (int (m_distribute_hmode - 2), m_distribute_hpitch, m_distribute_hspace);
placer.distribute_h (href, vref, m_distribute_hpitch, m_distribute_hspace);
} else if (m_vdistribute) {
placer.distribute_v (2 - int (m_distribute_vmode), m_distribute_vpitch, m_distribute_vspace);
placer.distribute_v (vref, href, m_distribute_vpitch, m_distribute_vspace);
}
transformations.resize (org_boxes.size ());

View File

@ -53,27 +53,42 @@ TEST(1)
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_h (-1, 0, 100);
p.distribute_h (-1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(200,0;300,200)[0],(400,100;450,250)[3],(550,-50;600,150)[4],(700,0;800,500)[1]");
p = placer;
p.distribute_h (-1, 100, 0);
p.distribute_h (-1, -1, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(200,-100;300,100)[0],(400,-100;450,50)[3],(550,-100;600,100)[4],(700,-100;800,400)[1]");
p = placer;
p.distribute_h (-1, 0, 0, 100);
EXPECT_EQ (plc2string (p), "(0,100;100,300)[2],(200,100;300,300)[0],(400,125;450,275)[3],(550,100;600,300)[4],(700,-50;800,450)[1]");
p = placer;
p.distribute_h (-1, 1, 0, 100);
EXPECT_EQ (plc2string (p), "(0,300;100,500)[2],(200,300;300,500)[0],(400,350;450,500)[3],(550,300;600,500)[4],(700,0;800,500)[1]");
p = placer;
p.distribute_h (-1, 2, 100, 0);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(100,0;200,200)[0],(200,100;250,250)[3],(300,-50;350,150)[4],(400,0;500,500)[1]");
p = placer;
p.distribute_h (-1, 0, 0);
p.distribute_h (-1, 2, 0, 0);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(100,0;200,200)[0],(200,100;250,250)[3],(250,-50;300,150)[4],(300,0;400,500)[1]");
p = placer;
p.distribute_h (1, 0, 100);
p.distribute_h (1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(1300,-100;1400,100)[2],(1500,100;1550,250)[3],(1650,-50;1700,150)[4],(1800,0;1900,200)[0],(2000,0;2100,500)[1]");
p = placer;
p.distribute_v (-1, 0, 100);
p.distribute_v (-1, 2, 0, 100);
EXPECT_EQ (plc2string (p), "(0,-100;100,100)[2],(1050,200;1100,400)[4],(1000,500;1100,700)[0],(2000,800;2100,1300)[1],(1000,1400;1050,1550)[3]");
}
@ -96,3 +111,49 @@ TEST(2)
EXPECT_EQ (plc2string (p), "(-5,0;95,100)[0],(-5,100;95,200)[1],(95,100;195,200)[2],(95,0;195,100)[3]");
}
TEST(3)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (0, 20, 1, 23), 0);
placer.insert (db::Box (3, 8, 8, 19), 1);
placer.insert (db::Box (6, 0, 12, 5), 2);
placer.insert (db::Box (13, 1, 19, 6), 3);
placer.insert (db::Box (10, 16, 11, 17), 4);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_matrix (-1, 0, 0, -1, 0, 0);
EXPECT_EQ (plc2string (p), "(0,17;1,20)[0],(1,5;6,16)[1],(6,0;12,5)[2],(13,0;19,5)[3],(12,16;13,17)[4]");
}
TEST(4)
{
edt::distributed_placer<db::Box, size_t> placer;
placer.insert (db::Box (0, 16, 1, 20), 0);
placer.insert (db::Box (0, 8, 5, 19), 1);
placer.insert (db::Box (0, 0, 12, 5), 2);
placer.insert (db::Box (12, 1, 19, 6), 3);
placer.insert (db::Box (0, 18, 1, 19), 4);
edt::distributed_placer<db::Box, size_t> p;
p = placer;
p.distribute_matrix (-1, 0, 0, 1, 0, 0);
EXPECT_EQ (plc2string (p), "(6,9;7,13)[0],(1,9;6,20)[1],(0,4;12,9)[2],(12,4;19,9)[3],(0,9;1,10)[4]");
p = placer;
p.distribute_matrix (1, 10, 0, -1, 10, 0);
EXPECT_EQ (plc2string (p), "(-38,30;-37,34)[0],(-18,10;-13,21)[1],(-8,0;4,5)[2],(12,0;19,5)[3],(-28,30;-27,31)[4]");
p = placer;
p.distribute_matrix (1, 0, 1, 1, 0, 1);
EXPECT_EQ (plc2string (p), "(-9,16;-8,20)[0],(-7,9;-2,20)[1],(-1,3;11,8)[2],(12,3;19,8)[3],(-11,19;-10,20)[4]");
}