diff --git a/.github/workflows/issue-metrics.yml b/.github/workflows/issue-metrics.yml
index 76c947c4f2..e080fbf405 100644
--- a/.github/workflows/issue-metrics.yml
+++ b/.github/workflows/issue-metrics.yml
@@ -12,6 +12,7 @@ jobs:
build:
name: issue metrics
runs-on: ubuntu-latest
+ if: github.repository_owner == 'FreeCAD'
steps:
@@ -19,7 +20,7 @@ jobs:
shell: bash
run: |
# Calculate the first day of the previous month
- first_day=$(date -d "last month" +%Y-%m-01)
+ first_day=$(date -d "last month" +%Y-%m-15)
# Calculate the last day of the previous month
last_day=$(date -d "$first_day +1 month -1 day" +%Y-%m-%d)
@@ -32,7 +33,7 @@ jobs:
uses: github/issue-metrics@v2
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- SEARCH_QUERY: 'repo:FreeCAD/FreeCAD is:issue created:${{ env.last_month }} -reason:"not planned"'
+ SEARCH_QUERY: 'repo:FreeCAD/FreeCAD is:issue created:${{ env.last_month }}'
- name: Create issue
uses: peter-evans/create-issue-from-file@v4
@@ -40,4 +41,4 @@ jobs:
title: Monthly issue metrics report
token: ${{ secrets.GITHUB_TOKEN }}
content-filepath: ./issue_metrics.md
- assignees: maxwxyz
\ No newline at end of file
+ assignees: maxwxyz
diff --git a/conda/conda-env.yaml b/conda/conda-env.yaml
index 1bd63b1952..85f441dae3 100644
--- a/conda/conda-env.yaml
+++ b/conda/conda-env.yaml
@@ -3,6 +3,5 @@ channels:
- conda-forge
dependencies:
- conda-devenv
-- mamba==1.4.9 # NOTE: Pin to highest version supported by the devenv
-- python==3.11.* # dependencies. If a higher version is installed, a crash
- # occurs during the downgrade process.
+- mamba
+- python==3.11.*
diff --git a/conda/environment.devenv.yml b/conda/environment.devenv.yml
index fa434281b4..a2504b69e6 100644
--- a/conda/environment.devenv.yml
+++ b/conda/environment.devenv.yml
@@ -73,7 +73,7 @@ dependencies:
- graphviz
- hdf5
- libcxx
-- mamba==1.4.9
+- mamba
- matplotlib
- ninja
- numpy
diff --git a/src/Gui/PreferencePages/DlgSettings3DView.ui b/src/Gui/PreferencePages/DlgSettings3DView.ui
index 3a85779209..0854dd66a5 100644
--- a/src/Gui/PreferencePages/DlgSettings3DView.ui
+++ b/src/Gui/PreferencePages/DlgSettings3DView.ui
@@ -281,31 +281,6 @@ but slower response to any scene changes.
View
- -
-
- None
-
-
- -
-
- Line Smoothing
-
-
- -
-
- MSAA 2x
-
-
- -
-
- MSAA 4x
-
-
- -
-
- MSAA 8x
-
-
-
diff --git a/src/Gui/PreferencePages/DlgSettings3DViewImp.cpp b/src/Gui/PreferencePages/DlgSettings3DViewImp.cpp
index 49f175bb2a..9fc095a637 100644
--- a/src/Gui/PreferencePages/DlgSettings3DViewImp.cpp
+++ b/src/Gui/PreferencePages/DlgSettings3DViewImp.cpp
@@ -25,6 +25,9 @@
#ifndef _PreComp_
# include
# include
+# include
+# include
+# include
#endif
#include
@@ -40,42 +43,23 @@ using namespace Gui::Dialog;
/* TRANSLATOR Gui::Dialog::DlgSettings3DViewImp */
-bool DlgSettings3DViewImp::showMsg = true;
-
-/**
- * Constructs a DlgSettings3DViewImp which is a child of 'parent', with the
- * name 'name' and widget flags set to 'f'
- */
DlgSettings3DViewImp::DlgSettings3DViewImp(QWidget* parent)
: PreferencePage( parent )
, ui(new Ui_DlgSettings3DView)
{
ui->setupUi(this);
+ addAntiAliasing();
}
-/**
- * Destroys the object and frees any allocated resources
- */
DlgSettings3DViewImp::~DlgSettings3DViewImp() = default;
void DlgSettings3DViewImp::saveSettings()
{
- // must be done as very first because we create a new instance of NavigatorStyle
- // where we set some attributes afterwards
- ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
- ("User parameter:BaseApp/Preferences/View");
-
- int index = ui->comboAliasing->currentIndex();
- hGrp->SetInt("AntiAliasing", index);
-
- index = ui->renderCache->currentIndex();
- hGrp->SetInt("RenderCache", index);
+ saveAntiAliasing();
+ saveRenderCache();
+ saveMarkerSize();
ui->comboTransparentRender->onSave();
-
- QVariant const &vBoxMarkerSize = ui->boxMarkerSize->itemData(ui->boxMarkerSize->currentIndex());
- hGrp->SetInt("MarkerSize", vBoxMarkerSize.toInt());
-
ui->CheckBox_CornerCoordSystem->onSave();
ui->SpinBox_CornerCoordSystemSize->onSave();
ui->CheckBox_ShowAxisCross->onSave();
@@ -106,23 +90,139 @@ void DlgSettings3DViewImp::loadSettings()
ui->sliderIntensity->onRestore();
ui->radioPerspective->onRestore();
ui->radioOrthographic->onRestore();
+ ui->comboTransparentRender->onRestore();
+ loadAntiAliasing();
+ loadRenderCache();
+ loadMarkerSize();
+}
+
+namespace {
+class GLFormatCheck {
+public:
+ GLFormatCheck() {
+ context.setFormat(format);
+ context.create();
+ offscreen.setFormat(format);
+ offscreen.create();
+ context.makeCurrent(&offscreen);
+ }
+
+ bool testSamples(int num) {
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::Depth);
+ fboFormat.setSamples(num);
+ QOpenGLFramebufferObject fbo(100, 100, fboFormat); // NOLINT
+ return fbo.format().samples() == num;
+ }
+
+private:
+ QSurfaceFormat format;
+ QOpenGLContext context;
+ QOffscreenSurface offscreen;
+};
+}
+
+void DlgSettings3DViewImp::addAntiAliasing()
+{
+ QString none = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "None");
+ QString line = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "Line Smoothing");
+ QString msaa2x = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "MSAA 2x");
+ QString msaa4x = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "MSAA 4x");
+ QString msaa6x = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "MSAA 6x");
+ QString msaa8x = QCoreApplication::translate("Gui::Dialog::DlgSettings3DView", "MSAA 8x");
+ ui->comboAliasing->clear();
+ ui->comboAliasing->addItem(none, int(Gui::View3DInventorViewer::None));
+ ui->comboAliasing->addItem(line, int(Gui::View3DInventorViewer::Smoothing));
+
+ // Do the samples checks only once
+ static std::vector> modes;
+ static bool formatCheck = true;
+ if (formatCheck) {
+ formatCheck = false;
+
+ GLFormatCheck check;
+ // NOLINTBEGIN
+ if (check.testSamples(2)) {
+ modes.emplace_back(msaa2x, int(Gui::View3DInventorViewer::MSAA2x));
+ }
+ if (check.testSamples(4)) {
+ modes.emplace_back(msaa4x, int(Gui::View3DInventorViewer::MSAA4x));
+ }
+ if (check.testSamples(6)) {
+ modes.emplace_back(msaa6x, int(Gui::View3DInventorViewer::MSAA6x));
+ }
+ if (check.testSamples(8)) {
+ modes.emplace_back(msaa8x, int(Gui::View3DInventorViewer::MSAA8x));
+ }
+ // NOLINTEND
+ }
+
+ for (const auto& it : modes) {
+ ui->comboAliasing->addItem(it.first, it.second);
+ }
+}
+
+void DlgSettings3DViewImp::saveAntiAliasing()
+{
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/View");
- int index = hGrp->GetInt("AntiAliasing", int(Gui::View3DInventorViewer::None));
- index = Base::clamp(index, 0, ui->comboAliasing->count()-1);
- ui->comboAliasing->setCurrentIndex(index);
+ int index = ui->comboAliasing->currentIndex();
+ int aliasing = ui->comboAliasing->itemData(index).toInt();
+ hGrp->SetInt("AntiAliasing", aliasing);
+}
+
+void DlgSettings3DViewImp::loadAntiAliasing()
+{
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/View");
+
+ int aliasing = int(hGrp->GetInt("AntiAliasing", int(Gui::View3DInventorViewer::None)));
+ int index = ui->comboAliasing->findData(aliasing);
+ if (index != -1) {
+ ui->comboAliasing->setCurrentIndex(index);
+ }
+
// connect after setting current item of the combo box
connect(ui->comboAliasing, qOverload(&QComboBox::currentIndexChanged),
this, &DlgSettings3DViewImp::onAliasingChanged);
+}
- index = hGrp->GetInt("RenderCache", 0);
- ui->renderCache->setCurrentIndex(index);
+void DlgSettings3DViewImp::saveRenderCache()
+{
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/View");
- ui->comboTransparentRender->onRestore();
+ int cache = ui->renderCache->currentIndex();
+ hGrp->SetInt("RenderCache", cache);
+}
- int const current = hGrp->GetInt("MarkerSize", 9L);
+void DlgSettings3DViewImp::loadRenderCache()
+{
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/View");
+
+ long cache = hGrp->GetInt("RenderCache", 0);
+ ui->renderCache->setCurrentIndex(int(cache));
+}
+
+void DlgSettings3DViewImp::saveMarkerSize()
+{
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/View");
+
+ QVariant const &vBoxMarkerSize = ui->boxMarkerSize->itemData(ui->boxMarkerSize->currentIndex());
+ hGrp->SetInt("MarkerSize", vBoxMarkerSize.toInt());
+}
+
+void DlgSettings3DViewImp::loadMarkerSize()
+{
+ ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
+ ("User parameter:BaseApp/Preferences/View");
+
+ // NOLINTBEGIN
+ int marker = hGrp->GetInt("MarkerSize", 9L);
ui->boxMarkerSize->addItem(tr("5px"), QVariant(5));
ui->boxMarkerSize->addItem(tr("7px"), QVariant(7));
ui->boxMarkerSize->addItem(tr("9px"), QVariant(9));
@@ -132,9 +232,12 @@ void DlgSettings3DViewImp::loadSettings()
ui->boxMarkerSize->addItem(tr("20px"), QVariant(20));
ui->boxMarkerSize->addItem(tr("25px"), QVariant(25));
ui->boxMarkerSize->addItem(tr("30px"), QVariant(30));
- index = ui->boxMarkerSize->findData(QVariant(current));
- if (index < 0) index = 2;
- ui->boxMarkerSize->setCurrentIndex(index);
+ marker = ui->boxMarkerSize->findData(QVariant(marker));
+ if (marker < 0) {
+ marker = 2;
+ }
+ ui->boxMarkerSize->setCurrentIndex(marker);
+ // NOLINTEND
}
void DlgSettings3DViewImp::resetSettingsToDefaults()
@@ -161,24 +264,29 @@ void DlgSettings3DViewImp::changeEvent(QEvent *e)
ui->comboAliasing->blockSignals(true);
int aliasing = ui->comboAliasing->currentIndex();
ui->retranslateUi(this);
+ addAntiAliasing();
ui->comboAliasing->setCurrentIndex(aliasing);
ui->comboAliasing->blockSignals(false);
}
else {
- QWidget::changeEvent(e);
+ PreferencePage::changeEvent(e);
}
}
void DlgSettings3DViewImp::onAliasingChanged(int index)
{
- if (index < 0 || !isVisible())
+ if (index < 0 || !isVisible()) {
return;
+ }
+
// Show this message only once per application session to reduce
// annoyance when showing it too often.
+ static bool showMsg = true;
if (showMsg) {
showMsg = false;
QMessageBox::information(this, tr("Anti-aliasing"),
- tr("Open a new viewer or restart %1 to apply anti-aliasing changes.").arg(qApp->applicationName()));
+ tr("Open a new viewer or restart %1 to apply anti-aliasing changes.")
+ .arg(qApp->applicationName()));
}
}
diff --git a/src/Gui/PreferencePages/DlgSettings3DViewImp.h b/src/Gui/PreferencePages/DlgSettings3DViewImp.h
index 86af22838a..5d047f1152 100644
--- a/src/Gui/PreferencePages/DlgSettings3DViewImp.h
+++ b/src/Gui/PreferencePages/DlgSettings3DViewImp.h
@@ -56,9 +56,19 @@ private Q_SLOTS:
protected:
void changeEvent(QEvent *e) override;
+private:
+ void addAntiAliasing();
+ void saveAntiAliasing();
+ void loadAntiAliasing();
+ void saveRenderCache();
+ void loadRenderCache();
+ void saveMarkerSize();
+ void loadMarkerSize();
+
private:
std::unique_ptr ui;
- static bool showMsg;
+
+ Q_DISABLE_COPY_MOVE(DlgSettings3DViewImp)
};
} // namespace Dialog
diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp
index 62322b8683..671e6ee5b7 100644
--- a/src/Gui/View3DInventorViewer.cpp
+++ b/src/Gui/View3DInventorViewer.cpp
@@ -1963,6 +1963,8 @@ int View3DInventorViewer::getNumSamples()
return 2;
case View3DInventorViewer::MSAA4x:
return 4;
+ case View3DInventorViewer::MSAA6x:
+ return 6;
case View3DInventorViewer::MSAA8x:
return 8;
case View3DInventorViewer::Smoothing:
diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h
index 221ad4ba95..eca7f186b0 100644
--- a/src/Gui/View3DInventorViewer.h
+++ b/src/Gui/View3DInventorViewer.h
@@ -117,11 +117,12 @@ public:
*/
//@{
enum AntiAliasing {
- None,
- Smoothing,
- MSAA2x,
- MSAA4x,
- MSAA8x
+ None = 0,
+ Smoothing = 1,
+ MSAA2x = 2,
+ MSAA4x = 3,
+ MSAA6x = 5,
+ MSAA8x = 4
};
//@}
diff --git a/src/Gui/resource.cpp b/src/Gui/resource.cpp
index a5746990a6..05304998a6 100644
--- a/src/Gui/resource.cpp
+++ b/src/Gui/resource.cpp
@@ -124,5 +124,6 @@ WidgetFactorySupplier::WidgetFactorySupplier()
new WidgetProducer;
new WidgetProducer;
new WidgetProducer;
+ new WidgetProducer;
}
// clang-format on
diff --git a/src/Mod/Arch/exportIFC.py b/src/Mod/Arch/exportIFC.py
index d940b7c249..e168c3bf93 100644
--- a/src/Mod/Arch/exportIFC.py
+++ b/src/Mod/Arch/exportIFC.py
@@ -265,7 +265,12 @@ def export(exportList, filename, colors=None, preferences=None):
ifcfile = ifcopenshell.open(templatefile)
ifcfile = exportIFCHelper.writeUnits(ifcfile,preferences["IFC_UNIT"])
- history = ifcfile.by_type("IfcOwnerHistory")[0]
+ history = ifcfile.by_type("IfcOwnerHistory")
+ if history:
+ history = history[0]
+ else:
+ # IFC4 allows to not write any history
+ history = None
objectslist = Draft.get_group_contents(exportList, walls=True,
addgroups=True)
@@ -296,7 +301,9 @@ def export(exportList, filename, colors=None, preferences=None):
if existing_file:
project = ifcfile.by_type("IfcProject")[0]
- context = ifcfile.by_type("IFcGeometricRepresentationContext")[-1]
+ body_contexts = [c for c in ifcfile.by_type("IfcGeometricRepresentationSubContext") if c.ContextIdentifier in ["Body", "Facetation"]]
+ body_contexts.extend([c for c in ifcfile.by_type("IfcGeometricRepresentationContext", include_subtypes=False) if c.ContextType == "Model"])
+ context = body_contexts[0] # we take the first one (subcontext if existing, or context if not)
else:
contextCreator = exportIFCHelper.ContextCreator(ifcfile, objectslist)
context = contextCreator.model_view_subcontext
diff --git a/src/Mod/Fem/Gui/DlgSettingsFemCcx.ui b/src/Mod/Fem/Gui/DlgSettingsFemCcx.ui
index 46537effc4..f09608cf7f 100644
--- a/src/Mod/Fem/Gui/DlgSettingsFemCcx.ui
+++ b/src/Mod/Fem/Gui/DlgSettingsFemCcx.ui
@@ -393,14 +393,14 @@
- -
+
-
Time incrementation control parameter
- -
+
-
Use non ccx defaults
@@ -416,6 +416,38 @@
+ -
+
+
+ Maximum number of iterations
+
+
+
+ -
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 1
+
+
+ 10000000
+
+
+ 10
+
+
+ 2000
+
+
+ AnalysisMaxIterations
+
+
+ Mod/Fem/Ccx
+
+
+
-
@@ -445,10 +477,10 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- 3
+ 9
- 0.010000000000000
+ 0.000000001000000
0.010000000000000
@@ -465,7 +497,7 @@
-
-
+
s
@@ -484,10 +516,10 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- 3
+ 9
- 0.010000000000000
+ 0.000000001000000
0.010000000000000
@@ -504,20 +536,130 @@
-
+
+
+ s
+
+
+
+ -
+
+
+ Time Minimum Step
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::DefaultContextMenu
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 9
+
+
+ 0.000000001000000
+
+
+ 0.010000000000000
+
+
+ 0.000010000000000
+
+
+ AnalysisTimeMinimumStep
+
+
+ Mod/Fem/Ccx
+
+
+
+ -
+
+
+ s
+
+
+
+ -
+
+
+ Time Maximum Step
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::DefaultContextMenu
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 9
+
+
+ 0.000000001000000
+
+
+ 1.000000000000000
+
+
+ 1.000000000000000
+
+
+ AnalysisTimeMaximumStep
+
+
+ Mod/Fem/Ccx
+
+
+
+ -
s
- -
+
-
Beam, shell element 3D output format
- -
+
-
3D Output, unchecked for 2D
@@ -569,35 +711,6 @@
- -
-
-
- Maximum number of iterations
-
-
-
- -
-
-
- 1
-
-
- 10000000
-
-
- 10
-
-
- 2000
-
-
- AnalysisMaxIterations
-
-
- Mod/Fem/Ccx
-
-
-
@@ -695,7 +808,7 @@
-
-
+
Hz
diff --git a/src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp b/src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp
index a5030ffd0a..bea9df709f 100644
--- a/src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp
+++ b/src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp
@@ -73,6 +73,8 @@ void DlgSettingsFemCcxImp::saveSettings()
ui->sb_ccx_max_iterations->onSave(); // Max number of iterations
ui->dsb_ccx_initial_time_step->onSave(); // Initial time step
ui->dsb_ccx_analysis_time->onSave(); // Analysis time
+ ui->dsb_ccx_minimum_time_step->onSave(); // Minimum time step
+ ui->dsb_ccx_maximum_time_step->onSave(); // Maximum time step
ui->cb_analysis_type->onSave();
ui->cb_BeamShellOutput->onSave(); // Beam shell output 3d or 2d
@@ -98,6 +100,8 @@ void DlgSettingsFemCcxImp::loadSettings()
ui->sb_ccx_max_iterations->onRestore(); // Max number of iterations
ui->dsb_ccx_initial_time_step->onRestore(); // Initial time step
ui->dsb_ccx_analysis_time->onRestore(); // Analysis time
+ ui->dsb_ccx_minimum_time_step->onRestore(); // Minimum time step
+ ui->dsb_ccx_maximum_time_step->onRestore(); // Maximum time step
ui->cb_analysis_type->onRestore();
ui->cb_BeamShellOutput->onRestore(); // Beam shell output 3d or 2d
diff --git a/src/Mod/Fem/femexamples/thermomech_bimetall.py b/src/Mod/Fem/femexamples/thermomech_bimetall.py
index a34763d9c3..8368eb703a 100644
--- a/src/Mod/Fem/femexamples/thermomech_bimetall.py
+++ b/src/Mod/Fem/femexamples/thermomech_bimetall.py
@@ -145,7 +145,7 @@ def setup(doc=None, solvertype="ccxtools"):
# solver_obj.MatrixSolverType = "default"
solver_obj.MatrixSolverType = "spooles" # thomas
solver_obj.SplitInputWriter = False
- solver_obj.IterationsThermoMechMaximum = 2000
+ solver_obj.IterationsMaximum = 2000
# solver_obj.IterationsControlParameterTimeUse = True # thermomech spine
analysis.addObject(solver_obj)
diff --git a/src/Mod/Fem/femsolver/calculix/solver.py b/src/Mod/Fem/femsolver/calculix/solver.py
index fb5d18aeaf..8d60061ed8 100644
--- a/src/Mod/Fem/femsolver/calculix/solver.py
+++ b/src/Mod/Fem/femsolver/calculix/solver.py
@@ -198,19 +198,23 @@ def add_attributes(obj, ccx_prefs):
ehl = ccx_prefs.GetFloat("EigenmodeHighLimit", 1000000.0)
obj.EigenmodeHighLimit = (ehl, 0.0, 1000000.0, 10000.0)
- if not hasattr(obj, "IterationsThermoMechMaximum"):
- help_string_IterationsThermoMechMaximum = (
- "Maximum Number of thermo mechanical iterations "
+ if not hasattr(obj, "IterationsMaximum"):
+ help_string_IterationsMaximum = (
+ "Maximum Number of iterations "
"in each time step before stopping jobs"
)
obj.addProperty(
"App::PropertyIntegerConstraint",
- "IterationsThermoMechMaximum",
+ "IterationsMaximum",
"Fem",
- help_string_IterationsThermoMechMaximum
+ help_string_IterationsMaximum
)
niter = ccx_prefs.GetInt("AnalysisMaxIterations", 200)
- obj.IterationsThermoMechMaximum = niter
+ obj.IterationsMaximum = niter
+
+ if hasattr(obj, "IterationsThermoMechMaximum"):
+ obj.IterationsMaximum = obj.IterationsThermoMechMaximum
+ obj.removeProperty("IterationsThermoMechMaximum")
if not hasattr(obj, "BucklingFactors"):
obj.addProperty(
@@ -242,6 +246,26 @@ def add_attributes(obj, ccx_prefs):
eni = ccx_prefs.GetFloat("AnalysisTime", 1.0)
obj.TimeEnd = eni
+ if not hasattr(obj, "TimeMinimumStep"):
+ obj.addProperty(
+ "App::PropertyFloatConstraint",
+ "TimeMinimumStep",
+ "Fem",
+ "Minimum time step"
+ )
+ mini = ccx_prefs.GetFloat("AnalysisTimeMinimumStep", 0.00001)
+ obj.TimeMinimumStep = mini
+
+ if not hasattr(obj, "TimeMaximumStep"):
+ obj.addProperty(
+ "App::PropertyFloatConstraint",
+ "TimeMaximumStep",
+ "Fem",
+ "Maximum time step"
+ )
+ maxi = ccx_prefs.GetFloat("AnalysisTimeMaximumStep", 1.0)
+ obj.TimeMaximumStep = maxi
+
if not hasattr(obj, "ThermoMechSteadyState"):
obj.addProperty(
"App::PropertyBool",
@@ -332,7 +356,7 @@ def add_attributes(obj, ccx_prefs):
if not hasattr(obj, "IterationsUserDefinedTimeStepLength"):
help_string_IterationsUserDefinedTimeStepLength = (
"Set to True to use the user defined time steps. "
- "The time steps are set with TimeInitialStep and TimeEnd"
+ "They are set with TimeInitialStep, TimeEnd, TimeMinimum and TimeMaximum"
)
obj.addProperty(
"App::PropertyBool",
diff --git a/src/Mod/Fem/femsolver/calculix/write_step_equation.py b/src/Mod/Fem/femsolver/calculix/write_step_equation.py
index e4beef37c2..02a06c1f1f 100644
--- a/src/Mod/Fem/femsolver/calculix/write_step_equation.py
+++ b/src/Mod/Fem/femsolver/calculix/write_step_equation.py
@@ -45,12 +45,11 @@ def write_step_equation(f, ccxwriter):
"Analysis type frequency and geometrical nonlinear "
"analysis are not allowed together, linear is used instead!\n"
)
- if ccxwriter.solver_obj.IterationsThermoMechMaximum:
- if ccxwriter.analysis_type == "thermomech":
- step += ", INC={}".format(ccxwriter.solver_obj.IterationsThermoMechMaximum)
+ if ccxwriter.solver_obj.IterationsMaximum:
+ if ccxwriter.analysis_type == "thermomech" or ccxwriter.analysis_type == "static":
+ step += ", INC={}".format(ccxwriter.solver_obj.IterationsMaximum)
elif (
- ccxwriter.analysis_type == "static"
- or ccxwriter.analysis_type == "frequency"
+ ccxwriter.analysis_type == "frequency"
or ccxwriter.analysis_type == "buckling"
):
# parameter is for thermomechanical analysis only, see ccx manual *STEP
@@ -124,9 +123,11 @@ def write_step_equation(f, ccxwriter):
if ccxwriter.analysis_type == "static" or ccxwriter.analysis_type == "check":
if ccxwriter.solver_obj.IterationsUserDefinedIncrementations is True \
or ccxwriter.solver_obj.IterationsUserDefinedTimeStepLength is True:
- analysis_parameter = "{},{}".format(
+ analysis_parameter = "{},{},{},{}".format(
ccxwriter.solver_obj.TimeInitialStep,
- ccxwriter.solver_obj.TimeEnd
+ ccxwriter.solver_obj.TimeEnd,
+ ccxwriter.solver_obj.TimeMinimumStep,
+ ccxwriter.solver_obj.TimeMaximumStep
)
elif ccxwriter.analysis_type == "frequency":
if ccxwriter.solver_obj.EigenmodeLowLimit == 0.0 \
@@ -140,9 +141,11 @@ def write_step_equation(f, ccxwriter):
)
elif ccxwriter.analysis_type == "thermomech":
# OvG: 1.0 increment, total time 1 for steady state will cut back automatically
- analysis_parameter = "{},{}".format(
+ analysis_parameter = "{},{},{},{}".format(
ccxwriter.solver_obj.TimeInitialStep,
- ccxwriter.solver_obj.TimeEnd
+ ccxwriter.solver_obj.TimeEnd,
+ ccxwriter.solver_obj.TimeMinimumStep,
+ ccxwriter.solver_obj.TimeMaximumStep
)
elif ccxwriter.analysis_type == "buckling":
analysis_parameter = "{}\n".format(ccxwriter.solver_obj.BucklingFactors)
diff --git a/src/Mod/Fem/femtest/data/calculix/box_static.inp b/src/Mod/Fem/femtest/data/calculix/box_static.inp
index b3380bd960..2357b51200 100644
--- a/src/Mod/Fem/femtest/data/calculix/box_static.inp
+++ b/src/Mod/Fem/femtest/data/calculix/box_static.inp
@@ -489,7 +489,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp
index 31bcd23b49..c61d0b81d6 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_circle.inp
@@ -62,7 +62,7 @@ Eedges
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp
index 3b00eee774..b2366b0f18 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_pipe.inp
@@ -62,7 +62,7 @@ Eedges
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp
index 6d3eb29682..158145c70a 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_beam_rect.inp
@@ -62,7 +62,7 @@ Eedges
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp
index 3060c64375..bd7c47159e 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_hexa20.inp
@@ -385,7 +385,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp
index 4b9576c2bd..7b7cd41ff8 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad4.inp
@@ -86,7 +86,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp
index 111fdf49b7..a201a9c3a2 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_quad8.inp
@@ -74,7 +74,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp
index 73b099e0ef..fb0a022008 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg2.inp
@@ -204,7 +204,7 @@ Eedges
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp
index 49fb62c6b9..72dd4db87c 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_seg3.inp
@@ -62,7 +62,7 @@ Eedges
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp
index 7c062296e5..59da919b13 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria3.inp
@@ -1562,7 +1562,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp
index 5c0e12187f..04dda8c146 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_ele_tria6.inp
@@ -292,7 +292,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp
index 3a6ab24119..03f0e80bd7 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_faceload.inp
@@ -359,7 +359,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp
index 107253f1d5..9198e5c3a4 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_nodeload.inp
@@ -359,7 +359,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp
index 47cc8a4cc8..d4a67e562b 100644
--- a/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp
+++ b/src/Mod/Fem/femtest/data/calculix/ccx_cantilever_prescribeddisplacement.inp
@@ -377,7 +377,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp b/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp
index c39beee71f..1a6bc45f52 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_contact_shell_shell.inp
@@ -38373,7 +38373,7 @@ DEPConstraintContact, INDConstraintContact
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp b/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp
index 2c83229bb6..501355f029 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_sectionprint.inp
@@ -3401,7 +3401,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp b/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp
index e27d347cf4..6eb8cf3780 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_selfweight_cantilever.inp
@@ -2153,7 +2153,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp b/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp
index c00b1d5d73..cc73eb5c7f 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_tie.inp
@@ -18612,7 +18612,7 @@ TIE_DEPConstraintTie, TIE_INDConstraintTie
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp
index f20ff9d23f..23715d316d 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_beam_hinged.inp
@@ -3639,7 +3639,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp
index dd776985b2..7489f67648 100644
--- a/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp
+++ b/src/Mod/Fem/femtest/data/calculix/constraint_transform_torque.inp
@@ -10980,7 +10980,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp
index 517770b828..5ec1a3d3e7 100644
--- a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp
+++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fiveboxes.inp
@@ -27634,7 +27634,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp
index 08f88f3935..9ac894a8c5 100644
--- a/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp
+++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_bendingbeam_fivefaces.inp
@@ -2548,7 +2548,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp b/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp
index 193f9e780d..d378596781 100644
--- a/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp
+++ b/src/Mod/Fem/femtest/data/calculix/material_multiple_tensionrod_twoboxes.inp
@@ -1231,7 +1231,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp b/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp
index e0e16e90ed..c2cb7c0505 100644
--- a/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp
+++ b/src/Mod/Fem/femtest/data/calculix/material_nonlinear.inp
@@ -20004,7 +20004,7 @@ Evolumes
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP, NLGEOM
+*STEP, NLGEOM, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp
index 4bc8f67606..a70ab0a392 100644
--- a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp
+++ b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_edgeforces.inp
@@ -2560,7 +2560,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp
index 6aa03980b3..6e68876fff 100644
--- a/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp
+++ b/src/Mod/Fem/femtest/data/calculix/square_pipe_end_twisted_nodeforces.inp
@@ -2560,7 +2560,7 @@ Efaces
***********************************************************
** At least one step is needed to run an CalculiX analysis of FreeCAD
-*STEP
+*STEP, INC=200
*STATIC
diff --git a/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp b/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp
index 3d95c77f3d..90fce0f689 100644
--- a/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp
+++ b/src/Mod/Fem/femtest/data/calculix/thermomech_bimetall.inp
@@ -7081,7 +7081,7 @@ Nall,273.0
** At least one step is needed to run an CalculiX analysis of FreeCAD
*STEP, INC=2000
*COUPLED TEMPERATURE-DISPLACEMENT, SOLVER=SPOOLES, STEADY STATE
-1.0,1.0
+1.0,1.0,1e-05,1.0
***********************************************************
** Fixed Constraints
diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp
index c45a9841e4..1baf8ccb54 100644
--- a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp
+++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp
@@ -22,25 +22,25 @@
#include "PreCompiled.h"
#ifndef _PreComp_
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
-# include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#endif
#include
@@ -60,81 +60,79 @@
using namespace PartGui;
//////////////////////////////////////////////////////////////////////////
-class DlgProjectionOnSurface::EdgeSelection : public Gui::SelectionFilterGate
+class DlgProjectionOnSurface::EdgeSelection: public Gui::SelectionFilterGate
{
public:
- bool canSelect;
+ bool canSelect = false;
- EdgeSelection()
- : Gui::SelectionFilterGate(nullPointer())
- {
- canSelect = false;
- }
- ~EdgeSelection() override = default;
+ EdgeSelection()
+ : Gui::SelectionFilterGate(nullPointer())
+ {}
- bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
- {
- Part::Feature* aPart = dynamic_cast(iPObj);
- if (!aPart)
- return false;
- if (!sSubName)
- return false;
- std::string subName(sSubName);
- if (subName.empty())
- return false;
+ bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
+ {
+ auto aPart = dynamic_cast(iPObj);
+ if (!aPart) {
+ return false;
+ }
+ if (!sSubName) {
+ return false;
+ }
+ std::string subName(sSubName);
+ if (subName.empty()) {
+ return false;
+ }
- auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
- if (subShape.IsNull())
- return false;
- auto type = subShape.ShapeType();
- if (type != TopAbs_EDGE)
- return false;
- return true;
- }
+ auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
+ if (subShape.IsNull()) {
+ return false;
+ }
+ auto type = subShape.ShapeType();
+ return (type == TopAbs_EDGE);
+ }
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
-class DlgProjectionOnSurface::FaceSelection : public Gui::SelectionFilterGate
+class DlgProjectionOnSurface::FaceSelection: public Gui::SelectionFilterGate
{
public:
- bool canSelect;
+ bool canSelect = false;
- FaceSelection()
- : Gui::SelectionFilterGate(nullPointer())
- {
- canSelect = false;
- }
- ~FaceSelection() override = default;
+ FaceSelection()
+ : Gui::SelectionFilterGate(nullPointer())
+ {}
- bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
- {
- Part::Feature* aPart = dynamic_cast(iPObj);
- if (!aPart)
- return false;
- if (!sSubName)
- return false;
- std::string subName(sSubName);
- if (subName.empty())
- return false;
+ bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName) override
+ {
+ auto aPart = dynamic_cast(iPObj);
+ if (!aPart) {
+ return false;
+ }
+ if (!sSubName) {
+ return false;
+ }
+ std::string subName(sSubName);
+ if (subName.empty()) {
+ return false;
+ }
- auto subShape = aPart->Shape.getShape().getSubShape(sSubName, true);
- if (subShape.IsNull())
- return false;
- auto type = subShape.ShapeType();
- if (type != TopAbs_FACE)
- return false;
- return true;
- }
+ auto subShape = aPart->Shape.getShape().getSubShape(sSubName, true);
+ if (subShape.IsNull()) {
+ return false;
+ }
+ auto type = subShape.ShapeType();
+ return (type == TopAbs_FACE);
+ }
};
//////////////////////////////////////////////////////////////////////////
-DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::DlgProjectionOnSurface)
- , m_projectionObjectName(tr("Projection Object"))
- , filterEdge(nullptr)
- , filterFace(nullptr)
+DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui::DlgProjectionOnSurface)
+ , m_projectionObjectName(tr("Projection Object"))
+ , filterEdge(nullptr)
+ , filterFace(nullptr)
{
ui->setupUi(this);
setupConnections();
@@ -160,16 +158,15 @@ DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget *parent)
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
m_partDocument = App::GetApplication().getActiveDocument();
- if (!m_partDocument)
- {
- throw Base::ValueError(QString(tr("Have no active document!!!")).toUtf8());
+ if (!m_partDocument) {
+ throw Base::ValueError(QString(tr("Have no active document!!!")).toUtf8());
}
this->attachDocument(m_partDocument);
m_partDocument->openTransaction("Project on surface");
- m_projectionObject = dynamic_cast(m_partDocument->addObject("Part::Feature", "Projection Object"));
- if (!m_projectionObject)
- {
- throw Base::ValueError(QString(tr("Can not create a projection object!!!")).toUtf8());
+ m_projectionObject = dynamic_cast(
+ m_partDocument->addObject("Part::Feature", "Projection Object"));
+ if (!m_projectionObject) {
+ throw Base::ValueError(QString(tr("Can not create a projection object!!!")).toUtf8());
}
m_projectionObject->Label.setValue(std::string(m_projectionObjectName.toUtf8()).c_str());
onRadioButtonShowAllClicked();
@@ -178,965 +175,1013 @@ DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget *parent)
DlgProjectionOnSurface::~DlgProjectionOnSurface()
{
- delete ui;
- for (const auto& it : m_projectionSurfaceVec)
- {
- try {
- higlight_object(it.partFeature, it.partName, false, 0);
+ delete ui;
+ for (const auto& it : m_projectionSurfaceVec) {
+ try {
+ higlight_object(it.partFeature, it.partName, false, 0);
+ }
+ catch (Standard_NoSuchObject& e) {
+ Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s",
+ e.GetMessageString());
+ }
+ auto vp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(it.partFeature));
+ if (vp) {
+ vp->Selectable.setValue(it.is_selectable);
+ vp->Transparency.setValue(it.transparency);
+ }
}
- catch (Standard_NoSuchObject& e) {
- Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s", e.GetMessageString());
+ for (const auto& it : m_shapeVec) {
+ try {
+ higlight_object(it.partFeature, it.partName, false, 0);
+ }
+ catch (Standard_NoSuchObject& e) {
+ Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s",
+ e.GetMessageString());
+ }
}
- PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(it.partFeature));
- if (vp)
- {
- vp->Selectable.setValue(it.is_selectable);
- vp->Transparency.setValue(it.transparency);
- }
- }
- for (const auto& it : m_shapeVec)
- {
- try {
- higlight_object(it.partFeature, it.partName, false, 0);
- }
- catch (Standard_NoSuchObject& e) {
- Base::Console().Warning("DlgProjectionOnSurface::~DlgProjectionOnSurface: %s", e.GetMessageString());
- }
- }
- Gui::Selection().rmvSelectionGate();
+ Gui::Selection().rmvSelectionGate();
}
void PartGui::DlgProjectionOnSurface::setupConnections()
{
- connect(ui->pushButtonAddFace, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonAddFaceClicked);
- connect(ui->pushButtonAddEdge, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonAddEdgeClicked);
- connect(ui->pushButtonGetCurrentCamDir, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonGetCurrentCamDirClicked);
- connect(ui->pushButtonDirX, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonDirXClicked);
- connect(ui->pushButtonDirY, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonDirYClicked);
- connect(ui->pushButtonDirZ, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonDirZClicked);
- connect(ui->pushButtonAddProjFace, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonAddProjFaceClicked);
- connect(ui->radioButtonShowAll, &QRadioButton::clicked,
- this, &DlgProjectionOnSurface::onRadioButtonShowAllClicked);
- connect(ui->radioButtonFaces, &QRadioButton::clicked,
- this, &DlgProjectionOnSurface::onRadioButtonFacesClicked);
- connect(ui->radioButtonEdges, &QRadioButton::clicked,
- this, &DlgProjectionOnSurface::onRadioButtonEdgesClicked);
- connect(ui->doubleSpinBoxExtrudeHeight, qOverload(&QDoubleSpinBox::valueChanged),
- this, &DlgProjectionOnSurface::onDoubleSpinBoxExtrudeHeightValueChanged);
- connect(ui->pushButtonAddWire, &QPushButton::clicked,
- this, &DlgProjectionOnSurface::onPushButtonAddWireClicked);
- connect(ui->doubleSpinBoxSolidDepth, qOverload(&QDoubleSpinBox::valueChanged),
- this, &DlgProjectionOnSurface::onDoubleSpinBoxSolidDepthValueChanged);
+ connect(ui->pushButtonAddFace,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonAddFaceClicked);
+ connect(ui->pushButtonAddEdge,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonAddEdgeClicked);
+ connect(ui->pushButtonGetCurrentCamDir,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonGetCurrentCamDirClicked);
+ connect(ui->pushButtonDirX,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonDirXClicked);
+ connect(ui->pushButtonDirY,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonDirYClicked);
+ connect(ui->pushButtonDirZ,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonDirZClicked);
+ connect(ui->pushButtonAddProjFace,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonAddProjFaceClicked);
+ connect(ui->radioButtonShowAll,
+ &QRadioButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onRadioButtonShowAllClicked);
+ connect(ui->radioButtonFaces,
+ &QRadioButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onRadioButtonFacesClicked);
+ connect(ui->radioButtonEdges,
+ &QRadioButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onRadioButtonEdgesClicked);
+ connect(ui->doubleSpinBoxExtrudeHeight,
+ qOverload(&QDoubleSpinBox::valueChanged),
+ this,
+ &DlgProjectionOnSurface::onDoubleSpinBoxExtrudeHeightValueChanged);
+ connect(ui->pushButtonAddWire,
+ &QPushButton::clicked,
+ this,
+ &DlgProjectionOnSurface::onPushButtonAddWireClicked);
+ connect(ui->doubleSpinBoxSolidDepth,
+ qOverload(&QDoubleSpinBox::valueChanged),
+ this,
+ &DlgProjectionOnSurface::onDoubleSpinBoxSolidDepthValueChanged);
}
void PartGui::DlgProjectionOnSurface::slotDeletedDocument(const App::Document& Doc)
{
- if (m_partDocument == &Doc) {
- m_partDocument = nullptr;
- m_projectionObject = nullptr;
- }
+ if (m_partDocument == &Doc) {
+ m_partDocument = nullptr;
+ m_projectionObject = nullptr;
+ }
}
void PartGui::DlgProjectionOnSurface::slotDeletedObject(const App::DocumentObject& Obj)
{
- if (m_projectionObject == &Obj) {
- m_projectionObject = nullptr;
- }
+ if (m_projectionObject == &Obj) {
+ m_projectionObject = nullptr;
+ }
}
void PartGui::DlgProjectionOnSurface::apply()
{
- if (m_partDocument)
- m_partDocument->commitTransaction();
+ if (m_partDocument) {
+ m_partDocument->commitTransaction();
+ }
}
void PartGui::DlgProjectionOnSurface::reject()
{
- if (m_partDocument)
- m_partDocument->abortTransaction();
+ if (m_partDocument) {
+ m_partDocument->abortTransaction();
+ }
}
void PartGui::DlgProjectionOnSurface::onPushButtonAddFaceClicked()
{
- if ( ui->pushButtonAddFace->isChecked() )
- {
- m_currentSelection = "add_face";
- disable_ui_elements(m_guiObjectVec, ui->pushButtonAddFace);
- if (!filterFace)
- {
- filterFace = new FaceSelection();
- Gui::Selection().addSelectionGate(filterFace);
+ if (ui->pushButtonAddFace->isChecked()) {
+ m_currentSelection = "add_face";
+ disable_ui_elements(m_guiObjectVec, ui->pushButtonAddFace);
+ if (!filterFace) {
+ filterFace = new FaceSelection();
+ Gui::Selection().addSelectionGate(filterFace);
+ }
+ }
+ else {
+ m_currentSelection = "";
+ enable_ui_elements(m_guiObjectVec, nullptr);
+ Gui::Selection().rmvSelectionGate();
+ filterFace = nullptr;
}
- }
- else
- {
- m_currentSelection = "";
- enable_ui_elements(m_guiObjectVec, nullptr);
- Gui::Selection().rmvSelectionGate();
- filterFace = nullptr;
- }
}
void PartGui::DlgProjectionOnSurface::onPushButtonAddEdgeClicked()
{
- if (ui->pushButtonAddEdge->isChecked())
- {
- m_currentSelection = "add_edge";
- disable_ui_elements(m_guiObjectVec, ui->pushButtonAddEdge);
- if (!filterEdge)
- {
- filterEdge = new EdgeSelection();
- Gui::Selection().addSelectionGate(filterEdge);
+ if (ui->pushButtonAddEdge->isChecked()) {
+ m_currentSelection = "add_edge";
+ disable_ui_elements(m_guiObjectVec, ui->pushButtonAddEdge);
+ if (!filterEdge) {
+ filterEdge = new EdgeSelection();
+ Gui::Selection().addSelectionGate(filterEdge);
+ }
+ ui->radioButtonEdges->setChecked(true);
+ onRadioButtonEdgesClicked();
+ }
+ else {
+ m_currentSelection = "";
+ enable_ui_elements(m_guiObjectVec, nullptr);
+ Gui::Selection().rmvSelectionGate();
+ filterEdge = nullptr;
}
- ui->radioButtonEdges->setChecked(true);
- onRadioButtonEdgesClicked();
- }
- else
- {
- m_currentSelection = "";
- enable_ui_elements(m_guiObjectVec, nullptr);
- Gui::Selection().rmvSelectionGate();
- filterEdge = nullptr;
- }
}
void PartGui::DlgProjectionOnSurface::onPushButtonGetCurrentCamDirClicked()
{
- get_camera_direction();
+ get_camera_direction();
}
void PartGui::DlgProjectionOnSurface::onPushButtonDirXClicked()
{
- set_xyz_dir_spinbox(ui->doubleSpinBoxDirX);
+ set_xyz_dir_spinbox(ui->doubleSpinBoxDirX);
}
void PartGui::DlgProjectionOnSurface::onPushButtonDirYClicked()
{
- set_xyz_dir_spinbox(ui->doubleSpinBoxDirY);
+ set_xyz_dir_spinbox(ui->doubleSpinBoxDirY);
}
void PartGui::DlgProjectionOnSurface::onPushButtonDirZClicked()
{
- set_xyz_dir_spinbox(ui->doubleSpinBoxDirZ);
+ set_xyz_dir_spinbox(ui->doubleSpinBoxDirZ);
}
void PartGui::DlgProjectionOnSurface::onSelectionChanged(const Gui::SelectionChanges& msg)
{
- if (msg.Type == Gui::SelectionChanges::AddSelection)
- {
- if ( m_currentSelection == "add_face" || m_currentSelection == "add_edge" || m_currentSelection == "add_wire")
- {
- store_current_selected_parts(m_shapeVec, 0xff00ff00);
- create_projection_wire(m_shapeVec);
- create_projection_face_from_wire(m_shapeVec);
- create_face_extrude(m_shapeVec);
- show_projected_shapes(m_shapeVec);
- }
- else if (m_currentSelection == "add_projection_surface")
- {
- m_projectionSurfaceVec.clear();
- store_current_selected_parts(m_projectionSurfaceVec, 0xffff0000);
- if (!m_projectionSurfaceVec.empty())
- {
- PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(m_projectionSurfaceVec.back().partFeature));
- if (vp)
- {
- vp->Selectable.setValue(false);
- vp->Transparency.setValue(90);
+ if (msg.Type == Gui::SelectionChanges::AddSelection) {
+ if (m_currentSelection == "add_face" || m_currentSelection == "add_edge"
+ || m_currentSelection == "add_wire") {
+ store_current_selected_parts(m_shapeVec, 0xff00ff00);
+ create_projection_wire(m_shapeVec);
+ create_projection_face_from_wire(m_shapeVec);
+ create_face_extrude(m_shapeVec);
+ show_projected_shapes(m_shapeVec);
}
- }
+ else if (m_currentSelection == "add_projection_surface") {
+ m_projectionSurfaceVec.clear();
+ store_current_selected_parts(m_projectionSurfaceVec, 0xffff0000);
+ if (!m_projectionSurfaceVec.empty()) {
+ auto vp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(
+ m_projectionSurfaceVec.back().partFeature));
+ if (vp) {
+ vp->Selectable.setValue(false);
+ vp->Transparency.setValue(90);
+ }
+ }
- ui->pushButtonAddProjFace->setChecked(false);
- onPushButtonAddProjFaceClicked();
+ ui->pushButtonAddProjFace->setChecked(false);
+ onPushButtonAddProjFaceClicked();
+ }
}
- }
}
void PartGui::DlgProjectionOnSurface::get_camera_direction()
{
- auto mainWindow = Gui::getMainWindow();
+ auto mainWindow = Gui::getMainWindow();
- auto mdiObject = dynamic_cast(mainWindow->activeWindow());
- if (!mdiObject)
- return;
- auto camerRotation = mdiObject->getViewer()->getCameraOrientation();
-
- SbVec3f lookAt(0, 0, -1);
- camerRotation.multVec(lookAt, lookAt);
-
- float valX, valY, valZ;
- lookAt.getValue(valX, valY, valZ);
-
- ui->doubleSpinBoxDirX->setValue(valX);
- ui->doubleSpinBoxDirY->setValue(valY);
- ui->doubleSpinBoxDirZ->setValue(valZ);
-}
-
-void PartGui::DlgProjectionOnSurface::store_current_selected_parts(std::vector& iStoreVec, const unsigned int iColor)
-{
- if (!m_partDocument)
- return;
- std::vector selObj = Gui::Selection().getSelectionEx();
- if (!selObj.empty())
- {
- for (auto it = selObj.begin(); it != selObj.end(); ++it)
- {
- auto aPart = dynamic_cast(it->getObject());
- if (!aPart) continue;
-
- if (aPart)
- {
- SShapeStore currentShapeStore;
- currentShapeStore.inputShape = aPart->Shape.getShape().getShape();
- currentShapeStore.partFeature = aPart;
- currentShapeStore.partName = aPart->getNameInDocument();
-
- PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(aPart));
- if (vp)
- {
- currentShapeStore.is_selectable = vp->Selectable.getValue();
- currentShapeStore.transparency = vp->Transparency.getValue();
- }
- if (!it->getSubNames().empty() )
- {
- auto parentShape = currentShapeStore.inputShape;
- for (const auto & itName : selObj.front().getSubNames())
- {
- auto currentShape = aPart->Shape.getShape().getSubShape(itName.c_str());
-
- transform_shape_to_global_position(currentShape, aPart);
-
- currentShapeStore.inputShape = currentShape;
- currentShapeStore.partName = itName;
- auto store = store_part_in_vector(currentShapeStore, iStoreVec);
- higlight_object(aPart, itName, store, iColor);
- store_wire_in_vector(currentShapeStore, parentShape, iStoreVec, iColor);
- }
- }
- else
- {
- transform_shape_to_global_position(currentShapeStore.inputShape,currentShapeStore.partFeature);
- auto store = store_part_in_vector(currentShapeStore, iStoreVec);
- higlight_object(aPart, aPart->Shape.getName(), store, iColor);
- }
- Gui::Selection().clearSelection(m_partDocument->getName());
- Gui::Selection().rmvPreselect();
- }
- }
- }
-}
-
-bool PartGui::DlgProjectionOnSurface::store_part_in_vector(SShapeStore& iCurrentShape, std::vector& iStoreVec)
-{
- if (iCurrentShape.inputShape.IsNull())
- return false;
- auto currentType = iCurrentShape.inputShape.ShapeType();
- for ( auto it = iStoreVec.begin(); it != iStoreVec.end(); ++it)
- {
- if ( currentType == TopAbs_FACE )
- {
- if (it->aFace.IsSame(iCurrentShape.inputShape))
- {
- iStoreVec.erase(it);
- return false;
- }
- }
- else if ( currentType == TopAbs_EDGE )
- {
- if (it->aEdge.IsSame(iCurrentShape.inputShape))
- {
- iStoreVec.erase(it);
- return false;
- }
- }
- }
-
- if (currentType == TopAbs_FACE)
- {
- iCurrentShape.aFace = TopoDS::Face(iCurrentShape.inputShape);
- }
- else if (currentType == TopAbs_EDGE)
- {
- iCurrentShape.aEdge = TopoDS::Edge(iCurrentShape.inputShape);
- }
-
- auto valX = ui->doubleSpinBoxDirX->value();
- auto valY = ui->doubleSpinBoxDirY->value();
- auto valZ = ui->doubleSpinBoxDirZ->value();
-
- iCurrentShape.aProjectionDir = gp_Dir(valX, valY, valZ);
- if ( !m_projectionSurfaceVec.empty() )
- {
- iCurrentShape.surfaceToProject = m_projectionSurfaceVec.front().aFace;
- }
- iStoreVec.push_back(iCurrentShape);
- return true;
-}
-
-void PartGui::DlgProjectionOnSurface::create_projection_wire(std::vector& iCurrentShape)
-{
- try
- {
- if (iCurrentShape.empty())
+ auto mdiObject = dynamic_cast(mainWindow->activeWindow());
+ if (!mdiObject) {
return;
- for ( auto &itCurrentShape : iCurrentShape )
- {
- if (m_projectionSurfaceVec.empty()) continue;;
- if (!itCurrentShape.aProjectedEdgeVec.empty()) continue;;
- if (!itCurrentShape.aProjectedFace.IsNull()) continue;;
- if (!itCurrentShape.aProjectedWireVec.empty()) continue;;
-
- if (!itCurrentShape.aFace.IsNull())
- {
- get_all_wire_from_face(itCurrentShape);
- for (const auto& itWire : itCurrentShape.aWireVec)
- {
- BRepProj_Projection aProjection(itWire, itCurrentShape.surfaceToProject, itCurrentShape.aProjectionDir);
- double minDistance = std::numeric_limits::max();
- TopoDS_Wire wireToTake;
- for ( ; aProjection.More(); aProjection.Next() )
- {
- auto it = aProjection.Current();
- BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aFace);
- distanceMeasure.Perform();
- auto currentDistance = distanceMeasure.Value();
- if ( currentDistance > minDistance ) continue;
- wireToTake = it;
- minDistance = currentDistance;
- }
- auto aWire = sort_and_heal_wire(wireToTake, itCurrentShape.surfaceToProject);
- itCurrentShape.aProjectedWireVec.push_back(aWire);
- }
- }
- else if (!itCurrentShape.aEdge.IsNull())
- {
- BRepProj_Projection aProjection(itCurrentShape.aEdge, itCurrentShape.surfaceToProject, itCurrentShape.aProjectionDir);
- double minDistance = std::numeric_limits::max();
- TopoDS_Wire wireToTake;
- for (; aProjection.More(); aProjection.Next())
- {
- auto it = aProjection.Current();
- BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aEdge);
- distanceMeasure.Perform();
- auto currentDistance = distanceMeasure.Value();
- if (currentDistance > minDistance) continue;
- wireToTake = it;
- minDistance = currentDistance;
- }
- for (TopExp_Explorer aExplorer(wireToTake, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
- {
- itCurrentShape.aProjectedEdgeVec.push_back(TopoDS::Edge(aExplorer.Current()));
- }
- }
-
}
- }
- catch (const Standard_Failure& error)
- {
- std::stringstream ssOcc;
- error.Print(ssOcc);
- throw Base::ValueError(ssOcc.str().c_str());
- }
+ auto camerRotation = mdiObject->getViewer()->getCameraOrientation();
+
+ SbVec3f lookAt(0, 0, -1);
+ camerRotation.multVec(lookAt, lookAt);
+
+ float valX {};
+ float valY {};
+ float valZ {};
+ lookAt.getValue(valX, valY, valZ);
+
+ ui->doubleSpinBoxDirX->setValue(valX);
+ ui->doubleSpinBoxDirY->setValue(valY);
+ ui->doubleSpinBoxDirZ->setValue(valZ);
}
-TopoDS_Shape PartGui::DlgProjectionOnSurface::create_compound(const std::vector& iShapeVec)
+void PartGui::DlgProjectionOnSurface::store_current_selected_parts(
+ std::vector& iStoreVec,
+ unsigned int iColor)
{
- if (iShapeVec.empty())
- return {};
-
- TopoDS_Compound aCompound;
- TopoDS_Builder aBuilder;
- aBuilder.MakeCompound(aCompound);
-
- for (const auto& it : iShapeVec)
- {
- if ( m_currentShowType == "edges" )
- {
- for (const auto& it2 : it.aProjectedEdgeVec)
- {
- aBuilder.Add(aCompound, it2);
- }
- for (const auto& it2 : it.aProjectedWireVec)
- {
- aBuilder.Add(aCompound, it2);
- }
- continue;
- }
- else if ( m_currentShowType == "faces" )
- {
- if (it.aProjectedFace.IsNull())
- {
- for (const auto& it2 : it.aProjectedWireVec)
- {
- if (!it2.IsNull())
- {
- aBuilder.Add(aCompound, it2);
- }
- }
- }
- else aBuilder.Add(aCompound, it.aProjectedFace);
- continue;
- }
- else if ( m_currentShowType == "all" )
- {
- if (!it.aProjectedSolid.IsNull())
- {
- aBuilder.Add(aCompound, it.aProjectedSolid);
- }
- else if ( !it.aProjectedFace.IsNull() )
- {
- aBuilder.Add(aCompound, it.aProjectedFace);
- }
- else if (!it.aProjectedWireVec.empty())
- {
- for (const auto& itWire : it.aProjectedWireVec )
- {
- if ( itWire.IsNull() ) continue;
- aBuilder.Add(aCompound, itWire);
- }
- }
- else if (!it.aProjectedEdgeVec.empty())
- {
- for (const auto& itEdge : it.aProjectedEdgeVec)
- {
- if (itEdge.IsNull()) continue;
- aBuilder.Add(aCompound, itEdge);
- }
- }
- }
- }
- return TopoDS_Shape(std::move(aCompound));
-}
-
-void PartGui::DlgProjectionOnSurface::show_projected_shapes(const std::vector& iShapeStoreVec)
-{
- if (!m_projectionObject)
- return;
- auto aCompound = create_compound(iShapeStoreVec);
- if ( aCompound.IsNull() )
- {
- if (!m_partDocument)
+ if (!m_partDocument) {
return;
- m_projectionObject->Shape.setValue(TopoDS_Shape());
- return;
- }
- auto currentPlacement = m_projectionObject->Placement.getValue();
- m_projectionObject->Shape.setValue(aCompound);
- m_projectionObject->Placement.setValue(currentPlacement);
+ }
+ std::vector selObj = Gui::Selection().getSelectionEx();
+ if (!selObj.empty()) {
+ for (auto it = selObj.begin(); it != selObj.end(); ++it) {
+ auto aPart = dynamic_cast(it->getObject());
+ if (!aPart) {
+ continue;
+ }
- //set color
- PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(m_projectionObject));
- if (vp)
- {
- vp->LineColor.setValue(0x8ae23400);
- vp->ShapeColor.setValue(0x8ae23400);
- vp->PointColor.setValue(0x8ae23400);
- vp->Transparency.setValue(0);
- }
+ if (aPart) {
+ SShapeStore currentShapeStore;
+ currentShapeStore.inputShape = aPart->Shape.getShape().getShape();
+ currentShapeStore.partFeature = aPart;
+ currentShapeStore.partName = aPart->getNameInDocument();
+
+ auto vp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(aPart));
+ if (vp) {
+ currentShapeStore.is_selectable = vp->Selectable.getValue();
+ currentShapeStore.transparency = vp->Transparency.getValue();
+ }
+ if (!it->getSubNames().empty()) {
+ auto parentShape = currentShapeStore.inputShape;
+ for (const auto& itName : selObj.front().getSubNames()) {
+ auto currentShape = aPart->Shape.getShape().getSubShape(itName.c_str());
+
+ transform_shape_to_global_position(currentShape, aPart);
+
+ currentShapeStore.inputShape = currentShape;
+ currentShapeStore.partName = itName;
+ auto store = store_part_in_vector(currentShapeStore, iStoreVec);
+ higlight_object(aPart, itName, store, iColor);
+ store_wire_in_vector(currentShapeStore, parentShape, iStoreVec, iColor);
+ }
+ }
+ else {
+ transform_shape_to_global_position(currentShapeStore.inputShape,
+ currentShapeStore.partFeature);
+ auto store = store_part_in_vector(currentShapeStore, iStoreVec);
+ higlight_object(aPart, aPart->Shape.getName(), store, iColor);
+ }
+ Gui::Selection().clearSelection(m_partDocument->getName());
+ Gui::Selection().rmvPreselect();
+ }
+ }
+ }
}
-void PartGui::DlgProjectionOnSurface::disable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis)
+bool PartGui::DlgProjectionOnSurface::store_part_in_vector(SShapeStore& iCurrentShape,
+ std::vector& iStoreVec)
{
- for ( auto it : iObjectVec )
- {
- if ( !it ) continue;
- if ( it == iExceptThis ) continue;
- it->setDisabled(true);
- }
+ if (iCurrentShape.inputShape.IsNull()) {
+ return false;
+ }
+ auto currentType = iCurrentShape.inputShape.ShapeType();
+ for (auto it = iStoreVec.begin(); it != iStoreVec.end(); ++it) {
+ if (currentType == TopAbs_FACE) {
+ if (it->aFace.IsSame(iCurrentShape.inputShape)) {
+ iStoreVec.erase(it);
+ return false;
+ }
+ }
+ else if (currentType == TopAbs_EDGE) {
+ if (it->aEdge.IsSame(iCurrentShape.inputShape)) {
+ iStoreVec.erase(it);
+ return false;
+ }
+ }
+ }
+
+ if (currentType == TopAbs_FACE) {
+ iCurrentShape.aFace = TopoDS::Face(iCurrentShape.inputShape);
+ }
+ else if (currentType == TopAbs_EDGE) {
+ iCurrentShape.aEdge = TopoDS::Edge(iCurrentShape.inputShape);
+ }
+
+ auto valX = ui->doubleSpinBoxDirX->value();
+ auto valY = ui->doubleSpinBoxDirY->value();
+ auto valZ = ui->doubleSpinBoxDirZ->value();
+
+ iCurrentShape.aProjectionDir = gp_Dir(valX, valY, valZ);
+ if (!m_projectionSurfaceVec.empty()) {
+ iCurrentShape.surfaceToProject = m_projectionSurfaceVec.front().aFace;
+ }
+ iStoreVec.push_back(iCurrentShape);
+ return true;
}
-void PartGui::DlgProjectionOnSurface::enable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis)
+void PartGui::DlgProjectionOnSurface::create_projection_wire(
+ std::vector& iCurrentShape)
{
- for (auto it : iObjectVec)
- {
- if (!it) continue;
- if (it == iExceptThis) continue;
- it->setEnabled(true);
- }
+ try {
+ if (iCurrentShape.empty()) {
+ return;
+ }
+ for (auto& itCurrentShape : iCurrentShape) {
+ if (m_projectionSurfaceVec.empty()) {
+ continue;
+ };
+ if (!itCurrentShape.aProjectedEdgeVec.empty()) {
+ continue;
+ };
+ if (!itCurrentShape.aProjectedFace.IsNull()) {
+ continue;
+ };
+ if (!itCurrentShape.aProjectedWireVec.empty()) {
+ continue;
+ };
+
+ if (!itCurrentShape.aFace.IsNull()) {
+ get_all_wire_from_face(itCurrentShape);
+ for (const auto& itWire : itCurrentShape.aWireVec) {
+ BRepProj_Projection aProjection(itWire,
+ itCurrentShape.surfaceToProject,
+ itCurrentShape.aProjectionDir);
+ double minDistance = std::numeric_limits::max();
+ TopoDS_Wire wireToTake;
+ for (; aProjection.More(); aProjection.Next()) {
+ auto it = aProjection.Current();
+ BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aFace);
+ distanceMeasure.Perform();
+ auto currentDistance = distanceMeasure.Value();
+ if (currentDistance > minDistance) {
+ continue;
+ }
+ wireToTake = it;
+ minDistance = currentDistance;
+ }
+ auto aWire = sort_and_heal_wire(wireToTake, itCurrentShape.surfaceToProject);
+ itCurrentShape.aProjectedWireVec.push_back(aWire);
+ }
+ }
+ else if (!itCurrentShape.aEdge.IsNull()) {
+ BRepProj_Projection aProjection(itCurrentShape.aEdge,
+ itCurrentShape.surfaceToProject,
+ itCurrentShape.aProjectionDir);
+ double minDistance = std::numeric_limits::max();
+ TopoDS_Wire wireToTake;
+ for (; aProjection.More(); aProjection.Next()) {
+ auto it = aProjection.Current();
+ BRepExtrema_DistShapeShape distanceMeasure(it, itCurrentShape.aEdge);
+ distanceMeasure.Perform();
+ auto currentDistance = distanceMeasure.Value();
+ if (currentDistance > minDistance) {
+ continue;
+ }
+ wireToTake = it;
+ minDistance = currentDistance;
+ }
+ for (TopExp_Explorer aExplorer(wireToTake, TopAbs_EDGE); aExplorer.More();
+ aExplorer.Next()) {
+ itCurrentShape.aProjectedEdgeVec.push_back(TopoDS::Edge(aExplorer.Current()));
+ }
+ }
+ }
+ }
+ catch (const Standard_Failure& error) {
+ std::stringstream ssOcc;
+ error.Print(ssOcc);
+ throw Base::ValueError(ssOcc.str().c_str());
+ }
}
-void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObject, const std::string& iShapeName, bool iHighlight, const unsigned int iColor)
+TopoDS_Shape
+PartGui::DlgProjectionOnSurface::create_compound(const std::vector& iShapeVec)
{
- if (!iCurrentObject)
- return;
- auto partenShape = iCurrentObject->Shape.getShape().getShape();
- auto subShape = iCurrentObject->Shape.getShape().getSubShape(iShapeName.c_str(), true);
-
- TopoDS_Shape currentShape = subShape;
- if (subShape.IsNull()) currentShape = partenShape;
-
- auto currentShapeType = currentShape.ShapeType();
- TopTools_IndexedMapOfShape anIndices;
- TopExp::MapShapes(partenShape, currentShapeType, anIndices);
- if (anIndices.IsEmpty())
- return;
- if (!anIndices.Contains(currentShape))
- return;
- auto index = anIndices.FindIndex(currentShape);
-
- //set color
- PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(iCurrentObject));
- if (vp)
- {
- std::vector colors;
- App::Color defaultColor;
- if (currentShapeType == TopAbs_FACE)
- {
- colors = vp->DiffuseColor.getValues();
- defaultColor = vp->ShapeColor.getValue();
- }
- else if ( currentShapeType == TopAbs_EDGE )
- {
- colors = vp->LineColorArray.getValues();
- defaultColor = vp->LineColor.getValue();
+ if (iShapeVec.empty()) {
+ return {};
}
- if ( static_cast(colors.size()) != anIndices.Extent() )
- {
- colors.resize(anIndices.Extent(), defaultColor);
+ TopoDS_Compound aCompound;
+ TopoDS_Builder aBuilder;
+ aBuilder.MakeCompound(aCompound);
+
+ for (const auto& it : iShapeVec) {
+ if (m_currentShowType == "edges") {
+ for (const auto& it2 : it.aProjectedEdgeVec) {
+ aBuilder.Add(aCompound, it2);
+ }
+ for (const auto& it2 : it.aProjectedWireVec) {
+ aBuilder.Add(aCompound, it2);
+ }
+ }
+ else if (m_currentShowType == "faces") {
+ if (it.aProjectedFace.IsNull()) {
+ for (const auto& it2 : it.aProjectedWireVec) {
+ if (!it2.IsNull()) {
+ aBuilder.Add(aCompound, it2);
+ }
+ }
+ }
+ else {
+ aBuilder.Add(aCompound, it.aProjectedFace);
+ }
+ }
+ else if (m_currentShowType == "all") {
+ if (!it.aProjectedSolid.IsNull()) {
+ aBuilder.Add(aCompound, it.aProjectedSolid);
+ }
+ else if (!it.aProjectedFace.IsNull()) {
+ aBuilder.Add(aCompound, it.aProjectedFace);
+ }
+ else if (!it.aProjectedWireVec.empty()) {
+ for (const auto& itWire : it.aProjectedWireVec) {
+ if (itWire.IsNull()) {
+ continue;
+ }
+ aBuilder.Add(aCompound, itWire);
+ }
+ }
+ else if (!it.aProjectedEdgeVec.empty()) {
+ for (const auto& itEdge : it.aProjectedEdgeVec) {
+ if (itEdge.IsNull()) {
+ continue;
+ }
+ aBuilder.Add(aCompound, itEdge);
+ }
+ }
+ }
+ }
+ return {std::move(aCompound)};
+}
+
+void PartGui::DlgProjectionOnSurface::show_projected_shapes(
+ const std::vector& iShapeStoreVec)
+{
+ if (!m_projectionObject) {
+ return;
+ }
+ auto aCompound = create_compound(iShapeStoreVec);
+ if (aCompound.IsNull()) {
+ if (!m_partDocument) {
+ return;
+ }
+ m_projectionObject->Shape.setValue(TopoDS_Shape());
+ return;
+ }
+ auto currentPlacement = m_projectionObject->Placement.getValue();
+ m_projectionObject->Shape.setValue(aCompound);
+ m_projectionObject->Placement.setValue(currentPlacement);
+
+ // set color
+ auto vp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(m_projectionObject));
+ if (vp) {
+ const unsigned int color = 0x8ae23400;
+ vp->LineColor.setValue(color);
+ vp->ShapeColor.setValue(color);
+ vp->PointColor.setValue(color);
+ vp->Transparency.setValue(0);
+ }
+}
+
+void PartGui::DlgProjectionOnSurface::disable_ui_elements(const std::vector& iObjectVec,
+ QWidget* iExceptThis)
+{
+ for (auto it : iObjectVec) {
+ if (!it) {
+ continue;
+ }
+ if (it == iExceptThis) {
+ continue;
+ }
+ it->setDisabled(true);
+ }
+}
+
+void PartGui::DlgProjectionOnSurface::enable_ui_elements(const std::vector& iObjectVec,
+ QWidget* iExceptThis)
+{
+ for (auto it : iObjectVec) {
+ if (!it) {
+ continue;
+ }
+ if (it == iExceptThis) {
+ continue;
+ }
+ it->setEnabled(true);
+ }
+}
+
+void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObject,
+ const std::string& iShapeName,
+ bool iHighlight,
+ unsigned int iColor)
+{
+ if (!iCurrentObject) {
+ return;
+ }
+ auto partenShape = iCurrentObject->Shape.getShape().getShape();
+ auto subShape = iCurrentObject->Shape.getShape().getSubShape(iShapeName.c_str(), true);
+
+ TopoDS_Shape currentShape = subShape;
+ if (subShape.IsNull()) {
+ currentShape = partenShape;
}
- if ( iHighlight )
- {
- App::Color aColor;
- aColor.setPackedValue(iColor);
- colors.at(index - 1) = aColor;
+ auto currentShapeType = currentShape.ShapeType();
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(partenShape, currentShapeType, anIndices);
+ if (anIndices.IsEmpty()) {
+ return;
}
- else
- {
- colors.at(index - 1) = defaultColor;
+ if (!anIndices.Contains(currentShape)) {
+ return;
}
- if (currentShapeType == TopAbs_FACE)
- {
- vp->DiffuseColor.setValues(colors);
+ auto index = anIndices.FindIndex(currentShape);
+
+ // set color
+ auto vp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(iCurrentObject));
+ if (vp) {
+ std::vector colors;
+ App::Color defaultColor;
+ if (currentShapeType == TopAbs_FACE) {
+ colors = vp->DiffuseColor.getValues();
+ defaultColor = vp->ShapeColor.getValue();
+ }
+ else if (currentShapeType == TopAbs_EDGE) {
+ colors = vp->LineColorArray.getValues();
+ defaultColor = vp->LineColor.getValue();
+ }
+
+ if (static_cast(colors.size()) != anIndices.Extent()) {
+ colors.resize(anIndices.Extent(), defaultColor);
+ }
+
+ if (iHighlight) {
+ App::Color aColor;
+ aColor.setPackedValue(iColor);
+ colors.at(index - 1) = aColor;
+ }
+ else {
+ colors.at(index - 1) = defaultColor;
+ }
+ if (currentShapeType == TopAbs_FACE) {
+ vp->DiffuseColor.setValues(colors);
+ }
+ else if (currentShapeType == TopAbs_EDGE) {
+ vp->LineColorArray.setValues(colors);
+ }
}
- else if (currentShapeType == TopAbs_EDGE)
- {
- vp->LineColorArray.setValues(colors);
- }
- }
}
void PartGui::DlgProjectionOnSurface::get_all_wire_from_face(SShapeStore& ioCurrentSahpe)
{
- auto outerWire = ShapeAnalysis::OuterWire(ioCurrentSahpe.aFace);
- ioCurrentSahpe.aWireVec.push_back(outerWire);
- for (TopExp_Explorer aExplorer(ioCurrentSahpe.aFace, TopAbs_WIRE); aExplorer.More(); aExplorer.Next())
- {
- auto currentWire = TopoDS::Wire(aExplorer.Current());
- if (currentWire.IsSame(outerWire)) continue;
- ioCurrentSahpe.aWireVec.push_back(currentWire);
- }
-}
-
-void PartGui::DlgProjectionOnSurface::create_projection_face_from_wire(std::vector& iCurrentShape)
-{
- try
- {
- if (iCurrentShape.empty())
- return;
-
- for ( auto &itCurrentShape : iCurrentShape )
- {
- if (itCurrentShape.aFace.IsNull()) continue;;
- if (itCurrentShape.aProjectedWireVec.empty()) continue;;
- if (!itCurrentShape.aProjectedFace.IsNull()) continue;;
-
- auto surface = BRep_Tool::Surface(itCurrentShape.surfaceToProject);
-
- //create a wire of all edges in parametric space on the surface of the face to projected
- // --> otherwise BRepBuilderAPI_MakeFace can not make a face from the wire!
- for (const auto& itWireVec : itCurrentShape.aProjectedWireVec)
- {
- std::vector edgeVec;
- for (TopExp_Explorer aExplorer(itWireVec, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
- {
- auto currentEdge = TopoDS::Edge(aExplorer.Current());
- edgeVec.push_back(currentEdge);
+ auto outerWire = ShapeAnalysis::OuterWire(ioCurrentSahpe.aFace);
+ ioCurrentSahpe.aWireVec.push_back(outerWire);
+ for (TopExp_Explorer aExplorer(ioCurrentSahpe.aFace, TopAbs_WIRE); aExplorer.More();
+ aExplorer.Next()) {
+ auto currentWire = TopoDS::Wire(aExplorer.Current());
+ if (currentWire.IsSame(outerWire)) {
+ continue;
}
- if (edgeVec.empty()) continue;
-
- std::vector edgeInParametricSpaceVec;
- for (auto itEdge : edgeVec)
- {
- Standard_Real first, last;
- auto currentCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(itEdge), itCurrentShape.surfaceToProject, first, last);
- if (!currentCurve) continue;
- auto edgeInParametricSpace = BRepBuilderAPI_MakeEdge(currentCurve, surface, first,last).Edge();
- edgeInParametricSpaceVec.push_back(edgeInParametricSpace);
- }
- auto aWire = sort_and_heal_wire(edgeInParametricSpaceVec, itCurrentShape.surfaceToProject);
- itCurrentShape.aProjectedWireInParametricSpaceVec.push_back(aWire);
- }
-
- // try to create a face from the wires
- // the first wire is the otherwise
- // the following wires are the inside wires
- BRepBuilderAPI_MakeFace faceMaker;
- bool first = true;
- for (auto itWireVec : itCurrentShape.aProjectedWireInParametricSpaceVec)
- {
- if (first)
- {
- first = false;
- // change the wire direction, otherwise no face is created
- auto currentWire = TopoDS::Wire(itWireVec.Reversed());
- if (itCurrentShape.surfaceToProject.Orientation() == TopAbs_REVERSED) currentWire = itWireVec;
- faceMaker = BRepBuilderAPI_MakeFace(surface, currentWire);
- ShapeFix_Face fix(faceMaker.Face());
- fix.Perform();
- auto aFace = fix.Face();
- BRepCheck_Analyzer aChecker(aFace);
- if (!aChecker.IsValid())
- {
- faceMaker = BRepBuilderAPI_MakeFace(surface, TopoDS::Wire(currentWire.Reversed()));
- }
- }
- else
- {
- // make a copy of the current face maker
- // if the face fails just try again with the copy
- TopoDS_Face tempCopy = BRepBuilderAPI_MakeFace(faceMaker.Face()).Face();
- faceMaker.Add(TopoDS::Wire(itWireVec.Reversed()));
- ShapeFix_Face fix(faceMaker.Face());
- fix.Perform();
- auto aFace = fix.Face();
- BRepCheck_Analyzer aChecker(aFace);
- if (!aChecker.IsValid())
- {
- faceMaker = BRepBuilderAPI_MakeFace(tempCopy);
- faceMaker.Add(TopoDS::Wire(itWireVec));
- }
- }
- }
- //auto doneFlag = faceMaker.IsDone();
- //auto error = faceMaker.Error();
- itCurrentShape.aProjectedFace = faceMaker.Face();
+ ioCurrentSahpe.aWireVec.push_back(currentWire);
}
- }
- catch (const Standard_Failure& error)
- {
- std::stringstream ssOcc;
- error.Print(ssOcc);
- throw Base::ValueError(ssOcc.str().c_str());
- }
}
-TopoDS_Wire PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const TopoDS_Shape& iShape, const TopoDS_Face& iFaceToProject)
+void PartGui::DlgProjectionOnSurface::create_projection_face_from_wire(
+ std::vector& iCurrentShape)
{
- std::vector aEdgeVec;
- for (TopExp_Explorer aExplorer(iShape, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
- {
- auto anEdge = TopoDS::Edge(aExplorer.Current());
- aEdgeVec.push_back(anEdge);
- }
- return sort_and_heal_wire(aEdgeVec, iFaceToProject);
+ try {
+ if (iCurrentShape.empty()) {
+ return;
+ }
+
+ for (auto& itCurrentShape : iCurrentShape) {
+ if (itCurrentShape.aFace.IsNull()) {
+ continue;
+ };
+ if (itCurrentShape.aProjectedWireVec.empty()) {
+ continue;
+ };
+ if (!itCurrentShape.aProjectedFace.IsNull()) {
+ continue;
+ };
+
+ auto surface = BRep_Tool::Surface(itCurrentShape.surfaceToProject);
+
+ // create a wire of all edges in parametric space on the surface of the face to
+ // projected
+ // --> otherwise BRepBuilderAPI_MakeFace can not make a face from the wire!
+ for (const auto& itWireVec : itCurrentShape.aProjectedWireVec) {
+ std::vector edgeVec;
+ for (TopExp_Explorer aExplorer(itWireVec, TopAbs_EDGE); aExplorer.More();
+ aExplorer.Next()) {
+ auto currentEdge = TopoDS::Edge(aExplorer.Current());
+ edgeVec.push_back(currentEdge);
+ }
+ if (edgeVec.empty()) {
+ continue;
+ }
+
+ std::vector edgeInParametricSpaceVec;
+ for (auto itEdge : edgeVec) {
+ Standard_Real first {};
+ Standard_Real last {};
+ auto currentCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(itEdge),
+ itCurrentShape.surfaceToProject,
+ first,
+ last);
+ if (!currentCurve) {
+ continue;
+ }
+ auto edgeInParametricSpace =
+ BRepBuilderAPI_MakeEdge(currentCurve, surface, first, last).Edge();
+ edgeInParametricSpaceVec.push_back(edgeInParametricSpace);
+ }
+ auto aWire =
+ sort_and_heal_wire(edgeInParametricSpaceVec, itCurrentShape.surfaceToProject);
+ itCurrentShape.aProjectedWireInParametricSpaceVec.push_back(aWire);
+ }
+
+ // try to create a face from the wires
+ // the first wire is the otherwise
+ // the following wires are the inside wires
+ BRepBuilderAPI_MakeFace faceMaker;
+ bool first = true;
+ for (auto itWireVec : itCurrentShape.aProjectedWireInParametricSpaceVec) {
+ if (first) {
+ first = false;
+ // change the wire direction, otherwise no face is created
+ auto currentWire = TopoDS::Wire(itWireVec.Reversed());
+ if (itCurrentShape.surfaceToProject.Orientation() == TopAbs_REVERSED) {
+ currentWire = itWireVec;
+ }
+ faceMaker = BRepBuilderAPI_MakeFace(surface, currentWire);
+ ShapeFix_Face fix(faceMaker.Face());
+ fix.Perform();
+ auto aFace = fix.Face();
+ BRepCheck_Analyzer aChecker(aFace);
+ if (!aChecker.IsValid()) {
+ faceMaker =
+ BRepBuilderAPI_MakeFace(surface, TopoDS::Wire(currentWire.Reversed()));
+ }
+ }
+ else {
+ // make a copy of the current face maker
+ // if the face fails just try again with the copy
+ TopoDS_Face tempCopy = BRepBuilderAPI_MakeFace(faceMaker.Face()).Face();
+ faceMaker.Add(TopoDS::Wire(itWireVec.Reversed()));
+ ShapeFix_Face fix(faceMaker.Face());
+ fix.Perform();
+ auto aFace = fix.Face();
+ BRepCheck_Analyzer aChecker(aFace);
+ if (!aChecker.IsValid()) {
+ faceMaker = BRepBuilderAPI_MakeFace(tempCopy);
+ faceMaker.Add(TopoDS::Wire(itWireVec));
+ }
+ }
+ }
+ // auto doneFlag = faceMaker.IsDone();
+ // auto error = faceMaker.Error();
+ itCurrentShape.aProjectedFace = faceMaker.Face();
+ }
+ }
+ catch (const Standard_Failure& error) {
+ std::stringstream ssOcc;
+ error.Print(ssOcc);
+ throw Base::ValueError(ssOcc.str().c_str());
+ }
}
-TopoDS_Wire PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const std::vector& iEdgeVec, const TopoDS_Face& iFaceToProject)
+TopoDS_Wire PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const TopoDS_Shape& iShape,
+ const TopoDS_Face& iFaceToProject)
{
- // try to sort and heal all wires
-// if the wires are not clean making a face will fail!
- ShapeAnalysis_FreeBounds shapeAnalyzer;
- Handle(TopTools_HSequenceOfShape) shapeList = new TopTools_HSequenceOfShape;
- Handle(TopTools_HSequenceOfShape) aWireHandle;
- Handle(TopTools_HSequenceOfShape) aWireWireHandle;
+ std::vector aEdgeVec;
+ for (TopExp_Explorer aExplorer(iShape, TopAbs_EDGE); aExplorer.More(); aExplorer.Next()) {
+ auto anEdge = TopoDS::Edge(aExplorer.Current());
+ aEdgeVec.push_back(anEdge);
+ }
+ return sort_and_heal_wire(aEdgeVec, iFaceToProject);
+}
- for (const auto& it : iEdgeVec)
- {
- shapeList->Append(it);
- }
+TopoDS_Wire
+PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const std::vector& iEdgeVec,
+ const TopoDS_Face& iFaceToProject)
+{
+ // try to sort and heal all wires
+ // if the wires are not clean making a face will fail!
+ ShapeAnalysis_FreeBounds shapeAnalyzer;
+ Handle(TopTools_HSequenceOfShape) shapeList = new TopTools_HSequenceOfShape;
+ Handle(TopTools_HSequenceOfShape) aWireHandle;
+ Handle(TopTools_HSequenceOfShape) aWireWireHandle;
- shapeAnalyzer.ConnectEdgesToWires(shapeList, 0.0001, false, aWireHandle);
- shapeAnalyzer.ConnectWiresToWires(aWireHandle, 0.0001, false, aWireWireHandle);
- if (!aWireWireHandle)
- return {};
- for (auto it = 1; it <= aWireWireHandle->Length(); ++it)
- {
- auto aShape = TopoDS::Wire(aWireWireHandle->Value(it));
- ShapeFix_Wire aWireRepair(aShape, iFaceToProject, 0.0001);
- aWireRepair.FixAddCurve3dMode() = 1;
- aWireRepair.FixAddPCurveMode() = 1;
- aWireRepair.Perform();
- //return aWireRepair.Wire();
- ShapeFix_Wireframe aWireFramFix(aWireRepair.Wire());
- auto retVal = aWireFramFix.FixWireGaps();
- retVal = aWireFramFix.FixSmallEdges();
- Q_UNUSED(retVal);
- return TopoDS::Wire(aWireFramFix.Shape());
- }
- return {};
+ for (const auto& it : iEdgeVec) {
+ shapeList->Append(it);
+ }
+
+ const double tolerance = 0.0001;
+ ShapeAnalysis_FreeBounds::ConnectEdgesToWires(shapeList, tolerance, false, aWireHandle);
+ ShapeAnalysis_FreeBounds::ConnectWiresToWires(aWireHandle, tolerance, false, aWireWireHandle);
+ if (!aWireWireHandle) {
+ return {};
+ }
+ for (auto it = 1; it <= aWireWireHandle->Length(); ++it) {
+ auto aShape = TopoDS::Wire(aWireWireHandle->Value(it));
+ ShapeFix_Wire aWireRepair(aShape, iFaceToProject, tolerance);
+ aWireRepair.FixAddCurve3dMode() = 1;
+ aWireRepair.FixAddPCurveMode() = 1;
+ aWireRepair.Perform();
+ // return aWireRepair.Wire();
+ ShapeFix_Wireframe aWireFramFix(aWireRepair.Wire());
+ aWireFramFix.FixWireGaps();
+ aWireFramFix.FixSmallEdges();
+ return TopoDS::Wire(aWireFramFix.Shape());
+ }
+ return {};
}
void PartGui::DlgProjectionOnSurface::create_face_extrude(std::vector& iCurrentShape)
{
- try
- {
- if (iCurrentShape.empty())
- return;
+ try {
+ if (iCurrentShape.empty()) {
+ return;
+ }
- auto height = ui->doubleSpinBoxExtrudeHeight->value();
+ auto height = ui->doubleSpinBoxExtrudeHeight->value();
- for ( auto &itCurrentShape : iCurrentShape )
- {
- if (itCurrentShape.aProjectedFace.IsNull()) continue;;
- if (itCurrentShape.extrudeValue == height) continue;;
+ for (auto& itCurrentShape : iCurrentShape) {
+ if (itCurrentShape.aProjectedFace.IsNull()) {
+ continue;
+ }
+ if (itCurrentShape.extrudeValue == height) {
+ continue;
+ }
- itCurrentShape.extrudeValue = height;
- if (height == 0)
- {
- itCurrentShape.aProjectedSolid.Nullify();
- }
- else
- {
- gp_Vec directionToExtrude(itCurrentShape.aProjectionDir.XYZ());
- directionToExtrude.Reverse();
- directionToExtrude.Multiply(height);
- BRepPrimAPI_MakePrism extrude(itCurrentShape.aProjectedFace, directionToExtrude);
- itCurrentShape.aProjectedSolid = extrude.Shape();
- }
+ itCurrentShape.extrudeValue = height;
+ if (height == 0) {
+ itCurrentShape.aProjectedSolid.Nullify();
+ }
+ else {
+ gp_Vec directionToExtrude(itCurrentShape.aProjectionDir.XYZ());
+ directionToExtrude.Reverse();
+ directionToExtrude.Multiply(height);
+ BRepPrimAPI_MakePrism extrude(itCurrentShape.aProjectedFace, directionToExtrude);
+ itCurrentShape.aProjectedSolid = extrude.Shape();
+ }
+ }
+ }
+ catch (const Standard_Failure& error) {
+ std::stringstream ssOcc;
+ error.Print(ssOcc);
+ throw Base::ValueError(ssOcc.str().c_str());
}
- }
- catch (const Standard_Failure& error)
- {
- std::stringstream ssOcc;
- error.Print(ssOcc);
- throw Base::ValueError(ssOcc.str().c_str());
- }
}
-void PartGui::DlgProjectionOnSurface::store_wire_in_vector(const SShapeStore& iCurrentShape, const TopoDS_Shape& iParentShape, std::vector& iStoreVec, const unsigned int iColor)
+void PartGui::DlgProjectionOnSurface::store_wire_in_vector(const SShapeStore& iCurrentShape,
+ const TopoDS_Shape& iParentShape,
+ std::vector& iStoreVec,
+ unsigned int iColor)
{
- if (m_currentSelection != "add_wire")
- return;
- if (iParentShape.IsNull())
- return;
- if (iCurrentShape.inputShape.IsNull())
- return;
- auto currentType = iCurrentShape.inputShape.ShapeType();
- if (currentType != TopAbs_EDGE)
- return;
-
- std::vector aWireVec;
- for (TopExp_Explorer aExplorer(iParentShape, TopAbs_WIRE); aExplorer.More(); aExplorer.Next())
- {
- aWireVec.push_back(TopoDS::Wire(aExplorer.Current()));
- }
-
- std::vector edgeVec;
- for (const auto& it : aWireVec )
- {
- bool edgeExists = false;
- for (TopExp_Explorer aExplorer(it, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
- {
- auto currentEdge = TopoDS::Edge(aExplorer.Current());
- edgeVec.push_back(currentEdge);
- if (currentEdge.IsSame(iCurrentShape.inputShape)) edgeExists = true;
- }
- if (edgeExists) break;
- edgeVec.clear();
- }
-
- if (edgeVec.empty())
- return;
- TopTools_IndexedMapOfShape indexMap;
- TopExp::MapShapes(iParentShape, TopAbs_EDGE, indexMap);
- if (indexMap.IsEmpty())
- return;
-
- for (const auto& it : edgeVec )
- {
- if ( it.IsSame(iCurrentShape.inputShape)) continue;
- if (!indexMap.Contains(it))
+ if (m_currentSelection != "add_wire") {
return;
- auto index = indexMap.FindIndex(it);
- auto newEdgeObject = iCurrentShape;
- newEdgeObject.inputShape = it;
- newEdgeObject.partName = "Edge" + std::to_string(index);
+ }
+ if (iParentShape.IsNull()) {
+ return;
+ }
+ if (iCurrentShape.inputShape.IsNull()) {
+ return;
+ }
+ auto currentType = iCurrentShape.inputShape.ShapeType();
+ if (currentType != TopAbs_EDGE) {
+ return;
+ }
- auto store = store_part_in_vector(newEdgeObject, iStoreVec);
- higlight_object(newEdgeObject.partFeature, newEdgeObject.partName, store, iColor);
- }
+ std::vector aWireVec;
+ for (TopExp_Explorer aExplorer(iParentShape, TopAbs_WIRE); aExplorer.More(); aExplorer.Next()) {
+ aWireVec.push_back(TopoDS::Wire(aExplorer.Current()));
+ }
+
+ std::vector edgeVec;
+ for (const auto& it : aWireVec) {
+ bool edgeExists = false;
+ for (TopExp_Explorer aExplorer(it, TopAbs_EDGE); aExplorer.More(); aExplorer.Next()) {
+ auto currentEdge = TopoDS::Edge(aExplorer.Current());
+ edgeVec.push_back(currentEdge);
+ if (currentEdge.IsSame(iCurrentShape.inputShape)) {
+ edgeExists = true;
+ }
+ }
+ if (edgeExists) {
+ break;
+ }
+ edgeVec.clear();
+ }
+
+ if (edgeVec.empty()) {
+ return;
+ }
+ TopTools_IndexedMapOfShape indexMap;
+ TopExp::MapShapes(iParentShape, TopAbs_EDGE, indexMap);
+ if (indexMap.IsEmpty()) {
+ return;
+ }
+
+ for (const auto& it : edgeVec) {
+ if (it.IsSame(iCurrentShape.inputShape)) {
+ continue;
+ }
+ if (!indexMap.Contains(it)) {
+ return;
+ }
+ auto index = indexMap.FindIndex(it);
+ auto newEdgeObject = iCurrentShape;
+ newEdgeObject.inputShape = it;
+ newEdgeObject.partName = "Edge" + std::to_string(index);
+
+ auto store = store_part_in_vector(newEdgeObject, iStoreVec);
+ higlight_object(newEdgeObject.partFeature, newEdgeObject.partName, store, iColor);
+ }
}
void PartGui::DlgProjectionOnSurface::set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox)
{
- auto currentVal = icurrentSpinBox->value();
- auto newVal = 0.0;
- if (currentVal != 1.0 && currentVal != -1.0)
- {
- newVal = -1;
- }
- else if (currentVal == 1.0)
- {
- newVal = -1;
- }
- else if (currentVal == -1.0)
- {
- newVal = 1;
- }
- ui->doubleSpinBoxDirX->setValue(0);
- ui->doubleSpinBoxDirY->setValue(0);
- ui->doubleSpinBoxDirZ->setValue(0);
- icurrentSpinBox->setValue(newVal);
+ auto currentVal = icurrentSpinBox->value();
+ auto newVal = 0.0;
+ if (currentVal != 1.0 && currentVal != -1.0) {
+ newVal = -1;
+ }
+ else if (currentVal == 1.0) {
+ newVal = -1;
+ }
+ else if (currentVal == -1.0) {
+ newVal = 1;
+ }
+ ui->doubleSpinBoxDirX->setValue(0);
+ ui->doubleSpinBoxDirY->setValue(0);
+ ui->doubleSpinBoxDirZ->setValue(0);
+ icurrentSpinBox->setValue(newVal);
}
-void PartGui::DlgProjectionOnSurface::transform_shape_to_global_position(TopoDS_Shape& ioShape, Part::Feature* iPart)
+void PartGui::DlgProjectionOnSurface::transform_shape_to_global_position(TopoDS_Shape& ioShape,
+ Part::Feature* iPart)
{
- auto currentPos = iPart->Placement.getValue().getPosition();
- auto currentRotation = iPart->Placement.getValue().getRotation();
- auto globalPlacement = iPart->globalPlacement();
- auto globalPosition = globalPlacement.getPosition();
- auto globalRotation = globalPlacement.getRotation();
+ auto currentPos = iPart->Placement.getValue().getPosition();
+ auto currentRotation = iPart->Placement.getValue().getRotation();
+ auto globalPlacement = iPart->globalPlacement();
+ auto globalPosition = globalPlacement.getPosition();
+ auto globalRotation = globalPlacement.getRotation();
- if (currentRotation != globalRotation)
- {
- auto newRotation = globalRotation;
- newRotation *= currentRotation.invert();
+ if (currentRotation != globalRotation) {
+ auto newRotation = globalRotation;
+ newRotation *= currentRotation.invert();
- gp_Trsf aAngleTransform;
- Base::Vector3d rotationAxes;
- double rotationAngle;
- newRotation.getRawValue(rotationAxes, rotationAngle);
- aAngleTransform.SetRotation(gp_Ax1(gp_Pnt(currentPos.x, currentPos.y, currentPos.z), gp_Dir(rotationAxes.x, rotationAxes.y, rotationAxes.z)), rotationAngle);
- ioShape = BRepBuilderAPI_Transform(ioShape, aAngleTransform, true).Shape();
- }
+ gp_Trsf aAngleTransform;
+ Base::Vector3d rotationAxes;
+ double rotationAngle {};
+ newRotation.getRawValue(rotationAxes, rotationAngle);
+ aAngleTransform.SetRotation(gp_Ax1(gp_Pnt(currentPos.x, currentPos.y, currentPos.z),
+ gp_Dir(rotationAxes.x, rotationAxes.y, rotationAxes.z)),
+ rotationAngle);
+ ioShape = BRepBuilderAPI_Transform(ioShape, aAngleTransform, true).Shape();
+ }
- if (currentPos != globalPosition)
- {
- gp_Trsf aPosTransform;
- aPosTransform.SetTranslation(gp_Pnt(currentPos.x, currentPos.y, currentPos.z), gp_Pnt(globalPosition.x, globalPosition.y, globalPosition.z));
- ioShape = BRepBuilderAPI_Transform(ioShape, aPosTransform, true).Shape();
- }
+ if (currentPos != globalPosition) {
+ gp_Trsf aPosTransform;
+ aPosTransform.SetTranslation(gp_Pnt(currentPos.x, currentPos.y, currentPos.z),
+ gp_Pnt(globalPosition.x, globalPosition.y, globalPosition.z));
+ ioShape = BRepBuilderAPI_Transform(ioShape, aPosTransform, true).Shape();
+ }
}
void PartGui::DlgProjectionOnSurface::onPushButtonAddProjFaceClicked()
{
- if (ui->pushButtonAddProjFace->isChecked())
- {
- m_currentSelection = "add_projection_surface";
- disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
- if (!filterFace)
- {
- filterFace = new FaceSelection();
- Gui::Selection().addSelectionGate(filterFace);
+ if (ui->pushButtonAddProjFace->isChecked()) {
+ m_currentSelection = "add_projection_surface";
+ disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
+ if (!filterFace) {
+ filterFace = new FaceSelection();
+ Gui::Selection().addSelectionGate(filterFace);
+ }
+ }
+ else {
+ m_currentSelection = "";
+ enable_ui_elements(m_guiObjectVec, nullptr);
+ Gui::Selection().rmvSelectionGate();
+ filterFace = nullptr;
}
- }
- else
- {
- m_currentSelection = "";
- enable_ui_elements(m_guiObjectVec, nullptr);
- Gui::Selection().rmvSelectionGate();
- filterFace = nullptr;
- }
}
void PartGui::DlgProjectionOnSurface::onRadioButtonShowAllClicked()
{
- m_currentShowType = "all";
- show_projected_shapes(m_shapeVec);
+ m_currentShowType = "all";
+ show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::onRadioButtonFacesClicked()
{
- m_currentShowType = "faces";
- show_projected_shapes(m_shapeVec);
+ m_currentShowType = "faces";
+ show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::onRadioButtonEdgesClicked()
{
- m_currentShowType = "edges";
- show_projected_shapes(m_shapeVec);
+ m_currentShowType = "edges";
+ show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::onDoubleSpinBoxExtrudeHeightValueChanged(double arg1)
{
- Q_UNUSED(arg1);
- create_face_extrude(m_shapeVec);
- show_projected_shapes(m_shapeVec);
+ Q_UNUSED(arg1);
+ create_face_extrude(m_shapeVec);
+ show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::onPushButtonAddWireClicked()
{
- if (ui->pushButtonAddWire->isChecked())
- {
- m_currentSelection = "add_wire";
- disable_ui_elements(m_guiObjectVec, ui->pushButtonAddWire);
- if (!filterEdge)
- {
- filterEdge = new EdgeSelection();
- Gui::Selection().addSelectionGate(filterEdge);
+ if (ui->pushButtonAddWire->isChecked()) {
+ m_currentSelection = "add_wire";
+ disable_ui_elements(m_guiObjectVec, ui->pushButtonAddWire);
+ if (!filterEdge) {
+ filterEdge = new EdgeSelection();
+ Gui::Selection().addSelectionGate(filterEdge);
+ }
+ ui->radioButtonEdges->setChecked(true);
+ onRadioButtonEdgesClicked();
+ }
+ else {
+ m_currentSelection = "";
+ enable_ui_elements(m_guiObjectVec, nullptr);
+ Gui::Selection().rmvSelectionGate();
+ filterEdge = nullptr;
}
- ui->radioButtonEdges->setChecked(true);
- onRadioButtonEdgesClicked();
- }
- else
- {
- m_currentSelection = "";
- enable_ui_elements(m_guiObjectVec, nullptr);
- Gui::Selection().rmvSelectionGate();
- filterEdge = nullptr;
- }
}
void PartGui::DlgProjectionOnSurface::onDoubleSpinBoxSolidDepthValueChanged(double arg1)
{
- auto valX = ui->doubleSpinBoxDirX->value();
- auto valY = ui->doubleSpinBoxDirY->value();
- auto valZ = ui->doubleSpinBoxDirZ->value();
+ auto valX = ui->doubleSpinBoxDirX->value();
+ auto valY = ui->doubleSpinBoxDirY->value();
+ auto valZ = ui->doubleSpinBoxDirZ->value();
- auto valueToMove = arg1 - m_lastDepthVal;
- Base::Vector3d vectorToMove(valX, valY, valZ);
- vectorToMove *= valueToMove;
+ auto valueToMove = arg1 - m_lastDepthVal;
+ Base::Vector3d vectorToMove(valX, valY, valZ);
+ vectorToMove *= valueToMove;
- auto placment = m_projectionObject->Placement.getValue();
- placment.move(vectorToMove);
- m_projectionObject->Placement.setValue(placment);
+ auto placment = m_projectionObject->Placement.getValue();
+ placment.move(vectorToMove);
+ m_projectionObject->Placement.setValue(placment);
- m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
+ m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
}
// ---------------------------------------
TaskProjectionOnSurface::TaskProjectionOnSurface()
+ : widget(new DlgProjectionOnSurface())
+ , taskbox(new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
+ widget->windowTitle(),
+ true,
+ nullptr))
{
- widget = new DlgProjectionOnSurface();
- taskbox = new Gui::TaskView::TaskBox(
- Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
- widget->windowTitle(), true, nullptr);
- taskbox->groupLayout()->addWidget(widget);
- Content.push_back(taskbox);
+ taskbox->groupLayout()->addWidget(widget);
+ Content.push_back(taskbox);
}
bool TaskProjectionOnSurface::accept()
{
- widget->apply();
- return true;
- //return (widget->result() == QDialog::Accepted);
+ widget->apply();
+ return true;
}
bool TaskProjectionOnSurface::reject()
{
- widget->reject();
- return true;
+ widget->reject();
+ return true;
}
void TaskProjectionOnSurface::clicked(int id)
{
- if (id == QDialogButtonBox::Apply) {
- try {
- widget->apply();
+ if (id == QDialogButtonBox::Apply) {
+ try {
+ widget->apply();
+ }
+ catch (Base::AbortException&) {
+ }
}
- catch (Base::AbortException&) {
-
- };
- }
}
#include "moc_DlgProjectionOnSurface.cpp"
diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.h b/src/Mod/Part/Gui/DlgProjectionOnSurface.h
index ec1cd285b0..4a4f6c10bc 100644
--- a/src/Mod/Part/Gui/DlgProjectionOnSurface.h
+++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.h
@@ -36,22 +36,24 @@
#include
-namespace PartGui {
+namespace PartGui
+{
- class Ui_DlgProjectionOnSurface;
+class Ui_DlgProjectionOnSurface;
- namespace Ui {
- class DlgProjectionOnSurface;
- }
+namespace Ui
+{
+class DlgProjectionOnSurface;
+}
-class DlgProjectionOnSurface : public QWidget,
- public Gui::SelectionObserver,
- public App::DocumentObserver
+class DlgProjectionOnSurface: public QWidget,
+ public Gui::SelectionObserver,
+ public App::DocumentObserver
{
Q_OBJECT
public:
- explicit DlgProjectionOnSurface(QWidget *parent = nullptr);
+ explicit DlgProjectionOnSurface(QWidget* parent = nullptr);
~DlgProjectionOnSurface() override;
void apply();
@@ -74,57 +76,64 @@ private:
void onDoubleSpinBoxSolidDepthValueChanged(double arg1);
private:
+ struct SShapeStore
+ {
+ TopoDS_Shape inputShape;
+ TopoDS_Face surfaceToProject;
+ gp_Dir aProjectionDir;
+ TopoDS_Face aFace;
+ TopoDS_Edge aEdge;
+ std::vector aWireVec;
+ std::vector aProjectedWireVec;
+ std::vector aProjectedEdgeVec;
+ std::vector aProjectedWireInParametricSpaceVec;
+ TopoDS_Face aProjectedFace;
+ TopoDS_Shape aProjectedSolid;
+ Part::Feature* partFeature = nullptr;
+ std::string partName;
+ bool is_selectable = false;
+ long transparency = 0;
+ double extrudeValue = 0.0;
+ };
- struct SShapeStore
- {
- TopoDS_Shape inputShape;
- TopoDS_Face surfaceToProject;
- gp_Dir aProjectionDir;
- TopoDS_Face aFace;
- TopoDS_Edge aEdge;
- std::vector aWireVec;
- std::vector aProjectedWireVec;
- std::vector aProjectedEdgeVec;
- std::vector aProjectedWireInParametricSpaceVec;
- TopoDS_Face aProjectedFace;
- TopoDS_Shape aProjectedSolid;
- Part::Feature* partFeature = nullptr;
- std::string partName;
- bool is_selectable = false;
- long transparency = 0;
- float extrudeValue = 0.0f;
- };
-
- //from Gui::SelectionObserver
- void onSelectionChanged(const Gui::SelectionChanges& msg) override;
+ // from Gui::SelectionObserver
+ void onSelectionChanged(const Gui::SelectionChanges& msg) override;
- void get_camera_direction();
- void store_current_selected_parts(std::vector& iStoreVec, const unsigned int iColor);
- bool store_part_in_vector(SShapeStore& iCurrentShape, std::vector& iStoreVec);
- void create_projection_wire(std::vector& iCurrentShape);
- TopoDS_Shape create_compound(const std::vector& iShapeVec);
- void show_projected_shapes(const std::vector& iShapeStoreVec);
- void disable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis);
- void enable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis);
- void higlight_object(Part::Feature* iCurrentObject, const std::string& iShapeName, bool iHighlight, const unsigned int iColor);
- void get_all_wire_from_face(SShapeStore& ioCurrentSahpe);
- void create_projection_face_from_wire(std::vector& iCurrentShape);
- TopoDS_Wire sort_and_heal_wire(const TopoDS_Shape& iShape, const TopoDS_Face& iFaceToProject);
- TopoDS_Wire sort_and_heal_wire(const std::vector& iEdgeVec, const TopoDS_Face& iFaceToProject);
- void create_face_extrude(std::vector& iCurrentShape);
- void store_wire_in_vector(const SShapeStore& iCurrentShape, const TopoDS_Shape& iParentShape, std::vector& iStoreVec, const unsigned int iColor);
- void set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox);
- void transform_shape_to_global_position(TopoDS_Shape& ioShape, Part::Feature* iPart);
+ void get_camera_direction();
+ void store_current_selected_parts(std::vector& iStoreVec,
+ unsigned int iColor);
+ bool store_part_in_vector(SShapeStore& iCurrentShape, std::vector& iStoreVec);
+ void create_projection_wire(std::vector& iCurrentShape);
+ TopoDS_Shape create_compound(const std::vector& iShapeVec);
+ void show_projected_shapes(const std::vector& iShapeStoreVec);
+ void disable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis);
+ void enable_ui_elements(const std::vector& iObjectVec, QWidget* iExceptThis);
+ void higlight_object(Part::Feature* iCurrentObject,
+ const std::string& iShapeName,
+ bool iHighlight,
+ unsigned int iColor);
+ void get_all_wire_from_face(SShapeStore& ioCurrentSahpe);
+ void create_projection_face_from_wire(std::vector& iCurrentShape);
+ TopoDS_Wire sort_and_heal_wire(const TopoDS_Shape& iShape, const TopoDS_Face& iFaceToProject);
+ TopoDS_Wire sort_and_heal_wire(const std::vector& iEdgeVec,
+ const TopoDS_Face& iFaceToProject);
+ void create_face_extrude(std::vector& iCurrentShape);
+ void store_wire_in_vector(const SShapeStore& iCurrentShape,
+ const TopoDS_Shape& iParentShape,
+ std::vector& iStoreVec,
+ unsigned int iColor);
+ void set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox);
+ void transform_shape_to_global_position(TopoDS_Shape& ioShape, Part::Feature* iPart);
private:
- /** Checks if the given document is about to be closed */
- void slotDeletedDocument(const App::Document& Doc) override;
- /** Checks if the given object is about to be removed. */
- void slotDeletedObject(const App::DocumentObject& Obj) override;
+ /** Checks if the given document is about to be closed */
+ void slotDeletedDocument(const App::Document& Doc) override;
+ /** Checks if the given object is about to be removed. */
+ void slotDeletedObject(const App::DocumentObject& Obj) override;
private:
- Ui::DlgProjectionOnSurface *ui;
+ Ui::DlgProjectionOnSurface* ui;
std::vector m_shapeVec;
std::vector m_projectionSurfaceVec;
@@ -134,9 +143,9 @@ private:
std::vector m_guiObjectVec;
const QString m_projectionObjectName;
- Part::Feature* m_projectionObject;
- App::Document* m_partDocument;
- float m_lastDepthVal;
+ Part::Feature* m_projectionObject = nullptr;
+ App::Document* m_partDocument = nullptr;
+ double m_lastDepthVal;
class EdgeSelection;
EdgeSelection* filterEdge;
@@ -145,28 +154,28 @@ private:
FaceSelection* filterFace;
};
-class TaskProjectionOnSurface : public Gui::TaskView::TaskDialog
+class TaskProjectionOnSurface: public Gui::TaskView::TaskDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- TaskProjectionOnSurface();
+ TaskProjectionOnSurface();
public:
- bool accept() override;
- bool reject() override;
- void clicked(int) override;
+ bool accept() override;
+ bool reject() override;
+ void clicked(int id) override;
- QDialogButtonBox::StandardButtons getStandardButtons() const override
- {
- return QDialogButtonBox::Ok | QDialogButtonBox::Cancel;
- }
+ QDialogButtonBox::StandardButtons getStandardButtons() const override
+ {
+ return QDialogButtonBox::Ok | QDialogButtonBox::Cancel;
+ }
private:
- DlgProjectionOnSurface* widget;
- Gui::TaskView::TaskBox* taskbox;
+ DlgProjectionOnSurface* widget = nullptr;
+ Gui::TaskView::TaskBox* taskbox = nullptr;
};
-} // namespace PartGui
-#endif // PARTGUI_DLGPROJECTIONONSURFACE_H
+} // namespace PartGui
+#endif // PARTGUI_DLGPROJECTIONONSURFACE_H
diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp
index e9730b1a79..97c52a42fb 100644
--- a/src/Mod/PartDesign/App/FeatureHelix.cpp
+++ b/src/Mod/PartDesign/App/FeatureHelix.cpp
@@ -232,79 +232,12 @@ App::DocumentObjectExecReturn* Helix::execute()
// generate the helix path
TopoDS_Shape path = generateHelixPath();
- TopoDS_Shape auxpath = generateHelixPath(1.0);
- // Use MakePipe for frenet ( Angle is 0 ) calculations, faster than MakePipeShell
- if ( Angle.getValue() == 0 ) {
- TopoDS_Shape face = Part::FaceMakerCheese::makeFace(wires);
- face.Move(invObjLoc);
- BRepOffsetAPI_MakePipe mkPS(TopoDS::Wire(path), face, GeomFill_Trihedron::GeomFill_IsFrenet, Standard_False);
- mkPS.Build();
- result = mkPS.Shape();
- } else {
- std::vector> wiresections;
- for (TopoDS_Wire& wire : wires)
- wiresections.emplace_back(1, wire);
-
- //build all shells
- std::vector shells;
- std::vector frontwires, backwires;
- for (std::vector& wires : wiresections) {
-
- BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path));
-
- // Frenet mode doesn't place the face quite right on an angled helix, so
- // use the auxiliary spine to force that.
- mkPS.SetMode(TopoDS::Wire(auxpath), true); // this is for auxiliary
-
- for (TopoDS_Wire& wire : wires) {
- wire.Move(invObjLoc);
- mkPS.Add(wire);
- }
-
- if (!mkPS.IsReady())
- return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Could not build"));
- mkPS.Build();
-
- shells.push_back(mkPS.Shape());
-
- if (!mkPS.Shape().Closed()) {
- // // shell is not closed - use simulate to get the end wires
- TopTools_ListOfShape sim;
- mkPS.Simulate(2, sim);
-
- frontwires.push_back(TopoDS::Wire(sim.First()));
- backwires.push_back(TopoDS::Wire(sim.Last()));
- }
- BRepBuilderAPI_MakeSolid mkSolid;
-
- if (!frontwires.empty()) {
- // build the end faces, sew the shell and build the final solid
- TopoDS_Shape front = Part::FaceMakerCheese::makeFace(frontwires);
- TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires);
-
- BRepBuilderAPI_Sewing sewer;
- sewer.SetTolerance(Precision::Confusion());
- sewer.Add(front);
- sewer.Add(back);
-
- for (TopoDS_Shape& s : shells)
- sewer.Add(s);
- sewer.Perform();
- mkSolid.Add(TopoDS::Shell(sewer.SewedShape()));
- }
- else {
- // shells are already closed - add them directly
- for (TopoDS_Shape& s : shells) {
- mkSolid.Add(TopoDS::Shell(s));
- }
- }
- if (!mkSolid.IsDone())
- return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result is not a solid"));
-
- result = mkSolid.Shape();
- }
- }
+ TopoDS_Shape face = Part::FaceMakerCheese::makeFace(wires);
+ face.Move(invObjLoc);
+ BRepOffsetAPI_MakePipe mkPS(TopoDS::Wire(path), face, GeomFill_Trihedron::GeomFill_IsFrenet, Standard_False);
+ mkPS.Build();
+ result = mkPS.Shape();
BRepClass3d_SolidClassifier SC(result);
SC.PerformInfinitePoint(Precision::Confusion());
@@ -403,7 +336,7 @@ void Helix::updateAxis()
Axis.setValue(dir.x, dir.y, dir.z);
}
-TopoDS_Shape Helix::generateHelixPath(double startOffset0)
+TopoDS_Shape Helix::generateHelixPath()
{
double turns = Turns.getValue();
double height = Height.getValue();
@@ -449,7 +382,7 @@ TopoDS_Shape Helix::generateHelixPath(double startOffset0)
bool turned = axisOffset < 0;
// since the factor does not only change the radius but also the path position, we must shift its offset back
// using the square of the factor
- double startOffset = 10000.0 * std::fabs(startOffset0 + profileCenter * axisVector - baseVector * axisVector);
+ double startOffset = 10000.0 * std::fabs(baseVector * axisVector);
if (radius < Precision::Confusion()) {
// in this case ensure that axis is not in the sketch plane
@@ -466,8 +399,7 @@ TopoDS_Shape Helix::generateHelixPath(double startOffset0)
radiusTop = radius + height * tan(Base::toRadians(angle));
//build the helix path
- //TopoShape helix = TopoShape().makeLongHelix(pitch, height, radius, angle, leftHanded);
- TopoDS_Shape path = TopoShape().makeSpiralHelix(radius, radiusTop, height, turns, 1, leftHanded);
+ TopoDS_Shape path = TopoShape().makeSpiralHelix(radius, radiusTop, height, turns, 1000, leftHanded);
/*
* The helix wire is created with the axis coinciding with z-axis and the start point at (radius, 0, 0)
diff --git a/src/Mod/PartDesign/App/FeatureHelix.h b/src/Mod/PartDesign/App/FeatureHelix.h
index 531ded92d6..3a4a3a7cb7 100644
--- a/src/Mod/PartDesign/App/FeatureHelix.h
+++ b/src/Mod/PartDesign/App/FeatureHelix.h
@@ -80,7 +80,7 @@ protected:
void updateAxis();
/// generate helix and move it to the right location.
- TopoDS_Shape generateHelixPath(double startOffset0 = 0.0);
+ TopoDS_Shape generateHelixPath();
// project shape on plane. Used for detecting self intersection.
TopoDS_Shape projectShape(const TopoDS_Shape& input, const gp_Ax2& plane);
diff --git a/src/Mod/PartDesign/PartDesignTests/TestHelix.py b/src/Mod/PartDesign/PartDesignTests/TestHelix.py
index ea938b5a3e..3be150af22 100644
--- a/src/Mod/PartDesign/PartDesignTests/TestHelix.py
+++ b/src/Mod/PartDesign/PartDesignTests/TestHelix.py
@@ -87,15 +87,15 @@ class TestHelix(unittest.TestCase):
helix.Angle = 0
helix.Mode = 1
self.Doc.recompute()
- self.assertAlmostEqual(helix.Shape.Volume, 78.95687956849457,places=5)
+ self.assertAlmostEqual(helix.Shape.Volume, 78.957,places=3)
helix.Angle = 25
self.Doc.recompute()
- self.assertAlmostEqual(helix.Shape.Volume, 134.17450779511307,places=5)
+ self.assertAlmostEqual(helix.Shape.Volume, 134.17,places=2)
profileSketch.addGeometry(Part.Circle(FreeCAD.Vector(2, 0, 0), FreeCAD.Vector(0,0,1), 0.5) )
self.Doc.recompute()
- self.assertAlmostEqual(helix.Shape.Volume, 100.63088079046352,places=5)
+ self.assertAlmostEqual(helix.Shape.Volume, 100.63,places=2)
def testRectangle(self):
@@ -174,7 +174,7 @@ class TestHelix(unittest.TestCase):
helix.Mode = 0
helix.Reversed = True
self.Doc.recompute()
- self.assertAlmostEqual(helix.Shape.Volume, 388285.4117047924,places=5)
+ self.assertAlmostEqual(helix.Shape.Volume/1e5, 3.8828,places=4)
def tearDown(self):
FreeCAD.closeDocument("PartDesignTestHelix")
diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp
index ecb6c9abe6..6452b8607f 100644
--- a/src/Mod/Sketcher/App/SketchObject.cpp
+++ b/src/Mod/Sketcher/App/SketchObject.cpp
@@ -4227,105 +4227,298 @@ bool SketchObject::isCarbonCopyAllowed(App::Document* pDoc, App::DocumentObject*
}
int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
- Sketcher::PointPos refPosId /*=Sketcher::PointPos::none*/)
+ Sketcher::PointPos refPosId /*=Sketcher::PointPos::none*/,
+ bool addSymmetryConstraints /*= false*/)
{
// no need to check input data validity as this is an sketchobject managed operation.
Base::StateLocker lock(managedoperation, true);
- const std::vector& geovals = getInternalGeometry();
- std::vector newgeoVals(geovals);
-
const std::vector& constrvals = this->Constraints.getValues();
std::vector newconstrVals(constrvals);
- newgeoVals.reserve(geovals.size() + geoIdList.size());
-
- int cgeoid = getHighestCurveIndex() + 1;
-
- std::map geoIdMap;
- std::map isStartEndInverted;
-
// Find out if reference is aligned with V or H axis,
// if so we can keep Vertical and Horizontal constraints in the mirrored geometry.
+ bool refIsLine = refPosId == Sketcher::PointPos::none;
bool refIsAxisAligned = false;
- if (refGeoId == Sketcher::GeoEnum::VAxis || refGeoId == Sketcher::GeoEnum::HAxis) {
+ if (refGeoId == Sketcher::GeoEnum::VAxis || refGeoId == Sketcher::GeoEnum::HAxis || !refIsLine) {
refIsAxisAligned = true;
}
else {
- for (std::vector::const_iterator it = constrvals.begin();
- it != constrvals.end();
- ++it) {
- Constraint* constr = *(it);
+ for (auto* constr : constrvals) {
if (constr->First == refGeoId
- && (constr->Type == Sketcher::Vertical || constr->Type == Sketcher::Horizontal))
+ && (constr->Type == Sketcher::Vertical || constr->Type == Sketcher::Horizontal)){
refIsAxisAligned = true;
+ }
}
}
- // reference is a line
- if (refPosId == Sketcher::PointPos::none) {
- const Part::Geometry* georef = getGeometry(refGeoId);
- if (georef->getTypeId() != Part::GeomLineSegment::getClassTypeId()) {
- Base::Console().Error("Reference for symmetric is neither a point nor a line.\n");
- return -1;
+ // add the geometry
+ std::map geoIdMap;
+ std::map isStartEndInverted;
+ std::vector newgeoVals(getInternalGeometry());
+ std::vector symmetricVals = getSymmetric(geoIdList, geoIdMap, isStartEndInverted, refGeoId, refPosId);
+ newgeoVals.insert(newgeoVals.end(), symmetricVals.begin(), symmetricVals.end());
+
+ // Block acceptGeometry in OnChanged to avoid unnecessary checks and updates
+ {
+ Base::StateLocker lock(internaltransaction, true);
+ Geometry.setValues(std::move(newgeoVals));
+
+
+ for (auto* constr : constrvals) {
+ // we look in the map, because we might have skipped internal alignment geometry
+ auto fit = geoIdMap.find(constr->First);
+
+ if (fit != geoIdMap.end()) {// if First of constraint is in geoIdList
+ if (addSymmetryConstraints && constr->Type != Sketcher::InternalAlignment) {
+ // if we are making symmetric constraints, then we don't want to copy all constraints
+ continue;
+ }
+
+ if (constr->Second == GeoEnum::GeoUndef /*&& constr->Third == GeoEnum::GeoUndef*/) {
+ if (refIsAxisAligned) {
+ // in this case we want to keep the Vertical, Horizontal constraints
+ // DistanceX ,and DistanceY constraints should also be possible to keep in
+ // this case, but keeping them causes segfault, not sure why.
+
+ if (constr->Type != Sketcher::DistanceX
+ && constr->Type != Sketcher::DistanceY) {
+ Constraint* constNew = constr->copy();
+ constNew->First = fit->second;
+ newconstrVals.push_back(constNew);
+ }
+ }
+ else if (constr->Type != Sketcher::DistanceX
+ && constr->Type != Sketcher::DistanceY
+ && constr->Type != Sketcher::Vertical
+ && constr->Type != Sketcher::Horizontal) {
+ // this includes all non-directional single GeoId constraints, as radius,
+ // diameter, weight,...
+
+ Constraint* constNew = constr->copy();
+ constNew->First = fit->second;
+ newconstrVals.push_back(constNew);
+ }
+ }
+ else {// other geoids intervene in this constraint
+
+ auto sit = geoIdMap.find(constr->Second);
+
+ if (sit != geoIdMap.end()) {// Second is also in the list
+
+ if (constr->Third == GeoEnum::GeoUndef) {
+ if (constr->Type == Sketcher::Coincident
+ || constr->Type == Sketcher::Perpendicular
+ || constr->Type == Sketcher::Parallel
+ || constr->Type == Sketcher::Tangent
+ || constr->Type == Sketcher::Distance
+ || constr->Type == Sketcher::Equal || constr->Type == Sketcher::Angle
+ || constr->Type == Sketcher::PointOnObject
+ || constr->Type == Sketcher::InternalAlignment) {
+ Constraint* constNew = constr->copy();
+
+ constNew->First = fit->second;
+ constNew->Second = sit->second;
+ if (isStartEndInverted[constr->First]) {
+ if (constr->FirstPos == Sketcher::PointPos::start)
+ constNew->FirstPos = Sketcher::PointPos::end;
+ else if (constr->FirstPos == Sketcher::PointPos::end)
+ constNew->FirstPos = Sketcher::PointPos::start;
+ }
+ if (isStartEndInverted[constr->Second]) {
+ if (constr->SecondPos == Sketcher::PointPos::start)
+ constNew->SecondPos = Sketcher::PointPos::end;
+ else if (constr->SecondPos == Sketcher::PointPos::end)
+ constNew->SecondPos = Sketcher::PointPos::start;
+ }
+
+ if (constNew->Type == Tangent || constNew->Type == Perpendicular)
+ AutoLockTangencyAndPerpty(constNew, true);
+
+ if ((constr->Type == Sketcher::Angle)
+ && (refPosId == Sketcher::PointPos::none)) {
+ constNew->setValue(-constr->getValue());
+ }
+
+ newconstrVals.push_back(constNew);
+ }
+ }
+ else {// three GeoIds intervene in constraint
+ auto tit = geoIdMap.find(constr->Third);
+
+ if (tit != geoIdMap.end()) {// Third is also in the list
+ Constraint* constNew = constr->copy();
+ constNew->First = fit->second;
+ constNew->Second = sit->second;
+ constNew->Third = tit->second;
+ if (isStartEndInverted[constr->First]) {
+ if (constr->FirstPos == Sketcher::PointPos::start)
+ constNew->FirstPos = Sketcher::PointPos::end;
+ else if (constr->FirstPos == Sketcher::PointPos::end)
+ constNew->FirstPos = Sketcher::PointPos::start;
+ }
+ if (isStartEndInverted[constr->Second]) {
+ if (constr->SecondPos == Sketcher::PointPos::start)
+ constNew->SecondPos = Sketcher::PointPos::end;
+ else if (constr->SecondPos == Sketcher::PointPos::end)
+ constNew->SecondPos = Sketcher::PointPos::start;
+ }
+ if (isStartEndInverted[constr->Third]) {
+ if (constr->ThirdPos == Sketcher::PointPos::start)
+ constNew->ThirdPos = Sketcher::PointPos::end;
+ else if (constr->ThirdPos == Sketcher::PointPos::end)
+ constNew->ThirdPos = Sketcher::PointPos::start;
+ }
+ newconstrVals.push_back(constNew);
+ }
+ }
+ }
+ }
+ }
}
- const Part::GeomLineSegment* refGeoLine = static_cast(georef);
+ if (addSymmetryConstraints) {
+ auto createSymConstr = [&]
+ (int first, int second, Sketcher::PointPos firstPos, Sketcher::PointPos secondPos) {
+ auto symConstr = new Constraint();
+ symConstr->Type = Symmetric;
+ symConstr->First = first;
+ symConstr->Second = second;
+ symConstr->Third = refGeoId;
+ symConstr->FirstPos = firstPos;
+ symConstr->SecondPos = secondPos;
+ symConstr->ThirdPos = refPosId;
+ newconstrVals.push_back(symConstr);
+ };
+ auto createEqualityConstr = [&]
+ (int first, int second) {
+ auto symConstr = new Constraint();
+ symConstr->Type = Equal;
+ symConstr->First = first;
+ symConstr->Second = second;
+ newconstrVals.push_back(symConstr);
+ };
+
+ for (auto geoIdPair : geoIdMap) {
+ int geoId1 = geoIdPair.first;
+ int geoId2 = geoIdPair.second;
+ const Part::Geometry* geo = getGeometry(geoId1);
+
+ if (geo->is()) {
+ auto gf = GeometryFacade::getFacade(geo);
+ if (!gf->isInternalAligned()) {
+ // Note internal aligned lines (ellipse, parabola, hyperbola) are causing redundant constraint.
+ createSymConstr(geoId1, geoId2, PointPos::start, isStartEndInverted[geoId1] ? PointPos::end : PointPos::start);
+ createSymConstr(geoId1, geoId2, PointPos::end, isStartEndInverted[geoId1] ? PointPos::start : PointPos::end);
+ }
+ }
+ else if (geo->is() || geo->is()) {
+ createEqualityConstr(geoId1, geoId2);
+ createSymConstr(geoId1, geoId2, PointPos::mid, PointPos::mid);
+ }
+ else if (geo->is()
+ || geo->is()
+ || geo->is()
+ || geo->is()) {
+ createEqualityConstr(geoId1, geoId2);
+ createSymConstr(geoId1, geoId2, PointPos::start, isStartEndInverted[geoId1] ? PointPos::end : PointPos::start);
+ createSymConstr(geoId1, geoId2, PointPos::end, isStartEndInverted[geoId1] ? PointPos::start : PointPos::end);
+ }
+ else if (geo->is()) {
+ auto gf = GeometryFacade::getFacade(geo);
+ if (!gf->isInternalAligned()) {
+ createSymConstr(geoId1, geoId2, PointPos::start, PointPos::start);
+ }
+ }
+ // Note bspline has symmetric by the internal aligned circles.
+ }
+ }
+
+ if (newconstrVals.size() > constrvals.size()){
+ Constraints.setValues(std::move(newconstrVals));
+ }
+ }
+
+ // we delayed update, so trigger it now.
+ // Update geometry indices and rebuild vertexindex now via onChanged, so that
+ // ViewProvider::UpdateData is triggered.
+ Geometry.touch();
+
+ return Geometry.getSize() - 1;
+}
+
+
+std::vector SketchObject::getSymmetric(const std::vector& geoIdList,
+ std::map& geoIdMap,
+ std::map& isStartEndInverted,
+ int refGeoId,
+ Sketcher::PointPos refPosId)
+{
+ std::vector symmetricVals;
+ bool refIsLine = refPosId == Sketcher::PointPos::none;
+ int cgeoid = getHighestCurveIndex() + 1;
+
+ auto shouldCopyGeometry = [&](auto* geo, int geoId) -> bool {
+ auto gf = GeometryFacade::getFacade(geo);
+ if (gf->isInternalAligned()) {
+ // only add if the corresponding geometry it defines is also in the list.
+ int definedGeo = GeoEnum::GeoUndef;
+ for (auto c : Constraints.getValues()) {
+ if (c->Type == Sketcher::InternalAlignment && c->First == geoId) {
+ definedGeo = c->Second;
+ break;
+ }
+ }
+ // Return true if definedGeo is in geoIdList, false otherwise
+ return std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end();
+ }
+ // Return true if not internal aligned, indicating it should always be copied
+ return true;
+ };
+
+ if (refIsLine) {
+ const Part::Geometry* georef = getGeometry(refGeoId);
+ if (!georef->is()) {
+ Base::Console().Error("Reference for symmetric is neither a point nor a line.\n");
+ return {};
+ }
+
+ auto* refGeoLine = static_cast(georef);
// line
Base::Vector3d refstart = refGeoLine->getStartPoint();
Base::Vector3d vectline = refGeoLine->getEndPoint() - refstart;
- for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) {
- const Part::Geometry* geo = getGeometry(*it);
+ for (auto geoId : geoIdList) {
+ const Part::Geometry* geo = getGeometry(geoId);
Part::Geometry* geosym;
- auto gf = GeometryFacade::getFacade(geo);
-
- if (gf->isInternalAligned()) {
- // only add this geometry if the corresponding geometry it defines is also in the
- // list.
- int definedGeo = GeoEnum::GeoUndef;
-
- for (auto c : Constraints.getValues()) {
- if (c->Type == Sketcher::InternalAlignment && c->First == *it) {
- definedGeo = c->Second;
- break;
- }
- }
-
- if (std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end())
- geosym = geo->copy();
- else {
- // we should not mirror internal alignment geometry, unless the element they
- // define is also mirrored
- continue;
- }
- }
- else {
- geosym = geo->copy();
+ if (!shouldCopyGeometry(geo, geoId)) {
+ continue;
}
+ geosym = geo->copy();
+
// Handle Geometry
if (geosym->is()) {
- Part::GeomLineSegment* geosymline = static_cast(geosym);
+ auto* geosymline = static_cast(geosym);
Base::Vector3d sp = geosymline->getStartPoint();
Base::Vector3d ep = geosymline->getEndPoint();
geosymline->setPoints(
sp + 2.0 * (sp.Perpendicular(refGeoLine->getStartPoint(), vectline) - sp),
ep + 2.0 * (ep.Perpendicular(refGeoLine->getStartPoint(), vectline) - ep));
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is()) {
- Part::GeomCircle* geosymcircle = static_cast(geosym);
+ auto* geosymcircle = static_cast(geosym);
Base::Vector3d cp = geosymcircle->getCenter();
geosymcircle->setCenter(
cp + 2.0 * (cp.Perpendicular(refGeoLine->getStartPoint(), vectline) - cp));
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is()) {
- Part::GeomArcOfCircle* geoaoc = static_cast(geosym);
+ auto* geoaoc = static_cast(geosym);
Base::Vector3d sp = geoaoc->getStartPoint(true);
Base::Vector3d ep = geoaoc->getEndPoint(true);
Base::Vector3d cp = geoaoc->getCenter();
@@ -4342,10 +4535,10 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
geoaoc->setCenter(scp);
geoaoc->setRange(theta1, theta2, true);
- isStartEndInverted.insert(std::make_pair(*it, true));
+ isStartEndInverted.insert(std::make_pair(geoId, true));
}
else if (geosym->is()) {
- Part::GeomEllipse* geosymellipse = static_cast(geosym);
+ auto* geosymellipse = static_cast(geosym);
Base::Vector3d cp = geosymellipse->getCenter();
Base::Vector3d majdir = geosymellipse->getMajorAxisDir();
@@ -4362,10 +4555,10 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
geosymellipse->setMajorAxisDir(sf1 - scp);
geosymellipse->setCenter(scp);
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is()) {
- Part::GeomArcOfEllipse* geosymaoe = static_cast(geosym);
+ auto* geosymaoe = static_cast(geosym);
Base::Vector3d cp = geosymaoe->getCenter();
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
@@ -4394,11 +4587,10 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
}
geosymaoe->setRange(theta1, theta2, true);
- isStartEndInverted.insert(std::make_pair(*it, true));
+ isStartEndInverted.insert(std::make_pair(geoId, true));
}
else if (geosym->is()) {
- Part::GeomArcOfHyperbola* geosymaoe =
- static_cast(geosym);
+ auto* geosymaoe = static_cast(geosym);
Base::Vector3d cp = geosymaoe->getCenter();
Base::Vector3d majdir = geosymaoe->getMajorAxisDir();
@@ -4423,10 +4615,10 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
std::swap(theta1, theta2);
geosymaoe->setRange(theta1, theta2, true);
- isStartEndInverted.insert(std::make_pair(*it, true));
+ isStartEndInverted.insert(std::make_pair(geoId, true));
}
else if (geosym->is()) {
- Part::GeomArcOfParabola* geosymaoe = static_cast(geosym);
+ auto* geosymaoe = static_cast(geosym);
Base::Vector3d cp = geosymaoe->getCenter();
// double df= geosymaoe->getFocal();
@@ -4447,45 +4639,41 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
std::swap(theta1, theta2);
geosymaoe->setRange(theta1, theta2, true);
- isStartEndInverted.insert(std::make_pair(*it, true));
+ isStartEndInverted.insert(std::make_pair(geoId, true));
}
else if (geosym->is()) {
- Part::GeomBSplineCurve* geosymbsp = static_cast(geosym);
+ auto* geosymbsp = static_cast(geosym);
std::vector poles = geosymbsp->getPoles();
- for (std::vector::iterator jt = poles.begin(); jt != poles.end();
- ++jt) {
-
- (*jt) = (*jt)
- + 2.0
- * ((*jt).Perpendicular(refGeoLine->getStartPoint(), vectline) - (*jt));
+ for (auto& pole : poles) {
+ pole = pole
+ + 2.0 * (pole.Perpendicular(refGeoLine->getStartPoint(), vectline) - pole);
}
geosymbsp->setPoles(poles);
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is()) {
- Part::GeomPoint* geosympoint = static_cast(geosym);
+ auto* geosympoint = static_cast(geosym);
Base::Vector3d cp = geosympoint->getPoint();
geosympoint->setPoint(
cp + 2.0 * (cp.Perpendicular(refGeoLine->getStartPoint(), vectline) - cp));
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else {
Base::Console().Error("Unsupported Geometry!! Just copying it.\n");
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
- newgeoVals.push_back(geosym);
- geoIdMap.insert(std::make_pair(*it, cgeoid));
+ symmetricVals.push_back(geosym);
+ geoIdMap.insert(std::make_pair(geoId, cgeoid));
cgeoid++;
}
}
else {// reference is a point
- refIsAxisAligned = true;
Vector3d refpoint;
const Part::Geometry* georef = getGeometry(refGeoId);
@@ -4496,160 +4684,43 @@ int SketchObject::addSymmetric(const std::vector& geoIdList, int refGeoId,
refpoint = Vector3d(0, 0, 0);
}
else {
- switch (refPosId) {
- case Sketcher::PointPos::start:
- if (georef->is()) {
- const Part::GeomLineSegment* geosymline =
- static_cast(georef);
- refpoint = geosymline->getStartPoint();
- }
- else if (georef->is()) {
- const Part::GeomArcOfCircle* geoaoc =
- static_cast(georef);
- refpoint = geoaoc->getStartPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfEllipse* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getStartPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfHyperbola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getStartPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfParabola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getStartPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomBSplineCurve* geosymbsp =
- static_cast(georef);
- refpoint = geosymbsp->getStartPoint();
- }
- break;
- case Sketcher::PointPos::end:
- if (georef->is()) {
- const Part::GeomLineSegment* geosymline =
- static_cast(georef);
- refpoint = geosymline->getEndPoint();
- }
- else if (georef->is()) {
- const Part::GeomArcOfCircle* geoaoc =
- static_cast(georef);
- refpoint = geoaoc->getEndPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfEllipse* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getEndPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfHyperbola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getEndPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomArcOfParabola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getEndPoint(true);
- }
- else if (georef->is()) {
- const Part::GeomBSplineCurve* geosymbsp =
- static_cast(georef);
- refpoint = geosymbsp->getEndPoint();
- }
- break;
- case Sketcher::PointPos::mid:
- if (georef->is()) {
- const Part::GeomCircle* geosymcircle =
- static_cast(georef);
- refpoint = geosymcircle->getCenter();
- }
- else if (georef->is()) {
- const Part::GeomArcOfCircle* geoaoc =
- static_cast(georef);
- refpoint = geoaoc->getCenter();
- }
- else if (georef->is()) {
- const Part::GeomEllipse* geosymellipse =
- static_cast(georef);
- refpoint = geosymellipse->getCenter();
- }
- else if (georef->is()) {
- const Part::GeomArcOfEllipse* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getCenter();
- }
- else if (georef->is()) {
- const Part::GeomArcOfHyperbola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getCenter();
- }
- else if (georef->is()) {
- const Part::GeomArcOfParabola* geosymaoe =
- static_cast(georef);
- refpoint = geosymaoe->getCenter();
- }
- break;
- default:
- Base::Console().Error("Wrong PointPosId.\n");
- return -1;
+ if (refPosId == Sketcher::PointPos::none) {
+ Base::Console().Error("Wrong PointPosId.\n");
+ return {};
}
+ refpoint = getPoint(georef, refPosId);
}
- for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) {
- const Part::Geometry* geo = getGeometry(*it);
-
+ for (auto geoId : geoIdList) {
+ const Part::Geometry* geo = getGeometry(geoId);
Part::Geometry* geosym;
- auto gf = GeometryFacade::getFacade(geo);
-
- if (gf->isInternalAligned()) {
- // only add this geometry if the corresponding geometry it defines is also in the
- // list.
- int definedGeo = GeoEnum::GeoUndef;
-
- for (auto c : Constraints.getValues()) {
- if (c->Type == Sketcher::InternalAlignment && c->First == *it) {
- definedGeo = c->Second;
- break;
- }
- }
-
- if (std::find(geoIdList.begin(), geoIdList.end(), definedGeo) != geoIdList.end())
- geosym = geo->copy();
- else {
- // we should not mirror internal alignment geometry, unless the element they
- // define is also mirrored
- continue;
- }
- }
- else {
- geosym = geo->copy();
+ if (!shouldCopyGeometry(geo, geoId)) {
+ continue;
}
+ geosym = geo->copy();
+
// Handle Geometry
if (geosym->is()) {
- Part::GeomLineSegment* geosymline = static_cast(geosym);
+ auto* geosymline = static_cast(geosym);
Base::Vector3d sp = geosymline->getStartPoint();
Base::Vector3d ep = geosymline->getEndPoint();
Base::Vector3d ssp = sp + 2.0 * (refpoint - sp);
Base::Vector3d sep = ep + 2.0 * (refpoint - ep);
geosymline->setPoints(ssp, sep);
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is()) {
- Part::GeomCircle* geosymcircle = static_cast(geosym);
+ auto* geosymcircle = static_cast(geosym);
Base::Vector3d cp = geosymcircle->getCenter();
geosymcircle->setCenter(cp + 2.0 * (refpoint - cp));
- isStartEndInverted.insert(std::make_pair(*it, false));
+ isStartEndInverted.insert(std::make_pair(geoId, false));
}
else if (geosym->is