Sketcher: Code improvements for Constraint Widget

=================================================

This PR does not have added functionality. It contains only code improvements requiring at least c++17.

- It uses for the filters scoped enums (enum classes) instead of unscoped enums to avoid implicit conversion (c++11).
- It includes tools to deal with the necessary explicit conversions including type_t traits (c++14).
- It uses a couple of generic lambdas (c++17)
- It uses folding expressions to expand parameter packs (c++17)
- Refactoring of code
This commit is contained in:
Abdullah Tahiri
2021-10-12 10:54:34 +02:00
committed by abdullahtahiriyo
parent 90c97a3166
commit 925e115c93
5 changed files with 136 additions and 98 deletions

View File

@@ -30,7 +30,13 @@ namespace SketcherGui {
namespace ConstraintFilter {
enum FilterValue {
// FilterValue and SpecialFilterValue are the filters used for Constraint Filtering in the Constraint's Widget.
// FilterValue includes the filters used for the Multi-Filter dialog (SpecialFilterValue is not part of the multi-filter).
//
// The values are hardcoded to be the same as the indices in the combobox and viewlist. Addition of an element here requires
// the addition of the corresponding entry there and vice versa.
enum class FilterValue {
All = 0,
Geometric = 1,
Datums = 2,
@@ -55,48 +61,87 @@ namespace ConstraintFilter {
Angle = 21,
SnellsLaw = 22,
InternalAlignment = 23,
NumFilterValue
NumFilterValue // SpecialFilterValue shall start at the same index as this
};
enum SpecialFilterValue {
Multiple = 24,
Selection = 25,
AssociatedConstraints = 26,
constexpr auto FilterValueLength = static_cast<std::underlying_type_t<FilterValue>>(FilterValue::NumFilterValue);
enum class SpecialFilterValue {
Multiple = FilterValueLength, // = 24
Selection, // = 25
AssociatedConstraints, // = 26
NumSpecialFilterValue
};
constexpr std::array< std::bitset<FilterValue::NumFilterValue>, FilterValue::NumFilterValue> filterAggregates {
1 << FilterValue::All | 1 << FilterValue::Geometric | 1 << FilterValue::Datums | 1 << FilterValue::Named | 1 << FilterValue::NonDriving |
1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident | 1 << FilterValue::PointOnObject |
1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent | 1 << FilterValue::Equality |
1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance |
1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter |
1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw | 1 << FilterValue::InternalAlignment, // All = All other groups are covered (0)
1 << FilterValue::Geometric | 1 << FilterValue::Horizontal | 1 << FilterValue::Vertical | 1 << FilterValue::Coincident |
1 << FilterValue::PointOnObject | 1 << FilterValue::Parallel | 1 << FilterValue::Perpendicular | 1 << FilterValue::Tangent |
1 << FilterValue::Equality | 1 << FilterValue::Symmetric | 1 << FilterValue::Block | 1 << FilterValue::InternalAlignment, // Geometric = All others not being datums (1)
1 << FilterValue::Datums | 1 << FilterValue::Distance | 1 << FilterValue::HorizontalDistance | 1 << FilterValue::VerticalDistance | 1 << FilterValue::Radius | 1 << FilterValue::Weight | 1 << FilterValue::Diameter | 1 << FilterValue::Angle | 1 << FilterValue::SnellsLaw, // Datum = all others not being geometric (2)
1 << FilterValue::Named, // Named = Just this (3)
1 << FilterValue::NonDriving, // NonDriving = Just this (4)
1 << FilterValue::Coincident, // Coincident = Just this (5)
1 << FilterValue::PointOnObject, // PointOnObject = Just this (6)
1 << FilterValue::Vertical, // Vertical = Just this (7)
1 << FilterValue::Horizontal, // Horizontal = Just this (8)
1 << FilterValue::Parallel, // Parallel = Just this (9)
1 << FilterValue::Perpendicular, // Perpendicular = Just this (10)
1 << FilterValue::Tangent, // Tangent = Just this (11)
1 << FilterValue::Equality, // Equality = Just this (12)
1 << FilterValue::Symmetric, // Symmetric = Just this (13)
1 << FilterValue::Block, // Block = Just this (14)
1 << FilterValue::HorizontalDistance, // HorizontalDistance = Just this (15)
1 << FilterValue::VerticalDistance, // VerticalDistance = Just this (16)
1 << FilterValue::Distance, // Distance = Just this (17)
1 << FilterValue::Radius, // Radius = Just this (18)
1 << FilterValue::Weight, // Weight = Just this (19)
1 << FilterValue::Diameter, // Diameter = Just this (20)
1 << FilterValue::Angle, // Angle = Just this (21)
1 << FilterValue::SnellsLaw, // SnellsLaw = Just this (22)
1 << FilterValue::InternalAlignment, // InternalAlignment = Just this (23)
constexpr auto SpecialFilterValue = static_cast<std::underlying_type_t<FilterValue>>(SpecialFilterValue::NumSpecialFilterValue);
/// A std::bitset sized to provide one bit per FilterValue value
using FilterValueBitset = std::bitset<FilterValueLength>;
/// Helper function to retrieve the underlying integral type of a filter value
template <typename T>
inline auto getFilterIntegral(T filterValue) {
return static_cast<std::underlying_type_t<T>>(filterValue);
}
/// Helper function to test whether a provided integral value corresponds to the provided filter value
template <typename T>
inline bool isFilterMatch(T filterValue, std::underlying_type_t<T> integralTypeValue) {
auto underlyingFilterValue = static_cast<std::underlying_type_t<T>>(filterValue);
return (underlyingFilterValue == integralTypeValue);
}
/// Helper function to test whether a FilterValue value is set in a FilterValueBitset
inline bool checkFilterBitset(FilterValueBitset set, FilterValue filter)
{
auto underlyingFilterValue = static_cast<std::underlying_type_t<FilterValue>>(filter);
return set[underlyingFilterValue];
}
/// Helper function expanding a parameter pack value of enum classes to create a integral underlying type having
/// the bits corresponding to the parameter pack set
template<typename... Args>
constexpr decltype(auto) buildBitset(Args... args) {
return (... | (1 << static_cast<std::underlying_type_t<Args>>(args)));
}
/// Array of FilterValue bit sets of size the the number of FilterValues indicating for each FilterValue, which other
/// FilterValues are comprised therein. It defines the dependencies between filters.
constexpr std::array< FilterValueBitset, FilterValueLength> filterAggregates {
buildBitset(FilterValue::All, FilterValue::Geometric, FilterValue::Datums, FilterValue::Named, FilterValue::NonDriving, FilterValue::Horizontal,
FilterValue::Vertical, FilterValue::Coincident, FilterValue::PointOnObject, FilterValue::Parallel, FilterValue::Perpendicular,
FilterValue::Tangent, FilterValue::Equality, FilterValue::Symmetric, FilterValue::Block, FilterValue::Distance,
FilterValue::HorizontalDistance, FilterValue::VerticalDistance, FilterValue::Radius, FilterValue::Weight, FilterValue::Diameter,
FilterValue::Angle, FilterValue::SnellsLaw, FilterValue::InternalAlignment), // All = All other groups are covered (0)
buildBitset(FilterValue::Geometric, FilterValue::Horizontal, FilterValue::Vertical, FilterValue::Coincident, FilterValue::PointOnObject,
FilterValue::Parallel, FilterValue::Perpendicular, FilterValue::Tangent, FilterValue::Equality, FilterValue::Symmetric,
FilterValue::Block, FilterValue::InternalAlignment), // Geometric = All others not being datums (1)
buildBitset(FilterValue::Datums, FilterValue::Distance, FilterValue::HorizontalDistance, FilterValue::VerticalDistance, FilterValue::Radius,
FilterValue::Weight, FilterValue::Diameter, FilterValue::Angle, FilterValue::SnellsLaw), // Datum = all others not being geometric (2)
buildBitset(FilterValue::Named), // Named = Just this (3)
buildBitset(FilterValue::NonDriving), // NonDriving = Just this (4)
buildBitset(FilterValue::Coincident), // Coincident = Just this (5)
buildBitset(FilterValue::PointOnObject), // PointOnObject = Just this (6)
buildBitset(FilterValue::Vertical), // Vertical = Just this (7)
buildBitset(FilterValue::Horizontal), // Horizontal = Just this (8)
buildBitset(FilterValue::Parallel), // Parallel = Just this (9)
buildBitset(FilterValue::Perpendicular), // Perpendicular = Just this (10)
buildBitset(FilterValue::Tangent), // Tangent = Just this (11)
buildBitset(FilterValue::Equality), // Equality = Just this (12)
buildBitset(FilterValue::Symmetric), // Symmetric = Just this (13)
buildBitset(FilterValue::Block), // Block = Just this (14)
buildBitset(FilterValue::HorizontalDistance), // HorizontalDistance = Just this (15)
buildBitset(FilterValue::VerticalDistance), // VerticalDistance = Just this (16)
buildBitset(FilterValue::Distance), // Distance = Just this (17)
buildBitset(FilterValue::Radius), // Radius = Just this (18)
buildBitset(FilterValue::Weight), // Weight = Just this (19)
buildBitset(FilterValue::Diameter), // Diameter = Just this (20)
buildBitset(FilterValue::Angle), // Angle = Just this (21)
buildBitset(FilterValue::SnellsLaw), // SnellsLaw = Just this (22)
buildBitset(FilterValue::InternalAlignment) // InternalAlignment = Just this (23)
};
}

View File

@@ -60,7 +60,7 @@ ConstraintMultiFilterDialog::~ConstraintMultiFilterDialog()
{
}
void ConstraintMultiFilterDialog::setMultiFilter(const std::bitset<FilterValue::NumFilterValue> & bitset)
void ConstraintMultiFilterDialog::setMultiFilter(const FilterValueBitset & bitset)
{
ui->listMultiFilter->blockSignals(true);
for(int i = 0; i < ui->listMultiFilter->count(); i++) {
@@ -74,9 +74,9 @@ void ConstraintMultiFilterDialog::setMultiFilter(const std::bitset<FilterValue::
ui->listMultiFilter->blockSignals(false);
}
std::bitset<FilterValue::NumFilterValue> ConstraintMultiFilterDialog::getMultiFilter()
FilterValueBitset ConstraintMultiFilterDialog::getMultiFilter()
{
std::bitset<FilterValue::NumFilterValue> tmpBitset;
FilterValueBitset tmpBitset;
for(int i = 0; i < ui->listMultiFilter->count(); i++) {
QListWidgetItem* item = ui->listMultiFilter->item(i);
@@ -116,7 +116,7 @@ void ConstraintMultiFilterDialog::on_listMultiFilter_itemChanged(QListWidgetItem
if(filterAggregates[i][filterindex]) { // only for groups comprising the changed filter
bool mustBeChecked = true;
for(int j = 0; j < FilterValue::NumFilterValue; j++) {
for(int j = 0; j < FilterValueLength; j++) {
if (i == j)
continue;

View File

@@ -40,8 +40,8 @@ public:
ConstraintMultiFilterDialog(void);
~ConstraintMultiFilterDialog();
void setMultiFilter(const std::bitset<FilterValue::NumFilterValue> & bitset);
std::bitset<FilterValue::NumFilterValue> getMultiFilter();
void setMultiFilter(const FilterValueBitset & bitset);
FilterValueBitset getMultiFilter();
public Q_SLOTS:
void on_listMultiFilter_itemChanged(QListWidgetItem * item);

View File

@@ -811,8 +811,8 @@ void TaskSketcherConstrains::on_multipleFilterButton_clicked(bool)
int filterindex = ui->comboBoxFilter->currentIndex();
if(filterindex != ConstraintFilter::SpecialFilterValue::Multiple) {
ui->comboBoxFilter->setCurrentIndex(ConstraintFilter::SpecialFilterValue::Multiple); // Change filter to multi filter selection
if(!isFilterMatch(ConstraintFilter::SpecialFilterValue::Multiple, filterindex)) {
ui->comboBoxFilter->setCurrentIndex(getFilterIntegral(ConstraintFilter::SpecialFilterValue::Multiple)); // Change filter to multi filter selection
}
mf.setMultiFilter(multiFilterStatus);
@@ -1048,10 +1048,10 @@ void TaskSketcherConstrains::on_comboBoxFilter_currentIndexChanged(int filterind
selectionFilter.clear(); // reset the stored selection filter
associatedConstraintsFilter.clear();
if(filterindex == ConstraintFilter::SpecialFilterValue::Selection) {
if(isFilterMatch(ConstraintFilter::SpecialFilterValue::Selection, filterindex)) {
updateSelectionFilter();
}
else if(filterindex == ConstraintFilter::SpecialFilterValue::AssociatedConstraints) {
else if(isFilterMatch(ConstraintFilter::SpecialFilterValue::AssociatedConstraints, filterindex)) {
updateAssociatedConstraintsFilter();
}
@@ -1312,103 +1312,96 @@ bool TaskSketcherConstrains::isConstraintFiltered(QListWidgetItem * item)
int Filter = ui->comboBoxFilter->currentIndex();
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
bool hideInternalAlignment = hGrp->GetBool("HideInternalAlignment",false);
bool visible = true;
bool showAll = (Filter == FilterValue::All);
bool showGeometric = (Filter == FilterValue::Geometric);
bool showDatums = (Filter == FilterValue::Datums && constraint->isDriving);
bool showNamed = (Filter == FilterValue::Named && !(constraint->Name.empty()));
bool showNonDriving = (Filter == FilterValue::NonDriving && !constraint->isDriving);
bool showAll = isFilterMatch(FilterValue::All, Filter);
bool showGeometric = isFilterMatch(FilterValue::Geometric, Filter);
bool showDatums = (isFilterMatch(FilterValue::Datums, Filter) && constraint->isDriving);
bool showNamed = (isFilterMatch(FilterValue::Named, Filter) && !(constraint->Name.empty()));
bool showNonDriving = (isFilterMatch(FilterValue::NonDriving, Filter) && !constraint->isDriving);
auto geometricVisible = [showAll, showGeometric, showNamed, Filter, this](FilterValue filtervalue) {
return showAll || showGeometric || showNamed || isFilterMatch(filtervalue, Filter) ||
(isFilterMatch(SpecialFilterValue::Multiple, Filter) && checkFilterBitset(multiFilterStatus, filtervalue));
};
auto datumVisible = [showAll, showDatums, showNamed, showNonDriving, Filter, this](FilterValue filtervalue) {
return showAll || showDatums || showNamed || showNonDriving || isFilterMatch(filtervalue, Filter) ||
(isFilterMatch(SpecialFilterValue::Multiple, Filter) && checkFilterBitset(multiFilterStatus, filtervalue));
};
switch(constraint->Type) {
case Sketcher::Horizontal:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Horizontal) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Horizontal]);
visible = geometricVisible(FilterValue::Horizontal);
break;
case Sketcher::Vertical:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Vertical) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Vertical]);
visible = geometricVisible(FilterValue::Vertical);
break;
case Sketcher::Coincident:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Coincident) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Coincident]);
visible = geometricVisible(FilterValue::Coincident);
break;
case Sketcher::PointOnObject:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::PointOnObject) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::PointOnObject]);
visible = geometricVisible(FilterValue::PointOnObject);
break;
case Sketcher::Parallel:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Parallel) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Parallel]);
visible = geometricVisible(FilterValue::Parallel);
break;
case Sketcher::Perpendicular:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Perpendicular) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Perpendicular]);
visible = geometricVisible(FilterValue::Perpendicular);
break;
case Sketcher::Tangent:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Tangent) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Tangent]);
visible = geometricVisible(FilterValue::Tangent);
break;
case Sketcher::Equal:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Equality) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Equality]);
visible = geometricVisible(FilterValue::Equality);
break;
case Sketcher::Symmetric:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Symmetric) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Symmetric]);
visible = geometricVisible(FilterValue::Symmetric);
break;
case Sketcher::Block:
visible = showAll || showGeometric || showNamed || (Filter == FilterValue::Block) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Block]);
visible = geometricVisible(FilterValue::Block);
break;
case Sketcher::Distance:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Distance) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Distance]);
visible = datumVisible(FilterValue::Distance);
break;
case Sketcher::DistanceX:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::HorizontalDistance) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::HorizontalDistance]);
visible = datumVisible(FilterValue::HorizontalDistance);
break;
case Sketcher::DistanceY:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::VerticalDistance) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::VerticalDistance]);
visible = datumVisible(FilterValue::VerticalDistance);
break;
case Sketcher::Radius:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Radius) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Radius]);
visible = datumVisible(FilterValue::Radius);
break;
case Sketcher::Weight:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Weight) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Weight]);
visible = datumVisible(FilterValue::Weight);
break;
case Sketcher::Diameter:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Diameter) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Diameter]);
visible = datumVisible(FilterValue::Diameter);
break;
case Sketcher::Angle:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::Angle) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::Angle]);
visible = datumVisible(FilterValue::Angle);
break;
case Sketcher::SnellsLaw:
visible = ( showAll || showDatums || showNamed || showNonDriving) || (Filter == FilterValue::SnellsLaw) ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::SnellsLaw]);
visible = datumVisible(FilterValue::SnellsLaw);
break;
case Sketcher::InternalAlignment:
visible = (( showAll || showGeometric || showNamed || Filter == FilterValue::InternalAlignment ||
(Filter == SpecialFilterValue::Multiple && multiFilterStatus[FilterValue::InternalAlignment])) &&
(!hideInternalAlignment || (Filter == FilterValue::InternalAlignment)));
visible = geometricVisible(FilterValue::InternalAlignment) &&
(!hideInternalAlignment || isFilterMatch(FilterValue::InternalAlignment,Filter));
default:
break;
}
// Constraint Type independent, selection filter
visible = visible || (Filter == SpecialFilterValue::Selection &&
visible = visible || (isFilterMatch(SpecialFilterValue::Selection, Filter) &&
std::find(selectionFilter.begin(), selectionFilter.end(), it->ConstraintNbr) != selectionFilter.end());
// Constraint Type independent, associated Constraints Filter
visible = visible || (Filter == SpecialFilterValue::AssociatedConstraints &&
visible = visible || (isFilterMatch(SpecialFilterValue::AssociatedConstraints, Filter) &&
std::find(associatedConstraintsFilter.begin(), associatedConstraintsFilter.end(), it->ConstraintNbr) != associatedConstraintsFilter.end());
return !visible;
@@ -1477,7 +1470,7 @@ void TaskSketcherConstrains::changeEvent(QEvent *e)
template <class T>
bool TaskSketcherConstrains::isFilter(T filterValue) {
return (ui->comboBoxFilter->currentIndex() == filterValue);
return isFilterMatch(filterValue, ui->comboBoxFilter->currentIndex());
}

View File

@@ -134,9 +134,9 @@ private:
QWidget* proxy;
bool inEditMode;
std::unique_ptr<Ui_TaskSketcherConstrains> ui;
std::bitset<ConstraintFilter::FilterValue::NumFilterValue> multiFilterStatus;
std::vector<unsigned int> selectionFilter;
std::vector<unsigned int> associatedConstraintsFilter;
ConstraintFilter::FilterValueBitset multiFilterStatus; // Stores the filters to be aggregated to form the multifilter.
std::vector<unsigned int> selectionFilter; // holds the constraint ids of the selected constraints
std::vector<unsigned int> associatedConstraintsFilter; // holds the constraint ids of the constraints associated with the selected geometry
};
} //namespace SketcherGui